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/isci/isci_interrupt.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  * BSD LICENSE
    3  *
    4  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  *
   11  *   * Redistributions of source code must retain the above copyright
   12  *     notice, this list of conditions and the following disclaimer.
   13  *   * Redistributions in binary form must reproduce the above copyright
   14  *     notice, this list of conditions and the following disclaimer in
   15  *     the documentation and/or other materials provided with the
   16  *     distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/8.4/sys/dev/isci/isci_interrupt.c 236264 2012-05-29 23:15:23Z jimharris $");
   33 
   34 #include <dev/isci/isci.h>
   35 
   36 #include <dev/pci/pcireg.h>
   37 #include <dev/pci/pcivar.h>
   38 
   39 #include <dev/isci/scil/scif_controller.h>
   40 
   41 void isci_interrupt_legacy_handler(void *arg);
   42 void isci_interrupt_msix_handler(void *arg);
   43 
   44 static int
   45 isci_interrupt_setup_legacy(struct isci_softc *isci)
   46 {
   47         struct ISCI_INTERRUPT_INFO *interrupt_info = &isci->interrupt_info[0];
   48 
   49         isci->num_interrupts = 1;
   50 
   51         scic_controller_get_handler_methods(SCIC_LEGACY_LINE_INTERRUPT_TYPE,
   52             0, &isci->handlers[0]);
   53 
   54         interrupt_info->handlers = &isci->handlers[0];
   55         interrupt_info->rid = 0;
   56         interrupt_info->interrupt_target_handle = (void *)isci;
   57 
   58         interrupt_info->res = bus_alloc_resource_any(isci->device, SYS_RES_IRQ,
   59             &interrupt_info->rid, RF_SHAREABLE|RF_ACTIVE);
   60 
   61         if (interrupt_info->res == NULL) {
   62                 isci_log_message(0, "ISCI", "bus_alloc_resource failed\n");
   63                 return (-1);
   64         }
   65 
   66         interrupt_info->tag = NULL;
   67         if (bus_setup_intr(isci->device, interrupt_info->res,
   68             INTR_TYPE_CAM | INTR_MPSAFE, NULL, isci_interrupt_legacy_handler,
   69             interrupt_info, &interrupt_info->tag)) {
   70                 isci_log_message(0, "ISCI", "bus_setup_intr failed\n");
   71                 return (-1);
   72         }
   73 
   74         return (0);
   75 }
   76 
   77 static int
   78 isci_interrupt_setup_msix(struct isci_softc *isci)
   79 {
   80         uint32_t controller_index;
   81 
   82         scic_controller_get_handler_methods(SCIC_MSIX_INTERRUPT_TYPE,
   83             SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER, &isci->handlers[0]);
   84 
   85         for (controller_index = 0; controller_index < isci->controller_count;
   86             controller_index++) {
   87                 uint32_t msix_index;
   88                 uint8_t base_index = controller_index *
   89                     SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER;
   90 
   91                 for (msix_index = 0; msix_index < SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER;
   92                     msix_index++) {
   93                         struct ISCI_INTERRUPT_INFO *info =
   94                             &isci->interrupt_info[base_index+msix_index];
   95 
   96                         info->handlers = &isci->handlers[msix_index];
   97                         info->interrupt_target_handle =
   98                             &isci->controllers[controller_index];
   99 
  100                         info->rid = base_index+msix_index+1;
  101 
  102                         info->res = bus_alloc_resource_any(isci->device,
  103                             SYS_RES_IRQ, &info->rid, RF_ACTIVE);
  104                         if (info->res == NULL) {
  105                                 isci_log_message(0, "ISCI",
  106                                     "bus_alloc_resource failed\n");
  107                                 return (-1);
  108                         }
  109 
  110                         info->tag = NULL;
  111                         if (bus_setup_intr(isci->device, info->res,
  112                             INTR_TYPE_CAM | INTR_MPSAFE, NULL,
  113                             isci_interrupt_msix_handler, info, &info->tag)) {
  114                                 isci_log_message(0, "ISCI",
  115                                     "bus_setup_intr failed\n");
  116                                 return (-1);
  117                         }
  118                 }
  119         }
  120 
  121         return (0);
  122 }
  123 
  124 void
  125 isci_interrupt_setup(struct isci_softc *isci)
  126 {
  127         uint8_t max_msix_messages = SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER *
  128             isci->controller_count;
  129         BOOL use_msix = FALSE;
  130         uint32_t force_legacy_interrupts = 0;
  131 
  132         TUNABLE_INT_FETCH("hw.isci.force_legacy_interrupts",
  133             &force_legacy_interrupts);
  134 
  135         if (!force_legacy_interrupts &&
  136             pci_msix_count(isci->device) >= max_msix_messages) {
  137 
  138                 isci->num_interrupts = max_msix_messages;
  139                 pci_alloc_msix(isci->device, &isci->num_interrupts);
  140                 if (isci->num_interrupts == max_msix_messages)
  141                         use_msix = TRUE;
  142         }
  143 
  144         if (use_msix == TRUE)
  145                 isci_interrupt_setup_msix(isci);
  146         else
  147                 isci_interrupt_setup_legacy(isci);
  148 }
  149 
  150 void
  151 isci_interrupt_legacy_handler(void *arg)
  152 {
  153         struct ISCI_INTERRUPT_INFO *interrupt_info =
  154             (struct ISCI_INTERRUPT_INFO *)arg;
  155         struct isci_softc *isci =
  156             (struct isci_softc *)interrupt_info->interrupt_target_handle;
  157         SCIC_CONTROLLER_INTERRUPT_HANDLER  interrupt_handler;
  158         SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
  159         int index;
  160 
  161         interrupt_handler =  interrupt_info->handlers->interrupt_handler;
  162         completion_handler = interrupt_info->handlers->completion_handler;
  163 
  164         for (index = 0; index < isci->controller_count; index++) {
  165                 struct ISCI_CONTROLLER *controller = &isci->controllers[index];
  166 
  167                 /* If controller_count > 0, we will get interrupts here for
  168                  *  controller 0 before controller 1 has even started.  So
  169                  *  we need to make sure we don't call the completion handler
  170                  *  for a non-started controller.
  171                  */
  172                 if (controller->is_started == TRUE) {
  173                         SCI_CONTROLLER_HANDLE_T scic_controller_handle =
  174                             scif_controller_get_scic_handle(
  175                                 controller->scif_controller_handle);
  176 
  177                         if (interrupt_handler(scic_controller_handle)) {
  178                                 mtx_lock(&controller->lock);
  179                                 completion_handler(scic_controller_handle);
  180                                 if (controller->release_queued_ccbs == TRUE)
  181                                         isci_controller_release_queued_ccbs(
  182                                             controller);
  183                                 mtx_unlock(&controller->lock);
  184                         }
  185                 }
  186         }
  187 }
  188 
  189 void
  190 isci_interrupt_msix_handler(void *arg)
  191 {
  192         struct ISCI_INTERRUPT_INFO *interrupt_info =
  193             (struct ISCI_INTERRUPT_INFO *)arg;
  194         struct ISCI_CONTROLLER *controller =
  195             (struct ISCI_CONTROLLER *)interrupt_info->interrupt_target_handle;
  196         SCIC_CONTROLLER_INTERRUPT_HANDLER  interrupt_handler;
  197         SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler;
  198 
  199         interrupt_handler =  interrupt_info->handlers->interrupt_handler;
  200         completion_handler = interrupt_info->handlers->completion_handler;
  201 
  202         SCI_CONTROLLER_HANDLE_T scic_controller_handle;
  203 
  204         scic_controller_handle = scif_controller_get_scic_handle(
  205             controller->scif_controller_handle);
  206 
  207         if (interrupt_handler(scic_controller_handle)) {
  208                 mtx_lock(&controller->lock);
  209                 completion_handler(scic_controller_handle);
  210                 /*
  211                  * isci_controller_release_queued_ccb() is a relatively
  212                  *  expensive routine, so we don't call it until the controller
  213                  *  level flag is set to TRUE.
  214                  */
  215                 if (controller->release_queued_ccbs == TRUE)
  216                         isci_controller_release_queued_ccbs(controller);
  217                 mtx_unlock(&controller->lock);
  218         }
  219 }
  220 
  221 void
  222 isci_interrupt_poll_handler(struct ISCI_CONTROLLER *controller)
  223 {
  224         SCI_CONTROLLER_HANDLE_T scic_controller =
  225             scif_controller_get_scic_handle(controller->scif_controller_handle);
  226         SCIC_CONTROLLER_HANDLER_METHODS_T handlers;
  227 
  228         scic_controller_get_handler_methods(SCIC_NO_INTERRUPTS, 0x0, &handlers);
  229 
  230         if(handlers.interrupt_handler(scic_controller) == TRUE) {
  231                 /* Do not acquire controller lock in this path. xpt
  232                  *  poll routine will get called with this lock already
  233                  *  held, so we can't acquire it again here.  Other users
  234                  *  of this function must acquire the lock explicitly
  235                  *  before calling this handler.
  236                  */
  237                 handlers.completion_handler(scic_controller);
  238         }
  239 }

Cache object: df9608ea9d7208172a43ce9a4375b6d0


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