1be48125bSWojciech Macek /*-
2be48125bSWojciech Macek * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates
3be48125bSWojciech Macek * All rights reserved.
4be48125bSWojciech Macek *
5be48125bSWojciech Macek * Developed by Semihalf.
6be48125bSWojciech Macek *
7be48125bSWojciech Macek * Redistribution and use in source and binary forms, with or without
8be48125bSWojciech Macek * modification, are permitted provided that the following conditions
9be48125bSWojciech Macek * are met:
10be48125bSWojciech Macek * 1. Redistributions of source code must retain the above copyright
11be48125bSWojciech Macek * notice, this list of conditions and the following disclaimer.
12be48125bSWojciech Macek * 2. Redistributions in binary form must reproduce the above copyright
13be48125bSWojciech Macek * notice, this list of conditions and the following disclaimer in the
14be48125bSWojciech Macek * documentation and/or other materials provided with the distribution.
15be48125bSWojciech Macek *
16be48125bSWojciech Macek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17be48125bSWojciech Macek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18be48125bSWojciech Macek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19be48125bSWojciech Macek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20be48125bSWojciech Macek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21be48125bSWojciech Macek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22be48125bSWojciech Macek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23be48125bSWojciech Macek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24be48125bSWojciech Macek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25be48125bSWojciech Macek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26be48125bSWojciech Macek * SUCH DAMAGE.
27be48125bSWojciech Macek */
28be48125bSWojciech Macek
29be48125bSWojciech Macek #include <sys/param.h>
30be48125bSWojciech Macek #include <sys/systm.h>
31be48125bSWojciech Macek #include <sys/kernel.h>
32be48125bSWojciech Macek #include <sys/lock.h>
33be48125bSWojciech Macek #include <sys/malloc.h>
34be48125bSWojciech Macek #include <sys/module.h>
35be48125bSWojciech Macek #include <sys/mutex.h>
36be48125bSWojciech Macek #include <sys/bus.h>
37be48125bSWojciech Macek #include <sys/rman.h>
38be48125bSWojciech Macek #include <sys/vmem.h>
39be48125bSWojciech Macek
40be48125bSWojciech Macek #include <dev/ofw/ofw_bus.h>
41be48125bSWojciech Macek #include <dev/ofw/ofw_bus_subr.h>
42be48125bSWojciech Macek
43be48125bSWojciech Macek #include "msi_if.h"
44be48125bSWojciech Macek #include "pic_if.h"
45be48125bSWojciech Macek
46be48125bSWojciech Macek #define AL_SPI_INTR 0
47be48125bSWojciech Macek #define AL_EDGE_HIGH 1
48be48125bSWojciech Macek #define ERR_NOT_IN_MAP -1
49be48125bSWojciech Macek #define IRQ_OFFSET 1
50be48125bSWojciech Macek #define GIC_INTR_CELL_CNT 3
51be48125bSWojciech Macek #define INTR_RANGE_COUNT 2
52be48125bSWojciech Macek #define MAX_MSIX_COUNT 160
53be48125bSWojciech Macek
54be48125bSWojciech Macek static int al_msix_attach(device_t);
55be48125bSWojciech Macek static int al_msix_probe(device_t);
56be48125bSWojciech Macek
57be48125bSWojciech Macek static msi_alloc_msi_t al_msix_alloc_msi;
58be48125bSWojciech Macek static msi_release_msi_t al_msix_release_msi;
59be48125bSWojciech Macek static msi_alloc_msix_t al_msix_alloc_msix;
60be48125bSWojciech Macek static msi_release_msix_t al_msix_release_msix;
61be48125bSWojciech Macek static msi_map_msi_t al_msix_map_msi;
62be48125bSWojciech Macek
63be48125bSWojciech Macek static int al_find_intr_pos_in_map(device_t, struct intr_irqsrc *);
64be48125bSWojciech Macek
65be48125bSWojciech Macek static struct ofw_compat_data compat_data[] = {
66be48125bSWojciech Macek {"annapurna-labs,al-msix", true},
67be48125bSWojciech Macek {"annapurna-labs,alpine-msix", true},
68be48125bSWojciech Macek {NULL, false}
69be48125bSWojciech Macek };
70be48125bSWojciech Macek
71be48125bSWojciech Macek /*
72be48125bSWojciech Macek * Bus interface definitions.
73be48125bSWojciech Macek */
74be48125bSWojciech Macek static device_method_t al_msix_methods[] = {
75be48125bSWojciech Macek DEVMETHOD(device_probe, al_msix_probe),
76be48125bSWojciech Macek DEVMETHOD(device_attach, al_msix_attach),
77be48125bSWojciech Macek
78be48125bSWojciech Macek /* Interrupt controller interface */
79be48125bSWojciech Macek DEVMETHOD(msi_alloc_msi, al_msix_alloc_msi),
80be48125bSWojciech Macek DEVMETHOD(msi_release_msi, al_msix_release_msi),
81be48125bSWojciech Macek DEVMETHOD(msi_alloc_msix, al_msix_alloc_msix),
82be48125bSWojciech Macek DEVMETHOD(msi_release_msix, al_msix_release_msix),
83be48125bSWojciech Macek DEVMETHOD(msi_map_msi, al_msix_map_msi),
84be48125bSWojciech Macek
85be48125bSWojciech Macek DEVMETHOD_END
86be48125bSWojciech Macek };
87be48125bSWojciech Macek
88be48125bSWojciech Macek struct al_msix_softc {
89be48125bSWojciech Macek bus_addr_t base_addr;
90be48125bSWojciech Macek struct resource *res;
91be48125bSWojciech Macek uint32_t irq_min;
92be48125bSWojciech Macek uint32_t irq_max;
93be48125bSWojciech Macek uint32_t irq_count;
94be48125bSWojciech Macek struct mtx msi_mtx;
95be48125bSWojciech Macek vmem_t *irq_alloc;
96be48125bSWojciech Macek device_t gic_dev;
97be48125bSWojciech Macek /* Table of isrcs maps isrc pointer to vmem_alloc'd irq number */
98be48125bSWojciech Macek struct intr_irqsrc *isrcs[MAX_MSIX_COUNT];
99be48125bSWojciech Macek };
100be48125bSWojciech Macek
101be48125bSWojciech Macek static driver_t al_msix_driver = {
102be48125bSWojciech Macek "al_msix",
103be48125bSWojciech Macek al_msix_methods,
104be48125bSWojciech Macek sizeof(struct al_msix_softc),
105be48125bSWojciech Macek };
106be48125bSWojciech Macek
107b596f9b8SJohn Baldwin DRIVER_MODULE(al_msix, ofwbus, al_msix_driver, 0, 0);
108b596f9b8SJohn Baldwin DRIVER_MODULE(al_msix, simplebus, al_msix_driver, 0, 0);
109be48125bSWojciech Macek
110be48125bSWojciech Macek MALLOC_DECLARE(M_AL_MSIX);
111be48125bSWojciech Macek MALLOC_DEFINE(M_AL_MSIX, "al_msix", "Alpine MSIX");
112be48125bSWojciech Macek
113be48125bSWojciech Macek static int
al_msix_probe(device_t dev)114be48125bSWojciech Macek al_msix_probe(device_t dev)
115be48125bSWojciech Macek {
116be48125bSWojciech Macek
117be48125bSWojciech Macek if (!ofw_bus_status_okay(dev))
118be48125bSWojciech Macek return (ENXIO);
119be48125bSWojciech Macek
120be48125bSWojciech Macek if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
121be48125bSWojciech Macek return (ENXIO);
122be48125bSWojciech Macek
123be48125bSWojciech Macek device_set_desc(dev, "Annapurna-Labs MSI-X Controller");
124be48125bSWojciech Macek return (BUS_PROBE_DEFAULT);
125be48125bSWojciech Macek }
126be48125bSWojciech Macek
127be48125bSWojciech Macek static int
al_msix_attach(device_t dev)128be48125bSWojciech Macek al_msix_attach(device_t dev)
129be48125bSWojciech Macek {
130be48125bSWojciech Macek struct al_msix_softc *sc;
131be48125bSWojciech Macek device_t gic_dev;
132be48125bSWojciech Macek phandle_t iparent;
133be48125bSWojciech Macek phandle_t node;
134be48125bSWojciech Macek intptr_t xref;
135be48125bSWojciech Macek int interrupts[INTR_RANGE_COUNT];
136be48125bSWojciech Macek int nintr, i, rid;
137be48125bSWojciech Macek uint32_t icells, *intr;
138be48125bSWojciech Macek
139be48125bSWojciech Macek sc = device_get_softc(dev);
140be48125bSWojciech Macek
141be48125bSWojciech Macek node = ofw_bus_get_node(dev);
142be48125bSWojciech Macek xref = OF_xref_from_node(node);
143be48125bSWojciech Macek OF_device_register_xref(xref, dev);
144be48125bSWojciech Macek
145be48125bSWojciech Macek rid = 0;
146be48125bSWojciech Macek sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
147be48125bSWojciech Macek if (sc->res == NULL) {
148be48125bSWojciech Macek device_printf(dev, "Failed to allocate resource\n");
149be48125bSWojciech Macek return (ENXIO);
150be48125bSWojciech Macek }
151be48125bSWojciech Macek
152be48125bSWojciech Macek sc->base_addr = (bus_addr_t)rman_get_start(sc->res);
153be48125bSWojciech Macek
154be48125bSWojciech Macek /* Register this device to handle MSI interrupts */
155be48125bSWojciech Macek if (intr_msi_register(dev, xref) != 0) {
156be48125bSWojciech Macek device_printf(dev, "could not register MSI-X controller\n");
157be48125bSWojciech Macek return (ENXIO);
158be48125bSWojciech Macek }
159be48125bSWojciech Macek else
160be48125bSWojciech Macek device_printf(dev, "MSI-X controller registered\n");
161be48125bSWojciech Macek
162be48125bSWojciech Macek /* Find root interrupt controller */
163be48125bSWojciech Macek iparent = ofw_bus_find_iparent(node);
164be48125bSWojciech Macek if (iparent == 0) {
165be48125bSWojciech Macek device_printf(dev, "No interrupt-parrent found. "
166be48125bSWojciech Macek "Error in DTB\n");
167be48125bSWojciech Macek return (ENXIO);
168be48125bSWojciech Macek } else {
169be48125bSWojciech Macek /* While at parent - store interrupt cells prop */
170be48125bSWojciech Macek if (OF_searchencprop(OF_node_from_xref(iparent),
171be48125bSWojciech Macek "#interrupt-cells", &icells, sizeof(icells)) == -1) {
172be48125bSWojciech Macek device_printf(dev, "DTB: Missing #interrupt-cells "
173be48125bSWojciech Macek "property in GIC node\n");
174be48125bSWojciech Macek return (ENXIO);
175be48125bSWojciech Macek }
176be48125bSWojciech Macek }
177be48125bSWojciech Macek
178be48125bSWojciech Macek gic_dev = OF_device_from_xref(iparent);
179be48125bSWojciech Macek if (gic_dev == NULL) {
180be48125bSWojciech Macek device_printf(dev, "Cannot find GIC device\n");
181be48125bSWojciech Macek return (ENXIO);
182be48125bSWojciech Macek }
183be48125bSWojciech Macek sc->gic_dev = gic_dev;
184be48125bSWojciech Macek
185be48125bSWojciech Macek /* Manually read range of interrupts from DTB */
186f7604b1bSOleksandr Tymoshenko nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
187be48125bSWojciech Macek (void **)&intr);
188be48125bSWojciech Macek if (nintr == 0) {
189be48125bSWojciech Macek device_printf(dev, "Cannot read interrupts prop from DTB\n");
190be48125bSWojciech Macek return (ENXIO);
191be48125bSWojciech Macek } else if ((nintr / icells) != INTR_RANGE_COUNT) {
192be48125bSWojciech Macek /* Supposed to have min and max value only */
193be48125bSWojciech Macek device_printf(dev, "Unexpected count of interrupts "
194be48125bSWojciech Macek "in DTB node\n");
195be48125bSWojciech Macek return (EINVAL);
196be48125bSWojciech Macek }
197be48125bSWojciech Macek
198be48125bSWojciech Macek /* Read interrupt range values */
199be48125bSWojciech Macek for (i = 0; i < INTR_RANGE_COUNT; i++)
200be48125bSWojciech Macek interrupts[i] = intr[(i * icells) + IRQ_OFFSET];
201be48125bSWojciech Macek
202be48125bSWojciech Macek sc->irq_min = interrupts[0];
203be48125bSWojciech Macek sc->irq_max = interrupts[1];
204be48125bSWojciech Macek sc->irq_count = (sc->irq_max - sc->irq_min + 1);
205be48125bSWojciech Macek
206be48125bSWojciech Macek if (sc->irq_count > MAX_MSIX_COUNT) {
207be48125bSWojciech Macek device_printf(dev, "Available MSI-X count exceeds buffer size."
208be48125bSWojciech Macek " Capping to %d\n", MAX_MSIX_COUNT);
209be48125bSWojciech Macek sc->irq_count = MAX_MSIX_COUNT;
210be48125bSWojciech Macek }
211be48125bSWojciech Macek
212be48125bSWojciech Macek mtx_init(&sc->msi_mtx, "msi_mtx", NULL, MTX_DEF);
213be48125bSWojciech Macek
214be48125bSWojciech Macek sc->irq_alloc = vmem_create("Alpine MSI-X IRQs", 0, sc->irq_count,
215be48125bSWojciech Macek 1, 0, M_FIRSTFIT | M_WAITOK);
216be48125bSWojciech Macek
217be48125bSWojciech Macek device_printf(dev, "MSI-X SPI IRQ %d-%d\n", sc->irq_min, sc->irq_max);
218be48125bSWojciech Macek
219be48125bSWojciech Macek return (bus_generic_attach(dev));
220be48125bSWojciech Macek }
221be48125bSWojciech Macek
222be48125bSWojciech Macek static int
al_find_intr_pos_in_map(device_t dev,struct intr_irqsrc * isrc)223be48125bSWojciech Macek al_find_intr_pos_in_map(device_t dev, struct intr_irqsrc *isrc)
224be48125bSWojciech Macek {
225be48125bSWojciech Macek struct al_msix_softc *sc;
226be48125bSWojciech Macek int i;
227be48125bSWojciech Macek
228be48125bSWojciech Macek sc = device_get_softc(dev);
229be48125bSWojciech Macek for (i = 0; i < MAX_MSIX_COUNT; i++)
230be48125bSWojciech Macek if (sc->isrcs[i] == isrc)
231be48125bSWojciech Macek return (i);
232be48125bSWojciech Macek return (ERR_NOT_IN_MAP);
233be48125bSWojciech Macek }
234be48125bSWojciech Macek
235be48125bSWojciech Macek static int
al_msix_map_msi(device_t dev,device_t child,struct intr_irqsrc * isrc,uint64_t * addr,uint32_t * data)236be48125bSWojciech Macek al_msix_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
237be48125bSWojciech Macek uint64_t *addr, uint32_t *data)
238be48125bSWojciech Macek {
239be48125bSWojciech Macek struct al_msix_softc *sc;
240be48125bSWojciech Macek int i, spi;
241be48125bSWojciech Macek
242be48125bSWojciech Macek sc = device_get_softc(dev);
243be48125bSWojciech Macek
244be48125bSWojciech Macek i = al_find_intr_pos_in_map(dev, isrc);
245be48125bSWojciech Macek if (i == ERR_NOT_IN_MAP)
246be48125bSWojciech Macek return (EINVAL);
247be48125bSWojciech Macek
248be48125bSWojciech Macek spi = sc->irq_min + i;
249be48125bSWojciech Macek
250be48125bSWojciech Macek /*
251be48125bSWojciech Macek * MSIX message address format:
252be48125bSWojciech Macek * [63:20] - MSIx TBAR
253be48125bSWojciech Macek * Same value as the MSIx Translation Base Address Register
254be48125bSWojciech Macek * [19] - WFE_EXIT
255be48125bSWojciech Macek * Once set by MSIx message, an EVENTI is signal to the CPUs
256be48125bSWojciech Macek * cluster specified by ‘Local GIC Target List’
257be48125bSWojciech Macek * [18:17] - Target GIC ID
258be48125bSWojciech Macek * Specifies which IO-GIC (external shared GIC) is targeted
259be48125bSWojciech Macek * 0: Local GIC, as specified by the Local GIC Target List
260be48125bSWojciech Macek * 1: IO-GIC 0
261be48125bSWojciech Macek * 2: Reserved
262be48125bSWojciech Macek * 3: Reserved
263be48125bSWojciech Macek * [16:13] - Local GIC Target List
264be48125bSWojciech Macek * Specifies the Local GICs list targeted by this MSIx
265be48125bSWojciech Macek * message.
266be48125bSWojciech Macek * [16] If set, SPIn is set in Cluster 0 local GIC
267be48125bSWojciech Macek * [15:13] Reserved
268be48125bSWojciech Macek * [15] If set, SPIn is set in Cluster 1 local GIC
269be48125bSWojciech Macek * [14] If set, SPIn is set in Cluster 2 local GIC
270be48125bSWojciech Macek * [13] If set, SPIn is set in Cluster 3 local GIC
271be48125bSWojciech Macek * [12:3] - SPIn
272be48125bSWojciech Macek * Specifies the SPI (Shared Peripheral Interrupt) index to
273be48125bSWojciech Macek * be set in target GICs
274be48125bSWojciech Macek * Notes:
275be48125bSWojciech Macek * If targeting any local GIC than only SPI[249:0] are valid
276be48125bSWojciech Macek * [2] - Function vector
277be48125bSWojciech Macek * MSI Data vector extension hint
278be48125bSWojciech Macek * [1:0] - Reserved
279be48125bSWojciech Macek * Must be set to zero
280be48125bSWojciech Macek */
281be48125bSWojciech Macek *addr = (uint64_t)sc->base_addr + (uint64_t)((1 << 16) + (spi << 3));
282be48125bSWojciech Macek *data = 0;
283be48125bSWojciech Macek
284be48125bSWojciech Macek if (bootverbose)
285be48125bSWojciech Macek device_printf(dev, "MSI mapping: SPI: %d addr: %jx data: %x\n",
286be48125bSWojciech Macek spi, (uintmax_t)*addr, *data);
287be48125bSWojciech Macek return (0);
288be48125bSWojciech Macek }
289be48125bSWojciech Macek
290be48125bSWojciech Macek static int
al_msix_alloc_msi(device_t dev,device_t child,int count,int maxcount,device_t * pic,struct intr_irqsrc ** srcs)291be48125bSWojciech Macek al_msix_alloc_msi(device_t dev, device_t child, int count, int maxcount,
292be48125bSWojciech Macek device_t *pic, struct intr_irqsrc **srcs)
293be48125bSWojciech Macek {
294be48125bSWojciech Macek struct intr_map_data_fdt *fdt_data;
295be48125bSWojciech Macek struct al_msix_softc *sc;
296be48125bSWojciech Macek vmem_addr_t irq_base;
297be48125bSWojciech Macek int error;
298be48125bSWojciech Macek u_int i, j;
299be48125bSWojciech Macek
300be48125bSWojciech Macek sc = device_get_softc(dev);
301be48125bSWojciech Macek
302be48125bSWojciech Macek if ((powerof2(count) == 0) || (count > 8))
303be48125bSWojciech Macek return (EINVAL);
304be48125bSWojciech Macek
305be48125bSWojciech Macek if (vmem_alloc(sc->irq_alloc, count, M_FIRSTFIT | M_NOWAIT,
306be48125bSWojciech Macek &irq_base) != 0)
307be48125bSWojciech Macek return (ENOMEM);
308be48125bSWojciech Macek
309be48125bSWojciech Macek /* Fabricate OFW data to get ISRC from GIC and return it */
310be48125bSWojciech Macek fdt_data = malloc(sizeof(*fdt_data) +
311be48125bSWojciech Macek GIC_INTR_CELL_CNT * sizeof(pcell_t), M_AL_MSIX, M_WAITOK);
312be48125bSWojciech Macek fdt_data->hdr.type = INTR_MAP_DATA_FDT;
313be48125bSWojciech Macek fdt_data->iparent = 0;
314be48125bSWojciech Macek fdt_data->ncells = GIC_INTR_CELL_CNT;
315be48125bSWojciech Macek fdt_data->cells[0] = AL_SPI_INTR; /* code for SPI interrupt */
316be48125bSWojciech Macek fdt_data->cells[1] = 0; /* SPI number (uninitialized) */
317be48125bSWojciech Macek fdt_data->cells[2] = AL_EDGE_HIGH; /* trig = edge, pol = high */
318be48125bSWojciech Macek
319be48125bSWojciech Macek mtx_lock(&sc->msi_mtx);
320be48125bSWojciech Macek
321be48125bSWojciech Macek for (i = irq_base; i < irq_base + count; i++) {
322be48125bSWojciech Macek fdt_data->cells[1] = sc->irq_min + i;
323be48125bSWojciech Macek error = PIC_MAP_INTR(sc->gic_dev,
324be48125bSWojciech Macek (struct intr_map_data *)fdt_data, srcs);
325be48125bSWojciech Macek if (error) {
326be48125bSWojciech Macek for (j = irq_base; j < i; j++)
327be48125bSWojciech Macek sc->isrcs[j] = NULL;
328be48125bSWojciech Macek mtx_unlock(&sc->msi_mtx);
329be48125bSWojciech Macek vmem_free(sc->irq_alloc, irq_base, count);
330be48125bSWojciech Macek free(fdt_data, M_AL_MSIX);
331be48125bSWojciech Macek return (error);
332be48125bSWojciech Macek }
333be48125bSWojciech Macek
334be48125bSWojciech Macek sc->isrcs[i] = *srcs;
335be48125bSWojciech Macek srcs++;
336be48125bSWojciech Macek }
337be48125bSWojciech Macek
338be48125bSWojciech Macek mtx_unlock(&sc->msi_mtx);
339be48125bSWojciech Macek free(fdt_data, M_AL_MSIX);
340be48125bSWojciech Macek
341be48125bSWojciech Macek if (bootverbose)
342be48125bSWojciech Macek device_printf(dev,
343be48125bSWojciech Macek "MSI-X allocation: start SPI %d, count %d\n",
344be48125bSWojciech Macek (int)irq_base + sc->irq_min, count);
345be48125bSWojciech Macek
346be48125bSWojciech Macek *pic = sc->gic_dev;
347be48125bSWojciech Macek
348be48125bSWojciech Macek return (0);
349be48125bSWojciech Macek }
350be48125bSWojciech Macek
351be48125bSWojciech Macek static int
al_msix_release_msi(device_t dev,device_t child,int count,struct intr_irqsrc ** srcs)352be48125bSWojciech Macek al_msix_release_msi(device_t dev, device_t child, int count,
353be48125bSWojciech Macek struct intr_irqsrc **srcs)
354be48125bSWojciech Macek {
355be48125bSWojciech Macek struct al_msix_softc *sc;
356be48125bSWojciech Macek int i, pos;
357be48125bSWojciech Macek
358be48125bSWojciech Macek sc = device_get_softc(dev);
359be48125bSWojciech Macek
360be48125bSWojciech Macek mtx_lock(&sc->msi_mtx);
361be48125bSWojciech Macek
362be48125bSWojciech Macek pos = al_find_intr_pos_in_map(dev, *srcs);
363be48125bSWojciech Macek vmem_free(sc->irq_alloc, pos, count);
364be48125bSWojciech Macek for (i = 0; i < count; i++) {
365be48125bSWojciech Macek pos = al_find_intr_pos_in_map(dev, *srcs);
366be48125bSWojciech Macek if (pos != ERR_NOT_IN_MAP)
367be48125bSWojciech Macek sc->isrcs[pos] = NULL;
368be48125bSWojciech Macek srcs++;
369be48125bSWojciech Macek }
370be48125bSWojciech Macek
371be48125bSWojciech Macek mtx_unlock(&sc->msi_mtx);
372be48125bSWojciech Macek
373be48125bSWojciech Macek return (0);
374be48125bSWojciech Macek }
375be48125bSWojciech Macek
376be48125bSWojciech Macek static int
al_msix_alloc_msix(device_t dev,device_t child,device_t * pic,struct intr_irqsrc ** isrcp)377be48125bSWojciech Macek al_msix_alloc_msix(device_t dev, device_t child, device_t *pic,
378be48125bSWojciech Macek struct intr_irqsrc **isrcp)
379be48125bSWojciech Macek {
380be48125bSWojciech Macek
381be48125bSWojciech Macek return (al_msix_alloc_msi(dev, child, 1, 1, pic, isrcp));
382be48125bSWojciech Macek }
383be48125bSWojciech Macek
384be48125bSWojciech Macek static int
al_msix_release_msix(device_t dev,device_t child,struct intr_irqsrc * isrc)385be48125bSWojciech Macek al_msix_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc)
386be48125bSWojciech Macek {
387be48125bSWojciech Macek
388be48125bSWojciech Macek return (al_msix_release_msi(dev, child, 1, &isrc));
389be48125bSWojciech Macek }
390