diff options
-rw-r--r-- | drivers/net/phy/phy_device.c | 12 | ||||
-rw-r--r-- | include/linux/mod_devicetable.h | 26 | ||||
-rw-r--r-- | include/linux/phy.h | 1 | ||||
-rw-r--r-- | scripts/mod/file2alias.c | 26 |
4 files changed, 65 insertions, 0 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index db1794546c5..1a99bb24410 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -149,6 +149,7 @@ EXPORT_SYMBOL(phy_scan_fixups); struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) { struct phy_device *dev; + /* We allocate the device, and initialize the * default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -179,6 +180,17 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) mutex_init(&dev->lock); INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); + /* Request the appropriate module unconditionally; don't + bother trying to do so only if it isn't already loaded, + because that gets complicated. A hotplug event would have + done an unconditional modprobe anyway. + We don't do normal hotplug because it won't work for MDIO + -- because it relies on the device staying around for long + enough for the driver to get loaded. With MDIO, the NIC + driver will get bored and give up as soon as it finds that + there's no driver _already_ loaded. */ + request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id)); + return dev; } EXPORT_SYMBOL(phy_device_create); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index f58e9d836f3..55f1f9c9506 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -474,4 +474,30 @@ struct platform_device_id { __attribute__((aligned(sizeof(kernel_ulong_t)))); }; +#define MDIO_MODULE_PREFIX "mdio:" + +#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" +#define MDIO_ID_ARGS(_id) \ + (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ + ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \ + ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \ + ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \ + ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \ + ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \ + ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \ + ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1 + +/** + * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus + * @phy_id: The result of + * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask + * for this PHY type + * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0 + * is used to terminate an array of struct mdio_device_id. + */ +struct mdio_device_id { + __u32 phy_id; + __u32 phy_id_mask; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/phy.h b/include/linux/phy.h index d9bce4b526b..987e111f7b1 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -24,6 +24,7 @@ #include <linux/mii.h> #include <linux/timer.h> #include <linux/workqueue.h> +#include <linux/mod_devicetable.h> #include <asm/atomic.h> diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 220213e603d..36a60a85317 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -796,6 +796,28 @@ static int do_platform_entry(const char *filename, return 1; } +static int do_mdio_entry(const char *filename, + struct mdio_device_id *id, char *alias) +{ + int i; + + alias += sprintf(alias, MDIO_MODULE_PREFIX); + + for (i = 0; i < 32; i++) { + if (!((id->phy_id_mask >> (31-i)) & 1)) + *(alias++) = '?'; + else if ((id->phy_id >> (31-i)) & 1) + *(alias++) = '1'; + else + *(alias++) = '0'; + } + + /* Terminate the string */ + *alias = 0; + + return 1; +} + /* Ignore any prefix, eg. some architectures prepend _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -943,6 +965,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct platform_device_id), "platform", do_platform_entry, mod); + else if (sym_is(symname, "__mod_mdio_device_table")) + do_table(symval, sym->st_size, + sizeof(struct mdio_device_id), "mdio", + do_mdio_entry, mod); free(zeros); } |