summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authortmm <tmm@FreeBSD.org>2003-07-01 14:52:47 +0000
committertmm <tmm@FreeBSD.org>2003-07-01 14:52:47 +0000
commitc81d6d72070d973c221093542cdcd427ccb47918 (patch)
treeca2abf4f9a33cbb656a9282455f176ee57cc0c98 /sys
parent746493cc127d6c7ac328e12969d6b33a06a169ed (diff)
downloadFreeBSD-src-c81d6d72070d973c221093542cdcd427ccb47918.zip
FreeBSD-src-c81d6d72070d973c221093542cdcd427ccb47918.tar.gz
Add the new sparc64 OFW PCI framework, conditional on options OFW_NEWPCI
for now. It introduces a OFW PCI bus driver and a generic OFW PCI-PCI bridge driver. By utilizing these, the PCI handling is much more elegant now. The advantages of the new approach are: - Device enumeration should hopefully be more like on Solaris now, so unit numbers should match what's printed on the box more closely. - Real interrupt routing is implemented now, so cardbus bridges etc. have at least a chance to work. - The quirk tables are gone and have been replaced by (hopefully sufficient) heuristics. - Much cleaner code. There was also a report that previously bogus interrupt assignments are fixed now, which can be attributed to the new heuristics. A pitfall, and the reason why this is not the default yet, is that it changes device enumeration, as mentioned above, which can make it necessary to change the system configuration if more than one unit of a device type is present (on a system with two hme cars, for example, it is possible that hme0 becomes hme1 and vice versa after enabling the option). Systems with multiple disk controllers may need to be booted into single user (and require manual specification of the root file system on boot) to adjust the fstab. Nevertheless, I would like to encourage users to use this option, so that it can be made the default soon. In detail, the changes are: - Introduce an OFW PCI bus driver; it inherits most methods from the generic PCI bus driver, but uses the firmware for enumeration, performs additional initialization for devices and firmware-specific interrupt routing. It also implements an OFW-specific method to allow child devices to get their firmware nodes. - Introduce an OFW PCI-PCI bridge driver; again, it inherits most of the generic PCI-PCI bridge driver; it has it's own method for interrupt routing, as well as some sparc64-specific methods (one to get the node again, and one to adjust the bridge bus range, since we need to reenumerate all PCI buses). - Convert the apb driver to the new way of handling things. - Provide a common framework for OFW bridge drivers, used be the two drivers above. - Provide a small common framework for interrupt routing (for all bridge types). - Convert the psycho driver to the new framework; this gets rid of a bunch of old kludges in pci_read_config(), and the whole preinitialization (ofw_pci_init()). - Convert the ISA MD part and the EBus driver to the new way interrupts and nodes are handled. - Introduce types for firmware interrupt properties. - Rename the old sparcbus_if to ofw_pci_if by repo copy (it is only required for PCI), and move it to a more correct location (new support methodsx were also added, and an old one was deprecated). - Fix a bunch of minor bugs, perform some cleanups. In some cases, I introduced some minor code duplication to keep the new code clean, in hopes that the old code will be unifdef'ed soon. Reviewed in part by: imp Tested by: jake, Marius Strobl <marius@alchemy.franken.de>, Sergey Mokryshev <mokr@mokr.net>, Chris Jackman <cjackNOSPAM@klatsch.org> Info on u30 firmware provided by: kris
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/files.sparc645
-rw-r--r--sys/conf/options.sparc641
-rw-r--r--sys/sparc64/ebus/ebus.c37
-rw-r--r--sys/sparc64/include/ofw_bus.h27
-rw-r--r--sys/sparc64/isa/isa.c62
-rw-r--r--sys/sparc64/isa/ofw_isa.c33
-rw-r--r--sys/sparc64/isa/ofw_isa.h18
-rw-r--r--sys/sparc64/pci/apb.c182
-rw-r--r--sys/sparc64/pci/ofw_pci.c37
-rw-r--r--sys/sparc64/pci/ofw_pci.h31
-rw-r--r--sys/sparc64/pci/ofw_pci_if.m76
-rw-r--r--sys/sparc64/pci/ofw_pcib.c122
-rw-r--r--sys/sparc64/pci/ofw_pcib_subr.c134
-rw-r--r--sys/sparc64/pci/ofw_pcib_subr.h49
-rw-r--r--sys/sparc64/pci/ofw_pcibus.c264
-rw-r--r--sys/sparc64/pci/psycho.c228
-rw-r--r--sys/sparc64/pci/psychovar.h7
-rw-r--r--sys/sparc64/sparc64/ofw_bus.c126
-rw-r--r--sys/sparc64/sparc64/sparcbus_if.m93
19 files changed, 1160 insertions, 372 deletions
diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64
index 107312f..1f76310 100644
--- a/sys/conf/files.sparc64
+++ b/sys/conf/files.sparc64
@@ -34,6 +34,10 @@ sparc64/isa/ofw_isa.c optional ebus
sparc64/isa/ofw_isa.c optional isa
sparc64/pci/apb.c optional apb
sparc64/pci/ofw_pci.c optional pci
+sparc64/pci/ofw_pcib.c optional pci ofw_newpci
+sparc64/pci/ofw_pcib_subr.c optional pci ofw_newpci
+sparc64/pci/ofw_pcibus.c optional pci ofw_newpci
+sparc64/pci/ofw_pci_if.m optional pci
sparc64/pci/psycho.c optional pci
sparc64/sbus/sbus.c optional sbus
sparc64/sparc64/autoconf.c standard
@@ -71,7 +75,6 @@ sparc64/sparc64/ofw_machdep.c standard
sparc64/sparc64/pmap.c standard
sparc64/sparc64/prof_machdep.c optional profiling-routine
sparc64/sparc64/rwindow.c standard
-sparc64/sparc64/sparcbus_if.m standard
sparc64/sparc64/spitfire.c standard
sparc64/sparc64/support.S standard
sparc64/sparc64/sys_machdep.c standard
diff --git a/sys/conf/options.sparc64 b/sys/conf/options.sparc64
index d0893b7..5bd885a 100644
--- a/sys/conf/options.sparc64
+++ b/sys/conf/options.sparc64
@@ -6,6 +6,7 @@ EBUS_DEBUG opt_ebus.h
PSYCHO_DEBUG opt_psycho.h
DEBUGGER_ON_POWERFAIL opt_psycho.h
OFW_PCI_DEBUG opt_ofw_pci.h
+OFW_NEWPCI opt_ofw_pci.h
# Normal IOMMU debugging
IOMMU_DEBUG opt_iommu.h
# Debug IOMMU inserts/removes using diagnostic accesses. Very loud.
diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c
index 6c71e02..575ba0a 100644
--- a/sys/sparc64/ebus/ebus.c
+++ b/sys/sparc64/ebus/ebus.c
@@ -48,6 +48,8 @@
* there are machines with both ISA and EBus.
*/
+#include "opt_ofw_pci.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -101,6 +103,10 @@ struct ebus_softc {
int sc_nrange;
int sc_nimap;
+
+#ifdef OFW_NEWPCI
+ struct ofw_bus_iinfo sc_iinfo;
+#endif
};
static int ebus_probe(device_t);
@@ -159,12 +165,12 @@ ebus_probe(device_t dev)
phandle_t node;
char *cname;
- /*
- * XXX: PCI specific! There should be a common cookie IVAR value for all
- * buses! Does not really matter much here though...
- */
+#ifdef OFW_NEWPCI
+ node = ofw_pci_get_node(dev);
+#else
node = ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev),
pci_get_function(dev));
+#endif
if (node == 0)
return (ENXIO);
@@ -192,8 +198,12 @@ ebus_probe(device_t dev)
if (sc->sc_nrange == -1)
panic("ebus_attach: could not get ranges property");
+#ifdef OFW_NEWPCI
+ ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t));
+#endif
+
/*
- * now attach all our children
+ * Now attach our children.
*/
DPRINTF(EDB_CHILD, ("ebus node %08x, searching children...\n", node));
for (node = OF_child(node); node > 0; node = OF_peer(node)) {
@@ -368,7 +378,8 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node,
{
struct ebus_devinfo *edi;
struct isa_regs *reg;
- u_int32_t *intrs, intr;
+ ofw_isa_intr_t *intrs;
+ ofw_pci_intr_t rintr;
u_int64_t start;
int nreg, nintr, i;
@@ -395,20 +406,26 @@ ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node,
resource_list_add(&edi->edi_rl, SYS_RES_IOPORT, i,
start, start + reg[i].size - 1, reg[i].size);
}
+ free(reg, M_OFWPROP);
nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs),
(void **)&intrs);
for (i = 0; i < nintr; i++) {
- intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback,
+#ifdef OFW_NEWPCI
+ rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo, intrs[i]);
+ if (rintr == PCI_INVALID_IRQ) {
+#else
+ rintr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback,
dev);
- if (intr == ORIR_NOTFOUND) {
+ if (rintr == ORIR_NOTFOUND) {
+#endif
panic("ebus_setup_dinfo: could not map ebus "
"interrupt %d", intrs[i]);
}
resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i,
- intr, intr, 1);
+ rintr, rintr, 1);
}
- free(reg, M_OFWPROP);
+ free(intrs, M_OFWPROP);
return (edi);
}
diff --git a/sys/sparc64/include/ofw_bus.h b/sys/sparc64/include/ofw_bus.h
index 9f07183..f720180 100644
--- a/sys/sparc64/include/ofw_bus.h
+++ b/sys/sparc64/include/ofw_bus.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,34 @@
#define ORIP_NOINT -1
#define ORIR_NOTFOUND 0xffffffff
+/*
+ * Other than in OpenFirmware calls, the size of a bus cell seems to be always
+ * the same.
+ */
+typedef u_int32_t pcell_t;
+
+#ifdef OFW_NEWPCI
+
+struct ofw_bus_iinfo {
+ u_int8_t *opi_imap;
+ u_int8_t *opi_imapmsk;
+ int opi_imapsz;
+ pcell_t opi_addrc;
+};
+
+void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int);
+int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int,
+ void *, int, void *, int, void *);
+int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *,
+ void *, void *, int);
+
+#else
+
typedef int obr_callback_t(phandle_t, u_int8_t *, int, u_int8_t *, int,
u_int8_t **, int *, void *);
u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *, void *);
+#endif
+
#endif /* !_MACHINE_OFW_BUS_H_ */
diff --git a/sys/sparc64/isa/isa.c b/sys/sparc64/isa/isa.c
index 2df0257d..4916b1e 100644
--- a/sys/sparc64/isa/isa.c
+++ b/sys/sparc64/isa/isa.c
@@ -29,6 +29,8 @@
* $FreeBSD$
*/
+#include "opt_ofw_pci.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -57,8 +59,6 @@
#include <sparc64/pci/ofw_pci.h>
#include <sparc64/isa/ofw_isa.h>
-#include "sparcbus_if.h"
-
/* There can be only one ISA bus, so it is safe to use globals. */
bus_space_tag_t isa_io_bt = NULL;
bus_space_handle_t isa_io_hdl;
@@ -73,7 +73,11 @@ u_int64_t isa_mem_limit;
device_t isa_bus_device;
static phandle_t isab_node;
-static u_int32_t isa_ino[8];
+static ofw_pci_intr_t isa_ino[8];
+
+#ifdef OFW_NEWPCI
+struct ofw_bus_iinfo isa_iinfo;
+#endif
/*
* XXX: This is really partly partly PCI-specific, but unfortunately is
@@ -98,9 +102,9 @@ isa_irq_pending(void)
/* XXX: Is this correct? */
for (i = 7, pending = 0; i >= 0; i--) {
- pending <<= 1;
- if (isa_ino[i] != ORIR_NOTFOUND) {
- pending |= (SPARCBUS_INTR_PENDING(isa_bus_device,
+ pending <<= 1;
+ if (isa_ino[i] != PCI_INVALID_IRQ) {
+ pending |= (OFW_PCI_INTR_PENDING(isa_bus_device,
isa_ino[i]) == 0) ? 0 : 1;
}
}
@@ -112,29 +116,47 @@ isa_init(device_t dev)
{
device_t bridge;
phandle_t node;
- u_int32_t ino;
+ ofw_isa_intr_t ino;
+#ifndef OFW_NEWPCI
+ ofw_pci_intr_t rino;
+#endif
struct isa_ranges *br;
int nbr, i;
/* The parent of the bus must be a PCI-ISA bridge. */
bridge = device_get_parent(dev);
+#ifdef OFW_NEWPCI
+ isab_node = ofw_pci_get_node(bridge);
+#else
isab_node = ofw_pci_node(bridge);
+#endif
nbr = OF_getprop_alloc(isab_node, "ranges", sizeof(*br), (void **)&br);
if (nbr <= 0)
panic("isa_init: cannot get bridge range property");
+
+#ifdef OFW_NEWPCI
+ ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t));
+#endif
+
/*
- * This is really a bad kluge; however, it is needed to provide
- * isa_irq_pending().
+ * This is really a bad kludge; however, it is needed to provide
+ * isa_irq_pending(), which is unfortunately still used by some
+ * drivers.
*/
for (i = 0; i < 8; i++)
- isa_ino[i] = ORIR_NOTFOUND;
+ isa_ino[i] = PCI_INVALID_IRQ;
for (node = OF_child(isab_node); node != 0; node = OF_peer(node)) {
if (OF_getprop(node, "interrupts", &ino, sizeof(ino)) == -1)
continue;
if (ino > 7)
panic("isa_init: XXX: ino too large");
- isa_ino[ino] = ofw_bus_route_intr(node, ino,
- ofw_pci_orb_callback, dev);
+#ifdef OFW_NEWPCI
+ isa_ino[ino] = ofw_isa_route_intr(bridge, node, &isa_iinfo,
+ ino);
+#else
+ rino = ofw_bus_route_intr(node, ino, ofw_pci_orb_callback, dev);
+ isa_ino[ino] = rino == ORIR_NOTFOUND ? PCI_INVALID_IRQ : rino;
+#endif
}
for (nbr -= 1; nbr >= 0; nbr--) {
@@ -143,15 +165,15 @@ isa_init(device_t dev)
/* This is probably always 0. */
isa_io_base = ISAB_RANGE_PHYS(&br[nbr]);
isa_io_limit = br[nbr].size;
- isa_io_hdl = SPARCBUS_GET_BUS_HANDLE(bridge, SBBT_IO,
- isa_io_base, &isa_io_bt);
+ isa_io_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
+ SYS_RES_IOPORT, isa_io_base, &isa_io_bt);
break;
case ISAR_SPACE_MEM:
/* This is probably always 0. */
isa_mem_base = ISAB_RANGE_PHYS(&br[nbr]);
isa_mem_limit = br[nbr].size;
- isa_mem_hdl = SPARCBUS_GET_BUS_HANDLE(bridge, SBBT_MEM,
- isa_mem_base, &isa_mem_bt);
+ isa_mem_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
+ SYS_RES_MEMORY, isa_mem_base, &isa_mem_bt);
break;
}
}
@@ -170,7 +192,7 @@ isa_route_intr_res(device_t bus, u_long start, u_long end)
if (start > 7)
panic("isa_route_intr_res: start out of isa range");
res = isa_ino[start];
- if (res == ORIR_NOTFOUND)
+ if (res == PCI_INVALID_IRQ)
device_printf(bus, "could not map interrupt %d\n", res);
return (res);
}
@@ -244,7 +266,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
"irq allocation");
if (!isdefault) {
start = end = isa_route_intr_res(bus, start, end);
- if (start == 255)
+ if (start == PCI_INVALID_IRQ)
return (NULL);
}
break;
@@ -255,7 +277,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
start = ulmin(start + base, limit);
end = ulmin(end + base, limit);
}
-
+
/*
* This inlines a modified resource_list_alloc(); this is needed
* because the resources need to have offsets added to them, which
@@ -289,7 +311,7 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
break;
case SYS_RES_IRQ:
start = end = isa_route_intr_res(bus, start, end);
- if (start == 255)
+ if (start == PCI_INVALID_IRQ)
return (NULL);
break;
}
diff --git a/sys/sparc64/isa/ofw_isa.c b/sys/sparc64/isa/ofw_isa.c
index a87665e..986220d 100644
--- a/sys/sparc64/isa/ofw_isa.c
+++ b/sys/sparc64/isa/ofw_isa.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2000 Matthew R. Green
- * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
+ * Copyright (c) 2001, 2003 Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
* Helper functions which can be used in both ISA and EBus code.
*/
+#include "opt_ofw_pci.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -42,11 +44,14 @@
#include <ofw/openfirm.h>
#include <ofw/ofw_pci.h>
+#include <machine/bus.h>
#include <machine/resource.h>
#include <machine/ofw_bus.h>
-#include <sparc64/isa/ofw_isa.h>
#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/isa/ofw_isa.h>
+
+#include "pcib_if.h"
/* XXX: this only supports PCI as parent bus right now. */
int
@@ -86,3 +91,27 @@ ofw_isa_map_iorange(struct isa_ranges *range, int nrange, u_long *start,
panic("ofw_isa_map_iorange: could not map range %#lx - %#lx",
*start, *end);
}
+
+#ifdef OFW_NEWPCI
+ofw_pci_intr_t
+ofw_isa_route_intr(device_t bridge, phandle_t node, struct ofw_bus_iinfo *ii,
+ ofw_isa_intr_t intr)
+{
+ struct isa_regs reg;
+ u_int8_t maskbuf[sizeof(reg) + sizeof(intr)];
+ device_t pbridge;
+ ofw_isa_intr_t mintr;
+
+ pbridge = device_get_parent(device_get_parent(bridge));
+ /*
+ * If we get a match from using the map, the resulting INO is
+ * fully specified, so we may not continue to map.
+ */
+ if (!ofw_bus_lookup_imap(node, ii, &reg, sizeof(reg),
+ &intr, sizeof(intr), &mintr, sizeof(mintr), maskbuf)) {
+ /* Try routing at the parent bridge. */
+ mintr = PCIB_ROUTE_INTERRUPT(pbridge, bridge, intr);
+ }
+ return (mintr);
+}
+#endif /* OFW_NEWPCI */
diff --git a/sys/sparc64/isa/ofw_isa.h b/sys/sparc64/isa/ofw_isa.h
index 9402657..dd534ad 100644
--- a/sys/sparc64/isa/ofw_isa.h
+++ b/sys/sparc64/isa/ofw_isa.h
@@ -60,24 +60,28 @@ struct isa_ranges {
((((u_int64_t)((r)->child_hi)) << 32) | ((u_int64_t)(r)->child_lo))
#define ISA_RANGE_PS(r) (((r)->phys_hi >> 24) & 0x03)
+typedef u_int32_t ofw_isa_intr_t;
+
struct isa_imap {
u_int32_t phys_hi; /* high phys addr mask */
u_int32_t phys_lo; /* low phys addr mask */
- u_int32_t intr; /* interrupt mask */
- int32_t cnode; /* child node */
- u_int32_t cintr; /* child interrupt */
+ ofw_isa_intr_t intr; /* interrupt mask */
+ phandle_t cnode; /* child node */
+ ofw_pci_intr_t cintr; /* child interrupt */
};
struct isa_imap_msk {
u_int32_t phys_hi; /* high phys addr */
u_int32_t phys_lo; /* low phys addr */
- u_int32_t intr; /* interrupt */
+ ofw_isa_intr_t intr; /* interrupt */
};
-/* Map an interrupt property to an INO */
-int ofw_isa_map_intr(struct isa_imap *, int, struct isa_imap_msk *, int,
- struct isa_regs *, int);
/* Map an IO range. Returns the resource type of the range. */
int ofw_isa_map_iorange(struct isa_ranges *, int, u_long *, u_long *);
+#ifdef OFW_NEWPCI
+ofw_pci_intr_t ofw_isa_route_intr(device_t, phandle_t, struct ofw_bus_iinfo *,
+ ofw_isa_intr_t);
+#endif
+
#endif /* !_SPARC64_ISA_OFW_ISA_H_ */
diff --git a/sys/sparc64/pci/apb.c b/sys/sparc64/pci/apb.c
index 4e8b746..49324b2 100644
--- a/sys/sparc64/pci/apb.c
+++ b/sys/sparc64/pci/apb.c
@@ -2,7 +2,7 @@
* Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
* Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
* Copyright (c) 2000 BSDi
- * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
+ * Copyright (c) 2001, 2003 Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,6 +40,8 @@
* We can use some pf the pcib methods anyway.
*/
+#include "opt_ofw_pci.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -49,40 +51,34 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_pci.h>
+#include <machine/bus.h>
+#include <machine/ofw_bus.h>
#include <machine/resource.h>
-#include <sparc64/pci/ofw_pci.h>
-
-#include <pci/pcivar.h>
#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#include <pci/pcib_private.h>
#include "pcib_if.h"
+#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/pci/ofw_pcib_subr.h>
+
/*
* Bridge-specific data.
*/
struct apb_softc {
- device_t dev;
- u_int8_t secbus; /* secondary bus number */
- u_int8_t subbus; /* subordinate bus number */
- u_int8_t iomap;
- u_int8_t memmap;
+ struct ofw_pcib_gen_softc sc_bsc;
+ u_int8_t sc_iomap;
+ u_int8_t sc_memmap;
};
-static int apb_probe(device_t dev);
-static int apb_attach(device_t dev);
-static struct resource *apb_alloc_resource(device_t dev, device_t child,
- int type, int *rid, u_long start, u_long end, u_long count, u_int flags);
-static int apb_read_ivar(device_t dev, device_t child, int which,
- uintptr_t *result);
-static int apb_write_ivar(device_t dev, device_t child, int which,
- uintptr_t value);
-static int apb_maxslots(device_t dev);
-static u_int32_t apb_read_config(device_t dev, int b, int s, int f, int reg,
- int width);
-static void apb_write_config(device_t dev, int b, int s, int f, int reg,
- u_int32_t val, int width);
-static int apb_route_interrupt(device_t pcib, device_t dev, int pin);
+static device_probe_t apb_probe;
+static device_attach_t apb_attach;
+static bus_alloc_resource_t apb_alloc_resource;
+#ifndef OFW_NEWPCI
+static pcib_route_interrupt_t apb_route_interrupt;
+#endif
static device_method_t apb_methods[] = {
/* Device interface */
@@ -94,8 +90,8 @@ static device_method_t apb_methods[] = {
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_read_ivar, apb_read_ivar),
- DEVMETHOD(bus_write_ivar, apb_write_ivar),
+ DEVMETHOD(bus_read_ivar, pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, pcib_write_ivar),
DEVMETHOD(bus_alloc_resource, apb_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
@@ -104,10 +100,20 @@ static device_method_t apb_methods[] = {
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
/* pcib interface */
- DEVMETHOD(pcib_maxslots, apb_maxslots),
- DEVMETHOD(pcib_read_config, apb_read_config),
- DEVMETHOD(pcib_write_config, apb_write_config),
+ DEVMETHOD(pcib_maxslots, pcib_maxslots),
+ DEVMETHOD(pcib_read_config, pcib_read_config),
+ DEVMETHOD(pcib_write_config, pcib_write_config),
+#ifdef OFW_NEWPCI
+ DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt),
+#else
DEVMETHOD(pcib_route_interrupt, apb_route_interrupt),
+#endif
+
+ /* ofw_pci interface */
+#ifdef OFW_NEWPCI
+ DEVMETHOD(ofw_pci_get_node, ofw_pcib_gen_get_node),
+ DEVMETHOD(ofw_pci_adjust_busrange, ofw_pcib_gen_adjust_busrange),
+#endif
{ 0, 0 }
};
@@ -118,9 +124,7 @@ static driver_t apb_driver = {
sizeof(struct apb_softc),
};
-static devclass_t apb_devclass;
-
-DRIVER_MODULE(apb, pci, apb_driver, apb_devclass, 0, 0);
+DRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0);
/* APB specific registers */
#define APBR_IOMAP 0xde
@@ -178,42 +182,42 @@ static int
apb_attach(device_t dev)
{
struct apb_softc *sc;
- device_t child;
sc = device_get_softc(dev);
- sc->dev = dev;
/*
* Get current bridge configuration.
*/
- sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
- sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
- sc->iomap = pci_read_config(dev, APBR_IOMAP, 1);
- sc->memmap = pci_read_config(dev, APBR_MEMMAP, 1);
+ sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
+ sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
+#ifdef OFW_NEWPCI
+ ofw_pcib_gen_setup(dev);
+#else
+ sc->sc_bsc.ops_pcib_sc.dev = dev;
+ sc->sc_bsc.ops_pcib_sc.secbus = pci_read_config(dev, PCIR_SECBUS_1, 1);
+ sc->sc_bsc.ops_pcib_sc.subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1);
+#endif
if (bootverbose) {
- device_printf(dev, " secondary bus %d\n", sc->secbus);
- device_printf(dev, " subordinate bus %d\n", sc->subbus);
+ device_printf(dev, " secondary bus %d\n",
+ sc->sc_bsc.ops_pcib_sc.secbus);
+ device_printf(dev, " subordinate bus %d\n",
+ sc->sc_bsc.ops_pcib_sc.subbus);
device_printf(dev, " I/O decode ");
- apb_map_print(sc->iomap, APB_IO_SCALE);
+ apb_map_print(sc->sc_iomap, APB_IO_SCALE);
printf("\n");
device_printf(dev, " memory decode ");
- apb_map_print(sc->memmap, APB_MEM_SCALE);
+ apb_map_print(sc->sc_memmap, APB_MEM_SCALE);
printf("\n");
}
- /*
- * If we don't hardwire the bus down, pciconf gets confused.
- */
- if (sc->secbus != 0) {
- child = device_add_child(dev, "pci", sc->secbus);
- if (child != NULL)
- return (bus_generic_attach(dev));
- } else
+#ifndef OFW_NEWPCI
+ if (sc->sc_bsc.ops_pcib_sc.secbus == 0)
panic("apb_attach: APB with uninitialized secbus");
+#endif
- /* no secondary bus; we should have fixed this */
- return (0);
+ device_add_child(dev, "pci", sc->sc_bsc.ops_pcib_sc.secbus);
+ return (bus_generic_attach(dev));
}
/*
@@ -244,8 +248,8 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
*/
switch (type) {
case SYS_RES_IOPORT:
- if (!apb_map_checkrange(sc->iomap, APB_IO_SCALE, start,
- end)) {
+ if (!apb_map_checkrange(sc->sc_iomap, APB_IO_SCALE,
+ start, end)) {
device_printf(dev, "device %s%d requested "
"unsupported I/O range 0x%lx-0x%lx\n",
device_get_name(child),
@@ -253,14 +257,14 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (NULL);
}
if (bootverbose)
- device_printf(sc->dev, "device %s%d requested "
- "decoded I/O range 0x%lx-0x%lx\n",
- device_get_name(child),
+ device_printf(sc->sc_bsc.ops_pcib_sc.dev,
+ "device %s%d requested decoded I/O range "
+ "0x%lx-0x%lx\n", device_get_name(child),
device_get_unit(child), start, end);
break;
case SYS_RES_MEMORY:
- if (!apb_map_checkrange(sc->memmap, APB_MEM_SCALE,
+ if (!apb_map_checkrange(sc->sc_memmap, APB_MEM_SCALE,
start, end)) {
device_printf(dev, "device %s%d requested "
"unsupported memory range 0x%lx-0x%lx\n",
@@ -269,8 +273,9 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (NULL);
}
if (bootverbose)
- device_printf(sc->dev, "device %s%d requested "
- "decoded memory range 0x%lx-0x%lx\n",
+ device_printf(sc->sc_bsc.ops_pcib_sc.dev,
+ "device %s%d requested decoded memory "
+ "range 0x%lx-0x%lx\n",
device_get_name(child),
device_get_unit(child), start, end);
break;
@@ -287,63 +292,7 @@ apb_alloc_resource(device_t dev, device_t child, int type, int *rid,
count, flags));
}
-static int
-apb_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
-{
- struct apb_softc *sc = device_get_softc(dev);
-
- switch (which) {
- case PCIB_IVAR_BUS:
- *result = sc->secbus;
- return (0);
- }
- return (ENOENT);
-}
-
-static int
-apb_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
-{
- struct apb_softc *sc = device_get_softc(dev);
-
- switch (which) {
- case PCIB_IVAR_BUS:
- sc->secbus = value;
- break;
- }
- return (ENOENT);
-}
-
-/*
- * PCIB interface.
- */
-static int
-apb_maxslots(device_t dev)
-{
-
- return (PCI_SLOTMAX);
-}
-
-/*
- * Since we are a child of a PCI bus, its parent must support the pcib
- * interface.
- */
-static u_int32_t
-apb_read_config(device_t dev, int b, int s, int f, int reg, int width)
-{
-
- return (PCIB_READ_CONFIG(device_get_parent(device_get_parent(dev)), b,
- s, f, reg, width));
-}
-
-static void
-apb_write_config(device_t dev, int b, int s, int f, int reg, u_int32_t val,
- int width)
-{
-
- PCIB_WRITE_CONFIG(device_get_parent(device_get_parent(dev)), b, s, f, reg,
- val, width);
-}
-
+#ifndef OFW_NEWPCI
/*
* Route an interrupt across a PCI bridge - we need to rely on the firmware
* here.
@@ -369,3 +318,4 @@ apb_route_interrupt(device_t pcib, device_t dev, int pin)
*/
return (0);
}
+#endif /* !OFW_NEWPCI */
diff --git a/sys/sparc64/pci/ofw_pci.c b/sys/sparc64/pci/ofw_pci.c
index ca54bf1..7da9cbb 100644
--- a/sys/sparc64/pci/ofw_pci.c
+++ b/sys/sparc64/pci/ofw_pci.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1999, 2000 Matthew R. Green
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
- * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -38,27 +38,29 @@
#include <sys/systm.h>
#include <sys/bus.h>
-#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
#include <dev/ofw/ofw_pci.h>
#include <dev/ofw/openfirm.h>
-#include <sparc64/pci/ofw_pci.h>
-
#include <machine/bus.h>
#include <machine/cache.h>
#include <machine/iommureg.h>
#include <machine/ofw_bus.h>
#include <machine/ver.h>
+#include <sparc64/pci/ofw_pci.h>
+
#include "pcib_if.h"
-#include "sparcbus_if.h"
u_int8_t pci_bus_cnt;
phandle_t *pci_bus_map;
int pci_bus_map_sz;
+#define PCI_BUS_MAP_INC 10
+
+#ifndef OFW_NEWPCI
/* Do not swizzle on a PCI bus node with no interrupt-map propery. */
#define OPQ_NO_SWIZZLE 1
/*
@@ -85,7 +87,6 @@ static int pci_quirks;
#define OFW_PCI_PCIBUS "pci"
#define OFW_PCI_EBUS "ebus"
-#define PCI_BUS_MAP_INC 10
int
ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
@@ -94,7 +95,7 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
{
device_t dev = cookie;
struct ofw_pci_register preg;
- u_int32_t pintr, intr;
+ ofw_pci_intr_t pintr, intr;
u_int slot;
char type[32];
int found = 0;
@@ -105,7 +106,7 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
*terminate = 1;
return (-1);
}
- if (pintsz != sizeof(u_int32_t) || pregsz < sizeof(preg))
+ if (pintsz != sizeof(pintr) || pregsz < sizeof(preg))
return (-1);
bcopy(pintptr, &pintr, sizeof(pintr));
bcopy(pregptr, &preg, sizeof(preg));
@@ -119,13 +120,13 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
* values for external PCI devices seem to always be below 255
* and describe the interrupt pin to be used on the slot, while
* we have to figure out the base INO by looking at the slot
- * number (which we do using a sparcbus method).
+ * number (which we do using an ofw_pci method).
*
* Of course, there is an exception to that nice rule:
* in the ebus case, the interrupt property has the correct
* INO (but without IGN). This is dealt with above.
*/
- intr = SPARCBUS_GUESS_INO(dev, node, slot, pintr);
+ intr = OFW_PCI_GUESS_INO(dev, node, slot, pintr);
found = intr != 255;
*terminate = found;
}
@@ -150,14 +151,14 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
return (-1);
}
-static u_int32_t
-ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign)
+static ofw_pci_intr_t
+ofw_pci_route_intr(device_t dev, phandle_t node, ofw_pci_intr_t ign)
{
u_int32_t rv;
rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback, dev);
if (rv == ORIR_NOTFOUND)
- return (255);
+ return (PCI_INVALID_IRQ);
/*
* Some machines (notably the SPARCengine Ultra AX and the e450) have
* no mappings at all, but use complete interrupt vector number
@@ -167,6 +168,7 @@ ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign)
rv -= ign;
return (rv);
}
+#endif /* !OFW_NEWCPI */
u_int8_t
ofw_pci_alloc_busno(phandle_t node)
@@ -192,6 +194,7 @@ ofw_pci_alloc_busno(phandle_t node)
return (n);
}
+#ifndef OFW_NEWPCI
/*
* Initialize bridge bus numbers for bridges that implement the primary,
* secondary and subordinate bus number registers.
@@ -220,7 +223,7 @@ ofw_pci_binit(device_t busdev, struct ofw_pci_bdesc *obd)
* as well as the the bus numbers and ranges of the bridges.
*/
void
-ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
+ofw_pci_init(device_t dev, phandle_t bushdl, ofw_pci_intr_t ign,
struct ofw_pci_bdesc *obd)
{
struct ofw_pci_register pcir;
@@ -321,7 +324,8 @@ ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
}
/* Initialize the intline registers. */
- if ((intr = ofw_pci_route_intr(dev, node, ign)) != 255) {
+ if ((intr = ofw_pci_route_intr(dev, node, ign)) !=
+ PCI_INVALID_IRQ) {
#ifdef OFW_PCI_DEBUG
device_printf(dev, "%s: mapping intr for "
"%d/%d/%d to %d (preset was %d)\n",
@@ -344,7 +348,7 @@ ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
* 255.
*/
PCIB_WRITE_CONFIG(dev, busno, slot, func,
- PCIR_INTLINE, 255, 1);
+ PCIR_INTLINE, PCI_INVALID_IRQ, 1);
}
}
} while ((node = OF_peer(node)) != 0);
@@ -384,3 +388,4 @@ ofw_pci_node(device_t dev)
return (ofw_pci_find_node(pci_get_bus(dev), pci_get_slot(dev),
pci_get_function(dev)));
}
+#endif /* OFW_NEWPCI */
diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h
index 1c2122b..af26526 100644
--- a/sys/sparc64/pci/ofw_pci.h
+++ b/sys/sparc64/pci/ofw_pci.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1999, 2000 Matthew R. Green
+ * Copyright (c) 2001, 2003 by Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
- * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,6 +36,10 @@
#include <machine/ofw_bus.h>
+typedef u_int32_t ofw_pci_intr_t;
+
+#include "ofw_pci_if.h"
+
/* PCI range child spaces. XXX: are these MI? */
#define PCI_CS_CONFIG 0x00
#define PCI_CS_IO 0x01
@@ -46,18 +50,31 @@ struct ofw_pci_imap {
u_int32_t phys_hi;
u_int32_t phys_mid;
u_int32_t phys_lo;
- u_int32_t intr;
- int32_t child_node;
- u_int32_t child_intr;
+ ofw_pci_intr_t intr;
+ phandle_t child_node;
+ phandle_t child_intr;
};
struct ofw_pci_imap_msk {
u_int32_t phys_hi;
u_int32_t phys_mid;
u_int32_t phys_lo;
- u_int32_t intr;
+ ofw_pci_intr_t intr;
};
+u_int8_t ofw_pci_alloc_busno(phandle_t);
+
+#ifdef OFW_NEWPCI
+
+static __inline phandle_t
+ofw_pci_get_node(device_t dev)
+{
+
+ return (OFW_PCI_GET_NODE(device_get_parent(dev), dev));
+}
+
+#else
+
struct ofw_pci_bdesc;
typedef void ofw_pci_binit_t(device_t, struct ofw_pci_bdesc *);
@@ -72,10 +89,10 @@ struct ofw_pci_bdesc {
};
obr_callback_t ofw_pci_orb_callback;
-u_int8_t ofw_pci_alloc_busno(phandle_t);
ofw_pci_binit_t ofw_pci_binit;
-void ofw_pci_init(device_t, phandle_t, u_int32_t, struct ofw_pci_bdesc *);
+void ofw_pci_init(device_t, phandle_t, ofw_pci_intr_t, struct ofw_pci_bdesc *);
phandle_t ofw_pci_find_node(int, int, int);
phandle_t ofw_pci_node(device_t);
+#endif
#endif /* ! _SPARC64_PCI_OFW_PCI_H_ */
diff --git a/sys/sparc64/pci/ofw_pci_if.m b/sys/sparc64/pci/ofw_pci_if.m
index fe7826e..508e842 100644
--- a/sys/sparc64/pci/ofw_pci_if.m
+++ b/sys/sparc64/pci/ofw_pci_if.m
@@ -1,4 +1,4 @@
-# Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+# Copyright (c) 2001, 2003 by Thomas Moestl <tmm@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -28,66 +28,98 @@
#include <dev/ofw/openfirm.h>
-INTERFACE sparcbus;
+#include <sparc64/pci/ofw_pci.h>
-HEADER {
- /* Bus tag types for the get_bustag method */
- enum sbbt_id {
- SBBT_IO,
- SBBT_MEM,
- };
-};
+INTERFACE ofw_pci;
CODE {
+ static ofw_pci_intr_pending_t ofw_pci_default_intr_pending;
+ static ofw_pci_guess_ino_t ofw_pci_default_guess_ino;
+ static ofw_pci_get_bus_handle_t ofw_pci_default_get_bus_handle;
+ static ofw_pci_get_node_t ofw_pci_default_get_node;
+ static ofw_pci_adjust_busrange_t ofw_pci_default_adjust_busrange;
+
static int
- sparcbus_default_intr_pending(device_t dev, int intr)
+ ofw_pci_default_intr_pending(device_t dev, ofw_pci_intr_t intr)
{
- return (SPARCBUS_INTR_PENDING(device_get_parent(dev), intr));
+ return (OFW_PCI_INTR_PENDING(device_get_parent(dev), intr));
}
- static u_int32_t
- sparcbus_default_guess_ino(device_t dev, phandle_t node, u_int slot,
+ static ofw_pci_intr_t
+ ofw_pci_default_guess_ino(device_t dev, phandle_t node, u_int slot,
u_int pin)
{
- return (SPARCBUS_GUESS_INO(device_get_parent(dev), node, slot,
+ return (OFW_PCI_GUESS_INO(device_get_parent(dev), node, slot,
pin));
}
static bus_space_handle_t
- sparcbus_default_get_bus_handle(device_t dev, enum sbbt_id id,
+ ofw_pci_default_get_bus_handle(device_t dev, int type,
bus_space_handle_t childhdl, bus_space_tag_t *tag)
{
- return (SPARCBUS_GET_BUS_HANDLE(device_get_parent(dev), id,
+ return (OFW_PCI_GET_BUS_HANDLE(device_get_parent(dev), type,
childhdl, tag));
}
+
+ static phandle_t
+ ofw_pci_default_get_node(device_t bus, device_t dev)
+ {
+
+ return (0);
+ }
+
+ static void
+ ofw_pci_default_adjust_busrange(device_t dev, u_int busno)
+ {
+
+ return (OFW_PCI_ADJUST_BUSRANGE(device_get_parent(dev), busno));
+ }
};
# Return whether an interrupt request is pending for the INO intr.
METHOD int intr_pending {
device_t dev;
- int intr;
-} DEFAULT sparcbus_default_intr_pending;
+ ofw_pci_intr_t intr;
+} DEFAULT ofw_pci_default_intr_pending;
# Let the bus driver guess the INO of the device at the given slot and intpin
# on the bus described by the node if it could not be determined from the
# firmware properties. Returns 255 if no INO could be found (mapping will
# continue at the parent), or the desired INO.
-METHOD u_int32_t guess_ino {
+# This method is only used in the !OFW_NEWPCI case, and will go away soon.
+METHOD ofw_pci_intr_t guess_ino {
device_t dev;
phandle_t node;
u_int slot;
u_int pin;
-} DEFAULT sparcbus_default_guess_ino;
+} DEFAULT ofw_pci_default_guess_ino;
# Get the bustag for the root bus. This is needed for ISA old-stlye
# in[bwl]()/out[bwl]() support, where no tag retrieved from a resource is
# passed. The returned tag is used to construct a tag for the whole ISA bus.
METHOD bus_space_handle_t get_bus_handle {
device_t dev;
- enum sbbt_id id;
+ int type;
bus_space_handle_t childhdl;
bus_space_tag_t *tag;
-} DEFAULT sparcbus_default_get_bus_handle;
+} DEFAULT ofw_pci_default_get_bus_handle;
+
+# Get the firmware node for the device dev on the bus bus. The default mthod
+# will return 0, which signals that there is no such node.
+# This could be an ivar, but isn't to avoid numbering conflicts with standard
+# pci/pcib ones.
+METHOD phandle_t get_node {
+ device_t bus;
+ device_t dev;
+} DEFAULT ofw_pci_default_get_node;
+
+# Make sure that all PCI bridges up in the hierarchy contain this bus in their
+# subordinate bus range. This is required because we reenumerate all PCI
+# buses.
+METHOD void adjust_busrange {
+ device_t dev;
+ u_int subbus;
+} DEFAULT ofw_pci_default_adjust_busrange;
diff --git a/sys/sparc64/pci/ofw_pcib.c b/sys/sparc64/pci/ofw_pcib.c
new file mode 100644
index 0000000..c70286a
--- /dev/null
+++ b/sys/sparc64/pci/ofw_pcib.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
+ * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000 BSDi
+ * Copyright (c) 2001 - 2003 Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_ofw_pci.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/pciio.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/ofw_bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+
+#include "pcib_if.h"
+
+#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/pci/ofw_pcib_subr.h>
+
+static device_probe_t ofw_pcib_probe;
+static device_attach_t ofw_pcib_attach;
+
+static device_method_t ofw_pcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_pcib_probe),
+ DEVMETHOD(device_attach, ofw_pcib_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, pcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, pcib_write_ivar),
+ DEVMETHOD(bus_alloc_resource, pcib_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, pcib_maxslots),
+ DEVMETHOD(pcib_read_config, pcib_read_config),
+ DEVMETHOD(pcib_write_config, pcib_write_config),
+ DEVMETHOD(pcib_route_interrupt, ofw_pcib_gen_route_interrupt),
+
+ /* ofw_pci interface */
+ DEVMETHOD(ofw_pci_get_node, ofw_pcib_gen_get_node),
+ DEVMETHOD(ofw_pci_adjust_busrange, ofw_pcib_gen_adjust_busrange),
+
+ { 0, 0 }
+};
+
+static driver_t ofw_pcib_driver = {
+ "pcib",
+ ofw_pcib_methods,
+ sizeof(struct ofw_pcib_gen_softc),
+};
+
+DRIVER_MODULE(ofw_pcib, pci, ofw_pcib_driver, pcib_devclass, 0, 0);
+
+static int
+ofw_pcib_probe(device_t dev)
+{
+ if ((pci_get_class(dev) == PCIC_BRIDGE) &&
+ (pci_get_subclass(dev) == PCIS_BRIDGE_PCI) &&
+ ofw_pci_get_node(dev) != 0) {
+ device_set_desc(dev, "OFW PCI-PCI bridge");
+ return (0);
+ }
+ return (ENXIO);
+}
+
+static int
+ofw_pcib_attach(device_t dev)
+{
+ struct ofw_pcib_gen_softc *sc = device_get_softc(dev);
+
+ ofw_pcib_gen_setup(dev);
+ pcib_attach_common(dev);
+ device_add_child(dev, "pci", sc->ops_pcib_sc.secbus);
+ return (bus_generic_attach(dev));
+}
diff --git a/sys/sparc64/pci/ofw_pcib_subr.c b/sys/sparc64/pci/ofw_pcib_subr.c
new file mode 100644
index 0000000..0c72c48
--- /dev/null
+++ b/sys/sparc64/pci/ofw_pcib_subr.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2003 by Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_ofw_pci.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+
+#include <machine/bus.h>
+#include <machine/ofw_bus.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcib_private.h>
+
+#include "pcib_if.h"
+
+#include <sparc64/pci/ofw_pci.h>
+#include <sparc64/pci/ofw_pcib_subr.h>
+
+void
+ofw_pcib_gen_setup(device_t bridge)
+{
+ struct ofw_pcib_gen_softc *sc = device_get_softc(bridge);
+ u_int secbus;
+
+ sc->ops_pcib_sc.dev = bridge;
+ sc->ops_node = ofw_pci_get_node(bridge);
+ KASSERT(sc->ops_node != 0,
+ ("ofw_pcib_gen_setup: no ofw pci parent bus!"));
+
+ /*
+ * Setup the secondary bus number register, by allocating a new unique
+ * bus number for it; the firmware preset does not always seem to be
+ * correct.
+ */
+ secbus = ofw_pci_alloc_busno(sc->ops_node);
+ pci_write_config(bridge, PCIR_PRIBUS_1, pci_get_bus(bridge), 1);
+ pci_write_config(bridge, PCIR_SECBUS_1, secbus, 1);
+ pci_write_config(bridge, PCIR_SUBBUS_1, secbus, 1);
+ sc->ops_pcib_sc.subbus = sc->ops_pcib_sc.secbus = secbus;
+ /* Notify parent bridges. */
+ OFW_PCI_ADJUST_BUSRANGE(device_get_parent(bridge), secbus);
+
+ ofw_bus_setup_iinfo(sc->ops_node, &sc->ops_iinfo,
+ sizeof(ofw_pci_intr_t));
+}
+
+int
+ofw_pcib_gen_route_interrupt(device_t bridge, device_t dev, int intpin)
+{
+ struct ofw_pcib_gen_softc *sc = device_get_softc(bridge);
+ struct ofw_bus_iinfo *ii = &sc->ops_iinfo;
+ struct ofw_pci_register reg;
+ device_t pbridge = device_get_parent(device_get_parent(bridge));
+ phandle_t node = ofw_pci_get_node(dev);
+ ofw_pci_intr_t pintr, mintr;
+ u_int8_t maskbuf[sizeof(reg) + sizeof(pintr)];
+
+ if (ii->opi_imapsz > 0) {
+ pintr = intpin;
+ if (ofw_bus_lookup_imap(node, ii, &reg, sizeof(reg), &pintr,
+ sizeof(pintr), &mintr, sizeof(mintr), maskbuf)) {
+ /*
+ * If we've found a mapping, return it and don't map
+ * it again on higher levels - that causes problems
+ * in some cases, and never seems to be required.
+ */
+ return (mintr);
+ }
+ } else if (intpin >= 1 && intpin <= 4) {
+ /*
+ * When an interrupt map is missing, we need to do the
+ * standard PCI swizzle and continue mapping at the parent.
+ */
+ return (pcib_route_interrupt(bridge, dev, intpin));
+ }
+ /* Try at the parent. */
+ return (PCIB_ROUTE_INTERRUPT(pbridge, bridge, intpin));
+}
+
+phandle_t
+ofw_pcib_gen_get_node(device_t bridge, device_t dev)
+{
+ struct ofw_pcib_gen_softc *sc = device_get_softc(bridge);
+
+ return (sc->ops_node);
+}
+
+void
+ofw_pcib_gen_adjust_busrange(device_t bridge, u_int subbus)
+{
+ struct ofw_pcib_gen_softc *sc = device_get_softc(bridge);
+
+ if (subbus > sc->ops_pcib_sc.subbus) {
+#ifdef OFW_PCI_DEBUG
+ device_printf(bridge,
+ "adjusting secondary bus number from %d to %d\n",
+ sc->ops_pcib_sc.subbus, subbus);
+#endif
+ pci_write_config(bridge, PCIR_SUBBUS_1, subbus, 1);
+ sc->ops_pcib_sc.subbus = subbus;
+ /* Notify parent bridges. */
+ OFW_PCI_ADJUST_BUSRANGE(device_get_parent(bridge), subbus);
+ }
+}
+
diff --git a/sys/sparc64/pci/ofw_pcib_subr.h b/sys/sparc64/pci/ofw_pcib_subr.h
new file mode 100644
index 0000000..8e03532
--- /dev/null
+++ b/sys/sparc64/pci/ofw_pcib_subr.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003 by Thomas Moestl <tmm@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _SPARC64_PCI_OFW_PCI_SUBR_H
+#define _SPARC64_PCI_OFW_PCI_SUBR_H
+
+struct ofw_pcib_gen_softc {
+ /*
+ * This is here so that we can use pci bridge methods, too - the
+ * generic routines only need the dev, secbus and subbus members
+ * filled.
+ */
+ struct pcib_softc ops_pcib_sc;
+#ifdef OFW_NEWPCI
+ phandle_t ops_node;
+ struct ofw_bus_iinfo ops_iinfo;
+#endif
+};
+
+void ofw_pcib_gen_setup(device_t);
+pcib_route_interrupt_t ofw_pcib_gen_route_interrupt;
+ofw_pci_get_node_t ofw_pcib_gen_get_node;
+ofw_pci_adjust_busrange_t ofw_pcib_gen_adjust_busrange;
+
+#endif /* !_SPARC64_PCI_OFW_PCI_SUBR_H */
diff --git a/sys/sparc64/pci/ofw_pcibus.c b/sys/sparc64/pci/ofw_pcibus.c
new file mode 100644
index 0000000..597b656
--- /dev/null
+++ b/sys/sparc64/pci/ofw_pcibus.c
@@ -0,0 +1,264 @@
+/*-
+ * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
+ * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
+ * Copyright (c) 2000, BSDi
+ * Copyright (c) 2003, Thomas Moestl <tmm@FreeBSD.org>
+ * 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 unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_ofw_pci.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/module.h>
+#include <sys/pciio.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+
+#include <machine/bus.h>
+#include <machine/bus_common.h>
+#include <machine/cache.h>
+#include <machine/iommureg.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h>
+
+#include <sparc64/pci/ofw_pci.h>
+
+#include "pcib_if.h"
+#include "pci_if.h"
+
+/* Helper functions. */
+static void ofw_pcibus_setup_device(device_t, u_int, u_int, u_int);
+
+/* Methods. */
+static device_probe_t ofw_pcibus_probe;
+static device_attach_t ofw_pcibus_attach;
+static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
+static ofw_pci_get_node_t ofw_pcibus_get_node;
+
+static device_method_t ofw_pcibus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_pcibus_probe),
+ DEVMETHOD(device_attach, ofw_pcibus_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, pci_print_child),
+ DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch),
+ DEVMETHOD(bus_read_ivar, pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, pci_write_ivar),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ DEVMETHOD(bus_get_resource_list, pci_get_resource_list),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_delete_resource, pci_delete_resource),
+ DEVMETHOD(bus_alloc_resource, pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
+ DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
+
+ /* PCI interface */
+ DEVMETHOD(pci_read_config, pci_read_config_method),
+ DEVMETHOD(pci_write_config, pci_write_config_method),
+ DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method),
+ DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
+ DEVMETHOD(pci_enable_io, pci_enable_io_method),
+ DEVMETHOD(pci_disable_io, pci_disable_io_method),
+ DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method),
+ DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method),
+ DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt),
+
+ /* OFW PCI interface */
+ DEVMETHOD(ofw_pci_get_node, ofw_pcibus_get_node),
+
+ { 0, 0 }
+};
+
+struct ofw_pcibus_devinfo {
+ struct pci_devinfo opd_dinfo;
+ phandle_t opd_node;
+};
+
+struct ofw_pcibus_softc {
+ phandle_t ops_node;
+};
+
+static driver_t ofw_pcibus_driver = {
+ "pci",
+ ofw_pcibus_methods,
+ sizeof(struct ofw_pcibus_softc),
+};
+
+DRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0);
+MODULE_VERSION(ofw_pcibus, 1);
+MODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1);
+
+static int
+ofw_pcibus_probe(device_t dev)
+{
+
+ if (ofw_pci_get_node(dev) == 0)
+ return (ENXIO);
+ device_set_desc(dev, "OFW PCI bus");
+
+ return (0);
+}
+
+/*
+ * Perform miscellaneous setups the firmware usually does not do for us.
+ */
+static void
+ofw_pcibus_setup_device(device_t bridge, u_int busno, u_int slot, u_int func)
+{
+ u_int lat, clnsz;
+
+ /*
+ * Initialize the latency timer register for busmaster devices to work
+ * properly. This is another task which the firmware does not always
+ * perform. The Min_Gnt register can be used to compute it's recommended
+ * value: it contains the desired latency in units of 1/4 us. To
+ * calculate the correct latency timer value, a bus clock of 33MHz and
+ * no wait states should be assumed.
+ */
+ lat = PCIB_READ_CONFIG(bridge, busno, slot, func, PCIR_MINGNT, 1) *
+ 33 / 4;
+ if (lat != 0) {
+#ifdef OFW_PCI_DEBUG
+ device_printf(bridge, "device %d/%d/%d: latency timer %d -> "
+ "%d\n", busno, slot, func,
+ PCIB_READ_CONFIG(bridge, busno, slot, func,
+ PCIR_LATTIMER, 1), lat);
+#endif /* OFW_PCI_DEBUG */
+ PCIB_WRITE_CONFIG(bridge, busno, slot, func,
+ PCIR_LATTIMER, imin(lat, 255), 1);
+ }
+
+ /*
+ * Compute a value to write into the cache line size register.
+ * The role of the streaming cache is unclear in write invalidate
+ * transfers, so it is made sure that it's line size is always reached.
+ */
+ clnsz = imax(cache.ec_linesize, STRBUF_LINESZ);
+ KASSERT((clnsz / STRBUF_LINESZ) * STRBUF_LINESZ == clnsz &&
+ (clnsz / cache.ec_linesize) * cache.ec_linesize == clnsz &&
+ (clnsz / 4) * 4 == clnsz, ("bogus cache line size %d", clnsz));
+ PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_CACHELNSZ,
+ clnsz / 4, 1);
+
+ /*
+ * The preset in the intline register is usually wrong. Reset it to 255,
+ * so that the PCI code will reroute the interrupt if needed.
+ */
+ PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_INTLINE,
+ PCI_INVALID_IRQ, 1);
+}
+
+static int
+ofw_pcibus_attach(device_t dev)
+{
+ device_t pcib = device_get_parent(dev);
+ struct ofw_pci_register pcir;
+ struct ofw_pcibus_devinfo *dinfo;
+ phandle_t node, child;
+ u_int slot, busno, func;
+
+ /*
+ * Ask the bridge for the bus number - in some cases, we need to
+ * renumber buses, so the firmware information cannot be trusted.
+ */
+ busno = pcib_get_bus(dev);
+ if (bootverbose)
+ device_printf(dev, "physical bus=%d\n", busno);
+
+ node = ofw_pci_get_node(dev);
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
+ panic("ofw_pci_attach: OF_getprop failed");
+ slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
+ func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
+ ofw_pcibus_setup_device(pcib, busno, slot, func);
+ dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
+ busno, slot, func, sizeof(*dinfo));
+ if (dinfo != NULL) {
+ dinfo->opd_node = child;
+ pci_add_child(dev, (struct pci_devinfo *)dinfo);
+ }
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+ofw_pcibus_assign_interrupt(device_t dev, device_t child)
+{
+ struct ofw_pcibus_devinfo *dinfo = device_get_ivars(child);
+ pcicfgregs *cfg = &dinfo->opd_dinfo.cfg;
+ phandle_t node = ofw_pci_get_node(child);
+ ofw_pci_intr_t intr;
+ int isz;
+
+ isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
+ if (isz != sizeof(intr)) {
+ /* No property; our best guess is the intpin. */
+ intr = cfg->intpin;
+ } else if (intr >= 255) {
+ /*
+ * A fully specified interrupt (including IGN), as present on
+ * SPARCengine Ultra AX and e450. Extract the INO and return it.
+ */
+ return (INTINO(intr));
+ }
+ /*
+ * If we got intr from a property, it may or may not be an intpin.
+ * For on-board devices, it frequently is not, and is completely out
+ * of the valid intpin range. For PCI slots, it hopefully is, otherwise
+ * we will have trouble interfacing with non-OFW buses such as cardbus.
+ * Since we cannot tell which it is without violating layering, we
+ * will always use the route_interrupt method, and treat exceptions on
+ * the level they become apparent.
+ */
+ return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr));
+}
+
+static phandle_t
+ofw_pcibus_get_node(device_t bus, device_t dev)
+{
+ struct ofw_pcibus_devinfo *dinfo = device_get_ivars(dev);
+
+ return (dinfo->opd_node);
+}
diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c
index 4d5a3a3..a1d7fee 100644
--- a/sys/sparc64/pci/psycho.c
+++ b/sys/sparc64/pci/psycho.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1999, 2000 Matthew R. Green
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>
* All rights reserved.
- * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,6 +36,7 @@
* UltraSPARC IIi and IIe `sabre' PCI controllers.
*/
+#include "opt_ofw_pci.h"
#include "opt_psycho.h"
#include <sys/param.h>
@@ -55,6 +56,7 @@
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/nexusvar.h>
+#include <machine/ofw_bus.h>
#include <machine/ofw_upa.h>
#include <machine/resource.h>
#include <machine/cpu.h>
@@ -71,7 +73,6 @@
#include <sparc64/pci/psychovar.h>
#include "pcib_if.h"
-#include "sparcbus_if.h"
static void psycho_get_ranges(phandle_t, struct upa_ranges **, int *);
static void psycho_set_intr(struct psycho_softc *, int, device_t, bus_addr_t,
@@ -80,7 +81,9 @@ static int psycho_find_intrmap(struct psycho_softc *, int, bus_addr_t *,
bus_addr_t *, u_long *);
static void psycho_intr_stub(void *);
static bus_space_tag_t psycho_alloc_bus_tag(struct psycho_softc *, int);
-
+#ifndef OFW_NEWPCI
+static ofw_pci_binit_t psycho_binit;
+#endif
/* Interrupt handlers */
static void psycho_ue(void *);
@@ -94,34 +97,32 @@ static void psycho_wakeup(void *);
/* IOMMU support */
static void psycho_iommu_init(struct psycho_softc *, int);
-static ofw_pci_binit_t psycho_binit;
/*
- * autoconfiguration
+ * Methods.
*/
-static int psycho_probe(device_t);
-static int psycho_attach(device_t);
-static int psycho_read_ivar(device_t, device_t, int, u_long *);
-static int psycho_setup_intr(device_t, device_t, struct resource *, int,
- driver_intr_t *, void *, void **);
-static int psycho_teardown_intr(device_t, device_t, struct resource *, void *);
-static struct resource *psycho_alloc_resource(device_t, device_t, int, int *,
- u_long, u_long, u_long, u_int);
-static int psycho_activate_resource(device_t, device_t, int, int,
- struct resource *);
-static int psycho_deactivate_resource(device_t, device_t, int, int,
- struct resource *);
-static int psycho_release_resource(device_t, device_t, int, int,
- struct resource *);
-static int psycho_maxslots(device_t);
-static u_int32_t psycho_read_config(device_t, u_int, u_int, u_int, u_int, int);
-static void psycho_write_config(device_t, u_int, u_int, u_int, u_int, u_int32_t,
- int);
-static int psycho_route_interrupt(device_t, device_t, int);
-static int psycho_intr_pending(device_t, int);
-static u_int32_t psycho_guess_ino(device_t, phandle_t, u_int, u_int);
-static bus_space_handle_t psycho_get_bus_handle(device_t dev, enum sbbt_id id,
- bus_space_handle_t childhdl, bus_space_tag_t *tag);
+static device_probe_t psycho_probe;
+static device_attach_t psycho_attach;
+static bus_read_ivar_t psycho_read_ivar;
+static bus_setup_intr_t psycho_setup_intr;
+static bus_teardown_intr_t psycho_teardown_intr;
+static bus_alloc_resource_t psycho_alloc_resource;
+static bus_activate_resource_t psycho_activate_resource;
+static bus_deactivate_resource_t psycho_deactivate_resource;
+static bus_release_resource_t psycho_release_resource;
+static pcib_maxslots_t psycho_maxslots;
+static pcib_read_config_t psycho_read_config;
+static pcib_write_config_t psycho_write_config;
+static pcib_route_interrupt_t psycho_route_interrupt;
+static ofw_pci_intr_pending_t psycho_intr_pending;
+#ifndef OFW_NEWPCI
+static ofw_pci_guess_ino_t psycho_guess_ino;
+#endif
+static ofw_pci_get_bus_handle_t psycho_get_bus_handle;
+#ifdef OFW_NEWPCI
+static ofw_pci_get_node_t psycho_get_node;
+static ofw_pci_adjust_busrange_t psycho_adjust_busrange;
+#endif
static device_method_t psycho_methods[] = {
/* Device interface */
@@ -144,10 +145,16 @@ static device_method_t psycho_methods[] = {
DEVMETHOD(pcib_write_config, psycho_write_config),
DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt),
- /* sparcbus interface */
- DEVMETHOD(sparcbus_intr_pending, psycho_intr_pending),
- DEVMETHOD(sparcbus_guess_ino, psycho_guess_ino),
- DEVMETHOD(sparcbus_get_bus_handle, psycho_get_bus_handle),
+ /* ofw_pci interface */
+ DEVMETHOD(ofw_pci_intr_pending, psycho_intr_pending),
+#ifndef OFW_NEWPCI
+ DEVMETHOD(ofw_pci_guess_ino, psycho_guess_ino),
+#endif
+ DEVMETHOD(ofw_pci_get_bus_handle, psycho_get_bus_handle),
+#ifdef OFW_NEWPCI
+ DEVMETHOD(ofw_pci_get_node, psycho_get_node),
+ DEVMETHOD(ofw_pci_adjust_busrange, psycho_adjust_busrange),
+#endif
{ 0, 0 }
};
@@ -314,7 +321,9 @@ psycho_attach(device_t dev)
struct psycho_softc *osc = NULL;
struct psycho_softc *asc;
struct upa_regs *reg;
+#ifndef OFW_NEWPCI
struct ofw_pci_bdesc obd;
+#endif
struct psycho_desc *desc;
phandle_t node;
u_int64_t csr;
@@ -587,17 +596,30 @@ psycho_attach(device_t dev)
if (n != sizeof(psycho_br))
panic("broken psycho bus-range (%d)", n);
- sc->sc_busno = ofw_pci_alloc_busno(sc->sc_node);
- obd.obd_bus = psycho_br[0];
- obd.obd_secbus = obd.obd_subbus = sc->sc_busno;
+ sc->sc_secbus = sc->sc_subbus = ofw_pci_alloc_busno(sc->sc_node);
+ /*
+ * Program the bus range registers.
+ * NOTE: the psycho, the second write changes the bus number the
+ * psycho itself uses for it's configuration space, so these
+ * writes must be kept in this order!
+ * The sabre always uses bus 0, but there only can be one sabre per
+ * machine.
+ */
+ PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SUBBUS,
+ sc->sc_subbus, 1);
+ PCIB_WRITE_CONFIG(dev, psycho_br[0], PCS_DEVICE, PCS_FUNC, PCSR_SECBUS,
+ sc->sc_secbus, 1);
+
+#ifdef OFW_NEWPCI
+ ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_pci_intr_t));
+#else
+ obd.obd_bus = obd.obd_secbus = sc->sc_secbus;
+ obd.obd_subbus = sc->sc_subbus;
obd.obd_slot = PCS_DEVICE;
obd.obd_func = PCS_FUNC;
obd.obd_init = psycho_binit;
obd.obd_super = NULL;
- /* Initial setup. */
- psycho_binit(dev, &obd);
- /* Update the bus number to what was just programmed. */
- obd.obd_bus = obd.obd_secbus;
+
/*
* Initialize the interrupt registers of all devices hanging from
* the host bridge directly or indirectly via PCI-PCI bridges.
@@ -608,8 +630,9 @@ psycho_attach(device_t dev)
* Additionally, set up the bus numbers and ranges.
*/
ofw_pci_init(dev, sc->sc_node, sc->sc_ign, &obd);
+#endif /* OFW_NEWPCI */
- device_add_child(dev, "pci", device_get_unit(dev));
+ device_add_child(dev, "pci", sc->sc_secbus);
return (bus_generic_attach(dev));
}
@@ -726,8 +749,8 @@ psycho_ce(void *arg)
afar = PSYCHO_READ8(sc, PSR_CE_AFA);
afsr = PSYCHO_READ8(sc, PSR_CE_AFS);
/* It's correctable. Dump the regs and continue. */
- printf("%s: correctable DMA error AFAR %#lx AFSR %#lx\n",
- device_get_name(sc->sc_dev), (u_long)afar, (u_long)afsr);
+ device_printf(sc->sc_dev, "correctable DMA error AFAR %#lx "
+ "AFSR %#lx\n", (u_long)afar, (u_long)afsr);
}
static void
@@ -780,7 +803,7 @@ psycho_wakeup(void *arg)
PSYCHO_WRITE8(sc, PSR_PWRMGT_INT_CLR, 0);
/* Gee, we don't really have a framework to deal with this properly. */
- printf("%s: power management wakeup\n", device_get_name(sc->sc_dev));
+ device_printf(sc->sc_dev, "power management wakeup\n");
}
#endif /* PSYCHO_MAP_WAKEUP */
@@ -810,6 +833,7 @@ psycho_iommu_init(struct psycho_softc *sc, int tsbsize)
iommu_init(name, is, tsbsize, sc->sc_dvmabase, 0);
}
+#ifndef OFW_NEWPCI
static void
psycho_binit(device_t busdev, struct ofw_pci_bdesc *obd)
{
@@ -819,28 +843,20 @@ psycho_binit(device_t busdev, struct ofw_pci_bdesc *obd)
obd->obd_bus, obd->obd_slot, obd->obd_func, obd->obd_bus,
obd->obd_secbus, obd->obd_subbus);
#endif /* PSYCHO_DEBUG */
- /*
- * NOTE: this must be kept in this order, since the last write will
- * change the config space address of the psycho.
- */
PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
PCSR_SUBBUS, obd->obd_subbus, 1);
- PCIB_WRITE_CONFIG(busdev, obd->obd_bus, obd->obd_slot, obd->obd_func,
- PCSR_SECBUS, obd->obd_secbus, 1);
}
+#endif
static int
psycho_maxslots(device_t dev)
{
- /*
- * XXX: is this correct? At any rate, a number that is too high
- * shouldn't do any harm, if only because of the way things are
- * handled in psycho_read_config.
- */
- return (31);
+ /* XXX: is this correct? */
+ return (PCI_SLOTMAX);
}
+#ifndef OFW_NEWPCI
/*
* Keep a table of quirky PCI devices that need fixups before the MI PCI code
* creates the resource lists. This needs to be moved around once other bus
@@ -862,6 +878,7 @@ static struct psycho_dquirk dquirks[] = {
{ 0x1102108e, DQT_BAD_INTPIN }, /* Sun FireWire ctl. (PCIO2 func. 2) */
{ 0x1103108e, DQT_BAD_INTPIN }, /* Sun USB ctl. (PCIO2 func. 3) */
};
+#endif /* !OFW_NEWPCI */
#define NDQUIRKS (sizeof(dquirks) / sizeof(dquirks[0]))
@@ -872,10 +889,13 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
struct psycho_softc *sc;
bus_space_handle_t bh;
u_long offset = 0;
- u_int32_t r, devid;
+#ifndef OFW_NEWPCI
+ u_int32_t devid;
+#endif
u_int8_t byte;
u_int16_t shrt;
u_int32_t wrd;
+ u_int32_t r;
int i;
sc = (struct psycho_softc *)device_get_softc(dev);
@@ -906,6 +926,7 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
r = -1;
}
+#ifndef OFW_NEWPCI
if (reg == PCIR_INTPIN && r == 0) {
/* Check for DQT_BAD_INTPIN quirk. */
devid = psycho_read_config(dev, bus, slot, func,
@@ -927,6 +948,7 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
}
}
}
+#endif /* !OFW_NEWPCI */
return (r);
}
@@ -957,9 +979,44 @@ psycho_write_config(device_t dev, u_int bus, u_int slot, u_int func,
}
static int
-psycho_route_interrupt(device_t bus, device_t dev, int pin)
+psycho_route_interrupt(device_t bridge, device_t dev, int pin)
{
-
+#ifdef OFW_NEWPCI
+ struct psycho_softc *sc = device_get_softc(bridge);
+ struct ofw_pci_register reg;
+ bus_addr_t intrmap;
+ phandle_t node = ofw_pci_get_node(dev);
+ ofw_pci_intr_t pintr, mintr;
+ u_int8_t maskbuf[sizeof(reg) + sizeof(pintr)];
+
+ pintr = pin;
+ if (ofw_bus_lookup_imap(node, &sc->sc_iinfo, &reg, sizeof(reg),
+ &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf))
+ return (mintr);
+ /*
+ * If this is outside of the range for an intpin, it's likely a full
+ * INO, and no mapping is required at all; this happens on the u30,
+ * where there's no interrupt map at the psycho node. Fortunately,
+ * there seem to be no INOs in the intpin range on this boxen, so
+ * this easy heuristics will do.
+ */
+ if (pin > 4)
+ return (pin);
+ /*
+ * Guess the INO; we always assume that this is a non-OBIO
+ * device, and that pin is a "real" intpin number. Determine
+ * the mapping register to be used by the slot number.
+ * We only need to do this on e450s, it seems; here, the slot numbers
+ * for bus A are one-based, while those for bus B seemingly have an
+ * offset of 2 (hence the factor of 3 below).
+ */
+ intrmap = PSR_PCIA0_INT_MAP +
+ 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half);
+ mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1;
+ device_printf(bridge, "guessing interrupt %d for device %d/%d pin %d\n",
+ (int)mintr, pci_get_slot(dev), pci_get_function(dev), pin);
+ return (mintr);
+#else
/*
* XXX: ugly loathsome hack:
* We can't use ofw_pci_route_intr() here; the device passed may be
@@ -976,6 +1033,7 @@ psycho_route_interrupt(device_t bus, device_t dev, int pin)
* which case we are lost.
*/
return (0);
+#endif /* OFW_NEWPCI */
}
static int
@@ -986,7 +1044,7 @@ psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
sc = (struct psycho_softc *)device_get_softc(dev);
switch (which) {
case PCIB_IVAR_BUS:
- *result = sc->sc_busno;
+ *result = sc->sc_secbus;
return (0);
}
return (ENOENT);
@@ -1032,7 +1090,7 @@ psycho_setup_intr(device_t dev, device_t child,
ino = INTINO(vec);
if (!psycho_find_intrmap(sc, ino, &intrmapptr, &intrclrptr, NULL)) {
- printf("Cannot find interrupt vector %lx\n", vec);
+ device_printf(dev, "Cannot find interrupt vector %lx\n", vec);
free(pc, M_DEVBUF);
return (NULL);
}
@@ -1204,20 +1262,22 @@ psycho_release_resource(device_t bus, device_t child, int type, int rid,
}
static int
-psycho_intr_pending(device_t dev, int intr)
+psycho_intr_pending(device_t dev, ofw_pci_intr_t intr)
{
struct psycho_softc *sc;
u_long diag;
sc = (struct psycho_softc *)device_get_softc(dev);
if (!psycho_find_intrmap(sc, intr, NULL, NULL, &diag)) {
- printf("psycho_intr_pending: mapping not found for %d\n", intr);
+ device_printf(dev, "psycho_intr_pending: mapping not found for"
+ " %d\n", intr);
return (0);
}
return (diag != 0);
}
-static u_int32_t
+#ifndef OFW_NEWPCI
+static ofw_pci_intr_t
psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin)
{
struct psycho_softc *sc = (struct psycho_softc *)device_get_softc(dev);
@@ -1230,7 +1290,7 @@ psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin)
* the INO.
*/
if (node != sc->sc_node)
- return (255);
+ return (PCI_INVALID_IRQ);
/*
* Actually guess the INO. We always assume that this is a non-OBIO
* device, and use from the slot number to determine it.
@@ -1241,19 +1301,20 @@ psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin)
intrmap = PSR_PCIA0_INT_MAP + 8 * (slot - 1 + 3 * sc->sc_half);
return (INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1);
}
+#endif /* !OFW_NEWPCI */
static bus_space_handle_t
-psycho_get_bus_handle(device_t dev, enum sbbt_id id,
- bus_space_handle_t childhdl, bus_space_tag_t *tag)
+psycho_get_bus_handle(device_t dev, int type, bus_space_handle_t childhdl,
+ bus_space_tag_t *tag)
{
struct psycho_softc *sc;
sc = (struct psycho_softc *)device_get_softc(dev);
- switch(id) {
- case SBBT_IO:
+ switch (type) {
+ case SYS_RES_IOPORT:
*tag = sc->sc_iot;
return (sc->sc_bh[PCI_CS_IO] + childhdl);
- case SBBT_MEM:
+ case SYS_RES_MEMORY:
*tag = sc->sc_memt;
return (sc->sc_bh[PCI_CS_MEM32] + childhdl);
default:
@@ -1261,6 +1322,35 @@ psycho_get_bus_handle(device_t dev, enum sbbt_id id,
}
}
+#ifdef OFW_NEWPCI
+static phandle_t
+psycho_get_node(device_t bus, device_t dev)
+{
+ struct psycho_softc *sc = device_get_softc(bus);
+
+ /* We only have one child, the PCI bus, which needs our own node. */
+ return (sc->sc_node);
+}
+
+static void
+psycho_adjust_busrange(device_t dev, u_int subbus)
+{
+ struct psycho_softc *sc = device_get_softc(dev);
+
+ /* If necessary, adjust the subordinate bus number register. */
+ if (subbus > sc->sc_subbus) {
+#ifdef PSYCHO_DEBUG
+ device_printf(dev,
+ "adjusting secondary bus number from %d to %d\n",
+ sc->sc_subbus, subbus);
+#endif
+ sc->sc_subbus = subbus;
+ PCIB_WRITE_CONFIG(dev, sc->sc_secbus, PCS_DEVICE, PCS_FUNC,
+ PCSR_SUBBUS, subbus, 1);
+ }
+}
+#endif
+
/*
* below here is bus space and bus dma support
*/
diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h
index 2a77b15..584d8a4 100644
--- a/sys/sparc64/pci/psychovar.h
+++ b/sys/sparc64/pci/psychovar.h
@@ -71,6 +71,10 @@ struct psycho_softc {
struct resource *sc_irq_res[6];
void *sc_ihand[6];
+#ifdef OFW_NEWPCI
+ struct ofw_bus_iinfo sc_iinfo;
+#endif
+
/*
* note that the sabre really only has one ranges property,
* used for both simba a and simba b (but the ranges for
@@ -87,7 +91,8 @@ struct psycho_softc {
bus_space_handle_t sc_bh[4];
- int sc_busno;
+ u_int sc_secbus;
+ u_int sc_subbus;
struct rman sc_mem_rman;
struct rman sc_io_rman;
diff --git a/sys/sparc64/sparc64/ofw_bus.c b/sys/sparc64/sparc64/ofw_bus.c
index 6d8e242..359da41 100644
--- a/sys/sparc64/sparc64/ofw_bus.c
+++ b/sys/sparc64/sparc64/ofw_bus.c
@@ -29,7 +29,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
- * Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
+ * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -64,6 +64,8 @@
* bits left.
*/
+#include "opt_ofw_pci.h"
+
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/systm.h>
@@ -72,12 +74,6 @@
#include <machine/ofw_bus.h>
-/*
- * Other than in OpenFirmware calls, the size of a bus cell seems to be always
- * the same.
- */
-typedef u_int32_t pcell_t;
-
static int
ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen)
{
@@ -90,7 +86,122 @@ ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen)
return (-1);
}
+#ifdef OFW_NEWPCI
+
+void
+ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
+{
+ pcell_t addrc;
+ int msksz;
+
+ if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
+ addrc = 2;
+ ii->opi_addrc = addrc * sizeof(pcell_t);
+
+ ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1,
+ (void **)&ii->opi_imap);
+ if (ii->opi_imapsz > 0) {
+ msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1,
+ (void **)&ii->opi_imapmsk);
+ /*
+ * Failure to get the mask is ignored; a full mask is used then.
+ * Barf on bad mask sizes, however.
+ */
+ if (msksz != -1 && msksz != ii->opi_addrc + intrsz) {
+ panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
+ "property!");
+ }
+ }
+
+}
+
+int
+ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
+ int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
+ void *maskbuf)
+{
+ int rv;
+
+ if (ii->opi_imapsz <= 0)
+ return (0);
+ KASSERT(regsz >= ii->opi_addrc,
+ ("ofw_bus_lookup_imap: register size too small: %d < %d",
+ regsz, ii->opi_addrc));
+ rv = OF_getprop(node, "reg", reg, regsz);
+ if (rv < regsz)
+ panic("ofw_bus_lookup_imap: could not get reg property");
+ return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
+ ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
+ mintrsz));
+}
+
+/*
+ * Map an interrupt using the firmware reg, interrupt-map and
+ * interrupt-map-mask properties.
+ * The interrupt property to be mapped must be of size intrsz, and pointed to
+ * by intr. The regs property of the node for which the mapping is done must
+ * be passed as regs. This property is an array of register specifications;
+ * the size of the address part of such a specification must be passed as
+ * physsz. Only the first element of the property is used.
+ * imap and imapsz hold the interrupt mask and it's size.
+ * imapmsk is a pointer to the interrupt-map-mask property, which must have
+ * a size of physsz + intrsz; it may be NULL, in which case a full mask is
+ * assumed.
+ * maskbuf must point to a buffer of length physsz + intrsz.
+ * The interrupt is returned in result, which must point to a buffer of length
+ * rintrsz (which gives the expected size of the mapped interrupt).
+ * Returns 1 if a mapping was found, 0 otherwise.
+ */
+int
+ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
+ void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
+ int rintrsz)
+{
+ phandle_t parent;
+ u_int8_t *ref = maskbuf;
+ u_int8_t *uiintr = intr;
+ u_int8_t *uiregs = regs;
+ u_int8_t *uiimapmsk = imapmsk;
+ u_int8_t *mptr;
+ pcell_t pintrsz;
+ int i, rsz, tsz;
+
+ rsz = -1;
+ if (imapmsk != NULL) {
+ for (i = 0; i < physsz; i++)
+ ref[i] = uiregs[i] & uiimapmsk[i];
+ for (i = 0; i < intrsz; i++)
+ ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
+ } else {
+ bcopy(regs, ref, physsz);
+ bcopy(intr, ref + physsz, intrsz);
+ }
+
+ mptr = imap;
+ i = imapsz;
+ tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz;
+ while (i > 0) {
+ KASSERT(i >= tsz, ("ofw_bus_find_intr: truncated map"));
+ bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
+ if (ofw_bus_searchprop(parent, "#interrupt-cells",
+ &pintrsz, sizeof(pintrsz)) == -1)
+ pintrsz = 1; /* default */
+ pintrsz *= sizeof(pcell_t);
+ if (pintrsz != rintrsz)
+ panic("ofw_bus_search_intrmap: expected interrupt cell "
+ "size incorrect: %d != %d", rintrsz, pintrsz);
+ if (bcmp(ref, mptr, physsz + intrsz) == 0) {
+ bcopy(mptr + physsz + intrsz + sizeof(parent),
+ result, rintrsz);
+ return (1);
+ }
+ mptr += tsz;
+ i -= tsz;
+ }
+ return (0);
+}
+#else
/*
* Map an interrupt using the firmware reg, interrupt-map and
* interrupt-map-mask properties.
@@ -253,3 +364,4 @@ ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb, void *cookie)
free(intr, M_OFWPROP);
return (rv);
}
+#endif /* OFW_NEWPCI */
diff --git a/sys/sparc64/sparc64/sparcbus_if.m b/sys/sparc64/sparc64/sparcbus_if.m
deleted file mode 100644
index fe7826e..0000000
--- a/sys/sparc64/sparc64/sparcbus_if.m
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright (c) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# $FreeBSD$
-
-#include <sys/bus.h>
-#include <machine/bus.h>
-
-#include <dev/ofw/openfirm.h>
-
-INTERFACE sparcbus;
-
-HEADER {
- /* Bus tag types for the get_bustag method */
- enum sbbt_id {
- SBBT_IO,
- SBBT_MEM,
- };
-};
-
-CODE {
- static int
- sparcbus_default_intr_pending(device_t dev, int intr)
- {
-
- return (SPARCBUS_INTR_PENDING(device_get_parent(dev), intr));
- }
-
- static u_int32_t
- sparcbus_default_guess_ino(device_t dev, phandle_t node, u_int slot,
- u_int pin)
- {
-
- return (SPARCBUS_GUESS_INO(device_get_parent(dev), node, slot,
- pin));
- }
-
- static bus_space_handle_t
- sparcbus_default_get_bus_handle(device_t dev, enum sbbt_id id,
- bus_space_handle_t childhdl, bus_space_tag_t *tag)
- {
-
- return (SPARCBUS_GET_BUS_HANDLE(device_get_parent(dev), id,
- childhdl, tag));
- }
-};
-
-# Return whether an interrupt request is pending for the INO intr.
-METHOD int intr_pending {
- device_t dev;
- int intr;
-} DEFAULT sparcbus_default_intr_pending;
-
-# Let the bus driver guess the INO of the device at the given slot and intpin
-# on the bus described by the node if it could not be determined from the
-# firmware properties. Returns 255 if no INO could be found (mapping will
-# continue at the parent), or the desired INO.
-METHOD u_int32_t guess_ino {
- device_t dev;
- phandle_t node;
- u_int slot;
- u_int pin;
-} DEFAULT sparcbus_default_guess_ino;
-
-# Get the bustag for the root bus. This is needed for ISA old-stlye
-# in[bwl]()/out[bwl]() support, where no tag retrieved from a resource is
-# passed. The returned tag is used to construct a tag for the whole ISA bus.
-METHOD bus_space_handle_t get_bus_handle {
- device_t dev;
- enum sbbt_id id;
- bus_space_handle_t childhdl;
- bus_space_tag_t *tag;
-} DEFAULT sparcbus_default_get_bus_handle;
OpenPOWER on IntegriCloud