pci_host_generic.c revision 292215
1284317Sbr/*-
2284317Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3284317Sbr * Copyright (c) 2014 The FreeBSD Foundation
4284317Sbr * All rights reserved.
5284317Sbr *
6284317Sbr * This software was developed by Semihalf under
7284317Sbr * the sponsorship of the FreeBSD Foundation.
8284317Sbr *
9284317Sbr * Redistribution and use in source and binary forms, with or without
10284317Sbr * modification, are permitted provided that the following conditions
11284317Sbr * are met:
12284317Sbr * 1. Redistributions of source code must retain the above copyright
13284317Sbr * notice, this list of conditions and the following disclaimer.
14284317Sbr * 2. Redistributions in binary form must reproduce the above copyright
15284317Sbr * notice, this list of conditions and the following disclaimer in the
16284317Sbr * documentation and/or other materials provided with the distribution.
17284317Sbr *
18284317Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19284317Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20284317Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21284317Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22284317Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23284317Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24284317Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25284317Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26284317Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27284317Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28284317Sbr * SUCH DAMAGE.
29284317Sbr */
30284317Sbr
31284317Sbr/* Generic ECAM PCIe driver */
32284317Sbr
33284317Sbr#include <sys/cdefs.h>
34284317Sbr__FBSDID("$FreeBSD: head/sys/dev/pci/pci_host_generic.c 292215 2015-12-14 17:08:40Z andrew $");
35284317Sbr
36284317Sbr#include <sys/param.h>
37284317Sbr#include <sys/systm.h>
38284317Sbr#include <sys/malloc.h>
39284317Sbr#include <sys/kernel.h>
40284317Sbr#include <sys/rman.h>
41284317Sbr#include <sys/module.h>
42284317Sbr#include <sys/bus.h>
43284317Sbr#include <sys/endian.h>
44284317Sbr#include <sys/cpuset.h>
45284317Sbr#include <sys/rwlock.h>
46292215Sandrew
47284317Sbr#include <dev/ofw/openfirm.h>
48284317Sbr#include <dev/ofw/ofw_bus.h>
49284317Sbr#include <dev/ofw/ofw_bus_subr.h>
50292215Sandrew#include <dev/ofw/ofw_pci.h>
51284317Sbr#include <dev/pci/pcivar.h>
52284317Sbr#include <dev/pci/pcireg.h>
53284317Sbr#include <dev/pci/pcib_private.h>
54292215Sandrew
55284317Sbr#include <machine/cpu.h>
56284317Sbr#include <machine/bus.h>
57284317Sbr#include <machine/intr.h>
58284317Sbr#include <vm/vm_page.h>
59284317Sbr
60284317Sbr#include "pcib_if.h"
61284317Sbr
62284317Sbr/* Assembling ECAM Configuration Address */
63284317Sbr#define	PCIE_BUS_SHIFT		20
64284317Sbr#define	PCIE_SLOT_SHIFT		15
65284317Sbr#define	PCIE_FUNC_SHIFT		12
66284317Sbr#define	PCIE_BUS_MASK		0xFF
67284317Sbr#define	PCIE_SLOT_MASK		0x1F
68284317Sbr#define	PCIE_FUNC_MASK		0x07
69284317Sbr#define	PCIE_REG_MASK		0xFFF
70284317Sbr
71284317Sbr#define	PCIE_ADDR_OFFSET(bus, slot, func, reg)			\
72284317Sbr	((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT)	|	\
73284317Sbr	(((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT)	|	\
74284317Sbr	(((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT)	|	\
75284317Sbr	((reg) & PCIE_REG_MASK))
76284317Sbr
77284317Sbr#define	MAX_RANGES_TUPLES	5
78284317Sbr#define	MIN_RANGES_TUPLES	2
79284317Sbr
80284317Sbr#define	PCI_IO_WINDOW_OFFSET	0x1000
81284317Sbr
82284317Sbr#define	SPACE_CODE_SHIFT	24
83284317Sbr#define	SPACE_CODE_MASK		0x3
84284317Sbr#define	SPACE_CODE_IO_SPACE	0x1
85284317Sbr#define	PROPS_CELL_SIZE		1
86284317Sbr#define	PCI_ADDR_CELL_SIZE	2
87284317Sbr
88284317Sbrstruct pcie_range {
89284317Sbr	uint64_t	pci_base;
90284317Sbr	uint64_t	phys_base;
91284317Sbr	uint64_t	size;
92284317Sbr	uint64_t	flags;
93284317Sbr#define	FLAG_IO		(1 << 0)
94284317Sbr#define	FLAG_MEM	(1 << 1)
95284317Sbr};
96284317Sbr
97284317Sbrstruct generic_pcie_softc {
98284317Sbr	struct pcie_range	ranges[MAX_RANGES_TUPLES];
99284317Sbr	int			nranges;
100284317Sbr	struct rman		mem_rman;
101284317Sbr	struct rman		io_rman;
102284317Sbr	struct resource		*res;
103284317Sbr	struct resource		*res1;
104284317Sbr	int			ecam;
105284317Sbr	bus_space_tag_t		bst;
106284317Sbr	bus_space_handle_t	bsh;
107284317Sbr	device_t		dev;
108284317Sbr	bus_space_handle_t	ioh;
109292215Sandrew	struct ofw_bus_iinfo    pci_iinfo;
110284317Sbr};
111284317Sbr
112284317Sbr/* Forward prototypes */
113284317Sbr
114284317Sbrstatic int generic_pcie_probe(device_t dev);
115284317Sbrstatic int generic_pcie_attach(device_t dev);
116284317Sbrstatic int parse_pci_mem_ranges(struct generic_pcie_softc *sc);
117284317Sbrstatic uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
118284317Sbr    u_int func, u_int reg, int bytes);
119284317Sbrstatic void generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
120284317Sbr    u_int func, u_int reg, uint32_t val, int bytes);
121284317Sbrstatic int generic_pcie_maxslots(device_t dev);
122284317Sbrstatic int generic_pcie_read_ivar(device_t dev, device_t child, int index,
123284317Sbr    uintptr_t *result);
124284317Sbrstatic int generic_pcie_write_ivar(device_t dev, device_t child, int index,
125284317Sbr    uintptr_t value);
126284317Sbrstatic struct resource *generic_pcie_alloc_resource(device_t dev,
127284317Sbr    device_t child, int type, int *rid, u_long start, u_long end,
128284317Sbr    u_long count, u_int flags);
129284317Sbrstatic int generic_pcie_release_resource(device_t dev, device_t child,
130284317Sbr    int type, int rid, struct resource *res);
131284317Sbr
132284317Sbrstatic int
133284317Sbrgeneric_pcie_probe(device_t dev)
134284317Sbr{
135284317Sbr
136284317Sbr	if (!ofw_bus_status_okay(dev))
137284317Sbr		return (ENXIO);
138284317Sbr
139284317Sbr	if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) {
140284317Sbr		device_set_desc(dev, "Generic PCI host controller");
141284317Sbr		return (BUS_PROBE_DEFAULT);
142284317Sbr	}
143284317Sbr
144284317Sbr	return (ENXIO);
145284317Sbr}
146284317Sbr
147284317Sbrstatic int
148284317Sbrgeneric_pcie_attach(device_t dev)
149284317Sbr{
150284317Sbr	struct generic_pcie_softc *sc;
151284317Sbr	uint64_t phys_base;
152284317Sbr	uint64_t pci_base;
153284317Sbr	uint64_t size;
154284317Sbr	int error;
155284317Sbr	int tuple;
156284317Sbr	int rid;
157284317Sbr
158284317Sbr	sc = device_get_softc(dev);
159284317Sbr	sc->dev = dev;
160284317Sbr
161284317Sbr	rid = 0;
162284317Sbr	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
163284317Sbr	if (sc->res == NULL) {
164284317Sbr		device_printf(dev, "could not map memory.\n");
165284317Sbr		return (ENXIO);
166284317Sbr	}
167284317Sbr
168284317Sbr	sc->bst = rman_get_bustag(sc->res);
169284317Sbr	sc->bsh = rman_get_bushandle(sc->res);
170284317Sbr
171284317Sbr	sc->mem_rman.rm_type = RMAN_ARRAY;
172284317Sbr	sc->mem_rman.rm_descr = "PCIe Memory";
173284317Sbr	sc->io_rman.rm_type = RMAN_ARRAY;
174284317Sbr	sc->io_rman.rm_descr = "PCIe IO window";
175284317Sbr
176284317Sbr	/* Retrieve 'ranges' property from FDT */
177284317Sbr	if (bootverbose)
178284317Sbr		device_printf(dev, "parsing FDT for ECAM%d:\n",
179284317Sbr		    sc->ecam);
180284317Sbr	if (parse_pci_mem_ranges(sc))
181284317Sbr		return (ENXIO);
182284317Sbr
183284317Sbr	/* Initialize rman and allocate memory regions */
184284317Sbr	error = rman_init(&sc->mem_rman);
185284317Sbr	if (error) {
186284317Sbr		device_printf(dev, "rman_init() failed. error = %d\n", error);
187284317Sbr		return (error);
188284317Sbr	}
189284317Sbr
190284317Sbr	error = rman_init(&sc->io_rman);
191284317Sbr	if (error) {
192284317Sbr		device_printf(dev, "rman_init() failed. error = %d\n", error);
193284317Sbr		return (error);
194284317Sbr	}
195284317Sbr
196284317Sbr	for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
197284317Sbr		phys_base = sc->ranges[tuple].phys_base;
198284317Sbr		pci_base = sc->ranges[tuple].pci_base;
199284317Sbr		size = sc->ranges[tuple].size;
200284317Sbr		if (phys_base == 0 || size == 0)
201284317Sbr			continue; /* empty range element */
202284317Sbr		if (sc->ranges[tuple].flags & FLAG_MEM) {
203284317Sbr			error = rman_manage_region(&sc->mem_rman,
204284317Sbr						phys_base,
205284317Sbr						phys_base + size);
206284317Sbr		} else if (sc->ranges[tuple].flags & FLAG_IO) {
207284317Sbr			error = rman_manage_region(&sc->io_rman,
208284317Sbr					pci_base + PCI_IO_WINDOW_OFFSET,
209284317Sbr					pci_base + PCI_IO_WINDOW_OFFSET + size);
210284317Sbr		} else
211284317Sbr			continue;
212284317Sbr		if (error) {
213284317Sbr			device_printf(dev, "rman_manage_region() failed."
214284317Sbr						"error = %d\n", error);
215284317Sbr			rman_fini(&sc->mem_rman);
216284317Sbr			return (error);
217284317Sbr		}
218284317Sbr	}
219284317Sbr
220292215Sandrew	ofw_bus_setup_iinfo(ofw_bus_get_node(dev), &sc->pci_iinfo,
221292215Sandrew	    sizeof(cell_t));
222284317Sbr
223292215Sandrew
224284317Sbr	device_add_child(dev, "pci", -1);
225284317Sbr	return (bus_generic_attach(dev));
226284317Sbr}
227284317Sbr
228284317Sbrstatic int
229284317Sbrparse_pci_mem_ranges(struct generic_pcie_softc *sc)
230284317Sbr{
231284317Sbr	pcell_t pci_addr_cells, parent_addr_cells;
232284317Sbr	pcell_t attributes, size_cells;
233284317Sbr	cell_t *base_ranges;
234284317Sbr	int nbase_ranges;
235284317Sbr	phandle_t node;
236284317Sbr	int i, j, k;
237284317Sbr	int tuple;
238284317Sbr
239284317Sbr	node = ofw_bus_get_node(sc->dev);
240284317Sbr
241284317Sbr	OF_getencprop(node, "#address-cells", &pci_addr_cells,
242284317Sbr					sizeof(pci_addr_cells));
243284317Sbr	OF_getencprop(node, "#size-cells", &size_cells,
244284317Sbr					sizeof(size_cells));
245284317Sbr	OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells,
246284317Sbr					sizeof(parent_addr_cells));
247284317Sbr
248284317Sbr	if (parent_addr_cells != 2 || pci_addr_cells != 3 || size_cells != 2) {
249284317Sbr		device_printf(sc->dev,
250284317Sbr		    "Unexpected number of address or size cells in FDT\n");
251284317Sbr		return (ENXIO);
252284317Sbr	}
253284317Sbr
254284317Sbr	nbase_ranges = OF_getproplen(node, "ranges");
255284317Sbr	sc->nranges = nbase_ranges / sizeof(cell_t) /
256284317Sbr	    (parent_addr_cells + pci_addr_cells + size_cells);
257284317Sbr	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
258284317Sbr	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
259284317Sbr
260284317Sbr	for (i = 0, j = 0; i < sc->nranges; i++) {
261284317Sbr		attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \
262284317Sbr							SPACE_CODE_MASK;
263284317Sbr		if (attributes == SPACE_CODE_IO_SPACE) {
264284317Sbr			sc->ranges[i].flags |= FLAG_IO;
265284317Sbr		} else {
266284317Sbr			sc->ranges[i].flags |= FLAG_MEM;
267284317Sbr		}
268284317Sbr
269284317Sbr		sc->ranges[i].pci_base = 0;
270284317Sbr		for (k = 0; k < (pci_addr_cells - 1); k++) {
271284317Sbr			sc->ranges[i].pci_base <<= 32;
272284317Sbr			sc->ranges[i].pci_base |= base_ranges[j++];
273284317Sbr		}
274284317Sbr		sc->ranges[i].phys_base = 0;
275284317Sbr		for (k = 0; k < parent_addr_cells; k++) {
276284317Sbr			sc->ranges[i].phys_base <<= 32;
277284317Sbr			sc->ranges[i].phys_base |= base_ranges[j++];
278284317Sbr		}
279284317Sbr		sc->ranges[i].size = 0;
280284317Sbr		for (k = 0; k < size_cells; k++) {
281284317Sbr			sc->ranges[i].size <<= 32;
282284317Sbr			sc->ranges[i].size |= base_ranges[j++];
283284317Sbr		}
284284317Sbr	}
285284317Sbr
286284317Sbr	for (; i < MAX_RANGES_TUPLES; i++) {
287284317Sbr		/* zero-fill remaining tuples to mark empty elements in array */
288284317Sbr		sc->ranges[i].pci_base = 0;
289284317Sbr		sc->ranges[i].phys_base = 0;
290284317Sbr		sc->ranges[i].size = 0;
291284317Sbr	}
292284317Sbr
293284317Sbr	if (bootverbose) {
294284317Sbr		for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
295284317Sbr			device_printf(sc->dev,
296284317Sbr			    "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n",
297284317Sbr			    sc->ranges[tuple].pci_base,
298284317Sbr			    sc->ranges[tuple].phys_base,
299284317Sbr			    sc->ranges[tuple].size);
300284317Sbr		}
301284317Sbr	}
302284317Sbr
303284317Sbr	free(base_ranges, M_DEVBUF);
304284317Sbr	return (0);
305284317Sbr}
306284317Sbr
307284317Sbrstatic uint32_t
308284317Sbrgeneric_pcie_read_config(device_t dev, u_int bus, u_int slot,
309284317Sbr    u_int func, u_int reg, int bytes)
310284317Sbr{
311284317Sbr	struct generic_pcie_softc *sc;
312284317Sbr	bus_space_handle_t h;
313284317Sbr	bus_space_tag_t	t;
314284317Sbr	uint64_t offset;
315284317Sbr	uint32_t data;
316284317Sbr
317284317Sbr	if (bus > 255 || slot > 31 || func > 7 || reg > 4095)
318284317Sbr		return (~0U);
319284317Sbr
320284317Sbr	sc = device_get_softc(dev);
321284317Sbr
322284317Sbr	offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
323284317Sbr	t = sc->bst;
324284317Sbr	h = sc->bsh;
325284317Sbr
326284317Sbr	switch (bytes) {
327284317Sbr	case 1:
328284317Sbr		data = bus_space_read_1(t, h, offset);
329284317Sbr		break;
330284317Sbr	case 2:
331284317Sbr		data = le16toh(bus_space_read_2(t, h, offset));
332284317Sbr		break;
333284317Sbr	case 4:
334284317Sbr		data = le32toh(bus_space_read_4(t, h, offset));
335284317Sbr		break;
336284317Sbr	default:
337284317Sbr		return (~0U);
338284317Sbr	}
339284317Sbr
340284317Sbr	return (data);
341284317Sbr}
342284317Sbr
343284317Sbrstatic void
344284317Sbrgeneric_pcie_write_config(device_t dev, u_int bus, u_int slot,
345284317Sbr    u_int func, u_int reg, uint32_t val, int bytes)
346284317Sbr{
347284317Sbr	struct generic_pcie_softc *sc;
348284317Sbr	bus_space_handle_t h;
349284317Sbr	bus_space_tag_t t;
350284317Sbr	uint64_t offset;
351284317Sbr
352284317Sbr	if (bus > 255 || slot > 31 || func > 7 || reg > 4095)
353284317Sbr		return;
354284317Sbr
355284317Sbr	sc = device_get_softc(dev);
356284317Sbr
357284317Sbr	offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
358284317Sbr
359284317Sbr	t = sc->bst;
360284317Sbr	h = sc->bsh;
361284317Sbr
362284317Sbr	switch (bytes) {
363284317Sbr	case 1:
364284317Sbr		bus_space_write_1(t, h, offset, val);
365284317Sbr		break;
366284317Sbr	case 2:
367284317Sbr		bus_space_write_2(t, h, offset, htole16(val));
368284317Sbr		break;
369284317Sbr	case 4:
370284317Sbr		bus_space_write_4(t, h, offset, htole32(val));
371284317Sbr		break;
372284317Sbr	default:
373284317Sbr		return;
374284317Sbr	}
375284317Sbr}
376284317Sbr
377284317Sbrstatic int
378284317Sbrgeneric_pcie_maxslots(device_t dev)
379284317Sbr{
380284317Sbr
381284317Sbr	return (31); /* max slots per bus acc. to standard */
382284317Sbr}
383284317Sbr
384284317Sbrstatic int
385292215Sandrewgeneric_pcie_route_interrupt(device_t bus, device_t dev, int pin)
386292215Sandrew{
387292215Sandrew	struct generic_pcie_softc *sc;
388292215Sandrew	struct ofw_pci_register reg;
389292215Sandrew	uint32_t pintr, mintr[2];
390292215Sandrew	phandle_t iparent;
391292215Sandrew	int intrcells;
392292215Sandrew
393292215Sandrew	sc = device_get_softc(bus);
394292215Sandrew	pintr = pin;
395292215Sandrew
396292215Sandrew	bzero(&reg, sizeof(reg));
397292215Sandrew	reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
398292215Sandrew	    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
399292215Sandrew	    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
400292215Sandrew
401292215Sandrew	intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
402292215Sandrew	    &sc->pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
403292215Sandrew	    mintr, sizeof(mintr), &iparent);
404292215Sandrew	if (intrcells) {
405292215Sandrew		pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
406292215Sandrew		return (pintr);
407292215Sandrew	}
408292215Sandrew
409292215Sandrew	device_printf(bus, "could not route pin %d for device %d.%d\n",
410292215Sandrew	    pin, pci_get_slot(dev), pci_get_function(dev));
411292215Sandrew	return (PCI_INVALID_IRQ);
412292215Sandrew}
413292215Sandrew
414292215Sandrew
415292215Sandrewstatic int
416284317Sbrgeneric_pcie_read_ivar(device_t dev, device_t child, int index,
417284317Sbr    uintptr_t *result)
418284317Sbr{
419284317Sbr	struct generic_pcie_softc *sc;
420284317Sbr	int secondary_bus;
421284317Sbr
422284317Sbr	sc = device_get_softc(dev);
423284317Sbr
424284317Sbr	if (index == PCIB_IVAR_BUS) {
425284317Sbr		/* this pcib adds only pci bus 0 as child */
426284317Sbr		secondary_bus = 0;
427284317Sbr		*result = secondary_bus;
428284317Sbr		return (0);
429284317Sbr
430284317Sbr	}
431284317Sbr
432284317Sbr	if (index == PCIB_IVAR_DOMAIN) {
433284317Sbr		*result = sc->ecam;
434284317Sbr		return (0);
435284317Sbr	}
436284317Sbr
437284317Sbr	device_printf(dev, "ERROR: Unknown index.\n");
438284317Sbr	return (ENOENT);
439284317Sbr}
440284317Sbr
441284317Sbrstatic int
442284317Sbrgeneric_pcie_write_ivar(device_t dev, device_t child, int index,
443284317Sbr    uintptr_t value)
444284317Sbr{
445284317Sbr
446284317Sbr	return (ENOENT);
447284317Sbr}
448284317Sbr
449284317Sbrstatic struct rman *
450284317Sbrgeneric_pcie_rman(struct generic_pcie_softc *sc, int type)
451284317Sbr{
452284317Sbr
453284317Sbr	switch (type) {
454284317Sbr	case SYS_RES_IOPORT:
455284317Sbr		return (&sc->io_rman);
456284317Sbr	case SYS_RES_MEMORY:
457284317Sbr		return (&sc->mem_rman);
458284317Sbr	default:
459284317Sbr		break;
460284317Sbr	}
461284317Sbr
462284317Sbr	return (NULL);
463284317Sbr}
464284317Sbr
465284317Sbrstatic int
466284317Sbrgeneric_pcie_release_resource(device_t dev, device_t child, int type,
467284317Sbr    int rid, struct resource *res)
468284317Sbr{
469284317Sbr	struct generic_pcie_softc *sc;
470284317Sbr	struct rman *rm;
471284317Sbr
472284317Sbr	sc = device_get_softc(dev);
473284317Sbr
474284317Sbr	rm = generic_pcie_rman(sc, type);
475284317Sbr	if (rm != NULL) {
476284317Sbr		KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
477284317Sbr		rman_release_resource(res);
478284317Sbr	}
479284317Sbr
480284317Sbr	return (bus_generic_release_resource(dev, child, type, rid, res));
481284317Sbr}
482284317Sbr
483284317Sbrstatic struct resource *
484284317Sbrgeneric_pcie_alloc_resource(device_t dev, device_t child, int type, int *rid,
485284317Sbr    u_long start, u_long end, u_long count, u_int flags)
486284317Sbr{
487284317Sbr	struct generic_pcie_softc *sc;
488284317Sbr	struct resource *res;
489284317Sbr	struct rman *rm;
490284317Sbr
491284317Sbr	sc = device_get_softc(dev);
492284317Sbr
493284317Sbr	rm = generic_pcie_rman(sc, type);
494284317Sbr	if (rm == NULL)
495284317Sbr		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
496284317Sbr		    type, rid, start, end, count, flags));
497284317Sbr
498284317Sbr	if (bootverbose) {
499284317Sbr		device_printf(dev,
500284317Sbr		    "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
501284317Sbr		    start, end, count);
502284317Sbr	}
503284317Sbr
504284317Sbr	res = rman_reserve_resource(rm, start, end, count, flags, child);
505284317Sbr	if (res == NULL)
506284317Sbr		goto fail;
507284317Sbr
508284317Sbr	rman_set_rid(res, *rid);
509284317Sbr
510284317Sbr	if (flags & RF_ACTIVE)
511284317Sbr		if (bus_activate_resource(child, type, *rid, res)) {
512284317Sbr			rman_release_resource(res);
513284317Sbr			goto fail;
514284317Sbr		}
515284317Sbr
516284317Sbr	return (res);
517284317Sbr
518284317Sbrfail:
519284317Sbr	if (bootverbose) {
520284317Sbr		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
521284317Sbr		    "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
522284317Sbr		    __func__, type, *rid, start, end, count, flags);
523284317Sbr	}
524284317Sbr
525284317Sbr	return (NULL);
526284317Sbr}
527284317Sbr
528284317Sbrstatic int
529284317Sbrgeneric_pcie_adjust_resource(device_t dev, device_t child, int type,
530284317Sbr    struct resource *res, u_long start, u_long end)
531284317Sbr{
532284317Sbr	struct generic_pcie_softc *sc;
533284317Sbr	struct rman *rm;
534284317Sbr
535284317Sbr	sc = device_get_softc(dev);
536284317Sbr
537284317Sbr	rm = generic_pcie_rman(sc, type);
538284317Sbr	if (rm != NULL)
539284317Sbr		return (rman_adjust_resource(res, start, end));
540284317Sbr	return (bus_generic_adjust_resource(dev, child, type, res, start, end));
541284317Sbr}
542284317Sbr
543284317Sbrstatic int
544284317Sbrgeneric_pcie_activate_resource(device_t dev, device_t child, int type, int rid,
545284317Sbr    struct resource *r)
546284317Sbr{
547284317Sbr	struct generic_pcie_softc *sc;
548284317Sbr	uint64_t phys_base;
549284317Sbr	uint64_t pci_base;
550284317Sbr	uint64_t size;
551284317Sbr	int found;
552284317Sbr	int res;
553284317Sbr	int i;
554284317Sbr
555284317Sbr	sc = device_get_softc(dev);
556284317Sbr
557284317Sbr	if ((res = rman_activate_resource(r)) != 0)
558284317Sbr		return (res);
559284317Sbr
560284317Sbr	switch(type) {
561284317Sbr	case SYS_RES_IOPORT:
562284317Sbr		found = 0;
563284317Sbr		for (i = 0; i < MAX_RANGES_TUPLES; i++) {
564284317Sbr			pci_base = sc->ranges[i].pci_base;
565284317Sbr			phys_base = sc->ranges[i].phys_base;
566284317Sbr			size = sc->ranges[i].size;
567284317Sbr
568284317Sbr			if ((rid > pci_base) && (rid < (pci_base + size))) {
569284317Sbr				found = 1;
570284317Sbr				break;
571284317Sbr			}
572284317Sbr		}
573284317Sbr		if (found) {
574284317Sbr			rman_set_start(r, rman_get_start(r) + phys_base);
575284317Sbr			BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child,
576284317Sbr						type, rid, r);
577284317Sbr		} else {
578284317Sbr			device_printf(dev, "Failed to activate IOPORT resource\n");
579284317Sbr			res = 0;
580284317Sbr		}
581284317Sbr		break;
582284317Sbr	case SYS_RES_MEMORY:
583284317Sbr		BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r);
584284317Sbr		break;
585284317Sbr	default:
586284317Sbr		break;
587284317Sbr	}
588284317Sbr
589284317Sbr	return (res);
590284317Sbr}
591284317Sbr
592284317Sbrstatic int
593284317Sbrgeneric_pcie_deactivate_resource(device_t dev, device_t child, int type, int rid,
594284317Sbr    struct resource *r)
595284317Sbr{
596284317Sbr	struct generic_pcie_softc *sc;
597284317Sbr	vm_offset_t vaddr;
598284317Sbr	int res;
599284317Sbr
600284317Sbr	sc = device_get_softc(dev);
601284317Sbr
602284317Sbr	if ((res = rman_deactivate_resource(r)) != 0)
603284317Sbr		return (res);
604284317Sbr
605284317Sbr	switch(type) {
606284317Sbr	case SYS_RES_IOPORT:
607284317Sbr	case SYS_RES_MEMORY:
608284317Sbr		vaddr = (vm_offset_t)rman_get_virtual(r);
609284317Sbr		pmap_unmapdev(vaddr, rman_get_size(r));
610284317Sbr		break;
611284317Sbr	default:
612284317Sbr		break;
613284317Sbr	}
614284317Sbr
615284317Sbr	return (res);
616284317Sbr}
617284317Sbr
618284317Sbrstatic device_method_t generic_pcie_methods[] = {
619284317Sbr	DEVMETHOD(device_probe,			generic_pcie_probe),
620284317Sbr	DEVMETHOD(device_attach,		generic_pcie_attach),
621284317Sbr	DEVMETHOD(bus_read_ivar,		generic_pcie_read_ivar),
622284317Sbr	DEVMETHOD(bus_write_ivar,		generic_pcie_write_ivar),
623284317Sbr	DEVMETHOD(bus_alloc_resource,		generic_pcie_alloc_resource),
624284317Sbr	DEVMETHOD(bus_adjust_resource,		generic_pcie_adjust_resource),
625284317Sbr	DEVMETHOD(bus_release_resource,		generic_pcie_release_resource),
626284317Sbr	DEVMETHOD(bus_activate_resource,	generic_pcie_activate_resource),
627284317Sbr	DEVMETHOD(bus_deactivate_resource,	generic_pcie_deactivate_resource),
628284317Sbr	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
629284317Sbr	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
630292215Sandrew
631292215Sandrew	/* pcib interface */
632284317Sbr	DEVMETHOD(pcib_maxslots,		generic_pcie_maxslots),
633292215Sandrew	DEVMETHOD(pcib_route_interrupt,		generic_pcie_route_interrupt),
634284317Sbr	DEVMETHOD(pcib_read_config,		generic_pcie_read_config),
635284317Sbr	DEVMETHOD(pcib_write_config,		generic_pcie_write_config),
636292215Sandrew#if defined(__aarch64__)
637292215Sandrew	DEVMETHOD(pcib_alloc_msi,		arm_alloc_msi),
638292215Sandrew	DEVMETHOD(pcib_release_msi,		arm_release_msi),
639292215Sandrew	DEVMETHOD(pcib_alloc_msix,		arm_alloc_msix),
640292215Sandrew	DEVMETHOD(pcib_release_msix,		arm_release_msix),
641292215Sandrew	DEVMETHOD(pcib_map_msi,			arm_map_msi),
642292215Sandrew#endif
643292215Sandrew
644284317Sbr	DEVMETHOD_END
645284317Sbr};
646284317Sbr
647284317Sbrstatic driver_t generic_pcie_driver = {
648284317Sbr	"pcib",
649284317Sbr	generic_pcie_methods,
650284317Sbr	sizeof(struct generic_pcie_softc),
651284317Sbr};
652284317Sbr
653284317Sbrstatic devclass_t generic_pcie_devclass;
654284317Sbr
655284317SbrDRIVER_MODULE(pcib, simplebus, generic_pcie_driver,
656284317Sbrgeneric_pcie_devclass, 0, 0);
657284317SbrDRIVER_MODULE(pcib, ofwbus, generic_pcie_driver,
658284317Sbrgeneric_pcie_devclass, 0, 0);
659