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