Merge tag 'acpi-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Nov 2017 04:08:22 +0000 (20:08 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Nov 2017 04:08:22 +0000 (20:08 -0800)
Pull ACPI updates from Rafael Wysocki:
 "These update ACPICA to upstream revision 20170831, fix APEI to use the
  fixmap instead of ioremap_page_range(), add an operation region driver
  for TI PMIC TPS68470, add support for PCC subspace IDs to the ACPI
  CPPC driver, fix a few assorted issues and clean up some code.

  Specifics:

   - Update the ACPICA code to upstream revision 20170831 including
      * PDTT table header support (Bob Moore).
      * Cleanup and extension of internal string-to-integer conversion
        functions (Bob Moore).
      * Support for 64-bit hardware accesses (Lv Zheng).
      * ACPI PM Timer code adjustment to deal with 64-bit return values
        of acpi_hw_read() (Bob Moore).
      * Support for deferred table verification in acpiexec (Lv Zheng).

   - Fix APEI to use the fixmap instead of ioremap_page_range() which
     cannot work correctly the way the code in there attempted to use it
     and drop some code that's not necessary any more after that change
     (James Morse).

   - Clean up the APEI support code and make it use 64-bit timestamps
     (Arnd Bergmann, Dongjiu Geng, Jan Beulich).

   - Add operation region driver for TI PMIC TPS68470 (Rajmohan Mani).

   - Add support for PCC subspace IDs to the ACPI CPPC driver (George
     Cherian).

   - Fix an ACPI EC driver regression related to the handling of EC
     events during the "noirq" phases of system suspend/resume (Lv
     Zheng).

   - Delay the initialization of the lid state in the ACPI button driver
     to fix issues appearing on some systems (Hans de Goede).

   - Extend the KIOX000A "device always present" quirk to cover all
     affected BIOS versions (Hans de Goede).

   - Clean up some code in the ACPI core and drivers (Colin Ian King,
     Gustavo Silva)"

* tag 'acpi-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (24 commits)
  ACPI: Mark expected switch fall-throughs
  ACPI / LPSS: Remove redundant initialization of clk
  ACPI / CPPC: Make CPPC ACPI driver aware of PCC subspace IDs
  mailbox: PCC: Move the MAX_PCC_SUBSPACES definition to header file
  ACPI / sysfs: Make function param_set_trace_method_name() static
  ACPI / button: Delay acpi_lid_initialize_state() until first user space open
  ACPI / EC: Fix regression related to triggering source of EC event handling
  APEI / ERST: use 64-bit timestamps
  ACPI / APEI: Remove arch_apei_flush_tlb_one()
  arm64: mm: Remove arch_apei_flush_tlb_one()
  ACPI / APEI: Remove ghes_ioremap_area
  ACPI / APEI: Replace ioremap_page_range() with fixmap
  ACPI / APEI: remove the unused dead-code for SEA/NMI notification type
  ACPI / x86: Extend KIOX000A quirk to cover all affected BIOS versions
  ACPI / APEI: adjust a local variable type in ghes_ioremap_pfn_irq()
  ACPICA: Update version to 20170831
  ACPICA: Update acpi_get_timer for 64-bit interface to acpi_hw_read
  ACPICA: String conversions: Update to add new behaviors
  ACPICA: String conversions: Cleanup/format comments. No functional changes
  ACPICA: Restructure/cleanup all string-to-integer conversion functions
  ...

48 files changed:
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/fixmap.h
arch/arm64/mm/mmu.c
arch/x86/include/asm/fixmap.h
arch/x86/kernel/acpi/apei.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/ac.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acinterp.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dbconvert.c
drivers/acpi/acpica/dswexec.c
drivers/acpi/acpica/evgpe.c
drivers/acpi/acpica/exconcat.c
drivers/acpi/acpica/exconvrt.c
drivers/acpi/acpica/exmisc.c
drivers/acpi/acpica/exresop.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/hwtimer.c
drivers/acpi/acpica/hwxface.c
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/utstrsuppt.c [new file with mode: 0644]
drivers/acpi/acpica/utstrtoul64.c
drivers/acpi/apei/erst.c
drivers/acpi/apei/ghes.c
drivers/acpi/button.c
drivers/acpi/cppc_acpi.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/pmic/tps68470_pmic.c [new file with mode: 0644]
drivers/acpi/resource.c
drivers/acpi/sysfs.c
drivers/acpi/x86/utils.c
drivers/mailbox/pcc.c
include/acpi/acexcep.h
include/acpi/acpixf.h
include/acpi/actbl1.h
include/acpi/apei.h
include/acpi/pcc.h
tools/power/acpi/tools/acpidump/Makefile
tools/power/acpi/tools/acpidump/apdump.c
tools/power/acpi/tools/acpidump/apmain.c

index 59cca1d6ec547270adbd56a4e2265b9f9fc34375..32f465a80e4e86d5b13fd2d92925b16cceb0bf07 100644 (file)
@@ -126,18 +126,6 @@ static inline const char *acpi_get_enable_method(int cpu)
  */
 #define acpi_disable_cmcff 1
 pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
-
-/*
- * Despite its name, this function must still broadcast the TLB
- * invalidation in order to ensure other CPUs don't end up with junk
- * entries as a result of speculation. Unusually, its also called in
- * IRQ context (ghes_iounmap_irq) so if we ever need to use IPIs for
- * TLB broadcasting, then we're in trouble here.
- */
-static inline void arch_apei_flush_tlb_one(unsigned long addr)
-{
-       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
-}
 #endif /* CONFIG_ACPI_APEI */
 
 #ifdef CONFIG_ACPI_NUMA
index caf86be815ba2cfa26d6cbcab8ee1cd7f6bdf158..4052ec39e8dbb06feb74e1161dcf26ac94744fb2 100644 (file)
@@ -51,6 +51,13 @@ enum fixed_addresses {
 
        FIX_EARLYCON_MEM_BASE,
        FIX_TEXT_POKE0,
+
+#ifdef CONFIG_ACPI_APEI_GHES
+       /* Used for GHES mapping from assorted contexts */
+       FIX_APEI_GHES_IRQ,
+       FIX_APEI_GHES_NMI,
+#endif /* CONFIG_ACPI_APEI_GHES */
+
        __end_of_permanent_fixed_addresses,
 
        /*
index f1eb15e0e8642d2a74c7d19d18e8e8d3ae5a7062..267d2b79d52d6e3918a18a2c590d797bdec6d3cb 100644 (file)
@@ -778,6 +778,10 @@ void __init early_fixmap_init(void)
        }
 }
 
+/*
+ * Unusually, this is also called in IRQ context (ghes_iounmap_irq) so if we
+ * ever need to use IPIs for TLB broadcasting, then we're in trouble here.
+ */
 void __set_fixmap(enum fixed_addresses idx,
                               phys_addr_t phys, pgprot_t flags)
 {
index dcd9fb55e67991821d46602754a392c6f2ed0e06..b0c505fe9a958c701fef6d96f281bb8ab1a773de 100644 (file)
@@ -104,6 +104,12 @@ enum fixed_addresses {
        FIX_GDT_REMAP_BEGIN,
        FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1,
 
+#ifdef CONFIG_ACPI_APEI_GHES
+       /* Used for GHES mapping from assorted contexts */
+       FIX_APEI_GHES_IRQ,
+       FIX_APEI_GHES_NMI,
+#endif
+
        __end_of_permanent_fixed_addresses,
 
        /*
index ea3046e0b0cf53c44417eed99ae8f76b6fec08d9..bb8d300fecbdd09c9469f796934a1d25caf19fb5 100644 (file)
@@ -52,8 +52,3 @@ void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
        apei_mce_report_mem_error(sev, mem_err);
 #endif
 }
-
-void arch_apei_flush_tlb_one(unsigned long addr)
-{
-       __flush_tlb_one(addr);
-}
index 4cb763a01f4d02e9cebca31629d46ae3315fed2b..91477d5ab422c4795b56abffe1075f3c35e40b76 100644 (file)
@@ -541,4 +541,20 @@ if ARM64
 source "drivers/acpi/arm64/Kconfig"
 endif
 
+config TPS68470_PMIC_OPREGION
+       bool "ACPI operation region support for TPS68470 PMIC"
+       depends on MFD_TPS68470
+       help
+         This config adds ACPI operation region support for TI TPS68470 PMIC.
+         TPS68470 device is an advanced power management unit that powers
+         a Compact Camera Module (CCM), generates clocks for image sensors,
+         drives a dual LED for flash and incorporates two LED drivers for
+         general purpose indicators.
+         This driver enables ACPI operation region support control voltage
+         regulators and clocks.
+
+         This option is a bool as it provides an ACPI operation
+         region, which must be available before any of the devices
+         using this, are probed.
+
 endif  # ACPI
index 168e14d29d31a156f5d52911e0fd6c2ec84bb581..31c15d84a8d03811358cc4f0b9a40509694c10bc 100644 (file)
@@ -109,6 +109,8 @@ obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o
 
 obj-$(CONFIG_ACPI_CONFIGFS)    += acpi_configfs.o
 
+obj-$(CONFIG_TPS68470_PMIC_OPREGION)   += pmic/tps68470_pmic.o
+
 video-objs                     += acpi_video.o video_detect.o
 obj-y                          += dptf/
 
index 8f52483219ba109625792c24cc29e490068ea209..47a7ed557bd645924a6cfe112e8f712dfc18a6b9 100644 (file)
@@ -265,6 +265,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Unsupported event [0x%x]\n", event));
+       /* fall through */
        case ACPI_AC_NOTIFY_STATUS:
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
index de7385b824e153e1b5587bd134b7d42ca640d0e7..7f2b02cc8ea148c6091b56006889babfeb09e309 100644 (file)
@@ -362,7 +362,7 @@ static int register_device_clock(struct acpi_device *adev,
 {
        const struct lpss_device_desc *dev_desc = pdata->dev_desc;
        const char *devname = dev_name(&adev->dev);
-       struct clk *clk = ERR_PTR(-ENODEV);
+       struct clk *clk;
        struct lpss_clk_data *clk_data;
        const char *parent, *clk_name;
        void __iomem *prv_base;
index 86c10599d9f83e86517aa436d6d93f78839e0f5f..449d86d39965e6090a518eab4f9c18aa9f2f6852 100644 (file)
@@ -82,6 +82,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
                 * PIIX4 models.
                 */
                errata.piix4.throttle = 1;
+               /* fall through*/
 
        case 2:         /* PIIX4E */
        case 3:         /* PIIX4M */
index e05232da05888a69660082fcd7751652ec9e81d4..71f6f2624debca2c3909307c30ec17fc04409ea4 100644 (file)
@@ -178,6 +178,7 @@ acpi-y +=           \
        utresrc.o       \
        utstate.o       \
        utstring.o      \
+       utstrsuppt.o    \
        utstrtoul64.o   \
        utxface.o       \
        utxfinit.o      \
index fd4f3cacb356aa005d49f90572f32194894c6f75..cd722d8edacbb462c9977372b758b9de1a2518cb 100644 (file)
@@ -66,9 +66,9 @@ acpi_status
 acpi_hw_validate_register(struct acpi_generic_address *reg,
                          u8 max_bit_width, u64 *address);
 
-acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg);
+acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg);
 
-acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg);
+acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg);
 
 struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id);
 
index 29a863c8531835e7d17a82c649fca240f770d751..29555c8789a31e5e6d80ccf1fb7d5acd29899daf 100644 (file)
@@ -101,7 +101,8 @@ typedef const struct acpi_exdump_info {
  */
 acpi_status
 acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
-                          union acpi_operand_object **result_desc, u32 flags);
+                          union acpi_operand_object **result_desc,
+                          u32 implicit_conversion);
 
 acpi_status
 acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
@@ -424,9 +425,6 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                             struct acpi_walk_state *walk_state,
                             u8 implicit_conversion);
 
-#define ACPI_IMPLICIT_CONVERSION        TRUE
-#define ACPI_NO_IMPLICIT_CONVERSION     FALSE
-
 /*
  * exstoren - resolve/store object
  */
index 745134ade35fd72972efd708d0cb66c550a46037..83b75e9db7efc88003ffa6de681439e6bfa61b2d 100644 (file)
@@ -141,6 +141,11 @@ extern const char *acpi_gbl_ptyp_decode[];
 #define ACPI_MSG_SUFFIX \
        acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
 
+/* Flags to indicate implicit or explicit string-to-integer conversion */
+
+#define ACPI_IMPLICIT_CONVERSION        TRUE
+#define ACPI_NO_IMPLICIT_CONVERSION     FALSE
+
 /* Types for Resource descriptor entries */
 
 #define ACPI_INVALID_RESOURCE           0
@@ -197,15 +202,31 @@ void acpi_ut_strlwr(char *src_string);
 
 int acpi_ut_stricmp(char *string1, char *string2);
 
-acpi_status acpi_ut_strtoul64(char *string, u32 flags, u64 *ret_integer);
+/*
+ * utstrsuppt - string-to-integer conversion support functions
+ */
+acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value);
+
+acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr);
+
+acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr);
+
+char acpi_ut_remove_whitespace(char **string);
+
+char acpi_ut_remove_leading_zeros(char **string);
+
+u8 acpi_ut_detect_hex_prefix(char **string);
+
+u8 acpi_ut_detect_octal_prefix(char **string);
 
 /*
- * Values for Flags above
- * Note: LIMIT values correspond to acpi_gbl_integer_byte_width values (4/8)
+ * utstrtoul64 - string-to-integer conversion functions
  */
-#define ACPI_STRTOUL_32BIT          0x04       /* 4 bytes */
-#define ACPI_STRTOUL_64BIT          0x08       /* 8 bytes */
-#define ACPI_STRTOUL_BASE16         0x10       /* Default: Base10/16 */
+acpi_status acpi_ut_strtoul64(char *string, u64 *ret_integer);
+
+u64 acpi_ut_explicit_strtoul64(char *string);
+
+u64 acpi_ut_implicit_strtoul64(char *string);
 
 /*
  * utglobal - Global data structures and procedures
index 857dbc43a9b133cec8f4f9b27ca91434806fe7f1..32d546f0db2f567b8747d73fc6ffec18baa22036 100644 (file)
@@ -277,10 +277,7 @@ acpi_db_convert_to_object(acpi_object_type type,
        default:
 
                object->type = ACPI_TYPE_INTEGER;
-               status = acpi_ut_strtoul64(string,
-                                          (acpi_gbl_integer_byte_width |
-                                           ACPI_STRTOUL_BASE16),
-                                          &object->integer.value);
+               status = acpi_ut_strtoul64(string, &object->integer.value);
                break;
        }
 
index 20d7744b06ae7c77fb9acaaf088c28b4f9652b17..22f45d090733244e008607be4b4ad2e42df9f0de 100644 (file)
@@ -134,7 +134,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
         * object. Implicitly convert the argument if necessary.
         */
        status = acpi_ex_convert_to_integer(obj_desc, &local_obj_desc,
-                                           ACPI_STRTOUL_BASE16);
+                                           ACPI_IMPLICIT_CONVERSION);
        if (ACPI_FAILURE(status)) {
                goto cleanup;
        }
