diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-07-19 19:02:04 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2009-07-19 19:02:04 +0000 |
commit | cf8133281313c3daa4dce5de3450f41a2e3c9fdd (patch) | |
tree | e3aea3d7c73d24177c63d53b645e48a591b82a67 /sys | |
parent | 9eb003ff43d74194f602f6eff0e3670837be7fff (diff) |
Simplify code that sanitizes pci resources on the O2's mace PCI bridge.
The firmware messes up I/O BARs, so whack those back to 0, such that the MI
PCI code initializes on an as-needed basis.
ok miod@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/sgi/conf/files.sgi | 5 | ||||
-rw-r--r-- | sys/arch/sgi/pci/macepcibridge.c | 85 | ||||
-rw-r--r-- | sys/arch/sgi/pci/macepcimap.c | 315 |
3 files changed, 77 insertions, 328 deletions
diff --git a/sys/arch/sgi/conf/files.sgi b/sys/arch/sgi/conf/files.sgi index 2b8b33b347f..2ef7fb46583 100644 --- a/sys/arch/sgi/conf/files.sgi +++ b/sys/arch/sgi/conf/files.sgi @@ -1,4 +1,4 @@ -# $OpenBSD: files.sgi,v 1.28 2009/07/13 21:19:22 miod Exp $ +# $OpenBSD: files.sgi,v 1.29 2009/07/19 19:02:03 kettenis Exp $ # # maxpartitions must be first item in files.${ARCH} # @@ -75,8 +75,7 @@ include "dev/onewire/files.onewire" device macepcibr {} : pcibus attach macepcibr at macebus -file arch/sgi/pci/macepcibridge.c macepcibr needs-flag -file arch/sgi/pci/macepcimap.c macepcibr +file arch/sgi/pci/macepcibridge.c macepcibr # Use machine independent SCSI driver routines include "scsi/files.scsi" diff --git a/sys/arch/sgi/pci/macepcibridge.c b/sys/arch/sgi/pci/macepcibridge.c index cdf4b5247ce..b1b0931590e 100644 --- a/sys/arch/sgi/pci/macepcibridge.c +++ b/sys/arch/sgi/pci/macepcibridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macepcibridge.c,v 1.24 2009/07/17 18:06:51 miod Exp $ */ +/* $OpenBSD: macepcibridge.c,v 1.25 2009/07/19 19:02:03 kettenis Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se) @@ -73,8 +73,10 @@ void mace_pcibr_intr_disestablish(void *, void *); bus_addr_t mace_pcibr_pa_to_device(paddr_t); paddr_t mace_pcibr_device_to_pa(bus_addr_t); -void mace_pcibr_configure(struct mace_pcibr_softc *); int mace_pcibr_errintr(void *); + +void mace_pcibr_configure(struct mace_pcibr_softc *); +void mace_pcibr_device_fixup(struct mace_pcibr_softc *, int, int); int mace_pcibr_ppb_setup(void *, pcitag_t, bus_addr_t *, bus_addr_t *, bus_addr_t *, bus_addr_t *); @@ -238,12 +240,8 @@ mace_pcibrattach(struct device *parent, struct device *self, void *aux) sc->sc_pc.pc_ppb_setup = mace_pcibr_ppb_setup; /* - * Firmware sucks. Remap PCI BAR registers. (sigh) - */ - pciaddr_remap(&sc->sc_pc); - - /* - * Setup any PCI-PCI bridge. + * The O2 firmware sucks. It makes a mess off I/O BARs and + * an even bigger mess for PCI-PCI bridges. */ mace_pcibr_configure(sc); @@ -677,10 +675,11 @@ void mace_pcibr_configure(struct mace_pcibr_softc *sc) { pci_chipset_tag_t pc = &sc->sc_pc; - int dev; - uint curppb, nppb; pcitag_t tag; pcireg_t id, bhlcr; + int dev, nfuncs; + uint curppb, nppb; + const struct pci_quirkdata *qd; nppb = 0; for (dev = 0; dev < pci_bus_maxdevs(pc, 0); dev++) { @@ -694,6 +693,15 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); if (PCI_HDRTYPE_TYPE(bhlcr) == 1) nppb++; + + 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; + + mace_pcibr_device_fixup(sc, dev, nfuncs); } /* @@ -723,6 +731,63 @@ mace_pcibr_configure(struct mace_pcibr_softc *sc) } } +void +mace_pcibr_device_fixup(struct mace_pcibr_softc *sc, int dev, int nfuncs) +{ + pci_chipset_tag_t pc = &sc->sc_pc; + pcitag_t tag; + pcireg_t csr, bhlcr, type; + int function; + int reg, reg_start, reg_end; + + for (function = 0; function < nfuncs; function++) { + tag = pci_make_tag(pc, 0, dev, function); + + bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); + switch (PCI_HDRTYPE_TYPE(bhlcr)) { + case 0: + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_END; + break; + case 1: /* PCI-PCI bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PPB_END; + break; + case 2: /* PCI-CardBus bridge */ + reg_start = PCI_MAPREG_START; + reg_end = PCI_MAPREG_PCB_END; + break; + default: + continue; + } + + /* + * The firmware fails to initialize I/O BARs. Worse, it + * fills them with crap. So here we disable I/O space and + * reset the I/O BARs to 0. Device drivers will allocate + * resources themselves and enable I/O space on an as-needed + * basis. + */ + csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, + csr & ~PCI_COMMAND_IO_ENABLE); + + for (reg = reg_start; reg < reg_end; reg += 4) { + if (pci_mapreg_probe(pc, tag, reg, &type) == 0) + continue; + + switch (type) { + case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: + reg += 4; + break; + case PCI_MAPREG_TYPE_IO: + pci_conf_write(pc, tag, reg, 0); + break; + } + } + } +} + int mace_pcibr_ppb_setup(void *cookie, pcitag_t tag, bus_addr_t *iostart, bus_addr_t *ioend, bus_addr_t *memstart, bus_addr_t *memend) diff --git a/sys/arch/sgi/pci/macepcimap.c b/sys/arch/sgi/pci/macepcimap.c deleted file mode 100644 index 41d7bacd3a3..00000000000 --- a/sys/arch/sgi/pci/macepcimap.c +++ /dev/null @@ -1,315 +0,0 @@ -/* $OpenBSD: macepcimap.c,v 1.3 2004/09/09 22:11:39 pefo Exp $ */ -/* $NetBSD: pci_mace.c,v 1.2 2004/01/19 10:28:28 sekiya Exp $ */ - -/* - * Copyright (c) 2001,2003 Christopher Sekiya - * Copyright (c) 2000 Soren S. Jorvang - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed for the - * NetBSD Project. See http://www.NetBSD.org/ for - * information about NetBSD. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/device.h> -#include <sys/systm.h> - -#include <machine/cpu.h> -#include <machine/autoconf.h> -#include <machine/vmparam.h> -#include <machine/bus.h> - -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#include <dev/pci/pcidevs.h> - - -void pciaddr_remap(pci_chipset_tag_t); -void pciaddr_resource_manage(pci_chipset_tag_t, pcitag_t, void *); -bus_addr_t pciaddr_ioaddr(u_int32_t); -int pciaddr_do_resource_allocate(pci_chipset_tag_t, pcitag_t, int, void *, - int, bus_addr_t *, bus_size_t); -void pciaddr_print_devid(pci_chipset_tag_t, pcitag_t); - - -#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) -#define MEG_ALIGN(x) (((x) + 0x100000 - 1) & ~(0x100000 - 1)) - - -unsigned int ioaddr_base = 0x1000; -unsigned int memaddr_base = 0x80100000; - -#ifdef DEBUG -int pcibiosverbose = 1; -#endif - - -void -pciaddr_remap(pci_chipset_tag_t pc) -{ - pcitag_t devtag; - int device; - - /* Must fix up all PCI devices, ahc_pci expects proper i/o mapping */ - for (device = 1; device < 4; device++) { - const struct pci_quirkdata *qd; - int function, nfuncs; - pcireg_t bhlcr, id; - - devtag = pci_make_tag(pc, 0, device, 0); - id = pci_conf_read(pc, devtag, PCI_ID_REG); - - /* Invalid vendor ID value? */ - if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) - continue; - /* XXX Not invalid, but we've done this ~forever. */ - if (PCI_VENDOR(id) == 0) - continue; - - qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); - bhlcr = pci_conf_read(pc, devtag, PCI_BHLC_REG); - - if (PCI_HDRTYPE_MULTIFN(bhlcr) || - (qd != NULL && - (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) - nfuncs = 8; - else - nfuncs = 1; - - for (function = 0; function < nfuncs; function++) { - devtag = pci_make_tag(pc, 0, device, function); - id = pci_conf_read(pc, devtag, PCI_ID_REG); - - /* Invalid vendor ID value? */ - if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) - continue; - /* Not invalid, but we've done this ~forever */ - if (PCI_VENDOR(id) == 0) - continue; - - pciaddr_resource_manage(pc, devtag, NULL); - } - } -} - - -void -pciaddr_resource_manage(pc, tag, ctx) - pci_chipset_tag_t pc; - pcitag_t tag; - void *ctx; -{ - pcireg_t val, mask; - bus_addr_t addr; - bus_size_t size; - int error, mapreg, type, reg_start, reg_end, width; - - val = pci_conf_read(pc, tag, PCI_BHLC_REG); - switch (PCI_HDRTYPE_TYPE(val)) { - default: - printf("WARNING: unknown PCI device header."); - return; - case 0: - reg_start = PCI_MAPREG_START; - reg_end = PCI_MAPREG_END; - break; - case 1: /* PCI-PCI bridge */ - reg_start = PCI_MAPREG_START; - reg_end = PCI_MAPREG_PPB_END; - break; - case 2: /* PCI-CardBus bridge */ - reg_start = PCI_MAPREG_START; - reg_end = PCI_MAPREG_PCB_END; - break; - } - error = 0; - - for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { - /* inquire PCI device bus space requirement */ - val = pci_conf_read(pc, tag, mapreg); - pci_conf_write(pc, tag, mapreg, ~0); - - mask = pci_conf_read(pc, tag, mapreg); - pci_conf_write(pc, tag, mapreg, val); - - type = PCI_MAPREG_TYPE(val); - width = 4; - - if (type == PCI_MAPREG_TYPE_MEM) { - size = PCI_MAPREG_MEM_SIZE(mask); - - /* - * XXXrkb: for MEM64 BARs, to be totally kosher - * about the requested size, need to read mask - * from top 32bits of BAR and stir that into the - * size calculation, like so: - * - * case PCI_MAPREG_MEM_TYPE_64BIT: - * bar64 = pci_conf_read(pb->pc, tag, br + 4); - * pci_conf_write(pb->pc, tag, br + 4, 0xffffffff); - * mask64 = pci_conf_read(pb->pc, tag, br + 4); - * pci_conf_write(pb->pc, tag, br + 4, bar64); - * size = (u_int64_t) PCI_MAPREG_MEM64_SIZE( - * (((u_int64_t) mask64) << 32) | mask); - * width = 8; - * - * Fortunately, anything with all-zeros mask in the - * lower 32-bits will have size no less than 1 << 32, - * which we're not prepared to deal with, so I don't - * feel bad punting on it... - */ - if (PCI_MAPREG_MEM_TYPE(val) == - PCI_MAPREG_MEM_TYPE_64BIT) { - /* - * XXX We could examine the upper 32 bits - * XXX of the BAR here, but we are totally - * XXX unprepared to handle a non-zero value, - * XXX either here or anywhere else in the - * XXX sgimips code (not sure about MI code). - * XXX - * XXX So just arrange to skip the top 32 - * XXX bits of the BAR and zero then out - * XXX if the BAR is in use. - */ - width = 8; - - if (size != 0) - pci_conf_write(pc, tag, - mapreg + 4, 0); - } - } else { - /* - * Upper 16 bits must be one. Devices may hardwire - * them to zero, though, per PCI 2.2, 6.2.5.1, p 203. - */ - mask |= 0xffff0000; - size = PCI_MAPREG_IO_SIZE(mask); - } - - if (size == 0) /* unused register */ - continue; - - addr = pciaddr_ioaddr(val); - - /* reservation/allocation phase */ - error += pciaddr_do_resource_allocate(pc, tag, mapreg, - ctx, type, &addr, size); - - } - - /* enable/disable PCI device */ - val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); - - if (error == 0) - val |= (PCI_COMMAND_IO_ENABLE | - PCI_COMMAND_MEM_ENABLE | - PCI_COMMAND_MASTER_ENABLE | - PCI_COMMAND_SPECIAL_ENABLE | - PCI_COMMAND_INVALIDATE_ENABLE | - PCI_COMMAND_PARITY_ENABLE); - else - val &= ~(PCI_COMMAND_IO_ENABLE | - PCI_COMMAND_MEM_ENABLE | - PCI_COMMAND_MASTER_ENABLE); - - pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); - -} - -bus_addr_t -pciaddr_ioaddr(val) - u_int32_t val; -{ - - return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) ? - PCI_MAPREG_MEM_ADDR(val) : PCI_MAPREG_IO_ADDR(val)); -} - -int -pciaddr_do_resource_allocate(pc, tag, mapreg, ctx, type, addr, size) - pci_chipset_tag_t pc; - pcitag_t tag; - void *ctx; - int mapreg, type; - bus_addr_t *addr; - bus_size_t size; -{ - - switch (type) { - case PCI_MAPREG_TYPE_IO: - *addr = ioaddr_base; - ioaddr_base += PAGE_ALIGN(size); - break; - - case PCI_MAPREG_TYPE_MEM: - *addr = memaddr_base; - memaddr_base += MEG_ALIGN(size); - break; - - default: - printf("attempt to remap unknown region (addr 0x%lx, " - "size 0x%lx, type %d)\n", *addr, size, type); - return 0; - } - - - /* write new address to PCI device configuration header */ - pci_conf_write(pc, tag, mapreg, *addr); - - /* check */ -#ifdef DEBUG - if (!pcibiosverbose) { - printf("pci_addr_fixup: "); - pciaddr_print_devid(pc, tag); - } -#endif - if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) { - pci_conf_write(pc, tag, mapreg, 0); /* clear */ - printf("fixup failed. (new address=%#x)\n", (unsigned)*addr); - return (1); - } -#ifdef DEBUG - if (!pcibiosverbose) - printf("new address 0x%08x (size 0x%x)\n", (unsigned)*addr, - (unsigned)size); -#endif - - return (0); -} - -void -pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag) -{ - int bus, device, function; - pcireg_t id; - - id = pci_conf_read(pc, tag, PCI_ID_REG); - pci_decompose_tag(pc, tag, &bus, &device, &function); - printf("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function, - PCI_VENDOR(id), PCI_PRODUCT(id)); -} - |