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

Cache object: b5dd36bd29f95cd808fd3c560b2cde65


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