summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2009-07-19 19:02:04 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2009-07-19 19:02:04 +0000
commitcf8133281313c3daa4dce5de3450f41a2e3c9fdd (patch)
treee3aea3d7c73d24177c63d53b645e48a591b82a67 /sys
parent9eb003ff43d74194f602f6eff0e3670837be7fff (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.sgi5
-rw-r--r--sys/arch/sgi/pci/macepcibridge.c85
-rw-r--r--sys/arch/sgi/pci/macepcimap.c315
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));
-}
-