summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-09-16 07:41:48 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2024-09-16 07:41:48 +0200
commit11b3125073d16929403d3aa7b2ae6a482060a937 (patch)
treea28f8ac73cfb39b7ac9fde35a151ecb348ab20ea /drivers/acpi
parent64dd3b6a79f0907d36de481b0f15fab323a53e5a (diff)
parent3dd2fcf496359d2e196acd33e53dc921d6e39cff (diff)
Merge tag 'acpi-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki: "These update the ACPICA code in the kernel to upstream version 20240827, add support for ACPI-based enumeration of interrupt controllers on RISC-V along with some related irqchip updates, clean up the ACPI device object sysfs interface, add some quirks for backlight handling and IRQ overrides, fix assorted issues and clean up code. Specifics: - Check return value in acpi_db_convert_to_package() (Pei Xiao) - Detect FACS and allow setting the waking vector on reduced-hardware ACPI platforms (Jiaqing Zhao) - Allow ACPICA to represent semaphores as integers (Adrien Destugues) - Complete CXL 3.0 CXIMS structures support in ACPICA (Zhang Rui) - Make ACPICA support SPCR version 4 and add RISC-V SBI Subtype to DBG2 (Sia Jee Heng) - Implement the Dword_PCC Resource Descriptor Macro in ACPICA (Jose Marinho) - Correct the typo in struct acpi_mpam_msc_node member (Punit Agrawal) - Implement ACPI_WARNING_ONCE() and ACPI_ERROR_ONCE() and use them to prevent a Stall() violation warning from being printed every time this takes place (Vasily Khoruzhick) - Allow PCC Data Type in MCTP resource (Adam Young) - Fix memory leaks on acpi_ps_get_next_namepath() and acpi_ps_get_next_field() failures (Armin Wolf) - Add support for supressing leading zeros in hex strings when converting them to integers and update integer-to-hex-string conversions in ACPICA (Armin Wolf) - Add support for Windows 11 22H2 _OSI string (Armin Wolf) - Avoid warning for Dump Functions in ACPICA (Adam Lackorzynski) - Add extended linear address mode to HMAT MSCIS in ACPICA (Dave Jiang) - Handle empty connection_node in iasl (Aleksandrs Vinarskis) - Allow for more flexibility in _DSM args (Saket Dumbre) - Setup for ACPICA release 20240827 (Saket Dumbre) - Add ACPI device enumeration support for interrupt controller probing including taking dependencies into account (Sunil V L) - Implement ACPI-based interrupt controller probing on RISC-V (Sunil V L) - Add ACPI support for AIA in riscv-intc and add ACPI support to riscv-imsic, riscv-aplic, and sifive-plic (Sunil V L) - Do not release locks during operation region accesses in the ACPI EC driver (Rafael Wysocki) - Fix up the _STR handling in the ACPI device object sysfs interface, make it represent the device object attributes as an attribute group and make it rely on driver core functionality for sysfs attrubute management (Thomas Weißschuh) - Extend error messages printed to the kernel log when acpi_evaluate_dsm() fails to include revision and function number (David Wang) - Add a new AMDI0015 platform device ID to the ACPi APD driver for AMD SoCs (Shyam Sundar S K) - Use the driver core for the async probing management in the ACPI battery driver (Thomas Weißschuh) - Remove redundant initalizations of a local variable to NULL from the ACPI battery driver (Ilpo Järvinen) - Remove unneeded check in tps68470_pmic_opregion_probe() (Aleksandr Mishin) - Add support for setting the EPP register through the ACPI CPPC sysfs interface if it is in FFH (Mario Limonciello) - Fix MASK_VAL() usage in the ACPI CPPC library (Clément Léger) - Reduce the log level of a per-CPU message about idle states in the ACPI processor driver (Li RongQing) - Fix crash in exit_round_robin() in the ACPI processor aggregator device (PAD) driver (Seiji Nishikawa) - Add force_vendor quirk for Panasonic Toughbook CF-18 in the ACPI backlight driver (Hans de Goede) - Make the DMI checks related to backlight handling on Lenovo Yoga Tab 3 X90F less strict (Hans de Goede) - Enforce native backlight handling on Apple MacbookPro9,2 (Esther Shimanovich) - Add IRQ override quirks for Asus Vivobook Go E1404GAB and MECHREV GM7XG0M, and refine the TongFang GMxXGxx quirk (Li Chen, Tamim Khan, Werner Sembach) - Quirk ASUS ROG M16 to default to S3 sleep (Luke D. Jones) - Define and use symbols for device and class name lengths in the ACPI bus type code and make the code use strscpy() instead of strcpy() in several places (Muhammad Qasim Abdul Majeed)" * tag 'acpi-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (70 commits) ACPI: resource: Add another DMI match for the TongFang GMxXGxx ACPI: CPPC: Add support for setting EPP register in FFH ACPI: PM: Quirk ASUS ROG M16 to default to S3 sleep ACPI: video: Add force_vendor quirk for Panasonic Toughbook CF-18 ACPI: battery: use driver core managed async probing ACPI: button: Use strscpy() instead of strcpy() ACPI: resource: Skip IRQ override on Asus Vivobook Go E1404GAB ACPI: CPPC: Fix MASK_VAL() usage irqchip/sifive-plic: Add ACPI support ACPICA: Setup for ACPICA release 20240827 ACPICA: Allow for more flexibility in _DSM args ACPICA: iasl: handle empty connection_node ACPICA: HMAT: Add extended linear address mode to MSCIS ACPICA: Avoid warning for Dump Functions ACPICA: Add support for Windows 11 22H2 _OSI string ACPICA: Update integer-to-hex-string conversions ACPICA: Add support for supressing leading zeros in hex strings ACPICA: Allow for supressing leading zeros when using acpi_ex_convert_to_ascii() ACPICA: Fix memory leak if acpi_ps_get_next_field() fails ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails ...
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/ac.c4
-rw-r--r--drivers/acpi/acpi_apd.c6
-rw-r--r--drivers/acpi/acpi_pad.c10
-rw-r--r--drivers/acpi/acpi_processor.c6
-rw-r--r--drivers/acpi/acpica/acglobal.h6
-rw-r--r--drivers/acpi/acpica/aclocal.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/acpica/dbconvert.c2
-rw-r--r--drivers/acpi/acpica/exconvrt.c58
-rw-r--r--drivers/acpi/acpica/exprep.c3
-rw-r--r--drivers/acpi/acpica/exsystem.c11
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c15
-rw-r--r--drivers/acpi/acpica/psargs.c47
-rw-r--r--drivers/acpi/acpica/rsaddr.c3
-rw-r--r--drivers/acpi/acpica/rsdump.c2
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c4
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utosi.c1
-rw-r--r--drivers/acpi/acpica/utxfinit.c24
-rw-r--r--drivers/acpi/battery.c39
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/button.c6
-rw-r--r--drivers/acpi/cppc_acpi.c53
-rw-r--r--drivers/acpi/device_sysfs.c196
-rw-r--r--drivers/acpi/ec.c55
-rw-r--r--drivers/acpi/internal.h3
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/pmic/tps68470_pmic.c6
-rw-r--r--drivers/acpi/resource.c19
-rw-r--r--drivers/acpi/riscv/Makefile2
-rw-r--r--drivers/acpi/riscv/init.c13
-rw-r--r--drivers/acpi/riscv/init.h4
-rw-r--r--drivers/acpi/riscv/irq.c335
-rw-r--r--drivers/acpi/scan.c109
-rw-r--r--drivers/acpi/sleep.c14
-rw-r--r--drivers/acpi/utils.c3
-rw-r--r--drivers/acpi/video_detect.c17
-rw-r--r--drivers/acpi/x86/utils.c1
39 files changed, 832 insertions, 259 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index eaa70b23dd0b..7c5b040a83e8 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -213,8 +213,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
return -ENOMEM;
ac->device = adev;
- strcpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME);
- strcpy(acpi_device_class(adev), ACPI_AC_CLASS);
+ strscpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME);
+ strscpy(acpi_device_class(adev), ACPI_AC_CLASS);
platform_set_drvdata(pdev, ac);
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index 80f945cbec8a..800f97868448 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -118,6 +118,11 @@ static const struct apd_device_desc wt_i2c_desc = {
.fixed_clk_rate = 150000000,
};
+static const struct apd_device_desc wt_i3c_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 125000000,
+};
+
static struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
@@ -231,6 +236,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
{ "AMD0030", },
{ "AMD0040", APD_ADDR(fch_misc_desc)},
{ "AMDI0010", APD_ADDR(wt_i2c_desc) },
+ { "AMDI0015", APD_ADDR(wt_i3c_desc) },
{ "AMDI0019", APD_ADDR(wt_i2c_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
{ "AMDI0022", APD_ADDR(cz_uart_desc) },
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 350d3a892889..42b7220d4cfd 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -136,8 +136,10 @@ static void exit_round_robin(unsigned int tsk_index)
{
struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
- cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
- tsk_in_cpu[tsk_index] = -1;
+ if (tsk_in_cpu[tsk_index] != -1) {
+ cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+ tsk_in_cpu[tsk_index] = -1;
+ }
}
static unsigned int idle_pct = 5; /* percentage */
@@ -428,8 +430,8 @@ static int acpi_pad_probe(struct platform_device *pdev)
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
acpi_status status;
- strcpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
- strcpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS);
+ strscpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
+ strscpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS);
status = acpi_install_notify_handler(adev->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify, adev);
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 9916cc7ced39..7cf6101cb4c7 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -436,8 +436,8 @@ static int acpi_processor_add(struct acpi_device *device,
}
pr->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
+ strscpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
+ strscpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
device->driver_data = pr;
result = acpi_processor_get_info(device);
@@ -985,7 +985,7 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
memcpy(&info->states[++last_index], &cx, sizeof(cx));
}
- acpi_handle_info(handle, "Found %d idle states\n", last_index);
+ acpi_handle_debug(handle, "Found %d idle states\n", last_index);
info->count = last_index;
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index f4c90fc99be2..309ce8efb4f6 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -29,11 +29,7 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_dsdt_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_facs_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX);
ACPI_INIT_GLOBAL(u32, acpi_gbl_fadt_index, ACPI_INVALID_TABLE_INDEX);
-
-#if (!ACPI_REDUCED_HARDWARE)
-ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS);
-
-#endif /* !ACPI_REDUCED_HARDWARE */
+ACPI_INIT_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS, NULL);
/* These addresses are calculated from the FADT Event Block addresses */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 02012168a087..6f4fe47c955b 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -1090,6 +1090,8 @@ struct acpi_port_info {
#define ACPI_ADDRESS_TYPE_IO_RANGE 1
#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2
+#define ACPI_ADDRESS_TYPE_PCC_NUMBER 0xA
+
/* Resource descriptor types and masks */
#define ACPI_RESOURCE_NAME_LARGE 0x80
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 2e442f5a3123..ef068f4c864a 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -450,7 +450,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_DSM",
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
- ACPI_TYPE_PACKAGE),
+ ACPI_TYPE_ANY) | ARG_COUNT_IS_MINIMUM,
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
{{"_DSS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c
index 2b84ac093698..8dbab6932049 100644
--- a/drivers/acpi/acpica/dbconvert.c
+++ b/drivers/acpi/acpica/dbconvert.c
@@ -174,6 +174,8 @@ acpi_status acpi_db_convert_to_package(char *string, union acpi_object *object)
elements =
ACPI_ALLOCATE_ZEROED(DB_DEFAULT_PKG_ELEMENTS *
sizeof(union acpi_object));
+ if (!elements)
+ return (AE_NO_MEMORY);
this = string;
for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++) {
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 3729bf3b74f7..bb1be42daee1 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -17,7 +17,8 @@ ACPI_MODULE_NAME("exconvrt")
/* Local prototypes */
static u32
-acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 max_length);
+acpi_ex_convert_to_ascii(u64 integer,
+ u16 base, u8 *string, u8 max_length, u8 leading_zeros);
/*******************************************************************************
*
@@ -249,6 +250,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
* base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
* string - Where the string is returned
* data_width - Size of data item to be converted, in bytes
+ * leading_zeros - Allow leading zeros
*
* RETURN: Actual string length
*
@@ -257,7 +259,8 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
******************************************************************************/
static u32
-acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
+acpi_ex_convert_to_ascii(u64 integer,
+ u16 base, u8 *string, u8 data_width, u8 leading_zeros)
{
u64 digit;
u32 i;
@@ -266,7 +269,8 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
u32 hex_length;
u32 decimal_length;
u32 remainder;
- u8 supress_zeros;
+ u8 supress_zeros = !leading_zeros;
+ u8 hex_char;
ACPI_FUNCTION_ENTRY();
@@ -293,7 +297,6 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
break;
}
- supress_zeros = TRUE; /* No leading zeros */
remainder = 0;
for (i = decimal_length; i > 0; i--) {
@@ -328,8 +331,17 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
/* Get one hex digit, most significant digits first */
- string[k] = (u8)
+ hex_char = (u8)
acpi_ut_hex_to_ascii_char(integer, ACPI_MUL_4(j));
+
+ /* Supress leading zeros until the first non-zero character */
+
+ if (hex_char == ACPI_ASCII_ZERO && supress_zeros) {
+ continue;
+ }
+
+ supress_zeros = FALSE;
+ string[k] = hex_char;
k++;
}
break;
@@ -379,6 +391,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
u32 string_length = 0;
u16 base = 16;
u8 separator = ',';
+ u8 leading_zeros;
ACPI_FUNCTION_TRACE_PTR(ex_convert_to_string, obj_desc);
@@ -400,14 +413,26 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* Make room for the maximum decimal number size
*/
string_length = ACPI_MAX_DECIMAL_DIGITS;
+ leading_zeros = FALSE;
base = 10;
break;
+ case ACPI_EXPLICIT_CONVERT_HEX:
+ /*
+ * From to_hex_string.
+ *
+ * Supress leading zeros and append "0x"
+ */
+ string_length =
+ ACPI_MUL_2(acpi_gbl_integer_byte_width) + 2;
+ leading_zeros = FALSE;
+ break;
default:
/* Two hex string characters for each integer byte */
string_length = ACPI_MUL_2(acpi_gbl_integer_byte_width);
+ leading_zeros = TRUE;
break;
}
@@ -422,17 +447,32 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
}
new_buf = return_desc->buffer.pointer;
+ if (type == ACPI_EXPLICIT_CONVERT_HEX) {
+
+ /* Append "0x" prefix for explicit hex conversion */
+
+ *new_buf++ = '0';
+ *new_buf++ = 'x';
+ }
/* Convert integer to string */
string_length =
acpi_ex_convert_to_ascii(obj_desc->integer.value, base,
new_buf,
- acpi_gbl_integer_byte_width);
+ acpi_gbl_integer_byte_width,
+ leading_zeros);
/* Null terminate at the correct place */
return_desc->string.length = string_length;
+ if (type == ACPI_EXPLICIT_CONVERT_HEX) {
+
+ /* Take "0x" prefix into account */
+
+ return_desc->string.length += 2;
+ }
+
new_buf[string_length] = 0;
break;
@@ -448,6 +488,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
* From ACPI: "If the input is a buffer, it is converted to a
* a string of decimal values separated by commas."
*/
+ leading_zeros = FALSE;
base = 10;
/*
@@ -475,6 +516,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
*
* Each hex number is prefixed with 0x (11/2018)
*/
+ leading_zeros = TRUE;
separator = ' ';
string_length = (obj_desc->buffer.length * 5);
break;
@@ -488,6 +530,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
*
* Each hex number is prefixed with 0x (11/2018)
*/
+ leading_zeros = TRUE;
separator = ',';
string_length = (obj_desc->buffer.length * 5);
break;
@@ -528,7 +571,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
new_buf += acpi_ex_convert_to_ascii((u64) obj_desc->
buffer.pointer[i],
- base, new_buf, 1);
+ base, new_buf, 1,
+ leading_zeros);
/* Each digit is separated by either a comma or space */
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 08196fa17080..82b1fa2d201f 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -437,6 +437,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
if (info->connection_node) {
second_desc = info->connection_node->object;
+ if (second_desc == NULL) {
+ break;
+ }
if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
status =
acpi_ds_get_buffer_arguments(second_desc);
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index f665ffd9a396..2c384bd52b9c 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -133,14 +133,15 @@ acpi_status acpi_ex_system_do_stall(u32 how_long_us)
* (ACPI specifies 100 usec as max, but this gives some slack in
* order to support existing BIOSs)
*/
- ACPI_ERROR((AE_INFO,
- "Time parameter is too large (%u)", how_long_us));
+ ACPI_ERROR_ONCE((AE_INFO,
+ "Time parameter is too large (%u)",
+ how_long_us));
status = AE_AML_OPERAND_VALUE;
} else {
if (how_long_us > 100) {
- ACPI_WARNING((AE_INFO,
- "Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
- how_long_us));
+ ACPI_WARNING_ONCE((AE_INFO,
+ "Time parameter %u us > 100 us violating ACPI spec, please fix the firmware.",
+ how_long_us));
}
acpi_os_stall(how_long_us);
}
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 36ea48f64110..8dbf83aeb455 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -16,20 +16,11 @@
ACPI_MODULE_NAME("hwxfsleep")
/* Local prototypes */
-#if (!ACPI_REDUCED_HARDWARE)
static acpi_status
acpi_hw_set_firmware_waking_vector(struct acpi_table_facs *facs,
acpi_physical_address physical_address,
acpi_physical_address physical_address64);
-#endif
-
-/*
- * These functions are removed for the ACPI_REDUCED_HARDWARE case:
- * acpi_set_firmware_waking_vector
- * acpi_enter_sleep_state_s4bios
- */
-#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_hw_set_firmware_waking_vector
@@ -115,6 +106,12 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address,
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
+/*
+ * These functions are removed for the ACPI_REDUCED_HARDWARE case:
+ * acpi_enter_sleep_state_s4bios
+ */
+
+#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_s4bios
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 422c074ed289..28582adfc0ac 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -25,6 +25,8 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state);
static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
*parser_state);
+static void acpi_ps_free_field_list(union acpi_parse_object *start);
+
/*******************************************************************************
*
* FUNCTION: acpi_ps_get_next_package_length
@@ -685,6 +687,39 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
/*******************************************************************************
*
+ * FUNCTION: acpi_ps_free_field_list
+ *
+ * PARAMETERS: start - First Op in field list
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free all Op objects inside a field list.
+ *
+ ******************************************************************************/
+
+static void acpi_ps_free_field_list(union acpi_parse_object *start)
+{
+ union acpi_parse_object *cur = start;
+ union acpi_parse_object *next;
+ union acpi_parse_object *arg;
+
+ while (cur) {
+ next = cur->common.next;
+
+ /* AML_INT_CONNECTION_OP can have a single argument */
+
+ arg = acpi_ps_get_arg(cur, 0);
+ if (arg) {
+ acpi_ps_free_op(arg);
+ }
+
+ acpi_ps_free_op(cur);
+ cur = next;
+ }
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ps_get_next_arg
*
* PARAMETERS: walk_state - Current state
@@ -751,6 +786,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
while (parser_state->aml < parser_state->pkg_end) {
field = acpi_ps_get_next_field(parser_state);
if (!field) {
+ if (arg) {
+ acpi_ps_free_field_list(arg);
+ }
+
return_ACPI_STATUS(AE_NO_MEMORY);
}
@@ -820,6 +859,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_NOT_METHOD_CALL);
+ if (ACPI_FAILURE(status)) {
+ acpi_ps_free_op(arg);
+ return_ACPI_STATUS(status);
+ }
} else {
/* Single complex argument, nothing returned */
@@ -854,6 +897,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_POSSIBLE_METHOD_CALL);
+ if (ACPI_FAILURE(status)) {
+ acpi_ps_free_op(arg);
+ return_ACPI_STATUS(status);
+ }
if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index fff48001d7ef..27384ee245f0 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -282,7 +282,8 @@ acpi_rs_get_address_common(struct acpi_resource *resource,
/* Validate the Resource Type */
- if ((address.resource_type > 2) && (address.resource_type < 0xC0)) {
+ if ((address.resource_type > 2) &&
+ (address.resource_type < 0xC0) && (address.resource_type != 0x0A)) {
return (FALSE);
}
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 611bc71c193f..5b7d7074ce4f 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -48,6 +48,7 @@ static void acpi_rs_dump_address_common(union acpi_resource_data *resource);
static void
acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table);
+#ifdef ACPI_DEBUGGER
/*******************************************************************************
*
* FUNCTION: acpi_rs_dump_resource_list
@@ -160,6 +161,7 @@ void acpi_rs_dump_irq_list(u8 *route_table)
prt_element, prt_element->length);
}
}
+#endif
/*******************************************************************************
*
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 15fa68a5ea6e..dad7425fce3f 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -18,7 +18,6 @@ ACPI_MODULE_NAME("tbutils")
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
-#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
* FUNCTION: acpi_tb_initialize_facs
@@ -56,7 +55,6 @@ acpi_status acpi_tb_initialize_facs(void)
return (AE_OK);
}
-#endif /* !ACPI_REDUCED_HARDWARE */
/*******************************************************************************
*
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 8d7736d2d269..c85bfa13ac1e 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -140,7 +140,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
(void)
acpi_os_delete_semaphore
(acpi_gbl_global_lock_semaphore);
- acpi_gbl_global_lock_semaphore = NULL;
+ acpi_gbl_global_lock_semaphore = ACPI_SEMAPHORE_NULL;
acpi_os_delete_mutex(object->mutex.os_mutex);
acpi_gbl_global_lock_mutex = NULL;
@@ -157,7 +157,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
object, object->event.os_semaphore));
(void)acpi_os_delete_semaphore(object->event.os_semaphore);
- object->event.os_semaphore = NULL;
+ object->event.os_semaphore = ACPI_SEMAPHORE_NULL;
break;
case ACPI_TYPE_METHOD:
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 92fbaef161a7..6d78504e9fbc 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -154,7 +154,7 @@ acpi_status acpi_ut_init_globals(void)
/* Global Lock support */
- acpi_gbl_global_lock_semaphore = NULL;
+ acpi_gbl_global_lock_semaphore = ACPI_SEMAPHORE_NULL;
acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
acpi_gbl_global_lock_handle = 0;
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 251bd396c6fd..99b85fd6eccf 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -75,6 +75,7 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
{"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1}, /* Windows 10 version 1903 - Added 08/2019 */
{"Windows 2020", NULL, 0, ACPI_OSI_WIN_10_20H1}, /* Windows 10 version 2004 - Added 08/2021 */
{"Windows 2021", NULL, 0, ACPI_OSI_WIN_11}, /* Windows 11 - Added 01/2022 */
+ {"Windows 2022", NULL, 0, ACPI_OSI_WIN_11_22H2}, /* Windows 11 version 22H2 - Added 04/2024 */
/* Feature Group Strings */
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 1915bec2b279..70ae0afa7939 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -120,6 +120,18 @@ acpi_status ACPI_INIT_FUNCTION acpi_enable_subsystem(u32 flags)
*/
acpi_gbl_early_initialization = FALSE;
+ /*
+ * Obtain a permanent mapping for the FACS. This is required for the
+ * Global Lock and the Firmware Waking Vector
+ */
+ if (!(flags & ACPI_NO_FACS_INIT)) {
+ status = acpi_tb_initialize_facs();
+ if (ACPI_FAILURE(status)) {
+ ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
+ return_ACPI_STATUS(status);
+ }
+ }
+
#if (!ACPI_REDUCED_HARDWARE)
/* Enable ACPI mode */
@@ -138,18 +150,6 @@ acpi_status ACPI_INIT_FUNCTION acpi_enable_subsystem(u32 flags)
}
/*
- * Obtain a permanent mapping for the FACS. This is required for the
- * Global Lock and the Firmware Waking Vector
- */
- if (!(flags & ACPI_NO_FACS_INIT)) {
- status = acpi_tb_initialize_facs();
- if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
- return_ACPI_STATUS(status);
- }
- }
-
- /*
* Initialize ACPI Event handling (Fixed and General Purpose)
*
* Note1: We must have the hardware and events initialized before we can
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index da3a879d638a..f4599261cfc3 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -10,7 +10,6 @@
#define pr_fmt(fmt) "ACPI: battery: " fmt
-#include <linux/async.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/jiffies.h>
@@ -50,8 +49,6 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
-static async_cookie_t async_cookie;
-static bool battery_driver_registered;
static int battery_bix_broken_package;
static int battery_notification_delay_ms;
static int battery_ac_is_broken;
@@ -1207,7 +1204,7 @@ static int acpi_battery_update_retry(struct acpi_battery *battery)
static int acpi_battery_add(struct acpi_device *device)
{
int result = 0;
- struct acpi_battery *battery = NULL;
+ struct acpi_battery *battery;
if (!device)
return -EINVAL;
@@ -1219,8 +1216,8 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
battery->device = device;
- strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
+ strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
+ strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
device->driver_data = battery;
mutex_init(&battery->lock);
mutex_init(&battery->sysfs_lock);
@@ -1260,7 +1257,7 @@ fail:
static void acpi_battery_remove(struct acpi_device *device)
{
- struct acpi_battery *battery = NULL;
+ struct acpi_battery *battery;
if (!device || !acpi_driver_data(device))
return;
@@ -1311,37 +1308,23 @@ static struct acpi_driver acpi_battery_driver = {
.remove = acpi_battery_remove,
},
.drv.pm = &acpi_battery_pm,
+ .drv.probe_type = PROBE_PREFER_ASYNCHRONOUS,
};
-static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
-{
- int result;
-
- if (acpi_quirk_skip_acpi_ac_and_battery())
- return;
-
- dmi_check_system(bat_dmi_table);
-
- result = acpi_bus_register_driver(&acpi_battery_driver);
- battery_driver_registered = (result == 0);
-}
-
static int __init acpi_battery_init(void)
{
- if (acpi_disabled)
+ if (acpi_disabled || acpi_quirk_skip_acpi_ac_and_battery())
return -ENODEV;
- async_cookie = async_schedule(acpi_battery_init_async, NULL);
- return 0;
+ dmi_check_system(bat_dmi_table);
+
+ return acpi_bus_register_driver(&acpi_battery_driver);
}
static void __exit acpi_battery_exit(void)
{
- async_synchronize_cookie(async_cookie + 1);
- if (battery_driver_registered) {
- acpi_bus_unregister_driver(&acpi_battery_driver);
- battery_hook_exit();
- }
+ acpi_bus_unregister_driver(&acpi_battery_driver);
+ battery_hook_exit();
}
module_init(acpi_battery_init);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 284bc2e03580..16917dc3ad60 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1203,6 +1203,9 @@ static int __init acpi_bus_init_irq(void)
case ACPI_IRQ_MODEL_LPIC:
message = "LPIC";
break;
+ case ACPI_IRQ_MODEL_RINTC:
+ message = "RINTC";
+ break;
default:
pr_info("Unknown interrupt routing model\n");
return -ENODEV;
@@ -1459,6 +1462,7 @@ static int __init acpi_init(void)
acpi_hest_init();
acpi_ghes_init();
acpi_arm_init();
+ acpi_riscv_init();
acpi_scan_init();
acpi_ec_init();
acpi_debugfs_init();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index cc61020756be..51470208e6da 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -547,20 +547,20 @@ static int acpi_button_add(struct acpi_device *device)
!strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
button->type = ACPI_BUTTON_TYPE_POWER;
handler = acpi_button_notify;
- strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
+ strscpy(name, ACPI_BUTTON_DEVICE_NAME_POWER, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
} else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
!strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
button->type = ACPI_BUTTON_TYPE_SLEEP;
handler = acpi_button_notify;
- strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
+ strscpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
} else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
button->type = ACPI_BUTTON_TYPE_LID;
handler = acpi_lid_notify;
- strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
+ strscpy(name, ACPI_BUTTON_DEVICE_NAME_LID, MAX_ACPI_DEVICE_NAME_LEN);
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
input->open = acpi_lid_input_open;
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index dd3d3082c8c7..5b06e236aabe 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -103,6 +103,11 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
(cpc)->cpc_entry.reg.space_id == \
ACPI_ADR_SPACE_PLATFORM_COMM)
+/* Check if a CPC register is in FFH */
+#define CPC_IN_FFH(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
+ (cpc)->cpc_entry.reg.space_id == \
+ ACPI_ADR_SPACE_FIXED_HARDWARE)
+
/* Check if a CPC register is in SystemMemory */
#define CPC_IN_SYSTEM_MEMORY(cpc) ((cpc)->type == ACPI_TYPE_BUFFER && \
(cpc)->cpc_entry.reg.space_id == \
@@ -171,8 +176,11 @@ show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
#define GET_BIT_WIDTH(reg) ((reg)->access_width ? (8 << ((reg)->access_width - 1)) : (reg)->bit_width)
/* Shift and apply the mask for CPC reads/writes */
-#define MASK_VAL(reg, val) (((val) >> (reg)->bit_offset) & \
+#define MASK_VAL_READ(reg, val) (((val) >> (reg)->bit_offset) & \
GENMASK(((reg)->bit_width) - 1, 0))
+#define MASK_VAL_WRITE(reg, prev_val, val) \
+ ((((val) & GENMASK(((reg)->bit_width) - 1, 0)) << (reg)->bit_offset) | \
+ ((prev_val) & ~(GENMASK(((reg)->bit_width) - 1, 0) << (reg)->bit_offset))) \
static ssize_t show_feedback_ctrs(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@@ -859,6 +867,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
/* Store CPU Logical ID */
cpc_ptr->cpu_id = pr->id;
+ spin_lock_init(&cpc_ptr->rmw_lock);
/* Parse PSD data for this CPU */
ret = acpi_get_psd(cpc_ptr, handle);
@@ -1064,7 +1073,7 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
}
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- *val = MASK_VAL(reg, *val);
+ *val = MASK_VAL_READ(reg, *val);
return 0;
}
@@ -1073,9 +1082,11 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
{
int ret_val = 0;
int size;
+ u64 prev_val;
void __iomem *vaddr = NULL;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
struct cpc_reg *reg = &reg_res->cpc_entry.reg;
+ struct cpc_desc *cpc_desc;
size = GET_BIT_WIDTH(reg);
@@ -1108,8 +1119,34 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
return acpi_os_write_memory((acpi_physical_address)reg->address,
val, size);
- if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- val = MASK_VAL(reg, val);
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+ if (!cpc_desc) {
+ pr_debug("No CPC descriptor for CPU:%d\n", cpu);
+ return -ENODEV;
+ }
+
+ spin_lock(&cpc_desc->rmw_lock);
+ switch (size) {
+ case 8:
+ prev_val = readb_relaxed(vaddr);
+ break;
+ case 16:
+ prev_val = readw_relaxed(vaddr);
+ break;
+ case 32:
+ prev_val = readl_relaxed(vaddr);
+ break;
+ case 64:
+ prev_val = readq_relaxed(vaddr);
+ break;
+ default:
+ spin_unlock(&cpc_desc->rmw_lock);
+ return -EFAULT;
+ }
+ val = MASK_VAL_WRITE(reg, prev_val, val);
+ val |= prev_val;
+ }
switch (size) {
case 8:
@@ -1136,6 +1173,9 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
break;
}
+ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ spin_unlock(&cpc_desc->rmw_lock);
+
return ret_val;
}
@@ -1486,9 +1526,12 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
/* after writing CPC, transfer the ownership of PCC to platform */
ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
up_write(&pcc_ss_data->pcc_lock);
+ } else if (osc_cpc_flexible_adr_space_confirmed &&
+ CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
+ ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
} else {
ret = -ENOTSUPP;
- pr_debug("_CPC in PCC is not supported\n");
+ pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
}
return ret;
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 23373faa35ec..3961fc47152c 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -439,23 +439,33 @@ static ssize_t description_show(struct device *dev,
char *buf)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *str_obj;
+ acpi_status status;
int result;
- if (acpi_dev->pnp.str_obj == NULL)
- return 0;
+ status = acpi_evaluate_object_typed(acpi_dev->handle, "_STR",
+ NULL, &buffer,
+ ACPI_TYPE_BUFFER);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ str_obj = buffer.pointer;
/*
* The _STR object contains a Unicode identifier for a device.
* We need to convert to utf-8 so it can be displayed.
*/
result = utf16s_to_utf8s(
- (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer,
- acpi_dev->pnp.str_obj->buffer.length,
+ (wchar_t *)str_obj->buffer.pointer,
+ str_obj->buffer.length,
UTF16_LITTLE_ENDIAN, buf,
PAGE_SIZE - 1);
buf[result++] = '\n';
+ kfree(str_obj);
+
return result;
}
static DEVICE_ATTR_RO(description);
@@ -507,96 +517,97 @@ static ssize_t status_show(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR_RO(status);
-/**
- * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
- * @dev: ACPI device object.
- */
-int acpi_device_setup_files(struct acpi_device *dev)
-{
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- acpi_status status;
- int result = 0;
+static struct attribute *acpi_attrs[] = {
+ &dev_attr_path.attr,
+ &dev_attr_hid.attr,
+ &dev_attr_modalias.attr,
+ &dev_attr_description.attr,
+ &dev_attr_adr.attr,
+ &dev_attr_uid.attr,
+ &dev_attr_sun.attr,
+ &dev_attr_hrv.attr,
+ &dev_attr_status.attr,
+ &dev_attr_eject.attr,
+ &dev_attr_power_state.attr,
+ &dev_attr_real_power_state.attr,
+ NULL
+};
+static bool acpi_show_attr(struct acpi_device *dev, const struct device_attribute *attr)
+{
/*
* Devices gotten from FADT don't have a "path" attribute
*/
- if (dev->handle) {
- result = device_create_file(&dev->dev, &dev_attr_path);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_path)
+ return dev->handle;
- if (!list_empty(&dev->pnp.ids)) {
- result = device_create_file(&dev->dev, &dev_attr_hid);
- if (result)
- goto end;
+ if (attr == &dev_attr_hid || attr == &dev_attr_modalias)
+ return !list_empty(&dev->pnp.ids);
- result = device_create_file(&dev->dev, &dev_attr_modalias);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_description)
+ return acpi_has_method(dev->handle, "_STR");
- /*
- * If device has _STR, 'description' file is created
- */
- if (acpi_has_method(dev->handle, "_STR")) {
- status = acpi_evaluate_object(dev->handle, "_STR",
- NULL, &buffer);
- if (ACPI_FAILURE(status))
- buffer.pointer = NULL;
- dev->pnp.str_obj = buffer.pointer;
- result = device_create_file(&dev->dev, &dev_attr_description);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_adr)
+ return dev->pnp.type.bus_address;
- if (dev->pnp.type.bus_address)
- result = device_create_file(&dev->dev, &dev_attr_adr);
- if (acpi_device_uid(dev))
- result = device_create_file(&dev->dev, &dev_attr_uid);
+ if (attr == &dev_attr_uid)
+ return acpi_device_uid(dev);
- if (acpi_has_method(dev->handle, "_SUN")) {
- result = device_create_file(&dev->dev, &dev_attr_sun);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_sun)
+ return acpi_has_method(dev->handle, "_SUN");
- if (acpi_has_method(dev->handle, "_HRV")) {
- result = device_create_file(&dev->dev, &dev_attr_hrv);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_hrv)
+ return acpi_has_method(dev->handle, "_HRV");
- if (acpi_has_method(dev->handle, "_STA")) {
- result = device_create_file(&dev->dev, &dev_attr_status);
- if (result)
- goto end;
- }
+ if (attr == &dev_attr_status)
+ return acpi_has_method(dev->handle, "_STA");
/*
* If device has _EJ0, 'eject' file is created that is used to trigger
* hot-removal function from userland.
*/
- if (acpi_has_method(dev->handle, "_EJ0")) {
- result = device_create_file(&dev->dev, &dev_attr_eject);
- if (result)
- return result;
- }
+ if (attr == &dev_attr_eject)
+ return acpi_has_method(dev->handle, "_EJ0");
- if (dev->flags.power_manageable) {
- result = device_create_file(&dev->dev, &dev_attr_power_state);
- if (result)
- return result;
+ if (attr == &dev_attr_power_state)
+ return dev->flags.power_manageable;
- if (dev->power.flags.power_resources)
- result = device_create_file(&dev->dev,
- &dev_attr_real_power_state);
- }
+ if (attr == &dev_attr_real_power_state)
+ return dev->flags.power_manageable && dev->power.flags.power_resources;
- acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
+ dev_warn_once(&dev->dev, "Unexpected attribute: %s\n", attr->attr.name);
+ return false;
+}
-end:
- return result;
+static umode_t acpi_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int attrno)
+{
+ struct acpi_device *dev = to_acpi_device(kobj_to_dev(kobj));
+
+ if (acpi_show_attr(dev, container_of(attr, struct device_attribute, attr)))
+ return attr->mode;
+ else
+ return 0;
+}
+
+static const struct attribute_group acpi_group = {
+ .attrs = acpi_attrs,
+ .is_visible = acpi_attr_is_visible,
+};
+
+const struct attribute_group *acpi_groups[] = {
+ &acpi_group,
+ NULL
+};
+
+/**
+ * acpi_device_setup_files - Create sysfs attributes of an ACPI device.
+ * @dev: ACPI device object.
+ */
+void acpi_device_setup_files(struct acpi_device *dev)
+{
+ acpi_expose_nondev_subnodes(&dev->dev.kobj, &dev->data);
}
/**
@@ -606,41 +617,4 @@ end:
void acpi_device_remove_files(struct acpi_device *dev)
{
acpi_hide_nondev_subnodes(&dev->data);
-
- if (dev->flags.power_manageable) {
- device_remove_file(&dev->dev, &dev_attr_power_state);
- if (dev->power.flags.power_resources)
- device_remove_file(&dev->dev,
- &dev_attr_real_power_state);
- }
-
- /*
- * If device has _STR, remove 'description' file
- */
- if (acpi_has_method(dev->handle, "_STR")) {
- kfree(dev->pnp.str_obj);
- device_remove_file(&dev->dev, &dev_attr_description);
- }
- /*
- * If device has _EJ0, remove 'eject' file.
- */
- if (acpi_has_method(dev->handle, "_EJ0"))
- device_remove_file(&dev->dev, &dev_attr_eject);
-
- if (acpi_has_method(dev->handle, "_SUN"))
- device_remove_file(&dev->dev, &dev_attr_sun);
-
- if (acpi_has_method(dev->handle, "_HRV"))
- device_remove_file(&dev->dev, &dev_attr_hrv);
-
- if (acpi_device_uid(dev))
- device_remove_file(&dev->dev, &dev_attr_uid);
- if (dev->pnp.type.bus_address)
- device_remove_file(&dev->dev, &dev_attr_adr);
- device_remove_file(&dev->dev, &dev_attr_modalias);
- device_remove_file(&dev->dev, &dev_attr_hid);
- if (acpi_has_method(dev->handle, "_STA"))
- device_remove_file(&dev->dev, &dev_attr_status);
- if (dev->handle)
- device_remove_file(&dev->dev, &dev_attr_path);
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 38d2f6e6b12b..25399f6dde7e 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -783,6 +783,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
unsigned long tmp;
int ret = 0;
+ if (t->rdata)
+ memset(t->rdata, 0, t->rlen);
+
/* start transaction */
spin_lock_irqsave(&ec->lock, tmp);
/* Enable GPE for command processing (IBF=0/OBF=1) */
@@ -819,8 +822,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
return -EINVAL;
- if (t->rdata)
- memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->mutex);
if (ec->global_lock) {
@@ -847,7 +848,7 @@ static int acpi_ec_burst_enable(struct acpi_ec *ec)
.wdata = NULL, .rdata = &d,
.wlen = 0, .rlen = 1};
- return acpi_ec_transaction(ec, &t);
+ return acpi_ec_transaction_unlocked(ec, &t);
}
static int acpi_ec_burst_disable(struct acpi_ec *ec)
@@ -857,7 +858,7 @@ static int acpi_ec_burst_disable(struct acpi_ec *ec)
.wlen = 0, .rlen = 0};
return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
- acpi_ec_transaction(ec, &t) : 0;
+ acpi_ec_transaction_unlocked(ec, &t) : 0;
}
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
@@ -873,6 +874,19 @@ static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
return result;
}
+static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
+{
+ int result;
+ u8 d;
+ struct transaction t = {.command = ACPI_EC_COMMAND_READ,
+ .wdata = &address, .rdata = &d,
+ .wlen = 1, .rlen = 1};
+
+ result = acpi_ec_transaction_unlocked(ec, &t);
+ *data = d;
+ return result;
+}
+
static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
{
u8 wdata[2] = { address, data };
@@ -883,6 +897,16 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
return acpi_ec_transaction(ec, &t);
}
+static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
+{
+ u8 wdata[2] = { address, data };
+ struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
+ .wdata = wdata, .rdata = NULL,
+ .wlen = 2, .rlen = 0};
+
+ return acpi_ec_transaction_unlocked(ec, &t);
+}
+
int ec_read(u8 addr, u8 *val)
{
int err;
@@ -1323,6 +1347,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
struct acpi_ec *ec = handler_context;
int result = 0, i, bytes = bits / 8;
u8 *value = (u8 *)value64;
+ u32 glk;
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
@@ -1330,13 +1355,25 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
+ mutex_lock(&ec->mutex);
+
+ if (ec->global_lock) {
+ acpi_status status;
+
+ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+ if (ACPI_FAILURE(status)) {
+ result = -ENODEV;
+ goto unlock;
+ }
+ }
+
if (ec->busy_polling || bits > 8)
acpi_ec_burst_enable(ec);
for (i = 0; i < bytes; ++i, ++address, ++value) {
result = (function == ACPI_READ) ?
- acpi_ec_read(ec, address, value) :
- acpi_ec_write(ec, address, *value);
+ acpi_ec_read_unlocked(ec, address, value) :
+ acpi_ec_write_unlocked(ec, address, *value);
if (result < 0)
break;
}
@@ -1344,6 +1381,12 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (ec->busy_polling || bits > 8)
acpi_ec_burst_disable(ec);
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+
+unlock:
+ mutex_unlock(&ec->mutex);
+
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index aadd4c218b32..ced7dff9a5db 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -118,8 +118,9 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, void (*release)(struct device *));
int acpi_tie_acpi_dev(struct acpi_device *adev);
int acpi_device_add(struct acpi_device *device);
-int acpi_device_setup_files(struct acpi_device *dev);
+void acpi_device_setup_files(struct acpi_device *dev);
void acpi_device_remove_files(struct acpi_device *dev);
+extern const struct attribute_group *acpi_groups[];
void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
bool acpi_device_is_enabled(const struct acpi_device *adev);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index aa1038b8aec4..b727db968f33 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -748,6 +748,8 @@ static int acpi_pci_link_add(struct acpi_device *device,
if (result)
kfree(link);
+ acpi_dev_clear_dependencies(device);
+
return result < 0 ? result : 1;
}
diff --git a/drivers/acpi/pmic/tps68470_pmic.c b/drivers/acpi/pmic/tps68470_pmic.c
index ebd03e472955..0d1a82eeb4b0 100644
--- a/drivers/acpi/pmic/tps68470_pmic.c
+++ b/drivers/acpi/pmic/tps68470_pmic.c
@@ -376,10 +376,8 @@ static int tps68470_pmic_opregion_probe(struct platform_device *pdev)
struct tps68470_pmic_opregion *opregion;
acpi_status status;
- if (!dev || !tps68470_regmap) {
- dev_warn(dev, "dev or regmap is NULL\n");
- return -EINVAL;
- }
+ if (!tps68470_regmap)
+ return dev_err_probe(dev, -EINVAL, "regmap is missing\n");
if (!handle) {
dev_warn(dev, "acpi handle is NULL\n");
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index df5d5a554b38..8a4726e2eb69 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -504,6 +504,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
},
},
{
+ /* Asus Vivobook Go E1404GAB */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "E1404GAB"),
+ },
+ },
+ {
/* Asus Vivobook E1504GA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -555,6 +562,12 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
*/
static const struct dmi_system_id irq1_edge_low_force_override[] = {
{
+ /* MECHREV Jiaolong17KS Series GM7XG0M */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GM7XG0M"),
+ },
+ },
+ {
/* XMG APEX 17 (M23) */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GMxBGxx"),
@@ -573,6 +586,12 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = {
},
},
{
+ /* TongFang GMxXGxX/TUXEDO Polaris 15 Gen5 AMD */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GMxXGxX"),
+ },
+ },
+ {
/* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Eluktronics Inc."),
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 86b0925f612d..a96fdf1e2cb8 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += rhct.o
+obj-y += rhct.o init.o irq.o
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
new file mode 100644
index 000000000000..5ef97905a727
--- /dev/null
+++ b/drivers/acpi/riscv/init.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023-2024, Ventana Micro Systems Inc
+ * Author: Sunil V L <sunilvl@ventanamicro.com>
+ */
+
+#include <linux/acpi.h>
+#include "init.h"
+
+void __init acpi_riscv_init(void)
+{
+ riscv_acpi_init_gsi_mapping();
+}
diff --git a/drivers/acpi/riscv/init.h b/drivers/acpi/riscv/init.h
new file mode 100644
index 000000000000..0b9a07e4031f
--- /dev/null
+++ b/drivers/acpi/riscv/init.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <linux/init.h>
+
+void __init riscv_acpi_init_gsi_mapping(void);
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
new file mode 100644
index 000000000000..cced960c2aef
--- /dev/null
+++ b/drivers/acpi/riscv/irq.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023-2024, Ventana Micro Systems Inc
+ * Author: Sunil V L <sunilvl@ventanamicro.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/sort.h>
+#include <linux/irq.h>
+
+#include "init.h"
+
+struct riscv_ext_intc_list {
+ acpi_handle handle;
+ u32 gsi_base;
+ u32 nr_irqs;
+ u32 nr_idcs;
+ u32 id;
+ u32 type;
+ struct list_head list;
+};
+
+struct acpi_irq_dep_ctx {
+ int rc;
+ unsigned int index;
+ acpi_handle handle;
+};
+
+LIST_HEAD(ext_intc_list);
+
+static int irqchip_cmp_func(const void *in0, const void *in1)
+{
+ struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0;
+ struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1;
+
+ return (elem0->type > elem1->type) - (elem0->type < elem1->type);
+}
+
+/*
+ * On RISC-V, RINTC structures in MADT should be probed before any other
+ * interrupt controller structures and IMSIC before APLIC. The interrupt
+ * controller subtypes in MADT of ACPI spec for RISC-V are defined in
+ * the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27).
+ * Hence, simply sorting the subtypes in incremental order will
+ * establish the required order.
+ */
+void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)
+{
+ struct acpi_probe_entry *ape = ap_head;
+
+ if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id))
+ return;
+ sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);
+}
+
+static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle)
+{
+ struct riscv_ext_intc_list *ext_intc_element;
+ struct list_head *i, *tmp;
+
+ list_for_each_safe(i, tmp, &ext_intc_list) {
+ ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
+ if (gsi_base == ext_intc_element->gsi_base) {
+ ext_intc_element->handle = handle;
+ return AE_OK;
+ }
+ }
+
+ return AE_NOT_FOUND;
+}
+
+int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,
+ u32 *id, u32 *nr_irqs, u32 *nr_idcs)
+{
+ struct riscv_ext_intc_list *ext_intc_element;
+ struct list_head *i;
+
+ list_for_each(i, &ext_intc_list) {
+ ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
+ if (ext_intc_element->handle == ACPI_HANDLE_FWNODE(fwnode)) {
+ *gsi_base = ext_intc_element->gsi_base;
+ *id = ext_intc_element->id;
+ *nr_irqs = ext_intc_element->nr_irqs;
+ if (nr_idcs)
+ *nr_idcs = ext_intc_element->nr_idcs;
+
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi)
+{
+ struct riscv_ext_intc_list *ext_intc_element;
+ struct acpi_device *adev;
+ struct list_head *i;
+
+ list_for_each(i, &ext_intc_list) {
+ ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
+ if (gsi >= ext_intc_element->gsi_base &&
+ gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs)) {
+ adev = acpi_fetch_acpi_dev(ext_intc_element->handle);
+ if (!adev)
+ return NULL;
+
+ return acpi_fwnode_handle(adev);
+ }
+ }
+
+ return NULL;
+}
+
+static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs,
+ u32 id, u32 type)
+{
+ struct riscv_ext_intc_list *ext_intc_element;
+
+ ext_intc_element = kzalloc(sizeof(*ext_intc_element), GFP_KERNEL);
+ if (!ext_intc_element)
+ return -ENOMEM;
+
+ ext_intc_element->gsi_base = gsi_base;
+ ext_intc_element->nr_irqs = nr_irqs;
+ ext_intc_element->nr_idcs = nr_idcs;
+ ext_intc_element->id = id;
+ list_add_tail(&ext_intc_element->list, &ext_intc_list);
+ return 0;
+}
+
+static acpi_status __init riscv_acpi_create_gsi_map(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ acpi_status status;
+ u64 gbase;
+
+ if (!acpi_has_method(handle, "_GSB")) {
+ acpi_handle_err(handle, "_GSB method not found\n");
+ return AE_ERROR;
+ }
+
+ status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "failed to evaluate _GSB method\n");
+ return status;
+ }
+
+ status = riscv_acpi_update_gsi_handle((u32)gbase, handle);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "failed to find the GSI mapping entry\n");
+ return status;
+ }
+
+ return AE_OK;
+}
+
+static int __init riscv_acpi_aplic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header;
+
+ return riscv_acpi_register_ext_intc(aplic->gsi_base, aplic->num_sources, aplic->num_idcs,
+ aplic->id, ACPI_RISCV_IRQCHIP_APLIC);
+}
+
+static int __init riscv_acpi_plic_parse_madt(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_madt_plic *plic = (struct acpi_madt_plic *)header;
+
+ return riscv_acpi_register_ext_intc(plic->gsi_base, plic->num_irqs, 0,
+ plic->id, ACPI_RISCV_IRQCHIP_PLIC);
+}
+
+void __init riscv_acpi_init_gsi_mapping(void)
+{
+ /* There can be either PLIC or APLIC */
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_PLIC, riscv_acpi_plic_parse_madt, 0) > 0) {
+ acpi_get_devices("RSCV0001", riscv_acpi_create_gsi_map, NULL, NULL);
+ return;
+ }
+
+ if (acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, riscv_acpi_aplic_parse_madt, 0) > 0)
+ acpi_get_devices("RSCV0002", riscv_acpi_create_gsi_map, NULL, NULL);
+}
+
+static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
+{
+ struct riscv_ext_intc_list *ext_intc_element;
+ struct list_head *i;
+
+ list_for_each(i, &ext_intc_list) {
+ ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);
+ if (gsi >= ext_intc_element->gsi_base &&
+ gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs))
+ return ext_intc_element->handle;
+ }
+
+ return NULL;
+}
+
+static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)
+{
+ struct acpi_irq_dep_ctx *ctx = context;
+ struct acpi_resource_irq *irq;
+ struct acpi_resource_extended_irq *eirq;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ irq = &ares->data.irq;
+ if (ctx->index >= irq->interrupt_count) {
+ ctx->index -= irq->interrupt_count;
+ return AE_OK;
+ }
+ ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);
+ return AE_CTRL_TERMINATE;
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ eirq = &ares->data.extended_irq;
+ if (eirq->producer_consumer == ACPI_PRODUCER)
+ return AE_OK;
+
+ if (ctx->index >= eirq->interrupt_count) {
+ ctx->index -= eirq->interrupt_count;
+ return AE_OK;
+ }
+
+ /* Support GSIs only */
+ if (eirq->resource_source.string_length)
+ return AE_OK;
+
+ ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+ return AE_CTRL_TERMINATE;
+ }
+
+ return AE_OK;
+}
+
+static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
+{
+ struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
+
+ if (!gsi_handle)
+ return 0;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
+ *gsi_handle = ctx.handle;
+ if (*gsi_handle)
+ return 1;
+
+ return 0;
+}
+
+static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_pci_routing_table *entry;
+ struct acpi_handle_list dep_devices;
+ acpi_handle gsi_handle;
+ acpi_handle link_handle;
+ acpi_status status;
+ u32 count = 0;
+
+ status = acpi_get_irq_routing_table(handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_err(handle, "failed to get IRQ routing table\n");
+ kfree(buffer.pointer);
+ return 0;
+ }
+
+ entry = buffer.pointer;
+ while (entry && (entry->length > 0)) {
+ if (entry->source[0]) {
+ acpi_get_handle(handle, entry->source, &link_handle);
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = link_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ } else {
+ gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = gsi_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ }
+
+ entry = (struct acpi_pci_routing_table *)
+ ((unsigned long)entry + entry->length);
+ }
+
+ kfree(buffer.pointer);
+ return count;
+}
+
+static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
+{
+ struct acpi_handle_list dep_devices;
+ acpi_handle gsi_handle;
+ u32 count = 0;
+ int i;
+
+ for (i = 0;
+ riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
+ i++) {
+ dep_devices.count = 1;
+ dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+ if (!dep_devices.handles) {
+ acpi_handle_err(handle, "failed to allocate memory\n");
+ continue;
+ }
+
+ dep_devices.handles[0] = gsi_handle;
+ count += acpi_scan_add_dep(handle, &dep_devices);
+ }
+
+ return count;
+}
+
+u32 arch_acpi_add_auto_dep(acpi_handle handle)
+{
+ if (acpi_has_method(handle, "_PRT"))
+ return riscv_acpi_add_prt_dep(handle);
+
+ return riscv_acpi_add_irq_dep(handle);
+}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 22ae7829a915..7ecc401fb97f 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -795,10 +795,7 @@ int acpi_device_add(struct acpi_device *device)
goto err;
}
- result = acpi_device_setup_files(device);
- if (result)
- pr_err("Error creating sysfs interface for device %s\n",
- dev_name(&device->dev));
+ acpi_device_setup_files(device);
return 0;
@@ -861,6 +858,9 @@ static const char * const acpi_honor_dep_ids[] = {
"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
"INTC100A", /* IVSC (RPL) driver must be loaded to allow i2c access to camera sensors */
"INTC10CF", /* IVSC (MTL) driver must be loaded to allow i2c access to camera sensors */
+ "RSCV0001", /* RISC-V PLIC */
+ "RSCV0002", /* RISC-V APLIC */
+ "PNP0C0F", /* PCI Link Device */
NULL
};
@@ -1822,6 +1822,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->dev.parent = parent ? &parent->dev : NULL;
device->dev.release = release;
device->dev.bus = &acpi_bus_type;
+ device->dev.groups = acpi_groups;
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
acpi_set_device_status(device, ACPI_STA_DEFAULT);
acpi_device_get_busid(device);
@@ -2013,6 +2014,49 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
mutex_unlock(&acpi_scan_lock);
}
+int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices)
+{
+ u32 count;
+ int i;
+
+ for (count = 0, i = 0; i < dep_devices->count; i++) {
+ struct acpi_device_info *info;
+ struct acpi_dep_data *dep;
+ bool skip, honor_dep;
+ acpi_status status;
+
+ status = acpi_get_object_info(dep_devices->handles[i], &info);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(handle, "Error reading _DEP device info\n");
+ continue;
+ }
+
+ skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
+ honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
+ kfree(info);
+
+ if (skip)
+ continue;
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep)
+ continue;
+
+ count++;
+
+ dep->supplier = dep_devices->handles[i];
+ dep->consumer = handle;
+ dep->honor_dep = honor_dep;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_add_tail(&dep->node, &acpi_dep_list);
+ mutex_unlock(&acpi_dep_list_lock);
+ }
+
+ acpi_handle_list_free(dep_devices);
+ return count;
+}
+
static void acpi_scan_init_hotplug(struct acpi_device *adev)
{
struct acpi_hardware_id *hwid;
@@ -2032,11 +2076,21 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
}
}
+u32 __weak arch_acpi_add_auto_dep(acpi_handle handle) { return 0; }
+
static u32 acpi_scan_check_dep(acpi_handle handle)
{
struct acpi_handle_list dep_devices;
- u32 count;
- int i;
+ u32 count = 0;
+
+ /*
+ * Some architectures like RISC-V need to add dependencies for
+ * all devices which use GSI to the interrupt controller so that
+ * interrupt controller is probed before any of those devices.
+ * Instead of mandating _DEP on all the devices, detect the
+ * dependency and add automatically.
+ */
+ count += arch_acpi_add_auto_dep(handle);
/*
* Check for _HID here to avoid deferring the enumeration of:
@@ -2045,48 +2099,14 @@ static u32 acpi_scan_check_dep(acpi_handle handle)
* Still, checking for _HID catches more then just these cases ...
*/
if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID"))
- return 0;
+ return count;
if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) {
acpi_handle_debug(handle, "Failed to evaluate _DEP.\n");
- return 0;
- }
-
- for (count = 0, i = 0; i < dep_devices.count; i++) {
- struct acpi_device_info *info;
- struct acpi_dep_data *dep;
- bool skip, honor_dep;
- acpi_status status;
-
- status = acpi_get_object_info(dep_devices.handles[i], &info);
- if (ACPI_FAILURE(status)) {
- acpi_handle_debug(handle, "Error reading _DEP device info\n");
- continue;
- }
-
- skip = acpi_info_matches_ids(info, acpi_ignore_dep_ids);
- honor_dep = acpi_info_matches_ids(info, acpi_honor_dep_ids);
- kfree(info);
-
- if (skip)
- continue;
-
- dep = kzalloc(sizeof(*dep), GFP_KERNEL);
- if (!dep)
- continue;
-
- count++;
-
- dep->supplier = dep_devices.handles[i];
- dep->consumer = handle;
- dep->honor_dep = honor_dep;
-
- mutex_lock(&acpi_dep_list_lock);
- list_add_tail(&dep->node , &acpi_dep_list);
- mutex_unlock(&acpi_dep_list_lock);
+ return count;
}
- acpi_handle_list_free(&dep_devices);
+ count += acpi_scan_add_dep(handle, &dep_devices);
return count;
}
@@ -2757,6 +2777,8 @@ static int __init acpi_match_madt(union acpi_subtable_headers *header,
return 0;
}
+void __weak arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr) { }
+
int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
{
int count = 0;
@@ -2765,6 +2787,7 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
return 0;
mutex_lock(&acpi_probe_mutex);
+ arch_sort_irqchip_probe(ap_head, nr);
for (ape = ap_head; nr; ape++, nr--) {
if (ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id)) {
acpi_probe_count = 0;
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 889f1c1a1fa9..c8ee8e42b0f6 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -352,6 +352,20 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
},
},
/*
+ * The ASUS ROG M16 from 2023 has many events which wake it from s2idle
+ * resulting in excessive battery drain and risk of laptop overheating,
+ * these events can be caused by the MMC or y AniMe display if installed.
+ * The match is valid for all of the GU604V<x> range.
+ */
+ {
+ .callback = init_default_s3,
+ .ident = "ASUS ROG Zephyrus M16 (2023)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus M16 GU604V"),
+ },
+ },
+ /*
* https://bugzilla.kernel.org/show_bug.cgi?id=189431
* Lenovo G50-45 is a platform later than 2012, but needs nvs memory
* saving during S3.
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index ae9384282273..6de542d99518 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -801,7 +801,8 @@ acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func,
if (ret != AE_NOT_FOUND)
acpi_handle_warn(handle,
- "failed to evaluate _DSM %pUb (0x%x)\n", guid, ret);
+ "failed to evaluate _DSM %pUb rev:%lld func:%lld (0x%x)\n",
+ guid, rev, func, ret);
return NULL;
}
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 674b9db7a1ef..b70e84e8049a 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -254,6 +254,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"),
},
},
+ {
+ .callback = video_detect_force_vendor,
+ /* Panasonic Toughbook CF-18 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita Electric Industrial"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
+ },
+ },
/*
* Toshiba models with Transflective display, these need to use
@@ -550,6 +558,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ .callback = video_detect_force_native,
+ /* Apple MacBook Pro 9,2 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,2"),
+ },
+ },
+ {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
.callback = video_detect_force_native,
/* Apple MacBook Pro 12,1 */
@@ -896,7 +912,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
/* Lenovo Yoga Tab 3 Pro YT3-X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
},
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index ab2b5fa83e1f..6af546b21574 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -355,7 +355,6 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
/* Lenovo Yoga Tab 3 Pro X90F */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
},
.driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |