xref: /freebsd/sys/dev/xilinx/xlnx_pcib.c (revision cb7aa33ac6cd46a5434798e50363136e64f3ae98)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Ruslan Bukin <br@bsdpad.com>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory (Department of Computer Science and
8  * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
9  * DARPA SSITH research programme.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include "opt_platform.h"
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/types.h>
42 #include <sys/sysctl.h>
43 #include <sys/kernel.h>
44 #include <sys/rman.h>
45 #include <sys/module.h>
46 #include <sys/bus.h>
47 #include <sys/endian.h>
48 #include <sys/cpuset.h>
49 #include <sys/mutex.h>
50 #include <sys/proc.h>
51 
52 #include <machine/intr.h>
53 #include <machine/bus.h>
54 
55 #include <vm/vm.h>
56 #include <vm/vm_extern.h>
57 #include <vm/vm_kern.h>
58 #include <vm/pmap.h>
59 
60 #include <dev/ofw/openfirm.h>
61 #include <dev/ofw/ofw_bus.h>
62 #include <dev/ofw/ofw_bus_subr.h>
63 
64 #include <dev/pci/pcireg.h>
65 #include <dev/pci/pcivar.h>
66 #include <dev/pci/pci_host_generic.h>
67 #include <dev/pci/pci_host_generic_fdt.h>
68 #include <dev/pci/pcib_private.h>
69 
70 #include "xlnx_pcib.h"
71 
72 #include "ofw_bus_if.h"
73 #include "msi_if.h"
74 #include "pcib_if.h"
75 #include "pic_if.h"
76 
77 #define	XLNX_PCIB_MAX_MSI	64
78 
79 static int xlnx_pcib_fdt_attach(device_t);
80 static int xlnx_pcib_fdt_probe(device_t);
81 static int xlnx_pcib_fdt_get_id(device_t, device_t, enum pci_id_type,
82     uintptr_t *);
83 static void xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc,
84     bool mask);
85 
86 struct xlnx_pcib_softc {
87 	struct generic_pcie_fdt_softc	fdt_sc;
88 	struct resource			*res[4];
89 	struct mtx			mtx;
90 	vm_offset_t			msi_page;
91 	struct xlnx_pcib_irqsrc		*isrcs;
92 	device_t			dev;
93 	void				*intr_cookie[3];
94 };
95 
96 static struct resource_spec xlnx_pcib_spec[] = {
97 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
98 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
99 	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
100 	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
101 	{ -1, 0 }
102 };
103 
104 struct xlnx_pcib_irqsrc {
105 	struct intr_irqsrc	isrc;
106 	u_int			irq;
107 #define	XLNX_IRQ_FLAG_USED	(1 << 0)
108 	u_int			flags;
109 };
110 
111 static void
112 xlnx_pcib_clear_err_interrupts(struct generic_pcie_core_softc *sc)
113 {
114 	uint32_t reg;
115 
116 	reg = bus_read_4(sc->res, XLNX_PCIE_RPERRFRR);
117 
118 	if (reg & RPERRFRR_VALID) {
119 		device_printf(sc->dev, "Requested ID: %x\n",
120 		    reg & RPERRFRR_REQ_ID_M);
121 		bus_write_4(sc->res, XLNX_PCIE_RPERRFRR, ~0U);
122 	}
123 }
124 
125 static int
126 xlnx_pcib_intr(void *arg)
127 {
128 	struct generic_pcie_fdt_softc *fdt_sc;
129 	struct generic_pcie_core_softc *sc;
130 	struct xlnx_pcib_softc *xlnx_sc;
131 	uint32_t val, mask, status;
132 
133 	xlnx_sc = arg;
134 	fdt_sc = &xlnx_sc->fdt_sc;
135 	sc = &fdt_sc->base;
136 
137 	val = bus_read_4(sc->res, XLNX_PCIE_IDR);
138 	mask = bus_read_4(sc->res, XLNX_PCIE_IMR);
139 
140 	status = val & mask;
141 	if (!status)
142 		return (FILTER_HANDLED);
143 
144 	if (status & IMR_LINK_DOWN)
145 		device_printf(sc->dev, "Link down");
146 
147 	if (status & IMR_HOT_RESET)
148 		device_printf(sc->dev, "Hot reset");
149 
150 	if (status & IMR_CORRECTABLE)
151 		xlnx_pcib_clear_err_interrupts(sc);
152 
153 	if (status & IMR_FATAL)
154 		xlnx_pcib_clear_err_interrupts(sc);
155 
156 	if (status & IMR_NON_FATAL)
157 		xlnx_pcib_clear_err_interrupts(sc);
158 
159 	if (status & IMR_MSI) {
160 		device_printf(sc->dev, "MSI interrupt");
161 
162 		/* FIFO mode MSI not implemented. */
163 	}
164 
165 	if (status & IMR_INTX) {
166 		device_printf(sc->dev, "INTx received");
167 
168 		/* Not implemented. */
169 	}
170 
171 	if (status & IMR_SLAVE_UNSUPP_REQ)
172 		device_printf(sc->dev, "Slave unsupported request");
173 
174 	if (status & IMR_SLAVE_UNEXP_COMPL)
175 		device_printf(sc->dev, "Slave unexpected completion");
176 
177 	if (status & IMR_SLAVE_COMPL_TIMOUT)
178 		device_printf(sc->dev, "Slave completion timeout");
179 
180 	if (status & IMR_SLAVE_ERROR_POISON)
181 		device_printf(sc->dev, "Slave error poison");
182 
183 	if (status & IMR_SLAVE_COMPL_ABORT)
184 		device_printf(sc->dev, "Slave completion abort");
185 
186 	if (status & IMR_SLAVE_ILLEG_BURST)
187 		device_printf(sc->dev, "Slave illegal burst");
188 
189 	if (status & IMR_MASTER_DECERR)
190 		device_printf(sc->dev, "Master decode error");
191 
192 	if (status & IMR_MASTER_SLVERR)
193 		device_printf(sc->dev, "Master slave error");
194 
195 	bus_write_4(sc->res, XLNX_PCIE_IDR, val);
196 
197 	return (FILTER_HANDLED);
198 }
199 
200 static void
201 xlnx_pcib_handle_msi_intr(void *arg, int msireg)
202 {
203 	struct generic_pcie_fdt_softc *fdt_sc;
204 	struct generic_pcie_core_softc *sc;
205 	struct xlnx_pcib_softc *xlnx_sc;
206 	struct xlnx_pcib_irqsrc *xi;
207 	struct trapframe *tf;
208 	int irq;
209 	int reg;
210 	int i;
211 
212 	xlnx_sc = arg;
213 	fdt_sc = &xlnx_sc->fdt_sc;
214 	sc = &fdt_sc->base;
215 	tf = curthread->td_intr_frame;
216 
217 	do {
218 		reg = bus_read_4(sc->res, msireg);
219 
220 		for (i = 0; i < sizeof(uint32_t) * 8; i++) {
221 			if (reg & (1 << i)) {
222 				bus_write_4(sc->res, msireg, (1 << i));
223 
224 				irq = i;
225 				if (msireg == XLNX_PCIE_RPMSIID2)
226 					irq += 32;
227 
228 				xi = &xlnx_sc->isrcs[irq];
229 				if (intr_isrc_dispatch(&xi->isrc, tf) != 0) {
230 					/* Disable stray. */
231 					xlnx_pcib_msi_mask(sc->dev,
232 					    &xi->isrc, 1);
233 					device_printf(sc->dev,
234 					    "Stray irq %u disabled\n", irq);
235 				}
236 			}
237 		}
238 	} while (reg != 0);
239 }
240 
241 static int
242 xlnx_pcib_msi0_intr(void *arg)
243 {
244 
245 	xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID1);
246 
247 	return (FILTER_HANDLED);
248 }
249 
250 static int
251 xlnx_pcib_msi1_intr(void *arg)
252 {
253 
254 	xlnx_pcib_handle_msi_intr(arg, XLNX_PCIE_RPMSIID2);
255 
256 	return (FILTER_HANDLED);
257 }
258 
259 static int
260 xlnx_pcib_register_msi(struct xlnx_pcib_softc *sc)
261 {
262 	const char *name;
263 	int error;
264 	int irq;
265 
266 	sc->isrcs = malloc(sizeof(*sc->isrcs) * XLNX_PCIB_MAX_MSI, M_DEVBUF,
267 	    M_WAITOK | M_ZERO);
268 
269 	name = device_get_nameunit(sc->dev);
270 
271 	for (irq = 0; irq < XLNX_PCIB_MAX_MSI; irq++) {
272 		sc->isrcs[irq].irq = irq;
273 		error = intr_isrc_register(&sc->isrcs[irq].isrc,
274 		    sc->dev, 0, "%s,%u", name, irq);
275 		if (error != 0)
276 			return (error); /* XXX deregister ISRCs */
277 	}
278 
279 	if (intr_msi_register(sc->dev,
280 	    OF_xref_from_node(ofw_bus_get_node(sc->dev))) != 0)
281 		return (ENXIO);
282 
283 	return (0);
284 }
285 
286 static void
287 xlnx_pcib_init(struct xlnx_pcib_softc *sc)
288 {
289 	bus_addr_t addr;
290 	int reg;
291 
292 	/* Disable interrupts. */
293 	bus_write_4(sc->res[0], XLNX_PCIE_IMR, 0);
294 
295 	/* Clear pending interrupts.*/
296 	reg = bus_read_4(sc->res[0], XLNX_PCIE_IDR);
297 	bus_write_4(sc->res[0], XLNX_PCIE_IDR, reg);
298 
299 	/* Setup an MSI page. */
300 	sc->msi_page = kmem_alloc_contig(PAGE_SIZE, M_WAITOK, 0,
301 	    BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
302 	addr = vtophys(sc->msi_page);
303 	bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR1, (addr >> 32));
304 	bus_write_4(sc->res[0], XLNX_PCIE_RPMSIBR2, (addr >>  0));
305 
306 	/* Enable the bridge. */
307 	reg = bus_read_4(sc->res[0], XLNX_PCIE_RPSCR);
308 	reg |= RPSCR_BE;
309 	bus_write_4(sc->res[0], XLNX_PCIE_RPSCR, reg);
310 
311 	/* Enable interrupts. */
312 	reg = IMR_LINK_DOWN
313 		| IMR_HOT_RESET
314 		| IMR_CFG_COMPL_STATUS_M
315 		| IMR_CFG_TIMEOUT
316 		| IMR_CORRECTABLE
317 		| IMR_NON_FATAL
318 		| IMR_FATAL
319 		| IMR_INTX
320 		| IMR_MSI
321 		| IMR_SLAVE_UNSUPP_REQ
322 		| IMR_SLAVE_UNEXP_COMPL
323 		| IMR_SLAVE_COMPL_TIMOUT
324 		| IMR_SLAVE_ERROR_POISON
325 		| IMR_SLAVE_COMPL_ABORT
326 		| IMR_SLAVE_ILLEG_BURST
327 		| IMR_MASTER_DECERR
328 		| IMR_MASTER_SLVERR;
329 	bus_write_4(sc->res[0], XLNX_PCIE_IMR, reg);
330 }
331 
332 static int
333 xlnx_pcib_fdt_probe(device_t dev)
334 {
335 
336 	if (!ofw_bus_status_okay(dev))
337 		return (ENXIO);
338 
339 	if (ofw_bus_is_compatible(dev, "xlnx,xdma-host-3.00")) {
340 		device_set_desc(dev, "Xilinx XDMA PCIe Controller");
341 		return (BUS_PROBE_DEFAULT);
342 	}
343 
344 	return (ENXIO);
345 }
346 
347 static int
348 xlnx_pcib_fdt_attach(device_t dev)
349 {
350 	struct xlnx_pcib_softc *sc;
351 	int error;
352 
353 	sc = device_get_softc(dev);
354 	sc->dev = dev;
355 
356 	mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF);
357 
358 	if (bus_alloc_resources(dev, xlnx_pcib_spec, sc->res)) {
359 		device_printf(dev, "could not allocate resources\n");
360 		return (ENXIO);
361 	}
362 
363 	/* Setup MISC interrupt handler. */
364 	error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
365 	    xlnx_pcib_intr, NULL, sc, &sc->intr_cookie[0]);
366 	if (error != 0) {
367 		device_printf(dev, "could not setup interrupt handler.\n");
368 		return (ENXIO);
369 	}
370 
371 	/* Setup MSI0 interrupt handler. */
372 	error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE,
373 	    xlnx_pcib_msi0_intr, NULL, sc, &sc->intr_cookie[1]);
374 	if (error != 0) {
375 		device_printf(dev, "could not setup interrupt handler.\n");
376 		return (ENXIO);
377 	}
378 
379 	/* Setup MSI1 interrupt handler. */
380 	error = bus_setup_intr(dev, sc->res[3], INTR_TYPE_MISC | INTR_MPSAFE,
381 	    xlnx_pcib_msi1_intr, NULL, sc, &sc->intr_cookie[2]);
382 	if (error != 0) {
383 		device_printf(dev, "could not setup interrupt handler.\n");
384 		return (ENXIO);
385 	}
386 
387 	xlnx_pcib_init(sc);
388 
389 	/*
390 	 * Allow the core driver to map registers.
391 	 * We will be accessing the device memory using core_softc.
392 	 */
393 	bus_release_resources(dev, xlnx_pcib_spec, sc->res);
394 
395 	error = xlnx_pcib_register_msi(sc);
396 	if (error)
397 		return (error);
398 
399 	return (pci_host_generic_fdt_attach(dev));
400 }
401 
402 static int
403 xlnx_pcib_fdt_get_id(device_t pci, device_t child, enum pci_id_type type,
404     uintptr_t *id)
405 {
406 	phandle_t node;
407 	int bsf;
408 
409 	if (type != PCI_ID_MSI)
410 		return (pcib_get_id(pci, child, type, id));
411 
412 	node = ofw_bus_get_node(pci);
413 	if (OF_hasprop(node, "msi-map"))
414 		return (generic_pcie_get_id(pci, child, type, id));
415 
416 	bsf = pci_get_rid(child);
417 	*id = (pci_get_domain(child) << PCI_RID_DOMAIN_SHIFT) | bsf;
418 
419 	return (0);
420 }
421 
422 static int
423 xlnx_pcib_req_valid(struct generic_pcie_core_softc *sc,
424     u_int bus, u_int slot, u_int func, u_int reg)
425 {
426 	bus_space_handle_t h;
427 	bus_space_tag_t t;
428 	uint32_t val;
429 
430 	t = sc->bst;
431 	h = sc->bsh;
432 
433 	if ((bus < sc->bus_start) || (bus > sc->bus_end))
434 		return (0);
435 	if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) ||
436 	    (reg > PCIE_REGMAX))
437 		return (0);
438 
439 	if (bus == 0 && slot > 0)
440 		return (0);
441 
442 	val = bus_space_read_4(t, h, XLNX_PCIE_PHYSCR);
443 	if ((val & PHYSCR_LINK_UP) == 0) {
444 		/* Link is down */
445 		return (0);
446 	}
447 
448 	/* Valid */
449 
450 	return (1);
451 }
452 
453 static uint32_t
454 xlnx_pcib_read_config(device_t dev, u_int bus, u_int slot,
455     u_int func, u_int reg, int bytes)
456 {
457 	struct generic_pcie_fdt_softc *fdt_sc;
458 	struct xlnx_pcib_softc *xlnx_sc;
459 	struct generic_pcie_core_softc *sc;
460 	bus_space_handle_t h;
461 	bus_space_tag_t t;
462 	uint64_t offset;
463 	uint32_t data;
464 
465 	xlnx_sc = device_get_softc(dev);
466 	fdt_sc = &xlnx_sc->fdt_sc;
467 	sc = &fdt_sc->base;
468 
469 	if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg))
470 		return (~0U);
471 
472 	offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
473 	t = sc->bst;
474 	h = sc->bsh;
475 
476 	data = bus_space_read_4(t, h, offset & ~3);
477 
478 	switch (bytes) {
479 	case 1:
480 		data >>= (offset & 3) * 8;
481 		data &= 0xff;
482 		break;
483 	case 2:
484 		data >>= (offset & 3) * 8;
485 		data = le16toh(data);
486 		break;
487 	case 4:
488 		data = le32toh(data);
489 		break;
490 	default:
491 		return (~0U);
492 	}
493 
494 	return (data);
495 }
496 
497 static void
498 xlnx_pcib_write_config(device_t dev, u_int bus, u_int slot,
499     u_int func, u_int reg, uint32_t val, int bytes)
500 {
501 	struct generic_pcie_fdt_softc *fdt_sc;
502 	struct xlnx_pcib_softc *xlnx_sc;
503 	struct generic_pcie_core_softc *sc;
504 	bus_space_handle_t h;
505 	bus_space_tag_t t;
506 	uint64_t offset;
507 	uint32_t data;
508 
509 	xlnx_sc = device_get_softc(dev);
510 	fdt_sc = &xlnx_sc->fdt_sc;
511 	sc = &fdt_sc->base;
512 
513 	if (!xlnx_pcib_req_valid(sc, bus, slot, func, reg))
514 		return;
515 
516 	offset = PCIE_ADDR_OFFSET(bus - sc->bus_start, slot, func, reg);
517 
518 	t = sc->bst;
519 	h = sc->bsh;
520 
521 	/*
522 	 * 32-bit access used due to a bug in the Xilinx bridge that
523 	 * requires to write primary and secondary buses in one blast.
524 	 *
525 	 * TODO: This is probably wrong on big-endian.
526 	 */
527 	switch (bytes) {
528 	case 1:
529 		data = bus_space_read_4(t, h, offset & ~3);
530 		data &= ~(0xff << ((offset & 3) * 8));
531 		data |= (val & 0xff) << ((offset & 3) * 8);
532 		bus_space_write_4(t, h, offset & ~3, htole32(data));
533 		break;
534 	case 2:
535 		data = bus_space_read_4(t, h, offset & ~3);
536 		data &= ~(0xffff << ((offset & 3) * 8));
537 		data |= (val & 0xffff) << ((offset & 3) * 8);
538 		bus_space_write_4(t, h, offset & ~3, htole32(data));
539 		break;
540 	case 4:
541 		bus_space_write_4(t, h, offset, htole32(val));
542 		break;
543 	default:
544 		return;
545 	}
546 }
547 
548 static int
549 xlnx_pcib_alloc_msi(device_t pci, device_t child, int count, int maxcount,
550     int *irqs)
551 {
552 	phandle_t msi_parent;
553 
554 	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
555 	    NULL);
556 	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
557 	return (intr_alloc_msi(pci, child, msi_parent, count, maxcount,
558 	    irqs));
559 }
560 
561 static int
562 xlnx_pcib_release_msi(device_t pci, device_t child, int count, int *irqs)
563 {
564 	phandle_t msi_parent;
565 
566 	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
567 	    NULL);
568 	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
569 	return (intr_release_msi(pci, child, msi_parent, count, irqs));
570 }
571 
572 static int
573 xlnx_pcib_map_msi(device_t pci, device_t child, int irq, uint64_t *addr,
574     uint32_t *data)
575 {
576 	phandle_t msi_parent;
577 
578 	ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), &msi_parent,
579 	    NULL);
580 	msi_parent = OF_xref_from_node(ofw_bus_get_node(pci));
581 	return (intr_map_msi(pci, child, msi_parent, irq, addr, data));
582 }
583 
584 static int
585 xlnx_pcib_msi_alloc_msi(device_t dev, device_t child, int count, int maxcount,
586     device_t *pic, struct intr_irqsrc **srcs)
587 {
588 	struct xlnx_pcib_softc *sc;
589 	int irq, end_irq, i;
590 	bool found;
591 
592 	sc = device_get_softc(dev);
593 
594 	mtx_lock(&sc->mtx);
595 
596 	found = false;
597 
598 	for (irq = 0; (irq + count - 1) < XLNX_PCIB_MAX_MSI; irq++) {
599 		/* Assume the range is valid. */
600 		found = true;
601 
602 		/* Check this range is valid. */
603 		for (end_irq = irq; end_irq < irq + count; end_irq++) {
604 			if (sc->isrcs[end_irq].flags & XLNX_IRQ_FLAG_USED) {
605 				/* This is already used. */
606 				found = false;
607 				break;
608 			}
609 		}
610 
611 		if (found)
612 			break;
613 	}
614 
615 	if (!found || irq == (XLNX_PCIB_MAX_MSI - 1)) {
616 		/* Not enough interrupts were found. */
617 		mtx_unlock(&sc->mtx);
618 		return (ENXIO);
619 	}
620 
621 	/* Mark the interrupt as used. */
622 	for (i = 0; i < count; i++)
623 		sc->isrcs[irq + i].flags |= XLNX_IRQ_FLAG_USED;
624 
625 	mtx_unlock(&sc->mtx);
626 
627 	for (i = 0; i < count; i++)
628 		srcs[i] = (struct intr_irqsrc *)&sc->isrcs[irq + i];
629 
630 	*pic = device_get_parent(dev);
631 
632 	return (0);
633 }
634 
635 static int
636 xlnx_pcib_msi_release_msi(device_t dev, device_t child, int count,
637     struct intr_irqsrc **isrc)
638 {
639 	struct xlnx_pcib_softc *sc;
640 	struct xlnx_pcib_irqsrc *xi;
641 	int i;
642 
643 	sc = device_get_softc(dev);
644 	mtx_lock(&sc->mtx);
645 	for (i = 0; i < count; i++) {
646 		xi = (struct xlnx_pcib_irqsrc *)isrc[i];
647 
648 		KASSERT(xi->flags & XLNX_IRQ_FLAG_USED,
649 		    ("%s: Releasing an unused MSI interrupt", __func__));
650 
651 		xi->flags &= ~XLNX_IRQ_FLAG_USED;
652 	}
653 
654 	mtx_unlock(&sc->mtx);
655 	return (0);
656 }
657 
658 static int
659 xlnx_pcib_msi_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
660     uint64_t *addr, uint32_t *data)
661 {
662 	struct xlnx_pcib_softc *sc;
663 	struct xlnx_pcib_irqsrc *xi;
664 
665 	sc = device_get_softc(dev);
666 	xi = (struct xlnx_pcib_irqsrc *)isrc;
667 
668 	*addr = vtophys(sc->msi_page);
669 	*data = xi->irq;
670 
671 	return (0);
672 }
673 
674 static void
675 xlnx_pcib_msi_mask(device_t dev, struct intr_irqsrc *isrc, bool mask)
676 {
677 	struct generic_pcie_fdt_softc *fdt_sc;
678 	struct generic_pcie_core_softc *sc;
679 	struct xlnx_pcib_softc *xlnx_sc;
680 	struct xlnx_pcib_irqsrc *xi;
681 	uint32_t msireg, irq;
682 	uint32_t reg;
683 
684 	xlnx_sc = device_get_softc(dev);
685 	fdt_sc = &xlnx_sc->fdt_sc;
686 	sc = &fdt_sc->base;
687 
688 	xi = (struct xlnx_pcib_irqsrc *)isrc;
689 
690 	irq = xi->irq;
691 	if (irq < 32)
692 		msireg = XLNX_PCIE_RPMSIID1_MASK;
693 	else
694 		msireg = XLNX_PCIE_RPMSIID2_MASK;
695 
696 	reg = bus_read_4(sc->res, msireg);
697 	if (mask)
698 		reg &= ~(1 << irq);
699 	else
700 		reg |= (1 << irq);
701 	bus_write_4(sc->res, msireg, reg);
702 }
703 
704 static void
705 xlnx_pcib_msi_disable_intr(device_t dev, struct intr_irqsrc *isrc)
706 {
707 
708 	xlnx_pcib_msi_mask(dev, isrc, true);
709 }
710 
711 static void
712 xlnx_pcib_msi_enable_intr(device_t dev, struct intr_irqsrc *isrc)
713 {
714 
715 	xlnx_pcib_msi_mask(dev, isrc, false);
716 }
717 
718 static void
719 xlnx_pcib_msi_post_filter(device_t dev, struct intr_irqsrc *isrc)
720 {
721 
722 }
723 
724 static void
725 xlnx_pcib_msi_post_ithread(device_t dev, struct intr_irqsrc *isrc)
726 {
727 
728 	xlnx_pcib_msi_mask(dev, isrc, false);
729 }
730 
731 static void
732 xlnx_pcib_msi_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
733 {
734 
735 	xlnx_pcib_msi_mask(dev, isrc, true);
736 }
737 
738 static int
739 xlnx_pcib_msi_setup_intr(device_t dev, struct intr_irqsrc *isrc,
740     struct resource *res, struct intr_map_data *data)
741 {
742 
743 	return (0);
744 }
745 
746 static int
747 xlnx_pcib_msi_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
748     struct resource *res, struct intr_map_data *data)
749 {
750 
751 	return (0);
752 }
753 
754 static device_method_t xlnx_pcib_fdt_methods[] = {
755 	/* Device interface */
756 	DEVMETHOD(device_probe,		xlnx_pcib_fdt_probe),
757 	DEVMETHOD(device_attach,	xlnx_pcib_fdt_attach),
758 
759 	/* pcib interface */
760 	DEVMETHOD(pcib_get_id,		xlnx_pcib_fdt_get_id),
761 	DEVMETHOD(pcib_read_config,	xlnx_pcib_read_config),
762 	DEVMETHOD(pcib_write_config,	xlnx_pcib_write_config),
763 	DEVMETHOD(pcib_alloc_msi,	xlnx_pcib_alloc_msi),
764 	DEVMETHOD(pcib_release_msi,	xlnx_pcib_release_msi),
765 	DEVMETHOD(pcib_map_msi,		xlnx_pcib_map_msi),
766 
767 	/* MSI interface */
768 	DEVMETHOD(msi_alloc_msi,		xlnx_pcib_msi_alloc_msi),
769 	DEVMETHOD(msi_release_msi,		xlnx_pcib_msi_release_msi),
770 	DEVMETHOD(msi_map_msi,			xlnx_pcib_msi_map_msi),
771 
772 	/* Interrupt controller interface */
773 	DEVMETHOD(pic_disable_intr,		xlnx_pcib_msi_disable_intr),
774 	DEVMETHOD(pic_enable_intr,		xlnx_pcib_msi_enable_intr),
775 	DEVMETHOD(pic_setup_intr,		xlnx_pcib_msi_setup_intr),
776 	DEVMETHOD(pic_teardown_intr,		xlnx_pcib_msi_teardown_intr),
777 	DEVMETHOD(pic_post_filter,		xlnx_pcib_msi_post_filter),
778 	DEVMETHOD(pic_post_ithread,		xlnx_pcib_msi_post_ithread),
779 	DEVMETHOD(pic_pre_ithread,		xlnx_pcib_msi_pre_ithread),
780 
781 	/* End */
782 	DEVMETHOD_END
783 };
784 
785 DEFINE_CLASS_1(pcib, xlnx_pcib_fdt_driver, xlnx_pcib_fdt_methods,
786     sizeof(struct xlnx_pcib_softc), generic_pcie_fdt_driver);
787 
788 DRIVER_MODULE(xlnx_pcib, simplebus, xlnx_pcib_fdt_driver, 0, 0);
789 DRIVER_MODULE(xlnx_pcib, ofwbus, xlnx_pcib_fdt_driver, 0, 0);
790