1230557Sjimharris/*- 2230557Sjimharris * BSD LICENSE 3230557Sjimharris * 4230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 5230557Sjimharris * All rights reserved. 6230557Sjimharris * 7230557Sjimharris * Redistribution and use in source and binary forms, with or without 8230557Sjimharris * modification, are permitted provided that the following conditions 9230557Sjimharris * are met: 10230557Sjimharris * 11230557Sjimharris * * Redistributions of source code must retain the above copyright 12230557Sjimharris * notice, this list of conditions and the following disclaimer. 13230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 14230557Sjimharris * notice, this list of conditions and the following disclaimer in 15230557Sjimharris * the documentation and/or other materials provided with the 16230557Sjimharris * distribution. 17230557Sjimharris * 18230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29230557Sjimharris */ 30230557Sjimharris 31230557Sjimharris#include <sys/cdefs.h> 32230557Sjimharris__FBSDID("$FreeBSD$"); 33230557Sjimharris 34230557Sjimharris#include <dev/isci/isci.h> 35230557Sjimharris 36230557Sjimharris#include <dev/pci/pcireg.h> 37230557Sjimharris#include <dev/pci/pcivar.h> 38230557Sjimharris 39230557Sjimharris#include <dev/isci/scil/scif_controller.h> 40230557Sjimharris 41230557Sjimharrisvoid isci_interrupt_legacy_handler(void *arg); 42230557Sjimharrisvoid isci_interrupt_msix_handler(void *arg); 43230557Sjimharris 44230557Sjimharrisstatic int 45230557Sjimharrisisci_interrupt_setup_legacy(struct isci_softc *isci) 46230557Sjimharris{ 47230557Sjimharris struct ISCI_INTERRUPT_INFO *interrupt_info = &isci->interrupt_info[0]; 48230557Sjimharris 49230557Sjimharris isci->num_interrupts = 1; 50230557Sjimharris 51230557Sjimharris scic_controller_get_handler_methods(SCIC_LEGACY_LINE_INTERRUPT_TYPE, 52230557Sjimharris 0, &isci->handlers[0]); 53230557Sjimharris 54230557Sjimharris interrupt_info->handlers = &isci->handlers[0]; 55230557Sjimharris interrupt_info->rid = 0; 56230557Sjimharris interrupt_info->interrupt_target_handle = (void *)isci; 57230557Sjimharris 58230557Sjimharris interrupt_info->res = bus_alloc_resource_any(isci->device, SYS_RES_IRQ, 59230557Sjimharris &interrupt_info->rid, RF_SHAREABLE|RF_ACTIVE); 60230557Sjimharris 61230557Sjimharris if (interrupt_info->res == NULL) { 62230557Sjimharris isci_log_message(0, "ISCI", "bus_alloc_resource failed\n"); 63230557Sjimharris return (-1); 64230557Sjimharris } 65230557Sjimharris 66230557Sjimharris interrupt_info->tag = NULL; 67230557Sjimharris if (bus_setup_intr(isci->device, interrupt_info->res, 68230557Sjimharris INTR_TYPE_CAM | INTR_MPSAFE, NULL, isci_interrupt_legacy_handler, 69230557Sjimharris interrupt_info, &interrupt_info->tag)) { 70230557Sjimharris isci_log_message(0, "ISCI", "bus_setup_intr failed\n"); 71230557Sjimharris return (-1); 72230557Sjimharris } 73230557Sjimharris 74230557Sjimharris return (0); 75230557Sjimharris} 76230557Sjimharris 77230557Sjimharrisstatic int 78230557Sjimharrisisci_interrupt_setup_msix(struct isci_softc *isci) 79230557Sjimharris{ 80230557Sjimharris uint32_t controller_index; 81230557Sjimharris 82230557Sjimharris scic_controller_get_handler_methods(SCIC_MSIX_INTERRUPT_TYPE, 83230557Sjimharris SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER, &isci->handlers[0]); 84230557Sjimharris 85230557Sjimharris for (controller_index = 0; controller_index < isci->controller_count; 86230557Sjimharris controller_index++) { 87230557Sjimharris uint32_t msix_index; 88230557Sjimharris uint8_t base_index = controller_index * 89230557Sjimharris SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER; 90230557Sjimharris 91230557Sjimharris for (msix_index = 0; msix_index < SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER; 92230557Sjimharris msix_index++) { 93230557Sjimharris struct ISCI_INTERRUPT_INFO *info = 94230557Sjimharris &isci->interrupt_info[base_index+msix_index]; 95230557Sjimharris 96230557Sjimharris info->handlers = &isci->handlers[msix_index]; 97230557Sjimharris info->interrupt_target_handle = 98230557Sjimharris &isci->controllers[controller_index]; 99230557Sjimharris 100230557Sjimharris info->rid = base_index+msix_index+1; 101230557Sjimharris 102230557Sjimharris info->res = bus_alloc_resource_any(isci->device, 103230557Sjimharris SYS_RES_IRQ, &info->rid, RF_ACTIVE); 104230557Sjimharris if (info->res == NULL) { 105230557Sjimharris isci_log_message(0, "ISCI", 106230557Sjimharris "bus_alloc_resource failed\n"); 107230557Sjimharris return (-1); 108230557Sjimharris } 109230557Sjimharris 110230557Sjimharris info->tag = NULL; 111230557Sjimharris if (bus_setup_intr(isci->device, info->res, 112230557Sjimharris INTR_TYPE_CAM | INTR_MPSAFE, NULL, 113230557Sjimharris isci_interrupt_msix_handler, info, &info->tag)) { 114230557Sjimharris isci_log_message(0, "ISCI", 115230557Sjimharris "bus_setup_intr failed\n"); 116230557Sjimharris return (-1); 117230557Sjimharris } 118230557Sjimharris } 119230557Sjimharris } 120230557Sjimharris 121230557Sjimharris return (0); 122230557Sjimharris} 123230557Sjimharris 124230557Sjimharrisvoid 125230557Sjimharrisisci_interrupt_setup(struct isci_softc *isci) 126230557Sjimharris{ 127230557Sjimharris uint8_t max_msix_messages = SCI_MAX_MSIX_MESSAGES_PER_CONTROLLER * 128230557Sjimharris isci->controller_count; 129230557Sjimharris BOOL use_msix = FALSE; 130230557Sjimharris uint32_t force_legacy_interrupts = 0; 131230557Sjimharris 132230557Sjimharris TUNABLE_INT_FETCH("hw.isci.force_legacy_interrupts", 133230557Sjimharris &force_legacy_interrupts); 134230557Sjimharris 135230557Sjimharris if (!force_legacy_interrupts && 136230557Sjimharris pci_msix_count(isci->device) >= max_msix_messages) { 137230557Sjimharris 138230557Sjimharris isci->num_interrupts = max_msix_messages; 139287564Sjimharris if (pci_alloc_msix(isci->device, &isci->num_interrupts) == 0 && 140287564Sjimharris isci->num_interrupts == max_msix_messages) 141230557Sjimharris use_msix = TRUE; 142230557Sjimharris } 143230557Sjimharris 144230557Sjimharris if (use_msix == TRUE) 145230557Sjimharris isci_interrupt_setup_msix(isci); 146230557Sjimharris else 147230557Sjimharris isci_interrupt_setup_legacy(isci); 148230557Sjimharris} 149230557Sjimharris 150230557Sjimharrisvoid 151230557Sjimharrisisci_interrupt_legacy_handler(void *arg) 152230557Sjimharris{ 153230557Sjimharris struct ISCI_INTERRUPT_INFO *interrupt_info = 154230557Sjimharris (struct ISCI_INTERRUPT_INFO *)arg; 155230557Sjimharris struct isci_softc *isci = 156230557Sjimharris (struct isci_softc *)interrupt_info->interrupt_target_handle; 157230557Sjimharris SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler; 158230557Sjimharris SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler; 159230557Sjimharris int index; 160230557Sjimharris 161230557Sjimharris interrupt_handler = interrupt_info->handlers->interrupt_handler; 162230557Sjimharris completion_handler = interrupt_info->handlers->completion_handler; 163230557Sjimharris 164230557Sjimharris for (index = 0; index < isci->controller_count; index++) { 165230557Sjimharris struct ISCI_CONTROLLER *controller = &isci->controllers[index]; 166230557Sjimharris 167230557Sjimharris /* If controller_count > 0, we will get interrupts here for 168230557Sjimharris * controller 0 before controller 1 has even started. So 169230557Sjimharris * we need to make sure we don't call the completion handler 170230557Sjimharris * for a non-started controller. 171230557Sjimharris */ 172230557Sjimharris if (controller->is_started == TRUE) { 173230557Sjimharris SCI_CONTROLLER_HANDLE_T scic_controller_handle = 174230557Sjimharris scif_controller_get_scic_handle( 175230557Sjimharris controller->scif_controller_handle); 176230557Sjimharris 177230557Sjimharris if (interrupt_handler(scic_controller_handle)) { 178230557Sjimharris mtx_lock(&controller->lock); 179230557Sjimharris completion_handler(scic_controller_handle); 180235751Sjimharris if (controller->release_queued_ccbs == TRUE) 181235751Sjimharris isci_controller_release_queued_ccbs( 182235751Sjimharris controller); 183230557Sjimharris mtx_unlock(&controller->lock); 184230557Sjimharris } 185230557Sjimharris } 186230557Sjimharris } 187230557Sjimharris} 188230557Sjimharris 189230557Sjimharrisvoid 190230557Sjimharrisisci_interrupt_msix_handler(void *arg) 191230557Sjimharris{ 192230557Sjimharris struct ISCI_INTERRUPT_INFO *interrupt_info = 193230557Sjimharris (struct ISCI_INTERRUPT_INFO *)arg; 194230557Sjimharris struct ISCI_CONTROLLER *controller = 195230557Sjimharris (struct ISCI_CONTROLLER *)interrupt_info->interrupt_target_handle; 196230557Sjimharris SCIC_CONTROLLER_INTERRUPT_HANDLER interrupt_handler; 197230557Sjimharris SCIC_CONTROLLER_COMPLETION_HANDLER completion_handler; 198230557Sjimharris 199230557Sjimharris interrupt_handler = interrupt_info->handlers->interrupt_handler; 200230557Sjimharris completion_handler = interrupt_info->handlers->completion_handler; 201230557Sjimharris 202230557Sjimharris SCI_CONTROLLER_HANDLE_T scic_controller_handle; 203230557Sjimharris 204230557Sjimharris scic_controller_handle = scif_controller_get_scic_handle( 205230557Sjimharris controller->scif_controller_handle); 206230557Sjimharris 207230557Sjimharris if (interrupt_handler(scic_controller_handle)) { 208230557Sjimharris mtx_lock(&controller->lock); 209230557Sjimharris completion_handler(scic_controller_handle); 210235751Sjimharris /* 211235751Sjimharris * isci_controller_release_queued_ccb() is a relatively 212235751Sjimharris * expensive routine, so we don't call it until the controller 213235751Sjimharris * level flag is set to TRUE. 214235751Sjimharris */ 215235751Sjimharris if (controller->release_queued_ccbs == TRUE) 216235751Sjimharris isci_controller_release_queued_ccbs(controller); 217230557Sjimharris mtx_unlock(&controller->lock); 218230557Sjimharris } 219230557Sjimharris} 220230557Sjimharris 221230557Sjimharrisvoid 222230557Sjimharrisisci_interrupt_poll_handler(struct ISCI_CONTROLLER *controller) 223230557Sjimharris{ 224230557Sjimharris SCI_CONTROLLER_HANDLE_T scic_controller = 225230557Sjimharris scif_controller_get_scic_handle(controller->scif_controller_handle); 226230557Sjimharris SCIC_CONTROLLER_HANDLER_METHODS_T handlers; 227230557Sjimharris 228230557Sjimharris scic_controller_get_handler_methods(SCIC_NO_INTERRUPTS, 0x0, &handlers); 229230557Sjimharris 230230557Sjimharris if(handlers.interrupt_handler(scic_controller) == TRUE) { 231230557Sjimharris /* Do not acquire controller lock in this path. xpt 232230557Sjimharris * poll routine will get called with this lock already 233230557Sjimharris * held, so we can't acquire it again here. Other users 234230557Sjimharris * of this function must acquire the lock explicitly 235230557Sjimharris * before calling this handler. 236230557Sjimharris */ 237230557Sjimharris handlers.completion_handler(scic_controller); 238230557Sjimharris } 239230557Sjimharris} 240