1 From 8626d3b4328061f5b82b11ae1d6918a0c3602f42 Mon Sep 17 00:00:00 2001
2 From: David Woodhouse <dwmw2@infradead.org>
3 Date: Fri, 2 Apr 2010 01:05:27 +0000
4 Subject: [PATCH] phylib: Support phy module autoloading
6 Git-commit: 8626d3b4328061f5b82b11ae1d6918a0c3602f42
7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
9 We don't use the normal hotplug mechanism because it doesn't work. It will
10 load the module some time after the device appears, but that's not good
11 enough for us -- we need the driver loaded _immediately_ because otherwise
12 the NIC driver may just abort and then the phy 'device' goes away.
14 [bwh: s/phy/mdio/ in module alias, kerneldoc for struct mdio_device_id]
16 Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
17 Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
18 Acked-by: Andy Fleming <afleming@freescale.com>
19 Signed-off-by: David S. Miller <davem@davemloft.net>
21 drivers/net/phy/phy_device.c | 12 ++++++++++++
22 include/linux/mod_devicetable.h | 26 ++++++++++++++++++++++++++
23 include/linux/phy.h | 1 +
24 scripts/mod/file2alias.c | 26 ++++++++++++++++++++++++++
25 4 files changed, 65 insertions(+), 0 deletions(-)
27 diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
28 index db17945..1a99bb2 100644
29 --- a/drivers/net/phy/phy_device.c
30 +++ b/drivers/net/phy/phy_device.c
31 @@ -149,6 +149,7 @@ EXPORT_SYMBOL(phy_scan_fixups);
32 struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
34 struct phy_device *dev;
36 /* We allocate the device, and initialize the
38 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
39 @@ -179,6 +180,17 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
40 mutex_init(&dev->lock);
41 INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
43 + /* Request the appropriate module unconditionally; don't
44 + bother trying to do so only if it isn't already loaded,
45 + because that gets complicated. A hotplug event would have
46 + done an unconditional modprobe anyway.
47 + We don't do normal hotplug because it won't work for MDIO
48 + -- because it relies on the device staying around for long
49 + enough for the driver to get loaded. With MDIO, the NIC
50 + driver will get bored and give up as soon as it finds that
51 + there's no driver _already_ loaded. */
52 + request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
56 EXPORT_SYMBOL(phy_device_create);
57 diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
58 index f58e9d8..55f1f9c 100644
59 --- a/include/linux/mod_devicetable.h
60 +++ b/include/linux/mod_devicetable.h
61 @@ -474,4 +474,30 @@ struct platform_device_id {
62 __attribute__((aligned(sizeof(kernel_ulong_t))));
65 +#define MDIO_MODULE_PREFIX "mdio:"
67 +#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"
68 +#define MDIO_ID_ARGS(_id) \
69 + (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \
70 + ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
71 + ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
72 + ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
73 + ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \
74 + ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \
75 + ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \
76 + ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1
79 + * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus
80 + * @phy_id: The result of
81 + * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask
83 + * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0
84 + * is used to terminate an array of struct mdio_device_id.
86 +struct mdio_device_id {
91 #endif /* LINUX_MOD_DEVICETABLE_H */
92 diff --git a/include/linux/phy.h b/include/linux/phy.h
93 index d9bce4b..987e111 100644
94 --- a/include/linux/phy.h
95 +++ b/include/linux/phy.h
97 #include <linux/mii.h>
98 #include <linux/timer.h>
99 #include <linux/workqueue.h>
100 +#include <linux/mod_devicetable.h>
102 #include <asm/atomic.h>
104 diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
105 index 220213e..36a60a8 100644
106 --- a/scripts/mod/file2alias.c
107 +++ b/scripts/mod/file2alias.c
108 @@ -796,6 +796,28 @@ static int do_platform_entry(const char *filename,
112 +static int do_mdio_entry(const char *filename,
113 + struct mdio_device_id *id, char *alias)
117 + alias += sprintf(alias, MDIO_MODULE_PREFIX);
119 + for (i = 0; i < 32; i++) {
120 + if (!((id->phy_id_mask >> (31-i)) & 1))
122 + else if ((id->phy_id >> (31-i)) & 1)
128 + /* Terminate the string */
134 /* Ignore any prefix, eg. some architectures prepend _ */
135 static inline int sym_is(const char *symbol, const char *name)
137 @@ -943,6 +965,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
138 do_table(symval, sym->st_size,
139 sizeof(struct platform_device_id), "platform",
140 do_platform_entry, mod);
141 + else if (sym_is(symname, "__mod_mdio_device_table"))
142 + do_table(symval, sym->st_size,
143 + sizeof(struct mdio_device_id), "mdio",
144 + do_mdio_entry, mod);