xref: /dpdk/drivers/net/bnxt/bnxt_irq.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2018 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <inttypes.h>
7 
8 #include <rte_cycles.h>
9 #include <rte_malloc.h>
10 
11 #include "bnxt.h"
12 #include "bnxt_cpr.h"
13 #include "bnxt_irq.h"
14 #include "bnxt_ring.h"
15 #include "hsi_struct_def_dpdk.h"
16 
17 /*
18  * Interrupts
19  */
20 
21 static void bnxt_int_handler(void *param)
22 {
23 	struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
24 	struct bnxt *bp = eth_dev->data->dev_private;
25 	struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
26 	struct cmpl_base *cmp;
27 	uint32_t raw_cons;
28 	uint32_t cons;
29 
30 	if (cpr == NULL)
31 		return;
32 
33 	raw_cons = cpr->cp_raw_cons;
34 	while (1) {
35 		if (!cpr || !cpr->cp_ring_struct || !cpr->cp_db.doorbell)
36 			return;
37 
38 		cons = RING_CMP(cpr->cp_ring_struct, raw_cons);
39 		cmp = &cpr->cp_desc_ring[cons];
40 
41 		if (!CMP_VALID(cmp, raw_cons, cpr->cp_ring_struct))
42 			break;
43 
44 		bnxt_event_hwrm_resp_handler(bp, cmp);
45 		raw_cons = NEXT_RAW_CMP(raw_cons);
46 	}
47 
48 	cpr->cp_raw_cons = raw_cons;
49 	if (BNXT_HAS_NQ(bp))
50 		bnxt_db_nq_arm(cpr);
51 	else
52 		B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
53 }
54 
55 int bnxt_free_int(struct bnxt *bp)
56 {
57 	struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
58 	struct bnxt_irq *irq = bp->irq_tbl;
59 	int rc = 0;
60 
61 	if (!irq)
62 		return 0;
63 
64 	if (irq->requested) {
65 		int count = 0;
66 
67 		/*
68 		 * Callback deregistration will fail with rc -EAGAIN if the
69 		 * callback is currently active. Retry every 50 ms until
70 		 * successful or 500 ms has elapsed.
71 		 */
72 		do {
73 			rc = rte_intr_callback_unregister(intr_handle,
74 							  irq->handler,
75 							  bp->eth_dev);
76 			if (rc >= 0) {
77 				irq->requested = 0;
78 				break;
79 			}
80 			rte_delay_ms(50);
81 		} while (count++ < 10);
82 
83 		if (rc < 0) {
84 			PMD_DRV_LOG(ERR, "irq cb unregister failed rc: %d\n",
85 				    rc);
86 			return rc;
87 		}
88 	}
89 
90 	rte_free(bp->irq_tbl);
91 	bp->irq_tbl = NULL;
92 
93 	return 0;
94 }
95 
96 void bnxt_disable_int(struct bnxt *bp)
97 {
98 	struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
99 
100 	if (BNXT_NUM_ASYNC_CPR(bp) == 0)
101 		return;
102 
103 	if (!cpr || !cpr->cp_db.doorbell)
104 		return;
105 
106 	/* Only the default completion ring */
107 	if (BNXT_HAS_NQ(bp))
108 		bnxt_db_nq(cpr);
109 	else
110 		B_CP_DB_DISARM(cpr);
111 }
112 
113 void bnxt_enable_int(struct bnxt *bp)
114 {
115 	struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
116 
117 	if (BNXT_NUM_ASYNC_CPR(bp) == 0)
118 		return;
119 
120 	if (!cpr || !cpr->cp_db.doorbell)
121 		return;
122 
123 	/* Only the default completion ring */
124 	if (BNXT_HAS_NQ(bp))
125 		bnxt_db_nq_arm(cpr);
126 	else
127 		B_CP_DB_ARM(cpr);
128 }
129 
130 int bnxt_setup_int(struct bnxt *bp)
131 {
132 	uint16_t total_vecs;
133 	const int len = sizeof(bp->irq_tbl[0].name);
134 	int i;
135 
136 	/* DPDK host only supports 1 MSI-X vector */
137 	total_vecs = 1;
138 	bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs,
139 				 sizeof(struct bnxt_irq), 0);
140 	if (bp->irq_tbl) {
141 		for (i = 0; i < total_vecs; i++) {
142 			bp->irq_tbl[i].vector = i;
143 			snprintf(bp->irq_tbl[i].name, len,
144 				 "%s-%d", bp->eth_dev->device->name, i);
145 			bp->irq_tbl[i].handler = bnxt_int_handler;
146 		}
147 	} else {
148 		PMD_DRV_LOG(ERR, "bnxt_irq_tbl setup failed\n");
149 		return -ENOMEM;
150 	}
151 
152 	return 0;
153 }
154 
155 int bnxt_request_int(struct bnxt *bp)
156 {
157 	struct rte_intr_handle *intr_handle = &bp->pdev->intr_handle;
158 	struct bnxt_irq *irq = bp->irq_tbl;
159 	int rc = 0;
160 
161 	if (!irq)
162 		return 0;
163 
164 	if (!irq->requested) {
165 		rc = rte_intr_callback_register(intr_handle,
166 						irq->handler,
167 						bp->eth_dev);
168 		if (!rc)
169 			irq->requested = 1;
170 	}
171 
172 	return rc;
173 }
174