summaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:37:28 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-07 17:37:28 +0200
commit5eccd39d8efa3bc8d557be50f202bbf023837eed (patch)
tree6f1589cd863481a7dfdace2b9a692957dc94afbe /drivers/acpi
parent8fb649f3a174efaa618928cbe0737bf78b456eed (diff)
parent5015d0d945b3d3f2b038d2667880d5762f7d9437 (diff)
downloadlinux-rolling-stable.tar.gz
linux-rolling-stable.zip
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/acpi_platform.c45
-rw-r--r--drivers/acpi/acpi_tad.c50
-rw-r--r--drivers/acpi/apei/erst.c2
-rw-r--r--drivers/acpi/apei/ghes.c52
-rw-r--r--drivers/acpi/cppc_acpi.c24
-rw-r--r--drivers/acpi/pfr_update.c45
6 files changed, 153 insertions, 65 deletions
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index a09636a4168e..e3c77a65f61c 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
@@ -71,6 +72,42 @@ static struct notifier_block acpi_platform_notifier = {
.notifier_call = acpi_platform_device_remove_notify,
};
+static unsigned int acpi_platform_adjust_resources(struct acpi_device *adev,
+ struct resource *new_res,
+ struct resource *resources,
+ unsigned int count)
+{
+ unsigned int i;
+
+ if (!(new_res->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
+ return count;
+
+ for (i = 0; i < count; ) {
+ struct resource *res = &resources[i];
+
+ /*
+ * Look for overlaps of resources of the same type that would
+ * cause resource insertion to fail down the road.
+ */
+ if (__resource_contains_unbound(res, new_res) ||
+ __resource_contains_unbound(new_res, res) ||
+ resource_type(new_res) != resource_type(res) ||
+ !resource_union(new_res, res, new_res)) {
+ i++;
+ continue;
+ }
+
+ dev_info(&adev->dev, "%pR expanded due to overlap\n", new_res);
+ /*
+ * Eliminate the previously processed resource that overlapped
+ * with the new one because it is not necessary any more.
+ */
+ memmove(res, res + 1, (--count - i) * sizeof(*res));
+ }
+
+ return count;
+}
+
static void acpi_platform_fill_resource(struct acpi_device *adev,
const struct resource *src, struct resource *dest)
{
@@ -151,10 +188,14 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
return ERR_PTR(-ENOMEM);
}
count = 0;
- list_for_each_entry(rentry, &resource_list, node)
+ list_for_each_entry(rentry, &resource_list, node) {
+ count = acpi_platform_adjust_resources(adev,
+ rentry->res,
+ resources,
+ count);
acpi_platform_fill_resource(adev, rentry->res,
&resources[count++]);
-
+ }
acpi_dev_free_resource_list(&resource_list);
}
}
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index fc43df083738..45459a4cafae 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/rtc.h>
@@ -86,6 +87,8 @@ static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt)
rt->daylight > 3;
}
+static DEFINE_MUTEX(acpi_tad_aml_lock);
+
static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
acpi_handle handle = ACPI_HANDLE(dev);
@@ -113,6 +116,8 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
+ guard(mutex)(&acpi_tad_aml_lock);
+
status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);
if (ACPI_FAILURE(status) || retval)
return -EIO;
@@ -124,30 +129,27 @@ static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt)
{
acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
- union acpi_object *out_obj;
- struct acpi_tad_rt *data;
acpi_status status;
int ret = -EIO;
- status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
- if (ACPI_FAILURE(status))
- goto out_free;
-
- out_obj = output.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER)
- goto out_free;
-
- if (out_obj->buffer.length != sizeof(*rt))
- goto out_free;
-
- data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
- if (!data->valid)
- goto out_free;
-
- memcpy(rt, data, sizeof(*rt));
- ret = 0;
+ guard(mutex)(&acpi_tad_aml_lock);
-out_free:
+ status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
+ if (ACPI_SUCCESS(status)) {
+ union acpi_object *out_obj;
+
+ out_obj = output.pointer;
+ if (out_obj->type == ACPI_TYPE_BUFFER &&
+ out_obj->buffer.length == sizeof(*rt)) {
+ struct acpi_tad_rt *data;
+
+ data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
+ if (data->valid) {
+ memcpy(rt, data, sizeof(*rt));
+ ret = 0;
+ }
+ }
+ }
ACPI_FREE(output.pointer);
return ret;
}
@@ -193,6 +195,8 @@ static int __acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
args[0].integer.value = timer_id;
args[1].integer.value = value;
+ guard(mutex)(&acpi_tad_aml_lock);
+
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
if (ACPI_FAILURE(status) || retval)
return -EIO;
@@ -215,6 +219,8 @@ static int __acpi_tad_wake_read(struct device *dev, char *method, u32 timer_id,
args[0].integer.value = timer_id;
+ guard(mutex)(&acpi_tad_aml_lock);
+
status = acpi_evaluate_integer(handle, method, &arg_list, retval);
if (ACPI_FAILURE(status))
return -EIO;
@@ -416,6 +422,8 @@ static int acpi_tad_clear_status(struct device *dev, u32 timer_id)
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
+ guard(mutex)(&acpi_tad_aml_lock);
+
status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval);
if (ACPI_FAILURE(status) || retval)
return -EIO;
@@ -456,6 +464,8 @@ static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id)
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
+ guard(mutex)(&acpi_tad_aml_lock);
+
status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval);
if (ACPI_FAILURE(status))
return -EIO;
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index bf65e3461531..15ab797641cf 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -108,7 +108,7 @@ static inline u64 erst_get_timeout(void)
if (erst_erange.attr & ERST_RANGE_SLOW) {
timeout = ((erst_erange.timings & ERST_EXEC_TIMING_MAX_MASK) >>
- ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_MSEC;
+ ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_USEC;
if (timeout < FIRMWARE_TIMEOUT)
timeout = FIRMWARE_TIMEOUT;
}
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3236a3ce79d6..c40df9a3b37c 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -576,7 +576,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
return false;
p = (char *)(err + 1);
- length -= sizeof(err);
+ length -= sizeof(*err);
for (i = 0; i < err->err_info_num; i++) {
struct cper_arm_err_info *err_info;
@@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data,
CXL_CPER_PROT_ERR_FIFO_DEPTH);
/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */
-static DEFINE_SPINLOCK(cxl_cper_prot_err_work_lock);
+static DEFINE_RAW_SPINLOCK(cxl_cper_prot_err_work_lock);
struct work_struct *cxl_cper_prot_err_work;
static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
if (cxl_cper_sec_prot_err_valid(prot_err))
return;
- guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
+ guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
if (!cxl_cper_prot_err_work)
return;
@@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
int cxl_cper_register_prot_err_work(struct work_struct *work)
{
- if (cxl_cper_prot_err_work)
- return -EINVAL;
+ guard(raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);
- guard(spinlock)(&cxl_cper_prot_err_work_lock);
+ if (WARN_ONCE(cxl_cper_prot_err_work,
+ "CPER-CXL kfifo consumer already registered\n"))
+ return -EINVAL;
cxl_cper_prot_err_work = work;
return 0;
}
@@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");
int cxl_cper_unregister_prot_err_work(struct work_struct *work)
{
- if (cxl_cper_prot_err_work != work)
- return -EINVAL;
+ scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) {
+ if (WARN_ONCE(cxl_cper_prot_err_work != work,
+ "CPER-CXL kfifo consumer mismatch on unregister\n"))
+ return -EINVAL;
+ cxl_cper_prot_err_work = NULL;
+ }
+
+ cancel_work_sync(work);
+
+ /* Discard stale entries so they are not replayed on next module load */
+ kfifo_reset(&cxl_cper_prot_err_fifo);
- guard(spinlock)(&cxl_cper_prot_err_work_lock);
- cxl_cper_prot_err_work = NULL;
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_prot_err_work, "CXL");
@@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL");
DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);
/* Synchronize schedule_work() with cxl_cper_work changes */
-static DEFINE_SPINLOCK(cxl_cper_work_lock);
+static DEFINE_RAW_SPINLOCK(cxl_cper_work_lock);
struct work_struct *cxl_cper_work;
static void cxl_cper_post_event(enum cxl_event_type event_type,
@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,
return;
}
- guard(spinlock_irqsave)(&cxl_cper_work_lock);
+ guard(raw_spinlock_irqsave)(&cxl_cper_work_lock);
if (!cxl_cper_work)
return;
@@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,
int cxl_cper_register_work(struct work_struct *work)
{
- if (cxl_cper_work)
+ guard(raw_spinlock_irqsave)(&cxl_cper_work_lock);
+ if (WARN_ONCE(cxl_cper_work,
+ "CXL CPER kfifo consumer already registered\n"))
return -EINVAL;
- guard(spinlock)(&cxl_cper_work_lock);
cxl_cper_work = work;
return 0;
}
@@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");
int cxl_cper_unregister_work(struct work_struct *work)
{
- if (cxl_cper_work != work)
- return -EINVAL;
+ scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) {
+ if (WARN_ONCE(cxl_cper_work != work,
+ "CXL CPER kfifo consumer mismatch on unregister\n"))
+ return -EINVAL;
+ cxl_cper_work = NULL;
+ }
+
+ cancel_work_sync(work);
+
+ /* Discard stale entries so they are not replayed on next module load */
+ kfifo_reset(&cxl_cper_fifo);
- guard(spinlock)(&cxl_cper_work_lock);
- cxl_cper_work = NULL;
return 0;
}
EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL");
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 53d09ca98f06..becb7e442b30 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1316,15 +1316,30 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
return cpc_write(cpu, reg, val);
}
+static bool cppc_desired_perf_readable(const struct cpc_desc *cpc_desc)
+{
+ return cpc_desc->version < CPPC_V4_REV;
+}
+
/**
* cppc_get_desired_perf - Get the desired performance register value.
* @cpunum: CPU from which to get desired performance.
* @desired_perf: Return address.
*
- * Return: 0 for success, -EIO otherwise.
+ * Return: 0 for success, -EOPNOTSUPP for _CPC revision 4 or later, and a
+ * negative errno otherwise.
*/
int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
{
+ struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
+
+ if (!cpc_desc)
+ return -ENODEV;
+
+ /* _CPC revision 4 no longer specifies Desired Performance as readable. */
+ if (!cppc_desired_perf_readable(cpc_desc))
+ return -EOPNOTSUPP;
+
return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
}
EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
@@ -1830,12 +1845,14 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
struct cppc_pcc_data *pcc_ss_data = NULL;
+ bool read_desired_perf;
int ret = 0, regs_in_pcc = 0;
if (!cpc_desc) {
pr_debug("No CPC descriptor for CPU:%d\n", cpu);
return -ENODEV;
}
+ read_desired_perf = cppc_desired_perf_readable(cpc_desc);
if (!perf_ctrls) {
pr_debug("Invalid perf_ctrls pointer\n");
@@ -1849,7 +1866,8 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
/* Are any of the regs PCC ?*/
- if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
+ if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
+ CPC_IN_PCC(min_perf_reg) ||
CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
CPC_IN_PCC(auto_sel_reg)) {
if (pcc_ss_id < 0) {
@@ -1881,7 +1899,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
}
perf_ctrls->min_perf = min;
- if (CPC_SUPPORTED(desired_perf_reg)) {
+ if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
if (ret)
goto out_err;
diff --git a/drivers/acpi/pfr_update.c b/drivers/acpi/pfr_update.c
index 6283105bb0e8..9afd2c52fdbd 100644
--- a/drivers/acpi/pfr_update.c
+++ b/drivers/acpi/pfr_update.c
@@ -120,7 +120,7 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
struct pfru_device *pfru_dev)
{
acpi_handle handle = ACPI_HANDLE(pfru_dev->parent_dev);
- union acpi_object *out_obj;
+ union acpi_object *out_obj, *elem;
int ret = -EINVAL;
out_obj = acpi_evaluate_dsm_typed(handle, &pfru_guid,
@@ -150,7 +150,9 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
goto free_acpi_buffer;
}
- cap_hdr->status = out_obj->package.elements[CAP_STATUS_IDX].integer.value;
+ elem = out_obj->package.elements;
+
+ cap_hdr->status = elem[CAP_STATUS_IDX].integer.value;
if (cap_hdr->status != DSM_SUCCEED) {
ret = -EBUSY;
dev_dbg(pfru_dev->parent_dev, "Query cap Error Status:%d\n",
@@ -158,29 +160,30 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
goto free_acpi_buffer;
}
- cap_hdr->update_cap = out_obj->package.elements[CAP_UPDATE_IDX].integer.value;
+ if (elem[CAP_CODE_TYPE_IDX].buffer.length > sizeof(cap_hdr->code_type) ||
+ elem[CAP_DRV_TYPE_IDX].buffer.length > sizeof(cap_hdr->drv_type) ||
+ elem[CAP_PLAT_ID_IDX].buffer.length > sizeof(cap_hdr->platform_id) ||
+ elem[CAP_OEM_ID_IDX].buffer.length > sizeof(cap_hdr->oem_id))
+ goto free_acpi_buffer;
+
+ cap_hdr->update_cap = elem[CAP_UPDATE_IDX].integer.value;
memcpy(&cap_hdr->code_type,
- out_obj->package.elements[CAP_CODE_TYPE_IDX].buffer.pointer,
- out_obj->package.elements[CAP_CODE_TYPE_IDX].buffer.length);
- cap_hdr->fw_version =
- out_obj->package.elements[CAP_FW_VER_IDX].integer.value;
- cap_hdr->code_rt_version =
- out_obj->package.elements[CAP_CODE_RT_VER_IDX].integer.value;
+ elem[CAP_CODE_TYPE_IDX].buffer.pointer,
+ elem[CAP_CODE_TYPE_IDX].buffer.length);
+ cap_hdr->fw_version = elem[CAP_FW_VER_IDX].integer.value;
+ cap_hdr->code_rt_version = elem[CAP_CODE_RT_VER_IDX].integer.value;
memcpy(&cap_hdr->drv_type,
- out_obj->package.elements[CAP_DRV_TYPE_IDX].buffer.pointer,
- out_obj->package.elements[CAP_DRV_TYPE_IDX].buffer.length);
- cap_hdr->drv_rt_version =
- out_obj->package.elements[CAP_DRV_RT_VER_IDX].integer.value;
- cap_hdr->drv_svn =
- out_obj->package.elements[CAP_DRV_SVN_IDX].integer.value;
+ elem[CAP_DRV_TYPE_IDX].buffer.pointer,
+ elem[CAP_DRV_TYPE_IDX].buffer.length);
+ cap_hdr->drv_rt_version = elem[CAP_DRV_RT_VER_IDX].integer.value;
+ cap_hdr->drv_svn = elem[CAP_DRV_SVN_IDX].integer.value;
memcpy(&cap_hdr->platform_id,
- out_obj->package.elements[CAP_PLAT_ID_IDX].buffer.pointer,
- out_obj->package.elements[CAP_PLAT_ID_IDX].buffer.length);
+ elem[CAP_PLAT_ID_IDX].buffer.pointer,
+ elem[CAP_PLAT_ID_IDX].buffer.length);
memcpy(&cap_hdr->oem_id,
- out_obj->package.elements[CAP_OEM_ID_IDX].buffer.pointer,
- out_obj->package.elements[CAP_OEM_ID_IDX].buffer.length);
- cap_hdr->oem_info_len =
- out_obj->package.elements[CAP_OEM_INFO_IDX].buffer.length;
+ elem[CAP_OEM_ID_IDX].buffer.pointer,
+ elem[CAP_OEM_ID_IDX].buffer.length);
+ cap_hdr->oem_info_len = elem[CAP_OEM_INFO_IDX].buffer.length;
ret = 0;