index 229382035550bc4473d13272f76753fcc6e6e8e4..263d8fc4a9e2f848080cd3e16550082de819d9cc 100644 (file)
@@ -390,8 +390,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
        struct acpi_gpe_handler_info *gpe_handler_info;
        u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
        u8 enabled_status_byte;
-       u32 status_reg;
-       u32 enable_reg;
+       u64 status_reg;
+       u64 enable_reg;
        acpi_cpu_flags flags;
        u32 i;
        u32 j;
@@ -472,7 +472,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
                                          gpe_register_info->base_gpe_number,
                                          gpe_register_info->base_gpe_number +
                                          (ACPI_GPE_REGISTER_WIDTH - 1),
-                                         status_reg, enable_reg,
+                                         (u32)status_reg, (u32)enable_reg,
                                          gpe_register_info->enable_for_run,
                                          gpe_register_info->enable_for_wake));
 
index 76bfb7dcae2f083f1fb7f1a5231a2e973a65c673..59b8de2f07d3915a3e857980eac934d1d1c8ca10 100644 (file)
@@ -156,7 +156,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
 
                status =
                    acpi_ex_convert_to_integer(local_operand1, &temp_operand1,
-                                              ACPI_STRTOUL_BASE16);
+                                              ACPI_IMPLICIT_CONVERSION);
                break;
 
        case ACPI_TYPE_BUFFER:
index f71028e334eefe6fcdf65b0ab832031c19d6263e..23ebadb06a95b248830105d4c8b02bcc0cfb0044 100644 (file)
@@ -57,10 +57,10 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
  *
  * FUNCTION:    acpi_ex_convert_to_integer
  *
- * PARAMETERS:  obj_desc        - Object to be converted. Must be an
- *                                Integer, Buffer, or String
- *              result_desc     - Where the new Integer object is returned
- *              flags           - Used for string conversion
+ * PARAMETERS:  obj_desc            - Object to be converted. Must be an
+ *                                    Integer, Buffer, or String
+ *              result_desc         - Where the new Integer object is returned
+ *              implicit_conversion - Used for string conversion
  *
  * RETURN:      Status
  *
@@ -70,14 +70,14 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
 
 acpi_status
 acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
-                          union acpi_operand_object **result_desc, u32 flags)
+                          union acpi_operand_object **result_desc,
+                          u32 implicit_conversion)
 {
        union acpi_operand_object *return_desc;
        u8 *pointer;
        u64 result;
        u32 i;
        u32 count;
-       acpi_status status;
 
        ACPI_FUNCTION_TRACE_PTR(ex_convert_to_integer, obj_desc);
 
@@ -123,12 +123,18 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
                 * hexadecimal as per the ACPI specification. The only exception (as
                 * of ACPI 3.0) is that the to_integer() operator allows both decimal
                 * and hexadecimal strings (hex prefixed with "0x").
+                *
+                * Explicit conversion is used only by to_integer.
+                * All other string-to-integer conversions are implicit conversions.
                 */
-               status = acpi_ut_strtoul64(ACPI_CAST_PTR(char, pointer),
-                                          (acpi_gbl_integer_byte_width |
-                                           flags), &result);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
+               if (implicit_conversion) {
+                       result =
+                           acpi_ut_implicit_strtoul64(ACPI_CAST_PTR
+                                                      (char, pointer));
+               } else {
+                       result =
+                           acpi_ut_explicit_strtoul64(ACPI_CAST_PTR
+                                                      (char, pointer));
                }
                break;
 
@@ -631,7 +637,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
                         */
                        status =
                            acpi_ex_convert_to_integer(source_desc, result_desc,
-                                                      ACPI_STRTOUL_BASE16);
+                                                      ACPI_IMPLICIT_CONVERSION);
                        break;
 
                case ACPI_TYPE_STRING:
index 1e7649ce0a7b1b324862d69c9421f49eae49ca47..dbad3ebd7df504f362a97dc365b5475a8037cb29 100644 (file)
@@ -330,7 +330,7 @@ acpi_ex_do_logical_op(u16 opcode,
        case ACPI_TYPE_INTEGER:
 
                status = acpi_ex_convert_to_integer(operand1, &local_operand1,
-                                                   ACPI_STRTOUL_BASE16);
+                                                   ACPI_IMPLICIT_CONVERSION);
                break;
 
        case ACPI_TYPE_STRING:
