Skip to content

Commit 4aaf2c5

Browse files
ihuguetkuba-moo
authored andcommitted
sfc: use budget for TX completions
When running workloads heavy unbalanced towards TX (high TX, low RX traffic), sfc driver can retain the CPU during too long times. Although in many cases this is not enough to be visible, it can affect performance and system responsiveness. A way to reproduce it is to use a debug kernel and run some parallel netperf TX tests. In some systems, this will lead to this message being logged: kernel:watchdog: BUG: soft lockup - CPU#12 stuck for 22s! The reason is that sfc driver doesn't account any NAPI budget for the TX completion events work. With high-TX/low-RX traffic, this makes that the CPU is held for long time for NAPI poll. Documentations says "drivers can process completions for any number of Tx packets but should only process up to budget number of Rx packets". However, many drivers do limit the amount of TX completions that they process in a single NAPI poll. In the same way, this patch adds a limit for the TX work in sfc. With the patch applied, the watchdog warning never appears. Tested with netperf in different combinations: single process / parallel processes, TCP / UDP and different sizes of UDP messages. Repeated the tests before and after the patch, without any noticeable difference in network or CPU performance. Test hardware: Intel(R) Xeon(R) CPU E5-1620 v4 @ 3.50GHz (4 cores, 2 threads/core) Solarflare Communications XtremeScale X2522-25G Network Adapter Fixes: 5227ecc ("sfc: remove tx and MCDI handling from NAPI budget consideration") Fixes: d19a537 ("sfc_ef100: TX path for EF100 NICs") Reported-by: Fei Liu <[email protected]> Signed-off-by: Íñigo Huguet <[email protected]> Acked-by: Martin Habets <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent d4e0672 commit 4aaf2c5

File tree

6 files changed

+31
-13
lines changed

6 files changed

+31
-13
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2950,21 +2950,22 @@ static u32 efx_ef10_extract_event_ts(efx_qword_t *event)
29502950
return tstamp;
29512951
}
29522952

2953-
static void
2953+
static int
29542954
efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
29552955
{
29562956
struct efx_nic *efx = channel->efx;
29572957
struct efx_tx_queue *tx_queue;
29582958
unsigned int tx_ev_desc_ptr;
29592959
unsigned int tx_ev_q_label;
29602960
unsigned int tx_ev_type;
2961+
int work_done;
29612962
u64 ts_part;
29622963

29632964
if (unlikely(READ_ONCE(efx->reset_pending)))
2964-
return;
2965+
return 0;
29652966

29662967
if (unlikely(EFX_QWORD_FIELD(*event, ESF_DZ_TX_DROP_EVENT)))
2967-
return;
2968+
return 0;
29682969

29692970
/* Get the transmit queue */
29702971
tx_ev_q_label = EFX_QWORD_FIELD(*event, ESF_DZ_TX_QLABEL);
@@ -2973,8 +2974,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
29732974
if (!tx_queue->timestamping) {
29742975
/* Transmit completion */
29752976
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, ESF_DZ_TX_DESCR_INDX);
2976-
efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
2977-
return;
2977+
return efx_xmit_done(tx_queue, tx_ev_desc_ptr & tx_queue->ptr_mask);
29782978
}
29792979

29802980
/* Transmit timestamps are only available for 8XXX series. They result
@@ -3000,6 +3000,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
30003000
* fields in the event.
30013001
*/
30023002
tx_ev_type = EFX_QWORD_FIELD(*event, ESF_EZ_TX_SOFT1);
3003+
work_done = 0;
30033004

30043005
switch (tx_ev_type) {
30053006
case TX_TIMESTAMP_EVENT_TX_EV_COMPLETION:
@@ -3016,6 +3017,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
30163017
tx_queue->completed_timestamp_major = ts_part;
30173018

30183019
efx_xmit_done_single(tx_queue);
3020+
work_done = 1;
30193021
break;
30203022

30213023
default:
@@ -3026,6 +3028,8 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
30263028
EFX_QWORD_VAL(*event));
30273029
break;
30283030
}
3031+
3032+
return work_done;
30293033
}
30303034

30313035
static void
@@ -3081,13 +3085,16 @@ static void efx_ef10_handle_driver_generated_event(struct efx_channel *channel,
30813085
}
30823086
}
30833087

