ACPI updates for v4.15-rc1
- 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). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJaCg33AAoJEILEb/54YlRxTe0P/jEFsSXCmAussc0DoqcXuep/ GEzsMHZLBU59oVTVqiji19vkVEiJldANmnFniMTr3sJ52QSgLQH4Wtv5QGzTCmUq C3VzfSye5QS726f/Fk4tgZIFy5WL3EzweEbPmrcsFQvShU/vNHzvGUNcnPy9IWXE O+kISx8YTB6z4laa9cJLjTMEuDgRUpyubb9dZBBvXC7RIuHstk8+GyLvvPImKGBL sk5PNChP0WGLLSG7BayOUG3/7Q2RaFpbgjCos2dounPAJW5TXmMJUsZ0gvtXy0Z8 ZoPmqgPlYYlHVBlpy7oO4WGFLYJ+KZ+w27aEN1n0C3n9BU9AqWBKw8nkxfpCgPxy 3p2dwuh1igHsCAEVaaGjw02bewszIdl68q3ZfC7xujE401SG+Py7VCnTAbkffC0M nXP8RlGg4V3blwvNM47g3Hh8VG7vJgsW2fvBdSQa/Za7ML8aqxkvtk1BzhDCN19X tIqn9RMLWoPSnrEdqSi4HK88iHRvagPJncemFyDQl4LE+V5rWBCUqNumLLjL2i4L uBxqlK3tBVWKM0iKmISDHpjUZHaqM3g/Lmyo3aExWTog06OB81hMG3b57RrbWj9t 1PIbQOtAazhqM4Scdg1mWTaRNR1p40V9RyA6YvqTIbjDRDPkxEfIUECvRBFwgWkd JtFkKwR65EFkH8bGNXQi =7mrU -----END PGP SIGNATURE----- Merge tag 'acpi-4.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm 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 ...
This commit is contained in:
commit
04ed510988
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -178,6 +178,7 @@ acpi-y += \
|
|||
utresrc.o \
|
||||
utstate.o \
|
||||
utstring.o \
|
||||
utstrsuppt.o \
|
||||
utstrtoul64.o \
|
||||
utxface.o \
|
||||
utxfinit.o \
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -44,304 +45,319 @@
|
|||
#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.
|
||||
* This module contains the top-level string to 64/32-bit unsigned integer
|
||||
* conversion functions:
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Implicit data type conversion: string-to-integer
|
||||
* --------------------------------------------------
|
||||
* Current users of this module:
|
||||
*
|
||||
* Base is always 16. This is the ACPI_STRTOUL_BASE16 case.
|
||||
* 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
|
||||
*
|
||||
* Example:
|
||||
* Add ("BA98", Arg0, Local0)
|
||||
* Notes concerning users of these interfaces:
|
||||
*
|
||||
* The integer is initialized to the value zero.
|
||||
* The ASCII string is interpreted as a hexadecimal constant.
|
||||
* 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.
|
||||
*
|
||||
* 1) A "0x" prefix is not allowed. However, ACPICA allows this for
|
||||
* compatibility with previous ACPICA. (NO ERROR)
|
||||
*
|
||||
* 2) Terminates when the size of an integer is reached (32 or 64 bits).
|
||||
* (NO ERROR)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
* 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
|
||||
* returned. Must be a valid pointer
|
||||
*
|
||||
* RETURN: Status and Converted value
|
||||
* RETURN: Status and converted integer. Returns an exception on a
|
||||
* 64-bit numeric overflow
|
||||
*
|
||||
* 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).
|
||||
* 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.
|
||||
*
|
||||
* 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).
|
||||
* Current users of this function:
|
||||
*
|
||||
* NOTES:
|
||||
* Negative numbers are not supported, as they are not supported by ACPI.
|
||||
*
|
||||
* 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
|
||||
* flags - Conversion info
|
||||
* PARAMETERS: string - Null terminated input string,
|
||||
* must be a valid pointer
|
||||
*
|
||||
* RETURN: 64-bit converted integer
|
||||
* RETURN: Converted integer
|
||||
*
|
||||
* 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.
|
||||
* 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).
|
||||
*
|
||||
* 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 - 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;
|
||||
u64 converted_integer = 0;
|
||||
|
||||
/* Main loop: convert each ASCII byte in the input string */
|
||||
ACPI_FUNCTION_TRACE_STR(ut_implicit_strtoul64, string);
|
||||
|
||||
while (*string) {
|
||||
ascii_digit = *string;
|
||||
if (!isdigit(ascii_digit)) {
|
||||
|
||||
/* Not ASCII 0-9, terminate */
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Convert and insert (add) the decimal digit */
|
||||
|
||||
acpi_ut_short_multiply(return_value, 10, &next_value);
|
||||
next_value += (ascii_digit - ACPI_ASCII_ZERO);
|
||||
|
||||
/* Check for overflow (32 or 64 bit) - return current converted value */
|
||||
|
||||
if (((flags & ACPI_STRTOUL_32BIT) && (next_value > ACPI_UINT32_MAX)) || (next_value < return_value)) { /* 64-bit overflow case */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return_value = next_value;
|
||||
string++;
|
||||
if (!acpi_ut_remove_whitespace(&string)) {
|
||||
return_VALUE(0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return (return_value);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
if (!acpi_ut_remove_leading_zeros(&string)) {
|
||||
return_VALUE(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* flags - conversion info
|
||||
* PARAMETERS: string - Null terminated input string,
|
||||
* must be a valid pointer
|
||||
*
|
||||
* RETURN: 64-bit converted integer
|
||||
* RETURN: Converted integer
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* -----------------------------------------------------------------------------
|
||||
*
|
||||
* 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;
|
||||
u64 converted_integer = 0;
|
||||
u32 base = 10; /* Default is decimal */
|
||||
|
||||
/* Main loop: convert each ASCII byte in the input string */
|
||||
ACPI_FUNCTION_TRACE_STR(ut_explicit_strtoul64, string);
|
||||
|
||||
while (*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;
|
||||
}
|
||||
|
||||
/* Convert and insert the hex digit */
|
||||
|
||||
acpi_ut_short_shift_left(return_value, 4, &return_value);
|
||||
return_value |= acpi_ut_ascii_char_to_hex(ascii_digit);
|
||||
|
||||
string++;
|
||||
valid_digits++;
|
||||
if (!acpi_ut_remove_whitespace(&string)) {
|
||||
return_VALUE(0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return (return_value);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (!acpi_ut_remove_leading_zeros(&string)) {
|
||||
return_VALUE(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
return_VALUE(converted_integer);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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 @@ static int send_pcc_cmd(u16 cmd)
|
|||
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 @@ int acpi_get_psd_map(struct cppc_cpudata **all_cpu_data)
|
|||
}
|
||||
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_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_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length);
|
||||
if (!pcc_data.pcc_comm_addr) {
|
||||
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 = ®_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 = ®_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;
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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, ®, &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)
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -169,7 +169,8 @@ module_param_cb(debug_level, ¶m_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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -39,6 +39,7 @@ TOOL_OBJS = \
|
|||
utnonansi.o\
|
||||
utprint.o\
|
||||
utstring.o\
|
||||
utstrsuppt.o\
|
||||
utstrtoul64.o\
|
||||
utxferror.o\
|
||||
oslinuxtbl.o\
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue