Skip to content

Commit 648ea01

Browse files
ffainellidavem330
authored andcommitted
net: phy: Allow pre-declaration of MDIO devices
Allow board support code to collect pre-declarations for MDIO devices by registering them with mdiobus_register_board_info(). SPI and I2C buses have a similar feature, we were missing this for MDIO devices, but this is particularly useful for e.g: MDIO-connected switches which need to provide their port layout (often board-specific) to a MDIO Ethernet switch driver. Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 71e0bbd commit 648ea01

File tree

8 files changed

+145
-1
lines changed

8 files changed

+145
-1
lines changed

drivers/net/phy/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Makefile for Linux PHY drivers and MDIO bus drivers
22

3-
libphy-y := phy.o phy_device.o mdio_bus.o mdio_device.o
3+
libphy-y := phy.o phy_device.o mdio_bus.o mdio_device.o \
4+
mdio-boardinfo.o
45
libphy-$(CONFIG_SWPHY) += swphy.o
56
libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_led_triggers.o
67

drivers/net/phy/mdio-boardinfo.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* mdio-boardinfo - Collect pre-declarations for MDIO devices
3+
*
4+
* This program is free software; you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License as published by the
6+
* Free Software Foundation; either version 2 of the License, or (at your
7+
* option) any later version.
8+
*/
9+
10+
#include <linux/kernel.h>
11+
#include <linux/slab.h>
12+
#include <linux/export.h>
13+
#include <linux/mutex.h>
14+
#include <linux/list.h>
15+
16+
#include "mdio-boardinfo.h"
17+
18+
static LIST_HEAD(mdio_board_list);
19+
static DEFINE_MUTEX(mdio_board_lock);
20+
21+
/**
22+
* mdiobus_setup_mdiodev_from_board_info - create and setup MDIO devices
23+
* from pre-collected board specific MDIO information
24+
* @mdiodev: MDIO device pointer
25+
* Context: can sleep
26+
*/
27+
void mdiobus_setup_mdiodev_from_board_info(struct mii_bus *bus)
28+
{
29+
struct mdio_board_entry *be;
30+
struct mdio_device *mdiodev;
31+
struct mdio_board_info *bi;
32+
int ret;
33+
34+
mutex_lock(&mdio_board_lock);
35+
list_for_each_entry(be, &mdio_board_list, list) {
36+
bi = &be->board_info;
37+
38+
if (strcmp(bus->id, bi->bus_id))
39+
continue;
40+
41+
mdiodev = mdio_device_create(bus, bi->mdio_addr);
42+
if (IS_ERR(mdiodev))
43+
continue;
44+
45+
strncpy(mdiodev->modalias, bi->modalias,
46+
sizeof(mdiodev->modalias));
47+
mdiodev->bus_match = mdio_device_bus_match;
48+
mdiodev->dev.platform_data = (void *)bi->platform_data;
49+
50+
ret = mdio_device_register(mdiodev);
51+
if (ret) {
52+
mdio_device_free(mdiodev);
53+
continue;
54+
}
55+
}
56+
mutex_unlock(&mdio_board_lock);
57+
}
58+
59+
/**
60+
* mdio_register_board_info - register MDIO devices for a given board
61+
* @info: array of devices descriptors
62+
* @n: number of descriptors provided
63+
* Context: can sleep
64+
*
65+
* The board info passed can be marked with __initdata but be pointers
66+
* such as platform_data etc. are copied as-is
67+
*/
68+
int mdiobus_register_board_info(const struct mdio_board_info *info,
69+
unsigned int n)
70+
{
71+
struct mdio_board_entry *be;
72+
unsigned int i;
73+
74+
be = kcalloc(n, sizeof(*be), GFP_KERNEL);
75+
if (!be)
76+
return -ENOMEM;
77+
78+
for (i = 0; i < n; i++, be++, info++) {
79+
memcpy(&be->board_info, info, sizeof(*info));
80+
mutex_lock(&mdio_board_lock);
81+
list_add_tail(&be->list, &mdio_board_list);
82+
mutex_unlock(&mdio_board_lock);
83+
}
84+
85+
return 0;
86+
}

