arch/x86/power/cpu.c

Source file repositories/reference/linux-study-clean/arch/x86/power/cpu.c

File Facts

System
Linux kernel
Corpus path
arch/x86/power/cpu.c
Extension
.c
Size
13756 bytes
Lines
524
Domain
Architecture Layer
Bucket
arch/x86
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

core_initcall(bsp_pm_check_init);

static int msr_build_context(const u32 *msr_id, const int num)
{
	struct saved_msrs *saved_msrs = &saved_context.saved_msrs;
	struct saved_msr *msr_array;
	int total_num;
	int i, j;

	total_num = saved_msrs->num + num;

	msr_array = kmalloc_objs(struct saved_msr, total_num);
	if (!msr_array) {
		pr_err("x86/pm: Can not allocate memory to save/restore MSRs during suspend.\n");
		return -ENOMEM;
	}

	if (saved_msrs->array) {
		/*
		 * Multiple callbacks can invoke this function, so copy any
		 * MSR save requests from previous invocations.
		 */
		memcpy(msr_array, saved_msrs->array,
		       sizeof(struct saved_msr) * saved_msrs->num);

		kfree(saved_msrs->array);
	}

	for (i = saved_msrs->num, j = 0; i < total_num; i++, j++) {
		u64 dummy;

		msr_array[i].info.msr_no	= msr_id[j];
		msr_array[i].valid		= !rdmsrq_safe(msr_id[j], &dummy);
		msr_array[i].info.reg.q		= 0;
	}
	saved_msrs->num   = total_num;
	saved_msrs->array = msr_array;

	return 0;
}

/*
 * The following sections are a quirk framework for problematic BIOSen:
 * Sometimes MSRs are modified by the BIOSen after suspended to
 * RAM, this might cause unexpected behavior after wakeup.
 * Thus we save/restore these specified MSRs across suspend/resume
 * in order to work around it.
 *
 * For any further problematic BIOSen/platforms,
 * please add your own function similar to msr_initialize_bdw.
 */
static int msr_initialize_bdw(const struct dmi_system_id *d)
{
	/* Add any extra MSR ids into this array. */
	u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };

	pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
	return msr_build_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
}

static const struct dmi_system_id msr_save_dmi_table[] = {
	{
	 .callback = msr_initialize_bdw,
	 .ident = "BROADWELL BDX_EP",
	 .matches = {
		DMI_MATCH(DMI_PRODUCT_NAME, "GRANTLEY"),
		DMI_MATCH(DMI_PRODUCT_VERSION, "E63448-400"),
		},
	},
	{}
};

static int msr_save_cpuid_features(const struct x86_cpu_id *c)
{
	u32 cpuid_msr_id[] = {
		MSR_AMD64_CPUID_FN_1,
	};

	pr_info("x86/pm: family %#hx cpu detected, MSR saving is needed during suspending.\n",
		c->family);

	return msr_build_context(cpuid_msr_id, ARRAY_SIZE(cpuid_msr_id));
}

static const struct x86_cpu_id msr_save_cpu_table[] = {
	X86_MATCH_VENDOR_FAM(AMD, 0x15, &msr_save_cpuid_features),
	X86_MATCH_VENDOR_FAM(AMD, 0x16, &msr_save_cpuid_features),
	{}
};

Annotation

Implementation Notes