index c4852429e2fff62a561e7e495da1502983e5518c..1c7c9962b0de7f6180bc8561c9343703e9944cde 100644 (file)
@@ -415,7 +415,7 @@ acpi_ex_resolve_operands(u16 opcode,
                         * Known as "Implicit Source Operand Conversion"
                         */
                        status = acpi_ex_convert_to_integer(obj_desc, stack_ptr,
-                                                           ACPI_STRTOUL_BASE16);
+                                                           ACPI_IMPLICIT_CONVERSION);
                        if (ACPI_FAILURE(status)) {
                                if (status == AE_TYPE) {
                                        ACPI_ERROR((AE_INFO,
index 5eb11b30a79e6c685118e660a5d294c93d02e527..09b6822aa5cc2554e1043ef158c1e45f38c29b77 100644 (file)
@@ -99,7 +99,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
 {
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_status status = AE_OK;
-       u32 enable_mask;
+       u64 enable_mask;
        u32 register_bit;
 
        ACPI_FUNCTION_ENTRY();
@@ -214,7 +214,7 @@ acpi_status
 acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
                       acpi_event_status *event_status)
 {
-       u32 in_byte;
+       u64 in_byte;
        u32 register_bit;
        struct acpi_gpe_register_info *gpe_register_info;
        acpi_event_status local_event_status = 0;
index acb417b58bbb388f1f53325e154ade65cde131b9..aa6e000819155024631d1e0922d69abe297095a6 100644 (file)
@@ -220,16 +220,15 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
- *              version of acpi_read, used internally since the overhead of
- *              64-bit values is not needed.
+ * DESCRIPTION: Read from either memory or IO space. This is a 64-bit max
+ *              version of acpi_read.
  *
  * LIMITATIONS: <These limitations also apply to acpi_hw_write>
  *      space_ID must be system_memory or system_IO.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
+acpi_status acpi_hw_read(u64 *value, struct acpi_generic_address *reg)
 {
        u64 address;
        u8 access_width;
@@ -244,17 +243,17 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
 
        /* Validate contents of the GAS register */
 
-       status = acpi_hw_validate_register(reg, 32, &address);
+       status = acpi_hw_validate_register(reg, 64, &address);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
 
        /*
-        * Initialize entire 32-bit return value to zero, convert access_width
+        * Initialize entire 64-bit return value to zero, convert access_width
         * into number of bits based
         */
        *value = 0;
-       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
+       access_width = acpi_hw_get_access_bit_width(address, reg, 64);
        bit_width = reg->bit_offset + reg->bit_width;
        bit_offset = reg->bit_offset;
 
@@ -265,7 +264,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
        index = 0;
        while (bit_width) {
                if (bit_offset >= access_width) {
-                       value32 = 0;
+                       value64 = 0;
                        bit_offset -= access_width;
                } else {
                        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
@@ -276,7 +275,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
                                                        ACPI_DIV_8
                                                        (access_width),
                                                        &value64, access_width);
-                               value32 = (u32)value64;
                        } else {        /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
 
                                status = acpi_hw_read_port((acpi_io_address)
@@ -286,15 +284,16 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
                                                           (access_width),
                                                           &value32,
                                                           access_width);
+                               value64 = (u64)value32;
                        }
                }
 
                /*
                 * Use offset style bit writes because "Index * AccessWidth" is
-                * ensured to be less than 32-bits by acpi_hw_validate_register().
+                * ensured to be less than 64-bits by acpi_hw_validate_register().
                 */
                ACPI_SET_BITS(value, index * access_width,
-                             ACPI_MASK_BITS_ABOVE_32(access_width), value32);
+                             ACPI_MASK_BITS_ABOVE_64(access_width), value64);
 
                bit_width -=
                    bit_width > access_width ? access_width : bit_width;
@@ -302,8 +301,9 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
-                         *value, access_width, ACPI_FORMAT_UINT64(address),
+                         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
+                         ACPI_FORMAT_UINT64(*value), access_width,
+                         ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
@@ -318,20 +318,18 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
- *              version of acpi_write, used internally since the overhead of
- *              64-bit values is not needed.
+ * DESCRIPTION: Write to either memory or IO space. This is a 64-bit max
+ *              version of acpi_write.
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
+acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg)
 {
        u64 address;
        u8 access_width;
        u32 bit_width;
        u8 bit_offset;
        u64 value64;
-       u32 value32;
        u8 index;
        acpi_status status;
 
@@ -339,14 +337,14 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
 
        /* Validate contents of the GAS register */
 
-       status = acpi_hw_validate_register(reg, 32, &address);
+       status = acpi_hw_validate_register(reg, 64, &address);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
 
        /* Convert access_width into number of bits based */
 
-       access_width = acpi_hw_get_access_bit_width(address, reg, 32);
+       access_width = acpi_hw_get_access_bit_width(address, reg, 64);
        bit_width = reg->bit_offset + reg->bit_width;
        bit_offset = reg->bit_offset;
 
@@ -358,16 +356,15 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
        while (bit_width) {
                /*
                 * Use offset style bit reads because "Index * AccessWidth" is
-                * ensured to be less than 32-bits by acpi_hw_validate_register().
+                * ensured to be less than 64-bits by acpi_hw_validate_register().
                 */
-               value32 = ACPI_GET_BITS(&value, index * access_width,
-                                       ACPI_MASK_BITS_ABOVE_32(access_width));
+               value64 = ACPI_GET_BITS(&value, index * access_width,
+                                       ACPI_MASK_BITS_ABOVE_64(access_width));
 
                if (bit_offset >= access_width) {
                        bit_offset -= access_width;
                } else {
                        if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-                               value64 = (u64)value32;
                                status =
                                    acpi_os_write_memory((acpi_physical_address)
                                                         address +
@@ -382,7 +379,7 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
                                                            index *
                                                            ACPI_DIV_8
                                                            (access_width),
-                                                           value32,
+                                                           (u32)value64,
                                                            access_width);
                        }
                }
@@ -397,8 +394,9 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         value, access_width, ACPI_FORMAT_UINT64(address),
+                         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
+                         ACPI_FORMAT_UINT64(value), access_width,
+                         ACPI_FORMAT_UINT64(address),
                          acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
@@ -526,6 +524,7 @@ acpi_status acpi_hw_write_pm1_control(u32 pm1a_control, u32 pm1b_control)
 acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
 {
        u32 value = 0;
+       u64 value64;
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(hw_register_read);
@@ -564,12 +563,14 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
        case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
 
                status =
-                   acpi_hw_read(&value, &acpi_gbl_FADT.xpm2_control_block);
+                   acpi_hw_read(&value64, &acpi_gbl_FADT.xpm2_control_block);
+               value = (u32)value64;
                break;
 
        case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
 
-               status = acpi_hw_read(&value, &acpi_gbl_FADT.xpm_timer_block);
+               status = acpi_hw_read(&value64, &acpi_gbl_FADT.xpm_timer_block);
+               value = (u32)value64;
                break;
 
        case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
@@ -586,7 +587,7 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
        }
 
        if (ACPI_SUCCESS(status)) {
-               *return_value = value;
+               *return_value = (u32)value;
        }
 
        return_ACPI_STATUS(status);
@@ -622,6 +623,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
 {
        acpi_status status;
        u32 read_value;
+       u64 read_value64;
 
        ACPI_FUNCTION_TRACE(hw_register_write);
 
@@ -685,11 +687,12 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
                 * as per the ACPI spec.
                 */
                status =
-                   acpi_hw_read(&read_value,
+                   acpi_hw_read(&read_value64,
                                 &acpi_gbl_FADT.xpm2_control_block);
                if (ACPI_FAILURE(status)) {
                        goto exit;
                }
+               read_value = (u32)read_value64;
 
                /* Insert the bits to be preserved */
 
@@ -745,22 +748,25 @@ acpi_hw_read_multiple(u32 *value,
 {
        u32 value_a = 0;
        u32 value_b = 0;
+       u64 value64;
        acpi_status status;
 
        /* The first register is always required */
 
-       status = acpi_hw_read(&value_a, register_a);
+       status = acpi_hw_read(&value64, register_a);
        if (ACPI_FAILURE(status)) {
                return (status);
        }
+       value_a = (u32)value64;
 
        /* Second register is optional */
 
        if (register_b->address) {
-               status = acpi_hw_read(&value_b, register_b);
+               status = acpi_hw_read(&value64, register_b);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
+               value_b = (u32)value64;
        }
 
        /*
index b3c5d8c754bb864a0ddf18ac4759bbb301a1e93f..a2f4e25d45b18e5c241a02890d3302256b68c0d0 100644 (file)
@@ -94,6 +94,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution)
 acpi_status acpi_get_timer(u32 * ticks)
 {
        acpi_status status;
+       u64 timer_value;
 
        ACPI_FUNCTION_TRACE(acpi_get_timer);
 
@@ -107,7 +108,14 @@ acpi_status acpi_get_timer(u32 * ticks)
                return_ACPI_STATUS(AE_SUPPORT);
        }
 
-       status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block);
+       status = acpi_hw_read(&timer_value, &acpi_gbl_FADT.xpm_timer_block);
+       if (ACPI_SUCCESS(status)) {
+
+               /* ACPI PM Timer is defined to be 32 bits (PM_TMR_LEN) */
+
+               *ticks = (u32)timer_value;
+       }
+
        return_ACPI_STATUS(status);
 }
 
index 34684ae899810889738fee7bbe3c2d2f806d4d01..b3c6e439933c56e428ff6d58485c594ca959b4cd 100644 (file)
@@ -125,76 +125,12 @@ ACPI_EXPORT_SYMBOL(acpi_reset)
  ******************************************************************************/
 acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg)
 {
-       u32 value_lo;
-       u32 value_hi;
-       u32 width;
-       u64 address;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(acpi_read);
 
-       if (!return_value) {
-               return (AE_BAD_PARAMETER);
-       }
-
-       /* Validate contents of the GAS register. Allow 64-bit transfers */
-
-       status = acpi_hw_validate_register(reg, 64, &address);
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
-
-       /*
-        * Two address spaces supported: Memory or I/O. PCI_Config is
-        * not supported here because the GAS structure is insufficient
-        */
-       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               status = acpi_os_read_memory((acpi_physical_address)
-                                            address, return_value,
-                                            reg->bit_width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-               value_lo = 0;
-               value_hi = 0;
-
-               width = reg->bit_width;
-               if (width == 64) {
-                       width = 32;     /* Break into two 32-bit transfers */
-               }
-
-               status = acpi_hw_read_port((acpi_io_address)
-                                          address, &value_lo, width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-
-               if (reg->bit_width == 64) {
-
-                       /* Read the top 32 bits */
-
-                       status = acpi_hw_read_port((acpi_io_address)
-                                                  (address + 4), &value_hi,
-                                                  32);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-               }
-
-               /* Set the return value only if status is AE_OK */
-
-               *return_value = (value_lo | ((u64)value_hi << 32));
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Read:  %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n",
-                         ACPI_FORMAT_UINT64(*return_value), reg->bit_width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->space_id)));
-
-       return (AE_OK);
+       status = acpi_hw_read(return_value, reg);
+       return (status);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_read)
@@ -213,59 +149,11 @@ ACPI_EXPORT_SYMBOL(acpi_read)
  ******************************************************************************/
 acpi_status acpi_write(u64 value, struct acpi_generic_address *reg)
 {
-       u32 width;
-       u64 address;
        acpi_status status;
 
        ACPI_FUNCTION_NAME(acpi_write);
 
-       /* Validate contents of the GAS register. Allow 64-bit transfers */
-
-       status = acpi_hw_validate_register(reg, 64, &address);
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
-
-       /*
-        * Two address spaces supported: Memory or IO. PCI_Config is
-        * not supported here because the GAS structure is insufficient
-        */
-       if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
-               status = acpi_os_write_memory((acpi_physical_address)
-                                             address, value, reg->bit_width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-       } else {                /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
-
-               width = reg->bit_width;
-               if (width == 64) {
-                       width = 32;     /* Break into two 32-bit transfers */
-               }
-
-               status = acpi_hw_write_port((acpi_io_address)
-                                           address, ACPI_LODWORD(value),
-                                           width);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-
-               if (reg->bit_width == 64) {
-                       status = acpi_hw_write_port((acpi_io_address)
-                                                   (address + 4),
-                                                   ACPI_HIDWORD(value), 32);
-                       if (ACPI_FAILURE(status)) {
-                               return (status);
-                       }
-               }
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_IO,
-                         "Wrote: %8.8X%8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         ACPI_FORMAT_UINT64(value), reg->bit_width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->space_id)));
-
+       status = acpi_hw_write(value, reg);
        return (status);
 }
 
index e4a7da8a11f0ac014cee2a8b3013f5d8e3bc9024..539d775bbc92344ae719e0e1da38dbed9580419a 100644 (file)
@@ -78,8 +78,8 @@ acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
 
                /* String-to-Integer conversion */
 
-               status = acpi_ut_strtoul64(original_object->string.pointer,
-                                          acpi_gbl_integer_byte_width, &value);
+               status =
+                   acpi_ut_strtoul64(original_object->string.pointer, &value);
                if (ACPI_FAILURE(status)) {
                        return (status);
                }
index 26ad596c973e9309d8fb961c26100eae2d650d1b..5ecb8d2e683479e3f0fe249f724818ee319991c5 100644 (file)
@@ -173,10 +173,13 @@ acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void)
        ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
 
        /*
-        * Only reallocate the root table if the host provided a static buffer
-        * for the table array in the call to acpi_initialize_tables.
+        * If there are tables unverified, it is required to reallocate the
+        * root table list to clean up invalid table entries. Otherwise only
+        * reallocate the root table list if the host provided a static buffer
+        * for the table array in the call to acpi_initialize_tables().
         */
-       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+       if ((acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) &&
+           acpi_gbl_enable_table_validation) {
                return_ACPI_STATUS(AE_SUPPORT);
        }
 
diff --git a/drivers/acpi/acpica/utstrsuppt.c b/drivers/acpi/acpica/utstrsuppt.c
new file mode 100644 (file)
index 0000000..965fb5c
--- /dev/null
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ *
+ * Module Name: utstrsuppt - Support functions for string-to-integer conversion
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2017, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utstrsuppt")
+
+/* Local prototypes */
+static acpi_status
+acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit);
+
+static acpi_status
+acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product);
+
+static acpi_status
+acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_octal_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 8 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned octal value is 01777777777777777777777
+ *              Maximum 32-bit unsigned octal value is 037777777777
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Character must be ASCII 0-7, otherwise terminate with no error */
+
+               if (!(ACPI_IS_OCTAL_DIGIT(*string))) {
+                       break;
+               }
+
+               /* Convert and insert this octal digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 8, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_OCTAL_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_decimal_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 10 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned decimal value is 18446744073709551615
+ *              Maximum 32-bit unsigned decimal value is 4294967295
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Character must be ASCII 0-9, otherwise terminate with no error */
+
+               if (!isdigit(*string)) {
+                       break;
+               }
+
+               /* Convert and insert this decimal digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 10, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_DECIMAL_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_convert_hex_string
+ *
+ * PARAMETERS:  string                  - Null terminated input string
+ *              return_value_ptr        - Where the converted value is returned
+ *
+ * RETURN:      Status and 64-bit converted integer
+ *
+ * DESCRIPTION: Performs a base 16 conversion of the input string to an
+ *              integer value, either 32 or 64 bits.
+ *
+ * NOTE:        Maximum 64-bit unsigned hex value is 0xFFFFFFFFFFFFFFFF
+ *              Maximum 32-bit unsigned hex value is 0xFFFFFFFF
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr)
+{
+       u64 accumulated_value = 0;
+       acpi_status status = AE_OK;
+
+       /* Convert each ASCII byte in the input string */
+
+       while (*string) {
+
+               /* Must be ASCII A-F, a-f, or 0-9, otherwise terminate with no error */
+
+               if (!isxdigit(*string)) {
+                       break;
+               }
+
+               /* Convert and insert this hex digit into the accumulator */
+
+               status = acpi_ut_insert_digit(&accumulated_value, 16, *string);
+               if (ACPI_FAILURE(status)) {
+                       status = AE_HEX_OVERFLOW;
+                       break;
+               }
+
+               string++;
+       }
+
+       /* Always return the value that has been accumulated */
+
+       *return_value_ptr = accumulated_value;
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_leading_zeros
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      Next character after any leading zeros. This character may be
+ *              used by the caller to detect end-of-string.
+ *
+ * DESCRIPTION: Remove any leading zeros in the input string. Return the
+ *              next character after the final ASCII zero to enable the caller
+ *              to check for the end of the string (NULL terminator).
+ *
+ ******************************************************************************/
+
+char acpi_ut_remove_leading_zeros(char **string)
+{
+
+       while (**string == ACPI_ASCII_ZERO) {
+               *string += 1;
+       }
+
+       return (**string);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_whitespace
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      Next character after any whitespace. This character may be
+ *              used by the caller to detect end-of-string.
+ *
+ * DESCRIPTION: Remove any leading whitespace in the input string. Return the
+ *              next character after the final ASCII zero to enable the caller
+ *              to check for the end of the string (NULL terminator).
+ *
+ ******************************************************************************/
+
+char acpi_ut_remove_whitespace(char **string)
+{
+
+       while (isspace((u8)**string)) {
+               *string += 1;
+       }
+
+       return (**string);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_detect_hex_prefix
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      TRUE if a "0x" prefix was found at the start of the string
+ *
+ * DESCRIPTION: Detect and remove a hex "0x" prefix
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_detect_hex_prefix(char **string)
+{
+
+       if ((**string == ACPI_ASCII_ZERO) &&
+           (tolower((int)*(*string + 1)) == 'x')) {
+               *string += 2;   /* Go past the leading 0x */
+               return (TRUE);
+       }
+
+       return (FALSE);         /* Not a hex string */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_detect_octal_prefix
+ *
+ * PARAMETERS:  string                  - Pointer to input ASCII string
+ *
+ * RETURN:      True if an octal "0" prefix was found at the start of the
+ *              string
+ *
+ * DESCRIPTION: Detect and remove an octal prefix (zero)
+ *
+ ******************************************************************************/
+
+u8 acpi_ut_detect_octal_prefix(char **string)
+{
+
+       if (**string == ACPI_ASCII_ZERO) {
+               *string += 1;   /* Go past the leading 0 */
+               return (TRUE);
+       }
+
+       return (FALSE);         /* Not an octal string */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_insert_digit
+ *
+ * PARAMETERS:  accumulated_value       - Current value of the integer value
+ *                                        accumulator. The new value is
+ *                                        returned here.
+ *              base                    - Radix, either 8/10/16
+ *              ascii_digit             - ASCII single digit to be inserted
+ *
+ * RETURN:      Status and result of the convert/insert operation. The only
+ *              possible returned exception code is numeric overflow of
+ *              either the multiply or add conversion operations.
+ *
+ * DESCRIPTION: Generic conversion and insertion function for all bases:
+ *
+ *              1) Multiply the current accumulated/converted value by the
+ *              base in order to make room for the new character.
+ *
+ *              2) Convert the new character to binary and add it to the
+ *              current accumulated value.
+ *
+ *              Note: The only possible exception indicates an integer
+ *              overflow (AE_NUMERIC_OVERFLOW)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit)
+{
+       acpi_status status;
+       u64 product;
+
+       /* Make room in the accumulated value for the incoming digit */
+
+       status = acpi_ut_strtoul_multiply64(*accumulated_value, base, &product);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
+       /* Add in the new digit, and store the sum to the accumulated value */
+
+       status =
+           acpi_ut_strtoul_add64(product,
+                                 acpi_ut_ascii_char_to_hex(ascii_digit),
+                                 accumulated_value);
+
+       return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strtoul_multiply64
+ *
+ * PARAMETERS:  multiplicand            - Current accumulated converted integer
+ *              multiplier              - Base/Radix
+ *              out_product             - Where the product is returned
+ *
+ * RETURN:      Status and 64-bit product
+ *
+ * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as
+ *              well as 32-bit overflow if necessary (if the current global
+ *              integer width is 32).
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_strtoul_multiply64(u64 multiplicand, u64 multiplier, u64 *out_product)
+{
+       u64 val;
+
+       /* Exit if either operand is zero */
+
+       *out_product = 0;
+       if (!multiplicand || !multiplier) {
+               return (AE_OK);
+       }
+
+       /* Check for 64-bit overflow before the actual multiplication */
+
+       acpi_ut_short_divide(ACPI_UINT64_MAX, (u32)multiplier, &val, NULL);
+       if (multiplicand > val) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       val = multiplicand * multiplier;
+
+       /* Check for 32-bit overflow if necessary */
+
+       if ((acpi_gbl_integer_bit_width == 32) && (val > ACPI_UINT32_MAX)) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       *out_product = val;
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_strtoul_add64
+ *
+ * PARAMETERS:  addend1                 - Current accumulated converted integer
+ *              addend2                 - New hex value/char
+ *              out_sum                 - Where sum is returned (Accumulator)
+ *
+ * RETURN:      Status and 64-bit sum
+ *
+ * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as
+ *              well as 32-bit overflow if necessary (if the current global
+ *              integer width is 32).
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ut_strtoul_add64(u64 addend1, u64 addend2, u64 *out_sum)
+{
+       u64 sum;
+
+       /* Check for 64-bit overflow before the actual addition */
+
+       if ((addend1 > 0) && (addend2 > (ACPI_UINT64_MAX - addend1))) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       sum = addend1 + addend2;
+
+       /* Check for 32-bit overflow if necessary */
+
+       if ((acpi_gbl_integer_bit_width == 32) && (sum > ACPI_UINT32_MAX)) {
+               return (AE_NUMERIC_OVERFLOW);
+       }
+
+       *out_sum = sum;
+       return (AE_OK);
+}
index 9633ee142855b879feea438f62b6c80ad32b18c1..e2067dcb93893cde975502c952991fca76115266 100644 (file)
@@ -1,6 +1,7 @@
 /*******************************************************************************
  *
- * Module Name: utstrtoul64 - string to 64-bit integer support
+ * Module Name: utstrtoul64 - String-to-integer conversion support for both
+ *                            64-bit and 32-bit integers
  *
  ******************************************************************************/
 
 #include <acpi/acpi.h>
 #include "accommon.h"
 
-/*******************************************************************************
- *
- * The functions in this module satisfy the need for 64-bit string-to-integer
- * conversions on both 32-bit and 64-bit platforms.
- *
- ******************************************************************************/
-
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utstrtoul64")
 
-/* Local prototypes */
-static u64 acpi_ut_strtoul_base10(char *string, u32 flags);
-
-static u64 acpi_ut_strtoul_base16(char *string, u32 flags);
-
 /*******************************************************************************
  *
- * String conversion rules as written in the ACPI specification. The error
- * conditions and behavior are different depending on the type of conversion.
- *
- *
- * Implicit data type conversion: string-to-integer
- * --------------------------------------------------
- *
- * Base is always 16. This is the ACPI_STRTOUL_BASE16 case.
- *
- * Example:
- *      Add ("BA98", Arg0, Local0)
- *
- * The integer is initialized to the value zero.
- * The ASCII string is interpreted as a hexadecimal constant.
+ * This module contains the top-level string to 64/32-bit unsigned integer
+ * conversion functions:
  *
- *  1)  A "0x" prefix is not allowed. However, ACPICA allows this for
- *      compatibility with previous ACPICA. (NO ERROR)
+ *  1) A standard strtoul() function that supports 64-bit integers, base
+ *     8/10/16, with integer overflow support. This is used mainly by the
+ *     iASL compiler, which implements tighter constraints on integer
+ *     constants than the runtime (interpreter) integer-to-string conversions.
+ *  2) Runtime "Explicit conversion" as defined in the ACPI specification.
+ *  3) Runtime "Implicit conversion" as defined in the ACPI specification.
  *
- *  2)  Terminates when the size of an integer is reached (32 or 64 bits).
- *      (NO ERROR)
+ * Current users of this module:
  *
- *  3)  The first non-hex character terminates the conversion without error.
- *      (NO ERROR)
- *
- *  4)  Conversion of a null (zero-length) string to an integer is not
- *      allowed. However, ACPICA allows this for compatibility with previous
- *      ACPICA. This conversion returns the value 0. (NO ERROR)
- *
- *
- * Explicit data type conversion:  to_integer() with string operand
- * ---------------------------------------------------------------
- *
- * Base is either 10 (default) or 16 (with 0x prefix)
- *
- * Examples:
- *      to_integer ("1000")
- *      to_integer ("0xABCD")
- *
- *  1)  Can be (must be) either a decimal or hexadecimal numeric string.
- *      A hex value must be prefixed by "0x" or it is interpreted as a decimal.
+ *  iASL        - Preprocessor (constants and math expressions)
+ *  iASL        - Main parser, conversion of constants to integers
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
+ *  interpreter - Implicit and explicit conversions, GPE method names
+ *  interpreter - Repair code for return values from predefined names
+ *  debugger    - Command line input string conversion
+ *  acpi_dump   - ACPI table physical addresses
+ *  acpi_exec   - Support for namespace overrides
  *
- *  2)  The value must not exceed the maximum of an integer value. ACPI spec
- *      states the behavior is "unpredictable", so ACPICA matches the behavior
- *      of the implicit conversion case.(NO ERROR)
+ * Notes concerning users of these interfaces:
  *
- *  3)  Behavior on the first non-hex character is not specified by the ACPI
- *      spec, so ACPICA matches the behavior of the implicit conversion case
- *      and terminates. (NO ERROR)
+ * acpi_gbl_integer_byte_width is used to set the 32/64 bit limit for explicit
+ * and implicit conversions. This global must be set to the proper width.
+ * For the core ACPICA code, the width depends on the DSDT version. For the
+ * acpi_ut_strtoul64 interface, all conversions are 64 bits. This interface is
+ * used primarily for iASL, where the default width is 64 bits for all parsers,
+ * but error checking is performed later to flag cases where a 64-bit constant
+ * is wrongly defined in a 32-bit DSDT/SSDT.
  *
- *  4)  A null (zero-length) string is illegal.
- *      However, ACPICA allows this for compatibility with previous ACPICA.
- *      This conversion returns the value 0. (NO ERROR)
+ * In ACPI, the only place where octal numbers are supported is within
+ * the ASL language itself. This is implemented via the main acpi_ut_strtoul64
+ * interface. According the ACPI specification, there is no ACPI runtime
+ * support (explicit/implicit) for octal string conversions.
  *
  ******************************************************************************/
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_strtoul64
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - Conversion info, see below
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
  *              return_value            - Where the converted integer is
- *                                        returned
- *
- * RETURN:      Status and Converted value
+ *                                        returned. Must be a valid pointer
  *
- * DESCRIPTION: Convert a string into an unsigned value. Performs either a
- *              32-bit or 64-bit conversion, depending on the input integer
- *              size in Flags (often the current mode of the interpreter).
+ * RETURN:      Status and converted integer. Returns an exception on a
+ *              64-bit numeric overflow
  *
- * Values for Flags:
- *      ACPI_STRTOUL_32BIT      - Max integer value is 32 bits
- *      ACPI_STRTOUL_64BIT      - Max integer value is 64 bits
- *      ACPI_STRTOUL_BASE16     - Input string is hexadecimal. Default
- *                                is 10/16 based on string prefix (0x).
+ * DESCRIPTION: Convert a string into an unsigned integer. Always performs a
+ *              full 64-bit conversion, regardless of the current global
+ *              integer width. Supports Decimal, Hex, and Octal strings.
  *
- * NOTES:
- *   Negative numbers are not supported, as they are not supported by ACPI.
+ * Current users of this function:
  *
- *   Supports only base 16 or base 10 strings/values. Does not
- *   support Octal strings, as these are not supported by ACPI.
- *
- * Current users of this support:
- *
- *  interpreter - Implicit and explicit conversions, GPE method names
- *  debugger    - Command line input string conversion
- *  iASL        - Main parser, conversion of constants to integers
- *  iASL        - Data Table Compiler parser (constant math expressions)
- *  iASL        - Preprocessor (constant math expressions)
- *  acpi_dump   - Input table addresses
- *  acpi_exec   - Testing of the acpi_ut_strtoul64 function
- *
- * Note concerning callers:
- *   acpi_gbl_integer_byte_width can be used to set the 32/64 limit. If used,
- *   this global should be set to the proper width. For the core ACPICA code,
- *   this width depends on the DSDT version. For iASL, the default byte
- *   width is always 8 for the parser, but error checking is performed later
- *   to flag cases where a 64-bit constant is defined in a 32-bit DSDT/SSDT.
+ *  iASL        - Preprocessor (constants and math expressions)
+ *  iASL        - Main ASL parser, conversion of ASL constants to integers
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
+ *  interpreter - Repair code for return values from predefined names
+ *  acpi_dump   - ACPI table physical addresses
+ *  acpi_exec   - Support for namespace overrides
  *
  ******************************************************************************/
-
-acpi_status acpi_ut_strtoul64(char *string, u32 flags, u64 *return_value)
+acpi_status acpi_ut_strtoul64(char *string, u64 *return_value)
 {
        acpi_status status = AE_OK;
-       u32 base;
+       u8 original_bit_width;
+       u32 base = 10;          /* Default is decimal */
 
        ACPI_FUNCTION_TRACE_STR(ut_strtoul64, string);
 
-       /* Parameter validation */
-
-       if (!string || !return_value) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        *return_value = 0;
 
-       /* Check for zero-length string, returns 0 */
+       /* A NULL return string returns a value of zero */
 
        if (*string == 0) {
                return_ACPI_STATUS(AE_OK);
        }
 
-       /* Skip over any white space at start of string */
-
-       while (isspace((int)*string)) {
-               string++;
-       }
-
-       /* End of string? return 0 */
-
-       if (*string == 0) {
+       if (!acpi_ut_remove_whitespace(&string)) {
                return_ACPI_STATUS(AE_OK);
        }
 
        /*
-        * 1) The "0x" prefix indicates base 16. Per the ACPI specification,
-        * the "0x" prefix is only allowed for implicit (non-strict) conversions.
-        * However, we always allow it for compatibility with older ACPICA.
+        * 1) Check for a hex constant. A "0x" prefix indicates base 16.
         */
-       if ((*string == ACPI_ASCII_ZERO) &&
-           (tolower((int)*(string + 1)) == 'x')) {
-               string += 2;    /* Go past the 0x */
-               if (*string == 0) {
-                       return_ACPI_STATUS(AE_OK);      /* Return value 0 */
-               }
-
+       if (acpi_ut_detect_hex_prefix(&string)) {
                base = 16;
        }
 
-       /* 2) Force to base 16 (implicit conversion case) */
-
-       else if (flags & ACPI_STRTOUL_BASE16) {
-               base = 16;
+       /*
+        * 2) Check for an octal constant, defined to be a leading zero
+        * followed by sequence of octal digits (0-7)
+        */
+       else if (acpi_ut_detect_octal_prefix(&string)) {
+               base = 8;
        }
 
-       /* 3) Default fallback is to Base 10 */
-
-       else {
-               base = 10;
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_ACPI_STATUS(AE_OK);      /* Return value 0 */
        }
 
-       /* Skip all leading zeros */
+       /*
+        * Force a full 64-bit conversion. The caller (usually iASL) must
+        * check for a 32-bit overflow later as necessary (If current mode
+        * is 32-bit, meaning a 32-bit DSDT).
+        */
+       original_bit_width = acpi_gbl_integer_bit_width;
+       acpi_gbl_integer_bit_width = 64;
 
-       while (*string == ACPI_ASCII_ZERO) {
-               string++;
-               if (*string == 0) {
-                       return_ACPI_STATUS(AE_OK);      /* Return value 0 */
-               }
+       /*
+        * Perform the base 8, 10, or 16 conversion. A 64-bit numeric overflow
+        * will return an exception (to allow iASL to flag the statement).
+        */
+       switch (base) {
+       case 8:
+               status = acpi_ut_convert_octal_string(string, return_value);
+               break;
+
+       case 10:
+               status = acpi_ut_convert_decimal_string(string, return_value);
+               break;
+
+       case 16:
+       default:
+               status = acpi_ut_convert_hex_string(string, return_value);
+               break;
        }
 
-       /* Perform the base 16 or 10 conversion */
-
-       if (base == 16) {
-               *return_value = acpi_ut_strtoul_base16(string, flags);
-       } else {
-               *return_value = acpi_ut_strtoul_base10(string, flags);
-       }
+       /* Only possible exception from above is a 64-bit overflow */
 
+       acpi_gbl_integer_bit_width = original_bit_width;
        return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_strtoul_base10
+ * FUNCTION:    acpi_ut_implicit_strtoul64
+ *
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
+ *
+ * RETURN:      Converted integer
+ *
+ * DESCRIPTION: Perform a 64-bit conversion with restrictions placed upon
+ *              an "implicit conversion" by the ACPI specification. Used by
+ *              many ASL operators that require an integer operand, and support
+ *              an automatic (implicit) conversion from a string operand
+ *              to the final integer operand. The major restriction is that
+ *              only hex strings are supported.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Base is always 16, either with or without the 0x prefix. Decimal and
+ * Octal strings are not supported, as per the ACPI specification.
+ *
+ * Examples (both are hex values):
+ *      Add ("BA98", Arg0, Local0)
+ *      Subtract ("0x12345678", Arg1, Local1)
+ *
+ * Conversion rules as extracted from the ACPI specification:
+ *
+ *  The converted integer is initialized to the value zero.
+ *  The ASCII string is always interpreted as a hexadecimal constant.
+ *
+ *  1)  According to the ACPI specification, a "0x" prefix is not allowed.
+ *      However, ACPICA allows this as an ACPI extension on general
+ *      principle. (NO ERROR)
+ *
+ *  2)  The conversion terminates when the size of an integer is reached
+ *      (32 or 64 bits). There are no numeric overflow conditions. (NO ERROR)
+ *
+ *  3)  The first non-hex character terminates the conversion and returns
+ *      the current accumulated value of the converted integer (NO ERROR).
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - Conversion info
+ *  4)  Conversion of a null (zero-length) string to an integer is
+ *      technically not allowed. However, ACPICA allows this as an ACPI
+ *      extension. The conversion returns the value 0. (NO ERROR)
  *
- * RETURN:      64-bit converted integer
+ * NOTE: There are no error conditions returned by this function. At
+ * the minimum, a value of zero is returned.
  *
- * DESCRIPTION: Performs a base 10 conversion of the input string to an
- *              integer value, either 32 or 64 bits.
- *              Note: String must be valid and non-null.
+ * Current users of this function:
+ *
+ *  interpreter - All runtime implicit conversions, as per ACPI specification
+ *  iASL        - Data Table Compiler parser (constants and math expressions)
  *
  ******************************************************************************/
 
-static u64 acpi_ut_strtoul_base10(char *string, u32 flags)
+u64 acpi_ut_implicit_strtoul64(char *string)
 {
-       int ascii_digit;
-       u64 next_value;
-       u64 return_value = 0;
-
-       /* Main loop: convert each ASCII byte in the input string */
-
-       while (*string) {
-               ascii_digit = *string;
-               if (!isdigit(ascii_digit)) {
-
-                       /* Not ASCII 0-9, terminate */
-
-                       goto exit;
-               }
-
-               /* Convert and insert (add) the decimal digit */
+       u64 converted_integer = 0;
 
-               acpi_ut_short_multiply(return_value, 10, &next_value);
-               next_value += (ascii_digit - ACPI_ASCII_ZERO);
+       ACPI_FUNCTION_TRACE_STR(ut_implicit_strtoul64, string);
 
-               /* Check for overflow (32 or 64 bit) - return current converted value */
+       if (!acpi_ut_remove_whitespace(&string)) {
+               return_VALUE(0);
+       }
 
-               if (((flags & ACPI_STRTOUL_32BIT) && (next_value > ACPI_UINT32_MAX)) || (next_value < return_value)) {  /* 64-bit overflow case */
-                       goto exit;
-               }
+       /*
+        * Per the ACPI specification, only hexadecimal is supported for
+        * implicit conversions, and the "0x" prefix is "not allowed".
+        * However, allow a "0x" prefix as an ACPI extension.
+        */
+       acpi_ut_detect_hex_prefix(&string);
 
-               return_value = next_value;
-               string++;
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_VALUE(0);
        }
 
-exit:
-       return (return_value);
+       /*
+        * Ignore overflow as per the ACPI specification. This is implemented by
+        * ignoring the return status from the conversion function called below.
+        * On overflow, the input string is simply truncated.
+        */
+       acpi_ut_convert_hex_string(string, &converted_integer);
+       return_VALUE(converted_integer);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_strtoul_base16
+ * FUNCTION:    acpi_ut_explicit_strtoul64
+ *
+ * PARAMETERS:  string                  - Null terminated input string,
+ *                                        must be a valid pointer
  *
- * PARAMETERS:  string                  - Null terminated input string
- *              flags                   - conversion info
+ * RETURN:      Converted integer
  *
- * RETURN:      64-bit converted integer
+ * DESCRIPTION: Perform a 64-bit conversion with the restrictions placed upon
+ *              an "explicit conversion" by the ACPI specification. The
+ *              main restriction is that only hex and decimal are supported.
  *
- * DESCRIPTION: Performs a base 16 conversion of the input string to an
- *              integer value, either 32 or 64 bits.
- *              Note: String must be valid and non-null.
+ * -----------------------------------------------------------------------------
+ *
+ * Base is either 10 (default) or 16 (with 0x prefix). Octal (base 8) strings
+ * are not supported, as per the ACPI specification.
+ *
+ * Examples:
+ *      to_integer ("1000")     Decimal
+ *      to_integer ("0xABCD")   Hex
+ *
+ * Conversion rules as extracted from the ACPI specification:
+ *
+ *  1)  The input string is either a decimal or hexadecimal numeric string.
+ *      A hex value must be prefixed by "0x" or it is interpreted as decimal.
+ *
+ *  2)  The value must not exceed the maximum of an integer value
+ *      (32 or 64 bits). The ACPI specification states the behavior is
+ *      "unpredictable", so ACPICA matches the behavior of the implicit
+ *      conversion case. There are no numeric overflow conditions. (NO ERROR)
+ *
+ *  3)  Behavior on the first non-hex character is not defined by the ACPI
+ *      specification (for the to_integer operator), so ACPICA matches the
+ *      behavior of the implicit conversion case. It terminates the
+ *      conversion and returns the current accumulated value of the converted
+ *      integer. (NO ERROR)
+ *
+ *  4)  Conversion of a null (zero-length) string to an integer is
+ *      technically not allowed. However, ACPICA allows this as an ACPI
+ *      extension. The conversion returns the value 0. (NO ERROR)
+ *
+ * NOTE: There are no error conditions returned by this function. At the
+ * minimum, a value of zero is returned.
+ *
+ * Current users of this function:
+ *
+ *  interpreter - Runtime ASL to_integer operator, as per the ACPI specification
  *
  ******************************************************************************/
 
-static u64 acpi_ut_strtoul_base16(char *string, u32 flags)
+u64 acpi_ut_explicit_strtoul64(char *string)
 {
-       int ascii_digit;
-       u32 valid_digits = 1;
-       u64 return_value = 0;
-
-       /* Main loop: convert each ASCII byte in the input string */
+       u64 converted_integer = 0;
+       u32 base = 10;          /* Default is decimal */
 
-       while (*string) {
+       ACPI_FUNCTION_TRACE_STR(ut_explicit_strtoul64, string);
 
-               /* Check for overflow (32 or 64 bit) - return current converted value */
-
-               if ((valid_digits > 16) ||
-                   ((valid_digits > 8) && (flags & ACPI_STRTOUL_32BIT))) {
-                       goto exit;
-               }
-
-               ascii_digit = *string;
-               if (!isxdigit(ascii_digit)) {
-
-                       /* Not Hex ASCII A-F, a-f, or 0-9, terminate */
-
-                       goto exit;
-               }
+       if (!acpi_ut_remove_whitespace(&string)) {
+               return_VALUE(0);
+       }
 
-               /* Convert and insert the hex digit */
+       /*
+        * Only Hex and Decimal are supported, as per the ACPI specification.
+        * A "0x" prefix indicates hex; otherwise decimal is assumed.
+        */
+       if (acpi_ut_detect_hex_prefix(&string)) {
+               base = 16;
+       }
 
-               acpi_ut_short_shift_left(return_value, 4, &return_value);
-               return_value |= acpi_ut_ascii_char_to_hex(ascii_digit);
+       if (!acpi_ut_remove_leading_zeros(&string)) {
+               return_VALUE(0);
+       }
 
-               string++;
-               valid_digits++;
+       /*
+        * Ignore overflow as per the ACPI specification. This is implemented by
+        * ignoring the return status from the conversion functions called below.
+        * On overflow, the input string is simply truncated.
+        */
+       switch (base) {
+       case 10:
+       default:
+               acpi_ut_convert_decimal_string(string, &converted_integer);
+               break;
+
+       case 16:
+               acpi_ut_convert_hex_string(string, &converted_integer);
+               break;
        }
 
-exit:
-       return (return_value);
+       return_VALUE(converted_integer);
 }
index 2c462beee5513ec40448f6faf0179e621644558f..6742f6c68034c5e833505d294902dd97c274c1b0 100644 (file)
@@ -1061,7 +1061,7 @@ static int erst_writer(struct pstore_record *record)
        rcd->hdr.error_severity = CPER_SEV_FATAL;
        /* timestamp valid. platform_id, partition_id are invalid */
        rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
-       rcd->hdr.timestamp = get_seconds();
+       rcd->hdr.timestamp = ktime_get_real_seconds();
        rcd->hdr.record_length = sizeof(*rcd) + record->size;
        rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
        rcd->hdr.notification_type = CPER_NOTIFY_MCE;
index ebaa51ba8a225ef14108854bfe21d151293c2269..6402f7fad3bb3bf1cfb28384a4d843f0bd0b5bc8 100644 (file)
@@ -51,6 +51,7 @@
 #include <acpi/actbl1.h>
 #include <acpi/ghes.h>
 #include <acpi/apei.h>
+#include <asm/fixmap.h>
 #include <asm/tlbflush.h>
 #include <ras/ras_event.h>
 
@@ -112,22 +113,10 @@ static DEFINE_MUTEX(ghes_list_mutex);
  * Because the memory area used to transfer hardware error information
  * from BIOS to Linux can be determined only in NMI, IRQ or timer
  * handler, but general ioremap can not be used in atomic context, so
- * a special version of atomic ioremap is implemented for that.
- */
-
-/*
- * Two virtual pages are used, one for IRQ/PROCESS context, the other for
- * NMI context (optionally).
- */
-#define GHES_IOREMAP_PAGES           2
-#define GHES_IOREMAP_IRQ_PAGE(base)    (base)
-#define GHES_IOREMAP_NMI_PAGE(base)    ((base) + PAGE_SIZE)
-
-/* virtual memory area for atomic ioremap */
-static struct vm_struct *ghes_ioremap_area;
-/*
- * These 2 spinlock is used to prevent atomic ioremap virtual memory
- * area from being mapped simultaneously.
+ * the fixmap is used instead.
+ *
+ * These 2 spinlocks are used to prevent the fixmap entries from being used
+ * simultaneously.
  */
 static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
 static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
@@ -140,71 +129,38 @@ static atomic_t ghes_estatus_cache_alloced;
 
 static int ghes_panic_timeout __read_mostly = 30;
 
-static int ghes_ioremap_init(void)
-{
-       ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
-               VM_IOREMAP, VMALLOC_START, VMALLOC_END);
-       if (!ghes_ioremap_area) {
-               pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void ghes_ioremap_exit(void)
-{
-       free_vm_area(ghes_ioremap_area);
-}
-
 static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
 {
-       unsigned long vaddr;
        phys_addr_t paddr;
        pgprot_t prot;
 
-       vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
-
        paddr = pfn << PAGE_SHIFT;
        prot = arch_apei_get_mem_attribute(paddr);
-       ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
+       __set_fixmap(FIX_APEI_GHES_NMI, paddr, prot);
 
-       return (void __iomem *)vaddr;
+       return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI);
 }
 
 static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
 {
-       unsigned long vaddr, paddr;
+       phys_addr_t paddr;
        pgprot_t prot;
 
-       vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
-
        paddr = pfn << PAGE_SHIFT;
        prot = arch_apei_get_mem_attribute(paddr);
+       __set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot);
 
-       ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
-
-       return (void __iomem *)vaddr;
+       return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ);
 }
 
-static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
+static void ghes_iounmap_nmi(void)
 {
-       unsigned long vaddr = (unsigned long __force)vaddr_ptr;
-       void *base = ghes_ioremap_area->addr;
-
-       BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
-       unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
-       arch_apei_flush_tlb_one(vaddr);
+       clear_fixmap(FIX_APEI_GHES_NMI);
 }
 
-static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
+static void ghes_iounmap_irq(void)
 {
-       unsigned long vaddr = (unsigned long __force)vaddr_ptr;
-       void *base = ghes_ioremap_area->addr;
-
-       BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
-       unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
-       arch_apei_flush_tlb_one(vaddr);
+       clear_fixmap(FIX_APEI_GHES_IRQ);
 }
 
 static int ghes_estatus_pool_init(void)
@@ -360,10 +316,10 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
                paddr += trunk;
                buffer += trunk;
                if (in_nmi) {
-                       ghes_iounmap_nmi(vaddr);
+                       ghes_iounmap_nmi();
                        raw_spin_unlock(&ghes_ioremap_lock_nmi);
                } else {
-                       ghes_iounmap_irq(vaddr);
+                       ghes_iounmap_irq();
                        spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
                }
        }
@@ -851,17 +807,8 @@ static void ghes_sea_remove(struct ghes *ghes)
        synchronize_rcu();
 }
 #else /* CONFIG_ACPI_APEI_SEA */
