Skip to content

Commit 04a21ef

Browse files
sgoutham-marvelldavem330
authored andcommitted
octeontx2-pf: Setup interrupts and NAPI handler
Completion queue (CQ) is the one with which HW notifies SW on a packet reception or transmission. Each of the RQ and SQ are mapped to a unique CQ and again both CQs are mapped to same interrupt ie the CINT. So that each core has one interrupt source in whose handler both Rx and Tx notifications are processed. Also - Registered a NAPI handler for the CINT. - Setup coalescing parameters. - IRQ affinity hints etc Signed-off-by: Sunil Goutham <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent caa2da3 commit 04a21ef

File tree

6 files changed

+332
-10
lines changed

6 files changed

+332
-10
lines changed

drivers/net/ethernet/marvell/octeontx2/nic/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
obj-$(CONFIG_OCTEONTX2_PF) += octeontx2_nicpf.o
77

8-
octeontx2_nicpf-y := otx2_pf.o otx2_common.o
8+
octeontx2_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o
99

1010
ccflags-y += -I$(srctree)/drivers/net/ethernet/marvell/octeontx2/af

drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@
1515
#include "otx2_common.h"
1616
#include "otx2_struct.h"
1717

18+
void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx)
19+
{
20+
/* Configure CQE interrupt coalescing parameters
21+
*
22+
* HW triggers an irq when ECOUNT > cq_ecount_wait, hence
23+
* set 1 less than cq_ecount_wait. And cq_time_wait is in
24+
* usecs, convert that to 100ns count.
25+
*/
26+
otx2_write64(pfvf, NIX_LF_CINTX_WAIT(qidx),
27+
((u64)(pfvf->hw.cq_time_wait * 10) << 48) |
28+
((u64)pfvf->hw.cq_qcount_wait << 32) |
29+
(pfvf->hw.cq_ecount_wait - 1));
30+
}
31+
1832
dma_addr_t otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool,
1933
gfp_t gfp)
2034
{
@@ -904,6 +918,47 @@ void mbox_handler_msix_offset(struct otx2_nic *pfvf,
904918
pfvf->hw.nix_msixoff = rsp->nix_msixoff;
905919
}
906920

921+
void otx2_free_cints(struct otx2_nic *pfvf, int n)
922+
{
923+
struct otx2_qset *qset = &pfvf->qset;
924+
struct otx2_hw *hw = &pfvf->hw;
925+
int irq, qidx;
926+
927+
for (qidx = 0, irq = hw->nix_msixoff + NIX_LF_CINT_VEC_START;
928+
qidx < n;
929+
qidx++, irq++) {
930+
int vector = pci_irq_vector(pfvf->pdev, irq);
931+
932+
irq_set_affinity_hint(vector, NULL);
933+
free_cpumask_var(hw->affinity_mask[irq]);
934+
free_irq(vector, &qset->napi[qidx]);
935+
}
936+
}
937+
938+
void otx2_set_cints_affinity(struct otx2_nic *pfvf)
939+
{
940+
struct otx2_hw *hw = &pfvf->hw;
941+
int vec, cpu, irq, cint;
942+
943+
vec = hw->nix_msixoff + NIX_LF_CINT_VEC_START;
944+
cpu = cpumask_first(cpu_online_mask);
945+
946+
/* CQ interrupts */
947+
for (cint = 0; cint < pfvf->hw.cint_cnt; cint++, vec++) {
948+
if (!alloc_cpumask_var(&hw->affinity_mask[vec], GFP_KERNEL))
949+
return;
950+
951+
cpumask_set_cpu(cpu, hw->affinity_mask[vec]);
952+
953+
irq = pci_irq_vector(pfvf->pdev, vec);
954+
irq_set_affinity_hint(irq, hw->affinity_mask[vec]);
955+
956+
cpu = cpumask_next(cpu, cpu_online_mask);
957+
if (unlikely(cpu >= nr_cpu_ids))
958+
cpu = 0;
959+
}
960+
}
961+
907962
#define M(_name, _id, _fn_name, _req_type, _rsp_type) \
908963
int __weak \
909964
otx2_mbox_up_handler_ ## _fn_name(struct otx2_nic *pfvf, \

drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
/* PCI device IDs */
2222
#define PCI_DEVID_OCTEONTX2_RVU_PF 0xA063
2323

24+
#define PCI_SUBSYS_DEVID_96XX_RVU_PFVF 0xB200
25+
2426
/* PCI BAR nos */
2527
#define PCI_CFG_REG_BAR_NUM 2
2628
#define PCI_MBOX_BAR_NUM 4
@@ -32,6 +34,13 @@ enum arua_mapped_qtypes {
3234
AURA_NIX_SQ,
3335
};
3436

37+
/* NIX LF interrupts range*/
38+
#define NIX_LF_QINT_VEC_START 0x00
39+
#define NIX_LF_CINT_VEC_START 0x40
40+
#define NIX_LF_GINT_VEC 0x80
41+
#define NIX_LF_ERR_VEC 0x81
42+
#define NIX_LF_POISON_VEC 0x82
43+
3544
struct mbox {
3645
struct otx2_mbox mbox;
3746
struct work_struct mbox_wrk;
@@ -64,9 +73,13 @@ struct otx2_hw {
6473
/* HW settings, coalescing etc */
6574
u16 rx_chan_base;
6675
u16 tx_chan_base;
76+
u16 cq_qcount_wait;
77+
u16 cq_ecount_wait;
6778
u16 rq_skid;
79+
u8 cq_time_wait;
6880

6981
/* MSI-X */
82+
u8 cint_cnt; /* CQ interrupt count */
7083
u16 npa_msixoff; /* Offset of NPA vectors */
7184
u16 nix_msixoff; /* Offset of NIX vectors */
7285
char *irq_name;
@@ -94,6 +107,36 @@ struct otx2_nic {
94107
int nix_blkaddr;
95108
};
96109

110+
static inline bool is_96xx_A0(struct pci_dev *pdev)
111+
{
112+
return (pdev->revision == 0x00) &&
113+
(pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX_RVU_PFVF);
114+
}
115+
116+
static inline bool is_96xx_B0(struct pci_dev *pdev)
117+
{
118+
return (pdev->revision == 0x01) &&
119+
(pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX_RVU_PFVF);
120+
}
121+
122+
static inline void otx2_setup_dev_hw_settings(struct otx2_nic *pfvf)
123+
{
124+
pfvf->hw.cq_time_wait = CQ_TIMER_THRESH_DEFAULT;
125+
pfvf->hw.cq_ecount_wait = CQ_CQE_THRESH_DEFAULT;
126+
pfvf->hw.cq_qcount_wait = CQ_QCOUNT_DEFAULT;
127+
128+
if (is_96xx_A0(pfvf->pdev)) {
129+
/* Time based irq coalescing is not supported */
130+
pfvf->hw.cq_qcount_wait = 0x0;
131+
132+
/* Due to HW issue previous silicons required minimum
133+
* 600 unused CQE to avoid CQ overflow.
134+
*/
135+
pfvf->hw.rq_skid = 600;
136+
pfvf->qset.rqe_cnt = Q_COUNT(Q_SIZE_1K);
137+
}
138+
}
139+
97140
/* Register read/write APIs */
98141
static inline void __iomem *otx2_get_regaddr(struct otx2_nic *nic, u64 offset)
99142
{
@@ -337,6 +380,11 @@ MBOX_UP_CGX_MESSAGES
337380
#define RVU_PFVF_FUNC_SHIFT 0
338381
#define RVU_PFVF_FUNC_MASK 0x3FF
339382

383+
static inline int rvu_get_pf(u16 pcifunc)
384+
{
385+
return (pcifunc >> RVU_PFVF_PF_SHIFT) & RVU_PFVF_PF_MASK;
386+
}
387+
340388
static inline dma_addr_t otx2_dma_map_page(struct otx2_nic *pfvf,
341389
struct page *page,
342390
size_t offset, size_t size,
@@ -359,6 +407,12 @@ static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf,
359407
dir, DMA_ATTR_SKIP_CPU_SYNC);
360408
}
361409

410+
/* MSI-X APIs */
411+
void otx2_free_cints(struct otx2_nic *pfvf, int n);
412+
void otx2_set_cints_affinity(struct otx2_nic *pfvf);
413+
414+
void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx);
415+
362416
/* RVU block related APIs */
363417
int otx2_attach_npa_nix(struct otx2_nic *pfvf);
364418
int otx2_detach_resources(struct mbox *mbox);

drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,38 @@ static int otx2_set_real_num_queues(struct net_device *netdev,
386386
return err;
387387
}
388388

389+
static irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq)
390+
{
391+
struct otx2_cq_poll *cq_poll = (struct otx2_cq_poll *)cq_irq;
392+
struct otx2_nic *pf = (struct otx2_nic *)cq_poll->dev;
393+
int qidx = cq_poll->cint_idx;
394+
395+
/* Disable interrupts.
396+
*
397+
* Completion interrupts behave in a level-triggered interrupt
398+
* fashion, and hence have to be cleared only after it is serviced.
399+
*/
400+
otx2_write64(pf, NIX_LF_CINTX_ENA_W1C(qidx), BIT_ULL(0));
401+
402+
/* Schedule NAPI */
403+
napi_schedule_irqoff(&cq_poll->napi);
404+
405+
return IRQ_HANDLED;
406+
}
407+
408+
static void otx2_disable_napi(struct otx2_nic *pf)
409+
{
410+
struct otx2_qset *qset = &pf->qset;
411+
struct otx2_cq_poll *cq_poll;
412+
int qidx;
413+
414+
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
415+
cq_poll = &qset->napi[qidx];
416+
napi_disable(&cq_poll->napi);
417+
netif_napi_del(&cq_poll->napi);
418+
}
419+
}
420+
389421
static void otx2_free_cq_res(struct otx2_nic *pf)
390422
{
391423
struct otx2_qset *qset = &pf->qset;
@@ -564,12 +596,21 @@ static void otx2_free_hw_resources(struct otx2_nic *pf)
564596
static int otx2_open(struct net_device *netdev)
565597
{
566598
struct otx2_nic *pf = netdev_priv(netdev);
599+
struct otx2_cq_poll *cq_poll = NULL;
567600
struct otx2_qset *qset = &pf->qset;
568-
int err = 0;
601+
int err = 0, qidx, vec;
602+
char *irq_name;
569603

570604
netif_carrier_off(netdev);
571605

572606
pf->qset.cq_cnt = pf->hw.rx_queues + pf->hw.tx_queues;
607+
/* RQ and SQs are mapped to different CQs,
608+
* so find out max CQ IRQs (i.e CINTs) needed.
609+
*/
610+
pf->hw.cint_cnt = max(pf->hw.rx_queues, pf->hw.tx_queues);
611+
qset->napi = kcalloc(pf->hw.cint_cnt, sizeof(*cq_poll), GFP_KERNEL);
612+
if (!qset->napi)
613+
return -ENOMEM;
573614

574615
/* CQ size of RQ */
575616
qset->rqe_cnt = qset->rqe_cnt ? qset->rqe_cnt : Q_COUNT(Q_SIZE_256);
@@ -591,23 +632,100 @@ static int otx2_open(struct net_device *netdev)
591632
if (err)
592633
goto err_free_mem;
593634

635+
/* Register NAPI handler */
636+
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
637+
cq_poll = &qset->napi[qidx];
638+
cq_poll->cint_idx = qidx;
639+
/* RQ0 & SQ0 are mapped to CINT0 and so on..
640+
* 'cq_ids[0]' points to RQ's CQ and
641+
* 'cq_ids[1]' points to SQ's CQ and
642+
*/
643+
cq_poll->cq_ids[CQ_RX] =
644+
(qidx < pf->hw.rx_queues) ? qidx : CINT_INVALID_CQ;
645+
cq_poll->cq_ids[CQ_TX] = (qidx < pf->hw.tx_queues) ?
646+
qidx + pf->hw.rx_queues : CINT_INVALID_CQ;
647+
cq_poll->dev = (void *)pf;
648+
netif_napi_add(netdev, &cq_poll->napi,
649+
otx2_napi_handler, NAPI_POLL_WEIGHT);
650+
napi_enable(&cq_poll->napi);
651+
}
652+
653+
/* Register CQ IRQ handlers */
654+
vec = pf->hw.nix_msixoff + NIX_LF_CINT_VEC_START;
655+
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
656+
irq_name = &pf->hw.irq_name[vec * NAME_SIZE];
657+
658+
snprintf(irq_name, NAME_SIZE, "%s-rxtx-%d", pf->netdev->name,
659+
qidx);
660+
661+
err = request_irq(pci_irq_vector(pf->pdev, vec),
662+
otx2_cq_intr_handler, 0, irq_name,
663+
&qset->napi[qidx]);
664+
if (err) {
665+
dev_err(pf->dev,
666+
"RVUPF%d: IRQ registration failed for CQ%d\n",
667+
rvu_get_pf(pf->pcifunc), qidx);
668+
goto err_free_cints;
669+
}
670+
vec++;
671+
672+
otx2_config_irq_coalescing(pf, qidx);
673+
674+
/* Enable CQ IRQ */
675+
otx2_write64(pf, NIX_LF_CINTX_INT(qidx), BIT_ULL(0));
676+
otx2_write64(pf, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0));
677+
}
678+
679+
otx2_set_cints_affinity(pf);
680+
594681
return 0;
682+
683+
err_free_cints:
684+
otx2_free_cints(pf, qidx);
685+
otx2_disable_napi(pf);
686+
otx2_free_hw_resources(pf);
595687
err_free_mem:
596688
kfree(qset->sq);
597689
kfree(qset->cq);
690+
kfree(qset->napi);
598691
return err;
599692
}
600693

