Index: head/sys/conf/files.sparc64 =================================================================== --- head/sys/conf/files.sparc64 (revision 287725) +++ head/sys/conf/files.sparc64 (revision 287726) @@ -1,150 +1,151 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # atkbdmap.h optional atkbd_dflt_keymap \ compile-with "/usr/sbin/kbdcontrol -L ${ATKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > atkbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "atkbdmap.h" # sunkbdmap.h optional sunkbd_dflt_keymap \ compile-with "/usr/sbin/kbdcontrol -L ${SUNKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > sunkbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "sunkbdmap.h" # ukbdmap.h optional ukbd_dflt_keymap \ compile-with "/usr/sbin/kbdcontrol -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ no-obj no-implicit-rule before-depend \ clean "ukbdmap.h" # cddl/contrib/opensolaris/common/atomic/sparc64/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/atkbdc/atkbd.c optional atkbd atkbdc dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc dev/atkbdc/atkbdc.c optional atkbdc dev/atkbdc/atkbdc_ebus.c optional atkbdc ebus dev/atkbdc/atkbdc_isa.c optional atkbdc isa dev/atkbdc/atkbdc_subr.c optional atkbdc dev/atkbdc/psm.c optional psm atkbdc dev/auxio/auxio.c optional auxio sbus | auxio ebus dev/esp/esp_sbus.c optional esp sbus dev/fb/creator.c optional creator sc dev/fb/creator_vt.c optional creator vt dev/fb/fb.c optional sc dev/fb/gallant12x22.c optional sc dev/fb/machfb.c optional machfb sc dev/hwpmc/hwpmc_sparc64.c optional hwpmc dev/kbd/kbd.c optional atkbd | sc | ukbd | vt dev/le/if_le_lebuffer.c optional le sbus dev/le/if_le_ledma.c optional le sbus dev/le/lebuffer_sbus.c optional le sbus dev/ofw/ofw_bus_if.m standard dev/ofw/ofw_bus_subr.c standard dev/ofw/ofw_console.c optional ofw_console dev/ofw/ofw_if.m standard dev/ofw/ofw_standard.c standard dev/ofw/openfirm.c standard dev/ofw/openfirmio.c standard dev/ofw/openpromio.c standard dev/pcf/envctrl.c optional pcf ebus dev/pcf/pcf_ebus.c optional pcf ebus dev/sound/sbus/cs4231.c optional snd_audiocs ebus | \ snd_audiocs sbus dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc dev/uart/uart_cpu_sparc64.c optional uart dev/uart/uart_kbd_sun.c optional uart sc | vt dev/vt/hw/ofwfb/ofwfb.c optional vt kern/kern_clocksource.c standard kern/subr_dummy_vdso_tc.c standard kern/syscalls.c optional ktr kern/subr_sfbuf.c standard libkern/ffs.c standard libkern/ffsl.c standard libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/memmove.c standard sparc64/central/central.c optional central sparc64/ebus/ebus.c optional ebus sparc64/ebus/epic.c optional epic ebus sparc64/fhc/clkbrd.c optional fhc sparc64/fhc/fhc.c optional fhc sparc64/isa/isa.c optional isa sparc64/isa/isa_dma.c optional isa sparc64/isa/ofw_isa.c optional ebus | isa sparc64/pci/apb.c optional pci sparc64/pci/fire.c optional pci +sparc64/pci/ofw_pci.c optional pci sparc64/pci/ofw_pcib.c optional pci sparc64/pci/ofw_pcib_subr.c optional pci sparc64/pci/ofw_pcibus.c optional pci sparc64/pci/ofw_pci_if.m optional pci sparc64/pci/psycho.c optional pci sparc64/pci/sbbc.c optional sbbc uart sparc64/pci/schizo.c optional pci sparc64/sbus/dma_sbus.c optional sbus sparc64/sbus/sbus.c optional sbus sparc64/sbus/lsi64854.c optional sbus sparc64/sparc64/ata_machdep.c optional ada | da sparc64/sparc64/autoconf.c standard sparc64/sparc64/bus_machdep.c standard sparc64/sparc64/cache.c standard sparc64/sparc64/cam_machdep.c optional scbus sparc64/sparc64/cheetah.c standard sparc64/sparc64/clock.c standard sparc64/sparc64/counter.c standard sparc64/sparc64/db_disasm.c optional ddb sparc64/sparc64/db_interface.c optional ddb sparc64/sparc64/db_trace.c optional ddb sparc64/sparc64/db_hwwatch.c optional ddb sparc64/sparc64/dump_machdep.c standard sparc64/sparc64/elf_machdep.c standard sparc64/sparc64/exception.S standard no-obj \ compile-with "${NORMAL_S} -mcpu=ultrasparc" sparc64/sparc64/eeprom.c optional eeprom ebus | eeprom fhc | \ eeprom sbus sparc64/sparc64/gdb_machdep.c optional gdb sparc64/sparc64/identcpu.c standard sparc64/sparc64/in_cksum.c optional inet | inet6 sparc64/sparc64/interrupt.S standard no-obj \ compile-with "${NORMAL_S} -mcpu=ultrasparc" sparc64/sparc64/intr_machdep.c standard sparc64/sparc64/iommu.c standard sparc64/sparc64/jbusppm.c standard sparc64/sparc64/locore.S standard no-obj sparc64/sparc64/machdep.c standard sparc64/sparc64/mem.c optional mem sparc64/sparc64/mp_exception.S optional smp \ compile-with "${NORMAL_S} -mcpu=ultrasparc" sparc64/sparc64/mp_locore.S optional smp sparc64/sparc64/mp_machdep.c optional smp sparc64/sparc64/nexus.c standard sparc64/sparc64/ofw_machdep.c standard sparc64/sparc64/pmap.c standard sparc64/sparc64/prof_machdep.c optional profiling-routine sparc64/sparc64/rtc.c optional rtc ebus | rtc isa sparc64/sparc64/rwindow.c standard sparc64/sparc64/sc_machdep.c optional sc sparc64/sparc64/schppm.c standard sparc64/sparc64/spitfire.c standard sparc64/sparc64/ssm.c standard sparc64/sparc64/stack_machdep.c optional ddb | stack sparc64/sparc64/support.S standard \ compile-with "${NORMAL_S} -mcpu=ultrasparc" sparc64/sparc64/sys_machdep.c standard sparc64/sparc64/swtch.S standard sparc64/sparc64/tick.c standard sparc64/sparc64/tlb.c standard sparc64/sparc64/trap.c standard sparc64/sparc64/tsb.c standard sparc64/sparc64/uio_machdep.c standard sparc64/sparc64/upa.c optional creator sparc64/sparc64/vm_machdep.c standard sparc64/sparc64/zeus.c standard Index: head/sys/sparc64/pci/fire.c =================================================================== --- head/sys/sparc64/pci/fire.c (revision 287725) +++ head/sys/sparc64/pci/fire.c (revision 287726) @@ -1,2140 +1,1874 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2001 - 2003 by Thomas Moestl * Copyright (c) 2009 by Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp * from: FreeBSD: psycho.c 183152 2008-09-18 19:45:22Z marius */ #include __FBSDID("$FreeBSD$"); /* * Driver for `Fire' JBus to PCI Express and `Oberon' Uranus to PCI Express * bridges */ #include "opt_fire.h" #include "opt_ofw_pci.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" struct fire_msiqarg; static const struct fire_desc *fire_get_desc(device_t dev); static void fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map, bus_dmasync_op_t op); static int fire_get_intrmap(struct fire_softc *sc, u_int ino, bus_addr_t *intrmapptr, bus_addr_t *intrclrptr); static void fire_intr_assign(void *arg); static void fire_intr_clear(void *arg); static void fire_intr_disable(void *arg); static void fire_intr_enable(void *arg); static int fire_intr_register(struct fire_softc *sc, u_int ino); static inline void fire_msiq_common(struct intr_vector *iv, struct fire_msiqarg *fmqa); static void fire_msiq_filter(void *cookie); static void fire_msiq_handler(void *cookie); static void fire_set_intr(struct fire_softc *sc, u_int index, u_int ino, driver_filter_t handler, void *arg); static timecounter_get_t fire_get_timecount; /* Interrupt handlers */ static driver_filter_t fire_dmc_pec; static driver_filter_t fire_pcie; static driver_filter_t fire_xcb; /* * Methods */ -static bus_activate_resource_t fire_activate_resource; -static bus_adjust_resource_t fire_adjust_resource; static pcib_alloc_msi_t fire_alloc_msi; static pcib_alloc_msix_t fire_alloc_msix; static bus_alloc_resource_t fire_alloc_resource; static device_attach_t fire_attach; -static bus_get_dma_tag_t fire_get_dma_tag; -static ofw_bus_get_node_t fire_get_node; static pcib_map_msi_t fire_map_msi; static pcib_maxslots_t fire_maxslots; static device_probe_t fire_probe; static pcib_read_config_t fire_read_config; -static bus_read_ivar_t fire_read_ivar; static pcib_release_msi_t fire_release_msi; static pcib_release_msix_t fire_release_msix; static pcib_route_interrupt_t fire_route_interrupt; static bus_setup_intr_t fire_setup_intr; static bus_teardown_intr_t fire_teardown_intr; static pcib_write_config_t fire_write_config; static device_method_t fire_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fire_probe), DEVMETHOD(device_attach, fire_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, fire_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, fire_setup_intr), DEVMETHOD(bus_teardown_intr, fire_teardown_intr), DEVMETHOD(bus_alloc_resource, fire_alloc_resource), - DEVMETHOD(bus_activate_resource, fire_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, fire_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, fire_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, fire_maxslots), DEVMETHOD(pcib_read_config, fire_read_config), DEVMETHOD(pcib_write_config, fire_write_config), DEVMETHOD(pcib_route_interrupt, fire_route_interrupt), DEVMETHOD(pcib_alloc_msi, fire_alloc_msi), DEVMETHOD(pcib_release_msi, fire_release_msi), DEVMETHOD(pcib_alloc_msix, fire_alloc_msix), DEVMETHOD(pcib_release_msix, fire_release_msix), DEVMETHOD(pcib_map_msi, fire_map_msi), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, fire_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), DEVMETHOD_END }; static devclass_t fire_devclass; DEFINE_CLASS_0(pcib, fire_driver, fire_methods, sizeof(struct fire_softc)); EARLY_DRIVER_MODULE(fire, nexus, fire_driver, fire_devclass, 0, 0, BUS_PASS_BUS); MODULE_DEPEND(fire, nexus, 1, 1, 1); static const struct intr_controller fire_ic = { fire_intr_enable, fire_intr_disable, fire_intr_assign, fire_intr_clear }; struct fire_icarg { struct fire_softc *fica_sc; bus_addr_t fica_map; bus_addr_t fica_clr; }; static const struct intr_controller fire_msiqc_filter = { fire_intr_enable, fire_intr_disable, fire_intr_assign, NULL }; struct fire_msiqarg { struct fire_icarg fmqa_fica; struct mtx fmqa_mtx; struct fo_msiq_record *fmqa_base; uint64_t fmqa_head; uint64_t fmqa_tail; uint32_t fmqa_msiq; uint32_t fmqa_msi; }; #define FIRE_PERF_CNT_QLTY 100 #define FIRE_SPC_BARRIER(spc, sc, offs, len, flags) \ bus_barrier((sc)->sc_mem_res[(spc)], (offs), (len), (flags)) #define FIRE_SPC_READ_8(spc, sc, offs) \ bus_read_8((sc)->sc_mem_res[(spc)], (offs)) #define FIRE_SPC_WRITE_8(spc, sc, offs, v) \ bus_write_8((sc)->sc_mem_res[(spc)], (offs), (v)) #ifndef FIRE_DEBUG #define FIRE_SPC_SET(spc, sc, offs, reg, v) \ FIRE_SPC_WRITE_8((spc), (sc), (offs), (v)) #else #define FIRE_SPC_SET(spc, sc, offs, reg, v) do { \ device_printf((sc)->sc_dev, reg " 0x%016llx -> 0x%016llx\n", \ (unsigned long long)FIRE_SPC_READ_8((spc), (sc), (offs)), \ (unsigned long long)(v)); \ FIRE_SPC_WRITE_8((spc), (sc), (offs), (v)); \ } while (0) #endif #define FIRE_PCI_BARRIER(sc, offs, len, flags) \ FIRE_SPC_BARRIER(FIRE_PCI, (sc), (offs), len, flags) #define FIRE_PCI_READ_8(sc, offs) \ FIRE_SPC_READ_8(FIRE_PCI, (sc), (offs)) #define FIRE_PCI_WRITE_8(sc, offs, v) \ FIRE_SPC_WRITE_8(FIRE_PCI, (sc), (offs), (v)) #define FIRE_CTRL_BARRIER(sc, offs, len, flags) \ FIRE_SPC_BARRIER(FIRE_CTRL, (sc), (offs), len, flags) #define FIRE_CTRL_READ_8(sc, offs) \ FIRE_SPC_READ_8(FIRE_CTRL, (sc), (offs)) #define FIRE_CTRL_WRITE_8(sc, offs, v) \ FIRE_SPC_WRITE_8(FIRE_CTRL, (sc), (offs), (v)) #define FIRE_PCI_SET(sc, offs, v) \ FIRE_SPC_SET(FIRE_PCI, (sc), (offs), # offs, (v)) #define FIRE_CTRL_SET(sc, offs, v) \ FIRE_SPC_SET(FIRE_CTRL, (sc), (offs), # offs, (v)) struct fire_desc { const char *fd_string; int fd_mode; const char *fd_name; }; static const struct fire_desc fire_compats[] = { { "pciex108e,80f0", FIRE_MODE_FIRE, "Fire" }, #if 0 { "pciex108e,80f8", FIRE_MODE_OBERON, "Oberon" }, #endif { NULL, 0, NULL } }; static const struct fire_desc * fire_get_desc(device_t dev) { const struct fire_desc *desc; const char *compat; compat = ofw_bus_get_compat(dev); if (compat == NULL) return (NULL); for (desc = fire_compats; desc->fd_string != NULL; desc++) if (strcmp(desc->fd_string, compat) == 0) return (desc); return (NULL); } static int fire_probe(device_t dev) { const char *dtype; dtype = ofw_bus_get_type(dev); if (dtype != NULL && strcmp(dtype, OFW_TYPE_PCIE) == 0 && fire_get_desc(dev) != NULL) { device_set_desc(dev, "Sun Host-PCIe bridge"); return (BUS_PROBE_GENERIC); } return (ENXIO); } static int fire_attach(device_t dev) { struct fire_softc *sc; const struct fire_desc *desc; struct ofw_pci_msi_ranges msi_ranges; struct ofw_pci_msi_addr_ranges msi_addr_ranges; struct ofw_pci_msi_eq_to_devino msi_eq_to_devino; struct fire_msiqarg *fmqa; struct timecounter *tc; - struct ofw_pci_ranges *range; + bus_dma_tag_t dmat; uint64_t ino_bitmap, val; phandle_t node; uint32_t prop, prop_array[2]; int i, j, mode; u_int lw; uint16_t mps; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); desc = fire_get_desc(dev); mode = desc->fd_mode; sc->sc_dev = dev; - sc->sc_node = node; sc->sc_mode = mode; sc->sc_flags = 0; mtx_init(&sc->sc_msi_mtx, "msi_mtx", NULL, MTX_DEF); mtx_init(&sc->sc_pcib_mtx, "pcib_mtx", NULL, MTX_SPIN); /* * Fire and Oberon have two register banks: * (0) per-PBM PCI Express configuration and status registers * (1) (shared) Fire/Oberon controller configuration and status * registers */ for (i = 0; i < FIRE_NREG; i++) { j = i; sc->sc_mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j, RF_ACTIVE); if (sc->sc_mem_res[i] == NULL) panic("%s: could not allocate register bank %d", __func__, i); } if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) panic("%s: could not determine IGN", __func__); if (OF_getprop(node, "module-revision#", &prop, sizeof(prop)) == -1) panic("%s: could not determine module-revision", __func__); device_printf(dev, "%s, module-revision %d, IGN %#x\n", desc->fd_name, prop, sc->sc_ign); /* * Hunt through all the interrupt mapping regs and register * the interrupt controller for our interrupt vectors. We do * this early in order to be able to catch stray interrupts. */ i = OF_getprop(node, "ino-bitmap", (void *)prop_array, sizeof(prop_array)); if (i == -1) panic("%s: could not get ino-bitmap", __func__); ino_bitmap = ((uint64_t)prop_array[1] << 32) | prop_array[0]; for (i = 0; i <= FO_MAX_INO; i++) { if ((ino_bitmap & (1ULL << i)) == 0) continue; j = fire_intr_register(sc, i); if (j != 0) device_printf(dev, "could not register interrupt " "controller for INO %d (%d)\n", i, j); } /* JBC/UBC module initialization */ FIRE_CTRL_SET(sc, FO_XBC_ERR_LOG_EN, ~0ULL); FIRE_CTRL_SET(sc, FO_XBC_ERR_STAT_CLR, ~0ULL); /* not enabled by OpenSolaris */ FIRE_CTRL_SET(sc, FO_XBC_INT_EN, ~0ULL); if (sc->sc_mode == FIRE_MODE_FIRE) { FIRE_CTRL_SET(sc, FIRE_JBUS_PAR_CTRL, FIRE_JBUS_PAR_CTRL_P_EN); FIRE_CTRL_SET(sc, FIRE_JBC_FATAL_RST_EN, ((1ULL << FIRE_JBC_FATAL_RST_EN_SPARE_P_INT_SHFT) & FIRE_JBC_FATAL_RST_EN_SPARE_P_INT_MASK) | FIRE_JBC_FATAL_RST_EN_MB_PEA_P_INT | FIRE_JBC_FATAL_RST_EN_CPE_P_INT | FIRE_JBC_FATAL_RST_EN_APE_P_INT | FIRE_JBC_FATAL_RST_EN_PIO_CPE_INT | FIRE_JBC_FATAL_RST_EN_JTCEEW_P_INT | FIRE_JBC_FATAL_RST_EN_JTCEEI_P_INT | FIRE_JBC_FATAL_RST_EN_JTCEER_P_INT); FIRE_CTRL_SET(sc, FIRE_JBC_CORE_BLOCK_INT_EN, ~0ULL); } /* TLU initialization */ FIRE_PCI_SET(sc, FO_PCI_TLU_OEVENT_STAT_CLR, FO_PCI_TLU_OEVENT_S_MASK | FO_PCI_TLU_OEVENT_P_MASK); /* not enabled by OpenSolaris */ FIRE_PCI_SET(sc, FO_PCI_TLU_OEVENT_INT_EN, FO_PCI_TLU_OEVENT_S_MASK | FO_PCI_TLU_OEVENT_P_MASK); FIRE_PCI_SET(sc, FO_PCI_TLU_UERR_STAT_CLR, FO_PCI_TLU_UERR_INT_S_MASK | FO_PCI_TLU_UERR_INT_P_MASK); /* not enabled by OpenSolaris */ FIRE_PCI_SET(sc, FO_PCI_TLU_UERR_INT_EN, FO_PCI_TLU_UERR_INT_S_MASK | FO_PCI_TLU_UERR_INT_P_MASK); FIRE_PCI_SET(sc, FO_PCI_TLU_CERR_STAT_CLR, FO_PCI_TLU_CERR_INT_S_MASK | FO_PCI_TLU_CERR_INT_P_MASK); /* not enabled by OpenSolaris */ FIRE_PCI_SET(sc, FO_PCI_TLU_CERR_INT_EN, FO_PCI_TLU_CERR_INT_S_MASK | FO_PCI_TLU_CERR_INT_P_MASK); val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_CTRL) | ((FO_PCI_TLU_CTRL_L0S_TIM_DFLT << FO_PCI_TLU_CTRL_L0S_TIM_SHFT) & FO_PCI_TLU_CTRL_L0S_TIM_MASK) | ((FO_PCI_TLU_CTRL_CFG_DFLT << FO_PCI_TLU_CTRL_CFG_SHFT) & FO_PCI_TLU_CTRL_CFG_MASK); if (sc->sc_mode == FIRE_MODE_OBERON) val &= ~FO_PCI_TLU_CTRL_NWPR_EN; val |= FO_PCI_TLU_CTRL_CFG_REMAIN_DETECT_QUIET; FIRE_PCI_SET(sc, FO_PCI_TLU_CTRL, val); FIRE_PCI_SET(sc, FO_PCI_TLU_DEV_CTRL, 0); FIRE_PCI_SET(sc, FO_PCI_TLU_LNK_CTRL, FO_PCI_TLU_LNK_CTRL_CLK); /* DLU/LPU initialization */ if (sc->sc_mode == FIRE_MODE_OBERON) FIRE_PCI_SET(sc, FO_PCI_LPU_INT_MASK, 0); else FIRE_PCI_SET(sc, FO_PCI_LPU_RST, 0); FIRE_PCI_SET(sc, FO_PCI_LPU_LNK_LYR_CFG, FO_PCI_LPU_LNK_LYR_CFG_VC0_EN); FIRE_PCI_SET(sc, FO_PCI_LPU_FLW_CTRL_UPDT_CTRL, FO_PCI_LPU_FLW_CTRL_UPDT_CTRL_FC0_NP_EN | FO_PCI_LPU_FLW_CTRL_UPDT_CTRL_FC0_P_EN); if (sc->sc_mode == FIRE_MODE_OBERON) FIRE_PCI_SET(sc, FO_PCI_LPU_TXLNK_RPLY_TMR_THRS, (OBERON_PCI_LPU_TXLNK_RPLY_TMR_THRS_DFLT << FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_SHFT) & FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_MASK); else { switch ((FIRE_PCI_READ_8(sc, FO_PCI_TLU_LNK_STAT) & FO_PCI_TLU_LNK_STAT_WDTH_MASK) >> FO_PCI_TLU_LNK_STAT_WDTH_SHFT) { case 1: lw = 0; break; case 4: lw = 1; break; case 8: lw = 2; break; case 16: lw = 3; break; default: lw = 0; } mps = (FIRE_PCI_READ_8(sc, FO_PCI_TLU_CTRL) & FO_PCI_TLU_CTRL_CFG_MPS_MASK) >> FO_PCI_TLU_CTRL_CFG_MPS_SHFT; i = sizeof(fire_freq_nak_tmr_thrs) / sizeof(*fire_freq_nak_tmr_thrs); if (mps >= i) mps = i - 1; FIRE_PCI_SET(sc, FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS, (fire_freq_nak_tmr_thrs[mps][lw] << FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS_SHFT) & FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS_MASK); FIRE_PCI_SET(sc, FO_PCI_LPU_TXLNK_RPLY_TMR_THRS, (fire_rply_tmr_thrs[mps][lw] << FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_SHFT) & FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_MASK); FIRE_PCI_SET(sc, FO_PCI_LPU_TXLNK_RTR_FIFO_PTR, ((FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_DFLT << FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_SHFT) & FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_MASK) | ((FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_DFLT << FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_SHFT) & FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_MASK)); FIRE_PCI_SET(sc, FO_PCI_LPU_LTSSM_CFG2, (FO_PCI_LPU_LTSSM_CFG2_12_TO_DFLT << FO_PCI_LPU_LTSSM_CFG2_12_TO_SHFT) & FO_PCI_LPU_LTSSM_CFG2_12_TO_MASK); FIRE_PCI_SET(sc, FO_PCI_LPU_LTSSM_CFG3, (FO_PCI_LPU_LTSSM_CFG3_2_TO_DFLT << FO_PCI_LPU_LTSSM_CFG3_2_TO_SHFT) & FO_PCI_LPU_LTSSM_CFG3_2_TO_MASK); FIRE_PCI_SET(sc, FO_PCI_LPU_LTSSM_CFG4, ((FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_DFLT << FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_SHFT) & FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_MASK) | ((FO_PCI_LPU_LTSSM_CFG4_N_FTS_DFLT << FO_PCI_LPU_LTSSM_CFG4_N_FTS_SHFT) & FO_PCI_LPU_LTSSM_CFG4_N_FTS_MASK)); FIRE_PCI_SET(sc, FO_PCI_LPU_LTSSM_CFG5, 0); } /* ILU initialization */ FIRE_PCI_SET(sc, FO_PCI_ILU_ERR_STAT_CLR, ~0ULL); /* not enabled by OpenSolaris */ FIRE_PCI_SET(sc, FO_PCI_ILU_INT_EN, ~0ULL); /* IMU initialization */ FIRE_PCI_SET(sc, FO_PCI_IMU_ERR_STAT_CLR, ~0ULL); FIRE_PCI_SET(sc, FO_PCI_IMU_INT_EN, FIRE_PCI_READ_8(sc, FO_PCI_IMU_INT_EN) & ~(FO_PCI_IMU_ERR_INT_FATAL_MES_NOT_EN_S | FO_PCI_IMU_ERR_INT_NFATAL_MES_NOT_EN_S | FO_PCI_IMU_ERR_INT_COR_MES_NOT_EN_S | FO_PCI_IMU_ERR_INT_FATAL_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_NFATAL_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_COR_MES_NOT_EN_P)); /* MMU initialization */ FIRE_PCI_SET(sc, FO_PCI_MMU_ERR_STAT_CLR, FO_PCI_MMU_ERR_INT_S_MASK | FO_PCI_MMU_ERR_INT_P_MASK); /* not enabled by OpenSolaris */ FIRE_PCI_SET(sc, FO_PCI_MMU_INT_EN, FO_PCI_MMU_ERR_INT_S_MASK | FO_PCI_MMU_ERR_INT_P_MASK); /* DMC initialization */ FIRE_PCI_SET(sc, FO_PCI_DMC_CORE_BLOCK_INT_EN, ~0ULL); FIRE_PCI_SET(sc, FO_PCI_DMC_DBG_SEL_PORTA, 0); FIRE_PCI_SET(sc, FO_PCI_DMC_DBG_SEL_PORTB, 0); /* PEC initialization */ FIRE_PCI_SET(sc, FO_PCI_PEC_CORE_BLOCK_INT_EN, ~0ULL); /* Establish handlers for interesting interrupts. */ if ((ino_bitmap & (1ULL << FO_DMC_PEC_INO)) != 0) fire_set_intr(sc, 1, FO_DMC_PEC_INO, fire_dmc_pec, sc); if ((ino_bitmap & (1ULL << FO_XCB_INO)) != 0) fire_set_intr(sc, 0, FO_XCB_INO, fire_xcb, sc); /* MSI/MSI-X support */ if (OF_getprop(node, "#msi", &sc->sc_msi_count, sizeof(sc->sc_msi_count)) == -1) panic("%s: could not determine MSI count", __func__); if (OF_getprop(node, "msi-ranges", &msi_ranges, sizeof(msi_ranges)) == -1) sc->sc_msi_first = 0; else sc->sc_msi_first = msi_ranges.first; if (OF_getprop(node, "msi-data-mask", &sc->sc_msi_data_mask, sizeof(sc->sc_msi_data_mask)) == -1) panic("%s: could not determine MSI data mask", __func__); if (OF_getprop(node, "msix-data-width", &sc->sc_msix_data_width, sizeof(sc->sc_msix_data_width)) > 0) sc->sc_flags |= FIRE_MSIX; if (OF_getprop(node, "msi-address-ranges", &msi_addr_ranges, sizeof(msi_addr_ranges)) == -1) panic("%s: could not determine MSI address ranges", __func__); sc->sc_msi_addr32 = OFW_PCI_MSI_ADDR_RANGE_32(&msi_addr_ranges); sc->sc_msi_addr64 = OFW_PCI_MSI_ADDR_RANGE_64(&msi_addr_ranges); if (OF_getprop(node, "#msi-eqs", &sc->sc_msiq_count, sizeof(sc->sc_msiq_count)) == -1) panic("%s: could not determine MSI event queue count", __func__); if (OF_getprop(node, "msi-eq-size", &sc->sc_msiq_size, sizeof(sc->sc_msiq_size)) == -1) panic("%s: could not determine MSI event queue size", __func__); if (OF_getprop(node, "msi-eq-to-devino", &msi_eq_to_devino, sizeof(msi_eq_to_devino)) == -1 && OF_getprop(node, "msi-eq-devino", &msi_eq_to_devino, sizeof(msi_eq_to_devino)) == -1) { sc->sc_msiq_first = 0; sc->sc_msiq_ino_first = FO_EQ_FIRST_INO; } else { sc->sc_msiq_first = msi_eq_to_devino.eq_first; sc->sc_msiq_ino_first = msi_eq_to_devino.devino_first; } if (sc->sc_msiq_ino_first < FO_EQ_FIRST_INO || sc->sc_msiq_ino_first + sc->sc_msiq_count - 1 > FO_EQ_LAST_INO) panic("%s: event queues exceed INO range", __func__); sc->sc_msi_bitmap = malloc(roundup2(sc->sc_msi_count, NBBY) / NBBY, M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_msi_bitmap == NULL) panic("%s: could not malloc MSI bitmap", __func__); sc->sc_msi_msiq_table = malloc(sc->sc_msi_count * sizeof(*sc->sc_msi_msiq_table), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_msi_msiq_table == NULL) panic("%s: could not malloc MSI-MSI event queue table", __func__); sc->sc_msiq_bitmap = malloc(roundup2(sc->sc_msiq_count, NBBY) / NBBY, M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_msiq_bitmap == NULL) panic("%s: could not malloc MSI event queue bitmap", __func__); j = FO_EQ_RECORD_SIZE * FO_EQ_NRECORDS * sc->sc_msiq_count; sc->sc_msiq = contigmalloc(j, M_DEVBUF, M_NOWAIT, 0, ~0UL, FO_EQ_ALIGNMENT, 0); if (sc->sc_msiq == NULL) panic("%s: could not contigmalloc MSI event queue", __func__); memset(sc->sc_msiq, 0, j); FIRE_PCI_SET(sc, FO_PCI_EQ_BASE_ADDR, FO_PCI_EQ_BASE_ADDR_BYPASS | (pmap_kextract((vm_offset_t)sc->sc_msiq) & FO_PCI_EQ_BASE_ADDR_MASK)); for (i = 0; i < sc->sc_msi_count; i++) { j = (i + sc->sc_msi_first) << 3; FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_MAP_BASE + j, FIRE_PCI_READ_8(sc, FO_PCI_MSI_MAP_BASE + j) & ~FO_PCI_MSI_MAP_V); } for (i = 0; i < sc->sc_msiq_count; i++) { j = i + sc->sc_msiq_ino_first; if ((ino_bitmap & (1ULL << j)) == 0) { mtx_lock(&sc->sc_msi_mtx); setbit(sc->sc_msiq_bitmap, i); mtx_unlock(&sc->sc_msi_mtx); } fmqa = intr_vectors[INTMAP_VEC(sc->sc_ign, j)].iv_icarg; mtx_init(&fmqa->fmqa_mtx, "msiq_mtx", NULL, MTX_SPIN); fmqa->fmqa_base = (struct fo_msiq_record *)((caddr_t)sc->sc_msiq + (FO_EQ_RECORD_SIZE * FO_EQ_NRECORDS * i)); j = i + sc->sc_msiq_first; fmqa->fmqa_msiq = j; j <<= 3; fmqa->fmqa_head = FO_PCI_EQ_HD_BASE + j; fmqa->fmqa_tail = FO_PCI_EQ_TL_BASE + j; FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + j, FO_PCI_EQ_CTRL_CLR_COVERR | FO_PCI_EQ_CTRL_CLR_E2I | FO_PCI_EQ_CTRL_CLR_DIS); FIRE_PCI_WRITE_8(sc, fmqa->fmqa_tail, (0 << FO_PCI_EQ_TL_SHFT) & FO_PCI_EQ_TL_MASK); FIRE_PCI_WRITE_8(sc, fmqa->fmqa_head, (0 << FO_PCI_EQ_HD_SHFT) & FO_PCI_EQ_HD_MASK); } FIRE_PCI_SET(sc, FO_PCI_MSI_32_BIT_ADDR, sc->sc_msi_addr32 & FO_PCI_MSI_32_BIT_ADDR_MASK); FIRE_PCI_SET(sc, FO_PCI_MSI_64_BIT_ADDR, sc->sc_msi_addr64 & FO_PCI_MSI_64_BIT_ADDR_MASK); /* * Establish a handler for interesting PCIe messages and disable * unintersting ones. */ mtx_lock(&sc->sc_msi_mtx); for (i = 0; i < sc->sc_msiq_count; i++) { if (isclr(sc->sc_msiq_bitmap, i) != 0) { j = i; break; } } if (i == sc->sc_msiq_count) { mtx_unlock(&sc->sc_msi_mtx); panic("%s: no spare event queue for PCIe messages", __func__); } setbit(sc->sc_msiq_bitmap, j); mtx_unlock(&sc->sc_msi_mtx); i = INTMAP_VEC(sc->sc_ign, j + sc->sc_msiq_ino_first); if (bus_set_resource(dev, SYS_RES_IRQ, 2, i, 1) != 0) panic("%s: failed to add interrupt for PCIe messages", __func__); fire_set_intr(sc, 2, INTINO(i), fire_pcie, intr_vectors[i].iv_icarg); j += sc->sc_msiq_first; /* * "Please note that setting the EQNUM field to a value larger than * 35 will yield unpredictable results." */ if (j > 35) panic("%s: invalid queue for PCIe messages (%d)", __func__, j); FIRE_PCI_SET(sc, FO_PCI_ERR_COR, FO_PCI_ERR_PME_V | ((j << FO_PCI_ERR_PME_EQNUM_SHFT) & FO_PCI_ERR_PME_EQNUM_MASK)); FIRE_PCI_SET(sc, FO_PCI_ERR_NONFATAL, FO_PCI_ERR_PME_V | ((j << FO_PCI_ERR_PME_EQNUM_SHFT) & FO_PCI_ERR_PME_EQNUM_MASK)); FIRE_PCI_SET(sc, FO_PCI_ERR_FATAL, FO_PCI_ERR_PME_V | ((j << FO_PCI_ERR_PME_EQNUM_SHFT) & FO_PCI_ERR_PME_EQNUM_MASK)); FIRE_PCI_SET(sc, FO_PCI_PM_PME, 0); FIRE_PCI_SET(sc, FO_PCI_PME_TO_ACK, 0); FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_SET_BASE + (j << 3), FO_PCI_EQ_CTRL_SET_EN); #define TC_COUNTER_MAX_MASK 0xffffffff /* * Setup JBC/UBC performance counter 0 in bus cycle counting * mode as timecounter. */ if (device_get_unit(dev) == 0) { FIRE_CTRL_SET(sc, FO_XBC_PRF_CNT0, 0); FIRE_CTRL_SET(sc, FO_XBC_PRF_CNT1, 0); FIRE_CTRL_SET(sc, FO_XBC_PRF_CNT_SEL, (FO_XBC_PRF_CNT_NONE << FO_XBC_PRF_CNT_CNT1_SHFT) | (FO_XBC_PRF_CNT_XB_CLK << FO_XBC_PRF_CNT_CNT0_SHFT)); tc = malloc(sizeof(*tc), M_DEVBUF, M_NOWAIT | M_ZERO); if (tc == NULL) panic("%s: could not malloc timecounter", __func__); tc->tc_get_timecount = fire_get_timecount; tc->tc_counter_mask = TC_COUNTER_MAX_MASK; if (OF_getprop(OF_peer(0), "clock-frequency", &prop, sizeof(prop)) == -1) panic("%s: could not determine clock frequency", __func__); tc->tc_frequency = prop; tc->tc_name = strdup(device_get_nameunit(dev), M_DEVBUF); tc->tc_priv = sc; /* * Due to initial problems with the JBus-driven performance * counters not advancing which might be firmware dependent * ensure that it actually works. */ if (fire_get_timecount(tc) - fire_get_timecount(tc) != 0) tc->tc_quality = FIRE_PERF_CNT_QLTY; else tc->tc_quality = -FIRE_PERF_CNT_QLTY; tc_init(tc); } /* * Set up the IOMMU. Both Fire and Oberon have one per PBM, but * neither has a streaming buffer. */ memcpy(&sc->sc_dma_methods, &iommu_dma_methods, sizeof(sc->sc_dma_methods)); sc->sc_is.is_flags = IOMMU_FIRE | IOMMU_PRESERVE_PROM; if (sc->sc_mode == FIRE_MODE_OBERON) { sc->sc_is.is_flags |= IOMMU_FLUSH_CACHE; sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(OBERON_IOMMU_BITS); } else { sc->sc_dma_methods.dm_dmamap_sync = fire_dmamap_sync; sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(FIRE_IOMMU_BITS); } sc->sc_is.is_sb[0] = sc->sc_is.is_sb[1] = 0; /* Punch in our copies. */ sc->sc_is.is_bustag = rman_get_bustag(sc->sc_mem_res[FIRE_PCI]); sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[FIRE_PCI]); sc->sc_is.is_iommu = FO_PCI_MMU; val = FIRE_PCI_READ_8(sc, FO_PCI_MMU + IMR_CTL); - iommu_init(device_get_nameunit(sc->sc_dev), &sc->sc_is, 7, -1, 0); + iommu_init(device_get_nameunit(dev), &sc->sc_is, 7, -1, 0); #ifdef FIRE_DEBUG device_printf(dev, "FO_PCI_MMU + IMR_CTL 0x%016llx -> 0x%016llx\n", (long long unsigned)val, (long long unsigned)sc->sc_is.is_cr); #endif - - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Fire PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, FO_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Fire PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, FO_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != FIRE_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < FIRE_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0x100000000, sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, - 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = &sc->sc_is; - sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods; + dmat->dt_cookie = &sc->sc_is; + dmat->dt_mt = &sc->sc_dma_methods; - /* - * Get the bus range from the firmware. - * NB: Neither Fire nor Oberon support PCI bus reenumeration. - */ - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose != 0) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + if (ofw_pci_attach_common(dev, dmat, FO_IO_SIZE, FO_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); - #define FIRE_SYSCTL_ADD_UINT(name, arg, desc) \ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, \ (name), CTLFLAG_RD, (arg), 0, (desc)) FIRE_SYSCTL_ADD_UINT("ilu_err", &sc->sc_stats_ilu_err, "ILU unknown errors"); FIRE_SYSCTL_ADD_UINT("jbc_ce_async", &sc->sc_stats_jbc_ce_async, "JBC correctable errors"); FIRE_SYSCTL_ADD_UINT("jbc_unsol_int", &sc->sc_stats_jbc_unsol_int, "JBC unsolicited interrupt ACK/NACK errors"); FIRE_SYSCTL_ADD_UINT("jbc_unsol_rd", &sc->sc_stats_jbc_unsol_rd, "JBC unsolicited read response errors"); FIRE_SYSCTL_ADD_UINT("mmu_err", &sc->sc_stats_mmu_err, "MMU errors"); FIRE_SYSCTL_ADD_UINT("tlu_ce", &sc->sc_stats_tlu_ce, "DLU/TLU correctable errors"); FIRE_SYSCTL_ADD_UINT("tlu_oe_non_fatal", &sc->sc_stats_tlu_oe_non_fatal, "DLU/TLU other event non-fatal errors summary"), FIRE_SYSCTL_ADD_UINT("tlu_oe_rx_err", &sc->sc_stats_tlu_oe_rx_err, "DLU/TLU receive other event errors"), FIRE_SYSCTL_ADD_UINT("tlu_oe_tx_err", &sc->sc_stats_tlu_oe_tx_err, "DLU/TLU transmit other event errors"), FIRE_SYSCTL_ADD_UINT("ubc_dmardue", &sc->sc_stats_ubc_dmardue, "UBC DMARDUE erros"); #undef FIRE_SYSCTL_ADD_UINT device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static void fire_set_intr(struct fire_softc *sc, u_int index, u_int ino, driver_filter_t handler, void *arg) { u_long vec; int rid; rid = index; sc->sc_irq_res[index] = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res[index] == NULL || INTINO(vec = rman_get_start(sc->sc_irq_res[index])) != ino || INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &fire_ic || bus_setup_intr(sc->sc_dev, sc->sc_irq_res[index], INTR_TYPE_MISC | INTR_BRIDGE, handler, NULL, arg, &sc->sc_ihand[index]) != 0) panic("%s: failed to set up interrupt %d", __func__, index); } static int fire_intr_register(struct fire_softc *sc, u_int ino) { struct fire_icarg *fica; bus_addr_t intrclr, intrmap; int error; if (fire_get_intrmap(sc, ino, &intrmap, &intrclr) == 0) return (ENXIO); fica = malloc((ino >= FO_EQ_FIRST_INO && ino <= FO_EQ_LAST_INO) ? sizeof(struct fire_msiqarg) : sizeof(struct fire_icarg), M_DEVBUF, M_NOWAIT | M_ZERO); if (fica == NULL) return (ENOMEM); fica->fica_sc = sc; fica->fica_map = intrmap; fica->fica_clr = intrclr; error = (intr_controller_register(INTMAP_VEC(sc->sc_ign, ino), &fire_ic, fica)); if (error != 0) free(fica, M_DEVBUF); return (error); } static int fire_get_intrmap(struct fire_softc *sc, u_int ino, bus_addr_t *intrmapptr, bus_addr_t *intrclrptr) { if (ino > FO_MAX_INO) { device_printf(sc->sc_dev, "out of range INO %d requested\n", ino); return (0); } ino <<= 3; if (intrmapptr != NULL) *intrmapptr = FO_PCI_INT_MAP_BASE + ino; if (intrclrptr != NULL) *intrclrptr = FO_PCI_INT_CLR_BASE + ino; return (1); } /* * Interrupt handlers */ static int fire_dmc_pec(void *arg) { struct fire_softc *sc; device_t dev; uint64_t cestat, dmcstat, ilustat, imustat, mcstat, mmustat, mmutfar; uint64_t mmutfsr, oestat, pecstat, uestat, val; u_int fatal, oenfatal; fatal = 0; sc = arg; dev = sc->sc_dev; mtx_lock_spin(&sc->sc_pcib_mtx); mcstat = FIRE_PCI_READ_8(sc, FO_PCI_MULTI_CORE_ERR_STAT); if ((mcstat & FO_PCI_MULTI_CORE_ERR_STAT_DMC) != 0) { dmcstat = FIRE_PCI_READ_8(sc, FO_PCI_DMC_CORE_BLOCK_ERR_STAT); if ((dmcstat & FO_PCI_DMC_CORE_BLOCK_INT_EN_IMU) != 0) { imustat = FIRE_PCI_READ_8(sc, FO_PCI_IMU_INT_STAT); device_printf(dev, "IMU error %#llx\n", (unsigned long long)imustat); if ((imustat & FO_PCI_IMU_ERR_INT_EQ_NOT_EN_P) != 0) { fatal = 1; val = FIRE_PCI_READ_8(sc, FO_PCI_IMU_SCS_ERR_LOG); device_printf(dev, "SCS error log %#llx\n", (unsigned long long)val); } if ((imustat & FO_PCI_IMU_ERR_INT_EQ_OVER_P) != 0) { fatal = 1; val = FIRE_PCI_READ_8(sc, FO_PCI_IMU_EQS_ERR_LOG); device_printf(dev, "EQS error log %#llx\n", (unsigned long long)val); } if ((imustat & (FO_PCI_IMU_ERR_INT_MSI_MAL_ERR_P | FO_PCI_IMU_ERR_INT_MSI_PAR_ERR_P | FO_PCI_IMU_ERR_INT_PMEACK_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_PMPME_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_FATAL_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_NFATAL_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_COR_MES_NOT_EN_P | FO_PCI_IMU_ERR_INT_MSI_NOT_EN_P)) != 0) { fatal = 1; val = FIRE_PCI_READ_8(sc, FO_PCI_IMU_RDS_ERR_LOG); device_printf(dev, "RDS error log %#llx\n", (unsigned long long)val); } } if ((dmcstat & FO_PCI_DMC_CORE_BLOCK_INT_EN_MMU) != 0) { fatal = 1; mmustat = FIRE_PCI_READ_8(sc, FO_PCI_MMU_INT_STAT); mmutfar = FIRE_PCI_READ_8(sc, FO_PCI_MMU_TRANS_FAULT_ADDR); mmutfsr = FIRE_PCI_READ_8(sc, FO_PCI_MMU_TRANS_FAULT_STAT); if ((mmustat & (FO_PCI_MMU_ERR_INT_TBW_DPE_P | FO_PCI_MMU_ERR_INT_TBW_ERR_P | FO_PCI_MMU_ERR_INT_TBW_UDE_P | FO_PCI_MMU_ERR_INT_TBW_DME_P | FO_PCI_MMU_ERR_INT_TTC_CAE_P | FIRE_PCI_MMU_ERR_INT_TTC_DPE_P | OBERON_PCI_MMU_ERR_INT_TTC_DUE_P | FO_PCI_MMU_ERR_INT_TRN_ERR_P)) != 0) fatal = 1; else { sc->sc_stats_mmu_err++; FIRE_PCI_WRITE_8(sc, FO_PCI_MMU_ERR_STAT_CLR, mmustat); } device_printf(dev, "MMU error %#llx: TFAR %#llx TFSR %#llx\n", (unsigned long long)mmustat, (unsigned long long)mmutfar, (unsigned long long)mmutfsr); } } if ((mcstat & FO_PCI_MULTI_CORE_ERR_STAT_PEC) != 0) { pecstat = FIRE_PCI_READ_8(sc, FO_PCI_PEC_CORE_BLOCK_INT_STAT); if ((pecstat & FO_PCI_PEC_CORE_BLOCK_INT_STAT_UERR) != 0) { fatal = 1; uestat = FIRE_PCI_READ_8(sc, FO_PCI_TLU_UERR_INT_STAT); device_printf(dev, "DLU/TLU uncorrectable error %#llx\n", (unsigned long long)uestat); if ((uestat & (FO_PCI_TLU_UERR_INT_UR_P | OBERON_PCI_TLU_UERR_INT_POIS_P | FO_PCI_TLU_UERR_INT_MFP_P | FO_PCI_TLU_UERR_INT_ROF_P | FO_PCI_TLU_UERR_INT_UC_P | FIRE_PCI_TLU_UERR_INT_PP_P | OBERON_PCI_TLU_UERR_INT_POIS_P)) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_RX_UERR_HDR1_LOG); device_printf(dev, "receive header log %#llx\n", (unsigned long long)val); val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_RX_UERR_HDR2_LOG); device_printf(dev, "receive header log 2 %#llx\n", (unsigned long long)val); } if ((uestat & FO_PCI_TLU_UERR_INT_CTO_P) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_TX_UERR_HDR1_LOG); device_printf(dev, "transmit header log %#llx\n", (unsigned long long)val); val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_TX_UERR_HDR2_LOG); device_printf(dev, "transmit header log 2 %#llx\n", (unsigned long long)val); } if ((uestat & FO_PCI_TLU_UERR_INT_DLP_P) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT); device_printf(dev, "link layer interrupt and status %#llx\n", (unsigned long long)val); } if ((uestat & FO_PCI_TLU_UERR_INT_TE_P) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_LPU_PHY_LYR_INT_STAT); device_printf(dev, "phy layer interrupt and status %#llx\n", (unsigned long long)val); } } if ((pecstat & FO_PCI_PEC_CORE_BLOCK_INT_STAT_CERR) != 0) { sc->sc_stats_tlu_ce++; cestat = FIRE_PCI_READ_8(sc, FO_PCI_TLU_CERR_INT_STAT); device_printf(dev, "DLU/TLU correctable error %#llx\n", (unsigned long long)cestat); val = FIRE_PCI_READ_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT); device_printf(dev, "link layer interrupt and status %#llx\n", (unsigned long long)val); if ((cestat & FO_PCI_TLU_CERR_INT_RE_P) != 0) { FIRE_PCI_WRITE_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT, val); val = FIRE_PCI_READ_8(sc, FO_PCI_LPU_PHY_LYR_INT_STAT); device_printf(dev, "phy layer interrupt and status %#llx\n", (unsigned long long)val); } FIRE_PCI_WRITE_8(sc, FO_PCI_TLU_CERR_STAT_CLR, cestat); } if ((pecstat & FO_PCI_PEC_CORE_BLOCK_INT_STAT_OEVENT) != 0) { oenfatal = 0; oestat = FIRE_PCI_READ_8(sc, FO_PCI_TLU_OEVENT_INT_STAT); device_printf(dev, "DLU/TLU other event %#llx\n", (unsigned long long)oestat); if ((oestat & (FO_PCI_TLU_OEVENT_MFC_P | FO_PCI_TLU_OEVENT_MRC_P | FO_PCI_TLU_OEVENT_WUC_P | FO_PCI_TLU_OEVENT_RUC_P | FO_PCI_TLU_OEVENT_CRS_P)) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_RX_OEVENT_HDR1_LOG); device_printf(dev, "receive header log %#llx\n", (unsigned long long)val); val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_RX_OEVENT_HDR2_LOG); device_printf(dev, "receive header log 2 %#llx\n", (unsigned long long)val); if ((oestat & (FO_PCI_TLU_OEVENT_MFC_P | FO_PCI_TLU_OEVENT_MRC_P | FO_PCI_TLU_OEVENT_WUC_P | FO_PCI_TLU_OEVENT_RUC_P)) != 0) fatal = 1; else { sc->sc_stats_tlu_oe_rx_err++; oenfatal = 1; } } if ((oestat & (FO_PCI_TLU_OEVENT_MFC_P | FO_PCI_TLU_OEVENT_CTO_P | FO_PCI_TLU_OEVENT_WUC_P | FO_PCI_TLU_OEVENT_RUC_P)) != 0) { val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_TX_OEVENT_HDR1_LOG); device_printf(dev, "transmit header log %#llx\n", (unsigned long long)val); val = FIRE_PCI_READ_8(sc, FO_PCI_TLU_TX_OEVENT_HDR2_LOG); device_printf(dev, "transmit header log 2 %#llx\n", (unsigned long long)val); if ((oestat & (FO_PCI_TLU_OEVENT_MFC_P | FO_PCI_TLU_OEVENT_CTO_P | FO_PCI_TLU_OEVENT_WUC_P | FO_PCI_TLU_OEVENT_RUC_P)) != 0) fatal = 1; else { sc->sc_stats_tlu_oe_tx_err++; oenfatal = 1; } } if ((oestat & (FO_PCI_TLU_OEVENT_ERO_P | FO_PCI_TLU_OEVENT_EMP_P | FO_PCI_TLU_OEVENT_EPE_P | FIRE_PCI_TLU_OEVENT_ERP_P | OBERON_PCI_TLU_OEVENT_ERBU_P | FIRE_PCI_TLU_OEVENT_EIP_P | OBERON_PCI_TLU_OEVENT_EIUE_P)) != 0) { fatal = 1; val = FIRE_PCI_READ_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT); device_printf(dev, "link layer interrupt and status %#llx\n", (unsigned long long)val); } if ((oestat & (FO_PCI_TLU_OEVENT_IIP_P | FO_PCI_TLU_OEVENT_EDP_P | FIRE_PCI_TLU_OEVENT_EHP_P | OBERON_PCI_TLU_OEVENT_TLUEITMO_S | FO_PCI_TLU_OEVENT_ERU_P)) != 0) fatal = 1; if ((oestat & (FO_PCI_TLU_OEVENT_NFP_P | FO_PCI_TLU_OEVENT_LWC_P | FO_PCI_TLU_OEVENT_LIN_P | FO_PCI_TLU_OEVENT_LRS_P | FO_PCI_TLU_OEVENT_LDN_P | FO_PCI_TLU_OEVENT_LUP_P)) != 0) oenfatal = 1; if (oenfatal != 0) { sc->sc_stats_tlu_oe_non_fatal++; FIRE_PCI_WRITE_8(sc, FO_PCI_TLU_OEVENT_STAT_CLR, oestat); if ((oestat & FO_PCI_TLU_OEVENT_LIN_P) != 0) FIRE_PCI_WRITE_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT, FIRE_PCI_READ_8(sc, FO_PCI_LPU_LNK_LYR_INT_STAT)); } } if ((pecstat & FO_PCI_PEC_CORE_BLOCK_INT_STAT_ILU) != 0) { ilustat = FIRE_PCI_READ_8(sc, FO_PCI_ILU_INT_STAT); device_printf(dev, "ILU error %#llx\n", (unsigned long long)ilustat); if ((ilustat & (FIRE_PCI_ILU_ERR_INT_IHB_PE_P | FIRE_PCI_ILU_ERR_INT_IHB_PE_P)) != 0) fatal = 1; else { sc->sc_stats_ilu_err++; FIRE_PCI_WRITE_8(sc, FO_PCI_ILU_INT_STAT, ilustat); } } } mtx_unlock_spin(&sc->sc_pcib_mtx); if (fatal != 0) panic("%s: fatal DMC/PEC error", device_get_nameunit(sc->sc_dev)); return (FILTER_HANDLED); } static int fire_xcb(void *arg) { struct fire_softc *sc; device_t dev; uint64_t errstat, intstat, val; u_int fatal; fatal = 0; sc = arg; dev = sc->sc_dev; mtx_lock_spin(&sc->sc_pcib_mtx); if (sc->sc_mode == FIRE_MODE_OBERON) { intstat = FIRE_CTRL_READ_8(sc, FO_XBC_INT_STAT); device_printf(dev, "UBC error: interrupt status %#llx\n", (unsigned long long)intstat); if ((intstat & ~(OBERON_UBC_ERR_INT_DMARDUEB_P | OBERON_UBC_ERR_INT_DMARDUEA_P)) != 0) fatal = 1; else sc->sc_stats_ubc_dmardue++; if (fatal != 0) { mtx_unlock_spin(&sc->sc_pcib_mtx); panic("%s: fatal UBC core block error", device_get_nameunit(sc->sc_dev)); } else { FIRE_CTRL_SET(sc, FO_XBC_ERR_STAT_CLR, ~0ULL); mtx_unlock_spin(&sc->sc_pcib_mtx); } } else { errstat = FIRE_CTRL_READ_8(sc, FIRE_JBC_CORE_BLOCK_ERR_STAT); if ((errstat & (FIRE_JBC_CORE_BLOCK_ERR_STAT_MERGE | FIRE_JBC_CORE_BLOCK_ERR_STAT_JBCINT | FIRE_JBC_CORE_BLOCK_ERR_STAT_DMCINT)) != 0) { intstat = FIRE_CTRL_READ_8(sc, FO_XBC_INT_STAT); device_printf(dev, "JBC interrupt status %#llx\n", (unsigned long long)intstat); if ((intstat & FIRE_JBC_ERR_INT_EBUS_TO_P) != 0) { val = FIRE_CTRL_READ_8(sc, FIRE_JBC_CSR_ERR_LOG); device_printf(dev, "CSR error log %#llx\n", (unsigned long long)val); } if ((intstat & (FIRE_JBC_ERR_INT_UNSOL_RD_P | FIRE_JBC_ERR_INT_UNSOL_INT_P)) != 0) { if ((intstat & FIRE_JBC_ERR_INT_UNSOL_RD_P) != 0) sc->sc_stats_jbc_unsol_rd++; if ((intstat & FIRE_JBC_ERR_INT_UNSOL_INT_P) != 0) sc->sc_stats_jbc_unsol_int++; val = FIRE_CTRL_READ_8(sc, FIRE_DMCINT_IDC_ERR_LOG); device_printf(dev, "DMCINT IDC error log %#llx\n", (unsigned long long)val); } if ((intstat & (FIRE_JBC_ERR_INT_MB_PER_P | FIRE_JBC_ERR_INT_MB_PEW_P)) != 0) { fatal = 1; val = FIRE_CTRL_READ_8(sc, FIRE_MERGE_TRANS_ERR_LOG); device_printf(dev, "merge transaction error log %#llx\n", (unsigned long long)val); } if ((intstat & FIRE_JBC_ERR_INT_IJP_P) != 0) { fatal = 1; val = FIRE_CTRL_READ_8(sc, FIRE_JBCINT_OTRANS_ERR_LOG); device_printf(dev, "JBCINT out transaction error log " "%#llx\n", (unsigned long long)val); val = FIRE_CTRL_READ_8(sc, FIRE_JBCINT_OTRANS_ERR_LOG2); device_printf(dev, "JBCINT out transaction error log 2 " "%#llx\n", (unsigned long long)val); } if ((intstat & (FIRE_JBC_ERR_INT_UE_ASYN_P | FIRE_JBC_ERR_INT_CE_ASYN_P | FIRE_JBC_ERR_INT_JTE_P | FIRE_JBC_ERR_INT_JBE_P | FIRE_JBC_ERR_INT_JUE_P | FIRE_JBC_ERR_INT_ICISE_P | FIRE_JBC_ERR_INT_WR_DPE_P | FIRE_JBC_ERR_INT_RD_DPE_P | FIRE_JBC_ERR_INT_ILL_BMW_P | FIRE_JBC_ERR_INT_ILL_BMR_P | FIRE_JBC_ERR_INT_BJC_P)) != 0) { if ((intstat & (FIRE_JBC_ERR_INT_UE_ASYN_P | FIRE_JBC_ERR_INT_JTE_P | FIRE_JBC_ERR_INT_JBE_P | FIRE_JBC_ERR_INT_JUE_P | FIRE_JBC_ERR_INT_ICISE_P | FIRE_JBC_ERR_INT_WR_DPE_P | FIRE_JBC_ERR_INT_RD_DPE_P | FIRE_JBC_ERR_INT_ILL_BMW_P | FIRE_JBC_ERR_INT_ILL_BMR_P | FIRE_JBC_ERR_INT_BJC_P)) != 0) fatal = 1; else sc->sc_stats_jbc_ce_async++; val = FIRE_CTRL_READ_8(sc, FIRE_JBCINT_ITRANS_ERR_LOG); device_printf(dev, "JBCINT in transaction error log %#llx\n", (unsigned long long)val); val = FIRE_CTRL_READ_8(sc, FIRE_JBCINT_ITRANS_ERR_LOG2); device_printf(dev, "JBCINT in transaction error log 2 " "%#llx\n", (unsigned long long)val); } if ((intstat & (FIRE_JBC_ERR_INT_PIO_UNMAP_RD_P | FIRE_JBC_ERR_INT_ILL_ACC_RD_P | FIRE_JBC_ERR_INT_PIO_UNMAP_P | FIRE_JBC_ERR_INT_PIO_DPE_P | FIRE_JBC_ERR_INT_PIO_CPE_P | FIRE_JBC_ERR_INT_ILL_ACC_P)) != 0) { fatal = 1; val = FIRE_CTRL_READ_8(sc, FIRE_JBC_CSR_ERR_LOG); device_printf(dev, "DMCINT ODCD error log %#llx\n", (unsigned long long)val); } if ((intstat & (FIRE_JBC_ERR_INT_MB_PEA_P | FIRE_JBC_ERR_INT_CPE_P | FIRE_JBC_ERR_INT_APE_P | FIRE_JBC_ERR_INT_PIO_CPE_P | FIRE_JBC_ERR_INT_JTCEEW_P | FIRE_JBC_ERR_INT_JTCEEI_P | FIRE_JBC_ERR_INT_JTCEER_P)) != 0) { fatal = 1; val = FIRE_CTRL_READ_8(sc, FIRE_FATAL_ERR_LOG); device_printf(dev, "fatal error log %#llx\n", (unsigned long long)val); val = FIRE_CTRL_READ_8(sc, FIRE_FATAL_ERR_LOG2); device_printf(dev, "fatal error log 2 " "%#llx\n", (unsigned long long)val); } if (fatal != 0) { mtx_unlock_spin(&sc->sc_pcib_mtx); panic("%s: fatal JBC core block error", device_get_nameunit(sc->sc_dev)); } else { FIRE_CTRL_SET(sc, FO_XBC_ERR_STAT_CLR, ~0ULL); mtx_unlock_spin(&sc->sc_pcib_mtx); } } else { mtx_unlock_spin(&sc->sc_pcib_mtx); panic("%s: unknown JCB core block error status %#llx", device_get_nameunit(sc->sc_dev), (unsigned long long)errstat); } } return (FILTER_HANDLED); } static int fire_pcie(void *arg) { struct fire_msiqarg *fmqa; struct fire_softc *sc; struct fo_msiq_record *qrec; device_t dev; uint64_t word0; u_int head, msg, msiq; fmqa = arg; sc = fmqa->fmqa_fica.fica_sc; dev = sc->sc_dev; msiq = fmqa->fmqa_msiq; mtx_lock_spin(&fmqa->fmqa_mtx); head = (FIRE_PCI_READ_8(sc, fmqa->fmqa_head) & FO_PCI_EQ_HD_MASK) >> FO_PCI_EQ_HD_SHFT; qrec = &fmqa->fmqa_base[head]; word0 = qrec->fomqr_word0; for (;;) { KASSERT((word0 & FO_MQR_WORD0_FMT_TYPE_MSG) != 0, ("%s: received non-PCIe message in event queue %d " "(word0 %#llx)", device_get_nameunit(dev), msiq, (unsigned long long)word0)); msg = (word0 & FO_MQR_WORD0_DATA0_MASK) >> FO_MQR_WORD0_DATA0_SHFT; #define PCIE_MSG_CODE_ERR_COR 0x30 #define PCIE_MSG_CODE_ERR_NONFATAL 0x31 #define PCIE_MSG_CODE_ERR_FATAL 0x33 if (msg == PCIE_MSG_CODE_ERR_COR) device_printf(dev, "correctable PCIe error\n"); else if (msg == PCIE_MSG_CODE_ERR_NONFATAL || msg == PCIE_MSG_CODE_ERR_FATAL) panic("%s: %sfatal PCIe error", device_get_nameunit(dev), msg == PCIE_MSG_CODE_ERR_NONFATAL ? "non-" : ""); else panic("%s: received unknown PCIe message %#x", device_get_nameunit(dev), msg); qrec->fomqr_word0 &= ~FO_MQR_WORD0_FMT_TYPE_MASK; head = (head + 1) % sc->sc_msiq_size; qrec = &fmqa->fmqa_base[head]; word0 = qrec->fomqr_word0; if (__predict_true((word0 & FO_MQR_WORD0_FMT_TYPE_MASK) == 0)) break; } FIRE_PCI_WRITE_8(sc, fmqa->fmqa_head, (head & FO_PCI_EQ_HD_MASK) << FO_PCI_EQ_HD_SHFT); if ((FIRE_PCI_READ_8(sc, fmqa->fmqa_tail) & FO_PCI_EQ_TL_OVERR) != 0) { device_printf(dev, "event queue %d overflow\n", msiq); msiq <<= 3; FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + msiq, FIRE_PCI_READ_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + msiq) | FO_PCI_EQ_CTRL_CLR_COVERR); } mtx_unlock_spin(&fmqa->fmqa_mtx); return (FILTER_HANDLED); } static int fire_maxslots(device_t dev) { return (1); } static uint32_t fire_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint32_t r, wrd; - int i; - uint16_t shrt; - uint8_t byte; - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return (-1); - - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - - if (i) { -#ifdef FIRE_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, width)); } static void fire_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return; - - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, slot, + func, reg), bus, slot, func, reg, val, width); } static int fire_route_interrupt(device_t bridge, device_t dev, int pin) { - struct fire_softc *sc; - struct ofw_pci_register reg; - ofw_pci_intr_t pintr, mintr; + ofw_pci_intr_t mintr; - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL) != 0) - return (mintr); - - device_printf(bridge, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (!PCI_INTERRUPT_VALID(mintr)) + device_printf(bridge, + "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (mintr); } -static int -fire_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct fire_softc *sc; - - sc = device_get_softc(dev); - switch (which) { - case PCIB_IVAR_DOMAIN: - *result = device_get_unit(dev); - return (0); - case PCIB_IVAR_BUS: - *result = sc->sc_pci_secbus; - return (0); - } - return (ENOENT); -} - static void fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map, bus_dmasync_op_t op) { - static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); - register_t reg, s; if ((map->dm_flags & DMF_LOADED) == 0) return; - if ((op & BUS_DMASYNC_POSTREAD) != 0) { - s = intr_disable(); - reg = rd(fprs); - wr(fprs, reg | FPRS_FEF, 0); - __asm __volatile("stda %%f0, [%0] %1" - : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); + if ((op & BUS_DMASYNC_POSTREAD) != 0) + ofw_pci_dmamap_sync_stst_order_common(); + else if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); - wr(fprs, reg, 0); - intr_restore(s); - } else if ((op & BUS_DMASYNC_PREWRITE) != 0) - membar(Sync); } static void fire_intr_enable(void *arg) { struct intr_vector *iv; struct fire_icarg *fica; struct fire_softc *sc; struct pcpu *pc; uint64_t mr; u_int ctrl, i; iv = arg; fica = iv->iv_icarg; sc = fica->fica_sc; mr = FO_PCI_IMAP_V; if (sc->sc_mode == FIRE_MODE_OBERON) mr |= (iv->iv_mid << OBERON_PCI_IMAP_T_DESTID_SHFT) & OBERON_PCI_IMAP_T_DESTID_MASK; else mr |= (iv->iv_mid << FIRE_PCI_IMAP_T_JPID_SHFT) & FIRE_PCI_IMAP_T_JPID_MASK; /* * Given that all mondos for the same target are required to use the * same interrupt controller we just use the CPU ID for indexing the * latter. */ ctrl = 0; for (i = 0; i < mp_ncpus; ++i) { pc = pcpu_find(i); if (pc == NULL || iv->iv_mid != pc->pc_mid) continue; ctrl = pc->pc_cpuid % 4; break; } mr |= (1ULL << ctrl) << FO_PCI_IMAP_INT_CTRL_NUM_SHFT & FO_PCI_IMAP_INT_CTRL_NUM_MASK; FIRE_PCI_WRITE_8(sc, fica->fica_map, mr); } static void fire_intr_disable(void *arg) { struct intr_vector *iv; struct fire_icarg *fica; struct fire_softc *sc; iv = arg; fica = iv->iv_icarg; sc = fica->fica_sc; FIRE_PCI_WRITE_8(sc, fica->fica_map, FIRE_PCI_READ_8(sc, fica->fica_map) & ~FO_PCI_IMAP_V); } static void fire_intr_assign(void *arg) { struct intr_vector *iv; struct fire_icarg *fica; struct fire_softc *sc; uint64_t mr; iv = arg; fica = iv->iv_icarg; sc = fica->fica_sc; mr = FIRE_PCI_READ_8(sc, fica->fica_map); if ((mr & FO_PCI_IMAP_V) != 0) { FIRE_PCI_WRITE_8(sc, fica->fica_map, mr & ~FO_PCI_IMAP_V); FIRE_PCI_BARRIER(sc, fica->fica_map, 8, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } while (FIRE_PCI_READ_8(sc, fica->fica_clr) != INTCLR_IDLE) ; if ((mr & FO_PCI_IMAP_V) != 0) fire_intr_enable(arg); } static void fire_intr_clear(void *arg) { struct intr_vector *iv; struct fire_icarg *fica; iv = arg; fica = iv->iv_icarg; FIRE_PCI_WRITE_8(fica->fica_sc, fica->fica_clr, INTCLR_IDLE); } /* * Given that the event queue implementation matches our current MD and MI * interrupt frameworks like square pegs fit into round holes we are generous * and use one event queue per MSI for now, which limits us to 35 MSIs/MSI-Xs * per Host-PCIe-bridge (we use one event queue for the PCIe error messages). * This seems tolerable as long as most devices just use one MSI/MSI-X anyway. * Adding knowledge about MSIs/MSI-Xs to the MD interrupt code should allow us * to decouple the 1:1 mapping at the cost of no longer being able to bind * MSIs/MSI-Xs to specific CPUs as we currently have no reliable way to * quiesce a device while we move its MSIs/MSI-Xs to another event queue. */ static int fire_alloc_msi(device_t dev, device_t child, int count, int maxcount __unused, int *irqs) { struct fire_softc *sc; u_int i, j, msiqrun; if (powerof2(count) == 0 || count > 32) return (EINVAL); sc = device_get_softc(dev); mtx_lock(&sc->sc_msi_mtx); msiqrun = 0; for (i = 0; i < sc->sc_msiq_count; i++) { for (j = i; j < i + count; j++) { if (isclr(sc->sc_msiq_bitmap, j) == 0) break; } if (j == i + count) { msiqrun = i; break; } } if (i == sc->sc_msiq_count) { mtx_unlock(&sc->sc_msi_mtx); return (ENXIO); } for (i = 0; i + count < sc->sc_msi_count; i += count) { for (j = i; j < i + count; j++) if (isclr(sc->sc_msi_bitmap, j) == 0) break; if (j == i + count) { for (j = 0; j < count; j++) { setbit(sc->sc_msiq_bitmap, msiqrun + j); setbit(sc->sc_msi_bitmap, i + j); sc->sc_msi_msiq_table[i + j] = msiqrun + j; irqs[j] = sc->sc_msi_first + i + j; } mtx_unlock(&sc->sc_msi_mtx); return (0); } } mtx_unlock(&sc->sc_msi_mtx); return (ENXIO); } static int fire_release_msi(device_t dev, device_t child, int count, int *irqs) { struct fire_softc *sc; u_int i; sc = device_get_softc(dev); mtx_lock(&sc->sc_msi_mtx); for (i = 0; i < count; i++) { clrbit(sc->sc_msiq_bitmap, sc->sc_msi_msiq_table[irqs[i] - sc->sc_msi_first]); clrbit(sc->sc_msi_bitmap, irqs[i] - sc->sc_msi_first); } mtx_unlock(&sc->sc_msi_mtx); return (0); } static int fire_alloc_msix(device_t dev, device_t child, int *irq) { struct fire_softc *sc; int i, msiq; sc = device_get_softc(dev); if ((sc->sc_flags & FIRE_MSIX) == 0) return (ENXIO); mtx_lock(&sc->sc_msi_mtx); msiq = 0; for (i = 0; i < sc->sc_msiq_count; i++) { if (isclr(sc->sc_msiq_bitmap, i) != 0) { msiq = i; break; } } if (i == sc->sc_msiq_count) { mtx_unlock(&sc->sc_msi_mtx); return (ENXIO); } for (i = sc->sc_msi_count - 1; i >= 0; i--) { if (isclr(sc->sc_msi_bitmap, i) != 0) { setbit(sc->sc_msiq_bitmap, msiq); setbit(sc->sc_msi_bitmap, i); sc->sc_msi_msiq_table[i] = msiq; *irq = sc->sc_msi_first + i; mtx_unlock(&sc->sc_msi_mtx); return (0); } } mtx_unlock(&sc->sc_msi_mtx); return (ENXIO); } static int fire_release_msix(device_t dev, device_t child, int irq) { struct fire_softc *sc; sc = device_get_softc(dev); if ((sc->sc_flags & FIRE_MSIX) == 0) return (ENXIO); mtx_lock(&sc->sc_msi_mtx); clrbit(sc->sc_msiq_bitmap, sc->sc_msi_msiq_table[irq - sc->sc_msi_first]); clrbit(sc->sc_msi_bitmap, irq - sc->sc_msi_first); mtx_unlock(&sc->sc_msi_mtx); return (0); } static int fire_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, uint32_t *data) { struct fire_softc *sc; struct pci_devinfo *dinfo; sc = device_get_softc(dev); dinfo = device_get_ivars(child); if (dinfo->cfg.msi.msi_alloc > 0) { if ((irq & ~sc->sc_msi_data_mask) != 0) { device_printf(dev, "invalid MSI 0x%x\n", irq); return (EINVAL); } } else { if ((sc->sc_flags & FIRE_MSIX) == 0) return (ENXIO); if (fls(irq) > sc->sc_msix_data_width) { device_printf(dev, "invalid MSI-X 0x%x\n", irq); return (EINVAL); } } if (dinfo->cfg.msi.msi_alloc > 0 && (dinfo->cfg.msi.msi_ctrl & PCIM_MSICTRL_64BIT) == 0) *addr = sc->sc_msi_addr32; else *addr = sc->sc_msi_addr64; *data = irq; return (0); } static void fire_msiq_handler(void *cookie) { struct intr_vector *iv; struct fire_msiqarg *fmqa; iv = cookie; fmqa = iv->iv_icarg; /* * Note that since fire_intr_clear() will clear the event queue * interrupt after the handler associated with the MSI [sic] has * been executed we have to protect the access to the event queue as * otherwise nested event queue interrupts cause corruption of the * event queue on MP machines. Obviously especially when abandoning * the 1:1 mapping it would be better to not clear the event queue * interrupt after each handler invocation but only once when the * outstanding MSIs have been processed but unfortunately that * doesn't work well and leads to interrupt storms with controllers/ * drivers which don't mask interrupts while the handler is executed. * Maybe delaying clearing the MSI until after the handler has been * executed could be used to work around this but that's not the * intended usage and might in turn cause lost MSIs. */ mtx_lock_spin(&fmqa->fmqa_mtx); fire_msiq_common(iv, fmqa); mtx_unlock_spin(&fmqa->fmqa_mtx); } static void fire_msiq_filter(void *cookie) { struct intr_vector *iv; struct fire_msiqarg *fmqa; iv = cookie; fmqa = iv->iv_icarg; /* * For filters we don't use fire_intr_clear() since it would clear * the event queue interrupt while we're still processing the event * queue as filters and associated post-filter handler are executed * directly, which in turn would lead to lost MSIs. So we clear the * event queue interrupt only once after processing the event queue. * Given that this still guarantees the filters to not be executed * concurrently and no other CPU can clear the event queue interrupt * while the event queue is still processed, we don't even need to * interlock the access to the event queue in this case. */ critical_enter(); fire_msiq_common(iv, fmqa); FIRE_PCI_WRITE_8(fmqa->fmqa_fica.fica_sc, fmqa->fmqa_fica.fica_clr, INTCLR_IDLE); critical_exit(); } static inline void fire_msiq_common(struct intr_vector *iv, struct fire_msiqarg *fmqa) { struct fire_softc *sc; struct fo_msiq_record *qrec; device_t dev; uint64_t word0; u_int head, msi, msiq; sc = fmqa->fmqa_fica.fica_sc; dev = sc->sc_dev; msiq = fmqa->fmqa_msiq; head = (FIRE_PCI_READ_8(sc, fmqa->fmqa_head) & FO_PCI_EQ_HD_MASK) >> FO_PCI_EQ_HD_SHFT; qrec = &fmqa->fmqa_base[head]; word0 = qrec->fomqr_word0; for (;;) { if (__predict_false((word0 & FO_MQR_WORD0_FMT_TYPE_MASK) == 0)) break; KASSERT((word0 & FO_MQR_WORD0_FMT_TYPE_MSI64) != 0 || (word0 & FO_MQR_WORD0_FMT_TYPE_MSI32) != 0, ("%s: received non-MSI/MSI-X message in event queue %d " "(word0 %#llx)", device_get_nameunit(dev), msiq, (unsigned long long)word0)); msi = (word0 & FO_MQR_WORD0_DATA0_MASK) >> FO_MQR_WORD0_DATA0_SHFT; /* * Sanity check the MSI/MSI-X as long as we use a 1:1 mapping. */ KASSERT(msi == fmqa->fmqa_msi, ("%s: received non-matching MSI/MSI-X in event queue %d " "(%d versus %d)", device_get_nameunit(dev), msiq, msi, fmqa->fmqa_msi)); FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_CLR_BASE + (msi << 3), FO_PCI_MSI_CLR_EQWR_N); if (__predict_false(intr_event_handle(iv->iv_event, NULL) != 0)) printf("stray MSI/MSI-X in event queue %d\n", msiq); qrec->fomqr_word0 &= ~FO_MQR_WORD0_FMT_TYPE_MASK; head = (head + 1) % sc->sc_msiq_size; qrec = &fmqa->fmqa_base[head]; word0 = qrec->fomqr_word0; } FIRE_PCI_WRITE_8(sc, fmqa->fmqa_head, (head & FO_PCI_EQ_HD_MASK) << FO_PCI_EQ_HD_SHFT); if (__predict_false((FIRE_PCI_READ_8(sc, fmqa->fmqa_tail) & FO_PCI_EQ_TL_OVERR) != 0)) { device_printf(dev, "event queue %d overflow\n", msiq); msiq <<= 3; FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + msiq, FIRE_PCI_READ_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + msiq) | FO_PCI_EQ_CTRL_CLR_COVERR); } } static int fire_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { struct fire_softc *sc; struct fire_msiqarg *fmqa; u_long vec; int error; u_int msi, msiq; sc = device_get_softc(dev); /* * XXX this assumes that a device only has one INTx, while in fact * Cassini+ and Saturn can use all four the firmware has assigned * to them, but so does pci(4). */ if (rman_get_rid(ires) != 0) { msi = rman_get_start(ires); msiq = sc->sc_msi_msiq_table[msi - sc->sc_msi_first]; vec = INTMAP_VEC(sc->sc_ign, sc->sc_msiq_ino_first + msiq); msiq += sc->sc_msiq_first; if (intr_vectors[vec].iv_ic != &fire_ic) { device_printf(dev, "invalid interrupt controller for vector 0x%lx\n", vec); return (EINVAL); } /* * The MD interrupt code needs the vector rather than the MSI. */ rman_set_start(ires, vec); rman_set_end(ires, vec); error = bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep); rman_set_start(ires, msi); rman_set_end(ires, msi); if (error != 0) return (error); fmqa = intr_vectors[vec].iv_icarg; /* * XXX inject our event queue handler. */ if (filt != NULL) { intr_vectors[vec].iv_func = fire_msiq_filter; intr_vectors[vec].iv_ic = &fire_msiqc_filter; /* * Ensure the event queue interrupt is cleared, it * might have triggered before. Given we supply NULL * as ic_clear, inthand_add() won't do this for us. */ FIRE_PCI_WRITE_8(sc, fmqa->fmqa_fica.fica_clr, INTCLR_IDLE); } else intr_vectors[vec].iv_func = fire_msiq_handler; /* Record the MSI/MSI-X as long as we we use a 1:1 mapping. */ fmqa->fmqa_msi = msi; FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_SET_BASE + (msiq << 3), FO_PCI_EQ_CTRL_SET_EN); msi <<= 3; FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_MAP_BASE + msi, (FIRE_PCI_READ_8(sc, FO_PCI_MSI_MAP_BASE + msi) & ~FO_PCI_MSI_MAP_EQNUM_MASK) | ((msiq << FO_PCI_MSI_MAP_EQNUM_SHFT) & FO_PCI_MSI_MAP_EQNUM_MASK)); FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_CLR_BASE + msi, FO_PCI_MSI_CLR_EQWR_N); FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_MAP_BASE + msi, FIRE_PCI_READ_8(sc, FO_PCI_MSI_MAP_BASE + msi) | FO_PCI_MSI_MAP_V); return (error); } /* * Make sure the vector is fully specified and we registered * our interrupt controller for it. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } if (intr_vectors[vec].iv_ic != &fire_ic) { device_printf(dev, "invalid interrupt controller for vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } static int fire_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct fire_softc *sc; u_long vec; int error; u_int msi, msiq; sc = device_get_softc(dev); if (rman_get_rid(ires) != 0) { msi = rman_get_start(ires); msiq = sc->sc_msi_msiq_table[msi - sc->sc_msi_first]; vec = INTMAP_VEC(sc->sc_ign, msiq + sc->sc_msiq_ino_first); msiq += sc->sc_msiq_first; msi <<= 3; FIRE_PCI_WRITE_8(sc, FO_PCI_MSI_MAP_BASE + msi, FIRE_PCI_READ_8(sc, FO_PCI_MSI_MAP_BASE + msi) & ~FO_PCI_MSI_MAP_V); msiq <<= 3; FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_CTRL_CLR_BASE + msiq, FO_PCI_EQ_CTRL_CLR_COVERR | FO_PCI_EQ_CTRL_CLR_E2I | FO_PCI_EQ_CTRL_CLR_DIS); FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_TL_BASE + msiq, (0 << FO_PCI_EQ_TL_SHFT) & FO_PCI_EQ_TL_MASK); FIRE_PCI_WRITE_8(sc, FO_PCI_EQ_HD_BASE + msiq, (0 << FO_PCI_EQ_HD_SHFT) & FO_PCI_EQ_HD_MASK); intr_vectors[vec].iv_ic = &fire_ic; /* * The MD interrupt code needs the vector rather than the MSI. */ rman_set_start(ires, vec); rman_set_end(ires, vec); error = bus_generic_teardown_intr(dev, child, ires, cookie); msi >>= 3; rman_set_start(ires, msi); rman_set_end(ires, msi); return (error); } return (bus_generic_teardown_intr(dev, child, ires, cookie)); } static struct resource * fire_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct fire_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); - if (*rid == 0) - start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); + if (type == SYS_RES_IRQ && *rid == 0) { + sc = device_get_softc(bus); + start = end = INTMAP_VEC(sc->sc_ign, end); } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -fire_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct fire_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -fire_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct fire_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); - } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -fire_get_dma_tag(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -fire_get_node(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static u_int fire_get_timecount(struct timecounter *tc) { struct fire_softc *sc; sc = tc->tc_priv; return (FIRE_CTRL_READ_8(sc, FO_XBC_PRF_CNT0) & TC_COUNTER_MAX_MASK); } Index: head/sys/sparc64/pci/firereg.h =================================================================== --- head/sys/sparc64/pci/firereg.h (revision 287725) +++ head/sys/sparc64/pci/firereg.h (revision 287726) @@ -1,1011 +1,1010 @@ /*- * Copyright (c) 2009 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SPARC64_PCI_FIREREG_H_ #define _SPARC64_PCI_FIREREG_H_ #define FIRE_NINTR 3 /* 2 OFW + 1 MSIq */ -#define FIRE_NRANGE 4 #define FIRE_NREG 2 #define FIRE_PCI 0 #define FIRE_CTRL 1 /* PCI configuration and status registers */ #define FO_PCI_INT_MAP_BASE 0x01000 #define FO_PCI_INT_CLR_BASE 0x01400 #define FO_PCI_EQ_BASE_ADDR 0x10000 #define FO_PCI_EQ_CTRL_SET_BASE 0x11000 #define FO_PCI_EQ_CTRL_CLR_BASE 0x11200 #define FO_PCI_EQ_TL_BASE 0x11600 #define FO_PCI_EQ_HD_BASE 0x11800 #define FO_PCI_MSI_MAP_BASE 0x20000 #define FO_PCI_MSI_CLR_BASE 0x28000 #define FO_PCI_ERR_COR 0x30000 #define FO_PCI_ERR_NONFATAL 0x30008 #define FO_PCI_ERR_FATAL 0x30010 #define FO_PCI_PM_PME 0x30018 #define FO_PCI_PME_TO_ACK 0x30020 #define FO_PCI_IMU_INT_EN 0x31008 #define FO_PCI_IMU_INT_STAT 0x31010 #define FO_PCI_IMU_ERR_STAT_CLR 0x31018 #define FO_PCI_IMU_RDS_ERR_LOG 0x31028 #define FO_PCI_IMU_SCS_ERR_LOG 0x31030 #define FO_PCI_IMU_EQS_ERR_LOG 0x31038 #define FO_PCI_DMC_CORE_BLOCK_INT_EN 0x31800 #define FO_PCI_DMC_CORE_BLOCK_ERR_STAT 0x31808 #define FO_PCI_MULTI_CORE_ERR_STAT 0x31810 #define FO_PCI_MSI_32_BIT_ADDR 0x34000 #define FO_PCI_MSI_64_BIT_ADDR 0x34008 #define FO_PCI_MMU 0x40000 #define FO_PCI_MMU_INT_EN 0x41008 #define FO_PCI_MMU_INT_STAT 0x41010 #define FO_PCI_MMU_ERR_STAT_CLR 0x41018 #define FO_PCI_MMU_TRANS_FAULT_ADDR 0x41028 #define FO_PCI_MMU_TRANS_FAULT_STAT 0x41030 #define FO_PCI_ILU_INT_EN 0x51008 #define FO_PCI_ILU_INT_STAT 0x51010 #define FO_PCI_ILU_ERR_STAT_CLR 0x51018 #define FO_PCI_DMC_DBG_SEL_PORTA 0x53000 #define FO_PCI_DMC_DBG_SEL_PORTB 0x53008 #define FO_PCI_PEC_CORE_BLOCK_INT_EN 0x51800 #define FO_PCI_PEC_CORE_BLOCK_INT_STAT 0x51808 #define FO_PCI_TLU_CTRL 0x80000 #define FO_PCI_TLU_OEVENT_INT_EN 0x81008 #define FO_PCI_TLU_OEVENT_INT_STAT 0x81010 #define FO_PCI_TLU_OEVENT_STAT_CLR 0x81018 #define FO_PCI_TLU_RX_OEVENT_HDR1_LOG 0x81028 #define FO_PCI_TLU_RX_OEVENT_HDR2_LOG 0x81030 #define FO_PCI_TLU_TX_OEVENT_HDR1_LOG 0x81038 #define FO_PCI_TLU_TX_OEVENT_HDR2_LOG 0x81040 #define FO_PCI_TLU_DEV_CTRL 0x90008 #define FO_PCI_TLU_LNK_CTRL 0x90020 #define FO_PCI_TLU_LNK_STAT 0x90028 #define FO_PCI_TLU_UERR_INT_EN 0x91008 #define FO_PCI_TLU_UERR_INT_STAT 0x91010 #define FO_PCI_TLU_UERR_STAT_CLR 0x91018 #define FO_PCI_TLU_RX_UERR_HDR1_LOG 0x91028 #define FO_PCI_TLU_RX_UERR_HDR2_LOG 0x91030 #define FO_PCI_TLU_TX_UERR_HDR1_LOG 0x91038 #define FO_PCI_TLU_TX_UERR_HDR2_LOG 0x91040 #define FO_PCI_TLU_CERR_INT_EN 0xa1008 #define FO_PCI_TLU_CERR_INT_STAT 0xa1010 #define FO_PCI_TLU_CERR_STAT_CLR 0xa1018 #define FO_PCI_LPU_RST 0xe2008 #define FO_PCI_LPU_INT_STAT 0xe2040 #define FO_PCI_LPU_INT_MASK 0xe0248 #define FO_PCI_LPU_LNK_LYR_CFG 0xe2200 #define FO_PCI_LPU_LNK_LYR_INT_STAT 0xe2210 #define FO_PCI_LPU_FLW_CTRL_UPDT_CTRL 0xe2240 #define FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS 0xe2400 #define FO_PCI_LPU_TXLNK_RPLY_TMR_THRS 0xe2410 #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR 0xe2430 #define FO_PCI_LPU_PHY_LYR_INT_STAT 0xe2610 #define FO_PCI_LPU_LTSSM_CFG2 0xe2788 #define FO_PCI_LPU_LTSSM_CFG3 0xe2790 #define FO_PCI_LPU_LTSSM_CFG4 0xe2798 #define FO_PCI_LPU_LTSSM_CFG5 0xe27a0 /* PCI interrupt mapping registers */ #define FO_PCI_IMAP_MDO_MODE 0x8000000000000000ULL #define FO_PCI_IMAP_V 0x0000000080000000ULL #define FIRE_PCI_IMAP_T_JPID_MASK 0x000000007c000000ULL #define FIRE_PCI_IMAP_T_JPID_SHFT 26 #define OBERON_PCI_IMAP_T_DESTID_MASK 0x000000007fe00000ULL #define OBERON_PCI_IMAP_T_DESTID_SHFT 21 #define FO_PCI_IMAP_INT_CTRL_NUM_MASK 0x00000000000003c0ULL #define FO_PCI_IMAP_INT_CTRL_NUM_SHFT 6 /* PCI interrupt clear registers - use INTCLR_* from */ /* PCI event queue base address register */ #define FO_PCI_EQ_BASE_ADDR_BYPASS 0xfffc000000000000ULL #define FO_PCI_EQ_BASE_ADDR_MASK 0xfffffffffff80000ULL #define FO_PCI_EQ_BASE_ADDR_SHFT 19 /* PCI event queue control set registers */ #define FO_PCI_EQ_CTRL_SET_ENOVERR 0x0200000000000000ULL #define FO_PCI_EQ_CTRL_SET_EN 0x0000100000000000ULL /* PCI event queue control clear registers */ #define FO_PCI_EQ_CTRL_CLR_COVERR 0x0200000000000000ULL #define FO_PCI_EQ_CTRL_CLR_E2I 0x0000800000000000ULL #define FO_PCI_EQ_CTRL_CLR_DIS 0x0000100000000000ULL /* PCI event queue tail registers */ #define FO_PCI_EQ_TL_OVERR 0x0200000000000000ULL #define FO_PCI_EQ_TL_MASK 0x000000000000007fULL #define FO_PCI_EQ_TL_SHFT 0 /* PCI event queue head registers */ #define FO_PCI_EQ_HD_MASK 0x000000000000007fULL #define FO_PCI_EQ_HD_SHFT 0 /* PCI MSI mapping registers */ #define FO_PCI_MSI_MAP_V 0x8000000000000000ULL #define FO_PCI_MSI_MAP_EQWR_N 0x4000000000000000ULL #define FO_PCI_MSI_MAP_EQNUM_MASK 0x000000000000003fULL #define FO_PCI_MSI_MAP_EQNUM_SHFT 0 /* PCI MSI clear registers */ #define FO_PCI_MSI_CLR_EQWR_N 0x4000000000000000ULL /* * PCI IMU interrupt enable, interrupt status and error status clear * registers */ #define FO_PCI_IMU_ERR_INT_SPARE_S_MASK 0x00007c0000000000ULL #define FO_PCI_IMU_ERR_INT_SPARE_S_SHFT 42 #define FO_PCI_IMU_ERR_INT_EQ_OVER_S 0x0000020000000000ULL #define FO_PCI_IMU_ERR_INT_EQ_NOT_EN_S 0x0000010000000000ULL #define FO_PCI_IMU_ERR_INT_MSI_MAL_ERR_S 0x0000008000000000ULL #define FO_PCI_IMU_ERR_INT_MSI_PAR_ERR_S 0x0000004000000000ULL #define FO_PCI_IMU_ERR_INT_PMEACK_MES_NOT_EN_S 0x0000002000000000ULL #define FO_PCI_IMU_ERR_INT_PMPME_MES_NOT_EN_S 0x0000001000000000ULL #define FO_PCI_IMU_ERR_INT_FATAL_MES_NOT_EN_S 0x0000000800000000ULL #define FO_PCI_IMU_ERR_INT_NFATAL_MES_NOT_EN_S 0x0000000400000000ULL #define FO_PCI_IMU_ERR_INT_COR_MES_NOT_EN_S 0x0000000200000000ULL #define FO_PCI_IMU_ERR_INT_MSI_NOT_EN_S 0x0000000100000000ULL #define FO_PCI_IMU_ERR_INT_SPARE_P_MASK 0x0000000000007c00ULL #define FO_PCI_IMU_ERR_INT_SPARE_P_SHFT 10 #define FO_PCI_IMU_ERR_INT_EQ_OVER_P 0x0000000000000200ULL #define FO_PCI_IMU_ERR_INT_EQ_NOT_EN_P 0x0000000000000100ULL #define FO_PCI_IMU_ERR_INT_MSI_MAL_ERR_P 0x0000000000000080ULL #define FO_PCI_IMU_ERR_INT_MSI_PAR_ERR_P 0x0000000000000040ULL #define FO_PCI_IMU_ERR_INT_PMEACK_MES_NOT_EN_P 0x0000000000000020ULL #define FO_PCI_IMU_ERR_INT_PMPME_MES_NOT_EN_P 0x0000000000000010ULL #define FO_PCI_IMU_ERR_INT_FATAL_MES_NOT_EN_P 0x0000000000000008ULL #define FO_PCI_IMU_ERR_INT_NFATAL_MES_NOT_EN_P 0x0000000000000004ULL #define FO_PCI_IMU_ERR_INT_COR_MES_NOT_EN_P 0x0000000000000002ULL #define FO_PCI_IMU_ERR_INT_MSI_NOT_EN_P 0x0000000000000001ULL /* PCI IMU RDS error log register */ #define FO_PCI_IMU_RDS_ERR_LOG_TYPE_MASK 0xfc00000000000000ULL #define FO_PCI_IMU_RDS_ERR_LOG_TYPE_SHFT 58 #define FO_PCI_IMU_RDS_ERR_LOG_LENGTH_MASK 0x03ff000000000000ULL #define FO_PCI_IMU_RDS_ERR_LOG_LENGTH_SHFT 48 #define FO_PCI_IMU_RDS_ERR_LOG_REQ_ID_MASK 0x0000ffff00000000ULL #define FO_PCI_IMU_RDS_ERR_LOG_REQ_ID_SHFT 32 #define FO_PCI_IMU_RDS_ERR_LOG_TLP_TAG_MASK 0x00000000ff000000ULL #define FO_PCI_IMU_RDS_ERR_LOG_TLP_TAG_SHFT 24 #define FO_PCI_IMU_RDS_ERR_LOG_BE_MCODE_MASK 0x0000000000ff0000ULL #define FO_PCI_IMU_RDS_ERR_LOG_BE_MCODE_SHFT 16 #define FO_PCI_IMU_RDS_ERR_LOG_MSI_DATA_MASK 0x000000000000ffffULL #define FO_PCI_IMU_RDS_ERR_LOG_MSI_DATA_SHFT 0 /* PCI IMU SCS error log register */ #define FO_PCI_IMU_SCS_ERR_LOG_TYPE_MASK 0xfc00000000000000ULL #define FO_PCI_IMU_SCS_ERR_LOG_TYPE_SHFT 58 #define FO_PCI_IMU_SCS_ERR_LOG_LENGTH_MASK 0x03ff000000000000ULL #define FO_PCI_IMU_SCS_ERR_LOG_LENGTH_SHFT 48 #define FO_PCI_IMU_SCS_ERR_LOG_REQ_ID_MASK 0x0000ffff00000000ULL #define FO_PCI_IMU_SCS_ERR_LOG_REQ_ID_SHFT 32 #define FO_PCI_IMU_SCS_ERR_LOG_TLP_TAG_MASK 0x00000000ff000000ULL #define FO_PCI_IMU_SCS_ERR_LOG_TLP_TAG_SHFT 24 #define FO_PCI_IMU_SCS_ERR_LOG_BE_MODE_MASK 0x0000000000ff0000ULL #define FO_PCI_IMU_SCS_ERR_LOG_BE_MCODE_SHFT 16 #define FO_PCI_IMU_SCS_ERR_LOG_EQ_NUM_MASK 0x000000000000003fULL #define FO_PCI_IMU_SCS_ERR_LOG_EQ_NUM_SHFT 0 /* PCI IMU EQS error log register */ #define FO_PCI_IMU_EQS_ERR_LOG_EQ_NUM_MASK 0x000000000000003fULL #define FO_PCI_IMU_EQS_ERROR_LOG_EQ_NUM_SHFT 0 /* * PCI ERR COR, ERR NONFATAL, ERR FATAL, PM PME and PME To ACK mapping * registers */ #define FO_PCI_ERR_PME_V 0x8000000000000000ULL #define FO_PCI_ERR_PME_EQNUM_MASK 0x000000000000003fULL #define FO_PCI_ERR_PME_EQNUM_SHFT 0 /* PCI DMC core and block interrupt enable register */ #define FO_PCI_DMC_CORE_BLOCK_INT_EN_DMC 0x8000000000000000ULL #define FO_PCI_DMC_CORE_BLOCK_INT_EN_MMU 0x0000000000000002ULL #define FO_PCI_DMC_CORE_BLOCK_INT_EN_IMU 0x0000000000000001ULL /* PCI DMC core and block error status register */ #define FO_PCI_DMC_CORE_BLOCK_ERR_STAT_MMU 0x0000000000000002ULL #define FO_PCI_DMC_CORE_BLOCK_ERR_STAT_IMU 0x0000000000000001ULL /* PCI multi core error status register */ #define FO_PCI_MULTI_CORE_ERR_STAT_PEC 0x0000000000000002ULL #define FO_PCI_MULTI_CORE_ERR_STAT_DMC 0x0000000000000001ULL /* PCI MSI 32-bit address register */ #define FO_PCI_MSI_32_BIT_ADDR_MASK 0x00000000ffff0000ULL #define FO_PCI_MSI_32_BIT_ADDR_SHFT 16 /* PCI MSI 64-bit address register */ #define FO_PCI_MSI_64_BIT_ADDR_MASK 0x0000ffffffff0000ULL #define FO_PCI_MSI_64_BIT_ADDR_SHFT 16 /* * PCI MMU interrupt enable, interrupt status and error status clear * registers */ #define FO_PCI_MMU_ERR_INT_S_MASK 0x0000ffff00000000ULL #define FO_PCI_MMU_ERR_INT_S_SHFT 32 #define FO_PCI_MMU_ERR_INT_TBW_DPE_S 0x0000800000000000ULL #define FO_PCI_MMU_ERR_INT_TBW_ERR_S 0x0000400000000000ULL #define FO_PCI_MMU_ERR_INT_TBW_UDE_S 0x0000200000000000ULL #define FO_PCI_MMU_ERR_INT_TBW_DME_S 0x0000100000000000ULL #define FO_PCI_MMU_ERR_INT_SPARE3_S 0x0000080000000000ULL #define FO_PCI_MMU_ERR_INT_SPARE2_S 0x0000040000000000ULL #define FO_PCI_MMU_ERR_INT_TTC_CAE_S 0x0000020000000000ULL #define FIRE_PCI_MMU_ERR_INT_TTC_DPE_S 0x0000010000000000ULL #define OBERON_PCI_MMU_ERR_INT_TTC_DUE_S 0x0000010000000000ULL #define FO_PCI_MMU_ERR_INT_TTE_PRT_S 0x0000008000000000ULL #define FO_PCI_MMU_ERR_INT_TTE_INV_S 0x0000004000000000ULL #define FO_PCI_MMU_ERR_INT_TRN_OOR_S 0x0000002000000000ULL #define FO_PCI_MMU_ERR_INT_TRN_ERR_S 0x0000001000000000ULL #define FO_PCI_MMU_ERR_INT_SPARE1_S 0x0000000800000000ULL #define FO_PCI_MMU_ERR_INT_SPARE0_S 0x0000000400000000ULL #define FO_PCI_MMU_ERR_INT_BYP_OOR_S 0x0000000200000000ULL #define FO_PCI_MMU_ERR_INT_BYP_ERR_S 0x0000000100000000ULL #define FO_PCI_MMU_ERR_INT_P_MASK 0x000000000000ffffULL #define FO_PCI_MMU_ERR_INT_P_SHFT 0 #define FO_PCI_MMU_ERR_INT_TBW_DPE_P 0x0000000000008000ULL #define FO_PCI_MMU_ERR_INT_TBW_ERR_P 0x0000000000004000ULL #define FO_PCI_MMU_ERR_INT_TBW_UDE_P 0x0000000000002000ULL #define FO_PCI_MMU_ERR_INT_TBW_DME_P 0x0000000000001000ULL #define FO_PCI_MMU_ERR_INT_SPARE3_P 0x0000000000000800ULL #define FO_PCI_MMU_ERR_INT_SPARE2_P 0x0000000000000400ULL #define FO_PCI_MMU_ERR_INT_TTC_CAE_P 0x0000000000000200ULL #define FIRE_PCI_MMU_ERR_INT_TTC_DPE_P 0x0000000000000100ULL #define OBERON_PCI_MMU_ERR_INT_TTC_DUE_P 0x0000000000000100ULL #define FO_PCI_MMU_ERR_INT_TTE_PRT_P 0x0000000000000080ULL #define FO_PCI_MMU_ERR_INT_TTE_INV_P 0x0000000000000040ULL #define FO_PCI_MMU_ERR_INT_TRN_OOR_P 0x0000000000000020ULL #define FO_PCI_MMU_ERR_INT_TRN_ERR_P 0x0000000000000010ULL #define FO_PCI_MMU_ERR_INT_SPARE1_P 0x0000000000000008ULL #define FO_PCI_MMU_ERR_INT_SPARE0_P 0x0000000000000004ULL #define FO_PCI_MMU_ERR_INT_BYP_OOR_P 0x0000000000000002ULL #define FO_PCI_MMU_ERR_INT_BYP_ERR_P 0x0000000000000001ULL /* PCI MMU translation fault address register */ #define FO_PCI_MMU_TRANS_FAULT_ADDR_VA_MASK 0xfffffffffffffffcULL #define FO_PCI_MMU_TRANS_FAULT_ADDR_VA_SHFT 2 /* PCI MMU translation fault status register */ #define FO_PCI_MMU_TRANS_FAULT_STAT_ENTRY_MASK 0x000001ff00000000ULL #define FO_PCI_MMU_TRANS_FAULT_STAT_ENTRY_SHFT 32 #define FO_PCI_MMU_TRANS_FAULT_STAT_TYPE_MASK 0x00000000007f0000ULL #define FO_PCI_MMU_TRANS_FAULT_STAT_TYPE_SHFT 16 #define FO_PCI_MMU_TRANS_FAULT_STAT_ID_MASK 0x000000000000ffffULL #define FO_PCI_MMU_TRANS_FAULT_STAT_ID_SHFT 0 /* * PCI ILU interrupt enable, interrupt status and error status clear * registers */ #define FO_PCI_ILU_ERR_INT_SPARE3_S 0x0000008000000000ULL #define FO_PCI_ILU_ERR_INT_SPARE2_S 0x0000004000000000ULL #define FO_PCI_ILU_ERR_INT_SPARE1_S 0x0000002000000000ULL #define FIRE_PCI_ILU_ERR_INT_IHB_PE_S 0x0000001000000000ULL #define OBERON_PCI_ILU_ERR_INT_IHB_UE_S 0x0000001000000000ULL #define FO_PCI_ILU_ERR_INT_SPARE3_P 0x0000000000000080ULL #define FO_PCI_ILU_ERR_INT_SPARE2_P 0x0000000000000040ULL #define FO_PCI_ILU_ERR_INT_SPARE1_P 0x0000000000000020ULL #define FIRE_PCI_ILU_ERR_INT_IHB_PE_P 0x0000000000000010ULL #define OBERON_PCI_ILU_ERR_INT_IHB_UE_P 0x0000000000000010ULL /* PCI DMC debug select registers for port a/b */ #define FO_PCI_DMC_DBG_SEL_PORT_BLCK_MASK 0x00000000000003c0ULL #define FO_PCI_DMC_DBG_SEL_PORT_BLCK_SHFT 6 #define FO_PCI_DMC_DBG_SEL_PORT_SUB_MASK 0x0000000000000038ULL #define FO_PCI_DMC_DBG_SEL_PORT_SUB_SHFT 3 #define FO_PCI_DMC_DBG_SEL_PORT_SUB_SGNL_MASK 0x0000000000000007ULL #define FO_PCI_DMC_DBG_SEL_PORT_SUB_SGNL_SHFT 0 /* PCI PEC core and block interrupt enable register */ #define FO_PCI_PEC_CORE_BLOCK_INT_EN_PEC 0x8000000000000000ULL #define FO_PCI_PEC_CORE_BLOCK_INT_EN_ILU 0x0000000000000008ULL #define FO_PCI_PEC_CORE_BLOCK_INT_EN_UERR 0x0000000000000004ULL #define FO_PCI_PEC_CORE_BLOCK_INT_EN_CERR 0x0000000000000002ULL #define FO_PCI_PEC_CORE_BLOCK_INT_EN_OEVENT 0x0000000000000001ULL /* PCI PEC core and block interrupt status register */ #define FO_PCI_PEC_CORE_BLOCK_INT_STAT_ILU 0x0000000000000008ULL #define FO_PCI_PEC_CORE_BLOCK_INT_STAT_UERR 0x0000000000000004ULL #define FO_PCI_PEC_CORE_BLOCK_INT_STAT_CERR 0x0000000000000002ULL #define FO_PCI_PEC_CORE_BLOCK_INT_STAT_OEVENT 0x0000000000000001ULL /* PCI TLU control register */ #define FO_PCI_TLU_CTRL_L0S_TIM_MASK 0x00000000ff000000ULL #define FO_PCI_TLU_CTRL_L0S_TIM_SHFT 24 #define FO_PCI_TLU_CTRL_NWPR_EN 0x0000000000100000ULL #define FO_PCI_TLU_CTRL_CTO_SEL_MASK 0x0000000000070000ULL #define FO_PCI_TLU_CTRL_CTO_SEL_SHFT 16 #define FO_PCI_TLU_CTRL_CFG_MASK 0x000000000000ffffULL #define FO_PCI_TLU_CTRL_CFG_SHFT 0 #define FO_PCI_TLU_CTRL_CFG_REMAIN_DETECT_QUIET 0x0000000000000100ULL #define FO_PCI_TLU_CTRL_CFG_PAD_LOOPBACK_EN 0x0000000000000080ULL #define FO_PCI_TLU_CTRL_CFG_EWRAP_LOOPBACK_EN 0x0000000000000040ULL #define FO_PCI_TLU_CTRL_CFG_DIGITAL_LOOPBACK_EN 0x0000000000000020ULL #define FO_PCI_TLU_CTRL_CFG_MPS_MASK 0x000000000000001cULL #define FO_PCI_TLU_CTRL_CFG_MPS_SHFT 2 #define FO_PCI_TLU_CTRL_CFG_COMMON_CLK_CFG 0x0000000000000002ULL #define FO_PCI_TLU_CTRL_CFG_PORT 0x0000000000000001ULL /* * PCI TLU other event interrupt enable, interrupt status and status clear * registers */ #define FO_PCI_TLU_OEVENT_S_MASK 0x00ffffff00000000ULL #define FO_PCI_TLU_OEVENT_S_SHFT 32 #define FO_PCI_TLU_OEVENT_SPARE_S 0x0080000000000000ULL #define FO_PCI_TLU_OEVENT_MFC_S 0x0040000000000000ULL #define FO_PCI_TLU_OEVENT_CTO_S 0x0020000000000000ULL #define FO_PCI_TLU_OEVENT_NFP_S 0x0010000000000000ULL #define FO_PCI_TLU_OEVENT_LWC_S 0x0008000000000000ULL #define FO_PCI_TLU_OEVENT_MRC_S 0x0004000000000000ULL #define FO_PCI_TLU_OEVENT_WUC_S 0x0002000000000000ULL #define FO_PCI_TLU_OEVENT_RUC_S 0x0001000000000000ULL #define FO_PCI_TLU_OEVENT_CRS_S 0x0000800000000000ULL #define FO_PCI_TLU_OEVENT_IIP_S 0x0000400000000000ULL #define FO_PCI_TLU_OEVENT_EDP_S 0x0000200000000000ULL #define FIRE_PCI_TLU_OEVENT_EHP_S 0x0000100000000000ULL #define OBERON_PCI_TLU_OEVENT_EHBUE_S 0x0000100000000000ULL #define OBERON_PCI_TLU_OEVENT_EDBUE_S 0x0000100000000000ULL #define FO_PCI_TLU_OEVENT_LIN_S 0x0000080000000000ULL #define FO_PCI_TLU_OEVENT_LRS_S 0x0000040000000000ULL #define FO_PCI_TLU_OEVENT_LDN_S 0x0000020000000000ULL #define FO_PCI_TLU_OEVENT_LUP_S 0x0000010000000000ULL #define FO_PCI_TLU_OEVENT_LPU_S_MASK 0x000000c000000000ULL #define FO_PCI_TLU_OEVENT_LPU_S_SHFT 38 #define OBERON_PCI_TLU_OEVENT_TLUEITMO_S 0x0000008000000000ULL #define FO_PCI_TLU_OEVENT_ERU_S 0x0000002000000000ULL #define FO_PCI_TLU_OEVENT_ERO_S 0x0000001000000000ULL #define FO_PCI_TLU_OEVENT_EMP_S 0x0000000800000000ULL #define FO_PCI_TLU_OEVENT_EPE_S 0x0000000400000000ULL #define FIRE_PCI_TLU_OEVENT_ERP_S 0x0000000200000000ULL #define OBERON_PCI_TLU_OEVENT_ERBU_S 0x0000000200000000ULL #define FIRE_PCI_TLU_OEVENT_EIP_S 0x0000000100000000ULL #define OBERON_PCI_TLU_OEVENT_EIUE_S 0x0000000100000000ULL #define FO_PCI_TLU_OEVENT_P_MASK 0x0000000000ffffffULL #define FO_PCI_TLU_OEVENT_P_SHFT 0 #define FO_PCI_TLU_OEVENT_SPARE_P 0x0000000000800000ULL #define FO_PCI_TLU_OEVENT_MFC_P 0x0000000000400000ULL #define FO_PCI_TLU_OEVENT_CTO_P 0x0000000000200000ULL #define FO_PCI_TLU_OEVENT_NFP_P 0x0000000000100000ULL #define FO_PCI_TLU_OEVENT_LWC_P 0x0000000000080000ULL #define FO_PCI_TLU_OEVENT_MRC_P 0x0000000000040000ULL #define FO_PCI_TLU_OEVENT_WUC_P 0x0000000000020000ULL #define FO_PCI_TLU_OEVENT_RUC_P 0x0000000000010000ULL #define FO_PCI_TLU_OEVENT_CRS_P 0x0000000000008000ULL #define FO_PCI_TLU_OEVENT_IIP_P 0x0000000000004000ULL #define FO_PCI_TLU_OEVENT_EDP_P 0x0000000000002000ULL #define FIRE_PCI_TLU_OEVENT_EHP_P 0x0000000000001000ULL #define OBERON_PCI_TLU_OEVENT_EHBUE_P 0x0000000000001000ULL #define OBERON_PCI_TLU_OEVENT_EDBUE_P 0x0000000000001000ULL #define FO_PCI_TLU_OEVENT_LIN_P 0x0000000000000800ULL #define FO_PCI_TLU_OEVENT_LRS_P 0x0000000000000400ULL #define FO_PCI_TLU_OEVENT_LDN_P 0x0000000000000200ULL #define FO_PCI_TLU_OEVENT_LUP_P 0x0000000000000100ULL #define FO_PCI_TLU_OEVENT_LPU_P_MASK 0x00000000000000c0ULL #define FO_PCI_TLU_OEVENT_LPU_P_SHFT 6 #define OBERON_PCI_TLU_OEVENT_TLUEITMO_P 0x0000000000000080ULL #define FO_PCI_TLU_OEVENT_ERU_P 0x0000000000000020ULL #define FO_PCI_TLU_OEVENT_ERO_P 0x0000000000000010ULL #define FO_PCI_TLU_OEVENT_EMP_P 0x0000000000000008ULL #define FO_PCI_TLU_OEVENT_EPE_P 0x0000000000000004ULL #define FIRE_PCI_TLU_OEVENT_ERP_P 0x0000000000000002ULL #define OBERON_PCI_TLU_OEVENT_ERBU_P 0x0000000000000002ULL #define FIRE_PCI_TLU_OEVENT_EIP_P 0x0000000000000001ULL #define OBERON_PCI_TLU_OEVENT_EIUE_P 0x0000000000000001ULL /* PCI receive/transmit DLU/TLU other event header 1/2 log registers */ #define FO_PCI_TLU_OEVENT_HDR_LOG_MASK 0xffffffffffffffffULL #define FO_PCI_TLU_OEVENT_HDR_LOG_SHFT 0 /* PCI TLU device control register */ #define FO_PCI_TLU_DEV_CTRL_MRRS_MASK 0x0000000000007000ULL #define FO_PCI_TLU_DEV_CTRL_MRRS_SHFT 12 #define FO_PCI_TLU_DEV_CTRL_MPS_MASK 0x00000000000000e0ULL #define FO_PCI_TLU_DEV_CTRL_MPS_SHFT 5 /* * PCI TLU uncorrectable error interrupt enable, interrupt status and * status clear registers */ #define FO_PCI_TLU_UERR_INT_S_MASK 0x001fffff00000000ULL #define FO_PCI_TLU_UERR_INT_S_SHFT 32 #define FO_PCI_TLU_UERR_INT_UR_S 0x0010000000000000ULL #define OBERON_PCI_TLU_UERR_INT_ECRC_S 0x0008000000000000ULL #define FO_PCI_TLU_UERR_INT_MFP_S 0x0004000000000000ULL #define FO_PCI_TLU_UERR_INT_ROF_S 0x0002000000000000ULL #define FO_PCI_TLU_UERR_INT_UC_S 0x0001000000000000ULL #define FO_PCI_TLU_UERR_INT_CA_S 0x0000800000000000ULL #define FO_PCI_TLU_UERR_INT_CTO_S 0x0000400000000000ULL #define FO_PCI_TLU_UERR_INT_FCP_S 0x0000200000000000ULL #define FIRE_PCI_TLU_UERR_INT_PP_S 0x0000100000000000ULL #define OBERON_PCI_TLU_UERR_INT_POIS_S 0x0000100000000000ULL #define FO_PCI_TLU_UERR_INT_DLP_S 0x0000001000000000ULL #define FO_PCI_TLU_UERR_INT_TE_S 0x0000000100000000ULL #define FO_PCI_TLU_UERR_INT_P_MASK 0x00000000001fffffULL #define FO_PCI_TLU_UERR_INT_P_SHFT 0 #define FO_PCI_TLU_UERR_INT_UR_P 0x0000000000100000ULL #define OBERON_PCI_TLU_UERR_INT_ECRC_P 0x0000000000080000ULL #define FO_PCI_TLU_UERR_INT_MFP_P 0x0000000000040000ULL #define FO_PCI_TLU_UERR_INT_ROF_P 0x0000000000020000ULL #define FO_PCI_TLU_UERR_INT_UC_P 0x0000000000010000ULL #define FO_PCI_TLU_UERR_INT_CA_P 0x0000000000008000ULL #define FO_PCI_TLU_UERR_INT_CTO_P 0x0000000000004000ULL #define FO_PCI_TLU_UERR_INT_FCP_P 0x0000000000002000ULL #define FIRE_PCI_TLU_UERR_INT_PP_P 0x0000000000001000ULL #define OBERON_PCI_TLU_UERR_INT_POIS_P 0x0000000000001000ULL #define FO_PCI_TLU_UERR_INT_DLP_P 0x0000000000000010ULL #define FO_PCI_TLU_UERR_INT_TE_P 0x0000000000000001ULL /* * PCI TLU correctable error interrupt enable, interrupt status and * status clear registers */ #define FO_PCI_TLU_CERR_INT_S_MASK 0x001fffff00000000ULL #define FO_PCI_TLU_CERR_INT_S_SHFT 32 #define FO_PCI_TLU_CERR_INT_RTO_S 0x0000100000000000ULL #define FO_PCI_TLU_CERR_INT_RNR_S 0x0000010000000000ULL #define FO_PCI_TLU_CERR_INT_BDP_S 0x0000008000000000ULL #define FO_PCI_TLU_CERR_INT_BTP_S 0x0000004000000000ULL #define FO_PCI_TLU_CERR_INT_RE_S 0x0000000100000000ULL #define FO_PCI_TLU_CERR_INT_P_MASK 0x00000000001fffffULL #define FO_PCI_TLU_CERR_INT_P_SHFT 0 #define FO_PCI_TLU_CERR_INT_RTO_P 0x0000000000001000ULL #define FO_PCI_TLU_CERR_INT_RNR_P 0x0000000000000100ULL #define FO_PCI_TLU_CERR_INT_BDP_P 0x0000000000000080ULL #define FO_PCI_TLU_CERR_INT_BTP_P 0x0000000000000040ULL #define FO_PCI_TLU_CERR_INT_RE_P 0x0000000000000001ULL /* PCI TLU reset register */ #define FO_PCI_LPU_RST_WE 0x0000000080000000ULL #define FO_PCI_LPU_RST_UNUSED_MASK 0x0000000000000e00ULL #define FO_PCI_LPU_RST_UNUSED_SHFT 9 #define FO_PCI_LPU_RST_ERR 0x0000000000000100ULL #define FO_PCI_LPU_RST_TXLINK 0x0000000000000080ULL #define FO_PCI_LPU_RST_RXLINK 0x0000000000000040ULL #define FO_PCI_LPU_RST_SMLINK 0x0000000000000020ULL #define FO_PCI_LPU_RST_LTSSM 0x0000000000000010ULL #define FO_PCI_LPU_RST_TXPHY 0x0000000000000008ULL #define FO_PCI_LPU_RST_RXPHY 0x0000000000000004ULL #define FO_PCI_LPU_RST_TXPCS 0x0000000000000002ULL #define FO_PCI_LPU_RST_RXPCS 0x0000000000000001ULL /* PCI TLU link control register */ #define FO_PCI_TLU_LNK_CTRL_EXTSYNC 0x0000000000000080ULL #define FO_PCI_TLU_LNK_CTRL_CLK 0x0000000000000040ULL #define FO_PCI_TLU_LNK_CTRL_RETRAIN 0x0000000000000020ULL #define FO_PCI_TLU_LNK_CTRL_DIS 0x0000000000000010ULL #define FO_PCI_TLU_LNK_CTRL_RCB 0x0000000000000008ULL #define FO_PCI_TLU_LNK_CTRL_ASPM_L0S_L1S 0x0000000000000003ULL #define FO_PCI_TLU_LNK_CTRL_ASPM_L1S 0x0000000000000002ULL #define FO_PCI_TLU_LNK_CTRL_ASPM_L0S 0x0000000000000001ULL #define FO_PCI_TLU_LNK_CTRL_ASPM_DIS 0x0000000000000000ULL /* PCI TLU link status register */ #define FO_PCI_TLU_LNK_STAT_CLK 0x0000000000001000ULL #define FO_PCI_TLU_LNK_STAT_TRAIN 0x0000000000000800ULL #define FO_PCI_TLU_LNK_STAT_ERR 0x0000000000000400ULL #define FO_PCI_TLU_LNK_STAT_WDTH_MASK 0x00000000000003f0ULL #define FO_PCI_TLU_LNK_STAT_WDTH_SHFT 4 #define FO_PCI_TLU_LNK_STAT_SPEED_MASK 0x000000000000000fULL #define FO_PCI_TLU_LNK_STAT_SPEED_SHFT 0 /* * PCI receive/transmit DLU/TLU uncorrectable error header 1/2 log * registers */ #define FO_PCI_TLU_UERR_HDR_LOG_MASK 0xffffffffffffffffULL #define FO_PCI_TLU_UERR_HDR_LOG_SHFT 0 /* PCI DLU/LPU interrupt status and mask registers */ #define FO_PCI_LPU_INT_INT 0x0000000080000000ULL #define FIRE_PCI_LPU_INT_PRF_CNT2_OFLW 0x0000000000000080ULL #define FIRE_PCI_LPU_INT_PRF_CNT1_OFLW 0x0000000000000040ULL #define FO_PCI_LPU_INT_LNK_LYR 0x0000000000000020ULL #define FO_PCI_LPU_INT_PHY_ERR 0x0000000000000010ULL #define FIRE_PCI_LPU_INT_LTSSM 0x0000000000000008ULL #define FIRE_PCI_LPU_INT_PHY_TX 0x0000000000000004ULL #define FIRE_PCI_LPU_INT_PHY_RX 0x0000000000000002ULL #define FIRE_PCI_LPU_INT_PHY_GB 0x0000000000000001ULL /* PCI DLU/LPU link layer config register */ #define FIRE_PCI_LPU_LNK_LYR_CFG_AUTO_UPDT_DIS 0x0000000000080000ULL #define FIRE_PCI_LPU_LNK_LYR_CFG_FREQ_NAK_EN 0x0000000000040000ULL #define FIRE_PCI_LPU_LNK_LYR_CFG_RPLY_AFTER_REQ 0x0000000000020000ULL #define FIRE_PCI_LPU_LNK_LYR_CFG_LAT_THRS_WR_EN 0x0000000000010000ULL #define FO_PCI_LPU_LNK_LYR_CFG_VC0_EN 0x0000000000000100ULL #define FIRE_PCI_LPU_LNK_LYR_CFG_L0S_ADJ_FAC_EN 0x0000000000000010ULL #define FIER_PCI_LPU_LNK_LYR_CFG_TLP_XMIT_FC_EN 0x0000000000000008ULL #define FO_PCI_LPU_LNK_LYR_CFG_FREQ_ACK_EN 0x0000000000000004ULL #define FO_PCI_LPU_LNK_LYR_CFG_RETRY_DIS 0x0000000000000002ULL /* PCI DLU/LPU link layer interrupt and status register */ #define FO_PCI_LPU_LNK_LYR_INT_STAT_LNK_ERR_ACT 0x0000000080000000ULL #define OBERON_PCI_LPU_LNK_LYR_INT_STAT_PBUS_PE 0x0000000000800000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_USPRTD_DLLP 0x0000000000400000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_DLLP_RX_ERR 0x0000000000200000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_BAD_DLLP 0x0000000000100000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_TLP_RX_ERR 0x0000000000040000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_SRC_ERR_TLP 0x0000000000020000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_BAD_TLP 0x0000000000010000ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_RBF_UDF_ERR 0x0000000000000200ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_RBF_OVF_ERR 0x0000000000000100ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_EG_TLPM_ERR 0x0000000000000080ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_EG_TFRM_ERR 0x0000000000000040ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_RBF_PE 0x0000000000000020ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_EGRESS_PE 0x0000000000000010ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_RPLY_TMR_TO 0x0000000000000004ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_RPLY_NUM_RO 0x0000000000000002ULL #define FO_PCI_LPU_LNK_LYR_INT_STAT_DLNK_PES 0x0000000000000001ULL /* PCI DLU/LPU flow control update control register */ #define FO_PCI_LPU_FLW_CTRL_UPDT_CTRL_FC0_C_EN 0x0000000000000004ULL #define FO_PCI_LPU_FLW_CTRL_UPDT_CTRL_FC0_NP_EN 0x0000000000000002ULL #define FO_PCI_LPU_FLW_CTRL_UPDT_CTRL_FC0_P_EN 0x0000000000000001ULL /* PCI DLU/LPU txlink ACKNAK latency timer threshold register */ #define FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS_MASK 0x000000000000ffffULL #define FO_PCI_LPU_TXLNK_FREQ_LAT_TMR_THRS_SHFT 0 /* PCI DLU/LPU txlink replay timer threshold register */ #define FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_MASK 0x00000000000fffffULL #define FO_PCI_LPU_TXLNK_RPLY_TMR_THRS_SHFT 0 /* PCI DLU/LPU txlink FIFO pointer register */ #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_MASK 0x00000000ffff0000ULL #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_SHFT 16 #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_MASK 0x000000000000ffffULL #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_SHFT 0 /* PCI DLU/LPU phy layer interrupt and status register */ #define FO_PCI_LPU_PHY_LYR_INT_STAT_PHY_LYR_ERR 0x0000000080000000ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_KC_DLLP_ERR 0x0000000000000800ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_END_POS_ERR 0x0000000000000400ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_LNK_ERR 0x0000000000000200ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_TRN_ERR 0x0000000000000100ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_EDB_DET 0x0000000000000080ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_SDP_END 0x0000000000000040ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_STP_END_EDB 0x0000000000000020ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_INVC_ERR 0x0000000000000010ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_MULTI_SDP 0x0000000000000008ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_MULTI_STP 0x0000000000000004ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_ILL_SDP_POS 0x0000000000000002ULL #define FO_PCI_LPU_PHY_LYR_INT_STAT_ILL_STP_POS 0x0000000000000001ULL /* PCI DLU/LPU LTSSM config2 register */ #define FO_PCI_LPU_LTSSM_CFG2_12_TO_MASK 0x00000000ffffffffULL #define FO_PCI_LPU_LTSSM_CFG2_12_TO_SHFT 0 /* PCI DLU/LPU LTSSM config3 register */ #define FO_PCI_LPU_LTSSM_CFG3_2_TO_MASK 0x00000000ffffffffULL #define FO_PCI_LPU_LTSSM_CFG3_2_TO_SHFT 0 /* PCI DLU/LPU LTSSM config4 register */ #define FO_PCI_LPU_LTSSM_CFG4_TRN_CTRL_MASK 0x00000000ff000000ULL #define FO_PCI_LPU_LTSSM_CFG4_TRN_CTRL_SHFT 24 #define FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_MASK 0x0000000000ff0000ULL #define FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_SHFT 16 #define FO_PCI_LPU_LTSSM_CFG4_N_FTS_MASK 0x000000000000ff00ULL #define FO_PCI_LPU_LTSSM_CFG4_N_FTS_SHFT 8 #define FO_PCI_LPU_LTSSM_CFG4_LNK_NUM_MASK 0x00000000000000ffULL #define FO_PCI_LPU_LTSSM_CFG4_LNK_NUM_SHFT 0 /* PCI DLU/LPU LTSSM config5 register */ #define FO_PCI_LPU_LTSSM_CFG5_UNUSED0_MASK 0x00000000ffffe000ULL #define FO_PCI_LPU_LTSSM_CFG5_UNUSED0_SHFT 13 #define FO_PCI_LPU_LTSSM_CFG5_RCV_DET_TST_MODE 0x0000000000001000ULL #define FO_PCI_LPU_LTSSM_CFG5_POLL_CMPLNC_DIS 0x0000000000000800ULL #define FO_PCI_LPU_LTSSM_CFG5_TX_IDLE_TX_FTS 0x0000000000000400ULL #define FO_PCI_LPU_LTSSM_CFG5_RX_FTS_RVR_LK 0x0000000000000200ULL #define FO_PCI_LPU_LTSSM_CFG5_UNUSED1_MASK 0x0000000000000180ULL #define FO_PCI_LPU_LTSSM_CFG5_UNUSED1_SHFT 7 #define FO_PCI_LPU_LTSSM_CFG5_LPBK_NTRY_ACTIVE 0x0000000000000040ULL #define FO_PCI_LPU_LTSSM_CFG5_LPBK_NTRY_EXIT 0x0000000000000020ULL #define FO_PCI_LPU_LTSSM_CFG5_LPBK_ACTIVE_EXIT 0x0000000000000010ULL #define FO_PCI_LPU_LTSSM_CFG5_L1_IDLE_RCVRY_LK 0x0000000000000008ULL #define FO_PCI_LPU_LTSSM_CFG5_L0_TRN_CNTRL_RST 0x0000000000000004ULL #define FO_PCI_LPU_LTSSM_CFG5_L0_LPBK 0x0000000000000002ULL #define FO_PCI_LPU_LTSSM_CFG5_UNUSED2 0x0000000000000001ULL /* Controller configuration and status registers */ #define FIRE_JBUS_PAR_CTRL 0x60010 #define FO_XBC_ERR_LOG_EN 0x61000 #define FO_XBC_INT_EN 0x61008 #define FO_XBC_INT_STAT 0x61010 #define FO_XBC_ERR_STAT_CLR 0x61018 #define FIRE_JBC_FATAL_RST_EN 0x61028 #define FIRE_JBCINT_ITRANS_ERR_LOG 0x61040 #define FIRE_JBCINT_ITRANS_ERR_LOG2 0x61048 #define FIRE_JBCINT_OTRANS_ERR_LOG 0x61040 #define FIRE_JBCINT_OTRANS_ERR_LOG2 0x61048 #define FIRE_FATAL_ERR_LOG 0x61050 #define FIRE_FATAL_ERR_LOG2 0x61058 #define FIRE_MERGE_TRANS_ERR_LOG 0x61060 #define FIRE_DMCINT_ODCD_ERR_LOG 0x61068 #define FIRE_DMCINT_IDC_ERR_LOG 0x61070 #define FIRE_JBC_CSR_ERR_LOG 0x61078 #define FIRE_JBC_CORE_BLOCK_INT_EN 0x61800 #define FIRE_JBC_CORE_BLOCK_ERR_STAT 0x61808 #define FO_XBC_PRF_CNT_SEL 0x62000 #define FO_XBC_PRF_CNT0 0x62008 #define FO_XBC_PRF_CNT1 0x62010 /* JBus parity control register */ #define FIRE_JBUS_PAR_CTRL_P_EN 0x8000000000000000ULL #define FIRE_JBUS_PAR_CTRL_INVRTD_PAR_MASK 0x000000000000003cULL #define FIRE_JBUS_PAR_CTRL_INVRTD_PAR_SHFT 2 #define FIRE_JBUS_PAR_CTRL_NEXT_DATA 0x0000000000000002ULL #define FIRE_JBUS_PAR_CTRL_NEXT_ADDR 0x0000000000000001ULL /* JBC error log enable register - may also apply to UBC */ #define FIRE_JBC_ERR_LOG_EN_SPARE_MASK 0x00000000e0000000ULL #define FIRE_JBC_ERR_LOG_EN_SPARE_SHFT 29 #define FIRE_JBC_ERR_LOG_EN_PIO_UNMAP_RD 0x0000000010000000ULL #define FIRE_JBC_ERR_LOG_EN_ILL_ACC_RD 0x0000000008000000ULL #define FIRE_JBC_ERR_LOG_EN_EBUS_TO 0x0000000004000000ULL #define FIRE_JBC_ERR_LOG_EN_MB_PEA 0x0000000002000000ULL #define FIRE_JBC_ERR_LOG_EN_MB_PER 0x0000000001000000ULL #define FIRE_JBC_ERR_LOG_EN_MB_PEW 0x0000000000800000ULL #define FIRE_JBC_ERR_LOG_EN_UE_ASYN 0x0000000000400000ULL #define FIRE_JBC_ERR_LOG_EN_CE_ASYN 0x0000000000200000ULL #define FIRE_JBC_ERR_LOG_EN_JTE 0x0000000000100000ULL #define FIRE_JBC_ERR_LOG_EN_JBE 0x0000000000080000ULL #define FIRE_JBC_ERR_LOG_EN_JUE 0x0000000000040000ULL #define FIRE_JBC_ERR_LOG_EN_IJP 0x0000000000020000ULL #define FIRE_JBC_ERR_LOG_EN_ICISE 0x0000000000010000ULL #define FIRE_JBC_ERR_LOG_EN_CPE 0x0000000000008000ULL #define FIRE_JBC_ERR_LOG_EN_APE 0x0000000000004000ULL #define FIRE_JBC_ERR_LOG_EN_WR_DPE 0x0000000000002000ULL #define FIRE_JBC_ERR_LOG_EN_RD_DPE 0x0000000000001000ULL #define FIRE_JBC_ERR_LOG_EN_ILL_BMW 0x0000000000000800ULL #define FIRE_JBC_ERR_LOG_EN_ILL_BMR 0x0000000000000400ULL #define FIRE_JBC_ERR_LOG_EN_BJC 0x0000000000000200ULL #define FIRE_JBC_ERR_LOG_EN_PIO_UNMAP 0x0000000000000100ULL #define FIRE_JBC_ERR_LOG_EN_PIO_DPE 0x0000000000000080ULL #define FIRE_JBC_ERR_LOG_EN_PIO_CPE 0x0000000000000040ULL #define FIRE_JBC_ERR_LOG_EN_ILL_ACC 0x0000000000000020ULL #define FIRE_JBC_ERR_LOG_EN_UNSOL_RD 0x0000000000000010ULL #define FIRE_JBC_ERR_LOG_EN_UNSOL_INT 0x0000000000000008ULL #define FIRE_JBC_ERR_LOG_EN_JTCEEW 0x0000000000000004ULL #define FIRE_JBC_ERR_LOG_EN_JTCEEI 0x0000000000000002ULL #define FIRE_JBC_ERR_LOG_EN_JTCEER 0x0000000000000001ULL /* JBC interrupt enable, interrupt status and error status clear registers */ #define FIRE_JBC_ERR_INT_SPARE_S_MASK 0xe000000000000000ULL #define FIRE_JBC_ERR_INT_SPARE_S_SHFT 61 #define FIRE_JBC_ERR_INT_PIO_UNMAP_RD_S 0x1000000000000000ULL #define FIRE_JBC_ERR_INT_ILL_ACC_RD_S 0x0800000000000000ULL #define FIRE_JBC_ERR_INT_EBUS_TO_S 0x0400000000000000ULL #define FIRE_JBC_ERR_INT_MB_PEA_S 0x0200000000000000ULL #define FIRE_JBC_ERR_INT_MB_PER_S 0x0100000000000000ULL #define FIRE_JBC_ERR_INT_MB_PEW_S 0x0080000000000000ULL #define FIRE_JBC_ERR_INT_UE_ASYN_S 0x0040000000000000ULL #define FIRE_JBC_ERR_INT_CE_ASYN_S 0x0020000000000000ULL #define FIRE_JBC_ERR_INT_JTE_S 0x0010000000000000ULL #define FIRE_JBC_ERR_INT_JBE_S 0x0008000000000000ULL #define FIRE_JBC_ERR_INT_JUE_S 0x0004000000000000ULL #define FIRE_JBC_ERR_INT_IJP_S 0x0002000000000000ULL #define FIRE_JBC_ERR_INT_ICISE_S 0x0001000000000000ULL #define FIRE_JBC_ERR_INT_CPE_S 0x0000800000000000ULL #define FIRE_JBC_ERR_INT_APE_S 0x0000400000000000ULL #define FIRE_JBC_ERR_INT_WR_DPE_S 0x0000200000000000ULL #define FIRE_JBC_ERR_INT_RD_DPE_S 0x0000100000000000ULL #define FIRE_JBC_ERR_INT_ILL_BMW_S 0x0000080000000000ULL #define FIRE_JBC_ERR_INT_ILL_BMR_S 0x0000040000000000ULL #define FIRE_JBC_ERR_INT_BJC_S 0x0000020000000000ULL #define FIRE_JBC_ERR_INT_PIO_UNMAP_S 0x0000010000000000ULL #define FIRE_JBC_ERR_INT_PIO_DPE_S 0x0000008000000000ULL #define FIRE_JBC_ERR_INT_PIO_CPE_S 0x0000004000000000ULL #define FIRE_JBC_ERR_INT_ILL_ACC_S 0x0000002000000000ULL #define FIRE_JBC_ERR_INT_UNSOL_RD_S 0x0000001000000000ULL #define FIRE_JBC_ERR_INT_UNSOL_INT_S 0x0000000800000000ULL #define FIRE_JBC_ERR_INT_JTCEEW_S 0x0000000400000000ULL #define FIRE_JBC_ERR_INT_JTCEEI_S 0x0000000200000000ULL #define FIRE_JBC_ERR_INT_JTCEER_S 0x0000000100000000ULL #define FIRE_JBC_ERR_INT_SPARE_P_MASK 0x00000000e0000000ULL #define FIRE_JBC_ERR_INT_SPARE_P_SHFT 29 #define FIRE_JBC_ERR_INT_PIO_UNMAP_RD_P 0x0000000010000000ULL #define FIRE_JBC_ERR_INT_ILL_ACC_RD_P 0x0000000008000000ULL #define FIRE_JBC_ERR_INT_EBUS_TO_P 0x0000000004000000ULL #define FIRE_JBC_ERR_INT_MB_PEA_P 0x0000000002000000ULL #define FIRE_JBC_ERR_INT_MB_PER_P 0x0000000001000000ULL #define FIRE_JBC_ERR_INT_MB_PEW_P 0x0000000000800000ULL #define FIRE_JBC_ERR_INT_UE_ASYN_P 0x0000000000400000ULL #define FIRE_JBC_ERR_INT_CE_ASYN_P 0x0000000000200000ULL #define FIRE_JBC_ERR_INT_JTE_P 0x0000000000100000ULL #define FIRE_JBC_ERR_INT_JBE_P 0x0000000000080000ULL #define FIRE_JBC_ERR_INT_JUE_P 0x0000000000040000ULL #define FIRE_JBC_ERR_INT_IJP_P 0x0000000000020000ULL #define FIRE_JBC_ERR_INT_ICISE_P 0x0000000000010000ULL #define FIRE_JBC_ERR_INT_CPE_P 0x0000000000008000ULL #define FIRE_JBC_ERR_INT_APE_P 0x0000000000004000ULL #define FIRE_JBC_ERR_INT_WR_DPE_P 0x0000000000002000ULL #define FIRE_JBC_ERR_INT_RD_DPE_P 0x0000000000001000ULL #define FIRE_JBC_ERR_INT_ILL_BMW_P 0x0000000000000800ULL #define FIRE_JBC_ERR_INT_ILL_BMR_P 0x0000000000000400ULL #define FIRE_JBC_ERR_INT_BJC_P 0x0000000000000200ULL #define FIRE_JBC_ERR_INT_PIO_UNMAP_P 0x0000000000000100ULL #define FIRE_JBC_ERR_INT_PIO_DPE_P 0x0000000000000080ULL #define FIRE_JBC_ERR_INT_PIO_CPE_P 0x0000000000000040ULL #define FIRE_JBC_ERR_INT_ILL_ACC_P 0x0000000000000020ULL #define FIRE_JBC_ERR_INT_UNSOL_RD_P 0x0000000000000010ULL #define FIRE_JBC_ERR_INT_UNSOL_INT_P 0x0000000000000008ULL #define FIRE_JBC_ERR_INT_JTCEEW_P 0x0000000000000004ULL #define FIRE_JBC_ERR_INT_JTCEEI_P 0x0000000000000002ULL #define FIRE_JBC_ERR_INT_JTCEER_P 0x0000000000000001ULL /* UBC interrupt enable, error status and error status clear registers */ #define OBERON_UBC_ERR_INT_PIORBEUE_S 0x0004000000000000ULL #define OBERON_UBC_ERR_INT_PIOWBEUE_S 0x0002000000000000ULL #define OBERON_UBC_ERR_INT_PIOWTUE_S 0x0001000000000000ULL #define OBERON_UBC_ERR_INT_MEMWTAXB_S 0x0000080000000000ULL #define OBERON_UBC_ERR_INT_MEMRDAXB_S 0x0000040000000000ULL #define OBERON_UBC_ERR_INT_DMAWTUEB_S 0x0000020000000000ULL #define OBERON_UBC_ERR_INT_DMARDUEB_S 0x0000010000000000ULL #define OBERON_UBC_ERR_INT_MEMWTAXA_S 0x0000000800000000ULL #define OBERON_UBC_ERR_INT_MEMRDAXA_S 0x0000000400000000ULL #define OBERON_UBC_ERR_INT_DMAWTUEA_S 0x0000000200000000ULL #define OBERON_UBC_ERR_INT_DMARDUEA_S 0x0000000100000000ULL #define OBERON_UBC_ERR_INT_PIORBEUE_P 0x0000000000040000ULL #define OBERON_UBC_ERR_INT_PIOWBEUE_P 0x0000000000020000ULL #define OBERON_UBC_ERR_INT_PIOWTUE_P 0x0000000000010000ULL #define OBERON_UBC_ERR_INT_MEMWTAXB_P 0x0000000000000800ULL #define OBERON_UBC_ERR_INT_MEMRDAXB_P 0x0000000000000400ULL #define OBERON_UBC_ERR_INT_DMARDUEB_P 0x0000000000000200ULL #define OBERON_UBC_ERR_INT_DMAWTUEB_P 0x0000000000000100ULL #define OBERON_UBC_ERR_INT_MEMWTAXA_P 0x0000000000000008ULL #define OBERON_UBC_ERR_INT_MEMRDAXA_P 0x0000000000000004ULL #define OBERON_UBC_ERR_INT_DMAWTUEA_P 0x0000000000000002ULL #define OBERON_UBC_ERR_INT_DMARDUEA_P 0x0000000000000001ULL /* JBC fatal reset enable register */ #define FIRE_JBC_FATAL_RST_EN_SPARE_P_INT_MASK 0x000000000c000000ULL #define FIRE_JBC_FATAL_RST_EN_SPARE_P_INT_SHFT 26 #define FIRE_JBC_FATAL_RST_EN_MB_PEA_P_INT 0x0000000002000000ULL #define FIRE_JBC_FATAL_RST_EN_CPE_P_INT 0x0000000000008000ULL #define FIRE_JBC_FATAL_RST_EN_APE_P_INT 0x0000000000004000ULL #define FIRE_JBC_FATAL_RST_EN_PIO_CPE_INT 0x0000000000000040ULL #define FIRE_JBC_FATAL_RST_EN_JTCEEW_P_INT 0x0000000000000004ULL #define FIRE_JBC_FATAL_RST_EN_JTCEEI_P_INT 0x0000000000000002ULL #define FIRE_JBC_FATAL_RST_EN_JTCEER_P_INT 0x0000000000000001ULL /* JBC JBCINT in transaction error log register */ #define FIRE_JBCINT_ITRANS_ERR_LOG_Q_WORD_MASK 0x00c0000000000000ULL #define FIRE_JBCINT_ITRANS_ERR_LOG_Q_WORD_SHFT 54 #define FIRE_JBCINT_ITRANS_ERR_LOG_TRANSID_MASK 0x0003000000000000ULL #define FIRE_JBCINT_ITRANS_ERR_LOG_TRANSID_SHFT 48 #define FIRE_JBCINT_ITRANS_ERR_LOG_ADDR_MASK 0x000007ffffffffffULL #define FIRE_JBCINT_ITRANS_ERR_LOG_ADDR_SHFT 0 /* JBC JBCINT in transaction error log register 2 */ #define FIRE_JBCINT_ITRANS_ERR_LOG2_ARB_WN_MASK 0x000ffffff0000000ULL #define FIRE_JBCINT_ITRANS_ERR_LOG2_ARB_WN_SHFT 28 #define FIRE_JBCINT_ITRANS_ERR_LOG2_J_REQ_MASK 0x000000000fe00000ULL #define FIRE_JBCINT_ITRANS_ERR_LOG2_J_REQ_SHFT 21 #define FIRE_JBCINT_ITRANS_ERR_LOG2_J_PACK_MASK 0x00000000001fffffULL #define FIRE_JBCINT_ITRANS_ERR_LOG2_J_PACK_SHFT 0 /* JBC JBCINT out transaction error log register */ #define FIRE_JBCINT_OTRANS_ERR_LOG_TRANSID_MASK 0x003f000000000000ULL #define FIRE_JBCINT_OTRANS_ERR_LOG_TRANSID_SHFT 48 #define FIRE_JBCINT_OTRANS_ERR_LOG_ADDR_MASK 0x000007ffffffffffULL #define FIRE_JBCINT_OTRANS_ERR_LOG_ADDR_SHFT 0 /* JBC JBCINT out transaction error log register 2 */ #define FIRE_JBCINT_OTRANS_ERR_LOG2_ARB_WN_MASK 0x000ffffff0000000ULL #define FIRE_JBCINT_OTRANS_ERR_LOG2_ARB_WN_SHFT 28 #define FIRE_JBCINT_OTRANS_ERR_LOG2_J_REQ_MASK 0x000000000fe00000ULL #define FIRE_JBCINT_OTRANS_ERR_LOG2_J_REQ_SHFT 21 #define FIRE_JBCINT_OTRANS_ERR_LOG2_J_PACK_MASK 0x00000000001fffffULL #define FIRE_JBCINT_OTRANS_ERR_LOG2_J_PACK_SHFT 0 /* JBC merge transaction error log register */ #define FIRE_FATAL_ERR_LOG_DATA_MASK 0xffffffffffffffffULL #define FIRE_FATAL_ERR_LOG_DATA_SHFT 0 /* JBC merge transaction error log register 2 */ #define FIRE_FATAL_ERR_LOG2_ARB_WN_MASK 0x000ffffff0000000ULL #define FIRE_FATAL_ERR_LOG2_ARB_WN_SHFT 28 #define FIRE_FATAL_ERR_LOG2_J_REQ_MASK 0x000000000fe00000ULL #define FIRE_FATAL_ERR_LOG2_J_REQ_SHFT 21 #define FIRE_FATAL_ERR_LOG2_J_PACK_MASK 0x00000000001fffffULL #define FIRE_FATAL_ERR_LOG2_J_PACK_SHFT 0 /* JBC merge transaction error log register */ #define FIRE_MERGE_TRANS_ERR_LOG_Q_WORD_MASK 0x00c0000000000000ULL #define FIRE_MERGE_TRANS_ERR_LOG_Q_WORD_SHFT 54 #define FIRE_MERGE_TRANS_ERR_LOG_TRANSID_MASK 0x0003000000000000ULL #define FIRE_MERGE_TRANS_ERR_LOG_TRANSID_SHFT 48 #define FIRE_MERGE_TRANS_ERR_LOG_JBC_TAG_MASK 0x0000f80000000000ULL #define FIRE_MERGE_TRANS_ERR_LOG_JBC_TAG_SHFT 43 #define FIRE_MERGE_TRANS_ERR_LOG_ADDR_MASK 0x000007ffffffffffULL #define FIRE_MERGE_TRANS_ERR_LOG_ADDR_SHFT 0 /* JBC DMCINT ODCD error log register */ #define FIRE_DMCINT_ODCD_ERR_LOG_TRANS_ID_MASK 0x0030000000000000ULL #define FIRE_DMCINT_ODCD_ERR_LOG_TRANS_ID_SHFT 52 #define FIRE_DMCINT_ODCD_ERR_LOG_AID_MASK 0x000f000000000000ULL #define FIRE_DMCINT_ODCD_ERR_LOG_AID_SHFT 48 #define FIRE_DMCINT_ODCD_ERR_LOG_TTYPE_MASK 0x0000f80000000000ULL #define FIRE_DMCINT_ODCD_ERR_LOG_TTYPE_SHFT 43 #define FIRE_DMCINT_ODCD_ERR_LOG_ADDR_MASK 0x000007ffffffffffULL #define FIRE_DMCINT_ODCD_ERR_LOG_ADDR_SHFT 0 /* JBC DMCINT IDC error log register */ #define FIRE_DMCINT_IDC_ERR_DMC_CTAG_MASK 0x000000000fff0000ULL #define FIRE_DMCINT_IDC_ERR_DMC_CTAG_SHFT 16 #define FIRE_DMCINT_IDC_ERR_TRANSID_MASK 0x000000000000c000ULL #define FIRE_DMCINT_IDC_ERR_AGNTID_MASK 0x0000000000003c00ULL #define FIRE_DMCINT_IDC_ERR_AGNTID_SHFT 10 #define FIRE_DMCINT_IDC_ERR_SRCID_MASK 0x00000000000003e0ULL #define FIRE_DMCINT_IDC_ERR_SRCID_SHFT 5 #define FIRE_DMCINT_IDC_ERR_TARGID_MASK 0x000000000000001fULL #define FIRE_DMCINT_IDC_ERRO_TARGID_SHFT 0 /* JBC CSR error log register */ #define FIRE_JBC_CSR_ERR_LOG_WR 0x0000040000000000ULL #define FIRE_JBC_CSR_ERR_LOG_BMASK_MASK 0x000003fffc000000ULL #define FIRE_JBC_CSR_ERR_LOG_BMASK_SHFT 26 #define FIRE_JBC_CSR_ERR_LOG_ADDR_MASK 0x0000000003ffffffULL #define FIRE_JBC_CSR_ERR_LOG_ADDR_SHFT 0 /* JBC core and block interrupt enable register */ #define FIRE_JBC_CORE_BLOCK_INT_EN_JBC 0x8000000000000000ULL #define FIRE_JBC_CORE_BLOCK_INT_EN_CSR 0x0000000000000008ULL #define FIRE_JBC_CORE_BLOCK_INT_EN_MERGE 0x0000000000000004ULL #define FIRE_JBC_CORE_BLOCK_INT_EN_JBCINT 0x0000000000000002ULL #define FIRE_JBC_CORE_BLOCK_INT_EN_DMCINT 0x0000000000000001ULL /* JBC core and block error status register */ #define FIRE_JBC_CORE_BLOCK_ERR_STAT_CSR 0x0000000000000008ULL #define FIRE_JBC_CORE_BLOCK_ERR_STAT_MERGE 0x0000000000000004ULL #define FIRE_JBC_CORE_BLOCK_ERR_STAT_JBCINT 0x0000000000000002ULL #define FIRE_JBC_CORE_BLOCK_ERR_STAT_DMCINT 0x0000000000000001ULL /* JBC performance counter select register - may also apply to UBC */ #define FO_XBC_PRF_CNT_PIO_RD_PCIEB 0x0000000000000018ULL #define FO_XBC_PRF_CNT_PIO_WR_PCIEB 0x0000000000000017ULL #define FO_XBC_PRF_CNT_PIO_RD_PCIEA 0x0000000000000016ULL #define FO_XBC_PRF_CNT_PIO_WR_PCIEA 0x0000000000000015ULL #define FO_XBC_PRF_CNT_WB 0x0000000000000014ULL #define FO_XBC_PRF_CNT_PIO_FRGN 0x0000000000000013ULL #define FO_XBC_PRF_CNT_XB_NCHRNT 0x0000000000000012ULL #define FO_XBC_PRF_CNT_FO_CHRNT 0x0000000000000011ULL #define FO_XBC_PRF_CNT_XB_CHRNT 0x0000000000000010ULL #define FO_XBC_PRF_CNT_AOKOFF_DOKOFF 0x000000000000000fULL #define FO_XBC_PRF_CNT_DOKOFF 0x000000000000000eULL #define FO_XBC_PRF_CNT_AOKOFF 0x000000000000000dULL #define FO_XBC_PRF_CNT_RD_TOTAL 0x000000000000000cULL #define FO_XBC_PRF_CNT_WR_TOTAL 0x000000000000000bULL #define FO_XBC_PRF_CNT_WR_PARTIAL 0x000000000000000aULL #define FO_XBC_PRF_CNT_PIOS_CSR_RINGB 0x0000000000000009ULL #define FO_XBC_PRF_CNT_PIOS_CSR_RINGA 0x0000000000000008ULL #define FO_XBC_PRF_CNT_PIOS_EBUS 0x0000000000000007ULL #define FO_XBC_PRF_CNT_PIOS_I2C 0x0000000000000006ULL #define FO_XBC_PRF_CNT_RD_LAT_SMPLS 0x0000000000000005ULL #define FO_XBC_PRF_CNT_RD_LAT 0x0000000000000004ULL #define FO_XBC_PRF_CNT_ON_XB 0x0000000000000003ULL #define FO_XBC_PRF_CNT_XB_IDL 0x0000000000000002ULL #define FO_XBC_PRF_CNT_XB_CLK 0x0000000000000001ULL #define FO_XBC_PRF_CNT_NONE 0x0000000000000000ULL #define FO_XBC_PRF_CNT_CNT1_SHFT 8 #define FO_XBC_PRF_CNT_CNT0_SHFT 0 /* JBC performance counter 0/1 registers - may also apply to UBC */ #define FO_XBC_PRF_CNT_MASK 0xffffffffffffffffULL #define FO_XBC_PRF_CNT_SHFT 0 /* Lookup tables */ const uint16_t fire_freq_nak_tmr_thrs[6][4] = { { 0x00ed, 0x049, 0x043, 0x030 }, { 0x01a0, 0x076, 0x06b, 0x048 }, { 0x022f, 0x09a, 0x056, 0x056 }, { 0x042f, 0x11a, 0x096, 0x096 }, { 0x082f, 0x21a, 0x116, 0x116 }, { 0x102f, 0x41a, 0x216, 0x216 } }; const uint16_t fire_rply_tmr_thrs[6][4] = { { 0x0379, 0x112, 0x0fc, 0x0b4 }, { 0x0618, 0x1BA, 0x192, 0x10e }, { 0x0831, 0x242, 0x143, 0x143 }, { 0x0fb1, 0x422, 0x233, 0x233 }, { 0x1eb0, 0x7e1, 0x412, 0x412 }, { 0x3cb0, 0xf61, 0x7d2, 0x7d2 } }; /* Register default values */ #define FO_PCI_TLU_CTRL_L0S_TIM_DFLT 0xda #define FO_PCI_TLU_CTRL_CFG_DFLT 0x1 #define FO_PCI_LPU_LTSSM_CFG2_12_TO_DFLT 0x2dc6c0 #define FO_PCI_LPU_LTSSM_CFG3_2_TO_DFLT 0x7a120 #define FO_PCI_LPU_LTSSM_CFG4_DATA_RATE_DFLT 0x2 #define FO_PCI_LPU_LTSSM_CFG4_N_FTS_DFLT 0x8c #define OBERON_PCI_LPU_TXLNK_RPLY_TMR_THRS_DFLT 0xc9 #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_HD_DFLT 0x0 #define FO_PCI_LPU_TXLNK_RTR_FIFO_PTR_TL_DFLT 0xffff /* INO macros */ #define FO_EQ_FIRST_INO 0x18 #define FO_EQ_LAST_INO 0x3b #define FO_DMC_PEC_INO 0x3e #define FO_XCB_INO 0x3f #define FO_MAX_INO FO_XCB_INO /* Device space macros */ #define FO_CONF_BUS_SHFT 20 #define FO_CONF_DEV_SHFT 15 #define FO_CONF_FUNC_SHFT 12 #define FO_CONF_REG_SHFT 0 #define FO_IO_SIZE 0x10000000 #define FO_MEM_SIZE 0x1ffff0000 #define FO_CONF_OFF(bus, slot, func, reg) \ (((bus) << FO_CONF_BUS_SHFT) | \ ((slot) << FO_CONF_DEV_SHFT) | \ ((func) << FO_CONF_FUNC_SHFT) | \ ((reg) << FO_CONF_REG_SHFT)) /* Width of the physical addresses the IOMMU translates to */ #define FIRE_IOMMU_BITS 43 #define OBERON_IOMMU_BITS 47 /* Event queue macros */ #define FO_EQ_ALIGNMENT (512 * 1024) #define FO_EQ_NRECORDS 128 #define FO_EQ_RECORD_SIZE 64 /* Event queue record format */ struct fo_msiq_record { uint64_t fomqr_word0; uint64_t fomqr_word1; uint64_t fomqr_reserved[6]; }; #define FO_MQR_WORD0_FMT_TYPE_MASK 0x7f00000000000000ULL #define FO_MQR_WORD0_FMT_TYPE_SHFT 56 #define FO_MQR_WORD0_FMT_TYPE_MSI64 0x7800000000000000ULL #define FO_MQR_WORD0_FMT_TYPE_MSI32 0x5800000000000000ULL #define FO_MQR_WORD0_FMT_TYPE_MSG 0x3000000000000000ULL #define FO_MQR_WORD0_FMT_TYPE_MSG_ROUTE_MASK 0x0700000000000000ULL #define FO_MQR_WORD0_FMT_TYPE_MSG_ROUTE_SHFT 56 #define FO_MQR_WORD0_LENGTH_MASK 0x00ffc00000000000ULL #define FO_MQR_WORD0_LENGTH_SHFT 46 #define FO_MQR_WORD0_ADDR0_MASK 0x00003fff00000000ULL #define FO_MQR_WORD0_ADDR0_SHFT 32 #define FO_MQR_WORD0_RID_MASK 0x00000000ffff0000ULL #define FO_MQR_WORD0_RID_SHFT 16 #define FO_MQR_WORD0_DATA0_MASK 0x000000000000ffffULL #define FO_MQR_WORD0_DATA0_SHFT 0 #define FO_MQR_WORD1_ADDR1_MASK 0xffffffffffff0000ULL #define FO_MQR_WORD1_ADDR1_SHFT 16 #define FO_MQR_WORD1_DATA1_MASK 0x000000000000ffffULL #define FO_MQR_WORD1_DATA1_SHFT 0 #endif /* !_SPARC64_PCI_FIREREG_H_ */ Index: head/sys/sparc64/pci/firevar.h =================================================================== --- head/sys/sparc64/pci/firevar.h (revision 287725) +++ head/sys/sparc64/pci/firevar.h (revision 287726) @@ -1,97 +1,89 @@ /*- * Copyright (c) 2009 by Marius Strobl . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SPARC64_PCI_FIREVAR_H_ #define _SPARC64_PCI_FIREVAR_H_ struct fire_softc { + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; + struct iommu_state sc_is; struct bus_dma_methods sc_dma_methods; struct mtx sc_msi_mtx; struct mtx sc_pcib_mtx; struct resource *sc_mem_res[FIRE_NREG]; struct resource *sc_irq_res[FIRE_NINTR]; void *sc_ihand[FIRE_NINTR]; - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - bus_space_handle_t sc_pci_bh[FIRE_NRANGE]; - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - device_t sc_dev; uint64_t *sc_msiq; u_char *sc_msi_bitmap; uint32_t *sc_msi_msiq_table; u_char *sc_msiq_bitmap; uint64_t sc_msi_addr32; uint64_t sc_msi_addr64; uint32_t sc_msi_count; uint32_t sc_msi_first; uint32_t sc_msi_data_mask; uint32_t sc_msix_data_width; uint32_t sc_msiq_count; uint32_t sc_msiq_size; uint32_t sc_msiq_first; uint32_t sc_msiq_ino_first; - phandle_t sc_node; - u_int sc_mode; #define FIRE_MODE_FIRE 0 #define FIRE_MODE_OBERON 1 u_int sc_flags; #define FIRE_MSIX (1 << 0) uint32_t sc_ign; uint32_t sc_stats_ilu_err; uint32_t sc_stats_jbc_ce_async; uint32_t sc_stats_jbc_unsol_int; uint32_t sc_stats_jbc_unsol_rd; uint32_t sc_stats_mmu_err; uint32_t sc_stats_tlu_ce; uint32_t sc_stats_tlu_oe_non_fatal; uint32_t sc_stats_tlu_oe_rx_err; uint32_t sc_stats_tlu_oe_tx_err; uint32_t sc_stats_ubc_dmardue; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - struct ofw_bus_iinfo sc_pci_iinfo; }; #endif /* !_SPARC64_PCI_FIREVAR_H_ */ Index: head/sys/sparc64/pci/ofw_pci.c =================================================================== --- head/sys/sparc64/pci/ofw_pci.c (nonexistent) +++ head/sys/sparc64/pci/ofw_pci.c (revision 287726) @@ -0,0 +1,406 @@ +/*- + * Copyright (c) 1999, 2000 Matthew R. Green + * Copyright (c) 2001 - 2003 by Thomas Moestl + * Copyright (c) 2005 - 2015 by Marius Strobl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ofw_pci.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +int +ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_ranges *range; + phandle_t node; + uint32_t prop_array[2]; + u_int i, j, nrange; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + sc->sc_node = node; + sc->sc_pci_dmat = dmat; + + /* Initialize memory and I/O rmans. */ + sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports"; + if (rman_init(&sc->sc_pci_io_rman) != 0 || + rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) { + device_printf(dev, "failed to set up I/O rman\n"); + return (ENXIO); + } + sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_mem_rman.rm_descr = "PCI Memory"; + if (rman_init(&sc->sc_pci_mem_rman) != 0 || + rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) { + device_printf(dev, "failed to set up memory rman\n"); + return (ENXIO); + } + + /* + * Find the addresses of the various bus spaces. The physical + * start addresses of the ranges are the configuration, I/O and + * memory handles. There should not be multiple ones of one kind. + */ + nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), + (void **)&range); + for (i = 0; i < nrange; i++) { + j = OFW_PCI_RANGE_CS(&range[i]); + if (sc->sc_pci_bh[j] != 0) { + device_printf(dev, "duplicate range for space %d\n", + j); + free(range, M_OFWPROP); + return (EINVAL); + } + sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); + } + free(range, M_OFWPROP); + + /* + * Make sure that the expected ranges are actually present. + * The OFW_PCI_CS_MEM64 one is not currently used. + */ + if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) { + device_printf(dev, "missing CONFIG range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) { + device_printf(dev, "missing IO range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) { + device_printf(dev, "missing MEM32 range\n"); + return (ENXIO); + } + + /* Allocate our tags. */ + sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); + if (sc->sc_pci_iot == NULL) { + device_printf(dev, "could not allocate PCI I/O tag\n"); + return (ENXIO); + } + sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); + if (sc->sc_pci_cfgt == NULL) { + device_printf(dev, + "could not allocate PCI configuration space tag\n"); + return (ENXIO); + } + + /* + * Get the bus range from the firmware. + */ + i = OF_getprop(node, "bus-range", (void *)prop_array, + sizeof(prop_array)); + if (i == -1) { + device_printf(dev, "could not get bus-range\n"); + return (ENXIO); + } + if (i != sizeof(prop_array)) { + device_printf(dev, "broken bus-range (%d)", i); + return (EINVAL); + } + sc->sc_pci_secbus = prop_array[0]; + sc->sc_pci_subbus = prop_array[1]; + if (bootverbose != 0) + device_printf(dev, "bus range %u to %u; PCI bus %d\n", + sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + + return (0); +} + +uint32_t +ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + uint32_t r, wrd; + int i; + uint16_t shrt; + uint8_t byte; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return (-1); + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); + r = byte; + break; + case 2: + i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); + r = shrt; + break; + case 4: + i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); + r = wrd; + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } + + if (i) { +#ifdef OFW_PCI_DEBUG + printf("%s: read data error reading: %d.%d.%d: 0x%x\n", + __func__, bus, slot, func, reg); +#endif + r = -1; + } + return (r); +} + +void +ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return; + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); + break; + case 2: + bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); + break; + case 4: + bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } +} + +ofw_pci_intr_t +ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_register reg; + ofw_pci_intr_t pintr, mintr; + + sc = device_get_softc(bridge); + pintr = pin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, + ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), + NULL) != 0) + return (mintr); + return (PCI_INVALID_IRQ); +} + +void +ofw_pci_dmamap_sync_stst_order_common(void) +{ + static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); + register_t reg, s; + + s = intr_disable(); + reg = rd(fprs); + wr(fprs, reg | FPRS_FEF, 0); + __asm __volatile("stda %%f0, [%0] %1" + : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); + membar(Sync); + wr(fprs, reg, 0); + intr_restore(s); +} + +int +ofw_pci_read_ivar(device_t dev, device_t child __unused, int which, + uintptr_t *result) +{ + struct ofw_pci_softc *sc; + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = device_get_unit(dev); + return (0); + case PCIB_IVAR_BUS: + sc = device_get_softc(dev); + *result = sc->sc_pci_secbus; + return (0); + } + return (ENOENT); +} + +struct resource * +ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct ofw_pci_softc *sc; + struct resource *rv; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + /* + * XXX: Don't accept blank ranges for now, only single + * interrupts. The other case should not happen with + * the MI PCI code ... + * XXX: This may return a resource that is out of the + * range that was specified. Is this correct ...? + */ + if (start != end) + panic("%s: XXX: interrupt range", __func__); + return (bus_generic_alloc_resource(bus, child, type, rid, + start, end, count, flags)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (NULL); + } + + rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, + child); + if (rv == NULL) + return (NULL); + rman_set_rid(rv, *rid); + + if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, + *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); + } + return (rv); +} + +int +ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct ofw_pci_softc *sc; + struct bus_space_tag *tag; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_activate_resource(bus, child, type, rid, + r)); + case SYS_RES_MEMORY: + tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); + if (tag == NULL) + return (ENOMEM); + rman_set_bustag(r, tag); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + + rman_get_start(r)); + break; + case SYS_RES_IOPORT: + rman_set_bustag(r, sc->sc_pci_iot); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + + rman_get_start(r)); + break; + } + return (rman_activate_resource(r)); +} + +int +ofw_pci_adjust_resource(device_t bus, device_t child, int type, + struct resource *r, u_long start, u_long end) +{ + struct ofw_pci_softc *sc; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_adjust_resource(bus, child, type, r, + start, end)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (EINVAL); + } + if (rman_is_region_manager(r, rm) == 0) + return (EINVAL); + return (rman_adjust_resource(r, start, end)); +} + +bus_dma_tag_t +ofw_pci_get_dma_tag(device_t bus, device_t child __unused) +{ + struct ofw_pci_softc *sc; + + sc = device_get_softc(bus); + return (sc->sc_pci_dmat); +} + +phandle_t +ofw_pci_get_node(device_t bus, device_t child __unused) +{ + struct ofw_pci_softc *sc; + + sc = device_get_softc(bus); + /* We only have one child, the PCI bus, which needs our own node. */ + return (sc->sc_node); +} Property changes on: head/sys/sparc64/pci/ofw_pci.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/sys/sparc64/pci/ofw_pci.h =================================================================== --- head/sys/sparc64/pci/ofw_pci.h (revision 287725) +++ head/sys/sparc64/pci/ofw_pci.h (revision 287726) @@ -1,127 +1,170 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1998, 1999 Eduardo E. Horvath * Copyright (c) 2001, 2003 by Thomas Moestl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psychoreg.h,v 1.14 2008/05/30 02:29:37 mrg Exp * * $FreeBSD$ */ #ifndef _SPARC64_PCI_OFW_PCI_H_ #define _SPARC64_PCI_OFW_PCI_H_ +#include + #include #include "ofw_pci_if.h" typedef uint32_t ofw_pci_intr_t; /* PCI range child spaces. XXX: are these MI? */ #define OFW_PCI_CS_CONFIG 0x00 #define OFW_PCI_CS_IO 0x01 #define OFW_PCI_CS_MEM32 0x02 #define OFW_PCI_CS_MEM64 0x03 +#define OFW_PCI_NUM_CS 4 /* OFW device types */ #define OFW_TYPE_PCI "pci" #define OFW_TYPE_PCIE "pciex" struct ofw_pci_msi_addr_ranges { uint32_t addr32_hi; uint32_t addr32_lo; uint32_t addr32_sz; uint32_t addr64_hi; uint32_t addr64_lo; uint32_t addr64_sz; }; #define OFW_PCI_MSI_ADDR_RANGE_32(r) \ (((uint64_t)(r)->addr32_hi << 32) | (uint64_t)(r)->addr32_lo) #define OFW_PCI_MSI_ADDR_RANGE_64(r) \ (((uint64_t)(r)->addr64_hi << 32) | (uint64_t)(r)->addr64_lo) struct ofw_pci_msi_eq_to_devino { uint32_t eq_first; uint32_t eq_count; uint32_t devino_first; }; struct ofw_pci_msi_ranges { uint32_t first; uint32_t count; }; struct ofw_pci_ranges { uint32_t cspace; uint32_t child_hi; uint32_t child_lo; uint32_t phys_hi; uint32_t phys_lo; uint32_t size_hi; uint32_t size_lo; }; #define OFW_PCI_RANGE_CHILD(r) \ (((uint64_t)(r)->child_hi << 32) | (uint64_t)(r)->child_lo) #define OFW_PCI_RANGE_PHYS(r) \ (((uint64_t)(r)->phys_hi << 32) | (uint64_t)(r)->phys_lo) #define OFW_PCI_RANGE_SIZE(r) \ (((uint64_t)(r)->size_hi << 32) | (uint64_t)(r)->size_lo) #define OFW_PCI_RANGE_CS(r) (((r)->cspace >> 24) & 0x03) /* default values */ #define OFW_PCI_LATENCY 64 + +/* + * Common and generic parts of host-PCI-bridge support + */ + +struct ofw_pci_softc { + struct rman sc_pci_mem_rman; + struct rman sc_pci_io_rman; + + bus_space_handle_t sc_pci_bh[OFW_PCI_NUM_CS]; + bus_space_tag_t sc_pci_cfgt; + bus_space_tag_t sc_pci_iot; + bus_dma_tag_t sc_pci_dmat; + + struct ofw_bus_iinfo sc_pci_iinfo; + + phandle_t sc_node; + + uint8_t sc_pci_secbus; + uint8_t sc_pci_subbus; +}; + +int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize); +uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width); +void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width); +ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev, + int pin); + +void ofw_pci_dmamap_sync_stst_order_common(void); + +bus_activate_resource_t ofw_pci_activate_resource; +bus_adjust_resource_t ofw_pci_adjust_resource; +bus_alloc_resource_t ofw_pci_alloc_resource; +bus_get_dma_tag_t ofw_pci_get_dma_tag; +bus_read_ivar_t ofw_pci_read_ivar; + +ofw_bus_get_node_t ofw_pci_get_node; #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */ Index: head/sys/sparc64/pci/psycho.c =================================================================== --- head/sys/sparc64/pci/psycho.c (revision 287725) +++ head/sys/sparc64/pci/psycho.c (revision 287726) @@ -1,1313 +1,1070 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2001 - 2003 by Thomas Moestl * Copyright (c) 2005 - 2006 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp */ #include __FBSDID("$FreeBSD$"); /* * Support for `Hummingbird' (UltraSPARC IIe), `Psycho' and `Psycho+' * (UltraSPARC II) and `Sabre' (UltraSPARC IIi) UPA to PCI bridges. */ #include "opt_ofw_pci.h" #include "opt_psycho.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" static const struct psycho_desc *psycho_find_desc(const struct psycho_desc *, const char *); static const struct psycho_desc *psycho_get_desc(device_t); static void psycho_set_intr(struct psycho_softc *, u_int, bus_addr_t, driver_filter_t, driver_intr_t); static int psycho_find_intrmap(struct psycho_softc *, u_int, bus_addr_t *, bus_addr_t *, u_long *); static void sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op); static void psycho_intr_enable(void *); static void psycho_intr_disable(void *); static void psycho_intr_assign(void *); static void psycho_intr_clear(void *); /* Interrupt handlers */ static driver_filter_t psycho_ue; static driver_filter_t psycho_ce; static driver_filter_t psycho_pci_bus; static driver_filter_t psycho_powerdebug; static driver_intr_t psycho_powerdown; static driver_intr_t psycho_overtemp; #ifdef PSYCHO_MAP_WAKEUP static driver_filter_t psycho_wakeup; #endif /* IOMMU support */ static void psycho_iommu_init(struct psycho_softc *, int, uint32_t); /* * Methods */ static device_probe_t psycho_probe; static device_attach_t psycho_attach; -static bus_read_ivar_t psycho_read_ivar; static bus_setup_intr_t psycho_setup_intr; static bus_alloc_resource_t psycho_alloc_resource; -static bus_activate_resource_t psycho_activate_resource; -static bus_adjust_resource_t psycho_adjust_resource; -static bus_get_dma_tag_t psycho_get_dma_tag; static pcib_maxslots_t psycho_maxslots; static pcib_read_config_t psycho_read_config; static pcib_write_config_t psycho_write_config; static pcib_route_interrupt_t psycho_route_interrupt; -static ofw_bus_get_node_t psycho_get_node; static ofw_pci_setup_device_t psycho_setup_device; static device_method_t psycho_methods[] = { /* Device interface */ DEVMETHOD(device_probe, psycho_probe), DEVMETHOD(device_attach, psycho_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, psycho_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, psycho_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, psycho_alloc_resource), - DEVMETHOD(bus_activate_resource, psycho_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, psycho_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, psycho_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, psycho_maxslots), DEVMETHOD(pcib_read_config, psycho_read_config), DEVMETHOD(pcib_write_config, psycho_write_config), DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, psycho_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), /* ofw_pci interface */ DEVMETHOD(ofw_pci_setup_device, psycho_setup_device), DEVMETHOD_END }; static devclass_t psycho_devclass; DEFINE_CLASS_0(pcib, psycho_driver, psycho_methods, sizeof(struct psycho_softc)); EARLY_DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, NULL, NULL, BUS_PASS_BUS); static SYSCTL_NODE(_hw, OID_AUTO, psycho, CTLFLAG_RD, 0, "psycho parameters"); static u_int psycho_powerfail = 1; SYSCTL_UINT(_hw_psycho, OID_AUTO, powerfail, CTLFLAG_RDTUN, &psycho_powerfail, 0, "powerfail action (0: none, 1: shutdown (default), 2: debugger)"); static SLIST_HEAD(, psycho_softc) psycho_softcs = SLIST_HEAD_INITIALIZER(psycho_softcs); static const struct intr_controller psycho_ic = { psycho_intr_enable, psycho_intr_disable, psycho_intr_assign, psycho_intr_clear }; struct psycho_icarg { struct psycho_softc *pica_sc; bus_addr_t pica_map; bus_addr_t pica_clr; }; #define PSYCHO_READ8(sc, off) \ bus_read_8((sc)->sc_mem_res, (off)) #define PSYCHO_WRITE8(sc, off, v) \ bus_write_8((sc)->sc_mem_res, (off), (v)) #define PCICTL_READ8(sc, off) \ PSYCHO_READ8((sc), (sc)->sc_pcictl + (off)) #define PCICTL_WRITE8(sc, off, v) \ PSYCHO_WRITE8((sc), (sc)->sc_pcictl + (off), (v)) /* * "Sabre" is the UltraSPARC IIi onboard UPA to PCI bridge. It manages a * single PCI bus and does not have a streaming buffer. It often has an APB * (advanced PCI bridge) connected to it, which was designed specifically for * the IIi. The APB lets the IIi handle two independent PCI buses, and * appears as two "Simba"'s underneath the Sabre. * * "Hummingbird" is the UltraSPARC IIe onboard UPA to PCI bridge. It's * basically the same as Sabre but without an APB underneath it. * * "Psycho" and "Psycho+" are dual UPA to PCI bridges. They sit on the UPA * bus and manage two PCI buses. "Psycho" has two 64-bit 33MHz buses, while * "Psycho+" controls both a 64-bit 33Mhz and a 64-bit 66Mhz PCI bus. You * will usually find a "Psycho+" since I don't think the original "Psycho" * ever shipped, and if it did it would be in the U30. * * Each "Psycho" PCI bus appears as a separate OFW node, but since they are * both part of the same IC, they only have a single register space. As such, * they need to be configured together, even though the autoconfiguration will * attach them separately. * * On UltraIIi machines, "Sabre" itself usually takes pci0, with "Simba" often * as pci1 and pci2, although they have been implemented with other PCI bus * numbers on some machines. * * On UltraII machines, there can be any number of "Psycho+" ICs, each * providing two PCI buses. */ struct psycho_desc { const char *pd_string; int pd_mode; const char *pd_name; }; static const struct psycho_desc psycho_compats[] = { { "pci108e,8000", PSYCHO_MODE_PSYCHO, "Psycho compatible" }, { "pci108e,a000", PSYCHO_MODE_SABRE, "Sabre compatible" }, { "pci108e,a001", PSYCHO_MODE_SABRE, "Hummingbird compatible" }, { NULL, 0, NULL } }; static const struct psycho_desc psycho_models[] = { { "SUNW,psycho", PSYCHO_MODE_PSYCHO, "Psycho" }, { "SUNW,sabre", PSYCHO_MODE_SABRE, "Sabre" }, { NULL, 0, NULL } }; static const struct psycho_desc * psycho_find_desc(const struct psycho_desc *table, const char *string) { const struct psycho_desc *desc; if (string == NULL) return (NULL); for (desc = table; desc->pd_string != NULL; desc++) if (strcmp(desc->pd_string, string) == 0) return (desc); return (NULL); } static const struct psycho_desc * psycho_get_desc(device_t dev) { const struct psycho_desc *rv; rv = psycho_find_desc(psycho_models, ofw_bus_get_model(dev)); if (rv == NULL) rv = psycho_find_desc(psycho_compats, ofw_bus_get_compat(dev)); return (rv); } static int psycho_probe(device_t dev) { const char *dtype; dtype = ofw_bus_get_type(dev); if (dtype != NULL && strcmp(dtype, OFW_TYPE_PCI) == 0 && psycho_get_desc(dev) != NULL) { device_set_desc(dev, "U2P UPA-PCI bridge"); return (0); } return (ENXIO); } static int psycho_attach(device_t dev) { struct psycho_icarg *pica; struct psycho_softc *asc, *sc, *osc; - struct ofw_pci_ranges *range; const struct psycho_desc *desc; bus_addr_t intrclr, intrmap; + bus_dma_tag_t dmat; uint64_t csr, dr; phandle_t node; - uint32_t dvmabase, prop, prop_array[2]; + uint32_t dvmabase, prop; u_int rerun, ver; int i, j; node = ofw_bus_get_node(dev); sc = device_get_softc(dev); desc = psycho_get_desc(dev); - sc->sc_node = node; sc->sc_dev = dev; sc->sc_mode = desc->pd_mode; /* * The Psycho gets three register banks: * (0) per-PBM configuration and status registers * (1) per-PBM PCI configuration space, containing only the * PBM 256-byte PCI header * (2) the shared Psycho configuration registers */ if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { i = 2; sc->sc_pcictl = bus_get_resource_start(dev, SYS_RES_MEMORY, 0) - bus_get_resource_start(dev, SYS_RES_MEMORY, 2); switch (sc->sc_pcictl) { case PSR_PCICTL0: sc->sc_half = 0; break; case PSR_PCICTL1: sc->sc_half = 1; break; default: panic("%s: bogus PCI control register location", __func__); /* NOTREACHED */ } } else { i = 0; sc->sc_pcictl = PSR_PCICTL0; sc->sc_half = 0; } sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, (sc->sc_mode == PSYCHO_MODE_PSYCHO ? RF_SHAREABLE : 0) | RF_ACTIVE); if (sc->sc_mem_res == NULL) panic("%s: could not allocate registers", __func__); /* * Match other Psychos that are already configured against * the base physical address. This will be the same for a * pair of devices that share register space. */ osc = NULL; SLIST_FOREACH(asc, &psycho_softcs, sc_link) { if (rman_get_start(asc->sc_mem_res) == rman_get_start(sc->sc_mem_res)) { /* Found partner. */ osc = asc; break; } } if (osc == NULL) { sc->sc_mtx = malloc(sizeof(*sc->sc_mtx), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_mtx == NULL) panic("%s: could not malloc mutex", __func__); mtx_init(sc->sc_mtx, "pcib_mtx", NULL, MTX_SPIN); } else { if (sc->sc_mode != PSYCHO_MODE_PSYCHO) panic("%s: no partner expected", __func__); if (mtx_initialized(osc->sc_mtx) == 0) panic("%s: mutex not initialized", __func__); sc->sc_mtx = osc->sc_mtx; } + SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link); csr = PSYCHO_READ8(sc, PSR_CS); ver = PSYCHO_GCSR_VERS(csr); sc->sc_ign = 0x1f; /* Hummingbird/Sabre IGN is always 0x1f. */ if (sc->sc_mode == PSYCHO_MODE_PSYCHO) sc->sc_ign = PSYCHO_GCSR_IGN(csr); if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1) prop = 33000000; device_printf(dev, "%s, impl %d, version %d, IGN %#x, bus %c, %dMHz\n", desc->pd_name, (u_int)PSYCHO_GCSR_IMPL(csr), ver, sc->sc_ign, 'A' + sc->sc_half, prop / 1000 / 1000); /* Set up the PCI control and PCI diagnostic registers. */ csr = PCICTL_READ8(sc, PCR_CS); csr &= ~PCICTL_ARB_PARK; if (OF_getproplen(node, "no-bus-parking") < 0) csr |= PCICTL_ARB_PARK; /* Workarounds for version specific bugs. */ dr = PCICTL_READ8(sc, PCR_DIAG); switch (ver) { case 0: dr |= DIAG_RTRY_DIS; dr &= ~DIAG_DWSYNC_DIS; rerun = 0; break; case 1: csr &= ~PCICTL_ARB_PARK; dr |= DIAG_RTRY_DIS | DIAG_DWSYNC_DIS; rerun = 0; break; default: dr |= DIAG_DWSYNC_DIS; dr &= ~DIAG_RTRY_DIS; rerun = 1; break; } csr |= PCICTL_ERRINTEN | PCICTL_ARB_4; csr &= ~(PCICTL_SBHINTEN | PCICTL_WAKEUPEN); #ifdef PSYCHO_DEBUG device_printf(dev, "PCI CSR 0x%016llx -> 0x%016llx\n", (unsigned long long)PCICTL_READ8(sc, PCR_CS), (unsigned long long)csr); #endif PCICTL_WRITE8(sc, PCR_CS, csr); dr &= ~DIAG_ISYNC_DIS; #ifdef PSYCHO_DEBUG device_printf(dev, "PCI DR 0x%016llx -> 0x%016llx\n", (unsigned long long)PCICTL_READ8(sc, PCR_DIAG), (unsigned long long)dr); #endif PCICTL_WRITE8(sc, PCR_DIAG, dr); if (sc->sc_mode == PSYCHO_MODE_SABRE) { /* Use the PROM preset for now. */ csr = PCICTL_READ8(sc, PCR_TAS); if (csr == 0) panic("%s: Hummingbird/Sabre TAS not initialized.", __func__); dvmabase = (ffs(csr) - 1) << PCITAS_ADDR_SHIFT; } else dvmabase = -1; - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Psycho PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, PSYCHO_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Psycho PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, PSYCHO_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != PSYCHO_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < PSYCHO_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Register the softc, this is needed for paired Psychos. */ - SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link); - - /* * If we're a Hummingbird/Sabre or the first of a pair of Psychos * to arrive here, do the interrupt setup and start up the IOMMU. */ if (osc == NULL) { /* * Hunt through all the interrupt mapping regs and register * our interrupt controller for the corresponding interrupt * vectors. We do this early in order to be able to catch * stray interrupts. */ for (i = 0; i <= PSYCHO_MAX_INO; i++) { if (psycho_find_intrmap(sc, i, &intrmap, &intrclr, NULL) == 0) continue; pica = malloc(sizeof(*pica), M_DEVBUF, M_NOWAIT); if (pica == NULL) panic("%s: could not allocate interrupt " "controller argument", __func__); pica->pica_sc = sc; pica->pica_map = intrmap; pica->pica_clr = intrclr; #ifdef PSYCHO_DEBUG /* * Enable all interrupts and clear all interrupt * states. This aids the debugging of interrupt * routing problems. */ device_printf(dev, "intr map (INO %d, %s) %#lx: %#lx, clr: %#lx\n", i, intrmap <= PSR_PCIB3_INT_MAP ? "PCI" : "OBIO", (u_long)intrmap, (u_long)PSYCHO_READ8(sc, intrmap), (u_long)intrclr); PSYCHO_WRITE8(sc, intrmap, INTMAP_VEC(sc->sc_ign, i)); PSYCHO_WRITE8(sc, intrclr, INTCLR_IDLE); PSYCHO_WRITE8(sc, intrmap, INTMAP_ENABLE(INTMAP_VEC(sc->sc_ign, i), PCPU_GET(mid))); #endif j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), &psycho_ic, pica); if (j != 0) device_printf(dev, "could not register " "interrupt controller for INO %d (%d)\n", i, j); } if (sc->sc_mode == PSYCHO_MODE_PSYCHO) sparc64_counter_init(device_get_nameunit(dev), rman_get_bustag(sc->sc_mem_res), rman_get_bushandle(sc->sc_mem_res), PSR_TC0); /* * Set up IOMMU and PCI configuration if we're the first * of a pair of Psychos to arrive here or a Hummingbird * or Sabre. * * We should calculate a TSB size based on amount of RAM * and number of bus controllers and number and type of * child devices. * * For the moment, 32KB should be more than enough. */ sc->sc_is = malloc(sizeof(*sc->sc_is), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_is == NULL) panic("%s: could not malloc IOMMU state", __func__); sc->sc_is->is_flags = IOMMU_PRESERVE_PROM; if (sc->sc_mode == PSYCHO_MODE_SABRE) { sc->sc_dma_methods = malloc(sizeof(*sc->sc_dma_methods), M_DEVBUF, M_NOWAIT); if (sc->sc_dma_methods == NULL) panic("%s: could not malloc DMA methods", __func__); memcpy(sc->sc_dma_methods, &iommu_dma_methods, sizeof(*sc->sc_dma_methods)); sc->sc_dma_methods->dm_dmamap_sync = sabre_dmamap_sync; sc->sc_is->is_pmaxaddr = IOMMU_MAXADDR(SABRE_IOMMU_BITS); } else { sc->sc_dma_methods = &iommu_dma_methods; sc->sc_is->is_pmaxaddr = IOMMU_MAXADDR(PSYCHO_IOMMU_BITS); } sc->sc_is->is_sb[0] = sc->sc_is->is_sb[1] = 0; if (OF_getproplen(node, "no-streaming-cache") < 0) sc->sc_is->is_sb[0] = sc->sc_pcictl + PCR_STRBUF; sc->sc_is->is_flags |= (rerun != 1) ? IOMMU_RERUN_DISABLE : 0; psycho_iommu_init(sc, 3, dvmabase); } else { /* Just copy IOMMU state, config tag and address. */ sc->sc_dma_methods = &iommu_dma_methods; sc->sc_is = osc->sc_is; if (OF_getproplen(node, "no-streaming-cache") < 0) sc->sc_is->is_sb[1] = sc->sc_pcictl + PCR_STRBUF; iommu_reset(sc->sc_is); } - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is->is_pmaxaddr, ~0, NULL, NULL, sc->sc_is->is_pmaxaddr, - 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = sc->sc_is; - sc->sc_pci_dmat->dt_mt = sc->sc_dma_methods; + dmat->dt_cookie = sc->sc_is; + dmat->dt_mt = sc->sc_dma_methods; - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + if (ofw_pci_attach_common(dev, dmat, PSYCHO_IO_SIZE, + PSYCHO_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); /* Clear any pending PCI error bits. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, - PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus, + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, + PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_STATUS, 2), 2); PCICTL_WRITE8(sc, PCR_CS, PCICTL_READ8(sc, PCR_CS)); PCICTL_WRITE8(sc, PCR_AFS, PCICTL_READ8(sc, PCR_AFS)); if (osc == NULL) { /* * Establish handlers for interesting interrupts... * * XXX We need to remember these and remove this to support * hotplug on the UPA/FHC bus. * * XXX Not all controllers have these, but installing them * is better than trying to sort through this mess. */ psycho_set_intr(sc, 1, PSR_UE_INT_MAP, psycho_ue, NULL); psycho_set_intr(sc, 2, PSR_CE_INT_MAP, psycho_ce, NULL); switch (psycho_powerfail) { case 0: break; case 2: psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, psycho_powerdebug, NULL); break; default: psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, NULL, psycho_powerdown); break; } if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { /* * Hummingbirds/Sabres do not have the following two * interrupts. */ /* * The spare hardware interrupt is used for the * over-temperature interrupt. */ psycho_set_intr(sc, 4, PSR_SPARE_INT_MAP, NULL, psycho_overtemp); #ifdef PSYCHO_MAP_WAKEUP /* * psycho_wakeup() doesn't do anything useful right * now. */ psycho_set_intr(sc, 5, PSR_PWRMGT_INT_MAP, psycho_wakeup, NULL); #endif /* PSYCHO_MAP_WAKEUP */ } } /* * Register a PCI bus error interrupt handler according to which * half this is. Hummingbird/Sabre don't have a PCI bus B error * interrupt but they are also only used for PCI bus A. */ psycho_set_intr(sc, 0, sc->sc_half == 0 ? PSR_PCIAERR_INT_MAP : PSR_PCIBERR_INT_MAP, psycho_pci_bus, NULL); /* * Set the latency timer register as this isn't always done by the * firmware. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_LATTIMER, OFW_PCI_LATENCY, 1); for (i = PCIR_VENDOR; i < PCIR_STATUS; i += sizeof(uint16_t)) - le16enc(&sc->sc_pci_hpbcfg[i], bus_space_read_2( - sc->sc_pci_cfgt, sc->sc_pci_bh[OFW_PCI_CS_CONFIG], - PSYCHO_CONF_OFF(sc->sc_pci_secbus, PCS_DEVICE, + le16enc(&sc->sc_pci_hpbcfg[i], + bus_space_read_2(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], + PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i))); for (i = PCIR_REVID; i <= PCIR_BIST; i += sizeof(uint8_t)) - sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_pci_cfgt, - sc->sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF( - sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i)); + sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF( + sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i)); - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); /* * On E250 the interrupt map entry for the EBus bridge is wrong, * causing incorrect interrupts to be assigned to some devices on * the EBus. Work around it by changing our copy of the interrupt * map mask to perform a full comparison of the INO. That way * the interrupt map entry for the EBus bridge won't match at all * and the INOs specified in the "interrupts" properties of the * EBus devices will be used directly instead. */ if (strcmp(sparc64_model, "SUNW,Ultra-250") == 0 && - sc->sc_pci_iinfo.opi_imapmsk != NULL) - *(ofw_pci_intr_t *)(&sc->sc_pci_iinfo.opi_imapmsk[ - sc->sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK; + sc->sc_ops.sc_pci_iinfo.opi_imapmsk != NULL) + *(ofw_pci_intr_t *)(&sc->sc_ops.sc_pci_iinfo.opi_imapmsk[ + sc->sc_ops.sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK; device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static void psycho_set_intr(struct psycho_softc *sc, u_int index, bus_addr_t intrmap, driver_filter_t filt, driver_intr_t intr) { u_long vec; int rid; rid = index; sc->sc_irq_res[index] = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res[index] == NULL && intrmap >= PSR_POWER_INT_MAP) { /* * These interrupts aren't mandatory and not available * with all controllers (not even Psychos). */ return; } if (sc->sc_irq_res[index] == NULL || INTIGN(vec = rman_get_start(sc->sc_irq_res[index])) != sc->sc_ign || INTVEC(PSYCHO_READ8(sc, intrmap)) != vec || intr_vectors[vec].iv_ic != &psycho_ic || bus_setup_intr(sc->sc_dev, sc->sc_irq_res[index], INTR_TYPE_MISC | INTR_BRIDGE, filt, intr, sc, &sc->sc_ihand[index]) != 0) panic("%s: failed to set up interrupt %d", __func__, index); } static int psycho_find_intrmap(struct psycho_softc *sc, u_int ino, bus_addr_t *intrmapptr, bus_addr_t *intrclrptr, bus_addr_t *intrdiagptr) { bus_addr_t intrclr, intrmap; uint64_t diag; int found; /* * XXX we only compare INOs rather than INRs since the firmware may * not provide the IGN and the IGN is constant for all devices on * that PCI controller. * This could cause problems for the FFB/external interrupt which * has a full vector that can be set arbitrarily. */ if (ino > PSYCHO_MAX_INO) { device_printf(sc->sc_dev, "out of range INO %d requested\n", ino); return (0); } found = 0; /* Hunt through OBIO first. */ diag = PSYCHO_READ8(sc, PSR_OBIO_INT_DIAG); for (intrmap = PSR_SCSI_INT_MAP, intrclr = PSR_SCSI_INT_CLR; intrmap <= PSR_PWRMGT_INT_MAP; intrmap += 8, intrclr += 8, diag >>= 2) { if (sc->sc_mode == PSYCHO_MODE_SABRE && (intrmap == PSR_TIMER0_INT_MAP || intrmap == PSR_TIMER1_INT_MAP || intrmap == PSR_PCIBERR_INT_MAP || intrmap == PSR_PWRMGT_INT_MAP)) continue; if (INTINO(PSYCHO_READ8(sc, intrmap)) == ino) { diag &= 2; found = 1; break; } } if (!found) { diag = PSYCHO_READ8(sc, PSR_PCI_INT_DIAG); /* Now do PCI interrupts. */ for (intrmap = PSR_PCIA0_INT_MAP, intrclr = PSR_PCIA0_INT_CLR; intrmap <= PSR_PCIB3_INT_MAP; intrmap += 8, intrclr += 32, diag >>= 8) { if (sc->sc_mode == PSYCHO_MODE_PSYCHO && (intrmap == PSR_PCIA2_INT_MAP || intrmap == PSR_PCIA3_INT_MAP)) continue; if (((PSYCHO_READ8(sc, intrmap) ^ ino) & 0x3c) == 0) { intrclr += 8 * (ino & 3); diag = (diag >> ((ino & 3) * 2)) & 2; found = 1; break; } } } if (intrmapptr != NULL) *intrmapptr = intrmap; if (intrclrptr != NULL) *intrclrptr = intrclr; if (intrdiagptr != NULL) *intrdiagptr = diag; return (found); } /* * Interrupt handlers */ static int psycho_ue(void *arg) { struct psycho_softc *sc = arg; uint64_t afar, afsr; afar = PSYCHO_READ8(sc, PSR_UE_AFA); afsr = PSYCHO_READ8(sc, PSR_UE_AFS); /* * On the UltraSPARC-IIi/IIe, IOMMU misses/protection faults cause * the AFAR to be set to the physical address of the TTE entry that * was invalid/write protected. Call into the IOMMU code to have * them decoded to virtual I/O addresses. */ if ((afsr & UEAFSR_P_DTE) != 0) iommu_decode_fault(sc->sc_is, afar); panic("%s: uncorrectable DMA error AFAR %#lx AFSR %#lx", device_get_nameunit(sc->sc_dev), (u_long)afar, (u_long)afsr); return (FILTER_HANDLED); } static int psycho_ce(void *arg) { struct psycho_softc *sc = arg; uint64_t afar, afsr; mtx_lock_spin(sc->sc_mtx); afar = PSYCHO_READ8(sc, PSR_CE_AFA); afsr = PSYCHO_READ8(sc, PSR_CE_AFS); device_printf(sc->sc_dev, "correctable DMA error AFAR %#lx " "AFSR %#lx\n", (u_long)afar, (u_long)afsr); /* Clear the error bits that we caught. */ PSYCHO_WRITE8(sc, PSR_CE_AFS, afsr); mtx_unlock_spin(sc->sc_mtx); return (FILTER_HANDLED); } static int psycho_pci_bus(void *arg) { struct psycho_softc *sc = arg; uint64_t afar, afsr; afar = PCICTL_READ8(sc, PCR_AFA); afsr = PCICTL_READ8(sc, PCR_AFS); panic("%s: PCI bus %c error AFAR %#lx AFSR %#lx", device_get_nameunit(sc->sc_dev), 'A' + sc->sc_half, (u_long)afar, (u_long)afsr); return (FILTER_HANDLED); } static int psycho_powerdebug(void *arg __unused) { kdb_enter(KDB_WHY_POWERFAIL, "powerfail"); return (FILTER_HANDLED); } static void psycho_powerdown(void *arg __unused) { static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) return; shutdown++; printf("Power Failure Detected: Shutting down NOW.\n"); shutdown_nice(RB_POWEROFF); } static void psycho_overtemp(void *arg __unused) { static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) return; shutdown++; printf("DANGER: OVER TEMPERATURE detected.\nShutting down NOW.\n"); shutdown_nice(RB_POWEROFF); } #ifdef PSYCHO_MAP_WAKEUP static int psycho_wakeup(void *arg) { struct psycho_softc *sc = arg; /* We don't really have a framework to deal with this properly. */ device_printf(sc->sc_dev, "power management wakeup\n"); return (FILTER_HANDLED); } #endif /* PSYCHO_MAP_WAKEUP */ static void psycho_iommu_init(struct psycho_softc *sc, int tsbsize, uint32_t dvmabase) { struct iommu_state *is = sc->sc_is; /* Punch in our copies. */ is->is_bustag = rman_get_bustag(sc->sc_mem_res); is->is_bushandle = rman_get_bushandle(sc->sc_mem_res); is->is_iommu = PSR_IOMMU; is->is_dtag = PSR_IOMMU_TLB_TAG_DIAG; is->is_ddram = PSR_IOMMU_TLB_DATA_DIAG; is->is_dqueue = PSR_IOMMU_QUEUE_DIAG; is->is_dva = PSR_IOMMU_SVADIAG; is->is_dtcmp = PSR_IOMMU_TLB_CMP_DIAG; iommu_init(device_get_nameunit(sc->sc_dev), is, tsbsize, dvmabase, 0); } static int psycho_maxslots(device_t dev) { /* XXX: is this correct? */ return (PCI_SLOTMAX); } static uint32_t psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { struct psycho_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint8_t byte; - uint16_t shrt; - uint32_t r, wrd; - int i; sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return (-1); - - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - /* * The Hummingbird and Sabre bridges are picky in that they * only allow their config space to be accessed using the * "native" width of the respective register being accessed * and return semi-random other content of their config space * otherwise. Given that the PCI specs don't say anything * about such a (unusual) limitation and lots of stuff expects * to be able to access the contents of the config space at * any width we allow just that. We do this by using a copy * of the header of the bridge (the rest is all zero anyway) * read during attach (expect for PCIR_STATUS) in order to * simplify things. * The Psycho bridges contain a dupe of their header at 0x80 * which we nullify that way also. */ - if (bus == sc->sc_pci_secbus && slot == PCS_DEVICE && + if (bus == sc->sc_ops.sc_pci_secbus && slot == PCS_DEVICE && func == PCS_FUNC) { - if (offset % width != 0) + if (reg % width != 0) return (-1); if (reg >= sizeof(sc->sc_pci_hpbcfg)) return (0); if ((reg < PCIR_STATUS && reg + width > PCIR_STATUS) || reg == PCIR_STATUS || reg == PCIR_STATUS + 1) le16enc(&sc->sc_pci_hpbcfg[PCIR_STATUS], - bus_space_read_2(sc->sc_pci_cfgt, bh, - PSYCHO_CONF_OFF(sc->sc_pci_secbus, + bus_space_read_2(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], + PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_STATUS))); switch (width) { case 1: return (sc->sc_pci_hpbcfg[reg]); case 2: return (le16dec(&sc->sc_pci_hpbcfg[reg])); case 4: return (le32dec(&sc->sc_pci_hpbcfg[reg])); } } - offset = PSYCHO_CONF_OFF(bus, slot, func, reg); - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - - if (i) { -#ifdef PSYCHO_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCI_REGMAX, + PSYCHO_CONF_OFF(bus, slot, func, reg), bus, slot, func, reg, + width)); } static void psycho_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct psycho_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return; - - offset = PSYCHO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCI_REGMAX, PSYCHO_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, val, width); } static int psycho_route_interrupt(device_t bridge, device_t dev, int pin) { struct psycho_softc *sc; - struct ofw_pci_register reg; bus_addr_t intrmap; - ofw_pci_intr_t pintr, mintr; + ofw_pci_intr_t mintr; - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL)) + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (PCI_INTERRUPT_VALID(mintr)) return (mintr); /* * If this is outside of the range for an intpin, it's likely a full * INO, and no mapping is required at all; this happens on the U30, * where there's no interrupt map at the Psycho node. Fortunately, * there seem to be no INOs in the intpin range on this boxen, so * this easy heuristics will do. */ if (pin > 4) return (pin); /* * Guess the INO; we always assume that this is a non-OBIO * device, and that pin is a "real" intpin number. Determine * the mapping register to be used by the slot number. * We only need to do this on E450s, it seems; here, the slot numbers * for bus A are one-based, while those for bus B seemingly have an * offset of 2 (hence the factor of 3 below). */ + sc = device_get_softc(dev); intrmap = PSR_PCIA0_INT_MAP + 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half); mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1; device_printf(bridge, "guessing interrupt %d for device %d.%d pin %d\n", (int)mintr, pci_get_slot(dev), pci_get_function(dev), pin); return (mintr); } -static int -psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct psycho_softc *sc; - - sc = device_get_softc(dev); - switch (which) { - case PCIB_IVAR_DOMAIN: - *result = device_get_unit(dev); - return (0); - case PCIB_IVAR_BUS: - *result = sc->sc_pci_secbus; - return (0); - } - return (ENOENT); -} - static void sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) { struct iommu_state *is = dt->dt_cookie; if ((map->dm_flags & DMF_LOADED) == 0) return; if ((op & BUS_DMASYNC_POSTREAD) != 0) (void)bus_space_read_8(is->is_bustag, is->is_bushandle, PSR_DMA_WRITE_SYNC); if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); } static void psycho_intr_enable(void *arg) { struct intr_vector *iv = arg; struct psycho_icarg *pica = iv->iv_icarg; PSYCHO_WRITE8(pica->pica_sc, pica->pica_map, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); } static void psycho_intr_disable(void *arg) { struct intr_vector *iv = arg; struct psycho_icarg *pica = iv->iv_icarg; PSYCHO_WRITE8(pica->pica_sc, pica->pica_map, iv->iv_vec); } static void psycho_intr_assign(void *arg) { struct intr_vector *iv = arg; struct psycho_icarg *pica = iv->iv_icarg; PSYCHO_WRITE8(pica->pica_sc, pica->pica_map, INTMAP_TID( PSYCHO_READ8(pica->pica_sc, pica->pica_map), iv->iv_mid)); } static void psycho_intr_clear(void *arg) { struct intr_vector *iv = arg; struct psycho_icarg *pica = iv->iv_icarg; PSYCHO_WRITE8(pica->pica_sc, pica->pica_clr, INTCLR_IDLE); } static int psycho_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { struct psycho_softc *sc; u_long vec; sc = device_get_softc(dev); /* * Make sure the vector is fully specified and we registered * our interrupt controller for it. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &psycho_ic) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } static struct resource * psycho_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct psycho_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); + if (type == SYS_RES_IRQ) { + sc = device_get_softc(bus); start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -psycho_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct psycho_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -psycho_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct psycho_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); - } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -psycho_get_dma_tag(device_t bus, device_t child __unused) -{ - struct psycho_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -psycho_get_node(device_t bus, device_t child __unused) -{ - struct psycho_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static void psycho_setup_device(device_t bus, device_t child) { struct psycho_softc *sc; uint32_t rev; sc = device_get_softc(bus); /* * Revision 0 EBus bridges have a bug which prevents them from * working when bus parking is enabled. */ if ((strcmp(ofw_bus_get_name(child), "ebus") == 0 || strcmp(ofw_bus_get_name(child), "pci108e,1000") == 0) && OF_getprop(ofw_bus_get_node(child), "revision-id", &rev, sizeof(rev)) > 0 && rev == 0) PCICTL_WRITE8(sc, PCR_CS, PCICTL_READ8(sc, PCR_CS) & ~PCICTL_ARB_PARK); } Index: head/sys/sparc64/pci/psychoreg.h =================================================================== --- head/sys/sparc64/pci/psychoreg.h (revision 287725) +++ head/sys/sparc64/pci/psychoreg.h (revision 287726) @@ -1,328 +1,328 @@ /*- * Copyright (c) 1999 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1998, 1999 Eduardo E. Horvath * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psychoreg.h,v 1.14 2008/05/30 02:29:37 mrg Exp * * $FreeBSD$ */ #ifndef _SPARC64_PCI_PSYCHOREG_H_ #define _SPARC64_PCI_PSYCHOREG_H_ /* * Sun4u PCI definitions. Here's where we deal w/the machine * dependencies of Psycho and the PCI controller on the UltraIIi. * * All PCI registers are bit-swapped, however they are not byte-swapped. * This means that they must be accessed using little-endian access modes, * either map the pages little-endian or use little-endian ASIs. * * PSYCHO implements two PCI buses, A and B. */ #define PSYCHO_NINTR 6 -#define PSYCHO_NRANGE 4 /* * Psycho register offsets * * NB: FFB0 and FFB1 intr map regs also appear at 0x6000 and 0x8000 * respectively. */ #define PSR_UPA_PORTID 0x0000 /* UPA port ID register */ #define PSR_UPA_CONFIG 0x0008 /* UPA config register */ #define PSR_CS 0x0010 /* PSYCHO control/status register */ #define PSR_ECCC 0x0020 /* ECC control register */ #define PSR_UE_AFS 0x0030 /* Uncorrectable Error AFSR */ #define PSR_UE_AFA 0x0038 /* Uncorrectable Error AFAR */ #define PSR_CE_AFS 0x0040 /* Correctable Error AFSR */ #define PSR_CE_AFA 0x0048 /* Correctable Error AFAR */ #define PSR_PM_CTL 0x0100 /* Performance monitor control reg */ #define PSR_PM_COUNT 0x0108 /* Performance monitor counter reg */ #define PSR_IOMMU 0x0200 /* IOMMU registers */ #define PSR_PCIA0_INT_MAP 0x0c00 /* PCI bus a slot 0 irq map reg */ #define PSR_PCIA1_INT_MAP 0x0c08 /* PCI bus a slot 1 irq map reg */ #define PSR_PCIA2_INT_MAP 0x0c10 /* PCI bus a slot 2 irq map reg (IIi) */ #define PSR_PCIA3_INT_MAP 0x0c18 /* PCI bus a slot 3 irq map reg (IIi) */ #define PSR_PCIB0_INT_MAP 0x0c20 /* PCI bus b slot 0 irq map reg */ #define PSR_PCIB1_INT_MAP 0x0c28 /* PCI bus b slot 1 irq map reg */ #define PSR_PCIB2_INT_MAP 0x0c30 /* PCI bus b slot 2 irq map reg */ #define PSR_PCIB3_INT_MAP 0x0c38 /* PCI bus b slot 3 irq map reg */ #define PSR_SCSI_INT_MAP 0x1000 /* SCSI interrupt map reg */ #define PSR_ETHER_INT_MAP 0x1008 /* ethernet interrupt map reg */ #define PSR_BPP_INT_MAP 0x1010 /* parallel interrupt map reg */ #define PSR_AUDIOR_INT_MAP 0x1018 /* audio record interrupt map reg */ #define PSR_AUDIOP_INT_MAP 0x1020 /* audio playback interrupt map reg */ #define PSR_POWER_INT_MAP 0x1028 /* power fail interrupt map reg */ #define PSR_SKBDMS_INT_MAP 0x1030 /* serial/kbd/mouse interrupt map reg */ #define PSR_FD_INT_MAP 0x1038 /* floppy interrupt map reg */ #define PSR_SPARE_INT_MAP 0x1040 /* spare interrupt map reg */ #define PSR_KBD_INT_MAP 0x1048 /* kbd [unused] interrupt map reg */ #define PSR_MOUSE_INT_MAP 0x1050 /* mouse [unused] interrupt map reg */ #define PSR_SERIAL_INT_MAP 0x1058 /* second serial interrupt map reg */ #define PSR_TIMER0_INT_MAP 0x1060 /* timer 0 interrupt map reg */ #define PSR_TIMER1_INT_MAP 0x1068 /* timer 1 interrupt map reg */ #define PSR_UE_INT_MAP 0x1070 /* UE interrupt map reg */ #define PSR_CE_INT_MAP 0x1078 /* CE interrupt map reg */ #define PSR_PCIAERR_INT_MAP 0x1080 /* PCI bus a error interrupt map reg */ #define PSR_PCIBERR_INT_MAP 0x1088 /* PCI bus b error interrupt map reg */ #define PSR_PWRMGT_INT_MAP 0x1090 /* power mgmt wake interrupt map reg */ #define PSR_FFB0_INT_MAP 0x1098 /* FFB0 graphics interrupt map reg */ #define PSR_FFB1_INT_MAP 0x10a0 /* FFB1 graphics interrupt map reg */ -/* Note: clear interrupt 0 registers are not really used */ +/* Note: Clear interrupt 0 registers are not really used. */ #define PSR_PCIA0_INT_CLR 0x1400 /* PCI a slot 0 clear int regs 0..3 */ #define PSR_PCIA1_INT_CLR 0x1420 /* PCI a slot 1 clear int regs 0..3 */ #define PSR_PCIA2_INT_CLR 0x1440 /* PCI a slot 2 clear int regs 0..3 */ #define PSR_PCIA3_INT_CLR 0x1460 /* PCI a slot 3 clear int regs 0..3 */ #define PSR_PCIB0_INT_CLR 0x1480 /* PCI b slot 0 clear int regs 0..3 */ #define PSR_PCIB1_INT_CLR 0x14a0 /* PCI b slot 1 clear int regs 0..3 */ #define PSR_PCIB2_INT_CLR 0x14c0 /* PCI b slot 2 clear int regs 0..3 */ #define PSR_PCIB3_INT_CLR 0x14d0 /* PCI b slot 3 clear int regs 0..3 */ #define PSR_SCSI_INT_CLR 0x1800 /* SCSI clear int reg */ #define PSR_ETHER_INT_CLR 0x1808 /* ethernet clear int reg */ #define PSR_BPP_INT_CLR 0x1810 /* parallel clear int reg */ #define PSR_AUDIOR_INT_CLR 0x1818 /* audio record clear int reg */ #define PSR_AUDIOP_INT_CLR 0x1820 /* audio playback clear int reg */ #define PSR_POWER_INT_CLR 0x1828 /* power fail clear int reg */ #define PSR_SKBDMS_INT_CLR 0x1830 /* serial/kbd/mouse clear int reg */ #define PSR_FD_INT_CLR 0x1838 /* floppy clear int reg */ #define PSR_SPARE_INT_CLR 0x1840 /* spare clear int reg */ #define PSR_KBD_INT_CLR 0x1848 /* kbd [unused] clear int reg */ #define PSR_MOUSE_INT_CLR 0x1850 /* mouse [unused] clear int reg */ #define PSR_SERIAL_INT_CLR 0x1858 /* second serial clear int reg */ #define PSR_TIMER0_INT_CLR 0x1860 /* timer 0 clear int reg */ #define PSR_TIMER1_INT_CLR 0x1868 /* timer 1 clear int reg */ #define PSR_UE_INT_CLR 0x1870 /* UE clear int reg */ #define PSR_CE_INT_CLR 0x1878 /* CE clear int reg */ #define PSR_PCIAERR_INT_CLR 0x1880 /* PCI bus a error clear int reg */ #define PSR_PCIBERR_INT_CLR 0x1888 /* PCI bus b error clear int reg */ #define PSR_PWRMGT_INT_CLR 0x1890 /* power mgmt wake clr interrupt reg */ #define PSR_INTR_RETRY_TIM 0x1a00 /* interrupt retry timer */ #define PSR_TC0 0x1c00 /* timer/counter 0 */ #define PSR_TC1 0x1c10 /* timer/counter 1 */ #define PSR_DMA_WRITE_SYNC 0x1c20 /* PCI DMA write sync register (IIi) */ #define PSR_PCICTL0 0x2000 /* PCICTL registers for 1st Psycho */ #define PSR_PCICTL1 0x4000 /* PCICTL registers for 2nd Psycho */ #define PSR_DMA_SCB_DIAG0 0xa000 /* DMA scoreboard diag reg 0 */ #define PSR_DMA_SCB_DIAG1 0xa008 /* DMA scoreboard diag reg 1 */ #define PSR_IOMMU_SVADIAG 0xa400 /* IOMMU virtual addr diag reg */ #define PSR_IOMMU_TLB_CMP_DIAG 0xa408 /* IOMMU TLB tag compare diag reg */ #define PSR_IOMMU_QUEUE_DIAG 0xa500 /* IOMMU LRU queue diag regs 0..15 */ #define PSR_IOMMU_TLB_TAG_DIAG 0xa580 /* TLB tag diag regs 0..15 */ #define PSR_IOMMU_TLB_DATA_DIAG 0xa600 /* TLB data RAM diag regs 0..15 */ #define PSR_PCI_INT_DIAG 0xa800 /* PCI int state diag reg */ #define PSR_OBIO_INT_DIAG 0xa808 /* OBIO and misc int state diag reg */ #define PSR_STRBUF_DIAG 0xb000 /* Streaming buffer diag regs */ + /* * Here is the rest of the map, which we're not specifying: * * 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space * 1fe.0100.0000 - 1fe.0100.00ff PCI B configuration header * 1fe.0101.0000 - 1fe.0101.00ff PCI A configuration header * 1fe.0200.0000 - 1fe.0200.ffff PCI A I/O space * 1fe.0201.0000 - 1fe.0201.ffff PCI B I/O space * 1ff.0000.0000 - 1ff.7fff.ffff PCI A memory space * 1ff.8000.0000 - 1ff.ffff.ffff PCI B memory space * - * NB: config and I/O space can use 1-4 byte accesses, not 8 byte + * NB: Config and I/O space can use 1-4 byte accesses, not 8 byte * accesses. Memory space can use any sized accesses. * * Note that the SUNW,sabre/SUNW,simba combinations found on the * Ultra5 and Ultra10 machines uses slightly differrent addresses * than the above. This is mostly due to the fact that the APB is * a multi-function PCI device with two PCI bridges, and the U2P is * two separate PCI bridges. It uses the same PCI configuration * space, though the configuration header for each PCI bus is * located differently due to the SUNW,simba PCI busses being * function 0 and function 1 of the APB, whereas the Psycho's are * each their own PCI device. The I/O and memory spaces are each * split into 8 equally sized areas (8x2MB blocks for I/O space, * and 8x512MB blocks for memory space). These are allocated in to * either PCI A or PCI B, or neither in the APB's `I/O Address Map * Register A/B' (0xde) and `Memory Address Map Register A/B' (0xdf) * registers of each Simba. We must ensure that both of the * following are correct (the prom should do this for us): * * (PCI A Memory Address Map) & (PCI B Memory Address Map) == 0 * * (PCI A I/O Address Map) & (PCI B I/O Address Map) == 0 * * 1fe.0100.0000 - 1fe.01ff.ffff PCI configuration space * 1fe.0100.0800 - 1fe.0100.08ff PCI B configuration header * 1fe.0100.0900 - 1fe.0100.09ff PCI A configuration header * 1fe.0200.0000 - 1fe.02ff.ffff PCI I/O space (divided) * 1ff.0000.0000 - 1ff.ffff.ffff PCI memory space (divided) */ /* * PSR_CS defines: * * 63 59 55 50 45 4 3 2 1 0 * +------+------+------+------+--//---+--------+-------+-----+------+ * | IMPL | VERS | MID | IGN | xxx | APCKEN | APERR | IAP | MODE | * +------+------+------+------+--//---+--------+-------+-----+------+ * */ #define PSYCHO_GCSR_IMPL(csr) ((u_int)(((csr) >> 60) & 0xf)) #define PSYCHO_GCSR_VERS(csr) ((u_int)(((csr) >> 56) & 0xf)) #define PSYCHO_GCSR_MID(csr) ((u_int)(((csr) >> 51) & 0x1f)) #define PSYCHO_GCSR_IGN(csr) ((u_int)(((csr) >> 46) & 0x1f)) #define PSYCHO_CSR_APCKEN 8 /* UPA addr parity check enable */ #define PSYCHO_CSR_APERR 4 /* UPA addr parity error */ #define PSYCHO_CSR_IAP 2 /* invert UPA address parity */ #define PSYCHO_CSR_MODE 1 /* UPA/PCI handshake */ /* Offsets into the PSR_PCICTL* register block */ #define PCR_CS 0x0000 /* PCI control/status register */ #define PCR_AFS 0x0010 /* PCI AFSR register */ #define PCR_AFA 0x0018 /* PCI AFAR register */ #define PCR_DIAG 0x0020 /* PCI diagnostic register */ #define PCR_TAS 0x0028 /* PCI target address space reg (IIi) */ #define PCR_STRBUF 0x0800 /* IOMMU streaming buffer registers. */ /* INO defines */ #define PSYCHO_MAX_INO 0x3f /* Device space defines */ #define PSYCHO_CONF_SIZE 0x1000000 #define PSYCHO_CONF_BUS_SHIFT 16 #define PSYCHO_CONF_DEV_SHIFT 11 #define PSYCHO_CONF_FUNC_SHIFT 8 #define PSYCHO_CONF_REG_SHIFT 0 #define PSYCHO_IO_SIZE 0x1000000 #define PSYCHO_MEM_SIZE 0x100000000 #define PSYCHO_CONF_OFF(bus, slot, func, reg) \ (((bus) << PSYCHO_CONF_BUS_SHIFT) | \ ((slot) << PSYCHO_CONF_DEV_SHIFT) | \ ((func) << PSYCHO_CONF_FUNC_SHIFT) | \ ((reg) << PSYCHO_CONF_REG_SHIFT)) /* what the bits mean! */ /* * PCI [a|b] control/status register * Note that the Hummingbird/Sabre only has one set of PCI control/status * registers. */ #define PCICTL_SBHERR 0x0000000800000000 /* strm. byte hole error; W1C */ #define PCICTL_SERR 0x0000000400000000 /* SERR asserted; W1C */ #define PCICTL_PCISPEED 0x0000000200000000 /* 0:half 1:full bus speed */ #define PCICTL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */ #define PCICTL_SBHINTEN 0x0000000000000400 /* strm. byte hole int. en. */ #define PCICTL_WAKEUPEN 0x0000000000000200 /* power mgmt. wakeup enable */ #define PCICTL_ERRINTEN 0x0000000000000100 /* PCI error interrupt enable */ #define PCICTL_ARB_4 0x000000000000000f /* DVMA arb. 4 PCI slots mask */ #define PCICTL_ARB_6 0x000000000000003f /* DVMA arb. 6 PCI slots mask */ /* The following are Hummingbird/Sabre only. */ #define PCICTL_MRLM 0x0000001000000000 /* Memory Read Line/Multiple */ #define PCICTL_CPU_PRIO 0x0000000000100000 /* CPU extra arb. prio. en. */ #define PCICTL_ARB_PRIO 0x00000000000f0000 /* PCI extra arb. prio. en. */ #define PCICTL_RTRYWAIT 0x0000000000000080 /* 0:wait 1:retry DMA write */ /* Uncorrectable error asynchronous fault status register */ #define UEAFSR_BLK (1UL << 23) /* Error caused by block transaction */ #define UEAFSR_P_DTE (1UL << 56) /* Pri. DVMA translation error */ #define UEAFSR_S_DTE (1UL << 57) /* Sec. DVMA translation error */ #define UEAFSR_S_DWR (1UL << 58) /* Sec. error during DVMA write */ #define UEAFSR_S_DRD (1UL << 59) /* Sec. error during DVMA read */ #define UEAFSR_S_PIO (1UL << 60) /* Sec. error during PIO access */ #define UEAFSR_P_DWR (1UL << 61) /* Pri. error during DVMA write */ #define UEAFSR_P_DRD (1UL << 62) /* Pri. error during DVMA read */ #define UEAFSR_P_PIO (1UL << 63) /* Pri. error during PIO access */ /* Correctable error asynchronous fault status register */ #define CEAFSR_BLK (1UL << 23) /* Error caused by block transaction */ #define CEAFSR_S_DWR (1UL << 58) /* Sec. error caused by DVMA write */ #define CEAFSR_S_DRD (1UL << 59) /* Sec. error caused by DVMA read */ #define CEAFSR_S_PIO (1UL << 60) /* Sec. error caused by PIO access */ #define CEAFSR_P_DWR (1UL << 61) /* Pri. error caused by DVMA write */ #define CEAFSR_P_DRD (1UL << 62) /* Pri. error caused by DVMA read */ #define CEAFSR_P_PIO (1UL << 63) /* Pri. error caused by PIO access */ /* PCI asynchronous fault status register */ #define PCIAFSR_P_MA (1UL << 63) /* Pri. master abort */ #define PCIAFSR_P_TA (1UL << 62) /* Pri. target abort */ #define PCIAFSR_P_RTRY (1UL << 61) /* Pri. excessive retries */ #define PCIAFSR_P_RERR (1UL << 60) /* Pri. parity error */ #define PCIAFSR_S_MA (1UL << 59) /* Sec. master abort */ #define PCIAFSR_S_TA (1UL << 58) /* Sec. target abort */ #define PCIAFSR_S_RTRY (1UL << 57) /* Sec. excessive retries */ #define PCIAFSR_S_RERR (1UL << 56) /* Sec. parity error */ #define PCIAFSR_BMASK (0xffffUL << 32)/* Bytemask of failed pri. transfer */ #define PCIAFSR_BLK (1UL << 31) /* failed pri. transfer was block r/w */ #define PCIAFSR_MID (0x3eUL << 25) /* UPA MID causing error transaction */ /* PCI diagnostic register */ #define DIAG_RTRY_DIS 0x0000000000000040 /* dis. retry limit */ #define DIAG_ISYNC_DIS 0x0000000000000020 /* dis. DMA write / int sync */ #define DIAG_DWSYNC_DIS 0x0000000000000010 /* dis. DMA write / PIO sync */ /* Definitions for the target address space register */ #define PCITAS_ADDR_SHIFT 29 /* Definitions for the Psycho configuration space */ #define PCS_DEVICE 0 /* Device number of Psycho CS entry */ #define PCS_FUNC 0 /* Function number of Psycho CS entry */ /* Non-Standard registers in the configration space */ #define PCSR_SECBUS 0x40 /* Secondary bus number register */ #define PCSR_SUBBUS 0x41 /* Subordinate bus number register */ /* Width of the physical addresses the IOMMU translates to */ #define PSYCHO_IOMMU_BITS 41 #define SABRE_IOMMU_BITS 34 #endif /* !_SPARC64_PCI_PSYCHOREG_H_ */ Index: head/sys/sparc64/pci/psychovar.h =================================================================== --- head/sys/sparc64/pci/psychovar.h (revision 287725) +++ head/sys/sparc64/pci/psychovar.h (revision 287726) @@ -1,84 +1,73 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psychovar.h,v 1.15 2008/05/29 14:51:26 mrg Exp * * $FreeBSD$ */ #ifndef _SPARC64_PCI_PSYCHOVAR_H_ #define _SPARC64_PCI_PSYCHOVAR_H_ /* * Per-PCI bus on mainbus softc structure; one for sabre, or two * per pair of psychos. */ struct psycho_softc { + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; + + struct iommu_state *sc_is; struct bus_dma_methods *sc_dma_methods; - device_t sc_dev; - struct mtx *sc_mtx; - /* Interrupt Group Number for this device */ - uint32_t sc_ign; + struct resource *sc_mem_res; + struct resource *sc_irq_res[PSYCHO_NINTR]; + void *sc_ihand[PSYCHO_NINTR]; + uint8_t sc_pci_hpbcfg[16]; + + SLIST_ENTRY(psycho_softc) sc_link; + + device_t sc_dev; + bus_addr_t sc_pcictl; - phandle_t sc_node; /* Firmware node */ u_int sc_mode; #define PSYCHO_MODE_SABRE 0 #define PSYCHO_MODE_PSYCHO 1 /* Bus A or B of a psycho pair? */ u_int sc_half; - struct iommu_state *sc_is; - - struct resource *sc_mem_res; - struct resource *sc_irq_res[PSYCHO_NINTR]; - void *sc_ihand[PSYCHO_NINTR]; - - struct ofw_bus_iinfo sc_pci_iinfo; - - /* Tags for PCI access */ - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - - bus_space_handle_t sc_pci_bh[PSYCHO_NRANGE]; - - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - uint8_t sc_pci_hpbcfg[16]; - - SLIST_ENTRY(psycho_softc) sc_link; + /* Interrupt Group Number for this device */ + uint32_t sc_ign; }; #endif /* !_SPARC64_PCI_PSYCHOVAR_H_ */ Index: head/sys/sparc64/pci/schizo.c =================================================================== --- head/sys/sparc64/pci/schizo.c (revision 287725) +++ head/sys/sparc64/pci/schizo.c (revision 287726) @@ -1,1518 +1,1256 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2001 - 2003 by Thomas Moestl * Copyright (c) 2005 - 2011 by Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: NetBSD: psycho.c,v 1.39 2001/10/07 20:30:41 eeh Exp * from: FreeBSD: psycho.c 183152 2008-09-18 19:45:22Z marius */ #include __FBSDID("$FreeBSD$"); /* * Driver for `Schizo' Fireplane/Safari to PCI 2.1, `Tomatillo' JBus to * PCI 2.2 and `XMITS' Fireplane/Safari to PCI-X bridges */ #include "opt_ofw_pci.h" #include "opt_schizo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include "pcib_if.h" static const struct schizo_desc *schizo_get_desc(device_t); static void schizo_set_intr(struct schizo_softc *, u_int, u_int, driver_filter_t); static void schizo_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op); static void ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op); static void schizo_intr_enable(void *); static void schizo_intr_disable(void *); static void schizo_intr_assign(void *); static void schizo_intr_clear(void *); static int schizo_intr_register(struct schizo_softc *sc, u_int ino); static int schizo_get_intrmap(struct schizo_softc *, u_int, bus_addr_t *, bus_addr_t *); static timecounter_get_t schizo_get_timecount; /* Interrupt handlers */ static driver_filter_t schizo_pci_bus; static driver_filter_t schizo_ue; static driver_filter_t schizo_ce; static driver_filter_t schizo_host_bus; static driver_filter_t schizo_cdma; /* IOMMU support */ static void schizo_iommu_init(struct schizo_softc *, int, uint32_t); /* * Methods */ static device_probe_t schizo_probe; static device_attach_t schizo_attach; -static bus_read_ivar_t schizo_read_ivar; static bus_setup_intr_t schizo_setup_intr; static bus_alloc_resource_t schizo_alloc_resource; -static bus_activate_resource_t schizo_activate_resource; -static bus_adjust_resource_t schizo_adjust_resource; -static bus_get_dma_tag_t schizo_get_dma_tag; static pcib_maxslots_t schizo_maxslots; static pcib_read_config_t schizo_read_config; static pcib_write_config_t schizo_write_config; static pcib_route_interrupt_t schizo_route_interrupt; -static ofw_bus_get_node_t schizo_get_node; static ofw_pci_setup_device_t schizo_setup_device; static device_method_t schizo_methods[] = { /* Device interface */ DEVMETHOD(device_probe, schizo_probe), DEVMETHOD(device_attach, schizo_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, schizo_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, schizo_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, schizo_alloc_resource), - DEVMETHOD(bus_activate_resource, schizo_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, schizo_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, schizo_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, schizo_maxslots), DEVMETHOD(pcib_read_config, schizo_read_config), DEVMETHOD(pcib_write_config, schizo_write_config), DEVMETHOD(pcib_route_interrupt, schizo_route_interrupt), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, schizo_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), /* ofw_pci interface */ DEVMETHOD(ofw_pci_setup_device, schizo_setup_device), DEVMETHOD_END }; static devclass_t schizo_devclass; DEFINE_CLASS_0(pcib, schizo_driver, schizo_methods, sizeof(struct schizo_softc)); EARLY_DRIVER_MODULE(schizo, nexus, schizo_driver, schizo_devclass, 0, 0, BUS_PASS_BUS); static SLIST_HEAD(, schizo_softc) schizo_softcs = SLIST_HEAD_INITIALIZER(schizo_softcs); static const struct intr_controller schizo_ic = { schizo_intr_enable, schizo_intr_disable, schizo_intr_assign, schizo_intr_clear }; struct schizo_icarg { struct schizo_softc *sica_sc; bus_addr_t sica_map; bus_addr_t sica_clr; }; #define SCHIZO_CDMA_TIMEOUT 1 /* 1 second per try */ #define SCHIZO_CDMA_TRIES 15 #define SCHIZO_PERF_CNT_QLTY 100 #define SCHIZO_SPC_BARRIER(spc, sc, offs, len, flags) \ bus_barrier((sc)->sc_mem_res[(spc)], (offs), (len), (flags)) #define SCHIZO_SPC_READ_8(spc, sc, offs) \ bus_read_8((sc)->sc_mem_res[(spc)], (offs)) #define SCHIZO_SPC_WRITE_8(spc, sc, offs, v) \ bus_write_8((sc)->sc_mem_res[(spc)], (offs), (v)) #ifndef SCHIZO_DEBUG #define SCHIZO_SPC_SET(spc, sc, offs, reg, v) \ SCHIZO_SPC_WRITE_8((spc), (sc), (offs), (v)) #else #define SCHIZO_SPC_SET(spc, sc, offs, reg, v) do { \ device_printf((sc)->sc_dev, reg " 0x%016llx -> 0x%016llx\n", \ (unsigned long long)SCHIZO_SPC_READ_8((spc), (sc), (offs)), \ (unsigned long long)(v)); \ SCHIZO_SPC_WRITE_8((spc), (sc), (offs), (v)); \ } while (0) #endif #define SCHIZO_PCI_READ_8(sc, offs) \ SCHIZO_SPC_READ_8(STX_PCI, (sc), (offs)) #define SCHIZO_PCI_WRITE_8(sc, offs, v) \ SCHIZO_SPC_WRITE_8(STX_PCI, (sc), (offs), (v)) #define SCHIZO_CTRL_READ_8(sc, offs) \ SCHIZO_SPC_READ_8(STX_CTRL, (sc), (offs)) #define SCHIZO_CTRL_WRITE_8(sc, offs, v) \ SCHIZO_SPC_WRITE_8(STX_CTRL, (sc), (offs), (v)) #define SCHIZO_PCICFG_READ_8(sc, offs) \ SCHIZO_SPC_READ_8(STX_PCICFG, (sc), (offs)) #define SCHIZO_PCICFG_WRITE_8(sc, offs, v) \ SCHIZO_SPC_WRITE_8(STX_PCICFG, (sc), (offs), (v)) #define SCHIZO_ICON_READ_8(sc, offs) \ SCHIZO_SPC_READ_8(STX_ICON, (sc), (offs)) #define SCHIZO_ICON_WRITE_8(sc, offs, v) \ SCHIZO_SPC_WRITE_8(STX_ICON, (sc), (offs), (v)) #define SCHIZO_PCI_SET(sc, offs, v) \ SCHIZO_SPC_SET(STX_PCI, (sc), (offs), # offs, (v)) #define SCHIZO_CTRL_SET(sc, offs, v) \ SCHIZO_SPC_SET(STX_CTRL, (sc), (offs), # offs, (v)) struct schizo_desc { const char *sd_string; int sd_mode; const char *sd_name; }; static const struct schizo_desc schizo_compats[] = { { "pci108e,8001", SCHIZO_MODE_SCZ, "Schizo" }, #if 0 { "pci108e,8002", SCHIZO_MODE_XMS, "XMITS" }, #endif { "pci108e,a801", SCHIZO_MODE_TOM, "Tomatillo" }, { NULL, 0, NULL } }; static const struct schizo_desc * schizo_get_desc(device_t dev) { const struct schizo_desc *desc; const char *compat; compat = ofw_bus_get_compat(dev); if (compat == NULL) return (NULL); for (desc = schizo_compats; desc->sd_string != NULL; desc++) if (strcmp(desc->sd_string, compat) == 0) return (desc); return (NULL); } static int schizo_probe(device_t dev) { const char *dtype; dtype = ofw_bus_get_type(dev); if (dtype != NULL && strcmp(dtype, OFW_TYPE_PCI) == 0 && schizo_get_desc(dev) != NULL) { device_set_desc(dev, "Sun Host-PCI bridge"); return (0); } return (ENXIO); } static int schizo_attach(device_t dev) { - struct ofw_pci_ranges *range; const struct schizo_desc *desc; struct schizo_softc *asc, *sc, *osc; struct timecounter *tc; + bus_dma_tag_t dmat; uint64_t ino_bitmap, reg; phandle_t node; uint32_t prop, prop_array[2]; int i, j, mode, rid, tsbsize; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); desc = schizo_get_desc(dev); mode = desc->sd_mode; sc->sc_dev = dev; - sc->sc_node = node; sc->sc_mode = mode; sc->sc_flags = 0; /* * The Schizo has three register banks: * (0) per-PBM PCI configuration and status registers, but for bus B * shared with the UPA64s interrupt mapping register banks * (1) shared Schizo controller configuration and status registers * (2) per-PBM PCI configuration space * * The Tomatillo has four register banks: * (0) per-PBM PCI configuration and status registers * (1) per-PBM Tomatillo controller configuration registers, but on * machines having the `jbusppm' device shared with its Estar * register bank for bus A * (2) per-PBM PCI configuration space * (3) per-PBM interrupt concentrator registers */ sc->sc_half = (bus_get_resource_start(dev, SYS_RES_MEMORY, STX_PCI) >> 20) & 1; for (i = 0; i < (mode == SCHIZO_MODE_SCZ ? SCZ_NREG : TOM_NREG); i++) { rid = i; sc->sc_mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, (((mode == SCHIZO_MODE_SCZ && ((sc->sc_half == 1 && i == STX_PCI) || i == STX_CTRL)) || (mode == SCHIZO_MODE_TOM && sc->sc_half == 0 && i == STX_CTRL)) ? RF_SHAREABLE : 0) | RF_ACTIVE); if (sc->sc_mem_res[i] == NULL) panic("%s: could not allocate register bank %d", __func__, i); } /* * Match other Schizos that are already configured against * the controller base physical address. This will be the * same for a pair of devices that share register space. */ osc = NULL; SLIST_FOREACH(asc, &schizo_softcs, sc_link) { if (rman_get_start(asc->sc_mem_res[STX_CTRL]) == rman_get_start(sc->sc_mem_res[STX_CTRL])) { /* Found partner. */ osc = asc; break; } } if (osc == NULL) { sc->sc_mtx = malloc(sizeof(*sc->sc_mtx), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_mtx == NULL) panic("%s: could not malloc mutex", __func__); mtx_init(sc->sc_mtx, "pcib_mtx", NULL, MTX_SPIN); } else { if (sc->sc_mode != SCHIZO_MODE_SCZ) panic("%s: no partner expected", __func__); if (mtx_initialized(osc->sc_mtx) == 0) panic("%s: mutex not initialized", __func__); sc->sc_mtx = osc->sc_mtx; } + SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link); if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) panic("%s: could not determine IGN", __func__); if (OF_getprop(node, "version#", &sc->sc_ver, sizeof(sc->sc_ver)) == -1) panic("%s: could not determine version", __func__); if (mode == SCHIZO_MODE_XMS && OF_getprop(node, "module-revision#", &sc->sc_mrev, sizeof(sc->sc_mrev)) == -1) panic("%s: could not determine module-revision", __func__); if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1) prop = 33000000; if (mode == SCHIZO_MODE_XMS && (SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL) & XMS_PCI_CTRL_X_MODE) != 0) { if (sc->sc_mrev < 1) panic("PCI-X mode unsupported"); sc->sc_flags |= SCHIZO_FLAGS_XMODE; } device_printf(dev, "%s, version %d, ", desc->sd_name, sc->sc_ver); if (mode == SCHIZO_MODE_XMS) printf("module-revision %d, ", sc->sc_mrev); printf("IGN %#x, bus %c, PCI%s mode, %dMHz\n", sc->sc_ign, 'A' + sc->sc_half, (sc->sc_flags & SCHIZO_FLAGS_XMODE) != 0 ? "-X" : "", prop / 1000 / 1000); /* Set up the PCI interrupt retry timer. */ SCHIZO_PCI_SET(sc, STX_PCI_INTR_RETRY_TIM, 5); /* Set up the PCI control register. */ reg = SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL); reg &= ~(TOM_PCI_CTRL_DTO_IEN | STX_PCI_CTRL_ARB_PARK | STX_PCI_CTRL_ARB_MASK); reg |= STX_PCI_CTRL_MMU_IEN | STX_PCI_CTRL_SBH_IEN | STX_PCI_CTRL_ERR_IEN; if (OF_getproplen(node, "no-bus-parking") < 0) reg |= STX_PCI_CTRL_ARB_PARK; if (mode == SCHIZO_MODE_XMS && sc->sc_mrev == 1) reg |= XMS_PCI_CTRL_XMITS10_ARB_MASK; else reg |= STX_PCI_CTRL_ARB_MASK; if (mode == SCHIZO_MODE_TOM) { reg |= TOM_PCI_CTRL_PRM | TOM_PCI_CTRL_PRO | TOM_PCI_CTRL_PRL; if (sc->sc_ver <= 1) /* revision <= 2.0 */ reg |= TOM_PCI_CTRL_DTO_IEN; else reg |= STX_PCI_CTRL_PTO; } else if (mode == SCHIZO_MODE_XMS) { SCHIZO_PCI_SET(sc, XMS_PCI_PARITY_DETECT, 0x3fff); SCHIZO_PCI_SET(sc, XMS_PCI_UPPER_RETRY_COUNTER, 0x3e8); reg |= XMS_PCI_CTRL_X_ERRINT_EN; } SCHIZO_PCI_SET(sc, STX_PCI_CTRL, reg); /* Set up the PCI diagnostic register. */ reg = SCHIZO_PCI_READ_8(sc, STX_PCI_DIAG); reg &= ~(SCZ_PCI_DIAG_RTRYARB_DIS | STX_PCI_DIAG_RETRY_DIS | STX_PCI_DIAG_INTRSYNC_DIS); SCHIZO_PCI_SET(sc, STX_PCI_DIAG, reg); /* * Enable DMA write parity error interrupts of version >= 7 (i.e. * revision >= 2.5) Schizo and XMITS (enabling it on XMITS < 3.0 has * no effect though). */ if ((mode == SCHIZO_MODE_SCZ && sc->sc_ver >= 7) || mode == SCHIZO_MODE_XMS) { reg = SCHIZO_PCI_READ_8(sc, SX_PCI_CFG_ICD); reg |= SX_PCI_CFG_ICD_DMAW_PERR_IEN; SCHIZO_PCI_SET(sc, SX_PCI_CFG_ICD, reg); } /* * On Tomatillo clear the I/O prefetch lengths (workaround for a * Jalapeno bug). */ if (mode == SCHIZO_MODE_TOM) SCHIZO_PCI_SET(sc, TOM_PCI_IOC_CSR, TOM_PCI_IOC_PW | (1 << TOM_PCI_IOC_PREF_OFF_SHIFT) | TOM_PCI_IOC_CPRM | TOM_PCI_IOC_CPRO | TOM_PCI_IOC_CPRL); /* * Hunt through all the interrupt mapping regs and register * the interrupt controller for our interrupt vectors. We do * this early in order to be able to catch stray interrupts. * This is complicated by the fact that a pair of Schizo PBMs * shares one IGN. */ i = OF_getprop(node, "ino-bitmap", (void *)prop_array, sizeof(prop_array)); if (i != -1) ino_bitmap = ((uint64_t)prop_array[1] << 32) | prop_array[0]; else { /* * If the ino-bitmap property is missing, just provide the * default set of interrupts for this controller and let * schizo_setup_intr() take care of child interrupts. */ if (sc->sc_half == 0) ino_bitmap = (1ULL << STX_UE_INO) | (1ULL << STX_CE_INO) | (1ULL << STX_PCIERR_A_INO) | (1ULL << STX_BUS_INO); else ino_bitmap = 1ULL << STX_PCIERR_B_INO; } for (i = 0; i <= STX_MAX_INO; i++) { if ((ino_bitmap & (1ULL << i)) == 0) continue; if (i == STX_FB0_INO || i == STX_FB1_INO) /* Leave for upa(4). */ continue; j = schizo_intr_register(sc, i); if (j != 0) device_printf(dev, "could not register interrupt " "controller for INO %d (%d)\n", i, j); } /* * Setup Safari/JBus performance counter 0 in bus cycle counting * mode as timecounter. Unfortunately, this is broken with at * least the version 4 Tomatillos found in Fire V120 and Blade * 1500, which apparently actually count some different event at * ~0.5 and 3MHz respectively instead (also when running in full * power mode). Besides, one counter seems to be shared by a * "pair" of Tomatillos, too. */ if (sc->sc_half == 0) { SCHIZO_CTRL_SET(sc, STX_CTRL_PERF, (STX_CTRL_PERF_DIS << STX_CTRL_PERF_CNT1_SHIFT) | (STX_CTRL_PERF_BUSCYC << STX_CTRL_PERF_CNT0_SHIFT)); tc = malloc(sizeof(*tc), M_DEVBUF, M_NOWAIT | M_ZERO); if (tc == NULL) panic("%s: could not malloc timecounter", __func__); tc->tc_get_timecount = schizo_get_timecount; tc->tc_counter_mask = STX_CTRL_PERF_CNT_MASK; if (OF_getprop(OF_peer(0), "clock-frequency", &prop, sizeof(prop)) == -1) panic("%s: could not determine clock frequency", __func__); tc->tc_frequency = prop; tc->tc_name = strdup(device_get_nameunit(dev), M_DEVBUF); if (mode == SCHIZO_MODE_SCZ) tc->tc_quality = SCHIZO_PERF_CNT_QLTY; else tc->tc_quality = -SCHIZO_PERF_CNT_QLTY; tc->tc_priv = sc; tc_init(tc); } /* * Set up the IOMMU. Schizo, Tomatillo and XMITS all have * one per PBM. Schizo and XMITS additionally have a streaming * buffer, in Schizo version < 5 (i.e. revision < 2.3) it's * affected by several errata though. However, except for context * flushes, taking advantage of it should be okay even with those. */ memcpy(&sc->sc_dma_methods, &iommu_dma_methods, sizeof(sc->sc_dma_methods)); sc->sc_is.sis_sc = sc; sc->sc_is.sis_is.is_flags = IOMMU_PRESERVE_PROM; sc->sc_is.sis_is.is_pmaxaddr = IOMMU_MAXADDR(STX_IOMMU_BITS); sc->sc_is.sis_is.is_sb[0] = sc->sc_is.sis_is.is_sb[1] = 0; if (OF_getproplen(node, "no-streaming-cache") < 0) sc->sc_is.sis_is.is_sb[0] = STX_PCI_STRBUF; #define TSBCASE(x) \ case (IOTSB_BASESZ << (x)) << (IO_PAGE_SHIFT - IOTTE_SHIFT): \ tsbsize = (x); \ break; \ i = OF_getprop(node, "virtual-dma", (void *)prop_array, sizeof(prop_array)); if (i == -1 || i != sizeof(prop_array)) schizo_iommu_init(sc, 7, -1); else { switch (prop_array[1]) { TSBCASE(1); TSBCASE(2); TSBCASE(3); TSBCASE(4); TSBCASE(5); TSBCASE(6); TSBCASE(7); TSBCASE(8); default: panic("%s: unsupported DVMA size 0x%x", __func__, prop_array[1]); /* NOTREACHED */ } schizo_iommu_init(sc, tsbsize, prop_array[0]); } #undef TSBCASE - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Schizo PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, STX_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Schizo PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, STX_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != STX_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < STX_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Register the softc, this is needed for paired Schizos. */ - SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link); - - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is.sis_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.sis_is.is_pmaxaddr, 0xff, 0xffffffff, 0, NULL, NULL, - &sc->sc_pci_dmat) != 0) + &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = &sc->sc_is; - sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods; + dmat->dt_cookie = &sc->sc_is; + dmat->dt_mt = &sc->sc_dma_methods; - /* - * Get the bus range from the firmware. - * NB: Tomatillos don't support PCI bus reenumeration. - */ - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + if (ofw_pci_attach_common(dev, dmat, STX_IO_SIZE, STX_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); /* Clear any pending PCI error bits. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, - PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus, - STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2), 2); + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, + STX_CS_FUNC, PCIR_STATUS, PCIB_READ_CONFIG(dev, + sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, + 2), 2); SCHIZO_PCI_SET(sc, STX_PCI_CTRL, SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL)); SCHIZO_PCI_SET(sc, STX_PCI_AFSR, SCHIZO_PCI_READ_8(sc, STX_PCI_AFSR)); /* * Establish handlers for interesting interrupts... * Someone at Sun clearly was smoking crack; with Schizos PCI * bus error interrupts for one PBM can be routed to the other * PBM though we obviously need to use the softc of the former * as the argument for the interrupt handler and the softc of * the latter as the argument for the interrupt controller. */ if (sc->sc_half == 0) { if ((ino_bitmap & (1ULL << STX_PCIERR_A_INO)) != 0 || (osc != NULL && ((struct schizo_icarg *)intr_vectors[ INTMAP_VEC(sc->sc_ign, STX_PCIERR_A_INO)].iv_icarg)-> sica_sc == osc)) /* * We are the driver for PBM A and either also * registered the interrupt controller for us or * the driver for PBM B has probed first and * registered it for us. */ schizo_set_intr(sc, 0, STX_PCIERR_A_INO, schizo_pci_bus); if ((ino_bitmap & (1ULL << STX_PCIERR_B_INO)) != 0 && osc != NULL) /* * We are the driver for PBM A but registered * the interrupt controller for PBM B, i.e. the * driver for PBM B attached first but couldn't * set up a handler for PBM B. */ schizo_set_intr(osc, 0, STX_PCIERR_B_INO, schizo_pci_bus); } else { if ((ino_bitmap & (1ULL << STX_PCIERR_B_INO)) != 0 || (osc != NULL && ((struct schizo_icarg *)intr_vectors[ INTMAP_VEC(sc->sc_ign, STX_PCIERR_B_INO)].iv_icarg)-> sica_sc == osc)) /* * We are the driver for PBM B and either also * registered the interrupt controller for us or * the driver for PBM A has probed first and * registered it for us. */ schizo_set_intr(sc, 0, STX_PCIERR_B_INO, schizo_pci_bus); if ((ino_bitmap & (1ULL << STX_PCIERR_A_INO)) != 0 && osc != NULL) /* * We are the driver for PBM B but registered * the interrupt controller for PBM A, i.e. the * driver for PBM A attached first but couldn't * set up a handler for PBM A. */ schizo_set_intr(osc, 0, STX_PCIERR_A_INO, schizo_pci_bus); } if ((ino_bitmap & (1ULL << STX_UE_INO)) != 0) schizo_set_intr(sc, 1, STX_UE_INO, schizo_ue); if ((ino_bitmap & (1ULL << STX_CE_INO)) != 0) schizo_set_intr(sc, 2, STX_CE_INO, schizo_ce); if ((ino_bitmap & (1ULL << STX_BUS_INO)) != 0) schizo_set_intr(sc, 3, STX_BUS_INO, schizo_host_bus); /* * According to the Schizo Errata I-13, consistent DMA flushing/ * syncing is FUBAR in version < 5 (i.e. revision < 2.3) bridges, * so we can't use it and need to live with the consequences. With * Schizo version >= 5, CDMA flushing/syncing is usable but requires * the workaround described in Schizo Errata I-23. With Tomatillo * and XMITS, CDMA flushing/syncing works as expected, Tomatillo * version <= 4 (i.e. revision <= 2.3) bridges additionally require * a block store after a write to TOMXMS_PCI_DMA_SYNC_PEND though. */ if ((sc->sc_mode == SCHIZO_MODE_SCZ && sc->sc_ver >= 5) || sc->sc_mode == SCHIZO_MODE_TOM || sc->sc_mode == SCHIZO_MODE_XMS) { if (sc->sc_mode == SCHIZO_MODE_SCZ) { sc->sc_dma_methods.dm_dmamap_sync = schizo_dmamap_sync; sc->sc_cdma_state = SCHIZO_CDMA_STATE_IDLE; /* * Some firmware versions include the CDMA interrupt * at RID 4 but most don't. With the latter we add * it ourselves at the spare RID 5. */ i = INTINO(bus_get_resource_start(dev, SYS_RES_IRQ, 4)); if (i == STX_CDMA_A_INO || i == STX_CDMA_B_INO) { sc->sc_cdma_vec = INTMAP_VEC(sc->sc_ign, i); (void)schizo_get_intrmap(sc, i, &sc->sc_cdma_map, &sc->sc_cdma_clr); schizo_set_intr(sc, 4, i, schizo_cdma); } else { i = STX_CDMA_A_INO + sc->sc_half; sc->sc_cdma_vec = INTMAP_VEC(sc->sc_ign, i); if (bus_set_resource(dev, SYS_RES_IRQ, 5, sc->sc_cdma_vec, 1) != 0) panic("%s: failed to add CDMA " "interrupt", __func__); j = schizo_intr_register(sc, i); if (j != 0) panic("%s: could not register " "interrupt controller for CDMA " "(%d)", __func__, j); (void)schizo_get_intrmap(sc, i, &sc->sc_cdma_map, &sc->sc_cdma_clr); schizo_set_intr(sc, 5, i, schizo_cdma); } } else { if (sc->sc_mode == SCHIZO_MODE_XMS) mtx_init(&sc->sc_sync_mtx, "pcib_sync_mtx", NULL, MTX_SPIN); sc->sc_sync_val = 1ULL << (STX_PCIERR_A_INO + sc->sc_half); sc->sc_dma_methods.dm_dmamap_sync = ichip_dmamap_sync; } if (sc->sc_mode == SCHIZO_MODE_TOM && sc->sc_ver <= 4) sc->sc_flags |= SCHIZO_FLAGS_BSWAR; } /* * Set the latency timer register as this isn't always done by the * firmware. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, - PCIR_LATTIMER, OFW_PCI_LATENCY, 1); + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, + STX_CS_FUNC, PCIR_LATTIMER, OFW_PCI_LATENCY, 1); - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); - #define SCHIZO_SYSCTL_ADD_UINT(name, arg, desc) \ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, \ (name), CTLFLAG_RD, (arg), 0, (desc)) SCHIZO_SYSCTL_ADD_UINT("dma_ce", &sc->sc_stats_dma_ce, "DMA correctable errors"); SCHIZO_SYSCTL_ADD_UINT("pci_non_fatal", &sc->sc_stats_pci_non_fatal, "PCI bus non-fatal errors"); #undef SCHIZO_SYSCTL_ADD_UINT device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static void schizo_set_intr(struct schizo_softc *sc, u_int index, u_int ino, driver_filter_t handler) { u_long vec; int rid; rid = index; sc->sc_irq_res[index] = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res[index] == NULL || INTINO(vec = rman_get_start(sc->sc_irq_res[index])) != ino || INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &schizo_ic || bus_setup_intr(sc->sc_dev, sc->sc_irq_res[index], INTR_TYPE_MISC | INTR_BRIDGE, handler, NULL, sc, &sc->sc_ihand[index]) != 0) panic("%s: failed to set up interrupt %d", __func__, index); } static int schizo_intr_register(struct schizo_softc *sc, u_int ino) { struct schizo_icarg *sica; bus_addr_t intrclr, intrmap; int error; if (schizo_get_intrmap(sc, ino, &intrmap, &intrclr) == 0) return (ENXIO); sica = malloc(sizeof(*sica), M_DEVBUF, M_NOWAIT); if (sica == NULL) return (ENOMEM); sica->sica_sc = sc; sica->sica_map = intrmap; sica->sica_clr = intrclr; #ifdef SCHIZO_DEBUG device_printf(sc->sc_dev, "intr map (INO %d) %#lx: %#lx, clr: %#lx\n", ino, (u_long)intrmap, (u_long)SCHIZO_PCI_READ_8(sc, intrmap), (u_long)intrclr); #endif error = (intr_controller_register(INTMAP_VEC(sc->sc_ign, ino), &schizo_ic, sica)); if (error != 0) free(sica, M_DEVBUF); return (error); } static int schizo_get_intrmap(struct schizo_softc *sc, u_int ino, bus_addr_t *intrmapptr, bus_addr_t *intrclrptr) { bus_addr_t intrclr, intrmap; uint64_t mr; /* * XXX we only look for INOs rather than INRs since the firmware * may not provide the IGN and the IGN is constant for all devices * on that PCI controller. */ if (ino > STX_MAX_INO) { device_printf(sc->sc_dev, "out of range INO %d requested\n", ino); return (0); } intrmap = STX_PCI_IMAP_BASE + (ino << 3); intrclr = STX_PCI_ICLR_BASE + (ino << 3); mr = SCHIZO_PCI_READ_8(sc, intrmap); if (INTINO(mr) != ino) { device_printf(sc->sc_dev, "interrupt map entry does not match INO (%d != %d)\n", (int)INTINO(mr), ino); return (0); } if (intrmapptr != NULL) *intrmapptr = intrmap; if (intrclrptr != NULL) *intrclrptr = intrclr; return (1); } /* * Interrupt handlers */ static int schizo_pci_bus(void *arg) { struct schizo_softc *sc = arg; uint64_t afar, afsr, csr, iommu, xstat; uint32_t status; u_int fatal; fatal = 0; mtx_lock_spin(sc->sc_mtx); afar = SCHIZO_PCI_READ_8(sc, STX_PCI_AFAR); afsr = SCHIZO_PCI_READ_8(sc, STX_PCI_AFSR); csr = SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL); iommu = SCHIZO_PCI_READ_8(sc, STX_PCI_IOMMU); if ((sc->sc_flags & SCHIZO_FLAGS_XMODE) != 0) xstat = SCHIZO_PCI_READ_8(sc, XMS_PCI_X_ERR_STAT); else xstat = 0; - status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_pci_secbus, + status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2); /* * IOMMU errors are only fatal on Tomatillo and there also only if * target abort was not signaled. */ if ((csr & STX_PCI_CTRL_MMU_ERR) != 0 && (iommu & TOM_PCI_IOMMU_ERR) != 0 && ((status & PCIM_STATUS_STABORT) == 0 || ((iommu & TOM_PCI_IOMMU_ERRMASK) != TOM_PCI_IOMMU_INVALID_ERR && (iommu & TOM_PCI_IOMMU_ERR_ILLTSBTBW) == 0 && (iommu & TOM_PCI_IOMMU_ERR_BAD_VA) == 0))) fatal = 1; else if ((status & PCIM_STATUS_STABORT) != 0) fatal = 1; if ((status & (PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT | PCIM_STATUS_RTABORT | PCIM_STATUS_MDPERR)) != 0 || (csr & (SCZ_PCI_CTRL_BUS_UNUS | TOM_PCI_CTRL_DTO_ERR | STX_PCI_CTRL_TTO_ERR | STX_PCI_CTRL_RTRY_ERR | SCZ_PCI_CTRL_SBH_ERR | STX_PCI_CTRL_SERR)) != 0 || (afsr & (STX_PCI_AFSR_P_MA | STX_PCI_AFSR_P_TA | STX_PCI_AFSR_P_RTRY | STX_PCI_AFSR_P_PERR | STX_PCI_AFSR_P_TTO | STX_PCI_AFSR_P_UNUS)) != 0) fatal = 1; if (xstat & (XMS_PCI_X_ERR_STAT_P_SC_DSCRD | XMS_PCI_X_ERR_STAT_P_SC_TTO | XMS_PCI_X_ERR_STAT_P_SDSTAT | XMS_PCI_X_ERR_STAT_P_SMMU | XMS_PCI_X_ERR_STAT_P_CDSTAT | XMS_PCI_X_ERR_STAT_P_CMMU | XMS_PCI_X_ERR_STAT_PERR_RCV)) fatal = 1; if (fatal == 0) sc->sc_stats_pci_non_fatal++; device_printf(sc->sc_dev, "PCI bus %c error AFAR %#llx AFSR %#llx " "PCI CSR %#llx IOMMU %#llx PCI-X %#llx STATUS %#x\n", 'A' + sc->sc_half, (unsigned long long)afar, (unsigned long long)afsr, (unsigned long long)csr, (unsigned long long)iommu, (unsigned long long)xstat, status); /* Clear the error bits that we caught. */ - PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_pci_secbus, STX_CS_DEVICE, + PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, status, 2); SCHIZO_PCI_WRITE_8(sc, STX_PCI_CTRL, csr); SCHIZO_PCI_WRITE_8(sc, STX_PCI_AFSR, afsr); SCHIZO_PCI_WRITE_8(sc, STX_PCI_IOMMU, iommu); if ((sc->sc_flags & SCHIZO_FLAGS_XMODE) != 0) SCHIZO_PCI_WRITE_8(sc, XMS_PCI_X_ERR_STAT, xstat); mtx_unlock_spin(sc->sc_mtx); if (fatal != 0) panic("%s: fatal PCI bus error", device_get_nameunit(sc->sc_dev)); return (FILTER_HANDLED); } static int schizo_ue(void *arg) { struct schizo_softc *sc = arg; uint64_t afar, afsr; int i; afar = SCHIZO_CTRL_READ_8(sc, STX_CTRL_UE_AFAR); for (i = 0; i < 1000; i++) if (((afsr = SCHIZO_CTRL_READ_8(sc, STX_CTRL_UE_AFSR)) & STX_CTRL_CE_AFSR_ERRPNDG) == 0) break; panic("%s: uncorrectable DMA error AFAR %#llx AFSR %#llx", device_get_nameunit(sc->sc_dev), (unsigned long long)afar, (unsigned long long)afsr); return (FILTER_HANDLED); } static int schizo_ce(void *arg) { struct schizo_softc *sc = arg; uint64_t afar, afsr; int i; mtx_lock_spin(sc->sc_mtx); afar = SCHIZO_CTRL_READ_8(sc, STX_CTRL_CE_AFAR); for (i = 0; i < 1000; i++) if (((afsr = SCHIZO_CTRL_READ_8(sc, STX_CTRL_UE_AFSR)) & STX_CTRL_CE_AFSR_ERRPNDG) == 0) break; sc->sc_stats_dma_ce++; device_printf(sc->sc_dev, "correctable DMA error AFAR %#llx AFSR %#llx\n", (unsigned long long)afar, (unsigned long long)afsr); /* Clear the error bits that we caught. */ SCHIZO_CTRL_WRITE_8(sc, STX_CTRL_UE_AFSR, afsr); mtx_unlock_spin(sc->sc_mtx); return (FILTER_HANDLED); } static int schizo_host_bus(void *arg) { struct schizo_softc *sc = arg; uint64_t errlog; errlog = SCHIZO_CTRL_READ_8(sc, STX_CTRL_BUS_ERRLOG); panic("%s: %s error %#llx", device_get_nameunit(sc->sc_dev), sc->sc_mode == SCHIZO_MODE_TOM ? "JBus" : "Safari", (unsigned long long)errlog); return (FILTER_HANDLED); } static int schizo_cdma(void *arg) { struct schizo_softc *sc = arg; atomic_cmpset_32(&sc->sc_cdma_state, SCHIZO_CDMA_STATE_PENDING, SCHIZO_CDMA_STATE_RECEIVED); return (FILTER_HANDLED); } static void schizo_iommu_init(struct schizo_softc *sc, int tsbsize, uint32_t dvmabase) { /* Punch in our copies. */ sc->sc_is.sis_is.is_bustag = rman_get_bustag(sc->sc_mem_res[STX_PCI]); sc->sc_is.sis_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[STX_PCI]); sc->sc_is.sis_is.is_iommu = STX_PCI_IOMMU; sc->sc_is.sis_is.is_dtag = STX_PCI_IOMMU_TLB_TAG_DIAG; sc->sc_is.sis_is.is_ddram = STX_PCI_IOMMU_TLB_DATA_DIAG; sc->sc_is.sis_is.is_dqueue = STX_PCI_IOMMU_QUEUE_DIAG; sc->sc_is.sis_is.is_dva = STX_PCI_IOMMU_SVADIAG; sc->sc_is.sis_is.is_dtcmp = STX_PCI_IOMMU_TLB_CMP_DIAG; iommu_init(device_get_nameunit(sc->sc_dev), (struct iommu_state *)&sc->sc_is, tsbsize, dvmabase, 0); } static int schizo_maxslots(device_t dev) { struct schizo_softc *sc; sc = device_get_softc(dev); if (sc->sc_mode == SCHIZO_MODE_SCZ) return (sc->sc_half == 0 ? 4 : 6); /* XXX: is this correct? */ return (PCI_SLOTMAX); } static uint32_t schizo_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { struct schizo_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint32_t r, wrd; - int i; - uint16_t shrt; - uint8_t byte; sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return (-1); - /* * The Schizo bridges contain a dupe of their header at 0x80. */ - if (sc->sc_mode == SCHIZO_MODE_SCZ && bus == sc->sc_pci_secbus && - slot == STX_CS_DEVICE && func == STX_CS_FUNC && - reg + width > 0x80) + if (sc->sc_mode == SCHIZO_MODE_SCZ && + bus == sc->sc_ops.sc_pci_secbus && slot == STX_CS_DEVICE && + func == STX_CS_FUNC && reg + width > 0x80) return (0); - offset = STX_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - - if (i) { -#ifdef SCHIZO_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, width)); } static void schizo_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct schizo_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return; - - offset = STX_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus, slot, + func, reg), bus, slot, func, reg, val, width); } static int schizo_route_interrupt(device_t bridge, device_t dev, int pin) { - struct schizo_softc *sc; - struct ofw_pci_register reg; - ofw_pci_intr_t pintr, mintr; + ofw_pci_intr_t mintr; - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL)) - return (mintr); - - device_printf(bridge, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (!PCI_INTERRUPT_VALID(mintr)) + device_printf(bridge, + "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (mintr); } -static int -schizo_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct schizo_softc *sc; - - sc = device_get_softc(dev); - switch (which) { - case PCIB_IVAR_DOMAIN: - *result = device_get_unit(dev); - return (0); - case PCIB_IVAR_BUS: - *result = sc->sc_pci_secbus; - return (0); - } - return (ENOENT); -} - static void schizo_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) { struct timeval cur, end; struct schizo_iommu_state *sis = dt->dt_cookie; struct schizo_softc *sc = sis->sis_sc; int i, res; #ifdef INVARIANTS register_t pil; #endif if ((map->dm_flags & DMF_STREAMED) != 0) { iommu_dma_methods.dm_dmamap_sync(dt, map, op); return; } if ((map->dm_flags & DMF_LOADED) == 0) return; if ((op & BUS_DMASYNC_POSTREAD) != 0) { /* * Note that in order to allow this function to be called from * filters we would need to use a spin mutex for serialization * but given that these disable interrupts we have to emulate * one. */ critical_enter(); KASSERT((rdpr(pstate) & PSTATE_IE) != 0, ("%s: interrupts disabled", __func__)); KASSERT((pil = rdpr(pil)) <= PIL_BRIDGE, ("%s: PIL too low (%ld)", __func__, pil)); for (; atomic_cmpset_acq_32(&sc->sc_cdma_state, SCHIZO_CDMA_STATE_IDLE, SCHIZO_CDMA_STATE_PENDING) == 0;) ; SCHIZO_PCI_WRITE_8(sc, sc->sc_cdma_map, INTMAP_ENABLE(sc->sc_cdma_vec, PCPU_GET(mid))); for (i = 0; i < SCHIZO_CDMA_TRIES; i++) { if (i > 0) printf("%s: try %d\n", __func__, i); SCHIZO_PCI_WRITE_8(sc, sc->sc_cdma_clr, INTCLR_RECEIVED); microuptime(&cur); end.tv_sec = SCHIZO_CDMA_TIMEOUT; end.tv_usec = 0; timevaladd(&end, &cur); for (; (res = atomic_cmpset_rel_32(&sc->sc_cdma_state, SCHIZO_CDMA_STATE_RECEIVED, SCHIZO_CDMA_STATE_IDLE)) == 0 && timevalcmp(&cur, &end, <=);) microuptime(&cur); if (res != 0) break; } if (res == 0) panic("%s: DMA does not sync", __func__); critical_exit(); } if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); } static void ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) { - static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); struct timeval cur, end; struct schizo_iommu_state *sis = dt->dt_cookie; struct schizo_softc *sc = sis->sis_sc; - register_t reg, s; + uint64_t reg; if ((map->dm_flags & DMF_STREAMED) != 0) { iommu_dma_methods.dm_dmamap_sync(dt, map, op); return; } if ((map->dm_flags & DMF_LOADED) == 0) return; if ((op & BUS_DMASYNC_POSTREAD) != 0) { if (sc->sc_mode == SCHIZO_MODE_XMS) mtx_lock_spin(&sc->sc_sync_mtx); SCHIZO_PCI_WRITE_8(sc, TOMXMS_PCI_DMA_SYNC_PEND, sc->sc_sync_val); microuptime(&cur); end.tv_sec = 1; end.tv_usec = 0; timevaladd(&end, &cur); for (; ((reg = SCHIZO_PCI_READ_8(sc, TOMXMS_PCI_DMA_SYNC_PEND)) & sc->sc_sync_val) != 0 && timevalcmp(&cur, &end, <=);) microuptime(&cur); if ((reg & sc->sc_sync_val) != 0) panic("%s: DMA does not sync", __func__); if (sc->sc_mode == SCHIZO_MODE_XMS) mtx_unlock_spin(&sc->sc_sync_mtx); else if ((sc->sc_flags & SCHIZO_FLAGS_BSWAR) != 0) { - s = intr_disable(); - reg = rd(fprs); - wr(fprs, reg | FPRS_FEF, 0); - __asm __volatile("stda %%f0, [%0] %1" - : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); - membar(Sync); - wr(fprs, reg, 0); - intr_restore(s); + ofw_pci_dmamap_sync_stst_order_common(); return; } } if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); } static void schizo_intr_enable(void *arg) { struct intr_vector *iv = arg; struct schizo_icarg *sica = iv->iv_icarg; SCHIZO_PCI_WRITE_8(sica->sica_sc, sica->sica_map, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); } static void schizo_intr_disable(void *arg) { struct intr_vector *iv = arg; struct schizo_icarg *sica = iv->iv_icarg; SCHIZO_PCI_WRITE_8(sica->sica_sc, sica->sica_map, iv->iv_vec); } static void schizo_intr_assign(void *arg) { struct intr_vector *iv = arg; struct schizo_icarg *sica = iv->iv_icarg; SCHIZO_PCI_WRITE_8(sica->sica_sc, sica->sica_map, INTMAP_TID( SCHIZO_PCI_READ_8(sica->sica_sc, sica->sica_map), iv->iv_mid)); } static void schizo_intr_clear(void *arg) { struct intr_vector *iv = arg; struct schizo_icarg *sica = iv->iv_icarg; SCHIZO_PCI_WRITE_8(sica->sica_sc, sica->sica_clr, INTCLR_IDLE); } static int schizo_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { struct schizo_softc *sc; u_long vec; int error; sc = device_get_softc(dev); /* * Make sure the vector is fully specified. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } if (intr_vectors[vec].iv_ic == &schizo_ic) { /* * Ensure we use the right softc in case the interrupt * is routed to our companion PBM for some odd reason. */ sc = ((struct schizo_icarg *)intr_vectors[vec].iv_icarg)-> sica_sc; } else if (intr_vectors[vec].iv_ic == NULL) { /* * Work around broken firmware which misses entries in * the ino-bitmap. */ error = schizo_intr_register(sc, INTINO(vec)); if (error != 0) { device_printf(dev, "could not register interrupt " "controller for vector 0x%lx (%d)\n", vec, error); return (error); } if (bootverbose) device_printf(dev, "belatedly registered as " "interrupt controller for vector 0x%lx\n", vec); } else { device_printf(dev, "invalid interrupt controller for vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } static struct resource * schizo_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct schizo_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); + if (type == SYS_RES_IRQ) { + sc = device_get_softc(bus); start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -schizo_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct schizo_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -schizo_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct schizo_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); - } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -schizo_get_dma_tag(device_t bus, device_t child __unused) -{ - struct schizo_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -schizo_get_node(device_t bus, device_t child __unused) -{ - struct schizo_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static void schizo_setup_device(device_t bus, device_t child) { struct schizo_softc *sc; uint64_t reg; int capreg; sc = device_get_softc(bus); /* * Disable bus parking in order to work around a bus hang caused by * Casinni/Skyhawk combinations. */ if (OF_getproplen(ofw_bus_get_node(child), "pci-req-removal") >= 0) SCHIZO_PCI_SET(sc, STX_PCI_CTRL, SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL) & ~STX_PCI_CTRL_ARB_PARK); if (sc->sc_mode == SCHIZO_MODE_XMS) { /* XMITS NCPQ WAR: set outstanding split transactions to 1. */ if ((sc->sc_flags & SCHIZO_FLAGS_XMODE) != 0 && (pci_read_config(child, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE) != PCIM_HDRTYPE_BRIDGE && pci_find_cap(child, PCIY_PCIX, &capreg) == 0) pci_write_config(child, capreg + PCIXR_COMMAND, pci_read_config(child, capreg + PCIXR_COMMAND, 2) & 0x7c, 2); /* XMITS 3.x WAR: set BUGCNTL iff value is unexpected. */ if (sc->sc_mrev >= 4) { reg = ((sc->sc_flags & SCHIZO_FLAGS_XMODE) != 0 ? 0xa0UL : 0xffUL) << XMS_PCI_X_DIAG_BUGCNTL_SHIFT; if ((SCHIZO_PCI_READ_8(sc, XMS_PCI_X_DIAG) & XMS_PCI_X_DIAG_BUGCNTL_MASK) != reg) SCHIZO_PCI_SET(sc, XMS_PCI_X_DIAG, reg); } } } static u_int schizo_get_timecount(struct timecounter *tc) { struct schizo_softc *sc; sc = tc->tc_priv; return ((SCHIZO_CTRL_READ_8(sc, STX_CTRL_PERF_CNT) & (STX_CTRL_PERF_CNT_MASK << STX_CTRL_PERF_CNT_CNT0_SHIFT)) >> STX_CTRL_PERF_CNT_CNT0_SHIFT); } Index: head/sys/sparc64/pci/schizoreg.h =================================================================== --- head/sys/sparc64/pci/schizoreg.h (revision 287725) +++ head/sys/sparc64/pci/schizoreg.h (revision 287726) @@ -1,358 +1,357 @@ /*- * Copyright (c) 2002 Jason L. Wright (jason@thought.net) * Copyright (c) 2005 by Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULLAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * from: OpenBSD: schizoreg.h,v 1.8 2005/05/19 18:28:59 mickey Exp * $FreeBSD$ */ #ifndef _SPARC64_PCI_SCHIZOREG_H_ #define _SPARC64_PCI_SCHIZOREG_H_ #define STX_NINTR 5 /* 4 via OFW + 1 CDMA */ -#define STX_NRANGE 4 #define SCZ_NREG 3 #define TOM_NREG 4 #define STX_PCI 0 #define STX_CTRL 1 #define STX_PCICFG 2 #define STX_ICON 3 /* PCI configuration and status registers */ #define SX_PCI_CFG_ICD 0x00110 #define STX_PCI_IOMMU 0x00200 #define STX_PCI_IOMMU_CTXFLUSH 0x00218 #define STX_PCI_IMAP_BASE 0x01000 #define STX_PCI_ICLR_BASE 0x01400 #define STX_PCI_INTR_RETRY_TIM 0x01a00 #define SCZ_PCI_DMA_SYNC 0x01a08 #define TOM_PCI_DMA_SYNC_COMP 0x01a10 #define TOMXMS_PCI_DMA_SYNC_PEND 0x01a18 #define STX_PCI_CTRL 0x02000 #define STX_PCI_AFSR 0x02010 #define STX_PCI_AFAR 0x02018 #define STX_PCI_DIAG 0x02020 #define XMS_PCI_PARITY_DETECT 0x02040 #define TOM_PCI_IOC_CSR 0x02248 #define TOM_PCI_IOC_TAG 0x02290 #define TOM_PCI_IOC_DATA 0x02290 #define XMS_PCI_X_ERR_STAT 0x02300 #define XMS_PCI_X_DIAG 0x02308 #define XMS_PCI_UPPER_RETRY_COUNTER 0x02310 #define STX_PCI_STRBUF 0x02800 #define STX_PCI_STRBUF_CTXFLUSH 0x02818 #define STX_PCI_IOMMU_SVADIAG 0x0a400 #define STX_PCI_IOMMU_TLB_CMP_DIAG 0x0a408 #define STX_PCI_IOMMU_QUEUE_DIAG 0x0a500 #define STX_PCI_IOMMU_TLB_TAG_DIAG 0x0a580 #define STX_PCI_IOMMU_TLB_DATA_DIAG 0x0a600 #define STX_PCI_IOBIO_DIAG 0x0a808 #define STX_PCI_STRBUF_CTXMATCH 0x10000 /* PCI configuration/idle check diagnostic register */ #define SX_PCI_CFG_ICD_PCI_2_0_COMPAT 0x0000000000008000ULL #define SX_PCI_CFG_ICD_DMAW_PERR_IEN 0x0000000000004000ULL #define SX_PCI_CFG_ICD_IFC_NOT_IDLE 0x0000000000000010ULL #define SX_PCI_CFG_ICD_MDU_NOT_IDLE 0x0000000000000008ULL #define SX_PCI_CFG_ICD_MMU_NOT_IDLE 0x0000000000000004ULL #define SX_PCI_CFG_ICD_PBM_NOT_IDLE 0x0000000000000002ULL #define SX_PCI_CFG_ICD_STC_NOT_IDLE 0x0000000000000001ULL /* PCI IOMMU control register */ #define TOM_PCI_IOMMU_ERR_BAD_VA 0x0000000010000000ULL #define TOM_PCI_IOMMU_ERR_ILLTSBTBW 0x0000000008000000ULL #define TOM_PCI_IOMMU_ECC_ERR 0x0000000006000000ULL #define TOM_PCI_IOMMU_TIMEOUT_ERR 0x0000000004000000ULL #define TOM_PCI_IOMMU_INVALID_ERR 0x0000000002000000ULL #define TOM_PCI_IOMMU_PROTECTION_ERR 0x0000000000000000ULL #define TOM_PCI_IOMMU_ERRMASK \ (TOM_PCI_IOMMU_PROTECTION_ERR | TOM_PCI_IOMMU_INVALID_ERR | \ TOM_PCI_IOMMU_TIMEOUT_ERR | TOM_PCI_IOMMU_ECC_ERR) #define TOM_PCI_IOMMU_ERR 0x0000000001000000ULL /* PCI control/status register */ #define SCZ_PCI_CTRL_BUS_UNUS 0x8000000000000000ULL #define TOM_PCI_CTRL_DTO_ERR 0x4000000000000000ULL #define TOM_PCI_CTRL_DTO_IEN 0x2000000000000000ULL #define SCZ_PCI_CTRL_ESLCK 0x0008000000000000ULL #define XMS_PCI_CTRL_DMA_WR_PERR 0x0008000000000000ULL #define SCZ_PCI_CTRL_ERRSLOT 0x0007000000000000ULL #define STX_PCI_CTRL_TTO_ERR 0x0000004000000000ULL #define STX_PCI_CTRL_RTRY_ERR 0x0000002000000000ULL #define STX_PCI_CTRL_MMU_ERR 0x0000001000000000ULL #define SCZ_PCI_CTRL_SBH_ERR 0x0000000800000000ULL #define STX_PCI_CTRL_SERR 0x0000000400000000ULL #define SCZ_PCI_CTRL_PCISPD 0x0000000200000000ULL #define XMS_PCI_CTRL_X_MODE 0x0000000100000000ULL #define TOM_PCI_CTRL_PRM 0x0000000040000000ULL #define TOM_PCI_CTRL_PRO 0x0000000020000000ULL #define TOM_PCI_CTRL_PRL 0x0000000010000000ULL #define STX_PCI_CTRL_PTO 0x0000000003000000ULL #define XMS_PCI_CTRL_X_ERRINT_EN 0x0000000000100000ULL #define STX_PCI_CTRL_MMU_IEN 0x0000000000080000ULL #define STX_PCI_CTRL_SBH_IEN 0x0000000000040000ULL #define STX_PCI_CTRL_ERR_IEN 0x0000000000020000ULL #define STX_PCI_CTRL_ARB_PARK 0x0000000000010000ULL #define SCZ_PCI_CTRL_PCIRST 0x0000000000000100ULL #define STX_PCI_CTRL_ARB_MASK 0x00000000000000ffULL #define XMS_PCI_CTRL_XMITS10_ARB_MASK 0x000000000000000fULL /* PCI asynchronous fault status register */ #define STX_PCI_AFSR_P_MA 0x8000000000000000ULL #define STX_PCI_AFSR_P_TA 0x4000000000000000ULL #define STX_PCI_AFSR_P_RTRY 0x2000000000000000ULL #define STX_PCI_AFSR_P_PERR 0x1000000000000000ULL #define STX_PCI_AFSR_P_TTO 0x0800000000000000ULL #define STX_PCI_AFSR_P_UNUS 0x0400000000000000ULL #define STX_PCI_AFSR_S_MA 0x0200000000000000ULL #define STX_PCI_AFSR_S_TA 0x0100000000000000ULL #define STX_PCI_AFSR_S_RTRY 0x0080000000000000ULL #define STX_PCI_AFSR_S_PERR 0x0040000000000000ULL #define STX_PCI_AFSR_S_TTO 0x0020000000000000ULL #define STX_PCI_AFSR_S_UNUS 0x0010000000000000ULL #define STX_PCI_AFSR_DWMASK 0x0000030000000000ULL #define STX_PCI_AFSR_BMASK 0x000000ff00000000ULL #define STX_PCI_AFSR_BLK 0x0000000080000000ULL #define STX_PCI_AFSR_CFG 0x0000000040000000ULL #define STX_PCI_AFSR_MEM 0x0000000020000000ULL #define STX_PCI_AFSR_IO 0x0000000010000000ULL /* PCI diagnostic register */ #define SCZ_PCI_DIAG_BADECC_DIS 0x0000000000000400ULL #define STX_PCI_DIAG_BYPASS_DIS 0x0000000000000200ULL #define STX_PCI_DIAG_TTO_DIS 0x0000000000000100ULL #define SCZ_PCI_DIAG_RTRYARB_DIS 0x0000000000000080ULL #define STX_PCI_DIAG_RETRY_DIS 0x0000000000000040ULL #define STX_PCI_DIAG_INTRSYNC_DIS 0x0000000000000020ULL #define STX_PCI_DIAG_DMAPARITY_INV 0x0000000000000008ULL #define STX_PCI_DIAG_PIODPARITY_INV 0x0000000000000004ULL #define STX_PCI_DIAG_PIOAPARITY_INV 0x0000000000000002ULL /* Tomatillo I/O cache register */ #define TOM_PCI_IOC_PW 0x0000000000080000ULL #define TOM_PCI_IOC_PRM 0x0000000000040000ULL #define TOM_PCI_IOC_PRO 0x0000000000020000ULL #define TOM_PCI_IOC_PRL 0x0000000000010000ULL #define TOM_PCI_IOC_PRM_LEN 0x000000000000c000ULL #define TOM_PCI_IOC_PRM_LEN_SHIFT 14 #define TOM_PCI_IOC_PRO_LEN 0x0000000000003000ULL #define TOM_PCI_IOC_PRO_LEN_SHIFT 12 #define TOM_PCI_IOC_PRL_LEN 0x0000000000000c00ULL #define TOM_PCI_IOC_PRL_LEN_SHIFT 10 #define TOM_PCI_IOC_PREF_OFF 0x0000000000000038ULL #define TOM_PCI_IOC_PREF_OFF_SHIFT 3 #define TOM_PCI_IOC_CPRM 0x0000000000000004ULL #define TOM_PCI_IOC_CPRO 0x0000000000000002ULL #define TOM_PCI_IOC_CPRL 0x0000000000000001ULL /* XMITS PCI-X error status register */ #define XMS_PCI_X_ERR_STAT_P_SC_DSCRD 0x8000000000000000ULL #define XMS_PCI_X_ERR_STAT_P_SC_TTO 0x4000000000000000ULL #define XMS_PCI_X_ERR_STAT_P_SDSTAT 0x2000000000000000ULL #define XMS_PCI_X_ERR_STAT_P_SMMU 0x1000000000000000ULL #define XMS_PCI_X_ERR_STAT_P_CDSTAT 0x0800000000000000ULL #define XMS_PCI_X_ERR_STAT_P_CMMU 0x0400000000000000ULL #define XMS_PCI_X_ERR_STAT_S_SC_DSCRD 0x0080000000000000ULL #define XMS_PCI_X_ERR_STAT_S_SC_TTO 0x0040000000000000ULL #define XMS_PCI_X_ERR_STAT_S_SDSTAT 0x0020000000000000ULL #define XMS_PCI_X_ERR_STAT_S_SMMU 0x0010000000000000ULL #define XMS_PCI_X_ERR_STAT_S_CDSTAT 0x0008000000000000ULL #define XMS_PCI_X_ERR_STAT_S_CMMU 0x0004000000000000ULL #define XMS_PCI_X_ERR_STAT_PERR_RCV_IEN 0x0000000400000000ULL #define XMS_PCI_X_ERR_STAT_PERR_RCV 0x0000000200000000ULL #define XMS_PCI_X_ERR_STAT_SERR_ON_PERR 0x0000000100000000ULL /* XMITS PCI-X diagnostic register */ #define XMS_PCI_X_DIAG_DIS_FAIR 0x0000000000080000ULL #define XMS_PCI_X_DIAG_CRCQ_VALID 0x0000000000040000ULL #define XMS_PCI_X_DIAG_SRCQ_ONE 0x0000000000000200ULL #define XMS_PCI_X_DIAG_CRCQ_FLUSH 0x0000000000000100ULL #define XMS_PCI_X_DIAG_BUGCNTL_MASK 0x0000ffff00000000ULL #define XMS_PCI_X_DIAG_BUGCNTL_SHIFT 32 #define XMS_PCI_X_DIAG_SRCQ_MASK 0x00000000000000ffULL /* Controller configuration and status registers */ /* Note that these are shared on Schizo but per-PBM on Tomatillo. */ #define STX_CTRL_BUS_ERRLOG 0x00018 #define STX_CTRL_ECCCTRL 0x00020 #define STX_CTRL_UE_AFSR 0x00030 #define STX_CTRL_UE_AFAR 0x00038 #define STX_CTRL_CE_AFSR 0x00040 #define STX_CTRL_CE_AFAR 0x00048 #define STX_CTRL_PERF 0x07000 #define STX_CTRL_PERF_CNT 0x07008 /* Safari/JBus error log register */ #define STX_CTRL_BUS_ERRLOG_BADCMD 0x4000000000000000ULL #define SCZ_CTRL_BUS_ERRLOG_SSMDIS 0x2000000000000000ULL #define SCZ_CTRL_BUS_ERRLOG_BADMA 0x1000000000000000ULL #define SCZ_CTRL_BUS_ERRLOG_BADMB 0x0800000000000000ULL #define SCZ_CTRL_BUS_ERRLOG_BADMC 0x0400000000000000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_GR 0x0000000000200000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_PCI 0x0000000000100000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_RD 0x0000000000080000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_RDS 0x0000000000020000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_RDSA 0x0000000000010000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_OWN 0x0000000000008000ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_RDO 0x0000000000004000ULL #define SCZ_CTRL_BUS_ERRLOG_CPU1PS 0x0000000000002000ULL #define TOM_CTRL_BUS_ERRLOG_WDATA_PERR 0x0000000000002000ULL #define SCZ_CTRL_BUS_ERRLOG_CPU1PB 0x0000000000001000ULL #define TOM_CTRL_BUS_ERRLOG_CTRL_PERR 0x0000000000001000ULL #define SCZ_CTRL_BUS_ERRLOG_CPU0PS 0x0000000000000800ULL #define TOM_CTRL_BUS_ERRLOG_SNOOP_ERR 0x0000000000000800ULL #define SCZ_CTRL_BUS_ERRLOG_CPU0PB 0x0000000000000400ULL #define TOM_CTRL_BUS_ERRLOG_JBUS_ILL_B 0x0000000000000400ULL #define SCZ_CTRL_BUS_ERRLOG_CIQTO 0x0000000000000200ULL #define SCZ_CTRL_BUS_ERRLOG_LPQTO 0x0000000000000100ULL #define TOM_CTRL_BUS_ERRLOG_JBUS_ILL_C 0x0000000000000100ULL #define SCZ_CTRL_BUS_ERRLOG_SFPQTO 0x0000000000000080ULL #define SCZ_CTRL_BUS_ERRLOG_UFPQTO 0x0000000000000040ULL #define TOM_CTRL_BUS_ERRLOG_RD_PERR 0x0000000000000040ULL #define STX_CTRL_BUS_ERRLOG_APERR 0x0000000000000020ULL #define STX_CTRL_BUS_ERRLOG_UNMAP 0x0000000000000010ULL #define STX_CTRL_BUS_ERRLOG_BUSERR 0x0000000000000004ULL #define STX_CTRL_BUS_ERRLOG_TIMEOUT 0x0000000000000002ULL #define SCZ_CTRL_BUS_ERRLOG_ILL 0x0000000000000001ULL /* ECC control register */ #define STX_CTRL_ECCCTRL_EE 0x8000000000000000ULL #define STX_CTRL_ECCCTRL_UE 0x4000000000000000ULL #define STX_CTRL_ECCCTRL_CE 0x2000000000000000ULL /* Uncorrectable error asynchronous fault status register */ #define STX_CTRL_UE_AFSR_P_PIO 0x8000000000000000ULL #define STX_CTRL_UE_AFSR_P_DRD 0x4000000000000000ULL #define STX_CTRL_UE_AFSR_P_DWR 0x2000000000000000ULL #define STX_CTRL_UE_AFSR_S_PIO 0x1000000000000000ULL #define STX_CTRL_UE_AFSR_S_DRD 0x0800000000000000ULL #define STX_CTRL_UE_AFSR_S_DWR 0x0400000000000000ULL #define STX_CTRL_UE_AFSR_ERRPNDG 0x0300000000000000ULL #define STX_CTRL_UE_AFSR_BMASK 0x000003ff00000000ULL #define STX_CTRL_UE_AFSR_QOFF 0x00000000c0000000ULL #define STX_CTRL_UE_AFSR_AID 0x000000001f000000ULL #define STX_CTRL_UE_AFSR_PARTIAL 0x0000000000800000ULL #define STX_CTRL_UE_AFSR_OWNEDIN 0x0000000000400000ULL #define STX_CTRL_UE_AFSR_MTAGSYND 0x00000000000f0000ULL #define STX_CTRL_UE_AFSR_MTAG 0x000000000000e000ULL #define STX_CTRL_UE_AFSR_ECCSYND 0x00000000000001ffULL /* Correctable error asynchronous fault status register */ #define STX_CTRL_CE_AFSR_P_PIO 0x8000000000000000ULL #define STX_CTRL_CE_AFSR_P_DRD 0x4000000000000000ULL #define STX_CTRL_CE_AFSR_P_DWR 0x2000000000000000ULL #define STX_CTRL_CE_AFSR_S_PIO 0x1000000000000000ULL #define STX_CTRL_CE_AFSR_S_DRD 0x0800000000000000ULL #define STX_CTRL_CE_AFSR_S_DWR 0x0400000000000000ULL #define STX_CTRL_CE_AFSR_ERRPNDG 0x0300000000000000ULL #define STX_CTRL_CE_AFSR_BMASK 0x000003ff00000000ULL #define STX_CTRL_CE_AFSR_QOFF 0x00000000c0000000ULL #define STX_CTRL_CE_AFSR_AID 0x000000001f000000ULL #define STX_CTRL_CE_AFSR_PARTIAL 0x0000000000800000ULL #define STX_CTRL_CE_AFSR_OWNEDIN 0x0000000000400000ULL #define STX_CTRL_CE_AFSR_MTAGSYND 0x00000000000f0000ULL #define STX_CTRL_CE_AFSR_MTAG 0x000000000000e000ULL #define STX_CTRL_CE_AFSR_ECCSYND 0x00000000000001ffULL /* * Safari/JBus performance control register - * NB: for Tomatillo only events 0x00 through 0x08 are documented as + * NB: For Tomatillo only events 0x00 through 0x08 are documented as * implemented. */ #define SCZ_CTRL_PERF_ZDATA_OUT 0x0000000000000016ULL #define SCZ_CTRL_PERF_ZDATA_IN 0x0000000000000015ULL #define SCZ_CTRL_PERF_ORQFULL 0x0000000000000014ULL #define SCZ_CTRL_PERF_DVMA_WR 0x0000000000000013ULL #define SCZ_CTRL_PERF_DVMA_RD 0x0000000000000012ULL #define SCZ_CTRL_PERF_CYCPSESYS 0x0000000000000011ULL #define STX_CTRL_PERF_PCI_B 0x000000000000000fULL #define STX_CTRL_PERF_PCI_A 0x000000000000000eULL #define STX_CTRL_PERF_UPA 0x000000000000000dULL #define STX_CTRL_PERF_PIOINTRNL 0x000000000000000cULL #define TOM_CTRL_PERF_WRI_WRIS 0x000000000000000bULL #define STX_CTRL_PERF_INTRS 0x000000000000000aULL #define STX_CTRL_PERF_PRTLWRMRGBUF 0x0000000000000009ULL #define STX_CTRL_PERF_FGN_IO_HITS 0x0000000000000008ULL #define STX_CTRL_PERF_FGN_IO_TRNS 0x0000000000000007ULL #define STX_CTRL_PERF_OWN_CHRNT_HITS 0x0000000000000006ULL #define STX_CTRL_PERF_OWN_CHRNT_TRNS 0x0000000000000005ULL #define SCZ_CTRL_PERF_FGN_CHRNT_HITS 0x0000000000000004ULL #define STX_CTRL_PERF_FGN_CHRNT_TRNS 0x0000000000000003ULL #define STX_CTRL_PERF_CYCLES_PAUSE 0x0000000000000002ULL #define STX_CTRL_PERF_BUSCYC 0x0000000000000001ULL #define STX_CTRL_PERF_DIS 0x0000000000000000ULL #define STX_CTRL_PERF_CNT1_SHIFT 11 #define STX_CTRL_PERF_CNT0_SHIFT 4 /* Safari/JBus performance counter register */ #define STX_CTRL_PERF_CNT_MASK 0x00000000ffffffffULL #define STX_CTRL_PERF_CNT_CNT1_SHIFT 32 #define STX_CTRL_PERF_CNT_CNT0_SHIFT 0 /* INO defines */ #define STX_FB0_INO 0x2a /* FB0 int. shared w/ UPA64s */ #define STX_FB1_INO 0x2b /* FB1 int. shared w/ UPA64s */ #define STX_UE_INO 0x30 /* uncorrectable error */ #define STX_CE_INO 0x31 /* correctable error */ #define STX_PCIERR_A_INO 0x32 /* PCI bus A error */ #define STX_PCIERR_B_INO 0x33 /* PCI bus B error */ #define STX_BUS_INO 0x34 /* Safari/JBus error */ #define STX_CDMA_A_INO 0x35 /* PCI bus A CDMA */ #define STX_CDMA_B_INO 0x36 /* PCI bus B CDMA */ #define STX_MAX_INO 0x37 /* Device space defines */ #define STX_CONF_SIZE 0x1000000 #define STX_CONF_BUS_SHIFT 16 #define STX_CONF_DEV_SHIFT 11 #define STX_CONF_FUNC_SHIFT 8 #define STX_CONF_REG_SHIFT 0 #define STX_IO_SIZE 0x1000000 #define STX_MEM_SIZE 0x100000000 #define STX_CONF_OFF(bus, slot, func, reg) \ (((bus) << STX_CONF_BUS_SHIFT) | \ ((slot) << STX_CONF_DEV_SHIFT) | \ ((func) << STX_CONF_FUNC_SHIFT) | \ ((reg) << STX_CONF_REG_SHIFT)) /* Definitions for the Schizo/Tomatillo configuration space */ #define STX_CS_DEVICE 0 /* bridge CS device number */ #define STX_CS_FUNC 0 /* brdige CS function number */ /* Non-Standard registers in the configration space */ /* - * NB: for Tomatillo the secondary and subordinate bus number registers + * NB: For Tomatillo the secondary and subordinate bus number registers * apparently are read-only although documented otherwise; writing to * them just triggers a PCI bus error interrupt or has no effect at best. */ #define STX_CSR_SECBUS 0x40 /* secondary bus number */ #define STX_CSR_SUBBUS 0x41 /* subordinate bus number */ /* Width of the physical addresses the IOMMU translates to */ #define STX_IOMMU_BITS 43 #endif /* !_SPARC64_PCI_SCHIZOREG_H_ */ Index: head/sys/sparc64/pci/schizovar.h =================================================================== --- head/sys/sparc64/pci/schizovar.h (revision 287725) +++ head/sys/sparc64/pci/schizovar.h (revision 287726) @@ -1,99 +1,90 @@ /*- * Copyright (c) 2005 by Marius Strobl . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SPARC64_PCI_SCHIZOVAR_H_ #define _SPARC64_PCI_SCHIZOVAR_H_ struct schizo_softc; struct schizo_iommu_state { struct iommu_state sis_is; struct schizo_softc *sis_sc; }; struct schizo_softc { + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; + + struct schizo_iommu_state sc_is; struct bus_dma_methods sc_dma_methods; - device_t sc_dev; - struct mtx sc_sync_mtx; uint64_t sc_sync_val; struct mtx *sc_mtx; - phandle_t sc_node; + struct resource *sc_mem_res[TOM_NREG]; + struct resource *sc_irq_res[STX_NINTR]; + void *sc_ihand[STX_NINTR]; + SLIST_ENTRY(schizo_softc) sc_link; + + device_t sc_dev; + u_int sc_mode; #define SCHIZO_MODE_SCZ 0 #define SCHIZO_MODE_TOM 1 #define SCHIZO_MODE_XMS 2 u_int sc_flags; #define SCHIZO_FLAGS_BSWAR (1 << 0) #define SCHIZO_FLAGS_XMODE (1 << 1) bus_addr_t sc_cdma_map; bus_addr_t sc_cdma_clr; uint32_t sc_cdma_vec; uint32_t sc_cdma_state; #define SCHIZO_CDMA_STATE_IDLE (1 << 0) #define SCHIZO_CDMA_STATE_PENDING (1 << 1) #define SCHIZO_CDMA_STATE_RECEIVED (1 << 2) u_int sc_half; uint32_t sc_ign; uint32_t sc_ver; uint32_t sc_mrev; - struct resource *sc_mem_res[TOM_NREG]; - struct resource *sc_irq_res[STX_NINTR]; - void *sc_ihand[STX_NINTR]; - - struct schizo_iommu_state sc_is; - - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - bus_space_handle_t sc_pci_bh[STX_NRANGE]; - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - uint32_t sc_stats_dma_ce; uint32_t sc_stats_pci_non_fatal; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - struct ofw_bus_iinfo sc_pci_iinfo; - - SLIST_ENTRY(schizo_softc) sc_link; }; #endif /* !_SPARC64_PCI_SCHIZOVAR_H_ */