drivers/net/phy/mdio-boardinfo.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* mdio-boardinfo.h - board info interface internal to the mdio_bus
3+
* component
4+
*/
5+
6+
#ifndef __MDIO_BOARD_INFO_H
7+
#define __MDIO_BOARD_INFO_H
8+
9+
#include <linux/phy.h>
10+
#include <linux/mutex.h>
11+
12+
struct mdio_board_entry {
13+
struct list_head list;
14+
struct mdio_board_info board_info;
15+
};
16+
17+
void mdiobus_setup_mdiodev_from_board_info(struct mii_bus *bus);
18+
19+
#endif /* __MDIO_BOARD_INFO_H */

drivers/net/phy/mdio_bus.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#define CREATE_TRACE_POINTS
4242
#include <trace/events/mdio.h>
4343

44+
#include "mdio-boardinfo.h"
45+
4446
int mdiobus_register_device(struct mdio_device *mdiodev)
4547
{
4648
if (mdiodev->bus->mdio_map[mdiodev->addr])
@@ -343,6 +345,8 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
343345
}
344346
}
345347

348+
mdiobus_setup_mdiodev_from_board_info(bus);
349+
346350
bus->state = MDIOBUS_REGISTERED;
347351
pr_info("%s: probed\n", bus->name);
348352
return 0;

drivers/net/phy/mdio_device.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ static void mdio_device_release(struct device *dev)
3434
kfree(to_mdio_device(dev));
3535
}
3636

37+
int mdio_device_bus_match(struct device *dev, struct device_driver *drv)
38+
{
39+
struct mdio_device *mdiodev = to_mdio_device(dev);
40+
struct mdio_driver *mdiodrv = to_mdio_driver(drv);
41+
42+
if (mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY)
43+
return 0;
44+
45+
return strcmp(mdiodev->modalias, drv->name) == 0;
46+
}
47+
3748
struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
3849
{
3950
struct mdio_device *mdiodev;

include/linux/mdio.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define __LINUX_MDIO_H__
1111

1212
#include <uapi/linux/mdio.h>
13+
#include <linux/mod_devicetable.h>
1314

1415
struct mii_bus;
1516

@@ -29,6 +30,7 @@ struct mdio_device {
2930

3031
const struct dev_pm_ops *pm_ops;
3132
struct mii_bus *bus;
33+
char modalias[MDIO_NAME_SIZE];
3234

3335
int (*bus_match)(struct device *dev, struct device_driver *drv);
3436
void (*device_free)(struct mdio_device *mdiodev);
@@ -71,6 +73,7 @@ int mdio_device_register(struct mdio_device *mdiodev);
7173
void mdio_device_remove(struct mdio_device *mdiodev);
7274
int mdio_driver_register(struct mdio_driver *drv);
7375
void mdio_driver_unregister(struct mdio_driver *drv);
76+
int mdio_device_bus_match(struct device *dev, struct device_driver *drv);
7477

7578
static inline bool mdio_phy_id_is_c45(int phy_id)
7679
{

include/linux/mod_devicetable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ struct platform_device_id {
501501
kernel_ulong_t driver_data;
502502
};
503503

504+
#define MDIO_NAME_SIZE 32
504505
#define MDIO_MODULE_PREFIX "mdio:"
505506

506507
#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"

include/linux/phy.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,25 @@ void mdio_bus_exit(void);
886886

887887
extern struct bus_type mdio_bus_type;
888888

889+
struct mdio_board_info {
890+
const char *bus_id;
891+
char modalias[MDIO_NAME_SIZE];
892+
int mdio_addr;
893+
const void *platform_data;
894+
};
895+
896+
#if IS_ENABLED(CONFIG_PHYLIB)
897+
int mdiobus_register_board_info(const struct mdio_board_info *info,
898+
unsigned int n);
899+
#else
900+
static inline int mdiobus_register_board_info(const struct mdio_board_info *i,
901+
unsigned int n)
902+
{
903+
return 0;
904+
}
905+
#endif
906+
907+
889908
/**
890909
* module_phy_driver() - Helper macro for registering PHY drivers
891910
* @__phy_drivers: array of PHY drivers to register

0 commit comments

Comments
 (0)