1 /* $NetBSD: ebus_mainbus.c,v 1.9 2012/03/18 05:26:58 mrg 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.9 2012/03/18 05:26:58 mrg 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/malloc.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 int ebus_mainbus_match(device_t, cfdata_t, void *); 60 void ebus_mainbus_attach(device_t, device_t, void *); 61 62 CFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc), 63 ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL); 64 65 static int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 66 vaddr_t, bus_space_handle_t *); 67 static void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int, 68 int (*)(void *), void *, void (*)(void)); 69 static bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *, 70 bus_space_tag_t, int); 71 #ifdef SUN4V 72 static void ebus_mainbus_intr_ack(struct intrhand *); 73 #endif 74 75 int 76 ebus_mainbus_match(struct device *parent, cfdata_t cf, void *aux) 77 { 78 struct mainbus_attach_args *ma = aux; 79 80 if (strcmp(ma->ma_name, "ebus") == 0) 81 return (1); 82 return (0); 83 } 84 85 void 86 ebus_mainbus_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct ebus_softc *sc = device_private(self); 89 struct mainbus_attach_args *ma = aux; 90 struct ebus_attach_args eba; 91 struct ebus_interrupt_map_mask *immp; 92 int node, nmapmask, error; 93 struct pyro_softc *psc; 94 int i; 95 96 sc->sc_dev = self; 97 sc->sc_node = node = ma->ma_node; 98 sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT); 99 100 if (CPU_ISSUN4U) { 101 printf(": ign %x", sc->sc_ign); 102 /* XXX */ 103 extern struct cfdriver pyro_cd; 104 105 for (i = 0; i < pyro_cd.cd_ndevs; i++) { 106 device_t dt = pyro_cd.cd_devs[i]; 107 psc = device_private(dt); 108 if (psc && psc->sc_ign == sc->sc_ign) { 109 sc->sc_bust = psc->sc_bustag; 110 sc->sc_csr = psc->sc_csr; 111 sc->sc_csrh = psc->sc_csrh; 112 break; 113 } 114 } 115 116 if (sc->sc_csr == 0) { 117 printf(": can't find matching host bridge leaf\n"); 118 return; 119 } 120 } 121 122 printf("\n"); 123 124 sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, 125 PCI_MEMORY_BUS_SPACE); 126 sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, 127 PCI_IO_BUS_SPACE); 128 sc->sc_childbustag = sc->sc_memtag; 129 sc->sc_dmatag = ma->ma_dmatag; 130 131 /* 132 * fill in our softc with information from the prom 133 */ 134 sc->sc_intmap = NULL; 135 sc->sc_range = NULL; 136 error = prom_getprop(node, "interrupt-map", 137 sizeof(struct ebus_interrupt_map), 138 &sc->sc_nintmap, (void **)&sc->sc_intmap); 139 switch (error) { 140 case 0: 141 immp = &sc->sc_intmapmask; 142 nmapmask = 1; 143 error = prom_getprop(node, "interrupt-map-mask", 144 sizeof(struct ebus_interrupt_map_mask), &nmapmask, 145 (void **)&immp); 146 if (error) 147 panic("could not get ebus interrupt-map-mask: error %d", 148 error); 149 if (nmapmask != 1) 150 panic("ebus interrupt-map-mask is broken"); 151 break; 152 case ENOENT: 153 break; 154 default: 155 panic("ebus interrupt-map: error %d", error); 156 break; 157 } 158 159 error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges), 160 &sc->sc_nrange, (void **)&sc->sc_range); 161 if (error) 162 panic("ebus ranges: error %d", error); 163 164 /* 165 * now attach all our children 166 */ 167 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node)); 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 } 179 ebus_destroy_attach_args(&eba); 180 } 181 } 182 183 static bus_space_tag_t 184 ebus_mainbus_alloc_bus_tag(struct ebus_softc *sc, 185 bus_space_tag_t parent, 186 int type) 187 { 188 struct sparc_bus_space_tag *bt; 189 190 bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO); 191 if (bt == NULL) 192 panic("could not allocate ebus bus tag"); 193 194 bt->cookie = sc; 195 bt->parent = parent; 196 bt->type = type; 197 bt->sparc_bus_map = ebus_mainbus_bus_map; 198 bt->sparc_bus_mmap = ebus_bus_mmap; 199 bt->sparc_intr_establish = ebus_mainbus_intr_establish; 200 201 return (bt); 202 } 203 204 int 205 ebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size, 206 int flags, vaddr_t va, bus_space_handle_t *hp) 207 { 208 struct ebus_softc *sc = t->cookie; 209 struct ebus_mainbus_ranges *range; 210 bus_addr_t hi, lo; 211 int i, ss; 212 213 DPRINTF(EDB_BUSMAP, 214 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d", 215 (unsigned long long)offset, (int)size, (int)flags)); 216 217 if (t->parent == 0 || t->parent->sparc_bus_map == 0) { 218 printf("\n_ebus_mainbus_bus_map: invalid parent"); 219 return (EINVAL); 220 } 221 222 t = t->parent; 223 224 hi = offset >> 32UL; 225 lo = offset & 0xffffffff; 226 range = (struct ebus_mainbus_ranges *)sc->sc_range; 227 228 DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo)); 229 for (i = 0; i < sc->sc_nrange; i++) { 230 bus_addr_t addr; 231 232 if (hi != range[i].child_hi) 233 continue; 234 if (lo < range[i].child_lo || 235 (lo + size) > (range[i].child_lo + range[i].size)) 236 continue; 237 238 #if 0 239 /* Isolate address space and find the right tag */ 240 ss = (range[i].phys_hi>>24)&3; 241 switch (ss) { 242 case 1: /* I/O space */ 243 t = sc->sc_iotag; 244 break; 245 case 2: /* Memory space */ 246 t = sc->sc_memtag; 247 break; 248 case 0: /* Config space */ 249 case 3: /* 64-bit Memory space */ 250 default: /* WTF? */ 251 /* We don't handle these */ 252 panic("ebus_mainbus_bus_map: illegal space %x", ss); 253 break; 254 } 255 #else 256 ss = 0; 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 ebus_softc *sc = t->cookie; 276 struct intrhand *ih = NULL; 277 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL; 278 u_int64_t *imap, *iclr; 279 int ino; 280 281 #ifdef SUN4V 282 if (CPU_ISSUN4V) { 283 struct upa_reg reg; 284 u_int64_t devhandle, devino = INTINO(ihandle); 285 u_int64_t sysino; 286 int node = -1; 287 int i, err; 288 289 for (i = 0; i < sc->sc_nintmap; i++) { 290 if (sc->sc_intmap[i].cintr == ihandle) { 291 node = sc->sc_intmap[i].cnode; 292 break; 293 } 294 } 295 if (node == -1) 296 return (NULL); 297 298 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 299 return (NULL); 300 devhandle = (reg.ur_paddr >> 32) & 0x0fffffff; 301 302 err = hv_intr_devino_to_sysino(devhandle, devino, &sysino); 303 if (err != H_EOK) 304 return (NULL); 305 306 KASSERT(sysino == INTVEC(sysino)); 307 ih = bus_intr_allocate(t0, handler, arg, sysino, level, 308 NULL, NULL, what); 309 if (ih == NULL) 310 return (NULL); 311 312 intr_establish(ih->ih_pil, ih); 313 ih->ih_ack = ebus_mainbus_intr_ack; 314 315 err = hv_intr_settarget(sysino, cpus->ci_upaid); 316 if (err != H_EOK) 317 return (NULL); 318 319 /* Clear pending interrupts. */ 320 err = hv_intr_setstate(sysino, INTR_IDLE); 321 if (err != H_EOK) 322 return (NULL); 323 324 err = hv_intr_setenabled(sysino, INTR_ENABLED); 325 if (err != H_EOK) 326 return (NULL); 327 328 return (ih); 329 } 330 #endif 331 332 ihandle |= sc->sc_ign; 333 ino = INTINO(ihandle); 334 335 /* XXX */ 336 imap = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1000); 337 iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1400); 338 intrmapptr = &imap[ino]; 339 intrclrptr = &iclr[ino]; 340 ino |= INTVEC(ihandle); 341 342 ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); 343 if (ih == NULL) 344 return (NULL); 345 346 /* Register the map and clear intr registers */ 347 ih->ih_map = intrmapptr; 348 ih->ih_clr = intrclrptr; 349 350 ih->ih_ivec = ihandle; 351 ih->ih_fun = handler; 352 ih->ih_arg = arg; 353 ih->ih_pil = level; 354 ih->ih_number = ino; 355 ih->ih_pending = 0; 356 357 intr_establish(ih->ih_pil, level != IPL_VM, ih); 358 359 if (intrmapptr != NULL) { 360 u_int64_t imapval; 361 362 imapval = *intrmapptr; 363 imapval |= (1LL << 6); 364 imapval |= INTMAP_V; 365 *intrmapptr = imapval; 366 imapval = *intrmapptr; 367 ih->ih_number |= imapval & INTMAP_INR; 368 } 369 370 return (ih); 371 } 372 373 #ifdef SUN4V 374 375 static void 376 ebus_mainbus_intr_ack(struct intrhand *ih) 377 { 378 hv_intr_setstate(ih->ih_number, INTR_IDLE); 379 } 380 381 #endif 382