📄 smp.c
字号:
/* * Flush all other CPU's tlb and then mine. Do this with smp_call_function() * as we want to ensure all TLB's flushed before proceeding. */extern void flush_tlb_all_local(void);voidsmp_flush_tlb_all(void){ smp_call_function((void (*)(void *))flush_tlb_all_local, NULL, 1, 1); flush_tlb_all_local();}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 (test_and_set_bit(cpunum, (unsigned long *) (&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, cpunum); 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 */ /* Slaves wait here until Big Poppa daddy say "jump" */ mb(); /* PARANOID */ while (!smp_commenced) ; mb(); /* PARANOID */ cpu_idle(); /* Wait for timer to schedule some work */ /* NOTREACHED */ panic("smp_callin() AAAAaaaaahhhh....\n");}/* * Create the idle task for a new Slave CPU. DO NOT use kernel_thread() * because that could end up calling schedule(). If it did, the new idle * task could get scheduled before we had a chance to remove it from the * run-queue... */static int fork_by_hand(void){ struct pt_regs regs; /* * don't care about the regs settings since * we'll never reschedule the forked task. */ return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0);}/* * Bring one cpu online. */static int smp_boot_one_cpu(int cpuid, int cpunum){ 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 . . . */ if (fork_by_hand() < 0) panic("SMP: fork failed for CPU:%d", cpuid); idle = init_task.prev_task; if (!idle) panic("SMP: No idle process for CPU:%d", cpuid); task_set_cpu(idle, cpunum); /* manually schedule idle task */ del_from_runqueue(idle); unhash_process(idle); init_tasks[cpunum] = idle; /* Let _start know what logical CPU we're booting ** (offset into init_tasks[],cpu_data[]) */ cpu_now_booting = cpunum; /* ** boot strap code needs to know the task address since ** it also contains the process stack. */ smp_init_current_idle_task = idle ; mb(); /* ** This gets PDC to release the CPU from a very tight loop. ** See MEM_RENDEZ comments in head.S. */ __raw_writel(IRQ_OFFSET(TIMER_IRQ), cpu_data[cpunum].hpa); mb(); /* * OK, wait a bit for that CPU to finish staggering about. * Slave will set a bit when it reaches smp_cpu_init() and then * wait for smp_commenced to be 1. * Once we see the bit change, we can move on. */ for (timeout = 0; timeout < 10000; timeout++) { if(IS_LOGGED_IN(cpunum)) { /* Which implies Slave has started up */ cpu_now_booting = 0; smp_init_current_idle_task = NULL; goto alive ; } udelay(100); barrier(); } init_tasks[cpunum] = NULL; free_task_struct(idle); 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 (num %d) came alive after %ld _us\n", cpuid, cpunum, timeout * 100);#endif /* kDEBUG */#ifdef ENTRY_SYS_CPUS cpu_data[cpunum].state = STATE_RUNNING;#endif return 0;}/*** inventory.c:do_inventory() has already 'discovered' the additional CPU's.** We are ready to wrest them from PDC's control now.** Called by smp_init bring all the secondaries online and hold them. **** o Setup of the IPI irq handler is done in irq.c.** o MEM_RENDEZ is initialzed in head.S:stext()***/void __init smp_boot_cpus(void){ int i, cpu_count = 1; unsigned long bogosum = loops_per_jiffy; /* Count Monarch */ /* REVISIT - assumes first CPU reported by PAT PDC is BSP */ int bootstrap_processor=cpu_data[0].cpuid; /* CPU ID of BSP */ /* Setup BSP mappings */ printk(KERN_DEBUG "SMP: bootstrap CPU ID is %d\n",bootstrap_processor); init_task.processor = bootstrap_processor; current->processor = bootstrap_processor; cpu_online_map = 1 << bootstrap_processor; /* Mark Boostrap processor as present */ current->active_mm = &init_mm;#ifdef ENTRY_SYS_CPUS cpu_data[0].state = STATE_RUNNING;#endif /* Nothing to do when told not to. */ if (max_cpus == 0) { printk(KERN_INFO "SMP mode deactivated.\n"); return; } if (max_cpus != -1) printk(KERN_INFO "Limiting CPUs to %d\n", max_cpus); /* We found more than one CPU.... */ if (boot_cpu_data.cpu_count > 1) { for (i = 0; i < NR_CPUS; i++) { if (cpu_data[i].cpuid == NO_PROC_ID || cpu_data[i].cpuid == bootstrap_processor) continue; if (smp_boot_one_cpu(cpu_data[i].cpuid, cpu_count) < 0) continue; bogosum += loops_per_jiffy; cpu_count++; /* Count good CPUs only... */ /* Bail when we've started as many CPUS as told to */ if (cpu_count == max_cpus) break; } } if (cpu_count == 1) { printk(KERN_INFO "SMP: Bootstrap processor only.\n"); } printk(KERN_INFO "SMP: Total %d of %d processors activated " "(%lu.%02lu BogoMIPS noticed).\n", cpu_count, boot_cpu_data.cpu_count, (bogosum + 25) / 5000, ((bogosum + 25) / 50) % 100); smp_num_cpus = cpu_count;#ifdef PER_CPU_IRQ_REGION ipi_init();#endif return;}/* * Called from main.c by Monarch Processor. * After this, any CPU can schedule any task. */void smp_commence(void){ smp_commenced = 1; mb(); return;}#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(IS_LOGGED_IN(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 (!IS_LOGGED_IN(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(IS_LOGGED_IN(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 (!IS_LOGGED_IN(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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -