arch/powerpc/platforms/powernv/subcore.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/powernv/subcore.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/powernv/subcore.c
Extension
.c
Size
11282 bytes
Lines
452
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct split_state {
	u8 step;
	u8 master;
};

static DEFINE_PER_CPU(struct split_state, split_state);

static void wait_for_sync_step(int step)
{
	int i, cpu = smp_processor_id();

	for (i = cpu + 1; i < cpu + threads_per_core; i++)
		while(per_cpu(split_state, i).step < step)
			barrier();

	/* Order the wait loop vs any subsequent loads/stores. */
	mb();
}

static void update_hid_in_slw(u64 hid0)
{
	u64 idle_states = pnv_get_supported_cpuidle_states();

	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);
	}
}

static inline void update_power8_hid0(unsigned long hid0)
{
	/*
	 *  The HID0 update on Power8 should at the very least be
	 *  preceded by a SYNC instruction followed by an ISYNC
	 *  instruction
	 */
	asm volatile("sync; mtspr %0,%1; isync":: "i"(SPRN_HID0), "r"(hid0));
}

static void unsplit_core(void)
{
	u64 hid0, mask;
	int i, cpu;

	mask = HID0_POWER8_2LPARMODE | HID0_POWER8_4LPARMODE;

	cpu = smp_processor_id();
	if (cpu_thread_in_core(cpu) != 0) {
		while (mfspr(SPRN_HID0) & mask)
			power7_idle_type(PNV_THREAD_NAP);

		per_cpu(split_state, cpu).step = SYNC_STEP_UNSPLIT;
		return;
	}

	hid0 = mfspr(SPRN_HID0);
	hid0 &= ~HID0_POWER8_DYNLPARDIS;
	update_power8_hid0(hid0);
	update_hid_in_slw(hid0);

	while (mfspr(SPRN_HID0) & mask)
		cpu_relax();

	/* Wake secondaries out of NAP */
	for (i = cpu + 1; i < cpu + threads_per_core; i++)
		smp_send_reschedule(i);

	wait_for_sync_step(SYNC_STEP_UNSPLIT);
}

static void split_core(int new_mode)
{
	struct {  u64 value; u64 mask; } split_parms[2] = {
		{ HID0_POWER8_1TO2LPAR, HID0_POWER8_2LPARMODE },
		{ HID0_POWER8_1TO4LPAR, HID0_POWER8_4LPARMODE }
	};
	int i, cpu;
	u64 hid0;

	/* Convert new_mode (2 or 4) into an index into our parms array */
	i = (new_mode >> 1) - 1;
	BUG_ON(i < 0 || i > 1);

	cpu = smp_processor_id();
	if (cpu_thread_in_core(cpu) != 0) {
		split_core_secondary_loop(&per_cpu(split_state, cpu).step);
		return;
	}

Annotation

Implementation Notes