1 /* $OpenBSD: ebus_mainbus.c,v 1.12 2021/10/24 17:05:03 mpi 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 const 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, j; 91 92 printf("\n"); 93 94 sc->sc_memtag = ebus_alloc_bus_tag(sc, ma->ma_bustag); 95 sc->sc_iotag = ebus_alloc_bus_tag(sc, ma->ma_bustag); 96 sc->sc_dmatag = ebus_alloc_dma_tag(sc, ma->ma_dmatag); 97 98 sc->sc_node = node = ma->ma_node; 99 100 /* 101 * fill in our softc with information from the prom 102 */ 103 sc->sc_intmap = NULL; 104 sc->sc_range = NULL; 105 error = getprop(node, "interrupt-map", 106 sizeof(struct ebus_interrupt_map), 107 &sc->sc_nintmap, (void **)&sc->sc_intmap); 108 switch (error) { 109 case 0: 110 immp = &sc->sc_intmapmask; 111 error = getprop(node, "interrupt-map-mask", 112 sizeof(struct ebus_interrupt_map_mask), &nmapmask, 113 (void **)&immp); 114 if (error) 115 panic("could not get ebus interrupt-map-mask"); 116 if (nmapmask != 1) 117 panic("ebus interrupt-map-mask is broken"); 118 break; 119 case ENOENT: 120 break; 121 default: 122 panic("ebus interrupt-map: error %d", error); 123 break; 124 } 125 126 /* 127 * Ebus interrupts may be connected to any of the PCI Express 128 * leafs. Here we add the appropriate IGN to the interrupt 129 * mappings such that we can use it to distinguish between 130 * interrupts connected to PCIE-A and PCIE-B. 131 */ 132 for (i = 0; i < sc->sc_nintmap; i++) { 133 for (j = 0; j < pyro_cd.cd_ndevs; j++) { 134 psc = pyro_cd.cd_devs[j]; 135 if (psc && psc->sc_node == sc->sc_intmap[i].cnode) { 136 sc->sc_intmap[i].cintr |= psc->sc_ign; 137 break; 138 } 139 } 140 } 141 142 error = getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges), 143 &sc->sc_nrange, (void **)&sc->sc_range); 144 if (error) 145 panic("ebus ranges: error %d", error); 146 147 /* 148 * now attach all our children 149 */ 150 DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node)); 151 for (node = firstchild(node); node; node = nextsibling(node)) { 152 if (ebus_setup_attach_args(sc, node, &eba) != 0) { 153 DPRINTF(EDB_CHILD, 154 ("ebus_mainbus_attach: %s: incomplete\n", 155 getpropstring(node, "name"))); 156 continue; 157 } else { 158 DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n", 159 eba.ea_name)); 160 (void)config_found(self, &eba, ebus_print); 161 } 162 ebus_destroy_attach_args(&eba); 163 } 164 } 165 166 bus_space_tag_t 167 ebus_alloc_bus_tag(struct ebus_softc *sc, bus_space_tag_t parent) 168 { 169 struct sparc_bus_space_tag *bt; 170 171 bt = malloc(sizeof(*bt), M_DEVBUF, M_NOWAIT | M_ZERO); 172 if (bt == NULL) 173 panic("could not allocate ebus bus tag"); 174 175 strlcpy(bt->name, sc->sc_dev.dv_xname, sizeof(bt->name)); 176 bt->cookie = sc; 177 bt->parent = parent; 178 bt->asi = parent->asi; 179 bt->sasi = parent->sasi; 180 bt->sparc_bus_map = ebus_mainbus_bus_map; 181 bt->sparc_intr_establish = ebus_mainbus_intr_establish; 182 183 return (bt); 184 } 185 186 int 187 ebus_mainbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t offset, 188 bus_size_t size, int flags, bus_space_handle_t *hp) 189 { 190 struct ebus_softc *sc = t->cookie; 191 struct ebus_mainbus_ranges *range; 192 bus_addr_t hi, lo; 193 int i; 194 195 DPRINTF(EDB_BUSMAP, 196 ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d", 197 (unsigned long long)offset, (int)size, (int)flags)); 198 199 if (t->parent == 0 || t->parent->sparc_bus_map == 0) { 200 printf("\n_ebus_mainbus_bus_map: invalid parent"); 201 return (EINVAL); 202 } 203 204 t = t->parent; 205 206 if (flags & BUS_SPACE_MAP_PROMADDRESS) { 207 return ((*t->sparc_bus_map) 208 (t, t0, offset, size, flags, hp)); 209 } 210 211 hi = offset >> 32UL; 212 lo = offset & 0xffffffff; 213 range = (struct ebus_mainbus_ranges *)sc->sc_range; 214 215 DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo)); 216 for (i = 0; i < sc->sc_nrange; i++) { 217 bus_addr_t addr; 218 219 if (hi != range[i].child_hi) 220 continue; 221 if (lo < range[i].child_lo || 222 (lo + size) > (range[i].child_lo + range[i].size)) 223 continue; 224 225 addr = ((bus_addr_t)range[i].phys_hi << 32UL) | 226 range[i].phys_lo; 227 addr += lo; 228 DPRINTF(EDB_BUSMAP, 229 ("\n_ebus_mainbus_bus_map: paddr offset %llx addr %llx\n", 230 (unsigned long long)offset, (unsigned long long)addr)); 231 return ((*t->sparc_bus_map)(t, t0, addr, size, flags, hp)); 232 } 233 DPRINTF(EDB_BUSMAP, (": FAILED\n")); 234 return (EINVAL); 235 } 236 237 void * 238 ebus_mainbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, 239 int level, int flags, int (*handler)(void *), void *arg, const char *what) 240 { 241 struct ebus_softc *sc = t->cookie; 242 struct intrhand *ih = NULL; 243 volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL; 244 int ino; 245 246 #ifdef SUN4V 247 if (CPU_ISSUN4V) { 248 struct upa_reg reg; 249 u_int64_t devhandle, devino = INTINO(ihandle); 250 u_int64_t sysino; 251 int node = -1; 252 int i, err; 253 254 for (i = 0; i < sc->sc_nintmap; i++) { 255 if (sc->sc_intmap[i].cintr == ihandle) { 256 node = sc->sc_intmap[i].cnode; 257 break; 258 } 259 } 260 if (node == -1) 261 return (NULL); 262 263 if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 264 return (NULL); 265 devhandle = (reg.ur_paddr >> 32) & 0x0fffffff; 266 267 err = hv_intr_devino_to_sysino(devhandle, devino, &sysino); 268 if (err != H_EOK) 269 return (NULL); 270 271 KASSERT(sysino == INTVEC(sysino)); 272 ih = bus_intr_allocate(t0, handler, arg, sysino, level, 273 NULL, NULL, what); 274 if (ih == NULL) 275 return (NULL); 276 277 intr_establish(ih->ih_pil, ih); 278 ih->ih_ack = ebus_mainbus_intr_ack; 279 280 err = hv_intr_settarget(sysino, ih->ih_cpu->ci_upaid); 281 if (err != H_EOK) 282 return (NULL); 283 284 /* Clear pending interrupts. */ 285 err = hv_intr_setstate(sysino, INTR_IDLE); 286 if (err != H_EOK) 287 return (NULL); 288 289 err = hv_intr_setenabled(sysino, INTR_ENABLED); 290 if (err != H_EOK) 291 return (NULL); 292 293 return (ih); 294 } 295 #endif 296 297 ino = INTINO(ihandle); 298 299 if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) == 0) { 300 struct pyro_softc *psc = NULL; 301 u_int64_t *imap, *iclr; 302 int i; 303 304 for (i = 0; i < pyro_cd.cd_ndevs; i++) { 305 psc = pyro_cd.cd_devs[i]; 306 if (psc && psc->sc_ign == INTIGN(ihandle)) { 307 break; 308 } 309 } 310 if (psc == NULL) 311 return (NULL); 312 313 imap = bus_space_vaddr(psc->sc_bust, psc->sc_csrh) + 0x1000; 314 iclr = bus_space_vaddr(psc->sc_bust, psc->sc_csrh) + 0x1400; 315 intrmapptr = &imap[ino]; 316 intrclrptr = &iclr[ino]; 317 ino |= INTVEC(ihandle); 318 } 319 320 ih = bus_intr_allocate(t0, handler, arg, ino, level, intrmapptr, 321 intrclrptr, what); 322 if (ih == NULL) 323 return (NULL); 324 325 intr_establish(ih->ih_pil, ih); 326 327 if (intrmapptr != NULL) { 328 u_int64_t intrmap; 329 330 intrmap = *intrmapptr; 331 intrmap |= (1LL << 6); 332 intrmap |= INTMAP_V; 333 *intrmapptr = intrmap; 334 intrmap = *intrmapptr; 335 ih->ih_number |= intrmap & INTMAP_INR; 336 } 337 338 return (ih); 339 } 340 341 #ifdef SUN4V 342 343 void 344 ebus_mainbus_intr_ack(struct intrhand *ih) 345 { 346 hv_intr_setstate(ih->ih_number, INTR_IDLE); 347 } 348 349 #endif 350