mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 17:18:59 +00:00
327 lines
10 KiB
Diff
327 lines
10 KiB
Diff
|
From 4e4aafcddbbfcdd6eed5780e190fcbfac8b4685a Mon Sep 17 00:00:00 2001
|
||
|
From: Andrew Lunn <andrew@lunn.ch>
|
||
|
Date: Mon, 9 Jan 2023 16:30:41 +0100
|
||
|
Subject: [PATCH] net: mdio: Add dedicated C45 API to MDIO bus drivers
|
||
|
|
||
|
Currently C22 and C45 transactions are mixed over a combined API calls
|
||
|
which make use of a special bit in the reg address to indicate if a
|
||
|
C45 transaction should be performed. This makes it impossible to know
|
||
|
if the bus driver actually supports C45. Additionally, many C22 only
|
||
|
drivers don't return -EOPNOTSUPP when asked to perform a C45
|
||
|
transaction, they mistaking perform a C22 transaction.
|
||
|
|
||
|
This is the first step to cleanly separate C22 from C45. To maintain
|
||
|
backwards compatibility until all drivers which are capable of
|
||
|
performing C45 are converted to this new API, the helper functions
|
||
|
will fall back to the older API if the new API is not
|
||
|
supported. Eventually this fallback will be removed.
|
||
|
|
||
|
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||
|
Signed-off-by: Michael Walle <michael@walle.cc>
|
||
|
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||
|
---
|
||
|
drivers/net/phy/mdio_bus.c | 189 +++++++++++++++++++++++++++++++++++++
|
||
|
include/linux/mdio.h | 39 ++++----
|
||
|
include/linux/phy.h | 5 +
|
||
|
3 files changed, 214 insertions(+), 19 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/phy/mdio_bus.c
|
||
|
+++ b/drivers/net/phy/mdio_bus.c
|
||
|
@@ -832,6 +832,100 @@ int __mdiobus_modify_changed(struct mii_
|
||
|
EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
|
||
|
|
||
|
/**
|
||
|
+ * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @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_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
|
||
|
+{
|
||
|
+ int retval;
|
||
|
+
|
||
|
+ lockdep_assert_held_once(&bus->mdio_lock);
|
||
|
+
|
||
|
+ if (bus->read_c45)
|
||
|
+ retval = bus->read_c45(bus, addr, devad, regnum);
|
||
|
+ else
|
||
|
+ retval = bus->read(bus, addr, mdiobus_c45_addr(devad, regnum));
|
||
|
+
|
||
|
+ trace_mdio_access(bus, 1, addr, regnum, retval, retval);
|
||
|
+ mdiobus_stats_acct(&bus->stats[addr], true, retval);
|
||
|
+
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(__mdiobus_c45_read);
|
||
|
+
|
||
|
+/**
|
||
|
+ * __mdiobus_c45_write - Unlocked version of the mdiobus_write function
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @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_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 val)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+
|
||
|
+ lockdep_assert_held_once(&bus->mdio_lock);
|
||
|
+
|
||
|
+ if (bus->write_c45)
|
||
|
+ err = bus->write_c45(bus, addr, devad, regnum, val);
|
||
|
+ else
|
||
|
+ err = bus->write(bus, addr, mdiobus_c45_addr(devad, regnum),
|
||
|
+ val);
|
||
|
+
|
||
|
+ trace_mdio_access(bus, 0, addr, regnum, val, err);
|
||
|
+ mdiobus_stats_acct(&bus->stats[addr], false, err);
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(__mdiobus_c45_write);
|
||
|
+
|
||
|
+/**
|
||
|
+ * __mdiobus_c45_modify_changed - Unlocked version of the mdiobus_modify function
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @regnum: register number to modify
|
||
|
+ * @mask: bit mask of bits to clear
|
||
|
+ * @set: bit mask of bits to set
|
||
|
+ *
|
||
|
+ * Read, modify, and if any change, write the register value back to the
|
||
|
+ * device. Any error returns a negative number.
|
||
|
+ *
|
||
|
+ * NOTE: MUST NOT be called from interrupt context.
|
||
|
+ */
|
||
|
+static int __mdiobus_c45_modify_changed(struct mii_bus *bus, int addr,
|
||
|
+ int devad, u32 regnum, u16 mask,
|
||
|
+ u16 set)
|
||
|
+{
|
||
|
+ int new, ret;
|
||
|
+
|
||
|
+ ret = __mdiobus_c45_read(bus, addr, devad, regnum);
|
||
|
+ if (ret < 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ new = (ret & ~mask) | set;
|
||
|
+ if (new == ret)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ ret = __mdiobus_c45_write(bus, addr, devad, regnum, new);
|
||
|
+
|
||
|
+ return ret < 0 ? ret : 1;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
* mdiobus_read_nested - Nested version of the mdiobus_read function
|
||
|
* @bus: the mii_bus struct
|
||
|
* @addr: the phy address
|
||
|
@@ -879,6 +973,29 @@ int mdiobus_read(struct mii_bus *bus, in
|
||
|
EXPORT_SYMBOL(mdiobus_read);
|
||
|
|
||
|
/**
|
||
|
+ * mdiobus_c45_read - Convenience function for reading a given MII mgmt register
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @regnum: register number to read
|
||
|
+ *
|
||
|
+ * NOTE: MUST NOT be called from interrupt context,
|
||
|
+ * because the bus read/write functions may wait for an interrupt
|
||
|
+ * to conclude the operation.
|
||
|
+ */
|
||
|
+int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
|
||
|
+{
|
||
|
+ int retval;
|
||
|
+
|
||
|
+ mutex_lock(&bus->mdio_lock);
|
||
|
+ retval = __mdiobus_c45_read(bus, addr, devad, regnum);
|
||
|
+ mutex_unlock(&bus->mdio_lock);
|
||
|
+
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(mdiobus_c45_read);
|
||
|
+
|
||
|
+/**
|
||
|
* mdiobus_write_nested - Nested version of the mdiobus_write function
|
||
|
* @bus: the mii_bus struct
|
||
|
* @addr: the phy address
|
||
|
@@ -928,6 +1045,31 @@ int mdiobus_write(struct mii_bus *bus, i
|
||
|
EXPORT_SYMBOL(mdiobus_write);
|
||
|
|
||
|
/**
|
||
|
+ * mdiobus_c45_write - Convenience function for writing a given MII mgmt register
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @regnum: register number to write
|
||
|
+ * @val: value 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 mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 val)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+
|
||
|
+ mutex_lock(&bus->mdio_lock);
|
||
|
+ err = __mdiobus_c45_write(bus, addr, devad, regnum, val);
|
||
|
+ mutex_unlock(&bus->mdio_lock);
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(mdiobus_c45_write);
|
||
|
+
|
||
|
+/**
|
||
|
* mdiobus_modify - Convenience function for modifying a given mdio device
|
||
|
* register
|
||
|
* @bus: the mii_bus struct
|
||
|
@@ -949,6 +1091,30 @@ int mdiobus_modify(struct mii_bus *bus,
|
||
|
EXPORT_SYMBOL_GPL(mdiobus_modify);
|
||
|
|
||
|
/**
|
||
|
+ * mdiobus_c45_modify - Convenience function for modifying a given mdio device
|
||
|
+ * register
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @regnum: register number to write
|
||
|
+ * @mask: bit mask of bits to clear
|
||
|
+ * @set: bit mask of bits to set
|
||
|
+ */
|
||
|
+int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 mask, u16 set)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+
|
||
|
+ mutex_lock(&bus->mdio_lock);
|
||
|
+ err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum,
|
||
|
+ mask, set);
|
||
|
+ mutex_unlock(&bus->mdio_lock);
|
||
|
+
|
||
|
+ return err < 0 ? err : 0;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(mdiobus_c45_modify);
|
||
|
+
|
||
|
+/**
|
||
|
* mdiobus_modify_changed - Convenience function for modifying a given mdio
|
||
|
* device register and returning if it changed
|
||
|
* @bus: the mii_bus struct
|
||
|
@@ -971,6 +1137,29 @@ int mdiobus_modify_changed(struct mii_bu
|
||
|
EXPORT_SYMBOL_GPL(mdiobus_modify_changed);
|
||
|
|
||
|
/**
|
||
|
+ * mdiobus_c45_modify_changed - Convenience function for modifying a given mdio
|
||
|
+ * device register and returning if it changed
|
||
|
+ * @bus: the mii_bus struct
|
||
|
+ * @addr: the phy address
|
||
|
+ * @devad: device address to read
|
||
|
+ * @regnum: register number to write
|
||
|
+ * @mask: bit mask of bits to clear
|
||
|
+ * @set: bit mask of bits to set
|
||
|
+ */
|
||
|
+int mdiobus_c45_modify_changed(struct mii_bus *bus, int devad, int addr,
|
||
|
+ u32 regnum, u16 mask, u16 set)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+
|
||
|
+ mutex_lock(&bus->mdio_lock);
|
||
|
+ err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum, mask, set);
|
||
|
+ mutex_unlock(&bus->mdio_lock);
|
||
|
+
|
||
|
+ return err;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed);
|
||
|
+
|
||
|
+/**
|
||
|
* mdio_bus_match - determine if given MDIO driver supports the given
|
||
|
* MDIO device
|
||
|
* @dev: target MDIO device
|
||
|
--- a/include/linux/mdio.h
|
||
|
+++ b/include/linux/mdio.h
|
||
|
@@ -423,6 +423,17 @@ int mdiobus_modify(struct mii_bus *bus,
|
||
|
u16 set);
|
||
|
int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
|
||
|
u16 mask, u16 set);
|
||
|
+int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
|
||
|
+int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
|
||
|
+int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 val);
|
||
|
+int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 val);
|
||
|
+int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
|
||
|
+ u16 mask, u16 set);
|
||
|
+
|
||
|
+int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
|
||
|
+ u32 regnum, u16 mask, u16 set);
|
||
|
|
||
|
static inline int mdiodev_read(struct mdio_device *mdiodev, u32 regnum)
|
||
|
{
|
||
|
@@ -463,29 +474,19 @@ static inline u16 mdiobus_c45_devad(u32
|
||
|
return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
|
||
|
}
|
||
|
|
||
|
-static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
|
||
|
- u16 regnum)
|
||
|
-{
|
||
|
- return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
|
||
|
-}
|
||
|
-
|
||
|
-static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
|
||
|
- u16 regnum, u16 val)
|
||
|
-{
|
||
|
- return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum),
|
||
|
- val);
|
||
|
-}
|
||
|
-
|
||
|
-static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
|
||
|
- u16 regnum)
|
||
|
+static inline int mdiodev_c45_modify(struct mdio_device *mdiodev, int devad,
|
||
|
+ u32 regnum, u16 mask, u16 set)
|
||
|
{
|
||
|
- return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
|
||
|
+ return mdiobus_c45_modify(mdiodev->bus, mdiodev->addr, devad, regnum,
|
||
|
+ mask, set);
|
||
|
}
|
||
|
|
||
|
-static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
|
||
|
- u16 regnum, u16 val)
|
||
|
+static inline int mdiodev_c45_modify_changed(struct mdio_device *mdiodev,
|
||
|
+ int devad, u32 regnum, u16 mask,
|
||
|
+ u16 set)
|
||
|
{
|
||
|
- return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
|
||
|
+ return mdiobus_c45_modify_changed(mdiodev->bus, mdiodev->addr, devad,
|
||
|
+ regnum, mask, set);
|
||
|
}
|
||
|
|
||
|
int mdiobus_register_device(struct mdio_device *mdiodev);
|
||
|
--- a/include/linux/phy.h
|
||
|
+++ b/include/linux/phy.h
|
||
|
@@ -364,6 +364,11 @@ struct mii_bus {
|
||
|
int (*read)(struct mii_bus *bus, int addr, int regnum);
|
||
|
/** @write: Perform a write transfer on the bus */
|
||
|
int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
|
||
|
+ /** @read_c45: Perform a C45 read transfer on the bus */
|
||
|
+ int (*read_c45)(struct mii_bus *bus, int addr, int devnum, int regnum);
|
||
|
+ /** @write_c45: Perform a C45 write transfer on the bus */
|
||
|
+ int (*write_c45)(struct mii_bus *bus, int addr, int devnum,
|
||
|
+ int regnum, u16 val);
|
||
|
/** @reset: Perform a reset of the bus */
|
||
|
int (*reset)(struct mii_bus *bus);
|
||
|
|