target/linux: refresh 2.6.32 patches
[openwrt.git] / target / linux / rdc / patches-2.6.32 / 014-r6040_phylib_support.patch
1 --- a/drivers/net/r6040.c
2 +++ b/drivers/net/r6040.c
3 @@ -45,6 +45,7 @@
4  #include <linux/io.h>
5  #include <linux/irq.h>
6  #include <linux/uaccess.h>
7 +#include <linux/phy.h>
8  
9  #include <asm/processor.h>
10  
11 @@ -180,7 +181,6 @@ struct r6040_descriptor {
12  
13  struct r6040_private {
14         spinlock_t lock;                /* driver lock */
15 -       struct timer_list timer;
16         struct pci_dev *pdev;
17         struct r6040_descriptor *rx_insert_ptr;
18         struct r6040_descriptor *rx_remove_ptr;
19 @@ -190,13 +190,15 @@ struct r6040_private {
20         struct r6040_descriptor *tx_ring;
21         dma_addr_t rx_ring_dma;
22         dma_addr_t tx_ring_dma;
23 -       u16     tx_free_desc, phy_addr, phy_mode;
24 +       u16     tx_free_desc, phy_addr;
25         u16     mcr0, mcr1;
26 -       u16     switch_sig;
27         struct net_device *dev;
28 -       struct mii_if_info mii_if;
29 +       struct mii_bus *mii_bus;
30         struct napi_struct napi;
31         void __iomem *base;
32 +       struct phy_device *phydev;
33 +       int old_link;
34 +       int old_duplex;
35  };
36  
37  static char version[] __devinitdata = KERN_INFO DRV_NAME
38 @@ -239,20 +241,29 @@ static void r6040_phy_write(void __iomem
39         }
40  }
41  
42 -static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg)
43 +static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
44  {
45 +       struct net_device *dev = bus->priv;
46         struct r6040_private *lp = netdev_priv(dev);
47         void __iomem *ioaddr = lp->base;
48  
49 -       return (r6040_phy_read(ioaddr, lp->phy_addr, reg));
50 +       return r6040_phy_read(ioaddr, phy_addr, reg);
51  }
52  
53 -static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val)
54 +static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr, int reg, u16 value)
55  {
56 +       struct net_device *dev = bus->priv;
57         struct r6040_private *lp = netdev_priv(dev);
58         void __iomem *ioaddr = lp->base;
59  
60 -       r6040_phy_write(ioaddr, lp->phy_addr, reg, val);
61 +       r6040_phy_write(ioaddr, phy_addr, reg, value);
62 +
63 +       return 0;
64 +}
65 +
66 +static int r6040_mdiobus_reset(struct mii_bus *bus)
67 +{
68 +       return 0;
69  }
70  
71  static void r6040_free_txbufs(struct net_device *dev)
72 @@ -409,10 +420,9 @@ static void r6040_tx_timeout(struct net_
73         void __iomem *ioaddr = priv->base;
74  
75         printk(KERN_WARNING "%s: transmit timed out, int enable %4.4x "
76 -               "status %4.4x, PHY status %4.4x\n",
77 +               "status %4.4x\n",
78                 dev->name, ioread16(ioaddr + MIER),
79 -               ioread16(ioaddr + MISR),
80 -               r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
81 +               ioread16(ioaddr + MISR));
82  
83         dev->stats.tx_errors++;
84  
85 @@ -464,9 +474,6 @@ static int r6040_close(struct net_device
86         struct r6040_private *lp = netdev_priv(dev);
87         struct pci_dev *pdev = lp->pdev;
88  
89 -       /* deleted timer */
90 -       del_timer_sync(&lp->timer);
91 -
92         spin_lock_irq(&lp->lock);
93         napi_disable(&lp->napi);
94         netif_stop_queue(dev);
95 @@ -496,64 +503,14 @@ static int r6040_close(struct net_device
96         return 0;
97  }
98  
99 -/* Status of PHY CHIP */
100 -static int r6040_phy_mode_chk(struct net_device *dev)
101 -{
102 -       struct r6040_private *lp = netdev_priv(dev);
103 -       void __iomem *ioaddr = lp->base;
104 -       int phy_dat;
105 -
106 -       /* PHY Link Status Check */
107 -       phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
108 -       if (!(phy_dat & 0x4))
109 -               phy_dat = 0x8000;       /* Link Failed, full duplex */
110 -
111 -       /* PHY Chip Auto-Negotiation Status */
112 -       phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
113 -       if (phy_dat & 0x0020) {
114 -               /* Auto Negotiation Mode */
115 -               phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
116 -               phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
117 -               if (phy_dat & 0x140)
118 -                       /* Force full duplex */
119 -                       phy_dat = 0x8000;
120 -               else
121 -                       phy_dat = 0;
122 -       } else {
123 -               /* Force Mode */
124 -               phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
125 -               if (phy_dat & 0x100)
126 -                       phy_dat = 0x8000;
127 -               else
128 -                       phy_dat = 0x0000;
129 -       }
130 -
131 -       return phy_dat;
132 -};
133 -
134 -static void r6040_set_carrier(struct mii_if_info *mii)
135 -{
136 -       if (r6040_phy_mode_chk(mii->dev)) {
137 -               /* autoneg is off: Link is always assumed to be up */
138 -               if (!netif_carrier_ok(mii->dev))
139 -                       netif_carrier_on(mii->dev);
140 -       } else
141 -               r6040_phy_mode_chk(mii->dev);
142 -}
143 -
144  static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
145  {
146         struct r6040_private *lp = netdev_priv(dev);
147 -       struct mii_ioctl_data *data = if_mii(rq);
148 -       int rc;
149  
150 -       if (!netif_running(dev))
151 +       if (!lp->phydev)
152                 return -EINVAL;
153 -       spin_lock_irq(&lp->lock);
154 -       rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
155 -       spin_unlock_irq(&lp->lock);
156 -       r6040_set_carrier(&lp->mii_if);
157 -       return rc;
158 +
159 +       return phy_mii_ioctl(lp->phydev, if_mii(rq), cmd);
160  }
161  
162  static int r6040_rx(struct net_device *dev, int limit)
163 @@ -752,26 +709,6 @@ static int r6040_up(struct net_device *d
164         if (ret)
165                 return ret;
166  
167 -       /* Read the PHY ID */
168 -       lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
169 -
170 -       if (lp->switch_sig  == ICPLUS_PHY_ID) {
171 -               r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
172 -               lp->phy_mode = 0x8000;
173 -       } else {
174 -               /* PHY Mode Check */
175 -               r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
176 -               r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
177 -
178 -               if (PHY_MODE == 0x3100)
179 -                       lp->phy_mode = r6040_phy_mode_chk(dev);
180 -               else
181 -                       lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
182 -       }
183 -
184 -       /* Set duplex mode */
185 -       lp->mcr0 |= lp->phy_mode;
186 -
187         /* improve performance (by RDC guys) */
188         r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
189         r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
190 @@ -784,35 +721,6 @@ static int r6040_up(struct net_device *d
191         return 0;
192  }
193  
194 -/*
195 -  A periodic timer routine
196 -       Polling PHY Chip Link Status
197 -*/
198 -static void r6040_timer(unsigned long data)
199 -{
200 -       struct net_device *dev = (struct net_device *)data;
201 -       struct r6040_private *lp = netdev_priv(dev);
202 -       void __iomem *ioaddr = lp->base;
203 -       u16 phy_mode;
204 -
205 -       /* Polling PHY Chip Status */
206 -       if (PHY_MODE == 0x3100)
207 -               phy_mode = r6040_phy_mode_chk(dev);
208 -       else
209 -               phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
210 -
211 -       if (phy_mode != lp->phy_mode) {
212 -               lp->phy_mode = phy_mode;
213 -               lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
214 -               iowrite16(lp->mcr0, ioaddr);
215 -       }
216 -
217 -       /* Timer active again */
218 -       mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
219 -
220 -       /* Check media */
221 -       mii_check_media(&lp->mii_if, 1, 1);
222 -}
223  
224  /* Read/set MAC address routines */
225  static void r6040_mac_address(struct net_device *dev)
226 @@ -874,10 +782,6 @@ static int r6040_open(struct net_device 
227         napi_enable(&lp->napi);
228         netif_start_queue(dev);
229  
230 -       /* set and active a timer process */
231 -       setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
232 -       if (lp->switch_sig != ICPLUS_PHY_ID)
233 -               mod_timer(&lp->timer, jiffies + HZ);
234         return 0;
235  }
236  
237 @@ -1020,40 +924,22 @@ static void netdev_get_drvinfo(struct ne
238  static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
239  {
240         struct r6040_private *rp = netdev_priv(dev);
241 -       int rc;
242 -
243 -       spin_lock_irq(&rp->lock);
244 -       rc = mii_ethtool_gset(&rp->mii_if, cmd);
245 -       spin_unlock_irq(&rp->lock);
246  
247 -       return rc;
248 +       return  phy_ethtool_gset(rp->phydev, cmd);
249  }
250  
251  static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
252  {
253         struct r6040_private *rp = netdev_priv(dev);
254 -       int rc;
255 -
256 -       spin_lock_irq(&rp->lock);
257 -       rc = mii_ethtool_sset(&rp->mii_if, cmd);
258 -       spin_unlock_irq(&rp->lock);
259 -       r6040_set_carrier(&rp->mii_if);
260 -
261 -       return rc;
262 -}
263 -
264 -static u32 netdev_get_link(struct net_device *dev)
265 -{
266 -       struct r6040_private *rp = netdev_priv(dev);
267  
268 -       return mii_link_ok(&rp->mii_if);
269 +       return phy_ethtool_sset(rp->phydev, cmd);
270  }
271  
272  static const struct ethtool_ops netdev_ethtool_ops = {
273         .get_drvinfo            = netdev_get_drvinfo,
274         .get_settings           = netdev_get_settings,
275         .set_settings           = netdev_set_settings,
276 -       .get_link               = netdev_get_link,
277 +       .get_link               = ethtool_op_get_link,
278  };
279  
280  static const struct net_device_ops r6040_netdev_ops = {
281 @@ -1072,6 +958,86 @@ static const struct net_device_ops r6040
282  #endif
283  };
284  
285 +static void r6040_adjust_link(struct net_device *dev)
286 +{
287 +       struct r6040_private *lp = netdev_priv(dev);
288 +       struct phy_device *phydev = lp->phydev;
289 +       int status_changed = 0;
290 +       void __iomem *ioaddr = lp->base;
291 +
292 +       BUG_ON (!phydev);
293 +
294 +       if (lp->old_link != phydev->link) {
295 +               status_changed = 1;
296 +               lp->old_link = phydev->link;
297 +       }
298 +
299 +       /* reflect duplex change */
300 +       if (phydev->link && (lp->old_duplex != phydev->duplex)) {
301 +               lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
302 +               iowrite16(lp->mcr0, ioaddr);
303 +
304 +               status_changed = 1;
305 +               lp->old_duplex = phydev->duplex;
306 +       }
307 +
308 +       if (status_changed) {
309 +               pr_info("%s: link %s", dev->name, phydev->link ?
310 +                       "UP" : "DOWN");
311 +               if (phydev->link)
312 +                       pr_cont(" - %d/%s", phydev->speed,
313 +                               DUPLEX_FULL == phydev->duplex ? "full" : "half");
314 +               pr_cont("\n");
315 +       }
316 +}
317 +
318 +static int r6040_mii_probe(struct net_device *dev)
319 +{
320 +       struct r6040_private *lp = netdev_priv(dev);
321 +       struct phy_device *phydev = NULL;
322 +       int phy_addr;
323 +
324 +       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
325 +               if (lp->mii_bus->phy_map[phy_addr]) {
326 +                       phydev = lp->mii_bus->phy_map[phy_addr];
327 +                       break;
328 +               }
329 +       }
330 +
331 +       if (!phydev) {
332 +               printk(KERN_ERR DRV_NAME "no PHY found\n");
333 +               return -ENODEV;
334 +       }
335 +
336 +       phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
337 +                               0, PHY_INTERFACE_MODE_MII);
338 +
339 +       if (IS_ERR(phydev)) {
340 +               printk(KERN_ERR DRV_NAME "could not attach to PHY\n");
341 +               return PTR_ERR(phydev);
342 +       }
343 +
344 +       /* mask with MAC supported features */
345 +       phydev->supported &= (SUPPORTED_10baseT_Half
346 +                               | SUPPORTED_10baseT_Full
347 +                               | SUPPORTED_100baseT_Half
348 +                               | SUPPORTED_100baseT_Full
349 +                               | SUPPORTED_Autoneg
350 +                               | SUPPORTED_MII
351 +                               | SUPPORTED_TP);
352 +
353 +       phydev->advertising = phydev->supported;
354 +       lp->phydev = phydev;
355 +       lp->old_link = 0;
356 +       lp->old_duplex = -1;
357 +
358 +        printk(KERN_INFO "%s: attached PHY driver [%s] "
359 +               "(mii_bus:phy_addr=%s)\n", dev->name,
360 +               phydev->drv->name, dev_name(&phydev->dev));
361 +
362 +       return 0;
363 +}
364 +
365  static int __devinit r6040_init_one(struct pci_dev *pdev,
366                                          const struct pci_device_id *ent)
367  {
368 @@ -1082,6 +1048,7 @@ static int __devinit r6040_init_one(stru
369         static int card_idx = -1;
370         int bar = 0;
371         u16 *adrp;
372 +       int i;
373  
374         printk("%s\n", version);
375  
376 @@ -1169,7 +1136,6 @@ static int __devinit r6040_init_one(stru
377         /* Init RDC private data */
378         lp->mcr0 = 0x1002;
379         lp->phy_addr = phy_table[card_idx];
380 -       lp->switch_sig = 0;
381  
382         /* The RDC-specific entries in the device structure. */
383         dev->netdev_ops = &r6040_netdev_ops;
384 @@ -1177,28 +1143,61 @@ static int __devinit r6040_init_one(stru
385         dev->watchdog_timeo = TX_TIMEOUT;
386  
387         netif_napi_add(dev, &lp->napi, r6040_poll, 64);
388 -       lp->mii_if.dev = dev;
389 -       lp->mii_if.mdio_read = r6040_mdio_read;
390 -       lp->mii_if.mdio_write = r6040_mdio_write;
391 -       lp->mii_if.phy_id = lp->phy_addr;
392 -       lp->mii_if.phy_id_mask = 0x1f;
393 -       lp->mii_if.reg_num_mask = 0x1f;
394 +
395 +       lp->mii_bus = mdiobus_alloc();
396 +       if (!lp->mii_bus) {
397 +               printk(KERN_ERR DRV_NAME ": mdiobus_alloc failed\n");
398 +               goto err_out_unmap;
399 +       }
400 +
401 +       lp->mii_bus->priv = dev;
402 +       lp->mii_bus->read = r6040_mdiobus_read;
403 +       lp->mii_bus->write = r6040_mdiobus_write;
404 +       lp->mii_bus->reset = r6040_mdiobus_reset;
405 +       lp->mii_bus->name = "r6040_eth_mii";
406 +       snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
407 +       lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
408 +       if (!lp->mii_bus->irq) {
409 +               printk(KERN_ERR DRV_NAME ": allocation failed\n");
410 +               goto err_out_mdio;
411 +       }
412 +
413 +       for (i = 0; i < PHY_MAX_ADDR; i++)
414 +               lp->mii_bus->irq[i] = PHY_POLL;
415 +
416 +       err = mdiobus_register(lp->mii_bus);
417 +       if (err) {
418 +               printk(KERN_ERR DRV_NAME ": failed to register MII bus\n");
419 +               goto err_out_mdio_irq;
420 +       }
421 +
422 +       err = r6040_mii_probe(dev);
423 +       if (err) {
424 +               printk(KERN_ERR DRV_NAME ": failed to probe MII bus\n");
425 +               goto err_out_mdio_unregister;
426 +       }
427  
428         /* Check the vendor ID on the PHY, if 0xffff assume none attached */
429         if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
430                 printk(KERN_ERR DRV_NAME ": Failed to detect an attached PHY\n");
431                 err = -ENODEV;
432 -               goto err_out_unmap;
433 +               goto err_out_mdio_unregister;
434         }
435  
436         /* Register net device. After this dev->name assign */
437         err = register_netdev(dev);
438         if (err) {
439                 printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
440 -               goto err_out_unmap;
441 +               goto err_out_mdio_unregister;
442         }
443         return 0;
444  
445 +err_out_mdio_unregister:
446 +       mdiobus_unregister(lp->mii_bus);
447 +err_out_mdio_irq:
448 +       kfree(lp->mii_bus->irq);
449 +err_out_mdio:
450 +       mdiobus_free(lp->mii_bus);
451  err_out_unmap:
452         pci_iounmap(pdev, ioaddr);
453  err_out_free_res:
454 @@ -1212,8 +1211,12 @@ err_out:
455  static void __devexit r6040_remove_one(struct pci_dev *pdev)
456  {
457         struct net_device *dev = pci_get_drvdata(pdev);
458 +       struct r6040_private *lp = netdev_priv(dev);
459  
460         unregister_netdev(dev);
461 +       mdiobus_unregister(lp->mii_bus);
462 +       kfree(lp->mii_bus->irq);
463 +       mdiobus_free(lp->mii_bus);
464         pci_release_regions(pdev);
465         free_netdev(dev);
466         pci_disable_device(pdev);