Skip to content

Commit 9acf59a

Browse files
Andre Guedesanguy11
authored andcommitted
igc: Enable TX via AF_XDP zero-copy
Add support for transmitting packets via AF_XDP zero-copy mechanism. The packet transmission itself is implemented by igc_xdp_xmit_zc() which is called from igc_clean_tx_irq() when the ring has AF_XDP zero-copy enabled. Likewise i40e and ice drivers, the transmission budget used is the number of descriptors available on the ring. A new tx buffer type is introduced to 'enum igc_tx_buffer_type' to indicate the tx buffer uses memory from xsk pool so it can be properly cleaned after transmission or when the ring is cleaned. The I225 controller has only 4 Tx hardware queues so the main difference between igc and other Intel drivers that support AF_XDP zero-copy is that there is no tx ring dedicated exclusively to XDP. Instead, tx rings are shared between the network stack and XDP, and netdev queue lock is used to ensure mutual exclusion. This is the same approach implemented to support XDP_TX and XDP_REDIRECT actions. Signed-off-by: Andre Guedes <[email protected]> Signed-off-by: Vedang Patel <[email protected]> Signed-off-by: Jithu Joseph <[email protected]> Reviewed-by: Maciej Fijalkowski <[email protected]> Tested-by: Dvora Fuxbrumer <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent fc9df2a commit 9acf59a

File tree

4 files changed

+129
-8
lines changed

4 files changed

+129
-8
lines changed

drivers/net/ethernet/intel/igc/igc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx);
258258
void igc_update_stats(struct igc_adapter *adapter);
259259
void igc_disable_rx_ring(struct igc_ring *ring);
260260
void igc_enable_rx_ring(struct igc_ring *ring);
261+
void igc_disable_tx_ring(struct igc_ring *ring);
262+
void igc_enable_tx_ring(struct igc_ring *ring);
261263
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags);
262264

263265
/* igc_dump declarations */
@@ -413,6 +415,7 @@ enum igc_boards {
413415
enum igc_tx_buffer_type {
414416
IGC_TX_BUFFER_TYPE_SKB,
415417
IGC_TX_BUFFER_TYPE_XDP,
418+
IGC_TX_BUFFER_TYPE_XSK,
416419
};
417420

418421
/* wrapper around a pointer to a socket buffer,

drivers/net/ethernet/intel/igc/igc_base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ union igc_adv_rx_desc {
7878

7979
/* Additional Transmit Descriptor Control definitions */
8080
#define IGC_TXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Tx Queue */
81+
#define IGC_TXDCTL_SWFLUSH 0x04000000 /* Transmit Software Flush */
8182

8283
/* Additional Receive Descriptor Control definitions */
8384
#define IGC_RXDCTL_QUEUE_ENABLE 0x02000000 /* Ena specific Rx Queue */

drivers/net/ethernet/intel/igc/igc_main.c

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,24 +187,28 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
187187
{
188188
u16 i = tx_ring->next_to_clean;
189189
struct igc_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i];
190+
u32 xsk_frames = 0;
190191

191192
while (i != tx_ring->next_to_use) {
192193
union igc_adv_tx_desc *eop_desc, *tx_desc;
193194

194195
switch (tx_buffer->type) {
196+
case IGC_TX_BUFFER_TYPE_XSK:
197+
xsk_frames++;
198+
break;
195199
case IGC_TX_BUFFER_TYPE_XDP:
196200
xdp_return_frame(tx_buffer->xdpf);
201+
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
197202
break;
198203
case IGC_TX_BUFFER_TYPE_SKB:
199204
dev_kfree_skb_any(tx_buffer->skb);
205+
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
200206
break;
201207
default:
202208
netdev_warn_once(tx_ring->netdev, "Unknown Tx buffer type\n");
203209
break;
204210
}
205211

206-
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
207-
208212
/* check for eop_desc to determine the end of the packet */
209213
eop_desc = tx_buffer->next_to_watch;
210214
tx_desc = IGC_TX_DESC(tx_ring, i);
@@ -234,6 +238,9 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
234238
}
235239
}
236240

241+
if (tx_ring->xsk_pool && xsk_frames)
242+
xsk_tx_completed(tx_ring->xsk_pool, xsk_frames);
243+
237244
/* reset BQL for queue */
238245
netdev_tx_reset_queue(txring_txq(tx_ring));
239246

