ACPICA: Split out PM1 status registers from the FADT
authorBob Moore <robert.moore@intel.com>
Wed, 18 Feb 2009 06:06:12 +0000 (14:06 +0800)
committerLen Brown <len.brown@intel.com>
Thu, 26 Mar 2009 20:38:22 +0000 (16:38 -0400)
Add new globals for the PM1 status registers (A/B), similar to the
way the PM1 enable registers are handled. Instead of overloading
the FADT Event Register blocks. This makes the code clearer and
less prone to error.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/tbfadt.c

index 634fb0785e7e0d8933a10732d937440617b4867e..f3e87ba43dbe37a73e8c22aaa8678f5771f248f4 100644 (file)
@@ -148,9 +148,12 @@ ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
 ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
 ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
 
-/* These addresses are calculated from FADT address values */
+/* These addresses are calculated from the FADT Event Block addresses */
 
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_status;
 ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
+
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_status;
 ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
 
 /*
index 4dc43b018517a21310effd1fda6e9e05769b2128..7ef0b8eadbc70f5d0c10ea68293e612f44330f88 100644 (file)
@@ -72,21 +72,23 @@ acpi_status acpi_hw_clear_acpi_status(void)
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
                          ACPI_BITMASK_ALL_FIXED_STATUS,
-                         (u16) acpi_gbl_FADT.xpm1a_event_block.address));
+                         (u16) acpi_gbl_xpm1a_status.address));
 
        lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
 
+       /* Clear the fixed events */
+
        status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
                                        ACPI_BITMASK_ALL_FIXED_STATUS);
        if (ACPI_FAILURE(status)) {
                goto unlock_and_exit;
        }
 
-       /* Clear the fixed events */
+       /* Write PM1B register if present */
 
-       if (acpi_gbl_FADT.xpm1b_event_block.address) {
+       if (acpi_gbl_xpm1b_status.address) {
                status = acpi_write(ACPI_BITMASK_ALL_FIXED_STATUS,
-                                   &acpi_gbl_FADT.xpm1b_event_block);
+                                   &acpi_gbl_xpm1b_status);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
@@ -150,14 +152,14 @@ acpi_hw_register_read(u32 register_id, u32 * return_value)
        switch (register_id) {
        case ACPI_REGISTER_PM1_STATUS:  /* 16-bit access */
 
-               status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_event_block);
+               status = acpi_read(&value1, &acpi_gbl_xpm1a_status);
                if (ACPI_FAILURE(status)) {
                        goto exit;
                }
 
                /* PM1B is optional */
 
-               status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_event_block);
+               status = acpi_read(&value2, &acpi_gbl_xpm1b_status);
                value1 |= value2;
                break;
 
@@ -267,14 +269,14 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
 
                /* Now we can write the data */
 
-               status = acpi_write(value, &acpi_gbl_FADT.xpm1a_event_block);
+               status = acpi_write(value, &acpi_gbl_xpm1a_status);
                if (ACPI_FAILURE(status)) {
                        goto exit;
                }
 
                /* PM1B is optional */
 
-               status = acpi_write(value, &acpi_gbl_FADT.xpm1b_event_block);
+               status = acpi_write(value, &acpi_gbl_xpm1b_status);
                break;
 
        case ACPI_REGISTER_PM1_ENABLE:  /* 16-bit access */
index 4b683ccd4a94fe052d2245997e4944f72a8d1706..a8191efd9aa6bc0b47bc744193e39c0b8d38f6b4 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 {
@@ -132,6 +134,35 @@ static struct acpi_fadt_info fadt_info_table[] = {
 
 #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))
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_init_generic_address
@@ -207,7 +238,7 @@ void acpi_tb_parse_fadt(u32 table_index)
         */
        (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);
 
@@ -265,11 +296,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();
 }
 
 /*******************************************************************************
@@ -303,8 +340,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
 
 static void acpi_tb_convert_fadt(void)
 {
-       u8 pm1_register_bit_width;
-       u8 pm1_register_byte_width;
        struct acpi_generic_address *target64;
        u32 i;
 
@@ -379,112 +414,6 @@ static void acpi_tb_convert_fadt(void)
                                                                          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;
-                       }
-               }
-       }
-
-       /*
-        * 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;
-
-       }
 }
 
 /******************************************************************************
@@ -607,3 +536,94 @@ static void acpi_tb_validate_fadt(void)
                }
        }
 }
+
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+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);
+
+               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));
+       }
+}