2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2010-2016 Solarflare Communications Inc.
7 * This software was developed in part by Philip Paeps under contract for
8 * Solarflare Communications, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * The views and conclusions contained in the software and documentation are
32 * those of the authors and should not be interpreted as representing official
33 * policies, either expressed or implied, of the FreeBSD Project.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
41 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/queue.h>
47 #include <sys/syslog.h>
48 #include <sys/taskqueue.h>
50 #include <machine/bus.h>
51 #include <machine/resource.h>
53 #include <dev/pci/pcireg.h>
54 #include <dev/pci/pcivar.h>
57 #include <net/rss_config.h>
60 #include "common/efx.h"
65 sfxge_intr_line_filter(void *arg)
67 struct sfxge_evq *evq;
68 struct sfxge_softc *sc;
70 struct sfxge_intr *intr;
74 evq = (struct sfxge_evq *)arg;
79 KASSERT(intr != NULL, ("intr == NULL"));
80 KASSERT(intr->type == EFX_INTR_LINE,
81 ("intr->type != EFX_INTR_LINE"));
83 if (intr->state != SFXGE_INTR_STARTED)
84 return (FILTER_STRAY);
86 (void)efx_intr_status_line(enp, &fatal, &qmask);
89 (void) efx_intr_disable(enp);
90 (void) efx_intr_fatal(enp);
91 return (FILTER_HANDLED);
96 return (FILTER_SCHEDULE_THREAD);
99 /* SF bug 15783: If the function is not asserting its IRQ and
100 * we read the queue mask on the cycle before a flag is added
101 * to the mask, this inhibits the function from asserting the
102 * IRQ even though we don't see the flag set. To work around
103 * this, we must re-prime all event queues and report the IRQ
104 * as handled when we see a mask of zero. To allow for shared
105 * IRQs, we don't repeat this if we see a mask of zero twice
108 if (intr->zero_count++ == 0) {
109 if (evq->init_state == SFXGE_EVQ_STARTED) {
110 if (efx_ev_qpending(evq->common, evq->read_ptr))
111 return (FILTER_SCHEDULE_THREAD);
112 efx_ev_qprime(evq->common, evq->read_ptr);
113 return (FILTER_HANDLED);
117 return (FILTER_STRAY);
121 sfxge_intr_line(void *arg)
123 struct sfxge_evq *evq = arg;
125 (void)sfxge_ev_qpoll(evq);
129 sfxge_intr_message(void *arg)
131 struct sfxge_evq *evq;
132 struct sfxge_softc *sc;
134 struct sfxge_intr *intr;
138 evq = (struct sfxge_evq *)arg;
144 KASSERT(intr != NULL, ("intr == NULL"));
145 KASSERT(intr->type == EFX_INTR_MESSAGE,
146 ("intr->type != EFX_INTR_MESSAGE"));
148 if (__predict_false(intr->state != SFXGE_INTR_STARTED))
151 (void)efx_intr_status_message(enp, index, &fatal);
154 (void)efx_intr_disable(enp);
155 (void)efx_intr_fatal(enp);
159 (void)sfxge_ev_qpoll(evq);
163 sfxge_intr_bus_enable(struct sfxge_softc *sc)
165 struct sfxge_intr *intr;
166 struct sfxge_intr_hdl *table;
167 driver_filter_t *filter;
168 driver_intr_t *handler;
175 switch (intr->type) {
176 case EFX_INTR_MESSAGE:
177 filter = NULL; /* not shared */
178 handler = sfxge_intr_message;
182 filter = sfxge_intr_line_filter;
183 handler = sfxge_intr_line;
187 KASSERT(0, ("Invalid interrupt type"));
191 /* Try to add the handlers */
192 for (index = 0; index < intr->n_alloc; index++) {
193 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
194 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
195 sc->evq[index], &table[index].eih_tag)) != 0) {
198 #ifdef SFXGE_HAVE_DESCRIBE_INTR
199 if (intr->n_alloc > 1)
200 bus_describe_intr(sc->dev, table[index].eih_res,
201 table[index].eih_tag, "%d", index);
204 bus_bind_intr(sc->dev, table[index].eih_res,
207 bus_bind_intr(sc->dev, table[index].eih_res, index);
215 /* Remove remaining handlers */
217 bus_teardown_intr(sc->dev, table[index].eih_res,
218 table[index].eih_tag);
224 sfxge_intr_bus_disable(struct sfxge_softc *sc)
226 struct sfxge_intr *intr;
227 struct sfxge_intr_hdl *table;
233 /* Remove all handlers */
234 for (i = 0; i < intr->n_alloc; i++)
235 bus_teardown_intr(sc->dev, table[i].eih_res,
240 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
243 struct sfxge_intr_hdl *table;
244 struct sfxge_intr *intr;
245 struct resource *res;
254 table = malloc(count * sizeof(struct sfxge_intr_hdl),
258 for (i = 0; i < count; i++) {
260 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
261 RF_SHAREABLE | RF_ACTIVE);
263 device_printf(dev, "Couldn't allocate interrupts for "
264 "message %d\n", rid);
268 table[i].eih_rid = rid;
269 table[i].eih_res = res;
274 for (i = 0; i < count; i++)
275 bus_release_resource(dev, SYS_RES_IRQ,
276 table[i].eih_rid, table[i].eih_res);
283 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
286 struct resource *resp;
290 resp = sc->intr.msix_res;
292 rid = rman_get_rid(resp);
293 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
297 sfxge_intr_setup_msix(struct sfxge_softc *sc)
299 struct sfxge_intr *intr;
300 struct resource *resp;
308 /* Check if MSI-X is available. */
309 count = pci_msix_count(dev);
313 /* Do not try to allocate more than already estimated EVQ maximum */
314 KASSERT(sc->evq_max > 0, ("evq_max is zero"));
315 count = MIN(count, sc->evq_max);
318 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
322 if (pci_alloc_msix(dev, &count) != 0) {
323 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
327 /* Allocate interrupt handlers. */
328 if (sfxge_intr_alloc(sc, count) != 0) {
329 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
330 pci_release_msi(dev);
334 intr->type = EFX_INTR_MESSAGE;
335 intr->n_alloc = count;
336 intr->msix_res = resp;
342 sfxge_intr_setup_msi(struct sfxge_softc *sc)
344 struct sfxge_intr_hdl *table;
345 struct sfxge_intr *intr;
355 * Check if MSI is available. All messages must be written to
356 * the same address and on x86 this means the IRQs have the
357 * same CPU affinity. So we only ever allocate 1.
359 count = pci_msi_count(dev) ? 1 : 0;
363 if ((error = pci_alloc_msi(dev, &count)) != 0)
366 /* Allocate interrupt handler. */
367 if (sfxge_intr_alloc(sc, count) != 0) {
368 pci_release_msi(dev);
372 intr->type = EFX_INTR_MESSAGE;
373 intr->n_alloc = count;
379 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
381 struct sfxge_intr_hdl *table;
382 struct sfxge_intr *intr;
383 struct resource *res;
391 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
392 RF_SHAREABLE | RF_ACTIVE);
396 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
397 table[0].eih_rid = rid;
398 table[0].eih_res = res;
400 intr->type = EFX_INTR_LINE;
407 static const char *const __sfxge_err[] = {
409 "SRAM out-of-bounds",
410 "Buffer ID out-of-bounds",
411 "Internal memory parity",
412 "Receive buffer ownership",
413 "Transmit buffer ownership",
414 "Receive descriptor ownership",
415 "Transmit descriptor ownership",
416 "Event queue ownership",
417 "Event queue FIFO overflow",
423 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
426 struct sfxge_softc *sc = (struct sfxge_softc *)arg;
427 device_t dev = sc->dev;
429 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
430 device_get_name(dev), device_get_unit(dev),
431 __sfxge_err[code], dword1, dword0);
435 sfxge_intr_stop(struct sfxge_softc *sc)
437 struct sfxge_intr *intr;
441 KASSERT(intr->state == SFXGE_INTR_STARTED,
442 ("Interrupts not started"));
444 intr->state = SFXGE_INTR_INITIALIZED;
446 /* Disable interrupts at the NIC */
447 efx_intr_disable(sc->enp);
449 /* Disable interrupts at the bus */
450 sfxge_intr_bus_disable(sc);
452 /* Tear down common code interrupt bits. */
453 efx_intr_fini(sc->enp);
457 sfxge_intr_start(struct sfxge_softc *sc)
459 struct sfxge_intr *intr;
464 esmp = &intr->status;
466 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
467 ("Interrupts not initialized"));
469 /* Zero the memory. */
470 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
472 /* Initialize common code interrupt bits. */
473 (void)efx_intr_init(sc->enp, intr->type, esmp);
475 /* Enable interrupts at the bus */
476 if ((rc = sfxge_intr_bus_enable(sc)) != 0)
479 intr->state = SFXGE_INTR_STARTED;
481 /* Enable interrupts at the NIC */
482 efx_intr_enable(sc->enp);
487 /* Tear down common code interrupt bits. */
488 efx_intr_fini(sc->enp);
490 intr->state = SFXGE_INTR_INITIALIZED;
496 sfxge_intr_fini(struct sfxge_softc *sc)
498 struct sfxge_intr_hdl *table;
499 struct sfxge_intr *intr;
506 esmp = &intr->status;
509 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
510 ("intr->state != SFXGE_INTR_INITIALIZED"));
512 /* Free DMA memory. */
513 sfxge_dma_free(esmp);
515 /* Free interrupt handles. */
516 for (i = 0; i < intr->n_alloc; i++)
517 bus_release_resource(dev, SYS_RES_IRQ,
518 table[i].eih_rid, table[i].eih_res);
520 if (table[0].eih_rid != 0)
521 pci_release_msi(dev);
523 if (intr->msix_res != NULL)
524 sfxge_intr_teardown_msix(sc);
526 /* Free the handle table */
527 free(table, M_SFXGE);
531 /* Clear the interrupt type */
532 intr->type = EFX_INTR_INVALID;
534 intr->state = SFXGE_INTR_UNINITIALIZED;
538 sfxge_intr_init(struct sfxge_softc *sc)
541 struct sfxge_intr *intr;
547 esmp = &intr->status;
549 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
550 ("Interrupts already initialized"));
552 /* Try to setup MSI-X or MSI interrupts if available. */
553 if ((rc = sfxge_intr_setup_msix(sc)) == 0)
554 device_printf(dev, "Using MSI-X interrupts\n");
555 else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
556 device_printf(dev, "Using MSI interrupts\n");
557 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
558 device_printf(dev, "Using fixed interrupts\n");
560 device_printf(dev, "Couldn't setup interrupts\n");
564 /* Set up DMA for interrupts. */
565 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
568 intr->state = SFXGE_INTR_INITIALIZED;