/* $OpenBSD: xbridge.c,v 1.96 2015/06/24 16:52:52 miod Exp $ */ /* * Copyright (c) 2008, 2009, 2011 Miodrag Vallat. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * XBow Bridge (as well as XBridge and PIC) Widget driver. */ /* * IMPORTANT AUTHOR'S NOTE: I did not write any of this code under the * influence of drugs. Looking back at that particular piece of hardware, * I wonder if this hasn't been a terrible mistake. */ /* xbridge 101 =========== There are three ASIC using this model: - Bridge, used on Octane and maybe early Origin 200 and 2000 systems. - XBridge, used on later Origin 200/2000 and Origin 300/3000 systems. - PIC, used on Origin 350/3500 systems. (for the record, Fuel is Origin 300 like and Tezro is Origin 350 like). Bridge and XBridge each appear as a single widget, supporting 8 PCI devices, while PIC appears as two contiguous widgets, each supporting 2 PCI-X devices. - - address space Each widget has a 36-bit address space. xbridge widgets only use 33 bits though. On Octane systems, the whole 36 bit address space is fully available. On all other systems, the low 16MB (24 bit) address space is always available, and access to arbitrary areas of the address space can be achieved by programming the Crossbow's IOTTE (I/O Translation Table Entries). IMPORTANT! there is a limited number of IOTTE per Crossbow: 7, of which the seventh is used to workaround a hardware bug, leaving only 6 entries available accross all widgets. Each IOTTE opens a contiguous window of 28 or 29 bits, depending on the particular system model and configuration. On Origin 300/3000 and 350/3500, this will always be 29 bit (512MB), while on Origin 200/2000 systems, this depends on the ``M mode vs N mode'' configuration. Most systems run in M mode (which is the default) which also allows for 29 bit; systems in N mode (allowing more than 64 nodes to be connected) can only provide 28 bit IOTTE windows (256MB). The widget address space is as follows: offset size description 0##0000##0000 0##0003##0000 registers 0##4000##0000 0##4000##0000 PCI memory space 1##0000##0000 1##0000##0000 PCI I/O space Note the PCI memory space is limited to 30 bit; this is supposedly hardware enforced, i.e. one may set the top two bits of 32-bit memory BAR and they would be ignored. The xbridge driver doesn't try this though (-: IMPORTANT! On Bridge (not XBridge) revision up to 3, the I/O space is not available (apparently this would be because of a hardware issue in the byteswap logic, causing it to return unpredictable values when accessing this address range). - - PCI resource mapping Each BAR value is an offset within the memory or I/O space (with the memory space being limited to 30 bits, or 1GB), *EXCEPT* when the value fits in one of the ``devio'' slots. So now is a good time to introduce the devio. There are 8 devio registers, one per device; theses registers contain various device-global flags (such as byte swapping and coherency), as well as the location of a ``devio window'' in one of the address spaces, selected on a per-devio basis. The devio register only programs the upper 12 bits of the 32 window base address, the low 20 bits being zero; the window size are fixed and depend on the given device: devices 0 and 1 have ``large'' windows of 2MB (0020##0000), while devices 2 to 7 have ``small'' windows of 1MB (0010##0000). Apparently there are some hidden rules about the upper 12 bits, though, and the rules differ on Octane vs Origin systems. This is why the address space, from the pci driver point of view, is split in three parts: there is the ``devio black hole'' where we must make sure that no BAR allocation crosses a devio boundary, and the rest of the address space (under the devio zone and above it). I am slowly moving away from the devio mappings the PROM leaves us in, and eventually I expect to be able to have more flexibility in their position. However there is the console uart mapping I don't want to change now, and - of course - we inherit it from the prom as a devio register for the IOC3 or IOC4 device. So currently, the extents I provide the MI code with span the 0->ffff##ffff address space, with only the following areas available: - each devio range, if configured for the given address space - on Octane, the whole memory or I/O space minus the 16MB area in which all devio mappings take place - on Origin, if we have an IOTTE mapping a part of the memory or I/O address space, the whole window minus the 16MB area in which all devio mappings take place. Now I need to make sure that the MI code will never allocate mappings crossing devio ranges. So during the Bridge setup, I am initializing ALL BAR on a device-by-device basis, working with smaller extents: - if the device can have all its resources of a given type (I/O or mem) fitting in a devio area, I configure a devio, and make it allocate from an extent spanning only the devio range. - if there are not enough devio (because the device might need two devio ranges, one for I/O resources and one for memory resources, and there are only 8 devio, and if the bus is populated there might not be enough unused devio slots to hijack), then allocation is done on the larger address space (granted on Octane, or provided with an IOTTE window on Origin), using an extent covering this area minus the 16MB area in which all devio mappings take place. So in either case, I am now sure that there are no resources crossing the devio boundaries, which are invisible to the MI code. This also explains why I am making sure that the devio ranges are close to each other - it makes the creation of the temporary resource extents simpler (bear in mind that a device might need resources from the IOTTE window before all devio ranges are set up). And of course to make things even less simple, the IOTTE allocation may fail (e.g. on a P-Brick with 6 XBridge chips on the same Crossbow), and if we are using an old revision Bridge, all I/O resources need to be allocated with devio (so we can't decide to get rid of them anyway). So, when it's time to configure further devices (for ppb and pccbb), I need the same trick to prevent resource allocation to cross devio boundaries. Actually, as far as pccbb is concerned, I give up entirely on resources if all I have is a devio to map within - at least for now, because the devio do not cover the 0000..ffff range in I/O space needed for pcmcia. So for the I/O resources, I give rbus the low 16 bits of the I/O extent (if available); as for the memory resources, I need to exclude the devio area, and since rbus currently only supports a single contiguous area, I give it the area starting after the devio range (which is, by far, the largest part of the at-least-256MB region). Do you need aspirin yet? - - DMA Device DMA addresses can be constructed in three ways: - direct 64 bit address - 32 bit address within a programmable 31 bit ``direct DMA'' window - 32 bit translated address using ATE (Address Translation Entries) direct 64 bit address: These are easy to construct (pick your memory address, set bit 56, and you're done), but these can only work with pci devices aware of 64 bit addresses. direct DMA window: There is a Bridge global register to define the base address of the window, and then we have 2GB available. This is what I am currently using, and convenient for PCI devices unable to use 64 bit DMA addresses. translated DMA: There is another 2GB window in which accesses are indirected through ATE, which can point anywhere in memory. ATE are IOMMU translation entries. PCI addresses in the translated window transparently map to the address their ATE point to. Bridge chip have 128 so-called `internal' entries, and can use their optional `external' SSRAM to provide more (up to 65536 entries with 512KB SSRAM). However, due to chip bugs, those `external' entries can not be updated while there is DMA in progress using external entries, even if the updated entries are not related to those used by the DMA transfer. XBridge chip extend the internal entries to 1024, but do not provide support for external entries. All ATE share the same page size, which is configurable as 4KB or 16KB. Due to the small number of ATE entries, and since you can not use part of the system's RAM to add entries as you need them (unlike hppa or sparc64), the driver no longer uses them, as there is nothing we can do when we run out of ATE. - - interrupts This is easy, for a change. There are 8 interrupt sources, one per device; pins A and C map of devices 0-7 map to interrupt sources 0-7, and pins B and D of devices 0-7 map to interrupt sources 4-7 then 0-3 (i.e. device# ^ 4). All interrupts occuring on the Bridge cause an XIO interrupt packet to be sent to the XIO interrupt address programmed at Bridge initialization time; packets can be configured as self-clearing or not on an interrupt source basis. Due to silicon bugs, interrupts can be lost if two interrupt sources interrupt within a too short interval; there is a documented workaround for this which consists of recognizing this situation and self-inflicting ourselves the lost interrupt (see details in xbridge_intr_handler() ). - - endianness Endianness control is quite finegrained and quite complex at first glance: - memory and I/O accesses not occuring within devio ranges have their endianness controlled by the endianness flags in the (global) Bridge configuration register... - ... to which adds the per-device endianness flag in the device devio register... - and accesses occuring through devio register only use the per-device devio register mentioned above, even if the devio range is defined in a different register! i.e. devio 0 = endianness control C0, devio range R0 devio 1 = endianness control C1, devio range R1 global Bridge = endianness control C2 1. access from device 0 to R0 uses C2^C0 2. access from device 0 to R1 uses C2^C0 3. access from device 0 outside R0 and R1 uses C2 4. access from device 1 to R0 uses C2^C1 5. access from device 1 to R1 uses C2^C1 6. access from device 1 outside R0 and R1 uses C1 (note that, the way I set up devio registers, cases 2 and 4 can never occur if both device 0 and device 1 are present) Now for DMA: - i don't remember what 64 bit DMA uses - direct DMA (within the 2GB window) uses a per-device bit in devio - translated DMA (using ATE) uses a per-device bit in devio if the chip is a Bridge, while XBridge and PIC use different DMA addresses (i.e. with a given ATE, there is one address pointing to it in non-swapped mode, and another address pointing to it in swapped mode). */ #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 #ifdef TGT_OCTANE #include #endif #include "cardbus.h" int xbridge_match(struct device *, void *, void *); void xbridge_attach(struct device *, struct device *, void *); int xbridge_print(void *, const char *); int xbridge_submatch(struct device *, void *, void *); int xbpci_match(struct device *, void *, void *); void xbpci_attach(struct device *, struct device *, void *); int xbpci_print(void *, const char *); struct xbridge_intr; struct xbpci_attach_args { uint xaa_busno; int xaa_flags; int16_t xaa_nasid; int xaa_widget; uint xaa_devio_skew; int xaa_revision; bus_space_tag_t xaa_regt; bus_addr_t xaa_offset; }; struct xbpci_softc { struct device xb_dev; struct device *xb_bow; /* * Bridge register accessors. * Due to hardware bugs, PIC registers can only be accessed * with 64 bit operations, although the hardware was supposed * to be directly compatible with XBridge on that aspect. */ uint64_t (*xb_read_reg)(bus_space_tag_t, bus_space_handle_t, bus_addr_t); void (*xb_write_reg)(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint64_t); uint xb_busno; uint xb_nslots; int xb_flags; #define XF_XBRIDGE 0x01 /* is either PIC or XBridge */ #define XF_PIC 0x02 /* is PIC */ #define XF_NO_DIRECT_IO 0x04 /* no direct I/O mapping */ #define XF_PCIX 0x08 /* bus in PCIX mode */ int16_t xb_nasid; int xb_widget; uint xb_devio_skew; /* upper bits of devio ARCS mappings */ int xb_revision; struct mips_pci_chipset xb_pc; bus_space_tag_t xb_regt; bus_space_handle_t xb_regh; struct mips_bus_space *xb_mem_bus_space; struct mips_bus_space *xb_mem_bus_space_sw; struct mips_bus_space *xb_io_bus_space; struct mips_bus_space *xb_io_bus_space_sw; struct machine_bus_dma_tag *xb_dmat; struct xbridge_intr *xb_intr[BRIDGE_NINTRS]; char xb_intrstr[BRIDGE_NINTRS][sizeof("irq #, xbow irq ###")]; int xb_err_intrsrc; int (*xb_pci_intr_handler)(void *); uint64_t xb_ier; /* copy of BRIDGE_IER value */ /* * Device information. */ struct { pcireg_t id; uint32_t devio; } xb_devices[MAX_SLOTS]; uint xb_devio_usemask; /* * Large resource view sizes */ bus_addr_t xb_iostart, xb_ioend; bus_addr_t xb_memstart, xb_memend; /* * Resource extents for the large resource views, used during * resource setup, then cleaned up for the MI code. */ char xb_ioexname[32]; struct extent *xb_ioex; char xb_memexname[32]; struct extent *xb_memex; }; struct xbridge_softc { struct device sc_dev; uint sc_nbuses; struct mips_bus_space sc_regt; }; #define DEVNAME(xb) ((xb)->xb_dev.dv_xname) #define PCI_ID_EMPTY PCI_ID_CODE(PCI_VENDOR_INVALID, 0xffff); #define SLOT_EMPTY(xb,dev) \ (PCI_VENDOR((xb)->xb_devices[dev].id) == PCI_VENDOR_INVALID || \ PCI_VENDOR((xb)->xb_devices[dev].id) == 0) const struct cfattach xbridge_ca = { sizeof(struct xbridge_softc), xbridge_match, xbridge_attach }; struct cfdriver xbridge_cd = { NULL, "xbridge", DV_DULL }; const struct cfattach xbpci_ca = { sizeof(struct xbpci_softc), xbpci_match, xbpci_attach }; struct cfdriver xbpci_cd = { NULL, "xbpci", DV_DULL }; void xbridge_attach_hook(struct device *, struct device *, struct pcibus_attach_args *); int xbridge_bus_maxdevs(void *, int); pcitag_t xbridge_make_tag(void *, int, int, int); void xbridge_decompose_tag(void *, pcitag_t, int *, int *, int *); int xbridge_conf_size(void *, pcitag_t); pcireg_t xbridge_conf_read(void *, pcitag_t, int); void xbridge_conf_write(void *, pcitag_t, int, pcireg_t); int xbridge_intr_map(struct pci_attach_args *, pci_intr_handle_t *); const char *xbridge_intr_string(void *, pci_intr_handle_t); void *xbridge_intr_establish(void *, pci_intr_handle_t, int, int (*func)(void *), void *, const char *); void xbridge_intr_disestablish(void *, void *); int xbridge_intr_line(void *, pci_intr_handle_t); int xbridge_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, bus_addr_t *, bus_addr_t *); int xbridge_probe_device_hook(void *, struct pci_attach_args *); void *xbridge_rbus_parent_io(struct pci_attach_args *); void *xbridge_rbus_parent_mem(struct pci_attach_args *); int xbridge_get_widget(void *); int xbridge_get_dl(void *, pcitag_t, struct sgi_device_location *); int xbridge_pci_intr_handler(void *); int xbridge_picv1_pci_intr_handler(void *); int xbridge_err_intr_handler(void *); uint8_t xbridge_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); uint16_t xbridge_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); void xbridge_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint8_t); void xbridge_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, uint16_t); void xbridge_read_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint8_t *, bus_size_t); void xbridge_write_raw_2(bus_space_tag_t, bus_space_handle_t, bus_addr_t, const uint8_t *, bus_size_t); void xbridge_read_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint8_t *, bus_size_t); void xbridge_write_raw_4(bus_space_tag_t, bus_space_handle_t, bus_addr_t, const uint8_t *, bus_size_t); void xbridge_read_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint8_t *, bus_size_t); void xbridge_write_raw_8(bus_space_tag_t, bus_space_handle_t, bus_addr_t, const uint8_t *, bus_size_t); int xbridge_space_map_devio(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); int xbridge_space_map_io(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); int xbridge_space_map_mem(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); int xbridge_space_region_devio(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *); int xbridge_space_region_io(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *); int xbridge_space_region_mem(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *); void xbridge_space_barrier(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_size_t, int); bus_addr_t xbridge_pa_to_device(paddr_t); paddr_t xbridge_device_to_pa(bus_addr_t); int xbridge_rbus_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); void xbridge_rbus_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t, bus_addr_t *); void xbridge_err_clear(struct xbpci_softc *, uint64_t); void xbridge_err_handle(struct xbpci_softc *, uint64_t); int xbridge_allocate_devio(struct xbpci_softc *, int, int); void xbridge_set_devio(struct xbpci_softc *, int, uint32_t, int); int xbridge_resource_explore(struct xbpci_softc *, pcitag_t, struct extent *, struct extent *); void xbridge_resource_manage(struct xbpci_softc *, pcitag_t, struct extent *, struct extent *); void xbridge_device_setup(struct xbpci_softc *, int, int, uint32_t); int xbridge_extent_chomp(struct xbpci_softc *, struct extent *); void xbridge_extent_setup(struct xbpci_softc *); struct extent * xbridge_mapping_setup(struct xbpci_softc *, int); void xbridge_resource_setup(struct xbpci_softc *); void xbridge_rrb_setup(struct xbpci_softc *, int); const char * xbridge_setup(struct xbpci_softc *); uint64_t bridge_read_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t); void bridge_write_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint64_t); uint64_t pic_read_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t); void pic_write_reg(bus_space_tag_t, bus_space_handle_t, bus_addr_t, uint64_t); static __inline__ uint64_t xbridge_read_reg(struct xbpci_softc *xb, bus_addr_t a) { return (*xb->xb_read_reg)(xb->xb_regt, xb->xb_regh, a); } static __inline__ void xbridge_write_reg(struct xbpci_softc *xb, bus_addr_t a, uint64_t v) { (*xb->xb_write_reg)(xb->xb_regt, xb->xb_regh, a, v); } static __inline__ void xbridge_wbflush(struct xbpci_softc *xb, uint d) { while (xbridge_read_reg(xb, BRIDGE_DEVICE_WBFLUSH(d)) != 0) ; } static const struct machine_bus_dma_tag xbridge_dma_tag = { NULL, /* _cookie */ _dmamap_create, _dmamap_destroy, _dmamap_load, _dmamap_load_mbuf, _dmamap_load_uio, _dmamap_load_raw, _dmamap_load_buffer, _dmamap_unload, _dmamap_sync, _dmamem_alloc, _dmamem_free, _dmamem_map, _dmamem_unmap, _dmamem_mmap, xbridge_pa_to_device, xbridge_device_to_pa, BRIDGE_DMA_DIRECT_LENGTH - 1 }; static const struct mips_pci_chipset xbridge_pci_chipset = { .pc_attach_hook = xbridge_attach_hook, .pc_bus_maxdevs = xbridge_bus_maxdevs, .pc_make_tag = xbridge_make_tag, .pc_decompose_tag = xbridge_decompose_tag, .pc_conf_size = xbridge_conf_size, .pc_conf_read = xbridge_conf_read, .pc_conf_write = xbridge_conf_write, .pc_probe_device_hook = xbridge_probe_device_hook, .pc_get_widget = xbridge_get_widget, .pc_get_dl = xbridge_get_dl, .pc_intr_map = xbridge_intr_map, .pc_intr_string = xbridge_intr_string, .pc_intr_establish = xbridge_intr_establish, .pc_intr_disestablish = xbridge_intr_disestablish, .pc_intr_line = xbridge_intr_line, .pc_ppb_setup = xbridge_ppb_setup, #if NCARDBUS > 0 .pc_rbus_parent_io = xbridge_rbus_parent_io, .pc_rbus_parent_mem = xbridge_rbus_parent_mem #endif }; /* ********************* Autoconf glue. */ static const struct { uint32_t vendor; uint32_t product; int flags; } xbridge_devices[] = { /* original Bridge */ { XBOW_VENDOR_SGI4, XBOW_PRODUCT_SGI4_BRIDGE, 0 }, /* XBridge */ { XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_XBRIDGE, XF_XBRIDGE }, /* PIC */ { XBOW_VENDOR_SGI3, XBOW_PRODUCT_SGI3_PIC, XF_PIC } }; int xbridge_match(struct device *parent, void *match, void *aux) { struct xbow_attach_args *xaa = aux; uint i; for (i = 0; i < nitems(xbridge_devices); i++) if (xaa->xaa_vendor == xbridge_devices[i].vendor && xaa->xaa_product == xbridge_devices[i].product) return 1; return 0; } void xbridge_attach(struct device *parent, struct device *self, void *aux) { struct xbridge_softc *sc = (struct xbridge_softc *)self; struct xbow_attach_args *xaa = aux; struct xbpci_attach_args xbpa; int flags; uint devio_skew; uint i; printf(" revision %d\n", xaa->xaa_revision); for (i = 0; i < nitems(xbridge_devices); i++) if (xaa->xaa_vendor == xbridge_devices[i].vendor && xaa->xaa_product == xbridge_devices[i].product) { flags = xbridge_devices[i].flags; break; } /* PICs are XBridges without an I/O window */ if (ISSET(flags, XF_PIC)) SET(flags, XF_XBRIDGE | XF_NO_DIRECT_IO); /* Bridge < D lacks an I/O window */ if (!ISSET(flags, XF_XBRIDGE) && xaa->xaa_revision < 4) SET(flags, XF_NO_DIRECT_IO); /* * Figure out where the ARCS devio mappings will go. * ARCS configures all the devio in a contiguous 16MB area * (i.e. the upper 8 bits of the DEVIO_BASE field of the * devio registers are the same). * * In order to make our life simpler, on widgets where we may * want to keep some of the ARCS mappings (because that's where * our console device lives), we will use the same 16MB area. * * Otherwise, we can use whatever values we want; to keep the * code simpler, we will nevertheless use a 16MB area as well, * making sure it does not start at zero so that pcmcia bridges * can be used. * * On Octane, the upper bits of ARCS mappings are zero, and thus * point to the start of the widget. On Origin, they match the * widget number. */ #ifdef TGT_OCTANE if (sys_config.system_type == SGI_OCTANE && xaa->xaa_widget == IP30_BRIDGE_WIDGET) devio_skew = 0; else #endif devio_skew = xaa->xaa_widget; sc->sc_nbuses = ISSET(flags, XF_PIC) ? PIC_NBUSES : BRIDGE_NBUSES; /* make a permanent copy of the on-stack bus_space_tag */ bcopy(xaa->xaa_iot, &sc->sc_regt, sizeof(struct mips_bus_space)); /* configure and attach PCI buses */ for (i = 0; i < sc->sc_nbuses; i++) { xbpa.xaa_busno = i; xbpa.xaa_flags = flags; xbpa.xaa_nasid = xaa->xaa_nasid; xbpa.xaa_widget = xaa->xaa_widget; xbpa.xaa_devio_skew = devio_skew; xbpa.xaa_revision = xaa->xaa_revision; xbpa.xaa_regt = &sc->sc_regt; xbpa.xaa_offset = i != 0 ? BRIDGE_BUS_OFFSET : 0; config_found_sm(&sc->sc_dev, &xbpa, xbridge_print, xbridge_submatch); } } int xbridge_submatch(struct device *parent, void *vcf, void *aux) { struct cfdata *cf = vcf; struct xbpci_attach_args *xaa = aux; if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != xaa->xaa_busno) return 0; return (*cf->cf_attach->ca_match)(parent, vcf, aux); } int xbridge_print(void *aux, const char *pnp) { struct xbpci_attach_args *xaa = aux; if (pnp) printf("xbpci at %s", pnp); printf(" bus %d", xaa->xaa_busno); return UNCONF; } int xbpci_match(struct device *parent, void *vcf, void *aux) { return 1; } void xbpci_attach(struct device *parent, struct device *self, void *aux) { struct xbpci_softc *xb = (struct xbpci_softc *)self; struct xbpci_attach_args *xaa = (struct xbpci_attach_args *)aux; struct pcibus_attach_args pba; const char *errmsg = NULL; printf(": "); /* xbow -> xbridge -> xbpci: xbow device is our grandfather */ xb->xb_bow = parent->dv_parent; xb->xb_busno = xaa->xaa_busno; xb->xb_flags = xaa->xaa_flags; xb->xb_nasid = xaa->xaa_nasid; xb->xb_widget = xaa->xaa_widget; xb->xb_devio_skew = xaa->xaa_devio_skew; xb->xb_revision = xaa->xaa_revision; if (ISSET(xb->xb_flags, XF_PIC)) { xb->xb_nslots = PIC_NSLOTS; xb->xb_read_reg = pic_read_reg; xb->xb_write_reg = pic_write_reg; } else { xb->xb_nslots = BRIDGE_NSLOTS; xb->xb_read_reg = bridge_read_reg; xb->xb_write_reg = bridge_write_reg; } /* * Revision 1 of PIC requires a wrapper around * xbridge_pci_intr_handler(). */ if (ISSET(xb->xb_flags, XF_PIC) && xb->xb_revision <= 1) xb->xb_pci_intr_handler = xbridge_picv1_pci_intr_handler; else xb->xb_pci_intr_handler = xbridge_pci_intr_handler; /* * Map Bridge registers. */ xb->xb_regt = xaa->xaa_regt; if (bus_space_map(xaa->xaa_regt, xaa->xaa_offset, BRIDGE_REGISTERS_SIZE, 0, &xb->xb_regh)) { printf("unable to map control registers\n"); return; } /* * Create bus_space accessors... we inherit them from xbow, but * need to overwrite mapping routines, and set up byteswapping * versions. */ xb->xb_mem_bus_space = malloc(sizeof (*xb->xb_mem_bus_space), M_DEVBUF, M_NOWAIT); xb->xb_mem_bus_space_sw = malloc(sizeof (*xb->xb_mem_bus_space_sw), M_DEVBUF, M_NOWAIT); xb->xb_io_bus_space = malloc(sizeof (*xb->xb_io_bus_space), M_DEVBUF, M_NOWAIT); xb->xb_io_bus_space_sw = malloc(sizeof (*xb->xb_io_bus_space_sw), M_DEVBUF, M_NOWAIT); if (xb->xb_mem_bus_space == NULL || xb->xb_mem_bus_space_sw == NULL || xb->xb_io_bus_space == NULL || xb->xb_io_bus_space_sw == NULL) goto fail1; bcopy(xb->xb_regt, xb->xb_mem_bus_space, sizeof(*xb->xb_mem_bus_space)); xb->xb_mem_bus_space->bus_private = xb; xb->xb_mem_bus_space->_space_map = xbridge_space_map_devio; xb->xb_mem_bus_space->_space_subregion = xbridge_space_region_devio; xb->xb_mem_bus_space->_space_barrier = xbridge_space_barrier; bcopy(xb->xb_mem_bus_space, xb->xb_mem_bus_space_sw, sizeof(*xb->xb_mem_bus_space)); xb->xb_mem_bus_space_sw->_space_read_1 = xbridge_read_1; xb->xb_mem_bus_space_sw->_space_write_1 = xbridge_write_1; xb->xb_mem_bus_space_sw->_space_read_2 = xbridge_read_2; xb->xb_mem_bus_space_sw->_space_write_2 = xbridge_write_2; xb->xb_mem_bus_space_sw->_space_read_raw_2 = xbridge_read_raw_2; xb->xb_mem_bus_space_sw->_space_write_raw_2 = xbridge_write_raw_2; xb->xb_mem_bus_space_sw->_space_read_raw_4 = xbridge_read_raw_4; xb->xb_mem_bus_space_sw->_space_write_raw_4 = xbridge_write_raw_4; xb->xb_mem_bus_space_sw->_space_read_raw_8 = xbridge_read_raw_8; xb->xb_mem_bus_space_sw->_space_write_raw_8 = xbridge_write_raw_8; bcopy(xb->xb_regt, xb->xb_io_bus_space, sizeof(*xb->xb_io_bus_space)); xb->xb_io_bus_space->bus_private = xb; xb->xb_io_bus_space->_space_map = xbridge_space_map_devio; xb->xb_io_bus_space->_space_subregion = xbridge_space_region_devio; xb->xb_io_bus_space->_space_barrier = xbridge_space_barrier; bcopy(xb->xb_io_bus_space, xb->xb_io_bus_space_sw, sizeof(*xb->xb_io_bus_space)); xb->xb_io_bus_space_sw->_space_read_1 = xbridge_read_1; xb->xb_io_bus_space_sw->_space_write_1 = xbridge_write_1; xb->xb_io_bus_space_sw->_space_read_2 = xbridge_read_2; xb->xb_io_bus_space_sw->_space_write_2 = xbridge_write_2; xb->xb_io_bus_space_sw->_space_read_raw_2 = xbridge_read_raw_2; xb->xb_io_bus_space_sw->_space_write_raw_2 = xbridge_write_raw_2; xb->xb_io_bus_space_sw->_space_read_raw_4 = xbridge_read_raw_4; xb->xb_io_bus_space_sw->_space_write_raw_4 = xbridge_write_raw_4; xb->xb_io_bus_space_sw->_space_read_raw_8 = xbridge_read_raw_8; xb->xb_io_bus_space_sw->_space_write_raw_8 = xbridge_write_raw_8; xb->xb_dmat = malloc(sizeof (*xb->xb_dmat), M_DEVBUF, M_NOWAIT); if (xb->xb_dmat == NULL) goto fail1; memcpy(xb->xb_dmat, &xbridge_dma_tag, sizeof(*xb->xb_dmat)); xb->xb_dmat->_cookie = xb; /* * Initialize PCI methods. */ bcopy(&xbridge_pci_chipset, &xb->xb_pc, sizeof(xbridge_pci_chipset)); xb->xb_pc.pc_conf_v = xb; xb->xb_pc.pc_intr_v = xb; /* * Configure Bridge for proper operation (DMA, I/O mappings, * RRB allocation, etc). */ if ((errmsg = xbridge_setup(xb)) != NULL) goto fail2; printf("\n"); /* * Attach children. */ xbridge_extent_setup(xb); bzero(&pba, sizeof(pba)); pba.pba_busname = "pci"; /* * XXX pba_iot and pba_memt ought to be irrelevant, since we * XXX return the tags a device needs in probe_device_hook(); * XXX however the pci(4) device needs a valid pba_memt for the * XXX PCIOCGETROM* ioctls. * XXX * XXX Since most devices will need the byteswap tags, and those * XXX which don't do not have PCI roms, let's pass the byteswap * XXX versions by default. */ pba.pba_iot = xb->xb_io_bus_space_sw; pba.pba_memt = xb->xb_mem_bus_space_sw; pba.pba_dmat = xb->xb_dmat; pba.pba_ioex = xb->xb_ioex; pba.pba_memex = xb->xb_memex; #ifdef DEBUG if (xb->xb_ioex != NULL) extent_print(xb->xb_ioex); if (xb->xb_memex != NULL) extent_print(xb->xb_memex); #endif pba.pba_pc = &xb->xb_pc; pba.pba_domain = pci_ndomains++; pba.pba_bus = 0; config_found(self, &pba, xbpci_print); return; fail2: free(xb->xb_dmat, M_DEVBUF, 0); fail1: if (xb->xb_io_bus_space_sw != NULL) free(xb->xb_io_bus_space_sw, M_DEVBUF, 0); if (xb->xb_io_bus_space != NULL) free(xb->xb_io_bus_space, M_DEVBUF, 0); if (xb->xb_mem_bus_space_sw != NULL) free(xb->xb_mem_bus_space_sw, M_DEVBUF, 0); if (xb->xb_mem_bus_space != NULL) free(xb->xb_mem_bus_space, M_DEVBUF, 0); if (errmsg == NULL) errmsg = "not enough memory to build bus access structures"; printf("%s\n", errmsg); } int xbpci_print(void *aux, const char *pnp) { struct pcibus_attach_args *pba = aux; if (pnp) printf("%s at %s", pba->pba_busname, pnp); printf(" bus %d", pba->pba_bus); return UNCONF; } /* ********************* PCI glue. */ void xbridge_attach_hook(struct device *parent, struct device *self, struct pcibus_attach_args *pba) { } pcitag_t xbridge_make_tag(void *cookie, int bus, int dev, int func) { return (bus << 16) | (dev << 11) | (func << 8); } void xbridge_decompose_tag(void *cookie, pcitag_t tag, int *busp, int *devp, int *funcp) { if (busp != NULL) *busp = (tag >> 16) & 0xff; if (devp != NULL) *devp = (tag >> 11) & 0x1f; if (funcp != NULL) *funcp = (tag >> 8) & 0x7; } int xbridge_bus_maxdevs(void *cookie, int busno) { struct xbpci_softc *xb = cookie; return busno == 0 ? xb->xb_nslots : 32; } int xbridge_conf_size(void *cookie, pcitag_t tag) { #if 0 struct xbpci_softc *xb = cookie; int bus, dev, fn; xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn); /* * IOC3 devices only implement a subset of the PCI configuration * registers. Although xbridge_conf_{read,write} correctly * handle the unimplemented registers, better provide a limited * configuration space to userland. */ if (bus == 0 && xb->xb_devices[dev].id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) return PCI_INTERRUPT_REG + 4; #endif return PCI_CONFIG_SPACE_SIZE; } pcireg_t xbridge_conf_read(void *cookie, pcitag_t tag, int offset) { struct xbpci_softc *xb = cookie; pcireg_t data; int bus, dev, fn; paddr_t pa; int skip; int s; xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn); /* * IOC3 devices only implement a subset of the PCI configuration * registers (supposedly only the first 0x20 bytes, however * writing to the second BAR also writes to the first). * * Depending on which particular model we encounter, things may * seem to work, or write access to nonexisting registers would * completely freeze the machine. * * We thus check for the device type here, and handle the non * existing registers ourselves. */ skip = 0; if (bus == 0 && xb->xb_devices[dev].id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) { switch (offset) { case PCI_ID_REG: case PCI_COMMAND_STATUS_REG: case PCI_CLASS_REG: case PCI_BHLC_REG: case PCI_MAPREG_START: /* These registers are implemented. Go ahead. */ break; case PCI_INTERRUPT_REG: /* This register is not implemented. Fake it. */ data = (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT) | (dev << PCI_INTERRUPT_LINE_SHIFT); skip = 1; break; default: /* These registers are not implemented. */ data = 0; skip = 1; break; } } if (skip == 0) { /* * Disable interrupts on this bridge (especially error * interrupts). */ s = splhigh(); xbridge_write_reg(xb, BRIDGE_IER, 0); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); if (bus != 0) { xbridge_write_reg(xb, BRIDGE_PCI_CFG, (bus << 16) | (dev << 11)); pa = xb->xb_regh + BRIDGE_PCI_CFG1_SPACE; } else { /* * On PIC, device 0 in configuration space is the * PIC itself, device slots are offset by one. */ if (ISSET(xb->xb_flags, XF_PIC)) dev++; pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + (dev << 12); } pa += (fn << 8) + offset; if (guarded_read_4(pa, &data) != 0) data = 0xffffffff; xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); splx(s); } return data; } void xbridge_conf_write(void *cookie, pcitag_t tag, int offset, pcireg_t data) { struct xbpci_softc *xb = cookie; int bus, dev, fn; paddr_t pa; int skip; int s; xbridge_decompose_tag(cookie, tag, &bus, &dev, &fn); /* * IOC3 devices only implement a subset of the PCI configuration * registers. * Depending on which particular model we encounter, things may * seem to work, or write access to nonexisting registers would * completely freeze the machine. * * We thus check for the device type here, and handle the non * existing registers ourselves. */ skip = 0; if (bus == 0 && xb->xb_devices[dev].id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) { switch (offset) { case PCI_COMMAND_STATUS_REG: /* * Some IOC3 models do not support having this bit * cleared (which is what pci_mapreg_probe() will * do), so we set it unconditionnaly. */ data |= PCI_COMMAND_MEM_ENABLE; /* FALLTHROUGH */ case PCI_ID_REG: case PCI_CLASS_REG: case PCI_BHLC_REG: case PCI_MAPREG_START: /* These registers are implemented. Go ahead. */ break; default: /* These registers are not implemented. */ skip = 1; break; } } if (skip == 0) { /* * Disable interrupts on this bridge (especially error * interrupts). */ s = splhigh(); xbridge_write_reg(xb, BRIDGE_IER, 0); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); if (bus != 0) { xbridge_write_reg(xb, BRIDGE_PCI_CFG, (bus << 16) | (dev << 11)); pa = xb->xb_regh + BRIDGE_PCI_CFG1_SPACE; } else { /* * On PIC, device 0 in configuration space is the * PIC itself, device slots are offset by one. */ if (ISSET(xb->xb_flags, XF_PIC)) dev++; pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + (dev << 12); } pa += (fn << 8) + offset; guarded_write_4(pa, data); xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); splx(s); } } int xbridge_probe_device_hook(void *cookie, struct pci_attach_args *pa) { struct xbpci_softc *xb = cookie; /* * Check for the hardware byteswap setting of the device we are * interested in, and pick bus_space_tag accordingly. * Note that the device list here must match xbridge_resource_setup(). */ if (pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) || pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC4) || pa->pa_id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1)) { pa->pa_iot = xb->xb_io_bus_space; pa->pa_memt = xb->xb_mem_bus_space; } else { pa->pa_iot = xb->xb_io_bus_space_sw; pa->pa_memt = xb->xb_mem_bus_space_sw; } return 0; } int xbridge_get_widget(void *cookie) { struct xbpci_softc *xb = cookie; return xb->xb_widget; } int xbridge_get_dl(void *cookie, pcitag_t tag, struct sgi_device_location *sdl) { int bus, device, fn; struct xbpci_softc *xb = cookie; xbridge_decompose_tag(cookie, tag, &bus, &device, &fn); if (bus != 0) return 0; sdl->nasid = xb->xb_nasid; sdl->widget = xb->xb_widget; sdl->bus = xb->xb_busno; sdl->device = device; sdl->fn = fn; return 1; } /* ********************* Interrupt handling. */ /* * We map each slot to its own interrupt bit, which will in turn be routed to * the Heart or Hub widget in charge of interrupt processing. */ struct xbridge_intrhandler { LIST_ENTRY(xbridge_intrhandler) xih_nxt; struct xbridge_intr *xih_main; int (*xih_func)(void *); void *xih_arg; struct evcount xih_count; int xih_level; int xih_device; /* device slot number */ }; struct xbridge_intr { struct xbpci_softc *xi_bus; int xi_intrsrc; /* interrupt source on interrupt widget */ int xi_intrbit; /* interrupt source on BRIDGE */ LIST_HEAD(, xbridge_intrhandler) xi_handlers; }; /* how our pci_intr_handle_t are constructed... */ #define XBRIDGE_INTR_VALID 0x100 #define XBRIDGE_INTR_HANDLE(d,b) (XBRIDGE_INTR_VALID | ((d) << 3) | (b)) #define XBRIDGE_INTR_DEVICE(h) (((h) >> 3) & 07) #define XBRIDGE_INTR_BIT(h) ((h) & 07) int xbridge_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) { struct xbpci_softc *xb = pa->pa_pc->pc_conf_v; int bus, device, intr; int pin; *ihp = 0; if (pa->pa_intrpin == 0) { /* No IRQ used. */ return 1; } #ifdef DIAGNOSTIC if (pa->pa_intrpin > 4) { printf("%s: bad interrupt pin %d\n", __func__, pa->pa_intrpin); return 1; } #endif pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &device, NULL); if (pa->pa_bridgetag) { pin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, device); if (!ISSET(pa->pa_bridgeih[pin - 1], XBRIDGE_INTR_VALID)) return 0; intr = XBRIDGE_INTR_BIT(pa->pa_bridgeih[pin - 1]); } else { /* * For IOC3 devices, pin A is always the regular PCI interrupt, * but wiring of interrupt pin B may vary. * We rely upon ioc(4) being able to figure out whether it's * an onboard chip or not, and to require interrupt pin D * instead of B in the former case. */ intr = -1; if (xb->xb_devices[device].id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3)) { switch (pa->pa_intrpin) { case PCI_INTERRUPT_PIN_A: case PCI_INTERRUPT_PIN_B: break; case PCI_INTERRUPT_PIN_D: /* * If this device is an onboard IOC3, * interrupt pin B is wired as pin A of * the first empty PCI slot... */ for (intr = 0; intr < MAX_SLOTS; intr++) if (SLOT_EMPTY(xb, intr)) break; /* should not happen, but fallback anyway */ if (intr >= MAX_SLOTS) intr = -1; break; default: return 1; } } if (intr < 0) { if (pa->pa_intrpin & 1) intr = device; else intr = device ^ 4; } } *ihp = XBRIDGE_INTR_HANDLE(device, intr); return 0; } const char * xbridge_intr_string(void *cookie, pci_intr_handle_t ih) { struct xbpci_softc *xb = (struct xbpci_softc *)cookie; int intrbit = XBRIDGE_INTR_BIT(ih); if (xb->xb_intrstr[intrbit][0] == '\0') snprintf(xb->xb_intrstr[intrbit], sizeof xb->xb_intrstr[intrbit], "irq %ld", ih); return xb->xb_intrstr[intrbit]; } void * xbridge_intr_establish(void *cookie, pci_intr_handle_t ih, int level, int (*func)(void *), void *arg, const char *name) { struct xbpci_softc *xb = (struct xbpci_softc *)cookie; struct xbridge_intr *xi; struct xbridge_intrhandler *xih; uint64_t int_addr; int intrbit = XBRIDGE_INTR_BIT(ih); int device = XBRIDGE_INTR_DEVICE(ih); int intrsrc; int new; /* * Allocate bookkeeping structure if this is the * first time we're using this interrupt source. */ if ((xi = xb->xb_intr[intrbit]) == NULL) { xi = (struct xbridge_intr *) malloc(sizeof(*xi), M_DEVBUF, M_NOWAIT); if (xi == NULL) return NULL; xi->xi_bus = xb; xi->xi_intrbit = intrbit; LIST_INIT(&xi->xi_handlers); if (xbow_intr_register(xb->xb_widget, level, &intrsrc) != 0) { free(xi, M_DEVBUF, 0); return NULL; } xi->xi_intrsrc = intrsrc; xb->xb_intr[intrbit] = xi; snprintf(xb->xb_intrstr[intrbit], sizeof xb->xb_intrstr[intrbit], "irq %d, xbow irq %d", intrbit, intrsrc); } else intrsrc = xi->xi_intrsrc; /* * Register the interrupt at the Heart or Hub level if this is the * first time we're using this interrupt source. */ new = LIST_EMPTY(&xi->xi_handlers); if (new) { /* * XXX The interrupt dispatcher is always registered * XXX at IPL_BIO, in case the interrupt will be shared * XXX between devices of different levels. */ if (xbow_intr_establish(xb->xb_pci_intr_handler, xi, intrsrc, IPL_BIO, NULL, NULL)) { printf("%s: unable to register interrupt handler\n", DEVNAME(xb)); return NULL; } } xih = (struct xbridge_intrhandler *) malloc(sizeof(*xih), M_DEVBUF, M_NOWAIT); if (xih == NULL) return NULL; xih->xih_main = xi; xih->xih_func = func; xih->xih_arg = arg; xih->xih_level = level; xih->xih_device = device; evcount_attach(&xih->xih_count, name, &xi->xi_intrsrc); LIST_INSERT_HEAD(&xi->xi_handlers, xih, xih_nxt); if (new) { /* * Note that, while PIC uses a complete XIO address, * Bridge will only store the interrupt source and high * bits of the address, and will reuse the widget interrupt * address for the low 38 bits of the XIO address. */ if (ISSET(xb->xb_flags, XF_PIC)) int_addr = ((uint64_t)intrsrc << 48) | (xbow_intr_address & ((1UL << 48) - 1)); else int_addr = ((xbow_intr_address >> 30) & 0x0003ff00) | intrsrc; xb->xb_ier |= 1L << intrbit; xbridge_write_reg(xb, BRIDGE_INT_ADDR(intrbit), int_addr); xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); /* * INT_MODE register controls which interrupt pins cause * ``interrupt clear'' packets to be sent for high->low * transition. * We enable such packets to be sent in order not to have to * clear interrupts ourselves. */ xbridge_write_reg(xb, BRIDGE_INT_MODE, xbridge_read_reg(xb, BRIDGE_INT_MODE) | (1 << intrbit)); xbridge_write_reg(xb, BRIDGE_INT_DEV, xbridge_read_reg(xb, BRIDGE_INT_DEV) | (device << (intrbit * 3))); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); } return (void *)xih; } void xbridge_intr_disestablish(void *cookie, void *vih) { struct xbpci_softc *xb = cookie; struct xbridge_intrhandler *xih = (struct xbridge_intrhandler *)vih; struct xbridge_intr *xi = xih->xih_main; int intrbit = xi->xi_intrbit; evcount_detach(&xih->xih_count); LIST_REMOVE(xih, xih_nxt); if (LIST_EMPTY(&xi->xi_handlers)) { xb->xb_ier &= ~(1 << intrbit); xbridge_write_reg(xb, BRIDGE_INT_ADDR(intrbit), 0); xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); xbridge_write_reg(xb, BRIDGE_INT_MODE, xbridge_read_reg(xb, BRIDGE_INT_MODE) & ~(1 << intrbit)); xbridge_write_reg(xb, BRIDGE_INT_DEV, xbridge_read_reg(xb, BRIDGE_INT_DEV) & ~(7 << (intrbit * 3))); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); xbow_intr_disestablish(xi->xi_intrsrc); /* * Note we could free xb->xb_intr[intrbit] at this point, * but it's not really worth doing. */ } free(xih, M_DEVBUF, 0); } int xbridge_intr_line(void *cookie, pci_intr_handle_t ih) { return XBRIDGE_INTR_BIT(ih); } int xbridge_err_intr_handler(void *v) { struct xbpci_softc *xb = (struct xbpci_softc *)v; uint64_t isr; isr = xbridge_read_reg(xb, BRIDGE_ISR) & ~BRIDGE_ISR_HWINTR_MASK; xbridge_err_handle(xb, isr); xbow_intr_clear(xb->xb_err_intrsrc); return 1; } int xbridge_pci_intr_handler(void *v) { struct xbridge_intr *xi = (struct xbridge_intr *)v; struct xbpci_softc *xb = xi->xi_bus; struct xbridge_intrhandler *xih; int rc; uint64_t isr; /* XXX shouldn't happen, and assumes interrupt is not shared */ if (LIST_EMPTY(&xi->xi_handlers)) { printf("%s: spurious irq %d\n", DEVNAME(xb), xi->xi_intrbit); return 0; } /* * Flush PCI write buffers before servicing the interrupt. */ LIST_FOREACH(xih, &xi->xi_handlers, xih_nxt) xbridge_wbflush(xb, xih->xih_device); isr = xbridge_read_reg(xb, BRIDGE_ISR); if ((isr & ~BRIDGE_ISR_HWINTR_MASK) != 0) { /* * This is an error interrupt triggered by a particular * device. */ xbridge_err_handle(xb, isr & ~BRIDGE_ISR_HWINTR_MASK); if ((isr &= BRIDGE_ISR_HWINTR_MASK) == 0) return 1; } if ((isr & (1L << xi->xi_intrbit)) == 0) { /* * May be a result of the lost interrupt workaround (see * near the end of this function); don't complain in that * case. */ rc = -1; #ifdef DEBUG printf("%s: irq %d but not pending in ISR %08x\n", DEVNAME(xb), xi->xi_intrbit, isr); #endif } else { rc = 0; LIST_FOREACH(xih, &xi->xi_handlers, xih_nxt) { splraise(xih->xih_level); if ((*xih->xih_func)(xih->xih_arg) != 0) { xih->xih_count.ec_count++; rc = 1; } /* * No need to lower spl here, as our caller will * lower spl upon our return. * However that splraise() is necessary so that * interrupt handler code calling splx() will not * cause our interrupt source to be unmasked. */ } /* XXX assumes interrupt is not shared */ if (rc == 0) printf("%s: spurious irq %d\n", DEVNAME(xb), xi->xi_intrbit); } /* * There is a known BRIDGE race in which, if two interrupts * on two different pins occur within 60nS of each other, * further interrupts on the first pin do not cause an * interrupt to be sent. * * The workaround against this is to check if our interrupt * source is still active (i.e. another interrupt is pending), * in which case we force an interrupt anyway. * * The XBridge even has a nice facility to do this, where we * do not even have to check if our interrupt is pending. */ if (ISSET(xb->xb_flags, XF_XBRIDGE)) { xbridge_write_reg(xb, BRIDGE_INT_FORCE_PIN(xi->xi_intrbit), 1); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); } else { if (xbridge_read_reg(xb, BRIDGE_ISR) & (1 << xi->xi_intrbit)) xbow_intr_set(xi->xi_intrsrc); } return rc; } int xbridge_picv1_pci_intr_handler(void *v) { struct xbridge_intr *xi = (struct xbridge_intr *)v; struct xbpci_softc *xb = xi->xi_bus; /* * Revision 1 of PIC is supposed to need the interrupt enable bit * to be toggled to prevent loss of interrupt. */ xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier & ~(1L << xi->xi_intrbit)); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); return xbridge_pci_intr_handler(v); } /* ********************* chip register access. */ uint64_t bridge_read_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a) { return (uint64_t)widget_read_4(t, h, a); } void bridge_write_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a, uint64_t v) { widget_write_4(t, h, a, (uint32_t)v); } uint64_t pic_read_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a) { return widget_read_8(t, h, a); } void pic_write_reg(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t a, uint64_t v) { widget_write_8(t, h, a, v); } /* ********************* bus_space glue. */ uint8_t xbridge_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) { return *(volatile uint8_t *)((h + o) ^ 3); } uint16_t xbridge_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) { return *(volatile uint16_t *)((h + o) ^ 2); } void xbridge_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t v) { *(volatile uint8_t *)((h + o) ^ 3) = v; } void xbridge_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t v) { *(volatile uint16_t *)((h + o) ^ 2) = v; } void xbridge_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, uint8_t *buf, bus_size_t len) { volatile uint16_t *addr = (volatile uint16_t *)((h + o) ^ 2); len >>= 1; while (len-- != 0) { *(uint16_t *)buf = letoh16(*addr); buf += 2; } } void xbridge_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, const uint8_t *buf, bus_size_t len) { volatile uint16_t *addr = (volatile uint16_t *)((h + o) ^ 2); len >>= 1; while (len-- != 0) { *addr = htole16(*(uint16_t *)buf); buf += 2; } } void xbridge_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, uint8_t *buf, bus_size_t len) { volatile uint32_t *addr = (volatile uint32_t *)(h + o); len >>= 2; while (len-- != 0) { *(uint32_t *)buf = letoh32(*addr); buf += 4; } } void xbridge_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, const uint8_t *buf, bus_size_t len) { volatile uint32_t *addr = (volatile uint32_t *)(h + o); len >>= 2; while (len-- != 0) { *addr = htole32(*(uint32_t *)buf); buf += 4; } } void xbridge_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, uint8_t *buf, bus_size_t len) { volatile uint64_t *addr = (volatile uint64_t *)(h + o); len >>= 3; while (len-- != 0) { *(uint64_t *)buf = letoh64(*addr); buf += 8; } } void xbridge_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, const uint8_t *buf, bus_size_t len) { volatile uint64_t *addr = (volatile uint64_t *)(h + o); len >>= 3; while (len-- != 0) { *addr = htole64(*(uint64_t *)buf); buf += 8; } } int xbridge_space_map_devio(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, bus_space_handle_t *bshp) { struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; bus_addr_t bpa; #ifdef DIAGNOSTIC bus_addr_t start, end; uint d; #endif if ((offs >> 24) != xb->xb_devio_skew) return EINVAL; /* not a devio mapping */ /* * Figure out which devio `slot' we are using, and make sure * we do not overrun it. */ bpa = offs & ((1UL << 24) - 1); #ifdef DIAGNOSTIC for (d = 0; d < xb->xb_nslots; d++) { start = PIC_DEVIO_OFFS(xb->xb_busno, d); end = start + BRIDGE_DEVIO_SIZE(d); if (bpa >= start && bpa < end) { if (bpa + size > end) return EINVAL; else break; } } if (d == xb->xb_nslots) return EINVAL; #endif /* * Note we can not use our own bus_base because it might not point * to our small window. Instead, use the one used by the xbridge * driver itself, which _always_ points to the short window. */ *bshp = xb->xb_regt->bus_base + bpa; return 0; } int xbridge_space_map_io(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, bus_space_handle_t *bshp) { struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; /* * Base address is either within the devio area, or our direct * window. */ if ((offs >> 24) == xb->xb_devio_skew) return xbridge_space_map_devio(t, offs, size, flags, bshp); #ifdef DIAGNOSTIC /* check that this does not overflow the mapping */ if (offs < xb->xb_iostart || offs + size - 1 > xb->xb_ioend) return EINVAL; #endif *bshp = (t->bus_base + offs); return 0; } int xbridge_space_map_mem(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, int flags, bus_space_handle_t *bshp) { #if defined(TGT_ORIGIN) || defined(DIAGNOSTIC) struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; #endif /* * Base address is either within the devio area, or our direct * window. Except on Octane where we never setup devio memory * mappings, because the large mapping is always available. */ #ifdef TGT_ORIGIN if (sys_config.system_type != SGI_OCTANE && (offs >> 24) == xb->xb_devio_skew) return xbridge_space_map_devio(t, offs, size, flags, bshp); #endif #ifdef DIAGNOSTIC /* check that this does not overflow the mapping */ if (offs < xb->xb_memstart || offs + size - 1 > xb->xb_memend) return EINVAL; #endif *bshp = (t->bus_base + offs); return 0; } int xbridge_space_region_devio(bus_space_tag_t t , bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { #ifdef DIAGNOSTIC struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; bus_addr_t bpa; bus_addr_t start, end; uint d; #endif #ifdef DIAGNOSTIC /* * Note we can not use our own bus_base because it might not point * to our small window. Instead, use the one used by the xbridge * driver itself, which _always_ points to the short window. */ bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base; if ((bpa >> 24) != 0) return EINVAL; /* not a devio mapping */ /* * Figure out which devio `slot' we are using, and make sure * we do not overrun it. */ for (d = 0; d < xb->xb_nslots; d++) { start = PIC_DEVIO_OFFS(xb->xb_busno, d); end = start + BRIDGE_DEVIO_SIZE(d); if (bpa >= start && bpa < end) { if (bpa + offset + size > end) return EINVAL; else break; } } if (d == xb->xb_nslots) return EINVAL; #endif *nbshp = bsh + offset; return 0; } int xbridge_space_region_io(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; bus_addr_t bpa; /* * Note we can not use our own bus_base because it might not point * to our small window. Instead, use the one used by the xbridge * driver itself, which _always_ points to the short window. */ bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base; if ((bpa >> 24) == 0) return xbridge_space_region_devio(t, bsh, offset, size, nbshp); #ifdef DIAGNOSTIC /* check that this does not overflow the mapping */ bpa = (bus_addr_t)bsh - t->bus_base; if (bpa + offset + size - 1 > xb->xb_ioend) return EINVAL; #endif *nbshp = bsh + offset; return 0; } int xbridge_space_region_mem(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) { #if defined(TGT_ORIGIN) || defined(DIAGNOSTIC) struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; bus_addr_t bpa; #endif /* * Base address is either within the devio area, or our direct * window. Except on Octane where we never setup devio memory * mappings, because the large mapping is always available. */ #ifdef TGT_ORIGIN if (sys_config.system_type != SGI_OCTANE) { /* * Note we can not use our own bus_base because it might not * point to our small window. Instead, use the one used by * the xbridge driver itself, which _always_ points to the * short window. */ bpa = (bus_addr_t)bsh - xb->xb_regt->bus_base; if ((bpa >> 24) == 0) return xbridge_space_region_devio(t, bsh, offset, size, nbshp); } #endif #ifdef DIAGNOSTIC /* check that this does not overflow the mapping */ bpa = (bus_addr_t)bsh - t->bus_base; if (bpa + offset + size - 1 > xb->xb_memend) return EINVAL; #endif *nbshp = bsh + offset; return 0; } void xbridge_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offs, bus_size_t len, int flags) { struct xbpci_softc *xb = (struct xbpci_softc *)t->bus_private; bus_addr_t bpa, start, end; uint d, devmin, devmax; mips_sync(); if (flags & BUS_SPACE_BARRIER_WRITE) { /* * Try to figure out which device we are working for, and * flush its PCI write buffer. * This is ugly; we really need to be able to provide a * different bus_space_tag_t to each slot, to be able * to tell them apart. */ if (t->_space_map == xbridge_space_map_devio) { bpa = (bus_addr_t)h - xb->xb_regt->bus_base; for (d = 0; d < xb->xb_nslots; d++) { start = PIC_DEVIO_OFFS(xb->xb_busno, d); end = start + BRIDGE_DEVIO_SIZE(d); if (bpa >= start && bpa < end) break; } devmin = d; devmax = d + 1; /* should not happen */ if (d == xb->xb_nslots) { devmin = 0; devmax = xb->xb_nslots; } } else { /* nothing better came up my sleeve... */ devmin = 0; devmax = xb->xb_nslots; } for (d = devmin; d < devmax; d++) xbridge_wbflush(xb, d); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); } } /* ********************* bus_dma helpers */ /* * Since the common bus_dma code makes sure DMA-able memory is allocated * within the dma_constraint limits, which are set to the direct DMA * window, we do not need to check for addresses outside this range here. */ bus_addr_t xbridge_pa_to_device(paddr_t pa) { return (pa - dma_constraint.ucr_low) + BRIDGE_DMA_DIRECT_BASE; } paddr_t xbridge_device_to_pa(bus_addr_t addr) { return (addr - BRIDGE_DMA_DIRECT_BASE) + dma_constraint.ucr_low; } /* ********************* Bridge configuration code. */ const char * xbridge_setup(struct xbpci_softc *xb) { bus_addr_t ba; paddr_t pa; uint64_t status, ctrl, int_addr, dirmap; int mode, speed, dev; status = xbridge_read_reg(xb, WIDGET_STATUS); ctrl = xbridge_read_reg(xb, WIDGET_CONTROL); /* * Print bus mode and speed. */ mode = ISSET(xb->xb_flags, XF_PIC) && ISSET(status, PIC_WIDGET_STATUS_PCIX_MODE); if (mode != 0) { SET(xb->xb_flags, XF_PCIX); speed = (status & PIC_WIDGET_STATUS_PCIX_SPEED_MASK) >> PIC_WIDGET_STATUS_PCIX_SPEED_SHIFT; } else if (ISSET(xb->xb_flags, XF_XBRIDGE)) { speed = (ctrl & BRIDGE_WIDGET_CONTROL_SPEED_MASK) >> BRIDGE_WIDGET_CONTROL_SPEED_SHIFT; } else speed = 0; /* 0 = 33 MHz, 1 = 66 MHz, 2 = 100 MHz, 3 = 133 MHz */ speed = (speed & 2 ? 100 : 33) + (speed & 1 ? 33 : 0); printf("%d MHz %s bus", speed, mode ? "PCIX" : "PCI"); /* * Gather device identification for all slots. * We need this to be able to allocate RRBs correctly, and also * to be able to check quickly whether a given device is an IOC3. */ for (dev = 0; dev < xb->xb_nslots; dev++) { if (ISSET(xb->xb_flags, XF_PIC)) pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + ((dev + 1) << 12) + PCI_ID_REG; else pa = xb->xb_regh + BRIDGE_PCI_CFG_SPACE + (dev << 12) + PCI_ID_REG; if (guarded_read_4(pa, &xb->xb_devices[dev].id) != 0) xb->xb_devices[dev].id = PCI_ID_EMPTY; } /* * Configure the direct DMA window to access the 2GB memory * window selected as our DMA memory range. */ dirmap = (dma_constraint.ucr_low >> BRIDGE_DIRMAP_BASE_SHIFT) & BRIDGE_DIRMAP_BASE_MASK; switch (sys_config.system_type) { default: #ifdef TGT_ORIGIN dirmap |= kl_hub_widget[ IP27_PHYS_TO_NODE(dma_constraint.ucr_low)] << BRIDGE_DIRMAP_WIDGET_SHIFT; break; #endif #ifdef TGT_OCTANE case SGI_OCTANE: dirmap |= IP30_HEART_WIDGET << BRIDGE_DIRMAP_WIDGET_SHIFT; break; #endif } xbridge_write_reg(xb, BRIDGE_DIR_MAP, dirmap); /* * Allocate RRB for the existing devices. */ xbridge_rrb_setup(xb, 0); xbridge_rrb_setup(xb, 1); /* * Enable(?) snooping and disable relaxed order on PIC. */ if (ISSET(xb->xb_flags, XF_PIC)) { ctrl &= ~PIC_WIDGET_CONTROL_NO_SNOOP; ctrl &= ~PIC_WIDGET_CONTROL_RELAX_ORDER; } /* * Disable byteswapping on PIO accesses through the large window * (we handle this at the bus_space level). It should not have * been enabled by ARCS, since IOC serial console relies on this, * but better enforce this anyway. */ ctrl &= ~BRIDGE_WIDGET_CONTROL_IO_SWAP; ctrl &= ~BRIDGE_WIDGET_CONTROL_MEM_SWAP; xbridge_write_reg(xb, WIDGET_CONTROL, ctrl); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); /* * The PROM will only configure the onboard devices. Set up * any other device we might encounter. */ xbridge_resource_setup(xb); /* * Older Bridge chips needs to run with pci timeouts * disabled. */ if (!ISSET(xb->xb_flags, XF_XBRIDGE) && xb->xb_revision < 4) { xbridge_write_reg(xb, BRIDGE_BUS_TIMEOUT, xbridge_read_reg(xb, BRIDGE_BUS_TIMEOUT) & ~BRIDGE_BUS_PCI_RETRY_CNT_MASK); } /* * AT&T/Lucent USS-302 and USS-312 USB controllers require * a larger PCI retry hold interval for proper operation. */ for (dev = 0; dev < xb->xb_nslots; dev++) { if (xb->xb_devices[dev].id == PCI_ID_CODE(PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_USBHC) || xb->xb_devices[dev].id == PCI_ID_CODE(PCI_VENDOR_LUCENT, PCI_PRODUCT_LUCENT_USBHC2)) { ctrl = xbridge_read_reg(xb, BRIDGE_BUS_TIMEOUT); ctrl &= ~BRIDGE_BUS_PCI_RETRY_HOLD_MASK; ctrl |= (4 << BRIDGE_BUS_PCI_RETRY_HOLD_SHIFT); xbridge_write_reg(xb, BRIDGE_BUS_TIMEOUT, ctrl); break; } } /* * Clear the write request memory in PIC, to avoid risking * spurious parity errors if it is not clean. */ if (ISSET(xb->xb_flags, XF_PIC)) { for (ba = PIC_WR_REQ_LOWER(0); ba != PIC_WR_REQ_LOWER(PIC_WR_REQ_ENTRIES); ba += 8) xbridge_write_reg(xb, ba, 0ULL); for (ba = PIC_WR_REQ_UPPER(0); ba != PIC_WR_REQ_UPPER(PIC_WR_REQ_ENTRIES); ba += 8) xbridge_write_reg(xb, ba, 0ULL); for (ba = PIC_WR_REQ_PARITY(0); ba != PIC_WR_REQ_PARITY(PIC_WR_REQ_ENTRIES); ba += 8) xbridge_write_reg(xb, ba, 0ULL); } /* * Setup interrupt handling. * * Note that, on PIC, the `lower address' register is a 64 bit * register and thus need to be initialized with the whole 64 bit * address; the `upper address' register is hardwired to zero and * ignores writes, so we can use the same logic on Bridge and PIC. * * Also, on Octane, we need to keep otherwise unused interrupt source * #6 enabled on the obio widget, as it controls routing of the * power button interrupt (and to make things more complicated than * necessary, this pin is wired to a particular Heart interrupt * register bit, so interrupts on this pin will never be seen at the * Bridge level). */ #ifdef TGT_OCTANE if (sys_config.system_type == SGI_OCTANE && xb->xb_widget == IP30_BRIDGE_WIDGET) xb->xb_ier = 1L << 6; else #endif xb->xb_ier = 0; xbridge_write_reg(xb, BRIDGE_IER, 0); xbridge_write_reg(xb, BRIDGE_INT_MODE, 0); xbridge_write_reg(xb, BRIDGE_INT_DEV, 0); int_addr = xbow_intr_address & ((1UL << 48) - 1); switch (sys_config.system_type) { default: #ifdef TGT_ORIGIN int_addr |= (uint64_t)kl_hub_widget[masternasid] << 48; break; #endif #ifdef TGT_OCTANE case SGI_OCTANE: int_addr |= (uint64_t)IP30_HEART_WIDGET << 48; break; #endif } xbridge_write_reg(xb, WIDGET_INTDEST_ADDR_LOWER, int_addr); xbridge_write_reg(xb, WIDGET_INTDEST_ADDR_UPPER, int_addr >> 32); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); /* * Register an error interrupt handler. */ if (xbow_intr_register(xb->xb_widget, IPL_HIGH, &xb->xb_err_intrsrc) != 0) return "can't allocate error interrupt source"; if (xbow_intr_establish(xbridge_err_intr_handler, xb, xb->xb_err_intrsrc, IPL_HIGH, DEVNAME(xb), NULL)) return "unable to register error interrupt handler"; xbridge_err_clear(xb, 0); xbridge_write_reg(xb, BRIDGE_INT_HOST_ERR, xb->xb_err_intrsrc); /* * Enable as many error interrupt sources as possible; older * Bridge chips need to have a few of them kept masked to * avoid hitting hardware issues. */ xb->xb_ier |= (ISSET(xb->xb_flags, XF_PIC) ? PIC_ISR_ERRMASK : BRIDGE_ISR_ERRMASK) & ~(BRIDGE_ISR_MULTIPLE_ERR | BRIDGE_ISR_SSRAM_PERR | BRIDGE_ISR_GIO_BENABLE_ERR); if (xb->xb_busno != 0) { /* xtalk errors will only show up on bus #0 */ xb->xb_ier &= ~(BRIDGE_ISR_UNSUPPORTED_XOP | BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR | BRIDGE_ISR_LLP_RCTY | BRIDGE_ISR_LLP_TX_RETRY | BRIDGE_ISR_LLP_TCTY); } if (!ISSET(xb->xb_flags, XF_XBRIDGE)) { if (xb->xb_revision < 2) xb->xb_ier &= ~(BRIDGE_ISR_UNEXPECTED_RESP | BRIDGE_ISR_PCI_MASTER_TMO | BRIDGE_ISR_RESP_XTALK_ERR | BRIDGE_ISR_LLP_TX_RETRY | BRIDGE_ISR_XREAD_REQ_TMO); if (xb->xb_revision < 3) xb->xb_ier &= ~BRIDGE_ISR_BAD_XRESP_PACKET; } xbridge_write_reg(xb, BRIDGE_IER, xb->xb_ier); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); return NULL; } /* * Handle PCI errors. */ void xbridge_err_handle(struct xbpci_softc *xb, uint64_t isr) { uint64_t pci_err, wid_err, resp_err; wid_err = xbridge_read_reg(xb, WIDGET_ERR_ADDR_LOWER); if (!ISSET(xb->xb_flags, XF_PIC)) wid_err |= xbridge_read_reg(xb, WIDGET_ERR_ADDR_UPPER) << 32; pci_err = xbridge_read_reg(xb, BRIDGE_PCI_ERR_LOWER); if (!ISSET(xb->xb_flags, XF_PIC)) pci_err |= xbridge_read_reg(xb, BRIDGE_PCI_ERR_UPPER) << 32; resp_err = xbridge_read_reg(xb, BRIDGE_WIDGET_RESP_LOWER); if (!ISSET(xb->xb_flags, XF_PIC)) resp_err |= xbridge_read_reg(xb, BRIDGE_WIDGET_RESP_UPPER) << 32; /* XXX give more detailed information */ printf("%s: error interrupt, isr %llx wid %llx pci %llx resp %llx\n", DEVNAME(xb), isr, wid_err, pci_err, resp_err); xbridge_err_clear(xb, isr); } /* * Clear any error condition. */ void xbridge_err_clear(struct xbpci_softc *xb, uint64_t isr) { if (ISSET(xb->xb_flags, XF_PIC)) { if (isr == 0) isr = xbridge_read_reg(xb, BRIDGE_ISR) & ~BRIDGE_ISR_HWINTR_MASK; xbridge_write_reg(xb, BRIDGE_ICR, isr); } else xbridge_write_reg(xb, BRIDGE_ICR, BRIDGE_ICR_ALL); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); } /* * Build a not-so-pessimistic RRB allocation register value. */ void xbridge_rrb_setup(struct xbpci_softc *xb, int odd) { uint rrb[MAX_SLOTS / 2]; /* tentative rrb assignment */ uint total; /* rrb count */ uint32_t proto; /* proto rrb value */ int dev, i, j; /* * First, try to allocate as many RRBs per device as possible. */ total = 0; for (i = 0; i < nitems(rrb); i++) { dev = (i << 1) + !!odd; if (dev >= xb->xb_nslots || SLOT_EMPTY(xb, dev)) rrb[i] = 0; else { rrb[i] = 4; /* optimistic value */ total += 4; } } /* * Then, try to reduce greed until we do not claim more than * the 8 RRBs we can afford. */ if (total > 8) { /* * All devices should be able to live with 3 RRBs, so * reduce their allocation from 4 to 3. */ for (i = 0; i < nitems(rrb); i++) { if (rrb[i] == 4) { rrb[i]--; if (--total == 8) break; } } } if (total > 8) { /* * There are too many devices for 3 RRBs per device to * be possible. Attempt to reduce from 3 to 2, except * for isp(4) devices. */ for (i = 0; i < nitems(rrb); i++) { if (rrb[i] == 3) { dev = (i << 1) + !!odd; if (PCI_VENDOR(xb->xb_devices[dev].id) != PCI_VENDOR_QLOGIC) { rrb[i]--; if (--total == 8) break; } } } } if (total > 8) { /* * Too bad, we need to shrink the RRB allocation for * isp devices too. We'll try to favour the lowest * slots, though, hence the reversed loop order. */ for (i = nitems(rrb) - 1; i >= 0; i--) { if (rrb[i] == 3) { rrb[i]--; if (--total == 8) break; } } } /* * Now build the RRB register value proper. */ proto = 0; for (i = 0; i < nitems(rrb); i++) { for (j = 0; j < rrb[i]; j++) proto = (proto << RRB_SHIFT) | (RRB_VALID | i); } xbridge_write_reg(xb, odd ? BRIDGE_RRB_ODD : BRIDGE_RRB_EVEN, proto); } /* * Configure PCI resources for all devices. */ void xbridge_resource_setup(struct xbpci_softc *xb) { pci_chipset_tag_t pc = &xb->xb_pc; int dev, nfuncs; pcitag_t tag; pcireg_t id, bhlcr; uint32_t devio; int need_setup; uint secondary, nppb, npccbb, ppbstride; const struct pci_quirkdata *qd; /* * On Octane, we will want to map everything through the large * windows, whenever possible. * * Set up these mappings now. */ if (sys_config.system_type == SGI_OCTANE) { xb->xb_ioex = xbridge_mapping_setup(xb, 1); xb->xb_memex = xbridge_mapping_setup(xb, 0); } /* * Configure all regular PCI devices. */ #ifdef DEBUG for (dev = 0; dev < xb->xb_nslots; dev++) printf("device %d: devio %08x\n", dev, xbridge_read_reg(xb, BRIDGE_DEVICE(dev))); #endif nppb = npccbb = 0; for (dev = 0; dev < xb->xb_nslots; dev++) { if (SLOT_EMPTY(xb, dev)) continue; /* * Count ppb and pccbb devices, we will need their number later. */ tag = pci_make_tag(pc, 0, dev, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) == 1) nppb++; if (PCI_HDRTYPE_TYPE(bhlcr) == 2) npccbb++; /* * We want to avoid changing mapping configuration for * devices which have been setup by ARCS. * * On Octane, the whole on-board I/O widget has been * set up, with direct mappings into widget space. * * On Origin, since direct mappings are expensive, * everything set up by ARCS has a valid devio * mapping; those can be identified as they sport the * widget number in the high address bits. * * We will only fix the device-global devio flags on * devices which have been set up by ARCS. Otherwise, * we'll need to perform proper PCI resource allocation. */ id = xb->xb_devices[dev].id; devio = xbridge_read_reg(xb, BRIDGE_DEVICE(dev)); if (id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) && id != PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC4)) need_setup = 1; else need_setup = xb->xb_busno != 0 || xb->xb_devio_skew != ((devio & BRIDGE_DEVICE_BASE_MASK) >> (24 - BRIDGE_DEVICE_BASE_SHIFT)); /* * Enable byte swapping for DMA, except on IOC3, IOC4 and * RAD1 devices. */ if (id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC3) || id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_IOC4) || id == PCI_ID_CODE(PCI_VENDOR_SGI, PCI_PRODUCT_SGI_RAD1)) devio &= ~(BRIDGE_DEVICE_SWAP_PMU | BRIDGE_DEVICE_SWAP_DIR); else devio |= BRIDGE_DEVICE_SWAP_PMU | BRIDGE_DEVICE_SWAP_DIR; /* * Disable write gathering. */ devio &= ~(BRIDGE_DEVICE_WGATHER_PMU | BRIDGE_DEVICE_WGATHER_DIR); /* * Disable prefetching - on-board isp(4) controllers on * Octane are set up with this, but this confuses the * driver. */ devio &= ~BRIDGE_DEVICE_PREFETCH; /* * Force cache coherency. */ devio |= BRIDGE_DEVICE_COHERENT; if (need_setup == 0) { xbridge_set_devio(xb, dev, devio, 1); continue; } /* * Clear any residual devio mapping. */ devio &= ~BRIDGE_DEVICE_BASE_MASK; devio &= ~BRIDGE_DEVICE_IO_MEM; xbridge_set_devio(xb, dev, devio, 0); /* * We now need to perform the resource allocation for this * device, which has not been setup by ARCS. */ qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); if (PCI_HDRTYPE_MULTIFN(bhlcr) || (qd != NULL && (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) nfuncs = 8; else nfuncs = 1; xbridge_device_setup(xb, dev, nfuncs, devio); } /* * Configure PCI-PCI and PCI-CardBus bridges, if any. * * We do this after all the other PCI devices have been configured * in order to favour them during resource allocation. */ if (npccbb != 0) { /* * If there are PCI-CardBus bridges, we really want to be * able to have large resource spaces... */ if (xb->xb_ioex == NULL) xb->xb_ioex = xbridge_mapping_setup(xb, 1); if (xb->xb_memex == NULL) xb->xb_memex = xbridge_mapping_setup(xb, 0); } secondary = 1; ppbstride = nppb == 0 ? 0 : (255 - npccbb) / nppb; for (dev = 0; dev < xb->xb_nslots; dev++) { if (SLOT_EMPTY(xb, dev)) continue; tag = pci_make_tag(pc, 0, dev, 0); bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(bhlcr)) { case 1: /* PCI-PCI bridge */ ppb_initialize(pc, tag, 0, secondary, secondary + ppbstride - 1); secondary += ppbstride; break; case 2: /* PCI-CardBus bridge */ /* * We do not expect cardbus devices to sport * PCI-PCI bridges themselves, so only one * PCI bus will do. */ pccbb_initialize(pc, tag, 0, secondary, secondary); secondary++; break; } } if (xb->xb_ioex != NULL) { extent_destroy(xb->xb_ioex); xb->xb_ioex = NULL; } if (xb->xb_memex != NULL) { extent_destroy(xb->xb_memex); xb->xb_memex = NULL; } } /* * Make the Octane flash area unavailable in the PCI space extents, so * that we do not try to map devices in its area. */ int xbridge_extent_chomp(struct xbpci_softc *xb, struct extent *ex) { #ifdef TGT_OCTANE /* * On Octane, the boot PROM is part of the onboard IOC3 * device, and is accessible through the PCI memory space * (and maybe through the PCI I/O space as well). * * To avoid undebuggable surprises, make sure we never use * this space. */ if (sys_config.system_type == SGI_OCTANE && xb->xb_widget == IP30_BRIDGE_WIDGET) { u_long fmin, fmax; /* * This relies upon the knowledge that both flash bases * are contiguous, to perform only one extent operation. * I don't think we need to be pedantic to the point of * doing this in two steps, really -- miod */ fmin = max(IP30_FLASH_BASE, ex->ex_start); fmax = min(IP30_FLASH_ALT + IP30_FLASH_SIZE - 1, ex->ex_end); if (fmax >= fmin) return extent_alloc_region(ex, fmin, fmax + 1 - fmin, EX_NOWAIT | EX_MALLOCOK); } #endif return 0; } /* * Build resource extents for the MI PCI code to play with. * These extents cover the configured devio areas, and the large resource * views, if applicable. */ void xbridge_extent_setup(struct xbpci_softc *xb) { int dev; int errors; bus_addr_t start, end; uint32_t devio; snprintf(xb->xb_ioexname, sizeof(xb->xb_ioexname), "%s_io", DEVNAME(xb)); xb->xb_ioex = extent_create(xb->xb_ioexname, 0, 0xffffffff, M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); if (xb->xb_ioex != NULL) { errors = 0; /* make all configured devio ranges available... */ for (dev = 0; dev < xb->xb_nslots; dev++) { devio = xb->xb_devices[dev].devio; if (devio == 0 || ISSET(devio, BRIDGE_DEVICE_IO_MEM)) continue; start = (devio & BRIDGE_DEVICE_BASE_MASK) << BRIDGE_DEVICE_BASE_SHIFT; if (start == 0) continue; if (extent_free(xb->xb_ioex, start, BRIDGE_DEVIO_SIZE(dev), EX_NOWAIT) != 0) { errors++; break; } } /* ...as well as the large views, if any */ if (xb->xb_ioend != 0) { start = xb->xb_iostart; if (start == 0) start = 1; end = xb->xb_devio_skew << 24; if (start < end) if (extent_free(xb->xb_ioex, start, end, EX_NOWAIT) != 0) errors++; start = (xb->xb_devio_skew + 1) << 24; if (start < xb->xb_iostart) start = xb->xb_iostart; if (extent_free(xb->xb_ioex, start, xb->xb_ioend + 1 - start, EX_NOWAIT) != 0) errors++; } if (xbridge_extent_chomp(xb, xb->xb_ioex) != 0) errors++; if (errors != 0) { extent_destroy(xb->xb_ioex); xb->xb_ioex = NULL; } } snprintf(xb->xb_memexname, sizeof(xb->xb_memexname), "%s_mem", DEVNAME(xb)); xb->xb_memex = extent_create(xb->xb_memexname, 0, 0xffffffff, M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); if (xb->xb_memex != NULL) { errors = 0; /* make all configured devio ranges available... */ for (dev = 0; dev < xb->xb_nslots; dev++) { devio = xb->xb_devices[dev].devio; if (devio == 0 || !ISSET(devio, BRIDGE_DEVICE_IO_MEM)) continue; start = (devio & BRIDGE_DEVICE_BASE_MASK) << BRIDGE_DEVICE_BASE_SHIFT; if (start == 0) continue; if (extent_free(xb->xb_memex, start, BRIDGE_DEVIO_SIZE(dev), EX_NOWAIT) != 0) { errors++; break; } } /* ...as well as the large views, if any */ if (xb->xb_memend != 0) { start = xb->xb_memstart; if (start == 0) start = 1; end = xb->xb_devio_skew << 24; if (start < end) if (extent_free(xb->xb_memex, start, end, EX_NOWAIT) != 0) errors++; start = (xb->xb_devio_skew + 1) << 24; if (start < xb->xb_memstart) start = xb->xb_memstart; if (extent_free(xb->xb_memex, start, xb->xb_memend + 1 - start, EX_NOWAIT) != 0) errors++; } if (xbridge_extent_chomp(xb, xb->xb_memex) != 0) errors++; if (errors != 0) { extent_destroy(xb->xb_memex); xb->xb_memex = NULL; } } } struct extent * xbridge_mapping_setup(struct xbpci_softc *xb, int io) { bus_addr_t membase, offs; bus_size_t len; paddr_t base; u_long start, end; struct extent *ex = NULL; if (io) { /* * I/O mappings are available in the widget at offset * BRIDGE_PCI_IO_SPACE_BASE onwards, but weren't working * correctly until Bridge revision 4 (apparently, what * didn't work was the byteswap logic). * * Also, this direct I/O space is not supported on PIC * widgets. */ if (!ISSET(xb->xb_flags, XF_NO_DIRECT_IO)) { offs = BRIDGE_PCI_IO_SPACE_BASE; len = BRIDGE_PCI_IO_SPACE_LENGTH; base = xbow_widget_map_space(xb->xb_bow, xb->xb_widget, &offs, &len); } else base = 0; if (base != 0) { if (offs + len > BRIDGE_PCI_IO_SPACE_BASE + BRIDGE_PCI_IO_SPACE_LENGTH) len = BRIDGE_PCI_IO_SPACE_BASE + BRIDGE_PCI_IO_SPACE_LENGTH - offs; #ifdef DEBUG printf("direct io %p-%p base %p\n", offs, offs + len - 1, base); #endif offs -= BRIDGE_PCI_IO_SPACE_BASE; ex = extent_create("xbridge_direct_io", offs == 0 ? 1 : offs, offs + len - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); /* * Note that we do not need to invoke * xbridge_extent_chomp() here since we will * reserve the whole devio area. */ if (ex != NULL) { xb->xb_io_bus_space->bus_base = base - offs; xb->xb_io_bus_space->_space_map = xbridge_space_map_io; xb->xb_io_bus_space->_space_subregion = xbridge_space_region_io; xb->xb_io_bus_space_sw->bus_base = base - offs; xb->xb_io_bus_space_sw->_space_map = xbridge_space_map_io; xb->xb_io_bus_space_sw->_space_subregion = xbridge_space_region_io; xb->xb_iostart = offs; xb->xb_ioend = offs + len - 1; } } } else { /* * Memory mappings are available in the widget at offset * BRIDGE_PCI#_MEM_SPACE_BASE onwards. */ membase = xb->xb_busno == 0 ? BRIDGE_PCI0_MEM_SPACE_BASE : BRIDGE_PCI1_MEM_SPACE_BASE; offs = membase; len = BRIDGE_PCI_MEM_SPACE_LENGTH; base = xbow_widget_map_space(xb->xb_bow, xb->xb_widget, &offs, &len); if (base != 0) { /* * Only the low 30 bits of memory BAR are honoured * by the hardware, thus restricting memory mappings * to 1GB. */ if (offs + len > membase + BRIDGE_PCI_MEM_SPACE_LENGTH) len = membase + BRIDGE_PCI_MEM_SPACE_LENGTH - offs; #ifdef DEBUG printf("direct mem %p-%p base %p\n", offs, offs + len - 1, base); #endif offs -= membase; ex = extent_create("xbridge_direct_mem", offs == 0 ? 1 : offs, offs + len - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); /* * Note that we do not need to invoke * xbridge_extent_chomp() here since we will * reserve the whole devio area. */ if (ex != NULL) { xb->xb_mem_bus_space->bus_base = base - offs; xb->xb_mem_bus_space->_space_map = xbridge_space_map_mem; xb->xb_mem_bus_space->_space_subregion = xbridge_space_region_mem; xb->xb_mem_bus_space_sw->bus_base = base - offs; xb->xb_mem_bus_space_sw->_space_map = xbridge_space_map_mem; xb->xb_mem_bus_space_sw->_space_subregion = xbridge_space_region_mem; xb->xb_memstart = offs; xb->xb_memend = offs + len - 1; } } } if (ex != NULL) { /* * Remove the devio mapping range from the extent * to avoid ambiguous mappings. * * Note that xbow_widget_map_space() may have returned * a range in which the devio area does not appear. */ start = xb->xb_devio_skew << 24; end = (xb->xb_devio_skew + 1) << 24; if (end >= ex->ex_start && start <= ex->ex_end) { if (start < ex->ex_start) start = ex->ex_start; if (end > ex->ex_end + 1) end = ex->ex_end + 1; if (extent_alloc_region(ex, start, end - start, EX_NOWAIT | EX_MALLOCOK) != 0) { printf("%s: failed to expurge devio range" " from %s large extent\n", DEVNAME(xb), io ? "i/o" : "mem"); extent_destroy(ex); ex = NULL; } } } return ex; } /* * Flags returned by xbridge_resource_explore() */ #define XR_IO 0x01 /* needs I/O mappings */ #define XR_MEM 0x02 /* needs memory mappings */ #define XR_IO_OFLOW_S 0x04 /* can't fit I/O in a short devio */ #define XR_MEM_OFLOW_S 0x08 /* can't fit memory in a short devio */ #define XR_IO_OFLOW 0x10 /* can't fit I/O in a large devio */ #define XR_MEM_OFLOW 0x20 /* can't fit memory in a large devio */ int xbridge_resource_explore(struct xbpci_softc *xb, pcitag_t tag, struct extent *ioex, struct extent *memex) { pci_chipset_tag_t pc = &xb->xb_pc; pcireg_t bhlc, type, addr, mask; bus_addr_t base; bus_size_t size; int reg, reg_start, reg_end, reg_rom; int rc = 0; bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(bhlc)) { case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; reg_rom = PCI_ROM_REG; break; case 1: /* PCI-PCI bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PPB_END; reg_rom = 0; /* 0x38 */ break; case 2: /* PCI-CardBus bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PCB_END; reg_rom = 0; break; default: return rc; } for (reg = reg_start; reg < reg_end; reg += 4) { if (pci_mapreg_probe(pc, tag, reg, &type) == 0) continue; if (pci_mapreg_info(pc, tag, reg, type, NULL, &size, NULL)) continue; switch (type) { case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: reg += 4; /* FALLTHROUGH */ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: rc |= XR_MEM; if (memex != NULL) { if (size > memex->ex_end - memex->ex_start) rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; else if (extent_alloc(memex, size, size, 0, 0, 0, &base) != 0) rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; else if (base >= BRIDGE_DEVIO_SHORT) rc |= XR_MEM_OFLOW_S; } else rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; break; case PCI_MAPREG_TYPE_IO: rc |= XR_IO; if (ioex != NULL) { if (size > ioex->ex_end - ioex->ex_start) rc |= XR_IO_OFLOW | XR_IO_OFLOW_S; else if (extent_alloc(ioex, size, size, 0, 0, 0, &base) != 0) rc |= XR_IO_OFLOW | XR_IO_OFLOW_S; else if (base >= BRIDGE_DEVIO_SHORT) rc |= XR_IO_OFLOW_S; } else rc |= XR_IO_OFLOW | XR_IO_OFLOW_S; break; } } if (reg_rom != 0) { addr = pci_conf_read(pc, tag, reg_rom); pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE); mask = pci_conf_read(pc, tag, reg_rom); pci_conf_write(pc, tag, reg_rom, addr); size = PCI_ROM_SIZE(mask); if (size != 0) { rc |= XR_MEM; if (memex != NULL) { if (size > memex->ex_end - memex->ex_start) rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; else if (extent_alloc(memex, size, size, 0, 0, 0, &base) != 0) rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; else if (base >= BRIDGE_DEVIO_SHORT) rc |= XR_MEM_OFLOW_S; } else rc |= XR_MEM_OFLOW | XR_MEM_OFLOW_S; } } return rc; } void xbridge_resource_manage(struct xbpci_softc *xb, pcitag_t tag, struct extent *ioex, struct extent *memex) { pci_chipset_tag_t pc = &xb->xb_pc; pcireg_t bhlc, type, mask; bus_addr_t base; bus_size_t size; int reg, reg_start, reg_end, reg_rom; bhlc = pci_conf_read(pc, tag, PCI_BHLC_REG); switch (PCI_HDRTYPE_TYPE(bhlc)) { case 0: reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_END; reg_rom = PCI_ROM_REG; break; case 1: /* PCI-PCI bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PPB_END; reg_rom = 0; /* 0x38 */ break; case 2: /* PCI-CardBus bridge */ reg_start = PCI_MAPREG_START; reg_end = PCI_MAPREG_PCB_END; reg_rom = 0; break; default: return; } for (reg = reg_start; reg < reg_end; reg += 4) { if (pci_mapreg_probe(pc, tag, reg, &type) == 0) continue; if (pci_mapreg_info(pc, tag, reg, type, &base, &size, NULL)) continue; /* * Note that we do not care about the existing BAR values, * since these devices either have not been setup by ARCS * or do not matter for early system setup (such as * optional IOC3 PCI boards, which will get setup by * ARCS but can be reinitialized as we see fit). */ #ifdef DEBUG printf("tag %04x bar %02x type %d base %p size %p", tag, reg, type, base, size); #endif switch (type) { case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: /* * Since our mapping ranges are restricted to * at most 30 bits, the upper part of the 64 bit * BAR registers is always zero. */ pci_conf_write(pc, tag, reg + 4, 0); /* FALLTHROUGH */ case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: if (memex != NULL) { if (extent_alloc(memex, size, size, 0, 0, 0, &base) != 0) base = 0; } else base = 0; break; case PCI_MAPREG_TYPE_IO: if (ioex != NULL) { if (extent_alloc(ioex, size, size, 0, 0, 0, &base) != 0) base = 0; } else base = 0; break; } #ifdef DEBUG printf(" setup at %p\n", base); #endif pci_conf_write(pc, tag, reg, base); if (type == (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) reg += 4; } if (reg_rom != 0) { base = (bus_addr_t)pci_conf_read(pc, tag, reg_rom); pci_conf_write(pc, tag, reg_rom, ~PCI_ROM_ENABLE); mask = pci_conf_read(pc, tag, reg_rom); size = PCI_ROM_SIZE(mask); if (size != 0) { #ifdef DEBUG printf("bar %02x type rom base %p size %p", reg_rom, base, size); #endif if (memex != NULL) { if (extent_alloc(memex, size, size, 0, 0, 0, &base) != 0) base = 0; } else base = 0; #ifdef DEBUG printf(" setup at %p\n", base); #endif } else base = 0; /* ROM intentionally left disabled */ pci_conf_write(pc, tag, reg_rom, base); } } void xbridge_device_setup(struct xbpci_softc *xb, int dev, int nfuncs, uint32_t devio) { pci_chipset_tag_t pc = &xb->xb_pc; int function; pcitag_t tag; pcireg_t id, csr; uint32_t baseio; int resources; int io_devio, mem_devio; struct extent *ioex, *memex; /* * In a first step, we enumerate all the requested resources, * and check if they could fit within devio mappings. * * If devio can't afford us the mappings we need, we'll * try and allocate a large window. */ /* * Allocate extents to use for devio mappings if necessary. * This can fail; in that case we'll try to use a large mapping * whenever possible, or silently fail to configure the device. */ if (xb->xb_ioex != NULL) ioex = NULL; else { ioex = extent_create("xbridge_io", 0, BRIDGE_DEVIO_LARGE - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); #ifdef DEBUG if (ioex == NULL) printf("%s: ioex extent_create failed\n", __func__); #endif } if (xb->xb_memex != NULL) memex = NULL; else { memex = extent_create("xbridge_mem", 0, BRIDGE_DEVIO_LARGE - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); #ifdef DEBUG if (memex == NULL) printf("%s: memex extent_create failed\n", __func__); #endif } resources = 0; for (function = 0; function < nfuncs; function++) { tag = pci_make_tag(pc, 0, dev, function); id = pci_conf_read(pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0) continue; csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE)); resources |= xbridge_resource_explore(xb, tag, ioex, memex); } #ifdef DEBUG printf("resources mask: %02x\n", resources); #endif if (memex != NULL) { extent_destroy(memex); memex = NULL; } if (ioex != NULL) { extent_destroy(ioex); ioex = NULL; } /* * In a second step, if resources can be mapped using devio slots, * allocate them. Otherwise, or if we can't get a devio slot * big enough for the resources we need to map, we'll need * to get a large window mapping. * * Note that, on Octane, we try to avoid using devio whenever * possible. */ io_devio = -1; if (ISSET(resources, XR_IO)) { if (!ISSET(resources, XR_IO_OFLOW) && (sys_config.system_type != SGI_OCTANE || xb->xb_ioex == NULL)) io_devio = xbridge_allocate_devio(xb, dev, ISSET(resources, XR_IO_OFLOW_S)); if (io_devio >= 0) { baseio = (xb->xb_devio_skew << 24) | PIC_DEVIO_OFFS(xb->xb_busno, io_devio); xbridge_set_devio(xb, io_devio, devio | (baseio >> BRIDGE_DEVICE_BASE_SHIFT), 1); ioex = extent_create("xbridge_io", baseio, baseio + BRIDGE_DEVIO_SIZE(io_devio) - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); } else { /* * Try to get a large window mapping if we don't * have one already. */ if (xb->xb_ioex == NULL) xb->xb_ioex = xbridge_mapping_setup(xb, 1); } } mem_devio = -1; if (ISSET(resources, XR_MEM)) { if (!ISSET(resources, XR_MEM_OFLOW) && sys_config.system_type != SGI_OCTANE) mem_devio = xbridge_allocate_devio(xb, dev, ISSET(resources, XR_MEM_OFLOW_S)); if (mem_devio >= 0) { baseio = (xb->xb_devio_skew << 24) | PIC_DEVIO_OFFS(xb->xb_busno, mem_devio); xbridge_set_devio(xb, mem_devio, devio | BRIDGE_DEVICE_IO_MEM | (baseio >> BRIDGE_DEVICE_BASE_SHIFT), 1); memex = extent_create("xbridge_mem", baseio, baseio + BRIDGE_DEVIO_SIZE(mem_devio) - 1, M_DEVBUF, NULL, 0, EX_NOWAIT); } else { /* * Try to get a large window mapping if we don't * have one already. */ if (xb->xb_memex == NULL) xb->xb_memex = xbridge_mapping_setup(xb, 0); } } /* * Finally allocate the resources proper and update the * device BARs accordingly. */ for (function = 0; function < nfuncs; function++) { tag = pci_make_tag(pc, 0, dev, function); id = pci_conf_read(pc, tag, PCI_ID_REG); if (PCI_VENDOR(id) == PCI_VENDOR_INVALID || PCI_VENDOR(id) == 0) continue; xbridge_resource_manage(xb, tag, ioex != NULL ? ioex : xb->xb_ioex, memex != NULL ? memex : xb->xb_memex); } if (memex != NULL) extent_destroy(memex); if (ioex != NULL) extent_destroy(ioex); } int xbridge_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend) { struct xbpci_softc *xb = cookie; pci_chipset_tag_t pc = &xb->xb_pc; uint32_t base, devio; bus_size_t exsize; u_long exstart; int dev, devio_idx, tries; pci_decompose_tag(pc, tag, NULL, &dev, NULL); devio = xbridge_read_reg(xb, BRIDGE_DEVICE(dev)); /* * Since our caller computes resource needs starting at zero, we * can ignore the start values when computing the amount of * resources we'll need. */ /* * Try and allocate I/O resources first, as we may not be able * to use a large I/O mapping, in which case we want to use our * reserved devio for this purpose. */ exsize = *ioend; *iostart = 0xffffffff; *ioend = 0; if (exsize++ != 0) { /* try to allocate through a devio slot whenever possible... */ if (exsize < BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(xb, dev, 0); else if (exsize < BRIDGE_DEVIO_LARGE) devio_idx = xbridge_allocate_devio(xb, dev, 1); else devio_idx = -1; /* ...if it fails, try the large view.... */ if (devio_idx < 0 && xb->xb_ioex == NULL) xb->xb_ioex = xbridge_mapping_setup(xb, 1); /* ...if it is not available, try to get a devio slot anyway. */ if (devio_idx < 0 && xb->xb_ioex == NULL) { if (exsize > BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(xb, dev, 1); if (devio_idx < 0) devio_idx = xbridge_allocate_devio(xb, dev, 0); } if (devio_idx >= 0) { base = (xb->xb_devio_skew << 24) | PIC_DEVIO_OFFS(xb->xb_busno, devio_idx); xbridge_set_devio(xb, devio_idx, devio | (base >> BRIDGE_DEVICE_BASE_SHIFT), 1); *iostart = base; *ioend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; } else if (xb->xb_ioex != NULL) { /* * We know that the direct I/O resource range fits * within the 32 bit address space, so our allocation, * if successful, will work as a 32 bit i/o range. */ if (exsize < 1UL << 12) exsize = 1UL << 12; for (tries = 0; tries < 5; tries++) { if (extent_alloc(xb->xb_ioex, exsize, 1UL << 12, 0, 0, EX_NOWAIT | EX_MALLOCOK, &exstart) == 0) { *iostart = exstart; *ioend = exstart + exsize - 1; break; } exsize >>= 1; if (exsize < 1UL << 12) break; } } } exsize = *memend; *memstart = 0xffffffff; *memend = 0; if (exsize++ != 0) { /* try to allocate through a devio slot whenever possible... */ if (exsize < BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(xb, dev, 0); else if (exsize < BRIDGE_DEVIO_LARGE) devio_idx = xbridge_allocate_devio(xb, dev, 1); else devio_idx = -1; /* ...if it fails, try the large view.... */ if (devio_idx < 0 && xb->xb_memex == NULL) xb->xb_memex = xbridge_mapping_setup(xb, 0); /* ...if it is not available, try to get a devio slot anyway. */ if (devio_idx < 0 && xb->xb_memex == NULL) { if (exsize > BRIDGE_DEVIO_SHORT) devio_idx = xbridge_allocate_devio(xb, dev, 1); if (devio_idx < 0) devio_idx = xbridge_allocate_devio(xb, dev, 0); } if (devio_idx >= 0) { base = (xb->xb_devio_skew << 24) | PIC_DEVIO_OFFS(xb->xb_busno, devio_idx); xbridge_set_devio(xb, devio_idx, devio | BRIDGE_DEVICE_IO_MEM | (base >> BRIDGE_DEVICE_BASE_SHIFT), 1); *memstart = base; *memend = base + BRIDGE_DEVIO_SIZE(devio_idx) - 1; } else if (xb->xb_memex != NULL) { /* * We know that the direct memory resource range fits * within the 32 bit address space, and is limited to * 30 bits, so our allocation, if successful, will * work as a 32 bit memory range. */ if (exsize < 1UL << 20) exsize = 1UL << 20; for (tries = 0; tries < 5; tries++) { if (extent_alloc(xb->xb_memex, exsize, 1UL << 20, 0, 0, EX_NOWAIT | EX_MALLOCOK, &exstart) == 0) { *memstart = exstart; *memend = exstart + exsize - 1; break; } exsize >>= 1; if (exsize < 1UL << 20) break; } } } return 0; } #if NCARDBUS > 0 static struct rb_md_fnptr xbridge_rb_md_fn = { xbridge_rbus_space_map, xbridge_rbus_space_unmap }; int xbridge_rbus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *bshp) { return bus_space_map(t, addr, size, flags, bshp); } void xbridge_rbus_space_unmap(bus_space_tag_t t, bus_space_handle_t h, bus_size_t size, bus_addr_t *addrp) { bus_space_unmap(t, h, size); *addrp = h - t->bus_base; } void * xbridge_rbus_parent_io(struct pci_attach_args *pa) { struct extent *ex = pa->pa_ioex; bus_addr_t start, end; rbus_tag_t rb = NULL; /* * We want to force I/O mappings to lie in the low 16 bits * area. This is mandatory for 16-bit pcmcia devices; and * although 32-bit cardbus devices could use a larger range, * the pccbb driver doesn't enable the large I/O windows. */ if (ex != NULL) { start = 0; end = 0x10000; if (start < ex->ex_start) start = ex->ex_start; if (end > ex->ex_end) end = ex->ex_end; if (start < end) { rb = rbus_new_root_share(pa->pa_iot, ex, start, end - start); if (rb != NULL) rb->rb_md = &xbridge_rb_md_fn; } } /* * We are not allowed to return NULL. If we can't provide * resources, return a valid body which will fail requests. */ if (rb == NULL) rb = rbus_new_body(pa->pa_iot, NULL, 0, 0, RBUS_SPACE_INVALID); return rb; } void * xbridge_rbus_parent_mem(struct pci_attach_args *pa) { struct xbpci_softc *xb = pa->pa_pc->pc_conf_v; struct extent *ex = pa->pa_memex; bus_addr_t start; rbus_tag_t rb = NULL; /* * There is no restriction for the memory mappings, * however we need to make sure these won't hit the * devio range (for md_space_unmap to work correctly). */ if (ex != NULL) { start = (xb->xb_devio_skew + 1) << 24; if (start < ex->ex_start) start = ex->ex_start; if (start < ex->ex_end) { rb = rbus_new_root_share(pa->pa_memt, ex, start, ex->ex_end - start); if (rb != NULL) rb->rb_md = &xbridge_rb_md_fn; } } /* * We are not allowed to return NULL. If we can't provide * resources, return a valid body which will fail requests. */ if (rb == NULL) rb = rbus_new_body(pa->pa_iot, NULL, 0, 0, RBUS_SPACE_INVALID); return rb; } #endif /* NCARDBUS > 0 */ int xbridge_allocate_devio(struct xbpci_softc *xb, int dev, int wantlarge) { #ifdef DEBUG int orig_dev = dev; #endif /* * If the preferred slot is available and matches the size requested, * use it. */ if (!ISSET(xb->xb_devio_usemask, 1 << dev)) { if (BRIDGE_DEVIO_SIZE(dev) >= wantlarge ? BRIDGE_DEVIO_LARGE : BRIDGE_DEVIO_SHORT) { #ifdef DEBUG printf("%s(%d,%d): using reserved entry\n", __func__, dev, wantlarge); #endif return dev; } } /* * Otherwise pick the smallest available devio matching our size * request. */ for (dev = 0; dev < xb->xb_nslots; dev++) { if (ISSET(xb->xb_devio_usemask, 1 << dev)) continue; /* devio in use */ if (!SLOT_EMPTY(xb, dev)) continue; /* devio to be used soon */ if (BRIDGE_DEVIO_SIZE(dev) >= wantlarge ? BRIDGE_DEVIO_LARGE : BRIDGE_DEVIO_SHORT) { #ifdef DEBUG printf("%s(%d,%d): using unused entry %d\n", __func__, orig_dev, wantlarge, dev); #endif return dev; } } #ifdef DEBUG printf("%s(%d,%d): no entry available\n", __func__, orig_dev, wantlarge); #endif return -1; } void xbridge_set_devio(struct xbpci_softc *xb, int dev, uint32_t devio, int final) { xbridge_write_reg(xb, BRIDGE_DEVICE(dev), devio); (void)xbridge_read_reg(xb, WIDGET_TFLUSH); xb->xb_devices[dev].devio = devio; if (final) SET(xb->xb_devio_usemask, 1 << dev); #ifdef DEBUG printf("device %d: new %sdevio %08x\n", dev, final ? "final " : "", devio); #endif } #ifdef DDB void xbridge_ddb(void); void xbridge_ddb() { struct xbpci_softc *xb; unsigned int n, intrbit; for (n = 0; n < xbpci_cd.cd_ndevs; n++) { xb = xbpci_cd.cd_devs[n]; if (xb == NULL) continue; printf("%s: ISR %p IER %p xb_ier %p\n", xb->xb_dev.dv_xname, (void *)xbridge_read_reg(xb, BRIDGE_ISR), (void *)xbridge_read_reg(xb, BRIDGE_IER), (void *)xb->xb_ier); printf("mode %p dev %p\n", (void *)xbridge_read_reg(xb, BRIDGE_INT_MODE), (void *)xbridge_read_reg(xb, BRIDGE_INT_DEV)); for (intrbit = 0; intrbit < 8; intrbit++) printf("IRQ%u to %p\n", intrbit, (void *)xbridge_read_reg(xb, BRIDGE_INT_ADDR(intrbit))); } } #endif