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)
69 return (FILTER_STRAY);
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);
102 return (FILTER_STRAY);
106 sfxge_intr_line(void *arg)
108 struct sfxge_evq *evq = arg;
110 (void)sfxge_ev_qpoll(evq);
114 sfxge_intr_message(void *arg)
116 struct sfxge_evq *evq;
117 struct sfxge_softc *sc;
119 struct sfxge_intr *intr;
123 evq = (struct sfxge_evq *)arg;
129 KASSERT(intr != NULL, ("intr == NULL"));
130 KASSERT(intr->type == EFX_INTR_MESSAGE,
131 ("intr->type != EFX_INTR_MESSAGE"));
133 if (intr->state != SFXGE_INTR_STARTED)
136 (void)efx_intr_status_message(enp, index, &fatal);
139 (void)efx_intr_disable(enp);
140 (void)efx_intr_fatal(enp);
144 (void)sfxge_ev_qpoll(evq);
148 sfxge_intr_bus_enable(struct sfxge_softc *sc)
150 struct sfxge_intr *intr;
151 struct sfxge_intr_hdl *table;
152 driver_filter_t *filter;
153 driver_intr_t *handler;
160 switch (intr->type) {
161 case EFX_INTR_MESSAGE:
162 filter = NULL; /* not shared */
163 handler = sfxge_intr_message;
167 filter = sfxge_intr_line_filter;
168 handler = sfxge_intr_line;
172 KASSERT(0, ("Invalid interrupt type"));
176 /* Try to add the handlers */
177 for (index = 0; index < intr->n_alloc; index++) {
178 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
179 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
180 sc->evq[index], &table[index].eih_tag)) != 0) {
183 #ifdef SFXGE_HAVE_DESCRIBE_INTR
184 if (intr->n_alloc > 1)
185 bus_describe_intr(sc->dev, table[index].eih_res,
186 table[index].eih_tag, "%d", index);
188 bus_bind_intr(sc->dev, table[index].eih_res, index);
195 /* Remove remaining handlers */
197 bus_teardown_intr(sc->dev, table[index].eih_res,
198 table[index].eih_tag);
204 sfxge_intr_bus_disable(struct sfxge_softc *sc)
206 struct sfxge_intr *intr;
207 struct sfxge_intr_hdl *table;
213 /* Remove all handlers */
214 for (i = 0; i < intr->n_alloc; i++)
215 bus_teardown_intr(sc->dev, table[i].eih_res,
220 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
223 struct sfxge_intr_hdl *table;
224 struct sfxge_intr *intr;
225 struct resource *res;
234 table = malloc(count * sizeof(struct sfxge_intr_hdl),
238 for (i = 0; i < count; i++) {
240 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
241 RF_SHAREABLE | RF_ACTIVE);
243 device_printf(dev, "Couldn't allocate interrupts for "
244 "message %d\n", rid);
248 table[i].eih_rid = rid;
249 table[i].eih_res = res;
254 for (i = 0; i < count; i++)
255 bus_release_resource(dev, SYS_RES_IRQ,
256 table[i].eih_rid, table[i].eih_res);
263 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
266 struct resource *resp;
270 resp = sc->intr.msix_res;
272 rid = rman_get_rid(resp);
273 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
277 sfxge_intr_setup_msix(struct sfxge_softc *sc)
279 struct sfxge_intr *intr;
280 struct resource *resp;
288 /* Check if MSI-X is available. */
289 count = pci_msix_count(dev);
293 /* Limit the number of interrupts to the number of CPUs. */
294 if (count > mp_ncpus)
297 /* Not very likely these days... */
298 if (count > EFX_MAXRSS)
301 if (sc->max_rss_channels > 0 && count > sc->max_rss_channels)
302 count = sc->max_rss_channels;
305 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
309 if (pci_alloc_msix(dev, &count) != 0) {
310 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
314 /* Allocate interrupt handlers. */
315 if (sfxge_intr_alloc(sc, count) != 0) {
316 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
317 pci_release_msi(dev);
321 intr->type = EFX_INTR_MESSAGE;
322 intr->n_alloc = count;
323 intr->msix_res = resp;
329 sfxge_intr_setup_msi(struct sfxge_softc *sc)
331 struct sfxge_intr_hdl *table;
332 struct sfxge_intr *intr;
342 * Check if MSI is available. All messages must be written to
343 * the same address and on x86 this means the IRQs have the
344 * same CPU affinity. So we only ever allocate 1.
346 count = pci_msi_count(dev) ? 1 : 0;
350 if ((error = pci_alloc_msi(dev, &count)) != 0)
353 /* Allocate interrupt handler. */
354 if (sfxge_intr_alloc(sc, count) != 0) {
355 pci_release_msi(dev);
359 intr->type = EFX_INTR_MESSAGE;
360 intr->n_alloc = count;
366 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
368 struct sfxge_intr_hdl *table;
369 struct sfxge_intr *intr;
370 struct resource *res;
378 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
379 RF_SHAREABLE | RF_ACTIVE);
383 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
384 table[0].eih_rid = rid;
385 table[0].eih_res = res;
387 intr->type = EFX_INTR_LINE;
394 static const char *const __sfxge_err[] = {
396 "SRAM out-of-bounds",
397 "Buffer ID out-of-bounds",
398 "Internal memory parity",
399 "Receive buffer ownership",
400 "Transmit buffer ownership",
401 "Receive descriptor ownership",
402 "Transmit descriptor ownership",
403 "Event queue ownership",
404 "Event queue FIFO overflow",
410 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
413 struct sfxge_softc *sc = (struct sfxge_softc *)arg;
414 device_t dev = sc->dev;
416 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
417 device_get_name(dev), device_get_unit(dev),
418 __sfxge_err[code], dword1, dword0);
422 sfxge_intr_stop(struct sfxge_softc *sc)
424 struct sfxge_intr *intr;
428 KASSERT(intr->state == SFXGE_INTR_STARTED,
429 ("Interrupts not started"));
431 intr->state = SFXGE_INTR_INITIALIZED;
433 /* Disable interrupts at the NIC */
434 efx_intr_disable(sc->enp);
436 /* Disable interrupts at the bus */
437 sfxge_intr_bus_disable(sc);
439 /* Tear down common code interrupt bits. */
440 efx_intr_fini(sc->enp);
444 sfxge_intr_start(struct sfxge_softc *sc)
446 struct sfxge_intr *intr;
451 esmp = &intr->status;
453 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
454 ("Interrupts not initialized"));
456 /* Zero the memory. */
457 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
459 /* Initialize common code interrupt bits. */
460 (void)efx_intr_init(sc->enp, intr->type, esmp);
462 /* Enable interrupts at the bus */
463 if ((rc = sfxge_intr_bus_enable(sc)) != 0)
466 intr->state = SFXGE_INTR_STARTED;
468 /* Enable interrupts at the NIC */
469 efx_intr_enable(sc->enp);
474 /* Tear down common code interrupt bits. */
475 efx_intr_fini(sc->enp);
477 intr->state = SFXGE_INTR_INITIALIZED;
483 sfxge_intr_fini(struct sfxge_softc *sc)
485 struct sfxge_intr_hdl *table;
486 struct sfxge_intr *intr;
493 esmp = &intr->status;
496 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
497 ("intr->state != SFXGE_INTR_INITIALIZED"));
499 /* Free DMA memory. */
500 sfxge_dma_free(esmp);
502 /* Free interrupt handles. */
503 for (i = 0; i < intr->n_alloc; i++)
504 bus_release_resource(dev, SYS_RES_IRQ,
505 table[i].eih_rid, table[i].eih_res);
507 if (table[0].eih_rid != 0)
508 pci_release_msi(dev);
510 if (intr->msix_res != NULL)
511 sfxge_intr_teardown_msix(sc);
513 /* Free the handle table */
514 free(table, M_SFXGE);
518 /* Clear the interrupt type */
519 intr->type = EFX_INTR_INVALID;
521 intr->state = SFXGE_INTR_UNINITIALIZED;
525 sfxge_intr_init(struct sfxge_softc *sc)
528 struct sfxge_intr *intr;
534 esmp = &intr->status;
536 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
537 ("Interrupts already initialized"));
539 /* Try to setup MSI-X or MSI interrupts if available. */
540 if ((rc = sfxge_intr_setup_msix(sc)) == 0)
541 device_printf(dev, "Using MSI-X interrupts\n");
542 else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
543 device_printf(dev, "Using MSI interrupts\n");
544 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
545 device_printf(dev, "Using fixed interrupts\n");
547 device_printf(dev, "Couldn't setup interrupts\n");
551 /* Set up DMA for interrupts. */
552 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
555 intr->state = SFXGE_INTR_INITIALIZED;