]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/acpica/tbfadt.c
Merge branch 'omap-pool'
[linux-2.6-omap-h63xx.git] / drivers / acpi / acpica / tbfadt.c
index 3636e4f8fb7331e66f6b59f6aa059b9b820fb620..71e655d14cb0759a71fff3da12188f6c8a0f0679 100644 (file)
@@ -57,6 +57,8 @@ static void acpi_tb_convert_fadt(void);
 
 static void acpi_tb_validate_fadt(void);
 
+static void acpi_tb_setup_fadt_registers(void);
+
 /* Table for conversion of FADT to common internal format and FADT validation */
 
 typedef struct acpi_fadt_info {
@@ -130,7 +132,38 @@ static struct acpi_fadt_info fadt_info_table[] = {
         ACPI_FADT_SEPARATE_LENGTH}
 };
 
-#define ACPI_FADT_INFO_ENTRIES        (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+#define ACPI_FADT_INFO_ENTRIES \
+                       (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/* Table used to split Event Blocks into separate status/enable registers */
+
+typedef struct acpi_fadt_pm_info {
+       struct acpi_generic_address *target;
+       u8 source;
+       u8 register_num;
+
+} acpi_fadt_pm_info;
+
+static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
+       {&acpi_gbl_xpm1a_status,
+        ACPI_FADT_OFFSET(xpm1a_event_block),
+        0},
+
+       {&acpi_gbl_xpm1a_enable,
+        ACPI_FADT_OFFSET(xpm1a_event_block),
+        1},
+
+       {&acpi_gbl_xpm1b_status,
+        ACPI_FADT_OFFSET(xpm1b_event_block),
+        0},
+
+       {&acpi_gbl_xpm1b_enable,
+        ACPI_FADT_OFFSET(xpm1b_event_block),
+        1}
+};
+
+#define ACPI_FADT_PM_INFO_ENTRIES \
+                       (sizeof (fadt_pm_info_table) / sizeof (struct acpi_fadt_pm_info))
 
 /*******************************************************************************
  *
@@ -172,7 +205,6 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
  * FUNCTION:    acpi_tb_parse_fadt
  *
  * PARAMETERS:  table_index         - Index for the FADT
- *              Flags               - Flags
  *
  * RETURN:      None
  *
@@ -181,7 +213,7 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
  *
  ******************************************************************************/
 
-void acpi_tb_parse_fadt(u32 table_index, u8 flags)
+void acpi_tb_parse_fadt(u32 table_index)
 {
        u32 length;
        struct acpi_table_header *table;
@@ -208,7 +240,7 @@ void acpi_tb_parse_fadt(u32 table_index, u8 flags)
         */
        (void)acpi_tb_verify_checksum(table, length);
 
-       /* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+       /* Create a local copy of the FADT in common ACPI 2.0+ format */
 
        acpi_tb_create_local_fadt(table, length);
 
@@ -219,10 +251,10 @@ void acpi_tb_parse_fadt(u32 table_index, u8 flags)
        /* Obtain the DSDT and FACS tables via their addresses within the FADT */
 
        acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
-                             flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+                             ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
 
        acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
-                             flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+                             ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
 }
 
 /*******************************************************************************
@@ -266,11 +298,17 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
        ACPI_MEMCPY(&acpi_gbl_FADT, table,
                    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
 
-       /*
-        * 1) Convert the local copy of the FADT to the common internal format
-        * 2) Validate some of the important values within the FADT
-        */
+       /* Convert the local copy of the FADT to the common internal format */
+
        acpi_tb_convert_fadt();
