/* * Split/unsplit procedure: * * A core can be in one of three states, unsplit, 2-way split, and 4-way split. * * The mapping to subcores_per_core is simple: * * State | subcores_per_core * ------------|------------------ * Unsplit | 1 * 2-way split | 2 * 4-way split | 4 * * The core is split along thread boundaries, the mapping between subcores and * threads is as follows: * * Unsplit: * ---------------------------- * Subcore | 0 | * ---------------------------- * Thread | 0 1 2 3 4 5 6 7 | * ---------------------------- * * 2-way split: * ------------------------------------- * Subcore | 0 | 1 | * ------------------------------------- * Thread | 0 1 2 3 | 4 5 6 7 | * ------------------------------------- * * 4-way split: * ----------------------------------------- * Subcore | 0 | 1 | 2 | 3 | * ----------------------------------------- * Thread | 0 1 | 2 3 | 4 5 | 6 7 | * ----------------------------------------- * * * Transitions * ----------- * * It is not possible to transition between either of the split states, the * core must first be unsplit. The legal transitions are: * * ----------- --------------- * | | <----> | 2-way split | * | | --------------- * | Unsplit | * | | --------------- * | | <----> | 4-way split | * ----------- --------------- * * Unsplitting * ----------- * * Unsplitting is the simpler procedure. It requires thread 0 to request the * unsplit while all other threads NAP. * * Thread 0 clears HID0_POWER8_DYNLPARDIS (Dynamic LPAR Disable). This tells * the hardware that if all threads except 0 are napping, the hardware should * unsplit the core. * * Non-zero threads are sent to a NAP loop, they don't exit the loop until they * see the core unsplit. * * Core 0 spins waiting for the hardware to see all the other threads napping * and perform the unsplit. * * Once thread 0 sees the unsplit, it IPIs the secondary threads to wake them * out of NAP. They will then see the core unsplit and exit the NAP loop. * * Splitting * --------- * * The basic splitting procedure is fairly straight forward. However it is * complicated by the fact that after the split occurs, the newly created * subcores are not in a fully initialised state. * * Most notably the subcores do not have the correct value for SDR1, which * means they must not be running in virtual mode when the split occurs. The * subcores have separate timebases SPRs but these are pre-synchronised by * opal. * * To begin with secondary threads are sent to an assembly routine. There they * switch to real mode, so they are immune to the uninitialised SDR1 value. * Once in real mode they indicate that they are in real mode, and spin waiting * to see the core split. * * Thread 0 waits to see that all secondaries are in real mode, and then begins * the splitting procedure. It firstly sets HID0_POWER8_DYNLPARDIS, which * prevents the hardware from unsplitting. Then it sets the appropriate HID bit * to request the split, and spins waiting to see that the split has happened. * * Concurrently the secondaries will notice the split. When they do they set up * their SPRs, notably SDR1, and then they can return to virtual mode and exit * the procedure.
*/
/* Initialised at boot by subcore_init() */ staticint subcores_per_core;
/* * Used to communicate to offline cpus that we want them to pop out of the * offline loop and do a split or unsplit. * * 0 - no split happening * 1 - unsplit in progress * 2 - split to 2 in progress * 4 - split to 4 in progress
*/ staticint new_split_mode;
if (idle_states & OPAL_PM_WINKLE_ENABLED) { /* OPAL call to patch slw with the new HID0 value */
u64 cpu_pir = hard_smp_processor_id();
opal_slw_set_reg(cpu_pir, SPRN_HID0, hid0);
}
}
staticinlinevoid update_power8_hid0(unsignedlong hid0)
{ /* * The HID0 update on Power8 should at the very least be * preceded by a SYNC instruction followed by an ISYNC * instruction
*/ asmvolatile("sync; mtspr %0,%1; isync":: "i"(SPRN_HID0), "r"(hid0));
}
staticvoid unsplit_core(void)
{
u64 hid0, mask; int i, cpu;
/* Wait for it to happen */ while (!(mfspr(SPRN_HID0) & split_parms[i].mask))
cpu_relax();
}
staticvoid cpu_do_split(int new_mode)
{ /* * At boot subcores_per_core will be 0, so we will always unsplit at * boot. In the usual case where the core is already unsplit it's a * nop, and this just ensures the kernel's notion of the mode is * consistent with the hardware.
*/ if (subcores_per_core != 1)
unsplit_core();
void update_subcore_sibling_mask(void)
{ int cpu; /* * sibling mask for the first cpu. Left shift this by required bits * to get sibling mask for the rest of the cpus.
*/ int sibling_mask_first_cpu = (1 << threads_per_subcore) - 1;
for_each_possible_cpu(cpu) { int tid = cpu_thread_in_core(cpu); int offset = (tid / threads_per_subcore) * threads_per_subcore; int mask = sibling_mask_first_cpu << offset;
paca_ptrs[cpu]->subcore_sibling_mask = mask;
}
}
staticint cpu_update_split_mode(void *data)
{ int cpu, new_mode = *(int *)data;
if (this_cpu_ptr(&split_state)->master) {
new_split_mode = new_mode;
smp_wmb();
/* This should work even though the cpu is offline */
for_each_cpu(cpu, cpu_offline_mask)
smp_send_reschedule(cpu);
}
cpu_do_split(new_mode);
if (this_cpu_ptr(&split_state)->master) { /* Wait for all cpus to finish before we touch subcores_per_core */
for_each_present_cpu(cpu) { if (cpu >= setup_max_cpus) break;
/* Make the new mode public */
subcores_per_core = new_mode;
threads_per_subcore = threads_per_core / subcores_per_core;
update_subcore_sibling_mask();
/* Make sure the new mode is written before we exit */
mb();
}
return 0;
}
staticint set_subcores_per_core(int new_mode)
{ struct split_state *state; int cpu;
if (kvm_hv_mode_active()) {
pr_err("Unable to change split core mode while KVM active.\n"); return -EBUSY;
}
/* * We are only called at boot, or from the sysfs write. If that ever * changes we'll need a lock here.
*/
BUG_ON(new_mode < 1 || new_mode > 4 || new_mode == 3);
/* * We need all threads in a core to be present to split/unsplit so * continue only if max_cpus are aligned to threads_per_core.
*/ if (setup_max_cpus % threads_per_core) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.