xref: /freebsd/sys/dev/sfxge/sfxge_intr.c (revision 10b59a9b4add0320d52c15ce057dd697261e7dfc)
1 /*-
2  * Copyright (c) 2010-2011 Solarflare Communications, Inc.
3  * All rights reserved.
4  *
5  * This software was developed in part by Philip Paeps under contract for
6  * Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/rman.h>
36 #include <sys/smp.h>
37 #include <sys/syslog.h>
38 
39 #include <machine/bus.h>
40 #include <machine/resource.h>
41 
42 #include <dev/pci/pcireg.h>
43 #include <dev/pci/pcivar.h>
44 
45 #include "common/efx.h"
46 
47 #include "sfxge.h"
48 
49 static int
50 sfxge_intr_line_filter(void *arg)
51 {
52 	struct sfxge_evq *evq;
53 	struct sfxge_softc *sc;
54 	efx_nic_t *enp;
55 	struct sfxge_intr *intr;
56 	boolean_t fatal;
57 	uint32_t qmask;
58 
59 	evq = (struct sfxge_evq *)arg;
60 	sc = evq->sc;
61 	enp = sc->enp;
62 	intr = &sc->intr;
63 
64 	KASSERT(intr != NULL, ("intr == NULL"));
65 	KASSERT(intr->type == EFX_INTR_LINE,
66 	    ("intr->type != EFX_INTR_LINE"));
67 
68 	if (intr->state != SFXGE_INTR_STARTED &&
69 	    intr->state != SFXGE_INTR_TESTING)
70 		return FILTER_STRAY;
71 
72 	if (intr->state == SFXGE_INTR_TESTING) {
73 		intr->mask |= 1;	/* only one interrupt */
74 		return FILTER_HANDLED;
75 	}
76 
77 	(void)efx_intr_status_line(enp, &fatal, &qmask);
78 
79 	if (fatal) {
80 		(void) efx_intr_disable(enp);
81 		(void) efx_intr_fatal(enp);
82 		return FILTER_HANDLED;
83 	}
84 
85 	if (qmask != 0) {
86 		intr->zero_count = 0;
87 		return FILTER_SCHEDULE_THREAD;
88 	}
89 
90 	/* SF bug 15783: If the function is not asserting its IRQ and
91 	 * we read the queue mask on the cycle before a flag is added
92 	 * to the mask, this inhibits the function from asserting the
93 	 * IRQ even though we don't see the flag set.  To work around
94 	 * this, we must re-prime all event queues and report the IRQ
95 	 * as handled when we see a mask of zero.  To allow for shared
96 	 * IRQs, we don't repeat this if we see a mask of zero twice
97 	 * or more in a row.
98 	 */
99 	if (intr->zero_count++ == 0) {
100 		if (evq->init_state == SFXGE_EVQ_STARTED) {
101 			if (efx_ev_qpending(evq->common, evq->read_ptr))
102 				return FILTER_SCHEDULE_THREAD;
103 			efx_ev_qprime(evq->common, evq->read_ptr);
104 			return FILTER_HANDLED;
105 		}
106 	}
107 
108 	return FILTER_STRAY;
109 }
110 
111 static void
112 sfxge_intr_line(void *arg)
113 {
114 	struct sfxge_evq *evq = arg;
115 	struct sfxge_softc *sc = evq->sc;
116 
117 	(void)sfxge_ev_qpoll(sc, 0);
118 }
119 
120 static void
121 sfxge_intr_message(void *arg)
122 {
123 	struct sfxge_evq *evq;
124 	struct sfxge_softc *sc;
125 	efx_nic_t *enp;
126 	struct sfxge_intr *intr;
127 	unsigned int index;
128 	boolean_t fatal;
129 
130 	evq = (struct sfxge_evq *)arg;
131 	sc = evq->sc;
132 	enp = sc->enp;
133 	intr = &sc->intr;
134 	index = evq->index;
135 
136 	KASSERT(intr != NULL, ("intr == NULL"));
137 	KASSERT(intr->type == EFX_INTR_MESSAGE,
138 	    ("intr->type != EFX_INTR_MESSAGE"));
139 
140 	if (intr->state != SFXGE_INTR_STARTED &&
141 	    intr->state != SFXGE_INTR_TESTING)
142 		return;
143 
144 	if (intr->state == SFXGE_INTR_TESTING) {
145 		uint64_t mask;
146 
147 		do {
148 			mask = intr->mask;
149 		} while (atomic_cmpset_ptr(&intr->mask, mask,
150 		    mask | (1 << index)) == 0);
151 
152 		return;
153 	}
154 
155 	(void)efx_intr_status_message(enp, index, &fatal);
156 
157 	if (fatal) {
158 		(void)efx_intr_disable(enp);
159 		(void)efx_intr_fatal(enp);
160 		return;
161 	}
162 
163 	(void)sfxge_ev_qpoll(sc, index);
164 }
165 
166 static int
167 sfxge_intr_bus_enable(struct sfxge_softc *sc)
168 {
169 	struct sfxge_intr *intr;
170 	struct sfxge_intr_hdl *table;
171 	driver_filter_t *filter;
172 	driver_intr_t *handler;
173 	int index;
174 	int err;
175 
176 	intr = &sc->intr;
177 	table = intr->table;
178 
179 	switch (intr->type) {
180 	case EFX_INTR_MESSAGE:
181 		filter = NULL; /* not shared */
182 		handler = sfxge_intr_message;
183 		break;
184 
185 	case EFX_INTR_LINE:
186 		filter = sfxge_intr_line_filter;
187 		handler = sfxge_intr_line;
188 		break;
189 
190 	default:
191 		KASSERT(0, ("Invalid interrupt type"));
192 		return EINVAL;
193 	}
194 
195 	/* Try to add the handlers */
196 	for (index = 0; index < intr->n_alloc; index++) {
197 		if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
198 			    INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
199 			    sc->evq[index], &table[index].eih_tag)) != 0) {
200 			goto fail;
201 		}
202 #ifdef SFXGE_HAVE_DESCRIBE_INTR
203 		if (intr->n_alloc > 1)
204 			bus_describe_intr(sc->dev, table[index].eih_res,
205 			    table[index].eih_tag, "%d", index);
206 #endif
207 		bus_bind_intr(sc->dev, table[index].eih_res, index);
208 
209 	}
210 
211 	return (0);
212 
213 fail:
214 	/* Remove remaining handlers */
215 	while (--index >= 0)
216 		bus_teardown_intr(sc->dev, table[index].eih_res,
217 		    table[index].eih_tag);
218 
219 	return (err);
220 }
221 
222 static void
223 sfxge_intr_bus_disable(struct sfxge_softc *sc)
224 {
225 	struct sfxge_intr *intr;
226 	struct sfxge_intr_hdl *table;
227 	int i;
228 
229 	intr = &sc->intr;
230 	table = intr->table;
231 
232 	/* Remove all handlers */
233 	for (i = 0; i < intr->n_alloc; i++)
234 		bus_teardown_intr(sc->dev, table[i].eih_res,
235 		    table[i].eih_tag);
236 }
237 
238 static int
239 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
240 {
241 	device_t dev;
242 	struct sfxge_intr_hdl *table;
243 	struct sfxge_intr *intr;
244 	struct resource *res;
245 	int rid;
246 	int error;
247 	int i;
248 
249 	dev = sc->dev;
250 	intr = &sc->intr;
251 	error = 0;
252 
253 	table = malloc(count * sizeof(struct sfxge_intr_hdl),
254 	    M_SFXGE, M_WAITOK);
255 	intr->table = table;
256 
257 	for (i = 0; i < count; i++) {
258 		rid = i + 1;
259 		res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
260 		    RF_SHAREABLE | RF_ACTIVE);
261 		if (res == NULL) {
262 			device_printf(dev, "Couldn't allocate interrupts for "
263 			    "message %d\n", rid);
264 			error = ENOMEM;
265 			break;
266 		}
267 		table[i].eih_rid = rid;
268 		table[i].eih_res = res;
269 	}
270 
271 	if (error) {
272 		count = i - 1;
273 		for (i = 0; i < count; i++)
274 			bus_release_resource(dev, SYS_RES_IRQ,
275 			    table[i].eih_rid, table[i].eih_res);
276 	}
277 
278 	return (error);
279 }
280 
281 static void
282 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
283 {
284 	device_t dev;
285 	struct resource *resp;
286 	int rid;
287 
288 	dev = sc->dev;
289 	resp = sc->intr.msix_res;
290 
291 	rid = rman_get_rid(resp);
292 	bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
293 }
294 
295 static int
296 sfxge_intr_setup_msix(struct sfxge_softc *sc)
297 {
298 	struct sfxge_intr *intr;
299 	struct resource *resp;
300 	device_t dev;
301 	int count;
302 	int rid;
303 
304 	dev = sc->dev;
305 	intr = &sc->intr;
306 
307 	/* Check if MSI-X is available. */
308 	count = pci_msix_count(dev);
309 	if (count == 0)
310 		return (EINVAL);
311 
312 	/* Limit the number of interrupts to the number of CPUs. */
313 	if (count > mp_ncpus)
314 		count = mp_ncpus;
315 
316 	/* Not very likely these days... */
317 	if (count > EFX_MAXRSS)
318 		count = EFX_MAXRSS;
319 
320 	rid = PCIR_BAR(4);
321 	resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
322 	if (resp == NULL)
323 		return (ENOMEM);
324 
325 	if (pci_alloc_msix(dev, &count) != 0) {
326 		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
327 		return (ENOMEM);
328 	}
329 
330 	/* Allocate interrupt handlers. */
331 	if (sfxge_intr_alloc(sc, count) != 0) {
332 		bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
333 		pci_release_msi(dev);
334 		return (ENOMEM);
335 	}
336 
337 	intr->type = EFX_INTR_MESSAGE;
338 	intr->n_alloc = count;
339 	intr->msix_res = resp;
340 
341 	return (0);
342 }
343 
344 static int
345 sfxge_intr_setup_msi(struct sfxge_softc *sc)
346 {
347 	struct sfxge_intr_hdl *table;
348 	struct sfxge_intr *intr;
349 	device_t dev;
350 	int count;
351 	int error;
352 
353 	dev = sc->dev;
354 	intr = &sc->intr;
355 	table = intr->table;
356 
357 	/*
358 	 * Check if MSI is available.  All messages must be written to
359 	 * the same address and on x86 this means the IRQs have the
360 	 * same CPU affinity.  So we only ever allocate 1.
361 	 */
362 	count = pci_msi_count(dev) ? 1 : 0;
363 	if (count == 0)
364 		return (EINVAL);
365 
366 	if ((error = pci_alloc_msi(dev, &count)) != 0)
367 		return (ENOMEM);
368 
369 	/* Allocate interrupt handler. */
370 	if (sfxge_intr_alloc(sc, count) != 0) {
371 		pci_release_msi(dev);
372 		return (ENOMEM);
373 	}
374 
375 	intr->type = EFX_INTR_MESSAGE;
376 	intr->n_alloc = count;
377 
378 	return (0);
379 }
380 
381 static int
382 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
383 {
384 	struct sfxge_intr_hdl *table;
385 	struct sfxge_intr *intr;
386 	struct resource *res;
387 	device_t dev;
388 	int rid;
389 
390 	dev = sc->dev;
391 	intr = &sc->intr;
392 
393 	rid = 0;
394 	res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
395 	    RF_SHAREABLE | RF_ACTIVE);
396 	if (res == NULL)
397 		return (ENOMEM);
398 
399 	table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
400 	table[0].eih_rid = rid;
401 	table[0].eih_res = res;
402 
403 	intr->type = EFX_INTR_LINE;
404 	intr->n_alloc = 1;
405 	intr->table = table;
406 
407 	return (0);
408 }
409 
410 static const char *const __sfxge_err[] = {
411 	"",
412 	"SRAM out-of-bounds",
413 	"Buffer ID out-of-bounds",
414 	"Internal memory parity",
415 	"Receive buffer ownership",
416 	"Transmit buffer ownership",
417 	"Receive descriptor ownership",
418 	"Transmit descriptor ownership",
419 	"Event queue ownership",
420 	"Event queue FIFO overflow",
421 	"Illegal address",
422 	"SRAM parity"
423 };
424 
425 void
426 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
427     uint32_t dword1)
428 {
429 	struct sfxge_softc *sc = (struct sfxge_softc *)arg;
430 	device_t dev = sc->dev;
431 
432 	log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
433 	    device_get_name(dev), device_get_unit(dev),
434 		__sfxge_err[code], dword1, dword0);
435 }
436 
437 void
438 sfxge_intr_stop(struct sfxge_softc *sc)
439 {
440 	struct sfxge_intr *intr;
441 
442 	intr = &sc->intr;
443 
444 	KASSERT(intr->state == SFXGE_INTR_STARTED,
445 	    ("Interrupts not started"));
446 
447 	intr->state = SFXGE_INTR_INITIALIZED;
448 
449 	/* Disable interrupts at the NIC */
450 	intr->mask = 0;
451 	efx_intr_disable(sc->enp);
452 
453 	/* Disable interrupts at the bus */
454 	sfxge_intr_bus_disable(sc);
455 
456 	/* Tear down common code interrupt bits. */
457 	efx_intr_fini(sc->enp);
458 }
459 
460 int
461 sfxge_intr_start(struct sfxge_softc *sc)
462 {
463 	struct sfxge_intr *intr;
464 	efsys_mem_t *esmp;
465 	int rc;
466 
467 	intr = &sc->intr;
468 	esmp = &intr->status;
469 
470 	KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
471 	    ("Interrupts not initialized"));
472 
473 	/* Zero the memory. */
474 	(void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
475 
476 	/* Initialize common code interrupt bits. */
477 	(void)efx_intr_init(sc->enp, intr->type, esmp);
478 
479 	/* Enable interrupts at the bus */
480 	if ((rc = sfxge_intr_bus_enable(sc)) != 0)
481 		goto fail;
482 
483 	intr->state = SFXGE_INTR_TESTING;
484 
485 	/* Enable interrupts at the NIC */
486 	efx_intr_enable(sc->enp);
487 
488 	intr->state = SFXGE_INTR_STARTED;
489 
490 	return (0);
491 
492 fail:
493 	/* Tear down common code interrupt bits. */
494 	efx_intr_fini(sc->enp);
495 
496 	intr->state = SFXGE_INTR_INITIALIZED;
497 
498 	return (rc);
499 }
500 
501 void
502 sfxge_intr_fini(struct sfxge_softc *sc)
503 {
504 	struct sfxge_intr_hdl *table;
505 	struct sfxge_intr *intr;
506 	efsys_mem_t *esmp;
507 	device_t dev;
508 	int i;
509 
510 	dev = sc->dev;
511 	intr = &sc->intr;
512 	esmp = &intr->status;
513 	table = intr->table;
514 
515 	KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
516 	    ("intr->state != SFXGE_INTR_INITIALIZED"));
517 
518 	/* Free DMA memory. */
519 	sfxge_dma_free(esmp);
520 
521 	/* Free interrupt handles. */
522 	for (i = 0; i < intr->n_alloc; i++)
523 		bus_release_resource(dev, SYS_RES_IRQ,
524 		    table[i].eih_rid, table[i].eih_res);
525 
526 	if (table[0].eih_rid != 0)
527 		pci_release_msi(dev);
528 
529 	if (intr->msix_res != NULL)
530 		sfxge_intr_teardown_msix(sc);
531 
532 	/* Free the handle table */
533 	free(table, M_SFXGE);
534 	intr->table = NULL;
535 	intr->n_alloc = 0;
536 
537 	/* Clear the interrupt type */
538 	intr->type = EFX_INTR_INVALID;
539 
540 	intr->state = SFXGE_INTR_UNINITIALIZED;
541 }
542 
543 int
544 sfxge_intr_init(struct sfxge_softc *sc)
545 {
546 	device_t dev;
547 	struct sfxge_intr *intr;
548 	efsys_mem_t *esmp;
549 	int rc;
550 
551 	dev = sc->dev;
552 	intr = &sc->intr;
553 	esmp = &intr->status;
554 
555 	KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
556 	    ("Interrupts already initialized"));
557 
558 	/* Try to setup MSI-X or MSI interrupts if available. */
559 	if ((rc = sfxge_intr_setup_msix(sc)) == 0)
560 		device_printf(dev, "Using MSI-X interrupts\n");
561 	else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
562 		device_printf(dev, "Using MSI interrupts\n");
563 	else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
564 		device_printf(dev, "Using fixed interrupts\n");
565 	} else {
566 		device_printf(dev, "Couldn't setup interrupts\n");
567 		return (ENOMEM);
568 	}
569 
570 	/* Set up DMA for interrupts. */
571 	if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
572 		return (ENOMEM);
573 
574 	intr->state = SFXGE_INTR_INITIALIZED;
575 
576 	return (0);
577 }
578