diff --git a/[refs] b/[refs] index f212a3e1fd2f..73c5bf157eb0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d81f087f1f1c1aacdb4f17224a554237285ddd11 +refs/heads/master: 21dccddf45aae2d9f973696ce06115da0d1012b6 diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index 63a027c9ada5..e560d102215a 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -25,10 +25,6 @@ config SPARC select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select HAVE_ARCH_JUMP_LABEL - select HAVE_GENERIC_HARDIRQS - select GENERIC_HARDIRQS_NO_DEPRECATED - select GENERIC_IRQ_SHOW - select USE_GENERIC_SMP_HELPERS if SMP config SPARC32 def_bool !64BIT @@ -47,12 +43,15 @@ config SPARC64 select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD select HAVE_SYSCALL_TRACEPOINTS + select USE_GENERIC_SMP_HELPERS if SMP select RTC_DRV_CMOS select RTC_DRV_BQ4802 select RTC_DRV_SUN4V select RTC_DRV_STARFIRE select HAVE_PERF_EVENTS select PERF_USE_VMALLOC + select HAVE_GENERIC_HARDIRQS + select GENERIC_IRQ_SHOW select IRQ_PREFLOW_FASTEOI config ARCH_DEFCONFIG diff --git a/trunk/arch/sparc/include/asm/cpudata_32.h b/trunk/arch/sparc/include/asm/cpudata_32.h index a4c5a938b936..31d48a0e32c7 100644 --- a/trunk/arch/sparc/include/asm/cpudata_32.h +++ b/trunk/arch/sparc/include/asm/cpudata_32.h @@ -16,10 +16,6 @@ typedef struct { unsigned long clock_tick; unsigned int multiplier; unsigned int counter; -#ifdef CONFIG_SMP - unsigned int irq_resched_count; - unsigned int irq_call_count; -#endif int prom_node; int mid; int next; @@ -27,6 +23,5 @@ typedef struct { DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); #define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu)) -#define local_cpu_data() __get_cpu_var(__cpu_data) #endif /* _SPARC_CPUDATA_H */ diff --git a/trunk/arch/sparc/include/asm/floppy_32.h b/trunk/arch/sparc/include/asm/floppy_32.h index 482c79e2a416..86666f70322e 100644 --- a/trunk/arch/sparc/include/asm/floppy_32.h +++ b/trunk/arch/sparc/include/asm/floppy_32.h @@ -281,27 +281,28 @@ static inline void sun_fd_enable_dma(void) pdma_areasize = pdma_size; } -extern int sparc_floppy_request_irq(unsigned int irq, - irq_handler_t irq_handler); +/* Our low-level entry point in arch/sparc/kernel/entry.S */ +extern int sparc_floppy_request_irq(int irq, unsigned long flags, + irq_handler_t irq_handler); static int sun_fd_request_irq(void) { static int once = 0; + int error; - if (!once) { + if(!once) { once = 1; - return sparc_floppy_request_irq(FLOPPY_IRQ, floppy_interrupt); - } else { - return 0; - } + error = sparc_floppy_request_irq(FLOPPY_IRQ, + IRQF_DISABLED, + floppy_interrupt); + return ((error == 0) ? 0 : -1); + } else return 0; } static struct linux_prom_registers fd_regs[2]; static int sun_floppy_init(void) { - struct platform_device *op; - struct device_node *dp; char state[128]; phandle tnode, fd_node; int num_regs; @@ -309,6 +310,7 @@ static int sun_floppy_init(void) use_virtual_dma = 1; + FLOPPY_IRQ = 11; /* Forget it if we aren't on a machine that could possibly * ever have a floppy drive. */ @@ -347,26 +349,6 @@ static int sun_floppy_init(void) sun_fdc = (struct sun_flpy_controller *) of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); - /* Look up irq in platform_device. - * We try "SUNW,fdtwo" and "fd" - */ - for_each_node_by_name(dp, "SUNW,fdtwo") { - op = of_find_device_by_node(dp); - if (op) - break; - } - if (!op) { - for_each_node_by_name(dp, "fd") { - op = of_find_device_by_node(dp); - if (op) - break; - } - } - if (!op) - goto no_sun_fdc; - - FLOPPY_IRQ = op->archdata.irqs[0]; - /* Last minute sanity check... */ if(sun_fdc->status_82072 == 0xff) { sun_fdc = NULL; diff --git a/trunk/arch/sparc/include/asm/io.h b/trunk/arch/sparc/include/asm/io.h index a34b2994937a..f6902cf3cbe9 100644 --- a/trunk/arch/sparc/include/asm/io.h +++ b/trunk/arch/sparc/include/asm/io.h @@ -5,4 +5,17 @@ #else #include #endif + +/* + * Defines used for both SPARC32 and SPARC64 + */ + +/* Big endian versions of memory read/write routines */ +#define readb_be(__addr) __raw_readb(__addr) +#define readw_be(__addr) __raw_readw(__addr) +#define readl_be(__addr) __raw_readl(__addr) +#define writeb_be(__b, __addr) __raw_writeb(__b, __addr) +#define writel_be(__w, __addr) __raw_writel(__w, __addr) +#define writew_be(__l, __addr) __raw_writew(__l, __addr) + #endif diff --git a/trunk/arch/sparc/include/asm/irq_32.h b/trunk/arch/sparc/include/asm/irq_32.h index 2ae3acaeb1b3..eced3e3ebd30 100644 --- a/trunk/arch/sparc/include/asm/irq_32.h +++ b/trunk/arch/sparc/include/asm/irq_32.h @@ -6,11 +6,7 @@ #ifndef _SPARC_IRQ_H #define _SPARC_IRQ_H -/* Allocated number of logical irq numbers. - * sun4d boxes (ss2000e) should be OK with ~32. - * Be on the safe side and make room for 64 - */ -#define NR_IRQS 64 +#define NR_IRQS 16 #include diff --git a/trunk/arch/sparc/include/asm/leon.h b/trunk/arch/sparc/include/asm/leon.h index 6bdaf1e43d2a..c04f96fb753c 100644 --- a/trunk/arch/sparc/include/asm/leon.h +++ b/trunk/arch/sparc/include/asm/leon.h @@ -52,6 +52,29 @@ #define LEON_DIAGF_VALID 0x2000 #define LEON_DIAGF_VALID_SHIFT 13 +/* + * Interrupt Sources + * + * The interrupt source numbers directly map to the trap type and to + * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask, + * and the Interrupt Pending Registers. + */ +#define LEON_INTERRUPT_CORRECTABLE_MEMORY_ERROR 1 +#define LEON_INTERRUPT_UART_1_RX_TX 2 +#define LEON_INTERRUPT_UART_0_RX_TX 3 +#define LEON_INTERRUPT_EXTERNAL_0 4 +#define LEON_INTERRUPT_EXTERNAL_1 5 +#define LEON_INTERRUPT_EXTERNAL_2 6 +#define LEON_INTERRUPT_EXTERNAL_3 7 +#define LEON_INTERRUPT_TIMER1 8 +#define LEON_INTERRUPT_TIMER2 9 +#define LEON_INTERRUPT_EMPTY1 10 +#define LEON_INTERRUPT_EMPTY2 11 +#define LEON_INTERRUPT_OPEN_ETH 12 +#define LEON_INTERRUPT_EMPTY4 13 +#define LEON_INTERRUPT_EMPTY5 14 +#define LEON_INTERRUPT_EMPTY6 15 + /* irq masks */ #define LEON_HARD_INT(x) (1 << (x)) /* irq 0-15 */ #define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */ @@ -160,6 +183,7 @@ static inline void leon_srmmu_enabletlb(void) /* macro access for leon_readnobuffer_reg() */ #define LEON_BYPASSCACHE_LOAD_VA(x) leon_readnobuffer_reg((unsigned long)(x)) +extern void sparc_leon_eirq_register(int eirq); extern void leon_init(void); extern void leon_switch_mm(void); extern void leon_init_IRQ(void); @@ -215,8 +239,8 @@ static inline int sparc_leon3_cpuid(void) #endif /*!__ASSEMBLY__*/ #ifdef CONFIG_SMP -# define LEON3_IRQ_IPI_DEFAULT 13 -# define LEON3_IRQ_TICKER (leon3_ticker_irq) +# define LEON3_IRQ_RESCHEDULE 13 +# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq) # define LEON3_IRQ_CROSS_CALL 15 #endif @@ -315,9 +339,9 @@ struct leon2_cacheregs { #include struct device_node; -extern unsigned int leon_build_device_irq(unsigned int real_irq, - irq_flow_handler_t flow_handler, - const char *name, int do_ack); +extern int sparc_leon_eirq_get(int eirq, int cpu); +extern irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id); +extern void sparc_leon_eirq_register(int eirq); extern void leon_clear_clock_irq(void); extern void leon_load_profile_irq(int cpu, unsigned int limit); extern void leon_init_timers(irq_handler_t counter_fn); @@ -334,7 +358,6 @@ extern void leon3_getCacheRegs(struct leon3_cacheregs *regs); extern int leon_flush_needed(void); extern void leon_switch_mm(void); extern int srmmu_swprobe_trace; -extern int leon3_ticker_irq; #ifdef CONFIG_SMP extern int leon_smp_nrcpus(void); @@ -343,19 +366,17 @@ extern void leon_smp_done(void); extern void leon_boot_cpus(void); extern int leon_boot_one_cpu(int i); void leon_init_smp(void); +extern void cpu_probe(void); extern void cpu_idle(void); extern void init_IRQ(void); extern void cpu_panic(void); extern int __leon_processor_id(void); void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu); -extern irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused); -extern unsigned int real_irq_entry[]; -extern unsigned int smpleon_ipi[]; +extern unsigned int real_irq_entry[], smpleon_ticker[]; extern unsigned int patchme_maybe_smp_msg[]; extern unsigned int t_nmi[], linux_trap_ipi15_leon[]; extern unsigned int linux_trap_ipi15_sun4m[]; -extern int leon_ipi_irq; #endif /* CONFIG_SMP */ diff --git a/trunk/arch/sparc/include/asm/pcic.h b/trunk/arch/sparc/include/asm/pcic.h index 7eb5d78f5211..f20ef562b265 100644 --- a/trunk/arch/sparc/include/asm/pcic.h +++ b/trunk/arch/sparc/include/asm/pcic.h @@ -29,17 +29,11 @@ struct linux_pcic { int pcic_imdim; }; -#ifdef CONFIG_PCI -extern int pcic_present(void); extern int pcic_probe(void); -extern void pci_time_init(void); +/* Erm... MJ redefined pcibios_present() so that it does not work early. */ +extern int pcic_present(void); extern void sun4m_pci_init_IRQ(void); -#else -static inline int pcic_present(void) { return 0; } -static inline int pcic_probe(void) { return 0; } -static inline void pci_time_init(void) {} -static inline void sun4m_pci_init_IRQ(void) {} -#endif + #endif /* Size of PCI I/O space which we relocate. */ diff --git a/trunk/arch/sparc/include/asm/pgtable_32.h b/trunk/arch/sparc/include/asm/pgtable_32.h index 5b31a8e89823..303bd4dc8292 100644 --- a/trunk/arch/sparc/include/asm/pgtable_32.h +++ b/trunk/arch/sparc/include/asm/pgtable_32.h @@ -8,8 +8,6 @@ * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#include - #ifndef __ASSEMBLY__ #include @@ -458,9 +456,9 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, #endif /* !(__ASSEMBLY__) */ -#define VMALLOC_START _AC(0xfe600000,UL) +#define VMALLOC_START 0xfe600000 /* XXX Alter this when I get around to fixing sun4c - Anton */ -#define VMALLOC_END _AC(0xffc00000,UL) +#define VMALLOC_END 0xffc00000 /* We provide our own get_unmapped_area to cope with VA holes for userland */ diff --git a/trunk/arch/sparc/include/asm/pgtable_64.h b/trunk/arch/sparc/include/asm/pgtable_64.h index b77128c80524..f8dddb7045bb 100644 --- a/trunk/arch/sparc/include/asm/pgtable_64.h +++ b/trunk/arch/sparc/include/asm/pgtable_64.h @@ -699,9 +699,6 @@ extern pmd_t swapper_low_pmd_dir[2048]; extern void paging_init(void); extern unsigned long find_ecache_flush_span(unsigned long size); -struct seq_file; -extern void mmu_info(struct seq_file *); - /* These do nothing with the way I have things setup. */ #define mmu_lockarea(vaddr, len) (vaddr) #define mmu_unlockarea(vaddr, len) do { } while(0) diff --git a/trunk/arch/sparc/include/asm/setup.h b/trunk/arch/sparc/include/asm/setup.h index 64718ba26434..2643c62f4ac0 100644 --- a/trunk/arch/sparc/include/asm/setup.h +++ b/trunk/arch/sparc/include/asm/setup.h @@ -11,16 +11,4 @@ # define COMMAND_LINE_SIZE 256 #endif -#ifdef __KERNEL__ - -#ifdef CONFIG_SPARC32 -/* The CPU that was used for booting - * Only sun4d + leon may have boot_cpu_id != 0 - */ -extern unsigned char boot_cpu_id; -extern unsigned char boot_cpu_id4; -#endif - -#endif /* __KERNEL__ */ - #endif /* _SPARC_SETUP_H */ diff --git a/trunk/arch/sparc/include/asm/smp_32.h b/trunk/arch/sparc/include/asm/smp_32.h index 093f10843ff2..d82d7f4c0a79 100644 --- a/trunk/arch/sparc/include/asm/smp_32.h +++ b/trunk/arch/sparc/include/asm/smp_32.h @@ -50,38 +50,42 @@ void smp_callin(void); void smp_boot_cpus(void); void smp_store_cpu_info(int); -void smp_resched_interrupt(void); -void smp_call_function_single_interrupt(void); -void smp_call_function_interrupt(void); - struct seq_file; void smp_bogo(struct seq_file *); void smp_info(struct seq_file *); BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, cpumask_t, unsigned long, unsigned long, unsigned long, unsigned long) BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void) -BTFIXUPDEF_CALL(void, smp_ipi_resched, int); -BTFIXUPDEF_CALL(void, smp_ipi_single, int); -BTFIXUPDEF_CALL(void, smp_ipi_mask_one, int); BTFIXUPDEF_BLACKBOX(hard_smp_processor_id) BTFIXUPDEF_BLACKBOX(load_current) #define smp_cross_call(func,mask,arg1,arg2,arg3,arg4) BTFIXUP_CALL(smp_cross_call)(func,mask,arg1,arg2,arg3,arg4) -static inline void xc0(smpfunc_t func) { smp_cross_call(func, *cpu_online_mask, 0, 0, 0, 0); } +static inline void xc0(smpfunc_t func) { smp_cross_call(func, cpu_online_map, 0, 0, 0, 0); } static inline void xc1(smpfunc_t func, unsigned long arg1) -{ smp_cross_call(func, *cpu_online_mask, arg1, 0, 0, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, 0, 0, 0); } static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2) -{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, 0, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, 0, 0); } static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3) -{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, 0); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, 0); } static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) -{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, arg4); } +{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, arg4); } + +static inline int smp_call_function(void (*func)(void *info), void *info, int wait) +{ + xc1((smpfunc_t)func, (unsigned long)info); + return 0; +} -extern void arch_send_call_function_single_ipi(int cpu); -extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); +static inline int smp_call_function_single(int cpuid, void (*func) (void *info), + void *info, int wait) +{ + smp_cross_call((smpfunc_t)func, cpumask_of_cpu(cpuid), + (unsigned long) info, 0, 0, 0); + return 0; +} static inline int cpu_logical_map(int cpu) { @@ -131,11 +135,6 @@ static inline int hard_smp_processor_id(void) __asm__ __volatile__("lda [%g0] ASI_M_VIKING_TMP1, %0\n\t" "nop; nop" : "=&r" (cpuid)); - - leon - __asm__ __volatile__( "rd %asr17, %0\n\t" - "srl %0, 0x1c, %0\n\t" - "nop\n\t" : - "=&r" (cpuid)); See btfixup.h and btfixupprep.c to understand how a blackbox works. */ __asm__ __volatile__("sethi %%hi(___b_hard_smp_processor_id), %0\n\t" diff --git a/trunk/arch/sparc/include/asm/smp_64.h b/trunk/arch/sparc/include/asm/smp_64.h index 20bca8950710..f49e11cd4ded 100644 --- a/trunk/arch/sparc/include/asm/smp_64.h +++ b/trunk/arch/sparc/include/asm/smp_64.h @@ -49,10 +49,6 @@ extern void cpu_play_dead(void); extern void smp_fetch_global_regs(void); -struct seq_file; -void smp_bogo(struct seq_file *); -void smp_info(struct seq_file *); - #ifdef CONFIG_HOTPLUG_CPU extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); diff --git a/trunk/arch/sparc/include/asm/system_32.h b/trunk/arch/sparc/include/asm/system_32.h index 47a7e862474e..890036b3689a 100644 --- a/trunk/arch/sparc/include/asm/system_32.h +++ b/trunk/arch/sparc/include/asm/system_32.h @@ -15,6 +15,11 @@ #include +static inline unsigned int probe_irq_mask(unsigned long val) +{ + return 0; +} + /* * Sparc (general) CPU types */ diff --git a/trunk/arch/sparc/include/asm/system_64.h b/trunk/arch/sparc/include/asm/system_64.h index 3c96d3bb9f15..e3b65d8cf41b 100644 --- a/trunk/arch/sparc/include/asm/system_64.h +++ b/trunk/arch/sparc/include/asm/system_64.h @@ -29,6 +29,10 @@ enum sparc_cpu { /* This cannot ever be a sun4c :) That's just history. */ #define ARCH_SUN4C 0 +extern const char *sparc_cpu_type; +extern const char *sparc_fpu_type; +extern const char *sparc_pmu_type; + extern char reboot_command[]; /* These are here in an effort to more fully work around Spitfire Errata diff --git a/trunk/arch/sparc/include/asm/winmacro.h b/trunk/arch/sparc/include/asm/winmacro.h index a9be04b0d049..5b0a06dc3bcb 100644 --- a/trunk/arch/sparc/include/asm/winmacro.h +++ b/trunk/arch/sparc/include/asm/winmacro.h @@ -103,7 +103,6 @@ st %scratch, [%cur_reg + TI_W_SAVED]; #ifdef CONFIG_SMP -/* Results of LOAD_CURRENT() after BTFIXUP for SUN4M, SUN4D & LEON (comments) */ #define LOAD_CURRENT4M(dest_reg, idreg) \ rd %tbr, %idreg; \ sethi %hi(current_set), %dest_reg; \ @@ -119,14 +118,6 @@ or %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \ ld [%idreg + %dest_reg], %dest_reg; -#define LOAD_CURRENT_LEON(dest_reg, idreg) \ - rd %asr17, %idreg; \ - sethi %hi(current_set), %dest_reg; \ - srl %idreg, 0x1c, %idreg; \ - or %dest_reg, %lo(current_set), %dest_reg; \ - sll %idreg, 0x2, %idreg; \ - ld [%idreg + %dest_reg], %dest_reg; - /* Blackbox - take care with this... - check smp4m and smp4d before changing this. */ #define LOAD_CURRENT(dest_reg, idreg) \ sethi %hi(___b_load_current), %idreg; \ diff --git a/trunk/arch/sparc/kernel/Makefile b/trunk/arch/sparc/kernel/Makefile index 9cff2709a96d..99aa4db6e9c2 100644 --- a/trunk/arch/sparc/kernel/Makefile +++ b/trunk/arch/sparc/kernel/Makefile @@ -71,6 +71,10 @@ obj-$(CONFIG_SPARC64) += pcr.o obj-$(CONFIG_SPARC64) += nmi.o obj-$(CONFIG_SPARC64_SMP) += cpumap.o +# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation +obj-$(CONFIG_SPARC32) += devres.o +devres-y := ../../../kernel/irq/devres.o + obj-y += dma.o obj-$(CONFIG_SPARC32_PCI) += pcic.o diff --git a/trunk/arch/sparc/kernel/apc.c b/trunk/arch/sparc/kernel/apc.c index f679c57644d5..1e34f29e58bb 100644 --- a/trunk/arch/sparc/kernel/apc.c +++ b/trunk/arch/sparc/kernel/apc.c @@ -165,7 +165,7 @@ static int __devinit apc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata apc_match[] = { +static struct of_device_id apc_match[] = { { .name = APC_OBPNAME, }, diff --git a/trunk/arch/sparc/kernel/cpu.c b/trunk/arch/sparc/kernel/cpu.c index 138dbbc8dc84..7925c54f4133 100644 --- a/trunk/arch/sparc/kernel/cpu.c +++ b/trunk/arch/sparc/kernel/cpu.c @@ -4,7 +4,6 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ -#include #include #include #include @@ -12,9 +11,7 @@ #include #include -#include #include -#include #include #include #include @@ -26,9 +23,6 @@ DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 }; EXPORT_PER_CPU_SYMBOL(__cpu_data); -int ncpus_probed; -unsigned int fsr_storage; - struct cpu_info { int psr_vers; const char *name; @@ -253,12 +247,13 @@ static const struct manufacturer_info __initconst manufacturer_info[] = { * machine type value into consideration too. I will fix this. */ -static const char *sparc_cpu_type; -static const char *sparc_fpu_type; +const char *sparc_cpu_type; +const char *sparc_fpu_type; const char *sparc_pmu_type; +unsigned int fsr_storage; -static void __init set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers) +static void set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers) { const struct manufacturer_info *manuf; int i; @@ -318,123 +313,7 @@ static void __init set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers) } #ifdef CONFIG_SPARC32 -static int show_cpuinfo(struct seq_file *m, void *__unused) -{ - seq_printf(m, - "cpu\t\t: %s\n" - "fpu\t\t: %s\n" - "promlib\t\t: Version %d Revision %d\n" - "prom\t\t: %d.%d\n" - "type\t\t: %s\n" - "ncpus probed\t: %d\n" - "ncpus active\t: %d\n" -#ifndef CONFIG_SMP - "CPU0Bogo\t: %lu.%02lu\n" - "CPU0ClkTck\t: %ld\n" -#endif - , - sparc_cpu_type, - sparc_fpu_type , - romvec->pv_romvers, - prom_rev, - romvec->pv_printrev >> 16, - romvec->pv_printrev & 0xffff, - &cputypval[0], - ncpus_probed, - num_online_cpus() -#ifndef CONFIG_SMP - , cpu_data(0).udelay_val/(500000/HZ), - (cpu_data(0).udelay_val/(5000/HZ)) % 100, - cpu_data(0).clock_tick -#endif - ); - -#ifdef CONFIG_SMP - smp_bogo(m); -#endif - mmu_info(m); -#ifdef CONFIG_SMP - smp_info(m); -#endif - return 0; -} -#endif /* CONFIG_SPARC32 */ - -#ifdef CONFIG_SPARC64 -unsigned int dcache_parity_tl1_occurred; -unsigned int icache_parity_tl1_occurred; - - -static int show_cpuinfo(struct seq_file *m, void *__unused) -{ - seq_printf(m, - "cpu\t\t: %s\n" - "fpu\t\t: %s\n" - "pmu\t\t: %s\n" - "prom\t\t: %s\n" - "type\t\t: %s\n" - "ncpus probed\t: %d\n" - "ncpus active\t: %d\n" - "D$ parity tl1\t: %u\n" - "I$ parity tl1\t: %u\n" -#ifndef CONFIG_SMP - "Cpu0ClkTck\t: %016lx\n" -#endif - , - sparc_cpu_type, - sparc_fpu_type, - sparc_pmu_type, - prom_version, - ((tlb_type == hypervisor) ? - "sun4v" : - "sun4u"), - ncpus_probed, - num_online_cpus(), - dcache_parity_tl1_occurred, - icache_parity_tl1_occurred -#ifndef CONFIG_SMP - , cpu_data(0).clock_tick -#endif - ); -#ifdef CONFIG_SMP - smp_bogo(m); -#endif - mmu_info(m); -#ifdef CONFIG_SMP - smp_info(m); -#endif - return 0; -} -#endif /* CONFIG_SPARC64 */ - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - /* The pointer we are returning is arbitrary, - * it just has to be non-NULL and not IS_ERR - * in the success case. - */ - return *pos == 0 ? &c_start : NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -const struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -#ifdef CONFIG_SPARC32 -static int __init cpu_type_probe(void) +void __cpuinit cpu_probe(void) { int psr_impl, psr_vers, fpu_vers; int psr; @@ -453,12 +332,8 @@ static int __init cpu_type_probe(void) put_psr(psr); set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers); - - return 0; } -#endif /* CONFIG_SPARC32 */ - -#ifdef CONFIG_SPARC64 +#else static void __init sun4v_cpu_probe(void) { switch (sun4v_chip_type) { @@ -499,6 +374,6 @@ static int __init cpu_type_probe(void) } return 0; } -#endif /* CONFIG_SPARC64 */ early_initcall(cpu_type_probe); +#endif diff --git a/trunk/arch/sparc/kernel/cpumap.c b/trunk/arch/sparc/kernel/cpumap.c index d91fd782743a..8de64c8126bc 100644 --- a/trunk/arch/sparc/kernel/cpumap.c +++ b/trunk/arch/sparc/kernel/cpumap.c @@ -202,7 +202,7 @@ static struct cpuinfo_tree *build_cpuinfo_tree(void) new_tree->total_nodes = n; memcpy(&new_tree->level, tmp_level, sizeof(tmp_level)); - prev_cpu = cpu = cpumask_first(cpu_online_mask); + prev_cpu = cpu = first_cpu(cpu_online_map); /* Initialize all levels in the tree with the first CPU */ for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) { @@ -381,7 +381,7 @@ static int simple_map_to_cpu(unsigned int index) } /* Impossible, since num_online_cpus() <= num_possible_cpus() */ - return cpumask_first(cpu_online_mask); + return first_cpu(cpu_online_map); } static int _map_to_cpu(unsigned int index) diff --git a/trunk/arch/sparc/kernel/devices.c b/trunk/arch/sparc/kernel/devices.c index 113c052c3043..d2eddd6647cd 100644 --- a/trunk/arch/sparc/kernel/devices.c +++ b/trunk/arch/sparc/kernel/devices.c @@ -20,6 +20,7 @@ #include #include +extern void cpu_probe(void); extern void clock_stop_probe(void); /* tadpole.c */ extern void sun4c_probe_memerr_reg(void); @@ -114,7 +115,7 @@ int cpu_get_hwmid(phandle prom_node) void __init device_scan(void) { - printk(KERN_NOTICE "Booting Linux...\n"); + prom_printf("Booting Linux...\n"); #ifndef CONFIG_SMP { @@ -132,6 +133,7 @@ void __init device_scan(void) } #endif /* !CONFIG_SMP */ + cpu_probe(); { extern void auxio_probe(void); extern void auxio_power_probe(void); diff --git a/trunk/arch/sparc/kernel/ds.c b/trunk/arch/sparc/kernel/ds.c index dd1342c0a3be..3add4de8a1a9 100644 --- a/trunk/arch/sparc/kernel/ds.c +++ b/trunk/arch/sparc/kernel/ds.c @@ -497,7 +497,7 @@ static void dr_cpu_init_response(struct ds_data *resp, u64 req_num, tag->num_records = ncpus; i = 0; - for_each_cpu(cpu, mask) { + for_each_cpu_mask(cpu, *mask) { ent[i].cpu = cpu; ent[i].result = DR_CPU_RES_OK; ent[i].stat = default_stat; @@ -534,7 +534,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp, int resp_len, ncpus, cpu; unsigned long flags; - ncpus = cpumask_weight(mask); + ncpus = cpus_weight(*mask); resp_len = dr_cpu_size_response(ncpus); resp = kzalloc(resp_len, GFP_KERNEL); if (!resp) @@ -547,7 +547,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp, mdesc_populate_present_mask(mask); mdesc_fill_in_cpu_data(mask); - for_each_cpu(cpu, mask) { + for_each_cpu_mask(cpu, *mask) { int err; printk(KERN_INFO "ds-%llu: Starting cpu %d...\n", @@ -593,7 +593,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp, int resp_len, ncpus, cpu; unsigned long flags; - ncpus = cpumask_weight(mask); + ncpus = cpus_weight(*mask); resp_len = dr_cpu_size_response(ncpus); resp = kzalloc(resp_len, GFP_KERNEL); if (!resp) @@ -603,7 +603,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp, resp_len, ncpus, mask, DR_CPU_STAT_UNCONFIGURED); - for_each_cpu(cpu, mask) { + for_each_cpu_mask(cpu, *mask) { int err; printk(KERN_INFO "ds-%llu: Shutting down cpu %d...\n", @@ -649,13 +649,13 @@ static void __cpuinit dr_cpu_data(struct ds_info *dp, purge_dups(cpu_list, tag->num_records); - cpumask_clear(&mask); + cpus_clear(mask); for (i = 0; i < tag->num_records; i++) { if (cpu_list[i] == CPU_SENTINEL) continue; if (cpu_list[i] < nr_cpu_ids) - cpumask_set_cpu(cpu_list[i], &mask); + cpu_set(cpu_list[i], mask); } if (tag->type == DR_CPU_CONFIGURE) diff --git a/trunk/arch/sparc/kernel/entry.S b/trunk/arch/sparc/kernel/entry.S index 8341963f4c84..6da784a5612b 100644 --- a/trunk/arch/sparc/kernel/entry.S +++ b/trunk/arch/sparc/kernel/entry.S @@ -269,22 +269,19 @@ smp4m_ticker: /* Here is where we check for possible SMP IPI passed to us * on some level other than 15 which is the NMI and only used * for cross calls. That has a separate entry point below. - * - * IPIs are sent on Level 12, 13 and 14. See IRQ_IPI_*. */ maybe_smp4m_msg: GET_PROCESSOR4M_ID(o3) sethi %hi(sun4m_irq_percpu), %l5 sll %o3, 2, %o3 or %l5, %lo(sun4m_irq_percpu), %o5 - sethi %hi(0x70000000), %o2 ! Check all soft-IRQs + sethi %hi(0x40000000), %o2 ld [%o5 + %o3], %o1 ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending andcc %o3, %o2, %g0 be,a smp4m_ticker cmp %l7, 14 - /* Soft-IRQ IPI */ - st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x70000000 + st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000 WRITE_PAUSE ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending WRITE_PAUSE @@ -293,27 +290,9 @@ maybe_smp4m_msg: WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE - sll %o2, 28, %o2 ! shift for simpler checks below -maybe_smp4m_msg_check_single: - andcc %o2, 0x1, %g0 - beq,a maybe_smp4m_msg_check_mask - andcc %o2, 0x2, %g0 - call smp_call_function_single_interrupt - nop - andcc %o2, 0x2, %g0 -maybe_smp4m_msg_check_mask: - beq,a maybe_smp4m_msg_check_resched - andcc %o2, 0x4, %g0 - call smp_call_function_interrupt - nop - andcc %o2, 0x4, %g0 -maybe_smp4m_msg_check_resched: - /* rescheduling is done in RESTORE_ALL regardless, but incr stats */ - beq,a maybe_smp4m_msg_out - nop - call smp_resched_interrupt + call smp_reschedule_irq nop -maybe_smp4m_msg_out: + RESTORE_ALL .align 4 @@ -422,18 +401,18 @@ linux_trap_ipi15_sun4d: 1: b,a 1b #ifdef CONFIG_SPARC_LEON - .globl smpleon_ipi - .extern leon_ipi_interrupt - /* SMP per-cpu IPI interrupts are handled specially. */ -smpleon_ipi: + + .globl smpleon_ticker + /* SMP per-cpu ticker interrupts are handled specially. */ +smpleon_ticker: SAVE_ALL or %l0, PSR_PIL, %g2 wr %g2, 0x0, %psr WRITE_PAUSE wr %g2, PSR_ET, %psr WRITE_PAUSE - call leonsmp_ipi_interrupt - add %sp, STACKFRAME_SZ, %o1 ! pt_regs + call leon_percpu_timer_interrupt + add %sp, STACKFRAME_SZ, %o0 wr %l0, PSR_ET, %psr WRITE_PAUSE RESTORE_ALL diff --git a/trunk/arch/sparc/kernel/head_32.S b/trunk/arch/sparc/kernel/head_32.S index 587785759838..59423491cef8 100644 --- a/trunk/arch/sparc/kernel/head_32.S +++ b/trunk/arch/sparc/kernel/head_32.S @@ -810,24 +810,30 @@ found_version: got_prop: #ifdef CONFIG_SPARC_LEON /* no cpu-type check is needed, it is a SPARC-LEON */ - - sethi %hi(boot_cpu_id), %g2 ! boot-cpu index - #ifdef CONFIG_SMP - ldub [%g2 + %lo(boot_cpu_id)], %g1 - cmp %g1, 0xff ! unset means first CPU - bne leon_smp_cpu_startup ! continue only with master + ba leon_smp_init nop -#endif - /* Get CPU-ID from most significant 4-bit of ASR17 */ - rd %asr17, %g1 - srl %g1, 28, %g1 - /* Update boot_cpu_id only on boot cpu */ - stub %g1, [%g2 + %lo(boot_cpu_id)] + .global leon_smp_init +leon_smp_init: + sethi %hi(boot_cpu_id), %g1 ! master always 0 + stb %g0, [%g1 + %lo(boot_cpu_id)] + sethi %hi(boot_cpu_id4), %g1 ! master always 0 + stb %g0, [%g1 + %lo(boot_cpu_id4)] + rd %asr17,%g1 + srl %g1,28,%g1 + + cmp %g0,%g1 + beq sun4c_continue_boot !continue with master + nop + + ba leon_smp_cpu_startup + nop +#else ba sun4c_continue_boot nop +#endif #endif set cputypval, %o2 ldub [%o2 + 0x4], %l1 @@ -887,6 +893,9 @@ sun4d_init: sta %g4, [%g0] ASI_M_VIKING_TMP1 sethi %hi(boot_cpu_id), %g5 stb %g4, [%g5 + %lo(boot_cpu_id)] + sll %g4, 2, %g4 + sethi %hi(boot_cpu_id4), %g5 + stb %g4, [%g5 + %lo(boot_cpu_id4)] #endif /* Fall through to sun4m_init */ @@ -1015,28 +1024,14 @@ sun4c_continue_boot: bl 1b add %o0, 0x1, %o0 - /* If boot_cpu_id has not been setup by machine specific - * init-code above we default it to zero. - */ - sethi %hi(boot_cpu_id), %g2 - ldub [%g2 + %lo(boot_cpu_id)], %g3 - cmp %g3, 0xff - bne 1f - nop - mov %g0, %g3 - stub %g3, [%g2 + %lo(boot_cpu_id)] - -1: /* boot_cpu_id set. calculate boot_cpu_id4 = boot_cpu_id*4 */ - sll %g3, 2, %g3 - sethi %hi(boot_cpu_id4), %g2 - stub %g3, [%g2 + %lo(boot_cpu_id4)] - /* Initialize the uwinmask value for init task just in case. * But first make current_set[boot_cpu_id] point to something useful. */ set init_thread_union, %g6 set current_set, %g2 #ifdef CONFIG_SMP + sethi %hi(boot_cpu_id4), %g3 + ldub [%g3 + %lo(boot_cpu_id4)], %g3 st %g6, [%g2] add %g2, %g3, %g2 #endif diff --git a/trunk/arch/sparc/kernel/ioport.c b/trunk/arch/sparc/kernel/ioport.c index 1c9c80a1a86a..c6ce9a6a4790 100644 --- a/trunk/arch/sparc/kernel/ioport.c +++ b/trunk/arch/sparc/kernel/ioport.c @@ -50,15 +50,10 @@ #include #include -/* This function must make sure that caches and memory are coherent after DMA - * On LEON systems without cache snooping it flushes the entire D-CACHE. - */ #ifndef CONFIG_SPARC_LEON -static inline void dma_make_coherent(unsigned long pa, unsigned long len) -{ -} +#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ #else -static inline void dma_make_coherent(unsigned long pa, unsigned long len) +static inline void mmu_inval_dma_area(void *va, unsigned long len) { if (!sparc_leon3_snooping_enabled()) leon_flush_dcache_all(); @@ -289,6 +284,7 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len, printk("sbus_alloc_consistent: cannot occupy 0x%lx", len_total); goto err_nova; } + mmu_inval_dma_area((void *)va, len_total); // XXX The mmu_map_dma_area does this for us below, see comments. // sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); @@ -340,6 +336,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p, release_resource(res); kfree(res); + /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ pgv = virt_to_page(p); mmu_unmap_dma_area(dev, ba, n); @@ -466,6 +463,7 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len, printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total); goto err_nova; } + mmu_inval_dma_area(va, len_total); sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ @@ -491,6 +489,7 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p, dma_addr_t ba) { struct resource *res; + void *pgp; if ((res = _sparc_find_resource(&_sparc_dvma, (unsigned long)p)) == NULL) { @@ -510,12 +509,14 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p, return; } - dma_make_coherent(ba, n); + pgp = phys_to_virt(ba); /* bus_to_virt actually */ + mmu_inval_dma_area(pgp, n); sparc_unmapiorange((unsigned long)p, n); release_resource(res); kfree(res); - free_pages((unsigned long)phys_to_virt(ba), get_order(n)); + + free_pages((unsigned long)pgp, get_order(n)); } /* @@ -534,7 +535,7 @@ static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { if (dir != PCI_DMA_TODEVICE) - dma_make_coherent(ba, PAGE_ALIGN(size)); + mmu_inval_dma_area(phys_to_virt(ba), PAGE_ALIGN(size)); } /* Map a set of buffers described by scatterlist in streaming @@ -561,7 +562,8 @@ static int pci32_map_sg(struct device *device, struct scatterlist *sgl, /* IIep is write-through, not flushing. */ for_each_sg(sgl, sg, nents, n) { - sg->dma_address = sg_phys(sg); + BUG_ON(page_address(sg_page(sg)) == NULL); + sg->dma_address = virt_to_phys(sg_virt(sg)); sg->dma_length = sg->length; } return nents; @@ -580,7 +582,9 @@ static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl, if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length)); + BUG_ON(page_address(sg_page(sg)) == NULL); + mmu_inval_dma_area(page_address(sg_page(sg)), + PAGE_ALIGN(sg->length)); } } } @@ -599,7 +603,8 @@ static void pci32_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, enum dma_data_direction dir) { if (dir != PCI_DMA_TODEVICE) { - dma_make_coherent(ba, PAGE_ALIGN(size)); + mmu_inval_dma_area(phys_to_virt(ba), + PAGE_ALIGN(size)); } } @@ -607,7 +612,8 @@ static void pci32_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, enum dma_data_direction dir) { if (dir != PCI_DMA_TODEVICE) { - dma_make_coherent(ba, PAGE_ALIGN(size)); + mmu_inval_dma_area(phys_to_virt(ba), + PAGE_ALIGN(size)); } } @@ -625,7 +631,9 @@ static void pci32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length)); + BUG_ON(page_address(sg_page(sg)) == NULL); + mmu_inval_dma_area(page_address(sg_page(sg)), + PAGE_ALIGN(sg->length)); } } } @@ -638,7 +646,9 @@ static void pci32_sync_sg_for_device(struct device *device, struct scatterlist * if (dir != PCI_DMA_TODEVICE) { for_each_sg(sgl, sg, nents, n) { - dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length)); + BUG_ON(page_address(sg_page(sg)) == NULL); + mmu_inval_dma_area(page_address(sg_page(sg)), + PAGE_ALIGN(sg->length)); } } } diff --git a/trunk/arch/sparc/kernel/irq.h b/trunk/arch/sparc/kernel/irq.h index 100b9c204e78..008453b798ec 100644 --- a/trunk/arch/sparc/kernel/irq.h +++ b/trunk/arch/sparc/kernel/irq.h @@ -2,23 +2,6 @@ #include -struct irq_bucket { - struct irq_bucket *next; - unsigned int real_irq; - unsigned int irq; - unsigned int pil; -}; - -#define SUN4D_MAX_BOARD 10 -#define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5) - -/* Map between the irq identifier used in hw to the - * irq_bucket. The map is sufficient large to hold - * the sun4d hw identifiers. - */ -extern struct irq_bucket *irq_map[SUN4D_MAX_IRQ]; - - /* sun4m specific type definitions */ /* This maps direct to CPU specific interrupt registers */ @@ -52,10 +35,6 @@ struct sparc_irq_config { }; extern struct sparc_irq_config sparc_irq_config; -unsigned int irq_alloc(unsigned int real_irq, unsigned int pil); -void irq_link(unsigned int irq); -void irq_unlink(unsigned int irq); -void handler_irq(unsigned int pil, struct pt_regs *regs); /* Dave Redman (djhr@tadpole.co.uk) * changed these to function pointers.. it saves cycles and will allow @@ -65,9 +44,33 @@ void handler_irq(unsigned int pil, struct pt_regs *regs); * Changed these to btfixup entities... It saves cycles :) */ +BTFIXUPDEF_CALL(void, disable_irq, unsigned int) +BTFIXUPDEF_CALL(void, enable_irq, unsigned int) +BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int) +BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int) BTFIXUPDEF_CALL(void, clear_clock_irq, void) BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) +static inline void __disable_irq(unsigned int irq) +{ + BTFIXUP_CALL(disable_irq)(irq); +} + +static inline void __enable_irq(unsigned int irq) +{ + BTFIXUP_CALL(enable_irq)(irq); +} + +static inline void disable_pil_irq(unsigned int irq) +{ + BTFIXUP_CALL(disable_pil_irq)(irq); +} + +static inline void enable_pil_irq(unsigned int irq) +{ + BTFIXUP_CALL(enable_pil_irq)(irq); +} + static inline void clear_clock_irq(void) { BTFIXUP_CALL(clear_clock_irq)(); @@ -86,10 +89,4 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int) #define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level) #define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level) #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) - -/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ -#define SUN4D_IPI_IRQ 14 - -extern void sun4d_ipi_interrupt(void); - #endif diff --git a/trunk/arch/sparc/kernel/irq_32.c b/trunk/arch/sparc/kernel/irq_32.c index 9b89d842913c..7c93df4099cb 100644 --- a/trunk/arch/sparc/kernel/irq_32.c +++ b/trunk/arch/sparc/kernel/irq_32.c @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -102,173 +101,284 @@ EXPORT_SYMBOL(arch_local_irq_restore); * directed CPU interrupts using the existing enable/disable irq code * with tweaks. * - * Sun4d complicates things even further. IRQ numbers are arbitrary - * 32-bit values in that case. Since this is similar to sparc64, - * we adopt a virtual IRQ numbering scheme as is done there. - * Virutal interrupt numbers are allocated by build_irq(). So NR_IRQS - * just becomes a limit of how many interrupt sources we can handle in - * a single system. Even fully loaded SS2000 machines top off at - * about 32 interrupt sources or so, therefore a NR_IRQS value of 64 - * is more than enough. - * - * We keep a map of per-PIL enable interrupts. These get wired - * up via the irq_chip->startup() method which gets invoked by - * the generic IRQ layer during request_irq(). */ -/* Table of allocated irqs. Unused entries has irq == 0 */ -static struct irq_bucket irq_table[NR_IRQS]; -/* Protect access to irq_table */ -static DEFINE_SPINLOCK(irq_table_lock); -/* Map between the irq identifier used in hw to the irq_bucket. */ -struct irq_bucket *irq_map[SUN4D_MAX_IRQ]; -/* Protect access to irq_map */ -static DEFINE_SPINLOCK(irq_map_lock); +/* + * Dave Redman (djhr@tadpole.co.uk) + * + * There used to be extern calls and hard coded values here.. very sucky! + * instead, because some of the devices attach very early, I do something + * equally sucky but at least we'll never try to free statically allocated + * space or call kmalloc before kmalloc_init :(. + * + * In fact it's the timer10 that attaches first.. then timer14 + * then kmalloc_init is called.. then the tty interrupts attach. + * hmmm.... + * + */ +#define MAX_STATIC_ALLOC 4 +struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +int static_irq_count; + +static struct { + struct irqaction *action; + int flags; +} sparc_irq[NR_IRQS]; +#define SPARC_IRQ_INPROGRESS 1 + +/* Used to protect the IRQ action lists */ +DEFINE_SPINLOCK(irq_action_lock); -/* Allocate a new irq from the irq_table */ -unsigned int irq_alloc(unsigned int real_irq, unsigned int pil) +int show_interrupts(struct seq_file *p, void *v) { + int i = *(loff_t *)v; + struct irqaction *action; unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&irq_table_lock, flags); - for (i = 1; i < NR_IRQS; i++) { - if (irq_table[i].real_irq == real_irq && irq_table[i].pil == pil) - goto found; - } +#ifdef CONFIG_SMP + int j; +#endif - for (i = 1; i < NR_IRQS; i++) { - if (!irq_table[i].irq) - break; - } + if (sparc_cpu_model == sun4d) + return show_sun4d_interrupts(p, v); + spin_lock_irqsave(&irq_action_lock, flags); if (i < NR_IRQS) { - irq_table[i].real_irq = real_irq; - irq_table[i].irq = i; - irq_table[i].pil = pil; - } else { - printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); - i = 0; + action = sparc_irq[i].action; + if (!action) + goto out_unlock; + seq_printf(p, "%3d: ", i); +#ifndef CONFIG_SMP + seq_printf(p, "%10u ", kstat_irqs(i)); +#else + for_each_online_cpu(j) { + seq_printf(p, "%10u ", + kstat_cpu(j).irqs[i]); + } +#endif + seq_printf(p, " %c %s", + (action->flags & IRQF_DISABLED) ? '+' : ' ', + action->name); + for (action = action->next; action; action = action->next) { + seq_printf(p, ",%s %s", + (action->flags & IRQF_DISABLED) ? " +" : "", + action->name); + } + seq_putc(p, '\n'); } -found: - spin_unlock_irqrestore(&irq_table_lock, flags); - - return i; +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); + return 0; } -/* Based on a single pil handler_irq may need to call several - * interrupt handlers. Use irq_map as entry to irq_table, - * and let each entry in irq_table point to the next entry. - */ -void irq_link(unsigned int irq) +void free_irq(unsigned int irq, void *dev_id) { - struct irq_bucket *p; + struct irqaction *action; + struct irqaction **actionp; unsigned long flags; - unsigned int pil; + unsigned int cpu_irq; - BUG_ON(irq >= NR_IRQS); + if (sparc_cpu_model == sun4d) { + sun4d_free_irq(irq, dev_id); + return; + } + cpu_irq = irq & (NR_IRQS - 1); + if (cpu_irq > 14) { /* 14 irq levels on the sparc */ + printk(KERN_ERR "Trying to free bogus IRQ %d\n", irq); + return; + } - spin_lock_irqsave(&irq_map_lock, flags); + spin_lock_irqsave(&irq_action_lock, flags); - p = &irq_table[irq]; - pil = p->pil; - BUG_ON(pil > SUN4D_MAX_IRQ); - p->next = irq_map[pil]; - irq_map[pil] = p; + actionp = &sparc_irq[cpu_irq].action; + action = *actionp; - spin_unlock_irqrestore(&irq_map_lock, flags); -} + if (!action->handler) { + printk(KERN_ERR "Trying to free free IRQ%d\n", irq); + goto out_unlock; + } + if (dev_id) { + for (; action; action = action->next) { + if (action->dev_id == dev_id) + break; + actionp = &action->next; + } + if (!action) { + printk(KERN_ERR "Trying to free free shared IRQ%d\n", + irq); + goto out_unlock; + } + } else if (action->flags & IRQF_SHARED) { + printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n", + irq); + goto out_unlock; + } + if (action->flags & SA_STATIC_ALLOC) { + /* + * This interrupt is marked as specially allocated + * so it is a bad idea to free it. + */ + printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n", + irq, action->name); + goto out_unlock; + } -void irq_unlink(unsigned int irq) -{ - struct irq_bucket *p, **pnext; - unsigned long flags; + *actionp = action->next; + + spin_unlock_irqrestore(&irq_action_lock, flags); - BUG_ON(irq >= NR_IRQS); + synchronize_irq(irq); - spin_lock_irqsave(&irq_map_lock, flags); + spin_lock_irqsave(&irq_action_lock, flags); - p = &irq_table[irq]; - BUG_ON(p->pil > SUN4D_MAX_IRQ); - pnext = &irq_map[p->pil]; - while (*pnext != p) - pnext = &(*pnext)->next; - *pnext = p->next; + kfree(action); - spin_unlock_irqrestore(&irq_map_lock, flags); + if (!sparc_irq[cpu_irq].action) + __disable_irq(irq); + +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); } +EXPORT_SYMBOL(free_irq); + +/* + * This is called when we want to synchronize with + * interrupts. We may for example tell a device to + * stop sending interrupts: but to make sure there + * are no interrupts that are executing on another + * CPU we need to call this function. + */ +#ifdef CONFIG_SMP +void synchronize_irq(unsigned int irq) +{ + unsigned int cpu_irq; + cpu_irq = irq & (NR_IRQS - 1); + while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS) + cpu_relax(); +} +EXPORT_SYMBOL(synchronize_irq); +#endif /* SMP */ -/* /proc/interrupts printing */ -int arch_show_interrupts(struct seq_file *p, int prec) +void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs) { - int j; + int i; + struct irqaction *action; + unsigned int cpu_irq; -#ifdef CONFIG_SMP - seq_printf(p, "RES: "); - for_each_online_cpu(j) - seq_printf(p, "%10u ", cpu_data(j).irq_resched_count); - seq_printf(p, " IPI rescheduling interrupts\n"); - seq_printf(p, "CAL: "); - for_each_online_cpu(j) - seq_printf(p, "%10u ", cpu_data(j).irq_call_count); - seq_printf(p, " IPI function call interrupts\n"); -#endif - seq_printf(p, "NMI: "); - for_each_online_cpu(j) - seq_printf(p, "%10u ", cpu_data(j).counter); - seq_printf(p, " Non-maskable interrupts\n"); - return 0; + cpu_irq = irq & (NR_IRQS - 1); + action = sparc_irq[cpu_irq].action; + + printk(KERN_ERR "IO device interrupt, irq = %d\n", irq); + printk(KERN_ERR "PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, + regs->npc, regs->u_regs[14]); + if (action) { + printk(KERN_ERR "Expecting: "); + for (i = 0; i < 16; i++) + if (action->handler) + printk(KERN_CONT "[%s:%d:0x%x] ", action->name, + i, (unsigned int)action->handler); + } + printk(KERN_ERR "AIEEE\n"); + panic("bogus interrupt received"); } -void handler_irq(unsigned int pil, struct pt_regs *regs) +void handler_irq(int pil, struct pt_regs *regs) { struct pt_regs *old_regs; - struct irq_bucket *p; + struct irqaction *action; + int cpu = smp_processor_id(); - BUG_ON(pil > 15); old_regs = set_irq_regs(regs); irq_enter(); - - p = irq_map[pil]; - while (p) { - struct irq_bucket *next = p->next; - - generic_handle_irq(p->irq); - p = next; - } + disable_pil_irq(pil); +#ifdef CONFIG_SMP + /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */ + if ((sparc_cpu_model==sun4m) && (pil < 10)) + smp4m_irq_rotate(cpu); +#endif + action = sparc_irq[pil].action; + sparc_irq[pil].flags |= SPARC_IRQ_INPROGRESS; + kstat_cpu(cpu).irqs[pil]++; + do { + if (!action || !action->handler) + unexpected_irq(pil, NULL, regs); + action->handler(pil, action->dev_id); + action = action->next; + } while (action); + sparc_irq[pil].flags &= ~SPARC_IRQ_INPROGRESS; + enable_pil_irq(pil); irq_exit(); set_irq_regs(old_regs); } #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE) -static unsigned int floppy_irq; -int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) +/* + * Fast IRQs on the Sparc can only have one routine attached to them, + * thus no sharing possible. + */ +static int request_fast_irq(unsigned int irq, + void (*handler)(void), + unsigned long irqflags, const char *devname) { + struct irqaction *action; + unsigned long flags; unsigned int cpu_irq; - int err; - + int ret; #if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON struct tt_entry *trap_table; #endif + cpu_irq = irq & (NR_IRQS - 1); + if (cpu_irq > 14) { + ret = -EINVAL; + goto out; + } + if (!handler) { + ret = -EINVAL; + goto out; + } - err = request_irq(irq, irq_handler, 0, "floppy", NULL); - if (err) - return -1; + spin_lock_irqsave(&irq_action_lock, flags); - /* Save for later use in floppy interrupt handler */ - floppy_irq = irq; + action = sparc_irq[cpu_irq].action; + if (action) { + if (action->flags & IRQF_SHARED) + panic("Trying to register fast irq when already shared.\n"); + if (irqflags & IRQF_SHARED) + panic("Trying to register fast irq as shared.\n"); - cpu_irq = (irq & (NR_IRQS - 1)); + /* Anyway, someone already owns it so cannot be made fast. */ + printk(KERN_ERR "request_fast_irq: Trying to register yet already owned.\n"); + ret = -EBUSY; + goto out_unlock; + } + + /* + * If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if (irqflags & SA_STATIC_ALLOC) { + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk(KERN_ERR "Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", + irq, devname); + } + + if (action == NULL) + action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) { + ret = -ENOMEM; + goto out_unlock; + } /* Dork with trap table if we get this far. */ #define INSTANTIATE(table) \ table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \ table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \ - SPARC_BRANCH((unsigned long) floppy_hardint, \ + SPARC_BRANCH((unsigned long) handler, \ (unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\ table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \ table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; @@ -289,9 +399,22 @@ int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) * writing we have no CPU-neutral interface to fine-grained flushes. */ flush_cache_all(); - return 0; + + action->flags = irqflags; + action->name = devname; + action->dev_id = NULL; + action->next = NULL; + + sparc_irq[cpu_irq].action = action; + + __enable_irq(irq); + + ret = 0; +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); +out: + return ret; } -EXPORT_SYMBOL(sparc_floppy_request_irq); /* * These variables are used to access state from the assembler @@ -317,23 +440,154 @@ EXPORT_SYMBOL(pdma_base); unsigned long pdma_areasize; EXPORT_SYMBOL(pdma_areasize); -/* Use the generic irq support to call floppy_interrupt - * which was setup using request_irq() in sparc_floppy_request_irq(). - * We only have one floppy interrupt so we do not need to check - * for additional handlers being wired up by irq_link() - */ +static irq_handler_t floppy_irq_handler; + void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) { struct pt_regs *old_regs; + int cpu = smp_processor_id(); old_regs = set_irq_regs(regs); + disable_pil_irq(irq); irq_enter(); - generic_handle_irq(floppy_irq); + kstat_cpu(cpu).irqs[irq]++; + floppy_irq_handler(irq, dev_id); irq_exit(); + enable_pil_irq(irq); set_irq_regs(old_regs); + /* + * XXX Eek, it's totally changed with preempt_count() and such + * if (softirq_pending(cpu)) + * do_softirq(); + */ +} + +int sparc_floppy_request_irq(int irq, unsigned long flags, + irq_handler_t irq_handler) +{ + floppy_irq_handler = irq_handler; + return request_fast_irq(irq, floppy_hardint, flags, "floppy"); } +EXPORT_SYMBOL(sparc_floppy_request_irq); + #endif +int request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) +{ + struct irqaction *action, **actionp; + unsigned long flags; + unsigned int cpu_irq; + int ret; + + if (sparc_cpu_model == sun4d) + return sun4d_request_irq(irq, handler, irqflags, devname, dev_id); + + cpu_irq = irq & (NR_IRQS - 1); + if (cpu_irq > 14) { + ret = -EINVAL; + goto out; + } + if (!handler) { + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&irq_action_lock, flags); + + actionp = &sparc_irq[cpu_irq].action; + action = *actionp; + if (action) { + if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) { + ret = -EBUSY; + goto out_unlock; + } + if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) { + printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n", + irq); + ret = -EBUSY; + goto out_unlock; + } + for ( ; action; action = *actionp) + actionp = &action->next; + } + + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if (irqflags & SA_STATIC_ALLOC) { + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", + irq, devname); + } + if (action == NULL) + action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + if (!action) { + ret = -ENOMEM; + goto out_unlock; + } + + action->handler = handler; + action->flags = irqflags; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + *actionp = action; + + __enable_irq(irq); + + ret = 0; +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); +out: + return ret; +} +EXPORT_SYMBOL(request_irq); + +void disable_irq_nosync(unsigned int irq) +{ + __disable_irq(irq); +} +EXPORT_SYMBOL(disable_irq_nosync); + +void disable_irq(unsigned int irq) +{ + __disable_irq(irq); +} +EXPORT_SYMBOL(disable_irq); + +void enable_irq(unsigned int irq) +{ + __enable_irq(irq); +} +EXPORT_SYMBOL(enable_irq); + +/* + * We really don't need these at all on the Sparc. We only have + * stubs here because they are exported to modules. + */ +unsigned long probe_irq_on(void) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_on); + +int probe_irq_off(unsigned long mask) +{ + return 0; +} +EXPORT_SYMBOL(probe_irq_off); + +static unsigned int build_device_irq(struct platform_device *op, + unsigned int real_irq) +{ + return real_irq; +} + /* djhr * This could probably be made indirect too and assigned in the CPU * bits of the code. That would be much nicer I think and would also @@ -344,6 +598,8 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) void __init init_IRQ(void) { + sparc_irq_config.build_device_irq = build_device_irq; + switch (sparc_cpu_model) { case sun4c: case sun4: @@ -351,11 +607,14 @@ void __init init_IRQ(void) break; case sun4m: +#ifdef CONFIG_PCI pcic_probe(); - if (pcic_present()) + if (pcic_present()) { sun4m_pci_init_IRQ(); - else - sun4m_init_IRQ(); + break; + } +#endif + sun4m_init_IRQ(); break; case sun4d: @@ -373,3 +632,9 @@ void __init init_IRQ(void) btfixup(); } +#ifdef CONFIG_PROC_FS +void init_irq_proc(void) +{ + /* For now, nothing... */ +} +#endif /* CONFIG_PROC_FS */ diff --git a/trunk/arch/sparc/kernel/irq_64.c b/trunk/arch/sparc/kernel/irq_64.c index 4e78862d12fd..b1d275ce3435 100644 --- a/trunk/arch/sparc/kernel/irq_64.c +++ b/trunk/arch/sparc/kernel/irq_64.c @@ -224,13 +224,13 @@ static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity) int cpuid; cpumask_copy(&mask, affinity); - if (cpumask_equal(&mask, cpu_online_mask)) { + if (cpus_equal(mask, cpu_online_map)) { cpuid = map_to_cpu(irq); } else { cpumask_t tmp; - cpumask_and(&tmp, cpu_online_mask, &mask); - cpuid = cpumask_empty(&tmp) ? map_to_cpu(irq) : cpumask_first(&tmp); + cpus_and(tmp, cpu_online_map, mask); + cpuid = cpus_empty(tmp) ? map_to_cpu(irq) : first_cpu(tmp); } return cpuid; diff --git a/trunk/arch/sparc/kernel/kernel.h b/trunk/arch/sparc/kernel/kernel.h index 6f6544cfa0ef..24ad449886be 100644 --- a/trunk/arch/sparc/kernel/kernel.h +++ b/trunk/arch/sparc/kernel/kernel.h @@ -6,9 +6,11 @@ #include /* cpu.c */ +extern const char *sparc_cpu_type; extern const char *sparc_pmu_type; +extern const char *sparc_fpu_type; + extern unsigned int fsr_storage; -extern int ncpus_probed; #ifdef CONFIG_SPARC32 /* cpu.c */ @@ -35,7 +37,6 @@ extern void sun4c_init_IRQ(void); extern unsigned int lvl14_resolution; extern void sun4m_init_IRQ(void); -extern void sun4m_unmask_profile_irq(void); extern void sun4m_clear_profile_irq(int cpu); /* sun4d_irq.c */ diff --git a/trunk/arch/sparc/kernel/leon_kernel.c b/trunk/arch/sparc/kernel/leon_kernel.c index 2f538ac2e139..2969f777fa11 100644 --- a/trunk/arch/sparc/kernel/leon_kernel.c +++ b/trunk/arch/sparc/kernel/leon_kernel.c @@ -19,70 +19,53 @@ #include #include #include -#include -#include #include "prom.h" #include "irq.h" struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address */ struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address */ +struct amba_apb_device leon_percpu_timer_dev[16]; int leondebug_irq_disable; int leon_debug_irqout; static int dummy_master_l10_counter; unsigned long amba_system_id; -static DEFINE_SPINLOCK(leon_irq_lock); unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ -int leon3_ticker_irq; /* Timer ticker IRQ */ unsigned int sparc_leon_eirq; -#define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) -#define LEON_IACK (&leon3_irqctrl_regs->iclear) -#define LEON_DO_ACK_HW 1 +#define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) -/* Return the last ACKed IRQ by the Extended IRQ controller. It has already - * been (automatically) ACKed when the CPU takes the trap. - */ -static inline unsigned int leon_eirq_get(int cpu) +/* Return the IRQ of the pending IRQ on the extended IRQ controller */ +int sparc_leon_eirq_get(int eirq, int cpu) { return LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->intid[cpu]) & 0x1f; } -/* Handle one or multiple IRQs from the extended interrupt controller */ -static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc) +irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id) { - unsigned int eirq; - int cpu = sparc_leon3_cpuid(); - - eirq = leon_eirq_get(cpu); - if ((eirq & 0x10) && irq_map[eirq]->irq) /* bit4 tells if IRQ happened */ - generic_handle_irq(irq_map[eirq]->irq); + printk(KERN_ERR "sparc_leon_eirq_isr: ERROR EXTENDED IRQ\n"); + return IRQ_HANDLED; } /* The extended IRQ controller has been found, this function registers it */ -void leon_eirq_setup(unsigned int eirq) +void sparc_leon_eirq_register(int eirq) { - unsigned long mask, oldmask; - unsigned int veirq; + int irq; - if (eirq < 1 || eirq > 0xf) { - printk(KERN_ERR "LEON EXT IRQ NUMBER BAD: %d\n", eirq); - return; + /* Register a "BAD" handler for this interrupt, it should never happen */ + irq = request_irq(eirq, sparc_leon_eirq_isr, + (IRQF_DISABLED | SA_STATIC_ALLOC), "extirq", NULL); + + if (irq) { + printk(KERN_ERR + "sparc_leon_eirq_register: unable to attach IRQ%d\n", + eirq); + } else { + sparc_leon_eirq = eirq; } - veirq = leon_build_device_irq(eirq, leon_handle_ext_irq, "extirq", 0); - - /* - * Unmask the Extended IRQ, the IRQs routed through the Ext-IRQ - * controller have a mask-bit of their own, so this is safe. - */ - irq_link(veirq); - mask = 1 << eirq; - oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(boot_cpu_id)); - LEON3_BYPASS_STORE_PA(LEON_IMASK(boot_cpu_id), (oldmask | mask)); - sparc_leon_eirq = eirq; } static inline unsigned long get_irqmask(unsigned int irq) @@ -100,151 +83,35 @@ static inline unsigned long get_irqmask(unsigned int irq) return mask; } -#ifdef CONFIG_SMP -static int irq_choose_cpu(const struct cpumask *affinity) -{ - cpumask_t mask; - - cpus_and(mask, cpu_online_map, *affinity); - if (cpus_equal(mask, cpu_online_map) || cpus_empty(mask)) - return boot_cpu_id; - else - return first_cpu(mask); -} -#else -#define irq_choose_cpu(affinity) boot_cpu_id -#endif - -static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest, - bool force) -{ - unsigned long mask, oldmask, flags; - int oldcpu, newcpu; - - mask = (unsigned long)data->chip_data; - oldcpu = irq_choose_cpu(data->affinity); - newcpu = irq_choose_cpu(dest); - - if (oldcpu == newcpu) - goto out; - - /* unmask on old CPU first before enabling on the selected CPU */ - spin_lock_irqsave(&leon_irq_lock, flags); - oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(oldcpu)); - LEON3_BYPASS_STORE_PA(LEON_IMASK(oldcpu), (oldmask & ~mask)); - oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(newcpu)); - LEON3_BYPASS_STORE_PA(LEON_IMASK(newcpu), (oldmask | mask)); - spin_unlock_irqrestore(&leon_irq_lock, flags); -out: - return IRQ_SET_MASK_OK; -} - -static void leon_unmask_irq(struct irq_data *data) -{ - unsigned long mask, oldmask, flags; - int cpu; - - mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); - spin_lock_irqsave(&leon_irq_lock, flags); - oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); - LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask)); - spin_unlock_irqrestore(&leon_irq_lock, flags); -} - -static void leon_mask_irq(struct irq_data *data) -{ - unsigned long mask, oldmask, flags; - int cpu; - - mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); - spin_lock_irqsave(&leon_irq_lock, flags); - oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); - LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask)); - spin_unlock_irqrestore(&leon_irq_lock, flags); -} - -static unsigned int leon_startup_irq(struct irq_data *data) -{ - irq_link(data->irq); - leon_unmask_irq(data); - return 0; -} - -static void leon_shutdown_irq(struct irq_data *data) +static void leon_enable_irq(unsigned int irq_nr) { - leon_mask_irq(data); - irq_unlink(data->irq); + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask))); + local_irq_restore(flags); } -/* Used by external level sensitive IRQ handlers on the LEON: ACK IRQ ctrl */ -static void leon_eoi_irq(struct irq_data *data) +static void leon_disable_irq(unsigned int irq_nr) { - unsigned long mask = (unsigned long)data->chip_data; - - if (mask & LEON_DO_ACK_HW) - LEON3_BYPASS_STORE_PA(LEON_IACK, mask & ~LEON_DO_ACK_HW); -} - -static struct irq_chip leon_irq = { - .name = "leon", - .irq_startup = leon_startup_irq, - .irq_shutdown = leon_shutdown_irq, - .irq_mask = leon_mask_irq, - .irq_unmask = leon_unmask_irq, - .irq_eoi = leon_eoi_irq, - .irq_set_affinity = leon_set_affinity, -}; - -/* - * Build a LEON IRQ for the edge triggered LEON IRQ controller: - * Edge (normal) IRQ - handle_simple_irq, ack=DONT-CARE, never ack - * Level IRQ (PCI|Level-GPIO) - handle_fasteoi_irq, ack=1, ack after ISR - * Per-CPU Edge - handle_percpu_irq, ack=0 - */ -unsigned int leon_build_device_irq(unsigned int real_irq, - irq_flow_handler_t flow_handler, - const char *name, int do_ack) -{ - unsigned int irq; - unsigned long mask; - - irq = 0; - mask = get_irqmask(real_irq); - if (mask == 0) - goto out; - - irq = irq_alloc(real_irq, real_irq); - if (irq == 0) - goto out; - - if (do_ack) - mask |= LEON_DO_ACK_HW; - - irq_set_chip_and_handler_name(irq, &leon_irq, - flow_handler, name); - irq_set_chip_data(irq, (void *)mask); - -out: - return irq; -} + unsigned long mask, flags; + mask = get_irqmask(irq_nr); + local_irq_save(flags); + LEON3_BYPASS_STORE_PA(LEON_IMASK, + (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask))); + local_irq_restore(flags); -static unsigned int _leon_build_device_irq(struct platform_device *op, - unsigned int real_irq) -{ - return leon_build_device_irq(real_irq, handle_simple_irq, "edge", 0); } void __init leon_init_timers(irq_handler_t counter_fn) { - int irq, eirq; + int irq; struct device_node *rootnp, *np, *nnp; struct property *pp; int len; - int icsel; + int cpu, icsel; int ampopts; - int err; leondebug_irq_disable = 0; leon_debug_irqout = 0; @@ -306,85 +173,98 @@ void __init leon_init_timers(irq_handler_t counter_fn) leon3_gptimer_irq = *(unsigned int *)pp->value; } while (0); - if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq)) - goto bad; - - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld, - (((1000000 / HZ) - 1))); - LEON3_BYPASS_STORE_PA( + if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx].rld, + (((1000000 / HZ) - 1))); + LEON3_BYPASS_STORE_PA( &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); #ifdef CONFIG_SMP - leon3_ticker_irq = leon3_gptimer_irq + 1 + leon3_gptimer_idx; + leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; + leon_percpu_timer_dev[0].irq = leon3_gptimer_irq + 1 + + leon3_gptimer_idx; + + if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & + (1<config) & - (1<e[leon3_gptimer_idx+1].val, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, + (((1000000/HZ) - 1))); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0); +# endif + + /* + * The IRQ controller may (if implemented) consist of multiple + * IRQ controllers, each mapped on a 4Kb boundary. + * Each CPU may be routed to different IRQCTRLs, however + * we assume that all CPUs (in SMP system) is routed to the + * same IRQ Controller, and for non-SMP only one IRQCTRL is + * accessed anyway. + * In AMP systems, Linux must run on CPU0 for the time being. + */ + cpu = sparc_leon3_cpuid(); + icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]); + icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf; + leon3_irqctrl_regs += icsel; + } else { + goto bad; } - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, - 0); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, - (((1000000/HZ) - 1))); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, - 0); -#endif + irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx, + counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); - /* - * The IRQ controller may (if implemented) consist of multiple - * IRQ controllers, each mapped on a 4Kb boundary. - * Each CPU may be routed to different IRQCTRLs, however - * we assume that all CPUs (in SMP system) is routed to the - * same IRQ Controller, and for non-SMP only one IRQCTRL is - * accessed anyway. - * In AMP systems, Linux must run on CPU0 for the time being. - */ - icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[boot_cpu_id/8]); - icsel = (icsel >> ((7 - (boot_cpu_id&0x7)) * 4)) & 0xf; - leon3_irqctrl_regs += icsel; - - /* Mask all IRQs on boot-cpu IRQ controller */ - LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[boot_cpu_id], 0); - - /* Probe extended IRQ controller */ - eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) - >> 16) & 0xf; - if (eirq != 0) - leon_eirq_setup(eirq); - - irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); - err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); - if (err) { - printk(KERN_ERR "unable to attach timer IRQ%d\n", irq); + if (irq) { + printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n", + LEON_INTERRUPT_TIMER1); prom_halt(); } - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, - LEON3_GPTIMER_EN | - LEON3_GPTIMER_RL | - LEON3_GPTIMER_LD | - LEON3_GPTIMER_IRQEN); +# ifdef CONFIG_SMP + { + unsigned long flags; + struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)]; -#ifdef CONFIG_SMP - /* Install per-cpu IRQ handler for broadcasted ticker */ - irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, - "per-cpu", 0); - err = request_irq(irq, leon_percpu_timer_interrupt, - IRQF_PERCPU | IRQF_TIMER, "ticker", - NULL); - if (err) { - printk(KERN_ERR "unable to attach ticker IRQ%d\n", irq); - prom_halt(); + /* For SMP we use the level 14 ticker, however the bootup code + * has copied the firmwares level 14 vector into boot cpu's + * trap table, we must fix this now or we get squashed. + */ + local_irq_save(flags); + + patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ + + /* Adjust so that we jump directly to smpleon_ticker */ + trap_table->inst_three += smpleon_ticker - real_irq_entry; + + local_flush_cache_all(); + local_irq_restore(flags); } +# endif + + if (leon3_gptimer_regs) { + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, + LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | + LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, - LEON3_GPTIMER_EN | - LEON3_GPTIMER_RL | - LEON3_GPTIMER_LD | - LEON3_GPTIMER_IRQEN); +#ifdef CONFIG_SMP + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, + LEON3_GPTIMER_EN | + LEON3_GPTIMER_RL | + LEON3_GPTIMER_LD | + LEON3_GPTIMER_IRQEN); #endif + + } return; bad: printk(KERN_ERR "No Timer/irqctrl found\n"); @@ -401,6 +281,9 @@ void leon_load_profile_irq(int cpu, unsigned int limit) BUG(); } + + + void __init leon_trans_init(struct device_node *dp) { if (strcmp(dp->type, "cpu") == 0 && strcmp(dp->name, "") == 0) { @@ -454,18 +337,22 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) { unsigned long mask, flags, *addr; mask = get_irqmask(irq_nr); - spin_lock_irqsave(&leon_irq_lock, flags); - addr = (unsigned long *)LEON_IMASK(cpu); - LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | mask)); - spin_unlock_irqrestore(&leon_irq_lock, flags); + local_irq_save(flags); + addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]); + LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask))); + local_irq_restore(flags); } #endif void __init leon_init_IRQ(void) { - sparc_irq_config.init_timers = leon_init_timers; - sparc_irq_config.build_device_irq = _leon_build_device_irq; + sparc_irq_config.init_timers = leon_init_timers; + + BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, BTFIXUPCALL_NORM); diff --git a/trunk/arch/sparc/kernel/leon_smp.c b/trunk/arch/sparc/kernel/leon_smp.c index fe8fb44c609c..8f5de4aa3c0a 100644 --- a/trunk/arch/sparc/kernel/leon_smp.c +++ b/trunk/arch/sparc/kernel/leon_smp.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include #include #include -#include #include #include @@ -52,12 +50,9 @@ extern ctxd_t *srmmu_ctx_table_phys; static int smp_processors_ready; extern volatile unsigned long cpu_callin_map[NR_CPUS]; +extern unsigned char boot_cpu_id; extern cpumask_t smp_commenced_mask; void __init leon_configure_cache_smp(void); -static void leon_ipi_init(void); - -/* IRQ number of LEON IPIs */ -int leon_ipi_irq = LEON3_IRQ_IPI_DEFAULT; static inline unsigned long do_swap(volatile unsigned long *ptr, unsigned long val) @@ -99,6 +94,8 @@ void __cpuinit leon_callin(void) local_flush_cache_all(); local_flush_tlb_all(); + cpu_probe(); + /* Fix idle thread fields. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(¤t_set[cpuid]) : "memory" /* paranoid */); @@ -107,11 +104,11 @@ void __cpuinit leon_callin(void) atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) + while (!cpu_isset(cpuid, smp_commenced_mask)) mb(); local_irq_enable(); - set_cpu_online(cpuid, true); + cpu_set(cpuid, cpu_online_map); } /* @@ -182,16 +179,13 @@ void __init leon_boot_cpus(void) int nrcpu = leon_smp_nrcpus(); int me = smp_processor_id(); - /* Setup IPI */ - leon_ipi_init(); - printk(KERN_INFO "%d:(%d:%d) cpus mpirq at 0x%x\n", (unsigned int)me, (unsigned int)nrcpu, (unsigned int)NR_CPUS, (unsigned int)&(leon3_irqctrl_regs->mpstatus)); leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, me); leon_enable_irq_cpu(LEON3_IRQ_TICKER, me); - leon_enable_irq_cpu(leon_ipi_irq, me); + leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, me); leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER); @@ -226,10 +220,6 @@ int __cpuinit leon_boot_one_cpu(int i) (unsigned int)&leon3_irqctrl_regs->mpstatus); local_flush_cache_all(); - /* Make sure all IRQs are of from the start for this new CPU */ - LEON_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[i], 0); - - /* Wake one CPU */ LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpstatus), 1 << i); /* wheee... it's going... */ @@ -246,7 +236,7 @@ int __cpuinit leon_boot_one_cpu(int i) } else { leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, i); leon_enable_irq_cpu(LEON3_IRQ_TICKER, i); - leon_enable_irq_cpu(leon_ipi_irq, i); + leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, i); } local_flush_cache_all(); @@ -272,21 +262,21 @@ void __init leon_smp_done(void) local_flush_cache_all(); /* Free unneeded trap tables */ - if (!cpu_present(1)) { + if (!cpu_isset(1, cpu_present_map)) { ClearPageReserved(virt_to_page(&trapbase_cpu1)); init_page_count(virt_to_page(&trapbase_cpu1)); free_page((unsigned long)&trapbase_cpu1); totalram_pages++; num_physpages++; } - if (!cpu_present(2)) { + if (!cpu_isset(2, cpu_present_map)) { ClearPageReserved(virt_to_page(&trapbase_cpu2)); init_page_count(virt_to_page(&trapbase_cpu2)); free_page((unsigned long)&trapbase_cpu2); totalram_pages++; num_physpages++; } - if (!cpu_present(3)) { + if (!cpu_isset(3, cpu_present_map)) { ClearPageReserved(virt_to_page(&trapbase_cpu3)); init_page_count(virt_to_page(&trapbase_cpu3)); free_page((unsigned long)&trapbase_cpu3); @@ -302,99 +292,6 @@ void leon_irq_rotate(int cpu) { } -struct leon_ipi_work { - int single; - int msk; - int resched; -}; - -static DEFINE_PER_CPU_SHARED_ALIGNED(struct leon_ipi_work, leon_ipi_work); - -/* Initialize IPIs on the LEON, in order to save IRQ resources only one IRQ - * is used for all three types of IPIs. - */ -static void __init leon_ipi_init(void) -{ - int cpu, len; - struct leon_ipi_work *work; - struct property *pp; - struct device_node *rootnp; - struct tt_entry *trap_table; - unsigned long flags; - - /* Find IPI IRQ or stick with default value */ - rootnp = of_find_node_by_path("/ambapp0"); - if (rootnp) { - pp = of_find_property(rootnp, "ipi_num", &len); - if (pp && (*(int *)pp->value)) - leon_ipi_irq = *(int *)pp->value; - } - printk(KERN_INFO "leon: SMP IPIs at IRQ %d\n", leon_ipi_irq); - - /* Adjust so that we jump directly to smpleon_ipi */ - local_irq_save(flags); - trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_ipi_irq - 1)]; - trap_table->inst_three += smpleon_ipi - real_irq_entry; - local_flush_cache_all(); - local_irq_restore(flags); - - for_each_possible_cpu(cpu) { - work = &per_cpu(leon_ipi_work, cpu); - work->single = work->msk = work->resched = 0; - } -} - -static void leon_ipi_single(int cpu) -{ - struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu); - - /* Mark work */ - work->single = 1; - - /* Generate IRQ on the CPU */ - set_cpu_int(cpu, leon_ipi_irq); -} - -static void leon_ipi_mask_one(int cpu) -{ - struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu); - - /* Mark work */ - work->msk = 1; - - /* Generate IRQ on the CPU */ - set_cpu_int(cpu, leon_ipi_irq); -} - -static void leon_ipi_resched(int cpu) -{ - struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu); - - /* Mark work */ - work->resched = 1; - - /* Generate IRQ on the CPU (any IRQ will cause resched) */ - set_cpu_int(cpu, leon_ipi_irq); -} - -void leonsmp_ipi_interrupt(void) -{ - struct leon_ipi_work *work = &__get_cpu_var(leon_ipi_work); - - if (work->single) { - work->single = 0; - smp_call_function_single_interrupt(); - } - if (work->msk) { - work->msk = 0; - smp_call_function_interrupt(); - } - if (work->resched) { - work->resched = 0; - smp_resched_interrupt(); - } -} - static struct smp_funcall { smpfunc_t func; unsigned long arg1; @@ -440,10 +337,10 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, { register int i; - cpumask_clear_cpu(smp_processor_id(), &mask); - cpumask_and(&mask, cpu_online_mask, &mask); + cpu_clear(smp_processor_id(), mask); + cpus_and(mask, cpu_online_map, mask); for (i = 0; i <= high; i++) { - if (cpumask_test_cpu(i, &mask)) { + if (cpu_isset(i, mask)) { ccall_info.processors_in[i] = 0; ccall_info.processors_out[i] = 0; set_cpu_int(i, LEON3_IRQ_CROSS_CALL); @@ -457,7 +354,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_in[i]) @@ -466,7 +363,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_out[i]) @@ -489,23 +386,27 @@ void leon_cross_call_irq(void) ccall_info.processors_out[i] = 1; } -irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused) +void leon_percpu_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs; int cpu = smp_processor_id(); + old_regs = set_irq_regs(regs); + leon_clear_profile_irq(cpu); profile_tick(CPU_PROFILING); if (!--prof_counter(cpu)) { - int user = user_mode(get_irq_regs()); + int user = user_mode(regs); + irq_enter(); update_process_times(user); + irq_exit(); prof_counter(cpu) = prof_multiplier(cpu); } - - return IRQ_HANDLED; + set_irq_regs(old_regs); } static void __init smp_setup_percpu_timer(void) @@ -548,9 +449,6 @@ void __init leon_init_smp(void) BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_resched, leon_ipi_resched, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_single, leon_ipi_single, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_mask_one, leon_ipi_mask_one, BTFIXUPCALL_NORM); } #endif /* CONFIG_SPARC_LEON */ diff --git a/trunk/arch/sparc/kernel/mdesc.c b/trunk/arch/sparc/kernel/mdesc.c index 42f28c7420e1..56db06432ce9 100644 --- a/trunk/arch/sparc/kernel/mdesc.c +++ b/trunk/arch/sparc/kernel/mdesc.c @@ -768,7 +768,7 @@ static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handl cpuid, NR_CPUS); continue; } - if (!cpumask_test_cpu(cpuid, mask)) + if (!cpu_isset(cpuid, *mask)) continue; #endif diff --git a/trunk/arch/sparc/kernel/of_device_64.c b/trunk/arch/sparc/kernel/of_device_64.c index 3bb2eace58cf..5c149689bb20 100644 --- a/trunk/arch/sparc/kernel/of_device_64.c +++ b/trunk/arch/sparc/kernel/of_device_64.c @@ -622,9 +622,8 @@ static unsigned int __init build_one_device_irq(struct platform_device *op, out: nid = of_node_to_nid(dp); if (nid != -1) { - cpumask_t numa_mask; + cpumask_t numa_mask = *cpumask_of_node(nid); - cpumask_copy(&numa_mask, cpumask_of_node(nid)); irq_set_affinity(irq, &numa_mask); } diff --git a/trunk/arch/sparc/kernel/pci_msi.c b/trunk/arch/sparc/kernel/pci_msi.c index 580651af73f2..30982e9ab626 100644 --- a/trunk/arch/sparc/kernel/pci_msi.c +++ b/trunk/arch/sparc/kernel/pci_msi.c @@ -284,9 +284,8 @@ static int bringup_one_msi_queue(struct pci_pbm_info *pbm, nid = pbm->numa_node; if (nid != -1) { - cpumask_t numa_mask; + cpumask_t numa_mask = *cpumask_of_node(nid); - cpumask_copy(&numa_mask, cpumask_of_node(nid)); irq_set_affinity(irq, &numa_mask); } err = request_irq(irq, sparc64_msiq_interrupt, 0, diff --git a/trunk/arch/sparc/kernel/pcic.c b/trunk/arch/sparc/kernel/pcic.c index 948601a066ff..2cdc131b50ac 100644 --- a/trunk/arch/sparc/kernel/pcic.c +++ b/trunk/arch/sparc/kernel/pcic.c @@ -164,9 +164,6 @@ void __iomem *pcic_regs; volatile int pcic_speculative; volatile int pcic_trapped; -/* forward */ -unsigned int pcic_build_device_irq(struct platform_device *op, - unsigned int real_irq); #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) @@ -526,7 +523,6 @@ static void pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) { struct pcic_ca2irq *p; - unsigned int real_irq; int i, ivec; char namebuf[64]; @@ -555,25 +551,26 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) i = p->pin; if (i >= 0 && i < 4) { ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); - real_irq = ivec >> (i << 2) & 0xF; + dev->irq = ivec >> (i << 2) & 0xF; } else if (i >= 4 && i < 8) { ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); - real_irq = ivec >> ((i-4) << 2) & 0xF; + dev->irq = ivec >> ((i-4) << 2) & 0xF; } else { /* Corrupted map */ printk("PCIC: BAD PIN %d\n", i); for (;;) {} } /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ - /* real_irq means PROM did not bother to program the upper + /* + * dev->irq=0 means PROM did not bother to program the upper * half of PCIC. This happens on JS-E with PROM 3.11, for instance. */ - if (real_irq == 0 || p->force) { + if (dev->irq == 0 || p->force) { if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} } printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", p->irq, p->pin, dev->bus->number, dev->devfn); - real_irq = p->irq; + dev->irq = p->irq; i = p->pin; if (i >= 4) { @@ -587,8 +584,7 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) ivec |= p->irq << (i << 2); writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); } - } - dev->irq = pcic_build_device_irq(NULL, real_irq); + } } /* @@ -733,7 +729,6 @@ void __init pci_time_init(void) struct linux_pcic *pcic = &pcic0; unsigned long v; int timer_irq, irq; - int err; do_arch_gettimeoffset = pci_gettimeoffset; @@ -745,10 +740,9 @@ void __init pci_time_init(void) timer_irq = PCI_COUNTER_IRQ_SYS(v); writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), pcic->pcic_regs+PCI_COUNTER_IRQ); - irq = pcic_build_device_irq(NULL, timer_irq); - err = request_irq(irq, pcic_timer_handler, - IRQF_TIMER, "timer", NULL); - if (err) { + irq = request_irq(timer_irq, pcic_timer_handler, + (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); + if (irq) { prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); prom_halt(); } @@ -809,73 +803,50 @@ static inline unsigned long get_irqmask(int irq_nr) return 1 << irq_nr; } -static void pcic_mask_irq(struct irq_data *data) +static void pcic_disable_irq(unsigned int irq_nr) { unsigned long mask, flags; - mask = (unsigned long)data->chip_data; + mask = get_irqmask(irq_nr); local_irq_save(flags); writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); local_irq_restore(flags); } -static void pcic_unmask_irq(struct irq_data *data) +static void pcic_enable_irq(unsigned int irq_nr) { unsigned long mask, flags; - mask = (unsigned long)data->chip_data; + mask = get_irqmask(irq_nr); local_irq_save(flags); writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); local_irq_restore(flags); } -static unsigned int pcic_startup_irq(struct irq_data *data) +static void pcic_load_profile_irq(int cpu, unsigned int limit) { - irq_link(data->irq); - pcic_unmask_irq(data); - return 0; + printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); } -static struct irq_chip pcic_irq = { - .name = "pcic", - .irq_startup = pcic_startup_irq, - .irq_mask = pcic_mask_irq, - .irq_unmask = pcic_unmask_irq, -}; - -unsigned int pcic_build_device_irq(struct platform_device *op, - unsigned int real_irq) +/* We assume the caller has disabled local interrupts when these are called, + * or else very bizarre behavior will result. + */ +static void pcic_disable_pil_irq(unsigned int pil) { - unsigned int irq; - unsigned long mask; - - irq = 0; - mask = get_irqmask(real_irq); - if (mask == 0) - goto out; - - irq = irq_alloc(real_irq, real_irq); - if (irq == 0) - goto out; - - irq_set_chip_and_handler_name(irq, &pcic_irq, - handle_level_irq, "PCIC"); - irq_set_chip_data(irq, (void *)mask); - -out: - return irq; + writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); } - -static void pcic_load_profile_irq(int cpu, unsigned int limit) +static void pcic_enable_pil_irq(unsigned int pil) { - printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); + writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); } void __init sun4m_pci_init_IRQ(void) { - sparc_irq_config.build_device_irq = pcic_build_device_irq; - + BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); } diff --git a/trunk/arch/sparc/kernel/perf_event.c b/trunk/arch/sparc/kernel/perf_event.c index 2cb0e1c001e2..ee8426ede7c7 100644 --- a/trunk/arch/sparc/kernel/perf_event.c +++ b/trunk/arch/sparc/kernel/perf_event.c @@ -26,7 +26,6 @@ #include #include -#include "kernel.h" #include "kstack.h" /* Sparc64 chips have two performance counters, 32-bits each, with diff --git a/trunk/arch/sparc/kernel/pmc.c b/trunk/arch/sparc/kernel/pmc.c index 93d7b4465f8d..6a585d393580 100644 --- a/trunk/arch/sparc/kernel/pmc.c +++ b/trunk/arch/sparc/kernel/pmc.c @@ -69,7 +69,7 @@ static int __devinit pmc_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata pmc_match[] = { +static struct of_device_id pmc_match[] = { { .name = PMC_OBPNAME, }, diff --git a/trunk/arch/sparc/kernel/process_32.c b/trunk/arch/sparc/kernel/process_32.c index c8cc461ff75f..17529298c50a 100644 --- a/trunk/arch/sparc/kernel/process_32.c +++ b/trunk/arch/sparc/kernel/process_32.c @@ -128,16 +128,8 @@ void cpu_idle(void) set_thread_flag(TIF_POLLING_NRFLAG); /* endless idle loop with no priority at all */ while(1) { -#ifdef CONFIG_SPARC_LEON - if (pm_idle) { - while (!need_resched()) - (*pm_idle)(); - } else -#endif - { - while (!need_resched()) - cpu_relax(); - } + while (!need_resched()) + cpu_relax(); preempt_enable_no_resched(); schedule(); preempt_disable(); diff --git a/trunk/arch/sparc/kernel/prom_32.c b/trunk/arch/sparc/kernel/prom_32.c index 5ce3d15a99b0..05fb25330583 100644 --- a/trunk/arch/sparc/kernel/prom_32.c +++ b/trunk/arch/sparc/kernel/prom_32.c @@ -326,6 +326,7 @@ void __init of_console_init(void) of_console_options = NULL; } + prom_printf(msg, of_console_path); printk(msg, of_console_path); } diff --git a/trunk/arch/sparc/kernel/setup_32.c b/trunk/arch/sparc/kernel/setup_32.c index 3609bdee9ed2..7b8b76c9557f 100644 --- a/trunk/arch/sparc/kernel/setup_32.c +++ b/trunk/arch/sparc/kernel/setup_32.c @@ -103,20 +103,16 @@ static unsigned int boot_flags __initdata = 0; /* Exported for mm/init.c:paging_init. */ unsigned long cmdline_memory_size __initdata = 0; -/* which CPU booted us (0xff = not set) */ -unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */ -unsigned char boot_cpu_id4; /* boot_cpu_id << 2 */ - static void prom_console_write(struct console *con, const char *s, unsigned n) { prom_write(s, n); } -static struct console prom_early_console = { - .name = "earlyprom", +static struct console prom_debug_console = { + .name = "debug", .write = prom_console_write, - .flags = CON_PRINTBUFFER | CON_BOOT, + .flags = CON_PRINTBUFFER, .index = -1, }; @@ -137,7 +133,8 @@ static void __init process_switch(char c) prom_halt(); break; case 'p': - /* Just ignore, this behavior is now the default. */ + /* Use PROM debug console. */ + register_console(&prom_debug_console); break; default: printk("Unknown boot switch (-%c)\n", c); @@ -218,10 +215,6 @@ void __init setup_arch(char **cmdline_p) strcpy(boot_command_line, *cmdline_p); parse_early_param(); - boot_flags_init(*cmdline_p); - - register_console(&prom_early_console); - /* Set sparc_cpu_model */ sparc_cpu_model = sun_unknown; if (!strcmp(&cputypval[0], "sun4 ")) @@ -272,6 +265,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + boot_flags_init(*cmdline_p); idprom_init(); if (ARCH_SUN4C) @@ -317,6 +311,75 @@ void __init setup_arch(char **cmdline_p) smp_setup_cpu_possible_map(); } +static int ncpus_probed; + +static int show_cpuinfo(struct seq_file *m, void *__unused) +{ + seq_printf(m, + "cpu\t\t: %s\n" + "fpu\t\t: %s\n" + "promlib\t\t: Version %d Revision %d\n" + "prom\t\t: %d.%d\n" + "type\t\t: %s\n" + "ncpus probed\t: %d\n" + "ncpus active\t: %d\n" +#ifndef CONFIG_SMP + "CPU0Bogo\t: %lu.%02lu\n" + "CPU0ClkTck\t: %ld\n" +#endif + , + sparc_cpu_type, + sparc_fpu_type , + romvec->pv_romvers, + prom_rev, + romvec->pv_printrev >> 16, + romvec->pv_printrev & 0xffff, + &cputypval[0], + ncpus_probed, + num_online_cpus() +#ifndef CONFIG_SMP + , cpu_data(0).udelay_val/(500000/HZ), + (cpu_data(0).udelay_val/(5000/HZ)) % 100, + cpu_data(0).clock_tick +#endif + ); + +#ifdef CONFIG_SMP + smp_bogo(m); +#endif + mmu_info(m); +#ifdef CONFIG_SMP + smp_info(m); +#endif + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + /* The pointer we are returning is arbitrary, + * it just has to be non-NULL and not IS_ERR + * in the success case. + */ + return *pos == 0 ? &c_start : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + extern int stop_a_enabled; void sun_do_break(void) diff --git a/trunk/arch/sparc/kernel/setup_64.c b/trunk/arch/sparc/kernel/setup_64.c index f3b6850cc8db..29bafe051bb1 100644 --- a/trunk/arch/sparc/kernel/setup_64.c +++ b/trunk/arch/sparc/kernel/setup_64.c @@ -339,6 +339,84 @@ void __init setup_arch(char **cmdline_p) paging_init(); } +/* BUFFER is PAGE_SIZE bytes long. */ + +extern void smp_info(struct seq_file *); +extern void smp_bogo(struct seq_file *); +extern void mmu_info(struct seq_file *); + +unsigned int dcache_parity_tl1_occurred; +unsigned int icache_parity_tl1_occurred; + +int ncpus_probed; + +static int show_cpuinfo(struct seq_file *m, void *__unused) +{ + seq_printf(m, + "cpu\t\t: %s\n" + "fpu\t\t: %s\n" + "pmu\t\t: %s\n" + "prom\t\t: %s\n" + "type\t\t: %s\n" + "ncpus probed\t: %d\n" + "ncpus active\t: %d\n" + "D$ parity tl1\t: %u\n" + "I$ parity tl1\t: %u\n" +#ifndef CONFIG_SMP + "Cpu0ClkTck\t: %016lx\n" +#endif + , + sparc_cpu_type, + sparc_fpu_type, + sparc_pmu_type, + prom_version, + ((tlb_type == hypervisor) ? + "sun4v" : + "sun4u"), + ncpus_probed, + num_online_cpus(), + dcache_parity_tl1_occurred, + icache_parity_tl1_occurred +#ifndef CONFIG_SMP + , cpu_data(0).clock_tick +#endif + ); +#ifdef CONFIG_SMP + smp_bogo(m); +#endif + mmu_info(m); +#ifdef CONFIG_SMP + smp_info(m); +#endif + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + /* The pointer we are returning is arbitrary, + * it just has to be non-NULL and not IS_ERR + * in the success case. + */ + return *pos == 0 ? &c_start : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return c_start(m, pos); +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + extern int stop_a_enabled; void sun_do_break(void) diff --git a/trunk/arch/sparc/kernel/smp_32.c b/trunk/arch/sparc/kernel/smp_32.c index 139c312a41f7..850a1360c0d6 100644 --- a/trunk/arch/sparc/kernel/smp_32.c +++ b/trunk/arch/sparc/kernel/smp_32.c @@ -37,6 +37,8 @@ #include "irq.h" volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,}; +unsigned char boot_cpu_id = 0; +unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */ cpumask_t smp_commenced_mask = CPU_MASK_NONE; @@ -51,6 +53,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE; void __cpuinit smp_store_cpu_info(int id) { int cpu_node; + int mid; cpu_data(id).udelay_val = loops_per_jiffy; @@ -58,10 +61,13 @@ void __cpuinit smp_store_cpu_info(int id) cpu_data(id).clock_tick = prom_getintdefault(cpu_node, "clock-frequency", 0); cpu_data(id).prom_node = cpu_node; - cpu_data(id).mid = cpu_get_hwmid(cpu_node); + mid = cpu_get_hwmid(cpu_node); - if (cpu_data(id).mid < 0) - panic("No MID found for CPU%d at node 0x%08d", id, cpu_node); + if (mid < 0) { + printk(KERN_NOTICE "No MID found for CPU%d at node 0x%08d", id, cpu_node); + mid = 0; + } + cpu_data(id).mid = mid; } void __init smp_cpus_done(unsigned int max_cpus) @@ -123,58 +129,13 @@ struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 }; void smp_send_reschedule(int cpu) { - /* - * CPU model dependent way of implementing IPI generation targeting - * a single CPU. The trap handler needs only to do trap entry/return - * to call schedule. - */ - BTFIXUP_CALL(smp_ipi_resched)(cpu); + /* See sparc64 */ } void smp_send_stop(void) { } -void arch_send_call_function_single_ipi(int cpu) -{ - /* trigger one IPI single call on one CPU */ - BTFIXUP_CALL(smp_ipi_single)(cpu); -} - -void arch_send_call_function_ipi_mask(const struct cpumask *mask) -{ - int cpu; - - /* trigger IPI mask call on each CPU */ - for_each_cpu(cpu, mask) - BTFIXUP_CALL(smp_ipi_mask_one)(cpu); -} - -void smp_resched_interrupt(void) -{ - local_cpu_data().irq_resched_count++; - /* - * do nothing, since it all was about calling re-schedule - * routine called by interrupt return code. - */ -} - -void smp_call_function_single_interrupt(void) -{ - irq_enter(); - generic_smp_call_function_single_interrupt(); - local_cpu_data().irq_call_count++; - irq_exit(); -} - -void smp_call_function_interrupt(void) -{ - irq_enter(); - generic_smp_call_function_interrupt(); - local_cpu_data().irq_call_count++; - irq_exit(); -} - void smp_flush_cache_all(void) { xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all)); @@ -190,10 +151,9 @@ void smp_flush_tlb_all(void) void smp_flush_cache_mm(struct mm_struct *mm) { if(mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm); local_flush_cache_mm(mm); } @@ -202,10 +162,9 @@ void smp_flush_cache_mm(struct mm_struct *mm) void smp_flush_tlb_mm(struct mm_struct *mm) { if(mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) { + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) { xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm); if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm) cpumask_copy(mm_cpumask(mm), @@ -221,10 +180,9 @@ void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start, struct mm_struct *mm = vma->vm_mm; if (mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end); local_flush_cache_range(vma, start, end); } @@ -236,10 +194,9 @@ void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, struct mm_struct *mm = vma->vm_mm; if (mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end); local_flush_tlb_range(vma, start, end); } @@ -250,10 +207,9 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page) struct mm_struct *mm = vma->vm_mm; if(mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page); local_flush_cache_page(vma, page); } @@ -264,15 +220,19 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) struct mm_struct *mm = vma->vm_mm; if(mm->context != NO_CONTEXT) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page); local_flush_tlb_page(vma, page); } } +void smp_reschedule_irq(void) +{ + set_need_resched(); +} + void smp_flush_page_to_ram(unsigned long page) { /* Current theory is that those who call this are the one's @@ -289,10 +249,9 @@ void smp_flush_page_to_ram(unsigned long page) void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) { - cpumask_t cpu_mask; - cpumask_copy(&cpu_mask, mm_cpumask(mm)); - cpumask_clear_cpu(smp_processor_id(), &cpu_mask); - if (!cpumask_empty(&cpu_mask)) + cpumask_t cpu_mask = *mm_cpumask(mm); + cpu_clear(smp_processor_id(), cpu_mask); + if (!cpus_empty(cpu_mask)) xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr); local_flush_sig_insns(mm, insn_addr); } @@ -446,7 +405,7 @@ int __cpuinit __cpu_up(unsigned int cpu) }; if (!ret) { - cpumask_set_cpu(cpu, &smp_commenced_mask); + cpu_set(cpu, smp_commenced_mask); while (!cpu_online(cpu)) mb(); } diff --git a/trunk/arch/sparc/kernel/smp_64.c b/trunk/arch/sparc/kernel/smp_64.c index c274a30c3cbf..3e94a8c23238 100644 --- a/trunk/arch/sparc/kernel/smp_64.c +++ b/trunk/arch/sparc/kernel/smp_64.c @@ -121,11 +121,11 @@ void __cpuinit smp_callin(void) /* inform the notifiers about the new cpu */ notify_cpu_starting(cpuid); - while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) + while (!cpu_isset(cpuid, smp_commenced_mask)) rmb(); ipi_call_lock_irq(); - set_cpu_online(cpuid, true); + cpu_set(cpuid, cpu_online_map); ipi_call_unlock_irq(); /* idle thread is expected to have preempt disabled */ @@ -785,7 +785,7 @@ static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask /* Send cross call to all processors mentioned in MASK_P * except self. Really, there are only two cases currently, - * "cpu_online_mask" and "mm_cpumask(mm)". + * "&cpu_online_map" and "&mm->cpu_vm_mask". */ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, const cpumask_t *mask) { @@ -797,7 +797,7 @@ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 d /* Send cross call to all processors except self. */ static void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) { - smp_cross_call_masked(func, ctx, data1, data2, cpu_online_mask); + smp_cross_call_masked(func, ctx, data1, data2, &cpu_online_map); } extern unsigned long xcall_sync_tick; @@ -805,7 +805,7 @@ extern unsigned long xcall_sync_tick; static void smp_start_sync_tick_client(int cpu) { xcall_deliver((u64) &xcall_sync_tick, 0, 0, - cpumask_of(cpu)); + &cpumask_of_cpu(cpu)); } extern unsigned long xcall_call_function; @@ -820,7 +820,7 @@ extern unsigned long xcall_call_function_single; void arch_send_call_function_single_ipi(int cpu) { xcall_deliver((u64) &xcall_call_function_single, 0, 0, - cpumask_of(cpu)); + &cpumask_of_cpu(cpu)); } void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs) @@ -918,7 +918,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) } if (data0) { xcall_deliver(data0, __pa(pg_addr), - (u64) pg_addr, cpumask_of(cpu)); + (u64) pg_addr, &cpumask_of_cpu(cpu)); #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes_xcall); #endif @@ -954,7 +954,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) } if (data0) { xcall_deliver(data0, __pa(pg_addr), - (u64) pg_addr, cpu_online_mask); + (u64) pg_addr, &cpu_online_map); #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes_xcall); #endif @@ -1197,32 +1197,32 @@ void __devinit smp_fill_in_sib_core_maps(void) for_each_present_cpu(i) { unsigned int j; - cpumask_clear(&cpu_core_map[i]); + cpus_clear(cpu_core_map[i]); if (cpu_data(i).core_id == 0) { - cpumask_set_cpu(i, &cpu_core_map[i]); + cpu_set(i, cpu_core_map[i]); continue; } for_each_present_cpu(j) { if (cpu_data(i).core_id == cpu_data(j).core_id) - cpumask_set_cpu(j, &cpu_core_map[i]); + cpu_set(j, cpu_core_map[i]); } } for_each_present_cpu(i) { unsigned int j; - cpumask_clear(&per_cpu(cpu_sibling_map, i)); + cpus_clear(per_cpu(cpu_sibling_map, i)); if (cpu_data(i).proc_id == -1) { - cpumask_set_cpu(i, &per_cpu(cpu_sibling_map, i)); + cpu_set(i, per_cpu(cpu_sibling_map, i)); continue; } for_each_present_cpu(j) { if (cpu_data(i).proc_id == cpu_data(j).proc_id) - cpumask_set_cpu(j, &per_cpu(cpu_sibling_map, i)); + cpu_set(j, per_cpu(cpu_sibling_map, i)); } } } @@ -1232,10 +1232,10 @@ int __cpuinit __cpu_up(unsigned int cpu) int ret = smp_boot_one_cpu(cpu); if (!ret) { - cpumask_set_cpu(cpu, &smp_commenced_mask); - while (!cpu_online(cpu)) + cpu_set(cpu, smp_commenced_mask); + while (!cpu_isset(cpu, cpu_online_map)) mb(); - if (!cpu_online(cpu)) { + if (!cpu_isset(cpu, cpu_online_map)) { ret = -ENODEV; } else { /* On SUN4V, writes to %tick and %stick are @@ -1269,7 +1269,7 @@ void cpu_play_dead(void) tb->nonresum_mondo_pa, 0); } - cpumask_clear_cpu(cpu, &smp_commenced_mask); + cpu_clear(cpu, smp_commenced_mask); membar_safe("#Sync"); local_irq_disable(); @@ -1290,13 +1290,13 @@ int __cpu_disable(void) cpuinfo_sparc *c; int i; - for_each_cpu(i, &cpu_core_map[cpu]) - cpumask_clear_cpu(cpu, &cpu_core_map[i]); - cpumask_clear(&cpu_core_map[cpu]); + for_each_cpu_mask(i, cpu_core_map[cpu]) + cpu_clear(cpu, cpu_core_map[i]); + cpus_clear(cpu_core_map[cpu]); - for_each_cpu(i, &per_cpu(cpu_sibling_map, cpu)) - cpumask_clear_cpu(cpu, &per_cpu(cpu_sibling_map, i)); - cpumask_clear(&per_cpu(cpu_sibling_map, cpu)); + for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu)) + cpu_clear(cpu, per_cpu(cpu_sibling_map, i)); + cpus_clear(per_cpu(cpu_sibling_map, cpu)); c = &cpu_data(cpu); @@ -1313,7 +1313,7 @@ int __cpu_disable(void) local_irq_disable(); ipi_call_lock(); - set_cpu_online(cpu, false); + cpu_clear(cpu, cpu_online_map); ipi_call_unlock(); cpu_map_rebuild(); @@ -1327,11 +1327,11 @@ void __cpu_die(unsigned int cpu) for (i = 0; i < 100; i++) { smp_rmb(); - if (!cpumask_test_cpu(cpu, &smp_commenced_mask)) + if (!cpu_isset(cpu, smp_commenced_mask)) break; msleep(100); } - if (cpumask_test_cpu(cpu, &smp_commenced_mask)) { + if (cpu_isset(cpu, smp_commenced_mask)) { printk(KERN_ERR "CPU %u didn't die...\n", cpu); } else { #if defined(CONFIG_SUN_LDOMS) @@ -1341,7 +1341,7 @@ void __cpu_die(unsigned int cpu) do { hv_err = sun4v_cpu_stop(cpu); if (hv_err == HV_EOK) { - set_cpu_present(cpu, false); + cpu_clear(cpu, cpu_present_map); break; } } while (--limit > 0); @@ -1362,7 +1362,7 @@ void __init smp_cpus_done(unsigned int max_cpus) void smp_send_reschedule(int cpu) { xcall_deliver((u64) &xcall_receive_signal, 0, 0, - cpumask_of(cpu)); + &cpumask_of_cpu(cpu)); } void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs) diff --git a/trunk/arch/sparc/kernel/sun4c_irq.c b/trunk/arch/sparc/kernel/sun4c_irq.c index f6bf25a2ff80..90eea38ad66f 100644 --- a/trunk/arch/sparc/kernel/sun4c_irq.c +++ b/trunk/arch/sparc/kernel/sun4c_irq.c @@ -65,94 +65,62 @@ */ unsigned char __iomem *interrupt_enable; -static void sun4c_mask_irq(struct irq_data *data) +static void sun4c_disable_irq(unsigned int irq_nr) { - unsigned long mask = (unsigned long)data->chip_data; - - if (mask) { - unsigned long flags; - - local_irq_save(flags); - mask = sbus_readb(interrupt_enable) & ~mask; - sbus_writeb(mask, interrupt_enable); + unsigned long flags; + unsigned char current_mask, new_mask; + + local_irq_save(flags); + irq_nr &= (NR_IRQS - 1); + current_mask = sbus_readb(interrupt_enable); + switch (irq_nr) { + case 1: + new_mask = ((current_mask) & (~(SUN4C_INT_E1))); + break; + case 8: + new_mask = ((current_mask) & (~(SUN4C_INT_E8))); + break; + case 10: + new_mask = ((current_mask) & (~(SUN4C_INT_E10))); + break; + case 14: + new_mask = ((current_mask) & (~(SUN4C_INT_E14))); + break; + default: local_irq_restore(flags); + return; } + sbus_writeb(new_mask, interrupt_enable); + local_irq_restore(flags); } -static void sun4c_unmask_irq(struct irq_data *data) +static void sun4c_enable_irq(unsigned int irq_nr) { - unsigned long mask = (unsigned long)data->chip_data; - - if (mask) { - unsigned long flags; - - local_irq_save(flags); - mask = sbus_readb(interrupt_enable) | mask; - sbus_writeb(mask, interrupt_enable); + unsigned long flags; + unsigned char current_mask, new_mask; + + local_irq_save(flags); + irq_nr &= (NR_IRQS - 1); + current_mask = sbus_readb(interrupt_enable); + switch (irq_nr) { + case 1: + new_mask = ((current_mask) | SUN4C_INT_E1); + break; + case 8: + new_mask = ((current_mask) | SUN4C_INT_E8); + break; + case 10: + new_mask = ((current_mask) | SUN4C_INT_E10); + break; + case 14: + new_mask = ((current_mask) | SUN4C_INT_E14); + break; + default: local_irq_restore(flags); + return; } -} - -static unsigned int sun4c_startup_irq(struct irq_data *data) -{ - irq_link(data->irq); - sun4c_unmask_irq(data); - - return 0; -} - -static void sun4c_shutdown_irq(struct irq_data *data) -{ - sun4c_mask_irq(data); - irq_unlink(data->irq); -} - -static struct irq_chip sun4c_irq = { - .name = "sun4c", - .irq_startup = sun4c_startup_irq, - .irq_shutdown = sun4c_shutdown_irq, - .irq_mask = sun4c_mask_irq, - .irq_unmask = sun4c_unmask_irq, -}; - -static unsigned int sun4c_build_device_irq(struct platform_device *op, - unsigned int real_irq) -{ - unsigned int irq; - - if (real_irq >= 16) { - prom_printf("Bogus sun4c IRQ %u\n", real_irq); - prom_halt(); - } - - irq = irq_alloc(real_irq, real_irq); - if (irq) { - unsigned long mask = 0UL; - - switch (real_irq) { - case 1: - mask = SUN4C_INT_E1; - break; - case 8: - mask = SUN4C_INT_E8; - break; - case 10: - mask = SUN4C_INT_E10; - break; - case 14: - mask = SUN4C_INT_E14; - break; - default: - /* All the rest are either always enabled, - * or are for signalling software interrupts. - */ - break; - } - irq_set_chip_and_handler_name(irq, &sun4c_irq, - handle_level_irq, "level"); - irq_set_chip_data(irq, (void *)mask); - } - return irq; + sbus_writeb(new_mask, interrupt_enable); + local_irq_restore(flags); } struct sun4c_timer_info { @@ -176,9 +144,8 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) static void __init sun4c_init_timers(irq_handler_t counter_fn) { - const struct linux_prom_irqs *prom_irqs; + const struct linux_prom_irqs *irq; struct device_node *dp; - unsigned int irq; const u32 *addr; int err; @@ -196,9 +163,9 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) sun4c_timers = (void __iomem *) (unsigned long) addr[0]; - prom_irqs = of_get_property(dp, "intr", NULL); + irq = of_get_property(dp, "intr", NULL); of_node_put(dp); - if (!prom_irqs) { + if (!irq) { prom_printf("sun4c_init_timers: No intr property\n"); prom_halt(); } @@ -211,15 +178,15 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn) master_l10_counter = &sun4c_timers->l10_count; - irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); - err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); + err = request_irq(irq[0].pri, counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), + "timer", NULL); if (err) { prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); prom_halt(); } - /* disable timer interrupt */ - sun4c_mask_irq(irq_get_irq_data(irq)); + sun4c_disable_irq(irq[1].pri); } #ifdef CONFIG_SMP @@ -248,11 +215,14 @@ void __init sun4c_init_IRQ(void) interrupt_enable = (void __iomem *) (unsigned long) addr[0]; + BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); - sparc_irq_config.init_timers = sun4c_init_timers; - sparc_irq_config.build_device_irq = sun4c_build_device_irq; + sparc_irq_config.init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); diff --git a/trunk/arch/sparc/kernel/sun4d_irq.c b/trunk/arch/sparc/kernel/sun4d_irq.c index a9ea60eb2c10..77b4a8992710 100644 --- a/trunk/arch/sparc/kernel/sun4d_irq.c +++ b/trunk/arch/sparc/kernel/sun4d_irq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "kernel.h" #include "irq.h" @@ -23,20 +22,22 @@ * cpu local. CPU local interrupts cover the timer interrupts * and whatnot, and we encode those as normal PILs between * 0 and 15. - * SBUS interrupts are encodes as a combination of board, level and slot. + * + * SBUS interrupts are encoded integers including the board number + * (plus one), the SBUS level, and the SBUS slot number. Sun4D + * IRQ dispatch is done by: + * + * 1) Reading the BW local interrupt table in order to get the bus + * interrupt mask. + * + * This table is indexed by SBUS interrupt level which can be + * derived from the PIL we got interrupted on. + * + * 2) For each bus showing interrupt pending from #1, read the + * SBI interrupt state register. This will indicate which slots + * have interrupts pending for that SBUS interrupt level. */ -struct sun4d_handler_data { - unsigned int cpuid; /* target cpu */ - unsigned int real_irq; /* interrupt level */ -}; - - -static unsigned int sun4d_encode_irq(int board, int lvl, int slot) -{ - return (board + 1) << 5 | (lvl << 2) | slot; -} - struct sun4d_timer_regs { u32 l10_timer_limit; u32 l10_cur_countx; @@ -47,12 +48,17 @@ struct sun4d_timer_regs { static struct sun4d_timer_regs __iomem *sun4d_timers; -#define SUN4D_TIMER_IRQ 10 +#define TIMER_IRQ 10 -/* Specify which cpu handle interrupts from which board. - * Index is board - value is cpu. - */ -static unsigned char board_to_cpu[32]; +#define MAX_STATIC_ALLOC 4 +static unsigned char sbus_tid[32]; + +static struct irqaction *irq_action[NR_IRQS]; + +static struct sbus_action { + struct irqaction *action; + /* For SMP this needs to be extended */ +} *sbus_actions; static int pil_to_sbus[] = { 0, @@ -73,81 +79,152 @@ static int pil_to_sbus[] = { 0, }; +static int sbus_to_pil[] = { + 0, + 2, + 3, + 5, + 7, + 9, + 11, + 13, +}; + +static int nsbi; + /* Exported for sun4d_smp.c */ DEFINE_SPINLOCK(sun4d_imsk_lock); -/* SBUS interrupts are encoded integers including the board number - * (plus one), the SBUS level, and the SBUS slot number. Sun4D - * IRQ dispatch is done by: - * - * 1) Reading the BW local interrupt table in order to get the bus - * interrupt mask. - * - * This table is indexed by SBUS interrupt level which can be - * derived from the PIL we got interrupted on. - * - * 2) For each bus showing interrupt pending from #1, read the - * SBI interrupt state register. This will indicate which slots - * have interrupts pending for that SBUS interrupt level. - * - * 3) Call the genreric IRQ support. - */ -static void sun4d_sbus_handler_irq(int sbusl) +int show_sun4d_interrupts(struct seq_file *p, void *v) { - unsigned int bus_mask; - unsigned int sbino, slot; - unsigned int sbil; - - bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff; - bw_clear_intr_mask(sbusl, bus_mask); - - sbil = (sbusl << 2); - /* Loop for each pending SBI */ - for (sbino = 0; bus_mask; sbino++) { - unsigned int idx, mask; - - bus_mask >>= 1; - if (!(bus_mask & 1)) - continue; - /* XXX This seems to ACK the irq twice. acquire_sbi() - * XXX uses swap, therefore this writes 0xf << sbil, - * XXX then later release_sbi() will write the individual - * XXX bits which were set again. - */ - mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil); - mask &= (0xf << sbil); - - /* Loop for each pending SBI slot */ - idx = 0; - slot = (1 << sbil); - while (mask != 0) { - unsigned int pil; - struct irq_bucket *p; - - idx++; - slot <<= 1; - if (!(mask & slot)) - continue; - - mask &= ~slot; - pil = sun4d_encode_irq(sbino, sbil, idx); - - p = irq_map[pil]; - while (p) { - struct irq_bucket *next; - - next = p->next; - generic_handle_irq(p->irq); - p = next; + int i = *(loff_t *) v, j = 0, k = 0, sbusl; + struct irqaction *action; + unsigned long flags; +#ifdef CONFIG_SMP + int x; +#endif + + spin_lock_irqsave(&irq_action_lock, flags); + if (i < NR_IRQS) { + sbusl = pil_to_sbus[i]; + if (!sbusl) { + action = *(i + irq_action); + if (!action) + goto out_unlock; + } else { + for (j = 0; j < nsbi; j++) { + for (k = 0; k < 4; k++) + action = sbus_actions[(j << 5) + (sbusl << 2) + k].action; + if (action) + goto found_it; + } + goto out_unlock; + } +found_it: seq_printf(p, "%3d: ", i); +#ifndef CONFIG_SMP + seq_printf(p, "%10u ", kstat_irqs(i)); +#else + for_each_online_cpu(x) + seq_printf(p, "%10u ", + kstat_cpu(cpu_logical_map(x)).irqs[i]); +#endif + seq_printf(p, "%c %s", + (action->flags & IRQF_DISABLED) ? '+' : ' ', + action->name); + action = action->next; + for (;;) { + for (; action; action = action->next) { + seq_printf(p, ",%s %s", + (action->flags & IRQF_DISABLED) ? " +" : "", + action->name); + } + if (!sbusl) + break; + k++; + if (k < 4) { + action = sbus_actions[(j << 5) + (sbusl << 2) + k].action; + } else { + j++; + if (j == nsbi) + break; + k = 0; + action = sbus_actions[(j << 5) + (sbusl << 2)].action; } - release_sbi(SBI2DEVID(sbino), slot); } + seq_putc(p, '\n'); } +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); + return 0; +} + +void sun4d_free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction *action, **actionp; + struct irqaction *tmp = NULL; + unsigned long flags; + + spin_lock_irqsave(&irq_action_lock, flags); + if (irq < 15) + actionp = irq + irq_action; + else + actionp = &(sbus_actions[irq - (1 << 5)].action); + action = *actionp; + if (!action) { + printk(KERN_ERR "Trying to free free IRQ%d\n", irq); + goto out_unlock; + } + if (dev_id) { + for (; action; action = action->next) { + if (action->dev_id == dev_id) + break; + tmp = action; + } + if (!action) { + printk(KERN_ERR "Trying to free free shared IRQ%d\n", + irq); + goto out_unlock; + } + } else if (action->flags & IRQF_SHARED) { + printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n", + irq); + goto out_unlock; + } + if (action->flags & SA_STATIC_ALLOC) { + /* + * This interrupt is marked as specially allocated + * so it is a bad idea to free it. + */ + printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n", + irq, action->name); + goto out_unlock; + } + + if (tmp) + tmp->next = action->next; + else + *actionp = action->next; + + spin_unlock_irqrestore(&irq_action_lock, flags); + + synchronize_irq(irq); + + spin_lock_irqsave(&irq_action_lock, flags); + + kfree(action); + + if (!(*actionp)) + __disable_irq(irq); + +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); } void sun4d_handler_irq(int pil, struct pt_regs *regs) { struct pt_regs *old_regs; + struct irqaction *action; + int cpu = smp_processor_id(); /* SBUS IRQ level (1 - 7) */ int sbusl = pil_to_sbus[pil]; @@ -156,95 +233,159 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs) cc_set_iclr(1 << pil); -#ifdef CONFIG_SMP - /* - * Check IPI data structures after IRQ has been cleared. Hard and Soft - * IRQ can happen at the same time, so both cases are always handled. - */ - if (pil == SUN4D_IPI_IRQ) - sun4d_ipi_interrupt(); -#endif - old_regs = set_irq_regs(regs); irq_enter(); - if (sbusl == 0) { - /* cpu interrupt */ - struct irq_bucket *p; - - p = irq_map[pil]; - while (p) { - struct irq_bucket *next; - - next = p->next; - generic_handle_irq(p->irq); - p = next; - } + kstat_cpu(cpu).irqs[pil]++; + if (!sbusl) { + action = *(pil + irq_action); + if (!action) + unexpected_irq(pil, NULL, regs); + do { + action->handler(pil, action->dev_id); + action = action->next; + } while (action); } else { - /* SBUS interrupt */ - sun4d_sbus_handler_irq(sbusl); + int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff; + int sbino; + struct sbus_action *actionp; + unsigned mask, slot; + int sbil = (sbusl << 2); + + bw_clear_intr_mask(sbusl, bus_mask); + + /* Loop for each pending SBI */ + for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) + if (bus_mask & 1) { + mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil); + mask &= (0xf << sbil); + actionp = sbus_actions + (sbino << 5) + (sbil); + /* Loop for each pending SBI slot */ + for (slot = (1 << sbil); mask; slot <<= 1, actionp++) + if (mask & slot) { + mask &= ~slot; + action = actionp->action; + + if (!action) + unexpected_irq(pil, NULL, regs); + do { + action->handler(pil, action->dev_id); + action = action->next; + } while (action); + release_sbi(SBI2DEVID(sbino), slot); + } + } } irq_exit(); set_irq_regs(old_regs); } - -static void sun4d_mask_irq(struct irq_data *data) +int sun4d_request_irq(unsigned int irq, + irq_handler_t handler, + unsigned long irqflags, const char *devname, void *dev_id) { - struct sun4d_handler_data *handler_data = data->handler_data; - unsigned int real_irq; -#ifdef CONFIG_SMP - int cpuid = handler_data->cpuid; + struct irqaction *action, *tmp = NULL, **actionp; unsigned long flags; -#endif - real_irq = handler_data->real_irq; -#ifdef CONFIG_SMP - spin_lock_irqsave(&sun4d_imsk_lock, flags); - cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq)); - spin_unlock_irqrestore(&sun4d_imsk_lock, flags); -#else - cc_set_imsk(cc_get_imsk() | (1 << real_irq)); -#endif + int ret; + + if (irq > 14 && irq < (1 << 5)) { + ret = -EINVAL; + goto out; + } + + if (!handler) { + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&irq_action_lock, flags); + + if (irq >= (1 << 5)) + actionp = &(sbus_actions[irq - (1 << 5)].action); + else + actionp = irq + irq_action; + action = *actionp; + + if (action) { + if ((action->flags & IRQF_SHARED) && (irqflags & IRQF_SHARED)) { + for (tmp = action; tmp->next; tmp = tmp->next) + /* find last entry - tmp used below */; + } else { + ret = -EBUSY; + goto out_unlock; + } + if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) { + printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n", + irq); + ret = -EBUSY; + goto out_unlock; + } + action = NULL; /* Or else! */ + } + + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + if (irqflags & SA_STATIC_ALLOC) { + if (static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", + irq, devname); + } + + if (action == NULL) + action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); + + if (!action) { + ret = -ENOMEM; + goto out_unlock; + } + + action->handler = handler; + action->flags = irqflags; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + if (tmp) + tmp->next = action; + else + *actionp = action; + + __enable_irq(irq); + + ret = 0; +out_unlock: + spin_unlock_irqrestore(&irq_action_lock, flags); +out: + return ret; } -static void sun4d_unmask_irq(struct irq_data *data) +static void sun4d_disable_irq(unsigned int irq) { - struct sun4d_handler_data *handler_data = data->handler_data; - unsigned int real_irq; -#ifdef CONFIG_SMP - int cpuid = handler_data->cpuid; + int tid = sbus_tid[(irq >> 5) - 1]; unsigned long flags; -#endif - real_irq = handler_data->real_irq; -#ifdef CONFIG_SMP + if (irq < NR_IRQS) + return; + spin_lock_irqsave(&sun4d_imsk_lock, flags); - cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq)); + cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7])); spin_unlock_irqrestore(&sun4d_imsk_lock, flags); -#else - cc_set_imsk(cc_get_imsk() | ~(1 << real_irq)); -#endif } -static unsigned int sun4d_startup_irq(struct irq_data *data) +static void sun4d_enable_irq(unsigned int irq) { - irq_link(data->irq); - sun4d_unmask_irq(data); - return 0; -} + int tid = sbus_tid[(irq >> 5) - 1]; + unsigned long flags; -static void sun4d_shutdown_irq(struct irq_data *data) -{ - sun4d_mask_irq(data); - irq_unlink(data->irq); -} + if (irq < NR_IRQS) + return; -struct irq_chip sun4d_irq = { - .name = "sun4d", - .irq_startup = sun4d_startup_irq, - .irq_shutdown = sun4d_shutdown_irq, - .irq_unmask = sun4d_unmask_irq, - .irq_mask = sun4d_mask_irq, -}; + spin_lock_irqsave(&sun4d_imsk_lock, flags); + cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7])); + spin_unlock_irqrestore(&sun4d_imsk_lock, flags); +} #ifdef CONFIG_SMP static void sun4d_set_cpu_int(int cpu, int level) @@ -272,7 +413,7 @@ void __init sun4d_distribute_irqs(void) for_each_node_by_name(dp, "sbi") { int devid = of_getintprop_default(dp, "device-id", 0); int board = of_getintprop_default(dp, "board#", 0); - board_to_cpu[board] = cpuid; + sbus_tid[board] = cpuid; set_sbi_tid(devid, cpuid << 3); } printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid); @@ -302,16 +443,15 @@ static void __init sun4d_load_profile_irqs(void) unsigned int sun4d_build_device_irq(struct platform_device *op, unsigned int real_irq) { + static int pil_to_sbus[] = { + 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, + }; struct device_node *dp = op->dev.of_node; struct device_node *io_unit, *sbi = dp->parent; const struct linux_prom_registers *regs; - struct sun4d_handler_data *handler_data; - unsigned int pil; - unsigned int irq; int board, slot; int sbusl; - irq = 0; while (sbi) { if (!strcmp(sbi->name, "sbi")) break; @@ -344,28 +484,7 @@ unsigned int sun4d_build_device_irq(struct platform_device *op, sbusl = pil_to_sbus[real_irq]; if (sbusl) - pil = sun4d_encode_irq(board, sbusl, slot); - else - pil = real_irq; - - irq = irq_alloc(real_irq, pil); - if (irq == 0) - goto err_out; - - handler_data = irq_get_handler_data(irq); - if (unlikely(handler_data)) - goto err_out; - - handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC); - if (unlikely(!handler_data)) { - prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n"); - prom_halt(); - } - handler_data->cpuid = board_to_cpu[board]; - handler_data->real_irq = real_irq; - irq_set_chip_and_handler_name(irq, &sun4d_irq, - handle_level_irq, "level"); - irq_set_handler_data(irq, handler_data); + return (((board + 1) << 5) + (sbusl << 2) + slot); err_out: return real_irq; @@ -399,7 +518,6 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) { struct device_node *dp; struct resource res; - unsigned int irq; const u32 *reg; int err; @@ -434,8 +552,9 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) master_l10_counter = &sun4d_timers->l10_cur_count; - irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ); - err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); + err = request_irq(TIMER_IRQ, counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), + "timer", NULL); if (err) { prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err); @@ -448,16 +567,27 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) void __init sun4d_init_sbi_irq(void) { struct device_node *dp; - int target_cpu; + int target_cpu = 0; +#ifdef CONFIG_SMP target_cpu = boot_cpu_id; +#endif + + nsbi = 0; + for_each_node_by_name(dp, "sbi") + nsbi++; + sbus_actions = kzalloc(nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); + if (!sbus_actions) { + prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); + prom_halt(); + } for_each_node_by_name(dp, "sbi") { int devid = of_getintprop_default(dp, "device-id", 0); int board = of_getintprop_default(dp, "board#", 0); unsigned int mask; set_sbi_tid(devid, target_cpu << 3); - board_to_cpu[board] = target_cpu; + sbus_tid[board] = target_cpu; /* Get rid of pending irqs from PROM */ mask = acquire_sbi(devid, 0xffffffff); @@ -473,10 +603,12 @@ void __init sun4d_init_IRQ(void) { local_irq_disable(); + BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); - sparc_irq_config.init_timers = sun4d_init_timers; + sparc_irq_config.init_timers = sun4d_init_timers; sparc_irq_config.build_device_irq = sun4d_build_device_irq; #ifdef CONFIG_SMP diff --git a/trunk/arch/sparc/kernel/sun4d_smp.c b/trunk/arch/sparc/kernel/sun4d_smp.c index 133387980b56..475d50b96cd0 100644 --- a/trunk/arch/sparc/kernel/sun4d_smp.c +++ b/trunk/arch/sparc/kernel/sun4d_smp.c @@ -32,7 +32,6 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon return val; } -static void smp4d_ipi_init(void); static void smp_setup_percpu_timer(void); static unsigned char cpu_leds[32]; @@ -81,6 +80,8 @@ void __cpuinit smp4d_callin(void) local_flush_cache_all(); local_flush_tlb_all(); + cpu_probe(); + while ((unsigned long)current_set[cpuid] < PAGE_OFFSET) barrier(); @@ -104,7 +105,7 @@ void __cpuinit smp4d_callin(void) local_irq_enable(); /* We don't allow PIL 14 yet */ - while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) + while (!cpu_isset(cpuid, smp_commenced_mask)) barrier(); spin_lock_irqsave(&sun4d_imsk_lock, flags); @@ -119,7 +120,6 @@ void __cpuinit smp4d_callin(void) */ void __init smp4d_boot_cpus(void) { - smp4d_ipi_init(); if (boot_cpu_id) current_set[0] = NULL; smp_setup_percpu_timer(); @@ -191,80 +191,6 @@ void __init smp4d_smp_done(void) sun4d_distribute_irqs(); } -/* Memory structure giving interrupt handler information about IPI generated */ -struct sun4d_ipi_work { - int single; - int msk; - int resched; -}; - -static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work); - -/* Initialize IPIs on the SUN4D SMP machine */ -static void __init smp4d_ipi_init(void) -{ - int cpu; - struct sun4d_ipi_work *work; - - printk(KERN_INFO "smp4d: setup IPI at IRQ %d\n", SUN4D_IPI_IRQ); - - for_each_possible_cpu(cpu) { - work = &per_cpu(sun4d_ipi_work, cpu); - work->single = work->msk = work->resched = 0; - } -} - -void sun4d_ipi_interrupt(void) -{ - struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work); - - if (work->single) { - work->single = 0; - smp_call_function_single_interrupt(); - } - if (work->msk) { - work->msk = 0; - smp_call_function_interrupt(); - } - if (work->resched) { - work->resched = 0; - smp_resched_interrupt(); - } -} - -static void smp4d_ipi_single(int cpu) -{ - struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); - - /* Mark work */ - work->single = 1; - - /* Generate IRQ on the CPU */ - sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); -} - -static void smp4d_ipi_mask_one(int cpu) -{ - struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); - - /* Mark work */ - work->msk = 1; - - /* Generate IRQ on the CPU */ - sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); -} - -static void smp4d_ipi_resched(int cpu) -{ - struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); - - /* Mark work */ - work->resched = 1; - - /* Generate IRQ on the CPU (any IRQ will cause resched) */ - sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); -} - static struct smp_funcall { smpfunc_t func; unsigned long arg1; @@ -313,10 +239,10 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, { register int i; - cpumask_clear_cpu(smp_processor_id(), &mask); - cpumask_and(&mask, cpu_online_mask, &mask); + cpu_clear(smp_processor_id(), mask); + cpus_and(mask, cpu_online_map, mask); for (i = 0; i <= high; i++) { - if (cpumask_test_cpu(i, &mask)) { + if (cpu_isset(i, mask)) { ccall_info.processors_in[i] = 0; ccall_info.processors_out[i] = 0; sun4d_send_ipi(i, IRQ_CROSS_CALL); @@ -329,7 +255,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_in[i]) barrier(); @@ -337,7 +263,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_out[i]) barrier(); @@ -430,9 +356,6 @@ void __init sun4d_init_smp(void) BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM); for (i = 0; i < NR_CPUS; i++) { ccall_info.processors_in[i] = 1; diff --git a/trunk/arch/sparc/kernel/sun4m_irq.c b/trunk/arch/sparc/kernel/sun4m_irq.c index 422c16dad1f6..69df6257a32e 100644 --- a/trunk/arch/sparc/kernel/sun4m_irq.c +++ b/trunk/arch/sparc/kernel/sun4m_irq.c @@ -100,11 +100,6 @@ struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; struct sun4m_irq_global __iomem *sun4m_irq_global; -struct sun4m_handler_data { - bool percpu; - long mask; -}; - /* Dave Redman (djhr@tadpole.co.uk) * The sun4m interrupt registers. */ @@ -147,9 +142,9 @@ struct sun4m_handler_data { #define OBP_INT_LEVEL_VME 0x40 #define SUN4M_TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10) -#define SUN4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14) +#define SUM4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14) -static unsigned long sun4m_imask[0x50] = { +static unsigned long irq_mask[0x50] = { /* 0x00 - SMP */ 0, SUN4M_SOFT_INT(1), SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), @@ -174,7 +169,7 @@ static unsigned long sun4m_imask[0x50] = { SUN4M_INT_VIDEO, SUN4M_INT_MODULE, SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY, (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), - SUN4M_INT_AUDIO, SUN4M_INT_E14, SUN4M_INT_MODULE_ERR, + SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR, /* 0x30 - sbus */ 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1), 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3), @@ -187,110 +182,105 @@ static unsigned long sun4m_imask[0x50] = { 0, SUN4M_INT_VME(6), 0, 0 }; -static void sun4m_mask_irq(struct irq_data *data) +static unsigned long sun4m_get_irqmask(unsigned int irq) { - struct sun4m_handler_data *handler_data = data->handler_data; - int cpu = smp_processor_id(); + unsigned long mask; - if (handler_data->mask) { - unsigned long flags; + if (irq < 0x50) + mask = irq_mask[irq]; + else + mask = 0; - local_irq_save(flags); - if (handler_data->percpu) { - sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->set); - } else { - sbus_writel(handler_data->mask, &sun4m_irq_global->mask_set); - } - local_irq_restore(flags); - } + if (!mask) + printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n", + irq); + + return mask; } -static void sun4m_unmask_irq(struct irq_data *data) +static void sun4m_disable_irq(unsigned int irq_nr) { - struct sun4m_handler_data *handler_data = data->handler_data; + unsigned long mask, flags; int cpu = smp_processor_id(); - if (handler_data->mask) { - unsigned long flags; + mask = sun4m_get_irqmask(irq_nr); + local_irq_save(flags); + if (irq_nr > 15) + sbus_writel(mask, &sun4m_irq_global->mask_set); + else + sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); + local_irq_restore(flags); +} +static void sun4m_enable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + int cpu = smp_processor_id(); + + /* Dreadful floppy hack. When we use 0x2b instead of + * 0x0b the system blows (it starts to whistle!). + * So we continue to use 0x0b. Fixme ASAP. --P3 + */ + if (irq_nr != 0x0b) { + mask = sun4m_get_irqmask(irq_nr); + local_irq_save(flags); + if (irq_nr > 15) + sbus_writel(mask, &sun4m_irq_global->mask_clear); + else + sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); + local_irq_restore(flags); + } else { local_irq_save(flags); - if (handler_data->percpu) { - sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->clear); - } else { - sbus_writel(handler_data->mask, &sun4m_irq_global->mask_clear); - } + sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); local_irq_restore(flags); } } -static unsigned int sun4m_startup_irq(struct irq_data *data) -{ - irq_link(data->irq); - sun4m_unmask_irq(data); - return 0; -} +static unsigned long cpu_pil_to_imask[16] = { +/*0*/ 0x00000000, +/*1*/ 0x00000000, +/*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), +/*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), +/*4*/ SUN4M_INT_SCSI, +/*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), +/*6*/ SUN4M_INT_ETHERNET, +/*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), +/*8*/ SUN4M_INT_VIDEO, +/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, +/*10*/ SUN4M_INT_REALTIME, +/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, +/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, +/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO, +/*14*/ SUN4M_INT_E14, +/*15*/ SUN4M_INT_ERROR, +}; -static void sun4m_shutdown_irq(struct irq_data *data) +/* We assume the caller has disabled local interrupts when these are called, + * or else very bizarre behavior will result. + */ +static void sun4m_disable_pil_irq(unsigned int pil) { - sun4m_mask_irq(data); - irq_unlink(data->irq); + sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); } -static struct irq_chip sun4m_irq = { - .name = "sun4m", - .irq_startup = sun4m_startup_irq, - .irq_shutdown = sun4m_shutdown_irq, - .irq_mask = sun4m_mask_irq, - .irq_unmask = sun4m_unmask_irq, -}; - - -static unsigned int sun4m_build_device_irq(struct platform_device *op, - unsigned int real_irq) +static void sun4m_enable_pil_irq(unsigned int pil) { - struct sun4m_handler_data *handler_data; - unsigned int irq; - unsigned int pil; - - if (real_irq >= OBP_INT_LEVEL_VME) { - prom_printf("Bogus sun4m IRQ %u\n", real_irq); - prom_halt(); - } - pil = (real_irq & 0xf); - irq = irq_alloc(real_irq, pil); - - if (irq == 0) - goto out; - - handler_data = irq_get_handler_data(irq); - if (unlikely(handler_data)) - goto out; - - handler_data = kzalloc(sizeof(struct sun4m_handler_data), GFP_ATOMIC); - if (unlikely(!handler_data)) { - prom_printf("IRQ: kzalloc(sun4m_handler_data) failed.\n"); - prom_halt(); - } - - handler_data->mask = sun4m_imask[real_irq]; - handler_data->percpu = real_irq < OBP_INT_LEVEL_ONBOARD; - irq_set_chip_and_handler_name(irq, &sun4m_irq, - handle_level_irq, "level"); - irq_set_handler_data(irq, handler_data); - -out: - return irq; + sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); } #ifdef CONFIG_SMP static void sun4m_send_ipi(int cpu, int level) { - sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set); + unsigned long mask = sun4m_get_irqmask(level); + + sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); } static void sun4m_clear_ipi(int cpu, int level) { - sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->clear); + unsigned long mask = sun4m_get_irqmask(level); + + sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); } static void sun4m_set_udt(int cpu) @@ -353,15 +343,7 @@ void sun4m_nmi(struct pt_regs *regs) prom_halt(); } -void sun4m_unmask_profile_irq(void) -{ - unsigned long flags; - - local_irq_save(flags); - sbus_writel(sun4m_imask[SUN4M_PROFILE_IRQ], &sun4m_irq_global->mask_clear); - local_irq_restore(flags); -} - +/* Exported for sun4m_smp.c */ void sun4m_clear_profile_irq(int cpu) { sbus_readl(&timers_percpu[cpu]->l14_limit); @@ -376,7 +358,6 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) { struct device_node *dp = of_find_node_by_name(NULL, "counter"); int i, err, len, num_cpu_timers; - unsigned int irq; const u32 *addr; if (!dp) { @@ -403,9 +384,8 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) master_l10_counter = &timers_global->l10_count; - irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ); - - err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); + err = request_irq(SUN4M_TIMER_IRQ, counter_fn, + (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); if (err) { printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", err); @@ -472,11 +452,14 @@ void __init sun4m_init_IRQ(void) if (num_cpu_iregs == 4) sbus_writel(0, &sun4m_irq_global->interrupt_target); + BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); sparc_irq_config.init_timers = sun4m_init_timers; - sparc_irq_config.build_device_irq = sun4m_build_device_irq; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); diff --git a/trunk/arch/sparc/kernel/sun4m_smp.c b/trunk/arch/sparc/kernel/sun4m_smp.c index 594768686525..5cc7dc51de3d 100644 --- a/trunk/arch/sparc/kernel/sun4m_smp.c +++ b/trunk/arch/sparc/kernel/sun4m_smp.c @@ -15,9 +15,6 @@ #include "irq.h" #include "kernel.h" -#define IRQ_IPI_SINGLE 12 -#define IRQ_IPI_MASK 13 -#define IRQ_IPI_RESCHED 14 #define IRQ_CROSS_CALL 15 static inline unsigned long @@ -29,7 +26,6 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val) return val; } -static void smp4m_ipi_init(void); static void smp_setup_percpu_timer(void); void __cpuinit smp4m_callin(void) @@ -63,6 +59,8 @@ void __cpuinit smp4m_callin(void) local_flush_cache_all(); local_flush_tlb_all(); + cpu_probe(); + /* Fix idle thread fields. */ __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r" (¤t_set[cpuid]) @@ -72,7 +70,7 @@ void __cpuinit smp4m_callin(void) atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - while (!cpumask_test_cpu(cpuid, &smp_commenced_mask)) + while (!cpu_isset(cpuid, smp_commenced_mask)) mb(); local_irq_enable(); @@ -85,7 +83,6 @@ void __cpuinit smp4m_callin(void) */ void __init smp4m_boot_cpus(void) { - smp4m_ipi_init(); smp_setup_percpu_timer(); local_flush_cache_all(); } @@ -153,25 +150,18 @@ void __init smp4m_smp_done(void) /* Ok, they are spinning and ready to go. */ } - -/* Initialize IPIs on the SUN4M SMP machine */ -static void __init smp4m_ipi_init(void) -{ -} - -static void smp4m_ipi_resched(int cpu) -{ - set_cpu_int(cpu, IRQ_IPI_RESCHED); -} - -static void smp4m_ipi_single(int cpu) +/* At each hardware IRQ, we get this called to forward IRQ reception + * to the next processor. The caller must disable the IRQ level being + * serviced globally so that there are no double interrupts received. + * + * XXX See sparc64 irq.c. + */ +void smp4m_irq_rotate(int cpu) { - set_cpu_int(cpu, IRQ_IPI_SINGLE); -} + int next = cpu_data(cpu).next; -static void smp4m_ipi_mask_one(int cpu) -{ - set_cpu_int(cpu, IRQ_IPI_MASK); + if (next != cpu) + set_irq_udt(next); } static struct smp_funcall { @@ -209,10 +199,10 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, { register int i; - cpumask_clear_cpu(smp_processor_id(), &mask); - cpumask_and(&mask, cpu_online_mask, &mask); + cpu_clear(smp_processor_id(), mask); + cpus_and(mask, cpu_online_map, mask); for (i = 0; i < ncpus; i++) { - if (cpumask_test_cpu(i, &mask)) { + if (cpu_isset(i, mask)) { ccall_info.processors_in[i] = 0; ccall_info.processors_out[i] = 0; set_cpu_int(i, IRQ_CROSS_CALL); @@ -228,7 +218,7 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_in[i]) barrier(); @@ -236,7 +226,7 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, i = 0; do { - if (!cpumask_test_cpu(i, &mask)) + if (!cpu_isset(i, mask)) continue; while (!ccall_info.processors_out[i]) barrier(); @@ -287,7 +277,7 @@ static void __cpuinit smp_setup_percpu_timer(void) load_profile_irq(cpu, lvl14_resolution); if (cpu == boot_cpu_id) - sun4m_unmask_profile_irq(); + enable_pil_irq(14); } static void __init smp4m_blackbox_id(unsigned *addr) @@ -316,7 +306,4 @@ void __init sun4m_init_smp(void) BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_resched, smp4m_ipi_resched, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_single, smp4m_ipi_single, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_ipi_mask_one, smp4m_ipi_mask_one, BTFIXUPCALL_NORM); } diff --git a/trunk/arch/sparc/kernel/sysfs.c b/trunk/arch/sparc/kernel/sysfs.c index 7408201d7efb..1eb8b00aed75 100644 --- a/trunk/arch/sparc/kernel/sysfs.c +++ b/trunk/arch/sparc/kernel/sysfs.c @@ -103,10 +103,9 @@ static unsigned long run_on_cpu(unsigned long cpu, unsigned long (*func)(unsigned long), unsigned long arg) { - cpumask_t old_affinity; + cpumask_t old_affinity = current->cpus_allowed; unsigned long ret; - cpumask_copy(&old_affinity, tsk_cpus_allowed(current)); /* should return -EINVAL to userspace */ if (set_cpus_allowed_ptr(current, cpumask_of(cpu))) return 0; diff --git a/trunk/arch/sparc/kernel/time_32.c b/trunk/arch/sparc/kernel/time_32.c index b61840300101..96046a4024c2 100644 --- a/trunk/arch/sparc/kernel/time_32.c +++ b/trunk/arch/sparc/kernel/time_32.c @@ -168,7 +168,7 @@ static int __devinit clock_probe(struct platform_device *op) return 0; } -static struct of_device_id __initdata clock_match[] = { +static struct of_device_id clock_match[] = { { .name = "eeprom", }, @@ -228,10 +228,14 @@ static void __init sbus_time_init(void) void __init time_init(void) { - if (pcic_present()) +#ifdef CONFIG_PCI + extern void pci_time_init(void); + if (pcic_present()) { pci_time_init(); - else - sbus_time_init(); + return; + } +#endif + sbus_time_init(); } diff --git a/trunk/arch/sparc/kernel/us2e_cpufreq.c b/trunk/arch/sparc/kernel/us2e_cpufreq.c index 531d54fc9829..8f982b76c712 100644 --- a/trunk/arch/sparc/kernel/us2e_cpufreq.c +++ b/trunk/arch/sparc/kernel/us2e_cpufreq.c @@ -237,7 +237,7 @@ static unsigned int us2e_freq_get(unsigned int cpu) if (!cpu_online(cpu)) return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); + cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); clock_tick = sparc64_get_clock_tick(cpu) / 1000; @@ -258,7 +258,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) if (!cpu_online(cpu)) return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); + cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000; diff --git a/trunk/arch/sparc/kernel/us3_cpufreq.c b/trunk/arch/sparc/kernel/us3_cpufreq.c index 9a8ceb700833..f35d1e794548 100644 --- a/trunk/arch/sparc/kernel/us3_cpufreq.c +++ b/trunk/arch/sparc/kernel/us3_cpufreq.c @@ -85,7 +85,7 @@ static unsigned int us3_freq_get(unsigned int cpu) if (!cpu_online(cpu)) return 0; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); + cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); reg = read_safari_cfg(); @@ -105,7 +105,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index) if (!cpu_online(cpu)) return; - cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); + cpus_allowed = current->cpus_allowed; set_cpus_allowed_ptr(current, cpumask_of(cpu)); new_freq = sparc64_get_clock_tick(cpu) / 1000; diff --git a/trunk/arch/sparc/lib/Makefile b/trunk/arch/sparc/lib/Makefile index 7f01b8fce8bc..846d1c4374ea 100644 --- a/trunk/arch/sparc/lib/Makefile +++ b/trunk/arch/sparc/lib/Makefile @@ -15,6 +15,7 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-y += atomic_$(BITS).o lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o +lib-$(CONFIG_SPARC32) += rwsem_32.o lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o diff --git a/trunk/arch/sparc/lib/checksum_32.S b/trunk/arch/sparc/lib/checksum_32.S index 3632cb34e914..0084c3361e15 100644 --- a/trunk/arch/sparc/lib/checksum_32.S +++ b/trunk/arch/sparc/lib/checksum_32.S @@ -289,10 +289,16 @@ cc_end_cruft: /* Also, handle the alignment code out of band. */ cc_dword_align: - cmp %g1, 6 - bl,a ccte + cmp %g1, 16 + bge 1f + srl %g1, 1, %o3 +2: cmp %o3, 0 + be,a ccte andcc %g1, 0xf, %o3 - andcc %o0, 0x1, %g0 + andcc %o3, %o0, %g0 ! Check %o0 only (%o1 has the same last 2 bits) + be,a 2b + srl %o3, 1, %o3 +1: andcc %o0, 0x1, %g0 bne ccslow andcc %o0, 0x2, %g0 be 1f diff --git a/trunk/arch/sparc/lib/rwsem_32.S b/trunk/arch/sparc/lib/rwsem_32.S new file mode 100644 index 000000000000..9675268e7fde --- /dev/null +++ b/trunk/arch/sparc/lib/rwsem_32.S @@ -0,0 +1,204 @@ +/* + * Assembly part of rw semaphores. + * + * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) + */ + +#include +#include + + .section .sched.text, "ax" + .align 4 + + .globl ___down_read +___down_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef CONFIG_SMP +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + sub %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + sub %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + add %g7, 1, %g7 + nop + nop + subcc %g7, 1, %g7 + bneg 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_read_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_read + restore %l5, %g0, %g5 +4: call down_read_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___down_write +___down_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef CONFIG_SMP +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + sub %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + sub %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + add %g7, %g2, %g7 + nop + nop + subcc %g7, %g2, %g7 + bne 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + bcs 4f + mov %g5, %l5 + call down_write_failed + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba ___down_write + restore %l5, %g0, %g5 +4: call down_write_failed_biased + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .text + .globl ___up_read +___up_read: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + nop + nop + nop +#ifdef CONFIG_SMP +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + add %g7, 1, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + add %g7, 1, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + nop + nop + nop + cmp %g7, 0 + be 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + clr %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 + + .globl ___up_write +___up_write: + rd %psr, %g3 + nop + nop + nop + or %g3, PSR_PIL, %g7 + wr %g7, 0, %psr + sethi %hi(0x01000000), %g2 + nop + nop +#ifdef CONFIG_SMP +1: ldstub [%g1 + 4], %g7 + tst %g7 + bne 1b + ld [%g1], %g7 + add %g7, %g2, %g7 + st %g7, [%g1] + stb %g0, [%g1 + 4] +#else + ld [%g1], %g7 + add %g7, %g2, %g7 + st %g7, [%g1] +#endif + wr %g3, 0, %psr + sub %g7, %g2, %g7 + nop + nop + addcc %g7, %g2, %g7 + bcs 3f + nop +2: jmpl %o7, %g0 + mov %g4, %o7 +3: save %sp, -64, %sp + mov %g1, %l1 + mov %g4, %l4 + mov %g5, %l5 + mov %g7, %o1 + call __rwsem_wake + mov %l1, %o0 + mov %l1, %g1 + mov %l4, %g4 + ba 2b + restore %l5, %g0, %g5 diff --git a/trunk/arch/sparc/mm/init_64.c b/trunk/arch/sparc/mm/init_64.c index e10cd03fab80..2f6ae1d1fb6b 100644 --- a/trunk/arch/sparc/mm/init_64.c +++ b/trunk/arch/sparc/mm/init_64.c @@ -862,7 +862,7 @@ static void init_node_masks_nonnuma(void) for (i = 0; i < NR_CPUS; i++) numa_cpu_lookup_table[i] = 0; - cpumask_setall(&numa_cpumask_lookup_table[0]); + numa_cpumask_lookup_table[0] = CPU_MASK_ALL; } #ifdef CONFIG_NEED_MULTIPLE_NODES @@ -1080,7 +1080,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md, { u64 arc; - cpumask_clear(mask); + cpus_clear(*mask); mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_BACK) { u64 target = mdesc_arc_target(md, arc); @@ -1091,7 +1091,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md, continue; id = mdesc_get_property(md, target, "id", NULL); if (*id < nr_cpu_ids) - cpumask_set_cpu(*id, mask); + cpu_set(*id, *mask); } } @@ -1153,13 +1153,13 @@ static int __init numa_parse_mdesc_group(struct mdesc_handle *md, u64 grp, numa_parse_mdesc_group_cpus(md, grp, &mask); - for_each_cpu(cpu, &mask) + for_each_cpu_mask(cpu, mask) numa_cpu_lookup_table[cpu] = index; - cpumask_copy(&numa_cpumask_lookup_table[index], &mask); + numa_cpumask_lookup_table[index] = mask; if (numa_debug) { printk(KERN_INFO "NUMA GROUP[%d]: cpus [ ", index); - for_each_cpu(cpu, &mask) + for_each_cpu_mask(cpu, mask) printk("%d ", cpu); printk("]\n"); } @@ -1218,7 +1218,7 @@ static int __init numa_parse_jbus(void) index = 0; for_each_present_cpu(cpu) { numa_cpu_lookup_table[cpu] = index; - cpumask_copy(&numa_cpumask_lookup_table[index], cpumask_of(cpu)); + numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu); node_masks[index].mask = ~((1UL << 36UL) - 1UL); node_masks[index].val = cpu << 36UL;