diff options
author | Vitaly Bordug <vitb@kernel.crashing.org> | 2007-08-10 17:05:16 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:53:50 -0400 |
commit | 7c32f470f4f6a0fdc6944cefcd22f288e59a0ae2 (patch) | |
tree | 747a4c855e6b6287421eb854496d23073315ba49 | |
parent | cdcc520d7b73445c3552a70786afed9a2b22c010 (diff) |
PHY fixed driver: rework release path and update phy_id notation
device_bind_driver() error code returning has been fixed. release()
function has been written, so that to free resources in correct way; the
release path is now clean.
Before the rework, it used to cause
Device 'fixed@100:1' does not have a release() function, it is broken
and must be fixed.
BUG: at drivers/base/core.c:104 device_release()
Call Trace:
[<ffffffff802ec380>] kobject_cleanup+0x53/0x7e
[<ffffffff802ec3ab>] kobject_release+0x0/0x9
[<ffffffff802ecf3f>] kref_put+0x74/0x81
[<ffffffff8035493b>] fixed_mdio_register_device+0x230/0x265
[<ffffffff80564d31>] fixed_init+0x1f/0x35
[<ffffffff802071a4>] init+0x147/0x2fb
[<ffffffff80223b6e>] schedule_tail+0x36/0x92
[<ffffffff8020a678>] child_rip+0xa/0x12
[<ffffffff80311714>] acpi_ds_init_one_object+0x0/0x83
[<ffffffff8020705d>] init+0x0/0x2fb
[<ffffffff8020a66e>] child_rip+0x0/0x12
Also changed the notation of the fixed phy definition on
mdio bus to the form of <speed>+<duplex> to make it able to be used by
gianfar and ucc_geth that define phy_id strictly as "%d:%d" and cleaned up
the whitespace issues.
Signed-off-by: Vitaly Bordug <vitb@kernel.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/phy/Kconfig | 14 | ||||
-rw-r--r-- | drivers/net/phy/fixed.c | 310 | ||||
-rw-r--r-- | include/linux/phy_fixed.h | 38 |
3 files changed, 207 insertions, 155 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index dd09011c7ee5..432c210513be 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig | |||
@@ -76,4 +76,18 @@ config FIXED_MII_100_FDX | |||
76 | bool "Emulation for 100M Fdx fixed PHY behavior" | 76 | bool "Emulation for 100M Fdx fixed PHY behavior" |
77 | depends on FIXED_PHY | 77 | depends on FIXED_PHY |
78 | 78 | ||
79 | config FIXED_MII_1000_FDX | ||
80 | bool "Emulation for 1000M Fdx fixed PHY behavior" | ||
81 | depends on FIXED_PHY | ||
82 | |||
83 | config FIXED_MII_AMNT | ||
84 | int "Number of emulated PHYs to allocate " | ||
85 | depends on FIXED_PHY | ||
86 | default "1" | ||
87 | ---help--- | ||
88 | Sometimes it is required to have several independent emulated | ||
89 | PHYs on the bus (in case of multi-eth but phy-less HW for instance). | ||
90 | This control will have specified number allocated for each fixed | ||
91 | PHY type enabled. | ||
92 | |||
79 | endif # PHYLIB | 93 | endif # PHYLIB |
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index bb966911a137..56191822fa26 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c | |||
@@ -30,53 +30,31 @@ | |||
30 | #include <linux/mii.h> | 30 | #include <linux/mii.h> |
31 | #include <linux/ethtool.h> | 31 | #include <linux/ethtool.h> |
32 | #include <linux/phy.h> | 32 | #include <linux/phy.h> |
33 | #include <linux/phy_fixed.h> | ||
33 | 34 | ||
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | 38 | ||
38 | #define MII_REGS_NUM 7 | 39 | /* we need to track the allocated pointers in order to free them on exit */ |
39 | 40 | static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT]; | |
40 | /* | ||
41 | The idea is to emulate normal phy behavior by responding with | ||
42 | pre-defined values to mii BMCR read, so that read_status hook could | ||
43 | take all the needed info. | ||
44 | */ | ||
45 | |||
46 | struct fixed_phy_status { | ||
47 | u8 link; | ||
48 | u16 speed; | ||
49 | u8 duplex; | ||
50 | }; | ||
51 | |||
52 | /*----------------------------------------------------------------------------- | ||
53 | * Private information hoder for mii_bus | ||
54 | *-----------------------------------------------------------------------------*/ | ||
55 | struct fixed_info { | ||
56 | u16 *regs; | ||
57 | u8 regs_num; | ||
58 | struct fixed_phy_status phy_status; | ||
59 | struct phy_device *phydev; /* pointer to the container */ | ||
60 | /* link & speed cb */ | ||
61 | int(*link_update)(struct net_device*, struct fixed_phy_status*); | ||
62 | |||
63 | }; | ||
64 | 41 | ||
65 | /*----------------------------------------------------------------------------- | 42 | /*----------------------------------------------------------------------------- |
66 | * If something weird is required to be done with link/speed, | 43 | * If something weird is required to be done with link/speed, |
67 | * network driver is able to assign a function to implement this. | 44 | * network driver is able to assign a function to implement this. |
68 | * May be useful for PHY's that need to be software-driven. | 45 | * May be useful for PHY's that need to be software-driven. |
69 | *-----------------------------------------------------------------------------*/ | 46 | *-----------------------------------------------------------------------------*/ |
70 | int fixed_mdio_set_link_update(struct phy_device* phydev, | 47 | int fixed_mdio_set_link_update(struct phy_device *phydev, |
71 | int(*link_update)(struct net_device*, struct fixed_phy_status*)) | 48 | int (*link_update) (struct net_device *, |
49 | struct fixed_phy_status *)) | ||
72 | { | 50 | { |
73 | struct fixed_info *fixed; | 51 | struct fixed_info *fixed; |
74 | 52 | ||
75 | if(link_update == NULL) | 53 | if (link_update == NULL) |
76 | return -EINVAL; | 54 | return -EINVAL; |
77 | 55 | ||
78 | if(phydev) { | 56 | if (phydev) { |
79 | if(phydev->bus) { | 57 | if (phydev->bus) { |
80 | fixed = phydev->bus->priv; | 58 | fixed = phydev->bus->priv; |
81 | fixed->link_update = link_update; | 59 | fixed->link_update = link_update; |
82 | return 0; | 60 | return 0; |
@@ -84,54 +62,64 @@ int fixed_mdio_set_link_update(struct phy_device* phydev, | |||
84 | } | 62 | } |
85 | return -EINVAL; | 63 | return -EINVAL; |
86 | } | 64 | } |
65 | |||
87 | EXPORT_SYMBOL(fixed_mdio_set_link_update); | 66 | EXPORT_SYMBOL(fixed_mdio_set_link_update); |
88 | 67 | ||
68 | struct fixed_info *fixed_mdio_get_phydev (int phydev_ind) | ||
69 | { | ||
70 | if (phydev_ind >= MAX_PHY_AMNT) | ||
71 | return NULL; | ||
72 | return fixed_phy_ptrs[phydev_ind]; | ||
73 | } | ||
74 | |||
75 | EXPORT_SYMBOL(fixed_mdio_get_phydev); | ||
76 | |||
89 | /*----------------------------------------------------------------------------- | 77 | /*----------------------------------------------------------------------------- |
90 | * This is used for updating internal mii regs from the status | 78 | * This is used for updating internal mii regs from the status |
91 | *-----------------------------------------------------------------------------*/ | 79 | *-----------------------------------------------------------------------------*/ |
92 | #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) | 80 | #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) |
93 | static int fixed_mdio_update_regs(struct fixed_info *fixed) | 81 | static int fixed_mdio_update_regs(struct fixed_info *fixed) |
94 | { | 82 | { |
95 | u16 *regs = fixed->regs; | 83 | u16 *regs = fixed->regs; |
96 | u16 bmsr = 0; | 84 | u16 bmsr = 0; |
97 | u16 bmcr = 0; | 85 | u16 bmcr = 0; |
98 | 86 | ||
99 | if(!regs) { | 87 | if (!regs) { |
100 | printk(KERN_ERR "%s: regs not set up", __FUNCTION__); | 88 | printk(KERN_ERR "%s: regs not set up", __FUNCTION__); |
101 | return -EINVAL; | 89 | return -EINVAL; |
102 | } | 90 | } |
103 | 91 | ||
104 | if(fixed->phy_status.link) | 92 | if (fixed->phy_status.link) |
105 | bmsr |= BMSR_LSTATUS; | 93 | bmsr |= BMSR_LSTATUS; |
106 | 94 | ||
107 | if(fixed->phy_status.duplex) { | 95 | if (fixed->phy_status.duplex) { |
108 | bmcr |= BMCR_FULLDPLX; | 96 | bmcr |= BMCR_FULLDPLX; |
109 | 97 | ||
110 | switch ( fixed->phy_status.speed ) { | 98 | switch (fixed->phy_status.speed) { |
111 | case 100: | 99 | case 100: |
112 | bmsr |= BMSR_100FULL; | 100 | bmsr |= BMSR_100FULL; |
113 | bmcr |= BMCR_SPEED100; | 101 | bmcr |= BMCR_SPEED100; |
114 | break; | 102 | break; |
115 | 103 | ||
116 | case 10: | 104 | case 10: |
117 | bmsr |= BMSR_10FULL; | 105 | bmsr |= BMSR_10FULL; |
118 | break; | 106 | break; |
119 | } | 107 | } |
120 | } else { | 108 | } else { |
121 | switch ( fixed->phy_status.speed ) { | 109 | switch (fixed->phy_status.speed) { |
122 | case 100: | 110 | case 100: |
123 | bmsr |= BMSR_100HALF; | 111 | bmsr |= BMSR_100HALF; |
124 | bmcr |= BMCR_SPEED100; | 112 | bmcr |= BMCR_SPEED100; |
125 | break; | 113 | break; |
126 | 114 | ||
127 | case 10: | 115 | case 10: |
128 | bmsr |= BMSR_100HALF; | 116 | bmsr |= BMSR_100HALF; |
129 | break; | 117 | break; |
130 | } | 118 | } |
131 | } | 119 | } |
132 | 120 | ||
133 | regs[MII_BMCR] = bmcr; | 121 | regs[MII_BMCR] = bmcr; |
134 | regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/ | 122 | regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */ |
135 | 123 | ||
136 | return 0; | 124 | return 0; |
137 | } | 125 | } |
@@ -141,29 +129,30 @@ static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location) | |||
141 | struct fixed_info *fixed = bus->priv; | 129 | struct fixed_info *fixed = bus->priv; |
142 | 130 | ||
143 | /* if user has registered link update callback, use it */ | 131 | /* if user has registered link update callback, use it */ |
144 | if(fixed->phydev) | 132 | if (fixed->phydev) |
145 | if(fixed->phydev->attached_dev) { | 133 | if (fixed->phydev->attached_dev) { |
146 | if(fixed->link_update) { | 134 | if (fixed->link_update) { |
147 | fixed->link_update(fixed->phydev->attached_dev, | 135 | fixed->link_update(fixed->phydev->attached_dev, |
148 | &fixed->phy_status); | 136 | &fixed->phy_status); |
149 | fixed_mdio_update_regs(fixed); | 137 | fixed_mdio_update_regs(fixed); |
150 | } | 138 | } |
151 | } | 139 | } |
152 | 140 | ||
153 | if ((unsigned int)location >= fixed->regs_num) | 141 | if ((unsigned int)location >= fixed->regs_num) |
154 | return -1; | 142 | return -1; |
155 | return fixed->regs[location]; | 143 | return fixed->regs[location]; |
156 | } | 144 | } |
157 | 145 | ||
158 | static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) | 146 | static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, |
147 | u16 val) | ||
159 | { | 148 | { |
160 | /* do nothing for now*/ | 149 | /* do nothing for now */ |
161 | return 0; | 150 | return 0; |
162 | } | 151 | } |
163 | 152 | ||
164 | static int fixed_mii_reset(struct mii_bus *bus) | 153 | static int fixed_mii_reset(struct mii_bus *bus) |
165 | { | 154 | { |
166 | /*nothing here - no way/need to reset it*/ | 155 | /*nothing here - no way/need to reset it */ |
167 | return 0; | 156 | return 0; |
168 | } | 157 | } |
169 | #endif | 158 | #endif |
@@ -171,8 +160,8 @@ static int fixed_mii_reset(struct mii_bus *bus) | |||
171 | static int fixed_config_aneg(struct phy_device *phydev) | 160 | static int fixed_config_aneg(struct phy_device *phydev) |
172 | { | 161 | { |
173 | /* :TODO:03/13/2006 09:45:37 PM:: | 162 | /* :TODO:03/13/2006 09:45:37 PM:: |
174 | The full autoneg funcionality can be emulated, | 163 | The full autoneg funcionality can be emulated, |
175 | but no need to have anything here for now | 164 | but no need to have anything here for now |
176 | */ | 165 | */ |
177 | return 0; | 166 | return 0; |
178 | } | 167 | } |
@@ -182,59 +171,79 @@ static int fixed_config_aneg(struct phy_device *phydev) | |||
182 | * match will never return true... | 171 | * match will never return true... |
183 | *-----------------------------------------------------------------------------*/ | 172 | *-----------------------------------------------------------------------------*/ |
184 | static struct phy_driver fixed_mdio_driver = { | 173 | static struct phy_driver fixed_mdio_driver = { |
185 | .name = "Fixed PHY", | 174 | .name = "Fixed PHY", |
186 | .features = PHY_BASIC_FEATURES, | 175 | #ifdef CONFIG_FIXED_MII_1000_FDX |
187 | .config_aneg = fixed_config_aneg, | 176 | .features = PHY_GBIT_FEATURES, |
188 | .read_status = genphy_read_status, | 177 | #else |
189 | .driver = { .owner = THIS_MODULE,}, | 178 | .features = PHY_BASIC_FEATURES, |
179 | #endif | ||
180 | .config_aneg = fixed_config_aneg, | ||
181 | .read_status = genphy_read_status, | ||
182 | .driver = { .owner = THIS_MODULE, }, | ||
190 | }; | 183 | }; |
191 | 184 | ||
185 | static void fixed_mdio_release(struct device *dev) | ||
186 | { | ||
187 | struct phy_device *phydev = container_of(dev, struct phy_device, dev); | ||
188 | struct mii_bus *bus = phydev->bus; | ||
189 | struct fixed_info *fixed = bus->priv; | ||
190 | |||
191 | kfree(phydev); | ||
192 | kfree(bus->dev); | ||
193 | kfree(bus); | ||
194 | kfree(fixed->regs); | ||
195 | kfree(fixed); | ||
196 | } | ||
197 | |||
192 | /*----------------------------------------------------------------------------- | 198 | /*----------------------------------------------------------------------------- |
193 | * This func is used to create all the necessary stuff, bind | 199 | * This func is used to create all the necessary stuff, bind |
194 | * the fixed phy driver and register all it on the mdio_bus_type. | 200 | * the fixed phy driver and register all it on the mdio_bus_type. |
195 | * speed is either 10 or 100, duplex is boolean. | 201 | * speed is either 10 or 100 or 1000, duplex is boolean. |
196 | * number is used to create multiple fixed PHYs, so that several devices can | 202 | * number is used to create multiple fixed PHYs, so that several devices can |
197 | * utilize them simultaneously. | 203 | * utilize them simultaneously. |
204 | * | ||
205 | * The device on mdio bus will look like [bus_id]:[phy_id], | ||
206 | * bus_id = number | ||
207 | * phy_id = speed+duplex. | ||
198 | *-----------------------------------------------------------------------------*/ | 208 | *-----------------------------------------------------------------------------*/ |
199 | #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) | 209 | #if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX) |
200 | static int fixed_mdio_register_device(int number, int speed, int duplex) | 210 | struct fixed_info *fixed_mdio_register_device( |
211 | int bus_id, int speed, int duplex, u8 phy_id) | ||
201 | { | 212 | { |
202 | struct mii_bus *new_bus; | 213 | struct mii_bus *new_bus; |
203 | struct fixed_info *fixed; | 214 | struct fixed_info *fixed; |
204 | struct phy_device *phydev; | 215 | struct phy_device *phydev; |
205 | int err = 0; | 216 | int err; |
206 | 217 | ||
207 | struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 218 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
208 | 219 | ||
209 | if (NULL == dev) | 220 | if (dev == NULL) |
210 | return -ENOMEM; | 221 | goto err_dev_alloc; |
211 | 222 | ||
212 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | 223 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); |
213 | 224 | ||
214 | if (NULL == new_bus) { | 225 | if (new_bus == NULL) |
215 | kfree(dev); | 226 | goto err_bus_alloc; |
216 | return -ENOMEM; | 227 | |
217 | } | ||
218 | fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); | 228 | fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL); |
219 | 229 | ||
220 | if (NULL == fixed) { | 230 | if (fixed == NULL) |
221 | kfree(dev); | 231 | goto err_fixed_alloc; |
222 | kfree(new_bus); | 232 | |
223 | return -ENOMEM; | 233 | fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL); |
224 | } | 234 | if (NULL == fixed->regs) |
235 | goto err_fixed_regs_alloc; | ||
225 | 236 | ||
226 | fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL); | ||
227 | fixed->regs_num = MII_REGS_NUM; | 237 | fixed->regs_num = MII_REGS_NUM; |
228 | fixed->phy_status.speed = speed; | 238 | fixed->phy_status.speed = speed; |
229 | fixed->phy_status.duplex = duplex; | 239 | fixed->phy_status.duplex = duplex; |
230 | fixed->phy_status.link = 1; | 240 | fixed->phy_status.link = 1; |
231 | 241 | ||
232 | new_bus->name = "Fixed MII Bus", | 242 | new_bus->name = "Fixed MII Bus"; |
233 | new_bus->read = &fixed_mii_read, | 243 | new_bus->read = &fixed_mii_read; |
234 | new_bus->write = &fixed_mii_write, | 244 | new_bus->write = &fixed_mii_write; |
235 | new_bus->reset = &fixed_mii_reset, | 245 | new_bus->reset = &fixed_mii_reset; |
236 | 246 | /*set up workspace */ | |
237 | /*set up workspace*/ | ||
238 | fixed_mdio_update_regs(fixed); | 247 | fixed_mdio_update_regs(fixed); |
239 | new_bus->priv = fixed; | 248 | new_bus->priv = fixed; |
240 | 249 | ||
@@ -243,119 +252,110 @@ static int fixed_mdio_register_device(int number, int speed, int duplex) | |||
243 | 252 | ||
244 | /* create phy_device and register it on the mdio bus */ | 253 | /* create phy_device and register it on the mdio bus */ |
245 | phydev = phy_device_create(new_bus, 0, 0); | 254 | phydev = phy_device_create(new_bus, 0, 0); |
255 | if (phydev == NULL) | ||
256 | goto err_phy_dev_create; | ||
246 | 257 | ||
247 | /* | 258 | /* |
248 | Put the phydev pointer into the fixed pack so that bus read/write code could | 259 | * Put the phydev pointer into the fixed pack so that bus read/write |
249 | be able to access for instance attached netdev. Well it doesn't have to do | 260 | * code could be able to access for instance attached netdev. Well it |
250 | so, only in case of utilizing user-specified link-update... | 261 | * doesn't have to do so, only in case of utilizing user-specified |
262 | * link-update... | ||
251 | */ | 263 | */ |
252 | fixed->phydev = phydev; | ||
253 | 264 | ||
254 | if(NULL == phydev) { | 265 | fixed->phydev = phydev; |
255 | err = -ENOMEM; | 266 | phydev->speed = speed; |
256 | goto device_create_fail; | 267 | phydev->duplex = duplex; |
257 | } | ||
258 | 268 | ||
259 | phydev->irq = PHY_IGNORE_INTERRUPT; | 269 | phydev->irq = PHY_IGNORE_INTERRUPT; |
260 | phydev->dev.bus = &mdio_bus_type; | 270 | phydev->dev.bus = &mdio_bus_type; |
261 | 271 | ||
262 | if(number) | 272 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, |
263 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, | 273 | PHY_ID_FMT, bus_id, phy_id); |
264 | "fixed_%d@%d:%d", number, speed, duplex); | ||
265 | else | ||
266 | snprintf(phydev->dev.bus_id, BUS_ID_SIZE, | ||
267 | "fixed@%d:%d", speed, duplex); | ||
268 | phydev->bus = new_bus; | ||
269 | 274 | ||
270 | err = device_register(&phydev->dev); | 275 | phydev->bus = new_bus; |
271 | if(err) { | ||
272 | printk(KERN_ERR "Phy %s failed to register\n", | ||
273 | phydev->dev.bus_id); | ||
274 | goto bus_register_fail; | ||
275 | } | ||
276 | 276 | ||
277 | /* | ||
278 | the mdio bus has phy_id match... In order not to do it | ||
279 | artificially, we are binding the driver here by hand; | ||
280 | it will be the same for all the fixed phys anyway. | ||
281 | */ | ||
282 | phydev->dev.driver = &fixed_mdio_driver.driver; | 277 | phydev->dev.driver = &fixed_mdio_driver.driver; |
283 | 278 | phydev->dev.release = fixed_mdio_release; | |
284 | err = phydev->dev.driver->probe(&phydev->dev); | 279 | err = phydev->dev.driver->probe(&phydev->dev); |
285 | if(err < 0) { | 280 | if (err < 0) { |
286 | printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id); | 281 | printk(KERN_ERR "Phy %s: problems with fixed driver\n", |
287 | goto probe_fail; | 282 | phydev->dev.bus_id); |
283 | goto err_out; | ||
288 | } | 284 | } |
285 | err = device_register(&phydev->dev); | ||
286 | if (err) { | ||
287 | printk(KERN_ERR "Phy %s failed to register\n", | ||
288 | phydev->dev.bus_id); | ||
289 | goto err_out; | ||
290 | } | ||
291 | //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX | ||
292 | return fixed; | ||
289 | 293 | ||
290 | err = device_bind_driver(&phydev->dev); | 294 | err_out: |
291 | if (err) | ||
292 | goto probe_fail; | ||
293 | |||
294 | return 0; | ||
295 | |||
296 | probe_fail: | ||
297 | device_unregister(&phydev->dev); | ||
298 | bus_register_fail: | ||
299 | kfree(phydev); | 295 | kfree(phydev); |
300 | device_create_fail: | 296 | err_phy_dev_create: |
301 | kfree(dev); | 297 | kfree(fixed->regs); |
302 | kfree(new_bus); | 298 | err_fixed_regs_alloc: |
303 | kfree(fixed); | 299 | kfree(fixed); |
300 | err_fixed_alloc: | ||
301 | kfree(new_bus); | ||
302 | err_bus_alloc: | ||
303 | kfree(dev); | ||
304 | err_dev_alloc: | ||
305 | |||
306 | return NULL; | ||
304 | 307 | ||
305 | return err; | ||
306 | } | 308 | } |
307 | #endif | 309 | #endif |
308 | 310 | ||
309 | |||
310 | MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); | 311 | MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); |
311 | MODULE_AUTHOR("Vitaly Bordug"); | 312 | MODULE_AUTHOR("Vitaly Bordug"); |
312 | MODULE_LICENSE("GPL"); | 313 | MODULE_LICENSE("GPL"); |
313 | 314 | ||
314 | static int __init fixed_init(void) | 315 | static int __init fixed_init(void) |
315 | { | 316 | { |
316 | #if 0 | 317 | int cnt = 0; |
317 | int ret; | 318 | int i; |
318 | int duplex = 0; | 319 | /* register on the bus... Not expected to be matched |
319 | #endif | 320 | * with anything there... |
320 | 321 | * | |
321 | /* register on the bus... Not expected to be matched with anything there... */ | 322 | */ |
322 | phy_driver_register(&fixed_mdio_driver); | 323 | phy_driver_register(&fixed_mdio_driver); |
323 | 324 | ||
324 | /* So let the fun begin... | 325 | /* We will create several mdio devices here, and will bound the upper |
325 | We will create several mdio devices here, and will bound the upper | 326 | * driver to them. |
326 | driver to them. | 327 | * |
327 | 328 | * Then the external software can lookup the phy bus by searching | |
328 | Then the external software can lookup the phy bus by searching | 329 | * for 0:101, to be connected to the virtual 100M Fdx phy. |
329 | fixed@speed:duplex, e.g. fixed@100:1, to be connected to the | 330 | * |
330 | virtual 100M Fdx phy. | 331 | * In case several virtual PHYs required, the bus_id will be in form |
331 | 332 | * [num]:[duplex]+[speed], which make it able even to define | |
332 | In case several virtual PHYs required, the bus_id will be in form | 333 | * driver-specific link control callback, if for instance PHY is |
333 | fixed_<num>@<speed>:<duplex>, which make it able even to define | 334 | * completely SW-driven. |
334 | driver-specific link control callback, if for instance PHY is completely | 335 | */ |
335 | SW-driven. | 336 | for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) { |
336 | 337 | #ifdef CONFIG_FIXED_MII_1000_FDX | |
337 | */ | 338 | fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i); |
338 | |||
339 | #ifdef CONFIG_FIXED_MII_DUPLEX | ||
340 | #if 0 | ||
341 | duplex = 1; | ||
342 | #endif | ||
343 | #endif | 339 | #endif |
344 | |||
345 | #ifdef CONFIG_FIXED_MII_100_FDX | 340 | #ifdef CONFIG_FIXED_MII_100_FDX |
346 | fixed_mdio_register_device(0, 100, 1); | 341 | fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i); |
347 | #endif | 342 | #endif |
348 | |||
349 | #ifdef CONFIG_FIXED_MII_10_FDX | 343 | #ifdef CONFIG_FIXED_MII_10_FDX |
350 | fixed_mdio_register_device(0, 10, 1); | 344 | fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i); |
351 | #endif | 345 | #endif |
346 | } | ||
347 | |||
352 | return 0; | 348 | return 0; |
353 | } | 349 | } |
354 | 350 | ||
355 | static void __exit fixed_exit(void) | 351 | static void __exit fixed_exit(void) |
356 | { | 352 | { |
353 | int i; | ||
354 | |||
357 | phy_driver_unregister(&fixed_mdio_driver); | 355 | phy_driver_unregister(&fixed_mdio_driver); |
358 | /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */ | 356 | for (i=0; i < MAX_PHY_AMNT; i++) |
357 | if ( fixed_phy_ptrs[i] ) | ||
358 | device_unregister(&fixed_phy_ptrs[i]->phydev->dev); | ||
359 | } | 359 | } |
360 | 360 | ||
361 | module_init(fixed_init); | 361 | module_init(fixed_init); |
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h new file mode 100644 index 000000000000..04ba70d49fb8 --- /dev/null +++ b/include/linux/phy_fixed.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef __PHY_FIXED_H | ||
2 | #define __PHY_FIXED_H | ||
3 | |||
4 | #define MII_REGS_NUM 29 | ||
5 | |||
6 | /* max number of virtual phy stuff */ | ||
7 | #define MAX_PHY_AMNT 10 | ||
8 | /* | ||
9 | The idea is to emulate normal phy behavior by responding with | ||
10 | pre-defined values to mii BMCR read, so that read_status hook could | ||
11 | take all the needed info. | ||
12 | */ | ||
13 | |||
14 | struct fixed_phy_status { | ||
15 | u8 link; | ||
16 | u16 speed; | ||
17 | u8 duplex; | ||
18 | }; | ||
19 | |||
20 | /*----------------------------------------------------------------------------- | ||
21 | * Private information hoder for mii_bus | ||
22 | *-----------------------------------------------------------------------------*/ | ||
23 | struct fixed_info { | ||
24 | u16 *regs; | ||
25 | u8 regs_num; | ||
26 | struct fixed_phy_status phy_status; | ||
27 | struct phy_device *phydev; /* pointer to the container */ | ||
28 | /* link & speed cb */ | ||
29 | int (*link_update) (struct net_device *, struct fixed_phy_status *); | ||
30 | |||
31 | }; | ||
32 | |||
33 | |||
34 | int fixed_mdio_set_link_update(struct phy_device *, | ||
35 | int (*link_update) (struct net_device *, struct fixed_phy_status *)); | ||
36 | struct fixed_info *fixed_mdio_get_phydev (int phydev_ind); | ||
37 | |||
38 | #endif /* __PHY_FIXED_H */ | ||