Revamp the interrupt handling in support of INTR_FILTER. This includes:

o  Revamp the PIC I/F to only abstract the PIC hardware. The
   resource handling has been moved to nexus, where it belongs.
o  Include EOI and MASK+EOI methods to the PIC I/F in support of
   INTR_FILTER.
o  With the allocation of interrupt resources and setup of
   interrupt handlers in the common platform code we can delay
   talking to the PIC hardware after enumeration of all devices.
   Introduce a call to powerpc_intr_enable() in configure_final()
   to achieve that and have powerpc_setup_intr() only program the
   PIC when !cold.
o  As a consequence of the above, remove all early_attach() glue
   from the OpenPIC and Heathrow PIC drivers and have them
   register themselves when they're found during enumeration.
o  Decouple the interrupt vector from the interrupt request line.
   Allocate vectors increasingly so that they can be used for
   the intrcnt index as well. Extend the Heathrow PIC driver to
   translate between IRQ and vector. The OpenPIC driver already
   has the support for vectors in hardware.

Approved by: re (blanket)
This commit is contained in:
marcel 2007-08-11 19:25:32 +00:00
parent 3a4b5d55d8
commit b031fef0fe
15 changed files with 527 additions and 1130 deletions

View File

@ -49,30 +49,19 @@
#include <sys/vmmeter.h>
#include <machine/cpu.h>
#include <machine/clock.h>
#include <machine/db_machdep.h>
#include <machine/fpu.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/spr.h>
#include <machine/sr.h>
void powerpc_interrupt(struct trapframe *);
/*
* External interrupt install routines
*/
static void (*powerpc_extintr_handler)(void);
void
ext_intr_install(void (*new_extint)(void))
{
powerpc_extintr_handler = new_extint;
}
extern void decr_intr(struct trapframe *);
#include "pic_if.h"
/*
* A very short dispatch, to try and maximise assembler code use
@ -90,7 +79,7 @@ powerpc_interrupt(struct trapframe *framep)
switch (framep->exc) {
case EXC_EXI:
atomic_add_int(&td->td_intr_nesting_level, 1);
(*powerpc_extintr_handler)();
PIC_DISPATCH(pic, framep);
atomic_subtract_int(&td->td_intr_nesting_level, 1);
break;

View File

@ -97,7 +97,7 @@ struct nexus_devinfo {
};
struct nexus_softc {
device_t sc_pic;
struct rman sc_rman;
};
/*
@ -182,12 +182,24 @@ nexus_probe(device_t dev)
phandle_t root;
phandle_t child;
struct nexus_softc *sc;
u_long start, end;
if ((root = OF_peer(0)) == -1)
panic("nexus_probe: OF_peer failed.");
sc = device_get_softc(dev);
start = 0;
end = INTR_VECTORS - 1;
sc->sc_rman.rm_start = start;
sc->sc_rman.rm_end = end;
sc->sc_rman.rm_type = RMAN_ARRAY;
sc->sc_rman.rm_descr = "Interrupt request lines";
if (rman_init(&sc->sc_rman) ||
rman_manage_region(&sc->sc_rman, start, end))
panic("nexus_probe IRQ rman");
/*
* Allow devices to identify
*/
@ -302,31 +314,40 @@ nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep)
driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
{
struct nexus_softc *sc;
driver_t *driver;
int error;
sc = device_get_softc(dev);
/* somebody tried to setup an irq that failed to allocate! */
if (res == NULL)
panic("nexus_setup_intr: NULL irq resource!");
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_setup_intr: no pic attached\n");
*cookiep = 0;
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
return (PIC_SETUP_INTR(sc->sc_pic, child, res, flags, filter, intr,
arg, cookiep));
driver = device_get_driver(child);
/*
* We depend here on rman_activate_resource() being idempotent.
*/
error = rman_activate_resource(res);
if (error)
return (error);
error = powerpc_setup_intr(device_get_nameunit(child),
rman_get_start(res), filter, ihand, arg, flags, cookiep);
return (error);
}
static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
void *ih)
void *cookie)
{
struct nexus_softc *sc;
sc = device_get_softc(dev);
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_teardown_intr: no pic attached\n");
return (PIC_TEARDOWN_INTR(sc->sc_pic, child, res, ih));
return (powerpc_teardown_intr(cookie));
}
/*
@ -337,10 +358,8 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct nexus_softc *sc;
struct resource *rv;
sc = device_get_softc(bus);
struct nexus_softc *sc;
struct resource *rv;
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@ -348,10 +367,21 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_alloc_resource: no pic attached\n");
if (count == 0 || start + count - 1 != end) {
device_printf(bus, "invalid IRQ allocation from %s\n",
device_get_nameunit(child));
return (NULL);
}
rv = PIC_ALLOCATE_INTR(sc->sc_pic, child, rid, start, flags);
sc = device_get_softc(bus);
rv = rman_reserve_resource(&sc->sc_rman, start, end, count,
flags, child);
if (rv == NULL) {
device_printf(bus, "IRQ allocation failed for %s\n",
device_get_nameunit(child));
} else
rman_set_rid(rv, *rid);
return (rv);
}
@ -378,9 +408,6 @@ static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
struct nexus_softc *sc;
sc = device_get_softc(bus);
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@ -388,10 +415,7 @@ nexus_release_resource(device_t bus, device_t child, int type, int rid,
return (EINVAL);
}
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_release_resource: no pic attached\n");
return (PIC_RELEASE_INTR(sc->sc_pic, child, rid, res));
return (rman_release_resource(res));
}
static device_t
@ -418,17 +442,6 @@ nexus_device_from_node(device_t parent, phandle_t node)
return (cdev);
}
int
nexus_install_intcntlr(device_t dev)
{
struct nexus_softc *sc;
sc = device_get_softc(device_get_parent(dev));
sc->sc_pic = dev;
return (0);
}
static const char *
nexus_ofw_get_name(device_t bus, device_t dev)
{

View File

@ -28,29 +28,18 @@
#ifndef _MACHINE_INTR_MACHDEP_H_
#define _MACHINE_INTR_MACHDEP_H_
typedef void ih_func_t(void *);
#define INTR_VECTORS 256
struct intr_event;
extern device_t pic;
struct ppc_intr_handler {
ih_func_t *ih_func;
void *ih_arg;
struct intr_event *ih_event;
u_int ih_irq;
u_int ih_flags;
u_int ih_index;
u_long *ih_count;
u_long *ih_straycount;
};
struct trapframe;
/* XXX temporary. */
void ext_intr_install(void (*new_extint)(void));
void powerpc_register_pic(device_t);
void intr_init(void (*)(void), int, void (*)(uintptr_t), void (*)(uintptr_t));
void intr_setup(u_int, ih_func_t *, void *, u_int);
int inthand_add(const char *, u_int, driver_filter_t *filter,
void (*)(void *), void *, int, void **);
int inthand_remove(u_int, void *);
void intr_handle(u_int);
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_teardown_intr(void *);
#endif /* _MACHINE_INTR_MACHDEP_H_ */

