]> code.ossystems Code Review - openembedded-core.git/blob
fae435e969d2e861ea4fd046dd0d80e5632675fa
[openembedded-core.git] /
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
5 Patch-mainline: 2.6.35
6 Git-commit: 8626d3b4328061f5b82b11ae1d6918a0c3602f42
7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
8
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.
13
14 [bwh: s/phy/mdio/ in module alias, kerneldoc for struct mdio_device_id]
15
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>
20 ---
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(-)
26
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)
33  {
34         struct phy_device *dev;
35 +
36         /* We allocate the device, and initialize the
37          * default values */
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);
42  
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));
53 +
54         return dev;
55  }
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))));
63  };
64  
65 +#define MDIO_MODULE_PREFIX     "mdio:"
66 +
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
77 +
78 +/**
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
82 + *     for this PHY type
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.
85 + */
86 +struct mdio_device_id {
87 +       __u32 phy_id;
88 +       __u32 phy_id_mask;
89 +};
90 +
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
96 @@ -24,6 +24,7 @@
97  #include <linux/mii.h>
98  #include <linux/timer.h>
99  #include <linux/workqueue.h>
100 +#include <linux/mod_devicetable.h>
101  
102  #include <asm/atomic.h>
103  
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,
109         return 1;
110  }
111  
112 +static int do_mdio_entry(const char *filename,
113 +                        struct mdio_device_id *id, char *alias)
114 +{
115 +       int i;
116 +
117 +       alias += sprintf(alias, MDIO_MODULE_PREFIX);
118 +
119 +       for (i = 0; i < 32; i++) {
120 +               if (!((id->phy_id_mask >> (31-i)) & 1))
121 +                       *(alias++) = '?';
122 +               else if ((id->phy_id >> (31-i)) & 1)
123 +                       *(alias++) = '1';
124 +               else
125 +                       *(alias++) = '0';
126 +       }
127 +
128 +       /* Terminate the string */
129 +       *alias = 0;
130 +
131 +       return 1;
132 +}
133 +
134  /* Ignore any prefix, eg. some architectures prepend _ */
135  static inline int sym_is(const char *symbol, const char *name)
136  {
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);
145         free(zeros);
146  }
147  
148 -- 
149 1.6.5
150