xref: /openbmc/linux/drivers/acpi/processor_throttling.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * processor_throttling.c - Throttling submodule of the ACPI processor driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
61da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
71da177e4SLinus Torvalds  *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
81da177e4SLinus Torvalds  *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
91da177e4SLinus Torvalds  *                      - Added processor hotplug support
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
124140054aSHanjun Guo #define pr_fmt(fmt) "ACPI: " fmt
134140054aSHanjun Guo 
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/module.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/init.h>
18357dc4c3SZhao Yakui #include <linux/sched.h>
191da177e4SLinus Torvalds #include <linux/cpufreq.h>
208b48463fSLv Zheng #include <linux/acpi.h>
218b48463fSLv Zheng #include <acpi/processor.h>
221da177e4SLinus Torvalds #include <asm/io.h>
237c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
241da177e4SLinus Torvalds 
2556c213faSZhang Rui /* ignore_tpc:
2656c213faSZhang Rui  *  0 -> acpi processor driver doesn't ignore _TPC values
2756c213faSZhang Rui  *  1 -> acpi processor driver ignores _TPC values
2856c213faSZhang Rui  */
2956c213faSZhang Rui static int ignore_tpc;
3056c213faSZhang Rui module_param(ignore_tpc, int, 0644);
3156c213faSZhang Rui MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support");
3256c213faSZhang Rui 
33e4aa5cb2SZhao Yakui struct throttling_tstate {
34e4aa5cb2SZhao Yakui 	unsigned int cpu;		/* cpu nr */
35e4aa5cb2SZhao Yakui 	int target_state;		/* target T-state */
36e4aa5cb2SZhao Yakui };
37e4aa5cb2SZhao Yakui 
38f3ca4164SLan Tianyu struct acpi_processor_throttling_arg {
39f3ca4164SLan Tianyu 	struct acpi_processor *pr;
40f3ca4164SLan Tianyu 	int target_state;
41f3ca4164SLan Tianyu 	bool force;
42f3ca4164SLan Tianyu };
43f3ca4164SLan Tianyu 
44e4aa5cb2SZhao Yakui #define THROTTLING_PRECHANGE       (1)
45e4aa5cb2SZhao Yakui #define THROTTLING_POSTCHANGE      (2)
46e4aa5cb2SZhao Yakui 
4701854e69SLuming Yu static int acpi_processor_get_throttling(struct acpi_processor *pr);
488153f9acSThomas Gleixner static int __acpi_processor_set_throttling(struct acpi_processor *pr,
498153f9acSThomas Gleixner 					   int state, bool force, bool direct);
5001854e69SLuming Yu 
acpi_processor_update_tsd_coord(void)511180509fSZhao Yakui static int acpi_processor_update_tsd_coord(void)
521180509fSZhao Yakui {
53*04068da8SColin Ian King 	int count_target;
541180509fSZhao Yakui 	int retval = 0;
551180509fSZhao Yakui 	unsigned int i, j;
562fdf66b4SRusty Russell 	cpumask_var_t covered_cpus;
571180509fSZhao Yakui 	struct acpi_processor *pr, *match_pr;
581180509fSZhao Yakui 	struct acpi_tsd_package *pdomain, *match_pdomain;
591180509fSZhao Yakui 	struct acpi_processor_throttling *pthrottling, *match_pthrottling;
601180509fSZhao Yakui 
6179f55997SLi Zefan 	if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
622fdf66b4SRusty Russell 		return -ENOMEM;
632fdf66b4SRusty Russell 
641180509fSZhao Yakui 	/*
651180509fSZhao Yakui 	 * Now that we have _TSD data from all CPUs, lets setup T-state
6633a2a529SZhao Yakui 	 * coordination between all CPUs.
671180509fSZhao Yakui 	 */
681180509fSZhao Yakui 	for_each_possible_cpu(i) {
69706546d0SMike Travis 		pr = per_cpu(processors, i);
701180509fSZhao Yakui 		if (!pr)
711180509fSZhao Yakui 			continue;
721180509fSZhao Yakui 
731180509fSZhao Yakui 		/* Basic validity check for domain info */
741180509fSZhao Yakui 		pthrottling = &(pr->throttling);
751180509fSZhao Yakui 
761180509fSZhao Yakui 		/*
771180509fSZhao Yakui 		 * If tsd package for one cpu is invalid, the coordination
781180509fSZhao Yakui 		 * among all CPUs is thought as invalid.
791180509fSZhao Yakui 		 * Maybe it is ugly.
801180509fSZhao Yakui 		 */
811180509fSZhao Yakui 		if (!pthrottling->tsd_valid_flag) {
821180509fSZhao Yakui 			retval = -EINVAL;
831180509fSZhao Yakui 			break;
841180509fSZhao Yakui 		}
851180509fSZhao Yakui 	}
861180509fSZhao Yakui 	if (retval)
871180509fSZhao Yakui 		goto err_ret;
881180509fSZhao Yakui 
891180509fSZhao Yakui 	for_each_possible_cpu(i) {
90706546d0SMike Travis 		pr = per_cpu(processors, i);
911180509fSZhao Yakui 		if (!pr)
921180509fSZhao Yakui 			continue;
931180509fSZhao Yakui 
942fdf66b4SRusty Russell 		if (cpumask_test_cpu(i, covered_cpus))
951180509fSZhao Yakui 			continue;
961180509fSZhao Yakui 		pthrottling = &pr->throttling;
971180509fSZhao Yakui 
981180509fSZhao Yakui 		pdomain = &(pthrottling->domain_info);
992fdf66b4SRusty Russell 		cpumask_set_cpu(i, pthrottling->shared_cpu_map);
1002fdf66b4SRusty Russell 		cpumask_set_cpu(i, covered_cpus);
1011180509fSZhao Yakui 		/*
1021180509fSZhao Yakui 		 * If the number of processor in the TSD domain is 1, it is
1031180509fSZhao Yakui 		 * unnecessary to parse the coordination for this CPU.
1041180509fSZhao Yakui 		 */
1051180509fSZhao Yakui 		if (pdomain->num_processors <= 1)
1061180509fSZhao Yakui 			continue;
1071180509fSZhao Yakui 
1081180509fSZhao Yakui 		/* Validate the Domain info */
1091180509fSZhao Yakui 		count_target = pdomain->num_processors;
1101180509fSZhao Yakui 
1111180509fSZhao Yakui 		for_each_possible_cpu(j) {
1121180509fSZhao Yakui 			if (i == j)
1131180509fSZhao Yakui 				continue;
1141180509fSZhao Yakui 
115706546d0SMike Travis 			match_pr = per_cpu(processors, j);
1161180509fSZhao Yakui 			if (!match_pr)
1171180509fSZhao Yakui 				continue;
1181180509fSZhao Yakui 
1191180509fSZhao Yakui 			match_pthrottling = &(match_pr->throttling);
1201180509fSZhao Yakui 			match_pdomain = &(match_pthrottling->domain_info);
1211180509fSZhao Yakui 			if (match_pdomain->domain != pdomain->domain)
1221180509fSZhao Yakui 				continue;
1231180509fSZhao Yakui 
1241180509fSZhao Yakui 			/* Here i and j are in the same domain.
1251180509fSZhao Yakui 			 * If two TSD packages have the same domain, they
1261180509fSZhao Yakui 			 * should have the same num_porcessors and
1271180509fSZhao Yakui 			 * coordination type. Otherwise it will be regarded
1281180509fSZhao Yakui 			 * as illegal.
1291180509fSZhao Yakui 			 */
1301180509fSZhao Yakui 			if (match_pdomain->num_processors != count_target) {
1311180509fSZhao Yakui 				retval = -EINVAL;
1321180509fSZhao Yakui 				goto err_ret;
1331180509fSZhao Yakui 			}
1341180509fSZhao Yakui 
1351180509fSZhao Yakui 			if (pdomain->coord_type != match_pdomain->coord_type) {
1361180509fSZhao Yakui 				retval = -EINVAL;
1371180509fSZhao Yakui 				goto err_ret;
1381180509fSZhao Yakui 			}
1391180509fSZhao Yakui 
1402fdf66b4SRusty Russell 			cpumask_set_cpu(j, covered_cpus);
1412fdf66b4SRusty Russell 			cpumask_set_cpu(j, pthrottling->shared_cpu_map);
1421180509fSZhao Yakui 		}
1431180509fSZhao Yakui 		for_each_possible_cpu(j) {
1441180509fSZhao Yakui 			if (i == j)
1451180509fSZhao Yakui 				continue;
1461180509fSZhao Yakui 
147706546d0SMike Travis 			match_pr = per_cpu(processors, j);
1481180509fSZhao Yakui 			if (!match_pr)
1491180509fSZhao Yakui 				continue;
1501180509fSZhao Yakui 
1511180509fSZhao Yakui 			match_pthrottling = &(match_pr->throttling);
1521180509fSZhao Yakui 			match_pdomain = &(match_pthrottling->domain_info);
1531180509fSZhao Yakui 			if (match_pdomain->domain != pdomain->domain)
1541180509fSZhao Yakui 				continue;
1551180509fSZhao Yakui 
1561180509fSZhao Yakui 			/*
1571180509fSZhao Yakui 			 * If some CPUS have the same domain, they
1581180509fSZhao Yakui 			 * will have the same shared_cpu_map.
1591180509fSZhao Yakui 			 */
1602fdf66b4SRusty Russell 			cpumask_copy(match_pthrottling->shared_cpu_map,
1612fdf66b4SRusty Russell 				     pthrottling->shared_cpu_map);
1621180509fSZhao Yakui 		}
1631180509fSZhao Yakui 	}
1641180509fSZhao Yakui 
1651180509fSZhao Yakui err_ret:
1662fdf66b4SRusty Russell 	free_cpumask_var(covered_cpus);
1672fdf66b4SRusty Russell 
1681180509fSZhao Yakui 	for_each_possible_cpu(i) {
169706546d0SMike Travis 		pr = per_cpu(processors, i);
1701180509fSZhao Yakui 		if (!pr)
1711180509fSZhao Yakui 			continue;
1721180509fSZhao Yakui 
1731180509fSZhao Yakui 		/*
1741180509fSZhao Yakui 		 * Assume no coordination on any error parsing domain info.
1751180509fSZhao Yakui 		 * The coordination type will be forced as SW_ALL.
1761180509fSZhao Yakui 		 */
1771180509fSZhao Yakui 		if (retval) {
1781180509fSZhao Yakui 			pthrottling = &(pr->throttling);
1792fdf66b4SRusty Russell 			cpumask_clear(pthrottling->shared_cpu_map);
1802fdf66b4SRusty Russell 			cpumask_set_cpu(i, pthrottling->shared_cpu_map);
1811180509fSZhao Yakui 			pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
1821180509fSZhao Yakui 		}
1831180509fSZhao Yakui 	}
1841180509fSZhao Yakui 
1851180509fSZhao Yakui 	return retval;
1861180509fSZhao Yakui }
1871180509fSZhao Yakui 
1881180509fSZhao Yakui /*
1891180509fSZhao Yakui  * Update the T-state coordination after the _TSD
1901180509fSZhao Yakui  * data for all cpus is obtained.
1911180509fSZhao Yakui  */
acpi_processor_throttling_init(void)1921180509fSZhao Yakui void acpi_processor_throttling_init(void)
1931180509fSZhao Yakui {
19452af99c3SRafael J. Wysocki 	if (acpi_processor_update_tsd_coord())
19552af99c3SRafael J. Wysocki 		pr_debug("Assume no T-state coordination\n");
1961180509fSZhao Yakui }
1971180509fSZhao Yakui 
acpi_processor_throttling_notifier(unsigned long event,void * data)198e4aa5cb2SZhao Yakui static int acpi_processor_throttling_notifier(unsigned long event, void *data)
199e4aa5cb2SZhao Yakui {
200e4aa5cb2SZhao Yakui 	struct throttling_tstate *p_tstate = data;
201e4aa5cb2SZhao Yakui 	struct acpi_processor *pr;
202e4aa5cb2SZhao Yakui 	unsigned int cpu;
203e4aa5cb2SZhao Yakui 	int target_state;
204e4aa5cb2SZhao Yakui 	struct acpi_processor_limit *p_limit;
205e4aa5cb2SZhao Yakui 	struct acpi_processor_throttling *p_throttling;
206e4aa5cb2SZhao Yakui 
207e4aa5cb2SZhao Yakui 	cpu = p_tstate->cpu;
208706546d0SMike Travis 	pr = per_cpu(processors, cpu);
209e4aa5cb2SZhao Yakui 	if (!pr) {
21052af99c3SRafael J. Wysocki 		pr_debug("Invalid pr pointer\n");
211e4aa5cb2SZhao Yakui 		return 0;
212e4aa5cb2SZhao Yakui 	}
213e4aa5cb2SZhao Yakui 	if (!pr->flags.throttling) {
21452af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle,
21552af99c3SRafael J. Wysocki 				  "Throttling control unsupported on CPU %d\n",
21652af99c3SRafael J. Wysocki 				  cpu);
217e4aa5cb2SZhao Yakui 		return 0;
218e4aa5cb2SZhao Yakui 	}
219e4aa5cb2SZhao Yakui 	target_state = p_tstate->target_state;
220e4aa5cb2SZhao Yakui 	p_throttling = &(pr->throttling);
221e4aa5cb2SZhao Yakui 	switch (event) {
222e4aa5cb2SZhao Yakui 	case THROTTLING_PRECHANGE:
223e4aa5cb2SZhao Yakui 		/*
224e4aa5cb2SZhao Yakui 		 * Prechange event is used to choose one proper t-state,
225e4aa5cb2SZhao Yakui 		 * which meets the limits of thermal, user and _TPC.
226e4aa5cb2SZhao Yakui 		 */
227e4aa5cb2SZhao Yakui 		p_limit = &pr->limit;
228e4aa5cb2SZhao Yakui 		if (p_limit->thermal.tx > target_state)
229e4aa5cb2SZhao Yakui 			target_state = p_limit->thermal.tx;
230e4aa5cb2SZhao Yakui 		if (p_limit->user.tx > target_state)
231e4aa5cb2SZhao Yakui 			target_state = p_limit->user.tx;
232e4aa5cb2SZhao Yakui 		if (pr->throttling_platform_limit > target_state)
233e4aa5cb2SZhao Yakui 			target_state = pr->throttling_platform_limit;
234e4aa5cb2SZhao Yakui 		if (target_state >= p_throttling->state_count) {
2354140054aSHanjun Guo 			pr_warn("Exceed the limit of T-state \n");
236e4aa5cb2SZhao Yakui 			target_state = p_throttling->state_count - 1;
237e4aa5cb2SZhao Yakui 		}
238e4aa5cb2SZhao Yakui 		p_tstate->target_state = target_state;
23952af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle,
24052af99c3SRafael J. Wysocki 				  "PreChange Event: target T-state of CPU %d is T%d\n",
24152af99c3SRafael J. Wysocki 				  cpu, target_state);
242e4aa5cb2SZhao Yakui 		break;
243e4aa5cb2SZhao Yakui 	case THROTTLING_POSTCHANGE:
244e4aa5cb2SZhao Yakui 		/*
245e4aa5cb2SZhao Yakui 		 * Postchange event is only used to update the
246e4aa5cb2SZhao Yakui 		 * T-state flag of acpi_processor_throttling.
247e4aa5cb2SZhao Yakui 		 */
248e4aa5cb2SZhao Yakui 		p_throttling->state = target_state;
24952af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle,
25052af99c3SRafael J. Wysocki 				  "PostChange Event: CPU %d is switched to T%d\n",
25152af99c3SRafael J. Wysocki 				  cpu, target_state);
252e4aa5cb2SZhao Yakui 		break;
253e4aa5cb2SZhao Yakui 	default:
2544140054aSHanjun Guo 		pr_warn("Unsupported Throttling notifier event\n");
255e4aa5cb2SZhao Yakui 		break;
256e4aa5cb2SZhao Yakui 	}
257e4aa5cb2SZhao Yakui 
258e4aa5cb2SZhao Yakui 	return 0;
259e4aa5cb2SZhao Yakui }
260e4aa5cb2SZhao Yakui 
261c30c620eSLen Brown /*
262c30c620eSLen Brown  * _TPC - Throttling Present Capabilities
263c30c620eSLen Brown  */
acpi_processor_get_platform_limit(struct acpi_processor * pr)26401854e69SLuming Yu static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
26501854e69SLuming Yu {
26601854e69SLuming Yu 	acpi_status status = 0;
26727663c58SMatthew Wilcox 	unsigned long long tpc = 0;
26801854e69SLuming Yu 
26901854e69SLuming Yu 	if (!pr)
27001854e69SLuming Yu 		return -EINVAL;
27156c213faSZhang Rui 
27256c213faSZhang Rui 	if (ignore_tpc)
27356c213faSZhang Rui 		goto end;
27456c213faSZhang Rui 
27501854e69SLuming Yu 	status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
276c30c620eSLen Brown 	if (ACPI_FAILURE(status)) {
27752af99c3SRafael J. Wysocki 		if (status != AE_NOT_FOUND)
2784c324548SRafael J. Wysocki 			acpi_evaluation_failure_warn(pr->handle, "_TPC", status);
27952af99c3SRafael J. Wysocki 
28001854e69SLuming Yu 		return -ENODEV;
28101854e69SLuming Yu 	}
28256c213faSZhang Rui 
28356c213faSZhang Rui end:
28401854e69SLuming Yu 	pr->throttling_platform_limit = (int)tpc;
28501854e69SLuming Yu 	return 0;
28601854e69SLuming Yu }
28701854e69SLuming Yu 
acpi_processor_tstate_has_changed(struct acpi_processor * pr)28801854e69SLuming Yu int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
28901854e69SLuming Yu {
290ef54d5adSZhao Yakui 	int result = 0;
291ef54d5adSZhao Yakui 	int throttling_limit;
292ef54d5adSZhao Yakui 	int current_state;
293ef54d5adSZhao Yakui 	struct acpi_processor_limit *limit;
294ef54d5adSZhao Yakui 	int target_state;
295ef54d5adSZhao Yakui 
29656c213faSZhang Rui 	if (ignore_tpc)
29756c213faSZhang Rui 		return 0;
29856c213faSZhang Rui 
299ef54d5adSZhao Yakui 	result = acpi_processor_get_platform_limit(pr);
300ef54d5adSZhao Yakui 	if (result) {
301ef54d5adSZhao Yakui 		/* Throttling Limit is unsupported */
302ef54d5adSZhao Yakui 		return result;
303ef54d5adSZhao Yakui 	}
304ef54d5adSZhao Yakui 
305ef54d5adSZhao Yakui 	throttling_limit = pr->throttling_platform_limit;
306ef54d5adSZhao Yakui 	if (throttling_limit >= pr->throttling.state_count) {
307ef54d5adSZhao Yakui 		/* Uncorrect Throttling Limit */
308ef54d5adSZhao Yakui 		return -EINVAL;
309ef54d5adSZhao Yakui 	}
310ef54d5adSZhao Yakui 
311ef54d5adSZhao Yakui 	current_state = pr->throttling.state;
312ef54d5adSZhao Yakui 	if (current_state > throttling_limit) {
313ef54d5adSZhao Yakui 		/*
314ef54d5adSZhao Yakui 		 * The current state can meet the requirement of
315ef54d5adSZhao Yakui 		 * _TPC limit. But it is reasonable that OSPM changes
316ef54d5adSZhao Yakui 		 * t-states from high to low for better performance.
317ef54d5adSZhao Yakui 		 * Of course the limit condition of thermal
318ef54d5adSZhao Yakui 		 * and user should be considered.
319ef54d5adSZhao Yakui 		 */
320ef54d5adSZhao Yakui 		limit = &pr->limit;
321ef54d5adSZhao Yakui 		target_state = throttling_limit;
322ef54d5adSZhao Yakui 		if (limit->thermal.tx > target_state)
323ef54d5adSZhao Yakui 			target_state = limit->thermal.tx;
324ef54d5adSZhao Yakui 		if (limit->user.tx > target_state)
325ef54d5adSZhao Yakui 			target_state = limit->user.tx;
326ef54d5adSZhao Yakui 	} else if (current_state == throttling_limit) {
327ef54d5adSZhao Yakui 		/*
328ef54d5adSZhao Yakui 		 * Unnecessary to change the throttling state
329ef54d5adSZhao Yakui 		 */
330ef54d5adSZhao Yakui 		return 0;
331ef54d5adSZhao Yakui 	} else {
332ef54d5adSZhao Yakui 		/*
333ef54d5adSZhao Yakui 		 * If the current state is lower than the limit of _TPC, it
334ef54d5adSZhao Yakui 		 * will be forced to switch to the throttling state defined
335ef54d5adSZhao Yakui 		 * by throttling_platfor_limit.
336ef54d5adSZhao Yakui 		 * Because the previous state meets with the limit condition
337ef54d5adSZhao Yakui 		 * of thermal and user, it is unnecessary to check it again.
338ef54d5adSZhao Yakui 		 */
339ef54d5adSZhao Yakui 		target_state = throttling_limit;
340ef54d5adSZhao Yakui 	}
3412a908002SFrans Pop 	return acpi_processor_set_throttling(pr, target_state, false);
34201854e69SLuming Yu }
34301854e69SLuming Yu 
344c30c620eSLen Brown /*
3455a344a50SZhao Yakui  * This function is used to reevaluate whether the T-state is valid
3465a344a50SZhao Yakui  * after one CPU is onlined/offlined.
3475a344a50SZhao Yakui  * It is noted that it won't reevaluate the following properties for
3485a344a50SZhao Yakui  * the T-state.
3495a344a50SZhao Yakui  *	1. Control method.
3505a344a50SZhao Yakui  *	2. the number of supported T-state
3515a344a50SZhao Yakui  *	3. TSD domain
3525a344a50SZhao Yakui  */
acpi_processor_reevaluate_tstate(struct acpi_processor * pr,bool is_dead)3535a344a50SZhao Yakui void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
35464f3bf2fSSebastian Andrzej Siewior 					bool is_dead)
3555a344a50SZhao Yakui {
3565a344a50SZhao Yakui 	int result = 0;
3575a344a50SZhao Yakui 
35864f3bf2fSSebastian Andrzej Siewior 	if (is_dead) {
3595a344a50SZhao Yakui 		/* When one CPU is offline, the T-state throttling
3605a344a50SZhao Yakui 		 * will be invalidated.
3615a344a50SZhao Yakui 		 */
3625a344a50SZhao Yakui 		pr->flags.throttling = 0;
3635a344a50SZhao Yakui 		return;
3645a344a50SZhao Yakui 	}
3655a344a50SZhao Yakui 	/* the following is to recheck whether the T-state is valid for
3665a344a50SZhao Yakui 	 * the online CPU
3675a344a50SZhao Yakui 	 */
3685a344a50SZhao Yakui 	if (!pr->throttling.state_count) {
3695a344a50SZhao Yakui 		/* If the number of T-state is invalid, it is
3705a344a50SZhao Yakui 		 * invalidated.
3715a344a50SZhao Yakui 		 */
3725a344a50SZhao Yakui 		pr->flags.throttling = 0;
3735a344a50SZhao Yakui 		return;
3745a344a50SZhao Yakui 	}
3755a344a50SZhao Yakui 	pr->flags.throttling = 1;
3765a344a50SZhao Yakui 
3775a344a50SZhao Yakui 	/* Disable throttling (if enabled).  We'll let subsequent
3785a344a50SZhao Yakui 	 * policy (e.g.thermal) decide to lower performance if it
3795a344a50SZhao Yakui 	 * so chooses, but for now we'll crank up the speed.
3805a344a50SZhao Yakui 	 */
3815a344a50SZhao Yakui 
3825a344a50SZhao Yakui 	result = acpi_processor_get_throttling(pr);
3835a344a50SZhao Yakui 	if (result)
3845a344a50SZhao Yakui 		goto end;
3855a344a50SZhao Yakui 
3865a344a50SZhao Yakui 	if (pr->throttling.state) {
3875a344a50SZhao Yakui 		result = acpi_processor_set_throttling(pr, 0, false);
3885a344a50SZhao Yakui 		if (result)
3895a344a50SZhao Yakui 			goto end;
3905a344a50SZhao Yakui 	}
3915a344a50SZhao Yakui 
3925a344a50SZhao Yakui end:
3935a344a50SZhao Yakui 	if (result)
3945a344a50SZhao Yakui 		pr->flags.throttling = 0;
3955a344a50SZhao Yakui }
3965a344a50SZhao Yakui /*
397c30c620eSLen Brown  * _PTC - Processor Throttling Control (and status) register location
398c30c620eSLen Brown  */
acpi_processor_get_throttling_control(struct acpi_processor * pr)39901854e69SLuming Yu static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
40001854e69SLuming Yu {
40101854e69SLuming Yu 	int result = 0;
40201854e69SLuming Yu 	acpi_status status = 0;
40301854e69SLuming Yu 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
40401854e69SLuming Yu 	union acpi_object *ptc = NULL;
40569530b43SYang Li 	union acpi_object obj;
4069bcb2721SZhao Yakui 	struct acpi_processor_throttling *throttling;
40701854e69SLuming Yu 
40801854e69SLuming Yu 	status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
40901854e69SLuming Yu 	if (ACPI_FAILURE(status)) {
41052af99c3SRafael J. Wysocki 		if (status != AE_NOT_FOUND)
4114c324548SRafael J. Wysocki 			acpi_evaluation_failure_warn(pr->handle, "_PTC", status);
41252af99c3SRafael J. Wysocki 
41301854e69SLuming Yu 		return -ENODEV;
41401854e69SLuming Yu 	}
41501854e69SLuming Yu 
41601854e69SLuming Yu 	ptc = (union acpi_object *)buffer.pointer;
41701854e69SLuming Yu 	if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
41801854e69SLuming Yu 	    || (ptc->package.count != 2)) {
4194140054aSHanjun Guo 		pr_err("Invalid _PTC data\n");
42001854e69SLuming Yu 		result = -EFAULT;
42101854e69SLuming Yu 		goto end;
42201854e69SLuming Yu 	}
42301854e69SLuming Yu 
42401854e69SLuming Yu 	/*
42501854e69SLuming Yu 	 * control_register
42601854e69SLuming Yu 	 */
42701854e69SLuming Yu 
42801854e69SLuming Yu 	obj = ptc->package.elements[0];
42901854e69SLuming Yu 
43001854e69SLuming Yu 	if ((obj.type != ACPI_TYPE_BUFFER)
43101854e69SLuming Yu 	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
43201854e69SLuming Yu 	    || (obj.buffer.pointer == NULL)) {
4334140054aSHanjun Guo 		pr_err("Invalid _PTC data (control_register)\n");
43401854e69SLuming Yu 		result = -EFAULT;
43501854e69SLuming Yu 		goto end;
43601854e69SLuming Yu 	}
43701854e69SLuming Yu 	memcpy(&pr->throttling.control_register, obj.buffer.pointer,
43801854e69SLuming Yu 	       sizeof(struct acpi_ptc_register));
43901854e69SLuming Yu 
44001854e69SLuming Yu 	/*
44101854e69SLuming Yu 	 * status_register
44201854e69SLuming Yu 	 */
44301854e69SLuming Yu 
44401854e69SLuming Yu 	obj = ptc->package.elements[1];
44501854e69SLuming Yu 
44601854e69SLuming Yu 	if ((obj.type != ACPI_TYPE_BUFFER)
44701854e69SLuming Yu 	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
44801854e69SLuming Yu 	    || (obj.buffer.pointer == NULL)) {
4494140054aSHanjun Guo 		pr_err("Invalid _PTC data (status_register)\n");
45001854e69SLuming Yu 		result = -EFAULT;
45101854e69SLuming Yu 		goto end;
45201854e69SLuming Yu 	}
45301854e69SLuming Yu 
45401854e69SLuming Yu 	memcpy(&pr->throttling.status_register, obj.buffer.pointer,
45501854e69SLuming Yu 	       sizeof(struct acpi_ptc_register));
45601854e69SLuming Yu 
4579bcb2721SZhao Yakui 	throttling = &pr->throttling;
4589bcb2721SZhao Yakui 
4599bcb2721SZhao Yakui 	if ((throttling->control_register.bit_width +
4609bcb2721SZhao Yakui 		throttling->control_register.bit_offset) > 32) {
4614140054aSHanjun Guo 		pr_err("Invalid _PTC control register\n");
4629bcb2721SZhao Yakui 		result = -EFAULT;
4639bcb2721SZhao Yakui 		goto end;
4649bcb2721SZhao Yakui 	}
4659bcb2721SZhao Yakui 
4669bcb2721SZhao Yakui 	if ((throttling->status_register.bit_width +
4679bcb2721SZhao Yakui 		throttling->status_register.bit_offset) > 32) {
4684140054aSHanjun Guo 		pr_err("Invalid _PTC status register\n");
4699bcb2721SZhao Yakui 		result = -EFAULT;
4709bcb2721SZhao Yakui 		goto end;
4719bcb2721SZhao Yakui 	}
4729bcb2721SZhao Yakui 
47301854e69SLuming Yu end:
47401854e69SLuming Yu 	kfree(buffer.pointer);
47501854e69SLuming Yu 
47601854e69SLuming Yu 	return result;
47701854e69SLuming Yu }
478c30c620eSLen Brown 
479c30c620eSLen Brown /*
480c30c620eSLen Brown  * _TSS - Throttling Supported States
481c30c620eSLen Brown  */
acpi_processor_get_throttling_states(struct acpi_processor * pr)48201854e69SLuming Yu static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
48301854e69SLuming Yu {
48401854e69SLuming Yu 	int result = 0;
48501854e69SLuming Yu 	acpi_status status = AE_OK;
48601854e69SLuming Yu 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
48701854e69SLuming Yu 	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
48801854e69SLuming Yu 	struct acpi_buffer state = { 0, NULL };
48901854e69SLuming Yu 	union acpi_object *tss = NULL;
49001854e69SLuming Yu 	int i;
49101854e69SLuming Yu 
49201854e69SLuming Yu 	status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
49301854e69SLuming Yu 	if (ACPI_FAILURE(status)) {
49452af99c3SRafael J. Wysocki 		if (status != AE_NOT_FOUND)
4954c324548SRafael J. Wysocki 			acpi_evaluation_failure_warn(pr->handle, "_TSS", status);
49652af99c3SRafael J. Wysocki 
49701854e69SLuming Yu 		return -ENODEV;
49801854e69SLuming Yu 	}
49901854e69SLuming Yu 
50001854e69SLuming Yu 	tss = buffer.pointer;
50101854e69SLuming Yu 	if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
5024140054aSHanjun Guo 		pr_err("Invalid _TSS data\n");
50301854e69SLuming Yu 		result = -EFAULT;
50401854e69SLuming Yu 		goto end;
50501854e69SLuming Yu 	}
50601854e69SLuming Yu 
50752af99c3SRafael J. Wysocki 	acpi_handle_debug(pr->handle, "Found %d throttling states\n",
50852af99c3SRafael J. Wysocki 			  tss->package.count);
50901854e69SLuming Yu 
51001854e69SLuming Yu 	pr->throttling.state_count = tss->package.count;
51101854e69SLuming Yu 	pr->throttling.states_tss =
5126da2ec56SKees Cook 	    kmalloc_array(tss->package.count,
5136da2ec56SKees Cook 			  sizeof(struct acpi_processor_tx_tss),
51401854e69SLuming Yu 			  GFP_KERNEL);
51501854e69SLuming Yu 	if (!pr->throttling.states_tss) {
51601854e69SLuming Yu 		result = -ENOMEM;
51701854e69SLuming Yu 		goto end;
51801854e69SLuming Yu 	}
51901854e69SLuming Yu 
52001854e69SLuming Yu 	for (i = 0; i < pr->throttling.state_count; i++) {
52101854e69SLuming Yu 
522ff55a9ceSLen Brown 		struct acpi_processor_tx_tss *tx =
523ff55a9ceSLen Brown 		    (struct acpi_processor_tx_tss *)&(pr->throttling.
524ff55a9ceSLen Brown 						      states_tss[i]);
52501854e69SLuming Yu 
52601854e69SLuming Yu 		state.length = sizeof(struct acpi_processor_tx_tss);
52701854e69SLuming Yu 		state.pointer = tx;
52801854e69SLuming Yu 
52952af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle, "Extracting state %d\n", i);
53001854e69SLuming Yu 
53101854e69SLuming Yu 		status = acpi_extract_package(&(tss->package.elements[i]),
53201854e69SLuming Yu 					      &format, &state);
53301854e69SLuming Yu 		if (ACPI_FAILURE(status)) {
53452af99c3SRafael J. Wysocki 			acpi_handle_warn(pr->handle, "Invalid _TSS data: %s\n",
53552af99c3SRafael J. Wysocki 					 acpi_format_exception(status));
53601854e69SLuming Yu 			result = -EFAULT;
53701854e69SLuming Yu 			kfree(pr->throttling.states_tss);
53801854e69SLuming Yu 			goto end;
53901854e69SLuming Yu 		}
54001854e69SLuming Yu 
54101854e69SLuming Yu 		if (!tx->freqpercentage) {
5424140054aSHanjun Guo 			pr_err("Invalid _TSS data: freq is zero\n");
54301854e69SLuming Yu 			result = -EFAULT;
54401854e69SLuming Yu 			kfree(pr->throttling.states_tss);
54501854e69SLuming Yu 			goto end;
54601854e69SLuming Yu 		}
54701854e69SLuming Yu 	}
54801854e69SLuming Yu 
54901854e69SLuming Yu end:
55001854e69SLuming Yu 	kfree(buffer.pointer);
55101854e69SLuming Yu 
55201854e69SLuming Yu 	return result;
55301854e69SLuming Yu }
554c30c620eSLen Brown 
555c30c620eSLen Brown /*
556c30c620eSLen Brown  * _TSD - T-State Dependencies
557c30c620eSLen Brown  */
acpi_processor_get_tsd(struct acpi_processor * pr)55801854e69SLuming Yu static int acpi_processor_get_tsd(struct acpi_processor *pr)
55901854e69SLuming Yu {
56001854e69SLuming Yu 	int result = 0;
56101854e69SLuming Yu 	acpi_status status = AE_OK;
56201854e69SLuming Yu 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
56301854e69SLuming Yu 	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
56401854e69SLuming Yu 	struct acpi_buffer state = { 0, NULL };
56501854e69SLuming Yu 	union acpi_object *tsd = NULL;
56601854e69SLuming Yu 	struct acpi_tsd_package *pdomain;
5671180509fSZhao Yakui 	struct acpi_processor_throttling *pthrottling;
5681180509fSZhao Yakui 
5691180509fSZhao Yakui 	pthrottling = &pr->throttling;
5701180509fSZhao Yakui 	pthrottling->tsd_valid_flag = 0;
57101854e69SLuming Yu 
57201854e69SLuming Yu 	status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
57301854e69SLuming Yu 	if (ACPI_FAILURE(status)) {
57452af99c3SRafael J. Wysocki 		if (status != AE_NOT_FOUND)
5754c324548SRafael J. Wysocki 			acpi_evaluation_failure_warn(pr->handle, "_TSD", status);
57652af99c3SRafael J. Wysocki 
57701854e69SLuming Yu 		return -ENODEV;
57801854e69SLuming Yu 	}
57901854e69SLuming Yu 
58001854e69SLuming Yu 	tsd = buffer.pointer;
58101854e69SLuming Yu 	if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
5824140054aSHanjun Guo 		pr_err("Invalid _TSD data\n");
58301854e69SLuming Yu 		result = -EFAULT;
58401854e69SLuming Yu 		goto end;
58501854e69SLuming Yu 	}
58601854e69SLuming Yu 
58701854e69SLuming Yu 	if (tsd->package.count != 1) {
5884140054aSHanjun Guo 		pr_err("Invalid _TSD data\n");
58901854e69SLuming Yu 		result = -EFAULT;
59001854e69SLuming Yu 		goto end;
59101854e69SLuming Yu 	}
59201854e69SLuming Yu 
59301854e69SLuming Yu 	pdomain = &(pr->throttling.domain_info);
59401854e69SLuming Yu 
59501854e69SLuming Yu 	state.length = sizeof(struct acpi_tsd_package);
59601854e69SLuming Yu 	state.pointer = pdomain;
59701854e69SLuming Yu 
59801854e69SLuming Yu 	status = acpi_extract_package(&(tsd->package.elements[0]),
59901854e69SLuming Yu 				      &format, &state);
60001854e69SLuming Yu 	if (ACPI_FAILURE(status)) {
6014140054aSHanjun Guo 		pr_err("Invalid _TSD data\n");
60201854e69SLuming Yu 		result = -EFAULT;
60301854e69SLuming Yu 		goto end;
60401854e69SLuming Yu 	}
60501854e69SLuming Yu 
60601854e69SLuming Yu 	if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
6074140054aSHanjun Guo 		pr_err("Unknown _TSD:num_entries\n");
60801854e69SLuming Yu 		result = -EFAULT;
60901854e69SLuming Yu 		goto end;
61001854e69SLuming Yu 	}
61101854e69SLuming Yu 
61201854e69SLuming Yu 	if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
6134140054aSHanjun Guo 		pr_err("Unknown _TSD:revision\n");
61401854e69SLuming Yu 		result = -EFAULT;
61501854e69SLuming Yu 		goto end;
61601854e69SLuming Yu 	}
61701854e69SLuming Yu 
6181180509fSZhao Yakui 	pthrottling = &pr->throttling;
6191180509fSZhao Yakui 	pthrottling->tsd_valid_flag = 1;
6201180509fSZhao Yakui 	pthrottling->shared_type = pdomain->coord_type;
6212fdf66b4SRusty Russell 	cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map);
6221180509fSZhao Yakui 	/*
6231180509fSZhao Yakui 	 * If the coordination type is not defined in ACPI spec,
6241180509fSZhao Yakui 	 * the tsd_valid_flag will be clear and coordination type
6251180509fSZhao Yakui 	 * will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
6261180509fSZhao Yakui 	 */
6271180509fSZhao Yakui 	if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
6281180509fSZhao Yakui 		pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
6291180509fSZhao Yakui 		pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
6301180509fSZhao Yakui 		pthrottling->tsd_valid_flag = 0;
6311180509fSZhao Yakui 		pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
6321180509fSZhao Yakui 	}
6331180509fSZhao Yakui 
63401854e69SLuming Yu end:
63501854e69SLuming Yu 	kfree(buffer.pointer);
63601854e69SLuming Yu 	return result;
63701854e69SLuming Yu }
63801854e69SLuming Yu 
6391da177e4SLinus Torvalds /* --------------------------------------------------------------------------
6401da177e4SLinus Torvalds                               Throttling Control
6411da177e4SLinus Torvalds    -------------------------------------------------------------------------- */
acpi_processor_get_throttling_fadt(struct acpi_processor * pr)64201854e69SLuming Yu static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds 	int state = 0;
6451da177e4SLinus Torvalds 	u32 value = 0;
6461da177e4SLinus Torvalds 	u32 duty_mask = 0;
6471da177e4SLinus Torvalds 	u32 duty_value = 0;
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 	if (!pr)
650d550d98dSPatrick Mochel 		return -EINVAL;
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 	if (!pr->flags.throttling)
653d550d98dSPatrick Mochel 		return -ENODEV;
6541da177e4SLinus Torvalds 
65586314751SRafael J. Wysocki 	/*
65686314751SRafael J. Wysocki 	 * We don't care about error returns - we just try to mark
65786314751SRafael J. Wysocki 	 * these reserved so that nobody else is confused into thinking
65886314751SRafael J. Wysocki 	 * that this region might be unused..
65986314751SRafael J. Wysocki 	 *
66086314751SRafael J. Wysocki 	 * (In particular, allocating the IO range for Cardbus)
66186314751SRafael J. Wysocki 	 */
66286314751SRafael J. Wysocki 	request_region(pr->throttling.address, 6, "ACPI CPU throttle");
66386314751SRafael J. Wysocki 
6641da177e4SLinus Torvalds 	pr->throttling.state = 0;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	duty_mask = pr->throttling.state_count - 1;
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds 	duty_mask <<= pr->throttling.duty_offset;
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	local_irq_disable();
6711da177e4SLinus Torvalds 
6721da177e4SLinus Torvalds 	value = inl(pr->throttling.address);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	/*
6751da177e4SLinus Torvalds 	 * Compute the current throttling state when throttling is enabled
6761da177e4SLinus Torvalds 	 * (bit 4 is on).
6771da177e4SLinus Torvalds 	 */
6781da177e4SLinus Torvalds 	if (value & 0x10) {
6791da177e4SLinus Torvalds 		duty_value = value & duty_mask;
6801da177e4SLinus Torvalds 		duty_value >>= pr->throttling.duty_offset;
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 		if (duty_value)
6831da177e4SLinus Torvalds 			state = pr->throttling.state_count - duty_value;
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	pr->throttling.state = state;
6871da177e4SLinus Torvalds 
6881da177e4SLinus Torvalds 	local_irq_enable();
6891da177e4SLinus Torvalds 
69052af99c3SRafael J. Wysocki 	acpi_handle_debug(pr->handle,
6911da177e4SLinus Torvalds 			  "Throttling state is T%d (%d%% throttling applied)\n",
69252af99c3SRafael J. Wysocki 			  state, pr->throttling.states[state].performance);
6931da177e4SLinus Torvalds 
694d550d98dSPatrick Mochel 	return 0;
6951da177e4SLinus Torvalds }
6961da177e4SLinus Torvalds 
697f79f06abSZhao Yakui #ifdef CONFIG_X86
acpi_throttling_rdmsr(u64 * value)6989d42a53eSChristoph Lameter static int acpi_throttling_rdmsr(u64 *value)
699f79f06abSZhao Yakui {
700f79f06abSZhao Yakui 	u64 msr_high, msr_low;
701f79f06abSZhao Yakui 	u64 msr = 0;
702f79f06abSZhao Yakui 	int ret = -1;
703f79f06abSZhao Yakui 
7049d42a53eSChristoph Lameter 	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
7059d42a53eSChristoph Lameter 		!this_cpu_has(X86_FEATURE_ACPI)) {
7064140054aSHanjun Guo 		pr_err("HARDWARE addr space,NOT supported yet\n");
707f79f06abSZhao Yakui 	} else {
708f79f06abSZhao Yakui 		msr_low = 0;
709f79f06abSZhao Yakui 		msr_high = 0;
710357dc4c3SZhao Yakui 		rdmsr_safe(MSR_IA32_THERM_CONTROL,
711f79f06abSZhao Yakui 			(u32 *)&msr_low, (u32 *) &msr_high);
712f79f06abSZhao Yakui 		msr = (msr_high << 32) | msr_low;
713439913ffSLin Ming 		*value = (u64) msr;
714f79f06abSZhao Yakui 		ret = 0;
715f79f06abSZhao Yakui 	}
716f79f06abSZhao Yakui 	return ret;
717f79f06abSZhao Yakui }
718f79f06abSZhao Yakui 
acpi_throttling_wrmsr(u64 value)7199d42a53eSChristoph Lameter static int acpi_throttling_wrmsr(u64 value)
720f79f06abSZhao Yakui {
721f79f06abSZhao Yakui 	int ret = -1;
722f79f06abSZhao Yakui 	u64 msr;
723f79f06abSZhao Yakui 
7249d42a53eSChristoph Lameter 	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
7259d42a53eSChristoph Lameter 		!this_cpu_has(X86_FEATURE_ACPI)) {
7264140054aSHanjun Guo 		pr_err("HARDWARE addr space,NOT supported yet\n");
727f79f06abSZhao Yakui 	} else {
728f79f06abSZhao Yakui 		msr = value;
729357dc4c3SZhao Yakui 		wrmsr_safe(MSR_IA32_THERM_CONTROL,
730f79f06abSZhao Yakui 			msr & 0xffffffff, msr >> 32);
731f79f06abSZhao Yakui 		ret = 0;
732f79f06abSZhao Yakui 	}
733f79f06abSZhao Yakui 	return ret;
734f79f06abSZhao Yakui }
735f79f06abSZhao Yakui #else
acpi_throttling_rdmsr(u64 * value)7369d42a53eSChristoph Lameter static int acpi_throttling_rdmsr(u64 *value)
737f79f06abSZhao Yakui {
7384140054aSHanjun Guo 	pr_err("HARDWARE addr space,NOT supported yet\n");
739f79f06abSZhao Yakui 	return -1;
740f79f06abSZhao Yakui }
741f79f06abSZhao Yakui 
acpi_throttling_wrmsr(u64 value)7429d42a53eSChristoph Lameter static int acpi_throttling_wrmsr(u64 value)
743f79f06abSZhao Yakui {
7444140054aSHanjun Guo 	pr_err("HARDWARE addr space,NOT supported yet\n");
745f79f06abSZhao Yakui 	return -1;
746f79f06abSZhao Yakui }
747f79f06abSZhao Yakui #endif
748f79f06abSZhao Yakui 
acpi_read_throttling_status(struct acpi_processor * pr,u64 * value)7490753f6e0SZhao Yakui static int acpi_read_throttling_status(struct acpi_processor *pr,
750439913ffSLin Ming 					u64 *value)
75101854e69SLuming Yu {
7529bcb2721SZhao Yakui 	u32 bit_width, bit_offset;
753344e222eSDan Carpenter 	u32 ptc_value;
7549bcb2721SZhao Yakui 	u64 ptc_mask;
7550753f6e0SZhao Yakui 	struct acpi_processor_throttling *throttling;
7560753f6e0SZhao Yakui 	int ret = -1;
7570753f6e0SZhao Yakui 
7580753f6e0SZhao Yakui 	throttling = &pr->throttling;
75901854e69SLuming Yu 	switch (throttling->status_register.space_id) {
76001854e69SLuming Yu 	case ACPI_ADR_SPACE_SYSTEM_IO:
7619bcb2721SZhao Yakui 		bit_width = throttling->status_register.bit_width;
7629bcb2721SZhao Yakui 		bit_offset = throttling->status_register.bit_offset;
7639bcb2721SZhao Yakui 
764ff55a9ceSLen Brown 		acpi_os_read_port((acpi_io_address) throttling->status_register.
765344e222eSDan Carpenter 				  address, &ptc_value,
7669bcb2721SZhao Yakui 				  (u32) (bit_width + bit_offset));
7679bcb2721SZhao Yakui 		ptc_mask = (1 << bit_width) - 1;
768439913ffSLin Ming 		*value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
7690753f6e0SZhao Yakui 		ret = 0;
77001854e69SLuming Yu 		break;
77101854e69SLuming Yu 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
7729d42a53eSChristoph Lameter 		ret = acpi_throttling_rdmsr(value);
77301854e69SLuming Yu 		break;
77401854e69SLuming Yu 	default:
7754140054aSHanjun Guo 		pr_err("Unknown addr space %d\n",
77601854e69SLuming Yu 		       (u32) (throttling->status_register.space_id));
77701854e69SLuming Yu 	}
7780753f6e0SZhao Yakui 	return ret;
77901854e69SLuming Yu }
78001854e69SLuming Yu 
acpi_write_throttling_state(struct acpi_processor * pr,u64 value)7810753f6e0SZhao Yakui static int acpi_write_throttling_state(struct acpi_processor *pr,
782439913ffSLin Ming 				u64 value)
78301854e69SLuming Yu {
7849bcb2721SZhao Yakui 	u32 bit_width, bit_offset;
7850753f6e0SZhao Yakui 	u64 ptc_value;
7869bcb2721SZhao Yakui 	u64 ptc_mask;
7870753f6e0SZhao Yakui 	struct acpi_processor_throttling *throttling;
78801854e69SLuming Yu 	int ret = -1;
78901854e69SLuming Yu 
7900753f6e0SZhao Yakui 	throttling = &pr->throttling;
79101854e69SLuming Yu 	switch (throttling->control_register.space_id) {
79201854e69SLuming Yu 	case ACPI_ADR_SPACE_SYSTEM_IO:
7939bcb2721SZhao Yakui 		bit_width = throttling->control_register.bit_width;
7949bcb2721SZhao Yakui 		bit_offset = throttling->control_register.bit_offset;
7959bcb2721SZhao Yakui 		ptc_mask = (1 << bit_width) - 1;
7969bcb2721SZhao Yakui 		ptc_value = value & ptc_mask;
7979bcb2721SZhao Yakui 
798ff55a9ceSLen Brown 		acpi_os_write_port((acpi_io_address) throttling->
7999bcb2721SZhao Yakui 					control_register.address,
8009bcb2721SZhao Yakui 					(u32) (ptc_value << bit_offset),
8019bcb2721SZhao Yakui 					(u32) (bit_width + bit_offset));
80201854e69SLuming Yu 		ret = 0;
80301854e69SLuming Yu 		break;
80401854e69SLuming Yu 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
8059d42a53eSChristoph Lameter 		ret = acpi_throttling_wrmsr(value);
80601854e69SLuming Yu 		break;
80701854e69SLuming Yu 	default:
8084140054aSHanjun Guo 		pr_err("Unknown addr space %d\n",
80901854e69SLuming Yu 		       (u32) (throttling->control_register.space_id));
81001854e69SLuming Yu 	}
81101854e69SLuming Yu 	return ret;
81201854e69SLuming Yu }
81301854e69SLuming Yu 
acpi_get_throttling_state(struct acpi_processor * pr,u64 value)8140753f6e0SZhao Yakui static int acpi_get_throttling_state(struct acpi_processor *pr,
815439913ffSLin Ming 				u64 value)
81601854e69SLuming Yu {
81701854e69SLuming Yu 	int i;
81801854e69SLuming Yu 
81901854e69SLuming Yu 	for (i = 0; i < pr->throttling.state_count; i++) {
820ff55a9ceSLen Brown 		struct acpi_processor_tx_tss *tx =
821ff55a9ceSLen Brown 		    (struct acpi_processor_tx_tss *)&(pr->throttling.
822ff55a9ceSLen Brown 						      states_tss[i]);
82301854e69SLuming Yu 		if (tx->control == value)
82401854e69SLuming Yu 			return i;
82501854e69SLuming Yu 	}
82653af9cfbSLen Brown 	return -1;
82753af9cfbSLen Brown }
82801854e69SLuming Yu 
acpi_get_throttling_value(struct acpi_processor * pr,int state,u64 * value)8290753f6e0SZhao Yakui static int acpi_get_throttling_value(struct acpi_processor *pr,
830439913ffSLin Ming 			int state, u64 *value)
83101854e69SLuming Yu {
8320753f6e0SZhao Yakui 	int ret = -1;
8330753f6e0SZhao Yakui 
83401854e69SLuming Yu 	if (state >= 0 && state <= pr->throttling.state_count) {
835ff55a9ceSLen Brown 		struct acpi_processor_tx_tss *tx =
836ff55a9ceSLen Brown 		    (struct acpi_processor_tx_tss *)&(pr->throttling.
837ff55a9ceSLen Brown 						      states_tss[state]);
8380753f6e0SZhao Yakui 		*value = tx->control;
8390753f6e0SZhao Yakui 		ret = 0;
84001854e69SLuming Yu 	}
8410753f6e0SZhao Yakui 	return ret;
84201854e69SLuming Yu }
84301854e69SLuming Yu 
acpi_processor_get_throttling_ptc(struct acpi_processor * pr)84401854e69SLuming Yu static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
84501854e69SLuming Yu {
84601854e69SLuming Yu 	int state = 0;
8470753f6e0SZhao Yakui 	int ret;
848439913ffSLin Ming 	u64 value;
84901854e69SLuming Yu 
85001854e69SLuming Yu 	if (!pr)
85101854e69SLuming Yu 		return -EINVAL;
85201854e69SLuming Yu 
85301854e69SLuming Yu 	if (!pr->flags.throttling)
85401854e69SLuming Yu 		return -ENODEV;
85501854e69SLuming Yu 
85601854e69SLuming Yu 	pr->throttling.state = 0;
857357dc4c3SZhao Yakui 
8580753f6e0SZhao Yakui 	value = 0;
8590753f6e0SZhao Yakui 	ret = acpi_read_throttling_status(pr, &value);
8600753f6e0SZhao Yakui 	if (ret >= 0) {
86101854e69SLuming Yu 		state = acpi_get_throttling_state(pr, value);
8624973b22aSZhang Rui 		if (state == -1) {
86352af99c3SRafael J. Wysocki 			acpi_handle_debug(pr->handle,
86452af99c3SRafael J. Wysocki 					  "Invalid throttling state, reset\n");
8654973b22aSZhang Rui 			state = 0;
8668153f9acSThomas Gleixner 			ret = __acpi_processor_set_throttling(pr, state, true,
8678153f9acSThomas Gleixner 							      true);
8684973b22aSZhang Rui 			if (ret)
8694973b22aSZhang Rui 				return ret;
8704973b22aSZhang Rui 		}
87101854e69SLuming Yu 		pr->throttling.state = state;
87201854e69SLuming Yu 	}
87301854e69SLuming Yu 
87401854e69SLuming Yu 	return 0;
87501854e69SLuming Yu }
87601854e69SLuming Yu 
__acpi_processor_get_throttling(void * data)8778153f9acSThomas Gleixner static long __acpi_processor_get_throttling(void *data)
8788153f9acSThomas Gleixner {
8798153f9acSThomas Gleixner 	struct acpi_processor *pr = data;
8808153f9acSThomas Gleixner 
8818153f9acSThomas Gleixner 	return pr->throttling.acpi_processor_get_throttling(pr);
8828153f9acSThomas Gleixner }
8838153f9acSThomas Gleixner 
acpi_processor_get_throttling(struct acpi_processor * pr)88401854e69SLuming Yu static int acpi_processor_get_throttling(struct acpi_processor *pr)
88501854e69SLuming Yu {
88687654273SZhao Yakui 	if (!pr)
88787654273SZhao Yakui 		return -EINVAL;
88887654273SZhao Yakui 
88987654273SZhao Yakui 	if (!pr->flags.throttling)
89087654273SZhao Yakui 		return -ENODEV;
8912fdf66b4SRusty Russell 
892357dc4c3SZhao Yakui 	/*
8938153f9acSThomas Gleixner 	 * This is either called from the CPU hotplug callback of
8948153f9acSThomas Gleixner 	 * processor_driver or via the ACPI probe function. In the latter
8958153f9acSThomas Gleixner 	 * case the CPU is not guaranteed to be online. Both call sites are
8968153f9acSThomas Gleixner 	 * protected against CPU hotplug.
897357dc4c3SZhao Yakui 	 */
8988153f9acSThomas Gleixner 	if (!cpu_online(pr->id))
899daef1f35SZhao Yakui 		return -ENODEV;
900357dc4c3SZhao Yakui 
9010266d81eSThomas Gleixner 	return call_on_cpu(pr->id, __acpi_processor_get_throttling, pr, false);
90201854e69SLuming Yu }
90301854e69SLuming Yu 
acpi_processor_get_fadt_info(struct acpi_processor * pr)90422cc5019SZhao Yakui static int acpi_processor_get_fadt_info(struct acpi_processor *pr)
90522cc5019SZhao Yakui {
90622cc5019SZhao Yakui 	int i, step;
90722cc5019SZhao Yakui 
90822cc5019SZhao Yakui 	if (!pr->throttling.address) {
90952af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle, "No throttling register\n");
91022cc5019SZhao Yakui 		return -EINVAL;
91122cc5019SZhao Yakui 	} else if (!pr->throttling.duty_width) {
91252af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle, "No throttling states\n");
91322cc5019SZhao Yakui 		return -EINVAL;
91422cc5019SZhao Yakui 	}
91522cc5019SZhao Yakui 	/* TBD: Support duty_cycle values that span bit 4. */
91622cc5019SZhao Yakui 	else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
9174140054aSHanjun Guo 		pr_warn("duty_cycle spans bit 4\n");
91822cc5019SZhao Yakui 		return -EINVAL;
91922cc5019SZhao Yakui 	}
92022cc5019SZhao Yakui 
92122cc5019SZhao Yakui 	pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
92222cc5019SZhao Yakui 
92322cc5019SZhao Yakui 	/*
92422cc5019SZhao Yakui 	 * Compute state values. Note that throttling displays a linear power
92522cc5019SZhao Yakui 	 * performance relationship (at 50% performance the CPU will consume
92622cc5019SZhao Yakui 	 * 50% power).  Values are in 1/10th of a percent to preserve accuracy.
92722cc5019SZhao Yakui 	 */
92822cc5019SZhao Yakui 
92922cc5019SZhao Yakui 	step = (1000 / pr->throttling.state_count);
93022cc5019SZhao Yakui 
93122cc5019SZhao Yakui 	for (i = 0; i < pr->throttling.state_count; i++) {
93222cc5019SZhao Yakui 		pr->throttling.states[i].performance = 1000 - step * i;
93322cc5019SZhao Yakui 		pr->throttling.states[i].power = 1000 - step * i;
93422cc5019SZhao Yakui 	}
93522cc5019SZhao Yakui 	return 0;
93622cc5019SZhao Yakui }
93722cc5019SZhao Yakui 
acpi_processor_set_throttling_fadt(struct acpi_processor * pr,int state,bool force)9386c5cf8aaSAdrian Bunk static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
9392a908002SFrans Pop 					      int state, bool force)
9401da177e4SLinus Torvalds {
9411da177e4SLinus Torvalds 	u32 value = 0;
9421da177e4SLinus Torvalds 	u32 duty_mask = 0;
9431da177e4SLinus Torvalds 	u32 duty_value = 0;
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	if (!pr)
946d550d98dSPatrick Mochel 		return -EINVAL;
9471da177e4SLinus Torvalds 
9481da177e4SLinus Torvalds 	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
949d550d98dSPatrick Mochel 		return -EINVAL;
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	if (!pr->flags.throttling)
952d550d98dSPatrick Mochel 		return -ENODEV;
9531da177e4SLinus Torvalds 
9542a908002SFrans Pop 	if (!force && (state == pr->throttling.state))
955d550d98dSPatrick Mochel 		return 0;
9561da177e4SLinus Torvalds 
95701854e69SLuming Yu 	if (state < pr->throttling_platform_limit)
95801854e69SLuming Yu 		return -EPERM;
9591da177e4SLinus Torvalds 	/*
9601da177e4SLinus Torvalds 	 * Calculate the duty_value and duty_mask.
9611da177e4SLinus Torvalds 	 */
9621da177e4SLinus Torvalds 	if (state) {
9631da177e4SLinus Torvalds 		duty_value = pr->throttling.state_count - state;
9641da177e4SLinus Torvalds 
9651da177e4SLinus Torvalds 		duty_value <<= pr->throttling.duty_offset;
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds 		/* Used to clear all duty_value bits */
9681da177e4SLinus Torvalds 		duty_mask = pr->throttling.state_count - 1;
9691da177e4SLinus Torvalds 
970cee324b1SAlexey Starikovskiy 		duty_mask <<= acpi_gbl_FADT.duty_offset;
9711da177e4SLinus Torvalds 		duty_mask = ~duty_mask;
9721da177e4SLinus Torvalds 	}
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds 	local_irq_disable();
9751da177e4SLinus Torvalds 
9761da177e4SLinus Torvalds 	/*
9771da177e4SLinus Torvalds 	 * Disable throttling by writing a 0 to bit 4.  Note that we must
9781da177e4SLinus Torvalds 	 * turn it off before you can change the duty_value.
9791da177e4SLinus Torvalds 	 */
9801da177e4SLinus Torvalds 	value = inl(pr->throttling.address);
9811da177e4SLinus Torvalds 	if (value & 0x10) {
9821da177e4SLinus Torvalds 		value &= 0xFFFFFFEF;
9831da177e4SLinus Torvalds 		outl(value, pr->throttling.address);
9841da177e4SLinus Torvalds 	}
9851da177e4SLinus Torvalds 
9861da177e4SLinus Torvalds 	/*
9871da177e4SLinus Torvalds 	 * Write the new duty_value and then enable throttling.  Note
9881da177e4SLinus Torvalds 	 * that a state value of 0 leaves throttling disabled.
9891da177e4SLinus Torvalds 	 */
9901da177e4SLinus Torvalds 	if (state) {
9911da177e4SLinus Torvalds 		value &= duty_mask;
9921da177e4SLinus Torvalds 		value |= duty_value;
9931da177e4SLinus Torvalds 		outl(value, pr->throttling.address);
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 		value |= 0x00000010;
9961da177e4SLinus Torvalds 		outl(value, pr->throttling.address);
9971da177e4SLinus Torvalds 	}
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 	pr->throttling.state = state;
10001da177e4SLinus Torvalds 
10011da177e4SLinus Torvalds 	local_irq_enable();
10021da177e4SLinus Torvalds 
100352af99c3SRafael J. Wysocki 	acpi_handle_debug(pr->handle,
10041da177e4SLinus Torvalds 			  "Throttling state set to T%d (%d%%)\n", state,
10054be44fcdSLen Brown 			  (pr->throttling.states[state].performance ? pr->
100652af99c3SRafael J. Wysocki 			   throttling.states[state].performance / 10 : 0));
10071da177e4SLinus Torvalds 
1008d550d98dSPatrick Mochel 	return 0;
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds 
acpi_processor_set_throttling_ptc(struct acpi_processor * pr,int state,bool force)10116c5cf8aaSAdrian Bunk static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
10122a908002SFrans Pop 					     int state, bool force)
101301854e69SLuming Yu {
10140753f6e0SZhao Yakui 	int ret;
1015439913ffSLin Ming 	u64 value;
101601854e69SLuming Yu 
101701854e69SLuming Yu 	if (!pr)
101801854e69SLuming Yu 		return -EINVAL;
101901854e69SLuming Yu 
102001854e69SLuming Yu 	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
102101854e69SLuming Yu 		return -EINVAL;
102201854e69SLuming Yu 
102301854e69SLuming Yu 	if (!pr->flags.throttling)
102401854e69SLuming Yu 		return -ENODEV;
102501854e69SLuming Yu 
10262a908002SFrans Pop 	if (!force && (state == pr->throttling.state))
102701854e69SLuming Yu 		return 0;
102801854e69SLuming Yu 
102901854e69SLuming Yu 	if (state < pr->throttling_platform_limit)
103001854e69SLuming Yu 		return -EPERM;
103101854e69SLuming Yu 
10320753f6e0SZhao Yakui 	value = 0;
10330753f6e0SZhao Yakui 	ret = acpi_get_throttling_value(pr, state, &value);
10340753f6e0SZhao Yakui 	if (ret >= 0) {
10350753f6e0SZhao Yakui 		acpi_write_throttling_state(pr, value);
103601854e69SLuming Yu 		pr->throttling.state = state;
103701854e69SLuming Yu 	}
103801854e69SLuming Yu 
103901854e69SLuming Yu 	return 0;
104001854e69SLuming Yu }
104101854e69SLuming Yu 
acpi_processor_throttling_fn(void * data)1042f3ca4164SLan Tianyu static long acpi_processor_throttling_fn(void *data)
1043f3ca4164SLan Tianyu {
1044f3ca4164SLan Tianyu 	struct acpi_processor_throttling_arg *arg = data;
1045f3ca4164SLan Tianyu 	struct acpi_processor *pr = arg->pr;
1046f3ca4164SLan Tianyu 
1047f3ca4164SLan Tianyu 	return pr->throttling.acpi_processor_set_throttling(pr,
1048f3ca4164SLan Tianyu 			arg->target_state, arg->force);
1049f3ca4164SLan Tianyu }
1050f3ca4164SLan Tianyu 
__acpi_processor_set_throttling(struct acpi_processor * pr,int state,bool force,bool direct)10518153f9acSThomas Gleixner static int __acpi_processor_set_throttling(struct acpi_processor *pr,
10528153f9acSThomas Gleixner 					   int state, bool force, bool direct)
105301854e69SLuming Yu {
10543391a76fSLen Brown 	int ret = 0;
105533a2a529SZhao Yakui 	unsigned int i;
105633a2a529SZhao Yakui 	struct acpi_processor *match_pr;
105733a2a529SZhao Yakui 	struct acpi_processor_throttling *p_throttling;
1058f3ca4164SLan Tianyu 	struct acpi_processor_throttling_arg arg;
105933a2a529SZhao Yakui 	struct throttling_tstate t_state;
106087654273SZhao Yakui 
106187654273SZhao Yakui 	if (!pr)
106287654273SZhao Yakui 		return -EINVAL;
106387654273SZhao Yakui 
106487654273SZhao Yakui 	if (!pr->flags.throttling)
106587654273SZhao Yakui 		return -ENODEV;
106687654273SZhao Yakui 
106787654273SZhao Yakui 	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
106887654273SZhao Yakui 		return -EINVAL;
106987654273SZhao Yakui 
1070daef1f35SZhao Yakui 	if (cpu_is_offline(pr->id)) {
1071daef1f35SZhao Yakui 		/*
1072daef1f35SZhao Yakui 		 * the cpu pointed by pr->id is offline. Unnecessary to change
1073daef1f35SZhao Yakui 		 * the throttling state any more.
1074daef1f35SZhao Yakui 		 */
1075daef1f35SZhao Yakui 		return -ENODEV;
1076daef1f35SZhao Yakui 	}
1077daef1f35SZhao Yakui 
107833a2a529SZhao Yakui 	t_state.target_state = state;
107933a2a529SZhao Yakui 	p_throttling = &(pr->throttling);
1080f3ca4164SLan Tianyu 
108133a2a529SZhao Yakui 	/*
108233a2a529SZhao Yakui 	 * The throttling notifier will be called for every
108333a2a529SZhao Yakui 	 * affected cpu in order to get one proper T-state.
108433a2a529SZhao Yakui 	 * The notifier event is THROTTLING_PRECHANGE.
108533a2a529SZhao Yakui 	 */
1086f3ca4164SLan Tianyu 	for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
108733a2a529SZhao Yakui 		t_state.cpu = i;
108833a2a529SZhao Yakui 		acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
108933a2a529SZhao Yakui 							&t_state);
109033a2a529SZhao Yakui 	}
109133a2a529SZhao Yakui 	/*
109233a2a529SZhao Yakui 	 * The function of acpi_processor_set_throttling will be called
109333a2a529SZhao Yakui 	 * to switch T-state. If the coordination type is SW_ALL or HW_ALL,
109433a2a529SZhao Yakui 	 * it is necessary to call it for every affected cpu. Otherwise
109533a2a529SZhao Yakui 	 * it can be called only for the cpu pointed by pr.
109633a2a529SZhao Yakui 	 */
109733a2a529SZhao Yakui 	if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
1098f3ca4164SLan Tianyu 		arg.pr = pr;
1099f3ca4164SLan Tianyu 		arg.target_state = state;
1100f3ca4164SLan Tianyu 		arg.force = force;
11018153f9acSThomas Gleixner 		ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg,
11028153f9acSThomas Gleixner 				  direct);
110333a2a529SZhao Yakui 	} else {
110433a2a529SZhao Yakui 		/*
110533a2a529SZhao Yakui 		 * When the T-state coordination is SW_ALL or HW_ALL,
110633a2a529SZhao Yakui 		 * it is necessary to set T-state for every affected
110733a2a529SZhao Yakui 		 * cpus.
110833a2a529SZhao Yakui 		 */
1109f3ca4164SLan Tianyu 		for_each_cpu_and(i, cpu_online_mask,
1110f3ca4164SLan Tianyu 		    p_throttling->shared_cpu_map) {
1111706546d0SMike Travis 			match_pr = per_cpu(processors, i);
111233a2a529SZhao Yakui 			/*
111333a2a529SZhao Yakui 			 * If the pointer is invalid, we will report the
111433a2a529SZhao Yakui 			 * error message and continue.
111533a2a529SZhao Yakui 			 */
111633a2a529SZhao Yakui 			if (!match_pr) {
111752af99c3SRafael J. Wysocki 				acpi_handle_debug(pr->handle,
111852af99c3SRafael J. Wysocki 					"Invalid Pointer for CPU %d\n", i);
111933a2a529SZhao Yakui 				continue;
112033a2a529SZhao Yakui 			}
112133a2a529SZhao Yakui 			/*
112233a2a529SZhao Yakui 			 * If the throttling control is unsupported on CPU i,
112333a2a529SZhao Yakui 			 * we will report the error message and continue.
112433a2a529SZhao Yakui 			 */
112533a2a529SZhao Yakui 			if (!match_pr->flags.throttling) {
112652af99c3SRafael J. Wysocki 				acpi_handle_debug(pr->handle,
112752af99c3SRafael J. Wysocki 					"Throttling Control unsupported on CPU %d\n", i);
112833a2a529SZhao Yakui 				continue;
112933a2a529SZhao Yakui 			}
1130f3ca4164SLan Tianyu 
1131f3ca4164SLan Tianyu 			arg.pr = match_pr;
1132f3ca4164SLan Tianyu 			arg.target_state = state;
1133f3ca4164SLan Tianyu 			arg.force = force;
11348153f9acSThomas Gleixner 			ret = call_on_cpu(pr->id, acpi_processor_throttling_fn,
11358153f9acSThomas Gleixner 					  &arg, direct);
113633a2a529SZhao Yakui 		}
113733a2a529SZhao Yakui 	}
113833a2a529SZhao Yakui 	/*
113933a2a529SZhao Yakui 	 * After the set_throttling is called, the
114033a2a529SZhao Yakui 	 * throttling notifier is called for every
114133a2a529SZhao Yakui 	 * affected cpu to update the T-states.
114233a2a529SZhao Yakui 	 * The notifier event is THROTTLING_POSTCHANGE
114333a2a529SZhao Yakui 	 */
1144f3ca4164SLan Tianyu 	for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
114533a2a529SZhao Yakui 		t_state.cpu = i;
114633a2a529SZhao Yakui 		acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
114733a2a529SZhao Yakui 							&t_state);
114833a2a529SZhao Yakui 	}
1149f3ca4164SLan Tianyu 
1150357dc4c3SZhao Yakui 	return ret;
115101854e69SLuming Yu }
115201854e69SLuming Yu 
acpi_processor_set_throttling(struct acpi_processor * pr,int state,bool force)11538153f9acSThomas Gleixner int acpi_processor_set_throttling(struct acpi_processor *pr, int state,
11548153f9acSThomas Gleixner 				  bool force)
11558153f9acSThomas Gleixner {
11568153f9acSThomas Gleixner 	return __acpi_processor_set_throttling(pr, state, force, false);
11578153f9acSThomas Gleixner }
11588153f9acSThomas Gleixner 
acpi_processor_get_throttling_info(struct acpi_processor * pr)11594be44fcdSLen Brown int acpi_processor_get_throttling_info(struct acpi_processor *pr)
11601da177e4SLinus Torvalds {
11611da177e4SLinus Torvalds 	int result = 0;
11621180509fSZhao Yakui 	struct acpi_processor_throttling *pthrottling;
11631da177e4SLinus Torvalds 
116452af99c3SRafael J. Wysocki 	acpi_handle_debug(pr->handle,
11651da177e4SLinus Torvalds 			  "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
11661da177e4SLinus Torvalds 			  pr->throttling.address,
11671da177e4SLinus Torvalds 			  pr->throttling.duty_offset,
116852af99c3SRafael J. Wysocki 			  pr->throttling.duty_width);
11691da177e4SLinus Torvalds 
1170c30c620eSLen Brown 	/*
1171c30c620eSLen Brown 	 * Evaluate _PTC, _TSS and _TPC
1172c30c620eSLen Brown 	 * They must all be present or none of them can be used.
1173c30c620eSLen Brown 	 */
1174c30c620eSLen Brown 	if (acpi_processor_get_throttling_control(pr) ||
1175c30c620eSLen Brown 		acpi_processor_get_throttling_states(pr) ||
11762ef53bf7SClayton Casciato 		acpi_processor_get_platform_limit(pr)) {
1177ff55a9ceSLen Brown 		pr->throttling.acpi_processor_get_throttling =
1178ff55a9ceSLen Brown 		    &acpi_processor_get_throttling_fadt;
1179ff55a9ceSLen Brown 		pr->throttling.acpi_processor_set_throttling =
1180ff55a9ceSLen Brown 		    &acpi_processor_set_throttling_fadt;
1181d1154be3SAlexey Starikovskiy 		if (acpi_processor_get_fadt_info(pr))
1182d1154be3SAlexey Starikovskiy 			return 0;
118301854e69SLuming Yu 	} else {
1184ff55a9ceSLen Brown 		pr->throttling.acpi_processor_get_throttling =
1185ff55a9ceSLen Brown 		    &acpi_processor_get_throttling_ptc;
1186ff55a9ceSLen Brown 		pr->throttling.acpi_processor_set_throttling =
1187ff55a9ceSLen Brown 		    &acpi_processor_set_throttling_ptc;
118801854e69SLuming Yu 	}
11891da177e4SLinus Torvalds 
11901180509fSZhao Yakui 	/*
11911180509fSZhao Yakui 	 * If TSD package for one CPU can't be parsed successfully, it means
11921180509fSZhao Yakui 	 * that this CPU will have no coordination with other CPUs.
11931180509fSZhao Yakui 	 */
11941180509fSZhao Yakui 	if (acpi_processor_get_tsd(pr)) {
11951180509fSZhao Yakui 		pthrottling = &pr->throttling;
11961180509fSZhao Yakui 		pthrottling->tsd_valid_flag = 0;
11972fdf66b4SRusty Russell 		cpumask_set_cpu(pr->id, pthrottling->shared_cpu_map);
11981180509fSZhao Yakui 		pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
11991180509fSZhao Yakui 	}
1200c30c620eSLen Brown 
12011da177e4SLinus Torvalds 	/*
12021da177e4SLinus Torvalds 	 * PIIX4 Errata: We don't support throttling on the original PIIX4.
12031da177e4SLinus Torvalds 	 * This shouldn't be an issue as few (if any) mobile systems ever
12041da177e4SLinus Torvalds 	 * used this part.
12051da177e4SLinus Torvalds 	 */
12061da177e4SLinus Torvalds 	if (errata.piix4.throttle) {
120752af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle,
120852af99c3SRafael J. Wysocki 				  "Throttling not supported on PIIX4 A- or B-step\n");
1209d550d98dSPatrick Mochel 		return 0;
12101da177e4SLinus Torvalds 	}
12111da177e4SLinus Torvalds 
121252af99c3SRafael J. Wysocki 	acpi_handle_debug(pr->handle, "Found %d throttling states\n",
121352af99c3SRafael J. Wysocki 			  pr->throttling.state_count);
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds 	pr->flags.throttling = 1;
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 	/*
12181da177e4SLinus Torvalds 	 * Disable throttling (if enabled).  We'll let subsequent policy (e.g.
12191da177e4SLinus Torvalds 	 * thermal) decide to lower performance if it so chooses, but for now
12201da177e4SLinus Torvalds 	 * we'll crank up the speed.
12211da177e4SLinus Torvalds 	 */
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds 	result = acpi_processor_get_throttling(pr);
12241da177e4SLinus Torvalds 	if (result)
12251da177e4SLinus Torvalds 		goto end;
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	if (pr->throttling.state) {
122852af99c3SRafael J. Wysocki 		acpi_handle_debug(pr->handle,
12294be44fcdSLen Brown 				  "Disabling throttling (was T%d)\n",
123052af99c3SRafael J. Wysocki 				  pr->throttling.state);
12312a908002SFrans Pop 		result = acpi_processor_set_throttling(pr, 0, false);
12321da177e4SLinus Torvalds 		if (result)
12331da177e4SLinus Torvalds 			goto end;
12341da177e4SLinus Torvalds 	}
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds end:
12371da177e4SLinus Torvalds 	if (result)
12381da177e4SLinus Torvalds 		pr->flags.throttling = 0;
12391da177e4SLinus Torvalds 
1240d550d98dSPatrick Mochel 	return result;
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
1243