View File

@ -44,12 +44,6 @@ extern vm_offset_t kstack0_phys;
extern u_long ns_per_tick;
struct fpreg;
struct proc;
struct reg;
struct cam_sim;
struct pcicfg;
#if defined(_KERNEL) || defined(_STANDALONE)
#define CACHELINESIZE 32
#endif
@ -64,4 +58,7 @@ void decr_init(void);
void cpu_setup(u_int);
struct trapframe;
void powerpc_interrupt(struct trapframe *);
#endif /* !_MACHINE_MD_VAR_H_ */

View File

@ -33,36 +33,31 @@
#define OPENPIC_IRQMAX 256 /* h/w allows more */
struct openpic_softc {
char *sc_version;
u_int sc_ncpu;
u_int sc_nirq;
int sc_psim;
struct rman sc_rman;
device_t sc_dev;
struct resource *sc_memr;
bus_space_tag_t sc_bt;
bus_space_handle_t sc_bh;
u_int sc_hwprobed;
u_int sc_early_done;
device_t sc_altdev;
u_char sc_irqrsv[OPENPIC_IRQMAX]; /* pre-h/w reservation */
char *sc_version;
int sc_rid;
u_int sc_ncpu;
u_int sc_nirq;
int sc_psim;
};
extern devclass_t openpic_devclass;
/*
* Bus-independent attach i/f
*/
int openpic_early_attach(device_t);
int openpic_attach(device_t);
int openpic_attach(device_t);
/*
* PIC interface.
*/
struct resource *openpic_allocate_intr(device_t, device_t, int *,
u_long, u_int);
int openpic_setup_intr(device_t, device_t,
struct resource *, int, driver_filter_t,
driver_intr_t, void *, void **);
int openpic_teardown_intr(device_t, device_t,
struct resource *, void *);
int openpic_release_intr(device_t dev, device_t, int,
struct resource *res);
void openpic_dispatch(device_t, struct trapframe *);
void openpic_enable(device_t, u_int, u_int);
void openpic_eoi(device_t, u_int);
void openpic_mask(device_t, u_int);
void openpic_unmask(device_t, u_int);
#endif /* _POWERPC_OPENPICVAR_H_ */

View File

