ebus_mainbus.c revision 1.12
11.12Spalle/*	$NetBSD: ebus_mainbus.c,v 1.12 2013/12/16 20:17:35 palle Exp $	*/
21.1Smrg/*	$OpenBSD: ebus_mainbus.c,v 1.7 2010/11/11 17:58:23 miod Exp $	*/
31.1Smrg
41.1Smrg/*
51.1Smrg * Copyright (c) 2007 Mark Kettenis
61.1Smrg *
71.1Smrg * Permission to use, copy, modify, and distribute this software for any
81.1Smrg * purpose with or without fee is hereby granted, provided that the above
91.1Smrg * copyright notice and this permission notice appear in all copies.
101.1Smrg *
111.1Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
121.1Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
131.1Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
141.1Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
151.1Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
161.1Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
171.1Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181.1Smrg */
191.1Smrg
201.9Smrg#include <sys/cdefs.h>
211.12Spalle__KERNEL_RCSID(0, "$NetBSD: ebus_mainbus.c,v 1.12 2013/12/16 20:17:35 palle Exp $");
221.9Smrg
231.1Smrg#ifdef DEBUG
241.1Smrg#define	EDB_PROM	0x01
251.1Smrg#define EDB_CHILD	0x02
261.1Smrg#define	EDB_INTRMAP	0x04
271.1Smrg#define EDB_BUSMAP	0x08
281.1Smrg#define EDB_BUSDMA	0x10
291.1Smrg#define EDB_INTR	0x20
301.1Smrgextern int ebus_debug;
311.1Smrg#define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
321.1Smrg#else
331.1Smrg#define DPRINTF(l, s)
341.1Smrg#endif
351.1Smrg
361.1Smrg#include <sys/param.h>
371.1Smrg#include <sys/conf.h>
381.1Smrg#include <sys/device.h>
391.1Smrg#include <sys/errno.h>
401.1Smrg#include <sys/extent.h>
411.1Smrg#include <sys/malloc.h>
421.1Smrg#include <sys/systm.h>
431.1Smrg#include <sys/time.h>
441.1Smrg
451.1Smrg#define _SPARC_BUS_DMA_PRIVATE
461.5Sdyoung#include <sys/bus.h>
471.1Smrg#include <machine/autoconf.h>
481.1Smrg#include <machine/openfirm.h>
491.1Smrg
501.1Smrg#include <dev/pci/pcivar.h>
511.1Smrg
521.1Smrg#include <sparc64/dev/iommureg.h>
531.2Smrg#include <sparc64/dev/iommuvar.h>
541.2Smrg#include <sparc64/dev/pyrovar.h>
551.2Smrg#include <dev/ebus/ebusreg.h>
561.2Smrg#include <dev/ebus/ebusvar.h>
571.1Smrg#include <sparc64/dev/ebusvar.h>
581.1Smrg
591.4Schristosint	ebus_mainbus_match(device_t, cfdata_t, void *);
601.4Schristosvoid	ebus_mainbus_attach(device_t, device_t, void *);
611.1Smrg
621.4SchristosCFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc),
631.2Smrg    ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL);
641.1Smrg
651.7Smrgstatic int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
661.7Smrg	vaddr_t, bus_space_handle_t *);
671.7Smrgstatic void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int,
681.2Smrg	int (*)(void *), void *, void (*)(void));
691.7Smrgstatic bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *,
701.7Smrg	bus_space_tag_t, int);
711.7Smrg#ifdef SUN4V
721.12Spalle#if 0
731.12SpalleXXX
741.7Smrgstatic void ebus_mainbus_intr_ack(struct intrhand *);
751.7Smrg#endif
761.12Spalle#endif
771.1Smrgint
781.10Schsebus_mainbus_match(device_t parent, cfdata_t cf, void *aux)
791.1Smrg{
801.1Smrg	struct mainbus_attach_args *ma = aux;
811.1Smrg
821.1Smrg	if (strcmp(ma->ma_name, "ebus") == 0)
831.1Smrg		return (1);
841.1Smrg	return (0);
851.1Smrg}
861.1Smrg
871.1Smrgvoid
881.10Schsebus_mainbus_attach(device_t parent, device_t self, void *aux)
891.1Smrg{
901.4Schristos	struct ebus_softc *sc = device_private(self);
911.1Smrg	struct mainbus_attach_args *ma = aux;
921.1Smrg	struct ebus_attach_args eba;
931.1Smrg	struct ebus_interrupt_map_mask *immp;
941.1Smrg	int node, nmapmask, error;
951.1Smrg	struct pyro_softc *psc;
961.1Smrg	int i;
971.1Smrg
981.4Schristos	sc->sc_dev = self;
991.1Smrg	sc->sc_node = node = ma->ma_node;
1001.1Smrg	sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
1011.1Smrg
1021.1Smrg	if (CPU_ISSUN4U) {
1031.1Smrg		printf(": ign %x", sc->sc_ign);
1041.2Smrg		/* XXX */
1051.2Smrg		extern struct cfdriver pyro_cd;
1061.1Smrg
1071.1Smrg		for (i = 0; i < pyro_cd.cd_ndevs; i++) {
1081.2Smrg			device_t dt = pyro_cd.cd_devs[i];
1091.6Smrg			psc = device_private(dt);
1101.1Smrg			if (psc && psc->sc_ign == sc->sc_ign) {
1111.2Smrg				sc->sc_bust = psc->sc_bustag;
1121.1Smrg				sc->sc_csr = psc->sc_csr;
1131.1Smrg				sc->sc_csrh = psc->sc_csrh;
1141.1Smrg				break;
1151.1Smrg			}
1161.1Smrg		}
1171.1Smrg
1181.1Smrg		if (sc->sc_csr == 0) {
1191.1Smrg			printf(": can't find matching host bridge leaf\n");
1201.1Smrg			return;
1211.1Smrg		}
1221.1Smrg	}
1231.1Smrg
1241.1Smrg	printf("\n");
1251.1Smrg
1261.7Smrg	sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
1271.7Smrg						   PCI_MEMORY_BUS_SPACE);
1281.7Smrg	sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
1291.7Smrg						  PCI_IO_BUS_SPACE);
1301.2Smrg	sc->sc_childbustag = sc->sc_memtag;
1311.2Smrg	sc->sc_dmatag = ma->ma_dmatag;
1321.1Smrg
1331.1Smrg	/*
1341.1Smrg	 * fill in our softc with information from the prom
1351.1Smrg	 */
1361.1Smrg	sc->sc_intmap = NULL;
1371.1Smrg	sc->sc_range = NULL;
1381.2Smrg	error = prom_getprop(node, "interrupt-map",
1391.1Smrg			sizeof(struct ebus_interrupt_map),
1401.1Smrg			&sc->sc_nintmap, (void **)&sc->sc_intmap);
1411.1Smrg	switch (error) {
1421.1Smrg	case 0:
1431.1Smrg		immp = &sc->sc_intmapmask;
1441.7Smrg		nmapmask = 1;
1451.2Smrg		error = prom_getprop(node, "interrupt-map-mask",
1461.1Smrg			    sizeof(struct ebus_interrupt_map_mask), &nmapmask,
1471.1Smrg			    (void **)&immp);
1481.1Smrg		if (error)
1491.7Smrg			panic("could not get ebus interrupt-map-mask: error %d",
1501.7Smrg			      error);
1511.1Smrg		if (nmapmask != 1)
1521.1Smrg			panic("ebus interrupt-map-mask is broken");
1531.1Smrg		break;
1541.1Smrg	case ENOENT:
1551.1Smrg		break;
1561.1Smrg	default:
1571.1Smrg		panic("ebus interrupt-map: error %d", error);
1581.1Smrg		break;
1591.1Smrg	}
1601.1Smrg
1611.2Smrg	error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
1621.1Smrg	    &sc->sc_nrange, (void **)&sc->sc_range);
1631.1Smrg	if (error)
1641.1Smrg		panic("ebus ranges: error %d", error);
1651.1Smrg
1661.1Smrg	/*
1671.1Smrg	 * now attach all our children
1681.1Smrg	 */
1691.1Smrg	DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
1701.1Smrg	for (node = firstchild(node); node; node = nextsibling(node)) {
1711.1Smrg		if (ebus_setup_attach_args(sc, node, &eba) != 0) {
1721.1Smrg			DPRINTF(EDB_CHILD,
1731.1Smrg			    ("ebus_mainbus_attach: %s: incomplete\n",
1741.2Smrg			    prom_getpropstring(node, "name")));
1751.1Smrg			continue;
1761.1Smrg		} else {
1771.1Smrg			DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
1781.1Smrg			    eba.ea_name));
1791.1Smrg			(void)config_found(self, &eba, ebus_print);
1801.1Smrg		}
1811.1Smrg		ebus_destroy_attach_args(&eba);
1821.1Smrg	}
1831.1Smrg}
1841.1Smrg
1851.7Smrgstatic bus_space_tag_t
1861.7Smrgebus_mainbus_alloc_bus_tag(struct ebus_softc *sc,
1871.7Smrg			   bus_space_tag_t parent,
1881.7Smrg			   int type)
1891.1Smrg{
1901.1Smrg	struct sparc_bus_space_tag *bt;
1911.1Smrg
1921.1Smrg	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
1931.1Smrg	if (bt == NULL)
1941.1Smrg		panic("could not allocate ebus bus tag");
1951.1Smrg
1961.1Smrg	bt->cookie = sc;
1971.1Smrg	bt->parent = parent;
1981.2Smrg	bt->type = type;
1991.1Smrg	bt->sparc_bus_map = ebus_mainbus_bus_map;
2001.2Smrg	bt->sparc_bus_mmap = ebus_bus_mmap;
2011.1Smrg	bt->sparc_intr_establish = ebus_mainbus_intr_establish;
2021.1Smrg
2031.1Smrg	return (bt);
2041.1Smrg}
2051.1Smrg
2061.1Smrgint
2071.2Smrgebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size,
2081.2Smrg	int flags, vaddr_t va, bus_space_handle_t *hp)
2091.1Smrg{
2101.1Smrg	struct ebus_softc *sc = t->cookie;
2111.1Smrg	struct ebus_mainbus_ranges *range;
2121.1Smrg	bus_addr_t hi, lo;
2131.11Smartin	int i;
2141.11Smartin#if 0
2151.11Smartin	int ss;
2161.11Smartin#endif
2171.1Smrg
2181.1Smrg	DPRINTF(EDB_BUSMAP,
2191.1Smrg	    ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
2201.1Smrg	    (unsigned long long)offset, (int)size, (int)flags));
2211.1Smrg
2221.1Smrg	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
2231.1Smrg		printf("\n_ebus_mainbus_bus_map: invalid parent");
2241.1Smrg		return (EINVAL);
2251.1Smrg	}
2261.1Smrg
2271.1Smrg	t = t->parent;
2281.1Smrg
2291.1Smrg	hi = offset >> 32UL;
2301.1Smrg	lo = offset & 0xffffffff;
2311.1Smrg	range = (struct ebus_mainbus_ranges *)sc->sc_range;
2321.1Smrg
2331.1Smrg	DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
2341.1Smrg	for (i = 0; i < sc->sc_nrange; i++) {
2351.1Smrg		bus_addr_t addr;
2361.1Smrg
2371.1Smrg		if (hi != range[i].child_hi)
2381.1Smrg			continue;
2391.1Smrg		if (lo < range[i].child_lo ||
2401.1Smrg		    (lo + size) > (range[i].child_lo + range[i].size))
2411.1Smrg			continue;
2421.1Smrg
2431.2Smrg#if 0
2441.2Smrg		/* Isolate address space and find the right tag */
2451.2Smrg		ss = (range[i].phys_hi>>24)&3;
2461.2Smrg		switch (ss) {
2471.2Smrg		case 1:	/* I/O space */
2481.2Smrg			t = sc->sc_iotag;
2491.2Smrg			break;
2501.2Smrg		case 2:	/* Memory space */
2511.2Smrg			t = sc->sc_memtag;
2521.2Smrg			break;
2531.2Smrg		case 0:	/* Config space */
2541.2Smrg		case 3:	/* 64-bit Memory space */
2551.2Smrg		default: /* WTF? */
2561.2Smrg			/* We don't handle these */
2571.2Smrg			panic("ebus_mainbus_bus_map: illegal space %x", ss);
2581.2Smrg			break;
2591.2Smrg		}
2601.2Smrg#endif
2611.2Smrg
2621.1Smrg		addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
2631.1Smrg				    range[i].phys_lo;
2641.1Smrg		addr += lo;
2651.1Smrg		DPRINTF(EDB_BUSMAP,
2661.1Smrg		    ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
2671.1Smrg		    (unsigned long long)offset, (unsigned long long)addr));
2681.2Smrg		return (bus_space_map(t, addr, size, flags, hp));
2691.1Smrg	}
2701.1Smrg	DPRINTF(EDB_BUSMAP, (": FAILED\n"));
2711.1Smrg	return (EINVAL);
2721.1Smrg}
2731.1Smrg
2741.7Smrgstatic void *
2751.2Smrgebus_mainbus_intr_establish(bus_space_tag_t t, int ihandle, int level,
2761.2Smrg	int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */)
2771.1Smrg{
2781.1Smrg	struct ebus_softc *sc = t->cookie;
2791.1Smrg	struct intrhand *ih = NULL;
2801.1Smrg	volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
2811.2Smrg	u_int64_t *imap, *iclr;
2821.1Smrg	int ino;
2831.1Smrg
2841.1Smrg#ifdef SUN4V
2851.12Spalle#if 0
2861.12SpalleXXX
2871.1Smrg	if (CPU_ISSUN4V) {
2881.1Smrg		struct upa_reg reg;
2891.1Smrg		u_int64_t devhandle, devino = INTINO(ihandle);
2901.1Smrg		u_int64_t sysino;
2911.1Smrg		int node = -1;
2921.1Smrg		int i, err;
2931.1Smrg
2941.1Smrg		for (i = 0; i < sc->sc_nintmap; i++) {
2951.1Smrg			if (sc->sc_intmap[i].cintr == ihandle) {
2961.1Smrg				node = sc->sc_intmap[i].cnode;
2971.1Smrg				break;
2981.1Smrg			}
2991.1Smrg		}
3001.1Smrg		if (node == -1)
3011.1Smrg			return (NULL);
3021.1Smrg
3031.1Smrg		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
3041.1Smrg			return (NULL);
3051.1Smrg		devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
3061.1Smrg
3071.1Smrg		err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
3081.1Smrg		if (err != H_EOK)
3091.1Smrg			return (NULL);
3101.1Smrg
3111.1Smrg		KASSERT(sysino == INTVEC(sysino));
3121.1Smrg		ih = bus_intr_allocate(t0, handler, arg, sysino, level,
3131.1Smrg		    NULL, NULL, what);
3141.1Smrg		if (ih == NULL)
3151.1Smrg			return (NULL);
3161.1Smrg
3171.1Smrg		intr_establish(ih->ih_pil, ih);
3181.1Smrg		ih->ih_ack = ebus_mainbus_intr_ack;
3191.1Smrg
3201.1Smrg		err = hv_intr_settarget(sysino, cpus->ci_upaid);
3211.1Smrg		if (err != H_EOK)
3221.1Smrg			return (NULL);
3231.1Smrg
3241.1Smrg		/* Clear pending interrupts. */
3251.1Smrg		err = hv_intr_setstate(sysino, INTR_IDLE);
3261.1Smrg		if (err != H_EOK)
3271.1Smrg			return (NULL);
3281.1Smrg
3291.1Smrg		err = hv_intr_setenabled(sysino, INTR_ENABLED);
3301.1Smrg		if (err != H_EOK)
3311.1Smrg			return (NULL);
3321.1Smrg
3331.1Smrg		return (ih);
3341.1Smrg	}
3351.1Smrg#endif
3361.12Spalle#endif
3371.1Smrg	ihandle |= sc->sc_ign;
3381.1Smrg	ino = INTINO(ihandle);
3391.1Smrg
3401.2Smrg	/* XXX */
3411.2Smrg	imap = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1000);
3421.2Smrg	iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1400);
3431.2Smrg	intrmapptr = &imap[ino];
3441.2Smrg	intrclrptr = &iclr[ino];
3451.2Smrg	ino |= INTVEC(ihandle);
3461.1Smrg
3471.2Smrg	ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT);
3481.1Smrg	if (ih == NULL)
3491.1Smrg		return (NULL);
3501.1Smrg
3511.2Smrg	/* Register the map and clear intr registers */
3521.2Smrg	ih->ih_map = intrmapptr;
3531.2Smrg	ih->ih_clr = intrclrptr;
3541.2Smrg
3551.8Smrg	ih->ih_ivec = ihandle;
3561.2Smrg	ih->ih_fun = handler;
3571.2Smrg	ih->ih_arg = arg;
3581.2Smrg	ih->ih_pil = level;
3591.2Smrg	ih->ih_number = ino;
3601.7Smrg	ih->ih_pending = 0;
3611.2Smrg
3621.2Smrg	intr_establish(ih->ih_pil, level != IPL_VM, ih);
3631.1Smrg
3641.1Smrg	if (intrmapptr != NULL) {
3651.2Smrg		u_int64_t imapval;
3661.1Smrg
3671.2Smrg		imapval = *intrmapptr;
3681.2Smrg		imapval |= (1LL << 6);
3691.2Smrg		imapval |= INTMAP_V;
3701.2Smrg		*intrmapptr = imapval;
3711.2Smrg		imapval = *intrmapptr;
3721.2Smrg		ih->ih_number |= imapval & INTMAP_INR;
3731.1Smrg	}
3741.1Smrg
3751.1Smrg	return (ih);
3761.1Smrg}
3771.1Smrg
3781.1Smrg#ifdef SUN4V
3791.12Spalle#if 0
3801.12SpalleXXX
3811.7Smrgstatic void
3821.1Smrgebus_mainbus_intr_ack(struct intrhand *ih)
3831.1Smrg{
3841.1Smrg	hv_intr_setstate(ih->ih_number, INTR_IDLE);
3851.1Smrg}
3861.12Spalle#endif
3871.1Smrg#endif
388