Home | History | Annotate | Line # | Download | only in dev
      1 /*	$NetBSD: ebus_mainbus.c,v 1.24 2026/09/25 07:17:17 jdc Exp $	*/
      2 /*	$OpenBSD: ebus_mainbus.c,v 1.7 2010/11/11 17:58:23 miod Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2007 Mark Kettenis
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __KERNEL_RCSID(0, "$NetBSD: ebus_mainbus.c,v 1.24 2026/09/25 07:17:17 jdc Exp $");
     22 
     23 #ifdef DEBUG
     24 #define	EDB_PROM	0x01
     25 #define EDB_CHILD	0x02
     26 #define	EDB_INTRMAP	0x04
     27 #define EDB_BUSMAP	0x08
     28 #define EDB_BUSDMA	0x10
     29 #define EDB_INTR	0x20
     30 extern int ebus_debug;
     31 #define DPRINTF(l, s)   do { if (ebus_debug & l) printf s; } while (0)
     32 #else
     33 #define DPRINTF(l, s)
     34 #endif
     35 
     36 #include <sys/param.h>
     37 #include <sys/conf.h>
     38 #include <sys/device.h>
     39 #include <sys/errno.h>
     40 #include <sys/extent.h>
     41 #include <sys/kmem.h>
     42 #include <sys/systm.h>
     43 #include <sys/time.h>
     44 
     45 #define _SPARC_BUS_DMA_PRIVATE
     46 #include <sys/bus.h>
     47 #include <machine/autoconf.h>
     48 #include <machine/openfirm.h>
     49 
     50 #include <dev/pci/pcivar.h>
     51 
     52 #include <sparc64/dev/iommureg.h>
     53 #include <sparc64/dev/iommuvar.h>
     54 #include <sparc64/dev/pyrovar.h>
     55 #include <dev/ebus/ebusreg.h>
     56 #include <dev/ebus/ebusvar.h>
     57 #include <sparc64/dev/ebusvar.h>
     58 
     59 #include "ioconf.h"
     60 
     61 int	ebus_mainbus_match(device_t, cfdata_t, void *);
     62 void	ebus_mainbus_attach(device_t, device_t, void *);
     63 
     64 CFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc),
     65     ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL);
     66 
     67 static int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
     68 	vaddr_t, bus_space_handle_t *);
     69 static void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int,
     70 	int (*)(void *), void *, void (*)(void));
     71 static bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *,
     72 	bus_space_tag_t, int);
     73 #ifdef SUN4V
     74 #if 0
     75 XXX
     76 static void ebus_mainbus_intr_ack(struct intrhand *);
     77 #endif
     78 #endif
     79 int
     80 ebus_mainbus_match(device_t parent, cfdata_t cf, void *aux)
     81 {
     82 	struct mainbus_attach_args *ma = aux;
     83 
     84 	if (strcmp(ma->ma_name, "ebus") == 0)
     85 		return (1);
     86 	return (0);
     87 }
     88 
     89 void
     90 ebus_mainbus_attach(device_t parent, device_t self, void *aux)
     91 {
     92 	struct ebus_softc *sc = device_private(self);
     93 	struct mainbus_attach_args *ma = aux;
     94 	struct ebus_attach_args eba;
     95 	struct ebus_interrupt_map_mask *immp;
     96 	int node, nmapmask, error;
     97 	struct pyro_softc *psc;
     98 	int i, j;
     99 
    100 	sc->sc_dev = self;
    101 
    102 	printf("\n");
    103 
    104 	sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
    105 						   PCI_MEMORY_BUS_SPACE);
    106 	sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag,
    107 						  PCI_IO_BUS_SPACE);
    108 	sc->sc_childbustag = sc->sc_memtag;
    109 	sc->sc_dmatag = ma->ma_dmatag;
    110 
    111 	sc->sc_node = node = ma->ma_node;
    112 
    113 	/*
    114 	 * fill in our softc with information from the prom
    115 	 */
    116 	sc->sc_intmap = NULL;
    117 	sc->sc_range = NULL;
    118 	error = prom_getprop(node, "interrupt-map",
    119 			sizeof(struct ebus_interrupt_map),
    120 			&sc->sc_nintmap, (void **)&sc->sc_intmap);
    121 	switch (error) {
    122 	case 0:
    123 		immp = &sc->sc_intmapmask;
    124 		nmapmask = 1;
    125 		error = prom_getprop(node, "interrupt-map-mask",
    126 			    sizeof(struct ebus_interrupt_map_mask), &nmapmask,
    127 			    (void **)&immp);
    128 		if (error)
    129 			panic("could not get ebus interrupt-map-mask: error %d",
    130 			      error);
    131 		if (nmapmask != 1)
    132 			panic("ebus interrupt-map-mask is broken");
    133 		break;
    134 	case ENOENT:
    135 		break;
    136 	default:
    137 		panic("ebus interrupt-map: error %d", error);
    138 		break;
    139 	}
    140 
    141 	/*
    142 	 * Ebus interrupts may be connected to any of the PCI Express
    143 	 * leafs.  Here we add the appropriate IGN to the interrupt
    144 	 * mappings such that we can use it to distinguish between
    145 	 * interrupts connected to PCIE-A and PCIE-B.
    146 	 */
    147 	for (i = 0; i < sc->sc_nintmap; i++) {
    148 		for (j = 0; j < pyro_cd.cd_ndevs; j++) {
    149 			device_t dt = device_lookup(&pyro_cd, j);
    150 			psc = device_private(dt);
    151 			if (psc && psc->sc_node == sc->sc_intmap[i].cnode) {
    152 				sc->sc_intmap[i].cintr |= psc->sc_ign;
    153 				break;
    154 			}
    155 		}
    156 	}
    157 
    158 	error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges),
    159 	    &sc->sc_nrange, (void **)&sc->sc_range);
    160 	if (error)
    161 		panic("ebus ranges: error %d", error);
    162 
    163 	/*
    164 	 * now attach all our children
    165 	 */
    166 	DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
    167 	devhandle_t selfh = device_handle(self);
    168 	for (node = firstchild(node); node; node = nextsibling(node)) {
    169 		if (ebus_setup_attach_args(sc, node, &eba) != 0) {
    170 			DPRINTF(EDB_CHILD,
    171 			    ("ebus_mainbus_attach: %s: incomplete\n",
    172 			    prom_getpropstring(node, "name")));
    173 			continue;
    174 		} else {
    175 			DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n",
    176 			    eba.ea_name));
    177 			(void)config_found(self, &eba, ebus_print,
    178 			    CFARGS(.devhandle = prom_node_to_devhandle(selfh,
    179 								       node)));
    180 		}
    181 		ebus_destroy_attach_args(&eba);
    182 	}
    183 }
    184 
    185 static bus_space_tag_t
    186 ebus_mainbus_alloc_bus_tag(struct ebus_softc *sc,
    187 			   bus_space_tag_t parent,
    188 			   int type)
    189 {
    190 	struct sparc_bus_space_tag *bt;
    191 
    192 	bt = kmem_zalloc(sizeof(*bt), KM_SLEEP);
    193 	bt->cookie = sc;
    194 	bt->parent = parent;
    195 	bt->type = type;
    196 	bt->sparc_bus_map = ebus_mainbus_bus_map;
    197 	bt->sparc_bus_mmap = ebus_bus_mmap;
    198 	bt->sparc_intr_establish = ebus_mainbus_intr_establish;
    199 
    200 	return (bt);
    201 }
    202 
    203 int
    204 ebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size,
    205 	int flags, vaddr_t va, bus_space_handle_t *hp)
    206 {
    207 	struct ebus_softc *sc = t->cookie;
    208 	struct ebus_mainbus_ranges *range;
    209 	bus_addr_t hi, lo;
    210 	int i;
    211 #if 0
    212 	int ss;
    213 #endif
    214 
    215 	DPRINTF(EDB_BUSMAP,
    216 	    ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d",
    217 	    (unsigned long long)offset, (int)size, (int)flags));
    218 
    219 	if (t->parent == 0 || t->parent->sparc_bus_map == 0) {
    220 		printf("\n_ebus_mainbus_bus_map: invalid parent");
    221 		return (EINVAL);
    222 	}
    223 
    224 	t = t->parent;
    225 
    226 	hi = offset >> 32UL;
    227 	lo = offset & 0xffffffff;
    228 	range = (struct ebus_mainbus_ranges *)sc->sc_range;
    229 
    230 	DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo));
    231 	for (i = 0; i < sc->sc_nrange; i++) {
    232 		bus_addr_t addr;
    233 
    234 		if (hi != range[i].child_hi)
    235 			continue;
    236 		if (lo < range[i].child_lo ||
    237 		    (lo + size) > (range[i].child_lo + range[i].size))
    238 			continue;
    239 
    240 #if 0
    241 		/* Isolate address space and find the right tag */
    242 		ss = (range[i].phys_hi>>24)&3;
    243 		switch (ss) {
    244 		case 1:	/* I/O space */
    245 			t = sc->sc_iotag;
    246 			break;
    247 		case 2:	/* Memory space */
    248 			t = sc->sc_memtag;
    249 			break;
    250 		case 0:	/* Config space */
    251 		case 3:	/* 64-bit Memory space */
    252 		default: /* WTF? */
    253 			/* We don't handle these */
    254 			panic("ebus_mainbus_bus_map: illegal space %x", ss);
    255 			break;
    256 		}
    257 #endif
    258 
    259 		addr = ((bus_addr_t)range[i].phys_hi << 32UL) |
    260 				    range[i].phys_lo;
    261 		addr += lo;
    262 		DPRINTF(EDB_BUSMAP,
    263 		    ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n",
    264 		    (unsigned long long)offset, (unsigned long long)addr));
    265 		return (bus_space_map(t, addr, size, flags, hp));
    266 	}
    267 	DPRINTF(EDB_BUSMAP, (": FAILED\n"));
    268 	return (EINVAL);
    269 }
    270 
    271 static void *
    272 ebus_mainbus_intr_establish(bus_space_tag_t t, int ihandle, int level,
    273 	int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */)
    274 {
    275 	struct pyro_softc *psc = NULL;
    276 	int i;
    277 
    278 #if 0
    279 XXX
    280 	if (CPU_ISSUN4V) {
    281 		struct upa_reg reg;
    282 		u_int64_t devhandle, devino = INTINO(ihandle);
    283 		u_int64_t sysino;
    284 		int node = -1;
    285 		int i, err;
    286 
    287 		for (i = 0; i < sc->sc_nintmap; i++) {
    288 			if (sc->sc_intmap[i].cintr == ihandle) {
    289 				node = sc->sc_intmap[i].cnode;
    290 				break;
    291 			}
    292 		}
    293 		if (node == -1)
    294 			return (NULL);
    295 
    296 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
    297 			return (NULL);
    298 		devhandle = (reg.ur_paddr >> 32) & 0x0fffffff;
    299 
    300 		err = hv_intr_devino_to_sysino(devhandle, devino, &sysino);
    301 		if (err != H_EOK)
    302 			return (NULL);
    303 
    304 		KASSERT(sysino == INTVEC(sysino));
    305 		ih = bus_intr_allocate(t0, handler, arg, sysino, level,
    306 		    NULL, NULL, what);
    307 		if (ih == NULL)
    308 			return (NULL);
    309 
    310 		intr_establish(ih->ih_pil, ih);
    311 		ih->ih_ack = ebus_mainbus_intr_ack;
    312 
    313 		err = hv_intr_settarget(sysino, cpus->ci_upaid);
    314 		if (err != H_EOK)
    315 			return (NULL);
    316 
    317 		/* Clear pending interrupts. */
    318 		err = hv_intr_setstate(sysino, INTR_IDLE);
    319 		if (err != H_EOK)
    320 			return (NULL);
    321 
    322 		err = hv_intr_setenabled(sysino, INTR_ENABLED);
    323 		if (err != H_EOK)
    324 			return (NULL);
    325 
    326 		return (ih);
    327 	}
    328 #endif
    329 
    330 	for (i = 0; i < pyro_cd.cd_ndevs; i++) {
    331 		device_t dt = device_lookup(&pyro_cd, i);
    332 		psc = device_private(dt);
    333 		if (psc && psc->sc_ign == INTIGN(ihandle)) {
    334 			break;
    335 		}
    336 	}
    337 	if (psc == NULL) {
    338 		aprint_error(": failed to match pyro leaf\n");
    339 		return (NULL);
    340 	}
    341 
    342 	return (psc->intr_establish_sc(psc,
    343 	    ihandle, level, handler, arg, NULL));
    344 }
    345 
    346 #ifdef SUN4V
    347 #if 0
    348 XXX
    349 static void
    350 ebus_mainbus_intr_ack(struct intrhand *ih)
    351 {
    352 	hv_intr_setstate(ih->ih_number, INTR_IDLE);
    353 }
    354 #endif
    355 #endif
    356