Skip to content

Commit 7e8fcb8

Browse files
committed
Merge branch 'ionic-rework-fix-for-doorbell-miss'
Shannon Nelson says: ==================== ionic: rework fix for doorbell miss A latency test in a scaled out setting (many VMs with many queues) has uncovered an issue with our missed doorbell fix from commit b69585b ("ionic: missed doorbell workaround") As a refresher, the Elba ASIC has an issue where once in a blue moon it might miss/drop a queue doorbell notification from the driver. This can result in Tx timeouts and potential Rx buffer misses. The basic problem with the original solution is that we're delaying things with a timer for every single queue, periodically using mod_timer() to reset to reset the alarm, and mod_timer() becomes a more and more expensive thing as there are more and more VFs and queues each with their own timer. A ping-pong latency test tends to exacerbate the effect such that every napi is doing a mod_timer() in every cycle. An alternative has been worked out to replace this using periodic workqueue items outside the napi cycle to request a napi_schedule driven by a single delayed-workqueue per device rather than a timer for every queue. Also, now that newer firmware is actually reporting its ASIC type, we can restrict this to the appropriate chip. The testing scenario used 128 VFs in UP state, 16 queues per VF, and latency tests were done using TCP_RR with adaptive interrupt coalescing enabled, running on 1 VF. We would see 99th percentile latencies of up to 900us range, with some max fliers as much as 4ms. With these fixes the 99th percentile latencies are typically well under 50us with the occasional max under 500us. v1: https://lore.kernel.org/netdev/20240610230706.34883-1-shannon.nelson@amd.com/ ==================== Link: https://lore.kernel.org/r/20240619003257.6138-1-shannon.nelson@amd.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 6f80fcd + da0262c commit 7e8fcb8

File tree

9 files changed

+264
-76
lines changed

9 files changed

+264
-76
lines changed

drivers/net/ethernet/pensando/ionic/ionic.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ struct ionic_lif;
1818
#define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_PF 0x1002
1919
#define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF 0x1003
2020

21+
#define IONIC_ASIC_TYPE_ELBA 2
22+
2123
#define DEVCMD_TIMEOUT 5
2224
#define IONIC_ADMINQ_TIME_SLICE msecs_to_jiffies(100)
2325

@@ -47,13 +49,16 @@ struct ionic {
4749
struct ionic_dev_bar bars[IONIC_BARS_MAX];
4850
unsigned int num_bars;
4951
struct ionic_identity ident;
52+
struct workqueue_struct *wq;
5053
struct ionic_lif *lif;
5154
unsigned int nnqs_per_lif;
5255
unsigned int neqs_per_lif;
5356
unsigned int ntxqs_per_lif;
5457
unsigned int nrxqs_per_lif;
5558
unsigned int nintrs;
5659
DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX);
60+
cpumask_var_t *affinity_masks;
61+
struct delayed_work doorbell_check_dwork;
5762
struct work_struct nb_work;
5863
struct notifier_block nb;
5964
struct rw_semaphore vf_op_lock; /* lock for VF operations */
@@ -93,4 +98,6 @@ int ionic_port_identify(struct ionic *ionic);
9398
int ionic_port_init(struct ionic *ionic);
9499
int ionic_port_reset(struct ionic *ionic);
95100

101+
bool ionic_doorbell_wa(struct ionic *ionic);
102+
96103
#endif /* _IONIC_H_ */

drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static int ionic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
377377

378378
mod_timer(&ionic->watchdog_timer,
379379
round_jiffies(jiffies + ionic->watchdog_period));
380+
ionic_queue_doorbell_check(ionic, IONIC_NAPI_DEADLINE);
380381

381382
return 0;
382383

@@ -411,6 +412,8 @@ static void ionic_remove(struct pci_dev *pdev)
411412
if (test_and_clear_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state))
412413
set_bit(IONIC_LIF_F_FW_STOPPING, ionic->lif->state);
413414

415+
if (ionic->lif->doorbell_wa)
416+
cancel_delayed_work_sync(&ionic->doorbell_check_dwork);
414417
ionic_lif_unregister(ionic->lif);
415418
ionic_devlink_unregister(ionic);
416419
ionic_lif_deinit(ionic->lif);

drivers/net/ethernet/pensando/ionic/ionic_dev.c

Lines changed: 121 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,99 @@ static void ionic_watchdog_cb(struct timer_list *t)
4343

4444
work->type = IONIC_DW_TYPE_RX_MODE;
4545
netdev_dbg(lif->netdev, "deferred: rx_mode\n");
46-
ionic_lif_deferred_enqueue(&lif->deferred, work);
46+
ionic_lif_deferred_enqueue(lif, work);
4747
}
4848
}
4949

