11.23Sandvar/* $NetBSD: ebus_mainbus.c,v 1.23 2022/05/24 20:50:19 andvar Exp $ */ 21.1Smrg/* $OpenBSD: ebus_mainbus.c,v 1.7 2010/11/11 17:58:23 miod Exp $ */ 31.1Smrg 41.1Smrg/* 51.1Smrg * Copyright (c) 2007 Mark Kettenis 61.1Smrg * 71.1Smrg * Permission to use, copy, modify, and distribute this software for any 81.1Smrg * purpose with or without fee is hereby granted, provided that the above 91.1Smrg * copyright notice and this permission notice appear in all copies. 101.1Smrg * 111.1Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 121.1Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 131.1Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 141.1Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 151.1Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 161.1Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 171.1Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 181.1Smrg */ 191.1Smrg 201.9Smrg#include <sys/cdefs.h> 211.23Sandvar__KERNEL_RCSID(0, "$NetBSD: ebus_mainbus.c,v 1.23 2022/05/24 20:50:19 andvar Exp $"); 221.9Smrg 231.1Smrg#ifdef DEBUG 241.1Smrg#define EDB_PROM 0x01 251.1Smrg#define EDB_CHILD 0x02 261.1Smrg#define EDB_INTRMAP 0x04 271.1Smrg#define EDB_BUSMAP 0x08 281.1Smrg#define EDB_BUSDMA 0x10 291.1Smrg#define EDB_INTR 0x20 301.1Smrgextern int ebus_debug; 311.1Smrg#define DPRINTF(l, s) do { if (ebus_debug & l) printf s; } while (0) 321.1Smrg#else 331.1Smrg#define DPRINTF(l, s) 341.1Smrg#endif 351.1Smrg 361.1Smrg#include <sys/param.h> 371.1Smrg#include <sys/conf.h> 381.1Smrg#include <sys/device.h> 391.1Smrg#include <sys/errno.h> 401.1Smrg#include <sys/extent.h> 411.18Sthorpej#include <sys/kmem.h> 421.1Smrg#include <sys/systm.h> 431.1Smrg#include <sys/time.h> 441.1Smrg 451.1Smrg#define _SPARC_BUS_DMA_PRIVATE 461.5Sdyoung#include <sys/bus.h> 471.1Smrg#include <machine/autoconf.h> 481.1Smrg#include <machine/openfirm.h> 491.1Smrg 501.1Smrg#include <dev/pci/pcivar.h> 511.1Smrg 521.1Smrg#include <sparc64/dev/iommureg.h> 531.2Smrg#include <sparc64/dev/iommuvar.h> 541.2Smrg#include <sparc64/dev/pyrovar.h> 551.2Smrg#include <dev/ebus/ebusreg.h> 561.2Smrg#include <dev/ebus/ebusvar.h> 571.1Smrg#include <sparc64/dev/ebusvar.h> 581.1Smrg 591.14Spalle#include "ioconf.h" 601.13Spalle 611.4Schristosint ebus_mainbus_match(device_t, cfdata_t, void *); 621.4Schristosvoid ebus_mainbus_attach(device_t, device_t, void *); 631.1Smrg 641.4SchristosCFATTACH_DECL_NEW(ebus_mainbus, sizeof(struct ebus_softc), 651.2Smrg ebus_mainbus_match, ebus_mainbus_attach, NULL, NULL); 661.1Smrg 671.7Smrgstatic int ebus_mainbus_bus_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, 681.7Smrg vaddr_t, bus_space_handle_t *); 691.7Smrgstatic void *ebus_mainbus_intr_establish(bus_space_tag_t, int, int, 701.2Smrg int (*)(void *), void *, void (*)(void)); 711.7Smrgstatic bus_space_tag_t ebus_mainbus_alloc_bus_tag(struct ebus_softc *, 721.7Smrg bus_space_tag_t, int); 731.7Smrg#ifdef SUN4V 741.12Spalle#if 0 751.12SpalleXXX 761.7Smrgstatic void ebus_mainbus_intr_ack(struct intrhand *); 771.7Smrg#endif 781.12Spalle#endif 791.1Smrgint 801.10Schsebus_mainbus_match(device_t parent, cfdata_t cf, void *aux) 811.1Smrg{ 821.1Smrg struct mainbus_attach_args *ma = aux; 831.1Smrg 841.1Smrg if (strcmp(ma->ma_name, "ebus") == 0) 851.1Smrg return (1); 861.1Smrg return (0); 871.1Smrg} 881.1Smrg 891.1Smrgvoid 901.10Schsebus_mainbus_attach(device_t parent, device_t self, void *aux) 911.1Smrg{ 921.4Schristos struct ebus_softc *sc = device_private(self); 931.1Smrg struct mainbus_attach_args *ma = aux; 941.1Smrg struct ebus_attach_args eba; 951.1Smrg struct ebus_interrupt_map_mask *immp; 961.1Smrg int node, nmapmask, error; 971.1Smrg struct pyro_softc *psc; 981.13Spalle int i, j; 991.1Smrg 1001.4Schristos sc->sc_dev = self; 1011.13Spalle 1021.1Smrg printf("\n"); 1031.1Smrg 1041.7Smrg sc->sc_memtag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, 1051.7Smrg PCI_MEMORY_BUS_SPACE); 1061.7Smrg sc->sc_iotag = ebus_mainbus_alloc_bus_tag(sc, ma->ma_bustag, 1071.7Smrg PCI_IO_BUS_SPACE); 1081.2Smrg sc->sc_childbustag = sc->sc_memtag; 1091.2Smrg sc->sc_dmatag = ma->ma_dmatag; 1101.1Smrg 1111.13Spalle sc->sc_node = node = ma->ma_node; 1121.13Spalle 1131.1Smrg /* 1141.1Smrg * fill in our softc with information from the prom 1151.1Smrg */ 1161.1Smrg sc->sc_intmap = NULL; 1171.1Smrg sc->sc_range = NULL; 1181.2Smrg error = prom_getprop(node, "interrupt-map", 1191.1Smrg sizeof(struct ebus_interrupt_map), 1201.1Smrg &sc->sc_nintmap, (void **)&sc->sc_intmap); 1211.1Smrg switch (error) { 1221.1Smrg case 0: 1231.1Smrg immp = &sc->sc_intmapmask; 1241.7Smrg nmapmask = 1; 1251.2Smrg error = prom_getprop(node, "interrupt-map-mask", 1261.1Smrg sizeof(struct ebus_interrupt_map_mask), &nmapmask, 1271.1Smrg (void **)&immp); 1281.1Smrg if (error) 1291.7Smrg panic("could not get ebus interrupt-map-mask: error %d", 1301.7Smrg error); 1311.1Smrg if (nmapmask != 1) 1321.1Smrg panic("ebus interrupt-map-mask is broken"); 1331.1Smrg break; 1341.1Smrg case ENOENT: 1351.1Smrg break; 1361.1Smrg default: 1371.1Smrg panic("ebus interrupt-map: error %d", error); 1381.1Smrg break; 1391.1Smrg } 1401.1Smrg 1411.13Spalle /* 1421.13Spalle * Ebus interrupts may be connected to any of the PCI Express 1431.13Spalle * leafs. Here we add the appropriate IGN to the interrupt 1441.23Sandvar * mappings such that we can use it to distinguish between 1451.13Spalle * interrupts connected to PCIE-A and PCIE-B. 1461.13Spalle */ 1471.13Spalle for (i = 0; i < sc->sc_nintmap; i++) { 1481.13Spalle for (j = 0; j < pyro_cd.cd_ndevs; j++) { 1491.14Spalle device_t dt = device_lookup(&pyro_cd, j); 1501.13Spalle psc = device_private(dt); 1511.13Spalle if (psc && psc->sc_node == sc->sc_intmap[i].cnode) { 1521.13Spalle sc->sc_intmap[i].cintr |= psc->sc_ign; 1531.13Spalle break; 1541.13Spalle } 1551.13Spalle } 1561.13Spalle } 1571.13Spalle 1581.2Smrg error = prom_getprop(node, "ranges", sizeof(struct ebus_mainbus_ranges), 1591.1Smrg &sc->sc_nrange, (void **)&sc->sc_range); 1601.1Smrg if (error) 1611.1Smrg panic("ebus ranges: error %d", error); 1621.1Smrg 1631.1Smrg /* 1641.1Smrg * now attach all our children 1651.1Smrg */ 1661.1Smrg DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node)); 1671.22Sthorpej devhandle_t selfh = device_handle(self); 1681.1Smrg for (node = firstchild(node); node; node = nextsibling(node)) { 1691.1Smrg if (ebus_setup_attach_args(sc, node, &eba) != 0) { 1701.1Smrg DPRINTF(EDB_CHILD, 1711.1Smrg ("ebus_mainbus_attach: %s: incomplete\n", 1721.2Smrg prom_getpropstring(node, "name"))); 1731.1Smrg continue; 1741.1Smrg } else { 1751.1Smrg DPRINTF(EDB_CHILD, ("- found child `%s', attaching\n", 1761.1Smrg eba.ea_name)); 1771.20Sthorpej (void)config_found(self, &eba, ebus_print, 1781.22Sthorpej CFARGS(.devhandle = prom_node_to_devhandle(selfh, 1791.22Sthorpej node))); 1801.1Smrg } 1811.1Smrg ebus_destroy_attach_args(&eba); 1821.1Smrg } 1831.1Smrg} 1841.1Smrg 1851.7Smrgstatic bus_space_tag_t 1861.7Smrgebus_mainbus_alloc_bus_tag(struct ebus_softc *sc, 1871.7Smrg bus_space_tag_t parent, 1881.7Smrg int type) 1891.1Smrg{ 1901.1Smrg struct sparc_bus_space_tag *bt; 1911.1Smrg 1921.18Sthorpej bt = kmem_zalloc(sizeof(*bt), KM_SLEEP); 1931.1Smrg bt->cookie = sc; 1941.1Smrg bt->parent = parent; 1951.2Smrg bt->type = type; 1961.1Smrg bt->sparc_bus_map = ebus_mainbus_bus_map; 1971.2Smrg bt->sparc_bus_mmap = ebus_bus_mmap; 1981.1Smrg bt->sparc_intr_establish = ebus_mainbus_intr_establish; 1991.1Smrg 2001.1Smrg return (bt); 2011.1Smrg} 2021.1Smrg 2031.1Smrgint 2041.2Smrgebus_mainbus_bus_map(bus_space_tag_t t, bus_addr_t offset, bus_size_t size, 2051.2Smrg int flags, vaddr_t va, bus_space_handle_t *hp) 2061.1Smrg{ 2071.1Smrg struct ebus_softc *sc = t->cookie; 2081.1Smrg struct ebus_mainbus_ranges *range; 2091.1Smrg bus_addr_t hi, lo; 2101.11Smartin int i; 2111.11Smartin#if 0 2121.11Smartin int ss; 2131.11Smartin#endif 2141.1Smrg 2151.1Smrg DPRINTF(EDB_BUSMAP, 2161.1Smrg ("\n_ebus_mainbus_bus_map: off %016llx sz %x flags %d", 2171.1Smrg (unsigned long long)offset, (int)size, (int)flags)); 2181.1Smrg 2191.1Smrg if (t->parent == 0 || t->parent->sparc_bus_map == 0) { 2201.1Smrg printf("\n_ebus_mainbus_bus_map: invalid parent"); 2211.1Smrg return (EINVAL); 2221.1Smrg } 2231.1Smrg 2241.1Smrg t = t->parent; 2251.1Smrg 2261.1Smrg hi = offset >> 32UL; 2271.1Smrg lo = offset & 0xffffffff; 2281.1Smrg range = (struct ebus_mainbus_ranges *)sc->sc_range; 2291.1Smrg 2301.1Smrg DPRINTF(EDB_BUSMAP, (" (hi %08x lo %08x)", (u_int)hi, (u_int)lo)); 2311.1Smrg for (i = 0; i < sc->sc_nrange; i++) { 2321.1Smrg bus_addr_t addr; 2331.1Smrg 2341.1Smrg if (hi != range[i].child_hi) 2351.1Smrg continue; 2361.1Smrg if (lo < range[i].child_lo || 2371.1Smrg (lo + size) > (range[i].child_lo + range[i].size)) 2381.1Smrg continue; 2391.1Smrg 2401.2Smrg#if 0 2411.2Smrg /* Isolate address space and find the right tag */ 2421.2Smrg ss = (range[i].phys_hi>>24)&3; 2431.2Smrg switch (ss) { 2441.2Smrg case 1: /* I/O space */ 2451.2Smrg t = sc->sc_iotag; 2461.2Smrg break; 2471.2Smrg case 2: /* Memory space */ 2481.2Smrg t = sc->sc_memtag; 2491.2Smrg break; 2501.2Smrg case 0: /* Config space */ 2511.2Smrg case 3: /* 64-bit Memory space */ 2521.2Smrg default: /* WTF? */ 2531.2Smrg /* We don't handle these */ 2541.2Smrg panic("ebus_mainbus_bus_map: illegal space %x", ss); 2551.2Smrg break; 2561.2Smrg } 2571.2Smrg#endif 2581.2Smrg 2591.1Smrg addr = ((bus_addr_t)range[i].phys_hi << 32UL) | 2601.1Smrg range[i].phys_lo; 2611.1Smrg addr += lo; 2621.1Smrg DPRINTF(EDB_BUSMAP, 2631.1Smrg ("\n_ebus_mainbus_bus_map: paddr offset %qx addr %qx\n", 2641.1Smrg (unsigned long long)offset, (unsigned long long)addr)); 2651.2Smrg return (bus_space_map(t, addr, size, flags, hp)); 2661.1Smrg } 2671.1Smrg DPRINTF(EDB_BUSMAP, (": FAILED\n")); 2681.1Smrg return (EINVAL); 2691.1Smrg} 2701.1Smrg 2711.7Smrgstatic void * 2721.2Smrgebus_mainbus_intr_establish(bus_space_tag_t t, int ihandle, int level, 2731.2Smrg int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */) 2741.1Smrg{ 2751.1Smrg struct intrhand *ih = NULL; 2761.1Smrg volatile u_int64_t *intrmapptr = NULL, *intrclrptr = NULL; 2771.2Smrg u_int64_t *imap, *iclr; 2781.1Smrg int ino; 2791.1Smrg 2801.12Spalle#if 0 2811.12SpalleXXX 2821.1Smrg if (CPU_ISSUN4V) { 2831.1Smrg struct upa_reg reg; 2841.1Smrg u_int64_t devhandle, devino = INTINO(ihandle); 2851.1Smrg u_int64_t sysino; 2861.1Smrg int node = -1; 2871.1Smrg int i, err; 2881.1Smrg 2891.1Smrg for (i = 0; i < sc->sc_nintmap; i++) { 2901.1Smrg if (sc->sc_intmap[i].cintr == ihandle) { 2911.1Smrg node = sc->sc_intmap[i].cnode; 2921.1Smrg break; 2931.1Smrg } 2941.1Smrg } 2951.1Smrg if (node == -1) 2961.1Smrg return (NULL); 2971.1Smrg 2981.1Smrg if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) 2991.1Smrg return (NULL); 3001.1Smrg devhandle = (reg.ur_paddr >> 32) & 0x0fffffff; 3011.1Smrg 3021.1Smrg err = hv_intr_devino_to_sysino(devhandle, devino, &sysino); 3031.1Smrg if (err != H_EOK) 3041.1Smrg return (NULL); 3051.1Smrg 3061.1Smrg KASSERT(sysino == INTVEC(sysino)); 3071.1Smrg ih = bus_intr_allocate(t0, handler, arg, sysino, level, 3081.1Smrg NULL, NULL, what); 3091.1Smrg if (ih == NULL) 3101.1Smrg return (NULL); 3111.1Smrg 3121.1Smrg intr_establish(ih->ih_pil, ih); 3131.1Smrg ih->ih_ack = ebus_mainbus_intr_ack; 3141.1Smrg 3151.1Smrg err = hv_intr_settarget(sysino, cpus->ci_upaid); 3161.1Smrg if (err != H_EOK) 3171.1Smrg return (NULL); 3181.1Smrg 3191.1Smrg /* Clear pending interrupts. */ 3201.1Smrg err = hv_intr_setstate(sysino, INTR_IDLE); 3211.1Smrg if (err != H_EOK) 3221.1Smrg return (NULL); 3231.1Smrg 3241.1Smrg err = hv_intr_setenabled(sysino, INTR_ENABLED); 3251.1Smrg if (err != H_EOK) 3261.1Smrg return (NULL); 3271.1Smrg 3281.1Smrg return (ih); 3291.1Smrg } 3301.1Smrg#endif 3311.13Spalle 3321.1Smrg ino = INTINO(ihandle); 3331.1Smrg 3341.13Spalle struct pyro_softc *psc = NULL; 3351.13Spalle int i; 3361.13Spalle 3371.13Spalle for (i = 0; i < pyro_cd.cd_ndevs; i++) { 3381.14Spalle device_t dt = device_lookup(&pyro_cd, i); 3391.13Spalle psc = device_private(dt); 3401.13Spalle if (psc && psc->sc_ign == INTIGN(ihandle)) { 3411.13Spalle break; 3421.13Spalle } 3431.13Spalle } 3441.13Spalle if (psc == NULL) 3451.13Spalle return (NULL); 3461.13Spalle 3471.13Spalle imap = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1000); 3481.13Spalle iclr = (uint64_t *)((uintptr_t)bus_space_vaddr(psc->sc_bustag, psc->sc_csrh) + 0x1400); 3491.2Smrg intrmapptr = &imap[ino]; 3501.2Smrg intrclrptr = &iclr[ino]; 3511.2Smrg ino |= INTVEC(ihandle); 3521.1Smrg 3531.16Snakayama ih = intrhand_alloc(); 3541.1Smrg 3551.2Smrg /* Register the map and clear intr registers */ 3561.2Smrg ih->ih_map = intrmapptr; 3571.2Smrg ih->ih_clr = intrclrptr; 3581.2Smrg 3591.8Smrg ih->ih_ivec = ihandle; 3601.2Smrg ih->ih_fun = handler; 3611.2Smrg ih->ih_arg = arg; 3621.2Smrg ih->ih_pil = level; 3631.2Smrg ih->ih_number = ino; 3641.7Smrg ih->ih_pending = 0; 3651.2Smrg 3661.2Smrg intr_establish(ih->ih_pil, level != IPL_VM, ih); 3671.1Smrg 3681.1Smrg if (intrmapptr != NULL) { 3691.2Smrg u_int64_t imapval; 3701.1Smrg 3711.2Smrg imapval = *intrmapptr; 3721.2Smrg imapval |= (1LL << 6); 3731.2Smrg imapval |= INTMAP_V; 3741.2Smrg *intrmapptr = imapval; 3751.2Smrg imapval = *intrmapptr; 3761.2Smrg ih->ih_number |= imapval & INTMAP_INR; 3771.1Smrg } 3781.1Smrg 3791.1Smrg return (ih); 3801.1Smrg} 3811.1Smrg 3821.1Smrg#ifdef SUN4V 3831.12Spalle#if 0 3841.12SpalleXXX 3851.7Smrgstatic void 3861.1Smrgebus_mainbus_intr_ack(struct intrhand *ih) 3871.1Smrg{ 3881.1Smrg hv_intr_setstate(ih->ih_number, INTR_IDLE); 3891.1Smrg} 3901.12Spalle#endif 3911.1Smrg#endif 392