aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/phy/Kconfig14
-rw-r--r--drivers/net/phy/fixed.c310
2 files changed, 169 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
79config FIXED_MII_1000_FDX
80 bool "Emulation for 1000M Fdx fixed PHY behavior"
81 depends on FIXED_PHY
82
83config 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
79endif # PHYLIB 93endif # 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 40static 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
46struct fixed_phy_status {
47 u8 link;
48 u16 speed;
49 u8 duplex;
50};
51
52/*-----------------------------------------------------------------------------
53 * Private information hoder for mii_bus
54 *-----------------------------------------------------------------------------*/
55struct 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 *-----------------------------------------------------------------------------*/
70int fixed_mdio_set_link_update(struct phy_device* phydev, 47int 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
87EXPORT_SYMBOL(fixed_mdio_set_link_update); 66EXPORT_SYMBOL(fixed_mdio_set_link_update);
88 67
68struct 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
75EXPORT_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)
93static int fixed_mdio_update_regs(struct fixed_info *fixed) 81static 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
158static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) 146static 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
164static int fixed_mii_reset(struct mii_bus *bus) 153static 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)
171static int fixed_config_aneg(struct phy_device *phydev) 160static 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 *-----------------------------------------------------------------------------*/
184static struct phy_driver fixed_mdio_driver = { 173static 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
185static 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)
200static int fixed_mdio_register_device(int number, int speed, int duplex) 210struct 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); 294err_out:
291 if (err)
292 goto probe_fail;
293
294 return 0;
295
296probe_fail:
297 device_unregister(&phydev->dev);
298bus_register_fail:
299 kfree(phydev); 295 kfree(phydev);
300device_create_fail: 296err_phy_dev_create:
301 kfree(dev); 297 kfree(fixed->regs);
302 kfree(new_bus); 298err_fixed_regs_alloc:
303 kfree(fixed); 299 kfree(fixed);
300err_fixed_alloc:
301 kfree(new_bus);
302err_bus_alloc:
303 kfree(dev);
304err_dev_alloc:
305
306 return NULL;
304 307
305 return err;
306} 308}
307#endif 309#endif
308 310
309
310MODULE_DESCRIPTION("Fixed PHY device & driver for PAL"); 311MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
311MODULE_AUTHOR("Vitaly Bordug"); 312MODULE_AUTHOR("Vitaly Bordug");
312MODULE_LICENSE("GPL"); 313MODULE_LICENSE("GPL");
313 314
314static int __init fixed_init(void) 315static 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
355static void __exit fixed_exit(void) 351static 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
361module_init(fixed_init); 361module_init(fixed_init);