Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 761c2a48 authored by Emil Tantilov's avatar Emil Tantilov Committed by Jeff Kirsher
Browse files

ixgbe: split Tx/Rx ring clearing for ethtool loopback test



Commit: fed21bcee7a5
("ixgbe: Don't bother clearing buffer memory for descriptor rings)

exposed some issues with the logic in the current implementation of
ixgbe_clean_test_rings() that are being addressed in this patch:

- Split the clearing of the Tx and Rx rings in separate loops. Previously
both Tx and Rx rings were cleared in a rx_desc->wb.upper.length based
loop which could lead to issues if for w/e reason packets were received
outside of the frames transmitted for the loopback test.

- Add check for IXGBE_TXD_STAT_DD to avoid clearing the rings if the
transmits have not comlpeted by the time we enter ixgbe_clean_test_rings()

- Exit early on ixgbe_check_lbtest_frame() failure.

This change fixes a crash during ethtool diagnostic (ethtool -t).

Signed-off-by: default avatarEmil Tantilov <emil.s.tantilov@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent c69be946
Loading
Loading
Loading
Loading
+34 −19
Original line number Diff line number Diff line
@@ -1916,8 +1916,6 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
				  unsigned int size)
{
	union ixgbe_adv_rx_desc *rx_desc;
	struct ixgbe_rx_buffer *rx_buffer;
	struct ixgbe_tx_buffer *tx_buffer;
	u16 rx_ntc, tx_ntc, count = 0;

	/* initialize next to clean and descriptor values */
@@ -1925,7 +1923,38 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
	tx_ntc = tx_ring->next_to_clean;
	rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc);

	while (tx_ntc != tx_ring->next_to_use) {
		union ixgbe_adv_tx_desc *tx_desc;
		struct ixgbe_tx_buffer *tx_buffer;

		tx_desc = IXGBE_TX_DESC(tx_ring, tx_ntc);

		/* if DD is not set transmit has not completed */
		if (!(tx_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
			return count;

		/* unmap buffer on Tx side */
		tx_buffer = &tx_ring->tx_buffer_info[tx_ntc];

		/* Free all the Tx ring sk_buffs */
		dev_kfree_skb_any(tx_buffer->skb);

		/* unmap skb header data */
		dma_unmap_single(tx_ring->dev,
				 dma_unmap_addr(tx_buffer, dma),
				 dma_unmap_len(tx_buffer, len),
				 DMA_TO_DEVICE);
		dma_unmap_len_set(tx_buffer, len, 0);

		/* increment Tx next to clean counter */
		tx_ntc++;
		if (tx_ntc == tx_ring->count)
			tx_ntc = 0;
	}

	while (rx_desc->wb.upper.length) {
		struct ixgbe_rx_buffer *rx_buffer;

		/* check Rx buffer */
		rx_buffer = &rx_ring->rx_buffer_info[rx_ntc];

@@ -1938,6 +1967,8 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
		/* verify contents of skb */
		if (ixgbe_check_lbtest_frame(rx_buffer, size))
			count++;
		else
			break;

		/* sync Rx buffer for device write */
		dma_sync_single_for_device(rx_ring->dev,
@@ -1945,26 +1976,10 @@ static u16 ixgbe_clean_test_rings(struct ixgbe_ring *rx_ring,
					   ixgbe_rx_bufsz(rx_ring),
					   DMA_FROM_DEVICE);

		/* unmap buffer on Tx side */
		tx_buffer = &tx_ring->tx_buffer_info[tx_ntc];

		/* Free all the Tx ring sk_buffs */
		dev_kfree_skb_any(tx_buffer->skb);

		/* unmap skb header data */
		dma_unmap_single(tx_ring->dev,
				 dma_unmap_addr(tx_buffer, dma),
				 dma_unmap_len(tx_buffer, len),
				 DMA_TO_DEVICE);
		dma_unmap_len_set(tx_buffer, len, 0);

		/* increment Rx/Tx next to clean counters */
		/* increment Rx next to clean counter */
		rx_ntc++;
		if (rx_ntc == rx_ring->count)
			rx_ntc = 0;
		tx_ntc++;
		if (tx_ntc == tx_ring->count)
			tx_ntc = 0;

		/* fetch next descriptor */
		rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc);