1 /* $NetBSD: ebus_mainbus.c,v 1.5 2011/07/01 18:48:36 dyoung 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 #ifdef DEBUG 21 #define EDB_PROM 0x01 22 #define EDB_CHILD 0x02 23 #define EDB_INTRMAP 0x04 24 #define EDB_BUSMAP 0x08 25 #define EDB_BUSDMA 0x10 26 #define EDB_INTR 0x20 27 extern int ebus_debug; 28 #define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0) 29 #else 30 #define DPRINTF(l, s) 31 #endif 32 33 #include <sys/param.h> 34 #include <sys/conf.h> 35 #include <sys/device.h> 36 #include <sys/errno.h> 37 #include <sys/extent.h> 38 #include <sys/malloc.h> 39 #include <sys/systm.h> 40 #include <sys/time.h> 41 42 #define _SPARC_BUS_DMA_PRIVATE 43 #include <sys/bus.h> 44 #include <machine/autoconf.h> 45 #include <machine/openfirm.h> 46 47 #include <dev/pci/pcivar.h> 48 49 #include <sparc64/dev/iommureg.h> 50 #include <sparc64/dev/iommuvar.h> 51 #include <sparc64/dev/pyrovar.h> 52 #include <dev/ebus/ebusreg.h> 53 #include <dev/ebus/ebusvar.h> 54 #include <sparc64/dev/ebusvar.h> 55 56 int ebus_mainbus_match(device_t, cfdata_t, void *); 57 void ebus_mainbus_attach(device_t, device_t, void *); 58 59 CFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc), 60 ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL); 61 62 int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 63 vaddr_t, bus_space_handle_t *); 64 void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int, 65 int (*)(void *), void *, void (*)(void)); 66 bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *, bus_space_tag_t, int); 67 void ebus_mainbus_intr_ack(struct intrhand *); 68 69 int 70 ebus_mainbus_match(struct device *parent, cfdata_t cf, void *aux) 71 { 72 struct mainbus_attach_args *ma = aux; 73 74 if (strcmp(ma->ma_name, "ebus") == 0) 75 return (1); 76 return (0); 77 } 78 79 void 80 ebus_mainbus_attach(struct device *parent, struct device *self, void *aux) 81 { 82 struct ebus_softc *sc = device_private(self); 83 struct mainbus_attach_args *ma = aux; 84 struct ebus_attach_args eba; 85 struct ebus_interrupt_map_mask *immp; 86 int node, nmapmask, error; 87 struct pyro_softc *psc; 88 int i; 89 90 sc->sc_dev = self; 91 sc->sc_node = node = ma->ma_node; 92 sc->sc_ign = INTIGN((ma->ma_upaid) << INTMAP_IGN_SHIFT); 93 94 if (CPU_ISSUN4U) { 95 printf(": ign %x", sc->sc_ign); 96 /* XXX */ 97 extern struct cfdriver pyro_cd; 98 99 for (i = 0; i < pyro_cd.cd_ndevs; i++) { 100 device_t dt = pyro_cd.cd_devs[i]; 101 psc = (struct pyro_softc *)dt; 102 if (psc && psc->sc_ign == sc->sc_ign) { 103 sc->sc_bust = psc->sc_bustag; 104 sc->sc_csr = psc->sc_csr; 105 sc->sc_csrh = psc->sc_csrh; 106 break; 107 } 108 } 109 110 if (sc->sc_csr == 0) { 111 printf(": can't find matching host bridge leaf\n"); 112 return; 113 } 114 } 115 116 printf("\n"); 117 118 sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, PCI_MEMORY_BUS_SPACE); 119 sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, PCI_IO_BUS_SPACE); 120 sc->sc_childbustag = sc->sc_memtag; 121 sc->sc_dmatag = ma->ma_dmatag; 122 123 /* 124 * fill in our softc with information from the prom 125 */ 126 sc->sc_intmap = NULL; 127 sc->sc_range = NULL; 128 error = prom_getprop(node, "interrupt-map", 129 sizeof(struct ebus_interrupt_map), 130 &sc->sc_nintmap, (void **)&sc->sc_intmap); 131 switch (error) { 132 case 0: 133 immp = &sc->sc_intmapmask; 134 error = prom_getprop(node, "interrupt-map-mask", 135 sizeof(struct ebus_interrupt_map_mask), &nmapmask, 136 (void **)&immp); 137 if (error) 138 panic("could not get ebus interrupt-map-mask"); 139 if (nmapmask != 1) 140 panic("ebus interrupt-map-mask is broken"); 141 break; 142 case ENOENT: 143 break; 144 default: 145 panic("ebus interrupt-map: error %d", error); 146 break; 147 } 148 149 error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges), 150 &sc->sc_nrange, (void **)&sc->sc_range); 151 if (error) 152 panic("ebus ranges: error %d", error); 153 154 /* 155 * now attach all our children 156 */ 157 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node)); 158 for (node = firstchild(node); node; node = nextsibling(node)) { 159 if (ebus_setup_attach_args(sc, node, &eba) != 0) { 160 DPRINTF(EDB_CHILD, 161 ("ebus_mainbus_attach: %s: incomplete\n", 162 prom_getpropstring(node, "name"))); 163 continue; 164 } else { 165 DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n", 166 eba.ea_name)); 167 (void)config_found(self, &eba, ebus_print); 168 } 169 ebus_destroy_attach_args(&eba); 170 } 171 } 172 173 bus_space_tag_t 174 ebus_mainbus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent, int type) 175 { 176 struct sparc_bus_space_tag *bt; 177 178 bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO); 179 if (bt == NULL) 180 panic("could not allocate ebus bus tag"); 181 182 bt->cookie = sc; 183 bt->parent = parent; 184 bt->type = type; 185 bt->sparc_bus_map = ebus_mainbus_bus_map; 186 bt->sparc_bus_mmap = ebus_bus_mmap; 187 bt->sparc_intr_establish = ebus_mainbus_intr_establish; 188 189 return (bt); 190 } 191 192 int 193 ebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size, 194 int flags, vaddr_t va, bus_space_handle_t *hp) 195 { 196 struct ebus_softc *sc = t->cookie; 197 struct ebus_mainbus_ranges *range; 198 bus_addr_t hi, lo; 199 int i, ss; 200 201 DPRINTF(EDB_BUSMAP, 202 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d", 203 (unsigned long long)offset, (int)size, (int)flags)); 204 205 if (t->parent == 0 || t->parent->sparc_bus_map == 0) { 206 printf("\n_ebus_mainbus_bus_map: invalid parent"); 207 return (EINVAL); 208 } 209 210 t = t->parent; 211 212 hi = offset >> 32UL; 213 lo = offset & 0xffffffff; 214 range = (struct ebus_mainbus_ranges *)sc->sc_range; 215 216 DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo)); 217 for (i = 0; i < sc->sc_nrange; i++) { 218 bus_addr_t addr; 219 220 if (hi != range[i].child_hi) 221 continue; 222 if (lo < range[i].child_lo || 223 (lo + size) > (range[i].child_lo + range[i].size)) 224 continue; 225 226 #if 0 227 /* Isolate address space and find the right tag */ 228 ss = (range[i].phys_hi>>24)&3; 229 switch (ss) { 230 case 1: /* I/O space */ 231 t = sc->sc_iotag; 232 break; 233 case 2: /* Memory space */ 234 t = sc->sc_memtag; 235 break; 236 case 0: /* Config space */ 237 case 3: /* 64-bit Memory space */ 238 default: /* WTF? */ 239 /* We don't handle these */ 240 panic("ebus_mainbus_bus_map: illegal space %x", ss); 241 break; 242 } 243 #else 244 ss = 0; 245 #endif 246 247 addr = ((bus_addr_t)range[i].phys_hi << 32UL) | 248 range[i].phys_lo; 249 addr += lo; 250 DPRINTF(EDB_BUSMAP, 251 ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n", 252 (unsigned long long)offset, (unsigned long long)addr)); 253 return (bus_space_map(t, addr, size, flags, hp)); 254 } 255 DPRINTF(EDB_BUSMAP, (": FAILED\n")); 256 return (EINVAL); 257 } 258 259 void * 260 ebus_mainbus_intr_establish(bus_space_tag_t t, int ihandle, int level, 261 int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */) 262 { 263 struct ebus_softc *sc = t->cookie; 264 struct intrhand *ih = NULL; 265 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL; 266 u_int64_t *imap, *iclr; 267 int ino; 268 269 #ifdef SUN4V 270 if (CPU_ISSUN4V) { 271 struct upa_reg reg; 272 u_int64_t devhandle, devino = INTINO(ihandle); 273 u_int64_t sysino; 274 int node = -1; 275 int i, err; 276 277 for (i = 0; i < sc->sc_nintmap; i++) { 278 if (sc->sc_intmap[i].cintr == ihandle) { 279 node = sc->sc_intmap[i].cnode; 280 break; 281 } 282 } 283 if (node == -1) 284 return (NULL); 285 286 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 287 return (NULL); 288 devhandle = (reg.ur_paddr >> 32) & 0x0fffffff; 289 290 err = hv_intr_devino_to_sysino(devhandle, devino, &sysino); 291 if (err != H_EOK) 292 return (NULL); 293 294 KASSERT(sysino == INTVEC(sysino)); 295 ih = bus_intr_allocate(t0, handler, arg, sysino, level, 296 NULL, NULL, what); 297 if (ih == NULL) 298 return (NULL); 299 300 intr_establish(ih->ih_pil, ih); 301 ih->ih_ack = ebus_mainbus_intr_ack; 302 303 err = hv_intr_settarget(sysino, cpus->ci_upaid); 304 if (err != H_EOK) 305 return (NULL); 306 307 /* Clear pending interrupts. */ 308 err = hv_intr_setstate(sysino, INTR_IDLE); 309 if (err != H_EOK) 310 return (NULL); 311 312 err = hv_intr_setenabled(sysino, INTR_ENABLED); 313 if (err != H_EOK) 314 return (NULL); 315 316 return (ih); 317 } 318 #endif 319 320 ihandle |= sc->sc_ign; 321 ino = INTINO(ihandle); 322 323 /* XXX */ 324 imap = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1000); 325 iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(sc->sc_bustag, sc->sc_csrh) + 0x1400); 326 intrmapptr = &imap[ino]; 327 intrclrptr = &iclr[ino]; 328 ino |= INTVEC(ihandle); 329 330 ih = malloc(sizeof *ih, M_DEVBUF, M_NOWAIT); 331 if (ih == NULL) 332 return (NULL); 333 334 /* Register the map and clear intr registers */ 335 ih->ih_map = intrmapptr; 336 ih->ih_clr = intrclrptr; 337 338 ih->ih_fun = handler; 339 ih->ih_arg = arg; 340 ih->ih_pil = level; 341 ih->ih_number = ino; 342 343 intr_establish(ih->ih_pil, level != IPL_VM, ih); 344 345 if (intrmapptr != NULL) { 346 u_int64_t imapval; 347 348 imapval = *intrmapptr; 349 imapval |= (1LL << 6); 350 imapval |= INTMAP_V; 351 *intrmapptr = imapval; 352 imapval = *intrmapptr; 353 ih->ih_number |= imapval & INTMAP_INR; 354 } 355 356 return (ih); 357 } 358 359 #ifdef SUN4V 360 361 void 362 ebus_mainbus_intr_ack(struct intrhand *ih) 363 { 364 hv_intr_setstate(ih->ih_number, INTR_IDLE); 365 } 366 367 #endif 368