2 * Copyright (c) 2010-2011 Solarflare Communications, Inc.
5 * This software was developed in part by Philip Paeps under contract for
6 * Solarflare Communications, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
37 #include <sys/syslog.h>
39 #include <machine/bus.h>
40 #include <machine/resource.h>
42 #include <dev/pci/pcireg.h>
43 #include <dev/pci/pcivar.h>
45 #include "common/efx.h"
50 sfxge_intr_line_filter(void *arg)
52 struct sfxge_evq *evq;
53 struct sfxge_softc *sc;
55 struct sfxge_intr *intr;
59 evq = (struct sfxge_evq *)arg;
64 KASSERT(intr != NULL, ("intr == NULL"));
65 KASSERT(intr->type == EFX_INTR_LINE,
66 ("intr->type != EFX_INTR_LINE"));
68 if (intr->state != SFXGE_INTR_STARTED)
71 (void)efx_intr_status_line(enp, &fatal, &qmask);
74 (void) efx_intr_disable(enp);
75 (void) efx_intr_fatal(enp);
76 return FILTER_HANDLED;
81 return FILTER_SCHEDULE_THREAD;
84 /* SF bug 15783: If the function is not asserting its IRQ and
85 * we read the queue mask on the cycle before a flag is added
86 * to the mask, this inhibits the function from asserting the
87 * IRQ even though we don't see the flag set. To work around
88 * this, we must re-prime all event queues and report the IRQ
89 * as handled when we see a mask of zero. To allow for shared
90 * IRQs, we don't repeat this if we see a mask of zero twice
93 if (intr->zero_count++ == 0) {
94 if (evq->init_state == SFXGE_EVQ_STARTED) {
95 if (efx_ev_qpending(evq->common, evq->read_ptr))
96 return FILTER_SCHEDULE_THREAD;
97 efx_ev_qprime(evq->common, evq->read_ptr);
98 return FILTER_HANDLED;
106 sfxge_intr_line(void *arg)
108 struct sfxge_evq *evq = arg;
109 struct sfxge_softc *sc = evq->sc;
111 (void)sfxge_ev_qpoll(sc, 0);
115 sfxge_intr_message(void *arg)
117 struct sfxge_evq *evq;
118 struct sfxge_softc *sc;
120 struct sfxge_intr *intr;
124 evq = (struct sfxge_evq *)arg;
130 KASSERT(intr != NULL, ("intr == NULL"));
131 KASSERT(intr->type == EFX_INTR_MESSAGE,
132 ("intr->type != EFX_INTR_MESSAGE"));
134 if (intr->state != SFXGE_INTR_STARTED)
137 (void)efx_intr_status_message(enp, index, &fatal);
140 (void)efx_intr_disable(enp);
141 (void)efx_intr_fatal(enp);
145 (void)sfxge_ev_qpoll(sc, index);
149 sfxge_intr_bus_enable(struct sfxge_softc *sc)
151 struct sfxge_intr *intr;
152 struct sfxge_intr_hdl *table;
153 driver_filter_t *filter;
154 driver_intr_t *handler;
161 switch (intr->type) {
162 case EFX_INTR_MESSAGE:
163 filter = NULL; /* not shared */
164 handler = sfxge_intr_message;
168 filter = sfxge_intr_line_filter;
169 handler = sfxge_intr_line;
173 KASSERT(0, ("Invalid interrupt type"));
177 /* Try to add the handlers */
178 for (index = 0; index < intr->n_alloc; index++) {
179 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
180 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
181 sc->evq[index], &table[index].eih_tag)) != 0) {
184 #ifdef SFXGE_HAVE_DESCRIBE_INTR
185 if (intr->n_alloc > 1)
186 bus_describe_intr(sc->dev, table[index].eih_res,
187 table[index].eih_tag, "%d", index);
189 bus_bind_intr(sc->dev, table[index].eih_res, index);
196 /* Remove remaining handlers */
198 bus_teardown_intr(sc->dev, table[index].eih_res,
199 table[index].eih_tag);
205 sfxge_intr_bus_disable(struct sfxge_softc *sc)
207 struct sfxge_intr *intr;
208 struct sfxge_intr_hdl *table;
214 /* Remove all handlers */
215 for (i = 0; i < intr->n_alloc; i++)
216 bus_teardown_intr(sc->dev, table[i].eih_res,
221 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
224 struct sfxge_intr_hdl *table;
225 struct sfxge_intr *intr;
226 struct resource *res;
235 table = malloc(count * sizeof(struct sfxge_intr_hdl),
239 for (i = 0; i < count; i++) {
241 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
242 RF_SHAREABLE | RF_ACTIVE);
244 device_printf(dev, "Couldn't allocate interrupts for "
245 "message %d\n", rid);
249 table[i].eih_rid = rid;
250 table[i].eih_res = res;
255 for (i = 0; i < count; i++)
256 bus_release_resource(dev, SYS_RES_IRQ,
257 table[i].eih_rid, table[i].eih_res);
264 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
267 struct resource *resp;
271 resp = sc->intr.msix_res;
273 rid = rman_get_rid(resp);
274 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
278 sfxge_intr_setup_msix(struct sfxge_softc *sc)
280 struct sfxge_intr *intr;
281 struct resource *resp;
289 /* Check if MSI-X is available. */
290 count = pci_msix_count(dev);
294 /* Limit the number of interrupts to the number of CPUs. */
295 if (count > mp_ncpus)
298 /* Not very likely these days... */
299 if (count > EFX_MAXRSS)
303 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
307 if (pci_alloc_msix(dev, &count) != 0) {
308 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
312 /* Allocate interrupt handlers. */
313 if (sfxge_intr_alloc(sc, count) != 0) {
314 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
315 pci_release_msi(dev);
319 intr->type = EFX_INTR_MESSAGE;
320 intr->n_alloc = count;
321 intr->msix_res = resp;
327 sfxge_intr_setup_msi(struct sfxge_softc *sc)
329 struct sfxge_intr_hdl *table;
330 struct sfxge_intr *intr;
340 * Check if MSI is available. All messages must be written to
341 * the same address and on x86 this means the IRQs have the
342 * same CPU affinity. So we only ever allocate 1.
344 count = pci_msi_count(dev) ? 1 : 0;
348 if ((error = pci_alloc_msi(dev, &count)) != 0)
351 /* Allocate interrupt handler. */
352 if (sfxge_intr_alloc(sc, count) != 0) {
353 pci_release_msi(dev);
357 intr->type = EFX_INTR_MESSAGE;
358 intr->n_alloc = count;
364 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
366 struct sfxge_intr_hdl *table;
367 struct sfxge_intr *intr;
368 struct resource *res;
376 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
377 RF_SHAREABLE | RF_ACTIVE);
381 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
382 table[0].eih_rid = rid;
383 table[0].eih_res = res;
385 intr->type = EFX_INTR_LINE;
392 static const char *const __sfxge_err[] = {
394 "SRAM out-of-bounds",
395 "Buffer ID out-of-bounds",
396 "Internal memory parity",
397 "Receive buffer ownership",
398 "Transmit buffer ownership",
399 "Receive descriptor ownership",
400 "Transmit descriptor ownership",
401 "Event queue ownership",
402 "Event queue FIFO overflow",
408 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
411 struct sfxge_softc *sc = (struct sfxge_softc *)arg;
412 device_t dev = sc->dev;
414 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
415 device_get_name(dev), device_get_unit(dev),
416 __sfxge_err[code], dword1, dword0);
420 sfxge_intr_stop(struct sfxge_softc *sc)
422 struct sfxge_intr *intr;
426 KASSERT(intr->state == SFXGE_INTR_STARTED,
427 ("Interrupts not started"));
429 intr->state = SFXGE_INTR_INITIALIZED;
431 /* Disable interrupts at the NIC */
432 efx_intr_disable(sc->enp);
434 /* Disable interrupts at the bus */
435 sfxge_intr_bus_disable(sc);
437 /* Tear down common code interrupt bits. */
438 efx_intr_fini(sc->enp);
442 sfxge_intr_start(struct sfxge_softc *sc)
444 struct sfxge_intr *intr;
449 esmp = &intr->status;
451 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
452 ("Interrupts not initialized"));
454 /* Zero the memory. */
455 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
457 /* Initialize common code interrupt bits. */
458 (void)efx_intr_init(sc->enp, intr->type, esmp);
460 /* Enable interrupts at the bus */
461 if ((rc = sfxge_intr_bus_enable(sc)) != 0)
464 intr->state = SFXGE_INTR_STARTED;
466 /* Enable interrupts at the NIC */
467 efx_intr_enable(sc->enp);
472 /* Tear down common code interrupt bits. */
473 efx_intr_fini(sc->enp);
475 intr->state = SFXGE_INTR_INITIALIZED;
481 sfxge_intr_fini(struct sfxge_softc *sc)
483 struct sfxge_intr_hdl *table;
484 struct sfxge_intr *intr;
491 esmp = &intr->status;
494 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
495 ("intr->state != SFXGE_INTR_INITIALIZED"));
497 /* Free DMA memory. */
498 sfxge_dma_free(esmp);
500 /* Free interrupt handles. */
501 for (i = 0; i < intr->n_alloc; i++)
502 bus_release_resource(dev, SYS_RES_IRQ,
503 table[i].eih_rid, table[i].eih_res);
505 if (table[0].eih_rid != 0)
506 pci_release_msi(dev);
508 if (intr->msix_res != NULL)
509 sfxge_intr_teardown_msix(sc);
511 /* Free the handle table */
512 free(table, M_SFXGE);
516 /* Clear the interrupt type */
517 intr->type = EFX_INTR_INVALID;
519 intr->state = SFXGE_INTR_UNINITIALIZED;
523 sfxge_intr_init(struct sfxge_softc *sc)
526 struct sfxge_intr *intr;
532 esmp = &intr->status;
534 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
535 ("Interrupts already initialized"));
537 /* Try to setup MSI-X or MSI interrupts if available. */
538 if ((rc = sfxge_intr_setup_msix(sc)) == 0)
539 device_printf(dev, "Using MSI-X interrupts\n");
540 else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
541 device_printf(dev, "Using MSI interrupts\n");
542 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
543 device_printf(dev, "Using fixed interrupts\n");
545 device_printf(dev, "Couldn't setup interrupts\n");
549 /* Set up DMA for interrupts. */
550 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
553 intr->state = SFXGE_INTR_INITIALIZED;