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>
40 #include <sys/syslog.h>
42 #include <machine/bus.h>
43 #include <machine/resource.h>
45 #include <dev/pci/pcireg.h>
46 #include <dev/pci/pcivar.h>
48 #include "common/efx.h"
53 sfxge_intr_line_filter(void *arg)
55 struct sfxge_evq *evq;
56 struct sfxge_softc *sc;
58 struct sfxge_intr *intr;
62 evq = (struct sfxge_evq *)arg;
67 KASSERT(intr != NULL, ("intr == NULL"));
68 KASSERT(intr->type == EFX_INTR_LINE,
69 ("intr->type != EFX_INTR_LINE"));
71 if (intr->state != SFXGE_INTR_STARTED)
72 return (FILTER_STRAY);
74 (void)efx_intr_status_line(enp, &fatal, &qmask);
77 (void) efx_intr_disable(enp);
78 (void) efx_intr_fatal(enp);
79 return (FILTER_HANDLED);
84 return (FILTER_SCHEDULE_THREAD);
87 /* SF bug 15783: If the function is not asserting its IRQ and
88 * we read the queue mask on the cycle before a flag is added
89 * to the mask, this inhibits the function from asserting the
90 * IRQ even though we don't see the flag set. To work around
91 * this, we must re-prime all event queues and report the IRQ
92 * as handled when we see a mask of zero. To allow for shared
93 * IRQs, we don't repeat this if we see a mask of zero twice
96 if (intr->zero_count++ == 0) {
97 if (evq->init_state == SFXGE_EVQ_STARTED) {
98 if (efx_ev_qpending(evq->common, evq->read_ptr))
99 return (FILTER_SCHEDULE_THREAD);
100 efx_ev_qprime(evq->common, evq->read_ptr);
101 return (FILTER_HANDLED);
105 return (FILTER_STRAY);
109 sfxge_intr_line(void *arg)
111 struct sfxge_evq *evq = arg;
113 (void)sfxge_ev_qpoll(evq);
117 sfxge_intr_message(void *arg)
119 struct sfxge_evq *evq;
120 struct sfxge_softc *sc;
122 struct sfxge_intr *intr;
126 evq = (struct sfxge_evq *)arg;
132 KASSERT(intr != NULL, ("intr == NULL"));
133 KASSERT(intr->type == EFX_INTR_MESSAGE,
134 ("intr->type != EFX_INTR_MESSAGE"));
136 if (__predict_false(intr->state != SFXGE_INTR_STARTED))
139 (void)efx_intr_status_message(enp, index, &fatal);
142 (void)efx_intr_disable(enp);
143 (void)efx_intr_fatal(enp);
147 (void)sfxge_ev_qpoll(evq);
151 sfxge_intr_bus_enable(struct sfxge_softc *sc)
153 struct sfxge_intr *intr;
154 struct sfxge_intr_hdl *table;
155 driver_filter_t *filter;
156 driver_intr_t *handler;
163 switch (intr->type) {
164 case EFX_INTR_MESSAGE:
165 filter = NULL; /* not shared */
166 handler = sfxge_intr_message;
170 filter = sfxge_intr_line_filter;
171 handler = sfxge_intr_line;
175 KASSERT(0, ("Invalid interrupt type"));
179 /* Try to add the handlers */
180 for (index = 0; index < intr->n_alloc; index++) {
181 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
182 INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
183 sc->evq[index], &table[index].eih_tag)) != 0) {
186 #ifdef SFXGE_HAVE_DESCRIBE_INTR
187 if (intr->n_alloc > 1)
188 bus_describe_intr(sc->dev, table[index].eih_res,
189 table[index].eih_tag, "%d", index);
191 bus_bind_intr(sc->dev, table[index].eih_res, index);
198 /* Remove remaining handlers */
200 bus_teardown_intr(sc->dev, table[index].eih_res,
201 table[index].eih_tag);
207 sfxge_intr_bus_disable(struct sfxge_softc *sc)
209 struct sfxge_intr *intr;
210 struct sfxge_intr_hdl *table;
216 /* Remove all handlers */
217 for (i = 0; i < intr->n_alloc; i++)
218 bus_teardown_intr(sc->dev, table[i].eih_res,
223 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
226 struct sfxge_intr_hdl *table;
227 struct sfxge_intr *intr;
228 struct resource *res;
237 table = malloc(count * sizeof(struct sfxge_intr_hdl),
241 for (i = 0; i < count; i++) {
243 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
244 RF_SHAREABLE | RF_ACTIVE);
246 device_printf(dev, "Couldn't allocate interrupts for "
247 "message %d\n", rid);
251 table[i].eih_rid = rid;
252 table[i].eih_res = res;
257 for (i = 0; i < count; i++)
258 bus_release_resource(dev, SYS_RES_IRQ,
259 table[i].eih_rid, table[i].eih_res);
266 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
269 struct resource *resp;
273 resp = sc->intr.msix_res;
275 rid = rman_get_rid(resp);
276 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
280 sfxge_intr_setup_msix(struct sfxge_softc *sc)
282 struct sfxge_intr *intr;
283 struct resource *resp;
291 /* Check if MSI-X is available. */
292 count = pci_msix_count(dev);
296 /* Do not try to allocate more than already estimated EVQ maximum */
297 KASSERT(sc->evq_max > 0, ("evq_max is zero"));
298 count = MIN(count, sc->evq_max);
301 resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
305 if (pci_alloc_msix(dev, &count) != 0) {
306 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
310 /* Allocate interrupt handlers. */
311 if (sfxge_intr_alloc(sc, count) != 0) {
312 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
313 pci_release_msi(dev);
317 intr->type = EFX_INTR_MESSAGE;
318 intr->n_alloc = count;
319 intr->msix_res = resp;
325 sfxge_intr_setup_msi(struct sfxge_softc *sc)
327 struct sfxge_intr_hdl *table;
328 struct sfxge_intr *intr;
338 * Check if MSI is available. All messages must be written to
339 * the same address and on x86 this means the IRQs have the
340 * same CPU affinity. So we only ever allocate 1.
342 count = pci_msi_count(dev) ? 1 : 0;
346 if ((error = pci_alloc_msi(dev, &count)) != 0)
349 /* Allocate interrupt handler. */
350 if (sfxge_intr_alloc(sc, count) != 0) {
351 pci_release_msi(dev);
355 intr->type = EFX_INTR_MESSAGE;
356 intr->n_alloc = count;
362 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
364 struct sfxge_intr_hdl *table;
365 struct sfxge_intr *intr;
366 struct resource *res;
374 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
375 RF_SHAREABLE | RF_ACTIVE);
379 table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
380 table[0].eih_rid = rid;
381 table[0].eih_res = res;
383 intr->type = EFX_INTR_LINE;
390 static const char *const __sfxge_err[] = {
392 "SRAM out-of-bounds",
393 "Buffer ID out-of-bounds",
394 "Internal memory parity",
395 "Receive buffer ownership",
396 "Transmit buffer ownership",
397 "Receive descriptor ownership",
398 "Transmit descriptor ownership",
399 "Event queue ownership",
400 "Event queue FIFO overflow",
406 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
409 struct sfxge_softc *sc = (struct sfxge_softc *)arg;
410 device_t dev = sc->dev;
412 log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
413 device_get_name(dev), device_get_unit(dev),
414 __sfxge_err[code], dword1, dword0);
418 sfxge_intr_stop(struct sfxge_softc *sc)
420 struct sfxge_intr *intr;
424 KASSERT(intr->state == SFXGE_INTR_STARTED,
425 ("Interrupts not started"));
427 intr->state = SFXGE_INTR_INITIALIZED;
429 /* Disable interrupts at the NIC */
430 efx_intr_disable(sc->enp);
432 /* Disable interrupts at the bus */
433 sfxge_intr_bus_disable(sc);
435 /* Tear down common code interrupt bits. */
436 efx_intr_fini(sc->enp);
440 sfxge_intr_start(struct sfxge_softc *sc)
442 struct sfxge_intr *intr;
447 esmp = &intr->status;
449 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
450 ("Interrupts not initialized"));
452 /* Zero the memory. */
453 (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
455 /* Initialize common code interrupt bits. */
456 (void)efx_intr_init(sc->enp, intr->type, esmp);
458 /* Enable interrupts at the bus */
459 if ((rc = sfxge_intr_bus_enable(sc)) != 0)
462 intr->state = SFXGE_INTR_STARTED;
464 /* Enable interrupts at the NIC */
465 efx_intr_enable(sc->enp);
470 /* Tear down common code interrupt bits. */
471 efx_intr_fini(sc->enp);
473 intr->state = SFXGE_INTR_INITIALIZED;
479 sfxge_intr_fini(struct sfxge_softc *sc)
481 struct sfxge_intr_hdl *table;
482 struct sfxge_intr *intr;
489 esmp = &intr->status;
492 KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
493 ("intr->state != SFXGE_INTR_INITIALIZED"));
495 /* Free DMA memory. */
496 sfxge_dma_free(esmp);
498 /* Free interrupt handles. */
499 for (i = 0; i < intr->n_alloc; i++)
500 bus_release_resource(dev, SYS_RES_IRQ,
501 table[i].eih_rid, table[i].eih_res);
503 if (table[0].eih_rid != 0)
504 pci_release_msi(dev);
506 if (intr->msix_res != NULL)
507 sfxge_intr_teardown_msix(sc);
509 /* Free the handle table */
510 free(table, M_SFXGE);
514 /* Clear the interrupt type */
515 intr->type = EFX_INTR_INVALID;
517 intr->state = SFXGE_INTR_UNINITIALIZED;
521 sfxge_intr_init(struct sfxge_softc *sc)
524 struct sfxge_intr *intr;
530 esmp = &intr->status;
532 KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
533 ("Interrupts already initialized"));
535 /* Try to setup MSI-X or MSI interrupts if available. */
536 if ((rc = sfxge_intr_setup_msix(sc)) == 0)
537 device_printf(dev, "Using MSI-X interrupts\n");
538 else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
539 device_printf(dev, "Using MSI interrupts\n");
540 else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
541 device_printf(dev, "Using fixed interrupts\n");
543 device_printf(dev, "Couldn't setup interrupts\n");
547 /* Set up DMA for interrupts. */
548 if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
551 intr->state = SFXGE_INTR_INITIALIZED;