diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-20 17:39:28 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-20 17:39:28 -0700 |
commit | be883da7594b0a2a02074e683673ae0e522566a4 (patch) | |
tree | b62f2a8a069fb4d389935c0b2de9bc78798f50c2 /arch | |
parent | 077e98945db7e54a9865b5f29a1f02f531eca414 (diff) | |
parent | 4c5eb38af2131d867842cdd09fa83a3ed77bfd26 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
[SPARC64]: Update defconfig.
[SPARC64]: Don't double-export synchronize_irq.
[SPARC64]: Move over to GENERIC_HARDIRQS.
[SPARC64]: Virtualize IRQ numbers.
[SPARC64]: Kill ino_bucket->pil
[SPARC]: Kill __irq_itoa().
[SPARC64]: bp->pil can never be zero
[SPARC64]: Send all device interrupts via one PIL.
[SPARC]: Fix iommu_flush_iotlb end address
[SPARC]: Mark smp init functions as cpuinit
[SPARC]: Add missing rw can_lock macros
[SPARC]: Setup cpu_possible_map
[SPARC]: Add topology_init()
Diffstat (limited to 'arch')
25 files changed, 515 insertions, 1204 deletions
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 42002b742de..bcdf5ad0f03 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -896,13 +896,6 @@ static inline unsigned long get_irqmask(int irq_nr) return 1 << irq_nr; } -static inline char *pcic_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void pcic_disable_irq(unsigned int irq_nr) { unsigned long mask, flags; @@ -955,7 +948,6 @@ void __init sun4m_pci_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); } int pcibios_assign_resource(struct pci_dev *pdev, int resource) diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 3509e430553..2cbf282f0d0 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -31,6 +31,7 @@ #include <linux/console.h> #include <linux/spinlock.h> #include <linux/root_dev.h> +#include <linux/cpu.h> #include <asm/system.h> #include <asm/io.h> @@ -348,6 +349,8 @@ void __init setup_arch(char **cmdline_p) init_mm.context = (unsigned long) NO_CONTEXT; init_task.thread.kregs = &fake_swapper_regs; + smp_setup_cpu_possible_map(); + paging_init(); } @@ -389,6 +392,8 @@ console_initcall(set_preferred_console); extern char *sparc_cpu_type; extern char *sparc_fpu_type; +static int ncpus_probed; + static int show_cpuinfo(struct seq_file *m, void *__unused) { seq_printf(m, @@ -411,7 +416,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused) romvec->pv_printrev >> 16, romvec->pv_printrev & 0xffff, &cputypval, - num_possible_cpus(), + ncpus_probed, num_online_cpus() #ifndef CONFIG_SMP , cpu_data(0).udelay_val/(500000/HZ), @@ -471,3 +476,30 @@ void sun_do_break(void) int serial_console = -1; int stop_a_enabled = 1; + +static int __init topology_init(void) +{ + int i, ncpus, err; + + /* Count the number of physically present processors in + * the machine, even on uniprocessor, so that /proc/cpuinfo + * output is consistent with 2.4.x + */ + ncpus = 0; + while (!cpu_find_by_instance(ncpus, NULL, NULL)) + ncpus++; + ncpus_probed = ncpus; + + err = 0; + for_each_online_cpu(i) { + struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + err = -ENOMEM; + else + register_cpu(p, i, NULL); + } + + return err; +} + +subsys_initcall(topology_init); diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 40b42c88e6a..6135d4faeee 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -58,7 +58,7 @@ cpumask_t smp_commenced_mask = CPU_MASK_NONE; /* Used to make bitops atomic */ unsigned char bitops_spinlock = 0; -void __init smp_store_cpu_info(int id) +void __cpuinit smp_store_cpu_info(int id) { int cpu_node; @@ -267,22 +267,18 @@ int setup_profiling_timer(unsigned int multiplier) void __init smp_prepare_cpus(unsigned int max_cpus) { extern void smp4m_boot_cpus(void); - int i, cpuid, ncpus, extra; + int i, cpuid, extra; BUG_ON(sparc_cpu_model != sun4m); printk("Entering SMP Mode...\n"); - ncpus = 1; extra = 0; for (i = 0; !cpu_find_by_instance(i, NULL, &cpuid); i++) { - if (cpuid == boot_cpu_id) - continue; - if (cpuid < NR_CPUS && ncpus++ < max_cpus) - cpu_set(cpuid, phys_cpu_present_map); - else + if (cpuid >= NR_CPUS) extra++; } - if (max_cpus >= NR_CPUS && extra) + /* i = number of cpus */ + if (extra && max_cpus > i - extra) printk("Warning: NR_CPUS is too low to start all cpus\n"); smp_store_cpu_info(boot_cpu_id); @@ -290,7 +286,25 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp4m_boot_cpus(); } -void __devinit smp_prepare_boot_cpu(void) +/* Set this up early so that things like the scheduler can init + * properly. We use the same cpu mask for both the present and + * possible cpu map. + */ +void __init smp_setup_cpu_possible_map(void) +{ + int instance, mid; + + instance = 0; + while (!cpu_find_by_instance(instance, NULL, &mid)) { + if (mid < NR_CPUS) { + cpu_set(mid, phys_cpu_present_map); + cpu_set(mid, cpu_present_map); + } + instance++; + } +} + +void __init smp_prepare_boot_cpu(void) { int cpuid = hard_smp_processor_id(); @@ -306,7 +320,7 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(cpuid, phys_cpu_present_map); } -int __devinit __cpu_up(unsigned int cpu) +int __cpuinit __cpu_up(unsigned int cpu) { extern int smp4m_boot_one_cpu(int); int ret; diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 4b376fae752..fd7deabf998 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -163,7 +163,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id)); #endif EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq)); EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq)); -EXPORT_SYMBOL(BTFIXUP_CALL(__irq_itoa)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea)); EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl)); diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 3d6a99073c4..0f2d8d9cbdb 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -198,8 +198,6 @@ static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, stru static void sun4c_nop(void) {} #endif -extern char *sun4m_irq_itoa(unsigned int irq); - void __init sun4c_init_IRQ(void) { struct linux_prom_registers int_regs[2]; @@ -238,7 +236,6 @@ void __init sun4c_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4c_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index ca656d9bd6f..9c30e35c88f 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -560,17 +560,6 @@ void __init sun4d_init_sbi_irq(void) } } -static char *sun4d_irq_itoa(unsigned int irq) -{ - static char buff[16]; - - if (irq < (1 << 5)) - sprintf(buff, "%d", irq); - else - sprintf(buff, "%d,%x", sbus_to_pil[(irq >> 2) & 7], irq); - return buff; -} - void __init sun4d_init_IRQ(void) { local_irq_disable(); @@ -581,7 +570,6 @@ void __init sun4d_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4d_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM); diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 39d712c3c80..a296c13ac18 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -229,13 +229,6 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit) sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; } -char *sun4m_irq_itoa(unsigned int irq) -{ - static char buff[16]; - sprintf(buff, "%d", irq); - return buff; -} - static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *)) { int reg_count, irq, cpu; @@ -388,7 +381,6 @@ void __init sun4m_init_IRQ(void) BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM); sparc_init_timers = sun4m_init_timers; #ifdef CONFIG_SMP BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 70b375a4c2c..3b32096134a 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -66,7 +66,7 @@ static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val) static void smp_setup_percpu_timer(void); extern void cpu_probe(void); -void __init smp4m_callin(void) +void __cpuinit smp4m_callin(void) { int cpuid = hard_smp_processor_id(); @@ -112,13 +112,8 @@ void __init smp4m_callin(void) local_irq_enable(); cpu_set(cpuid, cpu_online_map); - /* last one in gets all the interrupts (for testing) */ - set_irq_udt(boot_cpu_id); } -extern void init_IRQ(void); -extern void cpu_panic(void); - /* * Cycle through the processors asking the PROM to start each one. */ @@ -134,7 +129,7 @@ void __init smp4m_boot_cpus(void) local_flush_cache_all(); } -int smp4m_boot_one_cpu(int i) +int __cpuinit smp4m_boot_one_cpu(int i) { extern unsigned long sun4m_cpu_startup; unsigned long *entry = &sun4m_cpu_startup; diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 77840c80478..7215849db39 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c @@ -144,8 +144,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) unsigned long start; unsigned long end; - start = (unsigned long)iopte & PAGE_MASK; + start = (unsigned long)iopte; end = PAGE_ALIGN(start + niopte*sizeof(iopte_t)); + start &= PAGE_MASK; if (viking_mxcc_present) { while(start < end) { viking_mxcc_flush_page(start); diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 43a66f5407f..a7a111db25b 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -87,6 +87,10 @@ config SYSVIPC_COMPAT depends on COMPAT && SYSVIPC default y +config GENERIC_HARDIRQS + bool + default y + menu "General machine setup" config SMP diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index f09a70b8aab..9da75f89fe2 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.17-rc3 -# Fri May 12 12:43:49 2006 +# Linux kernel version: 2.6.17 +# Tue Jun 20 01:26:43 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -87,6 +87,7 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" CONFIG_SYSVIPC_COMPAT=y +CONFIG_GENERIC_HARDIRQS=y # # General machine setup @@ -183,6 +184,8 @@ CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y CONFIG_INET_XFRM_TUNNEL=y CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y CONFIG_TCP_CONG_ADVANCED=y @@ -198,6 +201,9 @@ CONFIG_TCP_CONG_HSTCP=m CONFIG_TCP_CONG_HYBLA=m CONFIG_TCP_CONG_VEGAS=m CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_LP=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_COMPOUND=m CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_IPV6_ROUTER_PREF=y @@ -207,7 +213,10 @@ CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m CONFIG_IPV6_TUNNEL=m +# CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set # @@ -260,6 +269,7 @@ CONFIG_VLAN_8021Q=m # Network testing # CONFIG_NET_PKTGEN=m +CONFIG_NET_TCPPROBE=m # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set @@ -562,6 +572,7 @@ CONFIG_BNX2=m # CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set +# CONFIG_MYRI10GE is not set # # Token Ring devices @@ -811,6 +822,7 @@ CONFIG_HWMON=y # Multimedia devices # # CONFIG_VIDEO_DEV is not set +CONFIG_VIDEO_V4L2=y # # Digital Video Broadcasting Devices @@ -1135,6 +1147,19 @@ CONFIG_USB_HIDDEV=y # CONFIG_RTC_CLASS is not set # +# DMA Engine support +# +# CONFIG_DMA_ENGINE is not set + +# +# DMA Clients +# + +# +# DMA Devices +# + +# # Misc Linux/SPARC drivers # CONFIG_SUN_OPENPROMIO=m diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 007e8922cd1..0dd95ae50e1 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -157,7 +157,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node) return 0; } - return sun4v_build_irq(sun4v_vdev_devhandle, irq, 5, 0); + return sun4v_build_irq(sun4v_vdev_devhandle, irq); } static const char *cpu_mid_prop(void) diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 6d0b3ed77a0..be85ce2a4ad 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -22,6 +22,7 @@ #include <asm/estate.h> #include <asm/auxio.h> #include <asm/sfafsr.h> +#include <asm/pil.h> #define curptr g6 @@ -431,20 +432,16 @@ do_ivec: membar #Sync sethi %hi(ivector_table), %g2 - sllx %g3, 5, %g3 + sllx %g3, 3, %g3 or %g2, %lo(ivector_table), %g2 add %g2, %g3, %g3 - ldub [%g3 + 0x04], %g4 /* pil */ - mov 1, %g2 - sllx %g2, %g4, %g2 - sllx %g4, 2, %g4 TRAP_LOAD_IRQ_WORK(%g6, %g1) - lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */ + lduw [%g6], %g5 /* g5 = irq_work(cpu) */ stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ - stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */ - wr %g2, 0x0, %set_softint + stw %g3, [%g6] /* irq_work(cpu) = bucket */ + wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint retry do_ivec_xcall: mov 0x50, %g1 diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 11e645c9ec5..a8c9dc8d195 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -22,6 +22,7 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/bootmem.h> +#include <linux/irq.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -42,10 +43,6 @@ #include <asm/auxio.h> #include <asm/head.h> -#ifdef CONFIG_SMP -static void distribute_irqs(void); -#endif - /* UPA nodes send interrupt packet to UltraSparc with first data reg * value low 5 (7 on Starfire) bits holding the IRQ identifier being * delivered. We must translate this into a non-vector IRQ so we can @@ -57,10 +54,29 @@ static void distribute_irqs(void); * The IVEC handler does not need to act atomically, the PIL dispatch * code uses CAS to get an atomic snapshot of the list and clear it * at the same time. + * + * If you make changes to ino_bucket, please update hand coded assembler + * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S */ +struct ino_bucket { + /* Next handler in per-CPU IRQ worklist. We know that + * bucket pointers have the high 32-bits clear, so to + * save space we only store the bits we need. + */ +/*0x00*/unsigned int irq_chain; + /* Virtual interrupt number assigned to this INO. */ +/*0x04*/unsigned int virt_irq; +}; + +#define NUM_IVECS (IMAP_INR + 1) struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); +#define __irq_ino(irq) \ + (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) +#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) +#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) + /* This has to be in the main kernel image, it cannot be * turned into per-cpu data. The reason is that the main * kernel image is locked into the TLB and this structure @@ -68,71 +84,82 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY * access to this structure takes a TLB miss it could cause * the 5-level sparc v9 trap stack to overflow. */ -struct irq_work_struct { - unsigned int irq_worklists[16]; -}; -struct irq_work_struct __irq_work[NR_CPUS]; -#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)]) +#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) -static struct irqaction *irq_action[NR_IRQS+1]; +static unsigned int virt_to_real_irq_table[NR_IRQS]; +static unsigned char virt_irq_cur = 1; -/* This only synchronizes entities which modify IRQ handler - * state and some selected user-level spots that want to - * read things in the table. IRQ handler processing orders - * its' accesses such that no locking is needed. - */ -static DEFINE_SPINLOCK(irq_action_lock); +static unsigned char virt_irq_alloc(unsigned int real_irq) +{ + unsigned char ent; + + BUILD_BUG_ON(NR_IRQS >= 256); + + ent = virt_irq_cur; + if (ent >= NR_IRQS) { + printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); + return 0; + } + + virt_irq_cur = ent + 1; + virt_to_real_irq_table[ent] = real_irq; + + return ent; +} + +#if 0 /* Currently unused. */ +static unsigned char real_to_virt_irq(unsigned int real_irq) +{ + struct ino_bucket *bucket = __bucket(real_irq); -static void register_irq_proc (unsigned int irq); + return bucket->virt_irq; +} +#endif + +static unsigned int virt_to_real_irq(unsigned char virt_irq) +{ + return virt_to_real_irq_table[virt_irq]; +} /* - * Upper 2b of irqaction->flags holds the ino. - * irqaction->mask holds the smp affinity information. + * /proc/interrupts printing: */ -#define put_ino_in_irqaction(action, irq) \ - action->flags &= 0xffffffffffffUL; \ - if (__bucket(irq) == &pil0_dummy_bucket) \ - action->flags |= 0xdeadUL << 48; \ - else \ - action->flags |= __irq_ino(irq) << 48; -#define get_ino_in_irqaction(action) (action->flags >> 48) - -#define put_smpaff_in_irqaction(action, smpaff) (action)->mask = (smpaff) -#define get_smpaff_in_irqaction(action) ((action)->mask) int show_interrupts(struct seq_file *p, void *v) { + int i = *(loff_t *) v, j; + struct irqaction * action; unsigned long flags; - int i = *(loff_t *) v; - struct irqaction *action; -#ifdef CONFIG_SMP - int j; -#endif - spin_lock_irqsave(&irq_action_lock, flags); - if (i <= NR_IRQS) { - if (!(action = *(i + irq_action))) - goto out_unlock; - seq_printf(p, "%3d: ", i); + if (i == 0) { + seq_printf(p, " "); + for_each_online_cpu(j) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } + + if (i < NR_IRQS) { + spin_lock_irqsave(&irq_desc[i].lock, flags); + action = irq_desc[i].action; + if (!action) + goto skip; + 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]); - } + for_each_online_cpu(j) + seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); #endif - seq_printf(p, " %s:%lx", action->name, - get_ino_in_irqaction(action)); - for (action = action->next; action; action = action->next) { - seq_printf(p, ", %s:%lx", action->name, - get_ino_in_irqaction(action)); - } + seq_printf(p, " %9s", irq_desc[i].handler->typename); + seq_printf(p, " %s", action->name); + + for (action=action->next; action; action = action->next) + seq_printf(p, ", %s", action->name); + seq_putc(p, '\n'); +skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } -out_unlock: - spin_unlock_irqrestore(&irq_action_lock, flags); - return 0; } @@ -173,556 +200,365 @@ static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) return tid; } -/* Now these are always passed a true fully specified sun4u INO. */ -void enable_irq(unsigned int irq) -{ - struct ino_bucket *bucket = __bucket(irq); - unsigned long imap, cpuid; - - imap = bucket->imap; - if (imap == 0UL) - return; - - preempt_disable(); - - /* This gets the physical processor ID, even on uniprocessor, - * so we can always program the interrupt target correctly. - */ - cpuid = real_hard_smp_processor_id(); - - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); - int err; +struct irq_handler_data { + unsigned long iclr; + unsigned long imap; - err = sun4v_intr_settarget(ino, cpuid); - if (err != HV_EOK) - printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", - ino, cpuid, err); - err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): err(%d)\n", - ino, err); - } else { - unsigned int tid = sun4u_compute_tid(imap, cpuid); - - /* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product - * of this SYSIO's preconfigured IGN in the SYSIO Control - * Register, the hardware just mirrors that value here. - * However for Graphics and UPA Slave devices the full - * IMAP_INR field can be set by the programmer here. - * - * Things like FFB can now be handled via the new IRQ - * mechanism. - */ - upa_writel(tid | IMAP_VALID, imap); - } - - preempt_enable(); -} + void (*pre_handler)(unsigned int, void *, void *); + void *pre_handler_arg1; + void *pre_handler_arg2; +}; -/* This now gets passed true ino's as well. */ -void disable_irq(unsigned int irq) +static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) { - struct ino_bucket *bucket = __bucket(irq); - unsigned long imap; - - imap = bucket->imap; - if (imap != 0UL) { - if (tlb_type == hypervisor) { - unsigned int ino = __irq_ino(irq); - int err; - - err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); - if (err != HV_EOK) - printk("sun4v_intr_setenabled(%x): " - "err(%d)\n", ino, err); - } else { - u32 tmp; - - /* NOTE: We do not want to futz with the IRQ clear registers - * and move the state to IDLE, the SCSI code does call - * disable_irq() to assure atomicity in the queue cmd - * SCSI adapter driver code. Thus we'd lose interrupts. - */ - tmp = upa_readl(imap); - tmp &= ~IMAP_VALID; - upa_writel(tmp, imap); - } - } -} + unsigned int real_irq = virt_to_real_irq(virt_irq); + struct ino_bucket *bucket = NULL; -/* The timer is the one "weird" interrupt which is generated by - * the CPU %tick register and not by some normal vectored interrupt - * source. To handle this special case, we use this dummy INO bucket. - */ -static struct irq_desc pil0_dummy_desc; -static struct ino_bucket pil0_dummy_bucket = { - .irq_info = &pil0_dummy_desc, -}; + if (likely(real_irq)) + bucket = __bucket(real_irq); -static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup, - unsigned long iclr, unsigned long imap, - struct ino_bucket *bucket) -{ - prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> " - "(%d:%d:%016lx:%016lx), halting...\n", - ino, bucket->pil, bucket->iclr, bucket->imap, - pil, inofixup, iclr, imap); - prom_halt(); + return bucket; } -unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap) +#ifdef CONFIG_SMP +static int irq_choose_cpu(unsigned int virt_irq) { - struct ino_bucket *bucket; - int ino; + cpumask_t mask = irq_affinity[virt_irq]; + int cpuid; - if (pil == 0) { - if (iclr != 0UL || imap != 0UL) { - prom_printf("Invalid dummy bucket for PIL0 (%lx:%lx)\n", - iclr, imap); - prom_halt(); - } - return __irq(&pil0_dummy_bucket); - } + if (cpus_equal(mask, CPU_MASK_ALL)) { + static int irq_rover; + static DEFINE_SPINLOCK(irq_rover_lock); + unsigned long flags; - BUG_ON(tlb_type == hypervisor); + /* Round-robin distribution... */ + do_round_robin: + spin_lock_irqsave(&irq_rover_lock, flags); - /* RULE: Both must be specified in all other cases. */ - if (iclr == 0UL || imap == 0UL) { - prom_printf("Invalid build_irq %d %d %016lx %016lx\n", - pil, inofixup, iclr, imap); - prom_halt(); - } - - ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; - if (ino > NUM_IVECS) { - prom_printf("Invalid INO %04x (%d:%d:%016lx:%016lx)\n", - ino, pil, inofixup, iclr, imap); - prom_halt(); - } + while (!cpu_online(irq_rover)) { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } + cpuid = irq_rover; + do { + if (++irq_rover >= NR_CPUS) + irq_rover = 0; + } while (!cpu_online(irq_rover)); - bucket = &ivector_table[ino]; - if (bucket->flags & IBF_ACTIVE) - build_irq_error("IRQ: Trying to build active INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + spin_unlock_irqrestore(&irq_rover_lock, flags); + } else { + cpumask_t tmp; - if (bucket->irq_info) { - if (bucket->imap != imap || bucket->iclr != iclr) - build_irq_error("IRQ: Trying to reinit INO bucket.\n", - ino, pil, inofixup, iclr, imap, bucket); + cpus_and(tmp, cpu_online_map, mask); - goto out; - } + if (cpus_empty(tmp)) + goto do_round_robin; - bucket->irq_info = kzalloc(sizeof(struct irq_desc), GFP_ATOMIC); - if (!bucket->irq_info) { - prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n"); - prom_halt(); + cpuid = first_cpu(tmp); } - /* Ok, looks good, set it up. Don't touch the irq_chain or - * the pending flag. - */ - bucket->imap = imap; - bucket->iclr = iclr; - bucket->pil = pil; - bucket->flags = 0; - -out: - return __irq(bucket); + return cpuid; } - -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags) +#else +static int irq_choose_cpu(unsigned int virt_irq) { - struct ino_bucket *bucket; - unsigned long sysino; + return real_hard_smp_processor_id(); +} +#endif - sysino = sun4v_devino_to_sysino(devhandle, devino); +static void sun4u_irq_enable(unsigned int virt_irq) +{ + irq_desc_t *desc = irq_desc + virt_irq; + struct irq_handler_data *data = desc->handler_data; - bucket = &ivector_table[sysino]; + if (likely(data)) { + unsigned long cpuid, imap; + unsigned int tid; - /* Catch accidental accesses to these things. I |