pci_host_generic.c revision 292215
1/*-
2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3 * Copyright (c) 2014 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * This software was developed by Semihalf under
7 * the sponsorship of the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/* Generic ECAM PCIe driver */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/pci/pci_host_generic.c 292215 2015-12-14 17:08:40Z andrew $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/malloc.h>
39#include <sys/kernel.h>
40#include <sys/rman.h>
41#include <sys/module.h>
42#include <sys/bus.h>
43#include <sys/endian.h>
44#include <sys/cpuset.h>
45#include <sys/rwlock.h>
46
47#include <dev/ofw/openfirm.h>
48#include <dev/ofw/ofw_bus.h>
49#include <dev/ofw/ofw_bus_subr.h>
50#include <dev/ofw/ofw_pci.h>
51#include <dev/pci/pcivar.h>
52#include <dev/pci/pcireg.h>
53#include <dev/pci/pcib_private.h>
54
55#include <machine/cpu.h>
56#include <machine/bus.h>
57#include <machine/intr.h>
58#include <vm/vm_page.h>
59
60#include "pcib_if.h"
61
62/* Assembling ECAM Configuration Address */
63#define	PCIE_BUS_SHIFT		20
64#define	PCIE_SLOT_SHIFT		15
65#define	PCIE_FUNC_SHIFT		12
66#define	PCIE_BUS_MASK		0xFF
67#define	PCIE_SLOT_MASK		0x1F
68#define	PCIE_FUNC_MASK		0x07
69#define	PCIE_REG_MASK		0xFFF
70
71#define	PCIE_ADDR_OFFSET(bus, slot, func, reg)			\
72	((((bus) & PCIE_BUS_MASK) << PCIE_BUS_SHIFT)	|	\
73	(((slot) & PCIE_SLOT_MASK) << PCIE_SLOT_SHIFT)	|	\
74	(((func) & PCIE_FUNC_MASK) << PCIE_FUNC_SHIFT)	|	\
75	((reg) & PCIE_REG_MASK))
76
77#define	MAX_RANGES_TUPLES	5
78#define	MIN_RANGES_TUPLES	2
79
80#define	PCI_IO_WINDOW_OFFSET	0x1000
81
82#define	SPACE_CODE_SHIFT	24
83#define	SPACE_CODE_MASK		0x3
84#define	SPACE_CODE_IO_SPACE	0x1
85#define	PROPS_CELL_SIZE		1
86#define	PCI_ADDR_CELL_SIZE	2
87
88struct pcie_range {
89	uint64_t	pci_base;
90	uint64_t	phys_base;
91	uint64_t	size;
92	uint64_t	flags;
93#define	FLAG_IO		(1 << 0)
94#define	FLAG_MEM	(1 << 1)
95};
96
97struct generic_pcie_softc {
98	struct pcie_range	ranges[MAX_RANGES_TUPLES];
99	int			nranges;
100	struct rman		mem_rman;
101	struct rman		io_rman;
102	struct resource		*res;
103	struct resource		*res1;
104	int			ecam;
105	bus_space_tag_t		bst;
106	bus_space_handle_t	bsh;
107	device_t		dev;
108	bus_space_handle_t	ioh;
109	struct ofw_bus_iinfo    pci_iinfo;
110};
111
112/* Forward prototypes */
113
114static int generic_pcie_probe(device_t dev);
115static int generic_pcie_attach(device_t dev);
116static int parse_pci_mem_ranges(struct generic_pcie_softc *sc);
117static uint32_t generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
118    u_int func, u_int reg, int bytes);
119static void generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
120    u_int func, u_int reg, uint32_t val, int bytes);
121static int generic_pcie_maxslots(device_t dev);
122static int generic_pcie_read_ivar(device_t dev, device_t child, int index,
123    uintptr_t *result);
124static int generic_pcie_write_ivar(device_t dev, device_t child, int index,
125    uintptr_t value);
126static struct resource *generic_pcie_alloc_resource(device_t dev,
127    device_t child, int type, int *rid, u_long start, u_long end,
128    u_long count, u_int flags);
129static int generic_pcie_release_resource(device_t dev, device_t child,
130    int type, int rid, struct resource *res);
131
132static int
133generic_pcie_probe(device_t dev)
134{
135
136	if (!ofw_bus_status_okay(dev))
137		return (ENXIO);
138
139	if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic")) {
140		device_set_desc(dev, "Generic PCI host controller");
141		return (BUS_PROBE_DEFAULT);
142	}
143
144	return (ENXIO);
145}
146
147static int
148generic_pcie_attach(device_t dev)
149{
150	struct generic_pcie_softc *sc;
151	uint64_t phys_base;
152	uint64_t pci_base;
153	uint64_t size;
154	int error;
155	int tuple;
156	int rid;
157
158	sc = device_get_softc(dev);
159	sc->dev = dev;
160
161	rid = 0;
162	sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
163	if (sc->res == NULL) {
164		device_printf(dev, "could not map memory.\n");
165		return (ENXIO);
166	}
167
168	sc->bst = rman_get_bustag(sc->res);
169	sc->bsh = rman_get_bushandle(sc->res);
170
171	sc->mem_rman.rm_type = RMAN_ARRAY;
172	sc->mem_rman.rm_descr = "PCIe Memory";
173	sc->io_rman.rm_type = RMAN_ARRAY;
174	sc->io_rman.rm_descr = "PCIe IO window";
175
176	/* Retrieve 'ranges' property from FDT */
177	if (bootverbose)
178		device_printf(dev, "parsing FDT for ECAM%d:\n",
179		    sc->ecam);
180	if (parse_pci_mem_ranges(sc))
181		return (ENXIO);
182
183	/* Initialize rman and allocate memory regions */
184	error = rman_init(&sc->mem_rman);
185	if (error) {
186		device_printf(dev, "rman_init() failed. error = %d\n", error);
187		return (error);
188	}
189
190	error = rman_init(&sc->io_rman);
191	if (error) {
192		device_printf(dev, "rman_init() failed. error = %d\n", error);
193		return (error);
194	}
195
196	for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
197		phys_base = sc->ranges[tuple].phys_base;
198		pci_base = sc->ranges[tuple].pci_base;
199		size = sc->ranges[tuple].size;
200		if (phys_base == 0 || size == 0)
201			continue; /* empty range element */
202		if (sc->ranges[tuple].flags & FLAG_MEM) {
203			error = rman_manage_region(&sc->mem_rman,
204						phys_base,
205						phys_base + size);
206		} else if (sc->ranges[tuple].flags & FLAG_IO) {
207			error = rman_manage_region(&sc->io_rman,
208					pci_base + PCI_IO_WINDOW_OFFSET,
209					pci_base + PCI_IO_WINDOW_OFFSET + size);
210		} else
211			continue;
212		if (error) {
213			device_printf(dev, "rman_manage_region() failed."
214						"error = %d\n", error);
215			rman_fini(&sc->mem_rman);
216			return (error);
217		}
218	}
219
220	ofw_bus_setup_iinfo(ofw_bus_get_node(dev), &sc->pci_iinfo,
221	    sizeof(cell_t));
222
223
224	device_add_child(dev, "pci", -1);
225	return (bus_generic_attach(dev));
226}
227
228static int
229parse_pci_mem_ranges(struct generic_pcie_softc *sc)
230{
231	pcell_t pci_addr_cells, parent_addr_cells;
232	pcell_t attributes, size_cells;
233	cell_t *base_ranges;
234	int nbase_ranges;
235	phandle_t node;
236	int i, j, k;
237	int tuple;
238
239	node = ofw_bus_get_node(sc->dev);
240
241	OF_getencprop(node, "#address-cells", &pci_addr_cells,
242					sizeof(pci_addr_cells));
243	OF_getencprop(node, "#size-cells", &size_cells,
244					sizeof(size_cells));
245	OF_getencprop(OF_parent(node), "#address-cells", &parent_addr_cells,
246					sizeof(parent_addr_cells));
247
248	if (parent_addr_cells != 2 || pci_addr_cells != 3 || size_cells != 2) {
249		device_printf(sc->dev,
250		    "Unexpected number of address or size cells in FDT\n");
251		return (ENXIO);
252	}
253
254	nbase_ranges = OF_getproplen(node, "ranges");
255	sc->nranges = nbase_ranges / sizeof(cell_t) /
256	    (parent_addr_cells + pci_addr_cells + size_cells);
257	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
258	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
259
260	for (i = 0, j = 0; i < sc->nranges; i++) {
261		attributes = (base_ranges[j++] >> SPACE_CODE_SHIFT) & \
262							SPACE_CODE_MASK;
263		if (attributes == SPACE_CODE_IO_SPACE) {
264			sc->ranges[i].flags |= FLAG_IO;
265		} else {
266			sc->ranges[i].flags |= FLAG_MEM;
267		}
268
269		sc->ranges[i].pci_base = 0;
270		for (k = 0; k < (pci_addr_cells - 1); k++) {
271			sc->ranges[i].pci_base <<= 32;
272			sc->ranges[i].pci_base |= base_ranges[j++];
273		}
274		sc->ranges[i].phys_base = 0;
275		for (k = 0; k < parent_addr_cells; k++) {
276			sc->ranges[i].phys_base <<= 32;
277			sc->ranges[i].phys_base |= base_ranges[j++];
278		}
279		sc->ranges[i].size = 0;
280		for (k = 0; k < size_cells; k++) {
281			sc->ranges[i].size <<= 32;
282			sc->ranges[i].size |= base_ranges[j++];
283		}
284	}
285
286	for (; i < MAX_RANGES_TUPLES; i++) {
287		/* zero-fill remaining tuples to mark empty elements in array */
288		sc->ranges[i].pci_base = 0;
289		sc->ranges[i].phys_base = 0;
290		sc->ranges[i].size = 0;
291	}
292
293	if (bootverbose) {
294		for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
295			device_printf(sc->dev,
296			    "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx\n",
297			    sc->ranges[tuple].pci_base,
298			    sc->ranges[tuple].phys_base,
299			    sc->ranges[tuple].size);
300		}
301	}
302
303	free(base_ranges, M_DEVBUF);
304	return (0);
305}
306
307static uint32_t
308generic_pcie_read_config(device_t dev, u_int bus, u_int slot,
309    u_int func, u_int reg, int bytes)
310{
311	struct generic_pcie_softc *sc;
312	bus_space_handle_t h;
313	bus_space_tag_t	t;
314	uint64_t offset;
315	uint32_t data;
316
317	if (bus > 255 || slot > 31 || func > 7 || reg > 4095)
318		return (~0U);
319
320	sc = device_get_softc(dev);
321
322	offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
323	t = sc->bst;
324	h = sc->bsh;
325
326	switch (bytes) {
327	case 1:
328		data = bus_space_read_1(t, h, offset);
329		break;
330	case 2:
331		data = le16toh(bus_space_read_2(t, h, offset));
332		break;
333	case 4:
334		data = le32toh(bus_space_read_4(t, h, offset));
335		break;
336	default:
337		return (~0U);
338	}
339
340	return (data);
341}
342
343static void
344generic_pcie_write_config(device_t dev, u_int bus, u_int slot,
345    u_int func, u_int reg, uint32_t val, int bytes)
346{
347	struct generic_pcie_softc *sc;
348	bus_space_handle_t h;
349	bus_space_tag_t t;
350	uint64_t offset;
351
352	if (bus > 255 || slot > 31 || func > 7 || reg > 4095)
353		return;
354
355	sc = device_get_softc(dev);
356
357	offset = PCIE_ADDR_OFFSET(bus, slot, func, reg);
358
359	t = sc->bst;
360	h = sc->bsh;
361
362	switch (bytes) {
363	case 1:
364		bus_space_write_1(t, h, offset, val);
365		break;
366	case 2:
367		bus_space_write_2(t, h, offset, htole16(val));
368		break;
369	case 4:
370		bus_space_write_4(t, h, offset, htole32(val));
371		break;
372	default:
373		return;
374	}
375}
376
377static int
378generic_pcie_maxslots(device_t dev)
379{
380
381	return (31); /* max slots per bus acc. to standard */
382}
383
384static int
385generic_pcie_route_interrupt(device_t bus, device_t dev, int pin)
386{
387	struct generic_pcie_softc *sc;
388	struct ofw_pci_register reg;
389	uint32_t pintr, mintr[2];
390	phandle_t iparent;
391	int intrcells;
392
393	sc = device_get_softc(bus);
394	pintr = pin;
395
396	bzero(&reg, sizeof(reg));
397	reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
398	    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
399	    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
400
401	intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
402	    &sc->pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
403	    mintr, sizeof(mintr), &iparent);
404	if (intrcells) {
405		pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
406		return (pintr);
407	}
408
409	device_printf(bus, "could not route pin %d for device %d.%d\n",
410	    pin, pci_get_slot(dev), pci_get_function(dev));
411	return (PCI_INVALID_IRQ);
412}
413
414
415static int
416generic_pcie_read_ivar(device_t dev, device_t child, int index,
417    uintptr_t *result)
418{
419	struct generic_pcie_softc *sc;
420	int secondary_bus;
421
422	sc = device_get_softc(dev);
423
424	if (index == PCIB_IVAR_BUS) {
425		/* this pcib adds only pci bus 0 as child */
426		secondary_bus = 0;
427		*result = secondary_bus;
428		return (0);
429
430	}
431
432	if (index == PCIB_IVAR_DOMAIN) {
433		*result = sc->ecam;
434		return (0);
435	}
436
437	device_printf(dev, "ERROR: Unknown index.\n");
438	return (ENOENT);
439}
440
441static int
442generic_pcie_write_ivar(device_t dev, device_t child, int index,
443    uintptr_t value)
444{
445
446	return (ENOENT);
447}
448
449static struct rman *
450generic_pcie_rman(struct generic_pcie_softc *sc, int type)
451{
452
453	switch (type) {
454	case SYS_RES_IOPORT:
455		return (&sc->io_rman);
456	case SYS_RES_MEMORY:
457		return (&sc->mem_rman);
458	default:
459		break;
460	}
461
462	return (NULL);
463}
464
465static int
466generic_pcie_release_resource(device_t dev, device_t child, int type,
467    int rid, struct resource *res)
468{
469	struct generic_pcie_softc *sc;
470	struct rman *rm;
471
472	sc = device_get_softc(dev);
473
474	rm = generic_pcie_rman(sc, type);
475	if (rm != NULL) {
476		KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
477		rman_release_resource(res);
478	}
479
480	return (bus_generic_release_resource(dev, child, type, rid, res));
481}
482
483static struct resource *
484generic_pcie_alloc_resource(device_t dev, device_t child, int type, int *rid,
485    u_long start, u_long end, u_long count, u_int flags)
486{
487	struct generic_pcie_softc *sc;
488	struct resource *res;
489	struct rman *rm;
490
491	sc = device_get_softc(dev);
492
493	rm = generic_pcie_rman(sc, type);
494	if (rm == NULL)
495		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
496		    type, rid, start, end, count, flags));
497
498	if (bootverbose) {
499		device_printf(dev,
500		    "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
501		    start, end, count);
502	}
503
504	res = rman_reserve_resource(rm, start, end, count, flags, child);
505	if (res == NULL)
506		goto fail;
507
508	rman_set_rid(res, *rid);
509
510	if (flags & RF_ACTIVE)
511		if (bus_activate_resource(child, type, *rid, res)) {
512			rman_release_resource(res);
513			goto fail;
514		}
515
516	return (res);
517
518fail:
519	if (bootverbose) {
520		device_printf(dev, "%s FAIL: type=%d, rid=%d, "
521		    "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
522		    __func__, type, *rid, start, end, count, flags);
523	}
524
525	return (NULL);
526}
527
528static int
529generic_pcie_adjust_resource(device_t dev, device_t child, int type,
530    struct resource *res, u_long start, u_long end)
531{
532	struct generic_pcie_softc *sc;
533	struct rman *rm;
534
535	sc = device_get_softc(dev);
536
537	rm = generic_pcie_rman(sc, type);
538	if (rm != NULL)
539		return (rman_adjust_resource(res, start, end));
540	return (bus_generic_adjust_resource(dev, child, type, res, start, end));
541}
542
543static int
544generic_pcie_activate_resource(device_t dev, device_t child, int type, int rid,
545    struct resource *r)
546{
547	struct generic_pcie_softc *sc;
548	uint64_t phys_base;
549	uint64_t pci_base;
550	uint64_t size;
551	int found;
552	int res;
553	int i;
554
555	sc = device_get_softc(dev);
556
557	if ((res = rman_activate_resource(r)) != 0)
558		return (res);
559
560	switch(type) {
561	case SYS_RES_IOPORT:
562		found = 0;
563		for (i = 0; i < MAX_RANGES_TUPLES; i++) {
564			pci_base = sc->ranges[i].pci_base;
565			phys_base = sc->ranges[i].phys_base;
566			size = sc->ranges[i].size;
567
568			if ((rid > pci_base) && (rid < (pci_base + size))) {
569				found = 1;
570				break;
571			}
572		}
573		if (found) {
574			rman_set_start(r, rman_get_start(r) + phys_base);
575			BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child,
576						type, rid, r);
577		} else {
578			device_printf(dev, "Failed to activate IOPORT resource\n");
579			res = 0;
580		}
581		break;
582	case SYS_RES_MEMORY:
583		BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r);
584		break;
585	default:
586		break;
587	}
588
589	return (res);
590}
591
592static int
593generic_pcie_deactivate_resource(device_t dev, device_t child, int type, int rid,
594    struct resource *r)
595{
596	struct generic_pcie_softc *sc;
597	vm_offset_t vaddr;
598	int res;
599
600	sc = device_get_softc(dev);
601
602	if ((res = rman_deactivate_resource(r)) != 0)
603		return (res);
604
605	switch(type) {
606	case SYS_RES_IOPORT:
607	case SYS_RES_MEMORY:
608		vaddr = (vm_offset_t)rman_get_virtual(r);
609		pmap_unmapdev(vaddr, rman_get_size(r));
610		break;
611	default:
612		break;
613	}
614
615	return (res);
616}
617
618static device_method_t generic_pcie_methods[] = {
619	DEVMETHOD(device_probe,			generic_pcie_probe),
620	DEVMETHOD(device_attach,		generic_pcie_attach),
621	DEVMETHOD(bus_read_ivar,		generic_pcie_read_ivar),
622	DEVMETHOD(bus_write_ivar,		generic_pcie_write_ivar),
623	DEVMETHOD(bus_alloc_resource,		generic_pcie_alloc_resource),
624	DEVMETHOD(bus_adjust_resource,		generic_pcie_adjust_resource),
625	DEVMETHOD(bus_release_resource,		generic_pcie_release_resource),
626	DEVMETHOD(bus_activate_resource,	generic_pcie_activate_resource),
627	DEVMETHOD(bus_deactivate_resource,	generic_pcie_deactivate_resource),
628	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
629	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
630
631	/* pcib interface */
632	DEVMETHOD(pcib_maxslots,		generic_pcie_maxslots),
633	DEVMETHOD(pcib_route_interrupt,		generic_pcie_route_interrupt),
634	DEVMETHOD(pcib_read_config,		generic_pcie_read_config),
635	DEVMETHOD(pcib_write_config,		generic_pcie_write_config),
636#if defined(__aarch64__)
637	DEVMETHOD(pcib_alloc_msi,		arm_alloc_msi),
638	DEVMETHOD(pcib_release_msi,		arm_release_msi),
639	DEVMETHOD(pcib_alloc_msix,		arm_alloc_msix),
640	DEVMETHOD(pcib_release_msix,		arm_release_msix),
641	DEVMETHOD(pcib_map_msi,			arm_map_msi),
642#endif
643
644	DEVMETHOD_END
645};
646
647static driver_t generic_pcie_driver = {
648	"pcib",
649	generic_pcie_methods,
650	sizeof(struct generic_pcie_softc),
651};
652
653static devclass_t generic_pcie_devclass;
654
655DRIVER_MODULE(pcib, simplebus, generic_pcie_driver,
656generic_pcie_devclass, 0, 0);
657DRIVER_MODULE(pcib, ofwbus, generic_pcie_driver,
658generic_pcie_devclass, 0, 0);
659