diff options
author | Simon Kagstrom <simon.kagstrom@netinsight.net> | 2009-11-25 17:10:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-26 18:51:22 -0500 |
commit | c79992fddee28bbd31b35ac297e1068d32930179 (patch) | |
tree | 1245a3626bd7745391211e1e1fb56a8bb69cbbc5 /drivers/net/via-velocity.c | |
parent | 2a5774f7d8b79243542d932a3a476f496d03f0ba (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.c | 83 |
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 | */ |
1644 | static int velocity_init_td_ring(struct velocity_info *vptr) | 1643 | static 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 | */ |
1717 | static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) | 1714 | static 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); |
2600 | out: | 2622 | out: |
@@ -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, |