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/smartpqi/smartpqi_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 2016-2021 Microchip Technology, Inc. and/or its subsidiaries.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 /* $FreeBSD$ */
   27 
   28 #include "smartpqi_includes.h"
   29 
   30 /*
   31  * Function to get processor count
   32  */
   33 int
   34 os_get_processor_config(pqisrc_softstate_t *softs)
   35 {
   36         DBG_FUNC("IN\n");
   37         softs->num_cpus_online = mp_ncpus;
   38         DBG_FUNC("OUT\n");
   39 
   40         return PQI_STATUS_SUCCESS;
   41 }
   42 
   43 /*
   44  * Function to get interrupt count and type supported
   45  */
   46 int
   47 os_get_intr_config(pqisrc_softstate_t *softs)
   48 {
   49         device_t dev = softs->os_specific.pqi_dev;
   50         int msi_count = pci_msix_count(dev);
   51         int error = BSD_SUCCESS;
   52 
   53         DBG_FUNC("IN\n");
   54 
   55         if (msi_count > softs->num_cpus_online)
   56                 msi_count = softs->num_cpus_online;
   57         if (msi_count > PQI_MAX_MSIX)
   58                 msi_count = PQI_MAX_MSIX;
   59         if (msi_count == 0 || (error = pci_alloc_msix(dev, &msi_count)) != 0) {
   60                 device_printf(dev, "alloc msix failed - msi_count=%d, err=%d; "
   61                                    "will try MSI\n", msi_count, error);
   62                 pci_release_msi(dev);
   63         } else {
   64                 softs->intr_count = msi_count;
   65                 softs->intr_type = INTR_TYPE_MSIX;
   66                 softs->os_specific.msi_enabled = TRUE;
   67                 device_printf(dev, "using MSI-X interrupts (%d vectors)\n",
   68                         msi_count);
   69         }
   70         if (!softs->intr_type) {
   71                 msi_count = 1;
   72                 if ((error = pci_alloc_msi(dev, &msi_count)) != 0) {
   73                         device_printf(dev, "alloc msi failed - err=%d; "
   74                                 "will use INTx\n", error);
   75                         pci_release_msi(dev);
   76                 } else {
   77                         softs->os_specific.msi_enabled = TRUE;
   78                         softs->intr_count = msi_count;
   79                         softs->intr_type = INTR_TYPE_MSI;
   80                         device_printf(dev, "using MSI interrupts\n");
   81                 }
   82         }
   83 
   84         if (!softs->intr_type) {
   85                 device_printf(dev, "using legacy interrupts\n");
   86                 softs->intr_type = INTR_TYPE_FIXED;
   87                 softs->intr_count = 1;
   88         }
   89 
   90         DBG_FUNC("OUT\n");
   91 
   92         error = bsd_status_to_pqi_status(BSD_SUCCESS);
   93 
   94         return error;
   95 }
   96 
   97 void
   98 os_eventtaskqueue_enqueue(pqisrc_softstate_t *sc)
   99 {
  100         taskqueue_enqueue(taskqueue_swi, &sc->os_specific.event_task);
  101 }
  102 
  103 void
  104 pqisrc_event_worker(void *arg1, int arg2)
  105 {
  106         pqisrc_ack_all_events(arg1);
  107 }
  108 
  109 /*
  110  * ithread routine to handle uniprocessor systems
  111  */
  112 static void
  113 shared_ithread_routine(void *arg)
  114 {
  115         pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
  116         pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
  117         int oq_id  = intr_ctx->oq_id;
  118 
  119         DBG_FUNC("IN\n");
  120 
  121         if (softs == NULL)
  122                 return;
  123 
  124         pqisrc_process_response_queue(softs, oq_id);
  125         pqisrc_process_event_intr_src(softs, oq_id - 1);
  126 
  127         DBG_FUNC("OUT\n");
  128 }
  129 
  130 /*
  131  * ithread routine to process non event response
  132  */
  133 static void
  134 common_ithread_routine(void *arg)
  135 {
  136         pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
  137         pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
  138         int oq_id  = intr_ctx->oq_id;
  139 
  140         DBG_FUNC("IN\n");
  141 
  142         if (softs == NULL)
  143                 return;
  144 
  145         pqisrc_process_response_queue(softs, oq_id);
  146 
  147         DBG_FUNC("OUT\n");
  148 }
  149 
  150 static void
  151 event_ithread_routine(void *arg)
  152 {
  153         pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
  154         pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
  155         int oq_id  = intr_ctx->oq_id;
  156 
  157         DBG_FUNC("IN\n");
  158 
  159         if (softs == NULL)
  160                 return;
  161 
  162         pqisrc_process_event_intr_src(softs, oq_id);
  163 
  164         DBG_FUNC("OUT\n");
  165 }
  166 
  167 /*
  168  * Registration of legacy interrupt in case MSI is unsupported
  169  */
  170 int
  171 register_legacy_intr(pqisrc_softstate_t *softs)
  172 {
  173         int error = BSD_SUCCESS;
  174         device_t dev = softs->os_specific.pqi_dev;
  175 
  176         DBG_FUNC("IN\n");
  177 
  178         softs->os_specific.pqi_irq_rid[0] = 0;
  179         softs->os_specific.pqi_irq[0] = bus_alloc_resource_any(dev, \
  180                 SYS_RES_IRQ, &softs->os_specific.pqi_irq_rid[0],
  181                 RF_ACTIVE | RF_SHAREABLE);
  182         if (NULL == softs->os_specific.pqi_irq[0]) {
  183                 DBG_ERR("Failed to allocate resource for interrupt\n");
  184                 return ENXIO;
  185         }
  186         if ((softs->os_specific.msi_ctx = os_mem_alloc(softs,sizeof(pqi_intr_ctx_t))) == NULL) {
  187                 DBG_ERR("Failed to allocate memory for msi_ctx\n");
  188                 return ENXIO;
  189         }
  190         softs->os_specific.msi_ctx[0].pqi_dev = dev;
  191         /* For Legacy support oq_id should be one */
  192         softs->os_specific.msi_ctx[0].oq_id = 1;
  193 
  194         error = bus_setup_intr(dev, softs->os_specific.pqi_irq[0],
  195                                 INTR_TYPE_CAM | INTR_MPSAFE, \
  196                                 NULL, shared_ithread_routine,
  197                                 &softs->os_specific.msi_ctx[0],
  198                                 &softs->os_specific.intrcookie[0]);
  199         if (error) {
  200                 DBG_ERR("Failed to setup legacy interrupt err = %d\n", error);
  201                 return error;
  202         }
  203         softs->os_specific.intr_registered[0] = TRUE;
  204 
  205         DBG_FUNC("OUT error = %d\n", error);
  206 
  207         return error;
  208 }
  209 
  210 /*
  211  * Registration of MSIx
  212  */
  213 int
  214 register_msix_intr(pqisrc_softstate_t *softs)
  215 {
  216         int error = BSD_SUCCESS;
  217         int i = 0;
  218         device_t dev = softs->os_specific.pqi_dev;
  219         int msix_count = softs->intr_count;
  220 
  221         DBG_FUNC("IN\n");
  222 
  223         softs->os_specific.msi_ctx = os_mem_alloc(softs, sizeof(pqi_intr_ctx_t) * msix_count);
  224         if (!softs->os_specific.msi_ctx) {
  225                 DBG_ERR("Memory allocation failed\n");
  226                 return ENXIO;
  227         }
  228 
  229         /*Add shared handler */
  230         if (softs->share_opq_and_eventq) {
  231                 softs->os_specific.pqi_irq_rid[i] = i+1;
  232                 softs->os_specific.pqi_irq[i] = bus_alloc_resource_any(dev, \
  233                                                 SYS_RES_IRQ,
  234                                                 &softs->os_specific.pqi_irq_rid[i],
  235                                                 RF_SHAREABLE |  RF_ACTIVE);
  236                 if (NULL == softs->os_specific.pqi_irq[i]) {
  237                         DBG_ERR("Failed to allocate \
  238                                 event interrupt resource\n");
  239                         return ENXIO;
  240                 }
  241 
  242                 softs->os_specific.msi_ctx[i].pqi_dev = dev;
  243                 softs->os_specific.msi_ctx[i].oq_id = i+1;
  244 
  245                 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
  246                                         INTR_TYPE_CAM | INTR_MPSAFE,\
  247                                         NULL,
  248                                         shared_ithread_routine,
  249                                         &softs->os_specific.msi_ctx[i],
  250                                         &softs->os_specific.intrcookie[i]);
  251 
  252                 if (error) {
  253                         DBG_ERR("Failed to setup interrupt for events r=%d\n",
  254                                 error);
  255                         return error;
  256                 }
  257                 softs->os_specific.intr_registered[i] = TRUE;
  258         }
  259         else {
  260                 /* Add event handler */
  261                 softs->os_specific.pqi_irq_rid[i] = i+1;
  262                 softs->os_specific.pqi_irq[i] = bus_alloc_resource_any(dev, \
  263                                                 SYS_RES_IRQ,
  264                                                 &softs->os_specific.pqi_irq_rid[i],
  265                                                 RF_SHAREABLE |  RF_ACTIVE);
  266                 if (NULL == softs->os_specific.pqi_irq[i]) {
  267                         DBG_ERR("Failed to allocate event interrupt resource\n");
  268                         return ENXIO;
  269                 }
  270 
  271                 softs->os_specific.msi_ctx[i].pqi_dev = dev;
  272                 softs->os_specific.msi_ctx[i].oq_id = i;
  273 
  274                 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
  275                                         INTR_TYPE_CAM | INTR_MPSAFE,\
  276                                         NULL,
  277                                         event_ithread_routine,
  278                                         &softs->os_specific.msi_ctx[i],
  279                                         &softs->os_specific.intrcookie[i]);
  280                 if (error) {
  281                         DBG_ERR("Failed to setup interrupt for events err=%d\n",
  282                                 error);
  283                         return error;
  284                 }
  285                 softs->os_specific.intr_registered[i] = TRUE;
  286                 /* Add interrupt handlers*/     
  287                 for (i = 1; i < msix_count; ++i) {
  288                         softs->os_specific.pqi_irq_rid[i] = i+1;
  289                         softs->os_specific.pqi_irq[i] = \
  290                                         bus_alloc_resource_any(dev,
  291                                         SYS_RES_IRQ,
  292                                         &softs->os_specific.pqi_irq_rid[i],
  293                                         RF_SHAREABLE | RF_ACTIVE);
  294                         if (NULL == softs->os_specific.pqi_irq[i]) {
  295                                 DBG_ERR("Failed to allocate \
  296                                         msi/x interrupt resource\n");
  297                                 return ENXIO;
  298                         }
  299                         softs->os_specific.msi_ctx[i].pqi_dev = dev;
  300                         softs->os_specific.msi_ctx[i].oq_id = i;
  301                         error = bus_setup_intr(dev,
  302                                         softs->os_specific.pqi_irq[i],
  303                                         INTR_TYPE_CAM | INTR_MPSAFE,\
  304                                         NULL,
  305                                         common_ithread_routine,
  306                                         &softs->os_specific.msi_ctx[i],
  307                                         &softs->os_specific.intrcookie[i]);
  308                         if (error) {
  309                                 DBG_ERR("Failed to setup \
  310                                         msi/x interrupt error = %d\n", error);
  311                                 return error;
  312                         }
  313                         softs->os_specific.intr_registered[i] = TRUE;
  314                 }
  315         }
  316 
  317         DBG_FUNC("OUT error = %d\n", error);
  318 
  319         return error;
  320 }
  321 
  322 /*
  323  * Setup interrupt depending on the configuration
  324  */
  325 int
  326 os_setup_intr(pqisrc_softstate_t *softs)
  327 {
  328         int bsd_status, pqi_status;
  329 
  330         DBG_FUNC("IN\n");
  331 
  332         if (softs->intr_type == INTR_TYPE_FIXED) {
  333                 bsd_status = register_legacy_intr(softs);
  334         }
  335         else {
  336                 bsd_status = register_msix_intr(softs);
  337         }
  338 
  339         if(bsd_status)
  340                 DBG_WARN("interrupt registration is failed, error = %d\n", bsd_status);
  341 
  342         pqi_status = bsd_status_to_pqi_status(bsd_status);
  343 
  344         DBG_FUNC("OUT\n");
  345 
  346         return pqi_status;
  347 }
  348 
  349 /*
  350  * Deregistration of legacy interrupt
  351  */
  352 void
  353 deregister_pqi_intx(pqisrc_softstate_t *softs)
  354 {
  355         device_t dev = softs->os_specific.pqi_dev;
  356 
  357         DBG_FUNC("IN\n");
  358 
  359         if (softs->os_specific.pqi_irq[0] != NULL) {
  360                 if (softs->os_specific.intr_registered[0]) {
  361                         bus_teardown_intr(dev, softs->os_specific.pqi_irq[0],
  362                                         softs->os_specific.intrcookie[0]);
  363                         softs->os_specific.intr_registered[0] = FALSE;
  364                 }
  365                 bus_release_resource(dev, SYS_RES_IRQ,
  366                         softs->os_specific.pqi_irq_rid[0],
  367                         softs->os_specific.pqi_irq[0]);
  368                 softs->os_specific.pqi_irq[0] = NULL;
  369                 os_mem_free(softs, (char*)softs->os_specific.msi_ctx, sizeof(pqi_intr_ctx_t));
  370         }
  371 
  372         DBG_FUNC("OUT\n");
  373 }
  374 
  375 /*
  376  * Deregistration of MSIx interrupt
  377  */
  378 void
  379 deregister_pqi_msix(pqisrc_softstate_t *softs)
  380 {
  381         device_t dev = softs->os_specific.pqi_dev;
  382         int msix_count = softs->intr_count;
  383         int i = 0;
  384 
  385         DBG_FUNC("IN\n");
  386 
  387         os_mem_free(softs, (char*)softs->os_specific.msi_ctx, sizeof(pqi_intr_ctx_t) * msix_count);
  388         softs->os_specific.msi_ctx = NULL;
  389 
  390         for (; i < msix_count; ++i) {
  391                 if (softs->os_specific.pqi_irq[i] != NULL) {
  392                         if (softs->os_specific.intr_registered[i]) {
  393                                 bus_teardown_intr(dev,
  394                                         softs->os_specific.pqi_irq[i],
  395                                         softs->os_specific.intrcookie[i]);
  396                                 softs->os_specific.intr_registered[i] = FALSE;
  397                         }
  398                         bus_release_resource(dev, SYS_RES_IRQ,
  399                                 softs->os_specific.pqi_irq_rid[i],
  400                         softs->os_specific.pqi_irq[i]);
  401                         softs->os_specific.pqi_irq[i] = NULL;
  402                 }
  403         }
  404 
  405         DBG_FUNC("OUT\n");
  406 }
  407 
  408 /*
  409  * Function to destroy interrupts registered
  410  */
  411 int
  412 os_destroy_intr(pqisrc_softstate_t *softs)
  413 {
  414         device_t dev = softs->os_specific.pqi_dev;
  415 
  416         DBG_FUNC("IN\n");
  417 
  418         if (softs->intr_type == INTR_TYPE_FIXED) {
  419                 deregister_pqi_intx(softs);
  420         } else if (softs->intr_type == INTR_TYPE_MSIX) {
  421                 deregister_pqi_msix(softs);
  422         }
  423         if (softs->os_specific.msi_enabled) {
  424                 pci_release_msi(dev);
  425                 softs->os_specific.msi_enabled = FALSE;
  426         } 
  427         
  428         DBG_FUNC("OUT\n");
  429 
  430         return PQI_STATUS_SUCCESS;
  431 }
  432 
  433 /*
  434  * Free interrupt related resources for the adapter
  435  */
  436 void
  437 os_free_intr_config(pqisrc_softstate_t *softs)
  438 {
  439         device_t dev = softs->os_specific.pqi_dev;
  440 
  441         DBG_FUNC("IN\n");
  442 
  443         if (softs->os_specific.msi_enabled) {
  444                 pci_release_msi(dev);
  445                 softs->os_specific.msi_enabled = FALSE;
  446         }
  447 
  448         DBG_FUNC("OUT\n");
  449 }

Cache object: 371f15162841b0a546f4821a94504507


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