+
+       /* Validate FADT values now, before we make any changes */
+
+       acpi_tb_validate_fadt();
+
+       /* Initialize the global ACPI register structures */
+
+       acpi_tb_setup_fadt_registers();
 }
 
 /*******************************************************************************
@@ -282,31 +320,35 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
  * RETURN:      None
  *
  * DESCRIPTION: Converts all versions of the FADT to a common internal format.
- *              Expand all 32-bit addresses to 64-bit.
+ *              Expand 32-bit addresses to 64-bit as necessary.
  *
  * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
  *              and must contain a copy of the actual FADT.
  *
- * ACPICA will use the "X" fields of the FADT for all addresses.
+ * Notes on 64-bit register addresses:
+ *
+ * After this FADT conversion, later ACPICA code will only use the 64-bit "X"
+ * fields of the FADT for all ACPI register addresses.
  *
- * "X" fields are optional extensions to the original V1.0 fields. Even if
- * they are present in the structure, they can be optionally not used by
- * setting them to zero. Therefore, we must selectively expand V1.0 fields
- * if the corresponding X field is zero.
+ * The 64-bit "X" fields are optional extensions to the original 32-bit FADT
+ * V1.0 fields. Even if they are present in the FADT, they are optional and
+ * are unused if the BIOS sets them to zero. Therefore, we must copy/expand
+ * 32-bit V1.0 fields if the corresponding X field is zero.
  *
- * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
- * "X" fields.
+ * For ACPI 1.0 FADTs, all 32-bit address fields are expanded to the
+ * corresponding "X" fields in the internal FADT.
  *
- * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
- * expanding the corresponding ACPI 1.0 field.
+ * For ACPI 2.0+ FADTs, all valid (non-zero) 32-bit address fields are expanded
+ * to the corresponding 64-bit X fields. For compatibility with other ACPI
+ * implementations, we ignore the 64-bit field if the 32-bit field is valid,
+ * regardless of whether the host OS is 32-bit or 64-bit.
  *
  ******************************************************************************/
 
 static void acpi_tb_convert_fadt(void)
 {
-       u8 pm1_register_bit_width;
-       u8 pm1_register_byte_width;
-       struct acpi_generic_address *target64;
+       struct acpi_generic_address *address64;
+       u32 address32;
        u32 i;
 
        /* Update the local FADT table header length */
@@ -355,140 +397,56 @@ static void acpi_tb_convert_fadt(void)
         * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
         * generic address structures as necessary. Later code will always use
         * the 64-bit address structures.
+        *
+        * March 2009:
+        * We now always use the 32-bit address if it is valid (non-null). This
+        * is not in accordance with the ACPI specification which states that
+        * the 64-bit address supersedes the 32-bit version, but we do this for
+        * compatibility with other ACPI implementations. Most notably, in the
+        * case where both the 32 and 64 versions are non-null, we use the 32-bit
+        * version. This is the only address that is guaranteed to have been
+        * tested by the BIOS manufacturer.
         */
        for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
-               target64 =
-                   ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
-                                fadt_info_table[i].address64);
+               address32 = *ACPI_ADD_PTR(u32,
+                                         &acpi_gbl_FADT,
+                                         fadt_info_table[i].address32);
 
-               /* Expand only if the 64-bit X target is null */
+               address64 = ACPI_ADD_PTR(struct acpi_generic_address,
+                                        &acpi_gbl_FADT,
+                                        fadt_info_table[i].address64);
 
-               if (!target64->address) {
+               /*
+                * If both 32- and 64-bit addresses are valid (non-zero),
+                * they must match.
+                */
+               if (address64->address && address32 &&
+                   (address64->address != (u64) address32)) {
+                       ACPI_ERROR((AE_INFO,
+                                   "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 32",
+                                   fadt_info_table[i].name, address32,
+                                   ACPI_FORMAT_UINT64(address64->address)));
+               }
 
-                       /* The space_id is always I/O for the 32-bit legacy address fields */
+               /* Always use 32-bit address if it is valid (non-null) */
 
-                       acpi_tb_init_generic_address(target64,
+               if (address32) {
+                       /*
+                        * Copy the 32-bit address to the 64-bit GAS structure. The
+                        * Space ID is always I/O for 32-bit legacy address fields
+                       */
+                       acpi_tb_init_generic_address(address64,
                                                     ACPI_ADR_SPACE_SYSTEM_IO,
                                                     *ACPI_ADD_PTR(u8,
                                                                   &acpi_gbl_FADT,
                                                                   fadt_info_table
                                                                   [i].length),
-                                                    (u64) * ACPI_ADD_PTR(u32,
-                                                                         &acpi_gbl_FADT,
-                                                                         fadt_info_table
-                                                                         [i].
-                                                                         address32));
-               }
-       }
-
-       /* Validate FADT values now, before we make any changes */
-
-       acpi_tb_validate_fadt();
-
-       /*
-        * Optionally check all register lengths against the default values and
-        * update them if they are incorrect.
-        */
-       if (acpi_gbl_use_default_register_widths) {
-               for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
-                       target64 =
-                           ACPI_ADD_PTR(struct acpi_generic_address,
-                                        &acpi_gbl_FADT,
-                                        fadt_info_table[i].address64);
-
-                       /*
-                        * If a valid register (Address != 0) and the (default_length > 0)
-                        * (Not a GPE register), then check the width against the default.
-                        */
-                       if ((target64->address) &&
-                           (fadt_info_table[i].default_length > 0) &&
-                           (fadt_info_table[i].default_length !=
-                            target64->bit_width)) {
-                               ACPI_WARNING((AE_INFO,
-                                             "Invalid length for %s: %d, using default %d",
-                                             fadt_info_table[i].name,
-                                             target64->bit_width,
-                                             fadt_info_table[i].
-                                             default_length));
-
-                               /* Incorrect size, set width to the default */
-
-                               target64->bit_width =
-                                   fadt_info_table[i].default_length;
-                       }
+                                                    address32);
                }
        }