-static inline void ghes_sea_add(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
-              ghes->generic->header.source_id);
-}
-
-static inline void ghes_sea_remove(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
-              ghes->generic->header.source_id);
-}
+static inline void ghes_sea_add(struct ghes *ghes) { }
+static inline void ghes_sea_remove(struct ghes *ghes) { }
 #endif /* CONFIG_ACPI_APEI_SEA */
 
 #ifdef CONFIG_HAVE_ACPI_APEI_NMI
@@ -1063,23 +1010,9 @@ static void ghes_nmi_init_cxt(void)
        init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
 }
 #else /* CONFIG_HAVE_ACPI_APEI_NMI */
-static inline void ghes_nmi_add(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to add NMI notification which is not supported!\n",
-              ghes->generic->header.source_id);
-       BUG();
-}
-
-static inline void ghes_nmi_remove(struct ghes *ghes)
-{
-       pr_err(GHES_PFX "ID: %d, trying to remove NMI notification which is not supported!\n",
-              ghes->generic->header.source_id);
-       BUG();
-}
-
-static inline void ghes_nmi_init_cxt(void)
-{
-}
+static inline void ghes_nmi_add(struct ghes *ghes) { }
+static inline void ghes_nmi_remove(struct ghes *ghes) { }
+static inline void ghes_nmi_init_cxt(void) { }
 #endif /* CONFIG_HAVE_ACPI_APEI_NMI */
 
 static int ghes_probe(struct platform_device *ghes_dev)
