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>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/queue.h>
40 #include <sys/syslog.h>
41 #include <sys/taskqueue.h>
43 #include <machine/bus.h>
44 #include <machine/resource.h>
46 #include <dev/pci/pcireg.h>
47 #include <dev/pci/pcivar.h>
49 #include "common/efx.h"
54 sfxge_intr_line_filter(void *arg)
56 struct sfxge_evq *evq;
57 struct sfxge_softc *sc;
59 struct sfxge_intr *intr;
63 evq = (struct sfxge_evq *)arg;
68 KASSERT(intr != NULL, ("intr == NULL"));
69 KASSERT(intr->type == EFX_INTR_LINE,
70 ("intr->type != EFX_INTR_LINE"));
72 if (intr->state != SFXGE_INTR_STARTED)
73 return (FILTER_STRAY);
75 (void)efx_intr_status_line(enp, &fatal, &qmask);
78 (void) efx_intr_disable(enp);
79 (void) efx_intr_fatal(enp);
80 return (FILTER_HANDLED);
85 return (FILTER_SCHEDULE_THREAD);
88 /* SF bug 15783: If the function is not asserting its IRQ and
89 * we read the queue mask on the cycle before a flag is added
90 * to the mask, this inhibits the function from asserting the
91 * IRQ even though we don't see the flag set. To work around
92 * this, we must re-prime all event queues and report the IRQ
93 * as handled when we see a mask of zero. To allow for shared
94 * IRQs, we don't repeat this if we see a mask of zero twice
97 if (intr->zero_count++ == 0) {
98 if (evq->init_state == SFXGE_EVQ_STARTED) {
99 if (efx_ev_qpending(evq->common, evq->read_ptr))
100 return (FILTER_SCHEDULE_THREAD);
101 efx_ev_qprime(evq->common, evq->read_ptr);
102 return (FILTER_HANDLED);
106 return (FILTER_STRAY);
110 sfxge_intr_line(void *arg)
112 struct sfxge_evq *evq = arg;
114 (void)sfxge_ev_qpoll(evq);
118 sfxge_intr_message(void *arg)
120 struct sfxge_evq *evq;
121 struct sfxge_softc *sc;
123 struct sfxge_intr *intr;
127 evq = (struct sfxge_evq *)arg;
133 KASSERT(intr != NULL, ("intr == NULL"));
134 KASSERT(intr->type == EFX_INTR_MESSAGE,
135 ("intr->type != EFX_INTR_MESSAGE"));
137 if (__predict_false(intr->state != SFXGE_INTR_STARTED))
140 (void)efx_intr_status_message(enp, index, &fatal);
143 (void)efx_intr_disable(enp);
144 (void)efx_intr_fatal(enp);
148 (void)sfxge_ev_qpoll(evq);
152 sfxge_intr_bus_enable(struct sfxge_softc *sc)
154 struct sfxge_intr *intr;
155 struct sfxge_intr_hdl *table;
156 driver_filter_t *filter;
157 driver_intr_t *handler;
164 switch (intr->type) {
165 case EFX_INTR_MESSAGE:
166 filter = NULL; /* not shared */
167 handler = sfxge_intr_message;
171 filter = sfxge_intr_line_filter;
172 handler = sfxge_intr_line;
176 KASSERT(0, ("Invalid interrupt type"));
180 /* Try to add the handlers */
181 for (index = 0; index < intr->n_alloc; index++) {
182 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
183 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
184 sc->evq[index], &table[index].eih_tag)) != 0) {
187 #ifdef SFXGE_HAVE_DESCRIBE_INTR
188 if (intr->n_alloc > 1)
189 bus_describe_intr(sc->dev, table[index].eih_res,
190 table[index].eih_tag, "%d", index);
192 bus_bind_intr(sc->dev, table[index].eih_res, index);
199 /* Remove remaining handlers */
201 bus_teardown_intr(sc->dev, table[index].eih_res,
202 table[index].eih_tag);
208 sfxge_intr_bus_disable(struct sfxge_softc *sc)
210 struct sfxge_intr *intr;
211 struct sfxge_intr_hdl *table;
217 /* Remove all handlers */
218 for (i = 0; i < intr->n_alloc; i++)
219 bus_teardown_intr(sc->dev, table[i].eih_res,
224 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
227 struct sfxge_intr_hdl *table;
228 struct sfxge_intr *intr;
229 struct resource *res;
238 table = malloc(count * sizeof(struct sfxge_intr_hdl),
242 for (i = 0; i < count; i++) {
244 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
245 RF_SHAREABLE | RF_ACTIVE);
247 device_printf(dev, "Couldn't allocate interrupts for "
248 "message %d\n", rid);
252 table[i].eih_rid = rid;
253 table[i].eih_res = res;
258 for (i = 0; i < count; i++)
259 bus_release_resource(dev, SYS_RES_IRQ,
260 table[i].eih_rid, table[i].eih_res);
267 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
270 struct resource *resp;
274 resp = sc->intr.msix_res;
276 rid = rman_get_rid(resp);
277 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
281 sfxge_intr_setup_msix(struct sfxge_softc *sc)
283 struct sfxge_intr *intr;
284 struct resource *resp;
292 /* Check if MSI-X is available. */
293 count = pci_msix_count(dev);
297 /* Limit the number of interrupts to the number of CPUs. */
298 if (count > mp_ncpus)
301 /* Not very likely these days... */
302 if (count > EFX_MAXRSS)
305 if (sc->max_rss_channels > 0 && count > sc->max_rss_channels)
306 count = sc->max_rss_channels;
309 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
313 if (pci_alloc_msix(dev, &count) != 0) {
314 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
318 /* Allocate interrupt handlers. */
319 if (sfxge_intr_alloc(sc, count) != 0) {
320 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
321 pci_release_msi(dev);
325 intr->type = EFX_INTR_MESSAGE;
326 intr->n_alloc = count;
327 intr->msix_res = resp;
333 sfxge_intr_setup_msi(struct sfxge_softc *sc)
335 struct sfxge_intr_hdl *table;
336 struct sfxge_intr *intr;
346 * Check if MSI is available. All messages must be written to
347 * the same address and on x86 this means the IRQs have the
348 * same CPU affinity. So we only ever allocate 1.
350 count = pci_msi_count(dev) ? 1 : 0;
354 if ((error = pci_alloc_msi(dev, &count)) != 0)
357 /* Allocate interrupt handler. */
358 if (sfxge_intr_alloc(sc, count) != 0) {
359 pci_release_msi(dev);
363 intr->type = EFX_INTR_MESSAGE;
364 intr->n_alloc = count;
370 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
372 struct sfxge_intr_hdl *table;
373 struct sfxge_intr *intr;
374 struct resource *res;
382 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
383 RF_SHAREABLE | RF_ACTIVE);
387 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
388 table[0].eih_rid = rid;
389 table[0].eih_res = res;
391 intr->type = EFX_INTR_LINE;
398 static const char *const __sfxge_err[] = {
400 "SRAM out-of-bounds",
401 "Buffer ID out-of-bounds",
402 "Internal memory parity",
403 "Receive buffer ownership",
404 "Transmit buffer ownership",
405 "Receive descriptor ownership",
406 "Transmit descriptor ownership",
407 "Event queue ownership",
408 "Event queue FIFO overflow",
414 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
417 struct sfxge_softc *sc = (struct sfxge_softc *)arg;
418 device_t dev = sc->dev;
420 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
421 device_get_name(dev), device_get_unit(dev),
422 __sfxge_err[code], dword1, dword0);
426 sfxge_intr_stop(struct sfxge_softc *sc)
428 struct sfxge_intr *intr;
432 KASSERT(intr->state == SFXGE_INTR_STARTED,
433 ("Interrupts not started"));
435 intr->state = SFXGE_INTR_INITIALIZED;
437 /* Disable interrupts at the NIC */
438 efx_intr_disable(sc->enp);
440 /* Disable interrupts at the bus */
441 sfxge_intr_bus_disable(sc);
443 /* Tear down common code interrupt bits. */
444 efx_intr_fini(sc->enp);
448 sfxge_intr_start(struct sfxge_softc *sc)
450 struct sfxge_intr *intr;
455 esmp = &intr->status;
457 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
458 ("Interrupts not initialized"));
460 /* Zero the memory. */
461 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
463 /* Initialize common code interrupt bits. */
464 (void)efx_intr_init(sc->enp, intr->type, esmp);
466 /* Enable interrupts at the bus */
467 if ((rc = sfxge_intr_bus_enable(sc)) != 0)
470 intr->state = SFXGE_INTR_STARTED;
472 /* Enable interrupts at the NIC */
473 efx_intr_enable(sc->enp);
478 /* Tear down common code interrupt bits. */
479 efx_intr_fini(sc->enp);
481 intr->state = SFXGE_INTR_INITIALIZED;
487 sfxge_intr_fini(struct sfxge_softc *sc)
489 struct sfxge_intr_hdl *table;
490 struct sfxge_intr *intr;
497 esmp = &intr->status;
500 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
501 ("intr->state != SFXGE_INTR_INITIALIZED"));
503 /* Free DMA memory. */
504 sfxge_dma_free(esmp);
506 /* Free interrupt handles. */
507 for (i = 0; i < intr->n_alloc; i++)
508 bus_release_resource(dev, SYS_RES_IRQ,
509 table[i].eih_rid, table[i].eih_res);
511 if (table[0].eih_rid != 0)
512 pci_release_msi(dev);
514 if (intr->msix_res != NULL)
515 sfxge_intr_teardown_msix(sc);
517 /* Free the handle table */
518 free(table, M_SFXGE);
522 /* Clear the interrupt type */
523 intr->type = EFX_INTR_INVALID;
525 intr->state = SFXGE_INTR_UNINITIALIZED;
529 sfxge_intr_init(struct sfxge_softc *sc)
532 struct sfxge_intr *intr;
538 esmp = &intr->status;
540 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
541 ("Interrupts already initialized"));
543 /* Try to setup MSI-X or MSI interrupts if available. */
544 if ((rc = sfxge_intr_setup_msix(sc)) == 0)
545 device_printf(dev, "Using MSI-X interrupts\n");
546 else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
547 device_printf(dev, "Using MSI interrupts\n");
548 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
549 device_printf(dev, "Using fixed interrupts\n");
551 device_printf(dev, "Couldn't setup interrupts\n");
555 /* Set up DMA for interrupts. */
556 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
559 intr->state = SFXGE_INTR_INITIALIZED;