2 * Copyright (c) 2010-2015 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 are met:
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * The views and conclusions contained in the software and documentation are
30 * those of the authors and should not be interpreted as representing official
31 * policies, either expressed or implied, of the FreeBSD Project.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
43 #include <sys/syslog.h>
44 #include <sys/taskqueue.h>
46 #include <machine/bus.h>
47 #include <machine/resource.h>
49 #include <dev/pci/pcireg.h>
50 #include <dev/pci/pcivar.h>
52 #include "common/efx.h"
57 sfxge_intr_line_filter(void *arg)
59 struct sfxge_evq *evq;
60 struct sfxge_softc *sc;
62 struct sfxge_intr *intr;
66 evq = (struct sfxge_evq *)arg;
71 KASSERT(intr != NULL, ("intr == NULL"));
72 KASSERT(intr->type == EFX_INTR_LINE,
73 ("intr->type != EFX_INTR_LINE"));
75 if (intr->state != SFXGE_INTR_STARTED)
76 return (FILTER_STRAY);
78 (void)efx_intr_status_line(enp, &fatal, &qmask);
81 (void) efx_intr_disable(enp);
82 (void) efx_intr_fatal(enp);
83 return (FILTER_HANDLED);
88 return (FILTER_SCHEDULE_THREAD);
91 /* SF bug 15783: If the function is not asserting its IRQ and
92 * we read the queue mask on the cycle before a flag is added
93 * to the mask, this inhibits the function from asserting the
94 * IRQ even though we don't see the flag set. To work around
95 * this, we must re-prime all event queues and report the IRQ
96 * as handled when we see a mask of zero. To allow for shared
97 * IRQs, we don't repeat this if we see a mask of zero twice
100 if (intr->zero_count++ == 0) {
101 if (evq->init_state == SFXGE_EVQ_STARTED) {
102 if (efx_ev_qpending(evq->common, evq->read_ptr))
103 return (FILTER_SCHEDULE_THREAD);
104 efx_ev_qprime(evq->common, evq->read_ptr);
105 return (FILTER_HANDLED);
109 return (FILTER_STRAY);
113 sfxge_intr_line(void *arg)
115 struct sfxge_evq *evq = arg;
117 (void)sfxge_ev_qpoll(evq);
121 sfxge_intr_message(void *arg)
123 struct sfxge_evq *evq;
124 struct sfxge_softc *sc;
126 struct sfxge_intr *intr;
130 evq = (struct sfxge_evq *)arg;
136 KASSERT(intr != NULL, ("intr == NULL"));
137 KASSERT(intr->type == EFX_INTR_MESSAGE,
138 ("intr->type != EFX_INTR_MESSAGE"));
140 if (__predict_false(intr->state != SFXGE_INTR_STARTED))
143 (void)efx_intr_status_message(enp, index, &fatal);
146 (void)efx_intr_disable(enp);
147 (void)efx_intr_fatal(enp);
151 (void)sfxge_ev_qpoll(evq);
155 sfxge_intr_bus_enable(struct sfxge_softc *sc)
157 struct sfxge_intr *intr;
158 struct sfxge_intr_hdl *table;
159 driver_filter_t *filter;
160 driver_intr_t *handler;
167 switch (intr->type) {
168 case EFX_INTR_MESSAGE:
169 filter = NULL; /* not shared */
170 handler = sfxge_intr_message;
174 filter = sfxge_intr_line_filter;
175 handler = sfxge_intr_line;
179 KASSERT(0, ("Invalid interrupt type"));
183 /* Try to add the handlers */
184 for (index = 0; index < intr->n_alloc; index++) {
185 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
186 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
187 sc->evq[index], &table[index].eih_tag)) != 0) {
190 #ifdef SFXGE_HAVE_DESCRIBE_INTR
191 if (intr->n_alloc > 1)
192 bus_describe_intr(sc->dev, table[index].eih_res,
193 table[index].eih_tag, "%d", index);
195 bus_bind_intr(sc->dev, table[index].eih_res, index);
202 /* Remove remaining handlers */
204 bus_teardown_intr(sc->dev, table[index].eih_res,
205 table[index].eih_tag);
211 sfxge_intr_bus_disable(struct sfxge_softc *sc)
213 struct sfxge_intr *intr;
214 struct sfxge_intr_hdl *table;
220 /* Remove all handlers */
221 for (i = 0; i < intr->n_alloc; i++)
222 bus_teardown_intr(sc->dev, table[i].eih_res,
227 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
230 struct sfxge_intr_hdl *table;
231 struct sfxge_intr *intr;
232 struct resource *res;
241 table = malloc(count * sizeof(struct sfxge_intr_hdl),
245 for (i = 0; i < count; i++) {
247 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
248 RF_SHAREABLE | RF_ACTIVE);
250 device_printf(dev, "Couldn't allocate interrupts for "
251 "message %d\n", rid);
255 table[i].eih_rid = rid;
256 table[i].eih_res = res;
261 for (i = 0; i < count; i++)
262 bus_release_resource(dev, SYS_RES_IRQ,
263 table[i].eih_rid, table[i].eih_res);
270 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
273 struct resource *resp;
277 resp = sc->intr.msix_res;
279 rid = rman_get_rid(resp);
280 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
284 sfxge_intr_setup_msix(struct sfxge_softc *sc)
286 struct sfxge_intr *intr;
287 struct resource *resp;
295 /* Check if MSI-X is available. */
296 count = pci_msix_count(dev);
300 /* Do not try to allocate more than already estimated EVQ maximum */
301 KASSERT(sc->evq_max > 0, ("evq_max is zero"));
302 count = MIN(count, sc->evq_max);
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;