Received: by 2002:ac0:a582:0:0:0:0:0 with SMTP id m2-v6csp933386imm; Thu, 4 Oct 2018 05:51:30 -0700 (PDT) X-Google-Smtp-Source: ACcGV63VAr3lw3j81LKFVnMorqzTc6DdrU11UvZ8E64EYO95HFttsoKIdKQOSvKBaw7DG5uO/9nN X-Received: by 2002:a62:184a:: with SMTP id 71-v6mr6613830pfy.246.1538657490228; Thu, 04 Oct 2018 05:51:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1538657490; cv=none; d=google.com; s=arc-20160816; b=gWbhgSGxXRZXlqnB6dKXH70T0FzRdCpx1LqnL6xinKpsKfILL9JGG0wnGnLpQlE1K6 ZwgyGCx0IfSjW2q0J3QMcXye0rEppXUMoM1ASOYK6KLtAMPmwIoe6gqvVfCR0wPazF32 ZtSo7JmfMhmGPhR5oqNlmyAiHxTOBfP8Q4n2vUHSSTpNcm5c7tGn0tArDs0dUhGSBbEN jBJYwGm45fyR9ysySIKrIplWAFLfSNTm59T0fXwtTJEkck3bVIxbbiRuhSODgtfjbloL 1uk3laubv9pXYYgu3DN2U3v5fhWJLg5h8Xy10LZxZEgL4GejQKA8YBq27e5heIOdMatE 0gWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=Q/SX4GIQ3fj/56YW8i6SOVc05o+zT4G+lth8tOz3PzQ=; b=y4X21KBUPbW7p8nVnK6HtlNqlFDRsGletNx+KOqe92VMsB8HXdtENrnNd3vbHmdI7c 5BiyWscEKdFVCMHWTG6XdxKM3BBPUeiiYWq/SYSsirYaapCCjE+rnMeRlyEdc/Xtrtgg rpAILsM56+q68MD3LFV2iWyN7sHNiNhX3R4GAxBIXQy7egjxpxrnKgt7U6cRFn82NP4V Qrw2ie2SfKi+jis2IDJJvsZJlNsfl+CSsi54YxuQM+05bPmqGi+QPE2qxe8uWlKWgAkZ 7Yg+tXsBZJ7NZeWooU895MY31GD+BiC/V89RiTIxlzU5ND1OYIZJJ+yn2TFi6JwhZsFn DOHA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d4-v6si4889516pgj.341.2018.10.04.05.51.13; Thu, 04 Oct 2018 05:51:30 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727606AbeJDToO (ORCPT + 99 others); Thu, 4 Oct 2018 15:44:14 -0400 Received: from mail.bootlin.com ([62.4.15.54]:37509 "EHLO mail.bootlin.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727256AbeJDToL (ORCPT ); Thu, 4 Oct 2018 15:44:11 -0400 Received: by mail.bootlin.com (Postfix, from userid 110) id 26E08208B7; Thu, 4 Oct 2018 14:50:59 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.bootlin.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost.localdomain (AAubervilliers-681-1-28-153.w90-88.abo.wanadoo.fr [90.88.148.153]) by mail.bootlin.com (Postfix) with ESMTPSA id CC3BD207B4; Thu, 4 Oct 2018 14:50:48 +0200 (CEST) From: Quentin Schulz To: davem@davemloft.net, andrew@lunn.ch, f.fainelli@gmail.com Cc: allan.nielsen@microchip.com, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, thomas.petazzoni@bootlin.com, alexandre.belloni@bootlin.com, Quentin Schulz Subject: [PATCH net-next v2 1/6] net: phy: mscc: migrate to phy_select/restore_page functions Date: Thu, 4 Oct 2018 14:47:23 +0200 Message-Id: <20181004124728.9821-2-quentin.schulz@bootlin.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181004124728.9821-1-quentin.schulz@bootlin.com> References: <20181004124728.9821-1-quentin.schulz@bootlin.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Microsemi PHYs have multiple banks of registers (called pages). Registers can only be accessed from one page, if we need a register from another page, we need to switch the page and the registers of all other pages are not accessible anymore. Basically, to read register 5 from page 0, 1, 2, etc., you do the same phy_read(phydev, 5); but you need to set the desired page beforehand. In order to guarantee that two concurrent functions do not change the page, we need to do some locking per page. This can be achieved with the use of phy_select_page and phy_restore_page functions but phy_write/read calls in-between those two functions shall be replaced by their lock-free alternative __phy_write/read. Let's migrate this driver to those functions. Suggested-by: Andrew Lunn Signed-off-by: Quentin Schulz --- drivers/net/phy/mscc.c | 142 +++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 63 deletions(-) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 7d0384e26c99..35d58e7b95e9 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -140,12 +140,14 @@ static const struct vsc8531_edge_rate_table edge_table[] = { }; #endif /* CONFIG_OF_MDIO */ -static int vsc85xx_phy_page_set(struct phy_device *phydev, u16 page) +static int vsc85xx_phy_read_page(struct phy_device *phydev) { - int rc; + return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS); +} - rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); - return rc; +static int vsc85xx_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); } static int vsc85xx_led_cntl_set(struct phy_device *phydev, @@ -180,7 +182,7 @@ static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix) static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) { - int rc; + int rc, oldpage; u16 reg_val; reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL); @@ -197,25 +199,30 @@ static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) if (rc != 0) return rc; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) - return rc; + oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED); + if (oldpage < 0) { + rc = oldpage; + goto out; + } - reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL); + reg_val = __phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL); reg_val &= ~(FORCE_MDI_CROSSOVER_MASK); if (mdix == ETH_TP_MDI) reg_val |= FORCE_MDI_CROSSOVER_MDI; else if (mdix == ETH_TP_MDI_X) reg_val |= FORCE_MDI_CROSSOVER_MDIX; - rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val); + rc = __phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val); if (rc != 0) - return rc; + goto out; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - if (rc != 0) + rc = phy_restore_page(phydev, oldpage, rc); + if (rc < 0) return rc; return genphy_restart_aneg(phydev); + +out: + return phy_restore_page(phydev, oldpage, rc); } static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) @@ -223,25 +230,24 @@ static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) int rc; u16 reg_val; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED); + if (rc < 0) goto out; - reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); + reg_val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); reg_val &= DOWNSHIFT_CNTL_MASK; if (!(reg_val & DOWNSHIFT_EN)) *count = DOWNSHIFT_DEV_DISABLE; else *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); out: - return rc; + return phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); } static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count) { - int rc; + int rc, oldpage; u16 reg_val; if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) { @@ -255,21 +261,19 @@ static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count) count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN); } - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); - if (rc != 0) + oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED); + if (oldpage < 0) { + rc = oldpage; goto out; + } - reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); + reg_val = __phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); reg_val &= ~(DOWNSHIFT_CNTL_MASK); reg_val |= count; - rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val); - if (rc != 0) - goto out; - - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); + rc = __phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val); out: - return rc; + return phy_restore_page(phydev, oldpage, rc > 0 ? 0 : rc); } static int vsc85xx_wol_set(struct phy_device *phydev, @@ -283,46 +287,48 @@ static int vsc85xx_wol_set(struct phy_device *phydev, u8 *mac_addr = phydev->attached_dev->dev_addr; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) { + rc = phy_restore_page(phydev, rc, rc); goto out_unlock; + } if (wol->wolopts & WAKE_MAGIC) { /* Store the device address for the magic packet */ for (i = 0; i < ARRAY_SIZE(pwd); i++) pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 | mac_addr[5 - i * 2]; - phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]); - phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]); - phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]); + __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]); } else { - phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0); - phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0); - phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0); } if (wol_conf->wolopts & WAKE_MAGICSECURE) { for (i = 0; i < ARRAY_SIZE(pwd); i++) pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 | wol_conf->sopass[5 - i * 2]; - phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]); - phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]); - phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]); + __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]); } else { - phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0); - phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0); - phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0); + __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0); } - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); + reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); if (wol_conf->wolopts & WAKE_MAGICSECURE) reg_val |= SECURE_ON_ENABLE; else reg_val &= ~SECURE_ON_ENABLE; - phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); + __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - if (rc != 0) + rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); + if (rc < 0) goto out_unlock; if (wol->wolopts & WAKE_MAGIC) { @@ -359,17 +365,17 @@ static void vsc85xx_wol_get(struct phy_device *phydev, struct ethtool_wolinfo *wol_conf = wol; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) goto out_unlock; - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); + reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); if (reg_val & SECURE_ON_ENABLE) wol_conf->wolopts |= WAKE_MAGICSECURE; if (wol_conf->wolopts & WAKE_MAGICSECURE) { - pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD); - pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD); - pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD); + pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD); + pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD); + pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD); for (i = 0; i < ARRAY_SIZE(pwd); i++) { wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff; wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00) @@ -377,9 +383,8 @@ static void vsc85xx_wol_get(struct phy_device *phydev, } } - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); - out_unlock: + phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); mutex_unlock(&phydev->lock); } @@ -473,22 +478,25 @@ static int vsc85xx_dt_led_modes_get(struct phy_device *phydev, static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate) { - int rc; + int rc, oldpage; u16 reg_val; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + oldpage = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (oldpage < 0) { + rc = oldpage; goto out_unlock; - reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); + } + + reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); reg_val &= ~(EDGE_RATE_CNTL_MASK); reg_val |= (edge_rate << EDGE_RATE_CNTL_POS); - rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); + rc = __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); if (rc != 0) goto out_unlock; - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); out_unlock: + rc = phy_restore_page(phydev, oldpage, rc > 0 ? 0 : rc); mutex_unlock(&phydev->lock); return rc; @@ -537,17 +545,17 @@ static int vsc85xx_default_config(struct phy_device *phydev) phydev->mdix_ctrl = ETH_TP_MDI_AUTO; mutex_lock(&phydev->lock); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); - if (rc != 0) + rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2); + if (rc < 0) goto out_unlock; reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL); reg_val &= ~(RGMII_RX_CLK_DELAY_MASK); reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS); phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val); - rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); out_unlock: + rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc); mutex_unlock(&phydev->lock); return rc; @@ -699,6 +707,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8531, @@ -720,6 +730,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8540, @@ -741,6 +753,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, }, { .phy_id = PHY_ID_VSC8541, @@ -762,6 +776,8 @@ static struct phy_driver vsc85xx_driver[] = { .get_wol = &vsc85xx_wol_get, .get_tunable = &vsc85xx_get_tunable, .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, } }; -- 2.17.1