-
-       /*
-        * Get the length of the individual PM1 registers (enable and status).
-        * Each register is defined to be (event block length / 2).
-        */
-       pm1_register_bit_width =
-           (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width);
-       pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width);
-
-       /*
-        * Adjust the lengths of the PM1 Event Blocks so that they can be used to
-        * access the PM1 status register(s). Use (width / 2)
-        */
-       acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width;
-       acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width;
-
-       /*
-        * Calculate separate GAS structs for the PM1 Enable registers.
-        * These addresses do not appear (directly) in the FADT, so it is
-        * useful to calculate them once, here.
-        *
-        * The PM event blocks are split into two register blocks, first is the
-        * PM Status Register block, followed immediately by the PM Enable
-        * Register block. Each is of length (xpm1x_event_block.bit_width/2).
-        *
-        * On various systems the v2 fields (and particularly the bit widths)
-        * cannot be relied upon, though. Hence resort to using the v1 length
-        * here (and warn about the inconsistency).
-        */
-       if (acpi_gbl_FADT.xpm1a_event_block.bit_width
-           != acpi_gbl_FADT.pm1_event_length * 8)
-               printk(KERN_WARNING "FADT: "
-                      "X_PM1a_EVT_BLK.bit_width (%u) does not match"
-                      " PM1_EVT_LEN (%u)\n",
-                      acpi_gbl_FADT.xpm1a_event_block.bit_width,
-                      acpi_gbl_FADT.pm1_event_length);
-
-       /* The PM1A register block is required */
-
-       acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
-                                    acpi_gbl_FADT.xpm1a_event_block.space_id,
-                                    pm1_register_byte_width,
-                                    (acpi_gbl_FADT.xpm1a_event_block.address +
-                                     pm1_register_byte_width));
-       /* Don't forget to copy space_id of the GAS */
-       acpi_gbl_xpm1a_enable.space_id =
-           acpi_gbl_FADT.xpm1a_event_block.space_id;
-
-       /* The PM1B register block is optional, ignore if not present */
-
-       if (acpi_gbl_FADT.xpm1b_event_block.address) {
-               if (acpi_gbl_FADT.xpm1b_event_block.bit_width
-                   != acpi_gbl_FADT.pm1_event_length * 8)
-                       printk(KERN_WARNING "FADT: "
-                              "X_PM1b_EVT_BLK.bit_width (%u) does not match"
-                              " PM1_EVT_LEN (%u)\n",
-                              acpi_gbl_FADT.xpm1b_event_block.bit_width,
-                              acpi_gbl_FADT.pm1_event_length);
-               acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
-                                            acpi_gbl_FADT.xpm1b_event_block.space_id,
-                                            pm1_register_byte_width,
-                                            (acpi_gbl_FADT.xpm1b_event_block.
-                                             address + pm1_register_byte_width));
-               /* Don't forget to copy space_id of the GAS */
-               acpi_gbl_xpm1b_enable.space_id =
-                   acpi_gbl_FADT.xpm1b_event_block.space_id;
-
-       }
 }
 
-/******************************************************************************
+/*******************************************************************************
  *
  * FUNCTION:    acpi_tb_validate_fadt
  *
@@ -525,18 +483,22 @@ static void acpi_tb_validate_fadt(void)
            (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) {
                ACPI_WARNING((AE_INFO,
                              "32/64X FACS address mismatch in FADT - "
-                             "two FACS tables! %8.8X/%8.8X%8.8X",
+                             "%8.8X/%8.8X%8.8X, using 32",
                              acpi_gbl_FADT.facs,
                              ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs)));
+
+               acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
        }
 
        if (acpi_gbl_FADT.dsdt &&
            (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) {
                ACPI_WARNING((AE_INFO,
                              "32/64X DSDT address mismatch in FADT - "
-                             "two DSDT tables! %8.8X/%8.8X%8.8X",
+                             "%8.8X/%8.8X%8.8X, using 32",
                              acpi_gbl_FADT.dsdt,
                              ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt)));
+
+               acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
        }
 
        /* Examine all of the 64-bit extended address fields (X fields) */
@@ -561,7 +523,8 @@ static void acpi_tb_validate_fadt(void)
                 * For each extended field, check for length mismatch between the
                 * legacy length field and the corresponding 64-bit X length field.
                 */
