summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2010-06-18 14:06:27 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2010-06-18 14:06:27 +0000
commitc757ee90aefd19aff23dfb5e938e8e1e8576dbd4 (patch)
tree28ab8d6b3802ae7f1a631f84f71839a5baa6a137 /sys/powerpc
parentf26dfb440a0d48a874435768ee94475ddbe496a2 (diff)
downloadFreeBSD-src-c757ee90aefd19aff23dfb5e938e8e1e8576dbd4.zip
FreeBSD-src-c757ee90aefd19aff23dfb5e938e8e1e8576dbd4.tar.gz
Provide for multiple, cascaded PICs on PowerPC systems, and extend the
OFW interrupt map interface to also return the device's interrupt parent. MFC after: 8.1-RELEASE
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/aim/interrupt.c2
-rw-r--r--sys/powerpc/aim/nexus.c2
-rw-r--r--sys/powerpc/booke/interrupt.c2
-rw-r--r--sys/powerpc/include/intr_machdep.h16
-rw-r--r--sys/powerpc/include/ocpbus.h4
-rw-r--r--sys/powerpc/include/openpicvar.h3
-rw-r--r--sys/powerpc/mpc85xx/atpic.c16
-rw-r--r--sys/powerpc/mpc85xx/isa.c9
-rw-r--r--sys/powerpc/mpc85xx/ocpbus.c42
-rw-r--r--sys/powerpc/mpc85xx/ocpbus.h8
-rw-r--r--sys/powerpc/mpc85xx/opic.c10
-rw-r--r--sys/powerpc/mpc85xx/pci_ocp.c2
-rw-r--r--sys/powerpc/ofw/ofw_pcib_pci.c7
-rw-r--r--sys/powerpc/ofw/ofw_pcibus.c32
-rw-r--r--sys/powerpc/powermac/cpcht.c8
-rw-r--r--sys/powerpc/powermac/grackle.c7
-rw-r--r--sys/powerpc/powermac/hrowpic.c11
-rw-r--r--sys/powerpc/powermac/macgpio.c17
-rw-r--r--sys/powerpc/powermac/macio.c18
-rw-r--r--sys/powerpc/powermac/openpic_macio.c9
-rw-r--r--sys/powerpc/powermac/uninorth.c14
-rw-r--r--sys/powerpc/powermac/uninorthpci.c5
-rw-r--r--sys/powerpc/powerpc/intr_machdep.c106
-rw-r--r--sys/powerpc/powerpc/mp_machdep.c2
-rw-r--r--sys/powerpc/powerpc/openpic.c39
-rw-r--r--sys/powerpc/powerpc/pic_if.m4
26 files changed, 288 insertions, 107 deletions
diff --git a/sys/powerpc/aim/interrupt.c b/sys/powerpc/aim/interrupt.c
index b436038..5f92d24 100644
--- a/sys/powerpc/aim/interrupt.c
+++ b/sys/powerpc/aim/interrupt.c
@@ -81,7 +81,7 @@ powerpc_interrupt(struct trapframe *framep)
switch (framep->exc) {
case EXC_EXI:
critical_enter();
- PIC_DISPATCH(pic, framep);
+ PIC_DISPATCH(root_pic, framep);
critical_exit();
break;
diff --git a/sys/powerpc/aim/nexus.c b/sys/powerpc/aim/nexus.c
index 54567b1..a9cf125 100644
--- a/sys/powerpc/aim/nexus.c
+++ b/sys/powerpc/aim/nexus.c
@@ -208,7 +208,7 @@ nexus_attach(device_t dev)
sc = device_get_softc(dev);
start = 0;
- end = INTR_VECTORS - 1;
+ end = MAX_PICS*INTR_VECTORS - 1;
sc->sc_rman.rm_start = start;
sc->sc_rman.rm_end = end;
diff --git a/sys/powerpc/booke/interrupt.c b/sys/powerpc/booke/interrupt.c
index 91ceeb7..1626a8f 100644
--- a/sys/powerpc/booke/interrupt.c
+++ b/sys/powerpc/booke/interrupt.c
@@ -134,7 +134,7 @@ powerpc_extr_interrupt(struct trapframe *framep)
{
critical_enter();
- PIC_DISPATCH(pic, framep);
+ PIC_DISPATCH(root_pic, framep);
critical_exit();
framep->srr1 &= ~PSL_WE;
}
diff --git a/sys/powerpc/include/intr_machdep.h b/sys/powerpc/include/intr_machdep.h
index 5f0a02a..6267055 100644
--- a/sys/powerpc/include/intr_machdep.h
+++ b/sys/powerpc/include/intr_machdep.h
@@ -29,26 +29,32 @@
#define _MACHINE_INTR_MACHDEP_H_
#define INTR_VECTORS 256
+#define MAX_PICS 5
+
+#define IGN_SHIFT 8
+#define INTR_INTLINE(irq) (irq & ((1 << IGN_SHIFT) - 1))
+#define INTR_IGN(irq) (irq >> IGN_SHIFT)
+
+#define INTR_VEC(pic_id, irq) ((powerpc_ign_lookup(pic_id) << IGN_SHIFT) | irq)
/*
* Default base address for MSI messages on PowerPC
*/
#define MSI_INTEL_ADDR_BASE 0xfee00000
-extern device_t pic;
-extern device_t pic8259;
+extern device_t root_pic;
struct trapframe;
driver_filter_t powerpc_ipi_handler;
void powerpc_register_pic(device_t, u_int);
-void powerpc_register_8259(device_t);
+int powerpc_ign_lookup(uint32_t pic_id);
void powerpc_dispatch_intr(u_int, struct trapframe *);
int powerpc_enable_intr(void);
-int powerpc_setup_intr(const char *, u_int, driver_filter_t,
- driver_intr_t, void *, enum intr_type, void **);
+int powerpc_setup_intr(const char *, u_int, driver_filter_t, driver_intr_t,
+ void *, enum intr_type, void **);
int powerpc_teardown_intr(void *);
int powerpc_config_intr(int, enum intr_trigger, enum intr_polarity);
diff --git a/sys/powerpc/include/ocpbus.h b/sys/powerpc/include/ocpbus.h
index 8b17508..daa952b 100644
--- a/sys/powerpc/include/ocpbus.h
+++ b/sys/powerpc/include/ocpbus.h
@@ -44,4 +44,8 @@
#define OCPBUS_DEVTYPE_I2C 7
#define OCPBUS_DEVTYPE_SEC 8
+/* PIC IDs */
+#define OPIC_ID 0
+#define ATPIC_ID 1
+
#endif /* _MACHINE_OCPBUS_H_ */
diff --git a/sys/powerpc/include/openpicvar.h b/sys/powerpc/include/openpicvar.h
index 403823b..5f28734 100644
--- a/sys/powerpc/include/openpicvar.h
+++ b/sys/powerpc/include/openpicvar.h
@@ -35,10 +35,13 @@
struct openpic_softc {
device_t sc_dev;
struct resource *sc_memr;
+ struct resource *sc_intr;
bus_space_tag_t sc_bt;
bus_space_handle_t sc_bh;
char *sc_version;
int sc_rid;
+ int sc_irq;
+ void *sc_icookie;
u_int sc_ncpu;
u_int sc_nirq;
int sc_psim;
diff --git a/sys/powerpc/mpc85xx/atpic.c b/sys/powerpc/mpc85xx/atpic.c
index f8d1318..4a4f5f1 100644
--- a/sys/powerpc/mpc85xx/atpic.c
+++ b/sys/powerpc/mpc85xx/atpic.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/intr_machdep.h>
+#include <machine/ocpbus.h>
#include <machine/pio.h>
#include <powerpc/mpc85xx/ocpbus.h>
@@ -79,6 +80,9 @@ static void atpic_eoi(device_t, u_int);
static void atpic_ipi(device_t, u_int);
static void atpic_mask(device_t, u_int);
static void atpic_unmask(device_t, u_int);
+static uint32_t atpic_id (device_t dev);
+
+static device_t pic8259;
static device_method_t atpic_isa_methods[] = {
/* Device interface */
@@ -94,6 +98,7 @@ static device_method_t atpic_isa_methods[] = {
DEVMETHOD(pic_ipi, atpic_ipi),
DEVMETHOD(pic_mask, atpic_mask),
DEVMETHOD(pic_unmask, atpic_unmask),
+ DEVMETHOD(pic_id, atpic_id),
{ 0, 0 },
};
@@ -219,7 +224,8 @@ atpic_isa_attach(device_t dev)
atpic_init(sc, ATPIC_SLAVE);
atpic_init(sc, ATPIC_MASTER);
- powerpc_register_8259(dev);
+ powerpc_register_pic(dev, 0x10);
+ pic8259 = dev;
return (0);
fail:
@@ -328,3 +334,11 @@ atpic_unmask(device_t dev, u_int irq)
atpic_write(sc, ATPIC_MASTER, 1, sc->sc_mask[ATPIC_MASTER]);
}
}
+
+static uint32_t
+atpic_id (device_t dev)
+{
+
+ return (ATPIC_ID);
+}
+
diff --git a/sys/powerpc/mpc85xx/isa.c b/sys/powerpc/mpc85xx/isa.c
index 5b996ca..eeffbfd 100644
--- a/sys/powerpc/mpc85xx/isa.c
+++ b/sys/powerpc/mpc85xx/isa.c
@@ -32,12 +32,16 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <sys/rman.h>
+#include <machine/intr_machdep.h>
+#include <machine/ocpbus.h>
#include <machine/resource.h>
#include <isa/isareg.h>
#include <isa/isavar.h>
#include <isa/isa_common.h>
+#include "ocpbus.h"
+
void
isa_init(device_t dev)
{
@@ -58,7 +62,10 @@ isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
resource_list_find(rl, type, *rid) == NULL) {
switch (type) {
case SYS_RES_IOPORT: rids = ISA_PNP_NPORT; break;
- case SYS_RES_IRQ: rids = ISA_PNP_NIRQ; break;
+ case SYS_RES_IRQ:
+ rids = ISA_PNP_NIRQ;
+ start = ISA_IRQ(start);
+ break;
case SYS_RES_MEMORY: rids = ISA_PNP_NMEM; break;
default: rids = 0; break;
}
diff --git a/sys/powerpc/mpc85xx/ocpbus.c b/sys/powerpc/mpc85xx/ocpbus.c
index 6c6515e..17f9d9d 100644
--- a/sys/powerpc/mpc85xx/ocpbus.c
+++ b/sys/powerpc/mpc85xx/ocpbus.c
@@ -277,7 +277,7 @@ ocpbus_attach(device_t dev)
ccsr_read4(OCP85XX_PORDEVSR),
ccsr_read4(OCP85XX_PORDEVSR2));
- for (i = PIC_IRQ_START; i < PIC_IRQ_START + 4; i++)
+ for (i = INTR_VEC(OPIC_ID, 0); i < INTR_VEC(OPIC_ID, 4); i++)
powerpc_config_intr(i, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
return (bus_generic_attach(dev));
@@ -305,35 +305,35 @@ const struct ocp_resource mpc8555_resources[] = {
{OCPBUS_DEVTYPE_QUICC, 0, SYS_RES_MEMORY, 0, OCP85XX_QUICC_OFF,
OCP85XX_QUICC_SIZE},
- {OCPBUS_DEVTYPE_QUICC, 0, SYS_RES_IRQ, 0, PIC_IRQ_INT(30), 1},
+ {OCPBUS_DEVTYPE_QUICC, 0, SYS_RES_IRQ, 0, 30, 1},
{OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_MEMORY, 0, OCP85XX_TSEC0_OFF,
OCP85XX_TSEC_SIZE},
- {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 0, PIC_IRQ_INT(13), 1},
- {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 1, PIC_IRQ_INT(14), 1},
- {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 2, PIC_IRQ_INT(18), 1},
+ {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 0, 13, 1},
+ {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 1, 14, 1},
+ {OCPBUS_DEVTYPE_TSEC, 0, SYS_RES_IRQ, 2, 18, 1},
{OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_MEMORY, 0, OCP85XX_TSEC1_OFF,
OCP85XX_TSEC_SIZE},
- {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 0, PIC_IRQ_INT(19), 1},
- {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 1, PIC_IRQ_INT(20), 1},
- {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 2, PIC_IRQ_INT(24), 1},
+ {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 0, 19, 1},
+ {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 1, 20, 1},
+ {OCPBUS_DEVTYPE_TSEC, 1, SYS_RES_IRQ, 2, 24, 1},
{OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_MEMORY, 0, OCP85XX_TSEC2_OFF,
OCP85XX_TSEC_SIZE},
- {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 0, PIC_IRQ_INT(15), 1},
- {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 1, PIC_IRQ_INT(16), 1},
- {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 2, PIC_IRQ_INT(17), 1},
+ {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 0, 15, 1},
+ {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 1, 16, 1},
+ {OCPBUS_DEVTYPE_TSEC, 2, SYS_RES_IRQ, 2, 17, 1},
{OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_MEMORY, 0, OCP85XX_TSEC3_OFF,
OCP85XX_TSEC_SIZE},
- {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 0, PIC_IRQ_INT(21), 1},
- {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 1, PIC_IRQ_INT(22), 1},
- {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 2, PIC_IRQ_INT(23), 1},
+ {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 0, 21, 1},
+ {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 1, 22, 1},
+ {OCPBUS_DEVTYPE_TSEC, 3, SYS_RES_IRQ, 2, 23, 1},
{OCPBUS_DEVTYPE_UART, 0, SYS_RES_MEMORY, 0, OCP85XX_UART0_OFF,
OCP85XX_UART_SIZE},
- {OCPBUS_DEVTYPE_UART, 0, SYS_RES_IRQ, 0, PIC_IRQ_INT(26), 1},
+ {OCPBUS_DEVTYPE_UART, 0, SYS_RES_IRQ, 0, 26, 1},
{OCPBUS_DEVTYPE_UART, 1, SYS_RES_MEMORY, 0, OCP85XX_UART1_OFF,
OCP85XX_UART_SIZE},
- {OCPBUS_DEVTYPE_UART, 1, SYS_RES_IRQ, 0, PIC_IRQ_INT(26), 1},
+ {OCPBUS_DEVTYPE_UART, 1, SYS_RES_IRQ, 0, 26, 1},
{OCPBUS_DEVTYPE_PCIB, 0, SYS_RES_MEMORY, 0, OCP85XX_PCI0_OFF,
OCP85XX_PCI_SIZE},
@@ -357,15 +357,15 @@ const struct ocp_resource mpc8555_resources[] = {
{OCPBUS_DEVTYPE_I2C, 0, SYS_RES_MEMORY, 0, OCP85XX_I2C0_OFF,
OCP85XX_I2C_SIZE},
- {OCPBUS_DEVTYPE_I2C, 0, SYS_RES_IRQ, 0, PIC_IRQ_INT(27), 1},
+ {OCPBUS_DEVTYPE_I2C, 0, SYS_RES_IRQ, 0, 27, 1},
{OCPBUS_DEVTYPE_I2C, 1, SYS_RES_MEMORY, 0, OCP85XX_I2C1_OFF,
OCP85XX_I2C_SIZE},
- {OCPBUS_DEVTYPE_I2C, 1, SYS_RES_IRQ, 0, PIC_IRQ_INT(27), 1},
+ {OCPBUS_DEVTYPE_I2C, 1, SYS_RES_IRQ, 0, 27, 1},
{OCPBUS_DEVTYPE_SEC, 0, SYS_RES_MEMORY, 0, OCP85XX_SEC_OFF,
OCP85XX_SEC_SIZE},
- {OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 0, PIC_IRQ_INT(29), 1},
- {OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 1, PIC_IRQ_INT(42), 1},
+ {OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 0, 29, 1},
+ {OCPBUS_DEVTYPE_SEC, 0, SYS_RES_IRQ, 1, 42, 1},
{0}
};
@@ -402,7 +402,7 @@ ocpbus_get_resource(device_t dev, device_t child, int type, int rid,
start = res->sr_offset + CCSRBAR_VA;
break;
case SYS_RES_IRQ:
- start = res->sr_offset;
+ start = PIC_IRQ_INT(res->sr_offset);
break;
default:
error = EINVAL;
diff --git a/sys/powerpc/mpc85xx/ocpbus.h b/sys/powerpc/mpc85xx/ocpbus.h
index fb715da..69c9569 100644
--- a/sys/powerpc/mpc85xx/ocpbus.h
+++ b/sys/powerpc/mpc85xx/ocpbus.h
@@ -104,11 +104,9 @@
/*
* PIC definitions
*/
-#define ISA_IRQ_START 0
-#define PIC_IRQ_START (ISA_IRQ_START + 16)
-#define ISA_IRQ(n) (ISA_IRQ_START + (n))
-#define PIC_IRQ_EXT(n) (PIC_IRQ_START + (n))
-#define PIC_IRQ_INT(n) (PIC_IRQ_START + 16 + (n))
+#define ISA_IRQ(n) (INTR_VEC(ATPIC_ID, n))
+#define PIC_IRQ_EXT(n) (INTR_VEC(OPIC_ID, (n)))
+#define PIC_IRQ_INT(n) (INTR_VEC(OPIC_ID, (16 + (n))))
#endif /* _MACHINE_OCP85XX_H */
diff --git a/sys/powerpc/mpc85xx/opic.c b/sys/powerpc/mpc85xx/opic.c
index 529226a..f2c5ef8 100644
--- a/sys/powerpc/mpc85xx/opic.c
+++ b/sys/powerpc/mpc85xx/opic.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
* OpenPIC attachment to ocpbus
*/
static int openpic_ocpbus_probe(device_t);
+static uint32_t openpic_ocpbus_id(device_t);
static device_method_t openpic_ocpbus_methods[] = {
/* Device interface */
@@ -63,6 +64,7 @@ static device_method_t openpic_ocpbus_methods[] = {
DEVMETHOD(pic_ipi, openpic_ipi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
+ DEVMETHOD(pic_id, openpic_ocpbus_id),
{ 0, 0 },
};
@@ -93,3 +95,11 @@ openpic_ocpbus_probe (device_t dev)
device_set_desc(dev, OPENPIC_DEVSTR);
return (BUS_PROBE_DEFAULT);
}
+
+static uint32_t
+openpic_ocpbus_id (device_t dev)
+{
+ return (OPIC_ID);
+}
+
+
diff --git a/sys/powerpc/mpc85xx/pci_ocp.c b/sys/powerpc/mpc85xx/pci_ocp.c
index cdcf986..f257882 100644
--- a/sys/powerpc/mpc85xx/pci_ocp.c
+++ b/sys/powerpc/mpc85xx/pci_ocp.c
@@ -792,7 +792,7 @@ pci_ocp_alloc_resource(device_t dev, device_t child, int type, int *rid,
va = sc->sc_iomem_va;
break;
case SYS_RES_IRQ:
- if (start < PIC_IRQ_START) {
+ if (INTR_IGN(start) == powerpc_ign_lookup(ATPIC_ID)) {
device_printf(dev, "%s requested ISA interrupt %lu\n",
device_get_nameunit(child), start);
}
diff --git a/sys/powerpc/ofw/ofw_pcib_pci.c b/sys/powerpc/ofw/ofw_pcib_pci.c
index 0b6e0ca..953f1b3 100644
--- a/sys/powerpc/ofw/ofw_pcib_pci.c
+++ b/sys/powerpc/ofw/ofw_pcib_pci.c
@@ -42,6 +42,8 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcib_private.h>
+#include <machine/intr_machdep.h>
+
#include "pcib_if.h"
static int ofw_pcib_pci_probe(device_t bus);
@@ -149,6 +151,7 @@ ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
struct ofw_bus_iinfo *ii;
struct ofw_pci_register reg;
cell_t pintr, mintr;
+ phandle_t iparent;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bridge);
@@ -157,13 +160,13 @@ ofw_pcib_pci_route_interrupt(device_t bridge, device_t dev, int intpin)
pintr = intpin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, &reg,
sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- maskbuf)) {
+ &iparent, 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);
+ return (INTR_VEC(iparent, mintr));
}
} else if (intpin >= 1 && intpin <= 4) {
/*
diff --git a/sys/powerpc/ofw/ofw_pcibus.c b/sys/powerpc/ofw/ofw_pcibus.c
index a87890f..3a7564b 100644
--- a/sys/powerpc/ofw/ofw_pcibus.c
+++ b/sys/powerpc/ofw/ofw_pcibus.c
@@ -212,13 +212,16 @@ ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
OF_getprop(iparent, "#interrupt-cells", &icells,
sizeof(icells));
+ if (iparent != 0)
+ intr[0] = INTR_VEC(iparent, intr[0]);
+
if (iparent != 0 && icells > 1) {
powerpc_config_intr(intr[0],
(intr[1] & 1) ? INTR_TRIGGER_LEVEL :
INTR_TRIGGER_EDGE,
INTR_POLARITY_HIGH);
}
-
+
resource_list_add(&dinfo->opd_dinfo.resources,
SYS_RES_IRQ, 0, intr[0], intr[0], 1);
}
@@ -293,7 +296,7 @@ static int
ofw_pcibus_assign_interrupt(device_t dev, device_t child)
{
ofw_pci_intr_t intr;
- phandle_t node;
+ phandle_t node, iparent;
int isz;
node = ofw_bus_get_node(child);
@@ -303,8 +306,8 @@ ofw_pcibus_assign_interrupt(device_t dev, device_t child)
/*
* XXX: Right now we don't have anything sensible to do here,
- * since the ofw_imap stuff relies on nodes have a reg
- * property. There exists ways around this, so the ePAPR
+ * since the ofw_imap stuff relies on nodes having a reg
+ * property. There exist ways around this, so the ePAPR
* spec will need to be studied.
*/
@@ -318,18 +321,29 @@ ofw_pcibus_assign_interrupt(device_t dev, device_t child)
}
/*
+ * Try to determine the node's interrupt parent so we know which
+ * PIC to use.
+ */
+
+ iparent = -1;
+ if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0)
+ iparent = -1;
+
+ /*
* Any AAPL,interrupts property gets priority and is
* fully specified (i.e. does not need routing)
*/
isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr));
- if (isz == sizeof(intr)) {
- return (intr);
- }
+ if (isz == sizeof(intr))
+ return ((iparent == -1) ? intr : INTR_VEC(iparent, intr));
isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
- if (isz != sizeof(intr)) {
- /* No property; our best guess is the intpin. */
+ if (isz == sizeof(intr)) {
+ if (iparent != -1)
+ intr = INTR_VEC(iparent, intr);
+ } else {
+ /* No property: our best guess is the intpin. */
intr = pci_get_intpin(child);
}
diff --git a/sys/powerpc/powermac/cpcht.c b/sys/powerpc/powermac/cpcht.c
index f08140b..6c8ad2f 100644
--- a/sys/powerpc/powermac/cpcht.c
+++ b/sys/powerpc/powermac/cpcht.c
@@ -595,6 +595,7 @@ static void openpic_cpcht_config(device_t, u_int irq,
static void openpic_cpcht_enable(device_t, u_int irq, u_int vector);
static void openpic_cpcht_unmask(device_t, u_int irq);
static void openpic_cpcht_eoi(device_t, u_int irq);
+static uint32_t openpic_cpcht_id(device_t);
static device_method_t openpic_cpcht_methods[] = {
/* Device interface */
@@ -609,6 +610,7 @@ static device_method_t openpic_cpcht_methods[] = {
DEVMETHOD(pic_ipi, openpic_ipi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_cpcht_unmask),
+ DEVMETHOD(pic_id, openpic_cpcht_id),
{ 0, 0 },
};
@@ -808,3 +810,9 @@ openpic_cpcht_eoi(device_t dev, u_int irq)
openpic_eoi(dev, irq);
}
+static uint32_t
+openpic_cpcht_id(device_t dev)
+{
+ return (ofw_bus_get_node(dev));
+}
+
diff --git a/sys/powerpc/powermac/grackle.c b/sys/powerpc/powermac/grackle.c
index fc323bf..381ff12 100644
--- a/sys/powerpc/powermac/grackle.c
+++ b/sys/powerpc/powermac/grackle.c
@@ -43,6 +43,7 @@
#include <dev/pci/pcireg.h>
#include <machine/bus.h>
+#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/pio.h>
#include <machine/resource.h>
@@ -341,13 +342,15 @@ grackle_route_interrupt(device_t bus, device_t dev, int pin)
struct grackle_softc *sc;
struct ofw_pci_register reg;
uint32_t pintr, mintr;
+ phandle_t iparent;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
- sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), maskbuf))
- return (mintr);
+ sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
+ &iparent, maskbuf))
+ return (INTR_VEC(iparent, mintr));
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
diff --git a/sys/powerpc/powermac/hrowpic.c b/sys/powerpc/powermac/hrowpic.c
index ce35d46..f2d8d89 100644
--- a/sys/powerpc/powermac/hrowpic.c
+++ b/sys/powerpc/powermac/hrowpic.c
@@ -70,6 +70,7 @@ static void hrowpic_eoi(device_t, u_int);
static void hrowpic_ipi(device_t, u_int);
static void hrowpic_mask(device_t, u_int);
static void hrowpic_unmask(device_t, u_int);
+static uint32_t hrowpic_id(device_t dev);
static device_method_t hrowpic_methods[] = {
/* Device interface */
@@ -80,6 +81,7 @@ static device_method_t hrowpic_methods[] = {
DEVMETHOD(pic_dispatch, hrowpic_dispatch),
DEVMETHOD(pic_enable, hrowpic_enable),
DEVMETHOD(pic_eoi, hrowpic_eoi),
+ DEVMETHOD(pic_id, hrowpic_id),
DEVMETHOD(pic_ipi, hrowpic_ipi),
DEVMETHOD(pic_mask, hrowpic_mask),
DEVMETHOD(pic_unmask, hrowpic_unmask),
@@ -169,6 +171,8 @@ hrowpic_attach(device_t dev)
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY, 0xffffffff);
powerpc_register_pic(dev, 64);
+ root_pic = dev; /* Heathrow systems have only one PIC */
+
return (0);
}
@@ -282,3 +286,10 @@ hrowpic_unmask(device_t dev, u_int irq)
sc = device_get_softc(dev);
hrowpic_toggle_irq(sc, irq, 1);
}
+
+static uint32_t
+hrowpic_id(device_t dev)
+{
+ return (ofw_bus_get_node(dev));
+}
+
diff --git a/sys/powerpc/powermac/macgpio.c b/sys/powerpc/powermac/macgpio.c
index 5c68dbc..5bdd54d 100644
--- a/sys/powerpc/powermac/macgpio.c
+++ b/sys/powerpc/powermac/macgpio.c
@@ -35,15 +35,16 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
-#include <machine/bus.h>
#include <sys/rman.h>
-#include <machine/vmparam.h>
#include <vm/vm.h>
#include <vm/pmap.h>
-#include <machine/pmap.h>
+#include <machine/bus.h>
+#include <machine/intr_machdep.h>
+#include <machine/pmap.h>
#include <machine/resource.h>
+#include <machine/vmparam.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -150,8 +151,7 @@ macgpio_attach(device_t dev)
{
struct macgpio_softc *sc;
struct macgpio_devinfo *dinfo;
- phandle_t root;
- phandle_t child;
+ phandle_t root, child, iparent;
device_t cdev;
uint32_t irq;
@@ -186,10 +186,13 @@ macgpio_attach(device_t dev)
resource_list_init(&dinfo->mdi_resources);
- if (OF_getprop(child,"interrupts",&irq, sizeof(irq)) ==
+ if (OF_getprop(child, "interrupts", &irq, sizeof(irq)) ==
sizeof(irq)) {
+ OF_searchprop(child, "interrupt-parent", &iparent,
+ sizeof(iparent));
resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
- 0, irq, irq, 1);
+ 0, INTR_VEC(iparent, irq), INTR_VEC(iparent, irq),
+ 1);
}
/* Fix messed-up offsets */
diff --git a/sys/powerpc/powermac/macio.c b/sys/powerpc/powermac/macio.c
index eab1011..1782a4e 100644
--- a/sys/powerpc/powermac/macio.c
+++ b/sys/powerpc/powermac/macio.c
@@ -37,15 +37,16 @@
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
-#include <machine/bus.h>
#include <sys/rman.h>
-#include <machine/vmparam.h>
#include <vm/vm.h>
#include <vm/pmap.h>
-#include <machine/pmap.h>
+#include <machine/bus.h>
+#include <machine/intr_machdep.h>
+#include <machine/pmap.h>
#include <machine/resource.h>
+#include <machine/vmparam.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -186,6 +187,7 @@ macio_get_quirks(const char *name)
static void
macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
{
+ phandle_t iparent;
int *intr;
int i, nintr;
int icells;
@@ -211,11 +213,17 @@ macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
if (intr[0] == -1)
return;
+ if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent))
+ <= 0)
+ panic("Interrupt but no interrupt parent!\n");
+
for (i = 0; i < nintr; i+=icells) {
resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
- dinfo->mdi_ninterrupts, intr[i], intr[i], 1);
+ dinfo->mdi_ninterrupts, INTR_VEC(iparent, intr[i]),
+ INTR_VEC(iparent, intr[i]), 1);
- dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = intr[i];
+ dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] =
+ INTR_VEC(iparent, intr[i]);
dinfo->mdi_ninterrupts++;
}
}
diff --git a/sys/powerpc/powermac/openpic_macio.c b/sys/powerpc/powermac/openpic_macio.c
index ca7f113..4a0eaf4 100644
--- a/sys/powerpc/powermac/openpic_macio.c
+++ b/sys/powerpc/powermac/openpic_macio.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
* MacIO interface
*/
static int openpic_macio_probe(device_t);
+static uint32_t openpic_macio_id(device_t);
static device_method_t openpic_macio_methods[] = {
/* Device interface */
@@ -73,6 +74,7 @@ static device_method_t openpic_macio_methods[] = {
DEVMETHOD(pic_ipi, openpic_ipi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
+ DEVMETHOD(pic_id, openpic_macio_id),
{ 0, 0 },
};
@@ -96,3 +98,10 @@ openpic_macio_probe(device_t dev)
device_set_desc(dev, OPENPIC_DEVSTR);
return (0);
}
+
+static uint32_t
+openpic_macio_id(device_t dev)
+{
+ return (ofw_bus_get_node(dev));
+}
+
diff --git a/sys/powerpc/powermac/uninorth.c b/sys/powerpc/powermac/uninorth.c
index 52f7aaa..c0d228b 100644
--- a/sys/powerpc/powermac/uninorth.c
+++ b/sys/powerpc/powermac/uninorth.c
@@ -144,9 +144,9 @@ DRIVER_MODULE(unin, nexus, unin_chip_driver, unin_chip_devclass, 0, 0);
static void
unin_chip_add_intr(phandle_t devnode, struct unin_chip_devinfo *dinfo)
{
+ phandle_t iparent;
int *intr;
int i, nintr;
- phandle_t iparent;
int icells;
if (dinfo->udi_ninterrupts >= 6) {
@@ -176,9 +176,17 @@ unin_chip_add_intr(phandle_t devnode, struct unin_chip_devinfo *dinfo)
for (i = 0; i < nintr; i+=icells) {
resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ,
- dinfo->udi_ninterrupts, intr[i], intr[i], 1);
+ dinfo->udi_ninterrupts, INTR_VEC(iparent, intr[i]),
+ INTR_VEC(iparent, intr[i]), 1);
+
+ if (icells > 1) {
+ powerpc_config_intr(INTR_VEC(iparent, intr[i]),
+ (intr[i+1] & 1) ? INTR_TRIGGER_LEVEL :
+ INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
+ }
- dinfo->udi_interrupts[dinfo->udi_ninterrupts] = intr[i];
+ dinfo->udi_interrupts[dinfo->udi_ninterrupts] =
+ INTR_VEC(iparent, intr[i]);
dinfo->udi_ninterrupts++;
}
}
diff --git a/sys/powerpc/powermac/uninorthpci.c b/sys/powerpc/powermac/uninorthpci.c
index a8e1f2c..cfc8862 100644
--- a/sys/powerpc/powermac/uninorthpci.c
+++ b/sys/powerpc/powermac/uninorthpci.c
@@ -356,14 +356,15 @@ uninorth_route_interrupt(device_t bus, device_t dev, int pin)
struct uninorth_softc *sc;
struct ofw_pci_register reg;
uint32_t pintr, mintr;
+ phandle_t iparent;
uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
sc = device_get_softc(bus);
pintr = pin;
if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
- maskbuf))
- return (mintr);
+ &iparent, maskbuf))
+ return (INTR_VEC(iparent, mintr));
/* Maybe it's a real interrupt, not an intpin */
if (pin > 4)
diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c
index 0f8520d..85291b1 100644
--- a/sys/powerpc/powerpc/intr_machdep.c
+++ b/sys/powerpc/powerpc/intr_machdep.c
@@ -85,14 +85,6 @@
#include "pic_if.h"
-#ifdef MPC85XX
-#define ISA_IRQ_COUNT 16
-#endif
-
-#ifndef ISA_IRQ_COUNT
-#define ISA_IRQ_COUNT 0
-#endif
-
#define MAX_STRAY_LOG 5
MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
@@ -108,20 +100,25 @@ struct powerpc_intr {
enum intr_polarity pol;
};
+struct pic {
+ device_t pic;
+ uint32_t pic_id;
+ int ipi_irq;
+};
+
static struct mtx intr_table_lock;
static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
+static struct pic piclist[MAX_PICS];
static u_int nvectors; /* Allocated vectors */
+static u_int npics; /* PICs registered */
static u_int stray_count;
+device_t root_pic;
+
#ifdef SMP
static void *ipi_cookie;
#endif
-static u_int ipi_irq;
-
-device_t pic;
-device_t pic8259;
-
static void
intr_init(void *dummy __unused)
{
@@ -198,21 +195,13 @@ static int
powerpc_map_irq(struct powerpc_intr *i)
{
-#if ISA_IRQ_COUNT > 0
- if (i->irq < ISA_IRQ_COUNT) {
- if (pic8259 == NULL) {
- i->pic = pic;
- i->intline = 0;
- return (ENXIO);
- }
- i->pic = pic8259;
- i->intline = i->irq;
- return (0);
- }
-#endif
+ i->intline = INTR_INTLINE(i->irq);
+ i->pic = piclist[INTR_IGN(i->irq)].pic;
+
+ /* Try a best guess if that failed */
+ if (i->pic == NULL)
+ i->pic = root_pic;
- i->pic = pic;
- i->intline = i->irq - ISA_IRQ_COUNT;
return (0);
}
@@ -243,16 +232,44 @@ powerpc_intr_unmask(void *arg)
void
powerpc_register_pic(device_t dev, u_int ipi)
{
+ int i;
+
+ mtx_lock(&intr_table_lock);
- pic = dev;
- ipi_irq = ipi + ISA_IRQ_COUNT;
+ for (i = 0; i < npics; i++) {
+ if (piclist[i].pic_id == PIC_ID(dev))
+ break;
+ }
+ piclist[i].pic = dev;
+ piclist[i].pic_id = PIC_ID(dev);
+ piclist[i].ipi_irq = ipi;
+ if (i == npics)
+ npics++;
+
+ mtx_unlock(&intr_table_lock);
}
-void
-powerpc_register_8259(device_t dev)
+int
+powerpc_ign_lookup(uint32_t pic_id)
{
+ int i;
+
+ mtx_lock(&intr_table_lock);
+
+ for (i = 0; i < npics; i++) {
+ if (piclist[i].pic_id == pic_id) {
+ mtx_unlock(&intr_table_lock);
+ return (i);
+ }
+ }
+ piclist[i].pic = NULL;
+ piclist[i].pic_id = pic_id;
+ piclist[i].ipi_irq = 0;
+ npics++;
- pic8259 = dev;
+ mtx_unlock(&intr_table_lock);
+
+ return (i);
}
int
@@ -260,17 +277,28 @@ powerpc_enable_intr(void)
{
struct powerpc_intr *i;
int error, vector;
+#ifdef SMP
+ int n;
+#endif
- if (pic == NULL)
+ if (npics == 0)
panic("no PIC detected\n");
#ifdef SMP
/* Install an IPI handler. */
- error = powerpc_setup_intr("IPI", ipi_irq, powerpc_ipi_handler,
- NULL, NULL, INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
- if (error) {
- printf("unable to setup IPI handler\n");
- return (error);
+
+ for (n = 0; n < npics; n++) {
+ if (piclist[n].pic != root_pic)
+ continue;
+
+ error = powerpc_setup_intr("IPI",
+ INTR_VEC(piclist[n].pic_id, piclist[n].ipi_irq),
+ powerpc_ipi_handler, NULL, NULL,
+ INTR_TYPE_MISC | INTR_EXCL | INTR_FAST, &ipi_cookie);
+ if (error) {
+ printf("unable to setup IPI handler\n");
+ return (error);
+ }
}
#endif
@@ -295,7 +323,7 @@ powerpc_enable_intr(void)
}
int
-powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
+powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
{
struct powerpc_intr *i;
diff --git a/sys/powerpc/powerpc/mp_machdep.c b/sys/powerpc/powerpc/mp_machdep.c
index f3e16e8..aaa8d66 100644
--- a/sys/powerpc/powerpc/mp_machdep.c
+++ b/sys/powerpc/powerpc/mp_machdep.c
@@ -319,7 +319,7 @@ ipi_send(struct pcpu *pc, int ipi)
pc, pc->pc_cpuid, ipi);
atomic_set_32(&pc->pc_ipimask, (1 << ipi));
- PIC_IPI(pic, pc->pc_cpuid);
+ PIC_IPI(root_pic, pc->pc_cpuid);
CTR1(KTR_SMP, "%s: sent", __func__);
}
diff --git a/sys/powerpc/powerpc/openpic.c b/sys/powerpc/powerpc/openpic.c
index 5a25fc0..3a13235 100644
--- a/sys/powerpc/powerpc/openpic.c
+++ b/sys/powerpc/powerpc/openpic.c
@@ -52,6 +52,7 @@ devclass_t openpic_devclass;
/*
* Local routines
*/
+static int openpic_intr(void *arg);
static __inline uint32_t
openpic_read(struct openpic_softc *sc, u_int reg)
@@ -110,6 +111,29 @@ openpic_attach(device_t dev)
DELAY(100);
}
+ /* Check if this is a cascaded PIC */
+ sc->sc_irq = 0;
+ sc->sc_intr = NULL;
+ if (resource_list_find(BUS_GET_RESOURCE_LIST(device_get_parent(dev),
+ dev), SYS_RES_IRQ, 0) != NULL) {
+ sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &sc->sc_irq, RF_ACTIVE);
+
+ /* XXX Cascaded PICs pass NULL trapframes! */
+ bus_setup_intr(dev, sc->sc_intr, INTR_TYPE_MISC | INTR_MPSAFE,
+ openpic_intr, NULL, dev, &sc->sc_icookie);
+ }
+
+ /* Reset the PIC */
+ x = openpic_read(sc, OPENPIC_CONFIG);
+ x |= OPENPIC_CONFIG_RESET;
+ openpic_write(sc, OPENPIC_CONFIG, x);
+
+ while (openpic_read(sc, OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET) {
+ powerpc_sync();
+ DELAY(100);
+ }
+
x = openpic_read(sc, OPENPIC_FEATURE);
switch (x & OPENPIC_FEATURE_VERSION_MASK) {
case 1:
@@ -185,6 +209,10 @@ openpic_attach(device_t dev)
powerpc_register_pic(dev, sc->sc_nirq);
+ /* If this is not a cascaded PIC, it must be the root PIC */
+ if (sc->sc_intr == NULL)
+ root_pic = dev;
+
return (0);
}
@@ -212,6 +240,17 @@ openpic_config(device_t dev, u_int irq, enum intr_trigger trig,
openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
}
+static int
+openpic_intr(void *arg)
+{
+ device_t dev = (device_t)(arg);
+
+ /* XXX Cascaded PICs do not pass non-NULL trapframes! */
+ openpic_dispatch(dev, NULL);
+
+ return (FILTER_HANDLED);
+}
+
void
openpic_dispatch(device_t dev, struct trapframe *tf)
{
diff --git a/sys/powerpc/powerpc/pic_if.m b/sys/powerpc/powerpc/pic_if.m
index 2fc5071..a472993 100644
--- a/sys/powerpc/powerpc/pic_if.m
+++ b/sys/powerpc/powerpc/pic_if.m
@@ -60,6 +60,10 @@ METHOD void ipi {
u_int cpu;
};
+METHOD uint32_t id {
+ device_t dev;
+};
+
METHOD void mask {
device_t dev;
u_int irq;
OpenPOWER on IntegriCloud