@@ -1284,13 +1217,9 @@ static int __init ghes_init(void)
 
        ghes_nmi_init_cxt();
 
-       rc = ghes_ioremap_init();
-       if (rc)
-               goto err;
-
        rc = ghes_estatus_pool_init();
        if (rc)
-               goto err_ioremap_exit;
+               goto err;
 
        rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE *
                                      GHES_ESTATUS_CACHE_ALLOCED_MAX);
@@ -1314,8 +1243,6 @@ static int __init ghes_init(void)
        return 0;
 err_pool_exit:
        ghes_estatus_pool_exit();
-err_ioremap_exit:
-       ghes_ioremap_exit();
 err:
        return rc;
 }
index ef1856b15488be10cf81f8abfa20c630f461768d..c391898b483c84067aadc35f8f36fd932d674fb9 100644 (file)
@@ -390,6 +390,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
 {
        struct acpi_button *button = acpi_driver_data(device);
        struct input_dev *input;
+       int users;
 
        switch (event) {
        case ACPI_FIXED_HARDWARE_EVENT:
@@ -398,7 +399,11 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
        case ACPI_BUTTON_NOTIFY_STATUS:
                input = button->input;
                if (button->type == ACPI_BUTTON_TYPE_LID) {
-                       acpi_lid_update_state(device);
+                       mutex_lock(&button->input->mutex);
+                       users = button->input->users;
+                       mutex_unlock(&button->input->mutex);
+                       if (users)
+                               acpi_lid_update_state(device);
                } else {
                        int keycode;
 
@@ -442,12 +447,24 @@ static int acpi_button_resume(struct device *dev)
        struct acpi_button *button = acpi_driver_data(device);
 
        button->suspended = false;
-       if (button->type == ACPI_BUTTON_TYPE_LID)
+       if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users)
                acpi_lid_initialize_state(device);
        return 0;
 }
 #endif
 
+static int acpi_lid_input_open(struct input_dev *input)
+{
+       struct acpi_device *device = input_get_drvdata(input);
+       struct acpi_button *button = acpi_driver_data(device);
+
+       button->last_state = !!acpi_lid_evaluate_state(device);
+       button->last_time = ktime_get();
+       acpi_lid_initialize_state(device);
+
+       return 0;
+}
+
 static int acpi_button_add(struct acpi_device *device)
 {
        struct acpi_button *button;
@@ -488,8 +505,7 @@ static int acpi_button_add(struct acpi_device *device)
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
-               button->last_state = !!acpi_lid_evaluate_state(device);
-               button->last_time = ktime_get();
+               input->open = acpi_lid_input_open;
        } else {
                printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
                error = -ENODEV;
@@ -522,11 +538,11 @@ static int acpi_button_add(struct acpi_device *device)
                break;
        }
 
+       input_set_drvdata(input, device);
        error = input_register_device(input);
        if (error)
                goto err_remove_fs;
        if (button->type == ACPI_BUTTON_TYPE_LID) {
-               acpi_lid_initialize_state(device);
                /*
                 * This assumes there's only one lid device, or if there are
                 * more we only care about the last one...
index e5b47f032d9af552a04dc9aee301a8160f942997..21c28433c590a4aec323bdcea19a0e1426c751e4 100644 (file)
@@ -48,7 +48,6 @@
 struct cppc_pcc_data {
        struct mbox_chan *pcc_channel;
        void __iomem *pcc_comm_addr;
-       int pcc_subspace_idx;
        bool pcc_channel_acquired;
        ktime_t deadline;
        unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
@@ -75,13 +74,16 @@ struct cppc_pcc_data {
 
        /* Wait queue for CPUs whose requests were batched */
        wait_queue_head_t pcc_write_wait_q;
+       ktime_t last_cmd_cmpl_time;
+       ktime_t last_mpar_reset;
+       int mpar_count;
+       int refcount;
 };
 
-/* Structure to represent the single PCC channel */
-static struct cppc_pcc_data pcc_data = {
-       .pcc_subspace_idx = -1,
-       .platform_owns_pcc = true,
-};
+/* Array  to represent the PCC channel per subspace id */
+static struct cppc_pcc_data *pcc_data[MAX_PCC_SUBSPACES];
+/* The cpu_pcc_subspace_idx containsper CPU subspace id */
+static DEFINE_PER_CPU(int, cpu_pcc_subspace_idx);
 
 /*
  * The cpc_desc structure contains the ACPI register details
@@ -93,7 +95,8 @@ static struct cppc_pcc_data pcc_data = {
 static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
 
 /* pcc mapped address + header size + offset within PCC subspace */
-#define GET_PCC_VADDR(offs) (pcc_data.pcc_comm_addr + 0x8 + (offs))
+#define GET_PCC_VADDR(offs, pcc_ss_id) (pcc_data[pcc_ss_id]->pcc_comm_addr + \
+                                               0x8 + (offs))
 
 /* Check if a CPC register is in PCC */
 #define CPC_IN_PCC(cpc) ((cpc)->type == ACPI_TYPE_BUFFER &&            \
@@ -188,13 +191,16 @@ static struct kobj_type cppc_ktype = {
        .default_attrs = cppc_attrs,
 };
 
-static int check_pcc_chan(bool chk_err_bit)
+static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
 {
        int ret = -EIO, status = 0;
-       struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_data.pcc_comm_addr;
-       ktime_t next_deadline = ktime_add(ktime_get(), pcc_data.deadline);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
+       struct acpi_pcct_shared_memory __iomem *generic_comm_base =
+               pcc_ss_data->pcc_comm_addr;
+       ktime_t next_deadline = ktime_add(ktime_get(),
+                                         pcc_ss_data->deadline);
 
-       if (!pcc_data.platform_owns_pcc)
+       if (!pcc_ss_data->platform_owns_pcc)
                return 0;
 
        /* Retry in case the remote processor was too slow to catch up. */
@@ -219,7 +225,7 @@ static int check_pcc_chan(bool chk_err_bit)
        }
 
        if (likely(!ret))
-               pcc_data.platform_owns_pcc = false;
+               pcc_ss_data->platform_owns_pcc = false;
        else
                pr_err("PCC check channel failed. Status=%x\n", status);
 
@@ -230,13 +236,12 @@ static int check_pcc_chan(bool chk_err_bit)
  * This function transfers the ownership of the PCC to the platform
  * So it must be called while holding write_lock(pcc_lock)
  */
-static int send_pcc_cmd(u16 cmd)
+static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
 {
        int ret = -EIO, i;
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        struct acpi_pcct_shared_memory *generic_comm_base =
-               (struct acpi_pcct_shared_memory *) pcc_data.pcc_comm_addr;
-       static ktime_t last_cmd_cmpl_time, last_mpar_reset;
-       static int mpar_count;
+               (struct acpi_pcct_shared_memory *)pcc_ss_data->pcc_comm_addr;
        unsigned int time_delta;
 
        /*
@@ -249,24 +254,25 @@ static int send_pcc_cmd(u16 cmd)
                 * before write completion, so first send a WRITE command to
                 * platform
                 */
-               if (pcc_data.pending_pcc_write_cmd)
-                       send_pcc_cmd(CMD_WRITE);
+               if (pcc_ss_data->pending_pcc_write_cmd)
+                       send_pcc_cmd(pcc_ss_id, CMD_WRITE);
 
-               ret = check_pcc_chan(false);
+               ret = check_pcc_chan(pcc_ss_id, false);
                if (ret)
                        goto end;
        } else /* CMD_WRITE */
-               pcc_data.pending_pcc_write_cmd = FALSE;
+               pcc_ss_data->pending_pcc_write_cmd = FALSE;
 
        /*
         * Handle the Minimum Request Turnaround Time(MRTT)
         * "The minimum amount of time that OSPM must wait after the completion
         * of a command before issuing the next command, in microseconds"
         */
