From mboxrd@z Thu Jan 1 00:00:00 1970 From: marc.zyngier@arm.com (Marc Zyngier) Date: Fri, 6 May 2011 11:33:13 +0100 Subject: [RFC PATCH v2 08/12] ARM: msm: use remapped PPI interrupts for local timer In-Reply-To: <1304677997-26947-1-git-send-email-marc.zyngier@arm.com> References: <1304677997-26947-1-git-send-email-marc.zyngier@arm.com> Message-ID: <1304677997-26947-9-git-send-email-marc.zyngier@arm.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Use the normal interrupt scheme for the local timers by using a remapped PPI interrupt. MSM already had a very similar scheme, though still mixing both GIC-specific and generic APIs. Fixes and ideas courtesy of Stephen Boyd. Cc: David Brown Cc: Daniel Walker Cc: Bryan Huntsman Cc: Stephen Boyd Signed-off-by: Marc Zyngier --- arch/arm/mach-msm/Kconfig | 2 + arch/arm/mach-msm/board-msm8x60.c | 11 --- arch/arm/mach-msm/include/mach/entry-macro-qgic.S | 73 +-------------------- arch/arm/mach-msm/timer.c | 62 ++++++++---------- 4 files changed, 30 insertions(+), 118 deletions(-) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 1516896..1ea7d6f 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -42,6 +42,7 @@ config ARCH_MSM8X60 && !MACH_MSM8X60_FFA) select ARCH_MSM_SCORPIONMP select ARM_GIC + select ARM_GIC_VPPI select CPU_V7 select MSM_V2_TLMM select MSM_GPIOMUX @@ -52,6 +53,7 @@ config ARCH_MSM8960 select ARCH_MSM_SCORPIONMP select MACH_MSM8960_SIM if (!MACH_MSM8960_RUMI3) select ARM_GIC + select ARM_GIC_VPPI select CPU_V7 select MSM_V2_TLMM select MSM_GPIOMUX diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index 1163b6f..d70a2f6 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -36,8 +36,6 @@ static void __init msm8x60_map_io(void) static void __init msm8x60_init_irq(void) { - unsigned int i; - gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE); @@ -49,15 +47,6 @@ static void __init msm8x60_init_irq(void) */ if (!machine_is_msm8x60_sim()) writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET); - - /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet - * as they are configured as level, which does not play nice with - * handle_percpu_irq. - */ - for (i = GIC_PPI_START; i < GIC_SPI_START; i++) { - if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE) - irq_set_handler(i, handle_percpu_irq); - } } static void __init msm8x60_init(void) diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S index 1246715..717076f 100644 --- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S +++ b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S @@ -8,81 +8,10 @@ * warranty of any kind, whether express or implied. */ -#include -#include +#include .macro disable_fiq .endm - .macro get_irqnr_preamble, base, tmp - ldr \base, =gic_cpu_base_addr - ldr \base, [\base] - .endm - .macro arch_ret_to_user, tmp1, tmp2 .endm - - /* - * The interrupt numbering scheme is defined in the - * interrupt controller spec. To wit: - * - * Migrated the code from ARM MP port to be more consistent - * with interrupt processing , the following still holds true - * however, all interrupts are treated the same regardless of - * if they are local IPI or PPI - * - * Interrupts 0-15 are IPI - * 16-31 are PPI - * (16-18 are the timers) - * 32-1020 are global - * 1021-1022 are reserved - * 1023 is "spurious" (no interrupt) - * - * A simple read from the controller will tell us the number of the - * highest priority enabled interrupt. We then just need to check - * whether it is in the valid range for an IRQ (0-1020 inclusive). - * - * Base ARM code assumes that the local (private) peripheral interrupts - * are not valid, we treat them differently, in that the privates are - * handled like normal shared interrupts with the exception that only - * one processor can register the interrupt and the handler must be - * the same for all processors. - */ - - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp - - ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU, - 9-0 =int # */ - - bic \irqnr, \irqstat, #0x1c00 @mask src - cmp \irqnr, #15 - ldr \tmp, =1021 - cmpcc \irqnr, \irqnr - cmpne \irqnr, \tmp - cmpcs \irqnr, \irqnr - - .endm - - /* We assume that irqstat (the raw value of the IRQ acknowledge - * register) is preserved from the macro above. - * If there is an IPI, we immediately signal end of interrupt on the - * controller, since this requires the original irqstat value which - * we won't easily be able to recreate later. - */ - .macro test_for_ipi, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - cmp \irqnr, #16 - strcc \irqstat, [\base, #GIC_CPU_EOI] - cmpcs \irqnr, \irqnr - .endm - - /* As above, this assumes that irqstat and base are preserved.. */ - - .macro test_for_ltirq, irqnr, irqstat, base, tmp - bic \irqnr, \irqstat, #0x1c00 - mov \tmp, #0 - cmp \irqnr, #16 - moveq \tmp, #1 - streq \irqstat, [\base, #GIC_CPU_EOI] - cmp \tmp, #0 - .endm diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 38b95e9..f063860 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -22,7 +22,9 @@ #include #include +#include #include +#include #include #include @@ -67,7 +69,7 @@ enum timer_location { struct msm_clock { struct clock_event_device clockevent; struct clocksource clocksource; - struct irqaction irq; + unsigned int irq; void __iomem *regbase; uint32_t freq; uint32_t shift; @@ -83,18 +85,7 @@ enum { static struct msm_clock msm_clocks[]; -static struct clock_event_device *local_clock_event; - -static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - if (smp_processor_id() != 0) - evt = local_clock_event; - if (evt->event_handler == NULL) - return IRQ_HANDLED; - evt->event_handler(evt); - return IRQ_HANDLED; -} +static int local_timer_inited; static cycle_t msm_read_timer_count(struct clocksource *cs) { @@ -140,6 +131,8 @@ static void msm_timer_set_mode(enum clock_event_mode mode, writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); break; case CLOCK_EVT_MODE_UNUSED: + free_irq(evt->irq, evt); + /* fall through */ case CLOCK_EVT_MODE_SHUTDOWN: writel(0, clock->regbase + TIMER_ENABLE); break; @@ -163,13 +156,7 @@ static struct msm_clock msm_clocks[] = { .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, - .irq = { - .name = "gp_timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, - .handler = msm_timer_interrupt, - .dev_id = &msm_clocks[0].clockevent, - .irq = INT_GP_TIMER_EXP - }, + .irq = INT_GP_TIMER_EXP, .freq = GPT_HZ, }, [MSM_CLOCK_DGT] = { @@ -188,13 +175,7 @@ static struct msm_clock msm_clocks[] = { .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, - .irq = { - .name = "dg_timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_RISING, - .handler = msm_timer_interrupt, - .dev_id = &msm_clocks[1].clockevent, - .irq = INT_DEBUG_TIMER_EXP - }, + .irq = INT_DEBUG_TIMER_EXP, .freq = DGT_HZ >> MSM_DGT_SHIFT, .shift = MSM_DGT_SHIFT, } @@ -232,6 +213,7 @@ static void __init msm_timer_init(void) struct msm_clock *clock = &msm_clocks[i]; struct clock_event_device *ce = &clock->clockevent; struct clocksource *cs = &clock->clocksource; + int irq; clock->local_counter = clock->regbase + TIMER_COUNT_VAL; clock->global_counter = clock->local_counter + global_offset; @@ -253,10 +235,13 @@ static void __init msm_timer_init(void) printk(KERN_ERR "msm_timer_init: clocksource_register " "failed for %s\n", cs->name); - res = setup_irq(clock->irq.irq, &clock->irq); + irq = gic_ppi_to_vppi(clock->irq); + res = request_irq(irq, percpu_timer_handler, + IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, + ce->name, ce); if (res) - printk(KERN_ERR "msm_timer_init: setup_irq " - "failed for %s\n", cs->name); + pr_err("msm_timer_init: request_irq failed for %s\n", + ce->name); clockevents_register_device(ce); } @@ -266,6 +251,7 @@ static void __init msm_timer_init(void) int __cpuinit local_timer_setup(struct clock_event_device *evt) { struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER]; + int res; /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) @@ -273,12 +259,13 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); - if (!local_clock_event) { + if (!local_timer_inited) { writel(0, clock->regbase + TIMER_ENABLE); writel(0, clock->regbase + TIMER_CLEAR); writel(~0, clock->regbase + TIMER_MATCH_VAL); + local_timer_inited = 1; } - evt->irq = clock->irq.irq; + evt->irq = gic_ppi_to_vppi(clock->irq); evt->name = "local_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT; evt->rating = clock->clockevent.rating; @@ -290,9 +277,14 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) clockevent_delta2ns(0xf0000000 >> clock->shift, evt); evt->min_delta_ns = clockevent_delta2ns(4, evt); - local_clock_event = evt; - - gic_enable_ppi(clock->irq.irq); + res = request_irq(evt->irq, percpu_timer_handler, + IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, + clock->clockevent.name, evt); + if (res) { + pr_err("local_timer_setup: request_irq failed for %s\n", + clock->clockevent.name); + return res; + } clockevents_register_device(evt); return 0; -- 1.7.0.4