diff options
-rw-r--r-- | drivers/net/phy/at803x.c | 20 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 442 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 65 | ||||
-rw-r--r-- | drivers/net/phy/phy-core.c | 216 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 50 | ||||
-rw-r--r-- | include/linux/mdio.h | 3 | ||||
-rw-r--r-- | include/linux/phy.h | 40 |
7 files changed, 490 insertions, 346 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 1e190f3bca63a..c2715908d43ec 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -215,34 +215,22 @@ static int at803x_suspend(struct phy_device *phydev) int value; int wol_enabled; - mutex_lock(&phydev->lock); - value = phy_read(phydev, AT803X_INTR_ENABLE); wol_enabled = value & AT803X_INTR_ENABLE_WOL; - value = phy_read(phydev, MII_BMCR); - if (wol_enabled) - value |= BMCR_ISOLATE; + value = BMCR_ISOLATE; else - value |= BMCR_PDOWN; + value = BMCR_PDOWN; - phy_write(phydev, MII_BMCR, value); - - mutex_unlock(&phydev->lock); + phy_modify(phydev, MII_BMCR, 0, value); return 0; } static int at803x_resume(struct phy_device *phydev) { - int value; - - value = phy_read(phydev, MII_BMCR); - value &= ~(BMCR_PDOWN | BMCR_ISOLATE); - phy_write(phydev, MII_BMCR, value); - - return 0; + return phy_modify(phydev, MII_BMCR, ~(BMCR_PDOWN | BMCR_ISOLATE), 0); } static int at803x_probe(struct phy_device *phydev) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 342325a89d5f1..2bd38962b5d2e 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -83,7 +83,7 @@ #define MII_88E1121_PHY_MSCR_REG 21 #define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) #define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) -#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(BIT(5) | BIT(4))) +#define MII_88E1121_PHY_MSCR_DELAY_MASK (BIT(5) | BIT(4)) #define MII_88E1121_MISC_TEST 0x1a #define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00 @@ -177,27 +177,19 @@ struct marvell_priv { struct device *hwmon_dev; }; -static int marvell_get_page(struct phy_device *phydev) +static int marvell_read_page(struct phy_device *phydev) { - return phy_read(phydev, MII_MARVELL_PHY_PAGE); + return __phy_read(phydev, MII_MARVELL_PHY_PAGE); } -static int marvell_set_page(struct phy_device *phydev, int page) +static int marvell_write_page(struct phy_device *phydev, int page) { - return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); + return __phy_write(phydev, MII_MARVELL_PHY_PAGE, page); } -static int marvell_get_set_page(struct phy_device *phydev, int page) +static int marvell_set_page(struct phy_device *phydev, int page) { - int oldpage = marvell_get_page(phydev); - - if (oldpage < 0) - return oldpage; - - if (page != oldpage) - return marvell_set_page(phydev, page); - - return 0; + return phy_write(phydev, MII_MARVELL_PHY_PAGE, page); } static int marvell_ack_interrupt(struct phy_device *phydev) @@ -399,7 +391,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev) static int marvell_of_reg_init(struct phy_device *phydev) { const __be32 *paddr; - int len, i, saved_page, current_page, ret; + int len, i, saved_page, current_page, ret = 0; if (!phydev->mdio.dev.of_node) return 0; @@ -409,12 +401,11 @@ static int marvell_of_reg_init(struct phy_device *phydev) if (!paddr || len < (4 * sizeof(*paddr))) return 0; - saved_page = marvell_get_page(phydev); + saved_page = phy_save_page(phydev); if (saved_page < 0) - return saved_page; + goto err; current_page = saved_page; - ret = 0; len /= sizeof(*paddr); for (i = 0; i < len - 3; i += 4) { u16 page = be32_to_cpup(paddr + i); @@ -425,14 +416,14 @@ static int marvell_of_reg_init(struct phy_device *phydev) if (page != current_page) { current_page = page; - ret = marvell_set_page(phydev, page); + ret = marvell_write_page(phydev, page); if (ret < 0) goto err; } val = 0; if (mask) { - val = phy_read(phydev, reg); + val = __phy_read(phydev, reg); if (val < 0) { ret = val; goto err; @@ -441,17 +432,12 @@ static int marvell_of_reg_init(struct phy_device *phydev) } val |= val_bits; - ret = phy_write(phydev, reg, val); + ret = __phy_write(phydev, reg, val); if (ret < 0) goto err; } err: - if (current_page != saved_page) { - i = marvell_set_page(phydev, saved_page); - if (ret == 0) - ret = i; - } - return ret; + return phy_restore_page(phydev, saved_page, ret); } #else static int marvell_of_reg_init(struct phy_device *phydev) @@ -462,34 +448,21 @@ static int marvell_of_reg_init(struct phy_device *phydev) static int m88e1121_config_aneg_rgmii_delays(struct phy_device *phydev) { - int err, oldpage, mscr; - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); - if (oldpage < 0) - return oldpage; - - mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG); - if (mscr < 0) { - err = mscr; - goto out; - } - - mscr &= MII_88E1121_PHY_MSCR_DELAY_MASK; + int mscr; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | - MII_88E1121_PHY_MSCR_TX_DELAY); + mscr = MII_88E1121_PHY_MSCR_RX_DELAY | + MII_88E1121_PHY_MSCR_TX_DELAY; else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; + mscr = MII_88E1121_PHY_MSCR_RX_DELAY; else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; - - err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); - -out: - marvell_set_page(phydev, oldpage); + mscr = MII_88E1121_PHY_MSCR_TX_DELAY; + else + mscr = 0; - return err; + return phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, + MII_88E1121_PHY_MSCR_REG, + MII_88E1121_PHY_MSCR_DELAY_MASK, mscr); } static int m88e1121_config_aneg(struct phy_device *phydev) @@ -498,7 +471,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (phy_interface_is_rgmii(phydev)) { err = m88e1121_config_aneg_rgmii_delays(phydev); - if (err) + if (err < 0) return err; } @@ -515,20 +488,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev) static int m88e1318_config_aneg(struct phy_device *phydev) { - int err, oldpage, mscr; - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE); - if (oldpage < 0) - return oldpage; - - mscr = phy_read(phydev, MII_88E1318S_PHY_MSCR1_REG); - mscr |= MII_88E1318S_PHY_MSCR1_PAD_ODD; - - err = phy_write(phydev, MII_88E1318S_PHY_MSCR1_REG, mscr); - if (err < 0) - return err; + int err; - err = marvell_set_page(phydev, oldpage); + err = phy_modify_paged(phydev, MII_MARVELL_MSCR_PAGE, + MII_88E1318S_PHY_MSCR1_REG, + 0, MII_88E1318S_PHY_MSCR1_PAD_ODD); if (err < 0) return err; @@ -700,19 +664,14 @@ static int m88e1116r_config_init(struct phy_device *phydev) static int m88e3016_config_init(struct phy_device *phydev) { - int reg; + int ret; /* Enable Scrambler and Auto-Crossover */ - reg = phy_read(phydev, MII_88E3016_PHY_SPEC_CTRL); - if (reg < 0) - return reg; - - reg &= ~MII_88E3016_DISABLE_SCRAMBLER; - reg |= MII_88E3016_AUTO_MDIX_CROSSOVER; - - reg = phy_write(phydev, MII_88E3016_PHY_SPEC_CTRL, reg); - if (reg < 0) - return reg; + ret = phy_modify(phydev, MII_88E3016_PHY_SPEC_CTRL, + ~MII_88E3016_DISABLE_SCRAMBLER, + MII_88E3016_AUTO_MDIX_CROSSOVER); + if (ret < 0) + return ret; return marvell_config_init(phydev); } @@ -721,42 +680,34 @@ static int m88e1111_config_init_hwcfg_mode(struct phy_device *phydev, u16 mode, int fibre_copper_auto) { - int temp; - - temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); - if (temp < 0) - return temp; - - temp &= ~(MII_M1111_HWCFG_MODE_MASK | - MII_M1111_HWCFG_FIBER_COPPER_AUTO | - MII_M1111_HWCFG_FIBER_COPPER_RES); - temp |= mode; - if (fibre_copper_auto) - temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; + mode |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; - return phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); + return phy_modify(phydev, MII_M1111_PHY_EXT_SR, + (u16)~(MII_M1111_HWCFG_MODE_MASK | + MII_M1111_HWCFG_FIBER_COPPER_AUTO | + MII_M1111_HWCFG_FIBER_COPPER_RES), + mode); } static int m88e1111_config_init_rgmii_delays(struct phy_device *phydev) { - int temp; - - temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); - if (temp < 0) - return temp; + int delay; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { - temp |= (MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY); + delay = MII_M1111_RGMII_RX_DELAY | MII_M1111_RGMII_TX_DELAY; } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { - temp &= ~MII_M1111_RGMII_TX_DELAY; - temp |= MII_M1111_RGMII_RX_DELAY; + delay = MII_M1111_RGMII_RX_DELAY; } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { - temp &= ~MII_M1111_RGMII_RX_DELAY; - temp |= MII_M1111_RGMII_TX_DELAY; + delay = MII_M1111_RGMII_TX_DELAY; + } else { + delay = 0; } - return phy_write(phydev, MII_M1111_PHY_EXT_CR, temp); + return phy_modify(phydev, MII_M1111_PHY_EXT_CR, + (u16)~(MII_M1111_RGMII_RX_DELAY | + MII_M1111_RGMII_TX_DELAY), + delay); } static int m88e1111_config_init_rgmii(struct phy_device *phydev) @@ -802,7 +753,7 @@ static int m88e1111_config_init_rtbi(struct phy_device *phydev) int err; err = m88e1111_config_init_rgmii_delays(phydev); - if (err) + if (err < 0) return err; err = m88e1111_config_init_hwcfg_mode( @@ -829,7 +780,7 @@ static int m88e1111_config_init(struct phy_device *phydev) if (phy_interface_is_rgmii(phydev)) { err = m88e1111_config_init_rgmii(phydev); - if (err) + if (err < 0) return err; } @@ -854,20 +805,15 @@ static int m88e1111_config_init(struct phy_device *phydev) static int m88e1121_config_init(struct phy_device *phydev) { - int err, oldpage; - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE); - if (oldpage < 0) - return oldpage; + int err; /* Default PHY LED config: LED[0] .. Link, LED[1] .. Activity */ - err = phy_write(phydev, MII_88E1121_PHY_LED_CTRL, - MII_88E1121_PHY_LED_DEF); + err = phy_write_paged(phydev, MII_MARVELL_LED_PAGE, + MII_88E1121_PHY_LED_CTRL, + MII_88E1121_PHY_LED_DEF); if (err < 0) return err; - marvell_set_page(phydev, oldpage); - /* Set marvell,reg-init configuration from device tree */ return marvell_config_init(phydev); } @@ -875,7 +821,6 @@ static int m88e1121_config_init(struct phy_device *phydev) static int m88e1510_config_init(struct phy_device *phydev) { int err; - int temp; /* SGMII-to-Copper mode initialization */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { @@ -887,16 +832,15 @@ static int m88e1510_config_init(struct phy_device *phydev) return err; /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */ - temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1); - temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK; - temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII; - err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); + err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, + ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK, + MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII); if (err < 0) return err; /* PHY reset is necessary after changing MODE[2:0] */ - temp |= MII_88E1510_GEN_CTRL_REG_1_RESET; - err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp); + err = phy_modify(phydev, MII_88E1510_GEN_CTRL_REG_1, 0, + MII_88E1510_GEN_CTRL_REG_1_RESET); if (err < 0) return err; @@ -1002,7 +946,6 @@ static int m88e1149_config_init(struct phy_device *phydev) static int m88e1145_config_init_rgmii(struct phy_device *phydev) { - int temp; int err; err = m88e1111_config_init_rgmii_delays(phydev); @@ -1014,15 +957,9 @@ static int m88e1145_config_init_rgmii(struct phy_device *phydev) if (err < 0) return err; - temp = phy_read(phydev, 0x1e); - if (temp < 0) - return temp; - - temp &= 0xf03f; - temp |= 2 << 9; /* 36 ohm */ - temp |= 2 << 6; /* 39 ohm */ - - err = phy_write(phydev, 0x1e, temp); + err = phy_modify(phydev, 0x1e, 0xf03f, + 2 << 9 | /* 36 ohm */ + 2 << 6); /* 39 ohm */ if (err < 0) return err; @@ -1398,100 +1335,98 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { + int oldpage, ret = 0; + wol->supported = WAKE_MAGIC; wol->wolopts = 0; - if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0) - return; + oldpage = phy_select_page(phydev, MII_MARVELL_WOL_PAGE); + if (oldpage < 0) + goto error; - if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) & - MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) + ret = __phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); + if (ret & MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE) wol->wolopts |= WAKE_MAGIC; - if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0) - return; +error: + phy_restore_page(phydev, oldpage, ret); } static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { - int err, oldpage, temp; + int err = 0, oldpage; - oldpage = marvell_get_page(phydev); + oldpage = phy_save_page(phydev); + if (oldpage < 0) + goto error; if (wol->wolopts & WAKE_MAGIC) { /* Explicitly switch to page 0x00, just to be sure */ - err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + err = marvell_write_page(phydev, MII_MARVELL_COPPER_PAGE); if (err < 0) - return err; + goto error; /* Enable the WOL interrupt */ - temp = phy_read(phydev, MII_88E1318S_PHY_CSIER); - temp |= MII_88E1318S_PHY_CSIER_WOL_EIE; - err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp); + err = __phy_modify(phydev, MII_88E1318S_PHY_CSIER, 0, + MII_88E1318S_PHY_CSIER_WOL_EIE); if (err < 0) - return err; + goto error; - err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE); + err = marvell_write_page(phydev, MII_MARVELL_LED_PAGE); if (err < 0) - return err; + goto error; /* Setup LED[2] as interrupt pin (active low) */ - temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR); - temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT; - temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE; - temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW; - err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp); + err = __phy_modify(phydev, MII_88E1318S_PHY_LED_TCR, + (u16)~MII_88E1318S_PHY_LED_TCR_FORCE_INT, + MII_88E1318S_PHY_LED_TCR_INTn_ENABLE | + MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW); if (err < 0) - return err; + goto error; - err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); + err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) - return err; + goto error; /* Store the device address for the magic packet */ - err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, + err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2, ((phydev->attached_dev->dev_addr[5] << 8) | phydev->attached_dev->dev_addr[4])); if (err < 0) - return err; - err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, + goto error; + err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1, ((phydev->attached_dev->dev_addr[3] << 8) | phydev->attached_dev->dev_addr[2])); if (err < 0) - return err; - err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, + goto error; + err = __phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0, ((phydev->attached_dev->dev_addr[1] << 8) | phydev->attached_dev->dev_addr[0])); if (err < 0) - return err; + goto error; /* Clear WOL status and enable magic packet matching */ - temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); - temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; - temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; - err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); + err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, 0, + MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS | + MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE); if (err < 0) - return err; + goto error; } else { - err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE); + err = marvell_write_page(phydev, MII_MARVELL_WOL_PAGE); if (err < 0) - return err; + goto error; /* Clear WOL status and disable magic packet matching */ - temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL); - temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS; - temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE; - err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp); + err = __phy_modify(phydev, MII_88E1318S_PHY_WOL_CTRL, + (u16)~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE, + MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); if (err < 0) - return err; + goto error; } - err = marvell_set_page(phydev, oldpage); - if (err < 0) - return err; - - return 0; +error: + return phy_restore_page(phydev, oldpage, err); } static int marvell_get_sset_count(struct phy_device *phydev) @@ -1519,14 +1454,10 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) { struct marvell_hw_stat stat = marvell_hw_stats[i]; struct marvell_priv *priv = phydev->priv; - int oldpage, val; + int val; u64 ret; - oldpage = marvell_get_set_page(phydev, stat.page); - if (oldpage < 0) - return UINT64_MAX; - - val = phy_read(phydev, stat.reg); + val = phy_read_paged(phydev, stat.page, stat.reg); if (val < 0) { ret = UINT64_MAX; } else { @@ -1535,8 +1466,6 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i) ret = priv->stats[i]; } - marvell_set_page(phydev, oldpage); - return ret; } @@ -1553,51 +1482,44 @@ static void marvell_get_stats(struct phy_device *phydev, static int m88e1121_get_temp(struct phy_device *phydev, long *temp) { int oldpage; - int ret; + int ret = 0; int val; *temp = 0; - mutex_lock(&phydev->lock); - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); - if (oldpage < 0) { - mutex_unlock(&phydev->lock); - return oldpage; - } + oldpage = phy_select_page(phydev, MII_MARVELL_MISC_TEST_PAGE); + if (oldpage < 0) + goto error; /* Enable temperature sensor */ - ret = phy_read(phydev, MII_88E1121_MISC_TEST); + ret = __phy_read(phydev, MII_88E1121_MISC_TEST); if (ret < 0) goto error; - ret = phy_write(phydev, MII_88E1121_MISC_TEST, - ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); + ret = __phy_write(phydev, MII_88E1121_MISC_TEST, + ret | MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); if (ret < 0) goto error; /* Wait for temperature to stabilize */ usleep_range(10000, 12000); - val = phy_read(phydev, MII_88E1121_MISC_TEST); + val = __phy_read(phydev, MII_88E1121_MISC_TEST); if (val < 0) { ret = val; goto error; } /* Disable temperature sensor */ - ret = phy_write(phydev, MII_88E1121_MISC_TEST, - ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); + ret = __phy_write(phydev, MII_88E1121_MISC_TEST, + ret & ~MII_88E1121_MISC_TEST_TEMP_SENSOR_EN); if (ret < 0) goto error; *temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000; error: - marvell_set_page(phydev, oldpage); - mutex_unlock(&phydev->lock); - - return ret; + return phy_restore_page(phydev, oldpage, ret); } static int m88e1121_hwmon_read(struct device *dev, @@ -1671,118 +1593,64 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = { static int m88e1510_get_temp(struct phy_device *phydev, long *temp) { - int oldpage; int ret; *temp = 0; - mutex_lock(&phydev->lock); - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); - if (oldpage < 0) { - mutex_unlock(&phydev->lock); - return oldpage; - } - - ret = phy_read(phydev, MII_88E1510_TEMP_SENSOR); + ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, + MII_88E1510_TEMP_SENSOR); if (ret < 0) - goto error; + return ret; *temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000; -error: - marvell_set_page(phydev, oldpage); - mutex_unlock(&phydev->lock); - - return ret; + return 0; } static int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp) { - int oldpage; int ret; *temp = 0; - mutex_lock(&phydev->lock); - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); - if (oldpage < 0) { - mutex_unlock(&phydev->lock); - return oldpage; - } - - ret = phy_read(phydev, MII_88E1121_MISC_TEST); + ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, + MII_88E1121_MISC_TEST); if (ret < 0) - goto error; + return ret; *temp = (((ret & MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) >> MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT) * 5) - 25; /* convert to mC */ *temp *= 1000; -error: - marvell_set_page(phydev, oldpage); - mutex_unlock(&phydev->lock); - - return ret; + return 0; } static int m88e1510_set_temp_critical(struct phy_device *phydev, long temp) { - int oldpage; - int ret; - - mutex_lock(&phydev->lock); - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); - if (oldpage < 0) { - mutex_unlock(&phydev->lock); - return oldpage; - } - - ret = phy_read(phydev, MII_88E1121_MISC_TEST); - if (ret < 0) - goto error; - temp = temp / 1000; temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - ret = phy_write(phydev, MII_88E1121_MISC_TEST, - (ret & ~MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK) | - (temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT)); -error: - marvell_set_page(phydev, oldpage); - mutex_unlock(&phydev->lock); - - return ret; + return phy_modify_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, + MII_88E1121_MISC_TEST, + MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK, + temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT); } static int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm) { - int oldpage; int ret; *alarm = false; - mutex_lock(&phydev->lock); - - oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE); - if (oldpage < 0) { - mutex_unlock(&phydev->lock); - return oldpage; - } - - ret = phy_read(phydev, MII_88E1121_MISC_TEST); + ret = phy_read_paged(phydev, MII_MARVELL_MISC_TEST_PAGE, + MII_88E1121_MISC_TEST); if (ret < 0) - goto error; - *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); + return ret; -error: - marvell_set_page(phydev, oldpage); - mutex_unlock(&phydev->lock); + *alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ); - return ret; + return 0; } static int m88e1510_hwmon_read(struct device *dev, @@ -1978,6 +1846,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -1995,6 +1865,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2013,6 +1885,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2030,6 +1904,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2049,6 +1925,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2070,6 +1948,8 @@ static struct phy_driver marvell_drivers[] = { .set_wol = &m88e1318_set_wol, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2088,6 +1968,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2105,6 +1987,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2122,6 +2006,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2138,6 +2024,8 @@ static struct phy_driver marvell_drivers[] = { .config_intr = &marvell_config_intr, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2159,6 +2047,8 @@ static struct phy_driver marvell_drivers[] = { .set_wol = &m88e1318_set_wol, .resume = &marvell_resume, .suspend = &marvell_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2179,6 +2069,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2198,6 +2090,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2217,6 +2111,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, @@ -2236,6 +2132,8 @@ static struct phy_driver marvell_drivers[] = { .did_interrupt = &m88e1121_did_interrupt, .resume = &genphy_resume, .suspend = &genphy_suspend, + .read_page = marvell_read_page, + .write_page = marvell_write_page, .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index a0f34c385cada..e2419c792a446 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -515,6 +515,55 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) EXPORT_SYMBOL(mdiobus_scan); /** + * __mdiobus_read - Unlocked version of the mdiobus_read function + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to read + * + * Read a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) +{ + int retval; + + WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); + + retval = bus->read(bus, addr, regnum); + + trace_mdio_access(bus, 1, addr, regnum, retval, retval); + + return retval; +} +EXPORT_SYMBOL(__mdiobus_read); + +/** + * __mdiobus_write - Unlocked version of the mdiobus_write function + * @bus: the mii_bus struct + * @addr: the phy address + * @regnum: register number to write + * @val: value to write to @regnum + * + * Write a MDIO bus register. Caller must hold the mdio bus lock. + * + * NOTE: MUST NOT be called from interrupt context. + */ +int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) +{ + int err; + + WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); + + err = bus->write(bus, addr, regnum, val); + + trace_mdio_access(bus, 0, addr, regnum, val, err); + + return err; +} +EXPORT_SYMBOL(__mdiobus_write); + +/** * mdiobus_read_nested - Nested version of the mdiobus_read function * @bus: the mii_bus struct * @addr: the phy address @@ -534,11 +583,9 @@ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum) BUG_ON(in_interrupt()); mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - retval = bus->read(bus, addr, regnum); + retval = __mdiobus_read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); - trace_mdio_access(bus, 1, addr, regnum, retval, retval); - return retval; } EXPORT_SYMBOL(mdiobus_read_nested); @@ -560,11 +607,9 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) BUG_ON(in_interrupt()); mutex_lock(&bus->mdio_lock); - retval = bus->read(bus, addr, regnum); + retval = __mdiobus_read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); - trace_mdio_access(bus, 1, addr, regnum, retval, retval); - return retval; } EXPORT_SYMBOL(mdiobus_read); @@ -590,11 +635,9 @@ int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val) BUG_ON(in_interrupt()); mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - err = bus->write(bus, addr, regnum, val); + err = __mdiobus_write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); - trace_mdio_access(bus, 0, addr, regnum, val, err); - return err; } EXPORT_SYMBOL(mdiobus_write_nested); @@ -617,11 +660,9 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) BUG_ON(in_interrupt()); mutex_lock(&bus->mdio_lock); - err = bus->write(bus, addr, regnum, val); + err = __mdiobus_write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); - trace_mdio_access(bus, 0, addr, regnum, val, err); - return err; } EXPORT_SYMBOL(mdiobus_write); diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index c0ad08fa9d2c7..44d09b1920149 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -236,13 +236,14 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad, u16 regnum) { /* Write the desired MMD Devad */ - bus->write(bus, phy_addr, MII_MMD_CTRL, devad); + __mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad); /* Write the desired MMD register address */ - bus->write(bus, phy_addr, MII_MMD_DATA, regnum); + __mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum); /* Select the Function : DATA with no post increment */ - bus->write(bus, phy_addr, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR); + __mdiobus_write(bus, phy_addr, MII_MMD_CTRL, + devad | MII_MMD_CTRL_NOINCR); } /** @@ -275,7 +276,7 @@ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) mmd_phy_indirect(bus, phy_addr, devad, regnum); /* Read the content of the MMD's selected register */ - val = bus->read(bus, phy_addr, MII_MMD_DATA); + val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA); mutex_unlock(&bus->mdio_lock); } return val; @@ -314,7 +315,7 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) mmd_phy_indirect(bus, phy_addr, devad, regnum); /* Write the data into MMD's selected register */ - bus->write(bus, phy_addr, MII_MMD_DATA, val); + __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val); mutex_unlock(&bus->mdio_lock); ret = 0; @@ -322,3 +323,208 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) return ret; } EXPORT_SYMBOL(phy_write_mmd); + +/** + * __phy_modify() - Convenience function for modifying a PHY register + * @phydev: a pointer to a &struct phy_device + * @regnum: register number + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + * + * Unlocked helper function which allows a PHY register to be modified as + * new register value = (old register value & mask) | set + */ +int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) +{ + int ret, res; + + ret = __phy_read(phydev, regnum); + if (ret >= 0) { + res = __phy_write(phydev, regnum, (ret & ~mask) | set); + if (res < 0) + ret = res; + } + + return ret; +} +EXPORT_SYMBOL_GPL(__phy_modify); + +/** + * phy_modify - Convenience function for modifying a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @mask: bit mask of bits to clear + * @set: new value of bits set in mask to write to @regnum + * + * NOTE: MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. + */ +int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) +{ + int ret; + + mutex_lock(&phydev->mdio.bus->mdio_lock); + ret = __phy_modify(phydev, regnum, mask, set); + mutex_unlock(&phydev->mdio.bus->mdio_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_modify); + +static int __phy_read_page(struct phy_device *phydev) +{ + return phydev->drv->read_page(phydev); +} + +static int __phy_write_page(struct phy_device *phydev, int page) +{ + return phydev->drv->write_page(phydev, page); +} + +/** + * phy_save_page() - take the bus lock and save the current page + * @phydev: a pointer to a &struct phy_device + * + * Take the MDIO bus lock, and return the current page number. On error, + * returns a negative errno. phy_restore_page() must always be called + * after this, irrespective of success or failure of this call. + */ +int phy_save_page(struct phy_device *phydev) +{ + mutex_lock(&phydev->mdio.bus->mdio_lock); + return __phy_read_page(phydev); +} +EXPORT_SYMBOL_GPL(phy_save_page); + +/** + * phy_select_page() - take the bus lock, save the current page, and set a page + * @phydev: a pointer to a &struct phy_device + * @page: desired page + * + * Take the MDIO bus lock to protect against concurrent access, save the + * current PHY page, and set the current page. On error, returns a + * negative errno, otherwise returns the previous page number. + * phy_restore_page() must always be called after this, irrespective + * of success or failure of this call. + */ +int phy_select_page(struct phy_device *phydev, int page) +{ + int ret, oldpage; + + oldpage = ret = phy_save_page(phydev); + if (ret < 0) + return ret; + + if (oldpage != page) { + ret = __phy_write_page(phydev, page); + if (ret < 0) + return ret; + } + + return oldpage; +} +EXPORT_SYMBOL_GPL(phy_select_page); + +/** + * phy_restore_page() - restore the page register and release the bus lock + * @phydev: a pointer to a &struct phy_device + * @oldpage: the old page, return value from phy_save_page() or phy_select_page() + * @ret: operation's return code + * + * Release the MDIO bus lock, restoring @oldpage if it is a valid page. + * This function propagates the earliest error code from the group of + * operations. + * + * Returns: + * @oldpage if it was a negative value, otherwise + * @ret if it was a negative errno value, otherwise + * phy_write_page()'s negative value if it were in error, otherwise + * @ret. + */ +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) +{ + int r; + + if (oldpage >= 0) { + r = __phy_write_page(phydev, oldpage); + + /* Propagate the operation return code if the page write + * was successful. + */ + if (ret >= 0 && r < 0) + ret = r; + } else { + /* Propagate the phy page selection error code */ + ret = oldpage; + } + + mutex_unlock(&phydev->mdio.bus->mdio_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_restore_page); + +/** + * phy_read_paged() - Convenience function for reading a paged register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number + * + * Same rules as for phy_read(). + */ +int phy_read_paged(struct phy_device *phydev, int page, u32 regnum) +{ + int ret = 0, oldpage; + + oldpage = phy_select_page(phydev, page); + if (oldpage >= 0) + ret = __phy_read(phydev, regnum); + + return phy_restore_page(phydev, oldpage, ret); +} +EXPORT_SYMBOL(phy_read_paged); + +/** + * phy_write_paged() - Convenience function for writing a paged register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number + * @val: value to write + * + * Same rules as for phy_write(). + */ +int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val) +{ + int ret = 0, oldpage; + + oldpage = phy_select_page(phydev, page); + if (oldpage >= 0) + ret = __phy_write(phydev, regnum, val); + + return phy_restore_page(phydev, oldpage, ret); +} +EXPORT_SYMBOL(phy_write_paged); + +/** + * phy_modify_paged() - Convenience function for modifying a paged register + * @phydev: a pointer to a &struct phy_device + * @page: the page for the phy + * @regnum: register number + * @mask: bit mask of bits to clear + * @set: bit mask of bits to set + * + * Same rules as for phy_read() and phy_write(). + */ +int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum, + u16 mask, u16 set) +{ + int ret = 0, oldpage; + + oldpage = phy_select_page(phydev, page); + if (oldpage >= 0) + ret = __phy_modify(phydev, regnum, mask, set); + + return phy_restore_page(phydev, oldpage, ret); +} +EXPORT_SYMBOL(phy_modify_paged); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index be13b5d6a8bf7..2c5b2e041c0fe 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1368,9 +1368,8 @@ static int genphy_config_eee_advert(struct phy_device *phydev) */ int genphy_setup_forced(struct phy_device *phydev) { - int ctl = phy_read(phydev, MII_BMCR); + u16 ctl = 0; - ctl &= BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN; phydev->pause = 0; phydev->asym_pause = 0; @@ -1382,7 +1381,8 @@ int genphy_setup_forced(struct phy_device *phydev) if (DUPLEX_FULL == phydev->duplex) ctl |= BMCR_FULLDPLX; - return phy_write(phydev, MII_BMCR, ctl); + return phy_modify(phydev, MII_BMCR, + BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl); } EXPORT_SYMBOL(genphy_setup_forced); @@ -1392,17 +1392,9 @@ EXPORT_SYMBOL(genphy_setup_forced); */ int genphy_restart_aneg(struct phy_device *phydev) { - int ctl = phy_read(phydev, MII_BMCR); - - if (ctl < 0) - return ctl; - - ctl |= BMCR_ANENABLE | BMCR_ANRESTART; - /* Don't isolate the PHY if we're negotiating */ - ctl &= ~BMCR_ISOLATE; - - return phy_write(phydev, MII_BMCR, ctl); + return phy_modify(phydev, MII_BMCR, ~BMCR_ISOLATE, + BMCR_ANENABLE | BMCR_ANRESTART); } EXPORT_SYMBOL(genphy_restart_aneg); @@ -1668,44 +1660,20 @@ EXPORT_SYMBOL(genphy_config_init); int genphy_suspend(struct phy_device *phydev) { - int value; - - mutex_lock(&phydev->lock); - - value = phy_read(phydev, MII_BMCR); - phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); - - mutex_unlock(&phydev->lock); - - return 0; + return phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN); } EXPORT_SYMBOL(genphy_suspend); int genphy_resume(struct phy_device *phydev) { - int value; - - value = phy_read(phydev, MII_BMCR); - phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); - - return 0; + return phy_modify(phydev, MII_BMCR, ~BMCR_PDOWN, 0); } EXPORT_SYMBOL(genphy_resume); int genphy_loopback(struct phy_device *phydev, bool enable) { - int value; - - value = phy_read(phydev, MII_BMCR); - if (value < 0) - return value; - - if (enable) - value |= BMCR_LOOPBACK; - else - value &= ~BMCR_LOOPBACK; - - return phy_write(phydev, MII_BMCR, value); + return phy_modify(phydev, MII_BMCR, ~BMCR_LOOPBACK, + enable ? BMCR_LOOPBACK : 0); } EXPORT_SYMBOL(genphy_loopback); diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 268aad47ecd36..2cfffe586885c 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -262,6 +262,9 @@ static inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv) return reg; } +int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); +int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); + int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum); int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); diff --git a/include/linux/phy.h b/include/linux/phy.h index a052e37684224..135aba5c3d393 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -634,6 +634,9 @@ struct phy_driver { int (*write_mmd)(struct phy_device *dev, int devnum, u16 regnum, u16 val); + int (*read_page)(struct phy_device *dev); + int (*write_page)(struct phy_device *dev, int page); + /* Get the size and type of the eeprom contained within a plug-in * module */ int (*module_info)(struct phy_device *dev, @@ -718,6 +721,18 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) } /** + * __phy_read - convenience function for reading a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to read + * + * The caller must have taken the MDIO bus lock. + */ +static inline int __phy_read(struct phy_device *phydev, u32 regnum) +{ + return __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum); +} + +/** * phy_write - Convenience function for writing a given PHY register * @phydev: the phy_device struct * @regnum: register number to write @@ -733,6 +748,23 @@ static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val) } /** + * __phy_write - Convenience function for writing a given PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @val: value to write to @regnum + * + * The caller must have taken the MDIO bus lock. + */ +static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val) +{ + return __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, regnum, + val); +} + +int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set); +int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set); + +/** * phy_interrupt_is_valid - Convenience function for testing a given PHY irq * @phydev: the phy_device struct * @@ -810,6 +842,14 @@ static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev) */ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val); +int phy_save_page(struct phy_device *phydev); +int phy_select_page(struct phy_device *phydev, int page); +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret); +int phy_read_paged(struct phy_device *phydev, int page, u32 regnum); +int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val); +int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum, + u16 mask, u16 set); + struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, bool is_c45, struct phy_c45_device_ids *c45_ids); |