-       if (pcc_data.pcc_mrtt) {
-               time_delta = ktime_us_delta(ktime_get(), last_cmd_cmpl_time);
-               if (pcc_data.pcc_mrtt > time_delta)
-                       udelay(pcc_data.pcc_mrtt - time_delta);
+       if (pcc_ss_data->pcc_mrtt) {
+               time_delta = ktime_us_delta(ktime_get(),
+                                           pcc_ss_data->last_cmd_cmpl_time);
+               if (pcc_ss_data->pcc_mrtt > time_delta)
+                       udelay(pcc_ss_data->pcc_mrtt - time_delta);
        }
 
        /*
@@ -280,18 +286,19 @@ static int send_pcc_cmd(u16 cmd)
         * not send the request to the platform after hitting the MPAR limit in
         * any 60s window
         */
-       if (pcc_data.pcc_mpar) {
-               if (mpar_count == 0) {
-                       time_delta = ktime_ms_delta(ktime_get(), last_mpar_reset);
-                       if (time_delta < 60 * MSEC_PER_SEC) {
+       if (pcc_ss_data->pcc_mpar) {
+               if (pcc_ss_data->mpar_count == 0) {
+                       time_delta = ktime_ms_delta(ktime_get(),
+                                                   pcc_ss_data->last_mpar_reset);
+                       if ((time_delta < 60 * MSEC_PER_SEC) && pcc_ss_data->last_mpar_reset) {
                                pr_debug("PCC cmd not sent due to MPAR limit");
                                ret = -EIO;
                                goto end;
                        }
-                       last_mpar_reset = ktime_get();
-                       mpar_count = pcc_data.pcc_mpar;
+                       pcc_ss_data->last_mpar_reset = ktime_get();
+                       pcc_ss_data->mpar_count = pcc_ss_data->pcc_mpar;
                }
-               mpar_count--;
+               pcc_ss_data->mpar_count--;
        }
 
        /* Write to the shared comm region. */
@@ -300,10 +307,10 @@ static int send_pcc_cmd(u16 cmd)
        /* Flip CMD COMPLETE bit */
        writew_relaxed(0, &generic_comm_base->status);
 
-       pcc_data.platform_owns_pcc = true;
+       pcc_ss_data->platform_owns_pcc = true;
 
        /* Ring doorbell */
-       ret = mbox_send_message(pcc_data.pcc_channel, &cmd);
+       ret = mbox_send_message(pcc_ss_data->pcc_channel, &cmd);
        if (ret < 0) {
                pr_err("Err sending PCC mbox message. cmd:%d, ret:%d\n",
                                cmd, ret);
@@ -311,15 +318,15 @@ static int send_pcc_cmd(u16 cmd)
        }
 
        /* wait for completion and check for PCC errro bit */
-       ret = check_pcc_chan(true);
+       ret = check_pcc_chan(pcc_ss_id, true);
 
-       if (pcc_data.pcc_mrtt)
-               last_cmd_cmpl_time = ktime_get();
+       if (pcc_ss_data->pcc_mrtt)
+               pcc_ss_data->last_cmd_cmpl_time = ktime_get();
 
-       if (pcc_data.pcc_channel->mbox->txdone_irq)
-               mbox_chan_txdone(pcc_data.pcc_channel, ret);
+       if (pcc_ss_data->pcc_channel->mbox->txdone_irq)
+               mbox_chan_txdone(pcc_ss_data->pcc_channel, ret);
        else
-               mbox_client_txdone(pcc_data.pcc_channel, ret);
+               mbox_client_txdone(pcc_ss_data->pcc_channel, ret);
 
 end:
        if (cmd == CMD_WRITE) {
@@ -329,12 +336,12 @@ end:
                                if (!desc)
                                        continue;
 
-                               if (desc->write_cmd_id == pcc_data.pcc_write_cnt)
+                               if (desc->write_cmd_id == pcc_ss_data->pcc_write_cnt)
                                        desc->write_cmd_status = ret;
                        }
                }
-               pcc_data.pcc_write_cnt++;
-               wake_up_all(&pcc_data.pcc_write_wait_q);
+               pcc_ss_data->pcc_write_cnt++;
+               wake_up_all(&pcc_ss_data->pcc_write_wait_q);
        }
 
        return ret;
@@ -536,16 +543,16 @@ err_ret:
 }
 EXPORT_SYMBOL_GPL(acpi_get_psd_map);
 
-static int register_pcc_channel(int pcc_subspace_idx)
+static int register_pcc_channel(int pcc_ss_idx)
 {
        struct acpi_pcct_hw_reduced *cppc_ss;
        u64 usecs_lat;
 
-       if (pcc_subspace_idx >= 0) {
-               pcc_data.pcc_channel = pcc_mbox_request_channel(&cppc_mbox_cl,
-                               pcc_subspace_idx);
+       if (pcc_ss_idx >= 0) {
+               pcc_data[pcc_ss_idx]->pcc_channel =
+                       pcc_mbox_request_channel(&cppc_mbox_cl, pcc_ss_idx);
 
-               if (IS_ERR(pcc_data.pcc_channel)) {
+               if (IS_ERR(pcc_data[pcc_ss_idx]->pcc_channel)) {
                        pr_err("Failed to find PCC communication channel\n");
                        return -ENODEV;
                }
@@ -556,7 +563,7 @@ static int register_pcc_channel(int pcc_subspace_idx)
                 * PCC channels) and stored pointers to the
                 * subspace communication region in con_priv.
                 */
-               cppc_ss = (pcc_data.pcc_channel)->con_priv;
+               cppc_ss = (pcc_data[pcc_ss_idx]->pcc_channel)->con_priv;
 
                if (!cppc_ss) {
                        pr_err("No PCC subspace found for CPPC\n");
@@ -569,19 +576,20 @@ static int register_pcc_channel(int pcc_subspace_idx)
                 * So add an arbitrary amount of wait on top of Nominal.
                 */
                usecs_lat = NUM_RETRIES * cppc_ss->latency;
-               pcc_data.deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
-               pcc_data.pcc_mrtt = cppc_ss->min_turnaround_time;
-               pcc_data.pcc_mpar = cppc_ss->max_access_rate;
-               pcc_data.pcc_nominal = cppc_ss->latency;
-
-               pcc_data.pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
-               if (!pcc_data.pcc_comm_addr) {
+               pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC);
+               pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time;
+               pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate;
+               pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency;
+
+               pcc_data[pcc_ss_idx]->pcc_comm_addr =
+                       acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
+               if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) {
                        pr_err("Failed to ioremap PCC comm region mem\n");
                        return -ENOMEM;
                }
 
                /* Set flag so that we dont come here for each CPU. */
-               pcc_data.pcc_channel_acquired = true;
+               pcc_data[pcc_ss_idx]->pcc_channel_acquired = true;
        }
 
        return 0;
@@ -600,6 +608,34 @@ bool __weak cpc_ffh_supported(void)
        return false;
 }
 
+
+/**
+ * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
+ *
+ * Check and allocate the cppc_pcc_data memory.
+ * In some processor configurations it is possible that same subspace
+ * is shared between multiple CPU's. This is seen especially in CPU's
+ * with hardware multi-threading support.
+ *
+ * Return: 0 for success, errno for failure
+ */
+int pcc_data_alloc(int pcc_ss_id)
+{
+       if (pcc_ss_id < 0 || pcc_ss_id >= MAX_PCC_SUBSPACES)
+               return -EINVAL;
+
+       if (pcc_data[pcc_ss_id]) {
+               pcc_data[pcc_ss_id]->refcount++;
+       } else {
+               pcc_data[pcc_ss_id] = kzalloc(sizeof(struct cppc_pcc_data),
+                                             GFP_KERNEL);
+               if (!pcc_data[pcc_ss_id])
+                       return -ENOMEM;
+               pcc_data[pcc_ss_id]->refcount++;
+       }
+
+       return 0;
+}
 /*
  * An example CPC table looks like the following.
  *
@@ -661,6 +697,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        struct device *cpu_dev;
        acpi_handle handle = pr->handle;
        unsigned int num_ent, i, cpc_rev;
+       int pcc_subspace_id = -1;
        acpi_status status;
        int ret = -EFAULT;
 
@@ -733,9 +770,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                         * so extract it only once.
                         */
                        if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) {
-                               if (pcc_data.pcc_subspace_idx < 0)
-                                       pcc_data.pcc_subspace_idx = gas_t->access_width;
-                               else if (pcc_data.pcc_subspace_idx != gas_t->access_width) {
+                               if (pcc_subspace_id < 0) {
+                                       pcc_subspace_id = gas_t->access_width;
+                                       if (pcc_data_alloc(pcc_subspace_id))
+                                               goto out_free;
+                               } else if (pcc_subspace_id != gas_t->access_width) {
                                        pr_debug("Mismatched PCC ids.\n");
                                        goto out_free;
                                }
@@ -763,6 +802,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                        goto out_free;
                }
        }
+       per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
        /* Store CPU Logical ID */
        cpc_ptr->cpu_id = pr->id;
 
@@ -771,14 +811,14 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        if (ret)
                goto out_free;
 
-       /* Register PCC channel once for all CPUs. */
-       if (!pcc_data.pcc_channel_acquired) {
-               ret = register_pcc_channel(pcc_data.pcc_subspace_idx);
+       /* Register PCC channel once for all PCC subspace id. */
+       if (pcc_subspace_id >= 0 && !pcc_data[pcc_subspace_id]->pcc_channel_acquired) {
+               ret = register_pcc_channel(pcc_subspace_id);
                if (ret)
                        goto out_free;
 
-               init_rwsem(&pcc_data.pcc_lock);
-               init_waitqueue_head(&pcc_data.pcc_write_wait_q);
+               init_rwsem(&pcc_data[pcc_subspace_id]->pcc_lock);
+               init_waitqueue_head(&pcc_data[pcc_subspace_id]->pcc_write_wait_q);
        }
 
        /* Everything looks okay */
@@ -831,6 +871,18 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
        struct cpc_desc *cpc_ptr;
        unsigned int i;
        void __iomem *addr;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, pr->id);
+
+       if (pcc_ss_id >=0 && pcc_data[pcc_ss_id]) {
+               if (pcc_data[pcc_ss_id]->pcc_channel_acquired) {
+                       pcc_data[pcc_ss_id]->refcount--;
+                       if (!pcc_data[pcc_ss_id]->refcount) {
+                               pcc_mbox_free_channel(pcc_data[pcc_ss_id]->pcc_channel);
+                               pcc_data[pcc_ss_id]->pcc_channel_acquired = 0;
+                               kfree(pcc_data[pcc_ss_id]);
+                       }
+               }
+       }
 
        cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
        if (!cpc_ptr)
@@ -888,6 +940,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
 {
        int ret_val = 0;
        void __iomem *vaddr = 0;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
        struct cpc_reg *reg = &reg_res->cpc_entry.reg;
 
        if (reg_res->type == ACPI_TYPE_INTEGER) {
@@ -897,7 +950,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
 
        *val = 0;
        if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
-               vaddr = GET_PCC_VADDR(reg->address);
+               vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
        else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
@@ -932,10 +985,11 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
 {
        int ret_val = 0;
        void __iomem *vaddr = 0;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
        struct cpc_reg *reg = &reg_res->cpc_entry.reg;
 
        if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
-               vaddr = GET_PCC_VADDR(reg->address);
+               vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id);
        else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                vaddr = reg_res->sys_mem_vaddr;
        else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
@@ -980,6 +1034,8 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
        struct cpc_register_resource *highest_reg, *lowest_reg,
                *lowest_non_linear_reg, *nominal_reg;
        u64 high, low, nom, min_nonlinear;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        int ret = 0, regs_in_pcc = 0;
 
        if (!cpc_desc) {
@@ -996,9 +1052,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
        if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
                CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) {
                regs_in_pcc = 1;
-               down_write(&pcc_data.pcc_lock);
+               down_write(&pcc_ss_data->pcc_lock);
                /* Ring doorbell once to update PCC subspace */
-               if (send_pcc_cmd(CMD_READ) < 0) {
+               if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
                        ret = -EIO;
                        goto out_err;
                }
@@ -1021,7 +1077,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
 
 out_err:
        if (regs_in_pcc)
-               up_write(&pcc_data.pcc_lock);
+               up_write(&pcc_ss_data->pcc_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
@@ -1038,6 +1094,8 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
        struct cpc_register_resource *delivered_reg, *reference_reg,
                *ref_perf_reg, *ctr_wrap_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        u64 delivered, reference, ref_perf, ctr_wrap_time;
        int ret = 0, regs_in_pcc = 0;
 
@@ -1061,10 +1119,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        /* Are any of the regs PCC ?*/
        if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) ||
                CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) {
-               down_write(&pcc_data.pcc_lock);
+               down_write(&pcc_ss_data->pcc_lock);
                regs_in_pcc = 1;
                /* Ring doorbell once to update PCC subspace */
-               if (send_pcc_cmd(CMD_READ) < 0) {
+               if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
                        ret = -EIO;
                        goto out_err;
                }
@@ -1094,7 +1152,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
        perf_fb_ctrs->wraparound_time = ctr_wrap_time;
 out_err:
        if (regs_in_pcc)
-               up_write(&pcc_data.pcc_lock);
+               up_write(&pcc_ss_data->pcc_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs);
@@ -1110,6 +1168,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 {
        struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
        struct cpc_register_resource *desired_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
        int ret = 0;
 
        if (!cpc_desc) {
@@ -1127,11 +1187,11 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
         * achieve that goal here
         */
        if (CPC_IN_PCC(desired_reg)) {
-               down_read(&pcc_data.pcc_lock);  /* BEGIN Phase-I */
-               if (pcc_data.platform_owns_pcc) {
-                       ret = check_pcc_chan(false);
+               down_read(&pcc_ss_data->pcc_lock); /* BEGIN Phase-I */
+               if (pcc_ss_data->platform_owns_pcc) {
+                       ret = check_pcc_chan(pcc_ss_id, false);
                        if (ret) {
-                               up_read(&pcc_data.pcc_lock);
+                               up_read(&pcc_ss_data->pcc_lock);
                                return ret;
                        }
                }
@@ -1139,8 +1199,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
                 * Update the pending_write to make sure a PCC CMD_READ will not
                 * arrive and steal the channel during the switch to write lock
                 */
-               pcc_data.pending_pcc_write_cmd = true;
-               cpc_desc->write_cmd_id = pcc_data.pcc_write_cnt;
+               pcc_ss_data->pending_pcc_write_cmd = true;
+               cpc_desc->write_cmd_id = pcc_ss_data->pcc_write_cnt;
                cpc_desc->write_cmd_status = 0;
        }
 
@@ -1151,7 +1211,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
        cpc_write(cpu, desired_reg, perf_ctrls->desired_perf);
 
        if (CPC_IN_PCC(desired_reg))
-               up_read(&pcc_data.pcc_lock);    /* END Phase-I */
+               up_read(&pcc_ss_data->pcc_lock);        /* END Phase-I */
        /*
         * This is Phase-II where we transfer the ownership of PCC to Platform
         *
@@ -1199,15 +1259,15 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
         * the write command before servicing the read command
         */
        if (CPC_IN_PCC(desired_reg)) {
-               if (down_write_trylock(&pcc_data.pcc_lock)) {   /* BEGIN Phase-II */
+               if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */
                        /* Update only if there are pending write commands */
-                       if (pcc_data.pending_pcc_write_cmd)
-                               send_pcc_cmd(CMD_WRITE);
-                       up_write(&pcc_data.pcc_lock);           /* END Phase-II */
+                       if (pcc_ss_data->pending_pcc_write_cmd)
+                               send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+                       up_write(&pcc_ss_data->pcc_lock);       /* END Phase-II */
                } else
                        /* Wait until pcc_write_cnt is updated by send_pcc_cmd */
-                       wait_event(pcc_data.pcc_write_wait_q,
-                               cpc_desc->write_cmd_id != pcc_data.pcc_write_cnt);
+                       wait_event(pcc_ss_data->pcc_write_wait_q,
+                                  cpc_desc->write_cmd_id != pcc_ss_data->pcc_write_cnt);
 
                /* send_pcc_cmd updates the status in case of failure */
                ret = cpc_desc->write_cmd_status;
@@ -1240,6 +1300,8 @@ unsigned int cppc_get_transition_latency(int cpu_num)
        unsigned int latency_ns = 0;
        struct cpc_desc *cpc_desc;
        struct cpc_register_resource *desired_reg;
+       int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu_num);
+       struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
 
        cpc_desc = per_cpu(cpc_desc_ptr, cpu_num);
        if (!cpc_desc)
@@ -1249,11 +1311,11 @@ unsigned int cppc_get_transition_latency(int cpu_num)
        if (!CPC_IN_PCC(desired_reg))
                return CPUFREQ_ETERNAL;
 
-       if (pcc_data.pcc_mpar)
-               latency_ns = 60 * (1000 * 1000 * 1000 / pcc_data.pcc_mpar);
+       if (pcc_ss_data->pcc_mpar)
+               latency_ns = 60 * (1000 * 1000 * 1000 / pcc_ss_data->pcc_mpar);
 
-       latency_ns = max(latency_ns, pcc_data.pcc_nominal * 1000);
-       latency_ns = max(latency_ns, pcc_data.pcc_mrtt * 1000);
+       latency_ns = max(latency_ns, pcc_ss_data->pcc_nominal * 1000);
+       latency_ns = max(latency_ns, pcc_ss_data->pcc_mrtt * 1000);
 
        return latency_ns;
 }
index 2305e1ab978ea0e09f6a7eb8cdb4e3dc78b0533e..e3fc1f045e1cd96cf67dec8d069f7d21c3a6c30d 100644 (file)
@@ -482,6 +482,7 @@ int dock_notify(struct acpi_device *adev, u32 event)
                surprise_removal = 1;
                event = ACPI_NOTIFY_EJECT_REQUEST;
                /* Fall back */
+               /* fall through */
        case ACPI_NOTIFY_EJECT_REQUEST:
                begin_undock(ds);
                if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
index 236b14324780a1c1c416c852957cfa732144b8fc..82b3ce5e937e8b980acd1a02e6a1f21c408a5ee0 100644 (file)
@@ -486,8 +486,11 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
 {
        if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
                ec_log_drv("event unblocked");
-       if (!test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
-               advance_transaction(ec);
+       /*
+        * Unconditionally invoke this once after enabling the event
+        * handling mechanism to detect the pending events.
+        */
+       advance_transaction(ec);
 }
 
 static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
@@ -1456,11 +1459,10 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
                        if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
                            ec->reference_count >= 1)
                                acpi_ec_enable_gpe(ec, true);
-
-                       /* EC is fully operational, allow queries */
-                       acpi_ec_enable_event(ec);
                }
        }
+       /* EC is fully operational, allow queries */
+       acpi_ec_enable_event(ec);
 
        return 0;
 }
diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c
new file mode 100644 (file)
index 0000000..7f3c567
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * TI TPS68470 PMIC operation region driver
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ * Author: Rajmohan Mani <rajmohan.mani@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Based on drivers/acpi/pmic/intel_pmic* drivers
+ */
+
+#include <linux/acpi.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct tps68470_pmic_table {
+       u32 address;            /* operation region address */
+       u32 reg;                /* corresponding register */
+       u32 bitmask;            /* bit mask for power, clock */
+};
+
+#define TI_PMIC_POWER_OPREGION_ID              0xB0
+#define TI_PMIC_VR_VAL_OPREGION_ID             0xB1
+#define TI_PMIC_CLOCK_OPREGION_ID              0xB2
+#define TI_PMIC_CLKFREQ_OPREGION_ID            0xB3
+
+struct tps68470_pmic_opregion {
+       struct mutex lock;
+       struct regmap *regmap;
+};
+
+#define S_IO_I2C_EN    (BIT(0) | BIT(1))
+
+static const struct tps68470_pmic_table power_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_S_I2C_CTL,
+               .bitmask = S_IO_I2C_EN,
+               /* S_I2C_CTL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_VCMCTL,
+               .bitmask = BIT(0),
+               /* VCMCTL */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_VAUX1CTL,
+               .bitmask = BIT(0),
+               /* VAUX1_CTL */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_VAUX2CTL,
+               .bitmask = BIT(0),
+               /* VAUX2CTL */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_VACTL,
+               .bitmask = BIT(0),
+               /* VACTL */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_VDCTL,
+               .bitmask = BIT(0),
+               /* VDCTL */
+       },
+};
+
+/* Table to set voltage regulator value */
+static const struct tps68470_pmic_table vr_val_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_VSIOVAL,
+               .bitmask = TPS68470_VSIOVAL_IOVOLT_MASK,
+               /* TPS68470_REG_VSIOVAL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_VIOVAL,
+               .bitmask = TPS68470_VIOVAL_IOVOLT_MASK,
+               /* TPS68470_REG_VIOVAL */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_VCMVAL,
+               .bitmask = TPS68470_VCMVAL_VCVOLT_MASK,
+               /* TPS68470_REG_VCMVAL */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_VAUX1VAL,
+               .bitmask = TPS68470_VAUX1VAL_AUX1VOLT_MASK,
+               /* TPS68470_REG_VAUX1VAL */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_VAUX2VAL,
+               .bitmask = TPS68470_VAUX2VAL_AUX2VOLT_MASK,
+               /* TPS68470_REG_VAUX2VAL */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_VAVAL,
+               .bitmask = TPS68470_VAVAL_AVOLT_MASK,
+               /* TPS68470_REG_VAVAL */
+       },
+       {
+               .address = 0x18,
+               .reg = TPS68470_REG_VDVAL,
+               .bitmask = TPS68470_VDVAL_DVOLT_MASK,
+               /* TPS68470_REG_VDVAL */
+       },
+};
+
+/* Table to configure clock frequency */
+static const struct tps68470_pmic_table clk_freq_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_POSTDIV2,
+               .bitmask = BIT(0) | BIT(1),
+               /* TPS68470_REG_POSTDIV2 */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_BOOSTDIV,
+               .bitmask = 0x1F,
+               /* TPS68470_REG_BOOSTDIV */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_BUCKDIV,
+               .bitmask = 0x0F,
+               /* TPS68470_REG_BUCKDIV */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_PLLSWR,
+               .bitmask = 0x13,
+               /* TPS68470_REG_PLLSWR */
+       },
+       {
+               .address = 0x10,
+               .reg = TPS68470_REG_XTALDIV,
+               .bitmask = 0xFF,
+               /* TPS68470_REG_XTALDIV */
+       },
+       {
+               .address = 0x14,
+               .reg = TPS68470_REG_PLLDIV,
+               .bitmask = 0xFF,
+               /* TPS68470_REG_PLLDIV */
+       },
+       {
+               .address = 0x18,
+               .reg = TPS68470_REG_POSTDIV,
+               .bitmask = 0x83,
+               /* TPS68470_REG_POSTDIV */
+       },
+};
+
+/* Table to configure and enable clocks */
+static const struct tps68470_pmic_table clk_table[] = {
+       {
+               .address = 0x00,
+               .reg = TPS68470_REG_PLLCTL,
+               .bitmask = 0xF5,
+               /* TPS68470_REG_PLLCTL */
+       },
+       {
+               .address = 0x04,
+               .reg = TPS68470_REG_PLLCTL2,
+               .bitmask = BIT(0),
+               /* TPS68470_REG_PLLCTL2 */
+       },
+       {
+               .address = 0x08,
+               .reg = TPS68470_REG_CLKCFG1,
+               .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |
+                       TPS68470_CLKCFG1_MODE_B_MASK,
+               /* TPS68470_REG_CLKCFG1 */
+       },
+       {
+               .address = 0x0C,
+               .reg = TPS68470_REG_CLKCFG2,
+               .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |
+                       TPS68470_CLKCFG1_MODE_B_MASK,
+               /* TPS68470_REG_CLKCFG2 */
+       },
+};
+
+static int pmic_get_reg_bit(u64 address,
+                           const struct tps68470_pmic_table *table,
+                           const unsigned int table_size, int *reg,
+                           int *bitmask)
+{
+       u64 i;
+
+       i = address / 4;
+       if (i >= table_size)
+               return -ENOENT;
+
+       if (!reg || !bitmask)
+               return -EINVAL;
+
+       *reg = table[i].reg;
+       *bitmask = table[i].bitmask;
+
+       return 0;
+}
+
+static int tps68470_pmic_get_power(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & bitmask) ? 1 : 0;
+       return 0;
+}
+
+static int tps68470_pmic_get_vr_val(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = data & bitmask;
+       return 0;
+}
+
+static int tps68470_pmic_get_clk(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = (data & bitmask) ? 1 : 0;
+       return 0;
+}
+
+static int tps68470_pmic_get_clk_freq(struct regmap *regmap, int reg,
+                                      int bitmask, u64 *value)
+{
+       unsigned int data;
+
+       if (regmap_read(regmap, reg, &data))
+               return -EIO;
+
+       *value = data & bitmask;
+       return 0;
+}
+
+static int ti_tps68470_regmap_update_bits(struct regmap *regmap, int reg,
+                                       int bitmask, u64 value)
+{
+       return regmap_update_bits(regmap, reg, bitmask, value);
+}
+
+static acpi_status tps68470_pmic_common_handler(u32 function,
+                                         acpi_physical_address address,
+                                         u32 bits, u64 *value,
+                                         void *region_context,
+                                         int (*get)(struct regmap *,
+                                                    int, int, u64 *),
+                                         int (*update)(struct regmap *,
+                                                       int, int, u64),
+                                         const struct tps68470_pmic_table *tbl,
+                                         unsigned int tbl_size)
+{
+       struct tps68470_pmic_opregion *opregion = region_context;
+       struct regmap *regmap = opregion->regmap;
+       int reg, ret, bitmask;
+
+       if (bits != 32)
+               return AE_BAD_PARAMETER;
+
+       ret = pmic_get_reg_bit(address, tbl, tbl_size, &reg, &bitmask);
+       if (ret < 0)
+               return AE_BAD_PARAMETER;
+
+       if (function == ACPI_WRITE && *value > bitmask)
+               return AE_BAD_PARAMETER;
+
+       mutex_lock(&opregion->lock);
+
+       ret = (function == ACPI_READ) ?
+               get(regmap, reg, bitmask, value) :
+               update(regmap, reg, bitmask, *value);
+
+       mutex_unlock(&opregion->lock);
+
+       return ret ? AE_ERROR : AE_OK;
+}
+
+static acpi_status tps68470_pmic_cfreq_handler(u32 function,
+                                           acpi_physical_address address,
+                                           u32 bits, u64 *value,
+                                           void *handler_context,
+                                           void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_clk_freq,
+                               ti_tps68470_regmap_update_bits,
+                               clk_freq_table,
+                               ARRAY_SIZE(clk_freq_table));
+}
+
+static acpi_status tps68470_pmic_clk_handler(u32 function,
+                                      acpi_physical_address address, u32 bits,
+                                      u64 *value, void *handler_context,
+                                      void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_clk,
+                               ti_tps68470_regmap_update_bits,
+                               clk_table,
+                               ARRAY_SIZE(clk_table));
+}
+
+static acpi_status tps68470_pmic_vrval_handler(u32 function,
+                                         acpi_physical_address address,
+                                         u32 bits, u64 *value,
+                                         void *handler_context,
+                                         void *region_context)
+{
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_vr_val,
+                               ti_tps68470_regmap_update_bits,
+                               vr_val_table,
+                               ARRAY_SIZE(vr_val_table));
+}
+
+static acpi_status tps68470_pmic_pwr_handler(u32 function,
+                                        acpi_physical_address address,
+                                        u32 bits, u64 *value,
+                                        void *handler_context,
+                                        void *region_context)
+{
+       if (bits != 32)
+               return AE_BAD_PARAMETER;
+
+       /* set/clear for bit 0, bits 0 and 1 together */
+       if (function == ACPI_WRITE &&
+           !(*value == 0 || *value == 1 || *value == 3)) {
+               return AE_BAD_PARAMETER;
+       }
+
+       return tps68470_pmic_common_handler(function, address, bits, value,
+                               region_context,
+                               tps68470_pmic_get_power,
+                               ti_tps68470_regmap_update_bits,
+                               power_table,
+                               ARRAY_SIZE(power_table));
+}
+
+static int tps68470_pmic_opregion_probe(struct platform_device *pdev)
+{
+       struct regmap *tps68470_regmap = dev_get_drvdata(pdev->dev.parent);
+       acpi_handle handle = ACPI_HANDLE(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct tps68470_pmic_opregion *opregion;
+       acpi_status status;
+
+       if (!dev || !tps68470_regmap) {
+               dev_warn(dev, "dev or regmap is NULL\n");
+               return -EINVAL;
+       }
+
+       if (!handle) {
+               dev_warn(dev, "acpi handle is NULL\n");
+               return -ENODEV;
+       }
+
+       opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+       if (!opregion)
+               return -ENOMEM;
+
+       mutex_init(&opregion->lock);
+       opregion->regmap = tps68470_regmap;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_POWER_OPREGION_ID,
+                                                   tps68470_pmic_pwr_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_mutex_destroy;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_VR_VAL_OPREGION_ID,
+                                                   tps68470_pmic_vrval_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_power_handler;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_CLOCK_OPREGION_ID,
+                                                   tps68470_pmic_clk_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_vr_val_handler;
+
+       status = acpi_install_address_space_handler(handle,
+                                                   TI_PMIC_CLKFREQ_OPREGION_ID,
+                                                   tps68470_pmic_cfreq_handler,
+                                                   NULL, opregion);
+       if (ACPI_FAILURE(status))
+               goto out_remove_clk_handler;
+
+       return 0;
+
+out_remove_clk_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_CLOCK_OPREGION_ID,
+                                         tps68470_pmic_clk_handler);
+out_remove_vr_val_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_VR_VAL_OPREGION_ID,
+                                         tps68470_pmic_vrval_handler);
+out_remove_power_handler:
+       acpi_remove_address_space_handler(handle, TI_PMIC_POWER_OPREGION_ID,
+                                         tps68470_pmic_pwr_handler);
+out_mutex_destroy:
+       mutex_destroy(&opregion->lock);
+       return -ENODEV;
+}
+
+static struct platform_driver tps68470_pmic_opregion_driver = {
+       .probe = tps68470_pmic_opregion_probe,
+       .driver = {
+               .name = "tps68470_pmic_opregion",
+       },
+};
+
+builtin_platform_driver(tps68470_pmic_opregion_driver)
index d85e010ee2cced7b840ebe59fc41a4830bef74e4..316a0fc785e3629a4bdd6dadd031cbe6691cec70 100644 (file)
@@ -381,6 +381,7 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity)
        case ACPI_ACTIVE_BOTH:
                if (triggering == ACPI_EDGE_SENSITIVE)
                        return IRQ_TYPE_EDGE_BOTH;
