net: txgbe: support TX head write-back mode

TX head write-back mode is supported on AML devices. When it is enabled,
the hardware no longer writes the descriptors DD one by one, but write
back pointer of completion descriptor to the head_wb address.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20251023014538.12644-3-jiawenwu@trustnetic.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Jiawen Wu
2025-10-23 09:45:37 +08:00
committed by Paolo Abeni
parent a71e367773
commit eb57b16d90
7 changed files with 81 additions and 2 deletions

View File

@@ -1905,6 +1905,15 @@ static void wx_configure_tx_ring(struct wx *wx,
memset(ring->tx_buffer_info, 0,
sizeof(struct wx_tx_buffer) * ring->count);
if (ring->headwb_mem) {
wr32(wx, WX_PX_TR_HEAD_ADDRL(reg_idx),
ring->headwb_dma & DMA_BIT_MASK(32));
wr32(wx, WX_PX_TR_HEAD_ADDRH(reg_idx),
upper_32_bits(ring->headwb_dma));
txdctl |= WX_PX_TR_CFG_HEAD_WB;
}
/* enable queue */
wr32(wx, WX_PX_TR_CFG(reg_idx), txdctl);

View File

@@ -735,9 +735,22 @@ static bool wx_clean_tx_irq(struct wx_q_vector *q_vector,
/* prevent any other reads prior to eop_desc */
smp_rmb();
/* if DD is not set pending work has not been completed */
if (!(eop_desc->wb.status & cpu_to_le32(WX_TXD_STAT_DD)))
if (tx_ring->headwb_mem) {
u32 head = *tx_ring->headwb_mem;
if (head == tx_ring->next_to_clean)
break;
else if (head > tx_ring->next_to_clean &&
!(tx_buffer->next_eop >= tx_ring->next_to_clean &&
tx_buffer->next_eop < head))
break;
else if (!(tx_buffer->next_eop >= tx_ring->next_to_clean ||
tx_buffer->next_eop < head))
break;
} else if (!(eop_desc->wb.status & cpu_to_le32(WX_TXD_STAT_DD))) {
/* if DD is not set pending work has not been completed */
break;
}
/* clear next_to_watch to prevent false hangs */
tx_buffer->next_to_watch = NULL;
@@ -1075,6 +1088,10 @@ static int wx_tx_map(struct wx_ring *tx_ring,
/* set next_to_watch value indicating a packet is present */
first->next_to_watch = tx_desc;
/* set next_eop for amlite tx head wb */
if (tx_ring->headwb_mem)
first->next_eop = i;
i++;
if (i == tx_ring->count)
i = 0;
@@ -2683,6 +2700,16 @@ void wx_clean_all_tx_rings(struct wx *wx)
}
EXPORT_SYMBOL(wx_clean_all_tx_rings);
static void wx_free_headwb_resources(struct wx_ring *tx_ring)
{
if (!tx_ring->headwb_mem)
return;
dma_free_coherent(tx_ring->dev, sizeof(u32),
tx_ring->headwb_mem, tx_ring->headwb_dma);
tx_ring->headwb_mem = NULL;
}
/**
* wx_free_tx_resources - Free Tx Resources per Queue
* @tx_ring: Tx descriptor ring for a specific queue
@@ -2702,6 +2729,8 @@ static void wx_free_tx_resources(struct wx_ring *tx_ring)
dma_free_coherent(tx_ring->dev, tx_ring->size,
tx_ring->desc, tx_ring->dma);
tx_ring->desc = NULL;
wx_free_headwb_resources(tx_ring);
}
/**
@@ -2840,6 +2869,24 @@ err_setup_rx:
return err;
}
static void wx_setup_headwb_resources(struct wx_ring *tx_ring)
{
struct wx *wx = netdev_priv(tx_ring->netdev);
if (!test_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags))
return;
if (!tx_ring->q_vector)
return;
tx_ring->headwb_mem = dma_alloc_coherent(tx_ring->dev,
sizeof(u32),
&tx_ring->headwb_dma,
GFP_KERNEL);
if (!tx_ring->headwb_mem)
dev_info(tx_ring->dev, "Allocate headwb memory failed, disable it\n");
}
/**
* wx_setup_tx_resources - allocate Tx resources (Descriptors)
* @tx_ring: tx descriptor ring (for a specific queue) to setup
@@ -2880,6 +2927,8 @@ static int wx_setup_tx_resources(struct wx_ring *tx_ring)
if (!tx_ring->desc)
goto err;
wx_setup_headwb_resources(tx_ring);
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;

View File

@@ -434,12 +434,15 @@ enum WX_MSCA_CMD_value {
#define WX_PX_TR_WP(_i) (0x03008 + ((_i) * 0x40))
#define WX_PX_TR_RP(_i) (0x0300C + ((_i) * 0x40))
#define WX_PX_TR_CFG(_i) (0x03010 + ((_i) * 0x40))
#define WX_PX_TR_HEAD_ADDRL(_i) (0x03028 + ((_i) * 0x40))
#define WX_PX_TR_HEAD_ADDRH(_i) (0x0302C + ((_i) * 0x40))
/* Transmit Config masks */
#define WX_PX_TR_CFG_ENABLE BIT(0) /* Ena specific Tx Queue */
#define WX_PX_TR_CFG_TR_SIZE_SHIFT 1 /* tx desc number per ring */
#define WX_PX_TR_CFG_SWFLSH BIT(26) /* Tx Desc. wr-bk flushing */
#define WX_PX_TR_CFG_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */
#define WX_PX_TR_CFG_THRE_SHIFT 8
#define WX_PX_TR_CFG_HEAD_WB BIT(27)
/* Receive DMA Registers */
#define WX_PX_RR_BAL(_i) (0x01000 + ((_i) * 0x40))
@@ -1011,6 +1014,7 @@ struct wx_tx_buffer {
DEFINE_DMA_UNMAP_LEN(len);
__be16 protocol;
u32 tx_flags;
u32 next_eop;
};
struct wx_rx_buffer {
@@ -1062,6 +1066,8 @@ struct wx_ring {
};
u8 __iomem *tail;
dma_addr_t dma; /* phys. address of descriptor ring */
dma_addr_t headwb_dma;
u32 *headwb_mem;
unsigned int size; /* length in bytes */
u16 count; /* amount of descriptors */
@@ -1239,6 +1245,7 @@ enum wx_pf_flags {
WX_FLAG_NEED_UPDATE_LINK,
WX_FLAG_NEED_DO_RESET,
WX_FLAG_RX_MERGE_ENABLED,
WX_FLAG_TXHEAD_WB_ENABLED,
WX_PF_FLAGS_NBITS /* must be last */
};

View File

@@ -92,6 +92,9 @@
#define WX_VXTXDCTL_PTHRESH(f) FIELD_PREP(GENMASK(11, 8), f)
#define WX_VXTXDCTL_WTHRESH(f) FIELD_PREP(GENMASK(22, 16), f)
#define WX_VXTXDCTL_FLUSH BIT(26)
#define WX_VXTXDCTL_HEAD_WB BIT(27)
#define WX_VXTXD_HEAD_ADDRL(r) (0x3028 + (0x40 * (r)))
#define WX_VXTXD_HEAD_ADDRH(r) (0x302C + (0x40 * (r)))
#define WX_PFLINK_STATUS(g) FIELD_GET(BIT(0), g)
#define WX_PFLINK_SPEED(g) FIELD_GET(GENMASK(31, 1), g)

View File

@@ -132,6 +132,15 @@ static void wx_configure_tx_ring_vf(struct wx *wx, struct wx_ring *ring)
txdctl |= WX_VXTXDCTL_BUFLEN(wx_buf_len(ring->count));
txdctl |= WX_VXTXDCTL_ENABLE;
if (ring->headwb_mem) {
wr32(wx, WX_VXTXD_HEAD_ADDRL(reg_idx),
ring->headwb_dma & DMA_BIT_MASK(32));
wr32(wx, WX_VXTXD_HEAD_ADDRH(reg_idx),
upper_32_bits(ring->headwb_dma));
txdctl |= WX_VXTXDCTL_HEAD_WB;
}
/* reinitialize tx_buffer_info */
memset(ring->tx_buffer_info, 0,
sizeof(struct wx_tx_buffer) * ring->count);

View File

@@ -424,6 +424,7 @@ static int txgbe_sw_init(struct wx *wx)
case wx_mac_aml:
case wx_mac_aml40:
set_bit(WX_FLAG_RX_MERGE_ENABLED, wx->flags);
set_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags);
set_bit(WX_FLAG_SWFW_RING, wx->flags);
wx->swfw_index = 0;
break;

View File

@@ -163,6 +163,7 @@ static int txgbevf_sw_init(struct wx *wx)
case wx_mac_aml:
case wx_mac_aml40:
set_bit(WX_FLAG_RX_MERGE_ENABLED, wx->flags);
set_bit(WX_FLAG_TXHEAD_WB_ENABLED, wx->flags);
break;
default:
break;