summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-01-03 11:00:24 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-03 11:00:24 -0500
commit318ff60eb4640817606cc2ea8d857b2d7de2455c (patch)
tree9144b3005e8ca0fe15e047c50dcabb0b8051f9a1 /include
parentbe6e36d916b1f7e6b0aec42d49cb5d5ea9590dff (diff)
parentfea23fb591cce99546baca043d2a068228e87a79 (diff)
Merge branch 'net-Resolve-races-in-phy-accessors'
Russell King says: ==================== Resolve races in phy accessors This series resolves races with various accesses to PHY registers. The first five patches are necessary before we add phylink support to mvneta, the remaining three are merely cleanups for unobserved races, and hence are less critical. There are two possible classes of races that can occur: where we write to a page register that changes the meaning of a group of other registers, and where we read-modify-write a register. Resolve these races by performing the accesses under the mdio bus lock, ensuring that no other user can access the bus while the series of atomic operations are being performed. These patches have been posted before, and have been modified along the lines of previous feedback: - The third patch was originally reviewed by Florian, but as I've added __phy_modify() to it, I've removed that attributation. - Included generic page-based accessors as suggested last time around. - Since we have the unlocked __phy_modify() in this patch series, it is sensible to include the changes for this to marvell.c - these accessors have to change anyway to avoid deadlocks on the mdio bus lock. I haven't been able to test the at803x.c changes yet beyond compile testing - although I do have systems with an ar8035 PHY. However, they should be straight forward to review. This is targetted for net-next because the races have not been found in existing drivers, but have been observed with phylink integrated into mvneta - that's not to say that the races do not exist today, they are just unobserved (probably through lack of rigorous enough testing.) The race provoking condition is detailed in patch 5. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/mdio.h3
-rw-r--r--include/linux/phy.h40
2 files changed, 43 insertions, 0 deletions
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index 268aad47ecd3..2cfffe586885 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 a052e3768422..135aba5c3d39 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);