📄 smp.c
字号:
send_IPI_single(cpuid, IPI_CALL_FUNC); /* Wait for response */ timeout = jiffies + HZ; while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) barrier(); if (atomic_read(&data.unstarted_count) > 0) {#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) goto resend;#else smp_call_function_data = NULL; return -ETIMEDOUT;#endif } if (wait) while (atomic_read(&data.unfinished_count) > 0) barrier(); /* unlock pointer */ smp_call_function_data = NULL; return 0;}/* * Run a function on all other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <retry> If true, keep retrying until ready. * <wait> If true, wait until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. * * Does not return until remote CPUs are nearly ready to execute <func> * or are or have executed. */intsmp_call_function (void (*func) (void *info), void *info, int retry, int wait){ struct smp_call_struct data; unsigned long timeout; int cpus = smp_num_cpus - 1; if (cpus == 0) return 0; data.func = func; data.info = info; data.wait = wait; atomic_set(&data.unstarted_count, cpus); atomic_set(&data.unfinished_count, cpus); if (pointer_lock(&smp_call_function_data, &data, retry)) return -EBUSY; /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(IPI_CALL_FUNC);retry: /* Wait for response */ timeout = jiffies + HZ; while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) barrier(); if (atomic_read(&data.unstarted_count) > 0) {#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) int i; for (i = 0; i < smp_num_cpus; i++) { if (i != smp_processor_id()) platform_send_ipi(i, IPI_IRQ, IA64_IPI_DM_INT, 0); } goto retry;#else smp_call_function_data = NULL; return -ETIMEDOUT;#endif } if (wait) while (atomic_read(&data.unfinished_count) > 0) barrier(); /* unlock pointer */ smp_call_function_data = NULL; return 0;}/* * 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. */voidsmp_flush_tlb_all(void){ smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1); __flush_tlb_all();}/* * Ideally sets up per-cpu profiling hooks. Doesn't do much now... */static inline void __initsmp_setup_percpu_timer(int cpuid){ cpu_data[cpuid].prof_counter = 1; cpu_data[cpuid].prof_multiplier = 1;}void smp_do_timer(struct pt_regs *regs){ int cpu = smp_processor_id(); int user = user_mode(regs); struct cpuinfo_ia64 *data = &cpu_data[cpu]; if (--data->prof_counter <= 0) { data->prof_counter = data->prof_multiplier; update_process_times(user); }}/* * AP's start using C here. */void __initsmp_callin (void) { extern void ia64_rid_init(void); extern void ia64_init_itm(void); extern void ia64_cpu_local_tick(void);#ifdef CONFIG_PERFMON extern void perfmon_init_percpu(void);#endif int cpu = smp_processor_id(); if (test_and_set_bit(cpu, &cpu_online_map)) { printk("CPU#%d already initialized!\n", cpu); machine_halt(); } efi_map_pal_code(); cpu_init(); smp_setup_percpu_timer(cpu); /* setup the CPU local timer tick */ ia64_init_itm();#ifdef CONFIG_PERFMON perfmon_init_percpu();#endif /* Disable all local interrupts */ ia64_set_lrr0(0, 1); ia64_set_lrr1(0, 1); local_irq_enable(); /* Interrupts have been off until now */ calibrate_delay(); my_cpu_data.loops_per_jiffy = loops_per_jiffy; /* allow the master to continue */ set_bit(cpu, &cpu_callin_map); /* finally, wait for the BP to finish initialization: */ while (!smp_commenced); cpu_idle(NULL);}/* * Create the idle task for a new AP. DO NOT use kernel_thread() because * that could end up calling schedule() in the ia64_leave_kernel exit * path in which case the new idle task could get scheduled before we * had a chance to remove it from the run-queue... */static int __init fork_by_hand(void){ /* * Don't care about the usp and regs settings since we'll never * reschedule the forked task. */ return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0);}/* * Bring one cpu online. Return 0 if this fails for any reason. */static int __initsmp_boot_one_cpu(int cpu){ struct task_struct *idle; int cpu_phys_id = cpu_physical_id(cpu); long timeout; /* * Create an idle task for this CPU. Note that the address we * 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("failed fork for CPU 0x%x", cpu_phys_id); /* * We remove it from the pidhash and the runqueue * once we got the process: */ idle = init_task.prev_task; if (!idle) panic("No idle process for CPU 0x%x", cpu_phys_id); init_tasks[cpu] = idle; del_from_runqueue(idle); unhash_process(idle); /* Schedule the first task manually. */ idle->processor = cpu; idle->has_cpu = 1; /* Let _start know what logical CPU we're booting (offset into init_tasks[] */ cpu_now_booting = cpu; /* Kick the AP in the butt */ platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); /* wait up to 10s for the AP to start */ for (timeout = 0; timeout < 100000; timeout++) { if (test_bit(cpu, &cpu_callin_map)) return 1; udelay(100); } printk(KERN_ERR "SMP: Processor 0x%x is stuck.\n", cpu_phys_id); return 0;}/* * Called by smp_init bring all the secondaries online and hold them. * XXX: this is ACPI specific; it uses "magic" variables exported from acpi.c * to 'discover' the AP's. Blech. */void __initsmp_boot_cpus(void){ int i, cpu_count = 1; unsigned long bogosum; /* Take care of some initial bookkeeping. */ memset(&__cpu_physical_id, -1, sizeof(__cpu_physical_id)); memset(&ipi_op, 0, sizeof(ipi_op)); /* Setup BP mappings */ __cpu_physical_id[0] = hard_smp_processor_id(); /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */ my_cpu_data.loops_per_jiffy = loops_per_jiffy;#if 0 smp_tune_scheduling();#endif smp_setup_percpu_timer(0); if (test_and_set_bit(0, &cpu_online_map)) { printk("CPU#%d already initialized!\n", smp_processor_id()); machine_halt(); } init_idle(); /* Nothing to do when told not to. */ if (max_cpus == 0) { printk(KERN_INFO "SMP mode deactivated.\n"); return; } if (max_cpus != -1) printk("Limiting CPUs to %d\n", max_cpus); if (smp_boot_data.cpu_count > 1) { printk(KERN_INFO "SMP: starting up secondaries.\n"); for (i = 0; i < smp_boot_data.cpu_count; i++) { /* skip performance restricted and bootstrap cpu: */ if (smp_boot_data.cpu_phys_id[i] == -1 || smp_boot_data.cpu_phys_id[i] == hard_smp_processor_id()) continue; cpu_physical_id(cpu_count) = smp_boot_data.cpu_phys_id[i]; if (!smp_boot_one_cpu(cpu_count)) continue; /* failed */ cpu_count++; /* Count good CPUs only... */ /* * Bail if we've started as many CPUS as we've been told to. */ if (cpu_count == max_cpus) break; } } if (cpu_count == 1) { printk(KERN_ERR "SMP: Bootstrap processor only.\n"); } bogosum = 0; for (i = 0; i < NR_CPUS; i++) { if (cpu_online_map & (1L << i)) bogosum += cpu_data[i].loops_per_jiffy; } printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100); smp_num_cpus = cpu_count;}/* * Called when the BP is just about to fire off init. */void __init smp_commence(void){ smp_commenced = 1;}int __initsetup_profiling_timer(unsigned int multiplier){ return -EINVAL;}/* * Assume that CPU's have been discovered by some platform-dependant * interface. For SoftSDV/Lion, that would be ACPI. * * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). * * This also registers the AP OS_MC_REDVEZ address with SAL. */void __initinit_smp_config(void){ struct fptr { unsigned long fp; unsigned long gp; } *ap_startup; long sal_ret; /* Tell SAL where to drop the AP's. */ ap_startup = (struct fptr *) start_ap; sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0); if (sal_ret < 0) { printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); printk(" Forcing UP mode\n"); max_cpus = 0; smp_num_cpus = 1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -