Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ionic: missed doorbell workaround

In one version of the HW there is a remote possibility that it
will miss the doorbell ring. This adds a bit of protection to
be sure we don't stall a queue from a missed doorbell.

Fixes: 0f3154e6bcb3 ("ionic: Add Tx and Rx handling")
Signed-off-by: Allen Hubbe <allen.hubbe@amd.com>
Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Allen Hubbe and committed by
Jakub Kicinski
b69585bf 1fffb025

+176 -4
+8 -1
drivers/net/ethernet/pensando/ionic/ionic_dev.c
··· 708 708 q->lif->index, q->name, q->hw_type, q->hw_index, 709 709 q->head_idx, ring_doorbell); 710 710 711 - if (ring_doorbell) 711 + if (ring_doorbell) { 712 712 ionic_dbell_ring(lif->kern_dbpage, q->hw_type, 713 713 q->dbval | q->head_idx); 714 + 715 + q->dbell_jiffies = jiffies; 716 + 717 + if (q_to_qcq(q)->napi_qcq) 718 + mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline, 719 + jiffies + IONIC_NAPI_DEADLINE); 720 + } 714 721 } 715 722 716 723 static bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos)
+12
drivers/net/ethernet/pensando/ionic/ionic_dev.h
··· 25 25 #define IONIC_DEV_INFO_REG_COUNT 32 26 26 #define IONIC_DEV_CMD_REG_COUNT 32 27 27 28 + #define IONIC_NAPI_DEADLINE (HZ / 200) /* 5ms */ 29 + #define IONIC_ADMIN_DOORBELL_DEADLINE (HZ / 2) /* 500ms */ 30 + #define IONIC_TX_DOORBELL_DEADLINE (HZ / 100) /* 10ms */ 31 + #define IONIC_RX_MIN_DOORBELL_DEADLINE (HZ / 100) /* 10ms */ 32 + #define IONIC_RX_MAX_DOORBELL_DEADLINE (HZ * 5) /* 5s */ 33 + 28 34 struct ionic_dev_bar { 29 35 void __iomem *vaddr; 30 36 phys_addr_t bus_addr; ··· 222 216 struct ionic_lif *lif; 223 217 struct ionic_desc_info *info; 224 218 u64 dbval; 219 + unsigned long dbell_deadline; 220 + unsigned long dbell_jiffies; 225 221 u16 head_idx; 226 222 u16 tail_idx; 227 223 unsigned int index; ··· 368 360 unsigned int stop_index); 369 361 int ionic_heartbeat_check(struct ionic *ionic); 370 362 bool ionic_is_fw_running(struct ionic_dev *idev); 363 + 364 + bool ionic_adminq_poke_doorbell(struct ionic_queue *q); 365 + bool ionic_txq_poke_doorbell(struct ionic_queue *q); 366 + bool ionic_rxq_poke_doorbell(struct ionic_queue *q); 371 367 372 368 #endif /* _IONIC_DEV_H_ */
+40 -1
drivers/net/ethernet/pensando/ionic/ionic_lif.c
··· 16 16 17 17 #include "ionic.h" 18 18 #include "ionic_bus.h" 19 + #include "ionic_dev.h" 19 20 #include "ionic_lif.h" 20 21 #include "ionic_txrx.h" 21 22 #include "ionic_ethtool.h" ··· 201 200 } 202 201 } 203 202 203 + static void ionic_napi_deadline(struct timer_list *timer) 204 + { 205 + struct ionic_qcq *qcq = container_of(timer, struct ionic_qcq, napi_deadline); 206 + 207 + napi_schedule(&qcq->napi); 208 + } 209 + 204 210 static irqreturn_t ionic_isr(int irq, void *data) 205 211 { 206 212 struct napi_struct *napi = data; ··· 333 325 synchronize_irq(qcq->intr.vector); 334 326 irq_set_affinity_hint(qcq->intr.vector, NULL); 335 327 napi_disable(&qcq->napi); 328 + del_timer_sync(&qcq->napi_deadline); 336 329 } 337 330 338 331 /* If there was a previous fw communcation error, don't bother with ··· 469 460 470 461 n_qcq->intr.vector = src_qcq->intr.vector; 471 462 n_qcq->intr.index = src_qcq->intr.index; 463 + n_qcq->napi_qcq = src_qcq->napi_qcq; 472 464 } 473 465 474 466 static int ionic_alloc_qcq_interrupt(struct ionic_lif *lif, struct ionic_qcq *qcq) ··· 794 784 dev_dbg(dev, "txq->hw_type %d\n", q->hw_type); 795 785 dev_dbg(dev, "txq->hw_index %d\n", q->hw_index); 796 786 797 - if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 787 + q->dbell_deadline = IONIC_TX_DOORBELL_DEADLINE; 788 + q->dbell_jiffies = jiffies; 789 + 790 + if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) { 798 791 netif_napi_add(lif->netdev, &qcq->napi, ionic_tx_napi); 792 + qcq->napi_qcq = qcq; 793 + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); 794 + } 799 795 800 796 qcq->flags |= IONIC_QCQ_F_INITED; 801 797 ··· 855 839 dev_dbg(dev, "rxq->hw_type %d\n", q->hw_type); 856 840 dev_dbg(dev, "rxq->hw_index %d\n", q->hw_index); 857 841 842 + q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE; 843 + q->dbell_jiffies = jiffies; 844 + 858 845 if (test_bit(IONIC_LIF_F_SPLIT_INTR, lif->state)) 859 846 netif_napi_add(lif->netdev, &qcq->napi, ionic_rx_napi); 860 847 else 861 848 netif_napi_add(lif->netdev, &qcq->napi, ionic_txrx_napi); 849 + 850 + qcq->napi_qcq = qcq; 851 + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); 862 852 863 853 qcq->flags |= IONIC_QCQ_F_INITED; 864 854 ··· 1183 1161 struct ionic_dev *idev = &lif->ionic->idev; 1184 1162 unsigned long irqflags; 1185 1163 unsigned int flags = 0; 1164 + bool resched = false; 1186 1165 int rx_work = 0; 1187 1166 int tx_work = 0; 1188 1167 int n_work = 0; ··· 1220 1197 credits = n_work + a_work + rx_work + tx_work; 1221 1198 ionic_intr_credits(idev->intr_ctrl, intr->index, credits, flags); 1222 1199 } 1200 + 1201 + if (!a_work && ionic_adminq_poke_doorbell(&lif->adminqcq->q)) 1202 + resched = true; 1203 + if (lif->hwstamp_rxq && !rx_work && ionic_rxq_poke_doorbell(&lif->hwstamp_rxq->q)) 1204 + resched = true; 1205 + if (lif->hwstamp_txq && !tx_work && ionic_txq_poke_doorbell(&lif->hwstamp_txq->q)) 1206 + resched = true; 1207 + if (resched) 1208 + mod_timer(&lif->adminqcq->napi_deadline, 1209 + jiffies + IONIC_NAPI_DEADLINE); 1223 1210 1224 1211 return work_done; 1225 1212 } ··· 3289 3256 dev_dbg(dev, "adminq->hw_type %d\n", q->hw_type); 3290 3257 dev_dbg(dev, "adminq->hw_index %d\n", q->hw_index); 3291 3258 3259 + q->dbell_deadline = IONIC_ADMIN_DOORBELL_DEADLINE; 3260 + q->dbell_jiffies = jiffies; 3261 + 3292 3262 netif_napi_add(lif->netdev, &qcq->napi, ionic_adminq_napi); 3263 + 3264 + qcq->napi_qcq = qcq; 3265 + timer_setup(&qcq->napi_deadline, ionic_napi_deadline, 0); 3293 3266 3294 3267 napi_enable(&qcq->napi); 3295 3268
+2
drivers/net/ethernet/pensando/ionic/ionic_lif.h
··· 74 74 struct ionic_queue q; 75 75 struct ionic_cq cq; 76 76 struct ionic_intr_info intr; 77 + struct timer_list napi_deadline; 77 78 struct napi_struct napi; 78 79 unsigned int flags; 80 + struct ionic_qcq *napi_qcq; 79 81 struct dentry *dentry; 80 82 }; 81 83
+29
drivers/net/ethernet/pensando/ionic/ionic_main.c
··· 289 289 complete_all(&ctx->work); 290 290 } 291 291 292 + bool ionic_adminq_poke_doorbell(struct ionic_queue *q) 293 + { 294 + struct ionic_lif *lif = q->lif; 295 + unsigned long now, then, dif; 296 + unsigned long irqflags; 297 + 298 + spin_lock_irqsave(&lif->adminq_lock, irqflags); 299 + 300 + if (q->tail_idx == q->head_idx) { 301 + spin_unlock_irqrestore(&lif->adminq_lock, irqflags); 302 + return false; 303 + } 304 + 305 + now = READ_ONCE(jiffies); 306 + then = q->dbell_jiffies; 307 + dif = now - then; 308 + 309 + if (dif > q->dbell_deadline) { 310 + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, 311 + q->dbval | q->head_idx); 312 + 313 + q->dbell_jiffies = now; 314 + } 315 + 316 + spin_unlock_irqrestore(&lif->adminq_lock, irqflags); 317 + 318 + return true; 319 + } 320 + 292 321 int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) 293 322 { 294 323 struct ionic_desc_info *desc_info;
+85 -2
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
··· 22 22 ionic_q_post(q, ring_dbell, cb_func, cb_arg); 23 23 } 24 24 25 + bool ionic_txq_poke_doorbell(struct ionic_queue *q) 26 + { 27 + unsigned long now, then, dif; 28 + struct netdev_queue *netdev_txq; 29 + struct net_device *netdev; 30 + 31 + netdev = q->lif->netdev; 32 + netdev_txq = netdev_get_tx_queue(netdev, q->index); 33 + 34 + HARD_TX_LOCK(netdev, netdev_txq, smp_processor_id()); 35 + 36 + if (q->tail_idx == q->head_idx) { 37 + HARD_TX_UNLOCK(netdev, netdev_txq); 38 + return false; 39 + } 40 + 41 + now = READ_ONCE(jiffies); 42 + then = q->dbell_jiffies; 43 + dif = now - then; 44 + 45 + if (dif > q->dbell_deadline) { 46 + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, 47 + q->dbval | q->head_idx); 48 + 49 + q->dbell_jiffies = now; 50 + } 51 + 52 + HARD_TX_UNLOCK(netdev, netdev_txq); 53 + 54 + return true; 55 + } 56 + 57 + bool ionic_rxq_poke_doorbell(struct ionic_queue *q) 58 + { 59 + unsigned long now, then, dif; 60 + 61 + /* no lock, called from rx napi or txrx napi, nothing else can fill */ 62 + 63 + if (q->tail_idx == q->head_idx) 64 + return false; 65 + 66 + now = READ_ONCE(jiffies); 67 + then = q->dbell_jiffies; 68 + dif = now - then; 69 + 70 + if (dif > q->dbell_deadline) { 71 + ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, 72 + q->dbval | q->head_idx); 73 + 74 + q->dbell_jiffies = now; 75 + 76 + dif = 2 * q->dbell_deadline; 77 + if (dif > IONIC_RX_MAX_DOORBELL_DEADLINE) 78 + dif = IONIC_RX_MAX_DOORBELL_DEADLINE; 79 + 80 + q->dbell_deadline = dif; 81 + } 82 + 83 + return true; 84 + } 85 + 25 86 static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) 26 87 { 27 88 return netdev_get_tx_queue(q->lif->netdev, q->index); ··· 485 424 486 425 ionic_dbell_ring(q->lif->kern_dbpage, q->hw_type, 487 426 q->dbval | q->head_idx); 427 + 428 + q->dbell_deadline = IONIC_RX_MIN_DOORBELL_DEADLINE; 429 + q->dbell_jiffies = jiffies; 430 + 431 + mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline, 432 + jiffies + IONIC_NAPI_DEADLINE); 488 433 } 489 434 490 435 void ionic_rx_empty(struct ionic_queue *q) ··· 578 511 work_done, flags); 579 512 } 580 513 514 + if (!work_done && ionic_txq_poke_doorbell(&qcq->q)) 515 + mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); 516 + 581 517 return work_done; 582 518 } 583 519 ··· 614 544 work_done, flags); 615 545 } 616 546 547 + if (!work_done && ionic_rxq_poke_doorbell(&qcq->q)) 548 + mod_timer(&qcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); 549 + 617 550 return work_done; 618 551 } 619 552 620 553 int ionic_txrx_napi(struct napi_struct *napi, int budget) 621 554 { 622 - struct ionic_qcq *qcq = napi_to_qcq(napi); 555 + struct ionic_qcq *rxqcq = napi_to_qcq(napi); 623 556 struct ionic_cq *rxcq = napi_to_cq(napi); 624 557 unsigned int qi = rxcq->bound_q->index; 558 + struct ionic_qcq *txqcq; 625 559 struct ionic_dev *idev; 626 560 struct ionic_lif *lif; 627 561 struct ionic_cq *txcq; 562 + bool resched = false; 628 563 u32 rx_work_done = 0; 629 564 u32 tx_work_done = 0; 630 565 u32 flags = 0; 631 566 632 567 lif = rxcq->bound_q->lif; 633 568 idev = &lif->ionic->idev; 569 + txqcq = lif->txqcqs[qi]; 634 570 txcq = &lif->txqcqs[qi]->cq; 635 571 636 572 tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT, ··· 648 572 ionic_rx_fill(rxcq->bound_q); 649 573 650 574 if (rx_work_done < budget && napi_complete_done(napi, rx_work_done)) { 651 - ionic_dim_update(qcq, 0); 575 + ionic_dim_update(rxqcq, 0); 652 576 flags |= IONIC_INTR_CRED_UNMASK; 653 577 rxcq->bound_intr->rearm_count++; 654 578 } ··· 658 582 ionic_intr_credits(idev->intr_ctrl, rxcq->bound_intr->index, 659 583 tx_work_done + rx_work_done, flags); 660 584 } 585 + 586 + if (!rx_work_done && ionic_rxq_poke_doorbell(&rxqcq->q)) 587 + resched = true; 588 + if (!tx_work_done && ionic_txq_poke_doorbell(&txqcq->q)) 589 + resched = true; 590 + if (resched) 591 + mod_timer(&rxqcq->napi_deadline, jiffies + IONIC_NAPI_DEADLINE); 661 592 662 593 return rx_work_done; 663 594 }