xref: /f-stack/dpdk/drivers/net/sfc/sfc_intr.c (revision 031be553)
1 /*-
2  *   BSD LICENSE
3  *
4  * Copyright (c) 2016-2017 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * This software was jointly developed between OKTET Labs (under contract
8  * for Solarflare) and Solarflare Communications, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * At the momemt of writing DPDK v16.07 has notion of two types of
34  * interrupts: LSC (link status change) and RXQ (receive indication).
35  * It allows to register interrupt callback for entire device which is
36  * not intended to be used for receive indication (i.e. link status
37  * change indication only). The handler has no information which HW
38  * interrupt has triggered it, so we don't know which event queue should
39  * be polled/reprimed (except qmask in the case of legacy line interrupt).
40  */
41 
42 #include <rte_common.h>
43 #include <rte_interrupts.h>
44 
45 #include "efx.h"
46 
47 #include "sfc.h"
48 #include "sfc_log.h"
49 #include "sfc_ev.h"
50 
51 static void
52 sfc_intr_handle_mgmt_evq(struct sfc_adapter *sa)
53 {
54 	struct sfc_evq *evq;
55 
56 	rte_spinlock_lock(&sa->mgmt_evq_lock);
57 
58 	evq = sa->mgmt_evq;
59 
60 	if (!sa->mgmt_evq_running) {
61 		sfc_log_init(sa, "interrupt on not running management EVQ %u",
62 			     evq->evq_index);
63 	} else {
64 		sfc_ev_qpoll(evq);
65 
66 		if (sfc_ev_qprime(evq) != 0)
67 			sfc_err(sa, "cannot prime EVQ %u", evq->evq_index);
68 	}
69 
70 	rte_spinlock_unlock(&sa->mgmt_evq_lock);
71 }
72 
73 static void
74 sfc_intr_line_handler(void *cb_arg)
75 {
76 	struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg;
77 	efx_nic_t *enp = sa->nic;
78 	boolean_t fatal;
79 	uint32_t qmask;
80 	unsigned int lsc_seq = sa->port.lsc_seq;
81 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
82 
83 	sfc_log_init(sa, "entry");
84 
85 	if (sa->state != SFC_ADAPTER_STARTED &&
86 	    sa->state != SFC_ADAPTER_STARTING &&
87 	    sa->state != SFC_ADAPTER_STOPPING) {
88 		sfc_log_init(sa,
89 			     "interrupt on stopped adapter, don't reenable");
90 		goto exit;
91 	}
92 
93 	efx_intr_status_line(enp, &fatal, &qmask);
94 	if (fatal) {
95 		(void)efx_intr_disable(enp);
96 		(void)efx_intr_fatal(enp);
97 		sfc_err(sa, "fatal, interrupts disabled");
98 		goto exit;
99 	}
100 
101 	if (qmask & (1 << sa->mgmt_evq_index))
102 		sfc_intr_handle_mgmt_evq(sa);
103 
104 	if (rte_intr_enable(&pci_dev->intr_handle) != 0)
105 		sfc_err(sa, "cannot reenable interrupts");
106 
107 	sfc_log_init(sa, "done");
108 
109 exit:
110 	if (lsc_seq != sa->port.lsc_seq) {
111 		sfc_info(sa, "link status change event: link %s",
112 			 sa->eth_dev->data->dev_link.link_status ?
113 			 "UP" : "DOWN");
114 		_rte_eth_dev_callback_process(sa->eth_dev,
115 					      RTE_ETH_EVENT_INTR_LSC,
116 					      NULL, NULL);
117 	}
118 }
119 
120 static void
121 sfc_intr_message_handler(void *cb_arg)
122 {
123 	struct sfc_adapter *sa = (struct sfc_adapter *)cb_arg;
124 	efx_nic_t *enp = sa->nic;
125 	boolean_t fatal;
126 	unsigned int lsc_seq = sa->port.lsc_seq;
127 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
128 
129 	sfc_log_init(sa, "entry");
130 
131 	if (sa->state != SFC_ADAPTER_STARTED &&
132 	    sa->state != SFC_ADAPTER_STARTING &&
133 	    sa->state != SFC_ADAPTER_STOPPING) {
134 		sfc_log_init(sa, "adapter not-started, don't reenable");
135 		goto exit;
136 	}
137 
138 	efx_intr_status_message(enp, sa->mgmt_evq_index, &fatal);
139 	if (fatal) {
140 		(void)efx_intr_disable(enp);
141 		(void)efx_intr_fatal(enp);
142 		sfc_err(sa, "fatal, interrupts disabled");
143 		goto exit;
144 	}
145 
146 	sfc_intr_handle_mgmt_evq(sa);
147 
148 	if (rte_intr_enable(&pci_dev->intr_handle) != 0)
149 		sfc_err(sa, "cannot reenable interrupts");
150 
151 	sfc_log_init(sa, "done");
152 
153 exit:
154 	if (lsc_seq != sa->port.lsc_seq) {
155 		sfc_info(sa, "link status change event");
156 		_rte_eth_dev_callback_process(sa->eth_dev,
157 					      RTE_ETH_EVENT_INTR_LSC,
158 					      NULL, NULL);
159 	}
160 }
161 
162 int
163 sfc_intr_start(struct sfc_adapter *sa)
164 {
165 	struct sfc_intr *intr = &sa->intr;
166 	struct rte_intr_handle *intr_handle;
167 	struct rte_pci_device *pci_dev;
168 	int rc;
169 
170 	sfc_log_init(sa, "entry");
171 
172 	/*
173 	 * The EFX common code event queue module depends on the interrupt
174 	 * module. Ensure that the interrupt module is always initialized
175 	 * (even if interrupts are not used).  Status memory is required
176 	 * for Siena only and may be NULL for EF10.
177 	 */
178 	sfc_log_init(sa, "efx_intr_init");
179 	rc = efx_intr_init(sa->nic, intr->type, NULL);
180 	if (rc != 0)
181 		goto fail_intr_init;
182 
183 	pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
184 	intr_handle = &pci_dev->intr_handle;
185 
186 	if (intr->handler != NULL) {
187 		sfc_log_init(sa, "rte_intr_callback_register");
188 		rc = rte_intr_callback_register(intr_handle, intr->handler,
189 						(void *)sa);
190 		if (rc != 0) {
191 			sfc_err(sa,
192 				"cannot register interrupt handler (rc=%d)",
193 				rc);
194 			/*
195 			 * Convert error code from negative returned by RTE API
196 			 * to positive used in the driver.
197 			 */
198 			rc = -rc;
199 			goto fail_rte_intr_cb_reg;
200 		}
201 
202 		sfc_log_init(sa, "rte_intr_enable");
203 		rc = rte_intr_enable(intr_handle);
204 		if (rc != 0) {
205 			sfc_err(sa, "cannot enable interrupts (rc=%d)", rc);
206 			/*
207 			 * Convert error code from negative returned by RTE API
208 			 * to positive used in the driver.
209 			 */
210 			rc = -rc;
211 			goto fail_rte_intr_enable;
212 		}
213 
214 		sfc_log_init(sa, "efx_intr_enable");
215 		efx_intr_enable(sa->nic);
216 	}
217 
218 	sfc_log_init(sa, "done type=%u max_intr=%d nb_efd=%u vec=%p",
219 		     intr_handle->type, intr_handle->max_intr,
220 		     intr_handle->nb_efd, intr_handle->intr_vec);
221 	return 0;
222 
223 fail_rte_intr_enable:
224 	rte_intr_callback_unregister(intr_handle, intr->handler, (void *)sa);
225 
226 fail_rte_intr_cb_reg:
227 	efx_intr_fini(sa->nic);
228 
229 fail_intr_init:
230 	sfc_log_init(sa, "failed %d", rc);
231 	return rc;
232 }
233 
234 void
235 sfc_intr_stop(struct sfc_adapter *sa)
236 {
237 	struct sfc_intr *intr = &sa->intr;
238 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
239 
240 	sfc_log_init(sa, "entry");
241 
242 	if (intr->handler != NULL) {
243 		struct rte_intr_handle *intr_handle;
244 		int rc;
245 
246 		efx_intr_disable(sa->nic);
247 
248 		intr_handle = &pci_dev->intr_handle;
249 		if (rte_intr_disable(intr_handle) != 0)
250 			sfc_err(sa, "cannot disable interrupts");
251 
252 		while ((rc = rte_intr_callback_unregister(intr_handle,
253 				intr->handler, (void *)sa)) == -EAGAIN)
254 			;
255 		if (rc != 1)
256 			sfc_err(sa,
257 				"cannot unregister interrupt handler %d",
258 				rc);
259 	}
260 
261 	efx_intr_fini(sa->nic);
262 
263 	sfc_log_init(sa, "done");
264 }
265 
266 int
267 sfc_intr_configure(struct sfc_adapter *sa)
268 {
269 	struct sfc_intr *intr = &sa->intr;
270 
271 	sfc_log_init(sa, "entry");
272 
273 	intr->handler = NULL;
274 	intr->lsc_intr = (sa->eth_dev->data->dev_conf.intr_conf.lsc != 0);
275 	if (!intr->lsc_intr) {
276 		sfc_info(sa, "LSC tracking using interrupts is disabled");
277 		goto done;
278 	}
279 
280 	switch (intr->type) {
281 	case EFX_INTR_MESSAGE:
282 		intr->handler = sfc_intr_message_handler;
283 		break;
284 	case EFX_INTR_LINE:
285 		intr->handler = sfc_intr_line_handler;
286 		break;
287 	case EFX_INTR_INVALID:
288 		sfc_warn(sa, "interrupts are not supported");
289 		break;
290 	default:
291 		sfc_panic(sa, "unexpected EFX interrupt type %u\n", intr->type);
292 		break;
293 	}
294 
295 done:
296 	sfc_log_init(sa, "done");
297 	return 0;
298 }
299 
300 void
301 sfc_intr_close(struct sfc_adapter *sa)
302 {
303 	sfc_log_init(sa, "entry");
304 
305 	sfc_log_init(sa, "done");
306 }
307 
308 int
309 sfc_intr_attach(struct sfc_adapter *sa)
310 {
311 	struct sfc_intr *intr = &sa->intr;
312 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev);
313 
314 	sfc_log_init(sa, "entry");
315 
316 	switch (pci_dev->intr_handle.type) {
317 #ifdef RTE_EXEC_ENV_LINUXAPP
318 	case RTE_INTR_HANDLE_UIO_INTX:
319 	case RTE_INTR_HANDLE_VFIO_LEGACY:
320 		intr->type = EFX_INTR_LINE;
321 		break;
322 	case RTE_INTR_HANDLE_UIO:
323 	case RTE_INTR_HANDLE_VFIO_MSI:
324 	case RTE_INTR_HANDLE_VFIO_MSIX:
325 		intr->type = EFX_INTR_MESSAGE;
326 		break;
327 #endif
328 	default:
329 		intr->type = EFX_INTR_INVALID;
330 		break;
331 	}
332 
333 	sfc_log_init(sa, "done");
334 	return 0;
335 }
336 
337 void
338 sfc_intr_detach(struct sfc_adapter *sa)
339 {
340 	sfc_log_init(sa, "entry");
341 
342 	sa->intr.type = EFX_INTR_INVALID;
343 
344 	sfc_log_init(sa, "done");
345 }
346