Commit bb40dcbb0fcebe1df08ba261483fcc38b307d063
Committed by
Jeff Garzik
1 parent
acc4b985a6
Exists in
master
and in
39 other branches
[netdrvr gianfar] use new phy layer
Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Showing 9 changed files with 433 additions and 1251 deletions Side-by-side Diff
drivers/net/Kconfig
... | ... | @@ -2075,6 +2075,8 @@ |
2075 | 2075 | config GIANFAR |
2076 | 2076 | tristate "Gianfar Ethernet" |
2077 | 2077 | depends on 85xx || 83xx |
2078 | + select PHYLIB | |
2079 | + select PHYCONTROL | |
2078 | 2080 | help |
2079 | 2081 | This driver supports the Gigabit TSEC on the MPC85xx |
2080 | 2082 | family of chips, and the FEC on the 8540 |
drivers/net/Makefile
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | obj-$(CONFIG_BONDING) += bonding/ |
14 | 14 | obj-$(CONFIG_GIANFAR) += gianfar_driver.o |
15 | 15 | |
16 | -gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o | |
16 | +gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o | |
17 | 17 | |
18 | 18 | # |
19 | 19 | # link order important here |
drivers/net/gianfar.c
... | ... | @@ -29,12 +29,7 @@ |
29 | 29 | * define the configuration needed by the board are defined in a |
30 | 30 | * board structure in arch/ppc/platforms (though I do not |
31 | 31 | * discount the possibility that other architectures could one |
32 | - * day be supported. One assumption the driver currently makes | |
33 | - * is that the PHY is configured in such a way to advertise all | |
34 | - * capabilities. This is a sensible default, and on certain | |
35 | - * PHYs, changing this default encounters substantial errata | |
36 | - * issues. Future versions may remove this requirement, but for | |
37 | - * now, it is best for the firmware to ensure this is the case. | |
32 | + * day be supported. | |
38 | 33 | * |
39 | 34 | * The Gianfar Ethernet Controller uses a ring of buffer |
40 | 35 | * descriptors. The beginning is indicated by a register |
... | ... | @@ -47,7 +42,7 @@ |
47 | 42 | * corresponding bit in the IMASK register is also set (if |
48 | 43 | * interrupt coalescing is active, then the interrupt may not |
49 | 44 | * happen immediately, but will wait until either a set number |
50 | - * of frames or amount of time have passed.). In NAPI, the | |
45 | + * of frames or amount of time have passed). In NAPI, the | |
51 | 46 | * interrupt handler will signal there is work to be done, and |
52 | 47 | * exit. Without NAPI, the packet(s) will be handled |
53 | 48 | * immediately. Both methods will start at the last known empty |
... | ... | @@ -75,6 +70,7 @@ |
75 | 70 | #include <linux/sched.h> |
76 | 71 | #include <linux/string.h> |
77 | 72 | #include <linux/errno.h> |
73 | +#include <linux/unistd.h> | |
78 | 74 | #include <linux/slab.h> |
79 | 75 | #include <linux/interrupt.h> |
80 | 76 | #include <linux/init.h> |
81 | 77 | |
... | ... | @@ -97,9 +93,11 @@ |
97 | 93 | #include <linux/version.h> |
98 | 94 | #include <linux/dma-mapping.h> |
99 | 95 | #include <linux/crc32.h> |
96 | +#include <linux/mii.h> | |
97 | +#include <linux/phy.h> | |
100 | 98 | |
101 | 99 | #include "gianfar.h" |
102 | -#include "gianfar_phy.h" | |
100 | +#include "gianfar_mii.h" | |
103 | 101 | |
104 | 102 | #define TX_TIMEOUT (1*HZ) |
105 | 103 | #define SKB_ALLOC_TIMEOUT 1000000 |
106 | 104 | |
... | ... | @@ -113,9 +111,8 @@ |
113 | 111 | #endif |
114 | 112 | |
115 | 113 | const char gfar_driver_name[] = "Gianfar Ethernet"; |
116 | -const char gfar_driver_version[] = "1.1"; | |
114 | +const char gfar_driver_version[] = "1.2"; | |
117 | 115 | |
118 | -int startup_gfar(struct net_device *dev); | |
119 | 116 | static int gfar_enet_open(struct net_device *dev); |
120 | 117 | static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); |
121 | 118 | static void gfar_timeout(struct net_device *dev); |
122 | 119 | |
123 | 120 | |
... | ... | @@ -126,17 +123,13 @@ |
126 | 123 | static int gfar_change_mtu(struct net_device *dev, int new_mtu); |
127 | 124 | static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs); |
128 | 125 | static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs); |
129 | -static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); | |
130 | 126 | static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs); |
131 | -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs); | |
132 | -static void gfar_phy_change(void *data); | |
133 | -static void gfar_phy_timer(unsigned long data); | |
134 | 127 | static void adjust_link(struct net_device *dev); |
135 | 128 | static void init_registers(struct net_device *dev); |
136 | 129 | static int init_phy(struct net_device *dev); |
137 | 130 | static int gfar_probe(struct device *device); |
138 | 131 | static int gfar_remove(struct device *device); |
139 | -void free_skb_resources(struct gfar_private *priv); | |
132 | +static void free_skb_resources(struct gfar_private *priv); | |
140 | 133 | static void gfar_set_multi(struct net_device *dev); |
141 | 134 | static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); |
142 | 135 | #ifdef CONFIG_GFAR_NAPI |
... | ... | @@ -144,7 +137,6 @@ |
144 | 137 | #endif |
145 | 138 | int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); |
146 | 139 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); |
147 | -static void gfar_phy_startup_timer(unsigned long data); | |
148 | 140 | static void gfar_vlan_rx_register(struct net_device *netdev, |
149 | 141 | struct vlan_group *grp); |
150 | 142 | static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); |
... | ... | @@ -162,6 +154,9 @@ |
162 | 154 | else |
163 | 155 | return 0; |
164 | 156 | } |
157 | + | |
158 | +/* Set up the ethernet device structure, private data, | |
159 | + * and anything else we need before we start */ | |
165 | 160 | static int gfar_probe(struct device *device) |
166 | 161 | { |
167 | 162 | u32 tempval; |
... | ... | @@ -175,7 +170,7 @@ |
175 | 170 | |
176 | 171 | einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; |
177 | 172 | |
178 | - if (einfo == NULL) { | |
173 | + if (NULL == einfo) { | |
179 | 174 | printk(KERN_ERR "gfar %d: Missing additional data!\n", |
180 | 175 | pdev->id); |
181 | 176 | |
... | ... | @@ -185,7 +180,7 @@ |
185 | 180 | /* Create an ethernet device instance */ |
186 | 181 | dev = alloc_etherdev(sizeof (*priv)); |
187 | 182 | |
188 | - if (dev == NULL) | |
183 | + if (NULL == dev) | |
189 | 184 | return -ENOMEM; |
190 | 185 | |
191 | 186 | priv = netdev_priv(dev); |
192 | 187 | |
... | ... | @@ -207,20 +202,11 @@ |
207 | 202 | priv->regs = (struct gfar *) |
208 | 203 | ioremap(r->start, sizeof (struct gfar)); |
209 | 204 | |
210 | - if (priv->regs == NULL) { | |
205 | + if (NULL == priv->regs) { | |
211 | 206 | err = -ENOMEM; |
212 | 207 | goto regs_fail; |
213 | 208 | } |
214 | 209 | |
215 | - /* Set the PHY base address */ | |
216 | - priv->phyregs = (struct gfar *) | |
217 | - ioremap(einfo->phy_reg_addr, sizeof (struct gfar)); | |
218 | - | |
219 | - if (priv->phyregs == NULL) { | |
220 | - err = -ENOMEM; | |
221 | - goto phy_regs_fail; | |
222 | - } | |
223 | - | |
224 | 210 | spin_lock_init(&priv->lock); |
225 | 211 | |
226 | 212 | dev_set_drvdata(device, dev); |
227 | 213 | |
... | ... | @@ -386,12 +372,10 @@ |
386 | 372 | return 0; |
387 | 373 | |
388 | 374 | register_fail: |
389 | - iounmap((void *) priv->phyregs); | |
390 | -phy_regs_fail: | |
391 | 375 | iounmap((void *) priv->regs); |
392 | 376 | regs_fail: |
393 | 377 | free_netdev(dev); |
394 | - return -ENOMEM; | |
378 | + return err; | |
395 | 379 | } |
396 | 380 | |
397 | 381 | static int gfar_remove(struct device *device) |
398 | 382 | |
399 | 383 | |
400 | 384 | |
401 | 385 | |
402 | 386 | |
403 | 387 | |
404 | 388 | |
405 | 389 | |
... | ... | @@ -402,108 +386,41 @@ |
402 | 386 | dev_set_drvdata(device, NULL); |
403 | 387 | |
404 | 388 | iounmap((void *) priv->regs); |
405 | - iounmap((void *) priv->phyregs); | |
406 | 389 | free_netdev(dev); |
407 | 390 | |
408 | 391 | return 0; |
409 | 392 | } |
410 | 393 | |
411 | 394 | |
412 | -/* Configure the PHY for dev. | |
413 | - * returns 0 if success. -1 if failure | |
395 | +/* Initializes driver's PHY state, and attaches to the PHY. | |
396 | + * Returns 0 on success. | |
414 | 397 | */ |
415 | 398 | static int init_phy(struct net_device *dev) |
416 | 399 | { |
417 | 400 | struct gfar_private *priv = netdev_priv(dev); |
418 | - struct phy_info *curphy; | |
419 | - unsigned int timeout = PHY_INIT_TIMEOUT; | |
420 | - struct gfar *phyregs = priv->phyregs; | |
421 | - struct gfar_mii_info *mii_info; | |
422 | - int err; | |
401 | + uint gigabit_support = | |
402 | + priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? | |
403 | + SUPPORTED_1000baseT_Full : 0; | |
404 | + struct phy_device *phydev; | |
423 | 405 | |
424 | 406 | priv->oldlink = 0; |
425 | 407 | priv->oldspeed = 0; |
426 | 408 | priv->oldduplex = -1; |
427 | 409 | |
428 | - mii_info = kmalloc(sizeof(struct gfar_mii_info), | |
429 | - GFP_KERNEL); | |
410 | + phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0); | |
430 | 411 | |
431 | - if(NULL == mii_info) { | |
432 | - if (netif_msg_ifup(priv)) | |
433 | - printk(KERN_ERR "%s: Could not allocate mii_info\n", | |
434 | - dev->name); | |
435 | - return -ENOMEM; | |
412 | + if (IS_ERR(phydev)) { | |
413 | + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | |
414 | + return PTR_ERR(phydev); | |
436 | 415 | } |
437 | 416 | |
438 | - mii_info->speed = SPEED_1000; | |
439 | - mii_info->duplex = DUPLEX_FULL; | |
440 | - mii_info->pause = 0; | |
441 | - mii_info->link = 1; | |
417 | + /* Remove any features not supported by the controller */ | |
418 | + phydev->supported &= (GFAR_SUPPORTED | gigabit_support); | |
419 | + phydev->advertising = phydev->supported; | |
442 | 420 | |
443 | - mii_info->advertising = (ADVERTISED_10baseT_Half | | |
444 | - ADVERTISED_10baseT_Full | | |
445 | - ADVERTISED_100baseT_Half | | |
446 | - ADVERTISED_100baseT_Full | | |
447 | - ADVERTISED_1000baseT_Full); | |
448 | - mii_info->autoneg = 1; | |
421 | + priv->phydev = phydev; | |
449 | 422 | |
450 | - spin_lock_init(&mii_info->mdio_lock); | |
451 | - | |
452 | - mii_info->mii_id = priv->einfo->phyid; | |
453 | - | |
454 | - mii_info->dev = dev; | |
455 | - | |
456 | - mii_info->mdio_read = &read_phy_reg; | |
457 | - mii_info->mdio_write = &write_phy_reg; | |
458 | - | |
459 | - priv->mii_info = mii_info; | |
460 | - | |
461 | - /* Reset the management interface */ | |
462 | - gfar_write(&phyregs->miimcfg, MIIMCFG_RESET); | |
463 | - | |
464 | - /* Setup the MII Mgmt clock speed */ | |
465 | - gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE); | |
466 | - | |
467 | - /* Wait until the bus is free */ | |
468 | - while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) && | |
469 | - timeout--) | |
470 | - cpu_relax(); | |
471 | - | |
472 | - if(timeout <= 0) { | |
473 | - printk(KERN_ERR "%s: The MII Bus is stuck!\n", | |
474 | - dev->name); | |
475 | - err = -1; | |
476 | - goto bus_fail; | |
477 | - } | |
478 | - | |
479 | - /* get info for this PHY */ | |
480 | - curphy = get_phy_info(priv->mii_info); | |
481 | - | |
482 | - if (curphy == NULL) { | |
483 | - if (netif_msg_ifup(priv)) | |
484 | - printk(KERN_ERR "%s: No PHY found\n", dev->name); | |
485 | - err = -1; | |
486 | - goto no_phy; | |
487 | - } | |
488 | - | |
489 | - mii_info->phyinfo = curphy; | |
490 | - | |
491 | - /* Run the commands which initialize the PHY */ | |
492 | - if(curphy->init) { | |
493 | - err = curphy->init(priv->mii_info); | |
494 | - | |
495 | - if (err) | |
496 | - goto phy_init_fail; | |
497 | - } | |
498 | - | |
499 | 423 | return 0; |
500 | - | |
501 | -phy_init_fail: | |
502 | -no_phy: | |
503 | -bus_fail: | |
504 | - kfree(mii_info); | |
505 | - | |
506 | - return err; | |
507 | 424 | } |
508 | 425 | |
509 | 426 | static void init_registers(struct net_device *dev) |
510 | 427 | |
511 | 428 | |
... | ... | @@ -603,24 +520,13 @@ |
603 | 520 | struct gfar *regs = priv->regs; |
604 | 521 | unsigned long flags; |
605 | 522 | |
523 | + phy_stop(priv->phydev); | |
524 | + | |
606 | 525 | /* Lock it down */ |
607 | 526 | spin_lock_irqsave(&priv->lock, flags); |
608 | 527 | |
609 | - /* Tell the kernel the link is down */ | |
610 | - priv->mii_info->link = 0; | |
611 | - adjust_link(dev); | |
612 | - | |
613 | 528 | gfar_halt(dev); |
614 | 529 | |
615 | - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { | |
616 | - /* Clear any pending interrupts */ | |
617 | - mii_clear_phy_interrupt(priv->mii_info); | |
618 | - | |
619 | - /* Disable PHY Interrupts */ | |
620 | - mii_configure_phy_interrupt(priv->mii_info, | |
621 | - MII_INTERRUPT_DISABLED); | |
622 | - } | |
623 | - | |
624 | 530 | spin_unlock_irqrestore(&priv->lock, flags); |
625 | 531 | |
626 | 532 | /* Free the IRQs */ |
627 | 533 | |
... | ... | @@ -629,15 +535,9 @@ |
629 | 535 | free_irq(priv->interruptTransmit, dev); |
630 | 536 | free_irq(priv->interruptReceive, dev); |
631 | 537 | } else { |
632 | - free_irq(priv->interruptTransmit, dev); | |
538 | + free_irq(priv->interruptTransmit, dev); | |
633 | 539 | } |
634 | 540 | |
635 | - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { | |
636 | - free_irq(priv->einfo->interruptPHY, dev); | |
637 | - } else { | |
638 | - del_timer_sync(&priv->phy_info_timer); | |
639 | - } | |
640 | - | |
641 | 541 | free_skb_resources(priv); |
642 | 542 | |
643 | 543 | dma_free_coherent(NULL, |
... | ... | @@ -649,7 +549,7 @@ |
649 | 549 | |
650 | 550 | /* If there are any tx skbs or rx skbs still around, free them. |
651 | 551 | * Then free tx_skbuff and rx_skbuff */ |
652 | -void free_skb_resources(struct gfar_private *priv) | |
552 | +static void free_skb_resources(struct gfar_private *priv) | |
653 | 553 | { |
654 | 554 | struct rxbd8 *rxbdp; |
655 | 555 | struct txbd8 *txbdp; |
... | ... | @@ -770,7 +670,7 @@ |
770 | 670 | (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * |
771 | 671 | priv->tx_ring_size, GFP_KERNEL); |
772 | 672 | |
773 | - if (priv->tx_skbuff == NULL) { | |
673 | + if (NULL == priv->tx_skbuff) { | |
774 | 674 | if (netif_msg_ifup(priv)) |
775 | 675 | printk(KERN_ERR "%s: Could not allocate tx_skbuff\n", |
776 | 676 | dev->name); |
... | ... | @@ -785,7 +685,7 @@ |
785 | 685 | (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) * |
786 | 686 | priv->rx_ring_size, GFP_KERNEL); |
787 | 687 | |
788 | - if (priv->rx_skbuff == NULL) { | |
688 | + if (NULL == priv->rx_skbuff) { | |
789 | 689 | if (netif_msg_ifup(priv)) |
790 | 690 | printk(KERN_ERR "%s: Could not allocate rx_skbuff\n", |
791 | 691 | dev->name); |
792 | 692 | |
... | ... | @@ -879,14 +779,8 @@ |
879 | 779 | } |
880 | 780 | } |
881 | 781 | |
882 | - /* Set up the PHY change work queue */ | |
883 | - INIT_WORK(&priv->tq, gfar_phy_change, dev); | |
782 | + phy_start(priv->phydev); | |
884 | 783 | |
885 | - init_timer(&priv->phy_info_timer); | |
886 | - priv->phy_info_timer.function = &gfar_phy_startup_timer; | |
887 | - priv->phy_info_timer.data = (unsigned long) priv->mii_info; | |
888 | - mod_timer(&priv->phy_info_timer, jiffies + HZ); | |
889 | - | |
890 | 784 | /* Configure the coalescing support */ |
891 | 785 | if (priv->txcoalescing) |
892 | 786 | gfar_write(®s->txic, |
... | ... | @@ -933,11 +827,6 @@ |
933 | 827 | priv->tx_bd_base, |
934 | 828 | gfar_read(®s->tbase0)); |
935 | 829 | |
936 | - if (priv->mii_info->phyinfo->close) | |
937 | - priv->mii_info->phyinfo->close(priv->mii_info); | |
938 | - | |
939 | - kfree(priv->mii_info); | |
940 | - | |
941 | 830 | return err; |
942 | 831 | } |
943 | 832 | |
... | ... | @@ -1035,7 +924,7 @@ |
1035 | 924 | txbdp->status &= TXBD_WRAP; |
1036 | 925 | |
1037 | 926 | /* Set up checksumming */ |
1038 | - if ((dev->features & NETIF_F_IP_CSUM) | |
927 | + if ((dev->features & NETIF_F_IP_CSUM) | |
1039 | 928 | && (CHECKSUM_HW == skb->ip_summed)) { |
1040 | 929 | fcb = gfar_add_fcb(skb, txbdp); |
1041 | 930 | gfar_tx_checksum(skb, fcb); |
1042 | 931 | |
... | ... | @@ -1103,12 +992,10 @@ |
1103 | 992 | struct gfar_private *priv = netdev_priv(dev); |
1104 | 993 | stop_gfar(dev); |
1105 | 994 | |
1106 | - /* Shutdown the PHY */ | |
1107 | - if (priv->mii_info->phyinfo->close) | |
1108 | - priv->mii_info->phyinfo->close(priv->mii_info); | |
995 | + /* Disconnect from the PHY */ | |
996 | + phy_disconnect(priv->phydev); | |
997 | + priv->phydev = NULL; | |
1109 | 998 | |
1110 | - kfree(priv->mii_info); | |
1111 | - | |
1112 | 999 | netif_stop_queue(dev); |
1113 | 1000 | |
1114 | 1001 | return 0; |
... | ... | @@ -1343,7 +1230,7 @@ |
1343 | 1230 | while ((!skb) && timeout--) |
1344 | 1231 | skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT); |
1345 | 1232 | |
1346 | - if (skb == NULL) | |
1233 | + if (NULL == skb) | |
1347 | 1234 | return NULL; |
1348 | 1235 | |
1349 | 1236 | /* We need the data buffer to be aligned properly. We will reserve |
... | ... | @@ -1490,7 +1377,7 @@ |
1490 | 1377 | struct gfar_private *priv = netdev_priv(dev); |
1491 | 1378 | struct rxfcb *fcb = NULL; |
1492 | 1379 | |
1493 | - if (skb == NULL) { | |
1380 | + if (NULL == skb) { | |
1494 | 1381 | if (netif_msg_rx_err(priv)) |
1495 | 1382 | printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); |
1496 | 1383 | priv->stats.rx_dropped++; |
1497 | 1384 | |
... | ... | @@ -1718,131 +1605,9 @@ |
1718 | 1605 | return IRQ_HANDLED; |
1719 | 1606 | } |
1720 | 1607 | |
1721 | -static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |
1722 | -{ | |
1723 | - struct net_device *dev = (struct net_device *) dev_id; | |
1724 | - struct gfar_private *priv = netdev_priv(dev); | |
1725 | - | |
1726 | - /* Clear the interrupt */ | |
1727 | - mii_clear_phy_interrupt(priv->mii_info); | |
1728 | - | |
1729 | - /* Disable PHY interrupts */ | |
1730 | - mii_configure_phy_interrupt(priv->mii_info, | |
1731 | - MII_INTERRUPT_DISABLED); | |
1732 | - | |
1733 | - /* Schedule the phy change */ | |
1734 | - schedule_work(&priv->tq); | |
1735 | - | |
1736 | - return IRQ_HANDLED; | |
1737 | -} | |
1738 | - | |
1739 | -/* Scheduled by the phy_interrupt/timer to handle PHY changes */ | |
1740 | -static void gfar_phy_change(void *data) | |
1741 | -{ | |
1742 | - struct net_device *dev = (struct net_device *) data; | |
1743 | - struct gfar_private *priv = netdev_priv(dev); | |
1744 | - int result = 0; | |
1745 | - | |
1746 | - /* Delay to give the PHY a chance to change the | |
1747 | - * register state */ | |
1748 | - msleep(1); | |
1749 | - | |
1750 | - /* Update the link, speed, duplex */ | |
1751 | - result = priv->mii_info->phyinfo->read_status(priv->mii_info); | |
1752 | - | |
1753 | - /* Adjust the known status as long as the link | |
1754 | - * isn't still coming up */ | |
1755 | - if((0 == result) || (priv->mii_info->link == 0)) | |
1756 | - adjust_link(dev); | |
1757 | - | |
1758 | - /* Reenable interrupts, if needed */ | |
1759 | - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) | |
1760 | - mii_configure_phy_interrupt(priv->mii_info, | |
1761 | - MII_INTERRUPT_ENABLED); | |
1762 | -} | |
1763 | - | |
1764 | -/* Called every so often on systems that don't interrupt | |
1765 | - * the core for PHY changes */ | |
1766 | -static void gfar_phy_timer(unsigned long data) | |
1767 | -{ | |
1768 | - struct net_device *dev = (struct net_device *) data; | |
1769 | - struct gfar_private *priv = netdev_priv(dev); | |
1770 | - | |
1771 | - schedule_work(&priv->tq); | |
1772 | - | |
1773 | - mod_timer(&priv->phy_info_timer, jiffies + | |
1774 | - GFAR_PHY_CHANGE_TIME * HZ); | |
1775 | -} | |
1776 | - | |
1777 | -/* Keep trying aneg for some time | |
1778 | - * If, after GFAR_AN_TIMEOUT seconds, it has not | |
1779 | - * finished, we switch to forced. | |
1780 | - * Either way, once the process has completed, we either | |
1781 | - * request the interrupt, or switch the timer over to | |
1782 | - * using gfar_phy_timer to check status */ | |
1783 | -static void gfar_phy_startup_timer(unsigned long data) | |
1784 | -{ | |
1785 | - int result; | |
1786 | - static int secondary = GFAR_AN_TIMEOUT; | |
1787 | - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; | |
1788 | - struct gfar_private *priv = netdev_priv(mii_info->dev); | |
1789 | - | |
1790 | - /* Configure the Auto-negotiation */ | |
1791 | - result = mii_info->phyinfo->config_aneg(mii_info); | |
1792 | - | |
1793 | - /* If autonegotiation failed to start, and | |
1794 | - * we haven't timed out, reset the timer, and return */ | |
1795 | - if (result && secondary--) { | |
1796 | - mod_timer(&priv->phy_info_timer, jiffies + HZ); | |
1797 | - return; | |
1798 | - } else if (result) { | |
1799 | - /* Couldn't start autonegotiation. | |
1800 | - * Try switching to forced */ | |
1801 | - mii_info->autoneg = 0; | |
1802 | - result = mii_info->phyinfo->config_aneg(mii_info); | |
1803 | - | |
1804 | - /* Forcing failed! Give up */ | |
1805 | - if(result) { | |
1806 | - if (netif_msg_link(priv)) | |
1807 | - printk(KERN_ERR "%s: Forcing failed!\n", | |
1808 | - mii_info->dev->name); | |
1809 | - return; | |
1810 | - } | |
1811 | - } | |
1812 | - | |
1813 | - /* Kill the timer so it can be restarted */ | |
1814 | - del_timer_sync(&priv->phy_info_timer); | |
1815 | - | |
1816 | - /* Grab the PHY interrupt, if necessary/possible */ | |
1817 | - if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) { | |
1818 | - if (request_irq(priv->einfo->interruptPHY, | |
1819 | - phy_interrupt, | |
1820 | - SA_SHIRQ, | |
1821 | - "phy_interrupt", | |
1822 | - mii_info->dev) < 0) { | |
1823 | - if (netif_msg_intr(priv)) | |
1824 | - printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n", | |
1825 | - mii_info->dev->name, | |
1826 | - priv->einfo->interruptPHY); | |
1827 | - } else { | |
1828 | - mii_configure_phy_interrupt(priv->mii_info, | |
1829 | - MII_INTERRUPT_ENABLED); | |
1830 | - return; | |
1831 | - } | |
1832 | - } | |
1833 | - | |
1834 | - /* Start the timer again, this time in order to | |
1835 | - * handle a change in status */ | |
1836 | - init_timer(&priv->phy_info_timer); | |
1837 | - priv->phy_info_timer.function = &gfar_phy_timer; | |
1838 | - priv->phy_info_timer.data = (unsigned long) mii_info->dev; | |
1839 | - mod_timer(&priv->phy_info_timer, jiffies + | |
1840 | - GFAR_PHY_CHANGE_TIME * HZ); | |
1841 | -} | |
1842 | - | |
1843 | 1608 | /* Called every time the controller might need to be made |
1844 | 1609 | * aware of new link state. The PHY code conveys this |
1845 | - * information through variables in the priv structure, and this | |
1610 | + * information through variables in the phydev structure, and this | |
1846 | 1611 | * function converts those variables into the appropriate |
1847 | 1612 | * register values, and can bring down the device if needed. |
1848 | 1613 | */ |
1849 | 1614 | |
1850 | 1615 | |
1851 | 1616 | |
1852 | 1617 | |
1853 | 1618 | |
1854 | 1619 | |
1855 | 1620 | |
1856 | 1621 | |
1857 | 1622 | |
1858 | 1623 | |
1859 | 1624 | |
1860 | 1625 | |
1861 | 1626 | |
1862 | 1627 | |
1863 | 1628 | |
1864 | 1629 | |
1865 | 1630 | |
1866 | 1631 | |
1867 | 1632 | |
... | ... | @@ -1850,85 +1615,69 @@ |
1850 | 1615 | { |
1851 | 1616 | struct gfar_private *priv = netdev_priv(dev); |
1852 | 1617 | struct gfar *regs = priv->regs; |
1853 | - u32 tempval; | |
1854 | - struct gfar_mii_info *mii_info = priv->mii_info; | |
1618 | + unsigned long flags; | |
1619 | + struct phy_device *phydev = priv->phydev; | |
1620 | + int new_state = 0; | |
1855 | 1621 | |
1856 | - if (mii_info->link) { | |
1622 | + spin_lock_irqsave(&priv->lock, flags); | |
1623 | + if (phydev->link) { | |
1624 | + u32 tempval = gfar_read(®s->maccfg2); | |
1625 | + | |
1857 | 1626 | /* Now we make sure that we can be in full duplex mode. |
1858 | 1627 | * If not, we operate in half-duplex mode. */ |
1859 | - if (mii_info->duplex != priv->oldduplex) { | |
1860 | - if (!(mii_info->duplex)) { | |
1861 | - tempval = gfar_read(®s->maccfg2); | |
1628 | + if (phydev->duplex != priv->oldduplex) { | |
1629 | + new_state = 1; | |
1630 | + if (!(phydev->duplex)) | |
1862 | 1631 | tempval &= ~(MACCFG2_FULL_DUPLEX); |
1863 | - gfar_write(®s->maccfg2, tempval); | |
1864 | - | |
1865 | - if (netif_msg_link(priv)) | |
1866 | - printk(KERN_INFO "%s: Half Duplex\n", | |
1867 | - dev->name); | |
1868 | - } else { | |
1869 | - tempval = gfar_read(®s->maccfg2); | |
1632 | + else | |
1870 | 1633 | tempval |= MACCFG2_FULL_DUPLEX; |
1871 | - gfar_write(®s->maccfg2, tempval); | |
1872 | 1634 | |
1873 | - if (netif_msg_link(priv)) | |
1874 | - printk(KERN_INFO "%s: Full Duplex\n", | |
1875 | - dev->name); | |
1876 | - } | |
1877 | - | |
1878 | - priv->oldduplex = mii_info->duplex; | |
1635 | + priv->oldduplex = phydev->duplex; | |
1879 | 1636 | } |
1880 | 1637 | |
1881 | - if (mii_info->speed != priv->oldspeed) { | |
1882 | - switch (mii_info->speed) { | |
1638 | + if (phydev->speed != priv->oldspeed) { | |
1639 | + new_state = 1; | |
1640 | + switch (phydev->speed) { | |
1883 | 1641 | case 1000: |
1884 | - tempval = gfar_read(®s->maccfg2); | |
1885 | 1642 | tempval = |
1886 | 1643 | ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); |
1887 | - gfar_write(®s->maccfg2, tempval); | |
1888 | 1644 | break; |
1889 | 1645 | case 100: |
1890 | 1646 | case 10: |
1891 | - tempval = gfar_read(®s->maccfg2); | |
1892 | 1647 | tempval = |
1893 | 1648 | ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII); |
1894 | - gfar_write(®s->maccfg2, tempval); | |
1895 | 1649 | break; |
1896 | 1650 | default: |
1897 | 1651 | if (netif_msg_link(priv)) |
1898 | 1652 | printk(KERN_WARNING |
1899 | - "%s: Ack! Speed (%d) is not 10/100/1000!\n", | |
1900 | - dev->name, mii_info->speed); | |
1653 | + "%s: Ack! Speed (%d) is not 10/100/1000!\n", | |
1654 | + dev->name, phydev->speed); | |
1901 | 1655 | break; |
1902 | 1656 | } |
1903 | 1657 | |
1904 | - if (netif_msg_link(priv)) | |
1905 | - printk(KERN_INFO "%s: Speed %dBT\n", dev->name, | |
1906 | - mii_info->speed); | |
1907 | - | |
1908 | - priv->oldspeed = mii_info->speed; | |
1658 | + priv->oldspeed = phydev->speed; | |
1909 | 1659 | } |
1910 | 1660 | |
1661 | + gfar_write(®s->maccfg2, tempval); | |
1662 | + | |
1911 | 1663 | if (!priv->oldlink) { |
1912 | - if (netif_msg_link(priv)) | |
1913 | - printk(KERN_INFO "%s: Link is up\n", dev->name); | |
1664 | + new_state = 1; | |
1914 | 1665 | priv->oldlink = 1; |
1915 | - netif_carrier_on(dev); | |
1916 | 1666 | netif_schedule(dev); |
1917 | 1667 | } |
1918 | - } else { | |
1919 | - if (priv->oldlink) { | |
1920 | - if (netif_msg_link(priv)) | |
1921 | - printk(KERN_INFO "%s: Link is down\n", | |
1922 | - dev->name); | |
1923 | - priv->oldlink = 0; | |
1924 | - priv->oldspeed = 0; | |
1925 | - priv->oldduplex = -1; | |
1926 | - netif_carrier_off(dev); | |
1927 | - } | |
1668 | + } else if (priv->oldlink) { | |
1669 | + new_state = 1; | |
1670 | + priv->oldlink = 0; | |
1671 | + priv->oldspeed = 0; | |
1672 | + priv->oldduplex = -1; | |
1928 | 1673 | } |
1929 | -} | |
1930 | 1674 | |
1675 | + if (new_state && netif_msg_link(priv)) | |
1676 | + phy_print_status(phydev); | |
1931 | 1677 | |
1678 | + spin_unlock_irqrestore(&priv->lock, flags); | |
1679 | +} | |
1680 | + | |
1932 | 1681 | /* Update the hash table based on the current list of multicast |
1933 | 1682 | * addresses we subscribe to. Also, change the promiscuity of |
1934 | 1683 | * the device based on the flags (this function is called |
1935 | 1684 | |
... | ... | @@ -2122,12 +1871,23 @@ |
2122 | 1871 | |
2123 | 1872 | static int __init gfar_init(void) |
2124 | 1873 | { |
2125 | - return driver_register(&gfar_driver); | |
1874 | + int err = gfar_mdio_init(); | |
1875 | + | |
1876 | + if (err) | |
1877 | + return err; | |
1878 | + | |
1879 | + err = driver_register(&gfar_driver); | |
1880 | + | |
1881 | + if (err) | |
1882 | + gfar_mdio_exit(); | |
1883 | + | |
1884 | + return err; | |
2126 | 1885 | } |
2127 | 1886 | |
2128 | 1887 | static void __exit gfar_exit(void) |
2129 | 1888 | { |
2130 | 1889 | driver_unregister(&gfar_driver); |
1890 | + gfar_mdio_exit(); | |
2131 | 1891 | } |
2132 | 1892 | |
2133 | 1893 | module_init(gfar_init); |
drivers/net/gianfar.h
... | ... | @@ -17,7 +17,6 @@ |
17 | 17 | * |
18 | 18 | * Still left to do: |
19 | 19 | * -Add support for module parameters |
20 | - * -Add support for ethtool -s | |
21 | 20 | * -Add patch for ethtool phys id |
22 | 21 | */ |
23 | 22 | #ifndef __GIANFAR_H |
... | ... | @@ -37,7 +36,8 @@ |
37 | 36 | #include <linux/skbuff.h> |
38 | 37 | #include <linux/spinlock.h> |
39 | 38 | #include <linux/mm.h> |
40 | -#include <linux/fsl_devices.h> | |
39 | +#include <linux/mii.h> | |
40 | +#include <linux/phy.h> | |
41 | 41 | |
42 | 42 | #include <asm/io.h> |
43 | 43 | #include <asm/irq.h> |
... | ... | @@ -48,7 +48,8 @@ |
48 | 48 | #include <linux/workqueue.h> |
49 | 49 | #include <linux/ethtool.h> |
50 | 50 | #include <linux/netdevice.h> |
51 | -#include "gianfar_phy.h" | |
51 | +#include <linux/fsl_devices.h> | |
52 | +#include "gianfar_mii.h" | |
52 | 53 | |
53 | 54 | /* The maximum number of packets to be handled in one call of gfar_poll */ |
54 | 55 | #define GFAR_DEV_WEIGHT 64 |
... | ... | @@ -73,7 +74,7 @@ |
73 | 74 | #define PHY_INIT_TIMEOUT 100000 |
74 | 75 | #define GFAR_PHY_CHANGE_TIME 2 |
75 | 76 | |
76 | -#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, " | |
77 | +#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, " | |
77 | 78 | #define DRV_NAME "gfar-enet" |
78 | 79 | extern const char gfar_driver_name[]; |
79 | 80 | extern const char gfar_driver_version[]; |
... | ... | @@ -578,12 +579,7 @@ |
578 | 579 | u32 hafdup; /* 0x.50c - Half Duplex Register */ |
579 | 580 | u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */ |
580 | 581 | u8 res18[12]; |
581 | - u32 miimcfg; /* 0x.520 - MII Management Configuration Register */ | |
582 | - u32 miimcom; /* 0x.524 - MII Management Command Register */ | |
583 | - u32 miimadd; /* 0x.528 - MII Management Address Register */ | |
584 | - u32 miimcon; /* 0x.52c - MII Management Control Register */ | |
585 | - u32 miimstat; /* 0x.530 - MII Management Status Register */ | |
586 | - u32 miimind; /* 0x.534 - MII Management Indicator Register */ | |
582 | + u8 gfar_mii_regs[24]; /* See gianfar_phy.h */ | |
587 | 583 | u8 res19[4]; |
588 | 584 | u32 ifstat; /* 0x.53c - Interface Status Register */ |
589 | 585 | u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */ |
... | ... | @@ -688,9 +684,6 @@ |
688 | 684 | struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */ |
689 | 685 | u32 *hash_regs[16]; |
690 | 686 | int hash_width; |
691 | - struct gfar *phyregs; | |
692 | - struct work_struct tq; | |
693 | - struct timer_list phy_info_timer; | |
694 | 687 | struct net_device_stats stats; /* linux network statistics */ |
695 | 688 | struct gfar_extra_stats extra_stats; |
696 | 689 | spinlock_t lock; |
... | ... | @@ -710,7 +703,8 @@ |
710 | 703 | unsigned int interruptError; |
711 | 704 | struct gianfar_platform_data *einfo; |
712 | 705 | |
713 | - struct gfar_mii_info *mii_info; | |
706 | + struct phy_device *phydev; | |
707 | + struct mii_bus *mii_bus; | |
714 | 708 | int oldspeed; |
715 | 709 | int oldduplex; |
716 | 710 | int oldlink; |
... | ... | @@ -731,6 +725,14 @@ |
731 | 725 | } |
732 | 726 | |
733 | 727 | extern struct ethtool_ops *gfar_op_array[]; |
728 | + | |
729 | +extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs); | |
730 | +extern int startup_gfar(struct net_device *dev); | |
731 | +extern void stop_gfar(struct net_device *dev); | |
732 | +extern void gfar_halt(struct net_device *dev); | |
733 | +extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, | |
734 | + int enable, u32 regnum, u32 read); | |
735 | +void gfar_setup_stashing(struct net_device *dev); | |
734 | 736 | |
735 | 737 | #endif /* __GIANFAR_H */ |
drivers/net/gianfar_ethtool.c
... | ... | @@ -39,17 +39,18 @@ |
39 | 39 | #include <asm/types.h> |
40 | 40 | #include <asm/uaccess.h> |
41 | 41 | #include <linux/ethtool.h> |
42 | +#include <linux/mii.h> | |
43 | +#include <linux/phy.h> | |
42 | 44 | |
43 | 45 | #include "gianfar.h" |
44 | 46 | |
45 | 47 | #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) |
46 | 48 | |
47 | -extern int startup_gfar(struct net_device *dev); | |
48 | -extern void stop_gfar(struct net_device *dev); | |
49 | -extern void gfar_halt(struct net_device *dev); | |
50 | 49 | extern void gfar_start(struct net_device *dev); |
51 | 50 | extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); |
52 | 51 | |
52 | +#define GFAR_MAX_COAL_USECS 0xffff | |
53 | +#define GFAR_MAX_COAL_FRAMES 0xff | |
53 | 54 | static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, |
54 | 55 | u64 * buf); |
55 | 56 | static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf); |
56 | 57 | |
57 | 58 | |
58 | 59 | |
59 | 60 | |
60 | 61 | |
... | ... | @@ -182,38 +183,32 @@ |
182 | 183 | drvinfo->eedump_len = 0; |
183 | 184 | } |
184 | 185 | |
185 | -/* Return the current settings in the ethtool_cmd structure */ | |
186 | -static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) | |
186 | + | |
187 | +static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd) | |
187 | 188 | { |
188 | 189 | struct gfar_private *priv = netdev_priv(dev); |
189 | - uint gigabit_support = | |
190 | - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? | |
191 | - SUPPORTED_1000baseT_Full : 0; | |
192 | - uint gigabit_advert = | |
193 | - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? | |
194 | - ADVERTISED_1000baseT_Full: 0; | |
190 | + struct phy_device *phydev = priv->phydev; | |
195 | 191 | |
196 | - cmd->supported = (SUPPORTED_10baseT_Half | |
197 | - | SUPPORTED_100baseT_Half | |
198 | - | SUPPORTED_100baseT_Full | |
199 | - | gigabit_support | SUPPORTED_Autoneg); | |
192 | + if (NULL == phydev) | |
193 | + return -ENODEV; | |
200 | 194 | |
201 | - /* For now, we always advertise everything */ | |
202 | - cmd->advertising = (ADVERTISED_10baseT_Half | |
203 | - | ADVERTISED_100baseT_Half | |
204 | - | ADVERTISED_100baseT_Full | |
205 | - | gigabit_advert | ADVERTISED_Autoneg); | |
195 | + return phy_ethtool_sset(phydev, cmd); | |
196 | +} | |
206 | 197 | |
207 | - cmd->speed = priv->mii_info->speed; | |
208 | - cmd->duplex = priv->mii_info->duplex; | |
209 | - cmd->port = PORT_MII; | |
210 | - cmd->phy_address = priv->mii_info->mii_id; | |
211 | - cmd->transceiver = XCVR_EXTERNAL; | |
212 | - cmd->autoneg = AUTONEG_ENABLE; | |
198 | + | |
199 | +/* Return the current settings in the ethtool_cmd structure */ | |
200 | +static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) | |
201 | +{ | |
202 | + struct gfar_private *priv = netdev_priv(dev); | |
203 | + struct phy_device *phydev = priv->phydev; | |
204 | + | |
205 | + if (NULL == phydev) | |
206 | + return -ENODEV; | |
207 | + | |
213 | 208 | cmd->maxtxpkt = priv->txcount; |
214 | 209 | cmd->maxrxpkt = priv->rxcount; |
215 | 210 | |
216 | - return 0; | |
211 | + return phy_ethtool_gset(phydev, cmd); | |
217 | 212 | } |
218 | 213 | |
219 | 214 | /* Return the length of the register structure */ |
220 | 215 | |
221 | 216 | |
... | ... | @@ -241,14 +236,14 @@ |
241 | 236 | unsigned int count; |
242 | 237 | |
243 | 238 | /* The timer is different, depending on the interface speed */ |
244 | - switch (priv->mii_info->speed) { | |
245 | - case 1000: | |
239 | + switch (priv->phydev->speed) { | |
240 | + case SPEED_1000: | |
246 | 241 | count = GFAR_GBIT_TIME; |
247 | 242 | break; |
248 | - case 100: | |
243 | + case SPEED_100: | |
249 | 244 | count = GFAR_100_TIME; |
250 | 245 | break; |
251 | - case 10: | |
246 | + case SPEED_10: | |
252 | 247 | default: |
253 | 248 | count = GFAR_10_TIME; |
254 | 249 | break; |
255 | 250 | |
256 | 251 | |
... | ... | @@ -265,14 +260,14 @@ |
265 | 260 | unsigned int count; |
266 | 261 | |
267 | 262 | /* The timer is different, depending on the interface speed */ |
268 | - switch (priv->mii_info->speed) { | |
269 | - case 1000: | |
263 | + switch (priv->phydev->speed) { | |
264 | + case SPEED_1000: | |
270 | 265 | count = GFAR_GBIT_TIME; |
271 | 266 | break; |
272 | - case 100: | |
267 | + case SPEED_100: | |
273 | 268 | count = GFAR_100_TIME; |
274 | 269 | break; |
275 | - case 10: | |
270 | + case SPEED_10: | |
276 | 271 | default: |
277 | 272 | count = GFAR_10_TIME; |
278 | 273 | break; |
... | ... | @@ -292,6 +287,9 @@ |
292 | 287 | if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) |
293 | 288 | return -EOPNOTSUPP; |
294 | 289 | |
290 | + if (NULL == priv->phydev) | |
291 | + return -ENODEV; | |
292 | + | |
295 | 293 | cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); |
296 | 294 | cvals->rx_max_coalesced_frames = priv->rxcount; |
297 | 295 | |
... | ... | @@ -348,6 +346,22 @@ |
348 | 346 | else |
349 | 347 | priv->rxcoalescing = 1; |
350 | 348 | |
349 | + if (NULL == priv->phydev) | |
350 | + return -ENODEV; | |
351 | + | |
352 | + /* Check the bounds of the values */ | |
353 | + if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) { | |
354 | + pr_info("Coalescing is limited to %d microseconds\n", | |
355 | + GFAR_MAX_COAL_USECS); | |
356 | + return -EINVAL; | |
357 | + } | |
358 | + | |
359 | + if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { | |
360 | + pr_info("Coalescing is limited to %d frames\n", | |
361 | + GFAR_MAX_COAL_FRAMES); | |
362 | + return -EINVAL; | |
363 | + } | |
364 | + | |
351 | 365 | priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); |
352 | 366 | priv->rxcount = cvals->rx_max_coalesced_frames; |
353 | 367 | |
... | ... | @@ -358,6 +372,19 @@ |
358 | 372 | else |
359 | 373 | priv->txcoalescing = 1; |
360 | 374 | |
375 | + /* Check the bounds of the values */ | |
376 | + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { | |
377 | + pr_info("Coalescing is limited to %d microseconds\n", | |
378 | + GFAR_MAX_COAL_USECS); | |
379 | + return -EINVAL; | |
380 | + } | |
381 | + | |
382 | + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { | |
383 | + pr_info("Coalescing is limited to %d frames\n", | |
384 | + GFAR_MAX_COAL_FRAMES); | |
385 | + return -EINVAL; | |
386 | + } | |
387 | + | |
361 | 388 | priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); |
362 | 389 | priv->txcount = cvals->tx_max_coalesced_frames; |
363 | 390 | |
... | ... | @@ -536,6 +563,7 @@ |
536 | 563 | |
537 | 564 | struct ethtool_ops gfar_ethtool_ops = { |
538 | 565 | .get_settings = gfar_gsettings, |
566 | + .set_settings = gfar_ssettings, | |
539 | 567 | .get_drvinfo = gfar_gdrvinfo, |
540 | 568 | .get_regs_len = gfar_reglen, |
541 | 569 | .get_regs = gfar_get_regs, |
drivers/net/gianfar_mii.c
1 | +/* | |
2 | + * drivers/net/gianfar_mii.c | |
3 | + * | |
4 | + * Gianfar Ethernet Driver -- MIIM bus implementation | |
5 | + * Provides Bus interface for MIIM regs | |
6 | + * | |
7 | + * Author: Andy Fleming | |
8 | + * Maintainer: Kumar Gala (kumar.gala@freescale.com) | |
9 | + * | |
10 | + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify it | |
13 | + * under the terms of the GNU General Public License as published by the | |
14 | + * Free Software Foundation; either version 2 of the License, or (at your | |
15 | + * option) any later version. | |
16 | + * | |
17 | + */ | |
18 | + | |
19 | +#include <linux/config.h> | |
20 | +#include <linux/kernel.h> | |
21 | +#include <linux/sched.h> | |
22 | +#include <linux/string.h> | |
23 | +#include <linux/errno.h> | |
24 | +#include <linux/unistd.h> | |
25 | +#include <linux/slab.h> | |
26 | +#include <linux/interrupt.h> | |
27 | +#include <linux/init.h> | |
28 | +#include <linux/delay.h> | |
29 | +#include <linux/netdevice.h> | |
30 | +#include <linux/etherdevice.h> | |
31 | +#include <linux/skbuff.h> | |
32 | +#include <linux/spinlock.h> | |
33 | +#include <linux/mm.h> | |
34 | +#include <linux/module.h> | |
35 | +#include <linux/version.h> | |
36 | +#include <asm/ocp.h> | |
37 | +#include <linux/crc32.h> | |
38 | +#include <linux/mii.h> | |
39 | +#include <linux/phy.h> | |
40 | + | |
41 | +#include <asm/io.h> | |
42 | +#include <asm/irq.h> | |
43 | +#include <asm/uaccess.h> | |
44 | + | |
45 | +#include "gianfar.h" | |
46 | +#include "gianfar_mii.h" | |
47 | + | |
48 | +/* Write value to the PHY at mii_id at register regnum, | |
49 | + * on the bus, waiting until the write is done before returning. | |
50 | + * All PHY configuration is done through the TSEC1 MIIM regs */ | |
51 | +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | |
52 | +{ | |
53 | + struct gfar_mii *regs = bus->priv; | |
54 | + | |
55 | + /* Set the PHY address and the register address we want to write */ | |
56 | + gfar_write(®s->miimadd, (mii_id << 8) | regnum); | |
57 | + | |
58 | + /* Write out the value we want */ | |
59 | + gfar_write(®s->miimcon, value); | |
60 | + | |
61 | + /* Wait for the transaction to finish */ | |
62 | + while (gfar_read(®s->miimind) & MIIMIND_BUSY) | |
63 | + cpu_relax(); | |
64 | + | |
65 | + return 0; | |
66 | +} | |
67 | + | |
68 | +/* Read the bus for PHY at addr mii_id, register regnum, and | |
69 | + * return the value. Clears miimcom first. All PHY | |
70 | + * configuration has to be done through the TSEC1 MIIM regs */ | |
71 | +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | |
72 | +{ | |
73 | + struct gfar_mii *regs = bus->priv; | |
74 | + u16 value; | |
75 | + | |
76 | + /* Set the PHY address and the register address we want to read */ | |
77 | + gfar_write(®s->miimadd, (mii_id << 8) | regnum); | |
78 | + | |
79 | + /* Clear miimcom, and then initiate a read */ | |
80 | + gfar_write(®s->miimcom, 0); | |
81 | + gfar_write(®s->miimcom, MII_READ_COMMAND); | |
82 | + | |
83 | + /* Wait for the transaction to finish */ | |
84 | + while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) | |
85 | + cpu_relax(); | |
86 | + | |
87 | + /* Grab the value of the register from miimstat */ | |
88 | + value = gfar_read(®s->miimstat); | |
89 | + | |
90 | + return value; | |
91 | +} | |
92 | + | |
93 | + | |
94 | +/* Reset the MIIM registers, and wait for the bus to free */ | |
95 | +int gfar_mdio_reset(struct mii_bus *bus) | |
96 | +{ | |
97 | + struct gfar_mii *regs = bus->priv; | |
98 | + unsigned int timeout = PHY_INIT_TIMEOUT; | |
99 | + | |
100 | + spin_lock_bh(&bus->mdio_lock); | |
101 | + | |
102 | + /* Reset the management interface */ | |
103 | + gfar_write(®s->miimcfg, MIIMCFG_RESET); | |
104 | + | |
105 | + /* Setup the MII Mgmt clock speed */ | |
106 | + gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE); | |
107 | + | |
108 | + /* Wait until the bus is free */ | |
109 | + while ((gfar_read(®s->miimind) & MIIMIND_BUSY) && | |
110 | + timeout--) | |
111 | + cpu_relax(); | |
112 | + | |
113 | + spin_unlock_bh(&bus->mdio_lock); | |
114 | + | |
115 | + if(timeout <= 0) { | |
116 | + printk(KERN_ERR "%s: The MII Bus is stuck!\n", | |
117 | + bus->name); | |
118 | + return -EBUSY; | |
119 | + } | |
120 | + | |
121 | + return 0; | |
122 | +} | |
123 | + | |
124 | + | |
125 | +int gfar_mdio_probe(struct device *dev) | |
126 | +{ | |
127 | + struct platform_device *pdev = to_platform_device(dev); | |
128 | + struct gianfar_mdio_data *pdata; | |
129 | + struct gfar_mii *regs; | |
130 | + struct mii_bus *new_bus; | |
131 | + int err = 0; | |
132 | + | |
133 | + if (NULL == dev) | |
134 | + return -EINVAL; | |
135 | + | |
136 | + new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL); | |
137 | + | |
138 | + if (NULL == new_bus) | |
139 | + return -ENOMEM; | |
140 | + | |
141 | + new_bus->name = "Gianfar MII Bus", | |
142 | + new_bus->read = &gfar_mdio_read, | |
143 | + new_bus->write = &gfar_mdio_write, | |
144 | + new_bus->reset = &gfar_mdio_reset, | |
145 | + new_bus->id = pdev->id; | |
146 | + | |
147 | + pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; | |
148 | + | |
149 | + if (NULL == pdata) { | |
150 | + printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); | |
151 | + return -ENODEV; | |
152 | + } | |
153 | + | |
154 | + /* Set the PHY base address */ | |
155 | + regs = (struct gfar_mii *) ioremap(pdata->paddr, | |
156 | + sizeof (struct gfar_mii)); | |
157 | + | |
158 | + if (NULL == regs) { | |
159 | + err = -ENOMEM; | |
160 | + goto reg_map_fail; | |
161 | + } | |
162 | + | |
163 | + new_bus->priv = regs; | |
164 | + | |
165 | + new_bus->irq = pdata->irq; | |
166 | + | |
167 | + new_bus->dev = dev; | |
168 | + dev_set_drvdata(dev, new_bus); | |
169 | + | |
170 | + err = mdiobus_register(new_bus); | |
171 | + | |
172 | + if (0 != err) { | |
173 | + printk (KERN_ERR "%s: Cannot register as MDIO bus\n", | |
174 | + new_bus->name); | |
175 | + goto bus_register_fail; | |
176 | + } | |
177 | + | |
178 | + return 0; | |
179 | + | |
180 | +bus_register_fail: | |
181 | + iounmap((void *) regs); | |
182 | +reg_map_fail: | |
183 | + kfree(new_bus); | |
184 | + | |
185 | + return err; | |
186 | +} | |
187 | + | |
188 | + | |
189 | +int gfar_mdio_remove(struct device *dev) | |
190 | +{ | |
191 | + struct mii_bus *bus = dev_get_drvdata(dev); | |
192 | + | |
193 | + mdiobus_unregister(bus); | |
194 | + | |
195 | + dev_set_drvdata(dev, NULL); | |
196 | + | |
197 | + iounmap((void *) (&bus->priv)); | |
198 | + bus->priv = NULL; | |
199 | + kfree(bus); | |
200 | + | |
201 | + return 0; | |
202 | +} | |
203 | + | |
204 | +static struct device_driver gianfar_mdio_driver = { | |
205 | + .name = "fsl-gianfar_mdio", | |
206 | + .bus = &platform_bus_type, | |
207 | + .probe = gfar_mdio_probe, | |
208 | + .remove = gfar_mdio_remove, | |
209 | +}; | |
210 | + | |
211 | +int __init gfar_mdio_init(void) | |
212 | +{ | |
213 | + return driver_register(&gianfar_mdio_driver); | |
214 | +} | |
215 | + | |
216 | +void __exit gfar_mdio_exit(void) | |
217 | +{ | |
218 | + driver_unregister(&gianfar_mdio_driver); | |
219 | +} |
drivers/net/gianfar_mii.h
1 | +/* | |
2 | + * drivers/net/gianfar_mii.h | |
3 | + * | |
4 | + * Gianfar Ethernet Driver -- MII Management Bus Implementation | |
5 | + * Driver for the MDIO bus controller in the Gianfar register space | |
6 | + * | |
7 | + * Author: Andy Fleming | |
8 | + * Maintainer: Kumar Gala (kumar.gala@freescale.com) | |
9 | + * | |
10 | + * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify it | |
13 | + * under the terms of the GNU General Public License as published by the | |
14 | + * Free Software Foundation; either version 2 of the License, or (at your | |
15 | + * option) any later version. | |
16 | + * | |
17 | + */ | |
18 | +#ifndef __GIANFAR_MII_H | |
19 | +#define __GIANFAR_MII_H | |
20 | + | |
21 | +#define MIIMIND_BUSY 0x00000001 | |
22 | +#define MIIMIND_NOTVALID 0x00000004 | |
23 | + | |
24 | +#define MII_READ_COMMAND 0x00000001 | |
25 | + | |
26 | +#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \ | |
27 | + | SUPPORTED_100baseT_Half \ | |
28 | + | SUPPORTED_100baseT_Full \ | |
29 | + | SUPPORTED_Autoneg \ | |
30 | + | SUPPORTED_MII) | |
31 | + | |
32 | +struct gfar_mii { | |
33 | + u32 miimcfg; /* 0x.520 - MII Management Config Register */ | |
34 | + u32 miimcom; /* 0x.524 - MII Management Command Register */ | |
35 | + u32 miimadd; /* 0x.528 - MII Management Address Register */ | |
36 | + u32 miimcon; /* 0x.52c - MII Management Control Register */ | |
37 | + u32 miimstat; /* 0x.530 - MII Management Status Register */ | |
38 | + u32 miimind; /* 0x.534 - MII Management Indicator Register */ | |
39 | +}; | |
40 | + | |
41 | +int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | |
42 | +int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | |
43 | +int __init gfar_mdio_init(void); | |
44 | +void __exit gfar_mdio_exit(void); | |
45 | +#endif /* GIANFAR_PHY_H */ |
drivers/net/gianfar_phy.c
1 | -/* | |
2 | - * drivers/net/gianfar_phy.c | |
3 | - * | |
4 | - * Gianfar Ethernet Driver -- PHY handling | |
5 | - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 | |
6 | - * Based on 8260_io/fcc_enet.c | |
7 | - * | |
8 | - * Author: Andy Fleming | |
9 | - * Maintainer: Kumar Gala (kumar.gala@freescale.com) | |
10 | - * | |
11 | - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | |
12 | - * | |
13 | - * This program is free software; you can redistribute it and/or modify it | |
14 | - * under the terms of the GNU General Public License as published by the | |
15 | - * Free Software Foundation; either version 2 of the License, or (at your | |
16 | - * option) any later version. | |
17 | - * | |
18 | - */ | |
19 | - | |
20 | -#include <linux/config.h> | |
21 | -#include <linux/kernel.h> | |
22 | -#include <linux/sched.h> | |
23 | -#include <linux/string.h> | |
24 | -#include <linux/errno.h> | |
25 | -#include <linux/slab.h> | |
26 | -#include <linux/interrupt.h> | |
27 | -#include <linux/init.h> | |
28 | -#include <linux/delay.h> | |
29 | -#include <linux/netdevice.h> | |
30 | -#include <linux/etherdevice.h> | |
31 | -#include <linux/skbuff.h> | |
32 | -#include <linux/spinlock.h> | |
33 | -#include <linux/mm.h> | |
34 | - | |
35 | -#include <asm/io.h> | |
36 | -#include <asm/irq.h> | |
37 | -#include <asm/uaccess.h> | |
38 | -#include <linux/module.h> | |
39 | -#include <linux/version.h> | |
40 | -#include <linux/crc32.h> | |
41 | -#include <linux/mii.h> | |
42 | - | |
43 | -#include "gianfar.h" | |
44 | -#include "gianfar_phy.h" | |
45 | - | |
46 | -static void config_genmii_advert(struct gfar_mii_info *mii_info); | |
47 | -static void genmii_setup_forced(struct gfar_mii_info *mii_info); | |
48 | -static void genmii_restart_aneg(struct gfar_mii_info *mii_info); | |
49 | -static int gbit_config_aneg(struct gfar_mii_info *mii_info); | |
50 | -static int genmii_config_aneg(struct gfar_mii_info *mii_info); | |
51 | -static int genmii_update_link(struct gfar_mii_info *mii_info); | |
52 | -static int genmii_read_status(struct gfar_mii_info *mii_info); | |
53 | -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum); | |
54 | -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val); | |
55 | - | |
56 | -/* Write value to the PHY for this device to the register at regnum, */ | |
57 | -/* waiting until the write is done before it returns. All PHY */ | |
58 | -/* configuration has to be done through the TSEC1 MIIM regs */ | |
59 | -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) | |
60 | -{ | |
61 | - struct gfar_private *priv = netdev_priv(dev); | |
62 | - struct gfar *regbase = priv->phyregs; | |
63 | - | |
64 | - /* Set the PHY address and the register address we want to write */ | |
65 | - gfar_write(®base->miimadd, (mii_id << 8) | regnum); | |
66 | - | |
67 | - /* Write out the value we want */ | |
68 | - gfar_write(®base->miimcon, value); | |
69 | - | |
70 | - /* Wait for the transaction to finish */ | |
71 | - while (gfar_read(®base->miimind) & MIIMIND_BUSY) | |
72 | - cpu_relax(); | |
73 | -} | |
74 | - | |
75 | -/* Reads from register regnum in the PHY for device dev, */ | |
76 | -/* returning the value. Clears miimcom first. All PHY */ | |
77 | -/* configuration has to be done through the TSEC1 MIIM regs */ | |
78 | -int read_phy_reg(struct net_device *dev, int mii_id, int regnum) | |
79 | -{ | |
80 | - struct gfar_private *priv = netdev_priv(dev); | |
81 | - struct gfar *regbase = priv->phyregs; | |
82 | - u16 value; | |
83 | - | |
84 | - /* Set the PHY address and the register address we want to read */ | |
85 | - gfar_write(®base->miimadd, (mii_id << 8) | regnum); | |
86 | - | |
87 | - /* Clear miimcom, and then initiate a read */ | |
88 | - gfar_write(®base->miimcom, 0); | |
89 | - gfar_write(®base->miimcom, MII_READ_COMMAND); | |
90 | - | |
91 | - /* Wait for the transaction to finish */ | |
92 | - while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) | |
93 | - cpu_relax(); | |
94 | - | |
95 | - /* Grab the value of the register from miimstat */ | |
96 | - value = gfar_read(®base->miimstat); | |
97 | - | |
98 | - return value; | |
99 | -} | |
100 | - | |
101 | -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info) | |
102 | -{ | |
103 | - if(mii_info->phyinfo->ack_interrupt) | |
104 | - mii_info->phyinfo->ack_interrupt(mii_info); | |
105 | -} | |
106 | - | |
107 | - | |
108 | -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts) | |
109 | -{ | |
110 | - mii_info->interrupts = interrupts; | |
111 | - if(mii_info->phyinfo->config_intr) | |
112 | - mii_info->phyinfo->config_intr(mii_info); | |
113 | -} | |
114 | - | |
115 | - | |
116 | -/* Writes MII_ADVERTISE with the appropriate values, after | |
117 | - * sanitizing advertise to make sure only supported features | |
118 | - * are advertised | |
119 | - */ | |
120 | -static void config_genmii_advert(struct gfar_mii_info *mii_info) | |
121 | -{ | |
122 | - u32 advertise; | |
123 | - u16 adv; | |
124 | - | |
125 | - /* Only allow advertising what this PHY supports */ | |
126 | - mii_info->advertising &= mii_info->phyinfo->features; | |
127 | - advertise = mii_info->advertising; | |
128 | - | |
129 | - /* Setup standard advertisement */ | |
130 | - adv = phy_read(mii_info, MII_ADVERTISE); | |
131 | - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); | |
132 | - if (advertise & ADVERTISED_10baseT_Half) | |
133 | - adv |= ADVERTISE_10HALF; | |
134 | - if (advertise & ADVERTISED_10baseT_Full) | |
135 | - adv |= ADVERTISE_10FULL; | |
136 | - if (advertise & ADVERTISED_100baseT_Half) | |
137 | - adv |= ADVERTISE_100HALF; | |
138 | - if (advertise & ADVERTISED_100baseT_Full) | |
139 | - adv |= ADVERTISE_100FULL; | |
140 | - phy_write(mii_info, MII_ADVERTISE, adv); | |
141 | -} | |
142 | - | |
143 | -static void genmii_setup_forced(struct gfar_mii_info *mii_info) | |
144 | -{ | |
145 | - u16 ctrl; | |
146 | - u32 features = mii_info->phyinfo->features; | |
147 | - | |
148 | - ctrl = phy_read(mii_info, MII_BMCR); | |
149 | - | |
150 | - ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE); | |
151 | - ctrl |= BMCR_RESET; | |
152 | - | |
153 | - switch(mii_info->speed) { | |
154 | - case SPEED_1000: | |
155 | - if(features & (SUPPORTED_1000baseT_Half | |
156 | - | SUPPORTED_1000baseT_Full)) { | |
157 | - ctrl |= BMCR_SPEED1000; | |
158 | - break; | |
159 | - } | |
160 | - mii_info->speed = SPEED_100; | |
161 | - case SPEED_100: | |
162 | - if (features & (SUPPORTED_100baseT_Half | |
163 | - | SUPPORTED_100baseT_Full)) { | |
164 | - ctrl |= BMCR_SPEED100; | |
165 | - break; | |
166 | - } | |
167 | - mii_info->speed = SPEED_10; | |
168 | - case SPEED_10: | |
169 | - if (features & (SUPPORTED_10baseT_Half | |
170 | - | SUPPORTED_10baseT_Full)) | |
171 | - break; | |
172 | - default: /* Unsupported speed! */ | |
173 | - printk(KERN_ERR "%s: Bad speed!\n", | |
174 | - mii_info->dev->name); | |
175 | - break; | |
176 | - } | |
177 | - | |
178 | - phy_write(mii_info, MII_BMCR, ctrl); | |
179 | -} | |
180 | - | |
181 | - | |
182 | -/* Enable and Restart Autonegotiation */ | |
183 | -static void genmii_restart_aneg(struct gfar_mii_info *mii_info) | |
184 | -{ | |
185 | - u16 ctl; | |
186 | - | |
187 | - ctl = phy_read(mii_info, MII_BMCR); | |
188 | - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); | |
189 | - phy_write(mii_info, MII_BMCR, ctl); | |
190 | -} | |
191 | - | |
192 | - | |
193 | -static int gbit_config_aneg(struct gfar_mii_info *mii_info) | |
194 | -{ | |
195 | - u16 adv; | |
196 | - u32 advertise; | |
197 | - | |
198 | - if(mii_info->autoneg) { | |
199 | - /* Configure the ADVERTISE register */ | |
200 | - config_genmii_advert(mii_info); | |
201 | - advertise = mii_info->advertising; | |
202 | - | |
203 | - adv = phy_read(mii_info, MII_1000BASETCONTROL); | |
204 | - adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | | |
205 | - MII_1000BASETCONTROL_HALFDUPLEXCAP); | |
206 | - if (advertise & SUPPORTED_1000baseT_Half) | |
207 | - adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; | |
208 | - if (advertise & SUPPORTED_1000baseT_Full) | |
209 | - adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; | |
210 | - phy_write(mii_info, MII_1000BASETCONTROL, adv); | |
211 | - | |
212 | - /* Start/Restart aneg */ | |
213 | - genmii_restart_aneg(mii_info); | |
214 | - } else | |
215 | - genmii_setup_forced(mii_info); | |
216 | - | |
217 | - return 0; | |
218 | -} | |
219 | - | |
220 | -static int marvell_config_aneg(struct gfar_mii_info *mii_info) | |
221 | -{ | |
222 | - /* The Marvell PHY has an errata which requires | |
223 | - * that certain registers get written in order | |
224 | - * to restart autonegotiation */ | |
225 | - phy_write(mii_info, MII_BMCR, BMCR_RESET); | |
226 | - | |
227 | - phy_write(mii_info, 0x1d, 0x1f); | |
228 | - phy_write(mii_info, 0x1e, 0x200c); | |
229 | - phy_write(mii_info, 0x1d, 0x5); | |
230 | - phy_write(mii_info, 0x1e, 0); | |
231 | - phy_write(mii_info, 0x1e, 0x100); | |
232 | - | |
233 | - gbit_config_aneg(mii_info); | |
234 | - | |
235 | - return 0; | |
236 | -} | |
237 | -static int genmii_config_aneg(struct gfar_mii_info *mii_info) | |
238 | -{ | |
239 | - if (mii_info->autoneg) { | |
240 | - config_genmii_advert(mii_info); | |
241 | - genmii_restart_aneg(mii_info); | |
242 | - } else | |
243 | - genmii_setup_forced(mii_info); | |
244 | - | |
245 | - return 0; | |
246 | -} | |
247 | - | |
248 | - | |
249 | -static int genmii_update_link(struct gfar_mii_info *mii_info) | |
250 | -{ | |
251 | - u16 status; | |
252 | - | |
253 | - /* Do a fake read */ | |
254 | - phy_read(mii_info, MII_BMSR); | |
255 | - | |
256 | - /* Read link and autonegotiation status */ | |
257 | - status = phy_read(mii_info, MII_BMSR); | |
258 | - if ((status & BMSR_LSTATUS) == 0) | |
259 | - mii_info->link = 0; | |
260 | - else | |
261 | - mii_info->link = 1; | |
262 | - | |
263 | - /* If we are autonegotiating, and not done, | |
264 | - * return an error */ | |
265 | - if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) | |
266 | - return -EAGAIN; | |
267 | - | |
268 | - return 0; | |
269 | -} | |
270 | - | |
271 | -static int genmii_read_status(struct gfar_mii_info *mii_info) | |
272 | -{ | |
273 | - u16 status; | |
274 | - int err; | |
275 | - | |
276 | - /* Update the link, but return if there | |
277 | - * was an error */ | |
278 | - err = genmii_update_link(mii_info); | |
279 | - if (err) | |
280 | - return err; | |
281 | - | |
282 | - if (mii_info->autoneg) { | |
283 | - status = phy_read(mii_info, MII_LPA); | |
284 | - | |
285 | - if (status & (LPA_10FULL | LPA_100FULL)) | |
286 | - mii_info->duplex = DUPLEX_FULL; | |
287 | - else | |
288 | - mii_info->duplex = DUPLEX_HALF; | |
289 | - if (status & (LPA_100FULL | LPA_100HALF)) | |
290 | - mii_info->speed = SPEED_100; | |
291 | - else | |
292 | - mii_info->speed = SPEED_10; | |
293 | - mii_info->pause = 0; | |
294 | - } | |
295 | - /* On non-aneg, we assume what we put in BMCR is the speed, | |
296 | - * though magic-aneg shouldn't prevent this case from occurring | |
297 | - */ | |
298 | - | |
299 | - return 0; | |
300 | -} | |
301 | -static int marvell_read_status(struct gfar_mii_info *mii_info) | |
302 | -{ | |
303 | - u16 status; | |
304 | - int err; | |
305 | - | |
306 | - /* Update the link, but return if there | |
307 | - * was an error */ | |
308 | - err = genmii_update_link(mii_info); | |
309 | - if (err) | |
310 | - return err; | |
311 | - | |
312 | - /* If the link is up, read the speed and duplex */ | |
313 | - /* If we aren't autonegotiating, assume speeds | |
314 | - * are as set */ | |
315 | - if (mii_info->autoneg && mii_info->link) { | |
316 | - int speed; | |
317 | - status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); | |
318 | - | |
319 | -#if 0 | |
320 | - /* If speed and duplex aren't resolved, | |
321 | - * return an error. Isn't this handled | |
322 | - * by checking aneg? | |
323 | - */ | |
324 | - if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0) | |
325 | - return -EAGAIN; | |
326 | -#endif | |
327 | - | |
328 | - /* Get the duplexity */ | |
329 | - if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) | |
330 | - mii_info->duplex = DUPLEX_FULL; | |
331 | - else | |
332 | - mii_info->duplex = DUPLEX_HALF; | |
333 | - | |
334 | - /* Get the speed */ | |
335 | - speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; | |
336 | - switch(speed) { | |
337 | - case MII_M1011_PHY_SPEC_STATUS_1000: | |
338 | - mii_info->speed = SPEED_1000; | |
339 | - break; | |
340 | - case MII_M1011_PHY_SPEC_STATUS_100: | |
341 | - mii_info->speed = SPEED_100; | |
342 | - break; | |
343 | - default: | |
344 | - mii_info->speed = SPEED_10; | |
345 | - break; | |
346 | - } | |
347 | - mii_info->pause = 0; | |
348 | - } | |
349 | - | |
350 | - return 0; | |
351 | -} | |
352 | - | |
353 | - | |
354 | -static int cis820x_read_status(struct gfar_mii_info *mii_info) | |
355 | -{ | |
356 | - u16 status; | |
357 | - int err; | |
358 | - | |
359 | - /* Update the link, but return if there | |
360 | - * was an error */ | |
361 | - err = genmii_update_link(mii_info); | |
362 | - if (err) | |
363 | - return err; | |
364 | - | |
365 | - /* If the link is up, read the speed and duplex */ | |
366 | - /* If we aren't autonegotiating, assume speeds | |
367 | - * are as set */ | |
368 | - if (mii_info->autoneg && mii_info->link) { | |
369 | - int speed; | |
370 | - | |
371 | - status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); | |
372 | - if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) | |
373 | - mii_info->duplex = DUPLEX_FULL; | |
374 | - else | |
375 | - mii_info->duplex = DUPLEX_HALF; | |
376 | - | |
377 | - speed = status & MII_CIS8201_AUXCONSTAT_SPEED; | |
378 | - | |
379 | - switch (speed) { | |
380 | - case MII_CIS8201_AUXCONSTAT_GBIT: | |
381 | - mii_info->speed = SPEED_1000; | |
382 | - break; | |
383 | - case MII_CIS8201_AUXCONSTAT_100: | |
384 | - mii_info->speed = SPEED_100; | |
385 | - break; | |
386 | - default: | |
387 | - mii_info->speed = SPEED_10; | |
388 | - break; | |
389 | - } | |
390 | - } | |
391 | - | |
392 | - return 0; | |
393 | -} | |
394 | - | |
395 | -static int marvell_ack_interrupt(struct gfar_mii_info *mii_info) | |
396 | -{ | |
397 | - /* Clear the interrupts by reading the reg */ | |
398 | - phy_read(mii_info, MII_M1011_IEVENT); | |
399 | - | |
400 | - return 0; | |
401 | -} | |
402 | - | |
403 | -static int marvell_config_intr(struct gfar_mii_info *mii_info) | |
404 | -{ | |
405 | - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) | |
406 | - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); | |
407 | - else | |
408 | - phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); | |
409 | - | |
410 | - return 0; | |
411 | -} | |
412 | - | |
413 | -static int cis820x_init(struct gfar_mii_info *mii_info) | |
414 | -{ | |
415 | - phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, | |
416 | - MII_CIS8201_AUXCONSTAT_INIT); | |
417 | - phy_write(mii_info, MII_CIS8201_EXT_CON1, | |
418 | - MII_CIS8201_EXTCON1_INIT); | |
419 | - | |
420 | - return 0; | |
421 | -} | |
422 | - | |
423 | -static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info) | |
424 | -{ | |
425 | - phy_read(mii_info, MII_CIS8201_ISTAT); | |
426 | - | |
427 | - return 0; | |
428 | -} | |
429 | - | |
430 | -static int cis820x_config_intr(struct gfar_mii_info *mii_info) | |
431 | -{ | |
432 | - if(mii_info->interrupts == MII_INTERRUPT_ENABLED) | |
433 | - phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); | |
434 | - else | |
435 | - phy_write(mii_info, MII_CIS8201_IMASK, 0); | |
436 | - | |
437 | - return 0; | |
438 | -} | |
439 | - | |
440 | -#define DM9161_DELAY 10 | |
441 | - | |
442 | -static int dm9161_read_status(struct gfar_mii_info *mii_info) | |
443 | -{ | |
444 | - u16 status; | |
445 | - int err; | |
446 | - | |
447 | - /* Update the link, but return if there | |
448 | - * was an error */ | |
449 | - err = genmii_update_link(mii_info); | |
450 | - if (err) | |
451 | - return err; | |
452 | - | |
453 | - /* If the link is up, read the speed and duplex */ | |
454 | - /* If we aren't autonegotiating, assume speeds | |
455 | - * are as set */ | |
456 | - if (mii_info->autoneg && mii_info->link) { | |
457 | - status = phy_read(mii_info, MII_DM9161_SCSR); | |
458 | - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) | |
459 | - mii_info->speed = SPEED_100; | |
460 | - else | |
461 | - mii_info->speed = SPEED_10; | |
462 | - | |
463 | - if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) | |
464 | - mii_info->duplex = DUPLEX_FULL; | |
465 | - else | |
466 | - mii_info->duplex = DUPLEX_HALF; | |
467 | - } | |
468 | - | |
469 | - return 0; | |
470 | -} | |
471 | - | |
472 | - | |
473 | -static int dm9161_config_aneg(struct gfar_mii_info *mii_info) | |
474 | -{ | |
475 | - struct dm9161_private *priv = mii_info->priv; | |
476 | - | |
477 | - if(0 == priv->resetdone) | |
478 | - return -EAGAIN; | |
479 | - | |
480 | - return 0; | |
481 | -} | |
482 | - | |
483 | -static void dm9161_timer(unsigned long data) | |
484 | -{ | |
485 | - struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data; | |
486 | - struct dm9161_private *priv = mii_info->priv; | |
487 | - u16 status = phy_read(mii_info, MII_BMSR); | |
488 | - | |
489 | - if (status & BMSR_ANEGCOMPLETE) { | |
490 | - priv->resetdone = 1; | |
491 | - } else | |
492 | - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | |
493 | -} | |
494 | - | |
495 | -static int dm9161_init(struct gfar_mii_info *mii_info) | |
496 | -{ | |
497 | - struct dm9161_private *priv; | |
498 | - | |
499 | - /* Allocate the private data structure */ | |
500 | - priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); | |
501 | - | |
502 | - if (NULL == priv) | |
503 | - return -ENOMEM; | |
504 | - | |
505 | - mii_info->priv = priv; | |
506 | - | |
507 | - /* Reset is not done yet */ | |
508 | - priv->resetdone = 0; | |
509 | - | |
510 | - /* Isolate the PHY */ | |
511 | - phy_write(mii_info, MII_BMCR, BMCR_ISOLATE); | |
512 | - | |
513 | - /* Do not bypass the scrambler/descrambler */ | |
514 | - phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); | |
515 | - | |
516 | - /* Clear 10BTCSR to default */ | |
517 | - phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); | |
518 | - | |
519 | - /* Reconnect the PHY, and enable Autonegotiation */ | |
520 | - phy_write(mii_info, MII_BMCR, BMCR_ANENABLE); | |
521 | - | |
522 | - /* Start a timer for DM9161_DELAY seconds to wait | |
523 | - * for the PHY to be ready */ | |
524 | - init_timer(&priv->timer); | |
525 | - priv->timer.function = &dm9161_timer; | |
526 | - priv->timer.data = (unsigned long) mii_info; | |
527 | - mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | |
528 | - | |
529 | - return 0; | |
530 | -} | |
531 | - | |
532 | -static void dm9161_close(struct gfar_mii_info *mii_info) | |
533 | -{ | |
534 | - struct dm9161_private *priv = mii_info->priv; | |
535 | - | |
536 | - del_timer_sync(&priv->timer); | |
537 | - kfree(priv); | |
538 | -} | |
539 | - | |
540 | -#if 0 | |
541 | -static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info) | |
542 | -{ | |
543 | - phy_read(mii_info, MII_DM9161_INTR); | |
544 | - | |
545 | - return 0; | |
546 | -} | |
547 | -#endif | |
548 | - | |
549 | -/* Cicada 820x */ | |
550 | -static struct phy_info phy_info_cis820x = { | |
551 | - 0x000fc440, | |
552 | - "Cicada Cis8204", | |
553 | - 0x000fffc0, | |
554 | - .features = MII_GBIT_FEATURES, | |
555 | - .init = &cis820x_init, | |
556 | - .config_aneg = &gbit_config_aneg, | |
557 | - .read_status = &cis820x_read_status, | |
558 | - .ack_interrupt = &cis820x_ack_interrupt, | |
559 | - .config_intr = &cis820x_config_intr, | |
560 | -}; | |
561 | - | |
562 | -static struct phy_info phy_info_dm9161 = { | |
563 | - .phy_id = 0x0181b880, | |
564 | - .name = "Davicom DM9161E", | |
565 | - .phy_id_mask = 0x0ffffff0, | |
566 | - .init = dm9161_init, | |
567 | - .config_aneg = dm9161_config_aneg, | |
568 | - .read_status = dm9161_read_status, | |
569 | - .close = dm9161_close, | |
570 | -}; | |
571 | - | |
572 | -static struct phy_info phy_info_marvell = { | |
573 | - .phy_id = 0x01410c00, | |
574 | - .phy_id_mask = 0xffffff00, | |
575 | - .name = "Marvell 88E1101/88E1111", | |
576 | - .features = MII_GBIT_FEATURES, | |
577 | - .config_aneg = &marvell_config_aneg, | |
578 | - .read_status = &marvell_read_status, | |
579 | - .ack_interrupt = &marvell_ack_interrupt, | |
580 | - .config_intr = &marvell_config_intr, | |
581 | -}; | |
582 | - | |
583 | -static struct phy_info phy_info_genmii= { | |
584 | - .phy_id = 0x00000000, | |
585 | - .phy_id_mask = 0x00000000, | |
586 | - .name = "Generic MII", | |
587 | - .features = MII_BASIC_FEATURES, | |
588 | - .config_aneg = genmii_config_aneg, | |
589 | - .read_status = genmii_read_status, | |
590 | -}; | |
591 | - | |
592 | -static struct phy_info *phy_info[] = { | |
593 | - &phy_info_cis820x, | |
594 | - &phy_info_marvell, | |
595 | - &phy_info_dm9161, | |
596 | - &phy_info_genmii, | |
597 | - NULL | |
598 | -}; | |
599 | - | |
600 | -u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum) | |
601 | -{ | |
602 | - u16 retval; | |
603 | - unsigned long flags; | |
604 | - | |
605 | - spin_lock_irqsave(&mii_info->mdio_lock, flags); | |
606 | - retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); | |
607 | - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | |
608 | - | |
609 | - return retval; | |
610 | -} | |
611 | - | |
612 | -void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val) | |
613 | -{ | |
614 | - unsigned long flags; | |
615 | - | |
616 | - spin_lock_irqsave(&mii_info->mdio_lock, flags); | |
617 | - mii_info->mdio_write(mii_info->dev, | |
618 | - mii_info->mii_id, | |
619 | - regnum, val); | |
620 | - spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | |
621 | -} | |
622 | - | |
623 | -/* Use the PHY ID registers to determine what type of PHY is attached | |
624 | - * to device dev. return a struct phy_info structure describing that PHY | |
625 | - */ | |
626 | -struct phy_info * get_phy_info(struct gfar_mii_info *mii_info) | |
627 | -{ | |
628 | - u16 phy_reg; | |
629 | - u32 phy_ID; | |
630 | - int i; | |
631 | - struct phy_info *theInfo = NULL; | |
632 | - struct net_device *dev = mii_info->dev; | |
633 | - | |
634 | - /* Grab the bits from PHYIR1, and put them in the upper half */ | |
635 | - phy_reg = phy_read(mii_info, MII_PHYSID1); | |
636 | - phy_ID = (phy_reg & 0xffff) << 16; | |
637 | - | |
638 | - /* Grab the bits from PHYIR2, and put them in the lower half */ | |
639 | - phy_reg = phy_read(mii_info, MII_PHYSID2); | |
640 | - phy_ID |= (phy_reg & 0xffff); | |
641 | - | |
642 | - /* loop through all the known PHY types, and find one that */ | |
643 | - /* matches the ID we read from the PHY. */ | |
644 | - for (i = 0; phy_info[i]; i++) | |
645 | - if (phy_info[i]->phy_id == | |
646 | - (phy_ID & phy_info[i]->phy_id_mask)) { | |
647 | - theInfo = phy_info[i]; | |
648 | - break; | |
649 | - } | |
650 | - | |
651 | - /* This shouldn't happen, as we have generic PHY support */ | |
652 | - if (theInfo == NULL) { | |
653 | - printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID); | |
654 | - return NULL; | |
655 | - } else { | |
656 | - printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name, | |
657 | - phy_ID); | |
658 | - } | |
659 | - | |
660 | - return theInfo; | |
661 | -} |
drivers/net/gianfar_phy.h
1 | -/* | |
2 | - * drivers/net/gianfar_phy.h | |
3 | - * | |
4 | - * Gianfar Ethernet Driver -- PHY handling | |
5 | - * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560 | |
6 | - * Based on 8260_io/fcc_enet.c | |
7 | - * | |
8 | - * Author: Andy Fleming | |
9 | - * Maintainer: Kumar Gala (kumar.gala@freescale.com) | |
10 | - * | |
11 | - * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | |
12 | - * | |
13 | - * This program is free software; you can redistribute it and/or modify it | |
14 | - * under the terms of the GNU General Public License as published by the | |
15 | - * Free Software Foundation; either version 2 of the License, or (at your | |
16 | - * option) any later version. | |
17 | - * | |
18 | - */ | |
19 | -#ifndef __GIANFAR_PHY_H | |
20 | -#define __GIANFAR_PHY_H | |
21 | - | |
22 | -#define MII_end ((u32)-2) | |
23 | -#define MII_read ((u32)-1) | |
24 | - | |
25 | -#define MIIMIND_BUSY 0x00000001 | |
26 | -#define MIIMIND_NOTVALID 0x00000004 | |
27 | - | |
28 | -#define GFAR_AN_TIMEOUT 2000 | |
29 | - | |
30 | -/* 1000BT control (Marvell & BCM54xx at least) */ | |
31 | -#define MII_1000BASETCONTROL 0x09 | |
32 | -#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 | |
33 | -#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 | |
34 | - | |
35 | -/* Cicada Extended Control Register 1 */ | |
36 | -#define MII_CIS8201_EXT_CON1 0x17 | |
37 | -#define MII_CIS8201_EXTCON1_INIT 0x0000 | |
38 | - | |
39 | -/* Cicada Interrupt Mask Register */ | |
40 | -#define MII_CIS8201_IMASK 0x19 | |
41 | -#define MII_CIS8201_IMASK_IEN 0x8000 | |
42 | -#define MII_CIS8201_IMASK_SPEED 0x4000 | |
43 | -#define MII_CIS8201_IMASK_LINK 0x2000 | |
44 | -#define MII_CIS8201_IMASK_DUPLEX 0x1000 | |
45 | -#define MII_CIS8201_IMASK_MASK 0xf000 | |
46 | - | |
47 | -/* Cicada Interrupt Status Register */ | |
48 | -#define MII_CIS8201_ISTAT 0x1a | |
49 | -#define MII_CIS8201_ISTAT_STATUS 0x8000 | |
50 | -#define MII_CIS8201_ISTAT_SPEED 0x4000 | |
51 | -#define MII_CIS8201_ISTAT_LINK 0x2000 | |
52 | -#define MII_CIS8201_ISTAT_DUPLEX 0x1000 | |
53 | - | |
54 | -/* Cicada Auxiliary Control/Status Register */ | |
55 | -#define MII_CIS8201_AUX_CONSTAT 0x1c | |
56 | -#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 | |
57 | -#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 | |
58 | -#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 | |
59 | -#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 | |
60 | -#define MII_CIS8201_AUXCONSTAT_100 0x0008 | |
61 | - | |
62 | -/* 88E1011 PHY Status Register */ | |
63 | -#define MII_M1011_PHY_SPEC_STATUS 0x11 | |
64 | -#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 | |
65 | -#define MII_M1011_PHY_SPEC_STATUS_100 0x4000 | |
66 | -#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 | |
67 | -#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 | |
68 | -#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 | |
69 | -#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 | |
70 | - | |
71 | -#define MII_M1011_IEVENT 0x13 | |
72 | -#define MII_M1011_IEVENT_CLEAR 0x0000 | |
73 | - | |
74 | -#define MII_M1011_IMASK 0x12 | |
75 | -#define MII_M1011_IMASK_INIT 0x6400 | |
76 | -#define MII_M1011_IMASK_CLEAR 0x0000 | |
77 | - | |
78 | -#define MII_DM9161_SCR 0x10 | |
79 | -#define MII_DM9161_SCR_INIT 0x0610 | |
80 | - | |
81 | -/* DM9161 Specified Configuration and Status Register */ | |
82 | -#define MII_DM9161_SCSR 0x11 | |
83 | -#define MII_DM9161_SCSR_100F 0x8000 | |
84 | -#define MII_DM9161_SCSR_100H 0x4000 | |
85 | -#define MII_DM9161_SCSR_10F 0x2000 | |
86 | -#define MII_DM9161_SCSR_10H 0x1000 | |
87 | - | |
88 | -/* DM9161 Interrupt Register */ | |
89 | -#define MII_DM9161_INTR 0x15 | |
90 | -#define MII_DM9161_INTR_PEND 0x8000 | |
91 | -#define MII_DM9161_INTR_DPLX_MASK 0x0800 | |
92 | -#define MII_DM9161_INTR_SPD_MASK 0x0400 | |
93 | -#define MII_DM9161_INTR_LINK_MASK 0x0200 | |
94 | -#define MII_DM9161_INTR_MASK 0x0100 | |
95 | -#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 | |
96 | -#define MII_DM9161_INTR_SPD_CHANGE 0x0008 | |
97 | -#define MII_DM9161_INTR_LINK_CHANGE 0x0004 | |
98 | -#define MII_DM9161_INTR_INIT 0x0000 | |
99 | -#define MII_DM9161_INTR_STOP \ | |
100 | -(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ | |
101 | - | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) | |
102 | - | |
103 | -/* DM9161 10BT Configuration/Status */ | |
104 | -#define MII_DM9161_10BTCSR 0x12 | |
105 | -#define MII_DM9161_10BTCSR_INIT 0x7800 | |
106 | - | |
107 | -#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ | |
108 | - SUPPORTED_10baseT_Full | \ | |
109 | - SUPPORTED_100baseT_Half | \ | |
110 | - SUPPORTED_100baseT_Full | \ | |
111 | - SUPPORTED_Autoneg | \ | |
112 | - SUPPORTED_TP | \ | |
113 | - SUPPORTED_MII) | |
114 | - | |
115 | -#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ | |
116 | - SUPPORTED_1000baseT_Half | \ | |
117 | - SUPPORTED_1000baseT_Full) | |
118 | - | |
119 | -#define MII_READ_COMMAND 0x00000001 | |
120 | - | |
121 | -#define MII_INTERRUPT_DISABLED 0x0 | |
122 | -#define MII_INTERRUPT_ENABLED 0x1 | |
123 | -/* Taken from mii_if_info and sungem_phy.h */ | |
124 | -struct gfar_mii_info { | |
125 | - /* Information about the PHY type */ | |
126 | - /* And management functions */ | |
127 | - struct phy_info *phyinfo; | |
128 | - | |
129 | - /* forced speed & duplex (no autoneg) | |
130 | - * partner speed & duplex & pause (autoneg) | |
131 | - */ | |
132 | - int speed; | |
133 | - int duplex; | |
134 | - int pause; | |
135 | - | |
136 | - /* The most recently read link state */ | |
137 | - int link; | |
138 | - | |
139 | - /* Enabled Interrupts */ | |
140 | - u32 interrupts; | |
141 | - | |
142 | - u32 advertising; | |
143 | - int autoneg; | |
144 | - int mii_id; | |
145 | - | |
146 | - /* private data pointer */ | |
147 | - /* For use by PHYs to maintain extra state */ | |
148 | - void *priv; | |
149 | - | |
150 | - /* Provided by host chip */ | |
151 | - struct net_device *dev; | |
152 | - | |
153 | - /* A lock to ensure that only one thing can read/write | |
154 | - * the MDIO bus at a time */ | |
155 | - spinlock_t mdio_lock; | |
156 | - | |
157 | - /* Provided by ethernet driver */ | |
158 | - int (*mdio_read) (struct net_device *dev, int mii_id, int reg); | |
159 | - void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val); | |
160 | -}; | |
161 | - | |
162 | -/* struct phy_info: a structure which defines attributes for a PHY | |
163 | - * | |
164 | - * id will contain a number which represents the PHY. During | |
165 | - * startup, the driver will poll the PHY to find out what its | |
166 | - * UID--as defined by registers 2 and 3--is. The 32-bit result | |
167 | - * gotten from the PHY will be ANDed with phy_id_mask to | |
168 | - * discard any bits which may change based on revision numbers | |
169 | - * unimportant to functionality | |
170 | - * | |
171 | - * There are 6 commands which take a gfar_mii_info structure. | |
172 | - * Each PHY must declare config_aneg, and read_status. | |
173 | - */ | |
174 | -struct phy_info { | |
175 | - u32 phy_id; | |
176 | - char *name; | |
177 | - unsigned int phy_id_mask; | |
178 | - u32 features; | |
179 | - | |
180 | - /* Called to initialize the PHY */ | |
181 | - int (*init)(struct gfar_mii_info *mii_info); | |
182 | - | |
183 | - /* Called to suspend the PHY for power */ | |
184 | - int (*suspend)(struct gfar_mii_info *mii_info); | |
185 | - | |
186 | - /* Reconfigures autonegotiation (or disables it) */ | |
187 | - int (*config_aneg)(struct gfar_mii_info *mii_info); | |
188 | - | |
189 | - /* Determines the negotiated speed and duplex */ | |
190 | - int (*read_status)(struct gfar_mii_info *mii_info); | |
191 | - | |
192 | - /* Clears any pending interrupts */ | |
193 | - int (*ack_interrupt)(struct gfar_mii_info *mii_info); | |
194 | - | |
195 | - /* Enables or disables interrupts */ | |
196 | - int (*config_intr)(struct gfar_mii_info *mii_info); | |
197 | - | |
198 | - /* Clears up any memory if needed */ | |
199 | - void (*close)(struct gfar_mii_info *mii_info); | |
200 | -}; | |
201 | - | |
202 | -struct phy_info *get_phy_info(struct gfar_mii_info *mii_info); | |
203 | -int read_phy_reg(struct net_device *dev, int mii_id, int regnum); | |
204 | -void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); | |
205 | -void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info); | |
206 | -void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts); | |
207 | - | |
208 | -struct dm9161_private { | |
209 | - struct timer_list timer; | |
210 | - int resetdone; | |
211 | -}; | |
212 | - | |
213 | -#endif /* GIANFAR_PHY_H */ |