static void pnv_kexec_wait_secondaries_down(void) { int my_cpu, i, notified = -1; my_cpu = get_cpu(); for_each_online_cpu(i) { uint8_t status; int64_t rc; if (i == my_cpu) continue; for (;;) { rc = opal_query_cpu_status(get_hard_smp_processor_id(i), &status); if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED) break; barrier(); if (i != notified) { printk(KERN_INFO "kexec: waiting for cpu %d " "(physical %d) to enter OPAL\n", i, paca[i].hw_cpu_id); notified = i; } } } }
static void pnv_kexec_wait_secondaries_down(void) { int my_cpu, i, notified = -1; my_cpu = get_cpu(); for_each_online_cpu(i) { uint8_t status; int64_t rc, timeout = 1000; if (i == my_cpu) continue; for (;;) { rc = opal_query_cpu_status(get_hard_smp_processor_id(i), &status); if (rc != OPAL_SUCCESS || status != OPAL_THREAD_STARTED) break; barrier(); if (i != notified) { printk(KERN_INFO "kexec: waiting for cpu %d " "(physical %d) to enter OPAL\n", i, paca[i].hw_cpu_id); notified = i; } /* * On crash secondaries might be unreachable or hung, * so timeout if we've waited too long * */ mdelay(1); if (timeout-- == 0) { printk(KERN_ERR "kexec: timed out waiting for " "cpu %d (physical %d) to enter OPAL\n", i, paca[i].hw_cpu_id); break; } } } }
int pnv_smp_kick_cpu(int nr) { unsigned int pcpu = get_hard_smp_processor_id(nr); unsigned long start_here = __pa(*((unsigned long *) generic_secondary_smp_init)); long rc; BUG_ON(nr < 0 || nr >= NR_CPUS); /* * If we already started or OPALv2 is not supported, we just * kick the CPU via the PACA */ if (paca[nr].cpu_start || !firmware_has_feature(FW_FEATURE_OPALv2)) goto kick; /* * At this point, the CPU can either be spinning on the way in * from kexec or be inside OPAL waiting to be started for the * first time. OPAL v3 allows us to query OPAL to know if it * has the CPUs, so we do that */ if (firmware_has_feature(FW_FEATURE_OPALv3)) { uint8_t status; rc = opal_query_cpu_status(pcpu, &status); if (rc != OPAL_SUCCESS) { pr_warn("OPAL Error %ld querying CPU %d state\n", rc, nr); return -ENODEV; } /* * Already started, just kick it, probably coming from * kexec and spinning */ if (status == OPAL_THREAD_STARTED) goto kick; /* * Available/inactive, let's kick it */ if (status == OPAL_THREAD_INACTIVE) { pr_devel("OPAL: Starting CPU %d (HW 0x%x)...\n", nr, pcpu); rc = opal_start_cpu(pcpu, start_here); if (rc != OPAL_SUCCESS) { pr_warn("OPAL Error %ld starting CPU %d\n", rc, nr); return -ENODEV; } } else { /* * An unavailable CPU (or any other unknown status) * shouldn't be started. It should also * not be in the possible map but currently it can * happen */ pr_devel("OPAL: CPU %d (HW 0x%x) is unavailable" " (status %d)...\n", nr, pcpu, status); return -ENODEV; } } else { /* * On OPAL v2, we just kick it and hope for the best, * we must not test the error from opal_start_cpu() or * we would fail to get CPUs from kexec. */ opal_start_cpu(pcpu, start_here); } kick: return smp_generic_kick_cpu(nr); }