diff options
Diffstat (limited to 'drivers/idle/intel_idle.c')
| -rw-r--r-- | drivers/idle/intel_idle.c | 154 | 
1 files changed, 89 insertions, 65 deletions
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 4466a2f969d7..7d8ea3d5fda6 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -98,8 +98,6 @@ static int intel_idle(struct cpuidle_device *dev,  			struct cpuidle_driver *drv, int index);  static void intel_idle_freeze(struct cpuidle_device *dev,  			      struct cpuidle_driver *drv, int index); -static int intel_idle_cpu_init(int cpu); -  static struct cpuidle_state *cpuidle_state_table;  /* @@ -724,6 +722,50 @@ static struct cpuidle_state atom_cstates[] = {  	{  		.enter = NULL }  }; +static struct cpuidle_state tangier_cstates[] = { +	{ +		.name = "C1-TNG", +		.desc = "MWAIT 0x00", +		.flags = MWAIT2flg(0x00), +		.exit_latency = 1, +		.target_residency = 4, +		.enter = &intel_idle, +		.enter_freeze = intel_idle_freeze, }, +	{ +		.name = "C4-TNG", +		.desc = "MWAIT 0x30", +		.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, +		.exit_latency = 100, +		.target_residency = 400, +		.enter = &intel_idle, +		.enter_freeze = intel_idle_freeze, }, +	{ +		.name = "C6-TNG", +		.desc = "MWAIT 0x52", +		.flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, +		.exit_latency = 140, +		.target_residency = 560, +		.enter = &intel_idle, +		.enter_freeze = intel_idle_freeze, }, +	{ +		.name = "C7-TNG", +		.desc = "MWAIT 0x60", +		.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, +		.exit_latency = 1200, +		.target_residency = 4000, +		.enter = &intel_idle, +		.enter_freeze = intel_idle_freeze, }, +	{ +		.name = "C9-TNG", +		.desc = "MWAIT 0x64", +		.flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED, +		.exit_latency = 10000, +		.target_residency = 20000, +		.enter = &intel_idle, +		.enter_freeze = intel_idle_freeze, }, +	{ +		.enter = NULL } +};  static struct cpuidle_state avn_cstates[] = {  	{  		.name = "C1-AVN", @@ -907,51 +949,15 @@ static void intel_idle_freeze(struct cpuidle_device *dev,  	mwait_idle_with_hints(eax, ecx);  } -static void __setup_broadcast_timer(void *arg) +static void __setup_broadcast_timer(bool on)  { -	unsigned long on = (unsigned long)arg; -  	if (on)  		tick_broadcast_enable();  	else  		tick_broadcast_disable();  } -static int cpu_hotplug_notify(struct notifier_block *n, -			      unsigned long action, void *hcpu) -{ -	int hotcpu = (unsigned long)hcpu; -	struct cpuidle_device *dev; - -	switch (action & ~CPU_TASKS_FROZEN) { -	case CPU_ONLINE: - -		if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) -			smp_call_function_single(hotcpu, __setup_broadcast_timer, -						 (void *)true, 1); - -		/* -		 * Some systems can hotplug a cpu at runtime after -		 * the kernel has booted, we have to initialize the -		 * driver in this case -		 */ -		dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu); -		if (dev->registered) -			break; - -		if (intel_idle_cpu_init(hotcpu)) -			return NOTIFY_BAD; - -		break; -	} -	return NOTIFY_OK; -} - -static struct notifier_block cpu_hotplug_notifier = { -	.notifier_call = cpu_hotplug_notify, -}; - -static void auto_demotion_disable(void *dummy) +static void auto_demotion_disable(void)  {  	unsigned long long msr_bits; @@ -959,7 +965,7 @@ static void auto_demotion_disable(void *dummy)  	msr_bits &= ~(icpu->auto_demotion_disable_flags);  	wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);  } -static void c1e_promotion_disable(void *dummy) +static void c1e_promotion_disable(void)  {  	unsigned long long msr_bits; @@ -978,6 +984,10 @@ static const struct idle_cpu idle_cpu_atom = {  	.state_table = atom_cstates,  }; +static const struct idle_cpu idle_cpu_tangier = { +	.state_table = tangier_cstates, +}; +  static const struct idle_cpu idle_cpu_lincroft = {  	.state_table = atom_cstates,  	.auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE, @@ -1066,6 +1076,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {  	ICPU(INTEL_FAM6_SANDYBRIDGE_X,		idle_cpu_snb),  	ICPU(INTEL_FAM6_ATOM_CEDARVIEW,		idle_cpu_atom),  	ICPU(INTEL_FAM6_ATOM_SILVERMONT1,	idle_cpu_byt), +	ICPU(INTEL_FAM6_ATOM_MERRIFIELD,	idle_cpu_tangier),  	ICPU(INTEL_FAM6_ATOM_AIRMONT,		idle_cpu_cht),  	ICPU(INTEL_FAM6_IVYBRIDGE,		idle_cpu_ivb),  	ICPU(INTEL_FAM6_IVYBRIDGE_X,		idle_cpu_ivt), @@ -1084,6 +1095,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {  	ICPU(INTEL_FAM6_KABYLAKE_DESKTOP,	idle_cpu_skl),  	ICPU(INTEL_FAM6_SKYLAKE_X,		idle_cpu_skx),  	ICPU(INTEL_FAM6_XEON_PHI_KNL,		idle_cpu_knl), +	ICPU(INTEL_FAM6_XEON_PHI_KNM,		idle_cpu_knl),  	ICPU(INTEL_FAM6_ATOM_GOLDMONT,		idle_cpu_bxt),  	ICPU(INTEL_FAM6_ATOM_DENVERTON,		idle_cpu_dnv),  	{} @@ -1373,12 +1385,11 @@ static void __init intel_idle_cpuidle_driver_init(void)   * allocate, initialize, register cpuidle_devices   * @cpu: cpu/core to initialize   */ -static int intel_idle_cpu_init(int cpu) +static int intel_idle_cpu_init(unsigned int cpu)  {  	struct cpuidle_device *dev;  	dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); -  	dev->cpu = cpu;  	if (cpuidle_register_device(dev)) { @@ -1387,17 +1398,36 @@ static int intel_idle_cpu_init(int cpu)  	}  	if (icpu->auto_demotion_disable_flags) -		smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); +		auto_demotion_disable();  	if (icpu->disable_promotion_to_c1e) -		smp_call_function_single(cpu, c1e_promotion_disable, NULL, 1); +		c1e_promotion_disable(); + +	return 0; +} + +static int intel_idle_cpu_online(unsigned int cpu) +{ +	struct cpuidle_device *dev; + +	if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) +		__setup_broadcast_timer(true); + +	/* +	 * Some systems can hotplug a cpu at runtime after +	 * the kernel has booted, we have to initialize the +	 * driver in this case +	 */ +	dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); +	if (!dev->registered) +		return intel_idle_cpu_init(cpu);  	return 0;  }  static int __init intel_idle_init(void)  { -	int retval, i; +	int retval;  	/* Do not load intel_idle at all for now if idle= is passed */  	if (boot_option_idle_override != IDLE_NO_OVERRIDE) @@ -1417,35 +1447,29 @@ static int __init intel_idle_init(void)  		struct cpuidle_driver *drv = cpuidle_get_driver();  		printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",  			drv ? drv->name : "none"); -		free_percpu(intel_idle_cpuidle_devices); -		return retval; +		goto init_driver_fail;  	} -	cpu_notifier_register_begin(); - -	for_each_online_cpu(i) { -		retval = intel_idle_cpu_init(i); -		if (retval) { -			intel_idle_cpuidle_devices_uninit(); -			cpu_notifier_register_done(); -			cpuidle_unregister_driver(&intel_idle_driver); -			free_percpu(intel_idle_cpuidle_devices); -			return retval; -		} -	} -	__register_cpu_notifier(&cpu_hotplug_notifier); -  	if (boot_cpu_has(X86_FEATURE_ARAT))	/* Always Reliable APIC Timer */  		lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; -	else -		on_each_cpu(__setup_broadcast_timer, (void *)true, 1); -	cpu_notifier_register_done(); +	retval = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "idle/intel:online", +				   intel_idle_cpu_online, NULL); +	if (retval < 0) +		goto hp_setup_fail;  	pr_debug(PREFIX "lapic_timer_reliable_states 0x%x\n",  		lapic_timer_reliable_states);  	return 0; + +hp_setup_fail: +	intel_idle_cpuidle_devices_uninit(); +	cpuidle_unregister_driver(&intel_idle_driver); +init_driver_fail: +	free_percpu(intel_idle_cpuidle_devices); +	return retval; +  }  device_initcall(intel_idle_init);  |