smp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 727 行 · 第 1/2 页
C
727 行
/* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(IPI_CALL_FUNC); /* Wait for response */ timeout = jiffies + HZ; while ( (atomic_read (&data.unstarted_count) > 0) && time_before (jiffies, timeout) ) barrier (); /* We either got one or timed out. Release the lock */ mb(); smp_call_function_data = NULL; if (atomic_read (&data.unstarted_count) > 0) { printk(KERN_CRIT "SMP CALL FUNCTION TIMED OUT! (cpu=%d)\n", smp_processor_id()); return -ETIMEDOUT; } while (wait && atomic_read (&data.unfinished_count) > 0) barrier (); return 0;}EXPORT_SYMBOL(smp_call_function);/* * Flush all other CPU's tlb and then mine. Do this with on_each_cpu() * as we want to ensure all TLB's flushed before proceeding. */extern void flush_tlb_all_local(void);voidsmp_flush_tlb_all(void){ on_each_cpu((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);}void smp_do_timer(struct pt_regs *regs){ int cpu = smp_processor_id(); struct cpuinfo_parisc *data = &cpu_data[cpu]; if (!--data->prof_counter) { data->prof_counter = data->prof_multiplier; update_process_times(user_mode(regs)); }}/* * Called by secondaries to update state and initialize CPU registers. */static void __initsmp_cpu_init(int cpunum){ extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ /* Set modes and Enable floating point coprocessor */ (void) init_per_cpu(cpunum); disable_sr_hashing(); mb(); /* Well, support 2.4 linux scheme as well. */ if (cpu_test_and_set(cpunum, cpu_online_map)) { extern void machine_halt(void); /* arch/parisc.../process.c */ printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum); machine_halt(); } /* Initialise the idle task for this CPU */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; if(current->mm) BUG(); enter_lazy_tlb(&init_mm, current); init_IRQ(); /* make sure no IRQ's are enabled or pending */}/* * Slaves start using C here. Indirectly called from smp_slave_stext. * Do what start_kernel() and main() do for boot strap processor (aka monarch) */void __init smp_callin(void){ extern void cpu_idle(void); /* arch/parisc/kernel/process.c */ int slave_id = cpu_now_booting;#if 0 void *istack;#endif smp_cpu_init(slave_id);#if 0 /* NOT WORKING YET - see entry.S */ istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER); if (istack == NULL) { printk(KERN_CRIT "Failed to allocate interrupt stack for cpu %d\n",slave_id); BUG(); } mtctl(istack,31);#endif flush_cache_all_local(); /* start with known state */ flush_tlb_all_local(); local_irq_enable(); /* Interrupts have been off until now */ cpu_idle(); /* Wait for timer to schedule some work */ /* NOTREACHED */ panic("smp_callin() AAAAaaaaahhhh....\n");}/* * Bring one cpu online. */int __init smp_boot_one_cpu(int cpuid){ struct task_struct *idle; long timeout; /* * Create an idle task for this CPU. Note the address wed* give * to kernel_thread is irrelevant -- it's going to start * where OS_BOOT_RENDEVZ vector in SAL says to start. But * this gets all the other task-y sort of data structures set * up like we wish. We need to pull the just created idle task * off the run queue and stuff it into the init_tasks[] array. * Sheesh . . . */ idle = fork_idle(cpuid); if (IS_ERR(idle)) panic("SMP: fork failed for CPU:%d", cpuid); idle->thread_info->cpu = cpuid; /* Let _start know what logical CPU we're booting ** (offset into init_tasks[],cpu_data[]) */ cpu_now_booting = cpuid; /* ** boot strap code needs to know the task address since ** it also contains the process stack. */ smp_init_current_idle_task = idle ; mb(); printk("Releasing cpu %d now, hpa=%lx\n", cpuid, cpu_data[cpuid].hpa); /* ** This gets PDC to release the CPU from a very tight loop. ** ** From the PA-RISC 2.0 Firmware Architecture Reference Specification: ** "The MEM_RENDEZ vector specifies the location of OS_RENDEZ which ** is executed after receiving the rendezvous signal (an interrupt to ** EIR{0}). MEM_RENDEZ is valid only when it is nonzero and the ** contents of memory are valid." */ __raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpuid].hpa); mb(); /* * OK, wait a bit for that CPU to finish staggering about. * Slave will set a bit when it reaches smp_cpu_init(). * Once the "monarch CPU" sees the bit change, it can move on. */ for (timeout = 0; timeout < 10000; timeout++) { if(cpu_online(cpuid)) { /* Which implies Slave has started up */ cpu_now_booting = 0; smp_init_current_idle_task = NULL; goto alive ; } udelay(100); barrier(); } put_task_struct(idle); idle = NULL; printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid); return -1;alive: /* Remember the Slave data */#if (kDEBUG>=100) printk(KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n", cpuid, timeout * 100);#endif /* kDEBUG */#ifdef ENTRY_SYS_CPUS cpu_data[cpuid].state = STATE_RUNNING;#endif return 0;}void __devinit smp_prepare_boot_cpu(void){ int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */#ifdef ENTRY_SYS_CPUS cpu_data[0].state = STATE_RUNNING;#endif /* Setup BSP mappings */ printk("SMP: bootstrap CPU ID is %d\n",bootstrap_processor); cpu_set(bootstrap_processor, cpu_online_map); cpu_set(bootstrap_processor, cpu_present_map); cache_decay_ticks = HZ/100; /* FIXME very rough. */}/*** inventory.c:do_inventory() hasn't yet been run and thus we** don't 'discover' the additional CPU's until later.*/void __init smp_prepare_cpus(unsigned int max_cpus){ cpus_clear(cpu_present_map); cpu_set(0, cpu_present_map); parisc_max_cpus = max_cpus; if (!max_cpus) printk(KERN_INFO "SMP mode deactivated.\n");}void smp_cpus_done(unsigned int cpu_max){ return;}int __devinit __cpu_up(unsigned int cpu){ if (cpu != 0 && cpu < parisc_max_cpus) smp_boot_one_cpu(cpu); return cpu_online(cpu) ? 0 : -ENOSYS;}#ifdef ENTRY_SYS_CPUS/* Code goes along with:** entry.s: ENTRY_NAME(sys_cpus) / * 215, for cpu stat * /*/int sys_cpus(int argc, char **argv){ int i,j=0; extern int current_pid(int cpu); if( argc > 2 ) { printk("sys_cpus:Only one argument supported\n"); return (-1); } if ( argc == 1 ){ #ifdef DUMP_MORE_STATE for(i=0; i<NR_CPUS; i++) { int cpus_per_line = 4; if(cpu_online(i)) { if (j++ % cpus_per_line) printk(" %3d",i); else printk("\n %3d",i); } } printk("\n"); #else printk("\n 0\n"); #endif } else if((argc==2) && !(strcmp(argv[1],"-l"))) { printk("\nCPUSTATE TASK CPUNUM CPUID HARDCPU(HPA)\n");#ifdef DUMP_MORE_STATE for(i=0;i<NR_CPUS;i++) { if (!cpu_online(i)) continue; if (cpu_data[i].cpuid != NO_PROC_ID) { switch(cpu_data[i].state) { case STATE_RENDEZVOUS: printk("RENDEZVS "); break; case STATE_RUNNING: printk((current_pid(i)!=0) ? "RUNNING " : "IDLING "); break; case STATE_STOPPED: printk("STOPPED "); break; case STATE_HALTED: printk("HALTED "); break; default: printk("%08x?", cpu_data[i].state); break; } if(cpu_online(i)) { printk(" %4d",current_pid(i)); } printk(" %6d",cpu_number_map(i)); printk(" %5d",i); printk(" 0x%lx\n",cpu_data[i].hpa); } }#else printk("\n%s %4d 0 0 --------", (current->pid)?"RUNNING ": "IDLING ",current->pid); #endif } else if ((argc==2) && !(strcmp(argv[1],"-s"))) { #ifdef DUMP_MORE_STATE printk("\nCPUSTATE CPUID\n"); for (i=0;i<NR_CPUS;i++) { if (!cpu_online(i)) continue; if (cpu_data[i].cpuid != NO_PROC_ID) { switch(cpu_data[i].state) { case STATE_RENDEZVOUS: printk("RENDEZVS");break; case STATE_RUNNING: printk((current_pid(i)!=0) ? "RUNNING " : "IDLING"); break; case STATE_STOPPED: printk("STOPPED ");break; case STATE_HALTED: printk("HALTED ");break; default: } printk(" %5d\n",i); } }#else printk("\n%s CPU0",(current->pid==0)?"RUNNING ":"IDLING "); #endif } else { printk("sys_cpus:Unknown request\n"); return (-1); } return 0;}#endif /* ENTRY_SYS_CPUS */#ifdef CONFIG_PROC_FSint __initsetup_profiling_timer(unsigned int multiplier){ return -EINVAL;}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?