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