@ -28,15 +28,9 @@
*/
/*
* A driver for the PIC found in the Heathrow/Paddington MacIO chips.
* A driver for the PIC found in the Heathrow/Paddington MacIO chips.
* This was superseded by an OpenPIC in the Keylargo and beyond
* MacIO versions.
*
* The device is initially located in the Open Firmware device tree
* in the earliest stage of the nexus probe. However, no device registers
* are touched until the actual h/w is probed later on during the
* MacIO probe. At that point, any interrupt sources that were allocated
* prior to this are activated.
*/
#include <sys/param.h>
@ -45,6 +39,7 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/rman.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/openfirm.h>
@ -60,67 +55,35 @@
#include <vm/vm.h>
#include <vm/pmap.h>
#include <sys/rman.h>
#include <powerpc/powermac/hrowpicvar.h>
#include "pic_if.h"
/*
* Device interface.
*/
static void hrowpic_identify(driver_t *, device_t);
static int hrowpic_probe(device_t);
static int hrowpic_attach(device_t);
/*
* PIC interface.
*/
static struct resource *hrowpic_allocate_intr(device_t, device_t, int *,
u_long, u_int);
static int hrowpic_setup_intr(device_t, device_t,
struct resource *, int, driver_filter_t,
driver_intr_t, void *, void **);
static int hrowpic_teardown_intr(device_t, device_t,
struct resource *, void *);
static int hrowpic_release_intr(device_t dev, device_t, int,
struct resource *res);
/*
* MacIO interface
*/
static int hrowpic_macio_probe(device_t);
static int hrowpic_macio_attach(device_t);
static int hrowpic_probe(device_t);
static int hrowpic_attach(device_t);
/*
* Local routines
*/
static void hrowpic_intr(void);
static void hrowpic_ext_enable_irq(uintptr_t);
static void hrowpic_ext_disable_irq(uintptr_t);
static void hrowpic_toggle_irq(struct hrowpic_softc *sc, int, int);
static void hrowpic_dispatch(device_t, struct trapframe *);
static void hrowpic_enable(device_t, u_int, u_int);
static void hrowpic_eoi(device_t, u_int);
static void hrowpic_mask(device_t, u_int);
static void hrowpic_unmask(device_t, u_int);
/*
* Interrupt controller softc. There should only be one.
*/
static struct hrowpic_softc *hpicsoftc;
/*
* Driver methods.
*/
static device_method_t hrowpic_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, hrowpic_identify),
DEVMETHOD(device_probe, hrowpic_probe),
DEVMETHOD(device_attach, hrowpic_attach),
/* PIC interface */
DEVMETHOD(pic_allocate_intr, hrowpic_allocate_intr),
DEVMETHOD(pic_setup_intr, hrowpic_setup_intr),
DEVMETHOD(pic_teardown_intr, hrowpic_teardown_intr),
DEVMETHOD(pic_release_intr, hrowpic_release_intr),
DEVMETHOD(pic_dispatch, hrowpic_dispatch),
DEVMETHOD(pic_enable, hrowpic_enable),
DEVMETHOD(pic_eoi, hrowpic_eoi),
DEVMETHOD(pic_mask, hrowpic_mask),
DEVMETHOD(pic_unmask, hrowpic_unmask),
{ 0, 0 }
{ 0, 0 },
};
static driver_t hrowpic_driver = {
@ -131,181 +94,9 @@ static driver_t hrowpic_driver = {
static devclass_t hrowpic_devclass;
DRIVER_MODULE(hrowpic, nexus, hrowpic_driver, hrowpic_devclass, 0, 0);
DRIVER_MODULE(hrowpic, macio, hrowpic_driver, hrowpic_devclass, 0, 0);
static void
hrowpic_identify(driver_t *driver, device_t parent)
{
phandle_t chosen, pic;
char type[40];
chosen = OF_finddevice("/chosen");
if (chosen == -1)
return;
if (OF_getprop(chosen, "interrupt-controller", &pic, 4) != 4)
return;
OF_getprop(pic, "compatible", type, sizeof(type));
if (strcmp(type, "heathrow"))
return;
BUS_ADD_CHILD(parent, 0, "hrowpic", 0);
}
static int
hrowpic_probe(device_t dev)
{
char *name;
name = nexus_get_name(dev);
if (strcmp(name, "hrowpic"))
return (ENXIO);
device_set_desc(dev, "Heathrow interrupt controller");
return (0);
}
static int
hrowpic_attach(device_t dev)
{
struct hrowpic_softc *sc;
sc = device_get_softc(dev);
sc->sc_rman.rm_type = RMAN_ARRAY;
sc->sc_rman.rm_descr = device_get_nameunit(dev);
if (rman_init(&sc->sc_rman) != 0 ||
rman_manage_region(&sc->sc_rman, 0, HROWPIC_IRQMAX-1) != 0) {
device_printf(dev, "could not set up resource management");
return (ENXIO);
}
nexus_install_intcntlr(dev);
intr_init(hrowpic_intr, HROWPIC_IRQMAX, hrowpic_ext_enable_irq,
hrowpic_ext_disable_irq);
KASSERT(hpicsoftc == NULL, ("hrowpic: h/w already probed"));
hpicsoftc = sc;
return (0);
}
/*
* PIC interface
*/
static struct resource *
hrowpic_allocate_intr(device_t picdev, device_t child, int *rid, u_long intr,
u_int flags)
{
struct hrowpic_softc *sc;
struct resource *rv;
int needactivate;
sc = device_get_softc(picdev);
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
if (rv == NULL) {
device_printf(picdev, "interrupt reservation failed for %s\n",
device_get_nameunit(child));
return (NULL);
}
rman_set_rid(rv, *rid);
return (rv);
}
static int
hrowpic_setup_intr(device_t picdev, device_t child, struct resource *res,
int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
void **cookiep)
{
struct hrowpic_softc *sc;
u_long start;
int error;
sc = device_get_softc(picdev);
start = rman_get_start(res);
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
/*
* We depend here on rman_activate_resource() being idempotent.
*/
error = rman_activate_resource(res);
if (error)
return (error);
error = inthand_add(device_get_nameunit(child), start, filt, intr, arg,
flags, cookiep);
if (!error) {
/*
* Record irq request, and enable if h/w has been probed
*/
sc->sc_irq[start] = 1;
if (sc->sc_memr) {
hrowpic_toggle_irq(sc, start, 1);
}
}
return (error);
}
static int
hrowpic_teardown_intr(device_t picdev, device_t child, struct resource *res,
void *ih)
{
int error;
error = rman_deactivate_resource(res);
if (error)
return (error);
error = inthand_remove(rman_get_start(res), ih);
return (error);
}
static int
hrowpic_release_intr(device_t picdev, device_t child, int rid,
struct resource *res)
{
int error;
if (rman_get_flags(res) & RF_ACTIVE) {
error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
if (error)
return (error);
}
return (rman_release_resource(res));
}
/*
* Interrupt interface
*/
static void
hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank,
u_int32_t val)
{
if (bank == HPIC_PRIMARY)
reg += HPIC_1ST_OFFSET;
bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
/*
* XXX Issue a read to force the write to complete
*/
bus_space_read_4(sc->sc_bt, sc->sc_bh, reg);
}
static u_int32_t
static uint32_t
hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank)
{
if (bank == HPIC_PRIMARY)
@ -315,8 +106,59 @@ hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank)
}
static void
hrowpic_clear_all(struct hrowpic_softc *sc)
hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank,
uint32_t val)
{
if (bank == HPIC_PRIMARY)
reg += HPIC_1ST_OFFSET;
bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
/* XXX Issue a read to force the write to complete. */
bus_space_read_4(sc->sc_bt, sc->sc_bh, reg);
}
static int
hrowpic_probe(device_t dev)
{
const char *type = ofw_bus_get_type(dev);
/*
* OpenPIC cells have a type of "open-pic", so this
* is sufficient to identify a Heathrow cell
*/
if (strcmp(type, "interrupt-controller") != 0)
return (ENXIO);
/*
* The description was already printed out in the nexus
* probe, so don't do it again here
*/
device_set_desc(dev, "Heathrow MacIO interrupt controller");
return (0);
}
static int
hrowpic_attach(device_t dev)
{
struct hrowpic_softc *sc;
sc = device_get_softc(dev);
sc->sc_dev = dev;
sc->sc_rrid = 0;
sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
RF_ACTIVE);
if (sc->sc_rres == NULL) {
device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
}
sc->sc_bt = rman_get_bustag(sc->sc_rres);
sc->sc_bh = rman_get_bushandle(sc->sc_rres);
/*
* Disable all interrupt sources and clear outstanding interrupts
*/
@ -324,8 +166,15 @@ hrowpic_clear_all(struct hrowpic_softc *sc)
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY, 0xffffffff);
hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_SECONDARY, 0);
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY, 0xffffffff);
powerpc_register_pic(dev);
return (0);
}
/*
* Local routines
*/
static void
hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable)
{
@ -349,143 +198,74 @@ hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable)
hrowpic_write_reg(sc, HPIC_ENABLE, roffset, sc->sc_softreg[roffset]);
}
static void
hrowpic_intr(void)
{
int irq_lo, irq_hi;
int i;
struct hrowpic_softc *sc;
sc = hpicsoftc;
/*
* Loop through both interrupt sources until they are empty.
* XXX simplistic code, far from optimal.
*/
do {
irq_lo = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY);
if (irq_lo) {
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY,
irq_lo);
for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
if (irq_lo & (1 << i)) {
/*
* Disable IRQ and call handler
*/
hrowpic_toggle_irq(sc, i, 0);
intr_handle(i);
}
}
}
irq_hi = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY);
if (irq_hi) {
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY,
irq_hi);
for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
if (irq_hi & (1 << i)) {
/*
* Disable IRQ and call handler
*/
hrowpic_toggle_irq(sc,
i + HROWPIC_IRQ_REGNUM, 0);
intr_handle(i + HROWPIC_IRQ_REGNUM);
}
}
}
} while (irq_lo && irq_hi);
}
static void
hrowpic_ext_enable_irq(uintptr_t irq)
{
hrowpic_toggle_irq(hpicsoftc, irq, 1);
}
static void
hrowpic_ext_disable_irq(uintptr_t irq)
{
hrowpic_toggle_irq(hpicsoftc, irq, 0);
}
/*
* MacIO interface
* PIC I/F methods.
*/
static device_method_t hrowpic_macio_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, hrowpic_macio_probe),
DEVMETHOD(device_attach, hrowpic_macio_attach),
{ 0, 0 },
};
static driver_t hrowpic_macio_driver = {
"hrowpicmacio",
hrowpic_macio_methods,
0
};
static devclass_t hrowpic_macio_devclass;
DRIVER_MODULE(hrowpicmacio, macio, hrowpic_macio_driver,
hrowpic_macio_devclass, 0, 0);
static int
hrowpic_macio_probe(device_t dev)
static void
hrowpic_dispatch(device_t dev, struct trapframe *tf)
{
const char *type = ofw_bus_get_type(dev);
struct hrowpic_softc *sc;
uint64_t mask;
uint32_t reg;
u_int irq;
/*
* OpenPIC cells have a type of "open-pic", so this
* is sufficient to identify a Heathrow cell
*/
if (strcmp(type, "interrupt-controller") != 0)
return (ENXIO);
sc = device_get_softc(dev);
while (1) {
mask = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY);
reg = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY);
mask = (mask << 32) | reg;
if (mask == 0)
break;
/*
* The description was already printed out in the nexus
* probe, so don't do it again here
*/
device_set_desc(dev, "Heathrow MacIO interrupt cell");
device_quiet(dev);
return (0);
}
static int
hrowpic_macio_attach(device_t dev)
{
struct hrowpic_softc *sc = hpicsoftc;
int rid;
int i;
KASSERT(sc != NULL, ("pic not nexus-probed\n"));
sc->sc_maciodev = dev;
rid = 0;
sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->sc_memr == NULL) {
device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
}
sc->sc_bt = rman_get_bustag(sc->sc_memr);
sc->sc_bh = rman_get_bushandle(sc->sc_memr);
hrowpic_clear_all(sc);
/*
* Enable all IRQs that were requested before the h/w
* was probed
*/
for (i = 0; i < HROWPIC_IRQMAX; i++)
if (sc->sc_irq[i]) {
hrowpic_toggle_irq(sc, i, 1);
irq = 0;
while (irq < HROWPIC_IRQMAX) {
if (mask & 1)
powerpc_dispatch_intr(sc->sc_vector[irq], tf);
mask >>= 1;
irq++;
}
return (0);
}
}
static void
hrowpic_enable(device_t dev, u_int irq, u_int vector)
{
struct hrowpic_softc *sc;
sc = device_get_softc(dev);
sc->sc_vector[irq] = vector;
hrowpic_toggle_irq(sc, irq, 1);
}
static void
hrowpic_eoi(device_t dev __unused, u_int irq __unused)
{
struct hrowpic_softc *sc;
int bank;
sc = device_get_softc(dev);
bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ;
hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f));
}
static void
hrowpic_mask(device_t dev, u_int irq)
{
struct hrowpic_softc *sc;
int bank;
sc = device_get_softc(dev);
hrowpic_toggle_irq(sc, irq, 0);
bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ;
hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f));
}
static void
hrowpic_unmask(device_t dev, u_int irq)
{
struct hrowpic_softc *sc;
sc = device_get_softc(dev);
hrowpic_toggle_irq(sc, irq, 1);
}

