]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/smartpqi/smartpqi_intr.c
Add missing const after 6c4f95161d6e
[FreeBSD/FreeBSD.git] / sys / dev / smartpqi / smartpqi_intr.c
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 }