diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2013-09-28 02:00:27 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2013-10-10 00:58:04 -0400 |
commit | a5e9c5726424b05a3643450d45c134cea103181e (patch) | |
tree | 33b514501c51d193e3a85b82addfec2feaaa2bb7 /drivers/net/ethernet/intel/i40e/i40e_txrx.c | |
parent | fc4ac67bc98f1d54ec0ef8bcddf54892ad78e1f9 (diff) |
i40e: clean up Tx fast path
Sync the fast path for i40e_tx_map and i40e_clean_tx_irq so that they
are similar to igb and ixgbe.
- Only update the Tx descriptor ring in tx_map
- Make skb mapping always on the first buffer in the chain
- Drop the use of MAPPED_AS_PAGE Tx flag
- Only store flags on the first buffer_info structure
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_txrx.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_txrx.c | 220 |
1 files changed, 122 insertions, 98 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index e8db4dca6e85..e96de7567856 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c | |||
@@ -189,27 +189,30 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id) | |||
189 | } | 189 | } |
190 | 190 | ||
191 | /** | 191 | /** |
192 | * i40e_unmap_tx_resource - Release a Tx buffer | 192 | * i40e_unmap_and_free_tx_resource - Release a Tx buffer |
193 | * @ring: the ring that owns the buffer | 193 | * @ring: the ring that owns the buffer |
194 | * @tx_buffer: the buffer to free | 194 | * @tx_buffer: the buffer to free |
195 | **/ | 195 | **/ |
196 | static inline void i40e_unmap_tx_resource(struct i40e_ring *ring, | 196 | static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring, |
197 | struct i40e_tx_buffer *tx_buffer) | 197 | struct i40e_tx_buffer *tx_buffer) |
198 | { | 198 | { |
199 | if (dma_unmap_len(tx_buffer, len)) { | 199 | if (tx_buffer->skb) { |
200 | if (tx_buffer->tx_flags & I40E_TX_FLAGS_MAPPED_AS_PAGE) | 200 | dev_kfree_skb_any(tx_buffer->skb); |
201 | dma_unmap_page(ring->dev, | 201 | if (dma_unmap_len(tx_buffer, len)) |
202 | dma_unmap_addr(tx_buffer, dma), | ||
203 | dma_unmap_len(tx_buffer, len), | ||
204 | DMA_TO_DEVICE); | ||
205 | else | ||
206 | dma_unmap_single(ring->dev, | 202 | dma_unmap_single(ring->dev, |
207 | dma_unmap_addr(tx_buffer, dma), | 203 | dma_unmap_addr(tx_buffer, dma), |
208 | dma_unmap_len(tx_buffer, len), | 204 | dma_unmap_len(tx_buffer, len), |
209 | DMA_TO_DEVICE); | 205 | DMA_TO_DEVICE); |
206 | } else if (dma_unmap_len(tx_buffer, len)) { | ||
207 | dma_unmap_page(ring->dev, | ||
208 | dma_unmap_addr(tx_buffer, dma), | ||
209 | dma_unmap_len(tx_buffer, len), | ||
210 | DMA_TO_DEVICE); | ||
210 | } | 211 | } |
211 | tx_buffer->time_stamp = 0; | 212 | tx_buffer->next_to_watch = NULL; |
213 | tx_buffer->skb = NULL; | ||
212 | dma_unmap_len_set(tx_buffer, len, 0); | 214 | dma_unmap_len_set(tx_buffer, len, 0); |
215 | /* tx_buffer must be completely set up in the transmit path */ | ||
213 | } | 216 | } |
214 | 217 | ||
215 | /** | 218 | /** |
@@ -218,7 +221,6 @@ static inline void i40e_unmap_tx_resource(struct i40e_ring *ring, | |||
218 | **/ | 221 | **/ |
219 | void i40e_clean_tx_ring(struct i40e_ring *tx_ring) | 222 | void i40e_clean_tx_ring(struct i40e_ring *tx_ring) |
220 | { | 223 | { |
221 | struct i40e_tx_buffer *tx_buffer; | ||
222 | unsigned long bi_size; | 224 | unsigned long bi_size; |
223 | u16 i; | 225 | u16 i; |
224 | 226 | ||
@@ -227,13 +229,8 @@ void i40e_clean_tx_ring(struct i40e_ring *tx_ring) | |||
227 | return; | 229 | return; |
228 | 230 | ||
229 | /* Free all the Tx ring sk_buffs */ | 231 | /* Free all the Tx ring sk_buffs */ |
230 | for (i = 0; i < tx_ring->count; i++) { | 232 | for (i = 0; i < tx_ring->count; i++) |
231 | tx_buffer = &tx_ring->tx_bi[i]; | 233 | i40e_unmap_and_free_tx_resource(tx_ring, &tx_ring->tx_bi[i]); |
232 | i40e_unmap_tx_resource(tx_ring, tx_buffer); | ||
233 | if (tx_buffer->skb) | ||
234 | dev_kfree_skb_any(tx_buffer->skb); | ||
235 | tx_buffer->skb = NULL; | ||
236 | } | ||
237 | 234 | ||
238 | bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; | 235 | bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count; |
239 | memset(tx_ring->tx_bi, 0, bi_size); | 236 | memset(tx_ring->tx_bi, 0, bi_size); |
@@ -332,16 +329,18 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) | |||
332 | 329 | ||
333 | tx_buf = &tx_ring->tx_bi[i]; | 330 | tx_buf = &tx_ring->tx_bi[i]; |
334 | tx_desc = I40E_TX_DESC(tx_ring, i); | 331 | tx_desc = I40E_TX_DESC(tx_ring, i); |
332 | i -= tx_ring->count; | ||
335 | 333 | ||
336 | for (; budget; budget--) { | 334 | do { |
337 | struct i40e_tx_desc *eop_desc; | 335 | struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch; |
338 | |||
339 | eop_desc = tx_buf->next_to_watch; | ||
340 | 336 | ||
341 | /* if next_to_watch is not set then there is no work pending */ | 337 | /* if next_to_watch is not set then there is no work pending */ |
342 | if (!eop_desc) | 338 | if (!eop_desc) |
343 | break; | 339 | break; |
344 | 340 | ||
341 | /* prevent any other reads prior to eop_desc */ | ||
342 | read_barrier_depends(); | ||
343 | |||
345 | /* if the descriptor isn't done, no work yet to do */ | 344 | /* if the descriptor isn't done, no work yet to do */ |
346 | if (!(eop_desc->cmd_type_offset_bsz & | 345 | if (!(eop_desc->cmd_type_offset_bsz & |
347 | cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE))) | 346 | cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE))) |
@@ -349,44 +348,67 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) | |||
349 | 348 | ||
350 | /* clear next_to_watch to prevent false hangs */ | 349 | /* clear next_to_watch to prevent false hangs */ |
351 | tx_buf->next_to_watch = NULL; | 350 | tx_buf->next_to_watch = NULL; |
352 | tx_buf->time_stamp = 0; | ||
353 | 351 | ||
354 | /* set memory barrier before eop_desc is verified */ | 352 | /* update the statistics for this packet */ |
355 | rmb(); | 353 | total_bytes += tx_buf->bytecount; |
354 | total_packets += tx_buf->gso_segs; | ||
356 | 355 | ||
357 | do { | 356 | /* free the skb */ |
358 | i40e_unmap_tx_resource(tx_ring, tx_buf); | 357 | dev_kfree_skb_any(tx_buf->skb); |
359 | 358 | ||
360 | /* clear dtype status */ | 359 | /* unmap skb header data */ |
361 | tx_desc->cmd_type_offset_bsz &= | 360 | dma_unmap_single(tx_ring->dev, |
362 | ~cpu_to_le64(I40E_TXD_QW1_DTYPE_MASK); | 361 | dma_unmap_addr(tx_buf, dma), |
362 | dma_unmap_len(tx_buf, len), | ||
363 | DMA_TO_DEVICE); | ||
363 | 364 | ||
364 | if (likely(tx_desc == eop_desc)) { | 365 | /* clear tx_buffer data */ |
365 | eop_desc = NULL; | 366 | tx_buf->skb = NULL; |
367 | dma_unmap_len_set(tx_buf, len, 0); | ||
366 | 368 | ||
367 | dev_kfree_skb_any(tx_buf->skb); | 369 | /* unmap remaining buffers */ |
368 | tx_buf->skb = NULL; | 370 | while (tx_desc != eop_desc) { |
369 | |||
370 | total_bytes += tx_buf->bytecount; | ||
371 | total_packets += tx_buf->gso_segs; | ||
372 | } | ||
373 | 371 | ||
374 | tx_buf++; | 372 | tx_buf++; |
375 | tx_desc++; | 373 | tx_desc++; |
376 | i++; | 374 | i++; |
377 | if (unlikely(i == tx_ring->count)) { | 375 | if (unlikely(!i)) { |
378 | i = 0; | 376 | i -= tx_ring->count; |
379 | tx_buf = tx_ring->tx_bi; | 377 | tx_buf = tx_ring->tx_bi; |
380 | tx_desc = I40E_TX_DESC(tx_ring, 0); | 378 | tx_desc = I40E_TX_DESC(tx_ring, 0); |
381 | } | 379 | } |
382 | } while (eop_desc); | ||
383 | } | ||
384 | 380 | ||
381 | /* unmap any remaining paged data */ | ||
382 | if (dma_unmap_len(tx_buf, len)) { | ||
383 | dma_unmap_page(tx_ring->dev, | ||
384 | dma_unmap_addr(tx_buf, dma), | ||
385 | dma_unmap_len(tx_buf, len), | ||
386 | DMA_TO_DEVICE); | ||
387 | dma_unmap_len_set(tx_buf, len, 0); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | /* move us one more past the eop_desc for start of next pkt */ | ||
392 | tx_buf++; | ||
393 | tx_desc++; | ||
394 | i++; | ||
395 | if (unlikely(!i)) { | ||
396 | i -= tx_ring->count; | ||
397 | tx_buf = tx_ring->tx_bi; | ||
398 | tx_desc = I40E_TX_DESC(tx_ring, 0); | ||
399 | } | ||
400 | |||
401 | /* update budget accounting */ | ||
402 | budget--; | ||
403 | } while (likely(budget)); | ||
404 | |||
405 | i += tx_ring->count; | ||
385 | tx_ring->next_to_clean = i; | 406 | tx_ring->next_to_clean = i; |
386 | tx_ring->tx_stats.bytes += total_bytes; | 407 | tx_ring->tx_stats.bytes += total_bytes; |
387 | tx_ring->tx_stats.packets += total_packets; | 408 | tx_ring->tx_stats.packets += total_packets; |
388 | tx_ring->q_vector->tx.total_bytes += total_bytes; | 409 | tx_ring->q_vector->tx.total_bytes += total_bytes; |
389 | tx_ring->q_vector->tx.total_packets += total_packets; | 410 | tx_ring->q_vector->tx.total_packets += total_packets; |
411 | |||
390 | if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) { | 412 | if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) { |
391 | /* schedule immediate reset if we believe we hung */ | 413 | /* schedule immediate reset if we believe we hung */ |
392 | dev_info(tx_ring->dev, "Detected Tx Unit Hang\n" | 414 | dev_info(tx_ring->dev, "Detected Tx Unit Hang\n" |
@@ -1515,68 +1537,71 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, | |||
1515 | struct i40e_tx_buffer *first, u32 tx_flags, | 1537 | struct i40e_tx_buffer *first, u32 tx_flags, |
1516 | const u8 hdr_len, u32 td_cmd, u32 td_offset) | 1538 | const u8 hdr_len, u32 td_cmd, u32 td_offset) |
1517 | { | 1539 | { |
1518 | struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; | ||
1519 | unsigned int data_len = skb->data_len; | 1540 | unsigned int data_len = skb->data_len; |
1520 | unsigned int size = skb_headlen(skb); | 1541 | unsigned int size = skb_headlen(skb); |
1521 | struct device *dev = tx_ring->dev; | 1542 | struct skb_frag_struct *frag; |
1522 | u32 paylen = skb->len - hdr_len; | ||
1523 | u16 i = tx_ring->next_to_use; | ||
1524 | struct i40e_tx_buffer *tx_bi; | 1543 | struct i40e_tx_buffer *tx_bi; |
1525 | struct i40e_tx_desc *tx_desc; | 1544 | struct i40e_tx_desc *tx_desc; |
1526 | u32 buf_offset = 0; | 1545 | u16 i = tx_ring->next_to_use; |
1527 | u32 td_tag = 0; | 1546 | u32 td_tag = 0; |
1528 | dma_addr_t dma; | 1547 | dma_addr_t dma; |
1529 | u16 gso_segs; | 1548 | u16 gso_segs; |
1530 | 1549 | ||
1531 | dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); | ||
1532 | if (dma_mapping_error(dev, dma)) | ||
1533 | goto dma_error; | ||
1534 | |||
1535 | if (tx_flags & I40E_TX_FLAGS_HW_VLAN) { | 1550 | if (tx_flags & I40E_TX_FLAGS_HW_VLAN) { |
1536 | td_cmd |= I40E_TX_DESC_CMD_IL2TAG1; | 1551 | td_cmd |= I40E_TX_DESC_CMD_IL2TAG1; |
1537 | td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >> | 1552 | td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >> |
1538 | I40E_TX_FLAGS_VLAN_SHIFT; | 1553 | I40E_TX_FLAGS_VLAN_SHIFT; |
1539 | } | 1554 | } |
1540 | 1555 | ||
1556 | if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) | ||
1557 | gso_segs = skb_shinfo(skb)->gso_segs; | ||
1558 | else | ||
1559 | gso_segs = 1; | ||
1560 | |||
1561 | /* multiply data chunks by size of headers */ | ||
1562 | first->bytecount = skb->len - hdr_len + (gso_segs * hdr_len); | ||
1563 | first->gso_segs = gso_segs; | ||
1564 | first->skb = skb; | ||
1565 | first->tx_flags = tx_flags; | ||
1566 | |||
1567 | dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); | ||
1568 | |||
1541 | tx_desc = I40E_TX_DESC(tx_ring, i); | 1569 | tx_desc = I40E_TX_DESC(tx_ring, i); |
1542 | for (;;) { | 1570 | tx_bi = first; |
1543 | while (size > I40E_MAX_DATA_PER_TXD) { | 1571 | |
1544 | tx_desc->buffer_addr = cpu_to_le64(dma + buf_offset); | 1572 | for (frag = &skb_shinfo(skb)->frags[0];; frag++) { |
1573 | if (dma_mapping_error(tx_ring->dev, dma)) | ||
1574 | goto dma_error; | ||
1575 | |||
1576 | /* record length, and DMA address */ | ||
1577 | dma_unmap_len_set(tx_bi, len, size); | ||
1578 | dma_unmap_addr_set(tx_bi, dma, dma); | ||
1579 | |||
1580 | tx_desc->buffer_addr = cpu_to_le64(dma); | ||
1581 | |||
1582 | while (unlikely(size > I40E_MAX_DATA_PER_TXD)) { | ||
1545 | tx_desc->cmd_type_offset_bsz = | 1583 | tx_desc->cmd_type_offset_bsz = |
1546 | build_ctob(td_cmd, td_offset, | 1584 | build_ctob(td_cmd, td_offset, |
1547 | I40E_MAX_DATA_PER_TXD, td_tag); | 1585 | I40E_MAX_DATA_PER_TXD, td_tag); |
1548 | 1586 | ||
1549 | buf_offset += I40E_MAX_DATA_PER_TXD; | ||
1550 | size -= I40E_MAX_DATA_PER_TXD; | ||
1551 | |||
1552 | tx_desc++; | 1587 | tx_desc++; |
1553 | i++; | 1588 | i++; |
1554 | if (i == tx_ring->count) { | 1589 | if (i == tx_ring->count) { |
1555 | tx_desc = I40E_TX_DESC(tx_ring, 0); | 1590 | tx_desc = I40E_TX_DESC(tx_ring, 0); |
1556 | i = 0; | 1591 | i = 0; |
1557 | } | 1592 | } |
1558 | } | ||
1559 | 1593 | ||
1560 | tx_bi = &tx_ring->tx_bi[i]; | 1594 | dma += I40E_MAX_DATA_PER_TXD; |
1561 | dma_unmap_len_set(tx_bi, len, buf_offset + size); | 1595 | size -= I40E_MAX_DATA_PER_TXD; |
1562 | dma_unmap_addr_set(tx_bi, dma, dma); | ||
1563 | tx_bi->tx_flags = tx_flags; | ||
1564 | 1596 | ||
1565 | tx_desc->buffer_addr = cpu_to_le64(dma + buf_offset); | 1597 | tx_desc->buffer_addr = cpu_to_le64(dma); |
1566 | tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, | 1598 | } |
1567 | size, td_tag); | ||
1568 | 1599 | ||
1569 | if (likely(!data_len)) | 1600 | if (likely(!data_len)) |
1570 | break; | 1601 | break; |
1571 | 1602 | ||
1572 | size = skb_frag_size(frag); | 1603 | tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, |
1573 | data_len -= size; | 1604 | size, td_tag); |
1574 | buf_offset = 0; | ||
1575 | tx_flags |= I40E_TX_FLAGS_MAPPED_AS_PAGE; | ||
1576 | |||
1577 | dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE); | ||
1578 | if (dma_mapping_error(dev, dma)) | ||
1579 | goto dma_error; | ||
1580 | 1605 | ||
1581 | tx_desc++; | 1606 | tx_desc++; |
1582 | i++; | 1607 | i++; |
@@ -1585,31 +1610,21 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, | |||
1585 | i = 0; | 1610 | i = 0; |
1586 | } | 1611 | } |
1587 | 1612 | ||
1588 | frag++; | 1613 | size = skb_frag_size(frag); |
1589 | } | 1614 | data_len -= size; |
1590 | |||
1591 | tx_desc->cmd_type_offset_bsz |= | ||
1592 | cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT); | ||
1593 | |||
1594 | i++; | ||
1595 | if (i == tx_ring->count) | ||
1596 | i = 0; | ||
1597 | 1615 | ||
1598 | tx_ring->next_to_use = i; | 1616 | dma = skb_frag_dma_map(tx_ring->dev, frag, 0, size, |
1617 | DMA_TO_DEVICE); | ||
1599 | 1618 | ||
1600 | if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) | 1619 | tx_bi = &tx_ring->tx_bi[i]; |
1601 | gso_segs = skb_shinfo(skb)->gso_segs; | 1620 | } |
1602 | else | ||
1603 | gso_segs = 1; | ||
1604 | 1621 | ||
1605 | /* multiply data chunks by size of headers */ | 1622 | tx_desc->cmd_type_offset_bsz = |
1606 | tx_bi->bytecount = paylen + (gso_segs * hdr_len); | 1623 | build_ctob(td_cmd, td_offset, size, td_tag) | |
1607 | tx_bi->gso_segs = gso_segs; | 1624 | cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT); |
1608 | tx_bi->skb = skb; | ||
1609 | 1625 | ||
1610 | /* set the timestamp and next to watch values */ | 1626 | /* set the timestamp */ |
1611 | first->time_stamp = jiffies; | 1627 | first->time_stamp = jiffies; |
1612 | first->next_to_watch = tx_desc; | ||
1613 | 1628 | ||
1614 | /* Force memory writes to complete before letting h/w | 1629 | /* Force memory writes to complete before letting h/w |
1615 | * know there are new descriptors to fetch. (Only | 1630 | * know there are new descriptors to fetch. (Only |
@@ -1618,16 +1633,27 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, | |||
1618 | */ | 1633 | */ |
1619 | wmb(); | 1634 | wmb(); |
1620 | 1635 | ||
1636 | /* set next_to_watch value indicating a packet is present */ | ||
1637 | first->next_to_watch = tx_desc; | ||
1638 | |||
1639 | i++; | ||
1640 | if (i == tx_ring->count) | ||
1641 | i = 0; | ||
1642 | |||
1643 | tx_ring->next_to_use = i; | ||
1644 | |||
1645 | /* notify HW of packet */ | ||
1621 | writel(i, tx_ring->tail); | 1646 | writel(i, tx_ring->tail); |
1647 | |||
1622 | return; | 1648 | return; |
1623 | 1649 | ||
1624 | dma_error: | 1650 | dma_error: |
1625 | dev_info(dev, "TX DMA map failed\n"); | 1651 | dev_info(tx_ring->dev, "TX DMA map failed\n"); |
1626 | 1652 | ||
1627 | /* clear dma mappings for failed tx_bi map */ | 1653 | /* clear dma mappings for failed tx_bi map */ |
1628 | for (;;) { | 1654 | for (;;) { |
1629 | tx_bi = &tx_ring->tx_bi[i]; | 1655 | tx_bi = &tx_ring->tx_bi[i]; |
1630 | i40e_unmap_tx_resource(tx_ring, tx_bi); | 1656 | i40e_unmap_and_free_tx_resource(tx_ring, tx_bi); |
1631 | if (tx_bi == first) | 1657 | if (tx_bi == first) |
1632 | break; | 1658 | break; |
1633 | if (i == 0) | 1659 | if (i == 0) |
@@ -1635,8 +1661,6 @@ dma_error: | |||
1635 | i--; | 1661 | i--; |
1636 | } | 1662 | } |
1637 | 1663 | ||
1638 | dev_kfree_skb_any(skb); | ||
1639 | |||
1640 | tx_ring->next_to_use = i; | 1664 | tx_ring->next_to_use = i; |
1641 | } | 1665 | } |
1642 | 1666 | ||