800-net-mdio-support-hardware-assisted-indirect-access.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. From 5d84f16b0036b33487b94abef15ad3c224c81ee9 Mon Sep 17 00:00:00 2001
  2. From: Daniel Golle <[email protected]>
  3. Date: Thu, 3 Feb 2022 16:38:50 +0000
  4. Subject: [PATCH] net: mdio: support hardware-assisted indirect access
  5. MDIO controllers found in Switch-SoCs can offload some MDIO operations
  6. to the hardware:
  7. * MMD register access via Clause-22
  8. Instead of using multiple operations to access MMD registers via
  9. MII register MII_MMD_CTRL and MII_MMD_DATA some controllers
  10. allow transparent access to MMD PHY registers.
  11. * paged MII register access
  12. Some PHYs (namely RealTek and Vitesse) use vendor-defined MII
  13. register 0x1f for paged access. Some MDIO host controllers support
  14. transparent paged access when used with such PHYs.
  15. * add convenience accessors to fully support paged access also on
  16. multi-PHY packages (like the embedded PHYs in RTL83xx):
  17. phy_package_read_paged and phy_package_write_paged
  18. phy_package_port_read and phy_package_port_write
  19. phy_package_port_read_paged and phy_package_port_write_paged
  20. Signed-off-by: Daniel Golle <[email protected]>
  21. ---
  22. drivers/net/phy/mdio_bus.c | 335 ++++++++++++++++++++++++++++++++++++-
  23. drivers/net/phy/phy-core.c | 66 +++++++-
  24. include/linux/mdio.h | 59 +++++++
  25. include/linux/phy.h | 129 ++++++++++++++
  26. include/uapi/linux/mii.h | 1 +
  27. 5 files changed, 580 insertions(+), 10 deletions(-)
  28. --- a/drivers/net/phy/mdio_bus.c
  29. +++ b/drivers/net/phy/mdio_bus.c
  30. @@ -742,6 +742,32 @@ out:
  31. }
  32. /**
  33. + * __mdiobus_select_page - Unlocked version of the mdiobus_select_page function
  34. + * @bus: the mii_bus struct
  35. + * @addr: the phy address
  36. + * @page: register page to select
  37. + *
  38. + * Selects a MDIO bus register page. Caller must hold the mdio bus lock.
  39. + *
  40. + * NOTE: MUST NOT be called from interrupt context.
  41. + */
  42. +int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page)
  43. +{
  44. + lockdep_assert_held_once(&bus->mdio_lock);
  45. +
  46. + if (bus->selected_page[addr] == page)
  47. + return 0;
  48. +
  49. + bus->selected_page[addr] = page;
  50. + if (bus->read_paged)
  51. + return 0;
  52. +
  53. + return bus->write(bus, addr, MII_MAINPAGE, page);
  54. +
  55. +}
  56. +EXPORT_SYMBOL(__mdiobus_select_page);
  57. +
  58. +/**
  59. * __mdiobus_read - Unlocked version of the mdiobus_read function
  60. * @bus: the mii_bus struct
  61. * @addr: the phy address
  62. @@ -757,7 +783,10 @@ int __mdiobus_read(struct mii_bus *bus,
  63. lockdep_assert_held_once(&bus->mdio_lock);
  64. - retval = bus->read(bus, addr, regnum);
  65. + if (bus->read_paged)
  66. + retval = bus->read_paged(bus, addr, bus->selected_page[addr], regnum);
  67. + else
  68. + retval = bus->read(bus, addr, regnum);
  69. trace_mdio_access(bus, 1, addr, regnum, retval, retval);
  70. mdiobus_stats_acct(&bus->stats[addr], true, retval);
  71. @@ -767,6 +796,40 @@ int __mdiobus_read(struct mii_bus *bus,
  72. EXPORT_SYMBOL(__mdiobus_read);
  73. /**
  74. + * __mdiobus_read_paged - Unlocked version of the mdiobus_read_paged function
  75. + * @bus: the mii_bus struct
  76. + * @addr: the phy address
  77. + * @page: the register page to access
  78. + * @regnum: register number to read
  79. + *
  80. + * Read a MDIO bus register. Caller must hold the mdio bus lock.
  81. + *
  82. + * NOTE: MUST NOT be called from interrupt context.
  83. + */
  84. +int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum)
  85. +{
  86. + int retval;
  87. + int oldpage;
  88. +
  89. + lockdep_assert_held_once(&bus->mdio_lock);
  90. +
  91. + if (bus->read_paged) {
  92. + retval = bus->read_paged(bus, addr, page, regnum);
  93. + } else {
  94. + oldpage = bus->selected_page[addr];
  95. + __mdiobus_select_page(bus, addr, page);
  96. + retval = bus->read(bus, addr, regnum);
  97. + __mdiobus_select_page(bus, addr, oldpage);
  98. + }
  99. +
  100. + trace_mdio_access(bus, 1, addr, regnum, retval, retval);
  101. + mdiobus_stats_acct(&bus->stats[addr], true, retval);
  102. +
  103. + return retval;
  104. +}
  105. +EXPORT_SYMBOL(__mdiobus_read_paged);
  106. +
  107. +/**
  108. * __mdiobus_write - Unlocked version of the mdiobus_write function
  109. * @bus: the mii_bus struct
  110. * @addr: the phy address
  111. @@ -783,7 +846,10 @@ int __mdiobus_write(struct mii_bus *bus,
  112. lockdep_assert_held_once(&bus->mdio_lock);
  113. - err = bus->write(bus, addr, regnum, val);
  114. + if (bus->write_paged)
  115. + err = bus->write_paged(bus, addr, bus->selected_page[addr], regnum, val);
  116. + else
  117. + err = bus->write(bus, addr, regnum, val);
  118. trace_mdio_access(bus, 0, addr, regnum, val, err);
  119. mdiobus_stats_acct(&bus->stats[addr], false, err);
  120. @@ -793,6 +859,39 @@ int __mdiobus_write(struct mii_bus *bus,
  121. EXPORT_SYMBOL(__mdiobus_write);
  122. /**
  123. + * __mdiobus_write_paged - Unlocked version of the mdiobus_write_paged function
  124. + * @bus: the mii_bus struct
  125. + * @addr: the phy address
  126. + * @page: the register page to access
  127. + * @regnum: register number to write
  128. + * @val: value to write to @regnum
  129. + *
  130. + * Write a MDIO bus register. Caller must hold the mdio bus lock.
  131. + *
  132. + * NOTE: MUST NOT be called from interrupt context.
  133. + */
  134. +int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
  135. +{
  136. + int err, oldpage;
  137. +
  138. + lockdep_assert_held_once(&bus->mdio_lock);
  139. +
  140. + if (bus->write_paged) {
  141. + err = bus->write_paged(bus, addr, page, regnum, val);
  142. + } else {
  143. + oldpage = bus->selected_page[addr];
  144. + __mdiobus_select_page(bus, addr, page);
  145. + err = bus->write(bus, addr, regnum, val);
  146. + __mdiobus_select_page(bus, addr, oldpage);
  147. + }
  148. + trace_mdio_access(bus, 0, addr, regnum, val, err);
  149. + mdiobus_stats_acct(&bus->stats[addr], false, err);
  150. + return err;
  151. +}
  152. +EXPORT_SYMBOL(__mdiobus_write_paged);
  153. +
  154. +
  155. +/**
  156. * __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function
  157. * @bus: the mii_bus struct
  158. * @addr: the phy address
  159. @@ -825,6 +924,43 @@ int __mdiobus_modify_changed(struct mii_
  160. EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
  161. /**
  162. + * __mdiobus_modify_changed_paged - Unlocked version of the mdiobus_modify_paged function
  163. + * @bus: the mii_bus struct
  164. + * @addr: the phy address
  165. + * @regnum: register number to modify
  166. + * @mask: bit mask of bits to clear
  167. + * @set: bit mask of bits to set
  168. + *
  169. + * Read, modify, and if any change, write the register value back to the
  170. + * device. Any error returns a negative number.
  171. + *
  172. + * NOTE: MUST NOT be called from interrupt context.
  173. + */
  174. +int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page,
  175. + u16 mask, u16 set)
  176. +{
  177. + int new, ret, oldpage;
  178. +
  179. + oldpage = bus->selected_page[addr];
  180. + __mdiobus_select_page(bus, addr, page);
  181. +
  182. + ret = __mdiobus_read_paged(bus, addr, page, regnum);
  183. + if (ret < 0)
  184. + return ret;
  185. +
  186. + new = (ret & ~mask) | set;
  187. + if (new == ret)
  188. + return 0;
  189. +
  190. + ret = __mdiobus_write_paged(bus, addr, page, regnum, new);
  191. +
  192. + __mdiobus_select_page(bus, addr, oldpage);
  193. +
  194. + return ret < 0 ? ret : 1;
  195. +}
  196. +EXPORT_SYMBOL_GPL(__mdiobus_modify_changed_paged);
  197. +
  198. +/**
  199. * mdiobus_read_nested - Nested version of the mdiobus_read function
  200. * @bus: the mii_bus struct
  201. * @addr: the phy address
  202. @@ -850,6 +986,79 @@ int mdiobus_read_nested(struct mii_bus *
  203. EXPORT_SYMBOL(mdiobus_read_nested);
  204. /**
  205. + * mdiobus_select_page_nested - Nested version of the mdiobus_select_page function
  206. + * @bus: the mii_bus struct
  207. + * @addr: the phy address
  208. + * @page: register page to access
  209. + *
  210. + * In case of nested MDIO bus access avoid lockdep false positives by
  211. + * using mutex_lock_nested().
  212. + *
  213. + * NOTE: MUST NOT be called from interrupt context,
  214. + * because the bus read/write functions may wait for an interrupt
  215. + * to conclude the operation.
  216. + */
  217. +int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page)
  218. +{
  219. + int retval;
  220. +
  221. + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
  222. + retval = __mdiobus_select_page(bus, addr, page);
  223. + mutex_unlock(&bus->mdio_lock);
  224. +
  225. + return retval;
  226. +}
  227. +EXPORT_SYMBOL(mdiobus_select_page_nested);
  228. +
  229. +/**
  230. + * mdiobus_read_paged_nested - Nested version of the mdiobus_read_paged function
  231. + * @bus: the mii_bus struct
  232. + * @addr: the phy address
  233. + * @page: register page to access
  234. + * @regnum: register number to read
  235. + *
  236. + * In case of nested MDIO bus access avoid lockdep false positives by
  237. + * using mutex_lock_nested().
  238. + *
  239. + * NOTE: MUST NOT be called from interrupt context,
  240. + * because the bus read/write functions may wait for an interrupt
  241. + * to conclude the operation.
  242. + */
  243. +int mdiobus_read_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum)
  244. +{
  245. + int retval;
  246. +
  247. + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
  248. + retval = __mdiobus_read_paged(bus, addr, page, regnum);
  249. + mutex_unlock(&bus->mdio_lock);
  250. +
  251. + return retval;
  252. +}
  253. +EXPORT_SYMBOL(mdiobus_read_paged_nested);
  254. +
  255. +/**
  256. + * mdiobus_select_page - Convenience function for setting the MII register page
  257. + * @bus: the mii_bus struct
  258. + * @addr: the phy address
  259. + * @page: the register page to set
  260. + *
  261. + * NOTE: MUST NOT be called from interrupt context,
  262. + * because the bus read/write functions may wait for an interrupt
  263. + * to conclude the operation.
  264. + */
  265. +int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page)
  266. +{
  267. + int retval;
  268. +
  269. + mutex_lock(&bus->mdio_lock);
  270. + retval = __mdiobus_select_page(bus, addr, page);
  271. + mutex_unlock(&bus->mdio_lock);
  272. +
  273. + return retval;
  274. +}
  275. +EXPORT_SYMBOL(mdiobus_select_page);
  276. +
  277. +/**
  278. * mdiobus_read - Convenience function for reading a given MII mgmt register
  279. * @bus: the mii_bus struct
  280. * @addr: the phy address
  281. @@ -872,6 +1081,29 @@ int mdiobus_read(struct mii_bus *bus, in
  282. EXPORT_SYMBOL(mdiobus_read);
  283. /**
  284. + * mdiobus_read_paged - Convenience function for reading a given paged MII mgmt register
  285. + * @bus: the mii_bus struct
  286. + * @addr: the phy address
  287. + * @page: register page to access
  288. + * @regnum: register number to read
  289. + *
  290. + * NOTE: MUST NOT be called from interrupt context,
  291. + * because the bus read/write functions may wait for an interrupt
  292. + * to conclude the operation.
  293. + */
  294. +int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum)
  295. +{
  296. + int retval;
  297. +
  298. + mutex_lock(&bus->mdio_lock);
  299. + retval = __mdiobus_read_paged(bus, addr, page, regnum);
  300. + mutex_unlock(&bus->mdio_lock);
  301. +
  302. + return retval;
  303. +}
  304. +EXPORT_SYMBOL(mdiobus_read_paged);
  305. +
  306. +/**
  307. * mdiobus_write_nested - Nested version of the mdiobus_write function
  308. * @bus: the mii_bus struct
  309. * @addr: the phy address
  310. @@ -898,6 +1130,33 @@ int mdiobus_write_nested(struct mii_bus
  311. EXPORT_SYMBOL(mdiobus_write_nested);
  312. /**
  313. + * mdiobus_write_paged_nested - Nested version of the mdiobus_write_aged function
  314. + * @bus: the mii_bus struct
  315. + * @addr: the phy address
  316. + * @page: the register page to access
  317. + * @regnum: register number to write
  318. + * @val: value to write to @regnum
  319. + *
  320. + * In case of nested MDIO bus access avoid lockdep false positives by
  321. + * using mutex_lock_nested().
  322. + *
  323. + * NOTE: MUST NOT be called from interrupt context,
  324. + * because the bus read/write functions may wait for an interrupt
  325. + * to conclude the operation.
  326. + */
  327. +int mdiobus_write_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
  328. +{
  329. + int err;
  330. +
  331. + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
  332. + err = __mdiobus_write_paged(bus, addr, page, regnum, val);
  333. + mutex_unlock(&bus->mdio_lock);
  334. +
  335. + return err;
  336. +}
  337. +EXPORT_SYMBOL(mdiobus_write_paged_nested);
  338. +
  339. +/**
  340. * mdiobus_write - Convenience function for writing a given MII mgmt register
  341. * @bus: the mii_bus struct
  342. * @addr: the phy address
  343. @@ -921,6 +1180,30 @@ int mdiobus_write(struct mii_bus *bus, i
  344. EXPORT_SYMBOL(mdiobus_write);
  345. /**
  346. + * mdiobus_write_paged - Convenience function for writing a given paged MII mgmt register
  347. + * @bus: the mii_bus struct
  348. + * @addr: the phy address
  349. + * @page: the register page to access
  350. + * @regnum: register number to write
  351. + * @val: value to write to @regnum
  352. + *
  353. + * NOTE: MUST NOT be called from interrupt context,
  354. + * because the bus read/write functions may wait for an interrupt
  355. + * to conclude the operation.
  356. + */
  357. +int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
  358. +{
  359. + int err;
  360. +
  361. + mutex_lock(&bus->mdio_lock);
  362. + err = __mdiobus_write_paged(bus, addr, page, regnum, val);
  363. + mutex_unlock(&bus->mdio_lock);
  364. +
  365. + return err;
  366. +}
  367. +EXPORT_SYMBOL(mdiobus_write_paged);
  368. +
  369. +/**
  370. * mdiobus_modify - Convenience function for modifying a given mdio device
  371. * register
  372. * @bus: the mii_bus struct
  373. @@ -942,6 +1225,51 @@ int mdiobus_modify(struct mii_bus *bus,
  374. EXPORT_SYMBOL_GPL(mdiobus_modify);
  375. /**
  376. + * mdiobus_modify_paged - Convenience function for modifying a given mdio device
  377. + * register
  378. + * @bus: the mii_bus struct
  379. + * @addr: the phy address
  380. + * @page: the register page to access
  381. + * @regnum: register number to write
  382. + * @mask: bit mask of bits to clear
  383. + * @set: bit mask of bits to set
  384. + */
  385. +int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask, u16 set)
  386. +{
  387. + int err;
  388. +
  389. + mutex_lock(&bus->mdio_lock);
  390. + err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set);
  391. + mutex_unlock(&bus->mdio_lock);
  392. +
  393. + return err < 0 ? err : 0;
  394. +}
  395. +EXPORT_SYMBOL_GPL(mdiobus_modify_paged);
  396. +
  397. +/**
  398. + * mdiobus_modify_changed_paged - Convenience function for modifying a given paged
  399. + * mdio device register and returning if it changed
  400. + * @bus: the mii_bus struct
  401. + * @addr: the phy address
  402. + * @page: the register page to access
  403. + * @regnum: register number to write
  404. + * @mask: bit mask of bits to clear
  405. + * @set: bit mask of bits to set
  406. + */
  407. +int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum,
  408. + u16 mask, u16 set)
  409. +{
  410. + int err;
  411. +
  412. + mutex_lock(&bus->mdio_lock);
  413. + err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set);
  414. + mutex_unlock(&bus->mdio_lock);
  415. +
  416. + return err;
  417. +}
  418. +EXPORT_SYMBOL_GPL(mdiobus_modify_changed_paged);
  419. +
  420. +/**
  421. * mdio_bus_match - determine if given MDIO driver supports the given
  422. * MDIO device
  423. * @dev: target MDIO device
  424. --- a/drivers/net/phy/phy-core.c
  425. +++ b/drivers/net/phy/phy-core.c
  426. @@ -557,10 +557,16 @@ int __phy_read_mmd(struct phy_device *ph
  427. struct mii_bus *bus = phydev->mdio.bus;
  428. int phy_addr = phydev->mdio.addr;
  429. - mmd_phy_indirect(bus, phy_addr, devad, regnum);
  430. -
  431. - /* Read the content of the MMD's selected register */
  432. - val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
  433. + if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) {
  434. + val = __mdiobus_c22_mmd_read(phydev->mdio.bus,
  435. + phydev->mdio.addr,
  436. + devad, regnum);
  437. + } else {
  438. + mmd_phy_indirect(bus, phy_addr, devad, regnum);
  439. +
  440. + /* Read the content of the MMD's selected register */
  441. + val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
  442. + }
  443. }
  444. return val;
  445. }
  446. @@ -613,12 +619,18 @@ int __phy_write_mmd(struct phy_device *p
  447. struct mii_bus *bus = phydev->mdio.bus;
  448. int phy_addr = phydev->mdio.addr;
  449. - mmd_phy_indirect(bus, phy_addr, devad, regnum);
  450. + if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) {
  451. + ret = __mdiobus_c22_mmd_write(phydev->mdio.bus,
  452. + phydev->mdio.addr,
  453. + devad, regnum, val);
  454. + } else {
  455. + mmd_phy_indirect(bus, phy_addr, devad, regnum);
  456. - /* Write the data into MMD's selected register */
  457. - __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
  458. + /* Write the data into MMD's selected register */
  459. + __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
  460. - ret = 0;
  461. + ret = 0;
  462. + }
  463. }
  464. return ret;
  465. }
  466. @@ -824,6 +836,13 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd);
  467. static int __phy_read_page(struct phy_device *phydev)
  468. {
  469. + if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
  470. + struct mii_bus *bus = phydev->mdio.bus;
  471. + int phy_addr = phydev->mdio.addr;
  472. +
  473. + return bus->selected_page[phy_addr];
  474. + }
  475. +
  476. if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n"))
  477. return -EOPNOTSUPP;
  478. @@ -832,6 +851,13 @@ static int __phy_read_page(struct phy_de
  479. static int __phy_write_page(struct phy_device *phydev, int page)
  480. {
  481. + if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
  482. + struct mii_bus *bus = phydev->mdio.bus;
  483. + int phy_addr = phydev->mdio.addr;
  484. +
  485. + return __mdiobus_select_page(bus, phy_addr, page);
  486. + }
  487. +
  488. if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n"))
  489. return -EOPNOTSUPP;
  490. @@ -933,6 +959,18 @@ int phy_read_paged(struct phy_device *ph
  491. {
  492. int ret = 0, oldpage;
  493. + if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
  494. + struct mii_bus *bus = phydev->mdio.bus;
  495. + int phy_addr = phydev->mdio.addr;
  496. +
  497. + if (bus->read_paged) {
  498. + phy_lock_mdio_bus(phydev);
  499. + ret = bus->read_paged(bus, phy_addr, page, regnum);
  500. + phy_unlock_mdio_bus(phydev);
  501. + return ret;
  502. + }
  503. + }
  504. +
  505. oldpage = phy_select_page(phydev, page);
  506. if (oldpage >= 0)
  507. ret = __phy_read(phydev, regnum);
  508. @@ -954,6 +992,18 @@ int phy_write_paged(struct phy_device *p
  509. {
  510. int ret = 0, oldpage;
  511. + if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
  512. + struct mii_bus *bus = phydev->mdio.bus;
  513. + int phy_addr = phydev->mdio.addr;
  514. +
  515. + if (bus->write_paged) {
  516. + phy_lock_mdio_bus(phydev);
  517. + ret = bus->write_paged(bus, phy_addr, page, regnum, val);
  518. + phy_unlock_mdio_bus(phydev);
  519. + return ret;
  520. + }
  521. + }
  522. +
  523. oldpage = phy_select_page(phydev, page);
  524. if (oldpage >= 0)
  525. ret = __phy_write(phydev, regnum, val);
  526. --- a/include/linux/mdio.h
  527. +++ b/include/linux/mdio.h
  528. @@ -14,6 +14,7 @@
  529. * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
  530. */
  531. #define MII_ADDR_C45 (1<<30)
  532. +#define MII_ADDR_C22_MMD (1<<29)
  533. #define MII_DEVADDR_C45_SHIFT 16
  534. #define MII_DEVADDR_C45_MASK GENMASK(20, 16)
  535. #define MII_REGADDR_C45_MASK GENMASK(15, 0)
  536. @@ -340,11 +341,19 @@ static inline void mii_10gbt_stat_mod_li
  537. advertising, lpa & MDIO_AN_10GBT_STAT_LP10G);
  538. }
  539. +int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page);
  540. int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
  541. int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
  542. int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
  543. u16 mask, u16 set);
  544. +int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
  545. +int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
  546. +int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page,
  547. + u16 mask, u16 set);
  548. +
  549. +int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page);
  550. +int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page);
  551. int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
  552. int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
  553. int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
  554. @@ -352,11 +361,51 @@ int mdiobus_write_nested(struct mii_bus
  555. int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
  556. u16 set);
  557. +int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
  558. +int mdiobus_read_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
  559. +int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
  560. +int mdiobus_write_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
  561. +int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask,
  562. + u16 set);
  563. +int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum,
  564. + u16 mask, u16 set);
  565. +
  566. +static inline int mdiodev_read_paged(struct mdio_device *mdiodev, u16 page,
  567. + u32 regnum)
  568. +{
  569. + return mdiobus_read_paged(mdiodev->bus, mdiodev->addr, page, regnum);
  570. +}
  571. +
  572. +static inline int mdiodev_write_paged(struct mdio_device *mdiodev, u16 page,
  573. + u32 regnum, u16 val)
  574. +{
  575. + return mdiobus_write_paged(mdiodev->bus, mdiodev->addr, page, regnum, val);
  576. +}
  577. +
  578. +static inline int mdiodev_modify_paged(struct mdio_device *mdiodev, u16 page,
  579. + u32 regnum, u16 mask, u16 set)
  580. +{
  581. + return mdiobus_modify_paged(mdiodev->bus, mdiodev->addr, page, regnum,
  582. + mask, set);
  583. +}
  584. +
  585. +static inline int mdiodev_modify_changed_paged(struct mdio_device *mdiodev, u16 page,
  586. + u32 regnum, u16 mask, u16 set)
  587. +{
  588. + return mdiobus_modify_changed_paged(mdiodev->bus, mdiodev->addr, page, regnum,
  589. + mask, set);
  590. +}
  591. +
  592. static inline u32 mdiobus_c45_addr(int devad, u16 regnum)
  593. {
  594. return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
  595. }
  596. +static inline u32 mdiobus_c22_mmd_addr(int devad, u16 regnum)
  597. +{
  598. + return MII_ADDR_C22_MMD | devad << MII_DEVADDR_C45_SHIFT | regnum;
  599. +}
  600. +
  601. static inline u16 mdiobus_c45_regad(u32 regnum)
  602. {
  603. return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
  604. @@ -380,6 +429,19 @@ static inline int __mdiobus_c45_write(st
  605. val);
  606. }
  607. +static inline int __mdiobus_c22_mmd_read(struct mii_bus *bus, int prtad,
  608. + int devad, u16 regnum)
  609. +{
  610. + return __mdiobus_read(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum));
  611. +}
  612. +
  613. +static inline int __mdiobus_c22_mmd_write(struct mii_bus *bus, int prtad,
  614. + int devad, u16 regnum, u16 val)
  615. +{
  616. + return __mdiobus_write(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum),
  617. + val);
  618. +}
  619. +
  620. static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
  621. u16 regnum)
  622. {
  623. --- a/include/linux/phy.h
  624. +++ b/include/linux/phy.h
  625. @@ -81,6 +81,7 @@ extern const int phy_10gbit_features_arr
  626. #define PHY_IS_INTERNAL 0x00000001
  627. #define PHY_RST_AFTER_CLK_EN 0x00000002
  628. #define PHY_POLL_CABLE_TEST 0x00000004
  629. +#define PHY_HAS_REALTEK_PAGES 0x00000010
  630. #define MDIO_DEVICE_IS_PHY 0x80000000
  631. /**
  632. @@ -428,6 +429,22 @@ struct mii_bus {
  633. /** @shared: shared state across different PHYs */
  634. struct phy_package_shared *shared[PHY_MAX_ADDR];
  635. +
  636. + /** @access_capabilities: hardware-assisted access capabilties */
  637. + enum {
  638. + MDIOBUS_ACCESS_SOFTWARE_ONLY = 0,
  639. + MDIOBUS_ACCESS_C22_MMD = 0x1,
  640. + } access_capabilities;
  641. +
  642. + /** @read: Perform a read transfer on the bus, offloading page access */
  643. + int (*read_paged)(struct mii_bus *bus, int addr, u16 page, int regnum);
  644. + /** @write: Perform a write transfer on the bus, offloading page access */
  645. + int (*write_paged)(struct mii_bus *bus, int addr, u16 page, int regnum, u16 val);
  646. + /** currently selected page when page access is offloaded
  647. + * array should be PHY_MAX_ADDR+1size, but current design of the MDIO driver
  648. + * uses port addresses as phy addresses and they are up to 6 bit.
  649. + */
  650. + u16 selected_page[64];
  651. };
  652. #define to_mii_bus(d) container_of(d, struct mii_bus, dev)
  653. @@ -1825,6 +1842,66 @@ static inline int __phy_package_read(str
  654. return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
  655. }
  656. +static inline int phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum)
  657. +{
  658. + struct phy_package_shared *shared = phydev->shared;
  659. +
  660. + if (!shared)
  661. + return -EIO;
  662. +
  663. + return mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum);
  664. +}
  665. +
  666. +static inline int __phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum)
  667. +{
  668. + struct phy_package_shared *shared = phydev->shared;
  669. +
  670. + if (!shared)
  671. + return -EIO;
  672. +
  673. + return __mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum);
  674. +}
  675. +
  676. +static inline int phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum)
  677. +{
  678. + struct phy_package_shared *shared = phydev->shared;
  679. +
  680. + if (!shared)
  681. + return -EIO;
  682. +
  683. + return mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum);
  684. +}
  685. +
  686. +static inline int __phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum)
  687. +{
  688. + struct phy_package_shared *shared = phydev->shared;
  689. +
  690. + if (!shared)
  691. + return -EIO;
  692. +
  693. + return __mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum);
  694. +}
  695. +
  696. +static inline int phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum)
  697. +{
  698. + struct phy_package_shared *shared = phydev->shared;
  699. +
  700. + if (!shared)
  701. + return -EIO;
  702. +
  703. + return mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum);
  704. +}
  705. +
  706. +static inline int __phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum)
  707. +{
  708. + struct phy_package_shared *shared = phydev->shared;
  709. +
  710. + if (!shared)
  711. + return -EIO;
  712. +
  713. + return __mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum);
  714. +}
  715. +
  716. static inline int phy_package_write(struct phy_device *phydev,
  717. u32 regnum, u16 val)
  718. {
  719. @@ -1847,6 +1924,72 @@ static inline int __phy_package_write(st
  720. return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
  721. }
  722. +static inline int phy_package_port_write(struct phy_device *phydev,
  723. + u16 port, u32 regnum, u16 val)
  724. +{
  725. + struct phy_package_shared *shared = phydev->shared;
  726. +
  727. + if (!shared)
  728. + return -EIO;
  729. +
  730. + return mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val);
  731. +}
  732. +
  733. +static inline int __phy_package_port_write(struct phy_device *phydev,
  734. + u16 port, u32 regnum, u16 val)
  735. +{
  736. + struct phy_package_shared *shared = phydev->shared;
  737. +
  738. + if (!shared)
  739. + return -EIO;
  740. +
  741. + return __mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val);
  742. +}
  743. +
  744. +static inline int phy_package_port_write_paged(struct phy_device *phydev,
  745. + u16 port, u16 page, u32 regnum, u16 val)
  746. +{
  747. + struct phy_package_shared *shared = phydev->shared;
  748. +
  749. + if (!shared)
  750. + return -EIO;
  751. +
  752. + return mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val);
  753. +}
  754. +
  755. +static inline int __phy_package_port_write_paged(struct phy_device *phydev,
  756. + u16 port, u16 page, u32 regnum, u16 val)
  757. +{
  758. + struct phy_package_shared *shared = phydev->shared;
  759. +
  760. + if (!shared)
  761. + return -EIO;
  762. +
  763. + return __mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val);
  764. +}
  765. +
  766. +static inline int phy_package_write_paged(struct phy_device *phydev,
  767. + u16 page, u32 regnum, u16 val)
  768. +{
  769. + struct phy_package_shared *shared = phydev->shared;
  770. +
  771. + if (!shared)
  772. + return -EIO;
  773. +
  774. + return mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val);
  775. +}
  776. +
  777. +static inline int __phy_package_write_paged(struct phy_device *phydev,
  778. + u16 page, u32 regnum, u16 val)
  779. +{
  780. + struct phy_package_shared *shared = phydev->shared;
  781. +
  782. + if (!shared)
  783. + return -EIO;
  784. +
  785. + return __mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val);
  786. +}
  787. +
  788. static inline bool __phy_package_set_once(struct phy_device *phydev,
  789. unsigned int b)
  790. {
  791. --- a/include/uapi/linux/mii.h
  792. +++ b/include/uapi/linux/mii.h
  793. @@ -36,6 +36,7 @@
  794. #define MII_RESV2 0x1a /* Reserved... */
  795. #define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
  796. #define MII_NCONFIG 0x1c /* Network interface config */
  797. +#define MII_MAINPAGE 0x1f /* Page register */
  798. /* Basic mode control register. */
  799. #define BMCR_RESV 0x003f /* Unused... */