2 * Copyright 2016-2021 Microchip Technology, Inc. and/or its subsidiaries.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
28 #include "smartpqi_includes.h"
31 * Function to get processor count
34 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
47 os_get_intr_config(pqisrc_softstate_t *softs)
49 device_t dev = softs->os_specific.pqi_dev;
50 int msi_count = pci_msix_count(dev);
51 int error = BSD_SUCCESS;
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);
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",
70 if (!softs->intr_type) {
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);
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");
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;
92 error = bsd_status_to_pqi_status(BSD_SUCCESS);
98 os_eventtaskqueue_enqueue(pqisrc_softstate_t *sc)
100 taskqueue_enqueue(taskqueue_swi, &sc->os_specific.event_task);
104 pqisrc_event_worker(void *arg1, int arg2)
106 pqisrc_ack_all_events(arg1);
110 * ithread routine to handle uniprocessor systems
113 shared_ithread_routine(void *arg)
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;
124 pqisrc_process_response_queue(softs, oq_id);
125 pqisrc_process_event_intr_src(softs, oq_id - 1);
131 * ithread routine to process non event response
134 common_ithread_routine(void *arg)
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;
145 pqisrc_process_response_queue(softs, oq_id);
151 event_ithread_routine(void *arg)
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;
162 pqisrc_process_event_intr_src(softs, oq_id);
168 * Registration of legacy interrupt in case MSI is unsupported
171 register_legacy_intr(pqisrc_softstate_t *softs)
173 int error = BSD_SUCCESS;
174 device_t dev = softs->os_specific.pqi_dev;
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");
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");
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;
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]);
200 DBG_ERR("Failed to setup legacy interrupt err = %d\n", error);
203 softs->os_specific.intr_registered[0] = TRUE;
205 DBG_FUNC("OUT error = %d\n", error);
211 * Registration of MSIx
214 register_msix_intr(pqisrc_softstate_t *softs)
216 int error = BSD_SUCCESS;
218 device_t dev = softs->os_specific.pqi_dev;
219 int msix_count = softs->intr_count;
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");
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, \
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");
242 softs->os_specific.msi_ctx[i].pqi_dev = dev;
243 softs->os_specific.msi_ctx[i].oq_id = i+1;
245 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
246 INTR_TYPE_CAM | INTR_MPSAFE,\
248 shared_ithread_routine,
249 &softs->os_specific.msi_ctx[i],
250 &softs->os_specific.intrcookie[i]);
253 DBG_ERR("Failed to setup interrupt for events r=%d\n",
257 softs->os_specific.intr_registered[i] = TRUE;
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, \
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");
271 softs->os_specific.msi_ctx[i].pqi_dev = dev;
272 softs->os_specific.msi_ctx[i].oq_id = i;
274 error = bus_setup_intr(dev,softs->os_specific.pqi_irq[i],
275 INTR_TYPE_CAM | INTR_MPSAFE,\
277 event_ithread_routine,
278 &softs->os_specific.msi_ctx[i],
279 &softs->os_specific.intrcookie[i]);
281 DBG_ERR("Failed to setup interrupt for events err=%d\n",
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,
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");
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,\
305 common_ithread_routine,
306 &softs->os_specific.msi_ctx[i],
307 &softs->os_specific.intrcookie[i]);
309 DBG_ERR("Failed to setup \
310 msi/x interrupt error = %d\n", error);
313 softs->os_specific.intr_registered[i] = TRUE;
317 DBG_FUNC("OUT error = %d\n", error);
323 * Setup interrupt depending on the configuration
326 os_setup_intr(pqisrc_softstate_t *softs)
328 int bsd_status, pqi_status;
332 if (softs->intr_type == INTR_TYPE_FIXED) {
333 bsd_status = register_legacy_intr(softs);
336 bsd_status = register_msix_intr(softs);
340 DBG_WARN("interrupt registration is failed, error = %d\n", bsd_status);
342 pqi_status = bsd_status_to_pqi_status(bsd_status);
350 * Deregistration of legacy interrupt
353 deregister_pqi_intx(pqisrc_softstate_t *softs)
355 device_t dev = softs->os_specific.pqi_dev;
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;
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));
376 * Deregistration of MSIx interrupt
379 deregister_pqi_msix(pqisrc_softstate_t *softs)
381 device_t dev = softs->os_specific.pqi_dev;
382 int msix_count = softs->intr_count;
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;
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;
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;
409 * Function to destroy interrupts registered
412 os_destroy_intr(pqisrc_softstate_t *softs)
414 device_t dev = softs->os_specific.pqi_dev;
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);
423 if (softs->os_specific.msi_enabled) {
424 pci_release_msi(dev);
425 softs->os_specific.msi_enabled = FALSE;
430 return PQI_STATUS_SUCCESS;
434 * Free interrupt related resources for the adapter
437 os_free_intr_config(pqisrc_softstate_t *softs)
439 device_t dev = softs->os_specific.pqi_dev;
443 if (softs->os_specific.msi_enabled) {
444 pci_release_msi(dev);
445 softs->os_specific.msi_enabled = FALSE;