forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-11 04dd17822334871b23ea2862f7798fb0e0007777
kernel/drivers/net/phy/mdio_bus.c
....@@ -1,46 +1,39 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /* MDIO Bus interface
23 *
34 * Author: Andy Fleming
45 *
56 * Copyright (c) 2004 Freescale Semiconductor, Inc.
6
- *
7
- * This program is free software; you can redistribute it and/or modify it
8
- * under the terms of the GNU General Public License as published by the
9
- * Free Software Foundation; either version 2 of the License, or (at your
10
- * option) any later version.
11
- *
127 */
138
149 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1510
16
-#include <linux/kernel.h>
17
-#include <linux/string.h>
18
-#include <linux/errno.h>
19
-#include <linux/unistd.h>
20
-#include <linux/slab.h>
21
-#include <linux/interrupt.h>
22
-#include <linux/init.h>
2311 #include <linux/delay.h>
2412 #include <linux/device.h>
13
+#include <linux/errno.h>
14
+#include <linux/etherdevice.h>
15
+#include <linux/ethtool.h>
2516 #include <linux/gpio.h>
2617 #include <linux/gpio/consumer.h>
27
-#include <linux/of_device.h>
28
-#include <linux/of_mdio.h>
29
-#include <linux/of_gpio.h>
30
-#include <linux/netdevice.h>
31
-#include <linux/etherdevice.h>
32
-#include <linux/skbuff.h>
33
-#include <linux/spinlock.h>
18
+#include <linux/init.h>
19
+#include <linux/interrupt.h>
20
+#include <linux/io.h>
21
+#include <linux/kernel.h>
22
+#include <linux/mii.h>
3423 #include <linux/mm.h>
3524 #include <linux/module.h>
36
-#include <linux/mii.h>
37
-#include <linux/ethtool.h>
25
+#include <linux/netdevice.h>
26
+#include <linux/of_device.h>
27
+#include <linux/of_gpio.h>
28
+#include <linux/of_mdio.h>
3829 #include <linux/phy.h>
39
-#include <linux/io.h>
30
+#include <linux/reset.h>
31
+#include <linux/skbuff.h>
32
+#include <linux/slab.h>
33
+#include <linux/spinlock.h>
34
+#include <linux/string.h>
4035 #include <linux/uaccess.h>
41
-#include <linux/gpio/consumer.h>
42
-
43
-#include <asm/irq.h>
36
+#include <linux/unistd.h>
4437
4538 #define CREATE_TRACE_POINTS
4639 #include <trace/events/mdio.h>
....@@ -49,24 +42,27 @@
4942
5043 static int mdiobus_register_gpiod(struct mdio_device *mdiodev)
5144 {
52
- struct gpio_desc *gpiod = NULL;
53
-
5445 /* Deassert the optional reset signal */
55
- if (mdiodev->dev.of_node)
56
- gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode,
57
- "reset-gpios", 0, GPIOD_OUT_LOW,
58
- "PHY reset");
59
- if (IS_ERR(gpiod)) {
60
- if (PTR_ERR(gpiod) == -ENOENT || PTR_ERR(gpiod) == -ENOSYS)
61
- gpiod = NULL;
62
- else
63
- return PTR_ERR(gpiod);
64
- }
46
+ mdiodev->reset_gpio = gpiod_get_optional(&mdiodev->dev,
47
+ "reset", GPIOD_OUT_LOW);
48
+ if (IS_ERR(mdiodev->reset_gpio))
49
+ return PTR_ERR(mdiodev->reset_gpio);
6550
66
- mdiodev->reset = gpiod;
51
+ if (mdiodev->reset_gpio)
52
+ gpiod_set_consumer_name(mdiodev->reset_gpio, "PHY reset");
6753
68
- /* Assert the reset signal again */
69
- mdio_device_reset(mdiodev, 1);
54
+ return 0;
55
+}
56
+
57
+static int mdiobus_register_reset(struct mdio_device *mdiodev)
58
+{
59
+ struct reset_control *reset;
60
+
61
+ reset = reset_control_get_optional_exclusive(&mdiodev->dev, "phy");
62
+ if (IS_ERR(reset))
63
+ return PTR_ERR(reset);
64
+
65
+ mdiodev->reset_ctrl = reset;
7066
7167 return 0;
7268 }
....@@ -82,6 +78,13 @@
8278 err = mdiobus_register_gpiod(mdiodev);
8379 if (err)
8480 return err;
81
+
82
+ err = mdiobus_register_reset(mdiodev);
83
+ if (err)
84
+ return err;
85
+
86
+ /* Assert the reset signal */
87
+ mdio_device_reset(mdiodev, 1);
8588 }
8689
8790 mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev;
....@@ -95,6 +98,8 @@
9598 if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev)
9699 return -EINVAL;
97100
101
+ reset_control_put(mdiodev->reset_ctrl);
102
+
98103 mdiodev->bus->mdio_map[mdiodev->addr] = NULL;
99104
100105 return 0;
....@@ -103,7 +108,12 @@
103108
104109 struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr)
105110 {
106
- struct mdio_device *mdiodev = bus->mdio_map[addr];
111
+ struct mdio_device *mdiodev;
112
+
113
+ if (addr < 0 || addr >= ARRAY_SIZE(bus->mdio_map))
114
+ return NULL;
115
+
116
+ mdiodev = bus->mdio_map[addr];
107117
108118 if (!mdiodev)
109119 return NULL;
....@@ -150,80 +160,15 @@
150160 if (size)
151161 bus->priv = (void *)bus + aligned_size;
152162
153
- /* Initialise the interrupts to polling */
154
- for (i = 0; i < PHY_MAX_ADDR; i++)
163
+ /* Initialise the interrupts to polling and 64-bit seqcounts */
164
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
155165 bus->irq[i] = PHY_POLL;
156
-
157
- return bus;
158
-}
159
-EXPORT_SYMBOL(mdiobus_alloc_size);
160
-
161
-static void _devm_mdiobus_free(struct device *dev, void *res)
162
-{
163
- mdiobus_free(*(struct mii_bus **)res);
164
-}
165
-
166
-static int devm_mdiobus_match(struct device *dev, void *res, void *data)
167
-{
168
- struct mii_bus **r = res;
169
-
170
- if (WARN_ON(!r || !*r))
171
- return 0;
172
-
173
- return *r == data;
174
-}
175
-
176
-/**
177
- * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size()
178
- * @dev: Device to allocate mii_bus for
179
- * @sizeof_priv: Space to allocate for private structure.
180
- *
181
- * Managed mdiobus_alloc_size. mii_bus allocated with this function is
182
- * automatically freed on driver detach.
183
- *
184
- * If an mii_bus allocated with this function needs to be freed separately,
185
- * devm_mdiobus_free() must be used.
186
- *
187
- * RETURNS:
188
- * Pointer to allocated mii_bus on success, NULL on failure.
189
- */
190
-struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv)
191
-{
192
- struct mii_bus **ptr, *bus;
193
-
194
- ptr = devres_alloc(_devm_mdiobus_free, sizeof(*ptr), GFP_KERNEL);
195
- if (!ptr)
196
- return NULL;
197
-
198
- /* use raw alloc_dr for kmalloc caller tracing */
199
- bus = mdiobus_alloc_size(sizeof_priv);
200
- if (bus) {
201
- *ptr = bus;
202
- devres_add(dev, ptr);
203
- } else {
204
- devres_free(ptr);
166
+ u64_stats_init(&bus->stats[i].syncp);
205167 }
206168
207169 return bus;
208170 }
209
-EXPORT_SYMBOL_GPL(devm_mdiobus_alloc_size);
210
-
211
-/**
212
- * devm_mdiobus_free - Resource-managed mdiobus_free()
213
- * @dev: Device this mii_bus belongs to
214
- * @bus: the mii_bus associated with the device
215
- *
216
- * Free mii_bus allocated with devm_mdiobus_alloc_size().
217
- */
218
-void devm_mdiobus_free(struct device *dev, struct mii_bus *bus)
219
-{
220
- int rc;
221
-
222
- rc = devres_release(dev, _devm_mdiobus_free,
223
- devm_mdiobus_match, bus);
224
- WARN_ON(rc);
225
-}
226
-EXPORT_SYMBOL_GPL(devm_mdiobus_free);
171
+EXPORT_SYMBOL(mdiobus_alloc_size);
227172
228173 /**
229174 * mdiobus_release - mii_bus device release callback
....@@ -241,17 +186,235 @@
241186 kfree(bus);
242187 }
243188
189
+struct mdio_bus_stat_attr {
190
+ int addr;
191
+ unsigned int field_offset;
192
+};
193
+
194
+static u64 mdio_bus_get_stat(struct mdio_bus_stats *s, unsigned int offset)
195
+{
196
+ const char *p = (const char *)s + offset;
197
+ unsigned int start;
198
+ u64 val = 0;
199
+
200
+ do {
201
+ start = u64_stats_fetch_begin(&s->syncp);
202
+ val = u64_stats_read((const u64_stats_t *)p);
203
+ } while (u64_stats_fetch_retry(&s->syncp, start));
204
+
205
+ return val;
206
+}
207
+
208
+static u64 mdio_bus_get_global_stat(struct mii_bus *bus, unsigned int offset)
209
+{
210
+ unsigned int i;
211
+ u64 val = 0;
212
+
213
+ for (i = 0; i < PHY_MAX_ADDR; i++)
214
+ val += mdio_bus_get_stat(&bus->stats[i], offset);
215
+
216
+ return val;
217
+}
218
+
219
+static ssize_t mdio_bus_stat_field_show(struct device *dev,
220
+ struct device_attribute *attr,
221
+ char *buf)
222
+{
223
+ struct mii_bus *bus = to_mii_bus(dev);
224
+ struct mdio_bus_stat_attr *sattr;
225
+ struct dev_ext_attribute *eattr;
226
+ u64 val;
227
+
228
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
229
+ sattr = eattr->var;
230
+
231
+ if (sattr->addr < 0)
232
+ val = mdio_bus_get_global_stat(bus, sattr->field_offset);
233
+ else
234
+ val = mdio_bus_get_stat(&bus->stats[sattr->addr],
235
+ sattr->field_offset);
236
+
237
+ return sprintf(buf, "%llu\n", val);
238
+}
239
+
240
+static ssize_t mdio_bus_device_stat_field_show(struct device *dev,
241
+ struct device_attribute *attr,
242
+ char *buf)
243
+{
244
+ struct mdio_device *mdiodev = to_mdio_device(dev);
245
+ struct mii_bus *bus = mdiodev->bus;
246
+ struct mdio_bus_stat_attr *sattr;
247
+ struct dev_ext_attribute *eattr;
248
+ int addr = mdiodev->addr;
249
+ u64 val;
250
+
251
+ eattr = container_of(attr, struct dev_ext_attribute, attr);
252
+ sattr = eattr->var;
253
+
254
+ val = mdio_bus_get_stat(&bus->stats[addr], sattr->field_offset);
255
+
256
+ return sprintf(buf, "%llu\n", val);
257
+}
258
+
259
+#define MDIO_BUS_STATS_ATTR_DECL(field, file) \
260
+static struct dev_ext_attribute dev_attr_mdio_bus_##field = { \
261
+ .attr = { .attr = { .name = file, .mode = 0444 }, \
262
+ .show = mdio_bus_stat_field_show, \
263
+ }, \
264
+ .var = &((struct mdio_bus_stat_attr) { \
265
+ -1, offsetof(struct mdio_bus_stats, field) \
266
+ }), \
267
+}; \
268
+static struct dev_ext_attribute dev_attr_mdio_bus_device_##field = { \
269
+ .attr = { .attr = { .name = file, .mode = 0444 }, \
270
+ .show = mdio_bus_device_stat_field_show, \
271
+ }, \
272
+ .var = &((struct mdio_bus_stat_attr) { \
273
+ -1, offsetof(struct mdio_bus_stats, field) \
274
+ }), \
275
+};
276
+
277
+#define MDIO_BUS_STATS_ATTR(field) \
278
+ MDIO_BUS_STATS_ATTR_DECL(field, __stringify(field))
279
+
280
+MDIO_BUS_STATS_ATTR(transfers);
281
+MDIO_BUS_STATS_ATTR(errors);
282
+MDIO_BUS_STATS_ATTR(writes);
283
+MDIO_BUS_STATS_ATTR(reads);
284
+
285
+#define MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, file) \
286
+static struct dev_ext_attribute dev_attr_mdio_bus_addr_##field##_##addr = { \
287
+ .attr = { .attr = { .name = file, .mode = 0444 }, \
288
+ .show = mdio_bus_stat_field_show, \
289
+ }, \
290
+ .var = &((struct mdio_bus_stat_attr) { \
291
+ addr, offsetof(struct mdio_bus_stats, field) \
292
+ }), \
293
+}
294
+
295
+#define MDIO_BUS_STATS_ADDR_ATTR(field, addr) \
296
+ MDIO_BUS_STATS_ADDR_ATTR_DECL(field, addr, \
297
+ __stringify(field) "_" __stringify(addr))
298
+
299
+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(addr) \
300
+ MDIO_BUS_STATS_ADDR_ATTR(transfers, addr); \
301
+ MDIO_BUS_STATS_ADDR_ATTR(errors, addr); \
302
+ MDIO_BUS_STATS_ADDR_ATTR(writes, addr); \
303
+ MDIO_BUS_STATS_ADDR_ATTR(reads, addr) \
304
+
305
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(0);
306
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(1);
307
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(2);
308
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(3);
309
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(4);
310
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(5);
311
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(6);
312
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(7);
313
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(8);
314
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(9);
315
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(10);
316
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(11);
317
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(12);
318
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(13);
319
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(14);
320
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(15);
321
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(16);
322
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(17);
323
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(18);
324
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(19);
325
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(20);
326
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(21);
327
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(22);
328
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(23);
329
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(24);
330
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(25);
331
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(26);
332
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(27);
333
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(28);
334
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(29);
335
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(30);
336
+MDIO_BUS_STATS_ADDR_ATTR_GROUP_DECL(31);
337
+
338
+#define MDIO_BUS_STATS_ADDR_ATTR_GROUP(addr) \
339
+ &dev_attr_mdio_bus_addr_transfers_##addr.attr.attr, \
340
+ &dev_attr_mdio_bus_addr_errors_##addr.attr.attr, \
341
+ &dev_attr_mdio_bus_addr_writes_##addr.attr.attr, \
342
+ &dev_attr_mdio_bus_addr_reads_##addr.attr.attr \
343
+
344
+static struct attribute *mdio_bus_statistics_attrs[] = {
345
+ &dev_attr_mdio_bus_transfers.attr.attr,
346
+ &dev_attr_mdio_bus_errors.attr.attr,
347
+ &dev_attr_mdio_bus_writes.attr.attr,
348
+ &dev_attr_mdio_bus_reads.attr.attr,
349
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(0),
350
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(1),
351
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(2),
352
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(3),
353
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(4),
354
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(5),
355
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(6),
356
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(7),
357
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(8),
358
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(9),
359
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(10),
360
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(11),
361
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(12),
362
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(13),
363
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(14),
364
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(15),
365
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(16),
366
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(17),
367
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(18),
368
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(19),
369
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(20),
370
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(21),
371
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(22),
372
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(23),
373
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(24),
374
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(25),
375
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(26),
376
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(27),
377
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(28),
378
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(29),
379
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(30),
380
+ MDIO_BUS_STATS_ADDR_ATTR_GROUP(31),
381
+ NULL,
382
+};
383
+
384
+static const struct attribute_group mdio_bus_statistics_group = {
385
+ .name = "statistics",
386
+ .attrs = mdio_bus_statistics_attrs,
387
+};
388
+
389
+static const struct attribute_group *mdio_bus_groups[] = {
390
+ &mdio_bus_statistics_group,
391
+ NULL,
392
+};
393
+
244394 static struct class mdio_bus_class = {
245395 .name = "mdio_bus",
246396 .dev_release = mdiobus_release,
397
+ .dev_groups = mdio_bus_groups,
247398 };
248399
249
-#if IS_ENABLED(CONFIG_OF_MDIO)
250
-/* Helper function for of_mdio_find_bus */
251
-static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np)
400
+/**
401
+ * mdio_find_bus - Given the name of a mdiobus, find the mii_bus.
402
+ * @mdio_name: The name of a mdiobus.
403
+ *
404
+ * Returns a reference to the mii_bus, or NULL if none found. The
405
+ * embedded struct device will have its reference count incremented,
406
+ * and this must be put_deviced'ed once the bus is finished with.
407
+ */
408
+struct mii_bus *mdio_find_bus(const char *mdio_name)
252409 {
253
- return dev->of_node == mdio_bus_np;
410
+ struct device *d;
411
+
412
+ d = class_find_device_by_name(&mdio_bus_class, mdio_name);
413
+ return d ? to_mii_bus(d) : NULL;
254414 }
415
+EXPORT_SYMBOL(mdio_find_bus);
416
+
417
+#if IS_ENABLED(CONFIG_OF_MDIO)
255418 /**
256419 * of_mdio_find_bus - Given an mii_bus node, find the mii_bus.
257420 * @mdio_bus_np: Pointer to the mii_bus.
....@@ -272,9 +435,7 @@
272435 if (!mdio_bus_np)
273436 return NULL;
274437
275
- d = class_find_device(&mdio_bus_class, NULL, mdio_bus_np,
276
- of_mdio_bus_match);
277
-
438
+ d = class_find_device_by_of_node(&mdio_bus_class, mdio_bus_np);
278439 return d ? to_mii_bus(d) : NULL;
279440 }
280441 EXPORT_SYMBOL(of_mdio_find_bus);
....@@ -392,6 +553,7 @@
392553 }
393554
394555 mutex_init(&bus->mdio_lock);
556
+ mutex_init(&bus->shared_lock);
395557
396558 /* de-assert bus level PHY GPIO reset */
397559 gpiod = devm_gpiod_get_optional(&bus->dev, "reset", GPIOD_OUT_LOW);
....@@ -404,15 +566,20 @@
404566 bus->reset_gpiod = gpiod;
405567
406568 gpiod_set_value_cansleep(gpiod, 1);
407
- udelay(bus->reset_delay_us);
569
+ fsleep(bus->reset_delay_us);
408570 gpiod_set_value_cansleep(gpiod, 0);
571
+ if (bus->reset_post_delay_us > 0)
572
+ fsleep(bus->reset_post_delay_us);
409573 }
410574
411
- if (bus->reset)
412
- bus->reset(bus);
575
+ if (bus->reset) {
576
+ err = bus->reset(bus);
577
+ if (err)
578
+ goto error_reset_gpiod;
579
+ }
413580
414581 for (i = 0; i < PHY_MAX_ADDR; i++) {
415
- if ((bus->phy_mask & (1 << i)) == 0) {
582
+ if ((bus->phy_mask & BIT(i)) == 0) {
416583 struct phy_device *phydev;
417584
418585 phydev = mdiobus_scan(bus, i);
....@@ -438,7 +605,7 @@
438605 mdiodev->device_remove(mdiodev);
439606 mdiodev->device_free(mdiodev);
440607 }
441
-
608
+error_reset_gpiod:
442609 /* Put PHYs in RESET to save power */
443610 if (bus->reset_gpiod)
444611 gpiod_set_value_cansleep(bus->reset_gpiod, 1);
....@@ -462,8 +629,8 @@
462629 if (!mdiodev)
463630 continue;
464631
465
- if (mdiodev->reset)
466
- gpiod_put(mdiodev->reset);
632
+ if (mdiodev->reset_gpio)
633
+ gpiod_put(mdiodev->reset_gpio);
467634
468635 mdiodev->device_remove(mdiodev);
469636 mdiodev->device_free(mdiodev);
....@@ -514,10 +681,24 @@
514681 */
515682 struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
516683 {
517
- struct phy_device *phydev;
684
+ struct phy_device *phydev = ERR_PTR(-ENODEV);
518685 int err;
519686
520
- phydev = get_phy_device(bus, addr, false);
687
+ switch (bus->probe_capabilities) {
688
+ case MDIOBUS_NO_CAP:
689
+ case MDIOBUS_C22:
690
+ phydev = get_phy_device(bus, addr, false);
691
+ break;
692
+ case MDIOBUS_C45:
693
+ phydev = get_phy_device(bus, addr, true);
694
+ break;
695
+ case MDIOBUS_C22_C45:
696
+ phydev = get_phy_device(bus, addr, false);
697
+ if (IS_ERR(phydev))
698
+ phydev = get_phy_device(bus, addr, true);
699
+ break;
700
+ }
701
+
521702 if (IS_ERR(phydev))
522703 return phydev;
523704
....@@ -536,6 +717,26 @@
536717 return phydev;
537718 }
538719 EXPORT_SYMBOL(mdiobus_scan);
720
+
721
+static void mdiobus_stats_acct(struct mdio_bus_stats *stats, bool op, int ret)
722
+{
723
+ preempt_disable();
724
+ u64_stats_update_begin(&stats->syncp);
725
+
726
+ u64_stats_inc(&stats->transfers);
727
+ if (ret < 0) {
728
+ u64_stats_inc(&stats->errors);
729
+ goto out;
730
+ }
731
+
732
+ if (op)
733
+ u64_stats_inc(&stats->reads);
734
+ else
735
+ u64_stats_inc(&stats->writes);
736
+out:
737
+ u64_stats_update_end(&stats->syncp);
738
+ preempt_enable();
739
+}
539740
540741 /**
541742 * __mdiobus_read - Unlocked version of the mdiobus_read function
....@@ -556,6 +757,7 @@
556757 retval = bus->read(bus, addr, regnum);
557758
558759 trace_mdio_access(bus, 1, addr, regnum, retval, retval);
760
+ mdiobus_stats_acct(&bus->stats[addr], true, retval);
559761
560762 return retval;
561763 }
....@@ -581,10 +783,43 @@
581783 err = bus->write(bus, addr, regnum, val);
582784
583785 trace_mdio_access(bus, 0, addr, regnum, val, err);
786
+ mdiobus_stats_acct(&bus->stats[addr], false, err);
584787
585788 return err;
586789 }
587790 EXPORT_SYMBOL(__mdiobus_write);
791
+
792
+/**
793
+ * __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function
794
+ * @bus: the mii_bus struct
795
+ * @addr: the phy address
796
+ * @regnum: register number to modify
797
+ * @mask: bit mask of bits to clear
798
+ * @set: bit mask of bits to set
799
+ *
800
+ * Read, modify, and if any change, write the register value back to the
801
+ * device. Any error returns a negative number.
802
+ *
803
+ * NOTE: MUST NOT be called from interrupt context.
804
+ */
805
+int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
806
+ u16 mask, u16 set)
807
+{
808
+ int new, ret;
809
+
810
+ ret = __mdiobus_read(bus, addr, regnum);
811
+ if (ret < 0)
812
+ return ret;
813
+
814
+ new = (ret & ~mask) | set;
815
+ if (new == ret)
816
+ return 0;
817
+
818
+ ret = __mdiobus_write(bus, addr, regnum, new);
819
+
820
+ return ret < 0 ? ret : 1;
821
+}
822
+EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
588823
589824 /**
590825 * mdiobus_read_nested - Nested version of the mdiobus_read function
....@@ -602,8 +837,6 @@
602837 int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum)
603838 {
604839 int retval;
605
-
606
- BUG_ON(in_interrupt());
607840
608841 mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
609842 retval = __mdiobus_read(bus, addr, regnum);
....@@ -626,8 +859,6 @@
626859 int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
627860 {
628861 int retval;
629
-
630
- BUG_ON(in_interrupt());
631862
632863 mutex_lock(&bus->mdio_lock);
633864 retval = __mdiobus_read(bus, addr, regnum);
....@@ -655,8 +886,6 @@
655886 {
656887 int err;
657888
658
- BUG_ON(in_interrupt());
659
-
660889 mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
661890 err = __mdiobus_write(bus, addr, regnum, val);
662891 mutex_unlock(&bus->mdio_lock);
....@@ -680,8 +909,6 @@
680909 {
681910 int err;
682911
683
- BUG_ON(in_interrupt());
684
-
685912 mutex_lock(&bus->mdio_lock);
686913 err = __mdiobus_write(bus, addr, regnum, val);
687914 mutex_unlock(&bus->mdio_lock);
....@@ -689,6 +916,27 @@
689916 return err;
690917 }
691918 EXPORT_SYMBOL(mdiobus_write);
919
+
920
+/**
921
+ * mdiobus_modify - Convenience function for modifying a given mdio device
922
+ * register
923
+ * @bus: the mii_bus struct
924
+ * @addr: the phy address
925
+ * @regnum: register number to write
926
+ * @mask: bit mask of bits to clear
927
+ * @set: bit mask of bits to set
928
+ */
929
+int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, u16 set)
930
+{
931
+ int err;
932
+
933
+ mutex_lock(&bus->mdio_lock);
934
+ err = __mdiobus_modify_changed(bus, addr, regnum, mask, set);
935
+ mutex_unlock(&bus->mdio_lock);
936
+
937
+ return err < 0 ? err : 0;
938
+}
939
+EXPORT_SYMBOL_GPL(mdiobus_modify);
692940
693941 /**
694942 * mdio_bus_match - determine if given MDIO driver supports the given
....@@ -726,8 +974,27 @@
726974 return 0;
727975 }
728976
977
+static struct attribute *mdio_bus_device_statistics_attrs[] = {
978
+ &dev_attr_mdio_bus_device_transfers.attr.attr,
979
+ &dev_attr_mdio_bus_device_errors.attr.attr,
980
+ &dev_attr_mdio_bus_device_writes.attr.attr,
981
+ &dev_attr_mdio_bus_device_reads.attr.attr,
982
+ NULL,
983
+};
984
+
985
+static const struct attribute_group mdio_bus_device_statistics_group = {
986
+ .name = "statistics",
987
+ .attrs = mdio_bus_device_statistics_attrs,
988
+};
989
+
990
+static const struct attribute_group *mdio_bus_dev_groups[] = {
991
+ &mdio_bus_device_statistics_group,
992
+ NULL,
993
+};
994
+
729995 struct bus_type mdio_bus_type = {
730996 .name = "mdio_bus",
997
+ .dev_groups = mdio_bus_dev_groups,
731998 .match = mdio_bus_match,
732999 .uevent = mdio_uevent,
7331000 };
....@@ -746,7 +1013,6 @@
7461013
7471014 return ret;
7481015 }
749
-EXPORT_SYMBOL_GPL(mdio_bus_init);
7501016
7511017 #if IS_ENABLED(CONFIG_PHYLIB)
7521018 void mdio_bus_exit(void)