summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-23 14:18:14 +0100
committerMark Brown <broonie@kernel.org>2026-07-23 14:18:14 +0100
commitcb80df544f31e233d767e4ecf94bbc1ae712da1f (patch)
tree01ace82b5d385af627d87911d39e1e55721db23c
parente08a9005e6fa61e8e0d0aa72f565101d368a032b (diff)
parent2f67e70aaf88cf8b81daac740e90956446f17a5e (diff)
downloadlinux-next-cb80df544f31e233d767e4ecf94bbc1ae712da1f.tar.gz
linux-next-cb80df544f31e233d767e4ecf94bbc1ae712da1f.zip
Merge branch 'linux-next' of https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-rw-r--r--Documentation/admin-guide/pm/cpufreq.rst2
-rw-r--r--Documentation/admin-guide/pm/intel_idle.rst54
-rw-r--r--Documentation/driver-api/acpi/acpi-drivers.rst80
-rw-r--r--Documentation/driver-api/acpi/index.rst1
-rw-r--r--Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst5
-rw-r--r--arch/riscv/include/asm/acpi.h1
-rw-r--r--arch/x86/include/asm/cpufeatures.h2
-rw-r--r--arch/x86/include/asm/msr-index.h2
-rw-r--r--drivers/acpi/acpi_fpdt.c53
-rw-r--r--drivers/acpi/acpi_processor.c354
-rw-r--r--drivers/acpi/acpi_video.c14
-rw-r--r--drivers/acpi/apei/ghes.c4
-rw-r--r--drivers/acpi/arm64/iort.c22
-rw-r--r--drivers/acpi/battery.c147
-rw-r--r--drivers/acpi/bus.c138
-rw-r--r--drivers/acpi/cppc_acpi.c22
-rw-r--r--drivers/acpi/ec.c40
-rw-r--r--drivers/acpi/fan.h27
-rw-r--r--drivers/acpi/fan_core.c25
-rw-r--r--drivers/acpi/irq.c172
-rw-r--r--drivers/acpi/numa/srat.c2
-rw-r--r--drivers/acpi/nvs.c4
-rw-r--r--drivers/acpi/pci_root.c36
-rw-r--r--drivers/acpi/power.c1
-rw-r--r--drivers/acpi/processor_core.c31
-rw-r--r--drivers/acpi/processor_idle.c269
-rw-r--r--drivers/acpi/riscv/irq.c141
-rw-r--r--drivers/acpi/scan.c22
-rw-r--r--drivers/acpi/sysfs.c11
-rw-r--r--drivers/acpi/utils.c17
-rw-r--r--drivers/acpi/video_detect.c9
-rw-r--r--drivers/base/power/runtime.c6
-rw-r--r--drivers/cpufreq/amd-pstate-ut.c5
-rw-r--r--drivers/cpufreq/amd-pstate.c35
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c33
-rw-r--r--drivers/cpufreq/cpufreq.c14
-rw-r--r--drivers/cpufreq/intel_pstate.c131
-rw-r--r--drivers/i2c/i2c-core-acpi.c15
-rw-r--r--drivers/idle/intel_idle.c195
-rw-r--r--drivers/irqchip/irq-gic-v3.c2
-rw-r--r--drivers/irqchip/irq-gic-v5-iwb.c2
-rw-r--r--drivers/irqchip/irq-gic-v5.c13
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--drivers/irqchip/irq-loongarch-cpu.c2
-rw-r--r--drivers/irqchip/irq-riscv-intc.c3
-rw-r--r--drivers/pci/vgaarb.c4
-rw-r--r--drivers/platform/x86/lenovo/thinkpad_acpi.c2
-rw-r--r--drivers/pnp/card.c11
-rw-r--r--drivers/pnp/pnpacpi/core.c5
-rw-r--r--drivers/pnp/system.c6
-rw-r--r--drivers/thermal/intel/int340x_thermal/int3400_thermal.c4
-rw-r--r--drivers/thermal/intel/int340x_thermal/platform_temperature_control.c13
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c8
-rw-r--r--drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c11
-rw-r--r--drivers/thermal/intel/intel_bxt_pmic_thermal.c4
-rw-r--r--drivers/thermal/intel/therm_throt.c277
-rw-r--r--drivers/xen/xen-acpi-pad.c5
-rw-r--r--include/acpi/acpi_bus.h54
-rw-r--r--include/acpi/acpi_drivers.h9
-rw-r--r--include/acpi/cppc_acpi.h5
-rw-r--r--include/acpi/nhlt.h1
-rw-r--r--include/linux/acpi.h27
-rw-r--r--include/linux/acpi_iort.h3
-rw-r--r--include/linux/acpi_pmtmr.h10
-rw-r--r--include/linux/cpufreq.h2
-rw-r--r--kernel/power/snapshot.c42
-rw-r--r--kernel/power/swap.c4
-rw-r--r--kernel/power/wakelock.c2
-rw-r--r--kernel/sched/cpufreq_schedutil.c19
-rw-r--r--rust/kernel/cpufreq.rs11
-rwxr-xr-xtools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py18
-rwxr-xr-xtools/testing/selftests/cpufreq/governor.sh26
-rwxr-xr-xtools/testing/selftests/cpufreq/special-tests.sh18
-rw-r--r--tools/thermal/thermometer/thermometer.c1
74 files changed, 1663 insertions, 1105 deletions
diff --git a/Documentation/admin-guide/pm/cpufreq.rst b/Documentation/admin-guide/pm/cpufreq.rst
index 8831cface585..34baf20cc202 100644
--- a/Documentation/admin-guide/pm/cpufreq.rst
+++ b/Documentation/admin-guide/pm/cpufreq.rst
@@ -497,7 +497,7 @@ This governor exposes the following tunables:
represented by it to be 1.5 times as high as the transition latency
(the default)::
- # echo `$(($(cat cpuinfo_transition_latency) * 3 / 2))` > ondemand/sampling_rate
+ # echo $(($(cat cpuinfo_transition_latency) * 3 / 2)) > ondemand/sampling_rate
``up_threshold``
If the estimated CPU load is above this value (in percent), the governor
diff --git a/Documentation/admin-guide/pm/intel_idle.rst b/Documentation/admin-guide/pm/intel_idle.rst
index 188d52cd26e8..996e5bd83c42 100644
--- a/Documentation/admin-guide/pm/intel_idle.rst
+++ b/Documentation/admin-guide/pm/intel_idle.rst
@@ -87,17 +87,22 @@ tables with any processor model recognized by it; see
`below <intel-idle-parameters_>`_.]
If the ACPI tables are going to be used for building the list of available idle
-states, ``intel_idle`` first looks for a ``_CST`` object under one of the ACPI
-objects corresponding to the CPUs in the system (refer to the ACPI specification
-[2]_ for the description of ``_CST`` and its output package). Because the
-``CPUIdle`` subsystem expects that the list of idle states supplied by the
-driver will be suitable for all of the CPUs handled by it and ``intel_idle`` is
-registered as the ``CPUIdle`` driver for all of the CPUs in the system, the
-driver looks for the first ``_CST`` object returning at least one valid idle
-state description and such that all of the idle states included in its return
-package are of the FFH (Functional Fixed Hardware) type, which means that the
-``MWAIT`` instruction is expected to be used to tell the processor that it can
-enter one of them. The return package of that ``_CST`` is then assumed to be
+states, ``intel_idle`` will be looking for ``_LPI`` or ``_CST`` objects in them
+(refer to the ACPI specification [2]_ for the definitions of the ``_LPI`` and
+``_CST`` objects). If ``_LPI`` is present under at least one of the ACPI
+objects representing the CPUs in the system and ``_LPI`` processing produces a
+non-empty list of valid idle states, it will be used. Otherwise, ``_CST`` will
+be used so long as it is present under at least one of the ACPI objects
+representing the CPUs in the system and it returns a non-empty list of valid
+idle states. In either case, since the ``CPUIdle`` subsystem expects that the
+list of idle states supplied by the driver will be suitable for all of the CPUs
+handled by it and ``intel_idle`` is registered as the ``CPUIdle`` driver for all
+of the CPUs in the system, ``intel_idle`` looks for the first CPU where the
+ACPI-supplied list of idle states (coming from either ``_LPI`` or ``_CST``)
+is not empty. Moreover, all of the states in that list need to be of the FFH
+(Functional Fixed Hardware) type, which means that the ``MWAIT`` instruction is
+expected to be used to tell the processor that the given idle state may be
+entered. If that expectation is met, the list of idle states is assumed to be
applicable to all of the other CPUs in the system and the idle state
descriptions extracted from it are stored in a preliminary list of idle states
coming from the ACPI tables. [This step is skipped if ``intel_idle`` is
@@ -129,18 +134,21 @@ If the given processor model is not recognized by ``intel_idle``, but it
supports ``MWAIT``, the preliminary list of idle states coming from the ACPI
tables is used for building the final list that will be supplied to the
``CPUIdle`` core during driver registration. For each idle state in that list,
-the description, ``MWAIT`` hint and exit latency are copied to the corresponding
-entry in the final list of idle states. The name of the idle state represented
-by it (to be returned by the ``name`` idle state attribute in ``sysfs``) is
-"CX_ACPI", where X is the index of that idle state in the final list (note that
-the minimum value of X is 1, because 0 is reserved for the "polling" state), and
-its target residency is based on the exit latency value. Specifically, for
-C1-type idle states the exit latency value is also used as the target residency
-(for compatibility with the majority of the "internal" tables of idle states for
-various processor models recognized by ``intel_idle``) and for the other idle
-state types (C2 and C3) the target residency value is 3 times the exit latency
-(again, that is because it reflects the target residency to exit latency ratio
-in the majority of cases for the processor models recognized by ``intel_idle``).
+the description, ``MWAIT`` hint and exit (wake) latency are copied to the
+corresponding entry in the final list of idle states. If the preliminary list
+of idle states has been obtained through ``_LPI`` processing, the minimum
+residency parameter of the given idle state is taken as its target residency.
+Otherwise, for C1-type idle states, the exit latency value is also used as the
+target residency (for compatibility with the majority of the "internal" tables
+of idle states for various processor models recognized by ``intel_idle``), and
+for the other idle state types (C2 and C3) the target residency value is 3 times
+the exit latency (again, that is because it reflects the target residency to
+exit latency ratio in the majority of cases for the processor models recognized
+by ``intel_idle``). The name of the idle state (to be returned by the ``name``
+idle state attribute in ``sysfs``) is either "Cx_LPI" (if it comes from ``_LPI``
+processing) or "Cx_ACPI", where x is the index of that idle state in the final
+list (note that the minimum value of x is 1, because 0 is reserved for the
+"polling" state), and its target residency is based on the exit latency value.
All of the idle states in the final list are enabled by default in this case.
diff --git a/Documentation/driver-api/acpi/acpi-drivers.rst b/Documentation/driver-api/acpi/acpi-drivers.rst
deleted file mode 100644
index 376b6d8a678c..000000000000
--- a/Documentation/driver-api/acpi/acpi-drivers.rst
+++ /dev/null
@@ -1,80 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-=========================================
-Why using ACPI drivers is not a good idea
-=========================================
-
-:Copyright: |copy| 2026, Intel Corporation
-
-:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-
-Even though binding drivers directly to struct acpi_device objects, also
-referred to as "ACPI device nodes", allows basic functionality to be provided
-at least in some cases, there are problems with it, related to general
-consistency, sysfs layout, power management operation ordering, and code
-cleanliness.
-
-First of all, ACPI device nodes represent firmware entities rather than
-hardware and in many cases they provide auxiliary information on devices
-enumerated independently (like PCI devices or CPUs). It is therefore generally
-questionable to assign resources to them because the entities represented by
-them do not decode addresses in the memory or I/O address spaces and do not
-generate interrupts or similar (all of that is done by hardware).
-
-Second, as a general rule, a struct acpi_device can only be a parent of another
-struct acpi_device. If that is not the case, the location of the child device
-in the device hierarchy is at least confusing and it may not be straightforward
-to identify the piece of hardware providing functionality represented by it.
-However, binding a driver directly to an ACPI device node may cause that to
-happen if the given driver registers input devices or wakeup sources under it,
-for example.
-
-Next, using system suspend and resume callbacks directly on ACPI device nodes
-is also questionable because it may cause ordering problems to appear. Namely,
-ACPI device nodes are registered before enumerating hardware corresponding to
-them and they land on the PM list in front of the majority of other device
-objects. Consequently, the execution ordering of their PM callbacks may be
-different from what is generally expected. Also, in general, dependencies
-returned by _DEP objects do not affect ACPI device nodes themselves, but the
-"physical" devices associated with them, which potentially is one more source
-of inconsistency related to treating ACPI device nodes as "real" device
-representation.
-
-All of the above means that binding drivers to ACPI device nodes should
-generally be avoided and so struct acpi_driver objects should not be used.
-
-Moreover, a device ID is necessary to bind a driver directly to an ACPI device
-node, but device IDs are not generally associated with all of them. Some of
-them contain alternative information allowing the corresponding pieces of
-hardware to be identified, for example represented by an _ADR object return
-value, and device IDs are not used in those cases. In consequence, confusingly
-enough, binding an ACPI driver to an ACPI device node may even be impossible.
-
-When that happens, the piece of hardware corresponding to the given ACPI device
-node is represented by another device object, like a struct pci_dev, and the
-ACPI device node is the "ACPI companion" of that device, accessible through its
-fwnode pointer used by the ACPI_COMPANION() macro. The ACPI companion holds
-additional information on the device configuration and possibly some "recipes"
-on device manipulation in the form of AML (ACPI Machine Language) bytecode
-provided by the platform firmware. Thus the role of the ACPI device node is
-similar to the role of a struct device_node on a system where Device Tree is
-used for platform description.
-
-For consistency, this approach has been extended to the cases in which ACPI
-device IDs are used. Namely, in those cases, an additional device object is
-created to represent the piece of hardware corresponding to a given ACPI device
-node. By default, it is a platform device, but it may also be a PNP device, a
-CPU device, or another type of device, depending on what the given piece of
-hardware actually is. There are even cases in which multiple devices are
-"backed" or "accompanied" by one ACPI device node (e.g. ACPI device nodes
-corresponding to GPUs that may provide firmware interfaces for backlight
-brightness control in addition to GPU configuration information).
-
-This means that it really should never be necessary to bind a driver directly to
-an ACPI device node because there is a "proper" device object representing the
-corresponding piece of hardware that can be bound to by a "proper" driver using
-the given ACPI device node as the device's ACPI companion. Thus, in principle,
-there is no reason to use ACPI drivers and if they all were replaced with other
-driver types (for example, platform drivers), some code could be dropped and
-some complexity would go away.
diff --git a/Documentation/driver-api/acpi/index.rst b/Documentation/driver-api/acpi/index.rst
index 2b10d83f9994..ace0008e54c2 100644
--- a/Documentation/driver-api/acpi/index.rst
+++ b/Documentation/driver-api/acpi/index.rst
@@ -7,4 +7,3 @@ ACPI Support
linuxized-acpica
scan_handlers
- acpi-drivers
diff --git a/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst b/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst
index d64a396fac81..78d9b712721c 100644
--- a/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst
+++ b/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst
@@ -64,9 +64,10 @@ defaults as [motorcomm-yt8xxx]_.
Enables adjustments related to ``motorcomm,tx-clk-*-inverted`` usage; see
[motorcomm-yt8xxx]_.
-``motorcomm,tx-clk-10-inverted`` (boolean, optional)
-``motorcomm,tx-clk-100-inverted`` (boolean, optional)
+``motorcomm,tx-clk-10-inverted`` (boolean, optional),
+``motorcomm,tx-clk-100-inverted`` (boolean, optional),
``motorcomm,tx-clk-1000-inverted`` (boolean, optional)
+
Per-speed TX clock inversion options; see [motorcomm-yt8xxx]_.
ASL example (illustrative)
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index d59bd06347cc..4e01ef15e201 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -67,6 +67,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
u32 *cboz_size, u32 *cbop_size);
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi);
#else
static inline void acpi_init_rintc_map(void) { }
static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 1b4a48bff18f..94764d69fa76 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -365,6 +365,8 @@
#define X86_FEATURE_HWP_HIGHEST_PERF_CHANGE (14*32+15) /* HWP Highest perf change */
#define X86_FEATURE_HFI (14*32+19) /* "hfi" Hardware Feedback Interface */
+#define X86_FEATURE_DPTI (14*32+24) /* Intel Directed Package Thermal Interrupt */
+
/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */
#define X86_FEATURE_NPT (15*32+ 0) /* "npt" Nested Page Table support */
#define X86_FEATURE_LBRV (15*32+ 1) /* "lbrv" LBR Virtualization support */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 18c4be75e927..3a8e51a0c9e8 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -1007,6 +1007,7 @@
#define THERM_INT_HIGH_ENABLE (1 << 0)
#define THERM_INT_LOW_ENABLE (1 << 1)
#define THERM_INT_PLN_ENABLE (1 << 24)
+#define THERM_INT_DPTI_ENABLE (1 << 25)
#define MSR_IA32_THERM_STATUS 0x0000019c
@@ -1036,6 +1037,7 @@
#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0)
#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10)
+#define PACKAGE_THERM_STATUS_DPTI_ACK (1 << 25)
#define PACKAGE_THERM_STATUS_HFI_UPDATED (1 << 26)
#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2
diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c
index e75dd28d31a9..79191ed20f76 100644
--- a/drivers/acpi/acpi_fpdt.c
+++ b/drivers/acpi/acpi_fpdt.c
@@ -168,7 +168,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
struct fpdt_subtable_header *subtable_header;
struct fpdt_record_header *record_header;
char *signature = (subtable_type == SUBTABLE_FBPT ? "FBPT" : "S3PT");
- u32 length, offset;
+ u32 length, offset, remaining;
int result;
if (!fpdt_address_valid(address)) {
@@ -182,10 +182,17 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
if (strncmp((char *)&subtable_header->signature, signature, 4)) {
pr_info(FW_BUG "subtable signature and type mismatch!\n");
+ acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header));
return -EINVAL;
}
length = subtable_header->length;
+ if (length < sizeof(*subtable_header)) {
+ pr_err(FW_BUG "Invalid FPDT subtable length %u.\n", length);
+ acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header));
+ return -EINVAL;
+ }
+
acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header));
subtable_header = acpi_os_map_memory(address, length);
@@ -194,17 +201,29 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
offset = sizeof(*subtable_header);
while (offset < length) {
- record_header = (void *)subtable_header + offset;
- offset += record_header->length;
+ remaining = length - offset;
+ if (remaining < sizeof(*record_header)) {
+ pr_err(FW_BUG "Truncated FPDT record header.\n");
+ result = -EINVAL;
+ goto err;
+ }
- if (!record_header->length) {
- pr_err(FW_BUG "Zero-length record found in FPTD.\n");
+ record_header = (void *)subtable_header + offset;
+ if (record_header->length < sizeof(*record_header) ||
+ record_header->length > remaining) {
+ pr_err(FW_BUG "Invalid FPDT record length %u.\n",
+ record_header->length);
result = -EINVAL;
goto err;
}
+ offset += record_header->length;
switch (record_header->type) {
case RECORD_S3_RESUME:
+ if (record_header->length < sizeof(*record_resume)) {
+ result = -EINVAL;
+ goto err;
+ }
if (subtable_type != SUBTABLE_S3PT) {
pr_err(FW_BUG "Invalid record %d for subtable %s\n",
record_header->type, signature);
@@ -221,6 +240,10 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
goto err;
break;
case RECORD_S3_SUSPEND:
+ if (record_header->length < sizeof(*record_suspend)) {
+ result = -EINVAL;
+ goto err;
+ }
if (subtable_type != SUBTABLE_S3PT) {
pr_err(FW_BUG "Invalid %d for subtable %s\n",
record_header->type, signature);
@@ -236,6 +259,10 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
goto err;
break;
case RECORD_BOOT:
+ if (record_header->length < sizeof(*record_boot)) {
+ result = -EINVAL;
+ goto err;
+ }
if (subtable_type != SUBTABLE_FBPT) {
pr_err(FW_BUG "Invalid %d for subtable %s\n",
record_header->type, signature);
@@ -317,7 +344,21 @@ static int __init acpi_init_fpdt(void)
}
while (offset < header->length) {
+ if (header->length - offset < sizeof(*subtable)) {
+ pr_err(FW_BUG "Truncated FPDT subtable entry.\n");
+ result = -EINVAL;
+ goto err_subtable;
+ }
+
subtable = (void *)header + offset;
+ if (subtable->length < sizeof(*subtable) ||
+ subtable->length > header->length - offset) {
+ pr_err(FW_BUG "Invalid FPDT subtable entry length %u.\n",
+ subtable->length);
+ result = -EINVAL;
+ goto err_subtable;
+ }
+
switch (subtable->type) {
case SUBTABLE_FBPT:
case SUBTABLE_S3PT:
@@ -330,7 +371,7 @@ static int __init acpi_init_fpdt(void)
/* Other types are reserved in ACPI 6.4 spec. */
break;
}
- offset += sizeof(*subtable);
+ offset += subtable->length;
}
return 0;
err_subtable:
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 00775b91bd41..5fbab54171b7 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -994,3 +994,357 @@ end:
}
EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE");
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
+
+#ifdef CONFIG_ACPI_PROCESSOR_IDLE
+struct acpi_lpi_states_array {
+ unsigned int size;
+ unsigned int composite_states_size;
+ struct acpi_lpi_state *entries;
+ struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
+};
+
+static int obj_get_integer(union acpi_object *obj, u32 *value)
+{
+ if (obj->type != ACPI_TYPE_INTEGER)
+ return -EINVAL;
+
+ *value = obj->integer.value;
+ return 0;
+}
+
+#define lpi_state_debug(handle, message, state_idx) \
+ acpi_handle_debug(handle, message " for _LPI state %u\n", state_idx)
+
+static void process_lpi_state_package(union acpi_object *lpi_pkg,
+ struct acpi_lpi_state *lpi_state,
+ acpi_handle handle,
+ unsigned int state_idx, bool strict)
+{
+ union acpi_object *lpi_pkg_elem, *obj;
+
+ if (lpi_pkg->type != ACPI_TYPE_PACKAGE || lpi_pkg->package.count < 7)
+ return;
+
+ lpi_pkg_elem = lpi_pkg->package.elements;
+
+ /* Get the entry method first and skip the state if that fails. */
+ obj = &lpi_pkg_elem[6];
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ struct acpi_power_register *reg;
+
+ if (obj->buffer.length < sizeof(*reg)) {
+ lpi_state_debug(handle, "Invalid register data", state_idx);
+ return;
+ }
+
+ reg = (struct acpi_power_register *)obj->buffer.pointer;
+ if (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ lpi_state_debug(handle, "Unsupported entry method", state_idx);
+ return;
+ }
+
+ lpi_state->entry_method = ACPI_CSTATE_FFH;
+ lpi_state->address = reg->address;
+ } else if (obj->type == ACPI_TYPE_INTEGER) {
+ lpi_state->entry_method = ACPI_CSTATE_INTEGER;
+ lpi_state->address = obj->integer.value;
+ } else {
+ lpi_state_debug(handle, "Invalid entry method", state_idx);
+ return;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[0], &lpi_state->min_residency)) {
+ if (strict) {
+ lpi_state_debug(handle, "No min. residency", state_idx);
+ return;
+ }
+
+ lpi_state_debug(handle, "Assuming 10 us min. residency", state_idx);
+ lpi_state->min_residency = 10;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[1], &lpi_state->wake_latency)) {
+ if (strict) {
+ lpi_state_debug(handle, "No wake latency", state_idx);
+ return;
+ }
+
+ lpi_state_debug(handle, "Assuming 10 us wake latency", state_idx);
+ lpi_state->wake_latency = 10;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[2], &lpi_state->flags))
+ lpi_state->flags = 0;
+
+ if (obj_get_integer(&lpi_pkg_elem[3], &lpi_state->arch_flags))
+ lpi_state->arch_flags = 0;
+
+ if (obj_get_integer(&lpi_pkg_elem[4], &lpi_state->res_cnt_freq))
+ lpi_state->res_cnt_freq = 1;
+
+ if (obj_get_integer(&lpi_pkg_elem[5], &lpi_state->enable_parent_state))
+ lpi_state->enable_parent_state = 0;
+
+ /* Skip elements [7-8] i.e. Residency/Usage counters. */
+
+ /*
+ * Avoid out-of-bounds access if the size of the package is less than
+ * expected.
+ */
+ if (lpi_pkg->package.count < 10)
+ return;
+
+ obj = &lpi_pkg_elem[9];
+ if (obj->type == ACPI_TYPE_STRING)
+ strscpy(lpi_state->desc, obj->string.pointer, ACPI_CX_DESC_LEN);
+}
+
+static int acpi_processor_evaluate_lpi(acpi_handle handle,
+ struct acpi_lpi_states_array *info,
+ bool strict)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *lpi_data, *lpi_pkg;
+ unsigned int lpi_pkg_count, state_idx;
+ struct acpi_lpi_state *lpi_state;
+ acpi_status status;
+ int ret = 0;
+
+ status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(handle, "No _LPI, giving up\n");
+ return -ENODEV;
+ }
+
+ lpi_data = buffer.pointer;
+
+ /* There must be at least 4 elements = 3 elements + 1 package */
+ if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
+ lpi_data->package.count < 4) {
+ acpi_handle_debug(handle, "Not enough elements in _LPI\n");
+ ret = -ENODATA;
+ goto end;
+ }
+
+ lpi_pkg_count = lpi_data->package.elements[2].integer.value;
+
+ /* Validate number of power states. */
+ if (!lpi_pkg_count || lpi_pkg_count != lpi_data->package.count - 3) {
+ acpi_handle_debug(handle, "Invalid _LPI state count\n");
+ ret = -ENODATA;
+ goto end;
+ }
+
+ lpi_state = kzalloc_objs(*lpi_state, lpi_pkg_count);
+ if (!lpi_state) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ info->size = lpi_pkg_count;
+ info->entries = lpi_state;
+
+ /* _LPI State packages start at index 3. */
+ lpi_pkg = &lpi_data->package.elements[3];
+
+ for (state_idx = 1; state_idx <= lpi_pkg_count; state_idx++) {
+ lpi_state->index = state_idx;
+ process_lpi_state_package(lpi_pkg++, lpi_state++, handle,
+ state_idx, strict);
+ }
+
+ acpi_handle_debug(handle, "Found %u power states\n", lpi_pkg_count);
+end:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+/**
+ * combine_lpi_states - combine local and parent LPI states to form a composite LPI state
+ *
+ * @local: local LPI state
+ * @parent: parent LPI state
+ * @result: composite LPI state
+ */
+static bool combine_lpi_states(struct acpi_lpi_state *local,
+ struct acpi_lpi_state *parent,
+ struct acpi_lpi_state *result)
+{
+ if (parent->entry_method == ACPI_CSTATE_INTEGER) {
+ if (!parent->address) /* 0 means autopromotable */
+ return false;
+ result->address = local->address + parent->address;
+ } else {
+ result->address = parent->address;
+ }
+
+ result->min_residency = max(local->min_residency, parent->min_residency);
+ result->wake_latency = local->wake_latency + parent->wake_latency;
+ result->enable_parent_state = parent->enable_parent_state;
+ result->entry_method = local->entry_method;
+
+ result->flags = parent->flags;
+ result->arch_flags = parent->arch_flags;
+ result->index = parent->index;
+
+ scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
+ return true;
+}
+
+#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0)
+
+static void stash_composite_state(struct acpi_lpi_states_array *curr_level,
+ struct acpi_lpi_state *t)
+{
+ curr_level->composite_states[curr_level->composite_states_size++] = t;
+}
+
+static bool too_many_states(acpi_handle handle, unsigned int state_count)
+{
+ if (state_count < ACPI_PROCESSOR_MAX_POWER)
+ return false;
+
+ acpi_handle_info(handle, "No space for more _LPI states than %d\n",
+ ACPI_PROCESSOR_MAX_POWER);
+ return true;
+}
+
+static unsigned int flatten_lpi_states(acpi_handle handle,
+ struct acpi_lpi_state *lpi_states,
+ unsigned int state_count,
+ struct acpi_lpi_states_array *curr,
+ struct acpi_lpi_states_array *prev)
+{
+ struct acpi_lpi_state *parent_lpi = curr->entries;
+ unsigned int j;
+
+ /*
+ * Combine each of the "raw" _LPI states from the current (processor
+ * container) level with all of the composite _LPI states from the
+ * previous (processor or processor container) level.
+ */
+ for (j = 0; j < curr->size; j++, parent_lpi++) {
+ struct acpi_lpi_state *flpi;
+ int i;
+
+ if (!(parent_lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
+ continue;
+
+ if (too_many_states(handle, state_count))
+ break;
+
+ flpi = &lpi_states[state_count];
+
+ for (i = 0; i < prev->composite_states_size; i++) {
+ struct acpi_lpi_state *local_lpi = prev->composite_states[i];
+
+ if (parent_lpi->index > local_lpi->enable_parent_state)
+ continue;
+
+ if (!combine_lpi_states(local_lpi, parent_lpi, flpi))
+ continue;
+
+ stash_composite_state(curr, flpi);
+ state_count++;
+ flpi++;
+
+ if (state_count >= ACPI_PROCESSOR_MAX_POWER)
+ break;
+ }
+ }
+
+ return state_count;
+}
+
+int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
+ struct acpi_processor_power *pr_power,
+ bool strict)
+{
+ struct acpi_lpi_states_array info[2], *prev, *curr;
+ acpi_handle handle = pr_handle;
+ unsigned int state_count = 0;
+ unsigned int i;
+ int ret;
+
+ if (!osc_pc_lpi_support_confirmed)
+ return -EOPNOTSUPP;
+
+ curr = &info[0];
+ curr->composite_states_size = 0;
+
+ ret = acpi_processor_evaluate_lpi(handle, curr, strict);
+ if (ret)
+ return ret;
+
+ /* Copy all of the usable first-level states to power.lpi_states[]. */
+ for (i = 0; i < curr->size; i++) {
+ struct acpi_lpi_state *lpi = &curr->entries[i];
+ struct acpi_lpi_state *flpi;
+
+ /*
+ * Skip states that are not enabled or have an inadequate entry
+ * method for this level.
+ */
+ if (!(lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED) ||
+ lpi->entry_method == ACPI_CSTATE_INTEGER)
+ continue;
+
+ if (too_many_states(pr_handle, state_count))
+ break;
+
+ flpi = &pr_power->lpi_states[state_count++];
+ memcpy(flpi, lpi, sizeof(*lpi));
+ stash_composite_state(curr, flpi);
+ }
+
+ kfree(curr->entries);
+
+ /*
+ * If there are no _LPI states at the first level, there are no _LPI
+ * states at all.
+ */
+ if (!state_count)
+ return -ENODATA;
+
+ prev = curr;
+ curr = &info[1];
+
+ for (;;) {
+ struct acpi_lpi_states_array *tmp;
+ struct acpi_device *d;
+
+ if (ACPI_FAILURE(acpi_get_parent(handle, &handle)))
+ break;
+
+ d = acpi_fetch_acpi_dev(handle);
+ if (!d)
+ break;
+
+ if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
+ break;
+
+ curr->composite_states_size = 0;
+
+ ret = acpi_processor_evaluate_lpi(handle, curr, strict);
+ if (ret)
+ break;
+
+ /* flatten all the LPI states in this level of hierarchy */
+ state_count = flatten_lpi_states(pr_handle, pr_power->lpi_states,
+ state_count, curr, prev);
+
+ kfree(curr->entries);
+
+ tmp = prev, prev = curr, curr = tmp;
+ }
+
+ /* reset the index after flattening */
+ for (i = 0; i < state_count; i++)
+ pr_power->lpi_states[i].index = i;
+
+ pr_power->count = state_count;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acpi_processor_extract_lpi_info, "ACPI_PROCESSOR_IDLE");
+#endif /* CONFIG_ACPI_PROCESSOR_IDLE */
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index f93e877f87f6..4d6fd9f6e9ad 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -1048,7 +1048,7 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
if (!video)
return -EINVAL;
- dev = acpi_get_pci_dev(video->device->handle);
+ dev = acpi_dev_get_pci_dev(video->device);
if (!dev)
return -ENODEV;
pci_dev_put(dev);
@@ -1702,7 +1702,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
{
struct backlight_properties props;
struct pci_dev *pdev;
- acpi_handle acpi_parent;
struct device *parent = NULL;
int result;
static int count;
@@ -1717,13 +1716,9 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
return;
count++;
- if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) {
- pdev = acpi_get_pci_dev(acpi_parent);
- if (pdev) {
- parent = &pdev->dev;
- pci_dev_put(pdev);
- }
- }
+ pdev = acpi_dev_get_pci_dev(acpi_dev_parent(device->dev));
+ if (pdev)
+ parent = &pdev->dev;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_FIRMWARE;
@@ -1734,6 +1729,7 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
device,
&acpi_backlight_ops,
&props);
+ put_device(parent);
kfree(name);
if (IS_ERR(device->backlight)) {
device->backlight = NULL;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 3236a3ce79d6..48f915ee5a0d 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -1397,8 +1397,8 @@ no_work:
return rc;
}
-static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
- enum fixed_addresses fixmap_idx)
+static int __maybe_unused ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
+ enum fixed_addresses fixmap_idx)
{
int ret = -ENOENT;
struct ghes *ghes;
diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index af7a9b2fd5bc..34412cd697d8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -789,11 +789,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
return irq_find_matching_fwnode(handle, bus_token);
}
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
+acpi_handle iort_iwb_handle(u32 iwb_id)
{
- struct fwnode_handle *fwnode;
struct acpi_iort_node *node;
- struct acpi_device *device;
struct acpi_iort_iwb *iwb;
acpi_status status;
acpi_handle handle;
@@ -808,6 +806,19 @@ struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
if (ACPI_FAILURE(status))
return NULL;
+ return handle;
+}
+
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id)
+{
+ struct fwnode_handle *fwnode;
+ struct acpi_device *device;
+ acpi_handle handle;
+
+ handle = iort_iwb_handle(iwb_id);
+ if (!handle)
+ return NULL;
+
device = acpi_get_acpi_dev(handle);
if (!device)
return NULL;
@@ -2090,6 +2101,11 @@ static void __init iort_init_platform_devices(void)
}
}
+u32 arch_acpi_add_auto_dep(acpi_handle handle)
+{
+ return acpi_irq_add_auto_dep(handle);
+}
+
void __init acpi_iort_init(void)
{
acpi_status status;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index f5e0eb299610..0084f308b790 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -10,10 +10,12 @@
#define pr_fmt(fmt) "ACPI: battery: " fmt
+#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
+#include <linux/kfifo.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -21,6 +23,7 @@
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <linux/unaligned.h>
@@ -43,6 +46,9 @@
#define MAX_STRING_LENGTH 64
+#define MAX_QUEUED_EVENTS 16
+#define NOTIF_MERGING_MS 10
+
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("ACPI Battery Driver");
@@ -95,6 +101,8 @@ struct acpi_battery {
struct power_supply_desc bat_desc;
struct acpi_device *device;
struct device *phys_dev;
+ struct kfifo acpi_notif_fifo;
+ struct delayed_work acpi_notif_dwork;
struct notifier_block pm_nb;
struct list_head list;
unsigned long update_time;
@@ -150,27 +158,28 @@ static int acpi_battery_technology(struct acpi_battery *battery)
static int acpi_battery_get_state(struct acpi_battery *battery);
-static int acpi_battery_is_charged(struct acpi_battery *battery)
+static bool acpi_battery_is_full(struct acpi_battery *battery)
{
- /* charging, discharging, critical low or charge limited */
- if (battery->state != 0)
- return 0;
-
/* battery not reporting charge */
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
battery->capacity_now == 0)
- return 0;
+ return false;
/* good batteries update full_charge as the batteries degrade */
if (battery->full_charge_capacity == battery->capacity_now)
- return 1;
+ return true;
/* fallback to using design values for broken batteries */
- if (battery->design_capacity <= battery->capacity_now)
- return 1;
+ return battery->design_capacity <= battery->capacity_now;
+}
- /* we don't do any sort of metric based on percentages */
- return 0;
+static int acpi_battery_is_charged(struct acpi_battery *battery)
+{
+ /* charging, discharging, critical low or charge limited */
+ if (battery->state != 0)
+ return 0;
+
+ return acpi_battery_is_full(battery);
}
static bool acpi_battery_is_degraded(struct acpi_battery *battery)
@@ -211,13 +220,14 @@ static int acpi_battery_get_property(struct power_supply *psy,
if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
val->intval = acpi_battery_handle_discharging(battery);
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
- /* Validate the status by checking the current. */
- if (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
- battery->rate_now == 0) {
- /* On charge but no current (0W/0mA). */
- val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
+ /* Check the rate and capacity to validate the status. */
+ if (!acpi_battery_is_full(battery) ||
+ (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
+ battery->rate_now > 0)) {
val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ } else {
+ /* Full and zero rate. */
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
@@ -483,6 +493,15 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
return 0;
}
+static void acpi_battery_clean_unprintable_chars(char *str, size_t length)
+{
+ for (unsigned int i = 0; i < length; i++) {
+ if (!isascii(str[i]) || !isprint(str[i])) {
+ str[i] = '\0';
+ break;
+ }
+ }
+}
static int extract_battery_info(const int use_bix,
struct acpi_battery *battery,
@@ -524,6 +543,10 @@ static int extract_battery_info(const int use_bix,
battery->capacity_now > battery->full_charge_capacity)
battery->capacity_now = battery->full_charge_capacity;
+ if (!result)
+ acpi_battery_clean_unprintable_chars(battery->model_number,
+ ARRAY_SIZE(battery->model_number));
+
return result;
}
@@ -668,9 +691,13 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
{
unsigned long x;
struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+ int err;
+
+ err = kstrtoul(buf, 10, &x);
+ if (err)
+ return err;
- if (sscanf(buf, "%lu\n", &x) == 1)
- battery->alarm = x/1000;
+ battery->alarm = x / 1000;
if (acpi_battery_present(battery))
acpi_battery_set_alarm(battery);
return count;
@@ -1059,14 +1086,24 @@ static void acpi_battery_refresh(struct acpi_battery *battery)
}
/* Driver Interface */
-static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
+static void acpi_battery_notification_worker(struct work_struct *work)
{
- struct acpi_battery *battery = data;
+ struct acpi_battery *battery = container_of(work, struct acpi_battery,
+ acpi_notif_dwork.work);
struct acpi_device *device = battery->device;
+ u32 events[MAX_QUEUED_EVENTS];
struct power_supply *old;
+ unsigned int count, i;
guard(mutex)(&battery->update_lock);
+ count = kfifo_out(&battery->acpi_notif_fifo, events, sizeof(events));
+ count /= sizeof(events[0]);
+ if (!count)
+ return;
+
+ pr_debug("merged %u battery notifications within %dms\n", count, NOTIF_MERGING_MS);
+
old = battery->bat;
/*
* On Acer Aspire V5-573G notifications are sometimes triggered too
@@ -1076,19 +1113,46 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
*/
if (battery_notification_delay_ms > 0)
msleep(battery_notification_delay_ms);
- if (event == ACPI_BATTERY_NOTIFY_INFO)
- acpi_battery_refresh(battery);
+
+ for (i = 0; i < count; i++) {
+ if (events[i] == ACPI_BATTERY_NOTIFY_INFO) {
+ acpi_battery_refresh(battery);
+ break;
+ }
+ }
+
acpi_battery_update(battery, false);
- acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS,
- dev_name(&device->dev), event,
- acpi_battery_present(battery));
- acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device),
- event, acpi_battery_present(battery));
+
+ for (i = 0; i < count; i++) {
+ acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS,
+ dev_name(&device->dev), events[i],
+ acpi_battery_present(battery));
+ acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device),
+ events[i], acpi_battery_present(battery));
+ }
+
/* acpi_battery_update could remove power_supply object */
if (old && battery->bat)
power_supply_changed(battery->bat);
}
+static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_battery *battery = data;
+
+ guard(mutex)(&battery->update_lock);
+
+ if (kfifo_avail(&battery->acpi_notif_fifo) >= sizeof(event)) {
+ kfifo_in(&battery->acpi_notif_fifo, &event, sizeof(event));
+ schedule_delayed_work(&battery->acpi_notif_dwork,
+ msecs_to_jiffies(NOTIF_MERGING_MS));
+
+ return;
+ }
+
+ pr_err_ratelimited("too many battery notifications within %dms\n", NOTIF_MERGING_MS);
+}
+
static int battery_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
{
@@ -1231,6 +1295,29 @@ static int devm_acpi_battery_update_retry(struct device *dev,
return ret;
}
+static void acpi_battery_notify_dwork_cleanup(void *data)
+{
+ struct acpi_battery *battery = data;
+
+ cancel_delayed_work_sync(&battery->acpi_notif_dwork);
+ kfifo_free(&battery->acpi_notif_fifo);
+}
+
+static int devm_acpi_battery_init_notify_dwork(struct device *dev,
+ struct acpi_battery *battery)
+{
+ int ret;
+
+ INIT_DELAYED_WORK(&battery->acpi_notif_dwork, acpi_battery_notification_worker);
+
+ ret = kfifo_alloc(&battery->acpi_notif_fifo,
+ MAX_QUEUED_EVENTS * sizeof(u32), GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(dev, acpi_battery_notify_dwork_cleanup, battery);
+}
+
static int acpi_battery_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1272,6 +1359,10 @@ static int acpi_battery_probe(struct platform_device *pdev)
if (result)
return result;
+ result = devm_acpi_battery_init_notify_dwork(dev, battery);
+ if (result)
+ return result;
+
result = devm_acpi_install_notify_handler(dev, ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (result)
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index a30a904f6535..fae79cdd3610 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -620,41 +620,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
}
-static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
-{
- struct acpi_device *device = data;
- struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver);
-
- acpi_drv->ops.notify(device, event);
-}
-
-static int acpi_device_install_notify_handler(struct acpi_device *device,
- struct acpi_driver *acpi_drv)
-{
- u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
- ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
- acpi_status status;
-
- status = acpi_install_notify_handler(device->handle, type,
- acpi_notify_device, device);
- if (ACPI_FAILURE(status))
- return -EINVAL;
-
- return 0;
-}
-
-static void acpi_device_remove_notify_handler(struct acpi_device *device,
- struct acpi_driver *acpi_drv)
-{
- u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
- ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
-
- acpi_remove_notify_handler(device->handle, type,
- acpi_notify_device);
-
- acpi_os_wait_events_complete();
-}
-
int acpi_dev_install_notify_handler(struct acpi_device *adev,
u32 handler_type,
acpi_notify_handler handler, void *context)
@@ -1122,56 +1087,12 @@ bool acpi_driver_match_device(struct device *dev,
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
/* --------------------------------------------------------------------------
- ACPI Driver Management
- -------------------------------------------------------------------------- */
-
-/**
- * __acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- * @owner: owning module/driver
- *
- * Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns zero for
- * success or a negative error status for failure.
- */
-int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner)
-{
- if (acpi_disabled)
- return -ENODEV;
- driver->drv.name = driver->name;
- driver->drv.bus = &acpi_bus_type;
- driver->drv.owner = owner;
-
- return driver_register(&driver->drv);
-}
-
-EXPORT_SYMBOL(__acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
-{
- driver_unregister(&driver->drv);
-}
-
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
-
-/* --------------------------------------------------------------------------
ACPI Bus operations
-------------------------------------------------------------------------- */
static int acpi_bus_match(struct device *dev, const struct device_driver *drv)
{
- struct acpi_device *acpi_dev = to_acpi_device(dev);
- const struct acpi_driver *acpi_drv = to_acpi_driver(drv);
-
- return acpi_dev->flags.match_driver
- && !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
+ return 0;
}
static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
@@ -1179,66 +1100,9 @@ static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *
return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
}
-static int acpi_device_probe(struct device *dev)
-{
- struct acpi_device *acpi_dev = to_acpi_device(dev);
- struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
- int ret;
-
- if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev))
- return -EINVAL;
-
- if (!acpi_drv->ops.add)
- return -ENOSYS;
-
- ret = acpi_drv->ops.add(acpi_dev);
- if (ret) {
- acpi_dev->driver_data = NULL;
- return ret;
- }
-
- pr_debug("Driver [%s] successfully bound to device [%s]\n",
- acpi_drv->name, acpi_dev->pnp.bus_id);
-
- if (acpi_drv->ops.notify) {
- ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv);
- if (ret) {
- if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev);
-
- acpi_dev->driver_data = NULL;
- return ret;
- }
- }
-
- pr_debug("Found driver [%s] for device [%s]\n", acpi_drv->name,
- acpi_dev->pnp.bus_id);
-
- get_device(dev);
- return 0;
-}
-
-static void acpi_device_remove(struct device *dev)
-{
- struct acpi_device *acpi_dev = to_acpi_device(dev);
- struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
-
- if (acpi_drv->ops.notify)
- acpi_device_remove_notify_handler(acpi_dev, acpi_drv);
-
- if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev);
-
- acpi_dev->driver_data = NULL;
-
- put_device(dev);
-}
-
const struct bus_type acpi_bus_type = {
.name = "acpi",
.match = acpi_bus_match,
- .probe = acpi_device_probe,
- .remove = acpi_device_remove,
.uevent = acpi_device_uevent,
};
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index b6356476a46e..9f1e7c16a092 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -475,17 +475,29 @@ bool acpi_cpc_valid(void)
}
EXPORT_SYMBOL_GPL(acpi_cpc_valid);
-bool cppc_allow_fast_switch(void)
+bool cppc_allow_fast_switch(const struct cpumask *cpus)
{
- struct cpc_register_resource *desired_reg;
+ struct cpc_register_resource *desired_reg, *min_reg, *max_reg;
struct cpc_desc *cpc_ptr;
int cpu;
- for_each_online_cpu(cpu) {
+ for_each_cpu(cpu, cpus) {
cpc_ptr = per_cpu(cpc_desc_ptr, cpu);
+ if (!cpc_ptr)
+ return false;
desired_reg = &cpc_ptr->cpc_regs[DESIRED_PERF];
- if (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
- !CPC_IN_SYSTEM_IO(desired_reg))
+ min_reg = &cpc_ptr->cpc_regs[MIN_PERF];
+ max_reg = &cpc_ptr->cpc_regs[MAX_PERF];
+
+ if (!CPC_SUPPORTED(desired_reg) ||
+ (!CPC_IN_SYSTEM_MEMORY(desired_reg) &&
+ !CPC_IN_SYSTEM_IO(desired_reg)) ||
+ (CPC_SUPPORTED(min_reg) &&
+ !CPC_IN_SYSTEM_MEMORY(min_reg) &&
+ !CPC_IN_SYSTEM_IO(min_reg)) ||
+ (CPC_SUPPORTED(max_reg) &&
+ !CPC_IN_SYSTEM_MEMORY(max_reg) &&
+ !CPC_IN_SYSTEM_IO(max_reg)))
return false;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 64ad4cfa6208..a89f10256dbb 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1510,6 +1510,24 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0;
}
+static int ec_prepare_gpio_irq(struct acpi_ec *ec, struct acpi_device *device)
+{
+ int irq;
+
+ if (!device || ec->gpe >= 0 || ec->irq >= 0)
+ return 0;
+
+ /* ACPI reduced hardware platforms use a GpioInt from _CRS. */
+ irq = acpi_dev_gpio_irq_get(device, 0);
+ if (irq == -EPROBE_DEFER)
+ return irq;
+
+ if (irq >= 0)
+ ec->irq = irq;
+
+ return 0;
+}
+
/**
* ec_install_handlers - Install service callbacks and register query methods.
* @ec: Target EC.
@@ -1524,7 +1542,6 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
* Return:
* -ENODEV if the address space handler cannot be installed, which means
* "unable to handle transactions",
- * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
* or 0 (success) otherwise.
*/
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
@@ -1557,19 +1574,6 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
if (!device)
return 0;
- if (ec->gpe < 0) {
- /* ACPI reduced hardware platforms use a GpioInt from _CRS. */
- int irq = acpi_dev_gpio_irq_get(device, 0);
- /*
- * Bail out right away for deferred probing or complete the
- * initialization regardless of any other errors.
- */
- if (irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- else if (irq >= 0)
- ec->irq = irq;
- }
-
if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
@@ -1647,6 +1651,14 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca
{
int ret;
+ /*
+ * GPIO IRQ lookup can defer. Do it before publishing the EC
+ * OpRegion to AML to avoid a spurious _REG(disconnect).
+ */
+ ret = ec_prepare_gpio_irq(ec, device);
+ if (ret)
+ return ret;
+
/* First EC capable of handling transactions */
if (!first_ec)
first_ec = ec;
diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h
index 97ce3212edf3..e20d6ad9df80 100644
--- a/drivers/acpi/fan.h
+++ b/drivers/acpi/fan.h
@@ -10,20 +10,21 @@
#ifndef _ACPI_FAN_H_
#define _ACPI_FAN_H_
-#include <linux/kconfig.h>
+#include <linux/device.h>
#include <linux/limits.h>
+#include <linux/types.h>
-#define ACPI_FAN_DEVICE_IDS \
- {"INT3404", }, /* Fan */ \
- {"INTC1044", }, /* Fan for Tiger Lake generation */ \
- {"INTC1048", }, /* Fan for Alder Lake generation */ \
- {"INTC1063", }, /* Fan for Meteor Lake generation */ \
- {"INTC106A", }, /* Fan for Lunar Lake generation */ \
- {"INTC10A2", }, /* Fan for Raptor Lake generation */ \
- {"INTC10D6", }, /* Fan for Panther Lake generation */ \
- {"INTC10FE", }, /* Fan for Wildcat Lake generation */ \
- {"INTC10F5", }, /* Fan for Nova Lake generation */ \
- {"PNP0C0B", } /* Generic ACPI fan */
+#define ACPI_FAN_DEVICE_IDS \
+ { .id = "INT3404" }, /* Fan */ \
+ { .id = "INTC1044" }, /* Fan for Tiger Lake generation */ \
+ { .id = "INTC1048" }, /* Fan for Alder Lake generation */ \
+ { .id = "INTC1063" }, /* Fan for Meteor Lake generation */ \
+ { .id = "INTC106A" }, /* Fan for Lunar Lake generation */ \
+ { .id = "INTC10A2" }, /* Fan for Raptor Lake generation */ \
+ { .id = "INTC10D6" }, /* Fan for Panther Lake generation */ \
+ { .id = "INTC10FE" }, /* Fan for Wildcat Lake generation */ \
+ { .id = "INTC10F5" }, /* Fan for Nova Lake generation */ \
+ { .id = "PNP0C0B" } /* Generic ACPI fan */
#define ACPI_FPS_NAME_LEN 20
@@ -69,7 +70,7 @@ struct acpi_fan {
/**
* acpi_fan_speed_valid - Check if fan speed value is valid
- * @speeed: Speed value returned by the ACPI firmware
+ * @speed: Speed value returned by the ACPI firmware
*
* Check if the fan speed value returned by the ACPI firmware is valid. This function is
* necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the
diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c
index fb08b8549ed7..624d0736b581 100644
--- a/drivers/acpi/fan_core.c
+++ b/drivers/acpi/fan_core.c
@@ -489,26 +489,6 @@ static void acpi_fan_notify_handler(acpi_handle handle, u32 event, void *context
}
}
-static void acpi_fan_notify_remove(void *data)
-{
- struct acpi_fan *fan = data;
-
- acpi_remove_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY, acpi_fan_notify_handler);
-}
-
-static int devm_acpi_fan_notify_init(struct device *dev)
-{
- struct acpi_fan *fan = dev_get_drvdata(dev);
- acpi_status status;
-
- status = acpi_install_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY,
- acpi_fan_notify_handler, dev);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- return devm_add_action_or_reset(dev, acpi_fan_notify_remove, fan);
-}
-
static int acpi_fan_probe(struct platform_device *pdev)
{
int result = 0;
@@ -556,7 +536,10 @@ static int acpi_fan_probe(struct platform_device *pdev)
if (result)
return result;
- result = devm_acpi_fan_notify_init(&pdev->dev);
+ result = devm_acpi_install_notify_handler(&pdev->dev,
+ ACPI_DEVICE_NOTIFY,
+ acpi_fan_notify_handler,
+ &pdev->dev);
if (result)
return result;
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index d1595156c86a..e4293458bf61 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -13,6 +13,7 @@
enum acpi_irq_model_id acpi_irq_model;
static acpi_gsi_domain_disp_fn acpi_get_gsi_domain_id;
+static acpi_gsi_handle_disp_fn acpi_get_gsi_handle;
static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);
/**
@@ -321,15 +322,19 @@ const struct cpumask *acpi_irq_get_affinity(acpi_handle handle,
/**
* acpi_set_irq_model - Setup the GSI irqdomain information
- * @model: the value assigned to acpi_irq_model
- * @fn: a dispatcher function that will return the domain fwnode
- * for a given GSI
+ * @model: the value assigned to acpi_irq_model
+ * @fn: a dispatcher function that will return the domain fwnode
+ * for a given GSI
+ * @gsi_dep_fn: a function to retrieve the acpi_handle a GSI interrupt is
+ * dependent on
+ *
*/
void __init acpi_set_irq_model(enum acpi_irq_model_id model,
- acpi_gsi_domain_disp_fn fn)
+ acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn)
{
acpi_irq_model = model;
acpi_get_gsi_domain_id = fn;
+ acpi_get_gsi_handle = gsi_dep_fn;
}
/*
@@ -385,3 +390,162 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
host_data);
}
EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
+
+struct acpi_irq_dep_ctx {
+ int rc;
+ unsigned int index;
+ acpi_handle handle;
+};
+
+static acpi_status 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 = acpi_get_gsi_handle(irq->interrupts[ctx->index]);
+ ctx->rc = 0;
+ 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 = acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+ ctx->rc = 0;
+ return AE_CTRL_TERMINATE;
+ }
+
+ return AE_OK;
+}
+
+static int 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 -EINVAL;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_get_parent, &ctx);
+ *gsi_handle = ctx.handle;
+
+ return ctx.rc;
+}
+
+static bool acpi_prt_entry_valid(void *prt_entry)
+{
+ struct acpi_pci_routing_table *entry = prt_entry;
+
+ return entry && entry->length > 0;
+}
+
+static void *acpi_prt_next_entry(void *prt_entry)
+{
+ struct acpi_pci_routing_table *entry = prt_entry;
+
+ return prt_entry + entry->length;
+}
+
+static u32 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;
+ for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
+ if (entry->source[0]) {
+ status = acpi_get_handle(handle, entry->source, &link_handle);
+ if (ACPI_FAILURE(status))
+ continue;
+ 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 = acpi_get_gsi_handle(entry->source_index);
+ if (!gsi_handle)
+ continue;
+ 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);
+ }
+ }
+
+ kfree(buffer.pointer);
+ return count;
+}
+
+static u32 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; !acpi_irq_get_dep(handle, i, &gsi_handle); i++) {
+ if (!gsi_handle)
+ continue;
+
+ 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 acpi_irq_add_auto_dep(acpi_handle handle)
+{
+ if (!acpi_get_gsi_handle)
+ return 0;
+
+ if (acpi_has_method(handle, "_PRT"))
+ return acpi_add_prt_dep(handle);
+
+ return acpi_add_irq_dep(handle);
+}
diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c
index 62d4a8df0b8c..5c407dc6401e 100644
--- a/drivers/acpi/numa/srat.c
+++ b/drivers/acpi/numa/srat.c
@@ -399,8 +399,6 @@ acpi_parse_memory_affinity(union acpi_subtable_headers *header,
goto out_err_bad_srat;
}
- node_set(node, numa_nodes_parsed);
-
pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n",
node, pxm,
(unsigned long long) start, (unsigned long long) end - 1,
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
index 6eaad7dd0241..12aee4102696 100644
--- a/drivers/acpi/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -133,7 +133,7 @@ void suspend_nvs_free(void)
list_for_each_entry(entry, &nvs_list, node)
if (entry->data) {
- free_page((unsigned long)entry->data);
+ kfree(entry->data);
entry->data = NULL;
if (entry->kaddr) {
if (entry->unmap) {
@@ -156,7 +156,7 @@ int suspend_nvs_alloc(void)
struct nvs_page *entry;
list_for_each_entry(entry, &nvs_list, node) {
- entry->data = (void *)__get_free_page(GFP_KERNEL);
+ entry->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!entry->data) {
suspend_nvs_free();
return -ENOMEM;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4c06c3ffd0cb..6f78f96332ea 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) "ACPI: " fmt
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -292,41 +293,37 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)
EXPORT_SYMBOL_GPL(acpi_pci_find_root);
/**
- * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev
- * @handle: the handle in question
+ * acpi_dev_get_pci_dev - Get a struct pci_dev for a given ACPI device
+ * @adev: Target ACPI device.
*
- * Given an ACPI CA handle, the desired PCI device is located in the
- * list of PCI devices.
+ * Find the PCI device associated with @adev, if any, and bump up its reference
+ * counter.
*
- * If the device is found, its reference count is increased and this
- * function returns a pointer to its data structure. The caller must
- * decrement the reference count by calling pci_dev_put().
- * If no device is found, %NULL is returned.
+ * Callers are responsible for dropping the PCI device reference obtained by
+ * this function.
+ *
+ * Return: The struct pci_dev pointer of a reference-counted PCI device on
+ * success or NULL on failure.
*/
-struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
+struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev)
{
- struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
struct acpi_device_physical_node *pn;
- struct pci_dev *pci_dev = NULL;
if (!adev)
return NULL;
- mutex_lock(&adev->physical_node_lock);
+ guard(mutex)(&adev->physical_node_lock);
list_for_each_entry(pn, &adev->physical_node_list, node) {
if (dev_is_pci(pn->dev)) {
get_device(pn->dev);
- pci_dev = to_pci_dev(pn->dev);
- break;
+ return to_pci_dev(pn->dev);
}
}
- mutex_unlock(&adev->physical_node_lock);
-
- return pci_dev;
+ return NULL;
}
-EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
+EXPORT_SYMBOL_GPL(acpi_dev_get_pci_dev);
/**
* acpi_pci_osc_control_set - Request control of PCI root _OSC features.
@@ -725,7 +722,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
dev_err(&device->dev,
"Bus %04x:%02x not present in PCI namespace\n",
root->segment, (unsigned int)root->secondary.start);
- device->driver_data = NULL;
result = -ENODEV;
goto remove_dmar;
}
@@ -765,6 +761,7 @@ remove_dmar:
if (hotadd)
dmar_device_remove(handle);
end:
+ device->driver_data = NULL;
kfree(root);
return result;
}
@@ -788,6 +785,7 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_unlock_rescan_remove();
+ device->driver_data = NULL;
kfree(root);
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index d4131c184be8..23a4e207a01e 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -954,7 +954,6 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
INIT_LIST_HEAD(&resource->list_node);
INIT_LIST_HEAD(&resource->dependents);
device->power.state = ACPI_STATE_UNKNOWN;
- device->flags.match_driver = true;
/* Evaluate the object to get the system level and resource order. */
status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a4498357bd16..3bf076c150fa 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -336,11 +336,26 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
-static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
+static bool madt_entry_is_valid(struct acpi_subtable_header *entry,
+ unsigned long end)
+{
+ unsigned long start = (unsigned long)entry;
+
+ if (start >= end || end - start < sizeof(*entry))
+ return false;
+
+ return entry->length >= sizeof(*entry) && entry->length <= end - start;
+}
+
+static int get_ioapic_id(struct acpi_subtable_header *entry,
+ const unsigned long end, u32 gsi_base,
u64 *phys_addr, int *ioapic_id)
{
struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
+ if (!madt_entry_is_valid(entry, end) || BAD_MADT_ENTRY(ioapic, end))
+ return 0;
+
if (ioapic->global_irq_base != gsi_base)
return 0;
@@ -361,17 +376,19 @@ static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
return apic_id;
entry = (unsigned long)madt;
+ if (madt->header.length < sizeof(*madt))
+ return apic_id;
madt_end = entry + madt->header.length;
/* Parse all entries looking for a match. */
entry += sizeof(struct acpi_table_madt);
- while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ while (madt_entry_is_valid((struct acpi_subtable_header *)entry,
+ madt_end)) {
hdr = (struct acpi_subtable_header *)entry;
if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
- get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
+ get_ioapic_id(hdr, madt_end, gsi_base, phys_addr, &apic_id))
break;
- else
- entry += hdr->length;
+ entry += hdr->length;
}
return apic_id;
@@ -398,7 +415,9 @@ static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
header = (struct acpi_subtable_header *)obj->buffer.pointer;
if (header->type == ACPI_MADT_TYPE_IO_APIC)
- get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
+ get_ioapic_id(header,
+ (unsigned long)header + obj->buffer.length,
+ gsi_base, phys_addr, &apic_id);
exit:
kfree(buffer.pointer);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 4482cf28f56a..e113bcbbb882 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -853,223 +853,6 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
-struct acpi_lpi_states_array {
- unsigned int size;
- unsigned int composite_states_size;
- struct acpi_lpi_state *entries;
- struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
-};
-
-static int obj_get_integer(union acpi_object *obj, u32 *value)
-{
- if (obj->type != ACPI_TYPE_INTEGER)
- return -EINVAL;
-
- *value = obj->integer.value;
- return 0;
-}
-
-static int acpi_processor_evaluate_lpi(acpi_handle handle,
- struct acpi_lpi_states_array *info)
-{
- acpi_status status;
- int ret = 0;
- int pkg_count, state_idx = 1, loop;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *lpi_data;
- struct acpi_lpi_state *lpi_state;
-
- status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- acpi_handle_debug(handle, "No _LPI, giving up\n");
- return -ENODEV;
- }
-
- lpi_data = buffer.pointer;
-
- /* There must be at least 4 elements = 3 elements + 1 package */
- if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
- lpi_data->package.count < 4) {
- pr_debug("not enough elements in _LPI\n");
- ret = -ENODATA;
- goto end;
- }
-
- pkg_count = lpi_data->package.elements[2].integer.value;
-
- /* Validate number of power states. */
- if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
- pr_debug("count given by _LPI is not valid\n");
- ret = -ENODATA;
- goto end;
- }
-
- lpi_state = kzalloc_objs(*lpi_state, pkg_count);
- if (!lpi_state) {
- ret = -ENOMEM;
- goto end;
- }
-
- info->size = pkg_count;
- info->entries = lpi_state;
-
- /* LPI States start at index 3 */
- for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) {
- union acpi_object *element, *pkg_elem, *obj;
-
- element = &lpi_data->package.elements[loop];
- if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7)
- continue;
-
- pkg_elem = element->package.elements;
-
- obj = pkg_elem + 6;
- if (obj->type == ACPI_TYPE_BUFFER) {
- struct acpi_power_register *reg;
-
- reg = (struct acpi_power_register *)obj->buffer.pointer;
- if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
- reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)
- continue;
-
- lpi_state->address = reg->address;
- lpi_state->entry_method =
- reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE ?
- ACPI_CSTATE_FFH : ACPI_CSTATE_SYSTEMIO;
- } else if (obj->type == ACPI_TYPE_INTEGER) {
- lpi_state->entry_method = ACPI_CSTATE_INTEGER;
- lpi_state->address = obj->integer.value;
- } else {
- pr_debug("Entry method of state-%d is invalid, disable it.\n",
- state_idx);
- continue;
- }
-
- /* elements[7,8] skipped for now i.e. Residency/Usage counter*/
-
- obj = pkg_elem + 9;
- if (obj->type == ACPI_TYPE_STRING)
- strscpy(lpi_state->desc, obj->string.pointer,
- ACPI_CX_DESC_LEN);
-
- lpi_state->index = state_idx;
- if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) {
- pr_debug("No min. residency found, assuming 10 us\n");
- lpi_state->min_residency = 10;
- }
-
- if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) {
- pr_debug("No wakeup residency found, assuming 10 us\n");
- lpi_state->wake_latency = 10;
- }
-
- if (obj_get_integer(pkg_elem + 2, &lpi_state->flags))
- lpi_state->flags = 0;
-
- if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags))
- lpi_state->arch_flags = 0;
-
- if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq))
- lpi_state->res_cnt_freq = 1;
-
- if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state))
- lpi_state->enable_parent_state = 0;
- }
-
- acpi_handle_debug(handle, "Found %d power states\n", state_idx);
-end:
- kfree(buffer.pointer);
- return ret;
-}
-
-/**
- * combine_lpi_states - combine local and parent LPI states to form a composite LPI state
- *
- * @local: local LPI state
- * @parent: parent LPI state
- * @result: composite LPI state
- */
-static bool combine_lpi_states(struct acpi_lpi_state *local,
- struct acpi_lpi_state *parent,
- struct acpi_lpi_state *result)
-{
- if (parent->entry_method == ACPI_CSTATE_INTEGER) {
- if (!parent->address) /* 0 means autopromotable */
- return false;
- result->address = local->address + parent->address;
- } else {
- result->address = parent->address;
- }
-
- result->min_residency = max(local->min_residency, parent->min_residency);
- result->wake_latency = local->wake_latency + parent->wake_latency;
- result->enable_parent_state = parent->enable_parent_state;
- result->entry_method = local->entry_method;
-
- result->flags = parent->flags;
- result->arch_flags = parent->arch_flags;
- result->index = parent->index;
-
- scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
- return true;
-}
-
-#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0)
-
-static void stash_composite_state(struct acpi_lpi_states_array *curr_level,
- struct acpi_lpi_state *t)
-{
- curr_level->composite_states[curr_level->composite_states_size++] = t;
-}
-
-static unsigned int flatten_lpi_states(struct acpi_processor *pr,
- unsigned int flat_state_cnt,
- struct acpi_lpi_states_array *curr_level,
- struct acpi_lpi_states_array *prev_level)
-{
- int i, j, state_count = curr_level->size;
- struct acpi_lpi_state *p, *t = curr_level->entries;
-
- curr_level->composite_states_size = 0;
- for (j = 0; j < state_count; j++, t++) {
- struct acpi_lpi_state *flpi;
-
- if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
- continue;
-
- if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) {
- pr_warn("Limiting number of LPI states to max (%d)\n",
- ACPI_PROCESSOR_MAX_POWER);
- pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
- break;
- }
-
- flpi = &pr->power.lpi_states[flat_state_cnt];
-
- if (!prev_level) { /* leaf/processor node */
- memcpy(flpi, t, sizeof(*t));
- stash_composite_state(curr_level, flpi);
- flat_state_cnt++;
- continue;
- }
-
- for (i = 0; i < prev_level->composite_states_size; i++) {
- p = prev_level->composite_states[i];
- if (t->index <= p->enable_parent_state &&
- combine_lpi_states(p, t, flpi)) {
- stash_composite_state(curr_level, flpi);
- flat_state_cnt++;
- flpi++;
- if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER)
- break;
- }
- }
- }
-
- kfree(curr_level->entries);
- return flat_state_cnt;
-}
-
int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
{
return -EOPNOTSUPP;
@@ -1077,64 +860,16 @@ int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu)
static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
{
- int ret, i;
- acpi_status status;
- acpi_handle handle = pr->handle, pr_ahandle;
- struct acpi_device *d = NULL;
- struct acpi_lpi_states_array info[2], *tmp, *prev, *curr;
- unsigned int state_count;
+ int ret;
/* make sure our architecture has support */
ret = acpi_processor_ffh_lpi_probe(pr->id);
if (ret == -EOPNOTSUPP)
return ret;
- if (!osc_pc_lpi_support_confirmed)
- return -EOPNOTSUPP;
-
- if (!acpi_has_method(handle, "_LPI"))
- return -EINVAL;
-
- prev = &info[0];
- curr = &info[1];
- handle = pr->handle;
- ret = acpi_processor_evaluate_lpi(handle, prev);
+ ret = acpi_processor_extract_lpi_info(pr->handle, &pr->power, false);
if (ret)
return ret;
- state_count = flatten_lpi_states(pr, 0, prev, NULL);
-
- status = acpi_get_parent(handle, &pr_ahandle);
- while (ACPI_SUCCESS(status)) {
- d = acpi_fetch_acpi_dev(pr_ahandle);
- if (!d)
- break;
-
- handle = pr_ahandle;
-
- if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
- break;
-
- /* can be optional ? */
- if (!acpi_has_method(handle, "_LPI"))
- break;
-
- ret = acpi_processor_evaluate_lpi(handle, curr);
- if (ret)
- break;
-
- /* flatten all the LPI states in this level of hierarchy */
- state_count = flatten_lpi_states(pr, state_count, curr, prev);
-
- tmp = prev, prev = curr, curr = tmp;
-
- status = acpi_get_parent(handle, &pr_ahandle);
- }
-
- /* reset the index after flattening */
- for (i = 0; i < state_count; i++)
- pr->power.lpi_states[i].index = i;
-
- pr->power.count = state_count;
/* Tell driver that _LPI is supported. */
pr->flags.has_lpi = 1;
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 9b88d0993e88..da2c42e0ebfd 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -23,12 +23,6 @@ struct riscv_ext_intc_list {
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)
@@ -254,7 +248,7 @@ void __init riscv_acpi_init_gsi_mapping(void)
acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL);
}
-static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi)
{
struct riscv_ext_intc_list *ext_intc_element;
struct list_head *i;
@@ -269,138 +263,7 @@ static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
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 = kzalloc_objs(*dep_devices.handles,
- 1);
- 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 = kzalloc_objs(*dep_devices.handles,
- 1);
- 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 = kzalloc_objs(*dep_devices.handles, 1);
- 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);
+ return acpi_irq_add_auto_dep(handle);
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 21937912a1a5..f4cc1da48224 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -273,13 +273,9 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p)
}
}
- adev->flags.match_driver = false;
- if (handler) {
- if (handler->detach)
- handler->detach(adev);
- } else {
- device_release_driver(&adev->dev);
- }
+ if (handler && handler->detach)
+ handler->detach(adev);
+
/*
* Most likely, the device is going away, so put it into D3cold before
* that.
@@ -854,6 +850,7 @@ static const char * const acpi_ignore_dep_ids[] = {
/* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
static const char * const acpi_honor_dep_ids[] = {
+ "ARMH0003", /* ARM GICv5 IWB */
"INT3472", /* Camera sensor PMIC / clk and regulator info */
"INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
@@ -1769,7 +1766,6 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
* Some ACPI devs contain SerialBus resources even though they are not
* attached to a serial bus at all.
*/
- {ACPI_VIDEO_HID, },
{"MSHW0028", },
/*
* HIDs of device with an UartSerialBusV2 resource for which userspace
@@ -1792,6 +1788,9 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
fwnode_property_present(&device->fwnode, "baud")))
return true;
+ if (acpi_dev_is_video_device(device))
+ return false;
+
if (!acpi_match_device_ids(device, ignore_serial_bus_ids))
return false;
@@ -1816,13 +1815,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->dev.release = release;
device->dev.bus = &acpi_bus_type;
device->dev.groups = acpi_groups;
+ device_set_pm_not_required(&device->dev);
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
acpi_set_device_status(device, ACPI_STA_DEFAULT);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_init_properties(device);
acpi_bus_get_flags(device);
- device->flags.match_driver = false;
device->flags.initialized = true;
device->flags.enumeration_by_parent =
acpi_device_enumeration_by_parent(device);
@@ -2376,16 +2375,11 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
if (ret < 0)
return 0;
- device->flags.match_driver = true;
if (ret > 0 && !device->flags.enumeration_by_parent) {
acpi_device_set_enumerated(device);
goto ok;
}
- ret = device_attach(&device->dev);
- if (ret < 0)
- return 0;
-
if (device->pnp.type.platform_id || device->pnp.type.backlight ||
device->flags.enumeration_by_parent)
acpi_default_enumeration(device);
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 908cc5c7e643..dd4a99f09efe 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -316,6 +316,7 @@ struct acpi_table_attr {
struct acpi_data_attr {
struct bin_attribute attr;
u64 addr;
+ char filename[ACPI_NAMESEG_SIZE+ACPI_INST_SIZE];
};
static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
@@ -447,13 +448,12 @@ static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr)
struct acpi_table_bert *bert = th;
if (bert->header.length < sizeof(struct acpi_table_bert) ||
- bert->region_length < sizeof(struct acpi_hest_generic_status)) {
+ bert->region_length < sizeof(struct acpi_bert_region)) {
kfree(data_attr);
return -EINVAL;
}
data_attr->addr = bert->address;
data_attr->attr.size = bert->region_length;
- data_attr->attr.attr.name = "BERT";
return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
}
@@ -469,7 +469,6 @@ static int acpi_ccel_data_init(void *th, struct acpi_data_attr *data_attr)
}
data_attr->addr = ccel->log_area_start_address;
data_attr->attr.size = ccel->log_area_minimum_length;
- data_attr->attr.attr.name = "CCEL";
return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr);
}
@@ -484,7 +483,7 @@ static struct acpi_data_obj {
#define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs)
-static int acpi_table_data_init(struct acpi_table_header *th)
+static int acpi_table_data_init(struct acpi_table_header *th, struct acpi_table_attr *table_attr)
{
struct acpi_data_attr *data_attr;
int i;
@@ -497,6 +496,8 @@ static int acpi_table_data_init(struct acpi_table_header *th)
sysfs_attr_init(&data_attr->attr.attr);
data_attr->attr.read = acpi_data_show;
data_attr->attr.attr.mode = 0400;
+ strscpy(data_attr->filename, table_attr->filename);
+ data_attr->attr.attr.name = data_attr->filename;
return acpi_data_objs[i].fn(th, data_attr);
}
}
@@ -543,7 +544,7 @@ static int acpi_tables_sysfs_init(void)
return ret;
}
list_add_tail(&table_attr->node, &acpi_table_attr_list);
- acpi_table_data_init(table_header);
+ acpi_table_data_init(table_header, table_attr);
}
kobject_uevent(tables_kobj, KOBJ_ADD);
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 6ab27e4826d1..d499b72574ab 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -1048,6 +1048,23 @@ static int __init acpi_backlight(char *str)
__setup("acpi_backlight=", acpi_backlight);
/**
+ * acpi_dev_is_video_device - test if device matches against ACPI video device IDs
+ * @adev: ACPI device to test
+ *
+ * Return: true when matches, otherwise false.
+ */
+bool acpi_dev_is_video_device(struct acpi_device *adev)
+{
+ static const struct acpi_device_id video_device_ids[] = {
+ { .id = ACPI_VIDEO_HID },
+ { }
+ };
+
+ return adev && !acpi_match_device_ids(adev, video_device_ids);
+}
+EXPORT_SYMBOL(acpi_dev_is_video_device);
+
+/**
* acpi_match_platform_list - Check if the system matches with a given list
* @plat: pointer to acpi_platform_list table terminated by a NULL entry
*
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 458efa4fe9d4..5b0dc679e322 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -67,13 +67,8 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
long *cap = context;
struct pci_dev *dev;
- static const struct acpi_device_id video_ids[] = {
- {ACPI_VIDEO_HID, 0},
- {"", 0},
- };
-
- if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) {
- dev = acpi_get_pci_dev(handle);
+ if (acpi_dev_is_video_device(acpi_dev)) {
+ dev = acpi_dev_get_pci_dev(acpi_dev);
if (!dev)
return AE_OK;
pci_dev_put(dev);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 335288e8b5b3..fab38bc98113 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -469,9 +469,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
if (retval == -EACCES)
retval = -EAGAIN;
- if (retval != -EAGAIN && retval != -EBUSY)
- dev->power.runtime_error = retval;
-
return retval;
}
@@ -751,6 +748,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);
+ if (retval != -EAGAIN && retval != -EBUSY)
+ dev->power.runtime_error = retval;
+
/*
* On transient errors, if the callback routine failed an autosuspend,
* and if the last_busy time has been updated so that there is a new
diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
index 735b29f76438..2142838ad6cc 100644
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -560,6 +560,11 @@ out:
static int __init amd_pstate_ut_init(void)
{
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
+ enum amd_pstate_mode mode = amd_pstate_get_status();
+
+ /* don't test if no running amd-pstate driver */
+ if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE)
+ return -EOPNOTSUPP;
for (i = 0; i < arr_size; i++) {
int ret;
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index a74a4cf99d22..6e255a22a0b8 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -199,7 +199,7 @@ static inline int get_mode_idx_from_str(const char *str, size_t size)
static DEFINE_MUTEX(amd_pstate_driver_lock);
-static u8 msr_get_epp(struct amd_cpudata *cpudata)
+static int msr_get_epp(struct amd_cpudata *cpudata)
{
u64 value;
int ret;
@@ -215,12 +215,12 @@ static u8 msr_get_epp(struct amd_cpudata *cpudata)
DEFINE_STATIC_CALL(amd_pstate_get_epp, msr_get_epp);
-static inline s16 amd_pstate_get_epp(struct amd_cpudata *cpudata)
+static inline int amd_pstate_get_epp(struct amd_cpudata *cpudata)
{
return static_call(amd_pstate_get_epp)(cpudata);
}
-static u8 shmem_get_epp(struct amd_cpudata *cpudata)
+static int shmem_get_epp(struct amd_cpudata *cpudata)
{
u64 epp;
int ret;
@@ -526,9 +526,6 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)
WRITE_ONCE(cpudata->perf, perf);
WRITE_ONCE(cpudata->prefcore_ranking, cppc_perf.highest_perf);
- if (cppc_state == AMD_PSTATE_ACTIVE)
- return 0;
-
ret = cppc_get_auto_sel(cpudata->cpu, &auto_sel);
if (ret) {
pr_warn("failed to get auto_sel, ret: %d\n", ret);
@@ -782,6 +779,7 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy,
static void amd_pstate_adjust_perf(struct cpufreq_policy *policy,
unsigned long _min_perf,
unsigned long target_perf,
+ unsigned long _max_perf,
unsigned long capacity)
{
u8 max_perf, min_perf, des_perf, cap_perf;
@@ -1031,7 +1029,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
return -EINVAL;
}
- if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq) {
+ if (lowest_nonlinear_freq < min_freq || lowest_nonlinear_freq > nominal_freq) {
pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n",
lowest_nonlinear_freq, min_freq, nominal_freq);
return -EINVAL;
@@ -1173,6 +1171,9 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
if (cpudata->current_profile != PLATFORM_PROFILE_BALANCED)
return 0;
+ if (!policy)
+ return NOTIFY_OK;
+
epp = amd_pstate_get_balanced_epp(policy);
ret = amd_pstate_set_epp(policy, epp);
@@ -1208,6 +1209,9 @@ static int amd_pstate_profile_set(struct device *dev,
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
int ret;
+ if (!policy)
+ return -ENODEV;
+
switch (profile) {
case PLATFORM_PROFILE_LOW_POWER:
ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE);
@@ -1876,6 +1880,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
struct amd_cpudata *cpudata;
union perf_cached perf;
struct device *dev;
+ int default_epp;
int ret;
/*
@@ -1924,6 +1929,14 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->boost_supported = READ_ONCE(cpudata->boost_supported);
+ /* Cache the firmware programmed EPP */
+ default_epp = amd_pstate_get_epp(cpudata);
+ if (default_epp < 0) {
+ ret = default_epp;
+ goto free_cpudata1;
+ }
+ FIELD_MODIFY(AMD_CPPC_EPP_PERF_MASK, &cpudata->cppc_req_cached, default_epp);
+
/*
* Set the policy to provide a valid fallback value in case
* the default cpufreq governor is neither powersave nor performance.
@@ -1931,7 +1944,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
if (amd_pstate_acpi_pm_profile_server() ||
amd_pstate_acpi_pm_profile_undefined()) {
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
- cpudata->epp_default_ac = cpudata->epp_default_dc = amd_pstate_get_epp(cpudata);
+ cpudata->epp_default_ac = cpudata->epp_default_dc = default_epp;
cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
} else {
policy->policy = CPUFREQ_POLICY_POWERSAVE;
@@ -2167,6 +2180,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
};
/*
+ * Processors without frequency scaling support can't do CPPC.
* CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F.
* show the debug message that helps to check if the CPU has CPPC support for loading issue.
*/
@@ -2175,6 +2189,11 @@ static bool amd_cppc_supported(void)
struct cpuinfo_x86 *c = &cpu_data(0);
bool warn = false;
+ if (!cpu_feature_enabled(X86_FEATURE_HW_PSTATE)) {
+ pr_debug_once("frequency scaling is not supported by the processor\n");
+ return false;
+ }
+
if ((boot_cpu_data.x86 == 0x17) && (boot_cpu_data.x86_model < 0x30)) {
pr_debug_once("CPPC feature is not supported by the processor\n");
return false;
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index f6cea0c54dd9..6fe0e972952a 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -290,19 +290,32 @@ static inline void cppc_freq_invariance_exit(void)
}
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
-static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
- struct cpufreq_policy *policy)
+static void cppc_cpufreq_get_perf_limits(struct cppc_cpudata *cpu_data,
+ struct cpufreq_policy *policy,
+ u32 *min_perf, u32 *max_perf)
{
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
- u32 min_perf, max_perf;
+ unsigned int min_freq, max_freq;
+ u32 min, max;
+
+ min_freq = READ_ONCE(policy->min);
+ max_freq = READ_ONCE(policy->max);
+ if (unlikely(min_freq > max_freq))
+ min_freq = max_freq;
+
+ min = cppc_khz_to_perf(caps, min_freq);
+ max = cppc_khz_to_perf(caps, max_freq);
- min_perf = cppc_khz_to_perf(caps, policy->min);
- max_perf = cppc_khz_to_perf(caps, policy->max);
+ *min_perf = clamp_t(u32, min, caps->lowest_perf, caps->highest_perf);
+ *max_perf = clamp_t(u32, max, caps->lowest_perf, caps->highest_perf);
+}
- cpu_data->perf_ctrls.min_perf =
- clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf);
- cpu_data->perf_ctrls.max_perf =
- clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf);
+static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
+ struct cpufreq_policy *policy)
+{
+ cppc_cpufreq_get_perf_limits(cpu_data, policy,
+ &cpu_data->perf_ctrls.min_perf,
+ &cpu_data->perf_ctrls.max_perf);
}
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
@@ -693,7 +706,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
goto out;
}
- policy->fast_switch_possible = cppc_allow_fast_switch();
+ policy->fast_switch_possible = cppc_allow_fast_switch(policy->cpus);
policy->dvfs_possible_from_any_cpu = true;
/*
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b898b6544069..0d0df986fa3d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2225,14 +2225,17 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
* @policy: cpufreq policy object of the target CPU.
* @min_perf: Minimum (required) performance level (units of @capacity).
* @target_perf: Target (desired) performance level (units of @capacity).
+ * @max_perf: Maximum (allowed) performance level (units of @capacity).
* @capacity: Capacity of the target CPU.
*
- * Carry out a fast performance level switch of @cpu without sleeping.
+ * Carry out a fast performance level adjustment for the CPU represented by
+ * @policy without sleeping.
*
* The driver's ->adjust_perf() callback invoked by this function must be
- * suitable for being called from within RCU-sched read-side critical sections
- * and it is expected to select a suitable performance level equal to or above
- * @min_perf and preferably equal to or below @target_perf.
+ * suitable for calling from within RCU-sched read-side critical sections and
+ * it is expected to program the processor to select suitable performance
+ * levels between @min_perf and @max_perf inclusive and preferably close to
+ * @target_perf going forward for the CPU represented by @policy.
*
* This function must not be called if policy->fast_switch_enabled is unset.
*
@@ -2244,9 +2247,10 @@ EXPORT_SYMBOL_GPL(cpufreq_driver_fast_switch);
void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity)
{
- cpufreq_driver->adjust_perf(policy, min_perf, target_perf, capacity);
+ cpufreq_driver->adjust_perf(policy, min_perf, target_perf, max_perf, capacity);
}
/**
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 6e984c114d96..2cbf810db66e 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -299,7 +299,6 @@ struct pstate_funcs {
static struct pstate_funcs pstate_funcs __read_mostly;
static bool hwp_active __ro_after_init;
-static int hwp_mode_bdw __ro_after_init;
static bool per_cpu_limits __ro_after_init;
static bool hwp_forced __ro_after_init;
static bool hwp_boost __read_mostly;
@@ -587,21 +586,14 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
hwp_is_hybrid = true;
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_pstate * scaling,
- perf_ctl_scaling);
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
- perf_ctl_scaling);
-
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
- freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.min_freq = freq;
/*
* Cast the min P-state value retrieved via pstate_funcs.get_min() to
* the effective range of HWP performance levels.
*/
- cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
+ cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, cpu->pstate.min_freq);
}
static bool turbo_is_disabled(void)
@@ -979,12 +971,10 @@ static int hybrid_get_cost(struct device *dev, unsigned long freq,
* capacity. Similarly, P-cores start to be populated when E-cores are
* utilized above 60% of the capacity.
*/
- if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_ATOM) {
- if (hybrid_has_l3(dev->id)) /* E-core */
- *cost += 1;
- } else { /* P-core */
+ if (hybrid_get_cpu_type(dev->id) == INTEL_CPU_TYPE_CORE) /* P-core */
*cost += 2;
- }
+ else if (hybrid_has_l3(dev->id)) /* E-core */
+ *cost += 1;
return 0;
}
@@ -1185,6 +1175,22 @@ static bool hybrid_clear_max_perf_cpu(void)
return ret;
}
+static void intel_pstate_update_freq_limits(struct cpudata *cpu)
+{
+ int scaling = cpu->pstate.scaling;
+ unsigned int turbo_freq = cpu->pstate.turbo_pstate * scaling;
+ unsigned int max_freq = cpu->pstate.max_pstate * scaling;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+
+ if (scaling != perf_ctl_scaling) {
+ turbo_freq = rounddown(turbo_freq, perf_ctl_scaling);
+ max_freq = rounddown(max_freq, perf_ctl_scaling);
+ }
+
+ cpu->pstate.turbo_freq = turbo_freq;
+ cpu->pstate.max_freq = max_freq;
+}
+
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
u64 cap;
@@ -1197,20 +1203,8 @@ static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
- int scaling = cpu->pstate.scaling;
-
__intel_pstate_get_hwp_cap(cpu);
-
- cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
- if (scaling != cpu->pstate.perf_ctl_scaling) {
- int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
-
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq,
- perf_ctl_scaling);
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq,
- perf_ctl_scaling);
- }
+ intel_pstate_update_freq_limits(cpu);
}
static void hybrid_update_capacity(struct cpudata *cpu)
@@ -2299,33 +2293,16 @@ static int hwp_get_cpu_scaling(int cpu)
return intel_pstate_cppc_get_scaling(cpu);
}
-static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
-{
- trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
- cpu->pstate.current_pstate = pstate;
- /*
- * Generally, there is no guarantee that this code will always run on
- * the CPU being updated, so force the register update to run on the
- * right CPU.
- */
- wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
- pstate_funcs.get_val(cpu, pstate));
-}
-
-static void intel_pstate_set_min_pstate(struct cpudata *cpu)
-{
- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
-}
-
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
int perf_ctl_scaling = pstate_funcs.get_scaling();
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu);
cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
+ cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
- if (hwp_active && !hwp_mode_bdw) {
+ if (hwp_active) {
__intel_pstate_get_hwp_cap(cpu);
if (pstate_funcs.get_cpu_scaling) {
@@ -2345,19 +2322,13 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
- if (cpu->pstate.scaling == perf_ctl_scaling) {
- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling;
- }
+ intel_pstate_update_freq_limits(cpu);
if (pstate_funcs.get_aperf_mperf_shift)
cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
if (pstate_funcs.get_vid)
pstate_funcs.get_vid(cpu);
-
- intel_pstate_set_min_pstate(cpu);
}
/*
@@ -2884,6 +2855,19 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
cpu->min_perf_ratio);
}
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+{
+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
+ cpu->pstate.current_pstate = pstate;
+ /*
+ * Generally, there is no guarantee that this code will always run on
+ * the CPU being updated, so force the register update to run on the
+ * right CPU.
+ */
+ wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
+ pstate_funcs.get_val(cpu, pstate));
+}
+
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{
struct cpudata *cpu;
@@ -2971,6 +2955,11 @@ static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
return 0;
}
+static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+{
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+}
+
static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
@@ -3063,6 +3052,7 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
{
int ret = __intel_pstate_cpu_init(policy);
+ struct cpudata *cpu;
if (ret)
return ret;
@@ -3073,11 +3063,11 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
*/
policy->policy = CPUFREQ_POLICY_POWERSAVE;
- if (hwp_active) {
- struct cpudata *cpu = all_cpu_data[policy->cpu];
-
+ cpu = all_cpu_data[policy->cpu];
+ if (hwp_active)
cpu->epp_cached = intel_pstate_get_epp(cpu, 0);
- }
+ else
+ intel_pstate_set_min_pstate(cpu);
return 0;
}
@@ -3243,6 +3233,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy,
static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
@@ -3273,7 +3264,13 @@ static void intel_cpufreq_adjust_perf(struct cpufreq_policy *policy,
if (min_pstate > cpu->max_perf_ratio)
min_pstate = cpu->max_perf_ratio;
- max_pstate = min(cap_pstate, cpu->max_perf_ratio);
+ max_pstate = cap_pstate;
+ if (max_perf < capacity)
+ max_pstate = DIV_ROUND_UP(cap_pstate * max_perf, capacity);
+
+ if (max_pstate > cpu->max_perf_ratio)
+ max_pstate = cpu->max_perf_ratio;
+
if (max_pstate < min_pstate)
max_pstate = min_pstate;
@@ -3301,8 +3298,6 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
return ret;
policy->cpuinfo.transition_latency = INTEL_CPUFREQ_TRANSITION_LATENCY;
- /* This reflects the intel_pstate_get_cpu_pstates() setting. */
- policy->cur = policy->cpuinfo.min_freq;
req = kzalloc_objs(*req, 2);
if (!req) {
@@ -3323,9 +3318,15 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
WRITE_ONCE(cpu->hwp_req_cached, value);
cpu->epp_cached = intel_pstate_get_epp(cpu, value);
+
+ intel_cpufreq_hwp_update(cpu, cpu->pstate.min_pstate,
+ cpu->pstate.max_pstate,
+ cpu->pstate.min_pstate, false);
} else {
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
+ intel_pstate_set_min_pstate(cpu);
}
+ policy->cur = policy->cpuinfo.min_freq;
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100);
@@ -3676,14 +3677,14 @@ static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
static inline void intel_pstate_request_control_from_smm(void) {}
#endif /* CONFIG_ACPI */
-#define INTEL_PSTATE_HWP_BROADWELL 0x01
+#define INTEL_PSTATE_HWP_NOT_HYBRID 0x01
#define X86_MATCH_HWP(vfm, hwp_mode) \
X86_MATCH_VFM_FEATURE(vfm, X86_FEATURE_HWP, hwp_mode)
static const struct x86_cpu_id hwp_support_ids[] __initconst = {
- X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_BROADWELL),
- X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_BROADWELL),
+ X86_MATCH_HWP(INTEL_BROADWELL_X, INTEL_PSTATE_HWP_NOT_HYBRID),
+ X86_MATCH_HWP(INTEL_BROADWELL_D, INTEL_PSTATE_HWP_NOT_HYBRID),
X86_MATCH_HWP(INTEL_ANY, 0),
{}
};
@@ -3808,7 +3809,6 @@ static int __init intel_pstate_init(void)
if (!no_hwp) {
hwp_active = true;
- hwp_mode_bdw = id->driver_data;
intel_pstate.attr = hwp_cpufreq_attrs;
intel_cpufreq.attr = hwp_cpufreq_attrs;
intel_cpufreq.flags |= CPUFREQ_NEED_UPDATE_LIMITS;
@@ -3816,7 +3816,8 @@ static int __init intel_pstate_init(void)
if (!default_driver)
default_driver = &intel_pstate;
- pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
+ if (!id->driver_data)
+ pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
goto hwp_cpu_matched;
}
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index 10cdceaba475..8f3bdd50186e 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -131,15 +131,6 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
return 1;
}
-static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = {
- /*
- * ACPI video acpi_devices, which are handled by the acpi-video driver
- * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
- */
- { ACPI_VIDEO_HID, 0 },
- {}
-};
-
struct i2c_acpi_irq_context {
int irq;
bool wake_capable;
@@ -158,7 +149,11 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
if (!acpi_dev_ready_for_enumeration(adev))
return -ENODEV;
- if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
+ /*
+ * ACPI video devices, which are handled by the acpi-video driver,
+ * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
+ */
+ if (acpi_dev_is_video_device(adev))
return -ENODEV;
memset(info, 0, sizeof(*info));
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index d74b478db280..bcc2725769c5 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -1779,6 +1779,7 @@ module_param_named(no_native, no_native, bool, 0444);
MODULE_PARM_DESC(no_native, "Ignore cpu specific (native) idle states in lieu of ACPI idle states");
static struct acpi_processor_power acpi_state_table __initdata;
+static bool acpi_lpi_available __initdata;
/**
* intel_idle_cst_usable - Check if the _CST information can be used.
@@ -1803,18 +1804,37 @@ static bool __init intel_idle_cst_usable(void)
return true;
}
-static bool __init intel_idle_acpi_cst_extract(void)
+static bool __init intel_idle_acpi_extract_lpi_cstates(void)
{
unsigned int cpu;
- if (no_acpi) {
- pr_debug("Not allowed to use ACPI _CST\n");
- return false;
+ for_each_possible_cpu(cpu) {
+ struct acpi_processor *pr;
+
+ pr = per_cpu(processors, cpu);
+ if (!pr)
+ continue;
+
+ if (acpi_processor_extract_lpi_info(pr->handle,
+ &acpi_state_table, true))
+ continue;
+
+ acpi_lpi_available = true;
+ return true;
}
+ pr_debug("No ACPI _LPI idle states\n");
+ return false;
+}
+
+static bool __init intel_idle_acpi_extract_cst_cstates(void)
+{
+ unsigned int cpu;
+
for_each_possible_cpu(cpu) {
- struct acpi_processor *pr = per_cpu(processors, cpu);
+ struct acpi_processor *pr;
+ pr = per_cpu(processors, cpu);
if (!pr)
continue;
@@ -1826,18 +1846,96 @@ static bool __init intel_idle_acpi_cst_extract(void)
if (!intel_idle_cst_usable())
continue;
- if (!acpi_processor_claim_cst_control())
- break;
+ return true;
+ }
+
+ pr_debug("ACPI _CST not found or not usable\n");
+ return false;
+}
+
+static bool __init intel_idle_acpi_extract_cstates(void)
+{
+ if (intel_idle_acpi_extract_lpi_cstates())
+ return true;
+ if (intel_idle_acpi_extract_cst_cstates())
return true;
+
+ return false;
+}
+
+static bool __init intel_idle_acpi_probe(void)
+{
+ if (no_acpi) {
+ pr_debug("Not allowed to use ACPI for C-states extraction\n");
+ return false;
}
+ if (intel_idle_acpi_extract_cstates() &&
+ acpi_processor_claim_cst_control())
+ return true;
+
acpi_state_table.count = 0;
- pr_debug("ACPI _CST not found or not usable\n");
return false;
}
-static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
+static void __init intel_idle_complete_state_init(struct cpuidle_state *state)
+{
+ if (intel_idle_state_needs_timer_stop(state))
+ state->flags |= CPUIDLE_FLAG_TIMER_STOP;
+
+ state->enter = intel_idle;
+ state->enter_dead = intel_idle_enter_dead;
+ state->enter_s2idle = intel_idle_s2idle;
+}
+
+static void __init intel_idle_init_cstates_acpi_lpi(struct cpuidle_driver *drv)
+{
+ int index;
+
+ for (index = 0; index < acpi_state_table.count; index++) {
+ struct acpi_lpi_state *lpi_state;
+ struct cpuidle_state *state;
+
+ if (intel_idle_max_cstate_reached(index))
+ break;
+
+ lpi_state = &acpi_state_table.lpi_states[index];
+
+ state = &drv->states[drv->state_count++];
+
+ scnprintf(state->name, CPUIDLE_NAME_LEN, "C%d_LPI", index + 1);
+ strscpy(state->desc, lpi_state->desc, CPUIDLE_DESC_LEN);
+ state->exit_latency = lpi_state->wake_latency;
+ state->target_residency = lpi_state->min_residency;
+ state->flags = MWAIT2flg(lpi_state->address);
+ /*
+ * Assume that entering any of the idle states extracted from
+ * _LPI except for the first two will cause the TLB to be
+ * flushed and let the core call leave_mm() for them upfront
+ * to avoid unnecessary wakeups due to TLB shootdowns.
+ */
+ if (index > 1)
+ state->flags |= CPUIDLE_FLAG_TLB_FLUSHED;
+
+ if (disabled_states_mask & BIT(index + 1))
+ state->flags |= CPUIDLE_FLAG_OFF;
+
+ intel_idle_complete_state_init(state);
+
+ pr_info("%s: MWAIT hint 0x%x\n", state->name, flg2MWAIT(state->flags));
+ }
+
+ /*
+ * Assume the first idle state in the table to be C1 and if any deeper
+ * idle states are exposed while X86_FEATURE_NONSTOP_TSC is unset, mark
+ * the TSC as unstable.
+ */
+ if (index > 1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ mark_tsc_unstable("TSC halts in idle");
+}
+
+static void __init intel_idle_init_cstates_acpi_cst(struct cpuidle_driver *drv)
{
int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
@@ -1879,49 +1977,76 @@ static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
if (disabled_states_mask & BIT(cstate))
state->flags |= CPUIDLE_FLAG_OFF;
- if (intel_idle_state_needs_timer_stop(state))
- state->flags |= CPUIDLE_FLAG_TIMER_STOP;
-
if (cx->type > ACPI_STATE_C1 && !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
mark_tsc_unstable("TSC halts in idle");
- state->enter = intel_idle;
- state->enter_dead = intel_idle_enter_dead;
- state->enter_s2idle = intel_idle_s2idle;
+ intel_idle_complete_state_init(state);
}
}
-static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
+static void __init intel_idle_init_cstates_acpi(struct cpuidle_driver *drv)
{
- int cstate, limit;
+ if (acpi_lpi_available)
+ intel_idle_init_cstates_acpi_lpi(drv);
+ else
+ intel_idle_init_cstates_acpi_cst(drv);
+}
- /*
- * If there are no _CST C-states, do not disable any C-states by
- * default.
- */
- if (!acpi_state_table.count)
- return false;
+static bool __init intel_idle_acpi_hint_match(unsigned int flags, u32 acpi_hint,
+ u32 table_hint)
+{
+ if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) {
+ acpi_hint &= ~MWAIT_SUBSTATE_MASK;
+ table_hint &= ~MWAIT_SUBSTATE_MASK;
+ }
+ return acpi_hint == table_hint;
+}
+
+static bool __init intel_idle_off_by_default_lpi(unsigned int flags, u32 mwait_hint)
+{
+ int index;
+
+ for (index = 0; index < acpi_state_table.count; index++) {
+ u32 acpi_hint = acpi_state_table.lpi_states[index].address;
+
+ if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint))
+ return false;
+ }
+ return true;
+}
+
+static bool __init intel_idle_off_by_default_cst(unsigned int flags, u32 mwait_hint)
+{
+ int cstate, limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
- limit = min_t(int, CPUIDLE_STATE_MAX, acpi_state_table.count);
/*
* If limit > 0, intel_idle_cst_usable() has returned 'true', so all of
* the interesting states are ACPI_CSTATE_FFH.
*/
for (cstate = 1; cstate < limit; cstate++) {
u32 acpi_hint = acpi_state_table.states[cstate].address;
- u32 table_hint = mwait_hint;
- if (flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH) {
- acpi_hint &= ~MWAIT_SUBSTATE_MASK;
- table_hint &= ~MWAIT_SUBSTATE_MASK;
- }
-
- if (acpi_hint == table_hint)
+ if (intel_idle_acpi_hint_match(flags, acpi_hint, mwait_hint))
return false;
}
return true;
}
+static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
+{
+ /*
+ * If there is no C-states information in the ACPI tables, do not
+ * disable any C-states by default.
+ */
+ if (!acpi_state_table.count)
+ return false;
+
+ if (acpi_lpi_available)
+ return intel_idle_off_by_default_lpi(flags, mwait_hint);
+
+ return intel_idle_off_by_default_cst(flags, mwait_hint);
+}
+
static inline bool ignore_native(void)
{
return no_native && !no_acpi;
@@ -1929,7 +2054,7 @@ static inline bool ignore_native(void)
#else /* !CONFIG_ACPI_PROCESSOR_CSTATE */
#define force_use_acpi (false)
-static inline bool intel_idle_acpi_cst_extract(void) { return false; }
+static inline bool intel_idle_acpi_probe(void) { return false; }
static inline void intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) { }
static inline bool intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
{
@@ -2741,7 +2866,7 @@ static int __init intel_idle_init(void)
if (icpu) {
if (icpu->state_table)
cpuidle_state_table = icpu->state_table;
- else if (!intel_idle_acpi_cst_extract())
+ else if (!intel_idle_acpi_probe())
return -ENODEV;
auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
@@ -2750,8 +2875,8 @@ static int __init intel_idle_init(void)
if (icpu->c1_demotion_supported)
c1_demotion_supported = true;
if (icpu->use_acpi || force_use_acpi)
- intel_idle_acpi_cst_extract();
- } else if (!intel_idle_acpi_cst_extract()) {
+ intel_idle_acpi_probe();
+ } else if (!intel_idle_acpi_probe()) {
return -ENODEV;
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 99444a1b2ffa..2673954d4577 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -2588,7 +2588,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
if (err)
goto out_fwhandle_free;
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id, NULL);
if (static_branch_likely(&supports_deactivate_key))
gic_acpi_setup_kvm_info();
diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
index 9103feb70ce8..6b02b90d9cce 100644
--- a/drivers/irqchip/irq-gic-v5-iwb.c
+++ b/drivers/irqchip/irq-gic-v5-iwb.c
@@ -269,6 +269,8 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
if (IS_ERR(iwb_node))
return PTR_ERR(iwb_node);
+ acpi_device_clear_deps(&pdev->dev);
+
return 0;
}
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index e9d1795235a6..5dcf404ab4c8 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1226,11 +1226,19 @@ static struct fwnode_handle *gsi_domain_handle;
static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
{
if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
- return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+ return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
return gsi_domain_handle;
}
+static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
+{
+ if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
+ return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+
+ return NULL;
+}
+
static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
{
struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
@@ -1251,7 +1259,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
if (ret)
goto out_irs;
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
+ gic_v5_get_gsi_handle);
return 0;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ec70c84e9f91..f6bc29f515fb 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1690,7 +1690,7 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
return ret;
}
- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id, NULL);
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
gicv2m_init(NULL, gic_data[0].domain);
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 950bc087e388..84ce24889488 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -168,7 +168,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
panic("Failed to add irqdomain for LoongArch CPU");
set_handle_irq(&handle_cpu_irq);
- acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id, NULL);
acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
ret = acpi_cascade_irqdomain_init();
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index 84418dbd5a27..0595144116e2 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -384,7 +384,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
if (rc)
irq_domain_free_fwnode(fn);
else
- acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
+ acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id,
+ acpi_get_riscv_gsi_handle);
return rc;
}
diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
index c360eee11dd9..3de05aee7859 100644
--- a/drivers/pci/vgaarb.c
+++ b/drivers/pci/vgaarb.c
@@ -575,9 +575,7 @@ static bool vga_is_firmware_default(struct pci_dev *pdev)
static bool vga_arb_integrated_gpu(struct device *dev)
{
#if defined(CONFIG_ACPI)
- struct acpi_device *adev = ACPI_COMPANION(dev);
-
- return adev && !strcmp(acpi_device_hid(adev), ACPI_VIDEO_HID);
+ return acpi_dev_is_video_device(ACPI_COMPANION(dev));
#else
return false;
#endif
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index 445e1403308e..b528a1e67dd3 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -768,7 +768,7 @@ static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle,
if (!strcmp(context, "video")) {
struct acpi_device *dev = acpi_fetch_acpi_dev(handle);
- if (!dev || strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev)))
+ if (!acpi_dev_is_video_device(dev))
return AE_OK;
}
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 87f5af454751..df5e3d3cbf6c 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -254,9 +254,16 @@ int pnp_add_card(struct pnp_card *card)
/* we wait until now to add devices in order to ensure the drivers
* will be able to use all of the related devices on the card
* without waiting an unreasonable length of time */
- list_for_each(pos, &card->devices) {
+ list_for_each_safe(pos, temp, &card->devices) {
struct pnp_dev *dev = card_to_pnp_dev(pos);
- __pnp_add_device(dev);
+ error = __pnp_add_device(dev);
+ if (error) {
+ mutex_lock(&pnp_lock);
+ list_del(&dev->card_list);
+ dev->card = NULL;
+ mutex_unlock(&pnp_lock);
+ put_device(&dev->dev);
+ }
}
/* match with card drivers */
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index fbf03ff007eb..d8ec0ad2ab4e 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -248,10 +248,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (acpi_has_method(device->handle, "_DIS"))
dev->capabilities |= PNP_DISABLE;
- if (strlen(acpi_device_name(device)))
- strscpy(dev->name, acpi_device_name(device), sizeof(dev->name));
- else
- strscpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
+ strscpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
if (dev->active)
pnpacpi_parse_allocated_resource(dev);
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index 835113b2cb04..bd939b564379 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -17,10 +17,10 @@
static const struct pnp_device_id pnp_dev_table[] = {
/* General ID for reserving resources */
- {"PNP0c02", 0},
+ { .id = "PNP0c02" },
/* memory controller */
- {"PNP0c01", 0},
- {"", 0}
+ { .id = "PNP0c01" },
+ { }
};
static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index d200734625ee..5d70301d4a3d 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -356,8 +356,10 @@ static void cleanup_odvp(struct int3400_thermal_priv *priv)
kfree(priv->odvp_attrs[i].attr.attr.name);
}
kfree(priv->odvp_attrs);
+ priv->odvp_attrs = NULL;
}
kfree(priv->odvp);
+ priv->odvp = NULL;
priv->odvp_count = 0;
}
@@ -635,7 +637,6 @@ free_notify:
acpi_remove_notify_handler(priv->adev->handle, ACPI_DEVICE_NOTIFY,
int3400_notify);
free_sysfs:
- cleanup_odvp(priv);
if (!ZERO_OR_NULL_PTR(priv->data_vault)) {
device_remove_bin_file(&pdev->dev, &bin_attr_data_vault);
kfree(priv->data_vault);
@@ -649,6 +650,7 @@ free_rel_misc:
acpi_thermal_rel_misc_device_remove(priv->adev->handle);
thermal_zone_device_unregister(priv->thermal);
free_art_trt:
+ cleanup_odvp(priv);
kfree(priv->trts);
kfree(priv->arts);
free_priv:
diff --git a/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c b/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
index d92a6f84a778..43cb809c5dcc 100644
--- a/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
+++ b/drivers/thermal/intel/int340x_thermal/platform_temperature_control.c
@@ -227,17 +227,12 @@ static ssize_t ptc_temperature_write(struct file *file, const char __user *data,
{
struct ptc_data *ptc_instance = file->private_data;
struct pci_dev *pdev = ptc_instance->pdev;
- char buf[32];
- ssize_t len;
u32 value;
+ int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, data, len))
- return -EFAULT;
-
- buf[len] = '\0';
- if (kstrtouint(buf, 0, &value))
- return -EINVAL;
+ ret = kstrtou32_from_user(data, count, 0, &value);
+ if (unlikely(ret))
+ return ret;
if (ptc_mmio_regs[PTC_TEMP_OVERRIDE_INDEX].units)
value /= ptc_mmio_regs[PTC_TEMP_OVERRIDE_INDEX].units;
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
index c693d934103a..c5131423ec9b 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c
@@ -308,10 +308,8 @@ static int proc_thermal_setup_msi(struct pci_dev *pdev, struct proc_thermal_pci
ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
proc_thermal_irq_thread_handler,
0, KBUILD_MODNAME, pci_info);
- if (ret) {
- dev_err(&pdev->dev, "Request IRQ %d failed\n", irq);
+ if (ret)
goto err_free_msi_vectors;
- }
proc_thermal_msi_map[i] = irq;
}
@@ -394,10 +392,8 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
ret = devm_request_threaded_irq(&pdev->dev, irq, proc_thermal_irq_handler,
proc_thermal_irq_thread_handler, irq_flag,
KBUILD_MODNAME, pci_info);
- if (ret) {
- dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
+ if (ret)
goto err_ret_tzone;
- }
}
ret = thermal_zone_device_enable(pci_info->tzone);
diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
index 1a7e134dfcf8..96279756177f 100644
--- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
+++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c
@@ -491,12 +491,11 @@ int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
- if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
- sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
- return ret;
- }
- if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR) {
- sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);
+ if (ret) {
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DLVR)
+ sysfs_remove_group(&pdev->dev.kobj, &dlvr_attribute_group);
+ if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
+ sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
return ret;
}
}
diff --git a/drivers/thermal/intel/intel_bxt_pmic_thermal.c b/drivers/thermal/intel/intel_bxt_pmic_thermal.c
index 6312c6ba081f..aeaefbbd5d8f 100644
--- a/drivers/thermal/intel/intel_bxt_pmic_thermal.c
+++ b/drivers/thermal/intel/intel_bxt_pmic_thermal.c
@@ -245,10 +245,8 @@ static int pmic_thermal_probe(struct platform_device *pdev)
NULL, pmic_thermal_irq_handler,
IRQF_ONESHOT, "pmic_thermal", pdev);
- if (ret) {
- dev_err(dev, "request irq(%d) failed: %d\n", virq, ret);
+ if (ret)
return ret;
- }
pmic_irq_count++;
}
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c
index 45a8ef4a608b..d1f9cf8bf6c5 100644
--- a/drivers/thermal/intel/therm_throt.c
+++ b/drivers/thermal/intel/therm_throt.c
@@ -14,12 +14,14 @@
* Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c.
* Inspired by Ross Biro's and Al Borchers' counter code.
*/
+#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/percpu.h>
#include <linux/export.h>
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/smp.h>
@@ -244,16 +246,23 @@ static void thermal_intr_init_pkg_clear_mask(void)
* IA32_PACKAGE_THERM_STATUS.
*/
- /* All bits except BIT 26 depend on CPUID.06H: EAX[6] = 1 */
+ /* All bits except BITs 25 and 26 depend on CPUID.06H: EAX[6] = 1 */
if (boot_cpu_has(X86_FEATURE_PTS))
therm_intr_pkg_clear_mask = (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11));
/*
- * Intel SDM Volume 2A: Thermal and Power Management Leaf
+ * Intel SDM Volume 1: Thermal and Power Management Leaf
* Bit 26: CPUID.06H: EAX[19] = 1
*/
if (boot_cpu_has(X86_FEATURE_HFI))
therm_intr_pkg_clear_mask |= BIT(26);
+
+ /*
+ * Intel SDM Volume 1: Thermal and Power Management Leaf
+ * Bit 25: CPUID.06H: EAX[24] = 1
+ */
+ if (boot_cpu_has(X86_FEATURE_DPTI))
+ therm_intr_pkg_clear_mask |= BIT(25);
}
/*
@@ -524,6 +533,254 @@ static void thermal_throttle_remove_dev(struct device *dev)
sysfs_remove_group(&dev->kobj, &thermal_attr_group);
}
+static int check_directed_thermal_pkg_intr_ack(void)
+{
+ unsigned int count = 15000;
+ u64 msr_val;
+
+ /*
+ * Hardware acknowledges the directed interrupt setup in 10ms or less.
+ * Wait 15ms to be safe.
+ */
+ do {
+ rdmsrq(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ udelay(1);
+ } while (!(msr_val & PACKAGE_THERM_STATUS_DPTI_ACK) && --count);
+
+ if (!count)
+ return -ETIMEDOUT;
+
+ thermal_clear_package_intr_status(PACKAGE_LEVEL,
+ PACKAGE_THERM_STATUS_DPTI_ACK);
+
+ return 0;
+}
+
+static void config_directed_thermal_pkg_intr(void *info)
+{
+ bool enable = *((bool *)info);
+ u64 msr_val;
+
+ rdmsrq(MSR_IA32_THERM_INTERRUPT, msr_val);
+
+ if (enable)
+ msr_val |= THERM_INT_DPTI_ENABLE;
+ else
+ msr_val &= ~THERM_INT_DPTI_ENABLE;
+
+ wrmsrq(MSR_IA32_THERM_INTERRUPT, msr_val);
+}
+
+/*
+ * Accessed from CPU hotplug callbacks and from code that runs while CPU
+ * hotplug is inactive: the init and cleanup paths as well as syscore callbacks.
+ * No extra locking needed.
+ */
+static unsigned int *directed_intr_handler_cpus;
+
+static bool directed_thermal_pkg_intr_supported(void)
+{
+ if (!boot_cpu_has(X86_FEATURE_DPTI))
+ return false;
+
+ if (!directed_intr_handler_cpus)
+ return false;
+
+ return true;
+}
+
+/*
+ * Must be called with cpu_hotplug_lock held to prevent CPUs from going offline
+ * while iterating through packages and interrupts must be enabled to avoid
+ * deadlocks in SMP function calls. The syscore shutdown callback also calls
+ * this function, but runs with CPU hotplug disabled (and interrupts enabled).
+ */
+static void disable_directed_thermal_pkg_intr_all(void)
+{
+ bool enable = false;
+ int i;
+
+ if (!directed_thermal_pkg_intr_supported())
+ return;
+
+ for (i = 0; i < topology_max_packages(); i++) {
+ if (directed_intr_handler_cpus[i] == nr_cpu_ids)
+ continue;
+
+ smp_call_function_single(directed_intr_handler_cpus[i],
+ config_directed_thermal_pkg_intr,
+ &enable, true);
+ }
+}
+
+static int enable_directed_thermal_pkg_intr(unsigned int cpu)
+{
+ bool enable = true;
+ u16 pkg_id;
+
+ if (!directed_thermal_pkg_intr_supported())
+ return 0;
+
+ pkg_id = topology_logical_package_id(cpu);
+ if (pkg_id >= topology_max_packages())
+ return -EINVAL;
+
+ /* Another CPU in this package already handles the directed interrupt. */
+ if (directed_intr_handler_cpus[pkg_id] != nr_cpu_ids)
+ return 0;
+
+ thermal_clear_package_intr_status(PACKAGE_LEVEL,
+ PACKAGE_THERM_STATUS_DPTI_ACK);
+
+ config_directed_thermal_pkg_intr(&enable);
+ if (!check_directed_thermal_pkg_intr_ack()) {
+ directed_intr_handler_cpus[pkg_id] = cpu;
+ return 0;
+ }
+
+ /*
+ * A failure indicates faulty hardware. Roll back completely so that
+ * no other CPU tries. This is especially important during boot as all
+ * CPUs may come online and would otherwise keep trying.
+ */
+ enable = false;
+ config_directed_thermal_pkg_intr(&enable);
+
+ return -ETIMEDOUT;
+}
+
+static void disable_directed_thermal_pkg_intr(unsigned int cpu)
+{
+ unsigned int new_cpu;
+ bool enable;
+ u16 pkg_id;
+
+ if (!directed_thermal_pkg_intr_supported())
+ return;
+
+ pkg_id = topology_logical_package_id(cpu);
+ if (pkg_id >= topology_max_packages())
+ return;
+
+ /* Not the CPU handling the directed interrupt. */
+ if (directed_intr_handler_cpus[pkg_id] != cpu)
+ return;
+
+ /*
+ * The package-level interrupt must remain directed after this CPU goes
+ * offline.
+ */
+ new_cpu = cpumask_any_but(topology_core_cpumask(cpu), cpu);
+ if (new_cpu < nr_cpu_ids) {
+ enable = true;
+ thermal_clear_package_intr_status(PACKAGE_LEVEL,
+ PACKAGE_THERM_STATUS_DPTI_ACK);
+
+ /*
+ * We are here via CPU hotplug. Since we are holding the
+ * cpu_hotplug_lock, @new_cpu cannot go offline and interrupts
+ * are enabled, so the SMP function call is safe.
+ *
+ * The syscore suspend callback runs with interrupts disabled,
+ * but it does not reach this path because all the secondary
+ * CPUs are offline.
+ */
+ smp_call_function_single(new_cpu, config_directed_thermal_pkg_intr,
+ &enable, true);
+ }
+
+ /*
+ * If hardware does not acknowledge the directed interrupt setup on
+ * @new_cpu, disable the redirection. Since no other CPU is configured
+ * to receive the package-level interrupt, all CPUs in the package will
+ * receive it.
+ */
+ enable = false;
+ if (new_cpu < nr_cpu_ids && check_directed_thermal_pkg_intr_ack()) {
+ smp_call_function_single(new_cpu, config_directed_thermal_pkg_intr,
+ &enable, true);
+
+ pr_warn_once("Failed to redirect package thermal interrupt from CPU%u to CPU%u; reverting to broadcast.\n",
+ cpu, new_cpu);
+
+ new_cpu = nr_cpu_ids;
+ }
+
+ /*
+ * Clear the directed interrupt on @cpu. Hardware acknowledgment can be
+ * ignored since @cpu is going offline.
+ */
+ config_directed_thermal_pkg_intr(&enable);
+
+ directed_intr_handler_cpus[pkg_id] = (new_cpu < nr_cpu_ids) ? new_cpu : nr_cpu_ids;
+}
+
+/*
+ * CPU0 may be handling the directed interrupt, but the CPU hotplug callbacks
+ * are not called for CPU0 during suspend and resume.
+ */
+static void directed_pkg_intr_syscore_resume(void *data)
+{
+ /*
+ * We can't do anything to handle errors. If direction fails for CPU0,
+ * another CPU will take over or disable direction entirely during CPU
+ * hotplug.
+ */
+ enable_directed_thermal_pkg_intr(0);
+}
+
+static int directed_pkg_intr_syscore_suspend(void *data)
+{
+ disable_directed_thermal_pkg_intr(0);
+
+ return 0;
+}
+
+static void directed_pkg_intr_syscore_shutdown(void *data)
+{
+ disable_directed_thermal_pkg_intr_all();
+}
+
+static const struct syscore_ops directed_pkg_intr_pm_ops = {
+ .resume = directed_pkg_intr_syscore_resume,
+ .suspend = directed_pkg_intr_syscore_suspend,
+ .shutdown = directed_pkg_intr_syscore_shutdown,
+};
+
+static struct syscore directed_pkg_intr_pm = {
+ .ops = &directed_pkg_intr_pm_ops,
+};
+
+static __init void init_directed_pkg_intr(void)
+{
+ int i;
+
+ if (!boot_cpu_has(X86_FEATURE_DPTI))
+ return;
+
+ directed_intr_handler_cpus = kmalloc_array(topology_max_packages(),
+ sizeof(*directed_intr_handler_cpus),
+ GFP_KERNEL);
+ if (!directed_intr_handler_cpus)
+ return;
+
+ for (i = 0; i < topology_max_packages(); i++)
+ directed_intr_handler_cpus[i] = nr_cpu_ids;
+
+ register_syscore(&directed_pkg_intr_pm);
+}
+
+static void cleanup_directed_pkg_thermal_intr(void)
+{
+ if (!directed_thermal_pkg_intr_supported())
+ return;
+
+ unregister_syscore(&directed_pkg_intr_pm);
+ disable_directed_thermal_pkg_intr_all();
+ kfree(directed_intr_handler_cpus);
+ directed_intr_handler_cpus = NULL;
+}
+
/* Get notified when a cpu comes on/off. Be hotplug friendly. */
static int thermal_throttle_online(unsigned int cpu)
{
@@ -549,6 +806,11 @@ static int thermal_throttle_online(unsigned int cpu)
*/
intel_hfi_online(cpu);
+ if (enable_directed_thermal_pkg_intr(cpu)) {
+ pr_info_once("Failed to direct package thermal interrupts. All CPUs will receive it.\n");
+ cleanup_directed_pkg_thermal_intr();
+ }
+
/* Unmask the thermal vector after the above workqueues are initialized. */
l = apic_read(APIC_LVTTHMR);
apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
@@ -566,6 +828,8 @@ static int thermal_throttle_offline(unsigned int cpu)
l = apic_read(APIC_LVTTHMR);
apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
+ disable_directed_thermal_pkg_intr(cpu);
+
intel_hfi_offline(cpu);
cancel_delayed_work_sync(&state->package_throttle.therm_work);
@@ -585,12 +849,19 @@ static __init int thermal_throttle_init_device(void)
if (!atomic_read(&therm_throt_en))
return 0;
+ init_directed_pkg_intr();
+
intel_hfi_init();
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/therm:online",
thermal_throttle_online,
thermal_throttle_offline);
- return ret < 0 ? ret : 0;
+ if (ret >= 0)
+ return 0;
+
+ cleanup_directed_pkg_thermal_intr();
+
+ return ret;
}
device_initcall(thermal_throttle_init_device);
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index 5b98e0e93807..2fa9c7d3581f 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -17,8 +17,6 @@
#include <xen/xen-ops.h>
#include <asm/xen/hypercall.h>
-#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
-#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
static DEFINE_MUTEX(xen_cpu_lock);
@@ -117,9 +115,6 @@ static int acpi_pad_probe(struct platform_device *pdev)
if (!device)
return -ENODEV;
- strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
-
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
if (ACPI_FAILURE(status))
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 714d111d8053..32cac3a6f362 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -108,7 +108,6 @@ enum acpi_bus_device_type {
ACPI_BUS_DEVICE_TYPE_COUNT
};
-struct acpi_driver;
struct acpi_device;
/*
@@ -159,32 +158,6 @@ struct acpi_hotplug_context {
};
/*
- * ACPI Driver
- * -----------
- */
-
-typedef int (*acpi_op_add) (struct acpi_device * device);
-typedef void (*acpi_op_remove) (struct acpi_device *device);
-typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
-
-struct acpi_device_ops {
- acpi_op_add add;
- acpi_op_remove remove;
- acpi_op_notify notify;
-};
-
-#define ACPI_DRIVER_ALL_NOTIFY_EVENTS 0x1 /* system AND device events */
-
-struct acpi_driver {
- char name[80];
- char class[80];
- const struct acpi_device_id *ids; /* Supported Hardware IDs */
- unsigned int flags;
- struct acpi_device_ops ops;
- struct device_driver drv;
-};
-
-/*
* ACPI Device
* -----------
*/
@@ -211,7 +184,6 @@ struct acpi_device_flags {
u32 removable:1;
u32 ejectable:1;
u32 power_manageable:1;
- u32 match_driver:1;
u32 initialized:1;
u32 visited:1;
u32 hotplug_notify:1;
@@ -221,7 +193,7 @@ struct acpi_device_flags {
u32 cca_seen:1;
u32 enumeration_by_parent:1;
u32 honor_deps:1;
- u32 reserved:18;
+ u32 reserved:19;
};
/* File System */
@@ -438,7 +410,7 @@ enum acpi_device_swnode_ep_props {
* @lane_polarities: "lane-polarities" property values.
* @link_frequencies: "link_frequencies" property values.
* @port_nr: Port number.
- * @crs_crs2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
+ * @crs_csi2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
* @port_props: Port properties.
* @ep_props: Endpoint properties.
* @remote_ep: Reference to the remote endpoint.
@@ -461,7 +433,7 @@ struct acpi_device_software_node_port {
* struct acpi_device_software_nodes - Software nodes for an ACPI device
* @dev_props: Device properties.
* @nodes: Software nodes for root as well as ports and endpoints.
- * @nodeprts: Array of software node pointers, for (un)registering them.
+ * @nodeptrs: Array of software node pointers, for (un)registering them.
* @ports: Information related to each port and endpoint within a port.
* @num_ports: The number of ports.
*/
@@ -570,7 +542,6 @@ static inline void *acpi_driver_data(struct acpi_device *d)
}
#define to_acpi_device(d) container_of(d, struct acpi_device, dev)
-#define to_acpi_driver(d) container_of_const(d, struct acpi_driver, drv)
static inline struct acpi_device *acpi_dev_parent(struct acpi_device *adev)
{
@@ -676,13 +647,6 @@ void acpi_scan_lock_release(void);
void acpi_lock_hp_context(void);
void acpi_unlock_hp_context(void);
int acpi_scan_add_handler(struct acpi_scan_handler *handler);
-/*
- * use a macro to avoid include chaining to get THIS_MODULE
- */
-#define acpi_bus_register_driver(drv) \
- __acpi_bus_register_driver(drv, THIS_MODULE)
-int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner);
-void acpi_bus_unregister_driver(struct acpi_driver *driver);
int acpi_bus_scan(acpi_handle handle);
void acpi_bus_trim(struct acpi_device *start);
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
@@ -696,18 +660,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
return adev && adev->flags.initialized && adev->flags.visited;
}
-/**
- * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
- * @__acpi_driver: acpi_driver struct
- *
- * Helper macro for ACPI drivers which do not do anything special in module
- * init/exit. This eliminates a lot of boilerplate. Each module may only
- * use this macro once, and calling it replaces module_init() and module_exit()
- */
-#define module_acpi_driver(__acpi_driver) \
- module_driver(__acpi_driver, acpi_bus_register_driver, \
- acpi_bus_unregister_driver)
-
/*
* Bind physical devices with ACPI devices
*/
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 402b97d12138..bff2ca035fcf 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -59,14 +59,19 @@ int acpi_pci_link_free_irq(acpi_handle handle);
struct pci_bus;
#ifdef CONFIG_PCI
-struct pci_dev *acpi_get_pci_dev(acpi_handle);
+struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev);
#else
-static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
+static inline struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev)
{
return NULL;
}
#endif
+static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
+{
+ return acpi_dev_get_pci_dev(acpi_fetch_acpi_dev(handle));
+}
+
/* Arch-defined function to add a bus to the system */
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root);
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 5acebe62feac..c20e4e9daf79 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -170,7 +170,7 @@ extern u64 cppc_get_dmi_max_khz(void);
extern unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf);
extern unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq);
extern bool acpi_cpc_valid(void);
-extern bool cppc_allow_fast_switch(void);
+bool cppc_allow_fast_switch(const struct cpumask *cpus);
extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
extern int cppc_get_transition_latency(int cpu);
extern bool cpc_ffh_supported(void);
@@ -236,7 +236,8 @@ static inline bool acpi_cpc_valid(void)
{
return false;
}
-static inline bool cppc_allow_fast_switch(void)
+
+static inline bool cppc_allow_fast_switch(const struct cpumask *cpus)
{
return false;
}
diff --git a/include/acpi/nhlt.h b/include/acpi/nhlt.h
index 2108aa6d0207..370958d93706 100644
--- a/include/acpi/nhlt.h
+++ b/include/acpi/nhlt.h
@@ -10,7 +10,6 @@
#define __ACPI_NHLT_H__
#include <linux/acpi.h>
-#include <linux/kconfig.h>
#include <linux/overflow.h>
#include <linux/types.h>
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 60ab50cb8930..ddacac812094 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -94,6 +94,12 @@ static inline void acpi_preset_companion(struct device *dev,
ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, false));
}
+static inline void acpi_device_clear_deps(struct device *dev)
+{
+ if (has_acpi_companion(dev))
+ acpi_dev_clear_dependencies(ACPI_COMPANION(dev));
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return dev_name(&adev->dev);
@@ -315,6 +321,19 @@ static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
}
#endif
+#ifdef CONFIG_ACPI_PROCESSOR_IDLE
+int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
+ struct acpi_processor_power *pr_power,
+ bool strict);
+#else
+static inline int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
+ struct acpi_processor_power *pr_power,
+ bool strict)
+{
+ return -ENODEV;
+}
+#endif
+
#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* Arch dependent functions for cpu hotplug support */
int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id,
@@ -360,9 +379,10 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
typedef struct fwnode_handle *(*acpi_gsi_domain_disp_fn)(u32);
+typedef acpi_handle (*acpi_gsi_handle_disp_fn)(u32);
void acpi_set_irq_model(enum acpi_irq_model_id model,
- acpi_gsi_domain_disp_fn fn);
+ acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn);
acpi_gsi_domain_disp_fn acpi_get_gsi_dispatcher(void);
void acpi_set_gsi_to_irq_fallback(u32 (*)(u32));
@@ -372,6 +392,8 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
const struct irq_domain_ops *ops,
void *host_data);
+u32 acpi_irq_add_auto_dep(acpi_handle handle);
+
#ifdef CONFIG_X86_IO_APIC
extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
#else
@@ -448,6 +470,7 @@ extern char *wmi_get_acpi_device_uid(const char *guid);
#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800
extern char acpi_video_backlight_string[];
+extern bool acpi_dev_is_video_device(struct acpi_device *adev);
extern long acpi_is_video_device(acpi_handle handle);
extern void acpi_osi_setup(char *str);
@@ -908,6 +931,8 @@ static inline void acpi_preset_companion(struct device *dev,
{
}
+static inline void acpi_device_clear_deps(struct device *dev) {}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb3374f4ca..931eaa7bbf6a 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -27,7 +27,8 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
struct fwnode_handle *fw_node);
void iort_deregister_domain_token(int trans_id);
struct fwnode_handle *iort_find_domain_token(int trans_id);
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
+acpi_handle iort_iwb_handle(u32 iwb_id);
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id);
#ifdef CONFIG_ACPI_IORT
u32 iort_msi_map_id(struct device *dev, u32 id);
diff --git a/include/linux/acpi_pmtmr.h b/include/linux/acpi_pmtmr.h
index 0ded9220d379..cceed294d0b5 100644
--- a/include/linux/acpi_pmtmr.h
+++ b/include/linux/acpi_pmtmr.h
@@ -27,15 +27,17 @@ static inline u32 acpi_pm_read_early(void)
}
/**
- * Register callback for suspend and resume event
+ * acpi_pmtmr_register_suspend_resume_callback - Register callback for
+ * suspend and resume event
*
- * @cb Callback triggered on suspend and resume
- * @data Data passed with the callback
+ * @cb: Callback triggered on suspend and resume
+ * @data: Data passed with the callback
*/
void acpi_pmtmr_register_suspend_resume_callback(void (*cb)(void *data, bool suspend), void *data);
/**
- * Remove registered callback for suspend and resume event
+ * acpi_pmtmr_unregister_suspend_resume_callback - Remove registered callback
+ * for suspend and resume event
*/
void acpi_pmtmr_unregister_suspend_resume_callback(void);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ae9d1ce4f49c..35ce665edfd8 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -379,6 +379,7 @@ struct cpufreq_driver {
void (*adjust_perf)(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity);
/*
@@ -624,6 +625,7 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
void cpufreq_driver_adjust_perf(struct cpufreq_policy *policy,
unsigned long min_perf,
unsigned long target_perf,
+ unsigned long max_perf,
unsigned long capacity);
bool cpufreq_driver_has_adjust_perf(void);
int cpufreq_driver_target(struct cpufreq_policy *policy,
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index d933b5b2c05d..38c0a9d31d1a 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -458,7 +458,7 @@ static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed,
return node;
}
-/**
+/*
* add_rtree_block - Add a new leave node to the radix tree.
*
* The leave nodes need to be allocated in order to keep the leaves
@@ -528,7 +528,7 @@ static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask,
static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
int clear_nosave_free);
-/**
+/*
* create_zone_bm_rtree - Create a radix tree for one zone.
*
* Allocated the mem_zone_bm_rtree structure and initializes it.
@@ -566,7 +566,7 @@ static struct mem_zone_bm_rtree *create_zone_bm_rtree(gfp_t gfp_mask,
return zone;
}
-/**
+/*
* free_zone_bm_rtree - Free the memory of the radix tree.
*
* Free all node pages of the radix tree. The mem_zone_bm_rtree
@@ -678,7 +678,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
return 0;
}
-/**
+/*
* memory_bm_create - Allocate memory for a memory bitmap.
*/
static int memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask,
@@ -720,7 +720,7 @@ static int memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask,
goto Exit;
}
-/**
+/*
* memory_bm_free - Free memory occupied by the memory bitmap.
* @bm: Memory bitmap.
*/
@@ -736,7 +736,7 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
INIT_LIST_HEAD(&bm->zones);
}
-/**
+/*
* memory_bm_find_bit - Find the bit for a given PFN in a memory bitmap.
*
* Find the bit in memory bitmap @bm that corresponds to the given PFN.
@@ -988,7 +988,7 @@ static void memory_bm_recycle(struct memory_bitmap *bm)
}
}
-/**
+/*
* register_nosave_region - Register a region of unsaveable memory.
*
* Register a range of page frames the contents of which should not be saved
@@ -1305,7 +1305,7 @@ static unsigned int count_free_highmem_pages(void)
return cnt;
}
-/**
+/*
* saveable_highmem_page - Check if a highmem page is saveable.
*
* Determine whether a highmem page should be included in a hibernation image.
@@ -1362,7 +1362,7 @@ static unsigned int count_highmem_pages(void)
}
#endif /* CONFIG_HIGHMEM */
-/**
+/*
* saveable_page - Check if the given page is saveable.
*
* Determine whether a non-highmem page should be included in a hibernation
@@ -1440,7 +1440,7 @@ static inline bool do_copy_page(long *dst, long *src)
return !z;
}
-/**
+/*
* safe_copy_page - Copy a page in a safe way.
*
* Check if the page we are going to copy is marked as present in the kernel
@@ -1687,7 +1687,7 @@ static unsigned long preallocate_image_highmem(unsigned long nr_pages)
return preallocate_image_pages(nr_pages, GFP_IMAGE | __GFP_HIGHMEM);
}
-/**
+/*
* __fraction - Compute (an approximation of) x * (multiplier / base).
*/
static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
@@ -1982,7 +1982,7 @@ int hibernate_preallocate_memory(void)
}
#ifdef CONFIG_HIGHMEM
-/**
+/*
* count_pages_for_highmem - Count non-highmem pages needed for copying highmem.
*
* Compute the number of non-highmem pages that will be necessary for creating
@@ -2003,7 +2003,7 @@ static unsigned int count_pages_for_highmem(unsigned int nr_highmem)
static unsigned int count_pages_for_highmem(unsigned int nr_highmem) { return 0; }
#endif /* CONFIG_HIGHMEM */
-/**
+/*
* enough_free_mem - Check if there is enough free memory for the image.
*/
static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
@@ -2023,7 +2023,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
}
#ifdef CONFIG_HIGHMEM
-/**
+/*
* get_highmem_buffer - Allocate a buffer for highmem pages.
*
* If there are some highmem pages in the hibernation image, we may need a
@@ -2035,7 +2035,7 @@ static inline int get_highmem_buffer(int safe_needed)
return buffer ? 0 : -ENOMEM;
}
-/**
+/*
* alloc_highmem_pages - Allocate some highmem pages for the image.
*
* Try to allocate as many pages as needed, but if the number of free highmem
@@ -2065,7 +2065,7 @@ static inline unsigned int alloc_highmem_pages(struct memory_bitmap *bm,
unsigned int n) { return 0; }
#endif /* CONFIG_HIGHMEM */
-/**
+/*
* swsusp_alloc - Allocate memory for hibernation image.
*
* We first try to allocate as many highmem pages as there are
@@ -2292,7 +2292,7 @@ static void duplicate_memory_bitmap(struct memory_bitmap *dst,
}
}
-/**
+/*
* mark_unsafe_pages - Mark pages that were used before hibernation.
*
* Mark the pages that cannot be used for storing the image during restoration,
@@ -2330,7 +2330,7 @@ static int check_header(struct swsusp_info *info)
return 0;
}
-/**
+/*
* load_header - Check the image header and copy the data from it.
*/
static int load_header(struct swsusp_info *info)
@@ -2483,7 +2483,7 @@ static int prepare_highmem_image(struct memory_bitmap *bm,
static struct page *last_highmem_page;
-/**
+/*
* get_highmem_page_buffer - Prepare a buffer to store a highmem image page.
*
* For a given highmem image page get a buffer that suspend_write_next() should
@@ -2706,7 +2706,7 @@ static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm,
return error;
}
-/**
+/*
* get_buffer - Get the address to store the next image data page.
*
* Get the address that snapshot_write_next() should return to its caller to
@@ -2843,7 +2843,7 @@ next:
return PAGE_SIZE;
}
-/**
+/*
* snapshot_write_finalize - Complete the loading of a hibernation image.
*
* Must be called after the last call to snapshot_write_next() in case the last
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index c626e9dc3c1c..67570f74566c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -739,7 +739,7 @@ static int save_compressed_image(struct swap_map_handle *handle,
data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR_OR_NULL(data[thr].cc)) {
- pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
+ pr_err("Could not allocate comp stream %pe\n", data[thr].cc);
ret = -EFAULT;
goto out_clean;
}
@@ -1243,7 +1243,7 @@ static int load_compressed_image(struct swap_map_handle *handle,
data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR_OR_NULL(data[thr].cc)) {
- pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
+ pr_err("Could not allocate comp stream %pe\n", data[thr].cc);
ret = -EFAULT;
goto out_clean;
}
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index fd763da06a87..a8b6bd5ec46b 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -63,7 +63,7 @@ static unsigned int number_of_wakelocks;
static inline bool wakelocks_limit_exceeded(void)
{
- return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
+ return number_of_wakelocks >= CONFIG_PM_WAKELOCKS_LIMIT;
}
static inline void increment_wakelocks_number(void)
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index a4e689eefdfb..a1782755efcc 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -50,6 +50,7 @@ struct sugov_cpu {
unsigned long util;
unsigned long bw_min;
+ unsigned long bw_max;
/* The field below is for single-CPU policies only: */
#ifdef CONFIG_NO_HZ_COMMON
@@ -232,6 +233,7 @@ static void sugov_get_util(struct sugov_cpu *sg_cpu, unsigned long boost)
util = effective_cpu_util(sg_cpu->cpu, util, &min, &max);
util = max(util, boost);
sg_cpu->bw_min = min;
+ sg_cpu->bw_max = max;
sg_cpu->util = sugov_effective_cpu_perf(sg_cpu->cpu, util, min, max);
}
@@ -314,7 +316,7 @@ static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
* A CPU running a task which woken up after an IO operation can have its
* utilization boosted to speed up the completion of those IO operations.
* The IO boost value is increased each time a task wakes up from IO, in
- * sugov_iowait_apply(), and it's instead decreased by this function,
+ * sugov_iowait_boost(), and it's instead decreased by this function,
* each time an increase has not been requested (!iowait_boost_pending).
*
* A CPU which also appears to have been idle for at least one tick has also
@@ -484,7 +486,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
sg_cpu->util = prev_util;
cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
- sg_cpu->util, max_cap);
+ sg_cpu->util, sg_cpu->bw_max, max_cap);
sg_policy->need_freq_update = false;
sg_policy->last_freq_update_time = time;
@@ -590,7 +592,7 @@ static ssize_t rate_limit_us_show(struct gov_attr_set *attr_set, char *buf)
{
struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
- return sprintf(buf, "%u\n", tunables->rate_limit_us);
+ return sysfs_emit(buf, "%u\n", tunables->rate_limit_us);
}
static ssize_t
@@ -870,8 +872,19 @@ static int sugov_start(struct cpufreq_policy *policy)
memset(sg_cpu, 0, sizeof(*sg_cpu));
sg_cpu->cpu = cpu;
sg_cpu->sg_policy = sg_policy;
+ }
+
+ /*
+ * Publish the hooks only after all per-CPU data is initialized, so a
+ * shared policy's sugov_update_shared() never reads an uninitialized
+ * sibling sugov_cpu.
+ */
+ for_each_cpu(cpu, policy->cpus) {
+ struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
+
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu);
}
+
return 0;
}
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index 58ac04c650a1..d624cccb6540 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -792,7 +792,13 @@ pub trait Driver {
}
/// Driver's `adjust_perf` callback.
- fn adjust_perf(_policy: &mut Policy, _min_perf: usize, _target_perf: usize, _capacity: usize) {
+ fn adjust_perf(
+ _policy: &mut Policy,
+ _min_perf: usize,
+ _target_perf: usize,
+ _max_perf: usize,
+ _capacity: usize,
+ ) {
build_error!(VTABLE_DEFAULT_ERROR)
}
@@ -1263,12 +1269,13 @@ impl<T: Driver> Registration<T> {
ptr: *mut bindings::cpufreq_policy,
min_perf: c_ulong,
target_perf: c_ulong,
+ max_perf: c_ulong,
capacity: c_ulong,
) {
// SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the
// lifetime of `policy`.
let policy = unsafe { Policy::from_raw_mut(ptr) };
- T::adjust_perf(policy, min_perf, target_perf, capacity);
+ T::adjust_perf(policy, min_perf, target_perf, max_perf, capacity);
}
/// Driver's `get_intermediate` callback.
diff --git a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
index 38cfbdcdedb7..64001bc80f68 100755
--- a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
+++ b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
@@ -32,8 +32,6 @@ import re
import signal
import sys
import getopt
-import Gnuplot
-from numpy import *
from decimal import *
__author__ = "Srinivas Pandruvada"
@@ -88,8 +86,8 @@ def print_help(driver_name):
print(' kbytes: Kilo bytes of memory per CPU to allocate to the trace buffer. Default: 10240')
print(' Output:')
print(' If not already present, creates a "results/test_name" folder in the current working directory with:')
- print(' cpu.csv - comma seperated values file with trace contents and some additional calculations.')
- print(' cpu???.csv - comma seperated values file for CPU number ???.')
+ print(' cpu.csv - comma separated values file with trace contents and some additional calculations.')
+ print(' cpu???.csv - comma separated values file for CPU number ???.')
print(' *.png - a variety of PNG format plot files created from the trace contents and the additional calculations.')
print(' Notes:')
print(' Avoid the use of _ (underscore) in test names, because in gnuplot it is a subscript directive.')
@@ -295,6 +293,8 @@ def common_all_gnuplot_settings(output_png):
def common_gnuplot_settings():
""" common gnuplot settings. """
+ import Gnuplot
+
g_plot = Gnuplot.Gnuplot(persist=1)
# The following line is for rigor only. It seems to be assumed for .csv files
g_plot('set datafile separator \",\"')
@@ -343,7 +343,7 @@ def store_csv(cpu_int, time_pre_dec, time_post_dec, core_busy, scaled, _from, _t
graph_data_present = True;
def split_csv(current_max_cpu, cpu_mask):
- """ seperate the all csv file into per CPU csv files. """
+ """ separate the main csv file into per CPU csv files. """
if os.path.exists('cpu.csv'):
for index in range(0, current_max_cpu + 1):
@@ -482,7 +482,7 @@ def read_trace_data(filename, cpu_mask):
if cpu_int > current_max_cpu:
current_max_cpu = cpu_int
# End of for each trace line loop
-# Now seperate the main overall csv file into per CPU csv files.
+# Now separate the main overall csv file into per CPU csv files.
split_csv(current_max_cpu, cpu_mask)
def signal_handler(signal, frame):
@@ -508,8 +508,6 @@ if __name__ == "__main__":
valid1 = False
valid2 = False
- cpu_mask = zeros((MAX_CPUS,), dtype=int)
-
try:
opts, args = getopt.getopt(sys.argv[1:],"ht:i:c:n:m:",["help","trace_file=","interval=","cpu=","name=","memory="])
except getopt.GetoptError:
@@ -538,6 +536,10 @@ if __name__ == "__main__":
print_help('intel_pstate')
sys.exit()
+ from numpy import zeros
+
+ cpu_mask = zeros((MAX_CPUS,), dtype=int)
+
if cpu_list:
for p in re.split("[,]", cpu_list):
if int(p) < MAX_CPUS :
diff --git a/tools/testing/selftests/cpufreq/governor.sh b/tools/testing/selftests/cpufreq/governor.sh
index fe37df79c087..cf59e63f8e14 100755
--- a/tools/testing/selftests/cpufreq/governor.sh
+++ b/tools/testing/selftests/cpufreq/governor.sh
@@ -16,6 +16,12 @@ source cpufreq.sh
CUR_GOV=
CUR_FREQ=
+# Per-policy backup, keyed by policy so multiple policies can be saved at once
+# (backup_governor/restore_governor also keep CUR_GOV/CUR_FREQ for callers that
+# read them directly).
+declare -A SAVED_GOVERNORS
+declare -A SAVED_FREQS
+
# Find governor's directory path
# $1: policy, $2: governor
find_gov_directory()
@@ -39,11 +45,13 @@ find_current_governor()
backup_governor()
{
CUR_GOV=$(find_current_governor $1)
+ SAVED_GOVERNORS[$1]=$CUR_GOV
printf "Governor backup done for $1: $CUR_GOV\n"
if [ $CUR_GOV == "userspace" ]; then
CUR_FREQ=$(find_current_freq $1)
+ SAVED_FREQS[$1]=$CUR_FREQ
printf "Governor frequency backup done for $1: $CUR_FREQ\n"
fi
@@ -53,11 +61,13 @@ backup_governor()
# $1: policy
restore_governor()
{
+ CUR_GOV=${SAVED_GOVERNORS[$1]}
__switch_governor $1 $CUR_GOV
printf "Governor restored for $1 to $CUR_GOV\n"
if [ $CUR_GOV == "userspace" ]; then
+ CUR_FREQ=${SAVED_FREQS[$1]}
set_cpu_frequency $1 $CUR_FREQ
printf "Governor frequency restored for $1: $CUR_FREQ\n"
fi
@@ -65,6 +75,17 @@ restore_governor()
printf "\n"
}
+# Save/restore governors for every policy at once
+save_all_governors()
+{
+ for_each_policy backup_governor
+}
+
+restore_all_governors()
+{
+ for_each_policy restore_governor
+}
+
# param:
# $1: policy, $2: governor
__switch_governor()
@@ -100,11 +121,6 @@ switch_governor()
# $1: policy, $2: governor
switch_show_governor()
{
- cur_gov=find_current_governor
- if [ $cur_gov == "userspace" ]; then
- cur_freq=find_current_freq
- fi
-
# switch governor
__switch_governor $1 $2
diff --git a/tools/testing/selftests/cpufreq/special-tests.sh b/tools/testing/selftests/cpufreq/special-tests.sh
index 8d40505dc468..e87ed7c8e5e5 100755
--- a/tools/testing/selftests/cpufreq/special-tests.sh
+++ b/tools/testing/selftests/cpufreq/special-tests.sh
@@ -40,7 +40,9 @@ simple_lockdep()
{
printf "** Test: Running ${FUNCNAME[0]} **\n"
+ save_all_governors
for_each_policy __simple_lockdep
+ restore_all_governors
}
# Test 2
@@ -56,7 +58,10 @@ concurrent_lockdep()
{
printf "** Test: Running ${FUNCNAME[0]} **\n"
+ save_all_governors
for_each_policy_concurrent __concurrent_lockdep
+ wait
+ restore_all_governors
}
# Test 3
@@ -65,20 +70,26 @@ quick_shuffle()
# this is called concurrently from governor_race
for I in `seq 1000`
do
- echo ondemand | sudo tee $CPUFREQROOT/policy*/scaling_governor &
- echo userspace | sudo tee $CPUFREQROOT/policy*/scaling_governor &
+ echo ondemand | tee $CPUFREQROOT/policy*/scaling_governor &
+ echo userspace | tee $CPUFREQROOT/policy*/scaling_governor &
done
+ wait
}
governor_race()
{
printf "** Test: Running ${FUNCNAME[0]} **\n"
+ save_all_governors
+
# run 8 concurrent instances
for I in `seq 8`
do
quick_shuffle &
done
+ wait
+
+ restore_all_governors
}
# Test 4
@@ -112,5 +123,8 @@ hotplug_with_updates_cpu()
hotplug_with_updates()
{
+ save_all_governors
for_each_non_boot_cpu hotplug_with_updates_cpu
+ wait
+ restore_all_governors
}
diff --git a/tools/thermal/thermometer/thermometer.c b/tools/thermal/thermometer/thermometer.c
index 022865da8e3c..1ae6c3ecedb4 100644
--- a/tools/thermal/thermometer/thermometer.c
+++ b/tools/thermal/thermometer/thermometer.c
@@ -272,6 +272,7 @@ static int thermometer_add_tz(const char *path, const char *name, int polling,
tz = realloc(thermometer->tz, sizeof(*thermometer->tz) * (thermometer->nr_tz + 1));
if (!tz) {
ERROR("Failed to allocate thermometer->tz\n");
+ close(fd);
return -1;
}