diff options
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r-- | arch/blackfin/mach-common/arch_checks.c | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-common/cache.S | 38 | ||||
-rw-r--r-- | arch/blackfin/mach-common/cpufreq.c | 8 | ||||
-rw-r--r-- | arch/blackfin/mach-common/dpmc.c | 50 | ||||
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 19 | ||||
-rw-r--r-- | arch/blackfin/mach-common/head.S | 112 | ||||
-rw-r--r-- | arch/blackfin/mach-common/interrupt.S | 6 | ||||
-rw-r--r-- | arch/blackfin/mach-common/ints-priority.c | 271 | ||||
-rw-r--r-- | arch/blackfin/mach-common/smp.c | 35 |
9 files changed, 333 insertions, 208 deletions
diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c index bceb98126c2..d8643fdd0fc 100644 --- a/arch/blackfin/mach-common/arch_checks.c +++ b/arch/blackfin/mach-common/arch_checks.c @@ -61,6 +61,6 @@ # error "Anomaly 05000220 does not allow you to use Write Back cache with L2 or External Memory" #endif -#if ANOMALY_05000491 && !defined(CONFIG_CACHE_FLUSH_L1) +#if ANOMALY_05000491 && !defined(CONFIG_ICACHE_FLUSH_L1) # error You need IFLUSH in L1 inst while Anomaly 05000491 applies #endif diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S index ab4a925a443..9f4dd35bfd7 100644 --- a/arch/blackfin/mach-common/cache.S +++ b/arch/blackfin/mach-common/cache.S @@ -11,12 +11,6 @@ #include <asm/cache.h> #include <asm/page.h> -#ifdef CONFIG_CACHE_FLUSH_L1 -.section .l1.text -#else -.text -#endif - /* 05000443 - IFLUSH cannot be last instruction in hardware loop */ #if ANOMALY_05000443 # define BROK_FLUSH_INST "IFLUSH" @@ -68,11 +62,43 @@ RTS; .endm +#ifdef CONFIG_ICACHE_FLUSH_L1 +.section .l1.text +#else +.text +#endif + /* Invalidate all instruction cache lines assocoiated with this memory area */ +#ifdef CONFIG_SMP +# define _blackfin_icache_flush_range _blackfin_icache_flush_range_l1 +#endif ENTRY(_blackfin_icache_flush_range) do_flush IFLUSH ENDPROC(_blackfin_icache_flush_range) +#ifdef CONFIG_SMP +.text +# undef _blackfin_icache_flush_range +ENTRY(_blackfin_icache_flush_range) + p0.L = LO(DSPID); + p0.H = HI(DSPID); + r3 = [p0]; + r3 = r3.b (z); + p2 = r3; + p0.L = _blackfin_iflush_l1_entry; + p0.H = _blackfin_iflush_l1_entry; + p0 = p0 + (p2 << 2); + p1 = [p0]; + jump (p1); +ENDPROC(_blackfin_icache_flush_range) +#endif + +#ifdef CONFIG_DCACHE_FLUSH_L1 +.section .l1.text +#else +.text +#endif + /* Throw away all D-cached data in specified region without any obligation to * write them back. Since the Blackfin ISA does not have an "invalidate" * instruction, we use flush/invalidate. Perhaps as a speed optimization we diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c index f4cf11d362e..85dc6d69f9c 100644 --- a/arch/blackfin/mach-common/cpufreq.c +++ b/arch/blackfin/mach-common/cpufreq.c @@ -1,7 +1,7 @@ /* * Blackfin core clock scaling * - * Copyright 2008-2009 Analog Devices Inc. + * Copyright 2008-2011 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ @@ -16,10 +16,8 @@ #include <asm/time.h> #include <asm/dpmc.h> -#define CPUFREQ_CPU 0 - /* this is the table of CCLK frequencies, in Hz */ -/* .index is the entry in the auxillary dpm_state_table[] */ +/* .index is the entry in the auxiliary dpm_state_table[] */ static struct cpufreq_frequency_table bfin_freq_table[] = { { .frequency = CPUFREQ_TABLE_END, @@ -46,7 +44,7 @@ static struct bfin_dpm_state { #if defined(CONFIG_CYCLES_CLOCKSOURCE) /* - * normalized to maximum frequncy offset for CYCLES, + * normalized to maximum frequency offset for CYCLES, * used in time-ts cycles clock source, but could be used * somewhere also. */ diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c index 02c7efd1bcf..382099fd556 100644 --- a/arch/blackfin/mach-common/dpmc.c +++ b/arch/blackfin/mach-common/dpmc.c @@ -61,17 +61,63 @@ err_out: } #ifdef CONFIG_CPU_FREQ +# ifdef CONFIG_SMP +static void bfin_idle_this_cpu(void *info) +{ + unsigned long flags = 0; + unsigned long iwr0, iwr1, iwr2; + unsigned int cpu = smp_processor_id(); + + local_irq_save_hw(flags); + bfin_iwr_set_sup0(&iwr0, &iwr1, &iwr2); + + platform_clear_ipi(cpu, IRQ_SUPPLE_0); + SSYNC(); + asm("IDLE;"); + bfin_iwr_restore(iwr0, iwr1, iwr2); + + local_irq_restore_hw(flags); +} + +static void bfin_idle_cpu(void) +{ + smp_call_function(bfin_idle_this_cpu, NULL, 0); +} + +static void bfin_wakeup_cpu(void) +{ + unsigned int cpu; + unsigned int this_cpu = smp_processor_id(); + cpumask_t mask = cpu_online_map; + + cpu_clear(this_cpu, mask); + for_each_cpu_mask(cpu, mask) + platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0); +} + +# else +static void bfin_idle_cpu(void) {} +static void bfin_wakeup_cpu(void) {} +# endif + static int vreg_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) { struct cpufreq_freqs *freq = data; + if (freq->cpu != CPUFREQ_CPU) + return 0; + if (val == CPUFREQ_PRECHANGE && freq->old < freq->new) { + bfin_idle_cpu(); bfin_set_vlev(bfin_get_vlev(freq->new)); udelay(pdata->vr_settling_time); /* Wait until Volatge settled */ - - } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) + bfin_wakeup_cpu(); + } else if (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) { + bfin_idle_cpu(); bfin_set_vlev(bfin_get_vlev(freq->new)); + bfin_wakeup_cpu(); + } return 0; } diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index bc08c98d008..f96933f48a7 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -268,7 +268,7 @@ ENTRY(_handle_bad_cplb) /* To get here, we just tried and failed to change a CPLB * so, handle things in trap_c (C code), by lowering to * IRQ5, just like we normally do. Since this is not a - * "normal" return path, we have a do alot of stuff to + * "normal" return path, we have a do a lot of stuff to * the stack to get ready so, we can fall through - we * need to make a CPLB exception look like a normal exception */ @@ -817,7 +817,7 @@ _new_old_task: rets = [sp++]; /* - * When we come out of resume, r0 carries "old" task, becuase we are + * When we come out of resume, r0 carries "old" task, because we are * in "new" task. */ rts; @@ -952,8 +952,17 @@ ENDPROC(_evt_up_evt14) #ifdef CONFIG_IPIPE _resume_kernel_from_int: + r1 = LO(~0x8000) (Z); + r1 = r0 & r1; + r0 = 1; + r0 = r1 - r0; + r2 = r1 & r0; + cc = r2 == 0; + /* Sync the root stage only from the outer interrupt level. */ + if !cc jump .Lnosync; r0.l = ___ipipe_sync_root; r0.h = ___ipipe_sync_root; + [--sp] = reti; [--sp] = rets; [--sp] = ( r7:4, p5:3 ); SP += -12; @@ -961,6 +970,8 @@ _resume_kernel_from_int: SP += 12; ( r7:4, p5:3 ) = [sp++]; rets = [sp++]; + reti = [sp++]; +.Lnosync: rts #elif defined(CONFIG_PREEMPT) @@ -1738,6 +1749,10 @@ ENTRY(_sys_call_table) .long _sys_fanotify_mark .long _sys_prlimit64 .long _sys_cacheflush + .long _sys_name_to_handle_at /* 375 */ + .long _sys_open_by_handle_at + .long _sys_clock_adjtime + .long _sys_syncfs .rept NR_syscalls-(.-_sys_call_table)/4 .long _sys_ni_syscall diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index 4391621d904..76de5724c1e 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -31,6 +31,7 @@ ENDPROC(__init_clear_bss) ENTRY(__start) /* R0: argument of command line string, passed from uboot, save it */ R7 = R0; + /* Enable Cycle Counter and Nesting Of Interrupts */ #ifdef CONFIG_BFIN_SCRATCH_REG_CYCLES R0 = SYSCFG_SNEN; @@ -38,76 +39,49 @@ ENTRY(__start) R0 = SYSCFG_SNEN | SYSCFG_CCEN; #endif SYSCFG = R0; - R0 = 0; - - /* Clear Out All the data and pointer Registers */ - R1 = R0; - R2 = R0; - R3 = R0; - R4 = R0; - R5 = R0; - R6 = R0; - - P0 = R0; - P1 = R0; - P2 = R0; - P3 = R0; - P4 = R0; - P5 = R0; - - LC0 = r0; - LC1 = r0; - L0 = r0; - L1 = r0; - L2 = r0; - L3 = r0; - - /* Clear Out All the DAG Registers */ - B0 = r0; - B1 = r0; - B2 = r0; - B3 = r0; - - I0 = r0; - I1 = r0; - I2 = r0; - I3 = r0; - - M0 = r0; - M1 = r0; - M2 = r0; - M3 = r0; + + /* Optimization register tricks: keep a base value in the + * reserved P registers so we use the load/store with an + * offset syntax. R0 = [P5 + <constant>]; + * P5 - core MMR base + * R6 - 0 + */ + r6 = 0; + p5.l = 0; + p5.h = hi(COREMMR_BASE); + + /* Zero out registers required by Blackfin ABI */ + + /* Disable circular buffers */ + L0 = r6; + L1 = r6; + L2 = r6; + L3 = r6; + + /* Disable hardware loops in case we were started by 'go' */ + LC0 = r6; + LC1 = r6; /* * Clear ITEST_COMMAND and DTEST_COMMAND registers, * Leaving these as non-zero can confuse the emulator */ - p0.L = LO(DTEST_COMMAND); - p0.H = HI(DTEST_COMMAND); - [p0] = R0; - [p0 + (ITEST_COMMAND - DTEST_COMMAND)] = R0; + [p5 + (DTEST_COMMAND - COREMMR_BASE)] = r6; + [p5 + (ITEST_COMMAND - COREMMR_BASE)] = r6; CSYNC; trace_buffer_init(p0,r0); - P0 = R1; - R0 = R1; /* Turn off the icache */ - p0.l = LO(IMEM_CONTROL); - p0.h = HI(IMEM_CONTROL); - R1 = [p0]; - R0 = ~ENICPLB; - R0 = R0 & R1; - [p0] = R0; + r1 = [p5 + (IMEM_CONTROL - COREMMR_BASE)]; + BITCLR (r1, ENICPLB_P); + [p5 + (IMEM_CONTROL - COREMMR_BASE)] = r1; SSYNC; /* Turn off the dcache */ - p0.l = LO(DMEM_CONTROL); - p0.h = HI(DMEM_CONTROL); - R1 = [p0]; - R0 = ~ENDCPLB; - R0 = R0 & R1; - [p0] = R0; + r1 = [p5 + (DMEM_CONTROL - COREMMR_BASE)]; + BITCLR (r1, ENDCPLB_P); + [p5 + (DMEM_CONTROL - COREMMR_BASE)] = r1; SSYNC; /* in case of double faults, save a few things */ @@ -122,25 +96,25 @@ ENTRY(__start) * below */ GET_PDA(p0, r0); - r6 = [p0 + PDA_DF_RETX]; + r5 = [p0 + PDA_DF_RETX]; p1.l = _init_saved_retx; p1.h = _init_saved_retx; - [p1] = r6; + [p1] = r5; - r6 = [p0 + PDA_DF_DCPLB]; + r5 = [p0 + PDA_DF_DCPLB]; p1.l = _init_saved_dcplb_fault_addr; p1.h = _init_saved_dcplb_fault_addr; - [p1] = r6; + [p1] = r5; - r6 = [p0 + PDA_DF_ICPLB]; + r5 = [p0 + PDA_DF_ICPLB]; p1.l = _init_saved_icplb_fault_addr; p1.h = _init_saved_icplb_fault_addr; - [p1] = r6; + [p1] = r5; - r6 = [p0 + PDA_DF_SEQSTAT]; + r5 = [p0 + PDA_DF_SEQSTAT]; p1.l = _init_saved_seqstat; p1.h = _init_saved_seqstat; - [p1] = r6; + [p1] = r5; #endif /* Initialize stack pointer */ @@ -155,7 +129,7 @@ ENTRY(__start) sti r0; #endif - r0 = 0 (x); + r0 = r6; /* Zero out all of the fun bss regions */ #if L1_DATA_A_LENGTH > 0 r1.l = __sbss_l1; @@ -200,7 +174,7 @@ ENTRY(__start) sp.l = lo(KERNEL_CLOCK_STACK); sp.h = hi(KERNEL_CLOCK_STACK); call _init_clocks; - sp = usp; /* usp hasnt been touched, so restore from there */ + sp = usp; /* usp hasn't been touched, so restore from there */ #endif /* This section keeps the processor in supervisor mode @@ -210,11 +184,9 @@ ENTRY(__start) /* EVT15 = _real_start */ - p0.l = lo(EVT15); - p0.h = hi(EVT15); p1.l = _real_start; p1.h = _real_start; - [p0] = p1; + [p5 + (EVT15 - COREMMR_BASE)] = p1; csync; #ifdef CONFIG_EARLY_PRINTK diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 2df37db3b49..469ce7282dc 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -274,16 +274,16 @@ ENDPROC(_evt_system_call) * level to EVT14 to prepare the caller for a normal interrupt * return through RTI. * - * We currently use this facility in two occasions: + * We currently use this feature in two occasions: * - * - to branch to __ipipe_irq_tail_hook as requested by a high + * - before branching to __ipipe_irq_tail_hook as requested by a high * priority domain after the pipeline delivered an interrupt, * e.g. such as Xenomai, in order to start its rescheduling * procedure, since we may not switch tasks when IRQ levels are * nested on the Blackfin, so we have to fake an interrupt return * so that we may reschedule immediately. * - * - to branch to sync_root_irqs, in order to play any interrupt + * - before branching to __ipipe_sync_root(), in order to play any interrupt * pending for the root domain (i.e. the Linux kernel). This lowers * the core priority level enough so that Linux IRQ handlers may * never delay interrupts handled by high priority domains; we defer diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index a604f19d8dc..43d9fb195c1 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -15,6 +15,7 @@ #include <linux/kernel_stat.h> #include <linux/seq_file.h> #include <linux/irq.h> +#include <linux/sched.h> #ifdef CONFIG_IPIPE #include <linux/ipipe.h> #endif @@ -124,21 +125,21 @@ static void __init search_IAR(void) * This is for core internal IRQs */ -static void bfin_ack_noop(unsigned int irq) +static void bfin_ack_noop(struct irq_data *d) { /* Dummy function. */ } -static void bfin_core_mask_irq(unsigned int irq) +static void bfin_core_mask_irq(struct irq_data *d) { - bfin_irq_flags &= ~(1 << irq); + bfin_irq_flags &= ~(1 << d->irq); if (!hard_irqs_disabled()) hard_local_irq_enable(); } -static void bfin_core_unmask_irq(unsigned int irq) +static void bfin_core_unmask_irq(struct irq_data *d) { - bfin_irq_flags |= 1 << irq; + bfin_irq_flags |= 1 << d->irq; /* * If interrupts are enabled, IMASK must contain the same value * as bfin_irq_flags. Make sure that invariant holds. If interrupts @@ -176,6 +177,11 @@ static void bfin_internal_mask_irq(unsigned int irq) hard_local_irq_restore(flags); } +static void bfin_internal_mask_irq_chip(struct irq_data *d) +{ + bfin_internal_mask_irq(d->irq); +} + #ifdef CONFIG_SMP static void bfin_internal_unmask_irq_affinity(unsigned int irq, const struct cpumask *affinity) @@ -211,19 +217,24 @@ static void bfin_internal_unmask_irq(unsigned int irq) } #ifdef CONFIG_SMP -static void bfin_internal_unmask_irq(unsigned int irq) +static void bfin_internal_unmask_irq_chip(struct irq_data *d) { - struct irq_desc *desc = irq_to_desc(irq); - bfin_internal_unmask_irq_affinity(irq, desc->affinity); + bfin_internal_unmask_irq_affinity(d->irq, d->affinity); } -static int bfin_internal_set_affinity(unsigned int irq, const struct cpumask *mask) +static int bfin_internal_set_affinity(struct irq_data *d, + const struct cpumask *mask, bool force) { - bfin_internal_mask_irq(irq); - bfin_internal_unmask_irq_affinity(irq, mask); + bfin_internal_mask_irq(d->irq); + bfin_internal_unmask_irq_affinity(d->irq, mask); return 0; } +#else +static void bfin_internal_unmask_irq_chip(struct irq_data *d) +{ + bfin_internal_unmask_irq(d->irq); +} #endif #ifdef CONFIG_PM @@ -279,28 +290,33 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state) return 0; } + +static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state) +{ + return bfin_internal_set_wake(d->irq, state); +} #endif static struct irq_chip bfin_core_irqchip = { .name = "CORE", - .ack = bfin_ack_noop, - .mask = bfin_core_mask_irq, - .unmask = bfin_core_unmask_irq, + .irq_ack = bfin_ack_noop, + .irq_mask = bfin_core_mask_irq, + .irq_unmask = bfin_core_unmask_irq, }; static struct irq_chip bfin_internal_irqchip = { .name = "INTN", - .ack = bfin_ack_noop, - .mask = bfin_internal_mask_irq, - .unmask = bfin_internal_unmask_irq, - .mask_ack = bfin_internal_mask_irq, - .disable = bfin_internal_mask_irq, - .enable = bfin_internal_unmask_irq, + .irq_ack = bfin_ack_noop, + .irq_mask = bfin_internal_mask_irq_chip, + .irq_unmask = bfin_internal_unmask_irq_chip, + .irq_mask_ack = bfin_internal_mask_irq_chip, + .irq_disable = bfin_internal_mask_irq_chip, + .irq_enable = bfin_internal_unmask_irq_chip, #ifdef CONFIG_SMP - .set_affinity = bfin_internal_set_affinity, + .irq_set_affinity = bfin_internal_set_affinity, #endif #ifdef CONFIG_PM - .set_wake = bfin_internal_set_wake, + .irq_set_wake = bfin_internal_set_wake_chip, #endif }; @@ -312,33 +328,32 @@ static void bfin_handle_irq(unsigned irq) __ipipe_handle_irq(irq, ®s); ipipe_trace_irq_exit(irq); #else /* !CONFIG_IPIPE */ - struct irq_desc *desc = irq_desc + irq; - desc->handle_irq(irq, desc); + generic_handle_irq(irq); #endif /* !CONFIG_IPIPE */ } #ifdef BF537_GENERIC_ERROR_INT_DEMUX static int error_int_mask; -static void bfin_generic_error_mask_irq(unsigned int irq) +static void bfin_generic_error_mask_irq(struct irq_data *d) { - error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR)); + error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR)); if (!error_int_mask) bfin_internal_mask_irq(IRQ_GENERIC_ERROR); } -static void bfin_generic_error_unmask_irq(unsigned int irq) +static void bfin_generic_error_unmask_irq(struct irq_data *d) { bfin_internal_unmask_irq(IRQ_GENERIC_ERROR); - error_int_mask |= 1L << (irq - IRQ_PPI_ERROR); + error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR); } static struct irq_chip bfin_generic_error_irqchip = { .name = "ERROR", - .ack = bfin_ack_noop, - .mask_ack = bfin_generic_error_mask_irq, - .mask = bfin_generic_error_mask_irq, - .unmask = bfin_generic_error_unmask_irq, + .irq_ack = bfin_ack_noop, + .irq_mask_ack = bfin_generic_error_mask_irq, + .irq_mask = bfin_generic_error_mask_irq, + .irq_unmask = bfin_generic_error_unmask_irq, }; static void bfin_demux_error_irq(unsigned int int_err_irq, @@ -448,8 +463,10 @@ static void bfin_mac_status_ack_irq(unsigned int irq) } } -static void bfin_mac_status_mask_irq(unsigned int irq) +static void bfin_mac_status_mask_irq(struct irq_data *d) { + unsigned int irq = d->irq; + mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT)); #ifdef BF537_GENERIC_ERROR_INT_DEMUX switch (irq) { @@ -466,8 +483,10 @@ static void bfin_mac_status_mask_irq(unsigned int irq) bfin_mac_status_ack_irq(irq); } -static void bfin_mac_status_unmask_irq(unsigned int irq) +static void bfin_mac_status_unmask_irq(struct irq_data *d) { + unsigned int irq = d->irq; + #ifdef BF537_GENERIC_ERROR_INT_DEMUX switch (irq) { case IRQ_MAC_PHYINT: @@ -484,7 +503,7 @@ static void bfin_mac_status_unmask_irq(unsigned int irq) } #ifdef CONFIG_PM -int bfin_mac_status_set_wake(unsigned int irq, unsigned int state) +int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state) { #ifdef BF537_GENERIC_ERROR_INT_DEMUX return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state); @@ -496,12 +515,12 @@ int bfin_mac_status_set_wake(unsigned int irq, unsigned int state) static struct irq_chip bfin_mac_status_irqchip = { .name = "MACST", - .ack = bfin_ack_noop, - .mask_ack = bfin_mac_status_mask_irq, - .mask = bfin_mac_status_mask_irq, - .unmask = bfin_mac_status_unmask_irq, + .irq_ack = bfin_ack_noop, + .irq_mask_ack = bfin_mac_status_mask_irq, + .irq_mask = bfin_mac_status_mask_irq, + .irq_unmask = bfin_mac_status_unmask_irq, #ifdef CONFIG_PM - .set_wake = bfin_mac_status_set_wake, + .irq_set_wake = bfin_mac_status_set_wake, #endif }; @@ -538,13 +557,9 @@ static void bfin_demux_mac_status_irq(unsigned int int_err_irq, static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) { #ifdef CONFIG_IPIPE - _set_irq_handler(irq, handle_level_irq); -#else - struct irq_desc *desc = irq_desc + irq; - /* May not call generic set_irq_handler() due to spinlock - recursion. */ - desc->handle_irq = handle; + handle = handle_level_irq; #endif + __irq_set_handler_locked(irq, handle); } static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS); @@ -552,58 +567,59 @@ extern void bfin_gpio_irq_prepare(unsigned gpio); #if !defined(CONFIG_BF54x) -static void bfin_gpio_ack_irq(unsigned int irq) +static void bfin_gpio_ack_irq(struct irq_data *d) { /* AFAIK ack_irq in case mask_ack is provided * get's only called for edge sense irqs */ - set_gpio_data(irq_to_gpio(irq), 0); + set_gpio_data(irq_to_gpio(d->irq), 0); } -static void bfin_gpio_mask_ack_irq(unsigned int irq) +static void bfin_gpio_mask_ack_irq(struct irq_data *d) { - struct irq_desc *desc = irq_desc + irq; + unsigned int irq = d->irq; u32 gpionr = irq_to_gpio(irq); - if (desc->handle_irq == handle_edge_irq) + if (!irqd_is_level_type(d)) set_gpio_data(gpionr, 0); set_gpio_maska(gpionr, 0); } -static void bfin_gpio_mask_irq(unsigned int irq) +static void bfin_gpio_mask_irq(struct irq_data *d) { - set_gpio_maska(irq_to_gpio(irq), 0); + set_gpio_maska(irq_to_gpio(d->irq), 0); } -static void bfin_gpio_unmask_irq(unsigned int irq) +static void bfin_gpio_unmask_irq(struct irq_data *d) { - set_gpio_maska(irq_to_gpio(irq), 1); + set_gpio_maska(irq_to_gpio(d->irq), 1); } -static unsigned int bfin_gpio_irq_startup(unsigned int irq) +static unsigned int bfin_gpio_irq_startup(struct irq_data *d) { - u32 gpionr = irq_to_gpio(irq); + u32 gpionr = irq_to_gpio(d->irq); if (__test_and_set_bit(gpionr, gpio_enabled)) bfin_gpio_irq_prepare(gpionr); - bfin_gpio_unmask_irq(irq); + bfin_gpio_unmask_irq(d); return 0; } -static void bfin_gpio_irq_shutdown(unsigned int irq) +static void bfin_gpio_irq_shutdown(struct irq_data *d) { - u32 gpionr = irq_to_gpio(irq); + u32 gpionr = irq_to_gpio(d->irq); - bfin_gpio_mask_irq(irq); + bfin_gpio_mask_irq(d); __clear_bit(gpionr, gpio_enabled); bfin_gpio_irq_free(gpionr); } -static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) +static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type) { + unsigned int irq = d->irq; int ret; char buf[16]; u32 gpionr = irq_to_gpio(irq); @@ -664,9 +680,9 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) } #ifdef CONFIG_PM -int bfin_gpio_set_wake(unsigned int irq, unsigned int state) +int bfin_gpio_set_wake(struct irq_data *d, unsigned int state) { - return gpio_pm_wakeup_ctrl(irq_to_gpio(irq), state); + return gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state); } #endif @@ -818,14 +834,13 @@ void init_pint_lut(void) } } -static void bfin_gpio_ack_irq(unsigned int irq) +static void bfin_gpio_ack_irq(struct irq_data *d) { - struct irq_desc *desc = irq_desc + irq; - u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS]; u32 pintbit = PINT_BIT(pint_val); u32 bank = PINT_2_BANK(pint_val); - if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { if (pint[bank]->invert_set & pintbit) pint[bank]->invert_clear = pintbit; else @@ -835,14 +850,13 @@ static void bfin_gpio_ack_irq(unsigned int irq) } -static void bfin_gpio_mask_ack_irq(unsigned int irq) +static void bfin_gpio_mask_ack_irq(struct irq_data *d) { - struct irq_desc *desc = irq_desc + irq; - u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS]; u32 pintbit = PINT_BIT(pint_val); u32 bank = PINT_2_BANK(pint_val); - if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { if (pint[bank]->invert_set & pintbit) pint[bank]->invert_clear = pintbit; else @@ -853,24 +867,25 @@ static void bfin_gpio_mask_ack_irq(unsigned int irq) pint[bank]->mask_clear = pintbit; } -static void bfin_gpio_mask_irq(unsigned int irq) +static void bfin_gpio_mask_irq(struct irq_data *d) { - u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS]; pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val); } -static void bfin_gpio_unmask_irq(unsigned int irq) +static void bfin_gpio_unmask_irq(struct irq_data *d) { - u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS]; u32 pintbit = PINT_BIT(pint_val); u32 bank = PINT_2_BANK(pint_val); pint[bank]->mask_set = pintbit; } -static unsigned int bfin_gpio_irq_startup(unsigned int irq) +static unsigned int bfin_gpio_irq_startup(struct irq_data *d) { + unsigned int irq = d->irq; u32 gpionr = irq_to_gpio(irq); u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; @@ -884,22 +899,23 @@ static unsigned int bfin_gpio_irq_startup(unsigned int irq) if (__test_and_set_bit(gpionr, gpio_enabled)) bfin_gpio_irq_prepare(gpionr); - bfin_gpio_unmask_irq(irq); + bfin_gpio_unmask_irq(d); return 0; } -static void bfin_gpio_irq_shutdown(unsigned int irq) +static void bfin_gpio_irq_shutdown(struct irq_data *d) { - u32 gpionr = irq_to_gpio(irq); + u32 gpionr = irq_to_gpio(d->irq); - bfin_gpio_mask_irq(irq); + bfin_gpio_mask_irq(d); __clear_bit(gpionr, gpio_enabled); bfin_gpio_irq_free(gpionr); } -static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) +static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type) { + unsigned int irq = d->irq; int ret; char buf[16]; u32 gpionr = irq_to_gpio(irq); @@ -961,10 +977,10 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) u32 pint_saved_masks[NR_PINT_SYS_IRQS]; u32 pint_wakeup_masks[NR_PINT_SYS_IRQS]; -int bfin_gpio_set_wake(unsigned int irq, unsigned int state) +int bfin_gpio_set_wake(struct irq_data *d, unsigned int state) { u32 pint_irq; - u32 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS]; u32 bank = PINT_2_BANK(pint_val); u32 pintbit = PINT_BIT(pint_val); @@ -1066,17 +1082,17 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq, static struct irq_chip bfin_gpio_irqchip = { .name = "GPIO", - .ack = bfin_gpio_ack_irq, - .mask = bfin_gpio_mask_irq, - .mask_ack = bfin_gpio_mask_ack_irq, - .unmask = bfin_gpio_unmask_irq, - .disable = bfin_gpio_mask_irq, - .enable = bfin_gpio_unmask_irq, - .set_type = bfin_gpio_irq_type, - .startup = bfin_gpio_irq_startup, - .shutdown = bfin_gpio_irq_shutdown, + .irq_ack = bfin_gpio_ack_irq, + .irq_mask = bfin_gpio_mask_irq, + .irq_mask_ack = bfin_gpio_mask_ack_irq, + .irq_unmask = bfin_gpio_unmask_irq, + .irq_disable = bfin_gpio_mask_irq, + .irq_enable = bfin_gpio_unmask_irq, + .irq_set_type = bfin_gpio_irq_type, + .irq_startup = bfin_gpio_irq_startup, + .irq_shutdown = bfin_gpio_irq_shutdown, #ifdef CONFIG_PM - .set_wake = bfin_gpio_set_wake, + .irq_set_wake = bfin_gpio_set_wake, #endif }; @@ -1147,9 +1163,9 @@ int __init init_arch_irq(void) for (irq = 0; irq <= SYS_IRQS; irq++) { if (irq <= IRQ_CORETMR) - set_irq_chip(irq, &bfin_core_irqchip); + irq_set_chip(irq, &bfin_core_irqchip); else - set_irq_chip(irq, &bfin_internal_irqchip); + irq_set_chip(irq, &bfin_internal_irqchip); switch (irq) { #if defined(CONFIG_BF53x) @@ -1173,50 +1189,50 @@ int __init init_arch_irq(void) #elif defined(CONFIG_BF538) || defined(CONFIG_BF539) case IRQ_PORTF_INTA: #endif - set_irq_chained_handler(irq, - bfin_demux_gpio_irq); + irq_set_chained_handler(irq, bfin_demux_gpio_irq); break; #ifdef BF537_GENERIC_ERROR_INT_DEMUX case IRQ_GENERIC_ERROR: - set_irq_chained_handler(irq, bfin_demux_error_irq); + irq_set_chained_handler(irq, bfin_demux_error_irq); break; #endif #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) case IRQ_MAC_ERROR: - set_irq_chained_handler(irq, bfin_demux_mac_status_irq); + irq_set_chained_handler(irq, + bfin_demux_mac_status_irq); break; #endif #ifdef CONFIG_SMP case IRQ_SUPPLE_0: case IRQ_SUPPLE_1: - set_irq_handler(irq, handle_percpu_irq); + irq_set_handler(irq, handle_percpu_irq); break; #endif #ifdef CONFIG_TICKSOURCE_CORETMR case IRQ_CORETMR: # ifdef CONFIG_SMP - set_irq_handler(irq, handle_percpu_irq); + irq_set_handler(irq, handle_percpu_irq); break; # else - set_irq_handler(irq, handle_simple_irq); + irq_set_handler(irq, handle_simple_irq); break; # endif #endif #ifdef CONFIG_TICKSOURCE_GPTMR0 case IRQ_TIMER0: - set_irq_handler(irq, handle_simple_irq); + irq_set_handler(irq, handle_simple_irq); break; #endif #ifdef CONFIG_IPIPE default: - set_irq_handler(irq, handle_level_irq); + irq_set_handler(irq, handle_level_irq); break; #else /* !CONFIG_IPIPE */ default: - set_irq_handler(irq, handle_simple_irq); + irq_set_handler(irq, handle_simple_irq); break; #endif /* !CONFIG_IPIPE */ } @@ -1224,22 +1240,22 @@ int __init init_arch_irq(void) #ifdef BF537_GENERIC_ERROR_INT_DEMUX for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) - set_irq_chip_and_handler(irq, &bfin_generic_error_irqchip, + irq_set_chip_and_handler(irq, &bfin_generic_error_irqchip, handle_level_irq); #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) - set_irq_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq); + irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq); #endif #endif #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE) for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++) - set_irq_chip_and_handler(irq, &bfin_mac_status_irqchip, + irq_set_chip_and_handler(irq, &bfin_mac_status_irqchip, handle_level_irq); #endif /* if configured as edge, then will be changed to do_edge_IRQ */ for (irq = GPIO_IRQ_BASE; irq < (GPIO_IRQ_BASE + MAX_BLACKFIN_GPIOS); irq++) - set_irq_chip_and_handler(irq, &bfin_gpio_irqchip, + irq_set_chip_and_handler(irq, &bfin_gpio_irqchip, handle_level_irq); bfin_write_IMASK(0); @@ -1373,7 +1389,7 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) struct ipipe_domain *this_domain = __ipipe_current_domain; struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop; struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst; - int irq, s; + int irq, s = 0; if (likely(vec == EVT_IVTMR_P)) irq = IRQ_CORETMR; @@ -1423,6 +1439,21 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10; } + /* + * We don't want Linux interrupt handlers to run at the + * current core priority level (i.e. < EVT15), since this + * might delay other interrupts handled by a high priority + * domain. Here is what we do instead: + * + * - we raise the SYNCDEFER bit to prevent + * __ipipe_handle_irq() to sync the pipeline for the root + * stage for the incoming interrupt. Upon return, that IRQ is + * pending in the interrupt log. + * + * - we raise the TIF_IRQ_SYNC bit for the current thread, so + * that _schedule_and_signal_from_int will eventually sync the + * pipeline from EVT15. + */ if (this_domain == ipipe_root_domain) { s = __test_and_set_bit(IPIPE_SYNCDEFER_FLAG, &p->status); barrier(); @@ -1432,6 +1463,24 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) __ipipe_handle_irq(irq, regs); ipipe_trace_irq_exit(irq); + if (user_mode(regs) && + !ipipe_test_foreign_stack() && + (current->ipipe_flags & PF_EVTRET) != 0) { + /* + * Testing for user_regs() does NOT fully eliminate + * foreign stack contexts, because of the forged + * interrupt returns we do through + * __ipipe_call_irqtail. In that case, we might have + * preempted a foreign stack context in a high + * priority domain, with a single interrupt level now + * pending after the irqtail unwinding is done. In + * which case user_mode() is now true, and the event + * gets dispatched spuriously. + */ + current->ipipe_flags &= ~PF_EVTRET; + __ipipe_dispatch_event(IPIPE_EVENT_RETURN, regs); + } + if (this_domain == ipipe_root_domain) { set_thread_flag(TIF_IRQ_SYNC); if (!s) { diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 9f251406a76..8bce5ed031e 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -40,6 +40,10 @@ */ struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); +#ifdef CONFIG_ICACHE_FLUSH_L1 +unsigned long blackfin_iflush_l1_entry[NR_CPUS]; +#endif + void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb, *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb, *init_saved_dcplb_fault_addr_coreb; @@ -108,6 +112,19 @@ static void ipi_flush_icache(void *info) blackfin_dcache_invalidate_range((unsigned long)fdata, (unsigned long)fdata + sizeof(*fdata)); + /* Make sure all write buffers in the data side of the core + * are flushed before trying to invalidate the icache. This + * needs to be after the data flush and before the icache + * flush so that the SSYNC does the right thing in preventing + * the instruction prefetcher from hitting things in cached + * memory at the wrong time -- it runs much further ahead than + * the pipeline. + */ + SSYNC(); + + /* ipi_flaush_icache is invoked by generic flush_icache_range, + * so call blackfin arch icache flush directly here. + */ blackfin_icache_flush_range(fdata->start, fdata->end); } @@ -244,12 +261,13 @@ int smp_call_function(void (*func)(void *info), void *info, int wait) { cpumask_t callmap; + preempt_disable(); callmap = cpu_online_map; cpu_clear(smp_processor_id(), callmap); - if (cpus_empty(callmap)) - return 0; + if (!cpus_empty(callmap)) + smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait); - smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait); + preempt_enable(); return 0; } @@ -286,12 +304,13 @@ void smp_send_stop(void) { cpumask_t callmap; + preempt_disable(); callmap = cpu_online_map; cpu_clear(smp_processor_id(), callmap); - if (cpus_empty(callmap)) - return; + if (!cpus_empty(callmap)) + smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0); - smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0); + preempt_enable(); return; } @@ -361,8 +380,6 @@ void __cpuinit secondary_start_kernel(void) */ init_exception_vectors(); - bfin_setup_caches(cpu); - local_irq_disable(); /* Attach the new idle task to the global mm. */ @@ -381,6 +398,8 @@ void __cpuinit secondary_start_kernel(void) local_irq_enable(); + bfin_setup_caches(cpu); + /* * Calibrate loops per jiffy value. * IRQs need to be enabled here - D-cache can be invalidated |