50-
static void ionic_watchdog_init(struct ionic *ionic)
50+
static void ionic_napi_schedule_do_softirq(struct napi_struct *napi)
51+
{
52+
local_bh_disable();
53+
napi_schedule(napi);
54+
local_bh_enable();
55+
}
56+
57+
void ionic_doorbell_napi_work(struct work_struct *work)
58+
{
59+
struct ionic_qcq *qcq = container_of(work, struct ionic_qcq,
60+
doorbell_napi_work);
61+
unsigned long now, then, dif;
62+
63+
now = READ_ONCE(jiffies);
64+
then = qcq->q.dbell_jiffies;
65+
dif = now - then;
66+
67+
if (dif > qcq->q.dbell_deadline)
68+
ionic_napi_schedule_do_softirq(&qcq->napi);
69+
}
70+
71+
static int ionic_get_preferred_cpu(struct ionic *ionic,
72+
struct ionic_intr_info *intr)
73+
{
74+
int cpu;
75+
76+
cpu = cpumask_first_and(*intr->affinity_mask, cpu_online_mask);
77+
if (cpu >= nr_cpu_ids)
78+
cpu = cpumask_local_spread(0, dev_to_node(ionic->dev));
79+
80+
return cpu;
81+
}
82+
83+
static void ionic_queue_dbell_napi_work(struct ionic *ionic,
84+
struct ionic_qcq *qcq)
85+
{
86+
int cpu;
87+
88+
if (!(qcq->flags & IONIC_QCQ_F_INTR))
89+
return;
90+
91+
cpu = ionic_get_preferred_cpu(ionic, &qcq->intr);
92+
queue_work_on(cpu, ionic->wq, &qcq->doorbell_napi_work);
93+
}
94+
95+
static void ionic_doorbell_check_dwork(struct work_struct *work)
96+
{
97+
struct ionic *ionic = container_of(work, struct ionic,
98+
doorbell_check_dwork.work);
99+
struct ionic_lif *lif = ionic->lif;
100+
101+
mutex_lock(&lif->queue_lock);
102+
103+
if (test_bit(IONIC_LIF_F_FW_STOPPING, lif->state) ||
104+
test_bit(IONIC_LIF_F_FW_RESET, lif->state)) {
105+
mutex_unlock(&lif->queue_lock);
106+
return;
107+
}
108+
109+
ionic_napi_schedule_do_softirq(&lif->adminqcq->napi);
110+
111+
if (test_bit(IONIC_LIF_F_UP, lif->state)) {
112+
int i;
113+
114+
for (i = 0; i < lif->nxqs; i++) {
115+
ionic_queue_dbell_napi_work(ionic, lif->txqcqs[i]);
116+
ionic_queue_dbell_napi_work(ionic, lif->rxqcqs[i]);
117+
}
118+
119+
if (lif->hwstamp_txq &&
120+
lif->hwstamp_txq->flags & IONIC_QCQ_F_INTR)
121+
ionic_napi_schedule_do_softirq(&lif->hwstamp_txq->napi);
122+
if (lif->hwstamp_rxq &&
123+
lif->hwstamp_rxq->flags & IONIC_QCQ_F_INTR)
124+
ionic_napi_schedule_do_softirq(&lif->hwstamp_rxq->napi);
125+
}
126+
mutex_unlock(&lif->queue_lock);
127+
128+
ionic_queue_doorbell_check(ionic, IONIC_NAPI_DEADLINE);
129+
}
130+
131+
bool ionic_doorbell_wa(struct ionic *ionic)
132+
{
133+
u8 asic_type = ionic->idev.dev_info.asic_type;
134+
135+
return !asic_type || asic_type == IONIC_ASIC_TYPE_ELBA;
136+
}
137+
138+
static int ionic_watchdog_init(struct ionic *ionic)
51139
{
52140
struct ionic_dev *idev = &ionic->idev;
53141

@@ -63,6 +151,31 @@ static void ionic_watchdog_init(struct ionic *ionic)
63151
idev->fw_status_ready = true;
64152
idev->fw_generation = IONIC_FW_STS_F_GENERATION &
65153
ioread8(&idev->dev_info_regs->fw_status);
154+
155+
ionic->wq = alloc_workqueue("%s-wq", WQ_UNBOUND, 0,
156+
dev_name(ionic->dev));
157+
if (!ionic->wq) {
158+
dev_err(ionic->dev, "alloc_workqueue failed");
159+
return -ENOMEM;
160+
}
161+
162+
if (ionic_doorbell_wa(ionic))
163+
INIT_DELAYED_WORK(&ionic->doorbell_check_dwork,
164+
ionic_doorbell_check_dwork);
165+
166+
return 0;
167+
}
168+
169+
void ionic_queue_doorbell_check(struct ionic *ionic, int delay)
170+
{
171+
int cpu;
172+
173+
if (!ionic->lif->doorbell_wa)
174+
return;
175+
176+
cpu = ionic_get_preferred_cpu(ionic, &ionic->lif->adminqcq->intr);
177+
queue_delayed_work_on(cpu, ionic->wq, &ionic->doorbell_check_dwork,
178+
delay);
66179
}
67180

