diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-04 19:22:33 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-04 19:22:33 -0800 |
commit | 15a4cb9c25df05a5d4844e80a1aea83d66165868 (patch) | |
tree | bcb4f7c6e84f501ee6ce8c7a740cc7c4ec92447d /arch/powerpc/kernel/irq.c | |
parent | ff51a98799931256b555446b2f5675db08de6229 (diff) | |
parent | d8594d639135b500bf6010f981ea854092d54030 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc
* master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc: (194 commits)
[POWERPC] Add missing EXPORTS for mpc52xx support
[POWERPC] Remove obsolete PPC_52xx and update CLASSIC32 comment
[POWERPC] ps3: add a default zImage target
[POWERPC] Add of_platform_bus support to mpc52xx psc uart driver
[POWERPC] typo fix and whitespace cleanup on mpc52xx-uart driver
[POWERPC] Fix debug printks for 32-bit resources in the PCI code
[POWERPC] Replace kmalloc+memset with kzalloc
[POWERPC] Linkstation / kurobox support
[POWERPC] Add the e300c3 core to the CPU table.
[POWERPC] ppc: m48t35 add missing bracket
[POWERPC] iSeries: don't build head_64.o unnecessarily
[POWERPC] iSeries: stop dt_mod.o being rebuilt unnecessarily
[POWERPC] Fix cputable.h for combined build
[POWERPC] Allow CONFIG_BOOTX_TEXT on iSeries
[POWERPC] Allow xmon to build on legacy iSeries
[POWERPC] Change ppc64_defconfig to use AUTOFS_V4 not V3
[POWERPC] Tell firmware we can handle POWER6 compatible mode
[POWERPC] Clean images in arch/powerpc/boot
[POWERPC] Fix OF pci flags parsing
[POWERPC] defconfig for lite5200 board
...
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
-rw-r--r-- | arch/powerpc/kernel/irq.c | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5e37bf14ef2..0bd8c766583 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -64,8 +64,9 @@ #include <asm/ptrace.h> #include <asm/machdep.h> #include <asm/udbg.h> -#ifdef CONFIG_PPC_ISERIES +#ifdef CONFIG_PPC64 #include <asm/paca.h> +#include <asm/firmware.h> #endif int __irq_offset_value; @@ -95,6 +96,74 @@ extern atomic_t ipi_sent; EXPORT_SYMBOL(irq_desc); int distribute_irqs = 1; + +static inline unsigned long get_hard_enabled(void) +{ + unsigned long enabled; + + __asm__ __volatile__("lbz %0,%1(13)" + : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); + + return enabled; +} + +static inline void set_soft_enabled(unsigned long enable) +{ + __asm__ __volatile__("stb %0,%1(13)" + : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); +} + +void local_irq_restore(unsigned long en) +{ + /* + * get_paca()->soft_enabled = en; + * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1? + * That was allowed before, and in such a case we do need to take care + * that gcc will set soft_enabled directly via r13, not choose to use + * an intermediate register, lest we're preempted to a different cpu. + */ + set_soft_enabled(en); + if (!en) + return; + + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + /* + * Do we need to disable preemption here? Not really: in the + * unlikely event that we're preempted to a different cpu in + * between getting r13, loading its lppaca_ptr, and loading + * its any_int, we might call iseries_handle_interrupts without + * an interrupt pending on the new cpu, but that's no disaster, + * is it? And the business of preempting us off the old cpu + * would itself involve a local_irq_restore which handles the + * interrupt to that cpu. + * + * But use "local_paca->lppaca_ptr" instead of "get_lppaca()" + * to avoid any preemption checking added into get_paca(). + */ + if (local_paca->lppaca_ptr->int_dword.any_int) + iseries_handle_interrupts(); + return; + } + + /* + * if (get_paca()->hard_enabled) return; + * But again we need to take care that gcc gets hard_enabled directly + * via r13, not choose to use an intermediate register, lest we're + * preempted to a different cpu in between the two instructions. + */ + if (get_hard_enabled()) + return; + + /* + * Need to hard-enable interrupts here. Since currently disabled, + * no need to take further asm precautions against preemption; but + * use local_paca instead of get_paca() to avoid preemption checking. + */ + local_paca->hard_enabled = en; + if ((int)mfspr(SPRN_DEC) < 0) + mtspr(SPRN_DEC, 1); + hard_irq_enable(); +} #endif /* CONFIG_PPC64 */ int show_interrupts(struct seq_file *p, void *v) @@ -246,7 +315,8 @@ void do_IRQ(struct pt_regs *regs) set_irq_regs(old_regs); #ifdef CONFIG_PPC_ISERIES - if (get_lppaca()->int_dword.fields.decr_int) { + if (firmware_has_feature(FW_FEATURE_ISERIES) && + get_lppaca()->int_dword.fields.decr_int) { get_lppaca()->int_dword.fields.decr_int = 0; /* Signal a fake decrementer interrupt */ timer_interrupt(regs); @@ -626,10 +696,14 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); void irq_dispose_mapping(unsigned int virq) { - struct irq_host *host = irq_map[virq].host; + struct irq_host *host; irq_hw_number_t hwirq; unsigned long flags; + if (virq == NO_IRQ) + return; + + host = irq_map[virq].host; WARN_ON (host == NULL); if (host == NULL) return; |