View File

@ -62,16 +62,14 @@
#define HPIC_1ST_OFFSET 0x10 /* offset to primary reg bank */
struct hrowpic_softc {
struct rman sc_rman; /* resource mgr for IRQs */
u_int32_t sc_irq[HROWPIC_IRQMAX]; /* allocated IRQ flags */
u_int32_t sc_softreg[2]; /* ENABLE reg copy */
device_t sc_maciodev; /* macio device */
struct resource *sc_memr; /* macio bus resource */
device_t sc_dev; /* macio device */
struct resource *sc_rres; /* macio bus resource */
bus_space_tag_t sc_bt; /* macio bus tag/handle */
bus_space_handle_t sc_bh;
int sc_rrid;
uint32_t sc_softreg[2]; /* ENABLE reg copy */
u_int sc_vector[HROWPIC_IRQMAX];
};
#endif /* _POWERPC_POWERMAC_HROWPICVAR_H_ */

View File

@ -26,15 +26,6 @@
*
*/
/*
* The macio attachment for the OpenPIC interrupt controller.
* A nexus driver is defined so the number of interrupts can be
* determined early in the boot sequence before the hardware
* is accessed - the interrupt i/f is installed at this time,
* and when h/w is finally accessed, interrupt sources allocated
* prior to this are activated
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -65,123 +56,33 @@ __FBSDID("$FreeBSD$");
#include "pic_if.h"
struct openpic_ofw_softc {
struct openpic_softc osc;
struct resource *sc_memr; /* macio bus resource */
device_t sc_ndev; /* nexus device */
};
static struct openpic_ofw_softc *ofwpicsoftc;
/*
* MacIO interface
*/
static void openpic_ofw_identify(driver_t *, device_t);
static int openpic_ofw_probe(device_t);
static int openpic_ofw_attach(device_t);
static int openpic_macio_probe(device_t);
static int openpic_macio_attach(device_t);
/*
* Nexus attachment
*/
static device_method_t openpic_ofw_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, openpic_ofw_identify),
DEVMETHOD(device_probe, openpic_ofw_probe),
DEVMETHOD(device_attach, openpic_ofw_attach),
/* PIC interface */
DEVMETHOD(pic_allocate_intr, openpic_allocate_intr),
DEVMETHOD(pic_setup_intr, openpic_setup_intr),
DEVMETHOD(pic_teardown_intr, openpic_teardown_intr),
DEVMETHOD(pic_release_intr, openpic_release_intr),
{ 0, 0 }
};
static driver_t openpic_ofw_driver = {
"openpic",
openpic_ofw_methods,
sizeof(struct openpic_ofw_softc)
};
static devclass_t openpic_ofw_devclass;
DRIVER_MODULE(openpic_ofw, nexus, openpic_ofw_driver, openpic_ofw_devclass,
0, 0);
static void
openpic_ofw_identify(driver_t *driver, device_t parent)
{
device_t child;
phandle_t pic;
char type[40];
pic = OF_finddevice("mpic");
if (pic == -1)
return;
OF_getprop(pic, "device_type", type, sizeof(type));
if (strcmp(type, "open-pic") != 0)
return;
child = BUS_ADD_CHILD(parent, 0, "openpic", 0);
if (child != NULL)
nexus_set_device_type(child, "macio");
}
static int
openpic_ofw_probe(device_t dev)
{
char *name;
char *type;
name = nexus_get_name(dev);
type = nexus_get_device_type(dev);
if (strcmp(name, "openpic") != 0 ||
strcmp(type, "macio") != 0)
return (ENXIO);
device_set_desc(dev, OPENPIC_DEVSTR);
return (0);
}
static int
openpic_ofw_attach(device_t dev)
{
KASSERT(ofwpicsoftc == NULL, ("ofw openpic: already probed"));
ofwpicsoftc = device_get_softc(dev);
ofwpicsoftc->sc_ndev = dev;
nexus_install_intcntlr(dev);
openpic_early_attach(dev);
return (0);
}
/*
* MacIO attachment
*/
static device_method_t openpic_macio_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, openpic_macio_probe),
DEVMETHOD(device_attach, openpic_macio_attach),
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
DEVMETHOD(pic_eoi, openpic_eoi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
{ 0, 0 },
};
static driver_t openpic_macio_driver = {
"openpicmacio",
"openpic",
openpic_macio_methods,
0
sizeof(struct openpic_softc),
};
static devclass_t openpic_macio_devclass;
DRIVER_MODULE(openpicmacio, macio, openpic_macio_driver,
openpic_macio_devclass, 0, 0);
DRIVER_MODULE(openpic, macio, openpic_macio_driver, openpic_devclass, 0, 0);
static int
openpic_macio_probe(device_t dev)
@ -191,39 +92,6 @@ openpic_macio_probe(device_t dev)
if (strcmp(type, "open-pic") != 0)
return (ENXIO);
/*
* The description was already printed out in the nexus
* probe, so don't do it again here
*/
device_set_desc(dev, "OpenPIC MacIO interrupt cell");
if (!bootverbose)
device_quiet(dev);
device_set_desc(dev, OPENPIC_DEVSTR);
return (0);
}
static int
openpic_macio_attach(device_t dev)
{
struct openpic_ofw_softc *sc;
int rid;
sc = ofwpicsoftc;
KASSERT(sc != NULL, ("pic not nexus-probed\n"));
rid = 0;
sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->sc_memr == NULL) {
device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
}
sc->osc.sc_bt = rman_get_bustag(sc->sc_memr);
sc->osc.sc_bh = rman_get_bushandle(sc->sc_memr);
sc->osc.sc_altdev = dev;
return (openpic_attach(sc->sc_ndev));
}

