diff options
| author | Zhao Yakui <yakui.zhao@intel.com> | 2007-11-15 04:05:05 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2007-11-16 21:43:21 -0500 |
| commit | 9bcb27217344c2c1389db3983a436e19484c2f50 (patch) | |
| tree | 14c28cade53f8f64755f3d660149c3c7d501fd1d | |
| parent | 0753f6e0a3d9568fb6b8e34753b944d9f8eed05b (diff) | |
ACPI: Use _TSS for throttling control, when present. Add error checks.
_TSS was erroneously ignored, in favor of the FADT.
When TSS is used, the access width is included in the PTC control/status
register. So it is unnecessary that the access bit width is multiplied by 8.
At the same time the bit_offset should be considered for system I/O Access.
It should be checked the bit_width and bit_offset of PTC regsiter in order to
avoid the failure of system I/O access. It means that bit_width plus
bit_offset can't be greater than 32.
Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Signed-off-by: Li Shaohua <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/processor_throttling.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 5c96ef18e94c..f4b5f7d5dbe6 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
| @@ -131,6 +131,7 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr) | |||
| 131 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 131 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 132 | union acpi_object *ptc = NULL; | 132 | union acpi_object *ptc = NULL; |
| 133 | union acpi_object obj = { 0 }; | 133 | union acpi_object obj = { 0 }; |
| 134 | struct acpi_processor_throttling *throttling; | ||
| 134 | 135 | ||
| 135 | status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); | 136 | status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); |
| 136 | if (ACPI_FAILURE(status)) { | 137 | if (ACPI_FAILURE(status)) { |
| @@ -182,6 +183,22 @@ static int acpi_processor_get_throttling_control(struct acpi_processor *pr) | |||
| 182 | memcpy(&pr->throttling.status_register, obj.buffer.pointer, | 183 | memcpy(&pr->throttling.status_register, obj.buffer.pointer, |
| 183 | sizeof(struct acpi_ptc_register)); | 184 | sizeof(struct acpi_ptc_register)); |
| 184 | 185 | ||
| 186 | throttling = &pr->throttling; | ||
| 187 | |||
| 188 | if ((throttling->control_register.bit_width + | ||
| 189 | throttling->control_register.bit_offset) > 32) { | ||
| 190 | printk(KERN_ERR PREFIX "Invalid _PTC control register\n"); | ||
| 191 | result = -EFAULT; | ||
| 192 | goto end; | ||
| 193 | } | ||
| 194 | |||
| 195 | if ((throttling->status_register.bit_width + | ||
| 196 | throttling->status_register.bit_offset) > 32) { | ||
| 197 | printk(KERN_ERR PREFIX "Invalid _PTC status register\n"); | ||
| 198 | result = -EFAULT; | ||
| 199 | goto end; | ||
| 200 | } | ||
| 201 | |||
| 185 | end: | 202 | end: |
| 186 | kfree(buffer.pointer); | 203 | kfree(buffer.pointer); |
| 187 | 204 | ||
| @@ -379,7 +396,9 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) | |||
| 379 | static int acpi_read_throttling_status(struct acpi_processor *pr, | 396 | static int acpi_read_throttling_status(struct acpi_processor *pr, |
| 380 | acpi_integer *value) | 397 | acpi_integer *value) |
| 381 | { | 398 | { |
| 399 | u32 bit_width, bit_offset; | ||
| 382 | u64 ptc_value; | 400 | u64 ptc_value; |
| 401 | u64 ptc_mask; | ||
| 383 | struct acpi_processor_throttling *throttling; | 402 | struct acpi_processor_throttling *throttling; |
| 384 | int ret = -1; | 403 | int ret = -1; |
| 385 | 404 | ||
| @@ -387,11 +406,14 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, | |||
| 387 | switch (throttling->status_register.space_id) { | 406 | switch (throttling->status_register.space_id) { |
| 388 | case ACPI_ADR_SPACE_SYSTEM_IO: | 407 | case ACPI_ADR_SPACE_SYSTEM_IO: |
| 389 | ptc_value = 0; | 408 | ptc_value = 0; |
| 409 | bit_width = throttling->status_register.bit_width; | ||
| 410 | bit_offset = throttling->status_register.bit_offset; | ||
| 411 | |||
| 390 | acpi_os_read_port((acpi_io_address) throttling->status_register. | 412 | acpi_os_read_port((acpi_io_address) throttling->status_register. |
| 391 | address, (u32 *) &ptc_value, | 413 | address, (u32 *) &ptc_value, |
| 392 | (u32) throttling->status_register.bit_width * | 414 | (u32) (bit_width + bit_offset)); |
| 393 | 8); | 415 | ptc_mask = (1 << bit_width) - 1; |
| 394 | *value = (acpi_integer) ptc_value; | 416 | *value = (acpi_integer) ((ptc_value >> bit_offset) & ptc_mask); |
| 395 | ret = 0; | 417 | ret = 0; |
| 396 | break; | 418 | break; |
| 397 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | 419 | case ACPI_ADR_SPACE_FIXED_HARDWARE: |
| @@ -408,18 +430,24 @@ static int acpi_read_throttling_status(struct acpi_processor *pr, | |||
| 408 | static int acpi_write_throttling_state(struct acpi_processor *pr, | 430 | static int acpi_write_throttling_state(struct acpi_processor *pr, |
| 409 | acpi_integer value) | 431 | acpi_integer value) |
| 410 | { | 432 | { |
| 433 | u32 bit_width, bit_offset; | ||
| 411 | u64 ptc_value; | 434 | u64 ptc_value; |
| 435 | u64 ptc_mask; | ||
| 412 | struct acpi_processor_throttling *throttling; | 436 | struct acpi_processor_throttling *throttling; |
| 413 | int ret = -1; | 437 | int ret = -1; |
| 414 | 438 | ||
| 415 | throttling = &pr->throttling; | 439 | throttling = &pr->throttling; |
| 416 | switch (throttling->control_register.space_id) { | 440 | switch (throttling->control_register.space_id) { |
| 417 | case ACPI_ADR_SPACE_SYSTEM_IO: | 441 | case ACPI_ADR_SPACE_SYSTEM_IO: |
| 418 | ptc_value = value; | 442 | bit_width = throttling->control_register.bit_width; |
| 443 | bit_offset = throttling->control_register.bit_offset; | ||
| 444 | ptc_mask = (1 << bit_width) - 1; | ||
| 445 | ptc_value = value & ptc_mask; | ||
| 446 | |||
| 419 | acpi_os_write_port((acpi_io_address) throttling-> | 447 | acpi_os_write_port((acpi_io_address) throttling-> |
| 420 | control_register.address, (u32) ptc_value, | 448 | control_register.address, |
| 421 | (u32) throttling->control_register. | 449 | (u32) (ptc_value << bit_offset), |
| 422 | bit_width * 8); | 450 | (u32) (bit_width + bit_offset)); |
| 423 | ret = 0; | 451 | ret = 0; |
| 424 | break; | 452 | break; |
| 425 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | 453 | case ACPI_ADR_SPACE_FIXED_HARDWARE: |
