#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
+#define PREFIX "ACPI: "
+
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling");
+/* ignore_tpc:
+ * 0 -> acpi processor driver doesn't ignore _TPC values
+ * 1 -> acpi processor driver ignores _TPC values
+ */
+static int ignore_tpc;
+module_param(ignore_tpc, int, 0644);
+MODULE_PARM_DESC(ignore_tpc, "Disable broken BIOS _TPC throttling support");
+
struct throttling_tstate {
unsigned int cpu; /* cpu nr */
int target_state; /* target T-state */
#define THROTTLING_POSTCHANGE (2)
static int acpi_processor_get_throttling(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+int acpi_processor_set_throttling(struct acpi_processor *pr,
+ int state, bool force);
static int acpi_processor_update_tsd_coord(void)
{
struct acpi_tsd_package *pdomain, *match_pdomain;
struct acpi_processor_throttling *pthrottling, *match_pthrottling;
- if (!alloc_cpumask_var(&covered_cpus, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL))
return -ENOMEM;
/*
if (retval)
goto err_ret;
- cpumask_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = per_cpu(processors, i);
if (!pr)
if (!pr)
return -EINVAL;
+
+ if (ignore_tpc)
+ goto end;
+
status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
}
return -ENODEV;
}
+
+end:
pr->throttling_platform_limit = (int)tpc;
return 0;
}
struct acpi_processor_limit *limit;
int target_state;
+ if (ignore_tpc)
+ return 0;
+
result = acpi_processor_get_platform_limit(pr);
if (result) {
/* Throttling Limit is unsupported */
*/
target_state = throttling_limit;
}
- return acpi_processor_set_throttling(pr, target_state);
+ return acpi_processor_set_throttling(pr, target_state, false);
}
/*
#ifdef CONFIG_X86
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- acpi_integer * value)
+ u64 *value)
{
struct cpuinfo_x86 *c;
u64 msr_high, msr_low;
rdmsr_safe(MSR_IA32_THERM_CONTROL,
(u32 *)&msr_low , (u32 *) &msr_high);
msr = (msr_high << 32) | msr_low;
- *value = (acpi_integer) msr;
+ *value = (u64) msr;
ret = 0;
}
return ret;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
{
struct cpuinfo_x86 *c;
unsigned int cpu;
}
#else
static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- acpi_integer * value)
+ u64 *value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
return -1;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, acpi_integer value)
+static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
#endif
static int acpi_read_throttling_status(struct acpi_processor *pr,
- acpi_integer *value)
+ u64 *value)
{
u32 bit_width, bit_offset;
u64 ptc_value;
address, (u32 *) &ptc_value,
(u32) (bit_width + bit_offset));
ptc_mask = (1 << bit_width) - 1;
- *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask);
+ *value = (u64) ((ptc_value >> bit_offset) & ptc_mask);
ret = 0;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
}
static int acpi_write_throttling_state(struct acpi_processor *pr,
- acpi_integer value)
+ u64 value)
{
u32 bit_width, bit_offset;
u64 ptc_value;
}
static int acpi_get_throttling_state(struct acpi_processor *pr,
- acpi_integer value)
+ u64 value)
{
int i;
(struct acpi_processor_tx_tss *)&(pr->throttling.
states_tss[i]);
if (tx->control == value)
- break;
+ return i;
}
- if (i > pr->throttling.state_count)
- i = -1;
- return i;
+ return -1;
}
static int acpi_get_throttling_value(struct acpi_processor *pr,
- int state, acpi_integer *value)
+ int state, u64 *value)
{
int ret = -1;
{
int state = 0;
int ret;
- acpi_integer value;
+ u64 value;
if (!pr)
return -EINVAL;
ret = acpi_read_throttling_status(pr, &value);
if (ret >= 0) {
state = acpi_get_throttling_state(pr, value);
+ if (state == -1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Invalid throttling state, reset\n"));
+ state = 0;
+ ret = acpi_processor_set_throttling(pr, state, true);
+ if (ret)
+ return ret;
+ }
pr->throttling.state = state;
}
}
static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
- int state)
+ int state, bool force)
{
u32 value = 0;
u32 duty_mask = 0;
if (!pr->flags.throttling)
return -ENODEV;
- if (state == pr->throttling.state)
+ if (!force && (state == pr->throttling.state))
return 0;
if (state < pr->throttling_platform_limit)
}
static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
- int state)
+ int state, bool force)
{
int ret;
- acpi_integer value;
+ u64 value;
if (!pr)
return -EINVAL;
if (!pr->flags.throttling)
return -ENODEV;
- if (state == pr->throttling.state)
+ if (!force && (state == pr->throttling.state))
return 0;
if (state < pr->throttling_platform_limit)
return 0;
}
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+int acpi_processor_set_throttling(struct acpi_processor *pr,
+ int state, bool force)
{
cpumask_var_t saved_mask;
int ret = 0;
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr(current, cpumask_of(pr->id));
ret = p_throttling->acpi_processor_set_throttling(pr,
- t_state.target_state);
+ t_state.target_state, force);
} else {
/*
* When the T-state coordination is SW_ALL or HW_ALL,
set_cpus_allowed_ptr(current, cpumask_of(i));
ret = match_pr->throttling.
acpi_processor_set_throttling(
- match_pr, t_state.target_state);
+ match_pr, t_state.target_state, force);
}
}
/*
pr->throttling.duty_offset,
pr->throttling.duty_width));
- if (!pr)
- return -EINVAL;
-
/*
* Evaluate _PTC, _TSS and _TPC
* They must all be present or none of them can be used.
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Disabling throttling (was T%d)\n",
pr->throttling.state));
- result = acpi_processor_set_throttling(pr, 0);
+ result = acpi_processor_set_throttling(pr, 0, false);
if (result)
goto end;
}
}
/* proc interface */
-
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_processor_throttling_seq_show(struct seq_file *seq,
void *offset)
{
if (strcmp(tmpbuf, charp) != 0)
return -EINVAL;
- result = acpi_processor_set_throttling(pr, state_val);
+ result = acpi_processor_set_throttling(pr, state_val, false);
if (result)
return result;
return count;
}
-struct file_operations acpi_processor_throttling_fops = {
+const struct file_operations acpi_processor_throttling_fops = {
.owner = THIS_MODULE,
.open = acpi_processor_throttling_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
+#endif