68181
void ionic_init_devinfo(struct ionic *ionic)
@@ -94,6 +207,7 @@ int ionic_dev_setup(struct ionic *ionic)
94207
struct device *dev = ionic->dev;
95208
int size;
96209
u32 sig;
210+
int err;
97211

98212
/* BAR0: dev_cmd and interrupts */
99213
if (num_bars < 1) {
@@ -129,7 +243,9 @@ int ionic_dev_setup(struct ionic *ionic)
129243
return -EFAULT;
130244
}
131245

132-
ionic_watchdog_init(ionic);
246+
err = ionic_watchdog_init(ionic);
247+
if (err)
248+
return err;
133249

134250
idev->db_pages = bar->vaddr;
135251
idev->phy_db_pages = bar->bus_addr;
@@ -161,6 +277,7 @@ void ionic_dev_teardown(struct ionic *ionic)
161277
idev->phy_cmb_pages = 0;
162278
idev->cmb_npages = 0;
163279

280+
destroy_workqueue(ionic->wq);
164281
mutex_destroy(&idev->cmb_inuse_lock);
165282
}
166283

@@ -273,7 +390,7 @@ int ionic_heartbeat_check(struct ionic *ionic)
273390
if (work) {
274391
work->type = IONIC_DW_TYPE_LIF_RESET;
275392
work->fw_status = fw_status_ready;
276-
ionic_lif_deferred_enqueue(&lif->deferred, work);
393+
ionic_lif_deferred_enqueue(lif, work);
277394
}
278395
}
279396
}
@@ -703,10 +820,6 @@ void ionic_q_post(struct ionic_queue *q, bool ring_doorbell)
703820
q->dbval | q->head_idx);
704821

705822
q->dbell_jiffies = jiffies;
706-
707-
if (q_to_qcq(q)->napi_qcq)
708-
mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline,
709-
jiffies + IONIC_NAPI_DEADLINE);
710823
}
711824
}
712825

drivers/net/ethernet/pensando/ionic/ionic_dev.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define IONIC_DEV_INFO_REG_COUNT 32
2929
#define IONIC_DEV_CMD_REG_COUNT 32
3030

31-
#define IONIC_NAPI_DEADLINE (HZ / 200) /* 5ms */
31+
#define IONIC_NAPI_DEADLINE (HZ) /* 1 sec */
3232
#define IONIC_ADMIN_DOORBELL_DEADLINE (HZ / 2) /* 500ms */
3333
#define IONIC_TX_DOORBELL_DEADLINE (HZ / 100) /* 10ms */
3434
#define IONIC_RX_MIN_DOORBELL_DEADLINE (HZ / 100) /* 10ms */
@@ -280,9 +280,9 @@ struct ionic_intr_info {
280280
u64 rearm_count;
281281
unsigned int index;
282282
unsigned int vector;
283-
unsigned int cpu;
284283
u32 dim_coal_hw;
285-
cpumask_t affinity_mask;
284+
cpumask_var_t *affinity_mask;
285+
struct irq_affinity_notify aff_notify;
286286
};
287287

288288
struct ionic_cq {
@@ -386,6 +386,8 @@ bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos);
386386

387387
int ionic_heartbeat_check(struct ionic *ionic);
388388
bool ionic_is_fw_running(struct ionic_dev *idev);
389+
void ionic_doorbell_napi_work(struct work_struct *work);
390+
void ionic_queue_doorbell_check(struct ionic *ionic, int delay);
389391

390392
bool ionic_adminq_poke_doorbell(struct ionic_queue *q);
391393
bool ionic_txq_poke_doorbell(struct ionic_queue *q);

drivers/net/ethernet/pensando/ionic/ionic_ethtool.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include "ionic_ethtool.h"
1212
#include "ionic_stats.h"
1313

14+
#define IONIC_MAX_RX_COPYBREAK min(U16_MAX, IONIC_MAX_BUF_LEN)
15+
1416
static void ionic_get_stats_strings(struct ionic_lif *lif, u8 *buf)
1517
{
1618
u32 i;
@@ -872,10 +874,17 @@ static int ionic_set_tunable(struct net_device *dev,
872874
const void *data)
873875
{
874876
struct ionic_lif *lif = netdev_priv(dev);
877+
u32 rx_copybreak;
875878

876879
switch (tuna->id) {
877880
case ETHTOOL_RX_COPYBREAK:
878-
lif->rx_copybreak = *(u32 *)data;
881+
rx_copybreak = *(u32 *)data;
882+
if (rx_copybreak > IONIC_MAX_RX_COPYBREAK) {
883+
netdev_err(dev, "Max supported rx_copybreak size: %u\n",
884+
IONIC_MAX_RX_COPYBREAK);
885+
return -EINVAL;
886+
}
887+
lif->rx_copybreak = (u16)rx_copybreak;
879888
break;
880889
default:
881890
return -EOPNOTSUPP;

0 commit comments

Comments
 (0)