703-v6.3-net-mdio-Add-dedicated-C45-API-to-MDIO-bus-drivers.patch 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. From 4e4aafcddbbfcdd6eed5780e190fcbfac8b4685a Mon Sep 17 00:00:00 2001
  2. From: Andrew Lunn <[email protected]>
  3. Date: Mon, 9 Jan 2023 16:30:41 +0100
  4. Subject: [PATCH] net: mdio: Add dedicated C45 API to MDIO bus drivers
  5. Currently C22 and C45 transactions are mixed over a combined API calls
  6. which make use of a special bit in the reg address to indicate if a
  7. C45 transaction should be performed. This makes it impossible to know
  8. if the bus driver actually supports C45. Additionally, many C22 only
  9. drivers don't return -EOPNOTSUPP when asked to perform a C45
  10. transaction, they mistaking perform a C22 transaction.
  11. This is the first step to cleanly separate C22 from C45. To maintain
  12. backwards compatibility until all drivers which are capable of
  13. performing C45 are converted to this new API, the helper functions
  14. will fall back to the older API if the new API is not
  15. supported. Eventually this fallback will be removed.
  16. Signed-off-by: Andrew Lunn <[email protected]>
  17. Signed-off-by: Michael Walle <[email protected]>
  18. Signed-off-by: Jakub Kicinski <[email protected]>
  19. ---
  20. drivers/net/phy/mdio_bus.c | 189 +++++++++++++++++++++++++++++++++++++
  21. include/linux/mdio.h | 39 ++++----
  22. include/linux/phy.h | 5 +
  23. 3 files changed, 214 insertions(+), 19 deletions(-)
  24. --- a/drivers/net/phy/mdio_bus.c
  25. +++ b/drivers/net/phy/mdio_bus.c
  26. @@ -832,6 +832,100 @@ int __mdiobus_modify_changed(struct mii_
  27. EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
  28. /**
  29. + * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function
  30. + * @bus: the mii_bus struct
  31. + * @addr: the phy address
  32. + * @devad: device address to read
  33. + * @regnum: register number to read
  34. + *
  35. + * Read a MDIO bus register. Caller must hold the mdio bus lock.
  36. + *
  37. + * NOTE: MUST NOT be called from interrupt context.
  38. + */
  39. +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
  40. +{
  41. + int retval;
  42. +
  43. + lockdep_assert_held_once(&bus->mdio_lock);
  44. +
  45. + if (bus->read_c45)
  46. + retval = bus->read_c45(bus, addr, devad, regnum);
  47. + else
  48. + retval = bus->read(bus, addr, mdiobus_c45_addr(devad, regnum));
  49. +
  50. + trace_mdio_access(bus, 1, addr, regnum, retval, retval);
  51. + mdiobus_stats_acct(&bus->stats[addr], true, retval);
  52. +
  53. + return retval;
  54. +}
  55. +EXPORT_SYMBOL(__mdiobus_c45_read);
  56. +
  57. +/**
  58. + * __mdiobus_c45_write - Unlocked version of the mdiobus_write function
  59. + * @bus: the mii_bus struct
  60. + * @addr: the phy address
  61. + * @devad: device address to read
  62. + * @regnum: register number to write
  63. + * @val: value to write to @regnum
  64. + *
  65. + * Write a MDIO bus register. Caller must hold the mdio bus lock.
  66. + *
  67. + * NOTE: MUST NOT be called from interrupt context.
  68. + */
  69. +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
  70. + u16 val)
  71. +{
  72. + int err;
  73. +
  74. + lockdep_assert_held_once(&bus->mdio_lock);
  75. +
  76. + if (bus->write_c45)
  77. + err = bus->write_c45(bus, addr, devad, regnum, val);
  78. + else
  79. + err = bus->write(bus, addr, mdiobus_c45_addr(devad, regnum),
  80. + val);
  81. +
  82. + trace_mdio_access(bus, 0, addr, regnum, val, err);
  83. + mdiobus_stats_acct(&bus->stats[addr], false, err);
  84. +
  85. + return err;
  86. +}
  87. +EXPORT_SYMBOL(__mdiobus_c45_write);
  88. +
  89. +/**
  90. + * __mdiobus_c45_modify_changed - Unlocked version of the mdiobus_modify function
  91. + * @bus: the mii_bus struct
  92. + * @addr: the phy address
  93. + * @devad: device address to read
  94. + * @regnum: register number to modify
  95. + * @mask: bit mask of bits to clear
  96. + * @set: bit mask of bits to set
  97. + *
  98. + * Read, modify, and if any change, write the register value back to the
  99. + * device. Any error returns a negative number.
  100. + *
  101. + * NOTE: MUST NOT be called from interrupt context.
  102. + */
  103. +static int __mdiobus_c45_modify_changed(struct mii_bus *bus, int addr,
  104. + int devad, u32 regnum, u16 mask,
  105. + u16 set)
  106. +{
  107. + int new, ret;
  108. +
  109. + ret = __mdiobus_c45_read(bus, addr, devad, regnum);
  110. + if (ret < 0)
  111. + return ret;
  112. +
  113. + new = (ret & ~mask) | set;
  114. + if (new == ret)
  115. + return 0;
  116. +
  117. + ret = __mdiobus_c45_write(bus, addr, devad, regnum, new);
  118. +
  119. + return ret < 0 ? ret : 1;
  120. +}
  121. +
  122. +/**
  123. * mdiobus_read_nested - Nested version of the mdiobus_read function
  124. * @bus: the mii_bus struct
  125. * @addr: the phy address
  126. @@ -879,6 +973,29 @@ int mdiobus_read(struct mii_bus *bus, in
  127. EXPORT_SYMBOL(mdiobus_read);
  128. /**
  129. + * mdiobus_c45_read - Convenience function for reading a given MII mgmt register
  130. + * @bus: the mii_bus struct
  131. + * @addr: the phy address
  132. + * @devad: device address to read
  133. + * @regnum: register number to read
  134. + *
  135. + * NOTE: MUST NOT be called from interrupt context,
  136. + * because the bus read/write functions may wait for an interrupt
  137. + * to conclude the operation.
  138. + */
  139. +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
  140. +{
  141. + int retval;
  142. +
  143. + mutex_lock(&bus->mdio_lock);
  144. + retval = __mdiobus_c45_read(bus, addr, devad, regnum);
  145. + mutex_unlock(&bus->mdio_lock);
  146. +
  147. + return retval;
  148. +}
  149. +EXPORT_SYMBOL(mdiobus_c45_read);
  150. +
  151. +/**
  152. * mdiobus_write_nested - Nested version of the mdiobus_write function
  153. * @bus: the mii_bus struct
  154. * @addr: the phy address
  155. @@ -928,6 +1045,31 @@ int mdiobus_write(struct mii_bus *bus, i
  156. EXPORT_SYMBOL(mdiobus_write);
  157. /**
  158. + * mdiobus_c45_write - Convenience function for writing a given MII mgmt register
  159. + * @bus: the mii_bus struct
  160. + * @addr: the phy address
  161. + * @devad: device address to read
  162. + * @regnum: register number to write
  163. + * @val: value to write to @regnum
  164. + *
  165. + * NOTE: MUST NOT be called from interrupt context,
  166. + * because the bus read/write functions may wait for an interrupt
  167. + * to conclude the operation.
  168. + */
  169. +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
  170. + u16 val)
  171. +{
  172. + int err;
  173. +
  174. + mutex_lock(&bus->mdio_lock);
  175. + err = __mdiobus_c45_write(bus, addr, devad, regnum, val);
  176. + mutex_unlock(&bus->mdio_lock);
  177. +
  178. + return err;
  179. +}
  180. +EXPORT_SYMBOL(mdiobus_c45_write);
  181. +
  182. +/**
  183. * mdiobus_modify - Convenience function for modifying a given mdio device
  184. * register
  185. * @bus: the mii_bus struct
  186. @@ -949,6 +1091,30 @@ int mdiobus_modify(struct mii_bus *bus,
  187. EXPORT_SYMBOL_GPL(mdiobus_modify);
  188. /**
  189. + * mdiobus_c45_modify - Convenience function for modifying a given mdio device
  190. + * register
  191. + * @bus: the mii_bus struct
  192. + * @addr: the phy address
  193. + * @devad: device address to read
  194. + * @regnum: register number to write
  195. + * @mask: bit mask of bits to clear
  196. + * @set: bit mask of bits to set
  197. + */
  198. +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
  199. + u16 mask, u16 set)
  200. +{
  201. + int err;
  202. +
  203. + mutex_lock(&bus->mdio_lock);
  204. + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum,
  205. + mask, set);
  206. + mutex_unlock(&bus->mdio_lock);
  207. +
  208. + return err < 0 ? err : 0;
  209. +}
  210. +EXPORT_SYMBOL_GPL(mdiobus_c45_modify);
  211. +
  212. +/**
  213. * mdiobus_modify_changed - Convenience function for modifying a given mdio
  214. * device register and returning if it changed
  215. * @bus: the mii_bus struct
  216. @@ -971,6 +1137,29 @@ int mdiobus_modify_changed(struct mii_bu
  217. EXPORT_SYMBOL_GPL(mdiobus_modify_changed);
  218. /**
  219. + * mdiobus_c45_modify_changed - Convenience function for modifying a given mdio
  220. + * device register and returning if it changed
  221. + * @bus: the mii_bus struct
  222. + * @addr: the phy address
  223. + * @devad: device address to read
  224. + * @regnum: register number to write
  225. + * @mask: bit mask of bits to clear
  226. + * @set: bit mask of bits to set
  227. + */
  228. +int mdiobus_c45_modify_changed(struct mii_bus *bus, int devad, int addr,
  229. + u32 regnum, u16 mask, u16 set)
  230. +{
  231. + int err;
  232. +
  233. + mutex_lock(&bus->mdio_lock);
  234. + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum, mask, set);
  235. + mutex_unlock(&bus->mdio_lock);
  236. +
  237. + return err;
  238. +}
  239. +EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed);
  240. +
  241. +/**
  242. * mdio_bus_match - determine if given MDIO driver supports the given
  243. * MDIO device
  244. * @dev: target MDIO device
  245. --- a/include/linux/mdio.h
  246. +++ b/include/linux/mdio.h
  247. @@ -423,6 +423,17 @@ int mdiobus_modify(struct mii_bus *bus,
  248. u16 set);
  249. int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
  250. u16 mask, u16 set);
  251. +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
  252. +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
  253. +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
  254. + u16 val);
  255. +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
  256. + u16 val);
  257. +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
  258. + u16 mask, u16 set);
  259. +
  260. +int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
  261. + u32 regnum, u16 mask, u16 set);
  262. static inline int mdiodev_read(struct mdio_device *mdiodev, u32 regnum)
  263. {
  264. @@ -463,29 +474,19 @@ static inline u16 mdiobus_c45_devad(u32
  265. return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
  266. }
  267. -static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
  268. - u16 regnum)
  269. -{
  270. - return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
  271. -}
  272. -
  273. -static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
  274. - u16 regnum, u16 val)
  275. -{
  276. - return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum),
  277. - val);
  278. -}
  279. -
  280. -static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
  281. - u16 regnum)
  282. +static inline int mdiodev_c45_modify(struct mdio_device *mdiodev, int devad,
  283. + u32 regnum, u16 mask, u16 set)
  284. {
  285. - return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
  286. + return mdiobus_c45_modify(mdiodev->bus, mdiodev->addr, devad, regnum,
  287. + mask, set);
  288. }
  289. -static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
  290. - u16 regnum, u16 val)
  291. +static inline int mdiodev_c45_modify_changed(struct mdio_device *mdiodev,
  292. + int devad, u32 regnum, u16 mask,
  293. + u16 set)
  294. {
  295. - return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
  296. + return mdiobus_c45_modify_changed(mdiodev->bus, mdiodev->addr, devad,
  297. + regnum, mask, set);
  298. }
  299. int mdiobus_register_device(struct mdio_device *mdiodev);
  300. --- a/include/linux/phy.h
  301. +++ b/include/linux/phy.h
  302. @@ -364,6 +364,11 @@ struct mii_bus {
  303. int (*read)(struct mii_bus *bus, int addr, int regnum);
  304. /** @write: Perform a write transfer on the bus */
  305. int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
  306. + /** @read_c45: Perform a C45 read transfer on the bus */
  307. + int (*read_c45)(struct mii_bus *bus, int addr, int devnum, int regnum);
  308. + /** @write_c45: Perform a C45 write transfer on the bus */
  309. + int (*write_c45)(struct mii_bus *bus, int addr, int devnum,
  310. + int regnum, u16 val);
  311. /** @reset: Perform a reset of the bus */
  312. int (*reset)(struct mii_bus *bus);