View File

@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
#include <sys/cons.h>
#include <sys/kernel.h>
#include <machine/intr_machdep.h>
static device_t nexusdev;
static void configure_first(void *);
@ -65,9 +67,14 @@ configure(void *dummy)
static void
configure_final(void *dummy)
{
/*
* Enable device interrupts
* Now that we're guaranteed to have a PIC driver (or we'll never
* have one), program it with all the previously setup interrupts.
*/
powerpc_enable_intr();
/* Enable external interrupts. */
mtmsr(mfmsr() | PSL_EE | PSL_RI);
cninit_finish();

View File

@ -49,30 +49,19 @@
#include <sys/vmmeter.h>
#include <machine/cpu.h>
#include <machine/clock.h>
#include <machine/db_machdep.h>
#include <machine/fpu.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/spr.h>
#include <machine/sr.h>
void powerpc_interrupt(struct trapframe *);
/*
* External interrupt install routines
*/
static void (*powerpc_extintr_handler)(void);
void
ext_intr_install(void (*new_extint)(void))
{
powerpc_extintr_handler = new_extint;
}
extern void decr_intr(struct trapframe *);
#include "pic_if.h"
/*
* A very short dispatch, to try and maximise assembler code use
@ -90,7 +79,7 @@ powerpc_interrupt(struct trapframe *framep)
switch (framep->exc) {
case EXC_EXI:
atomic_add_int(&td->td_intr_nesting_level, 1);
(*powerpc_extintr_handler)();
PIC_DISPATCH(pic, framep);
atomic_subtract_int(&td->td_intr_nesting_level, 1);
break;

View File

@ -71,30 +71,32 @@
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/syslog.h>
#include <sys/vmmeter.h>
#include <sys/proc.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/trap.h>
#include "pic_if.h"
#define MAX_STRAY_LOG 5
MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
struct ppc_intr {
struct powerpc_intr {
struct intr_event *event;
long *cntp;
int cntidx;
u_int irq;
};
static struct mtx ppc_intrs_lock;
static struct ppc_intr **ppc_intrs;
static u_int ppc_nintrs;
static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
static u_int nvectors; /* Allocated vectors */
static u_int stray_count;
static int intrcnt_index;
static void (*irq_enable)(uintptr_t);
device_t pic;
static void
intrcnt_setname(const char *name, int index)
@ -103,111 +105,154 @@ intrcnt_setname(const char *name, int index)
MAXCOMLEN, name);
}
void
intr_init(void (*handler)(void), int nirq, void (*irq_e)(uintptr_t),
void (*irq_d)(uintptr_t))
#ifdef INTR_FILTER
static void
powerpc_intr_eoi(void *arg)
{
uint32_t msr;
u_int irq = (uintptr_t)arg;
if (ppc_intrs != NULL)
panic("intr_init: interrupts initialized twice\n");
PIC_EOI(pic, irq);
}
ppc_nintrs = nirq;
ppc_intrs = malloc(nirq * sizeof(struct ppc_intr *), M_INTR,
M_NOWAIT|M_ZERO);
if (ppc_intrs == NULL)
panic("intr_init: unable to allocate interrupt handler array");
static void
powerpc_intr_mask(void *arg)
{
u_int irq = (uintptr_t)arg;
mtx_init(&ppc_intrs_lock, "intr table", NULL, MTX_SPIN);
PIC_MASK(pic, irq);
}
#endif
irq_enable = irq_e;
static void
powerpc_intr_unmask(void *arg)
{
u_int irq = (uintptr_t)arg;
intrcnt_setname("???", 0);
intrcnt_index = 1;
PIC_UNMASK(pic, irq);
}
msr = mfmsr();
mtmsr(msr & ~PSL_EE);
ext_intr_install(handler);
mtmsr(msr);
void
powerpc_register_pic(device_t dev)
{
pic = dev;
}
int
inthand_add(const char *name, u_int irq, driver_filter_t *filter,
void (*handler)(void *), void *arg, int flags, void **cookiep)
powerpc_enable_intr(void)
{
struct ppc_intr *i, *orphan;
u_int idx;
struct powerpc_intr *i;
int vector;
for (vector = 0; vector < nvectors; vector++) {
i = powerpc_intrs[vector];
if (i == NULL)
continue;
PIC_ENABLE(pic, i->irq, vector);
}
return (0);
}
int
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;
u_int vector;
int error;
/*
* Work around a race where more than one CPU may be registering
* handlers on the same IRQ at the same time.
*/
mtx_lock_spin(&ppc_intrs_lock);
i = ppc_intrs[irq];
mtx_unlock_spin(&ppc_intrs_lock);
/* XXX lock */
i = NULL;
for (vector = 0; vector < nvectors; vector++) {
i = powerpc_intrs[vector];
if (i == NULL)
continue;
if (i->irq == irq)
break;
i = NULL;
}
if (i == NULL) {
if (nvectors >= INTR_VECTORS) {
/* XXX unlock */
return (ENOENT);
}
i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
if (i == NULL)
if (i == NULL) {
/* XXX unlock */
return (ENOMEM);
}
error = intr_event_create(&i->event, (void *)irq, 0,
(void (*)(void *))irq_enable, "irq%d:", irq);
powerpc_intr_unmask,
#ifdef INTR_FILTER
powerpc_intr_eoi, powerpc_intr_mask,
#endif
"irq%u:", irq);
if (error) {
/* XXX unlock */
free(i, M_INTR);
return (error);
}
mtx_lock_spin(&ppc_intrs_lock);
if (ppc_intrs[irq] != NULL) {
orphan = i;
i = ppc_intrs[irq];
mtx_unlock_spin(&ppc_intrs_lock);
vector = nvectors++;
powerpc_intrs[vector] = i;
intr_event_destroy(orphan->event);
free(orphan, M_INTR);
} else {
ppc_intrs[irq] = i;
idx = intrcnt_index++;
mtx_unlock_spin(&ppc_intrs_lock);
i->irq = irq;
i->cntidx = idx;
i->cntp = &intrcnt[idx];
intrcnt_setname(i->event->ie_fullname, idx);
}
/* XXX unlock */
i->cntp = &intrcnt[vector];
intrcnt_setname(i->event->ie_fullname, vector);
if (!cold)
PIC_ENABLE(pic, i->irq, vector);
} else {
/* XXX unlock */
}
error = intr_event_add_handler(i->event, name, filter, handler, arg,
intr_priority(flags), flags, cookiep);
if (!error)
intrcnt_setname(i->event->ie_fullname, i->cntidx);
intrcnt_setname(i->event->ie_fullname, vector);
return (error);
}
int
inthand_remove(u_int irq, void *cookie)
powerpc_teardown_intr(void *cookie)
{
return (intr_event_remove_handler(cookie));
}
void
intr_handle(u_int irq)
powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
{
struct ppc_intr *i;
struct powerpc_intr *i;
struct intr_event *ie;
#ifndef INTR_FILTER
struct intr_handler *ih;
int error, sched, ret;
#endif
i = ppc_intrs[irq];
i = powerpc_intrs[vector];
if (i == NULL)
goto stray;
atomic_add_long(i->cntp, 1);
(*i->cntp)++;
ie = i->event;
KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
#ifdef INTR_FILTER
if (intr_event_handle(ie, tf) != 0) {
PIC_MASK(pic, i->irq);
log(LOG_ERR, "stray irq%u\n", i->irq);
}
#else
if (TAILQ_EMPTY(&ie->ie_handlers))
goto stray;
@ -238,20 +283,24 @@ intr_handle(u_int irq)
critical_exit();
if (sched) {
PIC_MASK(pic, i->irq);
error = intr_event_schedule_thread(ie);
KASSERT(error == 0, ("%s: impossible stray interrupt",
__func__));
} else
irq_enable(irq);
PIC_EOI(pic, i->irq);
#endif
return;
stray:
atomic_add_long(&intrcnt[0], 1);
if (intrcnt[0] <= MAX_STRAY_LOG) {
printf("stray irq %d\n", irq);
if (intrcnt[0] >= MAX_STRAY_LOG) {
stray_count++;
if (stray_count <= MAX_STRAY_LOG) {
printf("stray irq %d\n", i->irq);
if (stray_count >= MAX_STRAY_LOG) {
printf("got %d stray interrupts, not logging anymore\n",
MAX_STRAY_LOG);
MAX_STRAY_LOG);
}
}
if (i != NULL)
PIC_MASK(pic, i->irq);
}

View File

@ -97,7 +97,7 @@ struct nexus_devinfo {
};
struct nexus_softc {
device_t sc_pic;
struct rman sc_rman;
};
/*
@ -182,12 +182,24 @@ nexus_probe(device_t dev)
phandle_t root;
phandle_t child;
struct nexus_softc *sc;
u_long start, end;
if ((root = OF_peer(0)) == -1)
panic("nexus_probe: OF_peer failed.");
sc = device_get_softc(dev);
start = 0;
end = INTR_VECTORS - 1;
sc->sc_rman.rm_start = start;
sc->sc_rman.rm_end = end;
sc->sc_rman.rm_type = RMAN_ARRAY;
sc->sc_rman.rm_descr = "Interrupt request lines";
if (rman_init(&sc->sc_rman) ||
rman_manage_region(&sc->sc_rman, start, end))
panic("nexus_probe IRQ rman");
/*
* Allow devices to identify
*/
@ -302,31 +314,40 @@ nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep)
driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
{
struct nexus_softc *sc;
driver_t *driver;
int error;
sc = device_get_softc(dev);
/* somebody tried to setup an irq that failed to allocate! */
if (res == NULL)
panic("nexus_setup_intr: NULL irq resource!");
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_setup_intr: no pic attached\n");
*cookiep = 0;
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
return (PIC_SETUP_INTR(sc->sc_pic, child, res, flags, filter, intr,
arg, cookiep));
driver = device_get_driver(child);
/*
* We depend here on rman_activate_resource() being idempotent.
*/
error = rman_activate_resource(res);
if (error)
return (error);
error = powerpc_setup_intr(device_get_nameunit(child),
rman_get_start(res), filter, ihand, arg, flags, cookiep);
return (error);
}
static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
void *ih)
void *cookie)
{
struct nexus_softc *sc;
sc = device_get_softc(dev);
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_teardown_intr: no pic attached\n");
return (PIC_TEARDOWN_INTR(sc->sc_pic, child, res, ih));
return (powerpc_teardown_intr(cookie));
}
/*
@ -337,10 +358,8 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
struct nexus_softc *sc;
struct resource *rv;
sc = device_get_softc(bus);
struct nexus_softc *sc;
struct resource *rv;
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@ -348,10 +367,21 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_alloc_resource: no pic attached\n");
if (count == 0 || start + count - 1 != end) {
device_printf(bus, "invalid IRQ allocation from %s\n",
device_get_nameunit(child));
return (NULL);
}
rv = PIC_ALLOCATE_INTR(sc->sc_pic, child, rid, start, flags);
sc = device_get_softc(bus);
rv = rman_reserve_resource(&sc->sc_rman, start, end, count,
flags, child);
if (rv == NULL) {
device_printf(bus, "IRQ allocation failed for %s\n",
device_get_nameunit(child));
} else
rman_set_rid(rv, *rid);
return (rv);
}
@ -378,9 +408,6 @@ static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
struct nexus_softc *sc;
sc = device_get_softc(bus);
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@ -388,10 +415,7 @@ nexus_release_resource(device_t bus, device_t child, int type, int rid,
return (EINVAL);
}
if (device_get_state(sc->sc_pic) != DS_ATTACHED)
panic("nexus_release_resource: no pic attached\n");
return (PIC_RELEASE_INTR(sc->sc_pic, child, rid, res));
return (rman_release_resource(res));
}
static device_t
@ -418,17 +442,6 @@ nexus_device_from_node(device_t parent, phandle_t node)
return (cdev);
}
int
nexus_install_intcntlr(device_t dev)
{
struct nexus_softc *sc;
sc = device_get_softc(device_get_parent(dev));
sc->sc_pic = dev;
return (0);
}
static const char *
nexus_ofw_get_name(device_t bus, device_t dev)
{

View File

@ -30,6 +30,7 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
@ -41,57 +42,38 @@
#include <vm/vm.h>
#include <vm/pmap.h>
#include <sys/rman.h>
#include <machine/openpicreg.h>
#include <machine/openpicvar.h>
#include "pic_if.h"
devclass_t openpic_devclass;
/*
* Local routines
*/
static u_int openpic_read(struct openpic_softc *, int);
static void openpic_write(struct openpic_softc *, int, u_int);
static int openpic_read_irq(struct openpic_softc *, int);
static void openpic_eoi(struct openpic_softc *, int);
static void openpic_enable_irq(struct openpic_softc *, int, int);
static void openpic_disable_irq(struct openpic_softc *, int);
static void openpic_set_priority(struct openpic_softc *, int, int);
static void openpic_intr(void);
static void openpic_ext_enable_irq(uintptr_t);
static void openpic_ext_disable_irq(uintptr_t);
/* XXX This limits us to one openpic */
static struct openpic_softc *openpic_softc;
/*
* Called at nexus-probe time to allow interrupts to be enabled by
* devices that are probed before the OpenPIC h/w is probed.
*/
int
openpic_early_attach(device_t dev)
static __inline uint32_t
openpic_read(struct openpic_softc *sc, u_int reg)
{
struct openpic_softc *sc;
return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
}
sc = device_get_softc(dev);
openpic_softc = sc;
static __inline void
openpic_write(struct openpic_softc *sc, u_int reg, uint32_t val)
{
bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
}
sc->sc_rman.rm_type = RMAN_ARRAY;
sc->sc_rman.rm_descr = device_get_nameunit(dev);
static __inline void
openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
{
uint32_t x;
if (rman_init(&sc->sc_rman) != 0 ||
rman_manage_region(&sc->sc_rman, 0, OPENPIC_IRQMAX-1) != 0) {
device_printf(dev, "could not set up resource management");
return (ENXIO);
}
intr_init(openpic_intr, OPENPIC_IRQMAX, openpic_ext_enable_irq,
openpic_ext_disable_irq);
sc->sc_early_done = 1;
return (0);
x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
x &= ~OPENPIC_CPU_PRIORITY_MASK;
x |= pri;
openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
}
int
@ -102,10 +84,19 @@ openpic_attach(device_t dev)
u_int32_t x;
sc = device_get_softc(dev);
sc->sc_hwprobed = 1;
sc->sc_dev = dev;
if (!sc->sc_early_done)
openpic_early_attach(dev);
sc->sc_rid = 0;
sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
RF_ACTIVE);
if (sc->sc_memr == NULL) {
device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
}
sc->sc_bt = rman_get_bustag(sc->sc_memr);
sc->sc_bh = rman_get_bushandle(sc->sc_memr);
x = openpic_read(sc, OPENPIC_FEATURE);
switch (x & OPENPIC_FEATURE_VERSION_MASK) {
@ -155,7 +146,7 @@ openpic_attach(device_t dev)
openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
for (irq = 0; irq < sc->sc_nirq; irq++) {
x = irq;
x = irq; /* irq == vector. */
x |= OPENPIC_IMASK;
x |= OPENPIC_POLARITY_POSITIVE;
x |= OPENPIC_SENSE_LEVEL;
@ -170,239 +161,78 @@ openpic_attach(device_t dev)
/* clear all pending interrupts */
for (irq = 0; irq < sc->sc_nirq; irq++) {
openpic_read_irq(sc, 0);
openpic_eoi(sc, 0);
(void)openpic_read(sc, OPENPIC_IACK(0));
openpic_write(sc, OPENPIC_EOI(0), 0);
}
/* enable pre-h/w reserved irqs, disable all others */
for (irq = 0; irq < sc->sc_nirq; irq++)
if (sc->sc_irqrsv[irq])
openpic_enable_irq(sc, irq, IST_LEVEL);
else
openpic_disable_irq(sc, irq);
powerpc_register_pic(dev);
return (0);
}
/*
* PIC interface
* PIC I/F methods
*/
struct resource *
openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
u_int flags)
void
openpic_dispatch(device_t dev, struct trapframe *tf)
{
struct openpic_softc *sc;
struct resource *rv;
int needactivate;
struct openpic_softc *sc;
u_int vector;
sc = device_get_softc(dev);
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
if (sc->sc_hwprobed && (intr > sc->sc_nirq)) {
device_printf(dev, "interrupt reservation %ld out of range\n",
intr);
return (NULL);
while (1) {
vector = openpic_read(sc, OPENPIC_IACK(0));
vector &= OPENPIC_VECTOR_MASK;
if (vector == 255)
break;
powerpc_dispatch_intr(vector, tf);
}
rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
if (rv == NULL) {
device_printf(dev, "interrupt reservation failed for %s\n",
device_get_nameunit(child));
return (NULL);
}
rman_set_rid(rv, *rid);
if (needactivate) {
if (bus_activate_resource(child, SYS_RES_IRQ, *rid, rv) != 0) {
device_printf(dev,
"resource activation failed for %s\n",
device_get_nameunit(child));
rman_release_resource(rv);
return (NULL);
}
}
return (rv);
}
int
openpic_setup_intr(device_t dev, device_t child, struct resource *res,
int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
void **cookiep)
void
openpic_enable(device_t dev, u_int irq, u_int vector)
{
struct openpic_softc *sc;
u_long start;
int error;
struct openpic_softc *sc;
uint32_t x;
sc = device_get_softc(dev);
start = rman_get_start(res);
if (res == NULL) {
device_printf(dev, "null interrupt resource from %s\n",
device_get_nameunit(child));
return (EINVAL);
}
if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
/*
* We depend here on rman_activate_resource() being idempotent.
*/
error = rman_activate_resource(res);
if (error)
return (error);
error = inthand_add(device_get_nameunit(child), start, filt, intr, arg,
flags, cookiep);
if (sc->sc_hwprobed)
openpic_enable_irq(sc, start, IST_LEVEL);
else
sc->sc_irqrsv[start] = 1;
return (error);
}
int
openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
void *ih)
{
int error;
error = rman_deactivate_resource(res);
if (error)
return (error);
error = inthand_remove(rman_get_start(res), ih);
return (error);
}
int
openpic_release_intr(device_t dev, device_t child, int rid,
struct resource *res)
{
int error;
if (rman_get_flags(res) & RF_ACTIVE) {
error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
if (error)
return (error);
}
return (rman_release_resource(res));
}
/*
* Local routines
*/
static u_int
openpic_read(struct openpic_softc *sc, int reg)
{
return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
}
static void
openpic_write(struct openpic_softc *sc, int reg, u_int val)
{
bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
}
static int
openpic_read_irq(struct openpic_softc *sc, int cpu)
{
return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
}
static void
openpic_eoi(struct openpic_softc *sc, int cpu)
{
openpic_write(sc, OPENPIC_EOI(cpu), 0);
}
static void
openpic_enable_irq(struct openpic_softc *sc, int irq, int type)
{
u_int x;
x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE);
if (type == IST_LEVEL)
x |= OPENPIC_SENSE_LEVEL;
else
x |= OPENPIC_SENSE_EDGE;
x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
x |= vector;
openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
}
static void
openpic_disable_irq(struct openpic_softc *sc, int irq)
void
openpic_eoi(device_t dev, u_int irq __unused)
{
u_int x;
struct openpic_softc *sc;
sc = device_get_softc(dev);
openpic_write(sc, OPENPIC_EOI(0), 0);
}
void
openpic_mask(device_t dev, u_int irq)
{
struct openpic_softc *sc;
uint32_t x;
sc = device_get_softc(dev);
x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
x |= OPENPIC_IMASK;
openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
openpic_write(sc, OPENPIC_EOI(0), 0);
}
static void
openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
{
u_int x;
x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
x &= ~OPENPIC_CPU_PRIORITY_MASK;
x |= pri;
openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
}
static void
openpic_intr(void)
void
openpic_unmask(device_t dev, u_int irq)
{
struct openpic_softc *sc;
int irq;
u_int32_t msr;
uint32_t x;
sc = openpic_softc;
msr = mfmsr();
irq = openpic_read_irq(sc, 0);
if (irq == 255) {
return;
}
start:
openpic_disable_irq(sc, irq);
/*mtmsr(msr | PSL_EE);*/
/* do the interrupt thang */
intr_handle(irq);
mtmsr(msr);
openpic_eoi(sc, 0);
irq = openpic_read_irq(sc, 0);
if (irq != 255)
goto start;
}
static void
openpic_ext_enable_irq(uintptr_t irq)
{
if (!openpic_softc->sc_hwprobed)
return;
openpic_enable_irq(openpic_softc, irq, IST_LEVEL);
}
static void
openpic_ext_disable_irq(uintptr_t irq)
{
if (!openpic_softc->sc_hwprobed)
return;
openpic_disable_irq(openpic_softc, irq);
sc = device_get_softc(dev);
x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
x &= ~OPENPIC_IMASK;
openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
}

