summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2012-03-12 01:23:09 +0000
committergonzo <gonzo@FreeBSD.org>2012-03-12 01:23:09 +0000
commit2bb441e96ed88fc503ae6e6581f99bd02249caa3 (patch)
treead8608cb1bf48af614ba3e63c83de033ed8d9dfd /sys/mips
parenta3042173e165bcb540868354a4e857cae1f48f50 (diff)
downloadFreeBSD-src-2bb441e96ed88fc503ae6e6581f99bd02249caa3.zip
FreeBSD-src-2bb441e96ed88fc503ae6e6581f99bd02249caa3.tar.gz
- Rename apb_intr to apb_filter since it's a filter handler
- Pass interrupt trapframe for handlers dow the chain - Add PMC interrupt handler PMC interrupt is a special case, so we want handle it as soon as possible with minimum overhead. So we handle it apb filter routine.
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/atheros/apb.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/sys/mips/atheros/apb.c b/sys/mips/atheros/apb.c
index a2f6163..b0e5524 100644
--- a/sys/mips/atheros/apb.c
+++ b/sys/mips/atheros/apb.c
@@ -36,6 +36,10 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/pmc.h>
+#include <sys/pmckern.h>
#include <machine/bus.h>
#include <machine/intr_machdep.h>
@@ -44,6 +48,8 @@ __FBSDID("$FreeBSD$");
#include <mips/atheros/ar71xxreg.h>
#include <mips/atheros/ar71xx_setup.h>
+#define APB_INTR_PMC 5
+
#undef APB_DEBUG
#ifdef APB_DEBUG
#define dprintf printf
@@ -63,7 +69,7 @@ static int apb_deactivate_resource(device_t, device_t, int, int,
static struct resource_list *
apb_get_resource_list(device_t, device_t);
static void apb_hinted_child(device_t, const char *, int);
-static int apb_intr(void *);
+static int apb_filter(void *);
static int apb_probe(device_t);
static int apb_release_resource(device_t, device_t, int, int,
struct resource *);
@@ -132,7 +138,7 @@ apb_attach(device_t dev)
}
if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC,
- apb_intr, NULL, sc, &sc->sc_misc_ih))) {
+ apb_filter, NULL, sc, &sc->sc_misc_ih))) {
device_printf(dev,
"WARNING: unable to register interrupt handler\n");
return (ENXIO);
@@ -142,6 +148,12 @@ apb_attach(device_t dev)
bus_enumerate_hinted_children(dev);
bus_generic_attach(dev);
+ /*
+ * Unmask performance counter IRQ
+ */
+ apb_unmask_irq((void*)APB_INTR_PMC);
+ sc->sc_intr_counter[APB_INTR_PMC] = mips_intrcnt_create("apb irq5: pmc");
+
return (0);
}
@@ -329,11 +341,12 @@ apb_teardown_intr(device_t dev, device_t child, struct resource *ires,
}
static int
-apb_intr(void *arg)
+apb_filter(void *arg)
{
struct apb_softc *sc = arg;
struct intr_event *event;
uint32_t reg, irq;
+ struct thread *td;
reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS);
for (irq = 0; irq < APB_NIRQS; irq++) {
@@ -354,14 +367,34 @@ apb_intr(void *arg)
event = sc->sc_eventstab[irq];
if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
+ if (irq == APB_INTR_PMC) {
+ register_t s;
+ struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame;
+ s = intr_disable();
+ mips_intrcnt_inc(sc->sc_intr_counter[irq]);
+
+ if (pmc_intr && (*pmc_intr)(PCPU_GET(cpuid), tf)) {
+ intr_restore(s);
+ continue;
+ }
+
+ intr_restore(s);
+ td = PCPU_GET(curthread);
+
+ if (pmc_hook && (td->td_pflags & TDP_CALLCHAIN))
+ pmc_hook(PCPU_GET(curthread),
+ PMC_FN_USER_CALLCHAIN, tf);
+
+ continue;
+
+ }
/* Ignore timer interrupts */
if (irq != 0)
printf("Stray APB IRQ %d\n", irq);
continue;
}
- /* TODO: frame instead of NULL? */
- intr_event_handle(event, NULL);
+ intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame);
mips_intrcnt_inc(sc->sc_intr_counter[irq]);
}
}
OpenPOWER on IntegriCloud