X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fmach-voyager%2Fvoyager_smp.c;h=74aeedf277f424896c1beaf01580468ecfbe90b5;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=7cb7e8046842a4606e6141bd5e3253121852bc3d;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c index 7cb7e8046..74aeedf27 100644 --- a/arch/i386/mach-voyager/voyager_smp.c +++ b/arch/i386/mach-voyager/voyager_smp.c @@ -9,7 +9,7 @@ * This file provides all the same external entries as smp.c but uses * the voyager hal to provide the functionality */ -#include +#include #include #include #include @@ -27,12 +27,8 @@ #include #include #include -#include #include - -#include - -int reboot_smp = 0; +#include /* TLB state -- visible externally, indexed physically */ DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0 }; @@ -40,13 +36,10 @@ DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_m /* CPU IRQ affinity -- set to all ones initially */ static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = ~0UL }; -/* Set when the idlers are all forked - Set in main.c but not actually - * used by any other parts of the kernel */ -int smp_threads_ready = 0; - /* per CPU data structure (for /proc/cpuinfo et al), visible externally * indexed physically */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +EXPORT_SYMBOL(cpu_data); /* physical ID of the CPU used to boot the system */ unsigned char boot_cpu_id; @@ -79,19 +72,12 @@ static volatile unsigned long smp_invalidate_needed; /* Bitmask of currently online CPUs - used by setup.c for /proc/cpuinfo, visible externally but still physical */ cpumask_t cpu_online_map = CPU_MASK_NONE; +EXPORT_SYMBOL(cpu_online_map); /* Bitmask of CPUs present in the system - exported by i386_syms.c, used * by scheduler but indexed physically */ cpumask_t phys_cpu_present_map = CPU_MASK_NONE; -/* estimate of time used to flush the SMP-local cache - used in - * processor affinity calculations */ -cycles_t cacheflush_time = 0; - -/* cache decay ticks for scheduler---a fairly useless quantity for the - voyager system with its odd affinity and huge L3 cache */ -unsigned long cache_decay_ticks = 20; - /* The internal functions */ static void send_CPI(__u32 cpuset, __u8 cpi); @@ -100,8 +86,8 @@ static int ack_QIC_CPI(__u8 cpi); static void ack_special_QIC_CPI(__u8 cpi); static void ack_VIC_CPI(__u8 cpi); static void send_CPI_allbutself(__u8 cpi); -static void enable_vic_irq(unsigned int irq); -static void disable_vic_irq(unsigned int irq); +static void mask_vic_irq(unsigned int irq); +static void unmask_vic_irq(unsigned int irq); static unsigned int startup_vic_irq(unsigned int irq); static void enable_local_vic_irq(unsigned int irq); static void disable_local_vic_irq(unsigned int irq); @@ -112,9 +98,9 @@ static void ack_vic_irq(unsigned int irq); static void vic_enable_cpi(void); static void do_boot_cpu(__u8 cpuid); static void do_quad_bootstrap(void); -static inline void wrapper_smp_local_timer_interrupt(struct pt_regs *); int hard_smp_processor_id(void); +int safe_smp_processor_id(void); /* Inline functions */ static inline void @@ -140,6 +126,14 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi) } } +static inline void +wrapper_smp_local_timer_interrupt(void) +{ + irq_enter(); + smp_local_timer_interrupt(); + irq_exit(); +} + static inline void send_one_CPI(__u8 cpu, __u8 cpi) { @@ -212,15 +206,12 @@ ack_CPI(__u8 cpi) /* The VIC IRQ descriptors -- these look almost identical to the * 8259 IRQs except that masks and things must be kept per processor */ -static struct hw_interrupt_type vic_irq_type = { - "VIC-level", - startup_vic_irq, /* startup */ - disable_vic_irq, /* shutdown */ - enable_vic_irq, /* enable */ - disable_vic_irq, /* disable */ - before_handle_vic_irq, /* ack */ - after_handle_vic_irq, /* end */ - set_vic_irq_affinity, /* affinity */ +static struct irq_chip vic_chip = { + .name = "VIC", + .startup = startup_vic_irq, + .mask = mask_vic_irq, + .unmask = unmask_vic_irq, + .set_affinity = set_vic_irq_affinity, }; /* used to count up as CPUs are brought on line (starts at 0) */ @@ -246,6 +237,9 @@ static cpumask_t smp_commenced_mask = CPU_MASK_NONE; /* This is for the new dynamic CPU boot code */ cpumask_t cpu_callin_map = CPU_MASK_NONE; cpumask_t cpu_callout_map = CPU_MASK_NONE; +EXPORT_SYMBOL(cpu_callout_map); +cpumask_t cpu_possible_map = CPU_MASK_NONE; +EXPORT_SYMBOL(cpu_possible_map); /* The per processor IRQ masks (these are usually kept in sync) */ static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned; @@ -254,7 +248,7 @@ static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned; static __u16 vic_irq_enable_mask[NR_CPUS] __cacheline_aligned = { 0 }; /* Lock for enable/disable of VIC interrupts */ -static spinlock_t vic_irq_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; +static __cacheline_aligned DEFINE_SPINLOCK(vic_irq_lock); /* The boot processor is correctly set up in PC mode when it * comes up, but the secondaries need their master/slave 8259 @@ -406,6 +400,7 @@ find_smp_config(void) cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8; cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16; cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24; + cpu_possible_map = phys_cpu_present_map; printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]); /* Here we set up the VIC to enable SMP */ /* enable the CPIs by writing the base vector to their register */ @@ -428,6 +423,7 @@ find_smp_config(void) VOYAGER_SUS_IN_CONTROL_PORT); current_thread_info()->cpu = boot_cpu_id; + write_pda(cpu_number, boot_cpu_id); } /* @@ -457,15 +453,14 @@ setup_trampoline(void) } /* Routine initially called when a non-boot CPU is brought online */ -int __init +static void __init start_secondary(void *unused) { __u8 cpuid = hard_smp_processor_id(); /* external functions not defined in the headers */ extern void calibrate_delay(void); - extern int cpu_idle(void); - cpu_init(); + secondary_cpu_init(); /* OK, we're in the routine */ ack_CPI(VIC_CPU_BOOT_CPI); @@ -520,7 +515,7 @@ start_secondary(void *unused) cpu_set(cpuid, cpu_online_map); wmb(); - return cpu_idle(); + cpu_idle(); } @@ -585,6 +580,15 @@ do_boot_cpu(__u8 cpu) /* init_tasks (in sched.c) is indexed logically */ stack_start.esp = (void *) idle->thread.esp; + /* Pre-allocate and initialize the CPU's GDT and PDA so it + doesn't have to do any memory allocation during the + delicate CPU-bringup phase. */ + if (!init_gdt(cpu, idle)) { + printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu); + cpucount--; + return; + } + irq_ctx_init(cpu); /* Note: Don't modify initial ss override */ @@ -665,6 +669,7 @@ do_boot_cpu(__u8 cpu) print_cpu_info(&cpu_data[cpu]); wmb(); cpu_set(cpu, cpu_callout_map); + cpu_set(cpu, cpu_present_map); } else { printk("CPU%d FAILED TO BOOT: ", cpu); @@ -767,6 +772,12 @@ initialize_secondary(void) set_current(hard_get_current()); #endif + /* + * switch to the per CPU GDT we already set up + * in do_boot_cpu() + */ + cpu_set_gdt(current_thread_info()->cpu); + /* * We don't actually need to load the full TSS, * basically just the stack pointer and the eip. @@ -785,21 +796,21 @@ initialize_secondary(void) * System interrupts occur because some problem was detected on the * various busses. To find out what you have to probe all the * hardware via the CAT bus. FIXME: At the moment we do nothing. */ -asmlinkage void -smp_vic_sys_interrupt(void) +fastcall void +smp_vic_sys_interrupt(struct pt_regs *regs) { ack_CPI(VIC_SYS_INT); - printk("Voyager SYSTEM INTERRUPT\n"); + printk("Voyager SYSTEM INTERRUPT\n"); } /* Handle a voyager CMN_INT; These interrupts occur either because of * a system status change or because a single bit memory error * occurred. FIXME: At the moment, ignore all this. */ -asmlinkage void -smp_vic_cmn_interrupt(void) +fastcall void +smp_vic_cmn_interrupt(struct pt_regs *regs) { static __u8 in_cmn_int = 0; - static spinlock_t cmn_int_lock = SPIN_LOCK_UNLOCKED; + static DEFINE_SPINLOCK(cmn_int_lock); /* common ints are broadcast, so make sure we only do this once */ _raw_spin_lock(&cmn_int_lock); @@ -824,7 +835,7 @@ smp_vic_cmn_interrupt(void) /* * Reschedule call back. Nothing to do, all the work is done * automatically when we return from the interrupt. */ -asmlinkage void +static void smp_reschedule_interrupt(void) { /* do nothing */ @@ -832,7 +843,7 @@ smp_reschedule_interrupt(void) static struct mm_struct * flush_mm; static unsigned long flush_va; -static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(tlbstate_lock); #define FLUSH_ALL 0xffffffff /* @@ -855,7 +866,7 @@ leave_mm (unsigned long cpu) /* * Invalidate call-back */ -asmlinkage void +static void smp_invalidate_interrupt(void) { __u8 cpu = smp_processor_id(); @@ -987,9 +998,10 @@ void flush_tlb_page(struct vm_area_struct * vma, unsigned long va) preempt_enable(); } +EXPORT_SYMBOL(flush_tlb_page); /* enable the requested IRQs */ -asmlinkage void +static void smp_enable_irq_interrupt(void) { __u8 irq; @@ -1019,10 +1031,10 @@ smp_stop_cpu_function(void *dummy) cpu_clear(smp_processor_id(), cpu_online_map); local_irq_disable(); for(;;) - __asm__("hlt"); + halt(); } -static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(call_lock); struct call_data_struct { void (*func) (void *info); @@ -1038,7 +1050,7 @@ static struct call_data_struct * call_data; * previously set up. This is used to schedule a function for * execution on all CPU's - set up the function then broadcast a * function_interrupt CPI to come here on each CPU */ -asmlinkage void +static void smp_call_function_interrupt(void) { void (*func) (void *info) = call_data->func; @@ -1118,6 +1130,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry, return 0; } +EXPORT_SYMBOL(smp_call_function); /* Sorry about the name. In an APIC based system, the APICs * themselves are programmed to send a timer interrupt. This is used @@ -1133,51 +1146,56 @@ smp_call_function (void (*func) (void *info), void *info, int retry, * no local APIC, so I can't do this * * This function is currently a placeholder and is unused in the code */ -asmlinkage void -smp_apic_timer_interrupt(struct pt_regs regs) +fastcall void +smp_apic_timer_interrupt(struct pt_regs *regs) { - wrapper_smp_local_timer_interrupt(®s); + struct pt_regs *old_regs = set_irq_regs(regs); + wrapper_smp_local_timer_interrupt(); + set_irq_regs(old_regs); } /* All of the QUAD interrupt GATES */ -asmlinkage void -smp_qic_timer_interrupt(struct pt_regs regs) +fastcall void +smp_qic_timer_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); ack_QIC_CPI(QIC_TIMER_CPI); - wrapper_smp_local_timer_interrupt(®s); + wrapper_smp_local_timer_interrupt(); + set_irq_regs(old_regs); } -asmlinkage void -smp_qic_invalidate_interrupt(void) +fastcall void +smp_qic_invalidate_interrupt(struct pt_regs *regs) { ack_QIC_CPI(QIC_INVALIDATE_CPI); smp_invalidate_interrupt(); } -asmlinkage void -smp_qic_reschedule_interrupt(void) +fastcall void +smp_qic_reschedule_interrupt(struct pt_regs *regs) { ack_QIC_CPI(QIC_RESCHEDULE_CPI); smp_reschedule_interrupt(); } -asmlinkage void -smp_qic_enable_irq_interrupt(void) +fastcall void +smp_qic_enable_irq_interrupt(struct pt_regs *regs) { ack_QIC_CPI(QIC_ENABLE_IRQ_CPI); smp_enable_irq_interrupt(); } -asmlinkage void -smp_qic_call_function_interrupt(void) +fastcall void +smp_qic_call_function_interrupt(struct pt_regs *regs) { ack_QIC_CPI(QIC_CALL_FUNCTION_CPI); smp_call_function_interrupt(); } -asmlinkage void -smp_vic_cpi_interrupt(struct pt_regs regs) +fastcall void +smp_vic_cpi_interrupt(struct pt_regs *regs) { + struct pt_regs *old_regs = set_irq_regs(regs); __u8 cpu = smp_processor_id(); if(is_cpu_quad()) @@ -1186,7 +1204,7 @@ smp_vic_cpi_interrupt(struct pt_regs regs) ack_VIC_CPI(VIC_CPI_LEVEL0); if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu])) - wrapper_smp_local_timer_interrupt(®s); + wrapper_smp_local_timer_interrupt(); if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu])) smp_invalidate_interrupt(); if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu])) @@ -1195,6 +1213,7 @@ smp_vic_cpi_interrupt(struct pt_regs regs) smp_enable_irq_interrupt(); if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu])) smp_call_function_interrupt(); + set_irq_regs(old_regs); } static void @@ -1249,6 +1268,12 @@ hard_smp_processor_id(void) return 0; } +int +safe_smp_processor_id(void) +{ + return hard_smp_processor_id(); +} + /* broadcast a halt to all other CPUs */ void smp_send_stop(void) @@ -1259,18 +1284,10 @@ smp_send_stop(void) /* this function is triggered in time.c when a clock tick fires * we need to re-broadcast the tick to all CPUs */ void -smp_vic_timer_interrupt(struct pt_regs *regs) +smp_vic_timer_interrupt(void) { send_CPI_allbutself(VIC_TIMER_CPI); - smp_local_timer_interrupt(regs); -} - -static inline void -wrapper_smp_local_timer_interrupt(struct pt_regs *regs) -{ - irq_enter(); - smp_local_timer_interrupt(regs); - irq_exit(); + smp_local_timer_interrupt(); } /* local (per CPU) timer interrupt. It does both profiling and @@ -1282,12 +1299,12 @@ wrapper_smp_local_timer_interrupt(struct pt_regs *regs) * value into /proc/profile. */ void -smp_local_timer_interrupt(struct pt_regs * regs) +smp_local_timer_interrupt(void) { int cpu = smp_processor_id(); long weight; - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); if (--per_cpu(prof_counter, cpu) <= 0) { /* * The multiplier may have changed since the last time we got @@ -1305,7 +1322,7 @@ smp_local_timer_interrupt(struct pt_regs * regs) per_cpu(prof_counter, cpu); } - update_process_times(user_mode(regs)); + update_process_times(user_mode_vm(get_irq_regs())); } if( ((1<cpu = hard_smp_processor_id(); + write_pda(cpu_number, hard_smp_processor_id()); +}