ebus_mainbus.c revision 1.1
11.1Smrg/*	$OpenBSD: ebus_mainbus.c,v 1.7 2010/11/11 17:58:23 miod Exp $	*/
21.1Smrg
31.1Smrg/*
41.1Smrg * Copyright (c) 2007 Mark Kettenis
51.1Smrg *
61.1Smrg * Permission to use, copy, modify, and distribute this software for any
71.1Smrg * purpose with or without fee is hereby granted, provided that the above
81.1Smrg * copyright notice and this permission notice appear in all copies.
91.1Smrg *
101.1Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111.1Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121.1Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131.1Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141.1Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151.1Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161.1Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171.1Smrg */
181.1Smrg
191.1Smrg#ifdef DEBUG
201.1Smrg#define	EDB_PROM	0x01
211.1Smrg#define EDB_CHILD	0x02
221.1Smrg#define	EDB_INTRMAP	0x04
231.1Smrg#define EDB_BUSMAP	0x08
241.1Smrg#define EDB_BUSDMA	0x10
251.1Smrg#define EDB_INTR	0x20
261.1Smrgextern int ebus_debug;
271.1Smrg#define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
281.1Smrg#else
291.1Smrg#define DPRINTF(l, s)
301.1Smrg#endif
311.1Smrg
321.1Smrg#include <sys/param.h>
331.1Smrg#include <sys/conf.h>
341.1Smrg#include <sys/device.h>
351.1Smrg#include <sys/errno.h>
361.1Smrg#include <sys/extent.h>
371.1Smrg#include <sys/malloc.h>
381.1Smrg#include <sys/systm.h>
391.1Smrg#include <sys/time.h>
401.1Smrg
411.1Smrg#define _SPARC_BUS_DMA_PRIVATE
421.1Smrg#include <machine/bus.h>
431.1Smrg#include <machine/autoconf.h>
441.1Smrg#include <machine/hypervisor.h>
451.1Smrg#include <machine/openfirm.h>
461.1Smrg
471.1Smrg#include <dev/pci/pcivar.h>
481.1Smrg
491.1Smrg#include <sparc64/dev/iommureg.h>
501.1Smrg#include <sparc64/dev/ebusreg.h>
511.1Smrg#include <sparc64/dev/ebusvar.h>
521.1Smrg#include <sparc64/dev/pyrovar.h>
531.1Smrg
541.1Smrgextern struct cfdriver pyro_cd;
551.1Smrg
561.1Smrgint	ebus_mainbus_match(struct device *, void *, void *);
571.1Smrgvoid	ebus_mainbus_attach(struct device *, struct device *, void *);
581.1Smrg
591.1Smrgstruct cfattach ebus_mainbus_ca = {
601.1Smrg	sizeof(struct ebus_softc), ebus_mainbus_match, ebus_mainbus_attach
611.1Smrg};
621.1Smrg
631.1Smrg
641.1Smrgint ebus_mainbus_bus_map(bus_space_tag_t, bus_space_tag_t,
651.1Smrg    bus_addr_t, bus_size_t, int, bus_space_handle_t *);
661.1Smrgvoid *ebus_mainbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
671.1Smrg    int, int, int, int (*)(void *), void *, const char *);
681.1Smrgbus_space_tag_t ebus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t);
691.1Smrgvoid ebus_mainbus_intr_ack(struct intrhand *);
701.1Smrg
711.1Smrgint
721.1Smrgebus_mainbus_match(struct device *parent, void *match, void *aux)
731.1Smrg{
741.1Smrg	struct mainbus_attach_args *ma = aux;
751.1Smrg
761.1Smrg	if (strcmp(ma->ma_name, "ebus") == 0)
771.1Smrg		return (1);
781.1Smrg	return (0);
791.1Smrg}
801.1Smrg
811.1Smrgvoid
821.1Smrgebus_mainbus_attach(struct device *parent, struct device *self, void *aux)
831.1Smrg{
841.1Smrg	struct ebus_softc *sc = (struct ebus_softc *)self;
851.1Smrg	struct mainbus_attach_args *ma = aux;
861.1Smrg	struct ebus_attach_args eba;
871.1Smrg	struct ebus_interrupt_map_mask *immp;
881.1Smrg	int node, nmapmask, error;
891.1Smrg	struct pyro_softc *psc;
901.1Smrg	int i;
911.1Smrg
921.1Smrg	sc->sc_node = node = ma->ma_node;
931.1Smrg	sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT);
941.1Smrg
951.1Smrg	if (CPU_ISSUN4U) {
961.1Smrg		printf(": ign %x", sc->sc_ign);
971.1Smrg
981.1Smrg		for (i = 0; i < pyro_cd.cd_ndevs; i++) {
991.1Smrg			psc = pyro_cd.cd_devs[i];
1001.1Smrg			if (psc && psc->sc_ign == sc->sc_ign) {
1011.1Smrg				sc->sc_bust = psc->sc_bust;
1021.1Smrg				sc->sc_csr = psc->sc_csr;
1031.1Smrg				sc->sc_csrh = psc->sc_csrh;
1041.1Smrg				break;
1051.1Smrg			}
1061.1Smrg		}
1071.1Smrg
1081.1Smrg		if (sc->sc_csr == 0) {
1091.1Smrg			printf(": can't find matching host bridge leaf\n");
1101.1Smrg			return;
1111.1Smrg		}
1121.1Smrg	}
1131.1Smrg
1141.1Smrg	printf("\n");
1151.1Smrg
1161.1Smrg	sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
1171.1Smrg	sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag);
1181.1Smrg	sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag);
1191.1Smrg
1201.1Smrg	/*
1211.1Smrg	 * fill in our softc with information from the prom
1221.1Smrg	 */
1231.1Smrg	sc->sc_intmap = NULL;
1241.1Smrg	sc->sc_range = NULL;
1251.1Smrg	error = getprop(node, "interrupt-map",
1261.1Smrg			sizeof(struct ebus_interrupt_map),
1271.1Smrg			&sc->sc_nintmap, (void **)&sc->sc_intmap);
1281.1Smrg	switch (error) {
1291.1Smrg	case 0:
1301.1Smrg		immp = &sc->sc_intmapmask;
1311.1Smrg		error = getprop(node, "interrupt-map-mask",
1321.1Smrg			    sizeof(struct ebus_interrupt_map_mask), &nmapmask,
1331.1Smrg			    (void **)&immp);
1341.1Smrg		if (error)
1351.1Smrg			panic("could not get ebus interrupt-map-mask");
1361.1Smrg		if (nmapmask != 1)
1371.1Smrg			panic("ebus interrupt-map-mask is broken");
1381.1Smrg		break;
1391.1Smrg	case ENOENT:
1401.1Smrg		break;
1411.1Smrg	default:
1421.1Smrg		panic("ebus interrupt-map: error %d", error);
1431.1Smrg		break;
1441.1Smrg	}
1451.1Smrg
1461.1Smrg	error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
1471.1Smrg	    &sc->sc_nrange, (void **)&sc->sc_range);
1481.1Smrg	if (error)
1491.1Smrg		panic("ebus ranges: error %d", error);
1501.1Smrg
1511.1Smrg	/*
1521.1Smrg	 * now attach all our children
1531.1Smrg	 */
1541.1Smrg	DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
1551.1Smrg	for (node = firstchild(node); node; node = nextsibling(node)) {
1561.1Smrg		if (ebus_setup_attach_args(sc, node, &eba) != 0) {
1571.1Smrg			DPRINTF(EDB_CHILD,
1581.1Smrg			    ("ebus_mainbus_attach: %s: incomplete\n",
1591.1Smrg			    getpropstring(node, "name")));
1601.1Smrg			continue;
1611.1Smrg		} else {
1621.1Smrg			DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
1631.1Smrg			    eba.ea_name));
1641.1Smrg			(void)config_found(self, &eba, ebus_print);
1651.1Smrg		}
1661.1Smrg		ebus_destroy_attach_args(&eba);
1671.1Smrg	}
1681.1Smrg}
1691.1Smrg
1701.1Smrgbus_space_tag_t
1711.1Smrgebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent)
1721.1Smrg{
1731.1Smrg	struct sparc_bus_space_tag *bt;
1741.1Smrg
1751.1Smrg	bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO);
1761.1Smrg	if (bt == NULL)
1771.1Smrg		panic("could not allocate ebus bus tag");
1781.1Smrg
1791.1Smrg	strlcpy(bt->name, sc->sc_dev.dv_xname, sizeof(bt->name));
1801.1Smrg	bt->cookie = sc;
1811.1Smrg	bt->parent = parent;
1821.1Smrg	bt->asi = parent->asi;
1831.1Smrg	bt->sasi = parent->sasi;
1841.1Smrg	bt->sparc_bus_map = ebus_mainbus_bus_map;
1851.1Smrg	bt->sparc_intr_establish = ebus_mainbus_intr_establish;
1861.1Smrg
1871.1Smrg	return (bt);
1881.1Smrg}
1891.1Smrg
1901.1Smrgint
1911.1Smrgebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset,
1921.1Smrg    bus_size_t size, int flags, bus_space_handle_t *hp)
1931.1Smrg{
1941.1Smrg	struct ebus_softc *sc = t->cookie;
1951.1Smrg	struct ebus_mainbus_ranges *range;
1961.1Smrg	bus_addr_t hi, lo;
1971.1Smrg	int i;
1981.1Smrg
1991.1Smrg	DPRINTF(EDB_BUSMAP,
2001.1Smrg	    ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
2011.1Smrg	    (unsigned long long)offset, (int)size, (int)flags));
2021.1Smrg
2031.1Smrg	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
2041.1Smrg		printf("\n_ebus_mainbus_bus_map: invalid parent");
2051.1Smrg		return (EINVAL);
2061.1Smrg	}
2071.1Smrg
2081.1Smrg	t = t->parent;
2091.1Smrg
2101.1Smrg	if (flags & BUS_SPACE_MAP_PROMADDRESS) {
2111.1Smrg		return ((*t->sparc_bus_map)
2121.1Smrg		    (t, t0, offset, size, flags, hp));
2131.1Smrg	}
2141.1Smrg
2151.1Smrg	hi = offset >> 32UL;
2161.1Smrg	lo = offset & 0xffffffff;
2171.1Smrg	range = (struct ebus_mainbus_ranges *)sc->sc_range;
2181.1Smrg
2191.1Smrg	DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
2201.1Smrg	for (i = 0; i < sc->sc_nrange; i++) {
2211.1Smrg		bus_addr_t addr;
2221.1Smrg
2231.1Smrg		if (hi != range[i].child_hi)
2241.1Smrg			continue;
2251.1Smrg		if (lo < range[i].child_lo ||
2261.1Smrg		    (lo + size) > (range[i].child_lo + range[i].size))
2271.1Smrg			continue;
2281.1Smrg
2291.1Smrg		addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
2301.1Smrg				    range[i].phys_lo;
2311.1Smrg		addr += lo;
2321.1Smrg		DPRINTF(EDB_BUSMAP,
2331.1Smrg		    ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
2341.1Smrg		    (unsigned long long)offset, (unsigned long long)addr));
2351.1Smrg                return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp));
2361.1Smrg	}
2371.1Smrg	DPRINTF(EDB_BUSMAP, (": FAILED\n"));
2381.1Smrg	return (EINVAL);
2391.1Smrg}
2401.1Smrg
2411.1Smrgvoid *
2421.1Smrgebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle,
2431.1Smrg    int level, int flags, int (*handler)(void *), void *arg, const char *what)
2441.1Smrg{
2451.1Smrg	struct ebus_softc *sc = t->cookie;
2461.1Smrg	struct intrhand *ih = NULL;
2471.1Smrg	volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL;
2481.1Smrg	int ino;
2491.1Smrg
2501.1Smrg#ifdef SUN4V
2511.1Smrg	if (CPU_ISSUN4V) {
2521.1Smrg		struct upa_reg reg;
2531.1Smrg		u_int64_t devhandle, devino = INTINO(ihandle);
2541.1Smrg		u_int64_t sysino;
2551.1Smrg		int node = -1;
2561.1Smrg		int i, err;
2571.1Smrg
2581.1Smrg		for (i = 0; i < sc->sc_nintmap; i++) {
2591.1Smrg			if (sc->sc_intmap[i].cintr == ihandle) {
2601.1Smrg				node = sc->sc_intmap[i].cnode;
2611.1Smrg				break;
2621.1Smrg			}
2631.1Smrg		}
2641.1Smrg		if (node == -1)
2651.1Smrg			return (NULL);
2661.1Smrg
2671.1Smrg		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
2681.1Smrg			return (NULL);
2691.1Smrg		devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
2701.1Smrg
2711.1Smrg		err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
2721.1Smrg		if (err != H_EOK)
2731.1Smrg			return (NULL);
2741.1Smrg
2751.1Smrg		KASSERT(sysino == INTVEC(sysino));
2761.1Smrg		ih = bus_intr_allocate(t0, handler, arg, sysino, level,
2771.1Smrg		    NULL, NULL, what);
2781.1Smrg		if (ih == NULL)
2791.1Smrg			return (NULL);
2801.1Smrg
2811.1Smrg		intr_establish(ih->ih_pil, ih);
2821.1Smrg		ih->ih_ack = ebus_mainbus_intr_ack;
2831.1Smrg
2841.1Smrg		err = hv_intr_settarget(sysino, cpus->ci_upaid);
2851.1Smrg		if (err != H_EOK)
2861.1Smrg			return (NULL);
2871.1Smrg
2881.1Smrg		/* Clear pending interrupts. */
2891.1Smrg		err = hv_intr_setstate(sysino, INTR_IDLE);
2901.1Smrg		if (err != H_EOK)
2911.1Smrg			return (NULL);
2921.1Smrg
2931.1Smrg		err = hv_intr_setenabled(sysino, INTR_ENABLED);
2941.1Smrg		if (err != H_EOK)
2951.1Smrg			return (NULL);
2961.1Smrg
2971.1Smrg		return (ih);
2981.1Smrg	}
2991.1Smrg#endif
3001.1Smrg
3011.1Smrg	ihandle |= sc->sc_ign;
3021.1Smrg	ino = INTINO(ihandle);
3031.1Smrg
3041.1Smrg	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) {
3051.1Smrg		u_int64_t *imap, *iclr;
3061.1Smrg
3071.1Smrg		/* XXX */
3081.1Smrg		imap = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1000;
3091.1Smrg		iclr = bus_space_vaddr(sc->sc_bust, sc->sc_csrh) + 0x1400;
3101.1Smrg		intrmapptr = &imap[ino];
3111.1Smrg		intrclrptr = &iclr[ino];
3121.1Smrg		ino |= INTVEC(ihandle);
3131.1Smrg	}
3141.1Smrg
3151.1Smrg	ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr,
3161.1Smrg	    intrclrptr, what);
3171.1Smrg	if (ih == NULL)
3181.1Smrg		return (NULL);
3191.1Smrg
3201.1Smrg	intr_establish(ih->ih_pil, ih);
3211.1Smrg
3221.1Smrg	if (intrmapptr != NULL) {
3231.1Smrg		u_int64_t intrmap;
3241.1Smrg
3251.1Smrg		intrmap = *intrmapptr;
3261.1Smrg		intrmap |= (1LL << 6);
3271.1Smrg		intrmap |= INTMAP_V;
3281.1Smrg		*intrmapptr = intrmap;
3291.1Smrg		intrmap = *intrmapptr;
3301.1Smrg		ih->ih_number |= intrmap & INTMAP_INR;
3311.1Smrg	}
3321.1Smrg
3331.1Smrg	return (ih);
3341.1Smrg}
3351.1Smrg
3361.1Smrg#ifdef SUN4V
3371.1Smrg
3381.1Smrgvoid
3391.1Smrgebus_mainbus_intr_ack(struct intrhand *ih)
3401.1Smrg{
3411.1Smrg	hv_intr_setstate(ih->ih_number, INTR_IDLE);
3421.1Smrg}
3431.1Smrg
3441.1Smrg#endif
345