601694
static int otx2_stop(struct net_device *netdev)
602695
{
603696
struct otx2_nic *pf = netdev_priv(netdev);
697+
struct otx2_cq_poll *cq_poll = NULL;
604698
struct otx2_qset *qset = &pf->qset;
699+
int qidx, vec;
700+
701+
netif_carrier_off(netdev);
702+
netif_tx_stop_all_queues(netdev);
703+
704+
/* Cleanup CQ NAPI and IRQ */
705+
vec = pf->hw.nix_msixoff + NIX_LF_CINT_VEC_START;
706+
for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) {
707+
/* Disable interrupt */
708+
otx2_write64(pf, NIX_LF_CINTX_ENA_W1C(qidx), BIT_ULL(0));
709+
710+
synchronize_irq(pci_irq_vector(pf->pdev, vec));
711+
712+
cq_poll = &qset->napi[qidx];
713+
napi_synchronize(&cq_poll->napi);
714+
vec++;
715+
}
716+
717+
netif_tx_disable(netdev);
605718

606719
otx2_free_hw_resources(pf);
720+
otx2_free_cints(pf, pf->hw.cint_cnt);
721+
otx2_disable_napi(pf);
722+
723+
for (qidx = 0; qidx < netdev->num_tx_queues; qidx++)
724+
netdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx));
607725

608726
kfree(qset->sq);
609727
kfree(qset->cq);
610-
728+
kfree(qset->napi);
611729
/* Do not clear RQ/SQ ringsize settings */
612730
memset((void *)qset + offsetof(struct otx2_qset, sqe_cnt), 0,
613731
sizeof(*qset) - offsetof(struct otx2_qset, sqe_cnt));
@@ -646,7 +764,6 @@ static int otx2_realloc_msix_vectors(struct otx2_nic *pf)
646764
* upto NIX vector offset.
647765
*/
648766
num_vec = hw->nix_msixoff;
649-
#define NIX_LF_CINT_VEC_START 0x40
650767
num_vec += NIX_LF_CINT_VEC_START + hw->max_queues;
651768

652769
otx2_disable_mbox_intr(pf);
@@ -769,6 +886,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id)
769886
if (err)
770887
goto err_detach_rsrc;
771888

889+
otx2_setup_dev_hw_settings(pf);
890+
772891
/* NPA's pool is a stack to which SW frees buffer pointers via Aura.
773892
* HW allocates buffer pointer from stack and uses it for DMA'ing
774893
* ingress packet. In some scenarios HW can free back allocated buffer

0 commit comments

Comments
 (0)