summaryrefslogtreecommitdiffstats
path: root/sys/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'sys/sparc64')
-rw-r--r--sys/sparc64/ebus/ebus.c10
-rw-r--r--sys/sparc64/include/ofw_bus.h4
-rw-r--r--sys/sparc64/isa/isa.c2
-rw-r--r--sys/sparc64/pci/ofw_pci.c86
-rw-r--r--sys/sparc64/pci/ofw_pci.h1
-rw-r--r--sys/sparc64/pci/ofw_pci_if.m26
-rw-r--r--sys/sparc64/pci/psycho.c51
-rw-r--r--sys/sparc64/pci/psychovar.h3
-rw-r--r--sys/sparc64/sparc64/ofw_bus.c4
-rw-r--r--sys/sparc64/sparc64/sparcbus_if.m26
10 files changed, 168 insertions, 45 deletions
diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c
index 42d78c8..6c71e02 100644
--- a/sys/sparc64/ebus/ebus.c
+++ b/sys/sparc64/ebus/ebus.c
@@ -112,7 +112,7 @@ static struct resource *ebus_alloc_resource(device_t, device_t, int, int *,
u_long, u_long, u_long, u_int);
static struct resource_list *ebus_get_resource_list(device_t, device_t);
-static struct ebus_devinfo *ebus_setup_dinfo(struct ebus_softc *,
+static struct ebus_devinfo *ebus_setup_dinfo(device_t, struct ebus_softc *,
phandle_t, char *);
static void ebus_destroy_dinfo(struct ebus_devinfo *);
static int ebus_print_res(struct ebus_devinfo *);
@@ -200,7 +200,7 @@ ebus_probe(device_t dev)
if ((OF_getprop_alloc(node, "name", 1, (void **)&cname)) == -1)
continue;
- if ((edi = ebus_setup_dinfo(sc, node, cname)) == NULL) {
+ if ((edi = ebus_setup_dinfo(dev, sc, node, cname)) == NULL) {
device_printf(dev, "<%s>: incomplete\n", cname);
free(cname, M_OFWPROP);
continue;
@@ -363,7 +363,8 @@ ebus_get_resource_list(device_t dev, device_t child)
}
static struct ebus_devinfo *
-ebus_setup_dinfo(struct ebus_softc *sc, phandle_t node, char *name)
+ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node,
+ char *name)
{
struct ebus_devinfo *edi;
struct isa_regs *reg;
@@ -398,7 +399,8 @@ ebus_setup_dinfo(struct ebus_softc *sc, phandle_t node, char *name)
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);
+ intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback,
+ dev);
if (intr == ORIR_NOTFOUND) {
panic("ebus_setup_dinfo: could not map ebus "
"interrupt %d", intrs[i]);
diff --git a/sys/sparc64/include/ofw_bus.h b/sys/sparc64/include/ofw_bus.h
index 2f67b24..9f07183 100644
--- a/sys/sparc64/include/ofw_bus.h
+++ b/sys/sparc64/include/ofw_bus.h
@@ -32,8 +32,8 @@
#define ORIR_NOTFOUND 0xffffffff
typedef int obr_callback_t(phandle_t, u_int8_t *, int, 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 *);
+u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *, void *);
#endif /* !_MACHINE_OFW_BUS_H_ */
diff --git a/sys/sparc64/isa/isa.c b/sys/sparc64/isa/isa.c
index ef746c3..09c95c1 100644
--- a/sys/sparc64/isa/isa.c
+++ b/sys/sparc64/isa/isa.c
@@ -134,7 +134,7 @@ isa_init(device_t dev)
if (ino > 7)
panic("isa_init: XXX: ino too large");
isa_ino[ino] = ofw_bus_route_intr(node, ino,
- ofw_pci_orb_callback);
+ ofw_pci_orb_callback, dev);
}
for (nbr -= 1; nbr >= 0; nbr--) {
diff --git a/sys/sparc64/pci/ofw_pci.c b/sys/sparc64/pci/ofw_pci.c
index 829ad60..ca54bf1 100644
--- a/sys/sparc64/pci/ofw_pci.c
+++ b/sys/sparc64/pci/ofw_pci.c
@@ -46,44 +46,90 @@
#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 "pcib_if.h"
+#include "sparcbus_if.h"
u_int8_t pci_bus_cnt;
phandle_t *pci_bus_map;
int pci_bus_map_sz;
-#define OPQ_NO_SWIZZLE 1
+/* Do not swizzle on a PCI bus node with no interrupt-map propery. */
+#define OPQ_NO_SWIZZLE 1
+/*
+ * INOs < 255 are really intpin numbers; use a driver method to figure out
+ * the real INO.
+ */
+#define OPQ_INO_CALLBACK 2
+/*
+ * Do not map EBus interrupts at PCI buses, but assume that they are fully
+ * specified already.
+ */
+#define OPQ_EBUS_NOMAP 4
+
static struct ofw_pci_quirk {
char *opq_model;
int opq_quirks;
} ofw_pci_quirks[] = {
- { "SUNW,Ultra-4", OPQ_NO_SWIZZLE },
- { "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE },
+ { "SUNW,Ultra-4", OPQ_INO_CALLBACK | OPQ_EBUS_NOMAP },
+ { "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE },
};
#define OPQ_NENT (sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0]))
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,
- u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate)
+ u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate,
+ void *cookie)
{
+ device_t dev = cookie;
struct ofw_pci_register preg;
u_int32_t pintr, intr;
+ u_int slot;
char type[32];
+ int found = 0;
- if (pintsz != sizeof(u_int32_t))
+ if ((pci_quirks & OPQ_EBUS_NOMAP) != 0 &&
+ OF_getprop(node, "name", type, sizeof(type)) != -1 &&
+ strcmp(type, OFW_PCI_EBUS) == 0) {
+ *terminate = 1;
+ return (-1);
+ }
+ if (pintsz != sizeof(u_int32_t) || pregsz < sizeof(preg))
return (-1);
bcopy(pintptr, &pintr, sizeof(pintr));
- if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) &&
+ bcopy(pregptr, &preg, sizeof(preg));
+ slot = OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi);
+
+ if ((pci_quirks & OPQ_INO_CALLBACK) != 0 && pintr <= 255) {
+ /*
+ * The e450 has no interrupt maps at all, and it usually has
+ * full interrupt numbers, including IGN, in the interrupt
+ * properties. There is one exception, however: the property
+ * 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).
+ *
+ * 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);
+ found = intr != 255;
+ *terminate = found;
+ }
+ if (!found && (pci_quirks & OPQ_NO_SWIZZLE) == 0 &&
OF_getprop(node, "device_type", type, sizeof(type)) != -1 &&
strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) {
/*
@@ -91,29 +137,31 @@ ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
* PCI bridges without interrupt maps, where we apparently must
* do the PCI swizzle and continue to map on at the parent.
*/
- bcopy(pregptr, &preg, sizeof(preg));
- intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) %
- 4 + 1;
+ intr = (slot + pintr + 3) % 4 + 1;
+ *terminate = 0;
+ found = 1;
+ }
+
+ if (found) {
*rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK);
bcopy(&intr, *rintr, sizeof(intr));
- *terminate = 0;
return (sizeof(intr));
- }
- return (-1);
+ } else
+ return (-1);
}
-u_int32_t
-ofw_pci_route_intr(phandle_t node, u_int32_t ign)
+static u_int32_t
+ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign)
{
u_int32_t rv;
- rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback);
+ rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback, dev);
if (rv == ORIR_NOTFOUND)
return (255);
/*
- * Some machines (notably the SPARCengine Ultra AX) have no mappings
- * at all, but use complete interrupt vector number including the IGN.
- * Catch this case and remove the IGN.
+ * Some machines (notably the SPARCengine Ultra AX and the e450) have
+ * no mappings at all, but use complete interrupt vector number
+ * including the IGN. Catch this case and remove the IGN.
*/
if (rv > ign)
rv -= ign;
@@ -273,7 +321,7 @@ ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
}
/* Initialize the intline registers. */
- if ((intr = ofw_pci_route_intr(node, ign)) != 255) {
+ if ((intr = ofw_pci_route_intr(dev, node, ign)) != 255) {
#ifdef OFW_PCI_DEBUG
device_printf(dev, "%s: mapping intr for "
"%d/%d/%d to %d (preset was %d)\n",
diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h
index 45bbb43..1c2122b 100644
--- a/sys/sparc64/pci/ofw_pci.h
+++ b/sys/sparc64/pci/ofw_pci.h
@@ -71,7 +71,6 @@ struct ofw_pci_bdesc {
struct ofw_pci_bdesc *obd_super;
};
-u_int32_t ofw_pci_route_intr(phandle_t, u_int32_t);
obr_callback_t ofw_pci_orb_callback;
u_int8_t ofw_pci_alloc_busno(phandle_t);
ofw_pci_binit_t ofw_pci_binit;
diff --git a/sys/sparc64/pci/ofw_pci_if.m b/sys/sparc64/pci/ofw_pci_if.m
index 2583878..fe7826e 100644
--- a/sys/sparc64/pci/ofw_pci_if.m
+++ b/sys/sparc64/pci/ofw_pci_if.m
@@ -26,6 +26,8 @@
#include <sys/bus.h>
#include <machine/bus.h>
+#include <dev/ofw/openfirm.h>
+
INTERFACE sparcbus;
HEADER {
@@ -37,10 +39,6 @@ HEADER {
};
CODE {
- static int sparcbus_default_intr_pending(device_t, int);
- static bus_space_handle_t sparcbus_default_get_bus_handle(device_t,
- enum sbbt_id, bus_space_handle_t childhdl, bus_space_tag_t *tag);
-
static int
sparcbus_default_intr_pending(device_t dev, int intr)
{
@@ -48,6 +46,15 @@ CODE {
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)
@@ -64,6 +71,17 @@ METHOD int intr_pending {
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.
diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c
index 4cd7fef..fc99bf0 100644
--- a/sys/sparc64/pci/psycho.c
+++ b/sys/sparc64/pci/psycho.c
@@ -141,6 +141,7 @@ 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);
@@ -167,6 +168,7 @@ static device_method_t psycho_methods[] = {
/* 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),
{ 0, 0 }
@@ -336,7 +338,6 @@ psycho_attach(device_t dev)
struct upa_regs *reg;
struct ofw_pci_bdesc obd;
struct psycho_desc *desc;
- vm_paddr_t pcictl_offs;
phandle_t node;
u_int64_t csr;
u_long mlen;
@@ -374,13 +375,25 @@ psycho_attach(device_t dev)
panic("psycho_attach: %d not enough registers", nreg);
sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(&reg[2]);
mlen = UPA_REG_SIZE(&reg[2]);
- pcictl_offs = UPA_REG_PHYS(&reg[0]);
+ sc->sc_pcictl = UPA_REG_PHYS(&reg[0]) - sc->sc_basepaddr;
+ switch (sc->sc_pcictl) {
+ case PSR_PCICTL0:
+ sc->sc_half = 0;
+ break;
+ case PSR_PCICTL1:
+ sc->sc_half = 1;
+ break;
+ default:
+ panic("psycho_attach: bogus pci control register "
+ "location");
+ }
} else {
if (nreg <= 0)
panic("psycho_attach: %d not enough registers", nreg);
sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(&reg[0]);
mlen = UPA_REG_SIZE(reg);
- pcictl_offs = sc->sc_basepaddr + PSR_PCICTL0;
+ sc->sc_pcictl = PSR_PCICTL0;
+ sc->sc_half = 0;
}
/*
@@ -415,17 +428,14 @@ psycho_attach(device_t dev)
sc->sc_bustag = osc->sc_bustag;
sc->sc_bushandle = osc->sc_bushandle;
}
- if (pcictl_offs < sc->sc_basepaddr)
- panic("psycho_attach: bogus pci control register location");
- sc->sc_pcictl = pcictl_offs - sc->sc_basepaddr;
csr = PSYCHO_READ8(sc, PSR_CS);
sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */
if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
- device_printf(dev, "%s, impl %d, version %d, ign %#x\n",
+ device_printf(dev, "%s, impl %d, version %d, ign %#x, bus %c\n",
desc->pd_name, (int)PSYCHO_GCSR_IMPL(csr),
- (int)PSYCHO_GCSR_VERS(csr), sc->sc_ign);
+ (int)PSYCHO_GCSR_VERS(csr), sc->sc_ign, 'A' + sc->sc_half);
/*
* Setup the PCI control register
@@ -1272,6 +1282,31 @@ psycho_intr_pending(device_t dev, int intr)
return (diag != 0);
}
+static u_int32_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);
+ bus_addr_t intrmap;
+
+ /*
+ * If this is not for one of our direct children (i.e. we are mapping
+ * at our node), tell the interrupt mapper to go on - we need the
+ * slot number of the device or it's topmost parent bridge to guess
+ * the INO.
+ */
+ if (node != sc->sc_node)
+ return (255);
+ /*
+ * Actually guess the INO. We always assume that this is a non-OBIO
+ * device, and use from the slot number to determine it.
+ * 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 * (slot - 1 + 3 * sc->sc_half);
+ return (INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1);
+}
+
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)
diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h
index 3b8fa73..2a77b15 100644
--- a/sys/sparc64/pci/psychovar.h
+++ b/sys/sparc64/pci/psychovar.h
@@ -61,6 +61,9 @@ struct psycho_softc {
#define PSYCHO_MODE_SABRE 1
#define PSYCHO_MODE_PSYCHO 2
+ /* Bus A or B of a psycho pair? */
+ int sc_half;
+
struct iommu_state *sc_is;
u_int32_t sc_dvmabase;
diff --git a/sys/sparc64/sparc64/ofw_bus.c b/sys/sparc64/sparc64/ofw_bus.c
index 605a347..6d8e242 100644
--- a/sys/sparc64/sparc64/ofw_bus.c
+++ b/sys/sparc64/sparc64/ofw_bus.c
@@ -160,7 +160,7 @@ ofw_bus_find_intr(u_int8_t *intr, int intrsz, u_int8_t *regs, int physsz,
* This should work for all bus systems.
*/
u_int32_t
-ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb)
+ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb, void *cookie)
{
u_int8_t *reg, *intr, *tintr, *imap, *imapmsk;
phandle_t parent;
@@ -201,7 +201,7 @@ ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb)
*/
if (cb != NULL) {
tisz = cb(parent, intr, isz, reg, regsz, &tintr,
- &found);
+ &found, cookie);
if (tisz != -1) {
isz = tisz;
free(intr, M_OFWPROP);
diff --git a/sys/sparc64/sparc64/sparcbus_if.m b/sys/sparc64/sparc64/sparcbus_if.m
index 2583878..fe7826e 100644
--- a/sys/sparc64/sparc64/sparcbus_if.m
+++ b/sys/sparc64/sparc64/sparcbus_if.m
@@ -26,6 +26,8 @@
#include <sys/bus.h>
#include <machine/bus.h>
+#include <dev/ofw/openfirm.h>
+
INTERFACE sparcbus;
HEADER {
@@ -37,10 +39,6 @@ HEADER {
};
CODE {
- static int sparcbus_default_intr_pending(device_t, int);
- static bus_space_handle_t sparcbus_default_get_bus_handle(device_t,
- enum sbbt_id, bus_space_handle_t childhdl, bus_space_tag_t *tag);
-
static int
sparcbus_default_intr_pending(device_t dev, int intr)
{
@@ -48,6 +46,15 @@ CODE {
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)
@@ -64,6 +71,17 @@ METHOD int intr_pending {
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.
OpenPOWER on IntegriCloud