@@ -17,8 +17,6 @@
#define ARCH_TIMER_CTL_IMASK (1 << 1)
#define ARCH_TIMER_CTL_ISTATUS (1 << 2)
-static void *gic_isactiver;
-static void *gic_ispendr;
static void *gic_isenabler;
static void *gic_icenabler;
@@ -183,28 +181,22 @@ static bool timer_pending(struct timer_info *info)
(info->read_ctl() & ARCH_TIMER_CTL_ISTATUS);
}
-static enum gic_state gic_timer_state(struct timer_info *info)
+static bool gic_timer_check_state(struct timer_info *info,
+ enum gic_irq_state expected_state)
{
- enum gic_state state = GIC_STATE_INACTIVE;
int i;
- bool pending, active;
/* Wait for up to 1s for the GIC to sample the interrupt. */
for (i = 0; i < 10; i++) {
- pending = readl(gic_ispendr) & (1 << PPI(info->irq));
- active = readl(gic_isactiver) & (1 << PPI(info->irq));
- if (!active && !pending)
- state = GIC_STATE_INACTIVE;
- if (pending)
- state = GIC_STATE_PENDING;
- if (active)
- state = GIC_STATE_ACTIVE;
- if (active && pending)
- state = GIC_STATE_ACTIVE_PENDING;
mdelay(100);
+ if (gic_irq_state(PPI(info->irq)) == expected_state) {
+ mdelay(100);
+ if (gic_irq_state(PPI(info->irq)) == expected_state)
+ return true;
+ }
}
- return state;
+ return false;
}
static bool test_cval_10msec(struct timer_info *info)
@@ -253,11 +245,11 @@ static void test_timer(struct timer_info *info)
/* Enable the timer, but schedule it for much later */
info->write_cval(later);
info->write_ctl(ARCH_TIMER_CTL_ENABLE);
- report(!timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"not pending before");
info->write_cval(now - 1);
- report(timer_pending(info) && gic_timer_state(info) == GIC_STATE_PENDING,
+ report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_PENDING),
"interrupt signal pending");
/* Disable the timer again and prepare to take interrupts */
@@ -265,12 +257,12 @@ static void test_timer(struct timer_info *info)
info->irq_received = false;
set_timer_irq_enabled(info, true);
report(!info->irq_received, "no interrupt when timer is disabled");
- report(!timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(!timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"interrupt signal no longer pending");
info->write_cval(now - 1);
info->write_ctl(ARCH_TIMER_CTL_ENABLE | ARCH_TIMER_CTL_IMASK);
- report(timer_pending(info) && gic_timer_state(info) == GIC_STATE_INACTIVE,
+ report(timer_pending(info) && gic_timer_check_state(info, GIC_IRQ_STATE_INACTIVE),
"interrupt signal not pending");
report(test_cval_10msec(info), "latency within 10 ms");
@@ -345,14 +337,10 @@ static void test_init(void)
switch (gic_version()) {
case 2:
- gic_isactiver = gicv2_dist_base() + GICD_ISACTIVER;
- gic_ispendr = gicv2_dist_base() + GICD_ISPENDR;
gic_isenabler = gicv2_dist_base() + GICD_ISENABLER;
gic_icenabler = gicv2_dist_base() + GICD_ICENABLER;
break;
case 3:
- gic_isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
- gic_ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
gic_isenabler = gicv3_sgi_base() + GICR_ISENABLER0;
gic_icenabler = gicv3_sgi_base() + GICR_ICENABLER0;
break;
@@ -47,11 +47,11 @@
#ifndef __ASSEMBLY__
#include <asm/cpumask.h>
-enum gic_state {
- GIC_STATE_INACTIVE,
- GIC_STATE_PENDING,
- GIC_STATE_ACTIVE,
- GIC_STATE_ACTIVE_PENDING,
+enum gic_irq_state {
+ GIC_IRQ_STATE_INACTIVE,
+ GIC_IRQ_STATE_PENDING,
+ GIC_IRQ_STATE_ACTIVE,
+ GIC_IRQ_STATE_ACTIVE_PENDING,
};
/*
@@ -80,6 +80,7 @@ extern u32 gic_iar_irqnr(u32 iar);
extern void gic_write_eoir(u32 irqstat);
extern void gic_ipi_send_single(int irq, int cpu);
extern void gic_ipi_send_mask(int irq, const cpumask_t *dest);
+extern enum gic_irq_state gic_irq_state(int irq);
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM_GIC_H_ */
@@ -146,3 +146,48 @@ void gic_ipi_send_mask(int irq, const cpumask_t *dest)
assert(gic_common_ops && gic_common_ops->ipi_send_mask);
gic_common_ops->ipi_send_mask(irq, dest);
}
+
+enum gic_irq_state gic_irq_state(int irq)
+{
+ enum gic_irq_state state;
+ void *ispendr, *isactiver;
+ bool pending, active;
+ int offset, mask;
+
+ assert(gic_common_ops);
+ assert(irq < 1020);
+
+ switch (gic_version()) {
+ case 2:
+ ispendr = gicv2_dist_base() + GICD_ISPENDR;
+ isactiver = gicv2_dist_base() + GICD_ISACTIVER;
+ break;
+ case 3:
+ if (irq < GIC_NR_PRIVATE_IRQS) {
+ ispendr = gicv3_sgi_base() + GICR_ISPENDR0;
+ isactiver = gicv3_sgi_base() + GICR_ISACTIVER0;
+ } else {
+ ispendr = gicv3_dist_base() + GICD_ISPENDR;
+ isactiver = gicv3_dist_base() + GICD_ISACTIVER;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ offset = irq / 32 * 4;
+ mask = 1 << (irq % 32);
+ pending = readl(ispendr + offset) & mask;
+ active = readl(isactiver + offset) & mask;
+
+ if (!active && !pending)
+ state = GIC_IRQ_STATE_INACTIVE;
+ if (pending)
+ state = GIC_IRQ_STATE_PENDING;
+ if (active)
+ state = GIC_IRQ_STATE_ACTIVE;
+ if (active && pending)
+ state = GIC_IRQ_STATE_ACTIVE_PENDING;
+
+ return state;
+}