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

Cache object: f0c344f379b785f9afa2d604aae15c8d


[ 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.