123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- From 4e4aafcddbbfcdd6eed5780e190fcbfac8b4685a Mon Sep 17 00:00:00 2001
- From: Andrew Lunn <[email protected]>
- 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 <[email protected]>
- Signed-off-by: Michael Walle <[email protected]>
- Signed-off-by: Jakub Kicinski <[email protected]>
- ---
- 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);
-
|