View File

@ -28,38 +28,32 @@
#
#include <sys/bus.h>
#include <machine/frame.h>
INTERFACE pic;
METHOD struct resource * allocate_intr {
METHOD void dispatch {
device_t dev;
device_t child;
int *rid;
u_long intr;
u_int flags;
struct trapframe *tf;
};
METHOD int setup_intr {
METHOD void enable {
device_t dev;
device_t child;
struct resource *res;
int flags;
driver_filter_t *filter;
driver_intr_t *intr;
void *arg;
void **cookiep;
u_int irq;
u_int vector;
};
METHOD int teardown_intr {
METHOD void eoi {
device_t dev;
device_t child;
struct resource *res;
void *ih;
u_int irq;
};
METHOD int release_intr {
METHOD void mask {
device_t dev;
device_t child;
int rid;
struct resource *res;
u_int irq;
};
METHOD void unmask {
device_t dev;
u_int irq;
};

View File

@ -60,117 +60,33 @@ __FBSDID("$FreeBSD$");
#include "pic_if.h"
struct openpic_iobus_softc {
struct openpic_softc osc;
struct resource *sc_memr; /* iobus mem resource */
device_t sc_ndev; /* nexus device */
};
static struct openpic_iobus_softc *ppicsoftc;
/*
* MacIO interface
* PSIM IOBus interface
*/
static void openpic_psim_identify(driver_t *, device_t);
static int openpic_psim_probe(device_t);
static int openpic_psim_attach(device_t);
static int openpic_iobus_probe(device_t);
static int openpic_iobus_attach(device_t);
/*
* Nexus attachment
*/
static device_method_t openpic_psim_methods[] = {
static device_method_t openpic_iobus_methods[] = {
/* Device interface */
DEVMETHOD(device_identify, openpic_psim_identify),
DEVMETHOD(device_probe, openpic_psim_probe),
DEVMETHOD(device_attach, openpic_psim_attach),
DEVMETHOD(device_probe, openpic_iobus_probe),
DEVMETHOD(device_attach, openpic_attach),
/* PIC interface */
DEVMETHOD(pic_allocate_intr, openpic_allocate_intr),
DEVMETHOD(pic_setup_intr, openpic_setup_intr),
DEVMETHOD(pic_teardown_intr, openpic_teardown_intr),
DEVMETHOD(pic_release_intr, openpic_release_intr),
DEVMETHOD(pic_dispatch, openpic_dispatch),
DEVMETHOD(pic_enable, openpic_enable),
DEVMETHOD(pic_eoi, openpic_eoi),
DEVMETHOD(pic_mask, openpic_mask),
DEVMETHOD(pic_unmask, openpic_unmask),
{ 0, 0 }
};
static driver_t openpic_psim_driver = {
"openpic",
openpic_psim_methods,
sizeof(struct openpic_iobus_softc)
};
static devclass_t openpic_psim_devclass;
DRIVER_MODULE(openpic_psim, nexus, openpic_psim_driver, openpic_psim_devclass,
0, 0);
static void
openpic_psim_identify(driver_t *driver, device_t parent)
{
device_t child;
phandle_t pic;
pic = OF_finddevice("/iobus/opic");
if (pic == -1)
return;
child = BUS_ADD_CHILD(parent, 0, "openpic", 0);
if (child != NULL)
nexus_set_device_type(child, "psim");
}
static int
openpic_psim_probe(device_t dev)
{
char *name;
char *type;
name = nexus_get_name(dev);
type = nexus_get_device_type(dev);
if (strcmp(name, "openpic") != 0 ||
strcmp(type, "psim") != 0)
return (ENXIO);
device_set_desc(dev, OPENPIC_DEVSTR);
return (0);
}
static int
openpic_psim_attach(device_t dev)
{
KASSERT(ppicsoftc == NULL, ("iobus openpic: already probed"));
ppicsoftc = device_get_softc(dev);
ppicsoftc->sc_ndev = dev;
nexus_install_intcntlr(dev);
openpic_early_attach(dev);
return (0);
}
/*
* PSIM IOBus attachment
*/
static device_method_t openpic_iobus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, openpic_iobus_probe),
DEVMETHOD(device_attach, openpic_iobus_attach),
{ 0, 0 },
};
static driver_t openpic_iobus_driver = {
"openpiciobus",
"openpic",
openpic_iobus_methods,
0
sizeof(struct openpic_softc)
};
static devclass_t openpic_iobus_devclass;
DRIVER_MODULE(openpiciobus, iobus, openpic_iobus_driver,
openpic_iobus_devclass, 0, 0);
DRIVER_MODULE(openpic, iobus, openpic_iobus_driver, openpic_devclass, 0, 0);
static int
openpic_iobus_probe(device_t dev)
@ -179,42 +95,12 @@ openpic_iobus_probe(device_t dev)
name = iobus_get_name(dev);
if (strcmp(name, "interrupt-controller") != 0)
return (ENXIO);
return (ENXIO);
/*
* The description was already printed out in the nexus
* probe, so don't do it again here
*/
device_set_desc(dev, "OpenPIC IOBus interrupt cell");
if (!bootverbose)
device_quiet(dev);
device_set_desc(dev, OPENPIC_DEVSTR);
return (0);
}
static int
openpic_iobus_attach(device_t dev)
{
struct openpic_iobus_softc *sc;
int rid;
sc = ppicsoftc;
KASSERT(sc != NULL, ("pic not nexus-probed\n"));
rid = 0;
sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->sc_memr == NULL) {
device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
}
sc->osc.sc_psim = 1;
sc->osc.sc_bt = rman_get_bustag(sc->sc_memr);
sc->osc.sc_bh = rman_get_bushandle(sc->sc_memr);
sc->osc.sc_altdev = dev;
return (openpic_attach(sc->sc_ndev));
}