1 /* $NetBSD: ebus_mainbus.c,v 1.20 2021/05/10 23:53:44 thorpej 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.20 2021/05/10 23:53:44 thorpej 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 distingish 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 for (node = firstchild(node); node; node = nextsibling(node)) { 168 if (ebus_setup_attach_args(sc, node, &eba) != 0) { 169 DPRINTF(EDB_CHILD, 170 ("ebus_mainbus_attach: %s: incomplete\n", 171 prom_getpropstring(node, "name"))); 172 continue; 173 } else { 174 DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n", 175 eba.ea_name)); 176 (void)config_found(self, &eba, ebus_print, 177 CFARG_DEVHANDLE, prom_node_to_devhandle(node), 178 CFARG_EOL); 179 } 180 ebus_destroy_attach_args(&eba); 181 } 182 } 183 184 static bus_space_tag_t 185 ebus_mainbus_alloc_bus_tag(struct ebus_softc *sc, 186 bus_space_tag_t parent, 187 int type) 188 { 189 struct sparc_bus_space_tag *bt; 190 191 bt = kmem_zalloc(sizeof(*bt), KM_SLEEP); 192 bt->cookie = sc; 193 bt->parent = parent; 194 bt->type = type; 195 bt->sparc_bus_map = ebus_mainbus_bus_map; 196 bt->sparc_bus_mmap = ebus_bus_mmap; 197 bt->sparc_intr_establish = ebus_mainbus_intr_establish; 198 199 return (bt); 200 } 201 202 int 203 ebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size, 204 int flags, vaddr_t va, bus_space_handle_t *hp) 205 { 206 struct ebus_softc *sc = t->cookie; 207 struct ebus_mainbus_ranges *range; 208 bus_addr_t hi, lo; 209 int i; 210 #if 0 211 int ss; 212 #endif 213 214 DPRINTF(EDB_BUSMAP, 215 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d", 216 (unsigned long long)offset, (int)size, (int)flags)); 217 218 if (t->parent == 0 || t->parent->sparc_bus_map == 0) { 219 printf("\n_ebus_mainbus_bus_map: invalid parent"); 220 return (EINVAL); 221 } 222 223 t = t->parent; 224 225 hi = offset >> 32UL; 226 lo = offset & 0xffffffff; 227 range = (struct ebus_mainbus_ranges *)sc->sc_range; 228 229 DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo)); 230 for (i = 0; i < sc->sc_nrange; i++) { 231 bus_addr_t addr; 232 233 if (hi != range[i].child_hi) 234 continue; 235 if (lo < range[i].child_lo || 236 (lo + size) > (range[i].child_lo + range[i].size)) 237 continue; 238 239 #if 0 240 /* Isolate address space and find the right tag */ 241 ss = (range[i].phys_hi>>24)&3; 242 switch (ss) { 243 case 1: /* I/O space */ 244 t = sc->sc_iotag; 245 break; 246 case 2: /* Memory space */ 247 t = sc->sc_memtag; 248 break; 249 case 0: /* Config space */ 250 case 3: /* 64-bit Memory space */ 251 default: /* WTF? */ 252 /* We don't handle these */ 253 panic("ebus_mainbus_bus_map: illegal space %x", ss); 254 break; 255 } 256 #endif 257 258 addr = ((bus_addr_t)range[i].phys_hi << 32UL) | 259 range[i].phys_lo; 260 addr += lo; 261 DPRINTF(EDB_BUSMAP, 262 ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n", 263 (unsigned long long)offset, (unsigned long long)addr)); 264 return (bus_space_map(t, addr, size, flags, hp)); 265 } 266 DPRINTF(EDB_BUSMAP, (": FAILED\n")); 267 return (EINVAL); 268 } 269 270 static void * 271 ebus_mainbus_intr_establish(bus_space_tag_t t, int ihandle, int level, 272 int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */) 273 { 274 struct intrhand *ih = NULL; 275 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL; 276 u_int64_t *imap, *iclr; 277 int ino; 278 279 #if 0 280 XXX 281 if (CPU_ISSUN4V) { 282 struct upa_reg reg; 283 u_int64_t devhandle, devino = INTINO(ihandle); 284 u_int64_t sysino; 285 int node = -1; 286 int i, err; 287 288 for (i = 0; i < sc->sc_nintmap; i++) { 289 if (sc->sc_intmap[i].cintr == ihandle) { 290 node = sc->sc_intmap[i].cnode; 291 break; 292 } 293 } 294 if (node == -1) 295 return (NULL); 296 297 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 298 return (NULL); 299 devhandle = (reg.ur_paddr >> 32) & 0x0fffffff; 300 301 err = hv_intr_devino_to_sysino(devhandle, devino, &sysino); 302 if (err != H_EOK) 303 return (NULL); 304 305 KASSERT(sysino == INTVEC(sysino)); 306 ih = bus_intr_allocate(t0, handler, arg, sysino, level, 307 NULL, NULL, what); 308 if (ih == NULL) 309 return (NULL); 310 311 intr_establish(ih->ih_pil, ih); 312 ih->ih_ack = ebus_mainbus_intr_ack; 313 314 err = hv_intr_settarget(sysino, cpus->ci_upaid); 315 if (err != H_EOK) 316 return (NULL); 317 318 /* Clear pending interrupts. */ 319 err = hv_intr_setstate(sysino, INTR_IDLE); 320 if (err != H_EOK) 321 return (NULL); 322 323 err = hv_intr_setenabled(sysino, INTR_ENABLED); 324 if (err != H_EOK) 325 return (NULL); 326 327 return (ih); 328 } 329 #endif 330 331 ino = INTINO(ihandle); 332 333 struct pyro_softc *psc = NULL; 334 int i; 335 336 for (i = 0; i < pyro_cd.cd_ndevs; i++) { 337 device_t dt = device_lookup(&pyro_cd, i); 338 psc = device_private(dt); 339 if (psc && psc->sc_ign == INTIGN(ihandle)) { 340 break; 341 } 342 } 343 if (psc == NULL) 344 return (NULL); 345 346 imap = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1000); 347 iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1400); 348 intrmapptr = &imap[ino]; 349 intrclrptr = &iclr[ino]; 350 ino |= INTVEC(ihandle); 351 352 ih = intrhand_alloc(); 353 354 /* Register the map and clear intr registers */ 355 ih->ih_map = intrmapptr; 356 ih->ih_clr = intrclrptr; 357 358 ih->ih_ivec = ihandle; 359 ih->ih_fun = handler; 360 ih->ih_arg = arg; 361 ih->ih_pil = level; 362 ih->ih_number = ino; 363 ih->ih_pending = 0; 364 365 intr_establish(ih->ih_pil, level != IPL_VM, ih); 366 367 if (intrmapptr != NULL) { 368 u_int64_t imapval; 369 370 imapval = *intrmapptr; 371 imapval |= (1LL << 6); 372 imapval |= INTMAP_V; 373 *intrmapptr = imapval; 374 imapval = *intrmapptr; 375 ih->ih_number |= imapval & INTMAP_INR; 376 } 377 378 return (ih); 379 } 380 381 #ifdef SUN4V 382 #if 0 383 XXX 384 static void 385 ebus_mainbus_intr_ack(struct intrhand *ih) 386 { 387 hv_intr_setstate(ih->ih_number, INTR_IDLE); 388 } 389 #endif 390 #endif 391