xref: /dpdk/drivers/net/bnxt/bnxt_irq.c (revision e99981af34632ecce3bac82d05db97b08308f9b5)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2023 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_irq.h"
13 #include "bnxt_ring.h"
14 #include "hsi_struct_def_dpdk.h"
15 
16 /*
17  * Interrupts
18  */
19 
20 static inline void bnxt_int_handler_rearm(struct bnxt *bp,
21 					  struct bnxt_cp_ring_info *cpr,
22 					  uint32_t raw_cons)
23 {
24 	cpr->cp_raw_cons = raw_cons;
25 	if (BNXT_HAS_NQ(bp))
26 		bnxt_db_nq_arm(cpr);
27 	else
28 		B_CP_DB_REARM(cpr, cpr->cp_raw_cons);
29 }
30 
31 /* ARM the default CQ/NQ at intervals of 1/8th of ring size */
32 #define BNXT_DB_REARM_FACTOR		8
33 void bnxt_int_handler(void *param)
34 {
35 	struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)param;
36 	struct bnxt *bp = eth_dev->data->dev_private;
37 	uint32_t cons, raw_cons, cp_ring_size;
38 	struct bnxt_cp_ring_info *cpr;
39 	struct cmpl_base *cmp;
40 	uint16_t cnt = 0;
41 
42 
43 	if (bp == NULL)
44 		return;
45 	cpr = bp->async_cp_ring;
46 	if (cpr == NULL)
47 		return;
48 
49 	raw_cons = cpr->cp_raw_cons;
50 	pthread_mutex_lock(&bp->def_cp_lock);
51 	while (1) {
52 		if (!cpr || !cpr->cp_ring_struct || !cpr->cp_db.doorbell) {
53 			pthread_mutex_unlock(&bp->def_cp_lock);
54 			return;
55 		}
56 
57 		if (is_bnxt_in_error(bp)) {
58 			pthread_mutex_unlock(&bp->def_cp_lock);
59 			return;
60 		}
61 
62 		cp_ring_size = cpr->cp_ring_struct->ring_size;
63 		cons = RING_CMP(cpr->cp_ring_struct, raw_cons);
64 		cmp = &cpr->cp_desc_ring[cons];
65 
66 		if (!bnxt_cpr_cmp_valid(cmp, raw_cons, cp_ring_size))
67 			break;
68 
69 		bnxt_event_hwrm_resp_handler(bp, cmp);
70 		raw_cons = NEXT_RAW_CMP(raw_cons);
71 		if (++cnt >= cp_ring_size / BNXT_DB_REARM_FACTOR) {
72 			bnxt_int_handler_rearm(bp, cpr, raw_cons);
73 			cnt = 0;
74 		}
75 	}
76 
77 	/* cnt = 0 means no work or we rearmed already */
78 	if (cnt > 0)
79 		bnxt_int_handler_rearm(bp, cpr, raw_cons);
80 
81 	pthread_mutex_unlock(&bp->def_cp_lock);
82 }
83 
84 int bnxt_free_int(struct bnxt *bp)
85 {
86 	struct rte_intr_handle *intr_handle = bp->pdev->intr_handle;
87 	struct bnxt_irq *irq = bp->irq_tbl;
88 	int rc = 0;
89 
90 	if (!irq)
91 		return 0;
92 
93 	if (irq->requested) {
94 		int count = 0;
95 
96 		/*
97 		 * Callback deregistration will fail with rc -EAGAIN if the
98 		 * callback is currently active. Retry every 50 ms until
99 		 * successful or 500 ms has elapsed.
100 		 */
101 		do {
102 			rc = rte_intr_callback_unregister(intr_handle,
103 							  irq->handler,
104 							  bp->eth_dev);
105 			if (rc >= 0) {
106 				irq->requested = 0;
107 				break;
108 			}
109 			rte_delay_ms(50);
110 		} while (count++ < 10);
111 
112 		if (rc < 0) {
113 			PMD_DRV_LOG_LINE(ERR, "irq cb unregister failed rc: %d",
114 				    rc);
115 			return rc;
116 		}
117 	}
118 
119 	rte_free(bp->irq_tbl);
120 	bp->irq_tbl = NULL;
121 
122 	return 0;
123 }
124 
125 void bnxt_disable_int(struct bnxt *bp)
126 {
127 	struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
128 
129 	if (BNXT_NUM_ASYNC_CPR(bp) == 0)
130 		return;
131 
132 	if (is_bnxt_in_error(bp))
133 		return;
134 
135 	if (!cpr || !cpr->cp_db.doorbell)
136 		return;
137 
138 	/* Only the default completion ring */
139 	if (BNXT_HAS_NQ(bp))
140 		bnxt_db_nq(cpr);
141 	else
142 		B_CP_DB_DISARM(cpr);
143 }
144 
145 void bnxt_enable_int(struct bnxt *bp)
146 {
147 	struct bnxt_cp_ring_info *cpr = bp->async_cp_ring;
148 
149 	if (BNXT_NUM_ASYNC_CPR(bp) == 0)
150 		return;
151 
152 	if (!cpr || !cpr->cp_db.doorbell)
153 		return;
154 
155 	/* Only the default completion ring */
156 	if (BNXT_HAS_NQ(bp))
157 		bnxt_db_nq_arm(cpr);
158 	else
159 		B_CP_DB_ARM(cpr);
160 }
161 
162 int bnxt_setup_int(struct bnxt *bp)
163 {
164 	uint16_t total_vecs;
165 	const int len = sizeof(bp->irq_tbl[0].name);
166 	int i;
167 
168 	/* DPDK host only supports 1 MSI-X vector */
169 	total_vecs = 1;
170 	bp->irq_tbl = rte_calloc("bnxt_irq_tbl", total_vecs,
171 				 sizeof(struct bnxt_irq), 0);
172 	if (bp->irq_tbl) {
173 		for (i = 0; i < total_vecs; i++) {
174 			bp->irq_tbl[i].vector_idx = i;
175 			snprintf(bp->irq_tbl[i].name, len,
176 				 "%s-%d", bp->eth_dev->device->name, i);
177 			bp->irq_tbl[i].handler = bnxt_int_handler;
178 		}
179 	} else {
180 		PMD_DRV_LOG_LINE(ERR, "bnxt_irq_tbl setup failed");
181 		return -ENOMEM;
182 	}
183 
184 	return 0;
185 }
186 
187 int bnxt_request_int(struct bnxt *bp)
188 {
189 	struct rte_intr_handle *intr_handle = bp->pdev->intr_handle;
190 	struct bnxt_irq *irq = bp->irq_tbl;
191 	int rc = 0;
192 
193 	if (!irq)
194 		return 0;
195 
196 	if (!irq->requested) {
197 		rc = rte_intr_callback_register(intr_handle,
198 						irq->handler,
199 						bp->eth_dev);
200 		if (!rc)
201 			irq->requested = 1;
202 	}
203 
204 #ifdef RTE_EXEC_ENV_FREEBSD
205 	/**
206 	 * In FreeBSD OS, nic_uio does not support interrupts and
207 	 * interrupt register callback will fail.
208 	 */
209 	rc = 0;
210 #endif
211 
212 	return rc;
213 }
214