]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: tbconvrt - ACPI Table conversion utilities | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2000 - 2005, R. Byron Moore | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions, and the following disclaimer, | |
16 | * without modification. | |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
18 | * substantially similar to the "NO WARRANTY" disclaimer below | |
19 | * ("Disclaimer") and any redistribution must be conditioned upon | |
20 | * including a substantially similar Disclaimer requirement for further | |
21 | * binary redistribution. | |
22 | * 3. Neither the names of the above-listed copyright holders nor the names | |
23 | * of any contributors may be used to endorse or promote products derived | |
24 | * from this software without specific prior written permission. | |
25 | * | |
26 | * Alternatively, this software may be distributed under the terms of the | |
27 | * GNU General Public License ("GPL") version 2 as published by the Free | |
28 | * Software Foundation. | |
29 | * | |
30 | * NO WARRANTY | |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
41 | * POSSIBILITY OF SUCH DAMAGES. | |
42 | */ | |
43 | ||
44 | #include <linux/module.h> | |
45 | ||
46 | #include <acpi/acpi.h> | |
47 | #include <acpi/actables.h> | |
48 | ||
49 | ||
50 | #define _COMPONENT ACPI_TABLES | |
51 | ACPI_MODULE_NAME ("tbconvrt") | |
52 | ||
44f6c012 RM |
53 | /* Local prototypes */ |
54 | ||
55 | static void | |
56 | acpi_tb_init_generic_address ( | |
57 | struct acpi_generic_address *new_gas_struct, | |
58 | u8 register_bit_width, | |
59 | acpi_physical_address address); | |
60 | ||
61 | static void | |
62 | acpi_tb_convert_fadt1 ( | |
63 | struct fadt_descriptor_rev2 *local_fadt, | |
64 | struct fadt_descriptor_rev1 *original_fadt); | |
65 | ||
66 | static void | |
67 | acpi_tb_convert_fadt2 ( | |
68 | struct fadt_descriptor_rev2 *local_fadt, | |
69 | struct fadt_descriptor_rev2 *original_fadt); | |
70 | ||
1da177e4 LT |
71 | |
72 | u8 acpi_fadt_is_v1; | |
73 | EXPORT_SYMBOL(acpi_fadt_is_v1); | |
74 | ||
75 | /******************************************************************************* | |
76 | * | |
77 | * FUNCTION: acpi_tb_get_table_count | |
78 | * | |
79 | * PARAMETERS: RSDP - Pointer to the RSDP | |
80 | * RSDT - Pointer to the RSDT/XSDT | |
81 | * | |
82 | * RETURN: The number of tables pointed to by the RSDT or XSDT. | |
83 | * | |
84 | * DESCRIPTION: Calculate the number of tables. Automatically handles either | |
85 | * an RSDT or XSDT. | |
86 | * | |
87 | ******************************************************************************/ | |
88 | ||
89 | u32 | |
90 | acpi_tb_get_table_count ( | |
91 | struct rsdp_descriptor *RSDP, | |
92 | struct acpi_table_header *RSDT) | |
93 | { | |
94 | u32 pointer_size; | |
95 | ||
96 | ||
97 | ACPI_FUNCTION_ENTRY (); | |
98 | ||
99 | ||
73459f73 RM |
100 | /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ |
101 | ||
102 | if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { | |
1da177e4 LT |
103 | pointer_size = sizeof (u32); |
104 | } | |
105 | else { | |
106 | pointer_size = sizeof (u64); | |
107 | } | |
108 | ||
109 | /* | |
110 | * Determine the number of tables pointed to by the RSDT/XSDT. | |
111 | * This is defined by the ACPI Specification to be the number of | |
112 | * pointers contained within the RSDT/XSDT. The size of the pointers | |
113 | * is architecture-dependent. | |
114 | */ | |
115 | return ((RSDT->length - sizeof (struct acpi_table_header)) / pointer_size); | |
116 | } | |
117 | ||
118 | ||
119 | /******************************************************************************* | |
120 | * | |
121 | * FUNCTION: acpi_tb_convert_to_xsdt | |
122 | * | |
123 | * PARAMETERS: table_info - Info about the RSDT | |
124 | * | |
125 | * RETURN: Status | |
126 | * | |
127 | * DESCRIPTION: Convert an RSDT to an XSDT (internal common format) | |
128 | * | |
129 | ******************************************************************************/ | |
130 | ||
131 | acpi_status | |
132 | acpi_tb_convert_to_xsdt ( | |
133 | struct acpi_table_desc *table_info) | |
134 | { | |
135 | acpi_size table_size; | |
136 | u32 i; | |
137 | XSDT_DESCRIPTOR *new_table; | |
138 | ||
139 | ||
140 | ACPI_FUNCTION_ENTRY (); | |
141 | ||
142 | ||
143 | /* Compute size of the converted XSDT */ | |
144 | ||
145 | table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof (u64)) + | |
146 | sizeof (struct acpi_table_header); | |
147 | ||
148 | /* Allocate an XSDT */ | |
149 | ||
150 | new_table = ACPI_MEM_CALLOCATE (table_size); | |
151 | if (!new_table) { | |
152 | return (AE_NO_MEMORY); | |
153 | } | |
154 | ||
155 | /* Copy the header and set the length */ | |
156 | ||
157 | ACPI_MEMCPY (new_table, table_info->pointer, sizeof (struct acpi_table_header)); | |
158 | new_table->length = (u32) table_size; | |
159 | ||
160 | /* Copy the table pointers */ | |
161 | ||
162 | for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { | |
73459f73 RM |
163 | /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */ |
164 | ||
165 | if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { | |
1da177e4 | 166 | ACPI_STORE_ADDRESS (new_table->table_offset_entry[i], |
44f6c012 RM |
167 | (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, |
168 | table_info->pointer))->table_offset_entry[i]); | |
1da177e4 LT |
169 | } |
170 | else { | |
171 | new_table->table_offset_entry[i] = | |
44f6c012 RM |
172 | (ACPI_CAST_PTR (XSDT_DESCRIPTOR, |
173 | table_info->pointer))->table_offset_entry[i]; | |
1da177e4 LT |
174 | } |
175 | } | |
176 | ||
177 | /* Delete the original table (either mapped or in a buffer) */ | |
178 | ||
179 | acpi_tb_delete_single_table (table_info); | |
180 | ||
181 | /* Point the table descriptor to the new table */ | |
182 | ||
183 | table_info->pointer = ACPI_CAST_PTR (struct acpi_table_header, new_table); | |
184 | table_info->length = table_size; | |
185 | table_info->allocation = ACPI_MEM_ALLOCATED; | |
186 | ||
187 | return (AE_OK); | |
188 | } | |
189 | ||
190 | ||
44f6c012 | 191 | /******************************************************************************* |
1da177e4 LT |
192 | * |
193 | * FUNCTION: acpi_tb_init_generic_address | |
194 | * | |
195 | * PARAMETERS: new_gas_struct - GAS struct to be initialized | |
196 | * register_bit_width - Width of this register | |
197 | * Address - Address of the register | |
198 | * | |
199 | * RETURN: None | |
200 | * | |
201 | * DESCRIPTION: Initialize a GAS structure. | |
202 | * | |
203 | ******************************************************************************/ | |
204 | ||
205 | static void | |
206 | acpi_tb_init_generic_address ( | |
207 | struct acpi_generic_address *new_gas_struct, | |
208 | u8 register_bit_width, | |
209 | acpi_physical_address address) | |
210 | { | |
211 | ||
212 | ACPI_STORE_ADDRESS (new_gas_struct->address, address); | |
213 | ||
214 | new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO; | |
215 | new_gas_struct->register_bit_width = register_bit_width; | |
216 | new_gas_struct->register_bit_offset = 0; | |
217 | new_gas_struct->access_width = 0; | |
218 | } | |
219 | ||
220 | ||
221 | /******************************************************************************* | |
222 | * | |
223 | * FUNCTION: acpi_tb_convert_fadt1 | |
224 | * | |
225 | * PARAMETERS: local_fadt - Pointer to new FADT | |
226 | * original_fadt - Pointer to old FADT | |
227 | * | |
44f6c012 | 228 | * RETURN: None, populates local_fadt |
1da177e4 LT |
229 | * |
230 | * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format | |
231 | * | |
232 | ******************************************************************************/ | |
233 | ||
234 | static void | |
235 | acpi_tb_convert_fadt1 ( | |
236 | struct fadt_descriptor_rev2 *local_fadt, | |
237 | struct fadt_descriptor_rev1 *original_fadt) | |
238 | { | |
239 | ||
1da177e4 LT |
240 | /* ACPI 1.0 FACS */ |
241 | /* The BIOS stored FADT should agree with Revision 1.0 */ | |
242 | acpi_fadt_is_v1 = 1; | |
243 | ||
244 | /* | |
245 | * Copy the table header and the common part of the tables. | |
246 | * | |
247 | * The 2.0 table is an extension of the 1.0 table, so the entire 1.0 | |
248 | * table can be copied first, then expand some fields to 64 bits. | |
249 | */ | |
250 | ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev1)); | |
251 | ||
252 | /* Convert table pointers to 64-bit fields */ | |
253 | ||
254 | ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl); | |
255 | ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); | |
256 | ||
257 | /* | |
44f6c012 RM |
258 | * System Interrupt Model isn't used in ACPI 2.0 |
259 | * (local_fadt->Reserved1 = 0;) | |
1da177e4 LT |
260 | */ |
261 | ||
262 | /* | |
263 | * This field is set by the OEM to convey the preferred power management | |
264 | * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't | |
265 | * know what kind of 32-bit system this is, we will use "unspecified". | |
266 | */ | |
267 | local_fadt->prefer_PM_profile = PM_UNSPECIFIED; | |
268 | ||
269 | /* | |
270 | * Processor Performance State Control. This is the value OSPM writes to | |
271 | * the SMI_CMD register to assume processor performance state control | |
272 | * responsibility. There isn't any equivalence in 1.0, but as many 1.x | |
273 | * ACPI tables contain _PCT and _PSS we also keep this value, unless | |
274 | * acpi_strict is set. | |
275 | */ | |
276 | if (acpi_strict) | |
277 | local_fadt->pstate_cnt = 0; | |
278 | ||
279 | /* | |
280 | * Support for the _CST object and C States change notification. | |
281 | * This data item hasn't any 1.0 equivalence so leave it zero. | |
282 | */ | |
283 | local_fadt->cst_cnt = 0; | |
284 | ||
285 | /* | |
286 | * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0. | |
287 | * It primarily adds the FADT reset mechanism. | |
288 | */ | |
289 | if ((original_fadt->revision == 2) && | |
290 | (original_fadt->length == sizeof (struct fadt_descriptor_rev2_minus))) { | |
291 | /* | |
292 | * Grab the entire generic address struct, plus the 1-byte reset value | |
293 | * that immediately follows. | |
294 | */ | |
295 | ACPI_MEMCPY (&local_fadt->reset_register, | |
44f6c012 RM |
296 | &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, |
297 | original_fadt))->reset_register, | |
1da177e4 LT |
298 | sizeof (struct acpi_generic_address) + 1); |
299 | } | |
300 | else { | |
301 | /* | |
302 | * Since there isn't any equivalence in 1.0 and since it is highly | |
303 | * likely that a 1.0 system has legacy support. | |
304 | */ | |
305 | local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES; | |
306 | } | |
307 | ||
308 | /* | |
309 | * Convert the V1.0 block addresses to V2.0 GAS structures | |
310 | */ | |
311 | acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, local_fadt->pm1_evt_len, | |
312 | (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); | |
313 | acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, local_fadt->pm1_evt_len, | |
314 | (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); | |
315 | acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, local_fadt->pm1_cnt_len, | |
316 | (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); | |
317 | acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, local_fadt->pm1_cnt_len, | |
318 | (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); | |
319 | acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, local_fadt->pm2_cnt_len, | |
320 | (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); | |
321 | acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, local_fadt->pm_tm_len, | |
322 | (acpi_physical_address) local_fadt->V1_pm_tmr_blk); | |
323 | acpi_tb_init_generic_address (&local_fadt->xgpe0_blk, 0, | |
324 | (acpi_physical_address) local_fadt->V1_gpe0_blk); | |
325 | acpi_tb_init_generic_address (&local_fadt->xgpe1_blk, 0, | |
326 | (acpi_physical_address) local_fadt->V1_gpe1_blk); | |
327 | ||
328 | /* Create separate GAS structs for the PM1 Enable registers */ | |
329 | ||
330 | acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, | |
331 | (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), | |
44f6c012 RM |
332 | (acpi_physical_address) |
333 | (local_fadt->xpm1a_evt_blk.address + | |
1da177e4 LT |
334 | ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); |
335 | ||
336 | /* PM1B is optional; leave null if not present */ | |
337 | ||
338 | if (local_fadt->xpm1b_evt_blk.address) { | |
339 | acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, | |
340 | (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), | |
44f6c012 RM |
341 | (acpi_physical_address) |
342 | (local_fadt->xpm1b_evt_blk.address + | |
1da177e4 LT |
343 | ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); |
344 | } | |
345 | } | |
346 | ||
347 | ||
348 | /******************************************************************************* | |
349 | * | |
350 | * FUNCTION: acpi_tb_convert_fadt2 | |
351 | * | |
352 | * PARAMETERS: local_fadt - Pointer to new FADT | |
353 | * original_fadt - Pointer to old FADT | |
354 | * | |
44f6c012 | 355 | * RETURN: None, populates local_fadt |
1da177e4 LT |
356 | * |
357 | * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format. | |
358 | * Handles optional "X" fields. | |
359 | * | |
360 | ******************************************************************************/ | |
361 | ||
362 | static void | |
363 | acpi_tb_convert_fadt2 ( | |
364 | struct fadt_descriptor_rev2 *local_fadt, | |
365 | struct fadt_descriptor_rev2 *original_fadt) | |
366 | { | |
367 | ||
368 | /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */ | |
369 | ||
370 | ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev2)); | |
371 | ||
372 | /* | |
373 | * "X" fields are optional extensions to the original V1.0 fields, so | |
374 | * we must selectively expand V1.0 fields if the corresponding X field | |
375 | * is zero. | |
376 | */ | |
377 | if (!(local_fadt->xfirmware_ctrl)) { | |
44f6c012 RM |
378 | ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, |
379 | local_fadt->V1_firmware_ctrl); | |
1da177e4 LT |
380 | } |
381 | ||
382 | if (!(local_fadt->Xdsdt)) { | |
383 | ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt); | |
384 | } | |
385 | ||
386 | if (!(local_fadt->xpm1a_evt_blk.address)) { | |
387 | acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, | |
44f6c012 RM |
388 | local_fadt->pm1_evt_len, |
389 | (acpi_physical_address) local_fadt->V1_pm1a_evt_blk); | |
1da177e4 LT |
390 | } |
391 | ||
392 | if (!(local_fadt->xpm1b_evt_blk.address)) { | |
393 | acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, | |
44f6c012 RM |
394 | local_fadt->pm1_evt_len, |
395 | (acpi_physical_address) local_fadt->V1_pm1b_evt_blk); | |
1da177e4 LT |
396 | } |
397 | ||
398 | if (!(local_fadt->xpm1a_cnt_blk.address)) { | |
399 | acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, | |
44f6c012 RM |
400 | local_fadt->pm1_cnt_len, |
401 | (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk); | |
1da177e4 LT |
402 | } |
403 | ||
404 | if (!(local_fadt->xpm1b_cnt_blk.address)) { | |
405 | acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, | |
44f6c012 RM |
406 | local_fadt->pm1_cnt_len, |
407 | (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk); | |
1da177e4 LT |
408 | } |
409 | ||
410 | if (!(local_fadt->xpm2_cnt_blk.address)) { | |
411 | acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, | |
44f6c012 RM |
412 | local_fadt->pm2_cnt_len, |
413 | (acpi_physical_address) local_fadt->V1_pm2_cnt_blk); | |
1da177e4 LT |
414 | } |
415 | ||
416 | if (!(local_fadt->xpm_tmr_blk.address)) { | |
417 | acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, | |
44f6c012 RM |
418 | local_fadt->pm_tm_len, |
419 | (acpi_physical_address) local_fadt->V1_pm_tmr_blk); | |
1da177e4 LT |
420 | } |
421 | ||
422 | if (!(local_fadt->xgpe0_blk.address)) { | |
423 | acpi_tb_init_generic_address (&local_fadt->xgpe0_blk, | |
424 | 0, (acpi_physical_address) local_fadt->V1_gpe0_blk); | |
425 | } | |
426 | ||
427 | if (!(local_fadt->xgpe1_blk.address)) { | |
428 | acpi_tb_init_generic_address (&local_fadt->xgpe1_blk, | |
429 | 0, (acpi_physical_address) local_fadt->V1_gpe1_blk); | |
430 | } | |
431 | ||
432 | /* Create separate GAS structs for the PM1 Enable registers */ | |
433 | ||
434 | acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable, | |
435 | (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), | |
44f6c012 RM |
436 | (acpi_physical_address) |
437 | (local_fadt->xpm1a_evt_blk.address + | |
1da177e4 | 438 | ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); |
44f6c012 RM |
439 | |
440 | acpi_gbl_xpm1a_enable.address_space_id = | |
441 | local_fadt->xpm1a_evt_blk.address_space_id; | |
1da177e4 LT |
442 | |
443 | /* PM1B is optional; leave null if not present */ | |
444 | ||
445 | if (local_fadt->xpm1b_evt_blk.address) { | |
446 | acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable, | |
447 | (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len), | |
44f6c012 RM |
448 | (acpi_physical_address) |
449 | (local_fadt->xpm1b_evt_blk.address + | |
1da177e4 | 450 | ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len))); |
44f6c012 RM |
451 | |
452 | acpi_gbl_xpm1b_enable.address_space_id = | |
453 | local_fadt->xpm1b_evt_blk.address_space_id; | |
1da177e4 LT |
454 | } |
455 | } | |
456 | ||
457 | ||
458 | /******************************************************************************* | |
459 | * | |
460 | * FUNCTION: acpi_tb_convert_table_fadt | |
461 | * | |
462 | * PARAMETERS: None | |
463 | * | |
464 | * RETURN: Status | |
465 | * | |
466 | * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local | |
467 | * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply | |
468 | * copied to the local FADT. The ACPI CA software uses this | |
469 | * local FADT. Thus a significant amount of special #ifdef | |
470 | * type codeing is saved. | |
471 | * | |
472 | ******************************************************************************/ | |
473 | ||
474 | acpi_status | |
44f6c012 RM |
475 | acpi_tb_convert_table_fadt ( |
476 | void) | |
1da177e4 LT |
477 | { |
478 | struct fadt_descriptor_rev2 *local_fadt; | |
479 | struct acpi_table_desc *table_desc; | |
480 | ||
481 | ||
482 | ACPI_FUNCTION_TRACE ("tb_convert_table_fadt"); | |
483 | ||
484 | ||
485 | /* | |
486 | * acpi_gbl_FADT is valid. Validate the FADT length. The table must be | |
487 | * at least as long as the version 1.0 FADT | |
488 | */ | |
489 | if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) { | |
44f6c012 RM |
490 | ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", |
491 | acpi_gbl_FADT->length)); | |
1da177e4 LT |
492 | return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); |
493 | } | |
494 | ||
495 | /* Allocate buffer for the ACPI 2.0(+) FADT */ | |
496 | ||
497 | local_fadt = ACPI_MEM_CALLOCATE (sizeof (struct fadt_descriptor_rev2)); | |
498 | if (!local_fadt) { | |
499 | return_ACPI_STATUS (AE_NO_MEMORY); | |
500 | } | |
501 | ||
502 | if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) { | |
503 | if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) { | |
504 | /* Length is too short to be a V2.0 table */ | |
505 | ||
44f6c012 RM |
506 | ACPI_REPORT_WARNING (( |
507 | "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n", | |
508 | acpi_gbl_FADT->length, acpi_gbl_FADT->revision)); | |
1da177e4 LT |
509 | |
510 | acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); | |
511 | } | |
512 | else { | |
513 | /* Valid V2.0 table */ | |
514 | ||
515 | acpi_tb_convert_fadt2 (local_fadt, acpi_gbl_FADT); | |
516 | } | |
517 | } | |
518 | else { | |
519 | /* Valid V1.0 table */ | |
520 | ||
521 | acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT); | |
522 | } | |
523 | ||
44f6c012 RM |
524 | /* Global FADT pointer will point to the new common V2.0 FADT */ |
525 | ||
1da177e4 LT |
526 | acpi_gbl_FADT = local_fadt; |
527 | acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR); | |
528 | ||
529 | /* Free the original table */ | |
530 | ||
531 | table_desc = acpi_gbl_table_lists[ACPI_TABLE_FADT].next; | |
532 | acpi_tb_delete_single_table (table_desc); | |
533 | ||
534 | /* Install the new table */ | |
535 | ||
536 | table_desc->pointer = ACPI_CAST_PTR (struct acpi_table_header, acpi_gbl_FADT); | |
537 | table_desc->allocation = ACPI_MEM_ALLOCATED; | |
538 | table_desc->length = sizeof (struct fadt_descriptor_rev2); | |
539 | ||
540 | /* Dump the entire FADT */ | |
541 | ||
542 | ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, | |
543 | "Hex dump of common internal FADT, size %d (%X)\n", | |
544 | acpi_gbl_FADT->length, acpi_gbl_FADT->length)); | |
545 | ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->length); | |
546 | ||
547 | return_ACPI_STATUS (AE_OK); | |
548 | } | |
549 | ||
550 | ||
551 | /******************************************************************************* | |
552 | * | |
44f6c012 | 553 | * FUNCTION: acpi_tb_build_common_facs |
1da177e4 LT |
554 | * |
555 | * PARAMETERS: table_info - Info for currently installed FACS | |
556 | * | |
557 | * RETURN: Status | |
558 | * | |
559 | * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal | |
560 | * table format. | |
561 | * | |
562 | ******************************************************************************/ | |
563 | ||
564 | acpi_status | |
565 | acpi_tb_build_common_facs ( | |
566 | struct acpi_table_desc *table_info) | |
567 | { | |
568 | ||
569 | ACPI_FUNCTION_TRACE ("tb_build_common_facs"); | |
570 | ||
571 | ||
572 | /* Absolute minimum length is 24, but the ACPI spec says 64 */ | |
573 | ||
574 | if (acpi_gbl_FACS->length < 24) { | |
44f6c012 RM |
575 | ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", |
576 | acpi_gbl_FACS->length)); | |
1da177e4 LT |
577 | return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); |
578 | } | |
579 | ||
580 | if (acpi_gbl_FACS->length < 64) { | |
44f6c012 RM |
581 | ACPI_REPORT_WARNING (( |
582 | "FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n", | |
1da177e4 LT |
583 | acpi_gbl_FACS->length)); |
584 | } | |
585 | ||
586 | /* Copy fields to the new FACS */ | |
587 | ||
588 | acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock); | |
589 | ||
590 | if ((acpi_gbl_RSDP->revision < 2) || | |
591 | (acpi_gbl_FACS->length < 32) || | |
592 | (!(acpi_gbl_FACS->xfirmware_waking_vector))) { | |
593 | /* ACPI 1.0 FACS or short table or optional X_ field is zero */ | |
594 | ||
44f6c012 RM |
595 | acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, |
596 | &(acpi_gbl_FACS->firmware_waking_vector)); | |
1da177e4 LT |
597 | acpi_gbl_common_fACS.vector_width = 32; |
598 | } | |
599 | else { | |
600 | /* ACPI 2.0 FACS with valid X_ field */ | |
601 | ||
602 | acpi_gbl_common_fACS.firmware_waking_vector = &acpi_gbl_FACS->xfirmware_waking_vector; | |
603 | acpi_gbl_common_fACS.vector_width = 64; | |
604 | } | |
605 | ||
606 | return_ACPI_STATUS (AE_OK); | |
607 | } | |
608 | ||
609 |