1/*-
2 * Copyright (c) 2011 Nathan Whitehorn
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: releng/11.0/sys/dev/ofw/ofwpci.c 297392 2016-03-29 15:19:56Z zbb $");
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/module.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/kernel.h>
35#include <sys/rman.h>
36
37#include <dev/ofw/openfirm.h>
38#include <dev/ofw/ofw_pci.h>
39#include <dev/ofw/ofw_bus.h>
40#include <dev/ofw/ofw_bus_subr.h>
41#include <dev/ofw/ofwpci.h>
42
43#include <dev/pci/pcivar.h>
44#include <dev/pci/pcireg.h>
45
46#include <machine/bus.h>
47#include <machine/md_var.h>
48#include <machine/resource.h>
49
50#include <vm/vm.h>
51#include <vm/pmap.h>
52
53#include "pcib_if.h"
54
55/*
56 * If it is necessary to set another value of this for
57 * some platforms it should be set at fdt.h file
58 */
59#ifndef PCI_MAP_INTR
60#define	PCI_MAP_INTR	4
61#endif
62
63#define	PCI_INTR_PINS	4
64
65/*
66 * bus interface.
67 */
68static struct resource * ofw_pci_alloc_resource(device_t, device_t,
69    int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
70static int ofw_pci_release_resource(device_t, device_t, int, int,
71    struct resource *);
72static int ofw_pci_activate_resource(device_t, device_t, int, int,
73    struct resource *);
74static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
75    struct resource *);
76static int ofw_pci_adjust_resource(device_t, device_t, int,
77    struct resource *, rman_res_t, rman_res_t);
78
79#ifdef __powerpc__
80static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
81#endif
82
83/*
84 * pcib interface
85 */
86static int ofw_pci_maxslots(device_t);
87
88/*
89 * ofw_bus interface
90 */
91static phandle_t ofw_pci_get_node(device_t, device_t);
92
93/*
94 * local methods
95 */
96static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
97
98/*
99 * Driver methods.
100 */
101static device_method_t	ofw_pci_methods[] = {
102
103	/* Device interface */
104	DEVMETHOD(device_attach,	ofw_pci_attach),
105
106	/* Bus interface */
107	DEVMETHOD(bus_print_child,	bus_generic_print_child),
108	DEVMETHOD(bus_read_ivar,	ofw_pci_read_ivar),
109	DEVMETHOD(bus_write_ivar,	ofw_pci_write_ivar),
110	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
111	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
112	DEVMETHOD(bus_alloc_resource,	ofw_pci_alloc_resource),
113	DEVMETHOD(bus_release_resource,	ofw_pci_release_resource),
114	DEVMETHOD(bus_activate_resource,	ofw_pci_activate_resource),
115	DEVMETHOD(bus_deactivate_resource,	ofw_pci_deactivate_resource),
116	DEVMETHOD(bus_adjust_resource,	ofw_pci_adjust_resource),
117#ifdef __powerpc__
118	DEVMETHOD(bus_get_bus_tag,	ofw_pci_bus_get_bus_tag),
119#endif
120
121	/* pcib interface */
122	DEVMETHOD(pcib_maxslots,	ofw_pci_maxslots),
123	DEVMETHOD(pcib_route_interrupt,	ofw_pci_route_interrupt),
124
125	/* ofw_bus interface */
126	DEVMETHOD(ofw_bus_get_node,	ofw_pci_get_node),
127
128	DEVMETHOD_END
129};
130
131DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
132
133int
134ofw_pci_init(device_t dev)
135{
136	struct ofw_pci_softc *sc;
137	phandle_t node;
138	u_int32_t busrange[2];
139	struct ofw_pci_range *rp;
140	int error;
141	struct ofw_pci_cell_info *cell_info;
142
143	node = ofw_bus_get_node(dev);
144	sc = device_get_softc(dev);
145	sc->sc_initialized = 1;
146	sc->sc_range = NULL;
147
148	cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
149	    M_DEVBUF, M_WAITOK | M_ZERO);
150
151	sc->sc_cell_info = cell_info;
152
153	if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
154		busrange[0] = 0;
155
156	sc->sc_dev = dev;
157	sc->sc_node = node;
158	sc->sc_bus = busrange[0];
159
160	if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
161		phandle_t c;
162		int n, i;
163
164		sc->sc_nrange = 0;
165		for (c = OF_child(node); c != 0; c = OF_peer(c)) {
166			n = ofw_pci_nranges(c, cell_info);
167			if (n > 0)
168				sc->sc_nrange += n;
169		}
170		if (sc->sc_nrange == 0) {
171			error = ENXIO;
172			goto out;
173		}
174		sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
175		    M_DEVBUF, M_WAITOK);
176		i = 0;
177		for (c = OF_child(node); c != 0; c = OF_peer(c)) {
178			n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
179			if (n > 0)
180				i += n;
181		}
182		KASSERT(i == sc->sc_nrange, ("range count mismatch"));
183	} else {
184		sc->sc_nrange = ofw_pci_nranges(node, cell_info);
185		if (sc->sc_nrange <= 0) {
186			device_printf(dev, "could not getranges\n");
187			error = ENXIO;
188			goto out;
189		}
190		sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
191		    M_DEVBUF, M_WAITOK);
192		ofw_pci_fill_ranges(node, sc->sc_range);
193	}
194
195	sc->sc_io_rman.rm_type = RMAN_ARRAY;
196	sc->sc_io_rman.rm_descr = "PCI I/O Ports";
197	error = rman_init(&sc->sc_io_rman);
198	if (error) {
199		device_printf(dev, "rman_init() failed. error = %d\n", error);
200		goto out;
201	}
202
203	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
204	sc->sc_mem_rman.rm_descr = "PCI Memory";
205	error = rman_init(&sc->sc_mem_rman);
206	if (error) {
207		device_printf(dev, "rman_init() failed. error = %d\n", error);
208		goto out;
209	}
210
211	for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
212	    rp->pci_hi != 0; rp++) {
213		error = 0;
214
215		switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
216		case OFW_PCI_PHYS_HI_SPACE_CONFIG:
217			break;
218		case OFW_PCI_PHYS_HI_SPACE_IO:
219			error = rman_manage_region(&sc->sc_io_rman, rp->pci,
220			    rp->pci + rp->size - 1);
221			break;
222		case OFW_PCI_PHYS_HI_SPACE_MEM32:
223		case OFW_PCI_PHYS_HI_SPACE_MEM64:
224			error = rman_manage_region(&sc->sc_mem_rman, rp->pci,
225			    rp->pci + rp->size - 1);
226			break;
227		}
228
229		if (error) {
230			device_printf(dev,
231			    "rman_manage_region(%x, %#jx, %#jx) failed. "
232			    "error = %d\n", rp->pci_hi &
233			    OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
234			    rp->pci + rp->size - 1, error);
235			goto out;
236		}
237	}
238
239	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
240	return (0);
241
242out:
243	free(cell_info, M_DEVBUF);
244	free(sc->sc_range, M_DEVBUF);
245	rman_fini(&sc->sc_io_rman);
246	rman_fini(&sc->sc_mem_rman);
247
248	return (error);
249}
250
251int
252ofw_pci_attach(device_t dev)
253{
254	struct ofw_pci_softc *sc;
255	int error;
256
257	sc = device_get_softc(dev);
258	if (!sc->sc_initialized) {
259		error = ofw_pci_init(dev);
260		if (error)
261			return (error);
262	}
263
264	device_add_child(dev, "pci", -1);
265	return (bus_generic_attach(dev));
266}
267
268static int
269ofw_pci_maxslots(device_t dev)
270{
271
272	return (PCI_SLOTMAX);
273}
274
275int
276ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
277{
278	struct ofw_pci_softc *sc;
279	struct ofw_pci_register reg;
280	uint32_t pintr, mintr[PCI_MAP_INTR];
281	int intrcells;
282	phandle_t iparent;
283
284	sc = device_get_softc(bus);
285	pintr = pin;
286
287	/* Fabricate imap information in case this isn't an OFW device */
288	bzero(&reg, sizeof(reg));
289	reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
290	    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
291	    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
292
293	intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
294	    &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
295	    mintr, sizeof(mintr), &iparent);
296	if (intrcells != 0) {
297		pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
298		return (pintr);
299	}
300
301	/*
302	 * Maybe it's a real interrupt, not an intpin
303	 */
304	if (pin > PCI_INTR_PINS)
305		return (pin);
306
307	device_printf(bus, "could not route pin %d for device %d.%d\n",
308	    pin, pci_get_slot(dev), pci_get_function(dev));
309	return (PCI_INVALID_IRQ);
310}
311
312int
313ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
314{
315	struct ofw_pci_softc *sc;
316
317	sc = device_get_softc(dev);
318
319	switch (which) {
320	case PCIB_IVAR_DOMAIN:
321		*result = device_get_unit(dev);
322		return (0);
323	case PCIB_IVAR_BUS:
324		*result = sc->sc_bus;
325		return (0);
326	default:
327		break;
328	}
329
330	return (ENOENT);
331}
332
333int
334ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
335{
336	struct ofw_pci_softc *sc;
337
338	sc = device_get_softc(dev);
339
340	switch (which) {
341	case PCIB_IVAR_BUS:
342		sc->sc_bus = value;
343		return (0);
344	default:
345		break;
346	}
347
348	return (ENOENT);
349}
350
351int
352ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
353{
354	ssize_t nbase_ranges;
355
356	if (info == NULL)
357		return (-1);
358
359	info->host_address_cells = 1;
360	info->size_cells = 2;
361	info->pci_address_cell = 3;
362
363	OF_getencprop(OF_parent(node), "#address-cells",
364	    &(info->host_address_cells), sizeof(info->host_address_cells));
365	OF_getencprop(node, "#address-cells",
366	    &(info->pci_address_cell), sizeof(info->pci_address_cell));
367	OF_getencprop(node, "#size-cells", &(info->size_cells),
368	    sizeof(info->size_cells));
369
370	nbase_ranges = OF_getproplen(node, "ranges");
371	if (nbase_ranges <= 0)
372		return (-1);
373
374	return (nbase_ranges / sizeof(cell_t) /
375	    (info->pci_address_cell + info->host_address_cells +
376	    info->size_cells));
377}
378
379static struct resource *
380ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
381    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
382{
383	struct ofw_pci_softc *sc;
384	struct resource *rv;
385	struct rman *rm;
386	int needactivate;
387
388	needactivate = flags & RF_ACTIVE;
389	flags &= ~RF_ACTIVE;
390
391	sc = device_get_softc(bus);
392
393	switch (type) {
394	case SYS_RES_MEMORY:
395		rm = &sc->sc_mem_rman;
396		break;
397
398	case SYS_RES_IOPORT:
399		rm = &sc->sc_io_rman;
400		break;
401
402	case SYS_RES_IRQ:
403		return (bus_alloc_resource(bus, type, rid, start, end, count,
404		    flags));
405
406	default:
407		device_printf(bus, "unknown resource request from %s\n",
408		    device_get_nameunit(child));
409		return (NULL);
410	}
411
412	rv = rman_reserve_resource(rm, start, end, count, flags, child);
413	if (rv == NULL) {
414		device_printf(bus, "failed to reserve resource for %s\n",
415		    device_get_nameunit(child));
416		return (NULL);
417	}
418
419	rman_set_rid(rv, *rid);
420
421	if (needactivate) {
422		if (bus_activate_resource(child, type, *rid, rv) != 0) {
423			device_printf(bus,
424			    "failed to activate resource for %s\n",
425			    device_get_nameunit(child));
426			rman_release_resource(rv);
427			return (NULL);
428		}
429	}
430
431	return (rv);
432}
433
434static int
435ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
436    struct resource *res)
437{
438
439	if (rman_get_flags(res) & RF_ACTIVE) {
440		int error = bus_deactivate_resource(child, type, rid, res);
441		if (error)
442			return error;
443	}
444
445	return (rman_release_resource(res));
446}
447
448static int
449ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
450    struct resource *res)
451{
452	struct ofw_pci_softc *sc;
453	bus_space_handle_t handle;
454	bus_space_tag_t tag;
455	int rv;
456
457	sc = device_get_softc(bus);
458
459	if (type == SYS_RES_IRQ) {
460		return (bus_activate_resource(bus, type, rid, res));
461	}
462	if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
463		struct ofw_pci_range *rp;
464		vm_paddr_t start;
465		int space;
466
467		start = (vm_paddr_t)rman_get_start(res);
468
469		/*
470		 * Map this through the ranges list
471		 */
472		for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
473		    rp->pci_hi != 0; rp++) {
474			if (start < rp->pci || start >= rp->pci + rp->size)
475				continue;
476
477			switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
478			case OFW_PCI_PHYS_HI_SPACE_IO:
479				space = SYS_RES_IOPORT;
480				break;
481			case OFW_PCI_PHYS_HI_SPACE_MEM32:
482			case OFW_PCI_PHYS_HI_SPACE_MEM64:
483				space = SYS_RES_MEMORY;
484				break;
485			default:
486				space = -1;
487			}
488
489			if (type == space) {
490				start += (rp->host - rp->pci);
491				break;
492			}
493		}
494
495		if (bootverbose)
496			printf("ofw_pci mapdev: start %jx, len %jd\n",
497			    (rman_res_t)start, rman_get_size(res));
498
499		tag = BUS_GET_BUS_TAG(child, child);
500		if (tag == NULL)
501			return (ENOMEM);
502
503		rman_set_bustag(res, tag);
504		rv = bus_space_map(tag, start,
505		    rman_get_size(res), 0, &handle);
506		if (rv != 0)
507			return (ENOMEM);
508
509		rman_set_bushandle(res, handle);
510		rman_set_virtual(res, (void *)handle); /* XXX  for powerpc only ? */
511	}
512
513	return (rman_activate_resource(res));
514}
515
516#ifdef __powerpc__
517static bus_space_tag_t
518ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
519{
520
521	return (&bs_le_tag);
522}
523#endif
524
525static int
526ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
527    struct resource *res)
528{
529
530	/*
531	 * If this is a memory resource, unmap it.
532	 */
533	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
534		u_int32_t psize;
535
536		psize = rman_get_size(res);
537		pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
538	}
539
540	return (rman_deactivate_resource(res));
541}
542
543static int
544ofw_pci_adjust_resource(device_t bus, device_t child, int type,
545    struct resource *res, rman_res_t start, rman_res_t end)
546{
547	struct rman *rm = NULL;
548	struct ofw_pci_softc *sc = device_get_softc(bus);
549
550	KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
551	    ("active resources cannot be adjusted"));
552	if (rman_get_flags(res) & RF_ACTIVE)
553		return (EINVAL);
554
555	switch (type) {
556	case SYS_RES_MEMORY:
557		rm = &sc->sc_mem_rman;
558		break;
559	case SYS_RES_IOPORT:
560		rm = &sc->sc_io_rman;
561		break;
562	default:
563		return (ENXIO);
564	}
565
566	if (!rman_is_region_manager(res, rm))
567		return (EINVAL);
568
569	return (rman_adjust_resource(res, start, end));
570}
571
572static phandle_t
573ofw_pci_get_node(device_t bus, device_t dev)
574{
575	struct ofw_pci_softc *sc;
576
577	sc = device_get_softc(bus);
578	/* We only have one child, the PCI bus, which needs our own node. */
579
580	return (sc->sc_node);
581}
582
583static int
584ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
585{
586	int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
587	cell_t *base_ranges;
588	ssize_t nbase_ranges;
589	int nranges;
590	int i, j, k;
591
592	OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
593	    sizeof(host_address_cells));
594	OF_getencprop(node, "#address-cells", &pci_address_cells,
595	    sizeof(pci_address_cells));
596	OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
597
598	nbase_ranges = OF_getproplen(node, "ranges");
599	if (nbase_ranges <= 0)
600		return (-1);
601	nranges = nbase_ranges / sizeof(cell_t) /
602	    (pci_address_cells + host_address_cells + size_cells);
603
604	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
605	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
606
607	for (i = 0, j = 0; i < nranges; i++) {
608		ranges[i].pci_hi = base_ranges[j++];
609		ranges[i].pci = 0;
610		for (k = 0; k < pci_address_cells - 1; k++) {
611			ranges[i].pci <<= 32;
612			ranges[i].pci |= base_ranges[j++];
613		}
614		ranges[i].host = 0;
615		for (k = 0; k < host_address_cells; k++) {
616			ranges[i].host <<= 32;
617			ranges[i].host |= base_ranges[j++];
618		}
619		ranges[i].size = 0;
620		for (k = 0; k < size_cells; k++) {
621			ranges[i].size <<= 32;
622			ranges[i].size |= base_ranges[j++];
623		}
624	}
625
626	free(base_ranges, M_DEVBUF);
627	return (nranges);
628}
629