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