diff options
author | Jan Beulich <jbeulich@novell.com> | 2008-09-19 18:50:32 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-10-10 15:31:48 -0400 |
commit | fcea94ba0773a4bf78d109f2acd72d003f0621f6 (patch) | |
tree | e05362e8dd4b6d941c4761c1945f64b13a4b69da /drivers/acpi | |
parent | 3fa8749e584b55f1180411ab1b51117190bac1e5 (diff) |
ACPI: fix FADT parsing
The (1.0 inherited) separate length fields in the FADT are byte granular.
Further, PM1a/b may have distinct lengths (if using the v2 fields was
okay) and may live in distinct address spaces. acpi_tb_convert_fadt()
should account for all of these conditions.
Apart from these changes I'm puzzled by the fact that, not just for
acpi_gbl_xpm1{a,b}_enable, acpi_hw_low_level_{read,write}() get an
explicit size passed rather than using the size found in the passed GAS.
What happens on a platform that defines PM1{a,b} wider than 16 bits? Of
course, acpi_hw_low_level_{read,write}() at present are entirely
un-prepared to deal with sizes other than 8, 16, or 32, not to speak of a
non-zero bit_offset or access_width...
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/tables/tbfadt.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index a4a41ba2484b..2c7885e7ffba 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c | |||
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("tbfadt") | |||
50 | /* Local prototypes */ | 50 | /* Local prototypes */ |
51 | static void inline | 51 | static void inline |
52 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | 52 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
53 | u8 bit_width, u64 address); | 53 | u8 byte_width, u64 address); |
54 | 54 | ||
55 | static void acpi_tb_convert_fadt(void); | 55 | static void acpi_tb_convert_fadt(void); |
56 | 56 | ||
@@ -111,7 +111,7 @@ static struct acpi_fadt_info fadt_info_table[] = { | |||
111 | * FUNCTION: acpi_tb_init_generic_address | 111 | * FUNCTION: acpi_tb_init_generic_address |
112 | * | 112 | * |
113 | * PARAMETERS: generic_address - GAS struct to be initialized | 113 | * PARAMETERS: generic_address - GAS struct to be initialized |
114 | * bit_width - Width of this register | 114 | * byte_width - Width of this register |
115 | * Address - Address of the register | 115 | * Address - Address of the register |
116 | * | 116 | * |
117 | * RETURN: None | 117 | * RETURN: None |
@@ -124,7 +124,7 @@ static struct acpi_fadt_info fadt_info_table[] = { | |||
124 | 124 | ||
125 | static void inline | 125 | static void inline |
126 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | 126 | acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, |
127 | u8 bit_width, u64 address) | 127 | u8 byte_width, u64 address) |
128 | { | 128 | { |
129 | 129 | ||
130 | /* | 130 | /* |
@@ -136,7 +136,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, | |||
136 | /* All other fields are byte-wide */ | 136 | /* All other fields are byte-wide */ |
137 | 137 | ||
138 | generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; | 138 | generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; |
139 | generic_address->bit_width = bit_width; | 139 | generic_address->bit_width = byte_width << 3; |
140 | generic_address->bit_offset = 0; | 140 | generic_address->bit_offset = 0; |
141 | generic_address->access_width = 0; | 141 | generic_address->access_width = 0; |
142 | } | 142 | } |
@@ -342,9 +342,20 @@ static void acpi_tb_convert_fadt(void) | |||
342 | * useful to calculate them once, here. | 342 | * useful to calculate them once, here. |
343 | * | 343 | * |
344 | * The PM event blocks are split into two register blocks, first is the | 344 | * The PM event blocks are split into two register blocks, first is the |
345 | * PM Status Register block, followed immediately by the PM Enable Register | 345 | * PM Status Register block, followed immediately by the PM Enable |
346 | * block. Each is of length (pm1_event_length/2) | 346 | * Register block. Each is of length (xpm1x_event_block.bit_width/2). |
347 | * | ||
348 | * On various systems the v2 fields (and particularly the bit widths) | ||
349 | * cannot be relied upon, though. Hence resort to using the v1 length | ||
350 | * here (and warn about the inconsistency). | ||
347 | */ | 351 | */ |
352 | if (acpi_gbl_FADT.xpm1a_event_block.bit_width | ||
353 | != acpi_gbl_FADT.pm1_event_length * 8) | ||
354 | printk(KERN_WARNING "FADT: " | ||
355 | "X_PM1a_EVT_BLK.bit_width (%u) does not match" | ||
356 | " PM1_EVT_LEN (%u)\n", | ||
357 | acpi_gbl_FADT.xpm1a_event_block.bit_width, | ||
358 | acpi_gbl_FADT.pm1_event_length); | ||
348 | pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); | 359 | pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); |
349 | 360 | ||
350 | /* The PM1A register block is required */ | 361 | /* The PM1A register block is required */ |
@@ -360,13 +371,20 @@ static void acpi_tb_convert_fadt(void) | |||
360 | /* The PM1B register block is optional, ignore if not present */ | 371 | /* The PM1B register block is optional, ignore if not present */ |
361 | 372 | ||
362 | if (acpi_gbl_FADT.xpm1b_event_block.address) { | 373 | if (acpi_gbl_FADT.xpm1b_event_block.address) { |
374 | if (acpi_gbl_FADT.xpm1b_event_block.bit_width | ||
375 | != acpi_gbl_FADT.pm1_event_length * 8) | ||
376 | printk(KERN_WARNING "FADT: " | ||
377 | "X_PM1b_EVT_BLK.bit_width (%u) does not match" | ||
378 | " PM1_EVT_LEN (%u)\n", | ||
379 | acpi_gbl_FADT.xpm1b_event_block.bit_width, | ||
380 | acpi_gbl_FADT.pm1_event_length); | ||
363 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, | 381 | acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, |
364 | pm1_register_length, | 382 | pm1_register_length, |
365 | (acpi_gbl_FADT.xpm1b_event_block. | 383 | (acpi_gbl_FADT.xpm1b_event_block. |
366 | address + pm1_register_length)); | 384 | address + pm1_register_length)); |
367 | /* Don't forget to copy space_id of the GAS */ | 385 | /* Don't forget to copy space_id of the GAS */ |
368 | acpi_gbl_xpm1b_enable.space_id = | 386 | acpi_gbl_xpm1b_enable.space_id = |
369 | acpi_gbl_FADT.xpm1a_event_block.space_id; | 387 | acpi_gbl_FADT.xpm1b_event_block.space_id; |
370 | 388 | ||
371 | } | 389 | } |
372 | } | 390 | } |