@@ -676,6 +683,8 @@ static void igc_configure_tx_ring(struct igc_adapter *adapter,
676683
u64 tdba = ring->dma;
677684
u32 txdctl = 0;
678685

686+
ring->xsk_pool = igc_get_xsk_pool(adapter, ring);
687+
679688
/* disable the queue */
680689
wr32(IGC_TXDCTL(reg_idx), 0);
681690
wrfl();
@@ -2509,6 +2518,65 @@ static void igc_update_tx_stats(struct igc_q_vector *q_vector,
25092518
q_vector->tx.total_packets += packets;
25102519
}
25112520

2521+
static void igc_xdp_xmit_zc(struct igc_ring *ring)
2522+
{
2523+
struct xsk_buff_pool *pool = ring->xsk_pool;
2524+
struct netdev_queue *nq = txring_txq(ring);
2525+
union igc_adv_tx_desc *tx_desc = NULL;
2526+
int cpu = smp_processor_id();
2527+
u16 ntu = ring->next_to_use;
2528+
struct xdp_desc xdp_desc;
2529+
u16 budget;
2530+
2531+
if (!netif_carrier_ok(ring->netdev))
2532+
return;
2533+
2534+
__netif_tx_lock(nq, cpu);
2535+
2536+
budget = igc_desc_unused(ring);
2537+
2538+
while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) {
2539+
u32 cmd_type, olinfo_status;
2540+
struct igc_tx_buffer *bi;
2541+
dma_addr_t dma;
2542+
2543+
cmd_type = IGC_ADVTXD_DTYP_DATA | IGC_ADVTXD_DCMD_DEXT |
2544+
IGC_ADVTXD_DCMD_IFCS | IGC_TXD_DCMD |
2545+
xdp_desc.len;
2546+
olinfo_status = xdp_desc.len << IGC_ADVTXD_PAYLEN_SHIFT;
2547+
2548+
dma = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
2549+
xsk_buff_raw_dma_sync_for_device(pool, dma, xdp_desc.len);
2550+
2551+
tx_desc = IGC_TX_DESC(ring, ntu);
2552+
tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);
2553+
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
2554+
tx_desc->read.buffer_addr = cpu_to_le64(dma);
2555+
2556+
bi = &ring->tx_buffer_info[ntu];
2557+
bi->type = IGC_TX_BUFFER_TYPE_XSK;
2558+
bi->protocol = 0;
2559+
bi->bytecount = xdp_desc.len;
2560+
bi->gso_segs = 1;
2561+
bi->time_stamp = jiffies;
2562+
bi->next_to_watch = tx_desc;
2563+
2564+
netdev_tx_sent_queue(txring_txq(ring), xdp_desc.len);
2565+
2566+
ntu++;
2567+
if (ntu == ring->count)
2568+
ntu = 0;
2569+
}
2570+
2571+
ring->next_to_use = ntu;
2572+
if (tx_desc) {
2573+
igc_flush_tx_descriptors(ring);
2574+
xsk_tx_release(pool);
2575+
}
2576+
2577+
__netif_tx_unlock(nq);
2578+
}
2579+
25122580
/**
25132581
* igc_clean_tx_irq - Reclaim resources after transmit completes
25142582
* @q_vector: pointer to q_vector containing needed info
@@ -2525,6 +2593,7 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
25252593
unsigned int i = tx_ring->next_to_clean;
25262594
struct igc_tx_buffer *tx_buffer;
25272595
union igc_adv_tx_desc *tx_desc;
2596+
u32 xsk_frames = 0;
25282597

25292598
if (test_bit(__IGC_DOWN, &adapter->state))
25302599
return true;
@@ -2555,19 +2624,22 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
25552624
total_packets += tx_buffer->gso_segs;
25562625

25572626
switch (tx_buffer->type) {
2627+
case IGC_TX_BUFFER_TYPE_XSK:
2628+
xsk_frames++;
2629+
break;
25582630
case IGC_TX_BUFFER_TYPE_XDP:
25592631
xdp_return_frame(tx_buffer->xdpf);
2632+
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
25602633
break;
25612634
case IGC_TX_BUFFER_TYPE_SKB:
25622635
napi_consume_skb(tx_buffer->skb, napi_budget);
2636+
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
25632637
break;
25642638
default:
25652639
netdev_warn_once(tx_ring->netdev, "Unknown Tx buffer type\n");
25662640
break;
25672641
}
25682642

2569-
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
2570-
25712643
/* clear last DMA location and unmap remaining buffers */
25722644
while (tx_desc != eop_desc) {
25732645
tx_buffer++;
@@ -2609,6 +2681,14 @@ static bool igc_clean_tx_irq(struct igc_q_vector *q_vector, int napi_budget)
26092681

26102682
igc_update_tx_stats(q_vector, total_packets, total_bytes);
26112683

2684+
if (tx_ring->xsk_pool) {
2685+
if (xsk_frames)
2686+
xsk_tx_completed(tx_ring->xsk_pool, xsk_frames);
2687+
if (xsk_uses_need_wakeup(tx_ring->xsk_pool))
2688+
xsk_set_tx_need_wakeup(tx_ring->xsk_pool);
2689+
igc_xdp_xmit_zc(tx_ring);
2690+
}
2691+
26122692
if (test_bit(IGC_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
26132693
struct igc_hw *hw = &adapter->hw;
26142694

@@ -6336,6 +6416,31 @@ void igc_enable_rx_ring(struct igc_ring *ring)
63366416
igc_alloc_rx_buffers(ring, igc_desc_unused(ring));
63376417
}
63386418

6419+
static void igc_disable_tx_ring_hw(struct igc_ring *ring)
6420+
{
6421+
struct igc_hw *hw = &ring->q_vector->adapter->hw;
6422+
u8 idx = ring->reg_idx;
6423+
u32 txdctl;
6424+
6425+
txdctl = rd32(IGC_TXDCTL(idx));
6426+
txdctl &= ~IGC_TXDCTL_QUEUE_ENABLE;
6427+
txdctl |= IGC_TXDCTL_SWFLUSH;
6428+
wr32(IGC_TXDCTL(idx), txdctl);
6429+
}
6430+
6431+
void igc_disable_tx_ring(struct igc_ring *ring)
6432+
{
6433+
igc_disable_tx_ring_hw(ring);
6434+
igc_clean_tx_ring(ring);
6435+
}
6436+
6437+
void igc_enable_tx_ring(struct igc_ring *ring)
6438+
{
6439+
struct igc_adapter *adapter = ring->q_vector->adapter;
6440+
6441+
igc_configure_tx_ring(adapter, ring);
6442+
}
6443+
63396444
/**
63406445
* igc_init_module - Driver Registration Routine
63416446
*

drivers/net/ethernet/intel/igc/igc_xdp.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ static int igc_xdp_enable_pool(struct igc_adapter *adapter,
3939
{
4040
struct net_device *ndev = adapter->netdev;
4141
struct device *dev = &adapter->pdev->dev;
42-
struct igc_ring *rx_ring;
42+
struct igc_ring *rx_ring, *tx_ring;
4343
struct napi_struct *napi;
4444
bool needs_reset;
4545
u32 frame_size;
4646
int err;
4747

48-
if (queue_id >= adapter->num_rx_queues)
48+
if (queue_id >= adapter->num_rx_queues ||
49+
queue_id >= adapter->num_tx_queues)
4950
return -EINVAL;
5051

5152
frame_size = xsk_pool_get_rx_frame_size(pool);
@@ -67,18 +68,23 @@ static int igc_xdp_enable_pool(struct igc_adapter *adapter,
6768
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
6869

6970
rx_ring = adapter->rx_ring[queue_id];
71+
tx_ring = adapter->tx_ring[queue_id];
72+
/* Rx and Tx rings share the same napi context. */
7073
napi = &rx_ring->q_vector->napi;
7174

7275
if (needs_reset) {
7376
igc_disable_rx_ring(rx_ring);
77+
igc_disable_tx_ring(tx_ring);
7478
napi_disable(napi);
7579
}
7680

7781
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
82+
set_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
7883

7984
if (needs_reset) {
8085
napi_enable(napi);
8186
igc_enable_rx_ring(rx_ring);
87+
igc_enable_tx_ring(tx_ring);
8288

8389
err = igc_xsk_wakeup(ndev, queue_id, XDP_WAKEUP_RX);
8490
if (err) {
@@ -92,12 +98,13 @@ static int igc_xdp_enable_pool(struct igc_adapter *adapter,
9298

9399
static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
94100
{
101+
struct igc_ring *rx_ring, *tx_ring;
95102
struct xsk_buff_pool *pool;
96-
struct igc_ring *rx_ring;
97103
struct napi_struct *napi;
98104
bool needs_reset;
99105

100-
if (queue_id >= adapter->num_rx_queues)
106+
if (queue_id >= adapter->num_rx_queues ||
107+
queue_id >= adapter->num_tx_queues)
101108
return -EINVAL;
102109

103110
pool = xsk_get_pool_from_qid(adapter->netdev, queue_id);
@@ -107,19 +114,24 @@ static int igc_xdp_disable_pool(struct igc_adapter *adapter, u16 queue_id)
107114
needs_reset = netif_running(adapter->netdev) && igc_xdp_is_enabled(adapter);
108115

109116
rx_ring = adapter->rx_ring[queue_id];
117+
tx_ring = adapter->tx_ring[queue_id];
118+
/* Rx and Tx rings share the same napi context. */
110119
napi = &rx_ring->q_vector->napi;
111120

112121
if (needs_reset) {
113122
igc_disable_rx_ring(rx_ring);
123+
igc_disable_tx_ring(tx_ring);
114124
napi_disable(napi);
115125
}
116126

117127
xsk_pool_dma_unmap(pool, IGC_RX_DMA_ATTR);
118128
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &rx_ring->flags);
129+
clear_bit(IGC_RING_FLAG_AF_XDP_ZC, &tx_ring->flags);
119130

120131
if (needs_reset) {
121132
napi_enable(napi);
122133
igc_enable_rx_ring(rx_ring);
134+
igc_enable_tx_ring(tx_ring);
123135
}
124136

125137
return 0;

0 commit comments

Comments
 (0)