+               /* fall through */
        default:
                return IRQ_TYPE_NONE;
        }
index 0fd57bf33524a46938396210eabfad57226100f6..bc303df60d5dcebf336d6a7822df02fa2b8cc68a 100644 (file)
@@ -169,7 +169,8 @@ module_param_cb(debug_level, &param_ops_debug_level, &acpi_dbg_level, 0644);
 
 static char trace_method_name[1024];
 
-int param_set_trace_method_name(const char *val, const struct kernel_param *kp)
+static int param_set_trace_method_name(const char *val,
+                                      const struct kernel_param *kp)
 {
        u32 saved_flags = 0;
        bool is_abs_path = true;
index b4fbb99294828cf06900ddd7c4c908c6f28c83cb..ec5b0f190231c8b6ce6a98d99ae33347ad51054a 100644 (file)
@@ -71,18 +71,34 @@ static const struct always_present_id always_present_ids[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
              }),
        /*
-        * The GPD win BIOS dated 20170320 has disabled the accelerometer, the
+        * The GPD win BIOS dated 20170221 has disabled the accelerometer, the
         * drivers sometimes cause crashes under Windows and this is how the
         * manufacturer has solved this :| Note that the the DMI data is less
         * generic then it seems, a board_vendor of "AMI Corporation" is quite
         * rare and a board_name of "Default String" also is rare.
+        *
+        * Unfortunately the GPD pocket also uses these strings and its BIOS
+        * was copy-pasted from the GPD win, so it has a disabled KIOX000A
+        * node which we should not enable, thus we also check the BIOS date.
         */
+       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+               DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+               DMI_MATCH(DMI_BIOS_DATE, "02/21/2017")
+             }),
        ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
                DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                DMI_MATCH(DMI_BOARD_NAME, "Default string"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
                DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
              }),
+       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+               DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
+               DMI_MATCH(DMI_BOARD_NAME, "Default string"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
+               DMI_MATCH(DMI_BIOS_DATE, "05/25/2017")
+             }),
 };
 
 bool acpi_device_always_present(struct acpi_device *adev)
index 9b7005e1345e1a2b0f76ddc8e429a070d4c65790..e5a69679cfa2a0ca4d60b4e18788db21a849ec66 100644 (file)
@@ -69,7 +69,6 @@
 
 #include "mailbox.h"
 
-#define MAX_PCC_SUBSPACES      256
 #define MBOX_IRQ_NAME          "pcc-mbox"
 
 static struct mbox_chan *pcc_mbox_channels;
index ad54610ea6cd4520812357633d8e461c6f49e744..17d61b1f2511ad71881b6ff4a182c10dcdf5191a 100644 (file)
@@ -126,8 +126,12 @@ struct acpi_exception_info {
 #define AE_NOT_CONFIGURED               EXCEP_ENV (0x001C)
 #define AE_ACCESS                       EXCEP_ENV (0x001D)
 #define AE_IO_ERROR                     EXCEP_ENV (0x001E)
+#define AE_NUMERIC_OVERFLOW             EXCEP_ENV (0x001F)
+#define AE_HEX_OVERFLOW                 EXCEP_ENV (0x0020)
+#define AE_DECIMAL_OVERFLOW             EXCEP_ENV (0x0021)
+#define AE_OCTAL_OVERFLOW               EXCEP_ENV (0x0022)
 
-#define AE_CODE_ENV_MAX                 0x001E
+#define AE_CODE_ENV_MAX                 0x0022
 
 /*
  * Programmer exceptions
@@ -263,7 +267,15 @@ static const struct acpi_exception_info acpi_gbl_exception_names_env[] = {
        EXCEP_TXT("AE_NOT_CONFIGURED",
                  "The interface is not part of the current subsystem configuration"),
        EXCEP_TXT("AE_ACCESS", "Permission denied for the requested operation"),
-       EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred")
+       EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred"),
+       EXCEP_TXT("AE_NUMERIC_OVERFLOW",
+                 "Overflow during string-to-integer conversion"),
+       EXCEP_TXT("AE_HEX_OVERFLOW",
+                 "Overflow during ASCII hex-to-binary conversion"),
+       EXCEP_TXT("AE_DECIMAL_OVERFLOW",
+                 "Overflow during ASCII decimal-to-binary conversion"),
+       EXCEP_TXT("AE_OCTAL_OVERFLOW",
+                 "Overflow during ASCII octal-to-binary conversion")
 };
 
 static const struct acpi_exception_info acpi_gbl_exception_names_pgm[] = {
index 53c5e2f7bcecd82f824d021de2d31d67e9206c71..e1dd1a8d42b60eb155796819b9518c34855cbfa5 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20170728
+#define ACPI_CA_VERSION                 0x20170831
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index 6b8714a428b6d78832b2a876d62482de97c07ad5..7a89e6de94da938e450aa10623e76a86dbe6602d 100644 (file)
@@ -69,6 +69,7 @@
 #define ACPI_SIG_HEST           "HEST" /* Hardware Error Source Table */
 #define ACPI_SIG_MADT           "APIC" /* Multiple APIC Description Table */
 #define ACPI_SIG_MSCT           "MSCT" /* Maximum System Characteristics Table */
+#define ACPI_SIG_PDTT           "PDTT" /* Processor Debug Trigger Table */
 #define ACPI_SIG_PPTT           "PPTT" /* Processor Properties Topology Table */
 #define ACPI_SIG_SBST           "SBST" /* Smart Battery Specification Table */
 #define ACPI_SIG_SLIT           "SLIT" /* System Locality Distance Information Table */
@@ -1280,6 +1281,35 @@ struct acpi_nfit_flush_address {
        u64 hint_address[1];    /* Variable length */
 };
 
+/*******************************************************************************
+ *
+ * PDTT - Processor Debug Trigger Table (ACPI 6.2)
+ *        Version 0
+ *
+ ******************************************************************************/
+
+struct acpi_table_pdtt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 trigger_count;
+       u8 reserved[3];
+       u32 array_offset;
+};
+
+/*
+ * PDTT Communication Channel Identifier Structure.
+ * The number of these structures is defined by trigger_count above,
+ * starting at array_offset.
+ */
+struct acpi_pdtt_channel {
+       u16 sub_channel_id;
+};
+
+/* Mask and Flags for above */
+
+#define ACPI_PDTT_SUBCHANNEL_ID_MASK        0x00FF
+#define ACPI_PDTT_RUNTIME_TRIGGER           (1<<8)
+#define ACPI_PPTT_WAIT_COMPLETION           (1<<9)
+
 /*******************************************************************************
  *
  * PPTT - Processor Properties Topology Table (ACPI 6.2)
index 1797e81a320408e79c24ab09c1802f6b86f28a12..680f80960c3dcf36f6dac83c4061cce7f5103f1b 100644 (file)
@@ -51,7 +51,6 @@ int erst_clear(u64 record_id);
 
 int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data);
 void arch_apei_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
-void arch_apei_flush_tlb_one(unsigned long addr);
 
 #endif
 #endif
index 8caa79c617035e60a41ee850150d2b472f35df5a..cd6ef45e614ea8131b8c0e1c50518d67b36a0d4e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mailbox_controller.h>
 #include <linux/mailbox_client.h>
 
+#define MAX_PCC_SUBSPACES      256
 #ifdef CONFIG_PCC
 extern struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
                                                  int subspace_id);
index f7c7af1f9258b08ec2eb4f1c01a63184ea217b95..b436f8675f6a2e75ffbe414de36096280d3fa542 100644 (file)
@@ -39,6 +39,7 @@ TOOL_OBJS = \
        utnonansi.o\
        utprint.o\
        utstring.o\
+       utstrsuppt.o\
        utstrtoul64.o\
        utxferror.o\
        oslinuxtbl.o\
index 60df1fbd4a776a7e23da202b3ea6e3d69f93de78..0634449156d82e028427a90654523e0477424393 100644 (file)
@@ -287,8 +287,7 @@ int ap_dump_table_by_address(char *ascii_address)
 
        /* Convert argument to an integer physical address */
 
-       status = acpi_ut_strtoul64(ascii_address, ACPI_STRTOUL_64BIT,
-                                  &long_address);
+       status = acpi_ut_strtoul64(ascii_address, &long_address);
        if (ACPI_FAILURE(status)) {
                fprintf(stderr, "%s: Could not convert to a physical address\n",
                        ascii_address);
index 943b6b6146834384128c63b47ca6317f5be8fec4..22c3b4ee1617b8c83cde926d5e9e9fb1f37ee882 100644 (file)
@@ -208,9 +208,7 @@ static int ap_do_options(int argc, char **argv)
                case 'r':       /* Dump tables from specified RSDP */
 
                        status =
-                           acpi_ut_strtoul64(acpi_gbl_optarg,
-                                             ACPI_STRTOUL_64BIT,
-                                             &gbl_rsdp_base);
+                           acpi_ut_strtoul64(acpi_gbl_optarg, &gbl_rsdp_base);
                        if (ACPI_FAILURE(status)) {
                                fprintf(stderr,
                                        "%s: Could not convert to a physical address\n",