]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/isci/isci_interrupt.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / isci / isci_interrupt.c
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$");
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 }