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

Cache object: 1b22c5dee06d0310484a6dde5f9c96ab


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