The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sfxge/sfxge_intr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2010-2016 Solarflare Communications Inc.
    3  * All rights reserved.
    4  *
    5  * This software was developed in part by Philip Paeps under contract for
    6  * Solarflare Communications, Inc.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions are met:
   10  *
   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.
   16  *
   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.
   28  *
   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.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/11.2/sys/dev/sfxge/sfxge_intr.c 331722 2018-03-29 02:50:57Z eadler $");
   36 
   37 #include "opt_rss.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/queue.h>
   44 #include <sys/rman.h>
   45 #include <sys/syslog.h>
   46 #include <sys/taskqueue.h>
   47 
   48 #include <machine/bus.h>
   49 #include <machine/resource.h>
   50 
   51 #include <dev/pci/pcireg.h>
   52 #include <dev/pci/pcivar.h>
   53 
   54 #ifdef RSS
   55 #include <net/rss_config.h>
   56 #endif
   57 
   58 #include "common/efx.h"
   59 
   60 #include "sfxge.h"
   61 
   62 static int
   63 sfxge_intr_line_filter(void *arg)
   64 {
   65         struct sfxge_evq *evq;
   66         struct sfxge_softc *sc;
   67         efx_nic_t *enp;
   68         struct sfxge_intr *intr;
   69         boolean_t fatal;
   70         uint32_t qmask;
   71 
   72         evq = (struct sfxge_evq *)arg;
   73         sc = evq->sc;
   74         enp = sc->enp;
   75         intr = &sc->intr;
   76 
   77         KASSERT(intr != NULL, ("intr == NULL"));
   78         KASSERT(intr->type == EFX_INTR_LINE,
   79             ("intr->type != EFX_INTR_LINE"));
   80 
   81         if (intr->state != SFXGE_INTR_STARTED)
   82                 return (FILTER_STRAY);
   83 
   84         (void)efx_intr_status_line(enp, &fatal, &qmask);
   85 
   86         if (fatal) {
   87                 (void) efx_intr_disable(enp);
   88                 (void) efx_intr_fatal(enp);
   89                 return (FILTER_HANDLED);
   90         }
   91 
   92         if (qmask != 0) {
   93                 intr->zero_count = 0;
   94                 return (FILTER_SCHEDULE_THREAD);
   95         }
   96 
   97         /* SF bug 15783: If the function is not asserting its IRQ and
   98          * we read the queue mask on the cycle before a flag is added
   99          * to the mask, this inhibits the function from asserting the
  100          * IRQ even though we don't see the flag set.  To work around
  101          * this, we must re-prime all event queues and report the IRQ
  102          * as handled when we see a mask of zero.  To allow for shared
  103          * IRQs, we don't repeat this if we see a mask of zero twice
  104          * or more in a row.
  105          */
  106         if (intr->zero_count++ == 0) {
  107                 if (evq->init_state == SFXGE_EVQ_STARTED) {
  108                         if (efx_ev_qpending(evq->common, evq->read_ptr))
  109                                 return (FILTER_SCHEDULE_THREAD);
  110                         efx_ev_qprime(evq->common, evq->read_ptr);
  111                         return (FILTER_HANDLED);
  112                 }
  113         }
  114 
  115         return (FILTER_STRAY);
  116 }
  117 
  118 static void
  119 sfxge_intr_line(void *arg)
  120 {
  121         struct sfxge_evq *evq = arg;
  122 
  123         (void)sfxge_ev_qpoll(evq);
  124 }
  125 
  126 static void
  127 sfxge_intr_message(void *arg)
  128 {
  129         struct sfxge_evq *evq;
  130         struct sfxge_softc *sc;
  131         efx_nic_t *enp;
  132         struct sfxge_intr *intr;
  133         unsigned int index;
  134         boolean_t fatal;
  135 
  136         evq = (struct sfxge_evq *)arg;
  137         sc = evq->sc;
  138         enp = sc->enp;
  139         intr = &sc->intr;
  140         index = evq->index;
  141 
  142         KASSERT(intr != NULL, ("intr == NULL"));
  143         KASSERT(intr->type == EFX_INTR_MESSAGE,
  144             ("intr->type != EFX_INTR_MESSAGE"));
  145 
  146         if (__predict_false(intr->state != SFXGE_INTR_STARTED))
  147                 return;
  148 
  149         (void)efx_intr_status_message(enp, index, &fatal);
  150 
  151         if (fatal) {
  152                 (void)efx_intr_disable(enp);
  153                 (void)efx_intr_fatal(enp);
  154                 return;
  155         }
  156 
  157         (void)sfxge_ev_qpoll(evq);
  158 }
  159 
  160 static int
  161 sfxge_intr_bus_enable(struct sfxge_softc *sc)
  162 {
  163         struct sfxge_intr *intr;
  164         struct sfxge_intr_hdl *table;
  165         driver_filter_t *filter;
  166         driver_intr_t *handler;
  167         int index;
  168         int err;
  169 
  170         intr = &sc->intr;
  171         table = intr->table;
  172 
  173         switch (intr->type) {
  174         case EFX_INTR_MESSAGE:
  175                 filter = NULL; /* not shared */
  176                 handler = sfxge_intr_message;
  177                 break;
  178 
  179         case EFX_INTR_LINE:
  180                 filter = sfxge_intr_line_filter;
  181                 handler = sfxge_intr_line;
  182                 break;
  183 
  184         default:
  185                 KASSERT(0, ("Invalid interrupt type"));
  186                 return (EINVAL);
  187         }
  188 
  189         /* Try to add the handlers */
  190         for (index = 0; index < intr->n_alloc; index++) {
  191                 if ((err = bus_setup_intr(sc->dev, table[index].eih_res,
  192                             INTR_MPSAFE|INTR_TYPE_NET, filter, handler,
  193                             sc->evq[index], &table[index].eih_tag)) != 0) {
  194                         goto fail;
  195                 }
  196 #ifdef SFXGE_HAVE_DESCRIBE_INTR
  197                 if (intr->n_alloc > 1)
  198                         bus_describe_intr(sc->dev, table[index].eih_res,
  199                             table[index].eih_tag, "%d", index);
  200 #endif
  201 #ifdef RSS
  202                 bus_bind_intr(sc->dev, table[index].eih_res,
  203                               rss_getcpu(index));
  204 #else
  205                 bus_bind_intr(sc->dev, table[index].eih_res, index);
  206 #endif
  207 
  208         }
  209 
  210         return (0);
  211 
  212 fail:
  213         /* Remove remaining handlers */
  214         while (--index >= 0)
  215                 bus_teardown_intr(sc->dev, table[index].eih_res,
  216                     table[index].eih_tag);
  217 
  218         return (err);
  219 }
  220 
  221 static void
  222 sfxge_intr_bus_disable(struct sfxge_softc *sc)
  223 {
  224         struct sfxge_intr *intr;
  225         struct sfxge_intr_hdl *table;
  226         int i;
  227 
  228         intr = &sc->intr;
  229         table = intr->table;
  230 
  231         /* Remove all handlers */
  232         for (i = 0; i < intr->n_alloc; i++)
  233                 bus_teardown_intr(sc->dev, table[i].eih_res,
  234                     table[i].eih_tag);
  235 }
  236 
  237 static int
  238 sfxge_intr_alloc(struct sfxge_softc *sc, int count)
  239 {
  240         device_t dev;
  241         struct sfxge_intr_hdl *table;
  242         struct sfxge_intr *intr;
  243         struct resource *res;
  244         int rid;
  245         int error;
  246         int i;
  247 
  248         dev = sc->dev;
  249         intr = &sc->intr;
  250         error = 0;
  251 
  252         table = malloc(count * sizeof(struct sfxge_intr_hdl),
  253             M_SFXGE, M_WAITOK);
  254         intr->table = table;
  255 
  256         for (i = 0; i < count; i++) {
  257                 rid = i + 1;
  258                 res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  259                     RF_SHAREABLE | RF_ACTIVE);
  260                 if (res == NULL) {
  261                         device_printf(dev, "Couldn't allocate interrupts for "
  262                             "message %d\n", rid);
  263                         error = ENOMEM;
  264                         break;
  265                 }
  266                 table[i].eih_rid = rid;
  267                 table[i].eih_res = res;
  268         }
  269 
  270         if (error != 0) {
  271                 count = i - 1;
  272                 for (i = 0; i < count; i++)
  273                         bus_release_resource(dev, SYS_RES_IRQ,
  274                             table[i].eih_rid, table[i].eih_res);
  275         }
  276 
  277         return (error);
  278 }
  279 
  280 static void
  281 sfxge_intr_teardown_msix(struct sfxge_softc *sc)
  282 {
  283         device_t dev;
  284         struct resource *resp;
  285         int rid;
  286 
  287         dev = sc->dev;
  288         resp = sc->intr.msix_res;
  289 
  290         rid = rman_get_rid(resp);
  291         bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
  292 }
  293 
  294 static int
  295 sfxge_intr_setup_msix(struct sfxge_softc *sc)
  296 {
  297         struct sfxge_intr *intr;
  298         struct resource *resp;
  299         device_t dev;
  300         int count;
  301         int rid;
  302 
  303         dev = sc->dev;
  304         intr = &sc->intr;
  305 
  306         /* Check if MSI-X is available. */
  307         count = pci_msix_count(dev);
  308         if (count == 0)
  309                 return (EINVAL);
  310 
  311         /* Do not try to allocate more than already estimated EVQ maximum */
  312         KASSERT(sc->evq_max > 0, ("evq_max is zero"));
  313         count = MIN(count, sc->evq_max);
  314 
  315         rid = PCIR_BAR(4);
  316         resp = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  317         if (resp == NULL)
  318                 return (ENOMEM);
  319 
  320         if (pci_alloc_msix(dev, &count) != 0) {
  321                 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
  322                 return (ENOMEM);
  323         }
  324 
  325         /* Allocate interrupt handlers. */
  326         if (sfxge_intr_alloc(sc, count) != 0) {
  327                 bus_release_resource(dev, SYS_RES_MEMORY, rid, resp);
  328                 pci_release_msi(dev);
  329                 return (ENOMEM);
  330         }
  331 
  332         intr->type = EFX_INTR_MESSAGE;
  333         intr->n_alloc = count;
  334         intr->msix_res = resp;
  335 
  336         return (0);
  337 }
  338 
  339 static int
  340 sfxge_intr_setup_msi(struct sfxge_softc *sc)
  341 {
  342         struct sfxge_intr_hdl *table;
  343         struct sfxge_intr *intr;
  344         device_t dev;
  345         int count;
  346         int error;
  347 
  348         dev = sc->dev;
  349         intr = &sc->intr;
  350         table = intr->table;
  351 
  352         /*
  353          * Check if MSI is available.  All messages must be written to
  354          * the same address and on x86 this means the IRQs have the
  355          * same CPU affinity.  So we only ever allocate 1.
  356          */
  357         count = pci_msi_count(dev) ? 1 : 0;
  358         if (count == 0)
  359                 return (EINVAL);
  360 
  361         if ((error = pci_alloc_msi(dev, &count)) != 0)
  362                 return (ENOMEM);
  363 
  364         /* Allocate interrupt handler. */
  365         if (sfxge_intr_alloc(sc, count) != 0) {
  366                 pci_release_msi(dev);
  367                 return (ENOMEM);
  368         }
  369 
  370         intr->type = EFX_INTR_MESSAGE;
  371         intr->n_alloc = count;
  372 
  373         return (0);
  374 }
  375 
  376 static int
  377 sfxge_intr_setup_fixed(struct sfxge_softc *sc)
  378 {
  379         struct sfxge_intr_hdl *table;
  380         struct sfxge_intr *intr;
  381         struct resource *res;
  382         device_t dev;
  383         int rid;
  384 
  385         dev = sc->dev;
  386         intr = &sc->intr;
  387 
  388         rid = 0;
  389         res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  390             RF_SHAREABLE | RF_ACTIVE);
  391         if (res == NULL)
  392                 return (ENOMEM);
  393 
  394         table = malloc(sizeof(struct sfxge_intr_hdl), M_SFXGE, M_WAITOK);
  395         table[0].eih_rid = rid;
  396         table[0].eih_res = res;
  397 
  398         intr->type = EFX_INTR_LINE;
  399         intr->n_alloc = 1;
  400         intr->table = table;
  401 
  402         return (0);
  403 }
  404 
  405 static const char *const __sfxge_err[] = {
  406         "",
  407         "SRAM out-of-bounds",
  408         "Buffer ID out-of-bounds",
  409         "Internal memory parity",
  410         "Receive buffer ownership",
  411         "Transmit buffer ownership",
  412         "Receive descriptor ownership",
  413         "Transmit descriptor ownership",
  414         "Event queue ownership",
  415         "Event queue FIFO overflow",
  416         "Illegal address",
  417         "SRAM parity"
  418 };
  419 
  420 void
  421 sfxge_err(efsys_identifier_t *arg, unsigned int code, uint32_t dword0,
  422           uint32_t dword1)
  423 {
  424         struct sfxge_softc *sc = (struct sfxge_softc *)arg;
  425         device_t dev = sc->dev;
  426 
  427         log(LOG_WARNING, "[%s%d] FATAL ERROR: %s (0x%08x%08x)",
  428             device_get_name(dev), device_get_unit(dev),
  429                 __sfxge_err[code], dword1, dword0);
  430 }
  431 
  432 void
  433 sfxge_intr_stop(struct sfxge_softc *sc)
  434 {
  435         struct sfxge_intr *intr;
  436 
  437         intr = &sc->intr;
  438 
  439         KASSERT(intr->state == SFXGE_INTR_STARTED,
  440             ("Interrupts not started"));
  441 
  442         intr->state = SFXGE_INTR_INITIALIZED;
  443 
  444         /* Disable interrupts at the NIC */
  445         efx_intr_disable(sc->enp);
  446 
  447         /* Disable interrupts at the bus */
  448         sfxge_intr_bus_disable(sc);
  449 
  450         /* Tear down common code interrupt bits. */
  451         efx_intr_fini(sc->enp);
  452 }
  453 
  454 int
  455 sfxge_intr_start(struct sfxge_softc *sc)
  456 {
  457         struct sfxge_intr *intr;
  458         efsys_mem_t *esmp;
  459         int rc;
  460 
  461         intr = &sc->intr;
  462         esmp = &intr->status;
  463 
  464         KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
  465             ("Interrupts not initialized"));
  466 
  467         /* Zero the memory. */
  468         (void)memset(esmp->esm_base, 0, EFX_INTR_SIZE);
  469 
  470         /* Initialize common code interrupt bits. */
  471         (void)efx_intr_init(sc->enp, intr->type, esmp);
  472 
  473         /* Enable interrupts at the bus */
  474         if ((rc = sfxge_intr_bus_enable(sc)) != 0)
  475                 goto fail;
  476 
  477         intr->state = SFXGE_INTR_STARTED;
  478 
  479         /* Enable interrupts at the NIC */
  480         efx_intr_enable(sc->enp);
  481 
  482         return (0);
  483 
  484 fail:
  485         /* Tear down common code interrupt bits. */
  486         efx_intr_fini(sc->enp);
  487 
  488         intr->state = SFXGE_INTR_INITIALIZED;
  489 
  490         return (rc);
  491 }
  492 
  493 void
  494 sfxge_intr_fini(struct sfxge_softc *sc)
  495 {
  496         struct sfxge_intr_hdl *table;
  497         struct sfxge_intr *intr;
  498         efsys_mem_t *esmp;
  499         device_t dev;
  500         int i;
  501 
  502         dev = sc->dev;
  503         intr = &sc->intr;
  504         esmp = &intr->status;
  505         table = intr->table;
  506 
  507         KASSERT(intr->state == SFXGE_INTR_INITIALIZED,
  508             ("intr->state != SFXGE_INTR_INITIALIZED"));
  509 
  510         /* Free DMA memory. */
  511         sfxge_dma_free(esmp);
  512 
  513         /* Free interrupt handles. */
  514         for (i = 0; i < intr->n_alloc; i++)
  515                 bus_release_resource(dev, SYS_RES_IRQ,
  516                     table[i].eih_rid, table[i].eih_res);
  517 
  518         if (table[0].eih_rid != 0)
  519                 pci_release_msi(dev);
  520 
  521         if (intr->msix_res != NULL)
  522                 sfxge_intr_teardown_msix(sc);
  523 
  524         /* Free the handle table */
  525         free(table, M_SFXGE);
  526         intr->table = NULL;
  527         intr->n_alloc = 0;
  528 
  529         /* Clear the interrupt type */
  530         intr->type = EFX_INTR_INVALID;
  531 
  532         intr->state = SFXGE_INTR_UNINITIALIZED;
  533 }
  534 
  535 int
  536 sfxge_intr_init(struct sfxge_softc *sc)
  537 {
  538         device_t dev;
  539         struct sfxge_intr *intr;
  540         efsys_mem_t *esmp;
  541         int rc;
  542 
  543         dev = sc->dev;
  544         intr = &sc->intr;
  545         esmp = &intr->status;
  546 
  547         KASSERT(intr->state == SFXGE_INTR_UNINITIALIZED,
  548             ("Interrupts already initialized"));
  549 
  550         /* Try to setup MSI-X or MSI interrupts if available. */
  551         if ((rc = sfxge_intr_setup_msix(sc)) == 0)
  552                 device_printf(dev, "Using MSI-X interrupts\n");
  553         else if ((rc = sfxge_intr_setup_msi(sc)) == 0)
  554                 device_printf(dev, "Using MSI interrupts\n");
  555         else if ((rc = sfxge_intr_setup_fixed(sc)) == 0) {
  556                 device_printf(dev, "Using fixed interrupts\n");
  557         } else {
  558                 device_printf(dev, "Couldn't setup interrupts\n");
  559                 return (ENOMEM);
  560         }
  561 
  562         /* Set up DMA for interrupts. */
  563         if ((rc = sfxge_dma_alloc(sc, EFX_INTR_SIZE, esmp)) != 0)
  564                 return (ENOMEM);
  565 
  566         intr->state = SFXGE_INTR_INITIALIZED;
  567 
  568         return (0);
  569 }

Cache object: cc003f3cc87aae89fccd8956739aabec


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.