diff options
Diffstat (limited to 'drivers/net/cpmac.c')
-rw-r--r-- | drivers/net/cpmac.c | 145 |
1 files changed, 87 insertions, 58 deletions
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 57541d2d9e..6fd95a2c8c 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/skbuff.h> | 34 | #include <linux/skbuff.h> |
35 | #include <linux/mii.h> | 35 | #include <linux/mii.h> |
36 | #include <linux/phy.h> | 36 | #include <linux/phy.h> |
37 | #include <linux/phy_fixed.h> | ||
37 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
38 | #include <linux/dma-mapping.h> | 39 | #include <linux/dma-mapping.h> |
39 | #include <asm/gpio.h> | 40 | #include <asm/gpio.h> |
@@ -53,12 +54,6 @@ MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); | |||
53 | MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); | 54 | MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); |
54 | 55 | ||
55 | #define CPMAC_VERSION "0.5.0" | 56 | #define CPMAC_VERSION "0.5.0" |
56 | /* stolen from net/ieee80211.h */ | ||
57 | #ifndef MAC_FMT | ||
58 | #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" | ||
59 | #define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ | ||
60 | ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] | ||
61 | #endif | ||
62 | /* frame size + 802.1q tag */ | 57 | /* frame size + 802.1q tag */ |
63 | #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) | 58 | #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) |
64 | #define CPMAC_QUEUES 8 | 59 | #define CPMAC_QUEUES 8 |
@@ -211,6 +206,7 @@ struct cpmac_priv { | |||
211 | struct net_device *dev; | 206 | struct net_device *dev; |
212 | struct work_struct reset_work; | 207 | struct work_struct reset_work; |
213 | struct platform_device *pdev; | 208 | struct platform_device *pdev; |
209 | struct napi_struct napi; | ||
214 | }; | 210 | }; |
215 | 211 | ||
216 | static irqreturn_t cpmac_irq(int, void *); | 212 | static irqreturn_t cpmac_irq(int, void *); |
@@ -362,47 +358,48 @@ static void cpmac_set_multicast_list(struct net_device *dev) | |||
362 | } | 358 | } |
363 | } | 359 | } |
364 | 360 | ||
365 | static struct sk_buff *cpmac_rx_one(struct net_device *dev, | 361 | static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv, |
366 | struct cpmac_priv *priv, | ||
367 | struct cpmac_desc *desc) | 362 | struct cpmac_desc *desc) |
368 | { | 363 | { |
369 | struct sk_buff *skb, *result = NULL; | 364 | struct sk_buff *skb, *result = NULL; |
370 | 365 | ||
371 | if (unlikely(netif_msg_hw(priv))) | 366 | if (unlikely(netif_msg_hw(priv))) |
372 | cpmac_dump_desc(dev, desc); | 367 | cpmac_dump_desc(priv->dev, desc); |
373 | cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping); | 368 | cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping); |
374 | if (unlikely(!desc->datalen)) { | 369 | if (unlikely(!desc->datalen)) { |
375 | if (netif_msg_rx_err(priv) && net_ratelimit()) | 370 | if (netif_msg_rx_err(priv) && net_ratelimit()) |
376 | printk(KERN_WARNING "%s: rx: spurious interrupt\n", | 371 | printk(KERN_WARNING "%s: rx: spurious interrupt\n", |
377 | dev->name); | 372 | priv->dev->name); |
378 | return NULL; | 373 | return NULL; |
379 | } | 374 | } |
380 | 375 | ||
381 | skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); | 376 | skb = netdev_alloc_skb(priv->dev, CPMAC_SKB_SIZE); |
382 | if (likely(skb)) { | 377 | if (likely(skb)) { |
383 | skb_reserve(skb, 2); | 378 | skb_reserve(skb, 2); |
384 | skb_put(desc->skb, desc->datalen); | 379 | skb_put(desc->skb, desc->datalen); |
385 | desc->skb->protocol = eth_type_trans(desc->skb, dev); | 380 | desc->skb->protocol = eth_type_trans(desc->skb, priv->dev); |
386 | desc->skb->ip_summed = CHECKSUM_NONE; | 381 | desc->skb->ip_summed = CHECKSUM_NONE; |
387 | dev->stats.rx_packets++; | 382 | priv->dev->stats.rx_packets++; |
388 | dev->stats.rx_bytes += desc->datalen; | 383 | priv->dev->stats.rx_bytes += desc->datalen; |
389 | result = desc->skb; | 384 | result = desc->skb; |
390 | dma_unmap_single(&dev->dev, desc->data_mapping, CPMAC_SKB_SIZE, | 385 | dma_unmap_single(&priv->dev->dev, desc->data_mapping, |
391 | DMA_FROM_DEVICE); | 386 | CPMAC_SKB_SIZE, DMA_FROM_DEVICE); |
392 | desc->skb = skb; | 387 | desc->skb = skb; |
393 | desc->data_mapping = dma_map_single(&dev->dev, skb->data, | 388 | desc->data_mapping = dma_map_single(&priv->dev->dev, skb->data, |
394 | CPMAC_SKB_SIZE, | 389 | CPMAC_SKB_SIZE, |
395 | DMA_FROM_DEVICE); | 390 | DMA_FROM_DEVICE); |
396 | desc->hw_data = (u32)desc->data_mapping; | 391 | desc->hw_data = (u32)desc->data_mapping; |
397 | if (unlikely(netif_msg_pktdata(priv))) { | 392 | if (unlikely(netif_msg_pktdata(priv))) { |
398 | printk(KERN_DEBUG "%s: received packet:\n", dev->name); | 393 | printk(KERN_DEBUG "%s: received packet:\n", |
399 | cpmac_dump_skb(dev, result); | 394 | priv->dev->name); |
395 | cpmac_dump_skb(priv->dev, result); | ||
400 | } | 396 | } |
401 | } else { | 397 | } else { |
402 | if (netif_msg_rx_err(priv) && net_ratelimit()) | 398 | if (netif_msg_rx_err(priv) && net_ratelimit()) |
403 | printk(KERN_WARNING | 399 | printk(KERN_WARNING |
404 | "%s: low on skbs, dropping packet\n", dev->name); | 400 | "%s: low on skbs, dropping packet\n", |
405 | dev->stats.rx_dropped++; | 401 | priv->dev->name); |
402 | priv->dev->stats.rx_dropped++; | ||
406 | } | 403 | } |
407 | 404 | ||
408 | desc->buflen = CPMAC_SKB_SIZE; | 405 | desc->buflen = CPMAC_SKB_SIZE; |
@@ -411,25 +408,25 @@ static struct sk_buff *cpmac_rx_one(struct net_device *dev, | |||
411 | return result; | 408 | return result; |
412 | } | 409 | } |
413 | 410 | ||
414 | static int cpmac_poll(struct net_device *dev, int *budget) | 411 | static int cpmac_poll(struct napi_struct *napi, int budget) |
415 | { | 412 | { |
416 | struct sk_buff *skb; | 413 | struct sk_buff *skb; |
417 | struct cpmac_desc *desc; | 414 | struct cpmac_desc *desc; |
418 | int received = 0, quota = min(dev->quota, *budget); | 415 | int received = 0; |
419 | struct cpmac_priv *priv = netdev_priv(dev); | 416 | struct cpmac_priv *priv = container_of(napi, struct cpmac_priv, napi); |
420 | 417 | ||
421 | spin_lock(&priv->rx_lock); | 418 | spin_lock(&priv->rx_lock); |
422 | if (unlikely(!priv->rx_head)) { | 419 | if (unlikely(!priv->rx_head)) { |
423 | if (netif_msg_rx_err(priv) && net_ratelimit()) | 420 | if (netif_msg_rx_err(priv) && net_ratelimit()) |
424 | printk(KERN_WARNING "%s: rx: polling, but no queue\n", | 421 | printk(KERN_WARNING "%s: rx: polling, but no queue\n", |
425 | dev->name); | 422 | priv->dev->name); |
426 | netif_rx_complete(dev); | 423 | netif_rx_complete(priv->dev, napi); |
427 | return 0; | 424 | return 0; |
428 | } | 425 | } |
429 | 426 | ||
430 | desc = priv->rx_head; | 427 | desc = priv->rx_head; |
431 | while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) { | 428 | while (((desc->dataflags & CPMAC_OWN) == 0) && (received < budget)) { |
432 | skb = cpmac_rx_one(dev, priv, desc); | 429 | skb = cpmac_rx_one(priv, desc); |
433 | if (likely(skb)) { | 430 | if (likely(skb)) { |
434 | netif_receive_skb(skb); | 431 | netif_receive_skb(skb); |
435 | received++; | 432 | received++; |
@@ -439,13 +436,11 @@ static int cpmac_poll(struct net_device *dev, int *budget) | |||
439 | 436 | ||
440 | priv->rx_head = desc; | 437 | priv->rx_head = desc; |
441 | spin_unlock(&priv->rx_lock); | 438 | spin_unlock(&priv->rx_lock); |
442 | *budget -= received; | ||
443 | dev->quota -= received; | ||
444 | if (unlikely(netif_msg_rx_status(priv))) | 439 | if (unlikely(netif_msg_rx_status(priv))) |
445 | printk(KERN_DEBUG "%s: poll processed %d packets\n", dev->name, | 440 | printk(KERN_DEBUG "%s: poll processed %d packets\n", |
446 | received); | 441 | priv->dev->name, received); |
447 | if (desc->dataflags & CPMAC_OWN) { | 442 | if (desc->dataflags & CPMAC_OWN) { |
448 | netif_rx_complete(dev); | 443 | netif_rx_complete(priv->dev, napi); |
449 | cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping); | 444 | cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping); |
450 | cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); | 445 | cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); |
451 | return 0; | 446 | return 0; |
@@ -655,6 +650,7 @@ static void cpmac_hw_error(struct work_struct *work) | |||
655 | spin_unlock(&priv->rx_lock); | 650 | spin_unlock(&priv->rx_lock); |
656 | cpmac_clear_tx(priv->dev); | 651 | cpmac_clear_tx(priv->dev); |
657 | cpmac_hw_start(priv->dev); | 652 | cpmac_hw_start(priv->dev); |
653 | napi_enable(&priv->napi); | ||
658 | netif_start_queue(priv->dev); | 654 | netif_start_queue(priv->dev); |
659 | } | 655 | } |
660 | 656 | ||
@@ -681,8 +677,10 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) | |||
681 | 677 | ||
682 | if (status & MAC_INT_RX) { | 678 | if (status & MAC_INT_RX) { |
683 | queue = (status >> 8) & 7; | 679 | queue = (status >> 8) & 7; |
684 | netif_rx_schedule(dev); | 680 | if (netif_rx_schedule_prep(dev, &priv->napi)) { |
685 | cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); | 681 | cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); |
682 | __netif_rx_schedule(dev, &priv->napi); | ||
683 | } | ||
686 | } | 684 | } |
687 | 685 | ||
688 | cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); | 686 | cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); |
@@ -692,6 +690,7 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) | |||
692 | printk(KERN_ERR "%s: hw error, resetting...\n", | 690 | printk(KERN_ERR "%s: hw error, resetting...\n", |
693 | dev->name); | 691 | dev->name); |
694 | netif_stop_queue(dev); | 692 | netif_stop_queue(dev); |
693 | napi_disable(&priv->napi); | ||
695 | cpmac_hw_stop(dev); | 694 | cpmac_hw_stop(dev); |
696 | schedule_work(&priv->reset_work); | 695 | schedule_work(&priv->reset_work); |
697 | if (unlikely(netif_msg_hw(priv))) | 696 | if (unlikely(netif_msg_hw(priv))) |
@@ -849,6 +848,15 @@ static void cpmac_adjust_link(struct net_device *dev) | |||
849 | spin_unlock(&priv->lock); | 848 | spin_unlock(&priv->lock); |
850 | } | 849 | } |
851 | 850 | ||
851 | static int cpmac_link_update(struct net_device *dev, | ||
852 | struct fixed_phy_status *status) | ||
853 | { | ||
854 | status->link = 1; | ||
855 | status->speed = 100; | ||
856 | status->duplex = 1; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
852 | static int cpmac_open(struct net_device *dev) | 860 | static int cpmac_open(struct net_device *dev) |
853 | { | 861 | { |
854 | int i, size, res; | 862 | int i, size, res; |
@@ -857,15 +865,6 @@ static int cpmac_open(struct net_device *dev) | |||
857 | struct cpmac_desc *desc; | 865 | struct cpmac_desc *desc; |
858 | struct sk_buff *skb; | 866 | struct sk_buff *skb; |
859 | 867 | ||
860 | priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, | ||
861 | 0, PHY_INTERFACE_MODE_MII); | ||
862 | if (IS_ERR(priv->phy)) { | ||
863 | if (netif_msg_drv(priv)) | ||
864 | printk(KERN_ERR "%s: Could not attach to PHY\n", | ||
865 | dev->name); | ||
866 | return PTR_ERR(priv->phy); | ||
867 | } | ||
868 | |||
869 | mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); | 868 | mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); |
870 | if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) { | 869 | if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) { |
871 | if (netif_msg_drv(priv)) | 870 | if (netif_msg_drv(priv)) |
@@ -927,6 +926,7 @@ static int cpmac_open(struct net_device *dev) | |||
927 | INIT_WORK(&priv->reset_work, cpmac_hw_error); | 926 | INIT_WORK(&priv->reset_work, cpmac_hw_error); |
928 | cpmac_hw_start(dev); | 927 | cpmac_hw_start(dev); |
929 | 928 | ||
929 | napi_enable(&priv->napi); | ||
930 | priv->phy->state = PHY_CHANGELINK; | 930 | priv->phy->state = PHY_CHANGELINK; |
931 | phy_start(priv->phy); | 931 | phy_start(priv->phy); |
932 | 932 | ||
@@ -951,8 +951,6 @@ fail_remap: | |||
951 | release_mem_region(mem->start, mem->end - mem->start); | 951 | release_mem_region(mem->start, mem->end - mem->start); |
952 | 952 | ||
953 | fail_reserve: | 953 | fail_reserve: |
954 | phy_disconnect(priv->phy); | ||
955 | |||
956 | return res; | 954 | return res; |
957 | } | 955 | } |
958 | 956 | ||
@@ -965,9 +963,8 @@ static int cpmac_stop(struct net_device *dev) | |||
965 | netif_stop_queue(dev); | 963 | netif_stop_queue(dev); |
966 | 964 | ||
967 | cancel_work_sync(&priv->reset_work); | 965 | cancel_work_sync(&priv->reset_work); |
966 | napi_disable(&priv->napi); | ||
968 | phy_stop(priv->phy); | 967 | phy_stop(priv->phy); |
969 | phy_disconnect(priv->phy); | ||
970 | priv->phy = NULL; | ||
971 | 968 | ||
972 | cpmac_hw_stop(dev); | 969 | cpmac_hw_stop(dev); |
973 | 970 | ||
@@ -1001,11 +998,13 @@ static int external_switch; | |||
1001 | 998 | ||
1002 | static int __devinit cpmac_probe(struct platform_device *pdev) | 999 | static int __devinit cpmac_probe(struct platform_device *pdev) |
1003 | { | 1000 | { |
1004 | int rc, phy_id; | 1001 | int rc, phy_id, i; |
1005 | struct resource *mem; | 1002 | struct resource *mem; |
1006 | struct cpmac_priv *priv; | 1003 | struct cpmac_priv *priv; |
1007 | struct net_device *dev; | 1004 | struct net_device *dev; |
1008 | struct plat_cpmac_data *pdata; | 1005 | struct plat_cpmac_data *pdata; |
1006 | struct fixed_info *fixed_phy; | ||
1007 | DECLARE_MAC_BUF(mac); | ||
1009 | 1008 | ||
1010 | pdata = pdev->dev.platform_data; | 1009 | pdata = pdev->dev.platform_data; |
1011 | 1010 | ||
@@ -1053,21 +1052,51 @@ static int __devinit cpmac_probe(struct platform_device *pdev) | |||
1053 | dev->set_multicast_list = cpmac_set_multicast_list; | 1052 | dev->set_multicast_list = cpmac_set_multicast_list; |
1054 | dev->tx_timeout = cpmac_tx_timeout; | 1053 | dev->tx_timeout = cpmac_tx_timeout; |
1055 | dev->ethtool_ops = &cpmac_ethtool_ops; | 1054 | dev->ethtool_ops = &cpmac_ethtool_ops; |
1056 | dev->poll = cpmac_poll; | ||
1057 | dev->weight = 64; | ||
1058 | dev->features |= NETIF_F_MULTI_QUEUE; | 1055 | dev->features |= NETIF_F_MULTI_QUEUE; |
1059 | 1056 | ||
1057 | netif_napi_add(dev, &priv->napi, cpmac_poll, 64); | ||
1058 | |||
1060 | spin_lock_init(&priv->lock); | 1059 | spin_lock_init(&priv->lock); |
1061 | spin_lock_init(&priv->rx_lock); | 1060 | spin_lock_init(&priv->rx_lock); |
1062 | priv->dev = dev; | 1061 | priv->dev = dev; |
1063 | priv->ring_size = 64; | 1062 | priv->ring_size = 64; |
1064 | priv->msg_enable = netif_msg_init(debug_level, 0xff); | 1063 | priv->msg_enable = netif_msg_init(debug_level, 0xff); |
1065 | memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); | 1064 | memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); |
1065 | |||
1066 | if (phy_id == 31) { | 1066 | if (phy_id == 31) { |
1067 | snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, | 1067 | snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id, |
1068 | cpmac_mii.id, phy_id); | 1068 | phy_id); |
1069 | } else | 1069 | } else { |
1070 | snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1); | 1070 | /* Let's try to get a free fixed phy... */ |
1071 | for (i = 0; i < MAX_PHY_AMNT; i++) { | ||
1072 | fixed_phy = fixed_mdio_get_phydev(i); | ||
1073 | if (!fixed_phy) | ||
1074 | continue; | ||
1075 | if (!fixed_phy->phydev->attached_dev) { | ||
1076 | strncpy(priv->phy_name, | ||
1077 | fixed_phy->phydev->dev.bus_id, | ||
1078 | BUS_ID_SIZE); | ||
1079 | fixed_mdio_set_link_update(fixed_phy->phydev, | ||
1080 | &cpmac_link_update); | ||
1081 | goto phy_found; | ||
1082 | } | ||
1083 | } | ||
1084 | if (netif_msg_drv(priv)) | ||
1085 | printk(KERN_ERR "%s: Could not find fixed PHY\n", | ||
1086 | dev->name); | ||
1087 | rc = -ENODEV; | ||
1088 | goto fail; | ||
1089 | } | ||
1090 | |||
1091 | phy_found: | ||
1092 | priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0, | ||
1093 | PHY_INTERFACE_MODE_MII); | ||
1094 | if (IS_ERR(priv->phy)) { | ||
1095 | if (netif_msg_drv(priv)) | ||
1096 | printk(KERN_ERR "%s: Could not attach to PHY\n", | ||
1097 | dev->name); | ||
1098 | return PTR_ERR(priv->phy); | ||
1099 | } | ||
1071 | 1100 | ||
1072 | if ((rc = register_netdev(dev))) { | 1101 | if ((rc = register_netdev(dev))) { |
1073 | printk(KERN_ERR "cpmac: error %i registering device %s\n", rc, | 1102 | printk(KERN_ERR "cpmac: error %i registering device %s\n", rc, |
@@ -1077,9 +1106,9 @@ static int __devinit cpmac_probe(struct platform_device *pdev) | |||
1077 | 1106 | ||
1078 | if (netif_msg_probe(priv)) { | 1107 | if (netif_msg_probe(priv)) { |
1079 | printk(KERN_INFO | 1108 | printk(KERN_INFO |
1080 | "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: " | 1109 | "cpmac: device %s (regs: %p, irq: %d, phy: %s, " |
1081 | MAC_FMT ")\n", dev->name, (void *)mem->start, dev->irq, | 1110 | "mac: %s)\n", dev->name, (void *)mem->start, dev->irq, |
1082 | priv->phy_name, MAC_ARG(dev->dev_addr)); | 1111 | priv->phy_name, print_mac(mac, dev->dev_addr)); |
1083 | } | 1112 | } |
1084 | return 0; | 1113 | return 0; |
1085 | 1114 | ||