3088+
#define EFX_NAPI_MAX_TX 512
3089+
30843090
static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
30853091
{
30863092
struct efx_nic *efx = channel->efx;
30873093
efx_qword_t event, *p_event;
30883094
unsigned int read_ptr;
3089-
int ev_code;
3095+
int spent_tx = 0;
30903096
int spent = 0;
3097+
int ev_code;
30913098

30923099
if (quota <= 0)
30933100
return spent;
@@ -3126,7 +3133,11 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
31263133
}
31273134
break;
31283135
case ESE_DZ_EV_CODE_TX_EV:
3129-
efx_ef10_handle_tx_event(channel, &event);
3136+
spent_tx += efx_ef10_handle_tx_event(channel, &event);
3137+
if (spent_tx >= EFX_NAPI_MAX_TX) {
3138+
spent = quota;
3139+
goto out;
3140+
}
31303141
break;
31313142
case ESE_DZ_EV_CODE_DRIVER_EV:
31323143
efx_ef10_handle_driver_event(channel, &event);

drivers/net/ethernet/sfc/ef100_nic.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,16 @@ static void ef100_ev_read_ack(struct efx_channel *channel)
253253
efx_reg(channel->efx, ER_GZ_EVQ_INT_PRIME));
254254
}
255255

256+
#define EFX_NAPI_MAX_TX 512
257+
256258
static int ef100_ev_process(struct efx_channel *channel, int quota)
257259
{
258260
struct efx_nic *efx = channel->efx;
259261
struct ef100_nic_data *nic_data;
260262
bool evq_phase, old_evq_phase;
261263
unsigned int read_ptr;
262264
efx_qword_t *p_event;
265+
int spent_tx = 0;
263266
int spent = 0;
264267
bool ev_phase;
265268
int ev_type;
@@ -295,7 +298,9 @@ static int ef100_ev_process(struct efx_channel *channel, int quota)
295298
efx_mcdi_process_event(channel, p_event);
296299
break;
297300
case ESE_GZ_EF100_EV_TX_COMPLETION:
298-
ef100_ev_tx(channel, p_event);
301+
spent_tx += ef100_ev_tx(channel, p_event);
302+
if (spent_tx >= EFX_NAPI_MAX_TX)
303+
spent = quota;
299304
break;
300305
case ESE_GZ_EF100_EV_DRIVER:
301306
netif_info(efx, drv, efx->net_dev,

drivers/net/ethernet/sfc/ef100_tx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ void ef100_tx_write(struct efx_tx_queue *tx_queue)
346346
ef100_tx_push_buffers(tx_queue);
347347
}
348348

349-
void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
349+
int ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
350350
{
351351
unsigned int tx_done =
352352
EFX_QWORD_FIELD(*p_event, ESF_GZ_EV_TXCMPL_NUM_DESC);
@@ -357,7 +357,7 @@ void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event)
357357
unsigned int tx_index = (tx_queue->read_count + tx_done - 1) &
358358
tx_queue->ptr_mask;
359359

360-
efx_xmit_done(tx_queue, tx_index);
360+
return efx_xmit_done(tx_queue, tx_index);
361361
}
362362

363363
/* Add a socket buffer to a TX queue

drivers/net/ethernet/sfc/ef100_tx.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ void ef100_tx_init(struct efx_tx_queue *tx_queue);
2020
void ef100_tx_write(struct efx_tx_queue *tx_queue);
2121
unsigned int ef100_tx_max_skb_descs(struct efx_nic *efx);
2222

23-
void ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event);
23+
int ef100_ev_tx(struct efx_channel *channel, const efx_qword_t *p_event);
2424

2525
netdev_tx_t ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
2626
int __ef100_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb,

drivers/net/ethernet/sfc/tx_common.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue)
249249
}
250250
}
251251

252-
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
252+
int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
253253
{
254254
unsigned int fill_level, pkts_compl = 0, bytes_compl = 0;
255255
unsigned int efv_pkts_compl = 0;
@@ -279,6 +279,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
279279
}
280280

281281
efx_xmit_done_check_empty(tx_queue);
282+
283+
return pkts_compl + efv_pkts_compl;
282284
}
283285

284286
/* Remove buffers put into a tx_queue for the current packet.

drivers/net/ethernet/sfc/tx_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static inline bool efx_tx_buffer_in_use(struct efx_tx_buffer *buffer)
2828
}
2929

3030
void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue);
31-
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
31+
int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
3232

3333
void efx_enqueue_unwind(struct efx_tx_queue *tx_queue,
3434
unsigned int insert_count);

0 commit comments

Comments
 (0)