2 * Copyright (c) 2018 Microsemi Corporation.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include "smartpqi_includes.h"
32 * Function to get processor count
34 int os_get_processor_config(pqisrc_softstate_t *softs)
37 softs->num_cpus_online = mp_ncpus;
40 return PQI_STATUS_SUCCESS;
44 * Function to get interrupt count and type supported
46 int os_get_intr_config(pqisrc_softstate_t *softs)
51 int ret = PQI_STATUS_SUCCESS;
52 dev = softs->os_specific.pqi_dev;
56 msi_count = pci_msix_count(dev);
58 if (msi_count > softs->num_cpus_online)
59 msi_count = softs->num_cpus_online;
60 if (msi_count > PQI_MAX_MSIX)
61 msi_count = PQI_MAX_MSIX;
62 if (msi_count == 0 || (error = pci_alloc_msix(dev, &msi_count)) != 0) {
63 device_printf(dev, "alloc msix failed - msi_count=%d, err=%d; "
64 "will try MSI\n", msi_count, error);
67 softs->intr_count = msi_count;
68 softs->intr_type = INTR_TYPE_MSIX;
69 softs->os_specific.msi_enabled = TRUE;
70 device_printf(dev, "using MSI-X interrupts (%d vectors)\n",
73 if (!softs->intr_type) {
75 if ((error = pci_alloc_msi(dev, &msi_count)) != 0) {
76 device_printf(dev, "alloc msi failed - err=%d; "
77 "will use INTx\n", error);
80 softs->os_specific.msi_enabled = TRUE;
81 softs->intr_count = msi_count;
82 softs->intr_type = INTR_TYPE_MSI;
83 device_printf(dev, "using MSI interrupts\n");
87 if (!softs->intr_type) {
88 device_printf(dev, "using legacy interrupts\n");
89 softs->intr_type = INTR_TYPE_FIXED;
90 softs->intr_count = 1;
93 if(!softs->intr_type) {
94 DBG_FUNC("OUT failed\n");
95 ret = PQI_STATUS_FAILURE;
102 void os_eventtaskqueue_enqueue(pqisrc_softstate_t *sc)
104 taskqueue_enqueue(taskqueue_swi, &sc->os_specific.event_task);
107 void pqisrc_event_worker(void *arg1, int arg2)
109 pqisrc_ack_all_events(arg1);
113 * ithread routine to handle uniprocessor systems
115 static void shared_ithread_routine(void *arg)
117 pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
118 pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
119 int oq_id = intr_ctx->oq_id;
123 pqisrc_process_response_queue(softs, oq_id);
124 pqisrc_process_event_intr_src(softs, oq_id - 1);
130 * ithread routine to process non event response
132 static void common_ithread_routine(void *arg)
134 pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
135 pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
136 int oq_id = intr_ctx->oq_id;
140 pqisrc_process_response_queue(softs, oq_id);
145 static void event_ithread_routine(void *arg)
147 pqi_intr_ctx_t *intr_ctx = (pqi_intr_ctx_t *)arg;
148 pqisrc_softstate_t *softs = device_get_softc(intr_ctx->pqi_dev);
149 int oq_id = intr_ctx->oq_id;
153 pqisrc_process_event_intr_src(softs, oq_id);
159 * Registration of legacy interrupt in case MSI is unsupported
161 int register_legacy_intr(pqisrc_softstate_t *softs)
168 dev = softs->os_specific.pqi_dev;
170 softs->os_specific.pqi_irq_rid[0] = 0;
171 softs->os_specific.pqi_irq[0] = bus_alloc_resource_any(dev, \
172 SYS_RES_IRQ, &softs->os_specific.pqi_irq_rid[0],
173 RF_ACTIVE | RF_SHAREABLE);
174 if (NULL == softs->os_specific.pqi_irq[0]) {
175 DBG_ERR("Failed to allocate resource for interrupt\n");
176 return PQI_STATUS_FAILURE;
178 if ((softs->os_specific.msi_ctx = os_mem_alloc(softs,sizeof(pqi_intr_ctx_t))) == NULL) {
179 DBG_ERR("Failed to allocate memory for msi_ctx\n");
180 return PQI_STATUS_FAILURE;
182 softs->os_specific.msi_ctx[0].pqi_dev = dev;
183 softs->os_specific.msi_ctx[0].oq_id = 1;
185 error = bus_setup_intr(dev, softs->os_specific.pqi_irq[0],
186 INTR_TYPE_CAM | INTR_MPSAFE, \
187 NULL, shared_ithread_routine,
188 &softs->os_specific.msi_ctx[0],
189 &softs->os_specific.intrcookie[0]);
191 DBG_ERR("Failed to setup legacy interrupt err = %d\n", error);
194 softs->os_specific.intr_registered[0] = TRUE;
196 DBG_FUNC("OUT error = %d\n", error);
202 * Registration of MSIx
204 int register_msix_intr(pqisrc_softstate_t *softs)
209 dev = softs->os_specific.pqi_dev;
210 int msix_count = softs->intr_count;
214 softs->os_specific.msi_ctx = os_mem_alloc(softs, sizeof(pqi_intr_ctx_t) * msix_count);
215 /*Add shared handler */
216 if (softs->share_opq_and_eventq) {
217 softs->os_specific.pqi_irq_rid[i] = i+1;
218 softs->os_specific.pqi_irq[i] = bus_alloc_resource_any(dev, \
220 &softs->os_specific.pqi_irq_rid[i],
221 RF_SHAREABLE | RF_ACTIVE);
222 if (NULL == softs->os_specific.pqi_irq[i]) {
223 DBG_ERR("Failed to allocate \
224 event interrupt resource\n");
225 return PQI_STATUS_FAILURE;
228 softs->os_specific.msi_ctx[i].pqi_dev = dev;
229 softs->os_specific.msi_ctx[i].oq_id = i+1;
231 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
232 INTR_TYPE_CAM | INTR_MPSAFE,\
234 shared_ithread_routine,
235 &softs->os_specific.msi_ctx[i],
236 &softs->os_specific.intrcookie[i]);
239 DBG_ERR("Failed to setup interrupt for events r=%d\n",
243 softs->os_specific.intr_registered[i] = TRUE;
246 /* Add event handler */
247 softs->os_specific.pqi_irq_rid[i] = i+1;
248 softs->os_specific.pqi_irq[i] = bus_alloc_resource_any(dev, \
250 &softs->os_specific.pqi_irq_rid[i],
251 RF_SHAREABLE | RF_ACTIVE);
252 if (NULL == softs->os_specific.pqi_irq[i]) {
253 DBG_ERR("ERR : Failed to allocate \
254 event interrupt resource\n");
255 return PQI_STATUS_FAILURE;
259 softs->os_specific.msi_ctx[i].pqi_dev = dev;
260 softs->os_specific.msi_ctx[i].oq_id = i;
263 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
264 INTR_TYPE_CAM | INTR_MPSAFE,\
266 event_ithread_routine,
267 &softs->os_specific.msi_ctx[i],
268 &softs->os_specific.intrcookie[i]);
270 DBG_ERR("Failed to setup interrupt for events err=%d\n",
274 softs->os_specific.intr_registered[i] = TRUE;
275 /* Add interrupt handlers*/
276 for (i = 1; i < msix_count; ++i) {
277 softs->os_specific.pqi_irq_rid[i] = i+1;
278 softs->os_specific.pqi_irq[i] = \
279 bus_alloc_resource_any(dev,
281 &softs->os_specific.pqi_irq_rid[i],
282 RF_SHAREABLE | RF_ACTIVE);
283 if (NULL == softs->os_specific.pqi_irq[i]) {
284 DBG_ERR("Failed to allocate \
285 msi/x interrupt resource\n");
286 return PQI_STATUS_FAILURE;
288 softs->os_specific.msi_ctx[i].pqi_dev = dev;
289 softs->os_specific.msi_ctx[i].oq_id = i;
290 error = bus_setup_intr(dev,
291 softs->os_specific.pqi_irq[i],
292 INTR_TYPE_CAM | INTR_MPSAFE,\
294 common_ithread_routine,
295 &softs->os_specific.msi_ctx[i],
296 &softs->os_specific.intrcookie[i]);
298 DBG_ERR("Failed to setup \
299 msi/x interrupt error = %d\n", error);
302 softs->os_specific.intr_registered[i] = TRUE;
306 DBG_FUNC("OUT error = %d\n", error);
312 * Setup interrupt depending on the configuration
314 int os_setup_intr(pqisrc_softstate_t *softs)
320 if (softs->intr_type == INTR_TYPE_FIXED) {
321 error = register_legacy_intr(softs);
324 error = register_msix_intr(softs);
327 DBG_FUNC("OUT failed error = %d\n", error);
331 DBG_FUNC("OUT error = %d\n", error);
337 * Deregistration of legacy interrupt
339 void deregister_pqi_intx(pqisrc_softstate_t *softs)
345 dev = softs->os_specific.pqi_dev;
346 if (softs->os_specific.pqi_irq[0] != NULL) {
347 if (softs->os_specific.intr_registered[0]) {
348 bus_teardown_intr(dev, softs->os_specific.pqi_irq[0],
349 softs->os_specific.intrcookie[0]);
350 softs->os_specific.intr_registered[0] = FALSE;
352 bus_release_resource(dev, SYS_RES_IRQ,
353 softs->os_specific.pqi_irq_rid[0],
354 softs->os_specific.pqi_irq[0]);
355 softs->os_specific.pqi_irq[0] = NULL;
356 os_mem_free(softs, (char*)softs->os_specific.msi_ctx, sizeof(pqi_intr_ctx_t));
363 * Deregistration of MSIx interrupt
365 void deregister_pqi_msix(pqisrc_softstate_t *softs)
368 dev = softs->os_specific.pqi_dev;
369 int msix_count = softs->intr_count;
374 os_mem_free(softs, (char*)softs->os_specific.msi_ctx, sizeof(pqi_intr_ctx_t) * msix_count);
375 softs->os_specific.msi_ctx = NULL;
377 for (; i < msix_count; ++i) {
378 if (softs->os_specific.pqi_irq[i] != NULL) {
379 if (softs->os_specific.intr_registered[i]) {
380 bus_teardown_intr(dev,
381 softs->os_specific.pqi_irq[i],
382 softs->os_specific.intrcookie[i]);
383 softs->os_specific.intr_registered[i] = FALSE;
385 bus_release_resource(dev, SYS_RES_IRQ,
386 softs->os_specific.pqi_irq_rid[i],
387 softs->os_specific.pqi_irq[i]);
388 softs->os_specific.pqi_irq[i] = NULL;
396 * Function to destroy interrupts registered
398 int os_destroy_intr(pqisrc_softstate_t *softs)
401 dev = softs->os_specific.pqi_dev;
405 if (softs->intr_type == INTR_TYPE_FIXED) {
406 deregister_pqi_intx(softs);
407 } else if (softs->intr_type == INTR_TYPE_MSIX) {
408 deregister_pqi_msix(softs);
410 if (softs->os_specific.msi_enabled) {
411 pci_release_msi(dev);
412 softs->os_specific.msi_enabled = FALSE;
417 return PQI_STATUS_SUCCESS;
421 * Free interrupt related resources for the adapter
423 void os_free_intr_config(pqisrc_softstate_t *softs)
426 dev = softs->os_specific.pqi_dev;
430 if (softs->os_specific.msi_enabled) {
431 pci_release_msi(dev);
432 softs->os_specific.msi_enabled = FALSE;