aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/via-velocity.c
diff options
context:
space:
mode:
authorSimon Kagstrom <simon.kagstrom@netinsight.net>2009-11-25 17:10:43 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-26 18:51:22 -0500
commitc79992fddee28bbd31b35ac297e1068d32930179 (patch)
tree1245a3626bd7745391211e1e1fb56a8bb69cbbc5 /drivers/net/via-velocity.c
parent2a5774f7d8b79243542d932a3a476f496d03f0ba (diff)
via-velocity: Re-enable transmit scatter-gather support
The velocity hardware can handle up to 7 memory segments. This can be turned on and off via ethtool. The support was removed in commit 83c98a8cd04dd0f848574370594886ba3bf56750 but is re-enabled and cleaned up here. It's off by default. Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/via-velocity.c')
-rw-r--r--drivers/net/via-velocity.c83
1 files changed, 53 insertions, 30 deletions
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 10c4fb25fb4b..a8009c217bd6 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -9,7 +9,6 @@
9 * 9 *
10 * TODO 10 * TODO
11 * rx_copybreak/alignment 11 * rx_copybreak/alignment
12 * Scatter gather
13 * More testing 12 * More testing
14 * 13 *
15 * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk> 14 * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk>
@@ -1643,12 +1642,10 @@ out:
1643 */ 1642 */
1644static int velocity_init_td_ring(struct velocity_info *vptr) 1643static int velocity_init_td_ring(struct velocity_info *vptr)
1645{ 1644{
1646 dma_addr_t curr;
1647 int j; 1645 int j;
1648 1646
1649 /* Init the TD ring entries */ 1647 /* Init the TD ring entries */
1650 for (j = 0; j < vptr->tx.numq; j++) { 1648 for (j = 0; j < vptr->tx.numq; j++) {
1651 curr = vptr->tx.pool_dma[j];
1652 1649
1653 vptr->tx.infos[j] = kcalloc(vptr->options.numtx, 1650 vptr->tx.infos[j] = kcalloc(vptr->options.numtx,
1654 sizeof(struct velocity_td_info), 1651 sizeof(struct velocity_td_info),
@@ -1714,21 +1711,27 @@ err_free_dma_rings_0:
1714 * Release an transmit buffer. If the buffer was preallocated then 1711 * Release an transmit buffer. If the buffer was preallocated then
1715 * recycle it, if not then unmap the buffer. 1712 * recycle it, if not then unmap the buffer.
1716 */ 1713 */
1717static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) 1714static void velocity_free_tx_buf(struct velocity_info *vptr,
1715 struct velocity_td_info *tdinfo, struct tx_desc *td)
1718{ 1716{
1719 struct sk_buff *skb = tdinfo->skb; 1717 struct sk_buff *skb = tdinfo->skb;
1720 int i;
1721 int pktlen;
1722 1718
1723 /* 1719 /*
1724 * Don't unmap the pre-allocated tx_bufs 1720 * Don't unmap the pre-allocated tx_bufs
1725 */ 1721 */
1726 if (tdinfo->skb_dma) { 1722 if (tdinfo->skb_dma) {
1723 int i;
1727 1724
1728 pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
1729 for (i = 0; i < tdinfo->nskb_dma; i++) { 1725 for (i = 0; i < tdinfo->nskb_dma; i++) {
1730 pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); 1726 size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN);
1731 tdinfo->skb_dma[i] = 0; 1727
1728 /* For scatter-gather */
1729 if (skb_shinfo(skb)->nr_frags > 0)
1730 pktlen = max_t(size_t, pktlen,
1731 td->td_buf[i].size & ~TD_QUEUE);
1732
1733 pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i],
1734 le16_to_cpu(pktlen), PCI_DMA_TODEVICE);
1732 } 1735 }
1733 } 1736 }
1734 dev_kfree_skb_irq(skb); 1737 dev_kfree_skb_irq(skb);
@@ -1930,7 +1933,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
1930 stats->tx_packets++; 1933 stats->tx_packets++;
1931 stats->tx_bytes += tdinfo->skb->len; 1934 stats->tx_bytes += tdinfo->skb->len;
1932 } 1935 }
1933 velocity_free_tx_buf(vptr, tdinfo); 1936 velocity_free_tx_buf(vptr, tdinfo, td);
1934 vptr->tx.used[qnum]--; 1937 vptr->tx.used[qnum]--;
1935 } 1938 }
1936 vptr->tx.tail[qnum] = idx; 1939 vptr->tx.tail[qnum] = idx;
@@ -2529,14 +2532,22 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
2529 struct velocity_td_info *tdinfo; 2532 struct velocity_td_info *tdinfo;
2530 unsigned long flags; 2533 unsigned long flags;
2531 int pktlen; 2534 int pktlen;
2532 __le16 len; 2535 int index, prev;
2533 int index; 2536 int i = 0;
2534 2537
2535 if (skb_padto(skb, ETH_ZLEN)) 2538 if (skb_padto(skb, ETH_ZLEN))
2536 goto out; 2539 goto out;
2537 pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
2538 2540
2539 len = cpu_to_le16(pktlen); 2541 /* The hardware can handle at most 7 memory segments, so merge
2542 * the skb if there are more */
2543 if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
2544 kfree_skb(skb);
2545 return NETDEV_TX_OK;
2546 }
2547
2548 pktlen = skb_shinfo(skb)->nr_frags == 0 ?
2549 max_t(unsigned int, skb->len, ETH_ZLEN) :
2550 skb_headlen(skb);
2540 2551
2541 spin_lock_irqsave(&vptr->lock, flags); 2552 spin_lock_irqsave(&vptr->lock, flags);
2542 2553
@@ -2553,11 +2564,24 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
2553 */ 2564 */
2554 tdinfo->skb = skb; 2565 tdinfo->skb = skb;
2555 tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); 2566 tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
2556 td_ptr->tdesc0.len = len; 2567 td_ptr->tdesc0.len = cpu_to_le16(pktlen);
2557 td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); 2568 td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
2558 td_ptr->td_buf[0].pa_high = 0; 2569 td_ptr->td_buf[0].pa_high = 0;
2559 td_ptr->td_buf[0].size = len; 2570 td_ptr->td_buf[0].size = cpu_to_le16(pktlen);
2560 tdinfo->nskb_dma = 1; 2571
2572 /* Handle fragments */
2573 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
2574 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
2575
2576 tdinfo->skb_dma[i + 1] = pci_map_page(vptr->pdev, frag->page,
2577 frag->page_offset, frag->size,
2578 PCI_DMA_TODEVICE);
2579
2580 td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
2581 td_ptr->td_buf[i + 1].pa_high = 0;
2582 td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size);
2583 }
2584 tdinfo->nskb_dma = i + 1;
2561 2585
2562 td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; 2586 td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
2563 2587
@@ -2578,23 +2602,21 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
2578 td_ptr->tdesc1.TCR |= (TCR0_UDPCK); 2602 td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
2579 td_ptr->tdesc1.TCR |= TCR0_IPCK; 2603 td_ptr->tdesc1.TCR |= TCR0_IPCK;
2580 } 2604 }
2581 {
2582 2605
2583 int prev = index - 1; 2606 prev = index - 1;
2607 if (prev < 0)
2608 prev = vptr->options.numtx - 1;
2609 td_ptr->tdesc0.len |= OWNED_BY_NIC;
2610 vptr->tx.used[qnum]++;
2611 vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
2584 2612
2585 if (prev < 0) 2613 if (AVAIL_TD(vptr, qnum) < 1)
2586 prev = vptr->options.numtx - 1; 2614 netif_stop_queue(dev);
2587 td_ptr->tdesc0.len |= OWNED_BY_NIC;
2588 vptr->tx.used[qnum]++;
2589 vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx;
2590 2615
2591 if (AVAIL_TD(vptr, qnum) < 1) 2616 td_ptr = &(vptr->tx.rings[qnum][prev]);
2592 netif_stop_queue(dev); 2617 td_ptr->td_buf[0].size |= TD_QUEUE;
2618 mac_tx_queue_wake(vptr->mac_regs, qnum);
2593 2619
2594 td_ptr = &(vptr->tx.rings[qnum][prev]);
2595 td_ptr->td_buf[0].size |= TD_QUEUE;
2596 mac_tx_queue_wake(vptr->mac_regs, qnum);
2597 }
2598 dev->trans_start = jiffies; 2620 dev->trans_start = jiffies;
2599 spin_unlock_irqrestore(&vptr->lock, flags); 2621 spin_unlock_irqrestore(&vptr->lock, flags);
2600out: 2622out:
@@ -3374,6 +3396,7 @@ static const struct ethtool_ops velocity_ethtool_ops = {
3374 .set_wol = velocity_ethtool_set_wol, 3396 .set_wol = velocity_ethtool_set_wol,
3375 .get_msglevel = velocity_get_msglevel, 3397 .get_msglevel = velocity_get_msglevel,
3376 .set_msglevel = velocity_set_msglevel, 3398 .set_msglevel = velocity_set_msglevel,
3399 .set_sg = ethtool_op_set_sg,
3377 .get_link = velocity_get_link, 3400 .get_link = velocity_get_link,
3378 .get_coalesce = velocity_get_coalesce, 3401 .get_coalesce = velocity_get_coalesce,
3379 .set_coalesce = velocity_set_coalesce, 3402 .set_coalesce = velocity_set_coalesce,