diff options
author | Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com> | 2009-02-07 00:47:24 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-07 00:47:24 -0500 |
commit | 12207e498b9b8f9f0c946db079ad17c7ca16cdf3 (patch) | |
tree | 05becdde5bd08f44d023ad5ef2ab2fd21b1050c0 /drivers/net/ixgbe | |
parent | 0ecc061d1967e9f2694502079e00d9d6e1e39072 (diff) |
ixgbe: Defeature Tx Head writeback
Tx Head writeback is causing multi-microsecond stalls on PCIe chipsets, due
to partial cacheline writebacks. Removing this feature removes these
issues.
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ixgbe')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 60 |
1 files changed, 23 insertions, 37 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 850361a4c38d..8e270b63e806 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -204,9 +204,6 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, | |||
204 | #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ | 204 | #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ |
205 | MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ | 205 | MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */ |
206 | 206 | ||
207 | #define GET_TX_HEAD_FROM_RING(ring) (\ | ||
208 | *(volatile u32 *) \ | ||
209 | ((union ixgbe_adv_tx_desc *)(ring)->desc + (ring)->count)) | ||
210 | static void ixgbe_tx_timeout(struct net_device *netdev); | 207 | static void ixgbe_tx_timeout(struct net_device *netdev); |
211 | 208 | ||
212 | /** | 209 | /** |
@@ -217,26 +214,27 @@ static void ixgbe_tx_timeout(struct net_device *netdev); | |||
217 | static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, | 214 | static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, |
218 | struct ixgbe_ring *tx_ring) | 215 | struct ixgbe_ring *tx_ring) |
219 | { | 216 | { |
220 | union ixgbe_adv_tx_desc *tx_desc; | ||
221 | struct ixgbe_tx_buffer *tx_buffer_info; | ||
222 | struct net_device *netdev = adapter->netdev; | 217 | struct net_device *netdev = adapter->netdev; |
223 | struct sk_buff *skb; | 218 | union ixgbe_adv_tx_desc *tx_desc, *eop_desc; |
224 | unsigned int i; | 219 | struct ixgbe_tx_buffer *tx_buffer_info; |
225 | u32 head, oldhead; | 220 | unsigned int i, eop, count = 0; |
226 | unsigned int count = 0; | ||
227 | unsigned int total_bytes = 0, total_packets = 0; | 221 | unsigned int total_bytes = 0, total_packets = 0; |
228 | 222 | ||
229 | rmb(); | ||
230 | head = GET_TX_HEAD_FROM_RING(tx_ring); | ||
231 | head = le32_to_cpu(head); | ||
232 | i = tx_ring->next_to_clean; | 223 | i = tx_ring->next_to_clean; |
233 | while (1) { | 224 | eop = tx_ring->tx_buffer_info[i].next_to_watch; |
234 | while (i != head) { | 225 | eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); |
226 | |||
227 | while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) && | ||
228 | (count < tx_ring->count)) { | ||
229 | bool cleaned = false; | ||
230 | for ( ; !cleaned; count++) { | ||
231 | struct sk_buff *skb; | ||
235 | tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); | 232 | tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i); |
236 | tx_buffer_info = &tx_ring->tx_buffer_info[i]; | 233 | tx_buffer_info = &tx_ring->tx_buffer_info[i]; |
234 | cleaned = (i == eop); | ||
237 | skb = tx_buffer_info->skb; | 235 | skb = tx_buffer_info->skb; |
238 | 236 | ||
239 | if (skb) { | 237 | if (cleaned && skb) { |
240 | unsigned int segs, bytecount; | 238 | unsigned int segs, bytecount; |
241 | 239 | ||
242 | /* gso_segs is currently only valid for tcp */ | 240 | /* gso_segs is currently only valid for tcp */ |
@@ -251,23 +249,17 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, | |||
251 | ixgbe_unmap_and_free_tx_resource(adapter, | 249 | ixgbe_unmap_and_free_tx_resource(adapter, |
252 | tx_buffer_info); | 250 | tx_buffer_info); |
253 | 251 | ||
252 | tx_desc->wb.status = 0; | ||
253 | |||
254 | i++; | 254 | i++; |
255 | if (i == tx_ring->count) | 255 | if (i == tx_ring->count) |
256 | i = 0; | 256 | i = 0; |
257 | |||
258 | count++; | ||
259 | if (count == tx_ring->count) | ||
260 | goto done_cleaning; | ||
261 | } | 257 | } |
262 | oldhead = head; | 258 | |
263 | rmb(); | 259 | eop = tx_ring->tx_buffer_info[i].next_to_watch; |
264 | head = GET_TX_HEAD_FROM_RING(tx_ring); | 260 | eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop); |
265 | head = le32_to_cpu(head); | 261 | } |
266 | if (head == oldhead) | 262 | |
267 | goto done_cleaning; | ||
268 | } /* while (1) */ | ||
269 | |||
270 | done_cleaning: | ||
271 | tx_ring->next_to_clean = i; | 263 | tx_ring->next_to_clean = i; |
272 | 264 | ||
273 | #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) | 265 | #define TX_WAKE_THRESHOLD (DESC_NEEDED * 2) |
@@ -301,8 +293,8 @@ done_cleaning: | |||
301 | 293 | ||
302 | tx_ring->total_bytes += total_bytes; | 294 | tx_ring->total_bytes += total_bytes; |
303 | tx_ring->total_packets += total_packets; | 295 | tx_ring->total_packets += total_packets; |
304 | tx_ring->stats.bytes += total_bytes; | ||
305 | tx_ring->stats.packets += total_packets; | 296 | tx_ring->stats.packets += total_packets; |
297 | tx_ring->stats.bytes += total_bytes; | ||
306 | adapter->net_stats.tx_bytes += total_bytes; | 298 | adapter->net_stats.tx_bytes += total_bytes; |
307 | adapter->net_stats.tx_packets += total_packets; | 299 | adapter->net_stats.tx_packets += total_packets; |
308 | return (total_packets ? true : false); | 300 | return (total_packets ? true : false); |
@@ -1484,7 +1476,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter) | |||
1484 | **/ | 1476 | **/ |
1485 | static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) | 1477 | static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) |
1486 | { | 1478 | { |
1487 | u64 tdba, tdwba; | 1479 | u64 tdba; |
1488 | struct ixgbe_hw *hw = &adapter->hw; | 1480 | struct ixgbe_hw *hw = &adapter->hw; |
1489 | u32 i, j, tdlen, txctrl; | 1481 | u32 i, j, tdlen, txctrl; |
1490 | 1482 | ||
@@ -1497,11 +1489,6 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) | |||
1497 | IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), | 1489 | IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), |
1498 | (tdba & DMA_32BIT_MASK)); | 1490 | (tdba & DMA_32BIT_MASK)); |
1499 | IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); | 1491 | IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); |
1500 | tdwba = ring->dma + | ||
1501 | (ring->count * sizeof(union ixgbe_adv_tx_desc)); | ||
1502 | tdwba |= IXGBE_TDWBAL_HEAD_WB_ENABLE; | ||
1503 | IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(j), tdwba & DMA_32BIT_MASK); | ||
1504 | IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(j), (tdwba >> 32)); | ||
1505 | IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen); | 1492 | IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), tdlen); |
1506 | IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); | 1493 | IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); |
1507 | IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); | 1494 | IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); |
@@ -2880,8 +2867,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter, | |||
2880 | memset(tx_ring->tx_buffer_info, 0, size); | 2867 | memset(tx_ring->tx_buffer_info, 0, size); |
2881 | 2868 | ||
2882 | /* round up to nearest 4K */ | 2869 | /* round up to nearest 4K */ |
2883 | tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc) + | 2870 | tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc); |
2884 | sizeof(u32); | ||
2885 | tx_ring->size = ALIGN(tx_ring->size, 4096); | 2871 | tx_ring->size = ALIGN(tx_ring->size, 4096); |
2886 | 2872 | ||
2887 | tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, | 2873 | tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, |