-               if (address64 && (address64->bit_width != ACPI_MUL_8(length))) {
+               if (address64->address &&
+                   (address64->bit_width != ACPI_MUL_8(length))) {
                        ACPI_WARNING((AE_INFO,
                                      "32/64X length mismatch in %s: %d/%d",
                                      name, ACPI_MUL_8(length),
@@ -575,7 +538,8 @@ static void acpi_tb_validate_fadt(void)
                         */
                        if (!address64->address || !length) {
                                ACPI_ERROR((AE_INFO,
-                                           "Required field %s has zero address and/or length: %8.8X%8.8X/%X",
+                                           "Required field %s has zero address and/or length:"
+                                           " %8.8X%8.8X/%X",
                                            name,
                                            ACPI_FORMAT_UINT64(address64->
                                                               address),
@@ -584,27 +548,112 @@ static void acpi_tb_validate_fadt(void)
                } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
                        /*
                         * Field is optional (PM2Control, GPE0, GPE1) AND has its own
-                        * length field. If present, both the address and length must be valid.
+                        * length field. If present, both the address and length must
+                        * be valid.
                         */
-                       if ((address64->address && !length)
-                           || (!address64->address && length)) {
+                       if ((address64->address && !length) ||
+                           (!address64->address && length)) {
                                ACPI_WARNING((AE_INFO,
-                                             "Optional field %s has zero address or length: %8.8X%8.8X/%X",
+                                             "Optional field %s has zero address or length: "
+                                             "%8.8X%8.8X/%X",
                                              name,
                                              ACPI_FORMAT_UINT64(address64->
                                                                 address),
                                              length));
                        }
                }
+       }
+}
 
-               /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_setup_fadt_registers
+ *
+ * PARAMETERS:  None, uses acpi_gbl_FADT.
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize global ACPI PM1 register definitions. Optionally,
+ *              force FADT register definitions to their default lengths.
+ *
+ ******************************************************************************/
 
-               if (address64->address && *address32 &&
-                   (address64->address != (u64) * address32)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 64X",
-                                   name, *address32,
-                                   ACPI_FORMAT_UINT64(address64->address)));
+static void acpi_tb_setup_fadt_registers(void)
+{
+       struct acpi_generic_address *target64;
+       struct acpi_generic_address *source64;
+       u8 pm1_register_byte_width;
+       u32 i;
+
+       /*
+        * Optionally check all register lengths against the default values and
+        * update them if they are incorrect.
+        */
+       if (acpi_gbl_use_default_register_widths) {
+               for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+                       target64 =
+                           ACPI_ADD_PTR(struct acpi_generic_address,
+                                        &acpi_gbl_FADT,
+                                        fadt_info_table[i].address64);
+
+                       /*
+                        * If a valid register (Address != 0) and the (default_length > 0)
+                        * (Not a GPE register), then check the width against the default.
+                        */
+                       if ((target64->address) &&
+                           (fadt_info_table[i].default_length > 0) &&
+                           (fadt_info_table[i].default_length !=
+                            target64->bit_width)) {
+                               ACPI_WARNING((AE_INFO,
+                                             "Invalid length for %s: %d, using default %d",
+                                             fadt_info_table[i].name,
+                                             target64->bit_width,
+                                             fadt_info_table[i].
+                                             default_length));
+
+                               /* Incorrect size, set width to the default */
+
+                               target64->bit_width =
+                                   fadt_info_table[i].default_length;
+                       }
+               }
+       }
+
+       /*
+        * Get the length of the individual PM1 registers (enable and status).
+        * Each register is defined to be (event block length / 2). Extra divide
+        * by 8 converts bits to bytes.
+        */
+       pm1_register_byte_width = (u8)
+           ACPI_DIV_16(acpi_gbl_FADT.xpm1a_event_block.bit_width);
+
+       /*
+        * Calculate separate GAS structs for the PM1x (A/B) Status and Enable
+        * registers. These addresses do not appear (directly) in the FADT, so it
+        * is useful to pre-calculate them from the PM1 Event Block definitions.
+        *
+        * The PM event blocks are split into two register blocks, first is the
+        * PM Status Register block, followed immediately by the PM Enable
+        * Register block. Each is of length (pm1_event_length/2)
+        *
+        * Note: The PM1A event block is required by the ACPI specification.
+        * However, the PM1B event block is optional and is rarely, if ever,
+        * used.
+        */
+
+       for (i = 0; i < ACPI_FADT_PM_INFO_ENTRIES; i++) {
+               source64 =
+                   ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+                                fadt_pm_info_table[i].source);
+
+               if (source64->address) {
+                       acpi_tb_init_generic_address(fadt_pm_info_table[i].
+                                                    target, source64->space_id,
+                                                    pm1_register_byte_width,
+                                                    source64->address +
+                                                    (fadt_pm_info_table[i].
+                                                     register_num *
+                                                     pm1_register_byte_width));
                }
        }
 }