aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sky2.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2009-08-18 11:17:09 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-18 23:26:51 -0400
commit6b84dacadbdc3dab6a5b313d20d5a93b0d998641 (patch)
tree20bd2d8b320f5a33da98b217fe0506757563cb66 /drivers/net/sky2.c
parentee5f68fea27b53b16c265b1f9ed8aa3bc9024c96 (diff)
sky2: optimize transmit completion
Don't reference the list element in hardware transmit ring on transmit completion. The list element is updated by hardware, therefore it causes a cache miss. Do book keeping in software structure. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r--drivers/net/sky2.c80
1 files changed, 31 insertions, 49 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7c1880d8b31f..a3e40d70c071 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1001,8 +1001,11 @@ static void sky2_prefetch_init(struct sky2_hw *hw, u32 qaddr,
1001static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) 1001static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
1002{ 1002{
1003 struct sky2_tx_le *le = sky2->tx_le + *slot; 1003 struct sky2_tx_le *le = sky2->tx_le + *slot;
1004 struct tx_ring_info *re = sky2->tx_ring + *slot;
1004 1005
1005 *slot = RING_NEXT(*slot, sky2->tx_ring_size); 1006 *slot = RING_NEXT(*slot, sky2->tx_ring_size);
1007 re->flags = 0;
1008 re->skb = NULL;
1006 le->ctrl = 0; 1009 le->ctrl = 0;
1007 return le; 1010 return le;
1008} 1011}
@@ -1021,12 +1024,6 @@ static void tx_init(struct sky2_port *sky2)
1021 sky2->tx_last_upper = 0; 1024 sky2->tx_last_upper = 0;
1022} 1025}
1023 1026
1024static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
1025 struct sky2_tx_le *le)
1026{
1027 return sky2->tx_ring + (le - sky2->tx_le);
1028}
1029
1030/* Update chip's next pointer */ 1027/* Update chip's next pointer */
1031static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) 1028static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
1032{ 1029{
@@ -1563,6 +1560,19 @@ static unsigned tx_le_req(const struct sk_buff *skb)
1563 return count; 1560 return count;
1564} 1561}
1565 1562
1563static void sky2_tx_unmap(struct pci_dev *pdev,
1564 const struct tx_ring_info *re)
1565{
1566 if (re->flags & TX_MAP_SINGLE)
1567 pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
1568 pci_unmap_len(re, maplen),
1569 PCI_DMA_TODEVICE);
1570 else if (re->flags & TX_MAP_PAGE)
1571 pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
1572 pci_unmap_len(re, maplen),
1573 PCI_DMA_TODEVICE);
1574}
1575
1566/* 1576/*
1567 * Put one packet in ring for transmit. 1577 * Put one packet in ring for transmit.
1568 * A single packet can generate multiple list elements, and 1578 * A single packet can generate multiple list elements, and
@@ -1667,16 +1677,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
1667 } 1677 }
1668 } 1678 }
1669 1679
1680 re = sky2->tx_ring + slot;
1681 re->flags = TX_MAP_SINGLE;
1682 pci_unmap_addr_set(re, mapaddr, mapping);
1683 pci_unmap_len_set(re, maplen, len);
1684
1670 le = get_tx_le(sky2, &slot); 1685 le = get_tx_le(sky2, &slot);
1671 le->addr = cpu_to_le32(lower_32_bits(mapping)); 1686 le->addr = cpu_to_le32(lower_32_bits(mapping));
1672 le->length = cpu_to_le16(len); 1687 le->length = cpu_to_le16(len);
1673 le->ctrl = ctrl; 1688 le->ctrl = ctrl;
1674 le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); 1689 le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER);
1675 1690
1676 re = tx_le_re(sky2, le);
1677 re->skb = skb;
1678 pci_unmap_addr_set(re, mapaddr, mapping);
1679 pci_unmap_len_set(re, maplen, len);
1680 1691
1681 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 1692 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
1682 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 1693 const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -1695,18 +1706,19 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
1695 le->opcode = OP_ADDR64 | HW_OWNER; 1706 le->opcode = OP_ADDR64 | HW_OWNER;
1696 } 1707 }
1697 1708
1709 re = sky2->tx_ring + slot;
1710 re->flags = TX_MAP_PAGE;
1711 pci_unmap_addr_set(re, mapaddr, mapping);
1712 pci_unmap_len_set(re, maplen, frag->size);
1713
1698 le = get_tx_le(sky2, &slot); 1714 le = get_tx_le(sky2, &slot);
1699 le->addr = cpu_to_le32(lower_32_bits(mapping)); 1715 le->addr = cpu_to_le32(lower_32_bits(mapping));
1700 le->length = cpu_to_le16(frag->size); 1716 le->length = cpu_to_le16(frag->size);
1701 le->ctrl = ctrl; 1717 le->ctrl = ctrl;
1702 le->opcode = OP_BUFFER | HW_OWNER; 1718 le->opcode = OP_BUFFER | HW_OWNER;
1703
1704 re = tx_le_re(sky2, le);
1705 re->skb = skb;
1706 pci_unmap_addr_set(re, mapaddr, mapping);
1707 pci_unmap_len_set(re, maplen, frag->size);
1708 } 1719 }
1709 1720
1721 re->skb = skb;
1710 le->ctrl |= EOP; 1722 le->ctrl |= EOP;
1711 1723
1712 sky2->tx_prod = slot; 1724 sky2->tx_prod = slot;
@@ -1720,23 +1732,9 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
1720 1732
1721mapping_unwind: 1733mapping_unwind:
1722 for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) { 1734 for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) {
1723 le = sky2->tx_le + i;
1724 re = sky2->tx_ring + i; 1735 re = sky2->tx_ring + i;
1725 1736
1726 switch(le->opcode & ~HW_OWNER) { 1737 sky2_tx_unmap(hw->pdev, re);
1727 case OP_LARGESEND:
1728 case OP_PACKET:
1729 pci_unmap_single(hw->pdev,
1730 pci_unmap_addr(re, mapaddr),
1731 pci_unmap_len(re, maplen),
1732 PCI_DMA_TODEVICE);
1733 break;
1734 case OP_BUFFER:
1735 pci_unmap_page(hw->pdev, pci_unmap_addr(re, mapaddr),
1736 pci_unmap_len(re, maplen),
1737 PCI_DMA_TODEVICE);
1738 break;
1739 }
1740 } 1738 }
1741 1739
1742mapping_error: 1740mapping_error:
@@ -1759,34 +1757,18 @@ mapping_error:
1759static void sky2_tx_complete(struct sky2_port *sky2, u16 done) 1757static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
1760{ 1758{
1761 struct net_device *dev = sky2->netdev; 1759 struct net_device *dev = sky2->netdev;
1762 struct pci_dev *pdev = sky2->hw->pdev;
1763 unsigned idx; 1760 unsigned idx;
1764 1761
1765 BUG_ON(done >= sky2->tx_ring_size); 1762 BUG_ON(done >= sky2->tx_ring_size);
1766 1763
1767 for (idx = sky2->tx_cons; idx != done; 1764 for (idx = sky2->tx_cons; idx != done;
1768 idx = RING_NEXT(idx, sky2->tx_ring_size)) { 1765 idx = RING_NEXT(idx, sky2->tx_ring_size)) {
1769 struct sky2_tx_le *le = sky2->tx_le + idx;
1770 struct tx_ring_info *re = sky2->tx_ring + idx; 1766 struct tx_ring_info *re = sky2->tx_ring + idx;
1767 struct sk_buff *skb = re->skb;
1771 1768
1772 switch(le->opcode & ~HW_OWNER) { 1769 sky2_tx_unmap(sky2->hw->pdev, re);
1773 case OP_LARGESEND:
1774 case OP_PACKET:
1775 pci_unmap_single(pdev,
1776 pci_unmap_addr(re, mapaddr),
1777 pci_unmap_len(re, maplen),
1778 PCI_DMA_TODEVICE);
1779 break;
1780 case OP_BUFFER:
1781 pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
1782 pci_unmap_len(re, maplen),
1783 PCI_DMA_TODEVICE);
1784 break;
1785 }
1786
1787 if (le->ctrl & EOP) {
1788 struct sk_buff *skb = re->skb;
1789 1770
1771 if (skb) {
1790 if (unlikely(netif_msg_tx_done(sky2))) 1772 if (unlikely(netif_msg_tx_done(sky2)))
1791 printk(KERN_DEBUG "%s: tx done %u\n", 1773 printk(KERN_DEBUG "%s: tx done %u\n",
1792 dev->name, idx); 1774 dev->name, idx);