void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) { struct _lowcore *lc, *current_lc; struct stack_frame *sf; struct pt_regs *regs; unsigned long sp; if (smp_processor_id() == 0) func(data); __load_psw_mask(PSW_BASE_BITS | PSW_DEFAULT_KEY); /* Disable lowcore protection */ __ctl_clear_bit(0, 28); current_lc = lowcore_ptr[smp_processor_id()]; lc = lowcore_ptr[0]; if (!lc) lc = current_lc; lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu; if (!cpu_online(0)) smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]); while (sigp(0, sigp_stop_and_store_status) == sigp_busy) cpu_relax(); sp = lc->panic_stack; sp -= sizeof(struct pt_regs); regs = (struct pt_regs *) sp; memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); regs->psw = lc->psw_save_area; sp -= STACK_FRAME_OVERHEAD; sf = (struct stack_frame *) sp; sf->back_chain = regs->gprs[15]; smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); }
/* * Send an external call sigp to another cpu and return without waiting * for its completion. */ static void smp_ext_bitcall(int cpu, int sig) { /* * Set signaling bit in lowcore of target cpu and kick it */ set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); while (sigp(cpu, sigp_emergency_signal) == sigp_busy) udelay(10); }
/* * Send an external call sigp to another cpu and return without waiting * for its completion. */ static void smp_ext_bitcall(int cpu, int sig) { int order; /* * Set signaling bit in lowcore of target cpu and kick it */ set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); while (1) { order = smp_vcpu_scheduled(cpu) ? sigp_external_call : sigp_emergency_signal; if (sigp(cpu, order) != sigp_busy) break; udelay(10); } }
/* * Ensure that PSW restart is done on an online CPU */ void smp_restart_with_online_cpu(void) { int cpu; for_each_online_cpu(cpu) { if (stap() == __cpu_logical_map[cpu]) { /* We are online: Enable DAT again and return */ __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); return; } } /* We are not online: Do PSW restart on an online CPU */ while (sigp(cpu, sigp_restart) == sigp_busy) cpu_relax(); /* And stop ourself */ while (raw_sigp(stap(), sigp_stop) == sigp_busy) cpu_relax(); for (;;); }
void smp_send_stop(void) { int cpu, rc; /* Disable all interrupts/machine checks */ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); trace_hardirqs_off(); /* stop all processors */ for_each_online_cpu(cpu) { if (cpu == smp_processor_id()) continue; do { rc = sigp(cpu, sigp_stop); } while (rc == sigp_busy); while (!cpu_stopped(cpu)) cpu_relax(); } }