summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/acpica/nswalk.c3
-rw-r--r--drivers/acpi/battery.c12
-rw-r--r--drivers/acpi/bus.c42
-rw-r--r--drivers/acpi/cppc_acpi.c3
-rw-r--r--drivers/acpi/ec.c90
-rw-r--r--drivers/acpi/fan.h44
-rw-r--r--drivers/acpi/fan_attr.c137
-rw-r--r--drivers/acpi/fan_core.c (renamed from drivers/acpi/fan.c)204
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/osl.c19
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/property.c29
-rw-r--r--drivers/acpi/scan.c15
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/acpi/tables.c2
17 files changed, 410 insertions, 201 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 273741dedfd2..1e34f846508f 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -302,7 +302,7 @@ config ACPI_IPMI
help
This driver enables the ACPI to access the BMC controller. And it
uses the IPMI request/response message to communicate with BMC
- controller, which can be found on on the server.
+ controller, which can be found on the server.
To compile this driver as a module, choose M here:
the module will be called as acpi_ipmi.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bb757148e7ba..b5a8d3e00a52 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -81,6 +81,9 @@ obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_TINY_POWER_BUTTON) += tiny-power-button.o
obj-$(CONFIG_ACPI_FAN) += fan.o
+fan-objs := fan_core.o
+fan-objs += fan_attr.o
+
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_TAD) += acpi_tad.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 915c2433463d..e7c30ce06e18 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -169,6 +169,9 @@ acpi_ns_walk_namespace(acpi_object_type type,
if (start_node == ACPI_ROOT_OBJECT) {
start_node = acpi_gbl_root_node;
+ if (!start_node) {
+ return_ACPI_STATUS(AE_NO_NAMESPACE);
+ }
}
/* Null child means "get first node" */
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index ea31ae01458b..dc208f5f5a1f 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -59,6 +59,10 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
static const struct acpi_device_id battery_device_ids[] = {
{"PNP0C0A", 0},
+
+ /* Microsoft Surface Go 3 */
+ {"MSHW0146", 0},
+
{"", 0},
};
@@ -1148,6 +1152,14 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"),
},
},
+ {
+ /* Microsoft Surface Go 3 */
+ .callback = battery_notification_delay_quirk,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
+ },
+ },
{},
};
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 07f604832fd6..8aa7860602e7 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -283,6 +283,8 @@ EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed);
bool osc_sb_native_usb4_support_confirmed;
EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
+bool osc_sb_cppc_not_supported;
+
static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
static void acpi_bus_osc_negotiate_platform_control(void)
{
@@ -332,21 +334,38 @@ static void acpi_bus_osc_negotiate_platform_control(void)
if (ACPI_FAILURE(acpi_run_osc(handle, &context)))
return;
- kfree(context.ret.pointer);
+ capbuf_ret = context.ret.pointer;
+ if (context.ret.length <= OSC_SUPPORT_DWORD) {
+ kfree(context.ret.pointer);
+ return;
+ }
+
+#ifdef CONFIG_X86
+ if (boot_cpu_has(X86_FEATURE_HWP))
+ osc_sb_cppc_not_supported = !(capbuf_ret[OSC_SUPPORT_DWORD] &
+ (OSC_SB_CPC_SUPPORT | OSC_SB_CPCV2_SUPPORT));
+#endif
- /* Now run _OSC again with query flag clear */
+ /*
+ * Now run _OSC again with query flag clear and with the caps
+ * supported by both the OS and the platform.
+ */
capbuf[OSC_QUERY_DWORD] = 0;
+ capbuf[OSC_SUPPORT_DWORD] = capbuf_ret[OSC_SUPPORT_DWORD];
+ kfree(context.ret.pointer);
if (ACPI_FAILURE(acpi_run_osc(handle, &context)))
return;
capbuf_ret = context.ret.pointer;
- osc_sb_apei_support_acked =
- capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
- osc_pc_lpi_support_confirmed =
- capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT;
- osc_sb_native_usb4_support_confirmed =
- capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT;
+ if (context.ret.length > OSC_SUPPORT_DWORD) {
+ osc_sb_apei_support_acked =
+ capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
+ osc_pc_lpi_support_confirmed =
+ capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT;
+ osc_sb_native_usb4_support_confirmed =
+ capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT;
+ }
kfree(context.ret.pointer);
}
@@ -1043,7 +1062,12 @@ struct bus_type acpi_bus_type = {
.remove = acpi_device_remove,
.uevent = acpi_device_uevent,
};
-EXPORT_SYMBOL_GPL(acpi_bus_type);
+
+int acpi_bus_for_each_dev(int (*fn)(struct device *, void *), void *data)
+{
+ return bus_for_each_dev(&acpi_bus_type, NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(acpi_bus_for_each_dev);
/* --------------------------------------------------------------------------
Initialization/Cleanup
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index bfd142ab4e07..d418449194ee 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -656,6 +656,9 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
acpi_status status;
int ret = -EFAULT;
+ if (osc_sb_cppc_not_supported)
+ return -ENODEV;
+
/* Parse the ACPI _CPC table for this CPU. */
status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
ACPI_TYPE_PACKAGE);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 46710380a402..a1b871a418f8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -168,7 +168,7 @@ struct acpi_ec_query {
};
static int acpi_ec_submit_query(struct acpi_ec *ec);
-static bool advance_transaction(struct acpi_ec *ec, bool interrupt);
+static void advance_transaction(struct acpi_ec *ec, bool interrupt);
static void acpi_ec_event_handler(struct work_struct *work);
struct acpi_ec *first_ec;
@@ -441,36 +441,35 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
return true;
}
-static bool acpi_ec_submit_event(struct acpi_ec *ec)
+static void acpi_ec_submit_event(struct acpi_ec *ec)
{
+ /*
+ * It is safe to mask the events here, because acpi_ec_close_event()
+ * will run at least once after this.
+ */
acpi_ec_mask_events(ec);
if (!acpi_ec_event_enabled(ec))
- return false;
-
- if (ec->event_state == EC_EVENT_READY) {
- ec_dbg_evt("Command(%s) submitted/blocked",
- acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
+ return;
- ec->event_state = EC_EVENT_IN_PROGRESS;
- /*
- * If events_to_process is greqter than 0 at this point, the
- * while () loop in acpi_ec_event_handler() is still running
- * and incrementing events_to_process will cause it to invoke
- * acpi_ec_submit_query() once more, so it is not necessary to
- * queue up the event work to start the same loop again.
- */
- if (ec->events_to_process++ > 0)
- return true;
+ if (ec->event_state != EC_EVENT_READY)
+ return;
- ec->events_in_progress++;
- return queue_work(ec_wq, &ec->work);
- }
+ ec_dbg_evt("Command(%s) submitted/blocked",
+ acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
+ ec->event_state = EC_EVENT_IN_PROGRESS;
/*
- * The event handling work has not been completed yet, so it needs to be
- * flushed.
+ * If events_to_process is greater than 0 at this point, the while ()
+ * loop in acpi_ec_event_handler() is still running and incrementing
+ * events_to_process will cause it to invoke acpi_ec_submit_query() once
+ * more, so it is not necessary to queue up the event work to start the
+ * same loop again.
*/
- return true;
+ if (ec->events_to_process++ > 0)
+ return;
+
+ ec->events_in_progress++;
+ queue_work(ec_wq, &ec->work);
}
static void acpi_ec_complete_event(struct acpi_ec *ec)
@@ -655,11 +654,10 @@ static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t
acpi_ec_mask_events(ec);
}
-static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
+static void advance_transaction(struct acpi_ec *ec, bool interrupt)
{
struct transaction *t = ec->curr;
bool wakeup = false;
- bool ret = false;
u8 status;
ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
@@ -724,12 +722,10 @@ static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
out:
if (status & ACPI_EC_FLAG_SCI)
- ret = acpi_ec_submit_event(ec);
+ acpi_ec_submit_event(ec);
if (wakeup && interrupt)
wake_up(&ec->wait);
-
- return ret;
}
static void start_transaction(struct acpi_ec *ec)
@@ -1242,6 +1238,7 @@ static void acpi_ec_event_handler(struct work_struct *work)
acpi_ec_submit_query(ec);
spin_lock_irq(&ec->lock);
+
ec->events_to_process--;
}
@@ -1250,27 +1247,30 @@ static void acpi_ec_event_handler(struct work_struct *work)
* event handling work again regardless of whether or not the query
* queued up above is processed successfully.
*/
- if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT)
+ if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
+ bool guard_timeout;
+
acpi_ec_complete_event(ec);
- else
- acpi_ec_close_event(ec);
- spin_unlock_irq(&ec->lock);
+ ec_dbg_evt("Event stopped");
- ec_dbg_evt("Event stopped");
+ spin_unlock_irq(&ec->lock);
+
+ guard_timeout = !!ec_guard(ec);
- if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && ec_guard(ec)) {
spin_lock_irq(&ec->lock);
/* Take care of SCI_EVT unless someone else is doing that. */
- if (!ec->curr)
+ if (guard_timeout && !ec->curr)
advance_transaction(ec, false);
+ } else {
+ acpi_ec_close_event(ec);
- spin_unlock_irq(&ec->lock);
+ ec_dbg_evt("Event stopped");
}
- spin_lock_irq(&ec->lock);
ec->events_in_progress--;
+
spin_unlock_irq(&ec->lock);
}
@@ -2051,6 +2051,11 @@ void acpi_ec_set_gpe_wake_mask(u8 action)
acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
}
+static bool acpi_ec_work_in_progress(struct acpi_ec *ec)
+{
+ return ec->events_in_progress + ec->queries_in_progress > 0;
+}
+
bool acpi_ec_dispatch_gpe(void)
{
bool work_in_progress = false;
@@ -2081,8 +2086,12 @@ bool acpi_ec_dispatch_gpe(void)
*/
spin_lock_irq(&first_ec->lock);
- if (acpi_ec_gpe_status_set(first_ec))
- work_in_progress = advance_transaction(first_ec, false);
+ if (acpi_ec_gpe_status_set(first_ec)) {
+ pm_pr_dbg("ACPI EC GPE status set\n");
+
+ advance_transaction(first_ec, false);
+ work_in_progress = acpi_ec_work_in_progress(first_ec);
+ }
spin_unlock_irq(&first_ec->lock);
@@ -2099,8 +2108,7 @@ bool acpi_ec_dispatch_gpe(void)
spin_lock_irq(&first_ec->lock);
- work_in_progress = first_ec->events_in_progress +
- first_ec->queries_in_progress > 0;
+ work_in_progress = acpi_ec_work_in_progress(first_ec);
spin_unlock_irq(&first_ec->lock);
} while (work_in_progress && !pm_wakeup_pending());
diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h
index dd9bb8ca2244..44728529a5b6 100644
--- a/drivers/acpi/fan.h
+++ b/drivers/acpi/fan.h
@@ -6,9 +6,53 @@
*
* Add new device IDs before the generic ACPI fan one.
*/
+
+#ifndef _ACPI_FAN_H_
+#define _ACPI_FAN_H_
+
#define ACPI_FAN_DEVICE_IDS \
{"INT3404", }, /* Fan */ \
{"INTC1044", }, /* Fan for Tiger Lake generation */ \
{"INTC1048", }, /* Fan for Alder Lake generation */ \
{"INTC10A2", }, /* Fan for Raptor Lake generation */ \
{"PNP0C0B", } /* Generic ACPI fan */
+
+#define ACPI_FPS_NAME_LEN 20
+
+struct acpi_fan_fps {
+ u64 control;
+ u64 trip_point;
+ u64 speed;
+ u64 noise_level;
+ u64 power;
+ char name[ACPI_FPS_NAME_LEN];
+ struct device_attribute dev_attr;
+};
+
+struct acpi_fan_fif {
+ u8 revision;
+ u8 fine_grain_ctrl;
+ u8 step_size;
+ u8 low_speed_notification;
+};
+
+struct acpi_fan_fst {
+ u64 revision;
+ u64 control;
+ u64 speed;
+};
+
+struct acpi_fan {
+ bool acpi4;
+ struct acpi_fan_fif fif;
+ struct acpi_fan_fps *fps;
+ int fps_count;
+ struct thermal_cooling_device *cdev;
+ struct device_attribute fst_speed;
+ struct device_attribute fine_grain_control;
+};
+
+int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst);
+int acpi_fan_create_attributes(struct acpi_device *device);
+void acpi_fan_delete_attributes(struct acpi_device *device);
+#endif
diff --git a/drivers/acpi/fan_attr.c b/drivers/acpi/fan_attr.c
new file mode 100644
index 000000000000..f15157d40713
--- /dev/null
+++ b/drivers/acpi/fan_attr.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * fan_attr.c - Create extra attributes for ACPI Fan driver
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2022 Intel Corporation. All rights reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#include "fan.h"
+
+MODULE_LICENSE("GPL");
+
+static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
+ int count;
+
+ if (fps->control == 0xFFFFFFFF || fps->control > 100)
+ count = scnprintf(buf, PAGE_SIZE, "not-defined:");
+ else
+ count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
+
+ if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point);
+
+ if (fps->speed == 0xFFFFFFFF)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed);
+
+ if (fps->noise_level == 0xFFFFFFFF)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100);
+
+ if (fps->power == 0xFFFFFFFF)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined\n");
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld\n", fps->power);
+
+ return count;
+}
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);
+ struct acpi_fan_fst fst;
+ int status;
+
+ status = acpi_fan_get_fst(acpi_dev, &fst);
+ if (status)
+ return status;
+
+ return sprintf(buf, "%lld\n", fst.speed);
+}
+
+static ssize_t show_fine_grain_control(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);
+ struct acpi_fan *fan = acpi_driver_data(acpi_dev);
+
+ return sprintf(buf, "%d\n", fan->fif.fine_grain_ctrl);
+}
+
+int acpi_fan_create_attributes(struct acpi_device *device)
+{
+ struct acpi_fan *fan = acpi_driver_data(device);
+ int i, status;
+
+ sysfs_attr_init(&fan->fine_grain_control.attr);
+ fan->fine_grain_control.show = show_fine_grain_control;
+ fan->fine_grain_control.store = NULL;
+ fan->fine_grain_control.attr.name = "fine_grain_control";
+ fan->fine_grain_control.attr.mode = 0444;
+ status = sysfs_create_file(&device->dev.kobj, &fan->fine_grain_control.attr);
+ if (status)
+ return status;
+
+ /* _FST is present if we are here */
+ sysfs_attr_init(&fan->fst_speed.attr);
+ fan->fst_speed.show = show_fan_speed;
+ fan->fst_speed.store = NULL;
+ fan->fst_speed.attr.name = "fan_speed_rpm";
+ fan->fst_speed.attr.mode = 0444;
+ status = sysfs_create_file(&device->dev.kobj, &fan->fst_speed.attr);
+ if (status)
+ goto rem_fine_grain_attr;
+
+ for (i = 0; i < fan->fps_count; ++i) {
+ struct acpi_fan_fps *fps = &fan->fps[i];
+
+ snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
+ sysfs_attr_init(&fps->dev_attr.attr);
+ fps->dev_attr.show = show_state;
+ fps->dev_attr.store = NULL;
+ fps->dev_attr.attr.name = fps->name;
+ fps->dev_attr.attr.mode = 0444;
+ status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
+ if (status) {
+ int j;
+
+ for (j = 0; j < i; ++j)
+ sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
+ goto rem_fst_attr;
+ }
+ }
+
+ return 0;
+
+rem_fst_attr:
+ sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
+
+rem_fine_grain_attr:
+ sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
+
+ return status;
+}
+
+void acpi_fan_delete_attributes(struct acpi_device *device)
+{
+ struct acpi_fan *fan = acpi_driver_data(device);
+ int i;
+
+ for (i = 0; i < fan->fps_count; ++i)
+ sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
+
+ sysfs_remove_file(&device->dev.kobj, &fan->fst_speed.attr);
+ sysfs_remove_file(&device->dev.kobj, &fan->fine_grain_control.attr);
+}
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan_core.c
index 5cd0ceb50bc8..b9a9a59ddcc1 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan_core.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
+ * fan_core.c - ACPI Fan core Driver
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2022 Intel Corporation. All rights reserved.
*/
#include <linux/kernel.h>
@@ -45,33 +46,6 @@ static const struct dev_pm_ops acpi_fan_pm = {
#define FAN_PM_OPS_PTR NULL
#endif
-#define ACPI_FPS_NAME_LEN 20
-
-struct acpi_fan_fps {
- u64 control;
- u64 trip_point;
- u64 speed;
- u64 noise_level;
- u64 power;
- char name[ACPI_FPS_NAME_LEN];
- struct device_attribute dev_attr;
-};
-
-struct acpi_fan_fif {
- u64 revision;
- u64 fine_grain_ctrl;
- u64 step_size;
- u64 low_speed_notification;
-};
-
-struct acpi_fan {
- bool acpi4;
- struct acpi_fan_fif fif;
- struct acpi_fan_fps *fps;
- int fps_count;
- struct thermal_cooling_device *cdev;
-};
-
static struct platform_driver acpi_fan_driver = {
.probe = acpi_fan_probe,
.remove = acpi_fan_remove,
@@ -89,25 +63,29 @@ static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
struct acpi_device *device = cdev->devdata;
struct acpi_fan *fan = acpi_driver_data(device);
- if (fan->acpi4)
- *state = fan->fps_count - 1;
- else
+ if (fan->acpi4) {
+ if (fan->fif.fine_grain_ctrl)
+ *state = 100 / fan->fif.step_size;
+ else
+ *state = fan->fps_count - 1;
+ } else {
*state = 1;
+ }
+
return 0;
}
-static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
+int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_fan *fan = acpi_driver_data(device);
union acpi_object *obj;
acpi_status status;
- int control, i;
+ int ret = 0;
status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
dev_err(&device->dev, "Get fan state failed\n");
- return status;
+ return -ENODEV;
}
obj = buffer.pointer;
@@ -115,35 +93,52 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
obj->package.count != 3 ||
obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
dev_err(&device->dev, "Invalid _FST data\n");
- status = -EINVAL;
+ ret = -EINVAL;
goto err;
}
- control = obj->package.elements[1].integer.value;
+ fst->revision = obj->package.elements[0].integer.value;
+ fst->control = obj->package.elements[1].integer.value;
+ fst->speed = obj->package.elements[2].integer.value;
+
+err:
+ kfree(obj);
+ return ret;
+}
+
+static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
+{
+ struct acpi_fan *fan = acpi_driver_data(device);
+ struct acpi_fan_fst fst;
+ int status, i;
+
+ status = acpi_fan_get_fst(device, &fst);
+ if (status)
+ return status;
+
+ if (fan->fif.fine_grain_ctrl) {
+ /* This control should be same what we set using _FSL by spec */
+ if (fst.control > 100) {
+ dev_dbg(&device->dev, "Invalid control value returned\n");
+ goto match_fps;
+ }
+
+ *state = (int) fst.control / fan->fif.step_size;
+ return 0;
+ }
+
+match_fps:
for (i = 0; i < fan->fps_count; i++) {
- /*
- * When Fine Grain Control is set, return the state
- * corresponding to maximum fan->fps[i].control
- * value compared to the current speed. Here the
- * fan->fps[] is sorted array with increasing speed.
- */
- if (fan->fif.fine_grain_ctrl && control < fan->fps[i].control) {
- i = (i > 0) ? i - 1 : 0;
+ if (fst.control == fan->fps[i].control)
break;
- } else if (control == fan->fps[i].control) {
- break;
- }
}
if (i == fan->fps_count) {
dev_dbg(&device->dev, "Invalid control value returned\n");
- status = -EINVAL;
- goto err;
+ return -EINVAL;
}
*state = i;
-err:
- kfree(obj);
return status;
}
@@ -187,15 +182,30 @@ static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
{
struct acpi_fan *fan = acpi_driver_data(device);
acpi_status status;
+ u64 value = state;
+ int max_state;
- if (state >= fan->fps_count)
+ if (fan->fif.fine_grain_ctrl)
+ max_state = 100 / fan->fif.step_size;
+ else
+ max_state = fan->fps_count - 1;
+
+ if (state > max_state)
return -EINVAL;
- status = acpi_execute_simple_method(device->handle, "_FSL",
- fan->fps[state].control);
+ if (fan->fif.fine_grain_ctrl) {
+ value *= fan->fif.step_size;
+ /* Spec allows compensate the last step only */
+ if (value + fan->fif.step_size > 100)
+ value = 100;
+ } else {
+ value = fan->fps[state].control;
+ }
+
+ status = acpi_execute_simple_method(device->handle, "_FSL", value);
if (ACPI_FAILURE(status)) {
dev_dbg(&device->dev, "Failed to set state by _FSL\n");
- return status;
+ return -ENODEV;
}
return 0;
@@ -237,7 +247,8 @@ static int acpi_fan_get_fif(struct acpi_device *device)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_fan *fan = acpi_driver_data(device);
struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
- struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
+ u64 fields[4];
+ struct acpi_buffer fif = { sizeof(fields), fields };
union acpi_object *obj;
acpi_status status;
@@ -258,6 +269,17 @@ static int acpi_fan_get_fif(struct acpi_device *device)
status = -EINVAL;
}
+ fan->fif.revision = fields[0];
+ fan->fif.fine_grain_ctrl = fields[1];
+ fan->fif.step_size = fields[2];
+ fan->fif.low_speed_notification = fields[3];
+
+ /* If there is a bug in step size and set as 0, change to 1 */
+ if (!fan->fif.step_size)
+ fan->fif.step_size = 1;
+ /* If step size > 9, change to 9 (by spec valid values 1-9) */
+ else if (fan->fif.step_size > 9)
+ fan->fif.step_size = 9;
err:
kfree(obj);
return status;
@@ -270,39 +292,6 @@ static int acpi_fan_speed_cmp(const void *a, const void *b)
return fps1->speed - fps2->speed;
}
-static ssize_t show_state(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct acpi_fan_fps *fps = container_of(attr, struct acpi_fan_fps, dev_attr);
- int count;
-
- if (fps->control == 0xFFFFFFFF || fps->control > 100)
- count = scnprintf(buf, PAGE_SIZE, "not-defined:");
- else
- count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
-
- if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
- else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point);
-
- if (fps->speed == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
- else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed);
-
- if (fps->noise_level == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
- else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100);
-
- if (fps->power == 0xFFFFFFFF)
- count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined\n");
- else
- count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld\n", fps->power);
-
- return count;
-}
-
static int acpi_fan_get_fps(struct acpi_device *device)
{
struct acpi_fan *fan = acpi_driver_data(device);
@@ -347,25 +336,6 @@ static int acpi_fan_get_fps(struct acpi_device *device)
sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
acpi_fan_speed_cmp, NULL);
- for (i = 0; i < fan->fps_count; ++i) {
- struct acpi_fan_fps *fps = &fan->fps[i];
-
- snprintf(fps->name, ACPI_FPS_NAME_LEN, "state%d", i);
- sysfs_attr_init(&fps->dev_attr.attr);
- fps->dev_attr.show = show_state;
- fps->dev_attr.store = NULL;
- fps->dev_attr.attr.name = fps->name;
- fps->dev_attr.attr.mode = 0444;
- status = sysfs_create_file(&device->dev.kobj, &fps->dev_attr.attr);
- if (status) {
- int j;
-
- for (j = 0; j < i; ++j)
- sysfs_remove_file(&device->dev.kobj, &fan->fps[j].dev_attr.attr);
- break;
- }
- }
-
err:
kfree(obj);
return status;
@@ -396,6 +366,10 @@ static int acpi_fan_probe(struct platform_device *pdev)
if (result)
return result;
+ result = acpi_fan_create_attributes(device);
+ if (result)
+ return result;
+
fan->acpi4 = true;
} else {
result = acpi_device_update_power(device, NULL);
@@ -437,12 +411,8 @@ static int acpi_fan_probe(struct platform_device *pdev)
return 0;
err_end:
- if (fan->acpi4) {
- int i;
-
- for (i = 0; i < fan->fps_count; ++i)
- sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
- }
+ if (fan->acpi4)
+ acpi_fan_delete_attributes(device);
return result;
}
@@ -453,10 +423,8 @@ static int acpi_fan_remove(struct platform_device *pdev)
if (fan->acpi4) {
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
- int i;
- for (i = 0; i < fan->fps_count; ++i)
- sysfs_remove_file(&device->dev.kobj, &fan->fps[i].dev_attr.attr);
+ acpi_fan_delete_attributes(device);
}
sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
sysfs_remove_link(&fan->cdev->device.kobj, "device");
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 457e11d851b8..628bf8f18130 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -96,8 +96,6 @@ void acpi_scan_table_notify(void);
extern struct list_head acpi_bus_id_list;
-#define ACPI_MAX_DEVICE_INSTANCES 4096
-
struct acpi_device_bus_id {
const char *bus_id;
struct ida instance_ida;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 45c5c0e45e33..7a70c4bfc23c 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -642,22 +642,24 @@ u64 acpi_os_get_timer(void)
(ACPI_100NSEC_PER_SEC / HZ);
}
-acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
+acpi_status acpi_os_read_port(acpi_io_address port, u32 *value, u32 width)
{
u32 dummy;
- if (!value)
+ if (value)
+ *value = 0;
+ else
value = &dummy;
- *value = 0;
if (width <= 8) {
- *(u8 *) value = inb(port);
+ *value = inb(port);
} else if (width <= 16) {
- *(u16 *) value = inw(port);
+ *value = inw(port);
} else if (width <= 32) {
- *(u32 *) value = inl(port);
+ *value = inl(port);
} else {
- BUG();
+ pr_debug("%s: Access width %d not supported\n", __func__, width);
+ return AE_BAD_PARAMETER;
}
return AE_OK;
@@ -674,7 +676,8 @@ acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
} else if (width <= 32) {
outl(value, port);
} else {
- BUG();
+ pr_debug("%s: Access width %d not supported\n", __func__, width);
+ return AE_BAD_PARAMETER;
}
return AE_OK;
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index d54fb8e54671..58647051c948 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -185,7 +185,7 @@ static acpi_status acpi_pci_link_check_current(struct acpi_resource *resource,
if (!p || !p->interrupt_count) {
/*
* IRQ descriptors may have no IRQ# bits set,
- * particularly those those w/ _STA disabled
+ * particularly those w/ _STA disabled
*/
pr_debug("Blank _CRS IRQ resource\n");
return AE_OK;
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index d0986bda2964..12bbfe833609 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -541,7 +541,8 @@ acpi_device_data_of_node(const struct fwnode_handle *fwnode)
if (is_acpi_device_node(fwnode)) {
const struct acpi_device *adev = to_acpi_device_node(fwnode);
return &adev->data;
- } else if (is_acpi_data_node(fwnode)) {
+ }
+ if (is_acpi_data_node(fwnode)) {
const struct acpi_data_node *dn = to_acpi_data_node(fwnode);
return &dn->data;
}
@@ -685,7 +686,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
*/
if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
if (index)
- return -EINVAL;
+ return -ENOENT;
device = acpi_fetch_acpi_dev(obj->reference.handle);
if (!device)
@@ -739,14 +740,19 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
return -EINVAL;
}
- /* assume following integer elements are all args */
+ /*
+ * Assume the following integer elements are all args.
+ * Stop counting on the first reference or end of the
+ * package arguments. In case of neither reference,
+ * nor integer, return an error, we can't parse it.
+ */
for (i = 0; element + i < end && i < num_args; i++) {
int type = element[i].type;
+ if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
if (type == ACPI_TYPE_INTEGER)
nargs++;
- else if (type == ACPI_TYPE_LOCAL_REFERENCE)
- break;
else
return -EINVAL;
}
@@ -950,7 +956,7 @@ static int acpi_data_prop_read(const struct acpi_device_data *data,
if (proptype != DEV_PROP_STRING && nval > obj->package.count)
return -EOVERFLOW;
- else if (nval <= 0)
+ if (nval == 0)
return -EINVAL;
items = obj->package.elements;
@@ -1012,14 +1018,10 @@ struct fwnode_handle *acpi_get_next_subnode(const struct fwnode_handle *fwnode,
const struct list_head *head;
struct list_head *next;
- if (!child || is_acpi_device_node(child)) {
+ if ((!child || is_acpi_device_node(child)) && adev) {
struct acpi_device *child_adev;
- if (adev)
- head = &adev->children;
- else
- goto nondev;
-
+ head = &adev->children;
if (list_empty(head))
goto nondev;
@@ -1089,7 +1091,8 @@ acpi_node_get_parent(const struct fwnode_handle *fwnode)
if (is_acpi_data_node(fwnode)) {
/* All data nodes have parent pointer so just return that */
return to_acpi_data_node(fwnode)->parent;
- } else if (is_acpi_device_node(fwnode)) {
+ }
+ if (is_acpi_device_node(fwnode)) {
struct device *dev = to_acpi_device_node(fwnode)->dev.parent;
if (dev)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1331756d4cfc..5ffd87ac42b3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -477,7 +477,8 @@ static void acpi_device_del(struct acpi_device *device)
list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
if (!strcmp(acpi_device_bus_id->bus_id,
acpi_device_hid(device))) {
- ida_simple_remove(&acpi_device_bus_id->instance_ida, device->pnp.instance_no);
+ ida_free(&acpi_device_bus_id->instance_ida,
+ device->pnp.instance_no);
if (ida_is_empty(&acpi_device_bus_id->instance_ida)) {
list_del(&acpi_device_bus_id->node);
kfree_const(acpi_device_bus_id->bus_id);
@@ -642,7 +643,7 @@ static int acpi_device_set_name(struct acpi_device *device,
struct ida *instance_ida = &acpi_device_bus_id->instance_ida;
int result;
- result = ida_simple_get(instance_ida, 0, ACPI_MAX_DEVICE_INSTANCES, GFP_KERNEL);
+ result = ida_alloc(instance_ida, GFP_KERNEL);
if (result < 0)
return result;
@@ -1377,11 +1378,11 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
if (info->valid & ACPI_VALID_HID) {
acpi_add_id(pnp, info->hardware_id.string);
pnp->type.platform_id = 1;
- if (info->valid & ACPI_VALID_CID) {
- cid_list = &info->compatible_id_list;
- for (i = 0; i < cid_list->count; i++)
- acpi_add_id(pnp, cid_list->ids[i].string);
- }
+ }
+ if (info->valid & ACPI_VALID_CID) {
+ cid_list = &info->compatible_id_list;
+ for (i = 0; i < cid_list->count; i++)
+ acpi_add_id(pnp, cid_list->ids[i].string);
}
if (info->valid & ACPI_VALID_ADR) {
pnp->bus_address = info->address;
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index d4fbea91ab6b..d068ff42fce4 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -758,6 +758,8 @@ bool acpi_s2idle_wake(void)
return true;
}
+ pm_pr_dbg("Rearming ACPI SCI for wakeup\n");
+
pm_wakeup_clear(acpi_sci_irq);
rearm_wake_irq(acpi_sci_irq);
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 34600b5b9d8e..ceee808f7f2a 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -545,7 +545,7 @@ static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = {
ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT,
ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT,
ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT,
- ACPI_SIG_NHLT, ACPI_SIG_AEST };
+ ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI };
#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)