diff options
author | Stephen Hemminger <shemminger@vyatta.com> | 2009-08-18 11:17:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-18 23:26:51 -0400 |
commit | 6b84dacadbdc3dab6a5b313d20d5a93b0d998641 (patch) | |
tree | 20bd2d8b320f5a33da98b217fe0506757563cb66 /drivers/net/sky2.c | |
parent | ee5f68fea27b53b16c265b1f9ed8aa3bc9024c96 (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.c | 80 |
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, | |||
1001 | static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot) | 1001 | static 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 | ||
1024 | static 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 */ |
1031 | static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) | 1028 | static 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 | ||
1563 | static 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 | ||
1721 | mapping_unwind: | 1733 | mapping_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 | ||
1742 | mapping_error: | 1740 | mapping_error: |
@@ -1759,34 +1757,18 @@ mapping_error: | |||
1759 | static void sky2_tx_complete(struct sky2_port *sky2, u16 done) | 1757 | static 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); |