aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ppc
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2008-09-15 22:26:32 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2008-09-15 22:26:32 +0000
commitca3d37955c7c41e64a80c97b3f1c1fa4e9ff4897 (patch)
treec5d594dd29d8cb1dbd07768c75b6649ad621cee2 /sys/dev/ppc
parent37e9511fcba3749b6c8d6cc176251210b27be78e (diff)
Notes
Diffstat (limited to 'sys/dev/ppc')
-rw-r--r--sys/dev/ppc/ppc.c158
-rw-r--r--sys/dev/ppc/ppc_acpi.c3
-rw-r--r--sys/dev/ppc/ppc_isa.c5
-rw-r--r--sys/dev/ppc/ppc_pci.c3
-rw-r--r--sys/dev/ppc/ppc_puc.c3
-rw-r--r--sys/dev/ppc/ppcreg.h3
-rw-r--r--sys/dev/ppc/ppcvar.h4
7 files changed, 116 insertions, 63 deletions
diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c
index 9a3f5e958159..a3724037da6f 100644
--- a/sys/dev/ppc/ppc.c
+++ b/sys/dev/ppc/ppc.c
@@ -32,10 +32,12 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/interrupt.h>
#include <sys/module.h>
-#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -1515,10 +1517,21 @@ ppc_exec_microseq(device_t dev, struct ppb_microseq **p_msq)
static void
ppcintr(void *arg)
{
- device_t dev = (device_t)arg;
- struct ppc_data *ppc = (struct ppc_data *)device_get_softc(dev);
+ struct ppc_data *ppc = arg;
u_char ctr, ecr, str;
+ /*
+ * If we have any child interrupt handlers registered, let
+ * them handle this interrupt.
+ *
+ * XXX: If DMA is in progress should we just complete that w/o
+ * doing this?
+ */
+ if (ppc->ppc_child_handlers > 0) {
+ intr_event_execute_handlers(curproc, ppc->ppc_intr_event);
+ return;
+ }
+
str = r_str(ppc);
ctr = r_ctr(ppc);
ecr = r_ecr(ppc);
@@ -1790,8 +1803,8 @@ int
ppc_attach(device_t dev)
{
struct ppc_data *ppc = DEVTOSOFTC(dev);
-
device_t ppbus;
+ int error;
device_printf(dev, "%s chipset (%s) in %s mode%s\n",
ppc_models[ppc->ppc_model], ppc_avms[ppc->ppc_avm],
@@ -1802,6 +1815,30 @@ ppc_attach(device_t dev)
device_printf(dev, "FIFO with %d/%d/%d bytes threshold\n",
ppc->ppc_fifo, ppc->ppc_wthr, ppc->ppc_rthr);
+ if (ppc->res_irq) {
+ /*
+ * Create an interrupt event to manage the handlers of
+ * child devices.
+ */
+ error = intr_event_create(&ppc->ppc_intr_event, ppc, 0, -1,
+ NULL, NULL, NULL, NULL, "%s:", device_get_nameunit(dev));
+ if (error) {
+ device_printf(dev,
+ "failed to create interrupt event: %d\n", error);
+ return (error);
+ }
+
+ /* default to the tty mask for registration */ /* XXX */
+ error = bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY,
+ NULL, ppcintr, ppc, &ppc->intr_cookie);
+ if (error) {
+ device_printf(dev,
+ "failed to register interrupt handler: %d\n",
+ error);
+ return (error);
+ }
+ }
+
/* add ppbus as a child of this isa to parallel bridge */
ppbus = device_add_child(dev, "ppbus", -1);
@@ -1810,17 +1847,6 @@ ppc_attach(device_t dev)
*/
device_probe_and_attach(ppbus);
- /* register the ppc interrupt handler as default */
- if (ppc->res_irq) {
- /* default to the tty mask for registration */ /* XXX */
- if (bus_setup_intr(dev, ppc->res_irq, INTR_TYPE_TTY,
- NULL, ppcintr, dev, &ppc->intr_cookie) == 0) {
-
- /* remember the ppcintr is registered */
- ppc->ppc_registered = 1;
- }
- }
-
return (0);
}
@@ -1935,9 +1961,6 @@ ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val)
case PPC_IVAR_EPP_PROTO:
*val = (u_long)ppc->ppc_epp;
break;
- case PPC_IVAR_IRQ:
- *val = (u_long)ppc->ppc_irq;
- break;
default:
return (ENOENT);
}
@@ -1946,63 +1969,84 @@ ppc_read_ivar(device_t bus, device_t dev, int index, uintptr_t *val)
}
/*
- * Resource is useless here since ppbus devices' interrupt handlers are
- * multiplexed to the same resource initially allocated by ppc
+ * We allow child devices to allocate an IRQ resource at rid 0 for their
+ * interrupt handlers.
*/
-int
-ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
- driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
+struct resource *
+ppc_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
{
- int error;
struct ppc_data *ppc = DEVTOSOFTC(bus);
- if (ppc->ppc_registered) {
- /* XXX refuse registration if DMA is in progress */
-
- /* first, unregister the default interrupt handler */
- if ((error = BUS_TEARDOWN_INTR(device_get_parent(bus),
- bus, ppc->res_irq, ppc->intr_cookie)))
- return (error);
+ switch (type) {
+ case SYS_RES_IRQ:
+ if (*rid == 0)
+ return (ppc->res_irq);
+ break;
+ }
+ return (NULL);
+}
-/* bus_deactivate_resource(bus, SYS_RES_IRQ, ppc->rid_irq, */
-/* ppc->res_irq); */
+int
+ppc_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+#ifdef INVARIANTS
+ struct ppc_data *ppc = DEVTOSOFTC(bus);
+#endif
- /* DMA/FIFO operation won't be possible anymore */
- ppc->ppc_registered = 0;
+ switch (type) {
+ case SYS_RES_IRQ:
+ if (rid == 0) {
+ KASSERT(r == ppc->res_irq,
+ ("ppc child IRQ resource mismatch"));
+ return (0);
+ }
+ break;
}
-
- /*
- * pass registration to the upper layer, ignore the incoming
- * resource
- */
- return (BUS_SETUP_INTR(device_get_parent(bus), child,
- r, flags, filt, ihand, arg, cookiep));
+ return (EINVAL);
}
/*
- * When no underlying device has a registered interrupt, register the ppc
- * layer one
+ * If a child wants to add a handler for our IRQ, add it to our interrupt
+ * event. Otherwise, fail the request.
*/
int
-ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
+ppc_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
+ driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
{
- int error;
struct ppc_data *ppc = DEVTOSOFTC(bus);
- device_t parent = device_get_parent(bus);
+ int error;
- /* pass unregistration to the upper layer */
- if ((error = BUS_TEARDOWN_INTR(parent, child, r, ih)))
- return (error);
+ if (r != ppc->res_irq)
+ return (EINVAL);
- /* default to the tty mask for registration */ /* XXX */
- if (ppc->ppc_irq &&
- !(error = BUS_SETUP_INTR(parent, bus, ppc->res_irq,
- INTR_TYPE_TTY, NULL, ppcintr, bus, &ppc->intr_cookie))) {
+ /* We don't allow filters. */
+ if (filt != NULL)
+ return (EINVAL);
- /* remember the ppcintr is registered */
- ppc->ppc_registered = 1;
- }
+ error = intr_event_add_handler(ppc->ppc_intr_event,
+ device_get_nameunit(child), NULL, ihand, arg, intr_priority(flags),
+ flags, cookiep);
+ if (error == 0)
+ ppc->ppc_child_handlers++;
+ return (error);
+}
+
+int
+ppc_teardown_intr(device_t bus, device_t child, struct resource *r, void *cookie)
+{
+ struct ppc_data *ppc = DEVTOSOFTC(bus);
+ int error;
+
+ if (r != ppc->res_irq)
+ return (EINVAL);
+ KASSERT(intr_handler_source(cookie) == ppc,
+ ("ppc_teardown_intr: source mismatch"));
+ error = intr_event_remove_handler(cookie);
+ if (error == 0)
+ ppc->ppc_child_handlers--;
return (error);
}
diff --git a/sys/dev/ppc/ppc_acpi.c b/sys/dev/ppc/ppc_acpi.c
index 1f85c729a698..04cee681a921 100644
--- a/sys/dev/ppc/ppc_acpi.c
+++ b/sys/dev/ppc/ppc_acpi.c
@@ -65,7 +65,8 @@ static device_method_t ppc_acpi_methods[] = {
DEVMETHOD(bus_read_ivar, ppc_read_ivar),
DEVMETHOD(bus_setup_intr, ppc_setup_intr),
DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
- DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_alloc_resource, ppc_alloc_resource),
+ DEVMETHOD(bus_release_resource, ppc_release_resource),
/* ppbus interface */
DEVMETHOD(ppbus_io, ppc_io),
diff --git a/sys/dev/ppc/ppc_isa.c b/sys/dev/ppc/ppc_isa.c
index b23ce823e153..5ac6990c7406 100644
--- a/sys/dev/ppc/ppc_isa.c
+++ b/sys/dev/ppc/ppc_isa.c
@@ -62,7 +62,8 @@ static device_method_t ppc_isa_methods[] = {
DEVMETHOD(bus_read_ivar, ppc_read_ivar),
DEVMETHOD(bus_setup_intr, ppc_setup_intr),
DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
- DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_alloc_resource, ppc_alloc_resource),
+ DEVMETHOD(bus_release_resource, ppc_release_resource),
/* ppbus interface */
DEVMETHOD(ppbus_io, ppc_io),
@@ -142,7 +143,7 @@ ppc_isa_write(device_t dev, char *buf, int len, int how)
int s, error = 0;
int spin;
- if (!(ppc->ppc_avm & PPB_ECP) || !ppc->ppc_registered)
+ if (!(ppc->ppc_avm & PPB_ECP))
return (EINVAL);
if (ppc->ppc_dmachan == 0)
return (EINVAL);
diff --git a/sys/dev/ppc/ppc_pci.c b/sys/dev/ppc/ppc_pci.c
index 77331e2524e2..a64a3fdf634b 100644
--- a/sys/dev/ppc/ppc_pci.c
+++ b/sys/dev/ppc/ppc_pci.c
@@ -55,7 +55,8 @@ static device_method_t ppc_pci_methods[] = {
DEVMETHOD(bus_read_ivar, ppc_read_ivar),
DEVMETHOD(bus_setup_intr, ppc_setup_intr),
DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
- DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_alloc_resource, ppc_alloc_resource),
+ DEVMETHOD(bus_release_resource, ppc_release_resource),
/* ppbus interface */
DEVMETHOD(ppbus_io, ppc_io),
diff --git a/sys/dev/ppc/ppc_puc.c b/sys/dev/ppc/ppc_puc.c
index adcc0580bed8..0aec89cc4bc4 100644
--- a/sys/dev/ppc/ppc_puc.c
+++ b/sys/dev/ppc/ppc_puc.c
@@ -57,7 +57,8 @@ static device_method_t ppc_puc_methods[] = {
DEVMETHOD(bus_read_ivar, ppc_read_ivar),
DEVMETHOD(bus_setup_intr, ppc_setup_intr),
DEVMETHOD(bus_teardown_intr, ppc_teardown_intr),
- DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
+ DEVMETHOD(bus_alloc_resource, ppc_alloc_resource),
+ DEVMETHOD(bus_release_resource, ppc_release_resource),
/* ppbus interface */
DEVMETHOD(ppbus_io, ppc_io),
diff --git a/sys/dev/ppc/ppcreg.h b/sys/dev/ppc/ppcreg.h
index 25f3fc2db852..8464f9c0a3df 100644
--- a/sys/dev/ppc/ppcreg.h
+++ b/sys/dev/ppc/ppcreg.h
@@ -109,7 +109,8 @@ struct ppc_data {
void *intr_cookie;
- int ppc_registered; /* 1 if ppcintr() is the registered interrupt */
+ struct intr_event *ppc_intr_event;
+ int ppc_child_handlers;
};
/*
diff --git a/sys/dev/ppc/ppcvar.h b/sys/dev/ppc/ppcvar.h
index b8723bc23518..18c159fc4171 100644
--- a/sys/dev/ppc/ppcvar.h
+++ b/sys/dev/ppc/ppcvar.h
@@ -42,6 +42,10 @@ int ppc_exec_microseq(device_t, struct ppb_microseq **);
int ppc_setup_intr(device_t, device_t, struct resource *, int,
driver_filter_t *filt, void (*)(void *), void *, void **);
int ppc_teardown_intr(device_t, device_t, struct resource *, void *);
+struct resource *ppc_alloc_resource(device_t bus, device_t child, int type,
+ int *rid, u_long start, u_long end, u_long count, u_int flags);
+int ppc_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r);
void ppc_reset_epp(device_t);
void ppc_ecp_sync(device_t);
int ppc_setmode(device_t, int);