aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c78
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index bc95aacab20f..c057694cf047 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -76,7 +76,7 @@
76#define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) 76#define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le))
77#define RX_MAX_PENDING (RX_LE_SIZE/2 - 1) 77#define RX_MAX_PENDING (RX_LE_SIZE/2 - 1)
78#define RX_DEF_PENDING 128 78#define RX_DEF_PENDING 128
79#define RX_COPY_THRESHOLD 128 79#define RX_COPY_THRESHOLD 256
80 80
81#define TX_RING_SIZE 512 81#define TX_RING_SIZE 512
82#define TX_DEF_PENDING (TX_RING_SIZE - 1) 82#define TX_DEF_PENDING (TX_RING_SIZE - 1)
@@ -692,18 +692,10 @@ static void sky2_rx_clean(struct sky2_port *sky2)
692 } 692 }
693} 693}
694 694
695static inline struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2, 695#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
696 unsigned int size, 696static inline unsigned sky2_rx_size(const struct sky2_port *sky2)
697 unsigned int gfp_mask)
698{ 697{
699 struct sk_buff *skb; 698 return roundup(sky2->netdev->mtu + ETH_HLEN + 4, 8);
700
701 skb = alloc_skb(size + NET_IP_ALIGN, gfp_mask);
702 if (likely(skb)) {
703 skb->dev = sky2->netdev;
704 skb_reserve(skb, NET_IP_ALIGN);
705 }
706 return skb;
707} 699}
708 700
709/* 701/*
@@ -711,22 +703,28 @@ static inline struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2,
711 * In case of 64 bit dma, there are 2X as many list elements 703 * In case of 64 bit dma, there are 2X as many list elements
712 * available as ring entries 704 * available as ring entries
713 * and need to reserve one list element so we don't wrap around. 705 * and need to reserve one list element so we don't wrap around.
706 *
707 * It appears the hardware has a bug in the FIFO logic that
708 * cause it to hang if the FIFO gets overrun and the receive buffer
709 * is not aligned. This means we can't use skb_reserve to align
710 * the IP header.
714 */ 711 */
715static int sky2_rx_fill(struct sky2_port *sky2) 712static int sky2_rx_fill(struct sky2_port *sky2)
716{ 713{
717 unsigned i; 714 unsigned i;
718 const unsigned rx_buf_size = sky2->netdev->mtu + ETH_HLEN + 8; 715 unsigned size = sky2_rx_size(sky2);
719 716
717 pr_debug("rx_fill size=%d\n", size);
720 for (i = 0; i < sky2->rx_pending; i++) { 718 for (i = 0; i < sky2->rx_pending; i++) {
721 struct ring_info *re = sky2->rx_ring + i; 719 struct ring_info *re = sky2->rx_ring + i;
722 720
723 re->skb = sky2_rx_alloc(sky2, rx_buf_size, GFP_KERNEL); 721 re->skb = dev_alloc_skb(size);
724 if (!re->skb) 722 if (!re->skb)
725 goto nomem; 723 goto nomem;
726 724
727 re->mapaddr = pci_map_single(sky2->hw->pdev, re->skb->data, 725 re->mapaddr = pci_map_single(sky2->hw->pdev, re->skb->data,
728 rx_buf_size, PCI_DMA_FROMDEVICE); 726 size, PCI_DMA_FROMDEVICE);
729 re->maplen = rx_buf_size; 727 re->maplen = size;
730 sky2_rx_add(sky2, re); 728 sky2_rx_add(sky2, re);
731 } 729 }
732 730
@@ -1408,8 +1406,8 @@ static struct sk_buff *sky2_receive(struct sky2_hw *hw, unsigned port,
1408 struct net_device *dev = hw->dev[port]; 1406 struct net_device *dev = hw->dev[port];
1409 struct sky2_port *sky2 = netdev_priv(dev); 1407 struct sky2_port *sky2 = netdev_priv(dev);
1410 struct ring_info *re = sky2->rx_ring + sky2->rx_next; 1408 struct ring_info *re = sky2->rx_ring + sky2->rx_next;
1411 struct sk_buff *skb, *nskb; 1409 struct sk_buff *skb = NULL;
1412 const unsigned int rx_buf_size = dev->mtu + ETH_HLEN + 8; 1410 const unsigned int bufsize = sky2_rx_size(sky2);
1413 1411
1414 if (unlikely(netif_msg_rx_status(sky2))) 1412 if (unlikely(netif_msg_rx_status(sky2)))
1415 printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", 1413 printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
@@ -1417,43 +1415,49 @@ static struct sk_buff *sky2_receive(struct sky2_hw *hw, unsigned port,
1417 1415
1418 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending; 1416 sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
1419 1417
1420 skb = NULL;
1421 if (!(status & GMR_FS_RX_OK) 1418 if (!(status & GMR_FS_RX_OK)
1422 || (status & GMR_FS_ANY_ERR) 1419 || (status & GMR_FS_ANY_ERR)
1423 || (length << 16) != (status & GMR_FS_LEN) 1420 || (length << 16) != (status & GMR_FS_LEN)
1424 || length > rx_buf_size) 1421 || length > bufsize)
1425 goto error; 1422 goto error;
1426 1423
1427 if (length < RX_COPY_THRESHOLD) { 1424 if (length < RX_COPY_THRESHOLD) {
1428 nskb = sky2_rx_alloc(sky2, length, GFP_ATOMIC); 1425 skb = alloc_skb(length + 2, GFP_ATOMIC);
1429 if (!nskb) 1426 if (!skb)
1430 goto resubmit; 1427 goto resubmit;
1431 1428
1429 skb_reserve(skb, 2);
1432 pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->mapaddr, 1430 pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->mapaddr,
1433 length, PCI_DMA_FROMDEVICE); 1431 length, PCI_DMA_FROMDEVICE);
1434 memcpy(nskb->data, re->skb->data, length); 1432 memcpy(skb->data, re->skb->data, length);
1435 pci_dma_sync_single_for_device(sky2->hw->pdev, re->mapaddr, 1433 pci_dma_sync_single_for_device(sky2->hw->pdev, re->mapaddr,
1436 length, PCI_DMA_FROMDEVICE); 1434 length, PCI_DMA_FROMDEVICE);
1437 skb = nskb;
1438 } else { 1435 } else {
1439 nskb = sky2_rx_alloc(sky2, rx_buf_size, GFP_ATOMIC); 1436 struct sk_buff *nskb;
1437
1438 nskb = dev_alloc_skb(bufsize);
1440 if (!nskb) 1439 if (!nskb)
1441 goto resubmit; 1440 goto resubmit;
1442 1441
1443 skb = re->skb; 1442 skb = re->skb;
1443 re->skb = nskb;
1444 pci_unmap_single(sky2->hw->pdev, re->mapaddr, 1444 pci_unmap_single(sky2->hw->pdev, re->mapaddr,
1445 re->maplen, PCI_DMA_FROMDEVICE); 1445 re->maplen, PCI_DMA_FROMDEVICE);
1446 prefetch(skb->data); 1446 prefetch(skb->data);
1447 1447
1448 re->skb = nskb;
1449 re->mapaddr = pci_map_single(sky2->hw->pdev, nskb->data, 1448 re->mapaddr = pci_map_single(sky2->hw->pdev, nskb->data,
1450 rx_buf_size, PCI_DMA_FROMDEVICE); 1449 bufsize, PCI_DMA_FROMDEVICE);
1451 re->maplen = rx_buf_size; 1450 re->maplen = bufsize;
1452 } 1451 }
1453 1452
1453 skb->dev = dev;
1454 skb_put(skb, length);
1455 skb->protocol = eth_type_trans(skb, dev);
1456 dev->last_rx = jiffies;
1457
1454resubmit: 1458resubmit:
1455 BUG_ON(re->skb == skb);
1456 sky2_rx_add(sky2, re); 1459 sky2_rx_add(sky2, re);
1460
1457 return skb; 1461 return skb;
1458 1462
1459error: 1463error:
@@ -1472,6 +1476,7 @@ error:
1472 sky2->net_stats.rx_crc_errors++; 1476 sky2->net_stats.rx_crc_errors++;
1473 if (status & GMR_FS_RX_FF_OV) 1477 if (status & GMR_FS_RX_FF_OV)
1474 sky2->net_stats.rx_fifo_errors++; 1478 sky2->net_stats.rx_fifo_errors++;
1479
1475 goto resubmit; 1480 goto resubmit;
1476} 1481}
1477 1482
@@ -1502,6 +1507,7 @@ static int sky2_poll(struct net_device *dev, int *budget)
1502 unsigned int csum[2]; 1507 unsigned int csum[2];
1503 1508
1504 hwidx = sky2_read16(hw, STAT_PUT_IDX); 1509 hwidx = sky2_read16(hw, STAT_PUT_IDX);
1510 BUG_ON(hwidx >= STATUS_RING_SIZE);
1505 rmb(); 1511 rmb();
1506 while (hw->st_idx != hwidx && work_done < to_do) { 1512 while (hw->st_idx != hwidx && work_done < to_do) {
1507 struct sky2_status_le *le = hw->st_le + hw->st_idx; 1513 struct sky2_status_le *le = hw->st_le + hw->st_idx;
@@ -1520,22 +1526,18 @@ static int sky2_poll(struct net_device *dev, int *budget)
1520 case OP_RXSTAT: 1526 case OP_RXSTAT:
1521 skb = sky2_receive(hw, port, length, status); 1527 skb = sky2_receive(hw, port, length, status);
1522 if (likely(skb)) { 1528 if (likely(skb)) {
1523 __skb_put(skb, length);
1524 skb->protocol = eth_type_trans(skb, dev);
1525
1526 /* Add hw checksum if available */ 1529 /* Add hw checksum if available */
1527 skb->ip_summed = summed[port]; 1530 skb->ip_summed = summed[port];
1528 skb->csum = csum[port]; 1531 skb->csum = csum[port];
1529 1532
1530 /* Clear for next packet */
1531 csum[port] = 0;
1532 summed[port] = CHECKSUM_NONE;
1533
1534 netif_receive_skb(skb); 1533 netif_receive_skb(skb);
1535
1536 dev->last_rx = jiffies;
1537 ++work_done; 1534 ++work_done;
1538 } 1535 }
1536
1537 /* Clear for next packet */
1538 csum[port] = 0;
1539 summed[port] = CHECKSUM_NONE;
1540
1539 break; 1541 break;
1540 1542
1541 case OP_RXCHKS: 1543 case OP_RXCHKS: