Merge d46ede3188 ("Merge tag 'pmdomain-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm") into android-mainline
Steps on the way to v6.11-rc1 Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: Ifa579b99625553a29d8143dc25b1f23b00a62edd
This commit is contained in:
@@ -694,3 +694,9 @@ Description:
|
||||
(RO) indicates whether or not the kernel directly supports
|
||||
modifying the crash elfcorehdr for CPU hot un/plug and/or
|
||||
on/offline changes.
|
||||
|
||||
What: /sys/devices/system/cpu/enabled
|
||||
Date: Nov 2022
|
||||
Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
|
||||
Description:
|
||||
(RO) the list of CPUs that can be brought online.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
acpi= [HW,ACPI,X86,ARM64,RISCV64,EARLY]
|
||||
Advanced Configuration and Power Interface
|
||||
Format: { force | on | off | strict | noirq | rsdt |
|
||||
copy_dsdt }
|
||||
copy_dsdt | nospcr }
|
||||
force -- enable ACPI if default was off
|
||||
on -- enable ACPI but allow fallback to DT [arm64,riscv64]
|
||||
off -- disable ACPI if default was on
|
||||
@@ -21,8 +21,12 @@
|
||||
strictly ACPI specification compliant.
|
||||
rsdt -- prefer RSDT over (default) XSDT
|
||||
copy_dsdt -- copy DSDT to memory
|
||||
For ARM64 and RISCV64, ONLY "acpi=off", "acpi=on" or
|
||||
"acpi=force" are available
|
||||
nospcr -- disable console in ACPI SPCR table as
|
||||
default _serial_ console on ARM64
|
||||
For ARM64, ONLY "acpi=off", "acpi=on", "acpi=force" or
|
||||
"acpi=nospcr" are available
|
||||
For RISCV64, ONLY "acpi=off", "acpi=on" or "acpi=force"
|
||||
are available
|
||||
|
||||
See also Documentation/power/runtime_pm.rst, pci=noacpi
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. _cpuhp_index:
|
||||
|
||||
====================
|
||||
CPU Hotplug and ACPI
|
||||
====================
|
||||
|
||||
CPU hotplug in the arm64 world is commonly used to describe the kernel taking
|
||||
CPUs online/offline using PSCI. This document is about ACPI firmware allowing
|
||||
CPUs that were not available during boot to be added to the system later.
|
||||
|
||||
``possible`` and ``present`` refer to the state of the CPU as seen by linux.
|
||||
|
||||
|
||||
CPU Hotplug on physical systems - CPUs not present at boot
|
||||
----------------------------------------------------------
|
||||
|
||||
Physical systems need to mark a CPU that is ``possible`` but not ``present`` as
|
||||
being ``present``. An example would be a dual socket machine, where the package
|
||||
in one of the sockets can be replaced while the system is running.
|
||||
|
||||
This is not supported.
|
||||
|
||||
In the arm64 world CPUs are not a single device but a slice of the system.
|
||||
There are no systems that support the physical addition (or removal) of CPUs
|
||||
while the system is running, and ACPI is not able to sufficiently describe
|
||||
them.
|
||||
|
||||
e.g. New CPUs come with new caches, but the platform's cache toplogy is
|
||||
described in a static table, the PPTT. How caches are shared between CPUs is
|
||||
not discoverable, and must be described by firmware.
|
||||
|
||||
e.g. The GIC redistributor for each CPU must be accessed by the driver during
|
||||
boot to discover the system wide supported features. ACPI's MADT GICC
|
||||
structures can describe a redistributor associated with a disabled CPU, but
|
||||
can't describe whether the redistributor is accessible, only that it is not
|
||||
'always on'.
|
||||
|
||||
arm64's ACPI tables assume that everything described is ``present``.
|
||||
|
||||
|
||||
CPU Hotplug on virtual systems - CPUs not enabled at boot
|
||||
---------------------------------------------------------
|
||||
|
||||
Virtual systems have the advantage that all the properties the system will
|
||||
ever have can be described at boot. There are no power-domain considerations
|
||||
as such devices are emulated.
|
||||
|
||||
CPU Hotplug on virtual systems is supported. It is distinct from physical
|
||||
CPU Hotplug as all resources are described as ``present``, but CPUs may be
|
||||
marked as disabled by firmware. Only the CPU's online/offline behaviour is
|
||||
influenced by firmware. An example is where a virtual machine boots with a
|
||||
single CPU, and additional CPUs are added once a cloud orchestrator deploys
|
||||
the workload.
|
||||
|
||||
For a virtual machine, the VMM (e.g. Qemu) plays the part of firmware.
|
||||
|
||||
Virtual hotplug is implemented as a firmware policy affecting which CPUs can be
|
||||
brought online. Firmware can enforce its policy via PSCI's return codes. e.g.
|
||||
``DENIED``.
|
||||
|
||||
The ACPI tables must describe all the resources of the virtual machine. CPUs
|
||||
that firmware wishes to disable either from boot (or later) should not be
|
||||
``enabled`` in the MADT GICC structures, but should have the ``online capable``
|
||||
bit set, to indicate they can be enabled later. The boot CPU must be marked as
|
||||
``enabled``. The 'always on' GICR structure must be used to describe the
|
||||
redistributors.
|
||||
|
||||
CPUs described as ``online capable`` but not ``enabled`` can be set to enabled
|
||||
by the DSDT's Processor object's _STA method. On virtual systems the _STA method
|
||||
must always report the CPU as ``present``. Changes to the firmware policy can
|
||||
be notified to the OS via device-check or eject-request.
|
||||
|
||||
CPUs described as ``enabled`` in the static table, should not have their _STA
|
||||
modified dynamically by firmware. Soft-restart features such as kexec will
|
||||
re-read the static properties of the system from these static tables, and
|
||||
may malfunction if these no longer describe the running system. Linux will
|
||||
re-discover the dynamic properties of the system from the _STA method later
|
||||
during boot.
|
||||
@@ -13,6 +13,7 @@ ARM64 Architecture
|
||||
asymmetric-32bit
|
||||
booting
|
||||
cpu-feature-registers
|
||||
cpu-hotplug
|
||||
elf_hwcaps
|
||||
hugetlbpage
|
||||
kdump
|
||||
|
||||
@@ -18,12 +18,10 @@ ARMv8.2 adds optional support for Large Virtual Address space. This is
|
||||
only available when running with a 64KB page size and expands the
|
||||
number of descriptors in the first level of translation.
|
||||
|
||||
User addresses have bits 63:48 set to 0 while the kernel addresses have
|
||||
the same bits set to 1. TTBRx selection is given by bit 63 of the
|
||||
virtual address. The swapper_pg_dir contains only kernel (global)
|
||||
mappings while the user pgd contains only user (non-global) mappings.
|
||||
The swapper_pg_dir address is written to TTBR1 and never written to
|
||||
TTBR0.
|
||||
TTBRx selection is given by bit 55 of the virtual address. The
|
||||
swapper_pg_dir contains only kernel (global) mappings while the user pgd
|
||||
contains only user (non-global) mappings. The swapper_pg_dir address is
|
||||
written to TTBR1 and never written to TTBR0.
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
|
||||
@@ -65,14 +63,14 @@ Translation table lookup with 4KB pages::
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| | | | | |
|
||||
| | | | | v
|
||||
| | | | | [11:0] in-page offset
|
||||
| | | | +-> [20:12] L3 index
|
||||
| | | +-----------> [29:21] L2 index
|
||||
| | +---------------------> [38:30] L1 index
|
||||
| +-------------------------------> [47:39] L0 index
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
| | | | | |
|
||||
| | | | | v
|
||||
| | | | | [11:0] in-page offset
|
||||
| | | | +-> [20:12] L3 index
|
||||
| | | +-----------> [29:21] L2 index
|
||||
| | +---------------------> [38:30] L1 index
|
||||
| +-------------------------------> [47:39] L0 index
|
||||
+----------------------------------------> [55] TTBR0/1
|
||||
|
||||
|
||||
Translation table lookup with 64KB pages::
|
||||
@@ -80,14 +78,14 @@ Translation table lookup with 64KB pages::
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
|
||||
+--------+--------+--------+--------+--------+--------+--------+--------+
|
||||
| | | | |
|
||||
| | | | v
|
||||
| | | | [15:0] in-page offset
|
||||
| | | +----------> [28:16] L3 index
|
||||
| | +--------------------------> [41:29] L2 index
|
||||
| +-------------------------------> [47:42] L1 index (48-bit)
|
||||
| [51:42] L1 index (52-bit)
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
| | | | |
|
||||
| | | | v
|
||||
| | | | [15:0] in-page offset
|
||||
| | | +----------> [28:16] L3 index
|
||||
| | +--------------------------> [41:29] L2 index
|
||||
| +-------------------------------> [47:42] L1 index (48-bit)
|
||||
| [51:42] L1 index (52-bit)
|
||||
+----------------------------------------> [55] TTBR0/1
|
||||
|
||||
|
||||
When using KVM without the Virtualization Host Extensions, the
|
||||
|
||||
@@ -132,16 +132,26 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A710 | #2224489 | ARM64_ERRATUM_2224489 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A710 | #3324338 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A720 | #3456091 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X1 | #1502854 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X2 | #3324338 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X3 | #3324335 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X4 | #3194386 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X925 | #3324334 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1188873,1418040| ARM64_ERRATUM_1418040 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N1 | #1349291 | N/A |
|
||||
@@ -156,9 +166,13 @@ stable kernels.
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-N2 | #3324339 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V1 | #1619801 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V3 | #3312417 | ARM64_ERRATUM_3312417 |
|
||||
| ARM | Neoverse-V2 | #3324336 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Neoverse-V3 | #3312417 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | MMU-500 | #841119,826419 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
|
||||
@@ -53,14 +53,20 @@ properties:
|
||||
- arm,cortex-a710-pmu
|
||||
- arm,cortex-a715-pmu
|
||||
- arm,cortex-a720-pmu
|
||||
- arm,cortex-a725-pmu
|
||||
- arm,cortex-x1-pmu
|
||||
- arm,cortex-x2-pmu
|
||||
- arm,cortex-x3-pmu
|
||||
- arm,cortex-x4-pmu
|
||||
- arm,cortex-x925-pmu
|
||||
- arm,neoverse-e1-pmu
|
||||
- arm,neoverse-n1-pmu
|
||||
- arm,neoverse-n2-pmu
|
||||
- arm,neoverse-n3-pmu
|
||||
- arm,neoverse-v1-pmu
|
||||
- arm,neoverse-v2-pmu
|
||||
- arm,neoverse-v3-pmu
|
||||
- arm,neoverse-v3ae-pmu
|
||||
- brcm,vulcan-pmu
|
||||
- cavium,thunder-pmu
|
||||
- nvidia,denver-pmu
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
GMT G762/G763 PWM Fan controller
|
||||
|
||||
Required node properties:
|
||||
|
||||
- "compatible": must be either "gmt,g762" or "gmt,g763"
|
||||
- "reg": I2C bus address of the device
|
||||
- "clocks": a fixed clock providing input clock frequency
|
||||
on CLK pin of the chip.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- "fan_startv": fan startup voltage. Accepted values are 0, 1, 2 and 3.
|
||||
The higher the more.
|
||||
|
||||
- "pwm_polarity": pwm polarity. Accepted values are 0 (positive duty)
|
||||
and 1 (negative duty).
|
||||
|
||||
- "fan_gear_mode": fan gear mode. Supported values are 0, 1 and 2.
|
||||
|
||||
If an optional property is not set in .dts file, then current value is kept
|
||||
unmodified (e.g. u-boot installed value).
|
||||
|
||||
Additional information on operational parameters for the device is available
|
||||
in Documentation/hwmon/g762.rst. A detailed datasheet for the device is available
|
||||
at http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf.
|
||||
|
||||
Example g762 node:
|
||||
|
||||
clocks {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
g762_clk: fixedclk {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <8192>;
|
||||
}
|
||||
}
|
||||
|
||||
g762: g762@3e {
|
||||
compatible = "gmt,g762";
|
||||
reg = <0x3e>;
|
||||
clocks = <&g762_clk>
|
||||
fan_gear_mode = <0>; /* chip default */
|
||||
fan_startv = <1>; /* chip default */
|
||||
pwm_polarity = <0>; /* chip default */
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/gmt,g762.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GMT G761/G762/G763 PWM Fan controller
|
||||
|
||||
maintainers:
|
||||
- Christian Marangi <ansuelsmth@gmail.com>
|
||||
|
||||
description: |
|
||||
GMT G761/G762/G763 PWM Fan controller.
|
||||
|
||||
G761 supports an internal-clock hence the clocks property is optional.
|
||||
If not defined, internal-clock will be used. (31KHz is the clock of
|
||||
the internal crystal oscillator)
|
||||
|
||||
If an optional property is not set in DT, then current value is kept
|
||||
unmodified (e.g. bootloader installed value).
|
||||
|
||||
Additional information on operational parameters for the device is available
|
||||
in Documentation/hwmon/g762.rst. A detailed datasheet for the device is available
|
||||
at http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- gmt,g761
|
||||
- gmt,g762
|
||||
- gmt,g763
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: a fixed clock providing input clock frequency on CLK
|
||||
pin of the chip.
|
||||
maxItems: 1
|
||||
|
||||
fan_startv:
|
||||
description: Fan startup voltage step
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
|
||||
pwm_polarity:
|
||||
description: PWM polarity (positive or negative duty)
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
fan_gear_mode:
|
||||
description: FAN gear mode. Configure High speed fan setting factor
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- gmt,g762
|
||||
- gmt,g763
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
g762@3e {
|
||||
compatible = "gmt,g762";
|
||||
reg = <0x3e>;
|
||||
clocks = <&g762_clk>;
|
||||
fan_gear_mode = <0>;
|
||||
fan_startv = <1>;
|
||||
pwm_polarity = <0>;
|
||||
};
|
||||
|
||||
g761@1e {
|
||||
compatible = "gmt,g761";
|
||||
reg = <0x1e>;
|
||||
fan_gear_mode = <0>;
|
||||
fan_startv = <1>;
|
||||
pwm_polarity = <0>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/hwmon/maxim,max6639.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim max6639
|
||||
|
||||
maintainers:
|
||||
- Naresh Solanki <naresh.solanki@9elements.com>
|
||||
|
||||
description: |
|
||||
The MAX6639 is a 2-channel temperature monitor with dual, automatic, PWM
|
||||
fan-speed controller. It monitors its own temperature and one external
|
||||
diode-connected transistor or the temperatures of two external diode-connected
|
||||
transistors, typically available in CPUs, FPGAs, or GPUs.
|
||||
|
||||
Datasheets:
|
||||
https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- maxim,max6639
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
'#pwm-cells':
|
||||
const: 3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
patternProperties:
|
||||
"^fan@[0-1]$":
|
||||
type: object
|
||||
description:
|
||||
Represents the two fans and their specific configuration.
|
||||
|
||||
$ref: fan-common.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
The fan number.
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fan1: fan-controller@10 {
|
||||
compatible = "maxim,max6639";
|
||||
reg = <0x10>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#pwm-cells = <3>;
|
||||
|
||||
fan@0 {
|
||||
reg = <0x0>;
|
||||
pulses-per-revolution = <2>;
|
||||
max-rpm = <4000>;
|
||||
target-rpm = <1000>;
|
||||
pwms = <&fan1 0 25000 0>;
|
||||
};
|
||||
|
||||
fan@1 {
|
||||
reg = <0x1>;
|
||||
pulses-per-revolution = <2>;
|
||||
max-rpm = <8000>;
|
||||
pwms = <&fan1 1 25000 0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -66,6 +66,14 @@ properties:
|
||||
description: phandle to the regulator that provides the VS supply typically
|
||||
in range from 2.7 V to 5.5 V.
|
||||
|
||||
ti,alert-polarity-active-high:
|
||||
description: Alert pin is asserted based on the value of Alert polarity Bit
|
||||
of Mask/Enable register. Default value is Normal (0 which maps to
|
||||
active-low open collector). The other value is Inverted
|
||||
(1 which maps to active-high open collector). Specify this property to set
|
||||
the alert polarity to active-high.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -88,5 +96,6 @@ examples:
|
||||
label = "vdd_3v0";
|
||||
shunt-resistor = <1000>;
|
||||
vs-supply = <&vdd_3v0>;
|
||||
ti,alert-polarity-active-high;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -9,6 +9,14 @@ title: TMP108 temperature sensor
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzk@kernel.org>
|
||||
|
||||
description: |
|
||||
The TMP108 is a digital-output temperature sensor with a
|
||||
dynamically-programmable limit window, and under- and overtemperature
|
||||
alert functions.
|
||||
|
||||
Datasheets:
|
||||
https://www.ti.com/product/TMP108
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
@@ -24,6 +32,9 @@ properties:
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
vcc-supply:
|
||||
description: phandle to the regulator that provides the V+ supply
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -45,6 +56,7 @@ examples:
|
||||
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&tmp_alrt>;
|
||||
vcc-supply = <&supply>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,6 +30,9 @@ properties:
|
||||
- items:
|
||||
- const: fsl,imx8dxl-ddr-pmu
|
||||
- const: fsl,imx8-ddr-pmu
|
||||
- items:
|
||||
- const: fsl,imx95-ddr-pmu
|
||||
- const: fsl,imx93-ddr-pmu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -20,6 +20,8 @@ properties:
|
||||
enum:
|
||||
- amlogic,meson-a1-pwrc
|
||||
- amlogic,meson-s4-pwrc
|
||||
- amlogic,a4-pwrc
|
||||
- amlogic,a5-pwrc
|
||||
- amlogic,c3-pwrc
|
||||
- amlogic,t7-pwrc
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/adi,axi-pwmgen.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AXI PWM generator
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
- Nuno Sá <nuno.sa@analog.com>
|
||||
|
||||
description:
|
||||
The Analog Devices AXI PWM generator can generate PWM signals
|
||||
with variable pulse width and period.
|
||||
|
||||
https://wiki.analog.com/resources/fpga/docs/axi_pwm_gen
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,axi-pwmgen-2.00.a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#pwm-cells":
|
||||
const: 2
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pwm@44b00000 {
|
||||
compatible = "adi,axi-pwmgen-2.00.a";
|
||||
reg = <0x44b00000 0x1000>;
|
||||
clocks = <&spi_clk>;
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
@@ -23,7 +23,9 @@ properties:
|
||||
- atmel,sama5d2-pwm
|
||||
- microchip,sam9x60-pwm
|
||||
- items:
|
||||
- const: microchip,sama7g5-pwm
|
||||
- enum:
|
||||
- microchip,sama7d65-pwm
|
||||
- microchip,sama7g5-pwm
|
||||
- const: atmel,sama5d2-pwm
|
||||
- items:
|
||||
- const: microchip,sam9x7-pwm
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/fsl,vf610-ftm-pwm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale FlexTimer Module (FTM) PWM controller
|
||||
|
||||
description: |
|
||||
The same FTM PWM device can have a different endianness on different SoCs. The
|
||||
device tree provides a property to describing this so that an operating system
|
||||
device driver can handle all variants of the device. Refer to the table below
|
||||
for the endianness of the FTM PWM block as integrated into the existing SoCs:
|
||||
|
||||
SoC | FTM-PWM endianness
|
||||
--------+-------------------
|
||||
Vybrid | LE
|
||||
LS1 | BE
|
||||
LS2 | LE
|
||||
|
||||
Please see ../regmap/regmap.txt for more detail about how to specify endian
|
||||
modes in device tree.
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,vf610-ftm-pwm
|
||||
- fsl,imx8qm-ftm-pwm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ftm_sys
|
||||
- const: ftm_ext
|
||||
- const: ftm_fix
|
||||
- const: ftm_cnt_clk_en
|
||||
|
||||
pinctrl-0: true
|
||||
pinctrl-1: true
|
||||
|
||||
pinctrl-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: default
|
||||
- const: sleep
|
||||
|
||||
big-endian:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Boolean property, required if the FTM PWM registers use a big-
|
||||
endian rather than little-endian layout.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/vf610-clock.h>
|
||||
|
||||
pwm@40038000 {
|
||||
compatible = "fsl,vf610-ftm-pwm";
|
||||
reg = <0x40038000 0x1000>;
|
||||
#pwm-cells = <3>;
|
||||
clocks = <&clks VF610_CLK_FTM0>,
|
||||
<&clks VF610_CLK_FTM0_EXT_SEL>,
|
||||
<&clks VF610_CLK_FTM0_FIX_SEL>,
|
||||
<&clks VF610_CLK_FTM0_EXT_FIX_EN>;
|
||||
clock-names = "ftm_sys", "ftm_ext", "ftm_fix", "ftm_cnt_clk_en";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_pwm0_1>;
|
||||
big-endian;
|
||||
};
|
||||
@@ -68,7 +68,6 @@ required:
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
Freescale FlexTimer Module (FTM) PWM controller
|
||||
|
||||
The same FTM PWM device can have a different endianness on different SoCs. The
|
||||
device tree provides a property to describing this so that an operating system
|
||||
device driver can handle all variants of the device. Refer to the table below
|
||||
for the endianness of the FTM PWM block as integrated into the existing SoCs:
|
||||
|
||||
SoC | FTM-PWM endianness
|
||||
--------+-------------------
|
||||
Vybrid | LE
|
||||
LS1 | BE
|
||||
LS2 | LE
|
||||
|
||||
Please see ../regmap/regmap.txt for more detail about how to specify endian
|
||||
modes in device tree.
|
||||
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "fsl,<soc>-ftm-pwm" and one of the following
|
||||
compatible strings:
|
||||
- "fsl,vf610-ftm-pwm" for PWM compatible with the one integrated on VF610
|
||||
- "fsl,imx8qm-ftm-pwm" for PWM compatible with the one integrated on i.MX8QM
|
||||
- reg: Physical base address and length of the controller's registers
|
||||
- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
|
||||
the cells format.
|
||||
- clock-names: Should include the following module clock source entries:
|
||||
"ftm_sys" (module clock, also can be used as counter clock),
|
||||
"ftm_ext" (external counter clock),
|
||||
"ftm_fix" (fixed counter clock),
|
||||
"ftm_cnt_clk_en" (external and fixed counter clock enable/disable).
|
||||
- clocks: Must contain a phandle and clock specifier for each entry in
|
||||
clock-names, please see clock/clock-bindings.txt for details of the property
|
||||
values.
|
||||
- pinctrl-names: Must contain a "default" entry.
|
||||
- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
|
||||
See pinctrl/pinctrl-bindings.txt for details of the property values.
|
||||
- big-endian: Boolean property, required if the FTM PWM registers use a big-
|
||||
endian rather than little-endian layout.
|
||||
|
||||
Example:
|
||||
|
||||
pwm0: pwm@40038000 {
|
||||
compatible = "fsl,vf610-ftm-pwm";
|
||||
reg = <0x40038000 0x1000>;
|
||||
#pwm-cells = <3>;
|
||||
clock-names = "ftm_sys", "ftm_ext",
|
||||
"ftm_fix", "ftm_cnt_clk_en";
|
||||
clocks = <&clks VF610_CLK_FTM0>,
|
||||
<&clks VF610_CLK_FTM0_EXT_SEL>,
|
||||
<&clks VF610_CLK_FTM0_FIX_SEL>,
|
||||
<&clks VF610_CLK_FTM0_EXT_FIX_EN>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_pwm0_1>;
|
||||
big-endian;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/pwm-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Generic software PWM for modulating GPIOs
|
||||
|
||||
maintainers:
|
||||
- Stefan Wahren <wahrenst@gmx.net>
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: pwm-gpio
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
description:
|
||||
See pwm.yaml in this directory for a description of the cells format.
|
||||
The first cell which represents the PWM instance number must always
|
||||
be zero.
|
||||
|
||||
gpios:
|
||||
description:
|
||||
GPIO to be modulated
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#pwm-cells"
|
||||
- gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
pwm {
|
||||
#pwm-cells = <3>;
|
||||
compatible = "pwm-gpio";
|
||||
gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
@@ -16,8 +16,10 @@ properties:
|
||||
pattern: "^pwm(@.*|-([0-9]|[1-9][0-9]+))?$"
|
||||
|
||||
"#pwm-cells":
|
||||
description:
|
||||
Number of cells in a PWM specifier.
|
||||
description: |
|
||||
Number of cells in a PWM specifier. Typically the cells represent, in
|
||||
order: the chip-relative PWM number, the PWM period in nanoseconds and
|
||||
optionally a number of flags (defined in <dt-bindings/pwm/pwm.h>).
|
||||
|
||||
required:
|
||||
- "#pwm-cells"
|
||||
|
||||
@@ -168,6 +168,8 @@ properties:
|
||||
- isil,isl69269
|
||||
# Intersil ISL76682 Ambient Light Sensor
|
||||
- isil,isl76682
|
||||
# JEDEC JESD300 (SPD5118) Hub and Serial Presence Detect
|
||||
- jedec,spd5118
|
||||
# Linear Technology LTC2488
|
||||
- lineartechnology,ltc2488
|
||||
# 5 Bit Programmable, Pulse-Width Modulator
|
||||
@@ -286,14 +288,22 @@ properties:
|
||||
- mps,mp2857
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2888
|
||||
- mps,mp2888
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2891
|
||||
- mps,mp2891
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2971
|
||||
- mps,mp2971
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2973
|
||||
- mps,mp2973
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2975
|
||||
- mps,mp2975
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2993
|
||||
- mps,mp2993
|
||||
# Monolithic Power Systems Inc. multi-phase hot-swap controller mp5920
|
||||
- mps,mp5920
|
||||
# Monolithic Power Systems Inc. multi-phase hot-swap controller mp5990
|
||||
- mps,mp5990
|
||||
# Monolithic Power Systems Inc. digital step-down converter mp9941
|
||||
- mps,mp9941
|
||||
# Monolithic Power Systems Inc. synchronous step-down converter mpq8785
|
||||
- mps,mpq8785
|
||||
# Temperature sensor with integrated fan control
|
||||
|
||||
@@ -27,7 +27,12 @@ hardware descriptions such as device tree or ACPI:
|
||||
to the lines for a more permanent solution of this type.
|
||||
|
||||
- gpio-beeper: drivers/input/misc/gpio-beeper.c is used to provide a beep from
|
||||
an external speaker connected to a GPIO line.
|
||||
an external speaker connected to a GPIO line. (If the beep is controlled by
|
||||
off/on, for an actual PWM waveform, see pwm-gpio below.)
|
||||
|
||||
- pwm-gpio: drivers/pwm/pwm-gpio.c is used to toggle a GPIO with a high
|
||||
resolution timer producing a PWM waveform on the GPIO line, as well as
|
||||
Linux high resolution timers can do.
|
||||
|
||||
- extcon-gpio: drivers/extcon/extcon-gpio.c is used when you need to read an
|
||||
external connector status, such as a headset line for an audio driver or an
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
Kernel driver adm1021
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Analog Devices ADM1021
|
||||
|
||||
Prefix: 'adm1021'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
* Analog Devices ADM1021A/ADM1023
|
||||
|
||||
Prefix: 'adm1023'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
* Genesys Logic GL523SM
|
||||
|
||||
Prefix: 'gl523sm'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet:
|
||||
|
||||
* Maxim MAX1617
|
||||
|
||||
Prefix: 'max1617'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
|
||||
* Maxim MAX1617A
|
||||
|
||||
Prefix: 'max1617a'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
|
||||
* National Semiconductor LM84
|
||||
|
||||
Prefix: 'lm84'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
|
||||
* Philips NE1617
|
||||
|
||||
Prefix: 'max1617' (probably detected as a max1617)
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Philips website
|
||||
|
||||
* Philips NE1617A
|
||||
|
||||
Prefix: 'max1617' (probably detected as a max1617)
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Philips website
|
||||
|
||||
* TI THMC10
|
||||
|
||||
Prefix: 'thmc10'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
* Onsemi MC1066
|
||||
|
||||
Prefix: 'mc1066'
|
||||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Onsemi website
|
||||
|
||||
|
||||
Authors:
|
||||
- Frodo Looijaard <frodol@dds.nl>,
|
||||
- Philip Edelbrock <phil@netroedge.com>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* read_only: int
|
||||
Don't set any values, read only mode
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The chips supported by this driver are very similar. The Maxim MAX1617 is
|
||||
the oldest; it has the problem that it is not very well detectable. The
|
||||
MAX1617A solves that. The ADM1021 is a straight clone of the MAX1617A.
|
||||
Ditto for the THMC10. From here on, we will refer to all these chips as
|
||||
ADM1021-clones.
|
||||
|
||||
The ADM1021 and MAX1617A reports a die code, which is a sort of revision
|
||||
code. This can help us pinpoint problems; it is not very useful
|
||||
otherwise.
|
||||
|
||||
ADM1021-clones implement two temperature sensors. One of them is internal,
|
||||
and measures the temperature of the chip itself; the other is external and
|
||||
is realised in the form of a transistor-like device. A special alarm
|
||||
indicates whether the remote sensor is connected.
|
||||
|
||||
Each sensor has its own low and high limits. When they are crossed, the
|
||||
corresponding alarm is set and remains on as long as the temperature stays
|
||||
out of range. Temperatures are measured in degrees Celsius. Measurements
|
||||
are possible between -65 and +127 degrees, with a resolution of one degree.
|
||||
|
||||
If an alarm triggers, it will remain triggered until the hardware register
|
||||
is read at least once. This means that the cause for the alarm may already
|
||||
have disappeared!
|
||||
|
||||
This driver only updates its values each 1.5 seconds; reading it more often
|
||||
will do no harm, but will return 'old' values. It is possible to make
|
||||
ADM1021-clones do faster measurements, but there is really no good reason
|
||||
for that.
|
||||
|
||||
|
||||
Netburst-based Xeon support
|
||||
---------------------------
|
||||
|
||||
Some Xeon processors based on the Netburst (early Pentium 4, from 2001 to
|
||||
2003) microarchitecture had real MAX1617, ADM1021, or compatible chips
|
||||
within them, with two temperature sensors. Other Xeon processors of this
|
||||
era (with 400 MHz FSB) had chips with only one temperature sensor.
|
||||
|
||||
If you have such an old Xeon, and you get two valid temperatures when
|
||||
loading the adm1021 module, then things are good.
|
||||
|
||||
If nothing happens when loading the adm1021 module, and you are certain
|
||||
that your specific Xeon processor model includes compatible sensors, you
|
||||
will have to explicitly instantiate the sensor chips from user-space. See
|
||||
method 4 in Documentation/i2c/instantiating-devices.rst. Possible slave
|
||||
addresses are 0x18, 0x1a, 0x29, 0x2b, 0x4c, or 0x4e. It is likely that
|
||||
only temp2 will be correct and temp1 will have to be ignored.
|
||||
|
||||
Previous generations of the Xeon processor (based on Pentium II/III)
|
||||
didn't have these sensors. Next generations of Xeon processors (533 MHz
|
||||
FSB and faster) lost them, until the Core-based generation which
|
||||
introduced integrated digital thermal sensors. These are supported by
|
||||
the coretemp driver.
|
||||
@@ -47,13 +47,18 @@ fan1_input ro tachometer speed
|
||||
fan1_min rw "
|
||||
fan1_max rw "
|
||||
fan1_fault ro "
|
||||
fan1_div rw Fan divisor can be either 2 or 4.
|
||||
fan1_pulses rw Pulses per revolution can be either 2 or 4.
|
||||
fan1_target rw Target fan speed, to be used with pwm1_enable
|
||||
mode 4.
|
||||
|
||||
pwm1 rw pwm1
|
||||
pwm1_enable rw regulator mode, 1=open loop, 2=fan controlled
|
||||
by remote temperature, 3=fan controlled by
|
||||
combination of the on-chip temperature and
|
||||
remote-sensor temperature,
|
||||
4=fan controlled by target rpm set with
|
||||
fan1_target attribute.
|
||||
pwm1_mode rw Fan duty control mode (0=DC, 1=PWM)
|
||||
pwm1_auto_channels_temp ro 1 if pwm_enable==2, 3 if pwm_enable==3
|
||||
pwm1_auto_point1_pwm ro Hardwired to 0, shared for both
|
||||
temperature channels.
|
||||
|
||||
@@ -8,6 +8,7 @@ Supported boards:
|
||||
* PRIME X570-PRO
|
||||
* Pro WS X570-ACE
|
||||
* ProArt X570-CREATOR WIFI
|
||||
* ProArt X670E-CREATOR WIFI
|
||||
* ProArt B550-CREATOR
|
||||
* ROG CROSSHAIR VIII DARK HERO
|
||||
* ROG CROSSHAIR VIII HERO (WI-FI)
|
||||
|
||||
@@ -39,3 +39,11 @@ fan[1-6]_target Sets fan speed target rpm.
|
||||
pwm[1-6] Sets the fan speed. Values from 0-255. Can only be read if pwm
|
||||
was set directly.
|
||||
======================= =====================================================================
|
||||
|
||||
Debugfs entries
|
||||
---------------
|
||||
|
||||
======================= ===================
|
||||
firmware_version Firmware version
|
||||
bootloader_version Bootloader version
|
||||
======================= ===================
|
||||
|
||||
@@ -15,11 +15,11 @@ Supported devices:
|
||||
|
||||
Corsair HX850i
|
||||
|
||||
Corsair HX1000i (Series 2022 and 2023)
|
||||
Corsair HX1000i (Legacy and Series 2023)
|
||||
|
||||
Corsair HX1200i
|
||||
Corsair HX1200i (Legacy and Series 2023)
|
||||
|
||||
Corsair HX1500i (Series 2022 and 2023)
|
||||
Corsair HX1500i (Legacy and Series 2023)
|
||||
|
||||
Corsair RM550i
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Kernel driver cros_ec_hwmon
|
||||
===========================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* ChromeOS embedded controllers.
|
||||
|
||||
Prefix: 'cros_ec'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Author:
|
||||
|
||||
- Thomas Weißschuh <linux@weissschuh.net>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for hardware monitoring commands exposed by the
|
||||
ChromeOS embedded controller used in Chromebooks and other devices.
|
||||
|
||||
The channel labels exposed via hwmon are retrieved from the EC itself.
|
||||
|
||||
Fan and temperature readings are supported.
|
||||
@@ -360,6 +360,8 @@ Firmware Bug Affected Machines
|
||||
======================================================= =================
|
||||
Reading of fan states return spurious errors. Precision 490
|
||||
|
||||
OptiPlex 7060
|
||||
|
||||
Reading of fan types causes erratic fan behaviour. Studio XPS 8000
|
||||
|
||||
Studio XPS 8100
|
||||
|
||||
@@ -25,7 +25,6 @@ Hardware Monitoring Kernel Drivers
|
||||
acpi_power_meter
|
||||
ad7314
|
||||
adc128d818
|
||||
adm1021
|
||||
adm1025
|
||||
adm1026
|
||||
adm1031
|
||||
@@ -58,6 +57,7 @@ Hardware Monitoring Kernel Drivers
|
||||
coretemp
|
||||
corsair-cpro
|
||||
corsair-psu
|
||||
cros_ec_hwmon
|
||||
da9052
|
||||
da9055
|
||||
dell-smm-hwmon
|
||||
@@ -154,7 +154,6 @@ Hardware Monitoring Kernel Drivers
|
||||
max34440
|
||||
max6620
|
||||
max6639
|
||||
max6642
|
||||
max6650
|
||||
max6697
|
||||
max8688
|
||||
@@ -165,9 +164,13 @@ Hardware Monitoring Kernel Drivers
|
||||
mlxreg-fan
|
||||
mp2856
|
||||
mp2888
|
||||
mp2891
|
||||
mp2975
|
||||
mp2993
|
||||
mp5023
|
||||
mp5920
|
||||
mp5990
|
||||
mp9941
|
||||
mpq8785
|
||||
nct6683
|
||||
nct6775
|
||||
@@ -215,6 +218,7 @@ Hardware Monitoring Kernel Drivers
|
||||
smsc47m192
|
||||
smsc47m1
|
||||
sparx5-temp
|
||||
spd5118
|
||||
stpddc60
|
||||
surface_fan
|
||||
sy7636a-hwmon
|
||||
|
||||
@@ -131,7 +131,14 @@ The Fault Queue bits select how many consecutive temperature faults must occur
|
||||
before overtemperature or undertemperature faults are indicated in the
|
||||
corresponding status bits.
|
||||
|
||||
Notes
|
||||
-----
|
||||
PEC Support
|
||||
-----------
|
||||
|
||||
PEC is not implemented.
|
||||
When reading a register value, the PEC byte is computed and sent by the chip.
|
||||
|
||||
PEC on word data transaction respresents a signifcant increase in bandwitdh
|
||||
usage (+33% for both write and reads) in normal conditions.
|
||||
|
||||
Since this operation implies there will be an extra delay to each
|
||||
transaction, PEC can be disabled or enabled through sysfs.
|
||||
Just write 1 to the "pec" file for enabling PEC and 0 for disabling it.
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
Kernel driver max6642
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Maxim MAX6642
|
||||
|
||||
Prefix: 'max6642'
|
||||
|
||||
Addresses scanned: I2C 0x48-0x4f
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
|
||||
|
||||
Authors:
|
||||
|
||||
Per Dalen <per.dalen@appeartv.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The MAX6642 is a digital temperature sensor. It senses its own temperature as
|
||||
well as the temperature on one external diode.
|
||||
|
||||
All temperature values are given in degrees Celsius. Resolution
|
||||
is 0.25 degree for the local temperature and for the remote temperature.
|
||||
@@ -0,0 +1,179 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp2891
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS mp2891
|
||||
|
||||
Prefix: 'mp2891'
|
||||
|
||||
* Datasheet
|
||||
|
||||
Publicly available at the MPS website : https://www.monolithicpower.com/en/mp2891.html
|
||||
|
||||
Author:
|
||||
|
||||
Noah Wang <noahwang.wang@outlook.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP2891 Multi-phase Digital VR Controller.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
Device supports direct and linear format for reading input voltage,
|
||||
output voltage, input current, output current, input power, output
|
||||
power, and temperature.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_crit_alarm**
|
||||
|
||||
**in1_lcrit**
|
||||
|
||||
**in1_lcrit_alarm**
|
||||
|
||||
**in1_min**
|
||||
|
||||
**in1_min_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_crit**
|
||||
|
||||
**in2_crit_alarm**
|
||||
|
||||
**in2_lcrit**
|
||||
|
||||
**in2_lcrit_alarm**
|
||||
|
||||
**in2_min**
|
||||
|
||||
**in2_min_alarm**
|
||||
|
||||
**in3_input**
|
||||
|
||||
**in3_label**
|
||||
|
||||
**in3_crit**
|
||||
|
||||
**in3_crit_alarm**
|
||||
|
||||
**in3_lcrit**
|
||||
|
||||
**in3_lcrit_alarm**
|
||||
|
||||
**in3_min**
|
||||
|
||||
**in3_min_alarm**
|
||||
|
||||
The driver provides the following attributes for input current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
**curr1_max**
|
||||
|
||||
**curr1_max_alarm**
|
||||
|
||||
**curr2_input**
|
||||
|
||||
**curr2_label**
|
||||
|
||||
**curr2_max**
|
||||
|
||||
**curr2_max_alarm**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr3_input**
|
||||
|
||||
**curr3_label**
|
||||
|
||||
**curr3_crit**
|
||||
|
||||
**curr3_crit_alarm**
|
||||
|
||||
**curr3_max**
|
||||
|
||||
**curr3_max_alarm**
|
||||
|
||||
**curr4_input**
|
||||
|
||||
**curr4_label**
|
||||
|
||||
**curr4_crit**
|
||||
|
||||
**curr4_crit_alarm**
|
||||
|
||||
**curr4_max**
|
||||
|
||||
**curr4_max_alarm**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
**power1_max**
|
||||
|
||||
**power1_alarm**
|
||||
|
||||
**power2_input**
|
||||
|
||||
**power2_label**
|
||||
|
||||
**power2_max**
|
||||
|
||||
**power2_alarm**
|
||||
|
||||
The driver provides the following attributes for output power:
|
||||
|
||||
**power3_input**
|
||||
|
||||
**power3_label**
|
||||
|
||||
**power4_input**
|
||||
|
||||
**power4_label**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_crit_alarm**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_max_alarm**
|
||||
|
||||
**temp2_input**
|
||||
|
||||
**temp2_crit**
|
||||
|
||||
**temp2_crit_alarm**
|
||||
|
||||
**temp2_max**
|
||||
|
||||
**temp2_max_alarm**
|
||||
@@ -0,0 +1,150 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp2993
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS mp2993
|
||||
|
||||
Prefix: 'mp2993'
|
||||
|
||||
* Datasheet
|
||||
https://scnbwymvp-my.sharepoint.com/:f:/g/personal/admin_scnbwy_com/Eth4kX1_J1hMsaASHiOYL4QBHU5a75r-tRfLKbHnJFdKLQ?e=vxj3DF
|
||||
|
||||
Author:
|
||||
|
||||
Noah Wang <noahwang.wang@outlook.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP2993 Dual Loop Digital Multi-phase Controller.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_crit_alarm**
|
||||
|
||||
**in1_lcrit**
|
||||
|
||||
**in1_lcrit_alarm**
|
||||
|
||||
**in1_max**
|
||||
|
||||
**in1_max_alarm**
|
||||
|
||||
**in1_min**
|
||||
|
||||
**in1_min_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_crit**
|
||||
|
||||
**in2_crit_alarm**
|
||||
|
||||
**in2_lcrit**
|
||||
|
||||
**in2_lcrit_alarm**
|
||||
|
||||
**in3_input**
|
||||
|
||||
**in3_label**
|
||||
|
||||
**in3_crit**
|
||||
|
||||
**in3_crit_alarm**
|
||||
|
||||
**in3_lcrit**
|
||||
|
||||
**in3_lcrit_alarm**
|
||||
|
||||
The driver provides the following attributes for input current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
**curr1_max**
|
||||
|
||||
**curr1_max_alarm**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr2_input**
|
||||
|
||||
**curr2_label**
|
||||
|
||||
**curr2_crit**
|
||||
|
||||
**curr2_crit_alarm**
|
||||
|
||||
**curr2_max**
|
||||
|
||||
**curr2_max_alarm**
|
||||
|
||||
**curr3_input**
|
||||
|
||||
**curr3_label**
|
||||
|
||||
**curr3_crit**
|
||||
|
||||
**curr3_crit_alarm**
|
||||
|
||||
**curr3_max**
|
||||
|
||||
**curr3_max_alarm**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
The driver provides the following attributes for output power:
|
||||
|
||||
**power2_input**
|
||||
|
||||
**power2_label**
|
||||
|
||||
**power3_input**
|
||||
|
||||
**power3_label**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_crit_alarm**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_max_alarm**
|
||||
|
||||
**temp2_input**
|
||||
|
||||
**temp2_crit**
|
||||
|
||||
**temp2_crit_alarm**
|
||||
|
||||
**temp2_max**
|
||||
|
||||
**temp2_max_alarm**
|
||||
@@ -0,0 +1,91 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp5920
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS MP5920
|
||||
|
||||
Prefix: 'mp5920'
|
||||
|
||||
* Datasheet
|
||||
|
||||
Publicly available at the MPS website : https://www.monolithicpower.com/en/mp5920.html
|
||||
|
||||
Authors:
|
||||
|
||||
Tony Ao <tony_ao@wiwynn.com>
|
||||
Alex Vdovydchenko <xzeol@yahoo.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP5920 Hot-Swap Controller.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
Device supports direct and linear format for reading input voltage,
|
||||
output voltage, output current, input power and temperature.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_rated_max**
|
||||
|
||||
**in1_rated_min**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_rated_max**
|
||||
|
||||
**in2_rated_min**
|
||||
|
||||
**in2_alarm**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
**curr1_crit**
|
||||
|
||||
**curr1_alarm**
|
||||
|
||||
**curr1_rated_max**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
**power1_max**
|
||||
|
||||
**power1_rated_max**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_alarm**
|
||||
@@ -0,0 +1,92 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp9941
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS mp9941
|
||||
|
||||
Prefix: 'mp9941'
|
||||
|
||||
* Datasheet
|
||||
https://scnbwymvp-my.sharepoint.com/:f:/g/personal/admin_scnbwy_com/Eth4kX1_J1hMsaASHiOYL4QBHU5a75r-tRfLKbHnJFdKLQ?e=vxj3DF
|
||||
|
||||
Author:
|
||||
|
||||
Noah Wang <noahwang.wang@outlook.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP9941 digital step-down converter.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_crit_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_lcrit**
|
||||
|
||||
**in2_lcrit_alarm**
|
||||
|
||||
**in2_rated_max**
|
||||
|
||||
**in2_rated_min**
|
||||
|
||||
The driver provides the following attributes for input current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
**curr1_max**
|
||||
|
||||
**curr1_max_alarm**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr2_input**
|
||||
|
||||
**curr2_label**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
The driver provides the following attributes for output power:
|
||||
|
||||
**power2_input**
|
||||
|
||||
**power2_label**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_crit_alarm**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_max_alarm**
|
||||
@@ -0,0 +1,63 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Kernel driver spd5118
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* SPD5118 (JEDEC JESD300) compliant temperature sensor chips
|
||||
|
||||
JEDEC standard download:
|
||||
https://www.jedec.org/standards-documents/docs/jesd300-5b01
|
||||
(account required)
|
||||
|
||||
|
||||
Prefix: 'spd5118'
|
||||
|
||||
Addresses scanned: I2C 0x50 - 0x57
|
||||
|
||||
Author:
|
||||
Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for SPD5118 (JEDEC JESD300) compliant temperature
|
||||
sensors, which are used on many DDR5 memory modules. Some systems use the sensor
|
||||
to prevent memory overheating by automatically throttling the memory controller.
|
||||
|
||||
The driver auto-detects SPD5118 compliant chips, but can also be instantiated
|
||||
using devicetree/firmware nodes.
|
||||
|
||||
A SPD5118 compliant chip supports a single temperature sensor. Critical minimum,
|
||||
minimum, maximum, and critical temperature can be configured. There are alarms
|
||||
for low critical, low, high, and critical thresholds.
|
||||
|
||||
|
||||
Hardware monitoring sysfs entries
|
||||
---------------------------------
|
||||
|
||||
======================= ==================================
|
||||
temp1_input Temperature (RO)
|
||||
temp1_lcrit Low critical high temperature (RW)
|
||||
temp1_min Minimum temperature (RW)
|
||||
temp1_max Maximum temperature (RW)
|
||||
temp1_crit Critical high temperature (RW)
|
||||
|
||||
temp1_lcrit_alarm Temperature low critical alarm
|
||||
temp1_min_alarm Temperature low alarm
|
||||
temp1_max_alarm Temperature high alarm
|
||||
temp1_crit_alarm Temperature critical alarm
|
||||
======================= ==================================
|
||||
|
||||
Alarm attributes are sticky until read and will be cleared afterwards
|
||||
unless the alarm condition still applies.
|
||||
|
||||
|
||||
SPD (Serial Presence Detect) support
|
||||
------------------------------------
|
||||
|
||||
The driver also supports reading the SPD NVRAM on SPD5118 compatible chips.
|
||||
SPD data is available from the 'eeprom' binary attribute file attached to the
|
||||
chip's I2C device.
|
||||
+60
@@ -3549,6 +3549,15 @@ W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml
|
||||
F: drivers/spi/spi-axi-spi-engine.c
|
||||
|
||||
AXI PWM GENERATOR
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
L: linux-pwm@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
|
||||
F: drivers/pwm/pwm-axi-pwmgen.c
|
||||
|
||||
AXXIA I2C CONTROLLER
|
||||
M: Krzysztof Adamski <krzysztof.adamski@nokia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
@@ -5128,11 +5137,25 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
|
||||
F: sound/soc/codecs/cros_ec_codec.*
|
||||
|
||||
CHROMEOS EC CHARGE CONTROL
|
||||
M: Thomas Weißschuh <thomas@weissschuh.net>
|
||||
S: Maintained
|
||||
F: drivers/power/supply/cros_charge-control.c
|
||||
|
||||
CHROMEOS EC HARDWARE MONITORING
|
||||
M: Thomas Weißschuh <thomas@weissschuh.net>
|
||||
L: chrome-platform@lists.linux.dev
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/cros_ec_hwmon.rst
|
||||
F: drivers/hwmon/cros_ec_hwmon.c
|
||||
|
||||
CHROMEOS EC SUBDRIVERS
|
||||
M: Benson Leung <bleung@chromium.org>
|
||||
R: Guenter Roeck <groeck@chromium.org>
|
||||
L: chrome-platform@lists.linux.dev
|
||||
S: Maintained
|
||||
F: drivers/power/supply/cros_charge-control.c
|
||||
F: drivers/power/supply/cros_usbpd-charger.c
|
||||
N: cros_ec
|
||||
N: cros-ec
|
||||
@@ -15258,6 +15281,27 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
|
||||
F: drivers/video/backlight/mp3309c.c
|
||||
|
||||
MPS MP2891 DRIVER
|
||||
M: Noah Wang <noahwang.wang@outlook.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/mp2891.rst
|
||||
F: drivers/hwmon/pmbus/mp2891.c
|
||||
|
||||
MPS MP2993 DRIVER
|
||||
M: Noah Wang <noahwang.wang@outlook.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/mp2993.rst
|
||||
F: drivers/hwmon/pmbus/mp2993.c
|
||||
|
||||
MPS MP9941 DRIVER
|
||||
M: Noah Wang <noahwang.wang@outlook.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/mp9941.rst
|
||||
F: drivers/hwmon/pmbus/mp9941.c
|
||||
|
||||
MR800 AVERMEDIA USB FM RADIO DRIVER
|
||||
M: Alexey Klimov <klimov.linux@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
@@ -17354,6 +17398,14 @@ F: Documentation/driver-api/pci/p2pdma.rst
|
||||
F: drivers/pci/p2pdma.c
|
||||
F: include/linux/pci-p2pdma.h
|
||||
|
||||
PCI POWER CONTROL
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
|
||||
F: drivers/pci/pwrctl/*
|
||||
F: include/linux/pci-pwrctl.h
|
||||
|
||||
PCI SUBSYSTEM
|
||||
M: Bjorn Helgaas <bhelgaas@google.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
@@ -17894,6 +17946,14 @@ F: include/linux/pm_*
|
||||
F: include/linux/powercap.h
|
||||
F: kernel/configs/nopm.config
|
||||
|
||||
POWER SEQUENCING
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
|
||||
F: drivers/power/sequencing/
|
||||
F: include/linux/pwrseq/
|
||||
|
||||
POWER STATE COORDINATION INTERFACE (PSCI)
|
||||
M: Mark Rutland <mark.rutland@arm.com>
|
||||
M: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
|
||||
@@ -78,8 +78,6 @@ obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o
|
||||
obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o
|
||||
obj-$(CONFIG_IWMMXT) += iwmmxt.o
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
|
||||
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \
|
||||
perf_event_v7.o
|
||||
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
|
||||
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
|
||||
obj-$(CONFIG_VDSO) += vdso.o
|
||||
|
||||
+14
-27
@@ -5,6 +5,7 @@ config ARM64
|
||||
select ACPI_CCA_REQUIRED if ACPI
|
||||
select ACPI_GENERIC_GSI if ACPI
|
||||
select ACPI_GTDT if ACPI
|
||||
select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU
|
||||
select ACPI_IORT if ACPI
|
||||
select ACPI_REDUCED_HARDWARE_ONLY if ACPI
|
||||
select ACPI_MCFG if (ACPI && PCI)
|
||||
@@ -381,7 +382,7 @@ config BROKEN_GAS_INST
|
||||
|
||||
config BUILTIN_RETURN_ADDRESS_STRIPS_PAC
|
||||
bool
|
||||
# Clang's __builtin_return_adddress() strips the PAC since 12.0.0
|
||||
# Clang's __builtin_return_address() strips the PAC since 12.0.0
|
||||
# https://github.com/llvm/llvm-project/commit/2a96f47c5ffca84cd774ad402cacd137f4bf45e2
|
||||
default y if CC_IS_CLANG
|
||||
# GCC's __builtin_return_address() strips the PAC since 11.1.0,
|
||||
@@ -1067,15 +1068,21 @@ config ARM64_ERRATUM_3117295
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
bool
|
||||
|
||||
config ARM64_ERRATUM_3194386
|
||||
bool "Cortex-X4: 3194386: workaround for MSR SSBS not self-synchronizing"
|
||||
select ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
bool "Cortex-{A720,X4,X925}/Neoverse-V3: workaround for MSR SSBS not self-synchronizing"
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Cortex-X4 erratum 3194386.
|
||||
This option adds the workaround for the following errata:
|
||||
|
||||
* ARM Cortex-A710 erratam 3324338
|
||||
* ARM Cortex-A720 erratum 3456091
|
||||
* ARM Cortex-X2 erratum 3324338
|
||||
* ARM Cortex-X3 erratum 3324335
|
||||
* ARM Cortex-X4 erratum 3194386
|
||||
* ARM Cortex-X925 erratum 3324334
|
||||
* ARM Neoverse N2 erratum 3324339
|
||||
* ARM Neoverse V2 erratum 3324336
|
||||
* ARM Neoverse-V3 erratum 3312417
|
||||
|
||||
On affected cores "MSR SSBS, #0" instructions may not affect
|
||||
subsequent speculative instructions, which may permit unexepected
|
||||
@@ -1089,26 +1096,6 @@ config ARM64_ERRATUM_3194386
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_ERRATUM_3312417
|
||||
bool "Neoverse-V3: 3312417: workaround for MSR SSBS not self-synchronizing"
|
||||
select ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Neoverse-V3 erratum 3312417.
|
||||
|
||||
On affected cores "MSR SSBS, #0" instructions may not affect
|
||||
subsequent speculative instructions, which may permit unexepected
|
||||
speculative store bypassing.
|
||||
|
||||
Work around this problem by placing a speculation barrier after
|
||||
kernel changes to SSBS. The presence of the SSBS special-purpose
|
||||
register is hidden from hwcaps and EL0 reads of ID_AA64PFR1_EL1, such
|
||||
that userspace will use the PR_SPEC_STORE_BYPASS prctl to change
|
||||
SSBS.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
||||
config CAVIUM_ERRATUM_22375
|
||||
bool "Cavium erratum 22375, 24313"
|
||||
default y
|
||||
|
||||
@@ -119,6 +119,18 @@ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
|
||||
return acpi_cpu_get_madt_gicc(cpu)->uid;
|
||||
}
|
||||
|
||||
static inline int get_cpu_for_acpi_id(u32 uid)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (acpi_cpu_get_madt_gicc(cpu) &&
|
||||
uid == get_acpi_id_for_cpu(cpu))
|
||||
return cpu;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void arch_fix_phys_package_id(int num, u32 slot) { }
|
||||
void __init acpi_init_cpus(void);
|
||||
int apei_claim_sea(struct pt_regs *regs);
|
||||
|
||||
@@ -175,21 +175,6 @@ static inline bool gic_prio_masking_enabled(void)
|
||||
|
||||
static inline void gic_pmr_mask_irqs(void)
|
||||
{
|
||||
BUILD_BUG_ON(GICD_INT_DEF_PRI < (__GIC_PRIO_IRQOFF |
|
||||
GIC_PRIO_PSR_I_SET));
|
||||
BUILD_BUG_ON(GICD_INT_DEF_PRI >= GIC_PRIO_IRQON);
|
||||
/*
|
||||
* Need to make sure IRQON allows IRQs when SCR_EL3.FIQ is cleared
|
||||
* and non-secure PMR accesses are not subject to the shifts that
|
||||
* are applied to IRQ priorities
|
||||
*/
|
||||
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) >= GIC_PRIO_IRQON);
|
||||
/*
|
||||
* Same situation as above, but now we make sure that we can mask
|
||||
* regular interrupts.
|
||||
*/
|
||||
BUILD_BUG_ON((0x80 | (GICD_INT_DEF_PRI >> 1)) < (__GIC_PRIO_IRQOFF_NS |
|
||||
GIC_PRIO_PSR_I_SET));
|
||||
gic_write_pmr(GIC_PRIO_IRQOFF);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <linux/bug.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef __ASM_PMUV3_H
|
||||
#define __ASM_PMUV3_H
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_host.h>
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
@@ -59,7 +59,7 @@ cpucap_is_possible(const unsigned int cap)
|
||||
case ARM64_WORKAROUND_REPEAT_TLBI:
|
||||
return IS_ENABLED(CONFIG_ARM64_WORKAROUND_REPEAT_TLBI);
|
||||
case ARM64_WORKAROUND_SPECULATIVE_SSBS:
|
||||
return IS_ENABLED(CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS);
|
||||
return IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -588,14 +588,14 @@ static inline bool id_aa64pfr0_32bit_el1(u64 pfr0)
|
||||
{
|
||||
u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL1_SHIFT);
|
||||
|
||||
return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
|
||||
return val == ID_AA64PFR0_EL1_EL1_AARCH32;
|
||||
}
|
||||
|
||||
static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
|
||||
{
|
||||
u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL0_SHIFT);
|
||||
|
||||
return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
|
||||
return val == ID_AA64PFR0_EL1_EL0_AARCH32;
|
||||
}
|
||||
|
||||
static inline bool id_aa64pfr0_sve(u64 pfr0)
|
||||
|
||||
@@ -86,9 +86,12 @@
|
||||
#define ARM_CPU_PART_CORTEX_X2 0xD48
|
||||
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
|
||||
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
|
||||
#define ARM_CPU_PART_CORTEX_X3 0xD4E
|
||||
#define ARM_CPU_PART_NEOVERSE_V2 0xD4F
|
||||
#define ARM_CPU_PART_CORTEX_A720 0xD81
|
||||
#define ARM_CPU_PART_CORTEX_X4 0xD82
|
||||
#define ARM_CPU_PART_NEOVERSE_V3 0xD84
|
||||
#define ARM_CPU_PART_CORTEX_X925 0xD85
|
||||
|
||||
#define APM_CPU_PART_XGENE 0x000
|
||||
#define APM_CPU_VAR_POTENZA 0x00
|
||||
@@ -162,9 +165,12 @@
|
||||
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
|
||||
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
|
||||
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
|
||||
#define MIDR_CORTEX_X3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X3)
|
||||
#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
|
||||
#define MIDR_CORTEX_A720 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A720)
|
||||
#define MIDR_CORTEX_X4 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X4)
|
||||
#define MIDR_NEOVERSE_V3 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V3)
|
||||
#define MIDR_CORTEX_X925 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X925)
|
||||
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
||||
|
||||
@@ -121,6 +121,14 @@
|
||||
#define ESR_ELx_FSC_SECC (0x18)
|
||||
#define ESR_ELx_FSC_SECC_TTW(n) (0x1c + (n))
|
||||
|
||||
/* Status codes for individual page table levels */
|
||||
#define ESR_ELx_FSC_ACCESS_L(n) (ESR_ELx_FSC_ACCESS + n)
|
||||
#define ESR_ELx_FSC_PERM_L(n) (ESR_ELx_FSC_PERM + n)
|
||||
|
||||
#define ESR_ELx_FSC_FAULT_nL (0x2C)
|
||||
#define ESR_ELx_FSC_FAULT_L(n) (((n) < 0 ? ESR_ELx_FSC_FAULT_nL : \
|
||||
ESR_ELx_FSC_FAULT) + (n))
|
||||
|
||||
/* ISS field definitions for Data Aborts */
|
||||
#define ESR_ELx_ISV_SHIFT (24)
|
||||
#define ESR_ELx_ISV (UL(1) << ESR_ELx_ISV_SHIFT)
|
||||
@@ -388,20 +396,33 @@ static inline bool esr_is_data_abort(unsigned long esr)
|
||||
|
||||
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
|
||||
{
|
||||
/* Translation fault, level -1 */
|
||||
if ((esr & ESR_ELx_FSC) == 0b101011)
|
||||
return true;
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_FAULT_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(0)) ||
|
||||
(esr == ESR_ELx_FSC_FAULT_L(-1));
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_permission_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_PERM_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_PERM_L(0));
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
|
||||
esr = esr & ESR_ELx_FSC;
|
||||
|
||||
return (esr == ESR_ELx_FSC_ACCESS_L(3)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(2)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(1)) ||
|
||||
(esr == ESR_ELx_FSC_ACCESS_L(0));
|
||||
}
|
||||
|
||||
/* Indicate whether ESR.EC==0x1A is for an ERETAx instruction */
|
||||
|
||||
@@ -72,11 +72,11 @@ static inline void __cpu_set_tcr_t0sz(unsigned long t0sz)
|
||||
{
|
||||
unsigned long tcr = read_sysreg(tcr_el1);
|
||||
|
||||
if ((tcr & TCR_T0SZ_MASK) >> TCR_T0SZ_OFFSET == t0sz)
|
||||
if ((tcr & TCR_T0SZ_MASK) == t0sz)
|
||||
return;
|
||||
|
||||
tcr &= ~TCR_T0SZ_MASK;
|
||||
tcr |= t0sz << TCR_T0SZ_OFFSET;
|
||||
tcr |= t0sz;
|
||||
write_sysreg(tcr, tcr_el1);
|
||||
isb();
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ void mte_check_tfsr_el1(void);
|
||||
|
||||
static inline void mte_check_tfsr_entry(void)
|
||||
{
|
||||
if (!system_supports_mte())
|
||||
if (!kasan_hw_tags_enabled())
|
||||
return;
|
||||
|
||||
mte_check_tfsr_el1();
|
||||
@@ -190,7 +190,7 @@ static inline void mte_check_tfsr_entry(void)
|
||||
|
||||
static inline void mte_check_tfsr_exit(void)
|
||||
{
|
||||
if (!system_supports_mte())
|
||||
if (!kasan_hw_tags_enabled())
|
||||
return;
|
||||
|
||||
/*
|
||||
|
||||
@@ -21,35 +21,12 @@
|
||||
#define INIT_PSTATE_EL2 \
|
||||
(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL2h)
|
||||
|
||||
/*
|
||||
* PMR values used to mask/unmask interrupts.
|
||||
*
|
||||
* GIC priority masking works as follows: if an IRQ's priority is a higher value
|
||||
* than the value held in PMR, that IRQ is masked. Lowering the value of PMR
|
||||
* means masking more IRQs (or at least that the same IRQs remain masked).
|
||||
*
|
||||
* To mask interrupts, we clear the most significant bit of PMR.
|
||||
*
|
||||
* Some code sections either automatically switch back to PSR.I or explicitly
|
||||
* require to not use priority masking. If bit GIC_PRIO_PSR_I_SET is included
|
||||
* in the priority mask, it indicates that PSR.I should be set and
|
||||
* interrupt disabling temporarily does not rely on IRQ priorities.
|
||||
*/
|
||||
#define GIC_PRIO_IRQON 0xe0
|
||||
#define __GIC_PRIO_IRQOFF (GIC_PRIO_IRQON & ~0x80)
|
||||
#define __GIC_PRIO_IRQOFF_NS 0xa0
|
||||
#define GIC_PRIO_PSR_I_SET (1 << 4)
|
||||
#include <linux/irqchip/arm-gic-v3-prio.h>
|
||||
|
||||
#define GIC_PRIO_IRQOFF \
|
||||
({ \
|
||||
extern struct static_key_false gic_nonsecure_priorities;\
|
||||
u8 __prio = __GIC_PRIO_IRQOFF; \
|
||||
\
|
||||
if (static_branch_unlikely(&gic_nonsecure_priorities)) \
|
||||
__prio = __GIC_PRIO_IRQOFF_NS; \
|
||||
\
|
||||
__prio; \
|
||||
})
|
||||
#define GIC_PRIO_IRQON GICV3_PRIO_UNMASKED
|
||||
#define GIC_PRIO_IRQOFF GICV3_PRIO_IRQ
|
||||
|
||||
#define GIC_PRIO_PSR_I_SET GICV3_PRIO_PSR_I_SET
|
||||
|
||||
/* Additional SPSR bits not exposed in the UABI */
|
||||
#define PSR_MODE_THREAD_BIT (1 << 0)
|
||||
|
||||
@@ -25,22 +25,11 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <asm/percpu.h>
|
||||
|
||||
#include <linux/threads.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/thread_info.h>
|
||||
|
||||
DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
|
||||
/*
|
||||
* We don't use this_cpu_read(cpu_number) as that has implicit writes to
|
||||
* preempt_count, and associated (compiler) barriers, that we'd like to avoid
|
||||
* the expense of. If we're preemptible, the value can be stale at use anyway.
|
||||
* And we can't use this_cpu_ptr() either, as that winds up recursing back
|
||||
* here under CONFIG_DEBUG_PREEMPT=y.
|
||||
*/
|
||||
#define raw_smp_processor_id() (*raw_cpu_ptr(&cpu_number))
|
||||
#define raw_smp_processor_id() (current_thread_info()->cpu)
|
||||
|
||||
/*
|
||||
* Logical CPU mapping.
|
||||
|
||||
@@ -872,10 +872,6 @@
|
||||
/* Position the attr at the correct index */
|
||||
#define MAIR_ATTRIDX(attr, idx) ((attr) << ((idx) * 8))
|
||||
|
||||
/* id_aa64pfr0 */
|
||||
#define ID_AA64PFR0_EL1_ELx_64BIT_ONLY 0x1
|
||||
#define ID_AA64PFR0_EL1_ELx_32BIT_64BIT 0x2
|
||||
|
||||
/* id_aa64mmfr0 */
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN 0x0
|
||||
#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
|
||||
|
||||
@@ -46,7 +46,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
|
||||
obj-$(CONFIG_HARDLOCKUP_DETECTOR_PERF) += watchdog_hld.o
|
||||
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||
obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
obj-$(CONFIG_KGDB) += kgdb.o
|
||||
obj-$(CONFIG_EFI) += efi.o efi-rt-wrapper.o
|
||||
|
||||
+31
-98
@@ -30,6 +30,7 @@
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
#include <acpi/ghes.h>
|
||||
#include <acpi/processor.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/cpu_ops.h>
|
||||
#include <asm/daifflags.h>
|
||||
@@ -45,6 +46,7 @@ EXPORT_SYMBOL(acpi_pci_disabled);
|
||||
static bool param_acpi_off __initdata;
|
||||
static bool param_acpi_on __initdata;
|
||||
static bool param_acpi_force __initdata;
|
||||
static bool param_acpi_nospcr __initdata;
|
||||
|
||||
static int __init parse_acpi(char *arg)
|
||||
{
|
||||
@@ -58,6 +60,8 @@ static int __init parse_acpi(char *arg)
|
||||
param_acpi_on = true;
|
||||
else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
|
||||
param_acpi_force = true;
|
||||
else if (strcmp(arg, "nospcr") == 0) /* disable SPCR as default console */
|
||||
param_acpi_nospcr = true;
|
||||
else
|
||||
return -EINVAL; /* Core will print when we return error */
|
||||
|
||||
@@ -237,7 +241,20 @@ done:
|
||||
acpi_put_table(facs);
|
||||
}
|
||||
#endif
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable, true);
|
||||
|
||||
/*
|
||||
* For varying privacy and security reasons, sometimes need
|
||||
* to completely silence the serial console output, and only
|
||||
* enable it when needed.
|
||||
* But there are many existing systems that depend on this
|
||||
* behaviour, use acpi=nospcr to disable console in ACPI SPCR
|
||||
* table as default serial console.
|
||||
*/
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable,
|
||||
!param_acpi_nospcr);
|
||||
pr_info("Use ACPI SPCR as default console: %s\n",
|
||||
param_acpi_nospcr ? "No" : "Yes");
|
||||
|
||||
if (IS_ENABLED(CONFIG_ACPI_BGRT))
|
||||
acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
|
||||
}
|
||||
@@ -423,107 +440,23 @@ void arch_reserve_mem_area(acpi_physical_address addr, size_t size)
|
||||
memblock_mark_nomap(addr, size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_FFH
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
|
||||
int *pcpu)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
/* If an error code is passed in this stub can't fix it */
|
||||
if (*pcpu < 0) {
|
||||
pr_warn_once("Unable to map CPU to valid ID\n");
|
||||
return *pcpu;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_map_cpu);
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
int acpi_unmap_cpu(int cpu)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_ACPI_FFH */
|
||||
EXPORT_SYMBOL(acpi_unmap_cpu);
|
||||
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
|
||||
|
||||
@@ -34,17 +34,6 @@ int __init acpi_numa_get_nid(unsigned int cpu)
|
||||
return acpi_early_node_map[cpu];
|
||||
}
|
||||
|
||||
static inline int get_cpu_for_acpi_id(u32 uid)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
|
||||
if (uid == get_acpi_id_for_cpu(cpu))
|
||||
return cpu;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int __init acpi_parse_gicc_pxm(union acpi_subtable_headers *header,
|
||||
const unsigned long end)
|
||||
{
|
||||
|
||||
@@ -432,14 +432,17 @@ static const struct midr_range erratum_spec_unpriv_load_list[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
static const struct midr_range erratum_spec_ssbs_list[] = {
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3194386
|
||||
static const struct midr_range erratum_spec_ssbs_list[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A720),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X3),
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X4),
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3312417
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_X925),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V3),
|
||||
#endif
|
||||
MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2),
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
@@ -741,9 +744,9 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
||||
MIDR_FIXED(MIDR_CPU_VAR_REV(1,1), BIT(25)),
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3194386
|
||||
{
|
||||
.desc = "ARM errata 3194386, 3312417",
|
||||
.desc = "SSBS not fully self-synchronizing",
|
||||
.capability = ARM64_WORKAROUND_SPECULATIVE_SSBS,
|
||||
ERRATA_MIDR_RANGE_LIST(erratum_spec_ssbs_list),
|
||||
},
|
||||
|
||||
@@ -285,8 +285,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
|
||||
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_FP_SHIFT, 4, ID_AA64PFR0_EL1_FP_NI),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL3_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL2_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL1_SHIFT, 4, ID_AA64PFR0_EL1_ELx_64BIT_ONLY),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL0_SHIFT, 4, ID_AA64PFR0_EL1_ELx_64BIT_ONLY),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL1_SHIFT, 4, ID_AA64PFR0_EL1_EL1_IMP),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_EL1_EL0_SHIFT, 4, ID_AA64PFR0_EL1_EL0_IMP),
|
||||
ARM64_FTR_END,
|
||||
};
|
||||
|
||||
@@ -429,6 +429,7 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
|
||||
};
|
||||
|
||||
static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_ECBHB_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_TIDCP1_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_AFP_SHIFT, 4, 0),
|
||||
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR1_EL1_HCX_SHIFT, 4, 0),
|
||||
|
||||
@@ -105,11 +105,6 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors);
|
||||
KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
|
||||
KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
|
||||
|
||||
#ifdef CONFIG_ARM64_PSEUDO_NMI
|
||||
/* Static key checked in GIC_PRIO_IRQOFF. */
|
||||
KVM_NVHE_ALIAS(gic_nonsecure_priorities);
|
||||
#endif
|
||||
|
||||
/* EL2 exception handling */
|
||||
KVM_NVHE_ALIAS(__start___kvm_ex_table);
|
||||
KVM_NVHE_ALIAS(__stop___kvm_ex_table);
|
||||
|
||||
@@ -567,7 +567,7 @@ static enum mitigation_state spectre_v4_enable_hw_mitigation(void)
|
||||
* Mitigate this with an unconditional speculation barrier, as CPUs
|
||||
* could mis-speculate branches and bypass a conditional barrier.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ARM64_WORKAROUND_SPECULATIVE_SSBS))
|
||||
if (IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386))
|
||||
spec_bar();
|
||||
|
||||
return SPECTRE_MITIGATED;
|
||||
|
||||
@@ -40,7 +40,7 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
|
||||
{
|
||||
phys_addr_t pa_secondary_entry = __pa_symbol(secondary_entry);
|
||||
int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry);
|
||||
if (err)
|
||||
if (err && err != -EPERM)
|
||||
pr_err("failed to boot CPU%d (%d)\n", cpu, err);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -74,4 +74,5 @@ static void __exit reloc_test_exit(void)
|
||||
module_init(reloc_test_init);
|
||||
module_exit(reloc_test_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Relocation testing module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
+63
-10
@@ -57,8 +57,6 @@
|
||||
#undef CREATE_TRACE_POINTS
|
||||
#include <trace/hooks/debug.h>
|
||||
|
||||
DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
||||
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_raise);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_entry);
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(ipi_exit);
|
||||
@@ -137,7 +135,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
|
||||
/* Now bring the CPU into our world */
|
||||
ret = boot_secondary(cpu, idle);
|
||||
if (ret) {
|
||||
pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
|
||||
if (ret != -EPERM)
|
||||
pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -515,6 +514,59 @@ static int __init smp_cpu_setup(int cpu)
|
||||
static bool bootcpu_valid __initdata;
|
||||
static unsigned int cpu_count = 1;
|
||||
|
||||
int arch_register_cpu(int cpu)
|
||||
{
|
||||
acpi_handle acpi_handle = acpi_get_processor_handle(cpu);
|
||||
struct cpu *c = &per_cpu(cpu_devices, cpu);
|
||||
|
||||
if (!acpi_disabled && !acpi_handle &&
|
||||
IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
/* For now block anything that looks like physical CPU Hotplug */
|
||||
if (invalid_logical_cpuid(cpu) || !cpu_present(cpu)) {
|
||||
pr_err_once("Changing CPU present bit is not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Availability of the acpi handle is sufficient to establish
|
||||
* that _STA has aleady been checked. No need to recheck here.
|
||||
*/
|
||||
c->hotpluggable = arch_cpu_is_hotpluggable(cpu);
|
||||
|
||||
return register_cpu(c, cpu);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
void arch_unregister_cpu(int cpu)
|
||||
{
|
||||
acpi_handle acpi_handle = acpi_get_processor_handle(cpu);
|
||||
struct cpu *c = &per_cpu(cpu_devices, cpu);
|
||||
acpi_status status;
|
||||
unsigned long long sta;
|
||||
|
||||
if (!acpi_handle) {
|
||||
pr_err_once("Removing a CPU without associated ACPI handle\n");
|
||||
return;
|
||||
}
|
||||
|
||||
status = acpi_evaluate_integer(acpi_handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
/* For now do not allow anything that looks like physical CPU HP */
|
||||
if (cpu_present(cpu) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
|
||||
pr_err_once("Changing CPU present bit is not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
unregister_cpu(c);
|
||||
}
|
||||
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static struct acpi_madt_generic_interrupt cpu_madt_gicc[NR_CPUS];
|
||||
|
||||
@@ -535,7 +587,8 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
|
||||
{
|
||||
u64 hwid = processor->arm_mpidr;
|
||||
|
||||
if (!acpi_gicc_is_usable(processor)) {
|
||||
if (!(processor->flags &
|
||||
(ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE))) {
|
||||
pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid);
|
||||
return;
|
||||
}
|
||||
@@ -754,8 +807,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
*/
|
||||
for_each_possible_cpu(cpu) {
|
||||
|
||||
per_cpu(cpu_number, cpu) = cpu;
|
||||
|
||||
if (cpu == smp_processor_id())
|
||||
continue;
|
||||
|
||||
@@ -772,13 +823,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
|
||||
}
|
||||
}
|
||||
|
||||
static const char *ipi_types[NR_IPI] __tracepoint_string = {
|
||||
static const char *ipi_types[MAX_IPI] __tracepoint_string = {
|
||||
[IPI_RESCHEDULE] = "Rescheduling interrupts",
|
||||
[IPI_CALL_FUNC] = "Function call interrupts",
|
||||
[IPI_CPU_STOP] = "CPU stop interrupts",
|
||||
[IPI_CPU_CRASH_STOP] = "CPU stop (for crash dump) interrupts",
|
||||
[IPI_TIMER] = "Timer broadcast interrupts",
|
||||
[IPI_IRQ_WORK] = "IRQ work interrupts",
|
||||
[IPI_CPU_BACKTRACE] = "CPU backtrace interrupts",
|
||||
[IPI_KGDB_ROUNDUP] = "KGDB roundup interrupts",
|
||||
};
|
||||
|
||||
static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
|
||||
@@ -789,7 +842,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
||||
{
|
||||
unsigned int cpu, i;
|
||||
|
||||
for (i = 0; i < NR_IPI; i++) {
|
||||
for (i = 0; i < MAX_IPI; i++) {
|
||||
seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
|
||||
prec >= 4 ? " " : "");
|
||||
for_each_online_cpu(cpu)
|
||||
@@ -1034,12 +1087,12 @@ void __init set_smp_ipi_range(int ipi_base, int n)
|
||||
|
||||
if (ipi_should_be_nmi(i)) {
|
||||
err = request_percpu_nmi(ipi_base + i, ipi_handler,
|
||||
"IPI", &cpu_number);
|
||||
"IPI", &irq_stat);
|
||||
WARN(err, "Could not request IPI %d as NMI, err=%d\n",
|
||||
i, err);
|
||||
} else {
|
||||
err = request_percpu_irq(ipi_base + i, ipi_handler,
|
||||
"IPI", &cpu_number);
|
||||
"IPI", &irq_stat);
|
||||
WARN(err, "Could not request IPI %d as IRQ, err=%d\n",
|
||||
i, err);
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@
|
||||
* Supported by KVM
|
||||
*/
|
||||
#define PVM_ID_AA64PFR0_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL2), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL3), ID_AA64PFR0_EL1_ELx_64BIT_ONLY) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_RAS), ID_AA64PFR0_EL1_RAS_IMP) \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL0, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL1, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL2, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, EL3, IMP) | \
|
||||
SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, RAS, IMP) \
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
@@ -33,9 +33,9 @@ static void pvm_init_traps_aa64pfr0(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* Protected KVM does not support AArch32 guests. */
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL0),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL0_IMP);
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) != ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
/*
|
||||
* Linux guests assume support for floating-point and Advanced SIMD. Do
|
||||
|
||||
@@ -276,7 +276,7 @@ static bool pvm_access_id_aarch32(struct kvm_vcpu *vcpu,
|
||||
* of AArch32 feature id registers.
|
||||
*/
|
||||
BUILD_BUG_ON(FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_EL1),
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) > ID_AA64PFR0_EL1_ELx_64BIT_ONLY);
|
||||
PVM_ID_AA64PFR0_RESTRICT_UNSIGNED) > ID_AA64PFR0_EL1_EL1_IMP);
|
||||
|
||||
return pvm_access_raz_wi(vcpu, p, r);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <kvm/arm_pmu.h>
|
||||
#include <kvm/arm_vgic.h>
|
||||
#include <asm/arm_pmuv3.h>
|
||||
|
||||
#define PERF_ATTR_CFG1_COUNTER_64BIT BIT(0)
|
||||
|
||||
|
||||
@@ -35,6 +35,17 @@ EXPORT_PER_CPU_SYMBOL(processors);
|
||||
struct acpi_processor_errata errata __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(errata);
|
||||
|
||||
acpi_handle acpi_get_processor_handle(int cpu)
|
||||
{
|
||||
struct acpi_processor *pr;
|
||||
|
||||
pr = per_cpu(processors, cpu);
|
||||
if (pr)
|
||||
return pr->handle;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
||||
{
|
||||
u8 value1 = 0;
|
||||
@@ -183,20 +194,44 @@ static void __init acpi_pcc_cpufreq_init(void) {}
|
||||
#endif /* CONFIG_X86 */
|
||||
|
||||
/* Initialization */
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
static int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
||||
static DEFINE_PER_CPU(void *, processor_device_array);
|
||||
|
||||
static int acpi_processor_set_per_cpu(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
BUG_ON(pr->id >= nr_cpu_ids);
|
||||
|
||||
/*
|
||||
* Buggy BIOS check.
|
||||
* ACPI id of processors can be reported wrongly by the BIOS.
|
||||
* Don't trust it blindly
|
||||
*/
|
||||
if (per_cpu(processor_device_array, pr->id) != NULL &&
|
||||
per_cpu(processor_device_array, pr->id) != device) {
|
||||
dev_warn(&device->dev,
|
||||
"BIOS reported wrong ACPI id %d for the processor\n",
|
||||
pr->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* processor_device_array is not cleared on errors to allow buggy BIOS
|
||||
* checks.
|
||||
*/
|
||||
per_cpu(processor_device_array, pr->id) = device;
|
||||
per_cpu(processors, pr->id) = pr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
static int acpi_processor_hotadd_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
|
||||
if (invalid_phys_cpuid(pr->phys_id))
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
|
||||
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
|
||||
return -ENODEV;
|
||||
|
||||
cpu_maps_update_begin();
|
||||
cpus_write_lock();
|
||||
|
||||
@@ -204,19 +239,26 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = arch_register_cpu(pr->id);
|
||||
ret = acpi_processor_set_per_cpu(pr, device);
|
||||
if (ret) {
|
||||
acpi_unmap_cpu(pr->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = arch_register_cpu(pr->id);
|
||||
if (ret) {
|
||||
/* Leave the processor device array in place to detect buggy bios */
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
acpi_unmap_cpu(pr->id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* CPU got hot-added, but cpu_data is not initialized yet. Set a flag
|
||||
* to delay cpu_idle/throttling initialization and do it when the CPU
|
||||
* gets online for the first time.
|
||||
* CPU got hot-added, but cpu_data is not initialized yet. Do
|
||||
* cpu_idle/throttling initialization when the CPU gets online for
|
||||
* the first time.
|
||||
*/
|
||||
pr_info("CPU%d has been hot-added\n", pr->id);
|
||||
pr->flags.need_hotplug_init = 1;
|
||||
|
||||
out:
|
||||
cpus_write_unlock();
|
||||
@@ -224,7 +266,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
||||
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -239,6 +282,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||
acpi_status status = AE_OK;
|
||||
static int cpu0_initialized;
|
||||
unsigned long long value;
|
||||
int ret;
|
||||
|
||||
acpi_processor_errata();
|
||||
|
||||
@@ -315,19 +359,19 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||
}
|
||||
|
||||
/*
|
||||
* Extra Processor objects may be enumerated on MP systems with
|
||||
* less than the max # of CPUs. They should be ignored _iff
|
||||
* they are physically not present.
|
||||
*
|
||||
* NOTE: Even if the processor has a cpuid, it may not be present
|
||||
* because cpuid <-> apicid mapping is persistent now.
|
||||
* This code is not called unless we know the CPU is present and
|
||||
* enabled. The two paths are:
|
||||
* a) Initially present CPUs on architectures that do not defer
|
||||
* their arch_register_cpu() calls until this point.
|
||||
* b) Hotplugged CPUs (enabled bit in _STA has transitioned from not
|
||||
* enabled to enabled)
|
||||
*/
|
||||
if (invalid_logical_cpuid(pr->id) || !cpu_present(pr->id)) {
|
||||
int ret = acpi_processor_hotadd_init(pr);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (!get_cpu_device(pr->id))
|
||||
ret = acpi_processor_hotadd_init(pr, device);
|
||||
else
|
||||
ret = acpi_processor_set_per_cpu(pr, device);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* On some boxes several processors use the same processor bus id.
|
||||
@@ -372,8 +416,6 @@ static int acpi_processor_get_info(struct acpi_device *device)
|
||||
* (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
|
||||
* Such things have to be put in and set up by the processor driver's .probe().
|
||||
*/
|
||||
static DEFINE_PER_CPU(void *, processor_device_array);
|
||||
|
||||
static int acpi_processor_add(struct acpi_device *device,
|
||||
const struct acpi_device_id *id)
|
||||
{
|
||||
@@ -400,39 +442,17 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
|
||||
result = acpi_processor_get_info(device);
|
||||
if (result) /* Processor is not physically present or unavailable */
|
||||
return 0;
|
||||
|
||||
BUG_ON(pr->id >= nr_cpu_ids);
|
||||
|
||||
/*
|
||||
* Buggy BIOS check.
|
||||
* ACPI id of processors can be reported wrongly by the BIOS.
|
||||
* Don't trust it blindly
|
||||
*/
|
||||
if (per_cpu(processor_device_array, pr->id) != NULL &&
|
||||
per_cpu(processor_device_array, pr->id) != device) {
|
||||
dev_warn(&device->dev,
|
||||
"BIOS reported wrong ACPI id %d for the processor\n",
|
||||
pr->id);
|
||||
/* Give up, but do not abort the namespace scan. */
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* processor_device_array is not cleared on errors to allow buggy BIOS
|
||||
* checks.
|
||||
*/
|
||||
per_cpu(processor_device_array, pr->id) = device;
|
||||
per_cpu(processors, pr->id) = pr;
|
||||
goto err_clear_driver_data;
|
||||
|
||||
dev = get_cpu_device(pr->id);
|
||||
if (!dev) {
|
||||
result = -ENODEV;
|
||||
goto err;
|
||||
goto err_clear_per_cpu;
|
||||
}
|
||||
|
||||
result = acpi_bind_one(dev, device);
|
||||
if (result)
|
||||
goto err;
|
||||
goto err_clear_per_cpu;
|
||||
|
||||
pr->dev = dev;
|
||||
|
||||
@@ -443,10 +463,11 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
dev_err(dev, "Processor driver could not be attached\n");
|
||||
acpi_unbind_one(dev);
|
||||
|
||||
err:
|
||||
free_cpumask_var(pr->throttling.shared_cpu_map);
|
||||
device->driver_data = NULL;
|
||||
err_clear_per_cpu:
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
err_clear_driver_data:
|
||||
device->driver_data = NULL;
|
||||
free_cpumask_var(pr->throttling.shared_cpu_map);
|
||||
err_free_pr:
|
||||
kfree(pr);
|
||||
return result;
|
||||
@@ -454,7 +475,7 @@ static int acpi_processor_add(struct acpi_device *device,
|
||||
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
/* Removal */
|
||||
static void acpi_processor_remove(struct acpi_device *device)
|
||||
static void acpi_processor_post_eject(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_processor *pr;
|
||||
|
||||
@@ -476,10 +497,6 @@ static void acpi_processor_remove(struct acpi_device *device)
|
||||
device_release_driver(pr->dev);
|
||||
acpi_unbind_one(pr->dev);
|
||||
|
||||
/* Clean up. */
|
||||
per_cpu(processor_device_array, pr->id) = NULL;
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
|
||||
cpu_maps_update_begin();
|
||||
cpus_write_lock();
|
||||
|
||||
@@ -487,6 +504,10 @@ static void acpi_processor_remove(struct acpi_device *device)
|
||||
arch_unregister_cpu(pr->id);
|
||||
acpi_unmap_cpu(pr->id);
|
||||
|
||||
/* Clean up. */
|
||||
per_cpu(processor_device_array, pr->id) = NULL;
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
|
||||
cpus_write_unlock();
|
||||
cpu_maps_update_done();
|
||||
|
||||
@@ -622,7 +643,7 @@ static struct acpi_scan_handler processor_handler = {
|
||||
.ids = processor_device_ids,
|
||||
.attach = acpi_processor_add,
|
||||
#ifdef CONFIG_ACPI_HOTPLUG_CPU
|
||||
.detach = acpi_processor_remove,
|
||||
.post_eject = acpi_processor_post_eject,
|
||||
#endif
|
||||
.hotplug = {
|
||||
.enabled = true,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_ACPI_AGDI) += agdi.o
|
||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||
obj-$(CONFIG_ACPI_APMT) += apmt.o
|
||||
obj-$(CONFIG_ACPI_FFH) += ffh.o
|
||||
obj-$(CONFIG_ACPI_GTDT) += gtdt.o
|
||||
obj-$(CONFIG_ACPI_IORT) += iort.o
|
||||
obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_ARM_AMBA) += amba.o
|
||||
obj-y += dma.o init.o
|
||||
obj-y += thermal_cpufreq.o
|
||||
|
||||
@@ -27,11 +27,7 @@ static const struct acpi_device_id amba_id_list[] = {
|
||||
|
||||
static void amba_register_dummy_clk(void)
|
||||
{
|
||||
static struct clk *amba_dummy_clk;
|
||||
|
||||
/* If clock already registered */
|
||||
if (amba_dummy_clk)
|
||||
return;
|
||||
struct clk *amba_dummy_clk;
|
||||
|
||||
amba_dummy_clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, 0, 0);
|
||||
clk_register_clkdev(amba_dummy_clk, "apb_pclk", NULL);
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/psci.h>
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_IDLE
|
||||
|
||||
#include <acpi/processor.h>
|
||||
|
||||
#define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags))
|
||||
@@ -71,4 +68,3 @@ __cpuidle int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
|
||||
return CPU_PM_CPU_IDLE_ENTER_PARAM_RCU(psci_cpu_suspend_enter,
|
||||
lpi->index, state);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Implements ARM64 specific callbacks to support ACPI FFH Operation Region as
|
||||
* specified in https://developer.arm.com/docs/den0048/latest
|
||||
*/
|
||||
struct acpi_ffh_data {
|
||||
struct acpi_ffh_info info;
|
||||
void (*invoke_ffh_fn)(unsigned long a0, unsigned long a1,
|
||||
unsigned long a2, unsigned long a3,
|
||||
unsigned long a4, unsigned long a5,
|
||||
unsigned long a6, unsigned long a7,
|
||||
struct arm_smccc_res *args,
|
||||
struct arm_smccc_quirk *res);
|
||||
void (*invoke_ffh64_fn)(const struct arm_smccc_1_2_regs *args,
|
||||
struct arm_smccc_1_2_regs *res);
|
||||
};
|
||||
|
||||
int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
{
|
||||
enum arm_smccc_conduit conduit;
|
||||
struct acpi_ffh_data *ffh_ctxt;
|
||||
|
||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
conduit = arm_smccc_1_1_get_conduit();
|
||||
if (conduit == SMCCC_CONDUIT_NONE) {
|
||||
pr_err("%s: invalid SMCCC conduit\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_hvc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_hvc;
|
||||
}
|
||||
|
||||
memcpy(ffh_ctxt, handler_ctxt, sizeof(ffh_ctxt->info));
|
||||
|
||||
*region_ctxt = ffh_ctxt;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static bool acpi_ffh_smccc_owner_allowed(u32 fid)
|
||||
{
|
||||
int owner = ARM_SMCCC_OWNER_NUM(fid);
|
||||
|
||||
if (owner == ARM_SMCCC_OWNER_STANDARD ||
|
||||
owner == ARM_SMCCC_OWNER_SIP || owner == ARM_SMCCC_OWNER_OEM)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_context)
|
||||
{
|
||||
int ret = 0;
|
||||
struct acpi_ffh_data *ffh_ctxt = region_context;
|
||||
|
||||
if (ffh_ctxt->info.offset == 0) {
|
||||
/* SMC/HVC 32bit call */
|
||||
struct arm_smccc_res res;
|
||||
u32 a[8] = { 0 }, *ptr = (u32 *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(*ptr) || ARM_SMCCC_IS_64(*ptr) ||
|
||||
!acpi_ffh_smccc_owner_allowed(*ptr) ||
|
||||
ffh_ctxt->info.length > 32) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
int idx, len = ffh_ctxt->info.length >> 2;
|
||||
|
||||
for (idx = 0; idx < len; idx++)
|
||||
a[idx] = *(ptr + idx);
|
||||
|
||||
ffh_ctxt->invoke_ffh_fn(a[0], a[1], a[2], a[3], a[4],
|
||||
a[5], a[6], a[7], &res, NULL);
|
||||
memcpy(value, &res, sizeof(res));
|
||||
}
|
||||
|
||||
} else if (ffh_ctxt->info.offset == 1) {
|
||||
/* SMC/HVC 64bit call */
|
||||
struct arm_smccc_1_2_regs *r = (struct arm_smccc_1_2_regs *)value;
|
||||
|
||||
if (!ARM_SMCCC_IS_FAST_CALL(r->a0) || !ARM_SMCCC_IS_64(r->a0) ||
|
||||
!acpi_ffh_smccc_owner_allowed(r->a0) ||
|
||||
ffh_ctxt->info.length > sizeof(*r)) {
|
||||
ret = AE_ERROR;
|
||||
} else {
|
||||
ffh_ctxt->invoke_ffh64_fn(r, r);
|
||||
memcpy(value, r, ffh_ctxt->info.length);
|
||||
}
|
||||
} else {
|
||||
ret = AE_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -756,6 +756,21 @@ end:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(battery_hook_register);
|
||||
|
||||
static void devm_battery_hook_unregister(void *data)
|
||||
{
|
||||
struct acpi_battery_hook *hook = data;
|
||||
|
||||
battery_hook_unregister(hook);
|
||||
}
|
||||
|
||||
int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook)
|
||||
{
|
||||
battery_hook_register(hook);
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_battery_hook_unregister, hook);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_battery_hook_register);
|
||||
|
||||
/*
|
||||
* This function gets called right after the battery sysfs
|
||||
* attributes have been added, so that the drivers that
|
||||
|
||||
@@ -90,7 +90,8 @@ static int map_gicc_mpidr(struct acpi_subtable_header *entry,
|
||||
struct acpi_madt_generic_interrupt *gicc =
|
||||
container_of(entry, struct acpi_madt_generic_interrupt, header);
|
||||
|
||||
if (!acpi_gicc_is_usable(gicc))
|
||||
if (!(gicc->flags &
|
||||
(ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
|
||||
return -ENODEV;
|
||||
|
||||
/* device_declaration means Device object in DSDT, in the
|
||||
|
||||
@@ -33,7 +33,6 @@ MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_DESCRIPTION("ACPI Processor Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int acpi_processor_start(struct device *dev);
|
||||
static int acpi_processor_stop(struct device *dev);
|
||||
|
||||
static const struct acpi_device_id processor_device_ids[] = {
|
||||
@@ -47,7 +46,6 @@ static struct device_driver acpi_processor_driver = {
|
||||
.name = "processor",
|
||||
.bus = &cpu_subsys,
|
||||
.acpi_match_table = processor_device_ids,
|
||||
.probe = acpi_processor_start,
|
||||
.remove = acpi_processor_stop,
|
||||
};
|
||||
|
||||
@@ -115,12 +113,9 @@ static int acpi_soft_cpu_online(unsigned int cpu)
|
||||
* CPU got physically hotplugged and onlined for the first time:
|
||||
* Initialize missing things.
|
||||
*/
|
||||
if (pr->flags.need_hotplug_init) {
|
||||
if (!pr->flags.previously_online) {
|
||||
int ret;
|
||||
|
||||
pr_info("Will online and init hotplugged CPU: %d\n",
|
||||
pr->id);
|
||||
pr->flags.need_hotplug_init = 0;
|
||||
ret = __acpi_processor_start(device);
|
||||
WARN(ret, "Failed to start CPU: %d\n", pr->id);
|
||||
} else {
|
||||
@@ -167,9 +162,6 @@ static int __acpi_processor_start(struct acpi_device *device)
|
||||
if (!pr)
|
||||
return -ENODEV;
|
||||
|
||||
if (pr->flags.need_hotplug_init)
|
||||
return 0;
|
||||
|
||||
result = acpi_cppc_processor_probe(pr);
|
||||
if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS))
|
||||
dev_dbg(&device->dev, "CPPC data invalid or not present\n");
|
||||
@@ -185,32 +177,21 @@ static int __acpi_processor_start(struct acpi_device *device)
|
||||
|
||||
status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
|
||||
acpi_processor_notify, device);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return 0;
|
||||
if (!ACPI_SUCCESS(status)) {
|
||||
result = -ENODEV;
|
||||
goto err_thermal_exit;
|
||||
}
|
||||
pr->flags.previously_online = 1;
|
||||
|
||||
result = -ENODEV;
|
||||
return 0;
|
||||
|
||||
err_thermal_exit:
|
||||
acpi_processor_thermal_exit(pr, device);
|
||||
|
||||
err_power_exit:
|
||||
acpi_processor_power_exit(pr);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int acpi_processor_start(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(dev);
|
||||
int ret;
|
||||
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
/* Protect against concurrent CPU hotplug operations */
|
||||
cpu_hotplug_disable();
|
||||
ret = __acpi_processor_start(device);
|
||||
cpu_hotplug_enable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_processor_stop(struct device *dev)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(dev);
|
||||
@@ -279,9 +260,9 @@ static int __init acpi_processor_driver_init(void)
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
||||
"acpi/cpu-drv:online",
|
||||
acpi_soft_cpu_online, NULL);
|
||||
result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
|
||||
"acpi/cpu-drv:online",
|
||||
acpi_soft_cpu_online, NULL);
|
||||
if (result < 0)
|
||||
goto err;
|
||||
hp_online = result;
|
||||
|
||||
+39
-8
@@ -243,13 +243,17 @@ static int acpi_scan_try_to_offline(struct acpi_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_scan_check_and_detach(struct acpi_device *adev, void *check)
|
||||
#define ACPI_SCAN_CHECK_FLAG_STATUS BIT(0)
|
||||
#define ACPI_SCAN_CHECK_FLAG_EJECT BIT(1)
|
||||
|
||||
static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
uintptr_t flags = (uintptr_t)p;
|
||||
|
||||
acpi_dev_for_each_child_reverse(adev, acpi_scan_check_and_detach, check);
|
||||
acpi_dev_for_each_child_reverse(adev, acpi_scan_check_and_detach, p);
|
||||
|
||||
if (check) {
|
||||
if (flags & ACPI_SCAN_CHECK_FLAG_STATUS) {
|
||||
acpi_bus_get_status(adev);
|
||||
/*
|
||||
* Skip devices that are still there and take the enabled
|
||||
@@ -269,8 +273,6 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *check)
|
||||
if (handler) {
|
||||
if (handler->detach)
|
||||
handler->detach(adev);
|
||||
|
||||
adev->handler = NULL;
|
||||
} else {
|
||||
device_release_driver(&adev->dev);
|
||||
}
|
||||
@@ -280,6 +282,28 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *check)
|
||||
*/
|
||||
acpi_device_set_power(adev, ACPI_STATE_D3_COLD);
|
||||
adev->flags.initialized = false;
|
||||
|
||||
/* For eject this is deferred to acpi_bus_post_eject() */
|
||||
if (!(flags & ACPI_SCAN_CHECK_FLAG_EJECT)) {
|
||||
adev->handler = NULL;
|
||||
acpi_device_clear_enumerated(adev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_bus_post_eject(struct acpi_device *adev, void *not_used)
|
||||
{
|
||||
struct acpi_scan_handler *handler = adev->handler;
|
||||
|
||||
acpi_dev_for_each_child_reverse(adev, acpi_bus_post_eject, NULL);
|
||||
|
||||
if (handler) {
|
||||
if (handler->post_eject)
|
||||
handler->post_eject(adev);
|
||||
|
||||
adev->handler = NULL;
|
||||
}
|
||||
|
||||
acpi_device_clear_enumerated(adev);
|
||||
|
||||
return 0;
|
||||
@@ -287,7 +311,9 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *check)
|
||||
|
||||
static void acpi_scan_check_subtree(struct acpi_device *adev)
|
||||
{
|
||||
acpi_scan_check_and_detach(adev, (void *)true);
|
||||
uintptr_t flags = ACPI_SCAN_CHECK_FLAG_STATUS;
|
||||
|
||||
acpi_scan_check_and_detach(adev, (void *)flags);
|
||||
}
|
||||
|
||||
static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
@@ -295,6 +321,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
acpi_handle handle = device->handle;
|
||||
unsigned long long sta;
|
||||
acpi_status status;
|
||||
uintptr_t flags = ACPI_SCAN_CHECK_FLAG_EJECT;
|
||||
|
||||
if (device->handler && device->handler->hotplug.demand_offline) {
|
||||
if (!acpi_scan_is_offline(device, true))
|
||||
@@ -307,7 +334,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
|
||||
acpi_handle_debug(handle, "Ejecting\n");
|
||||
|
||||
acpi_bus_trim(device);
|
||||
acpi_scan_check_and_detach(device, (void *)flags);
|
||||
|
||||
acpi_evaluate_lck(handle, 0);
|
||||
/*
|
||||
@@ -330,6 +357,8 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
|
||||
} else if (sta & ACPI_STA_DEVICE_ENABLED) {
|
||||
acpi_handle_warn(handle,
|
||||
"Eject incomplete - status 0x%llx\n", sta);
|
||||
} else {
|
||||
acpi_bus_post_eject(device, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2596,7 +2625,9 @@ EXPORT_SYMBOL(acpi_bus_scan);
|
||||
*/
|
||||
void acpi_bus_trim(struct acpi_device *adev)
|
||||
{
|
||||
acpi_scan_check_and_detach(adev, NULL);
|
||||
uintptr_t flags = 0;
|
||||
|
||||
acpi_scan_check_and_detach(adev, (void *)flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_bus_trim);
|
||||
|
||||
|
||||
+11
-1
@@ -95,6 +95,7 @@ void unregister_cpu(struct cpu *cpu)
|
||||
{
|
||||
int logical_cpu = cpu->dev.id;
|
||||
|
||||
set_cpu_enabled(logical_cpu, false);
|
||||
unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
|
||||
|
||||
device_unregister(&cpu->dev);
|
||||
@@ -273,6 +274,13 @@ static ssize_t print_cpus_offline(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
|
||||
|
||||
static ssize_t print_cpus_enabled(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(cpu_enabled_mask));
|
||||
}
|
||||
static DEVICE_ATTR(enabled, 0444, print_cpus_enabled, NULL);
|
||||
|
||||
static ssize_t print_cpus_isolated(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -413,6 +421,7 @@ int register_cpu(struct cpu *cpu, int num)
|
||||
register_cpu_under_node(num, cpu_to_node(num));
|
||||
dev_pm_qos_expose_latency_limit(&cpu->dev,
|
||||
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
|
||||
set_cpu_enabled(num, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -494,6 +503,7 @@ static struct attribute *cpu_root_attrs[] = {
|
||||
&cpu_attrs[2].attr.attr,
|
||||
&dev_attr_kernel_max.attr,
|
||||
&dev_attr_offline.attr,
|
||||
&dev_attr_enabled.attr,
|
||||
&dev_attr_isolated.attr,
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
&dev_attr_nohz_full.attr,
|
||||
@@ -558,7 +568,7 @@ static void __init cpu_dev_register_generic(void)
|
||||
|
||||
for_each_present_cpu(i) {
|
||||
ret = arch_register_cpu(i);
|
||||
if (ret)
|
||||
if (ret && ret != -EPROBE_DEFER)
|
||||
pr_warn("register_cpu %d failed (%d)\n", i, ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ static int ts_nbus_probe(struct platform_device *pdev)
|
||||
state.duty_cycle = state.period;
|
||||
state.enabled = true;
|
||||
|
||||
ret = pwm_apply_state(pwm, &state);
|
||||
ret = pwm_apply_might_sleep(pwm, &state);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed to configure PWM\n");
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ static int tpm_bios_measurements_open(struct inode *inode,
|
||||
if (!err) {
|
||||
seq = file->private_data;
|
||||
seq->private = chip;
|
||||
} else {
|
||||
put_device(&chip->dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
@@ -318,6 +318,7 @@ static void tpm_tis_spi_remove(struct spi_device *dev)
|
||||
}
|
||||
|
||||
static const struct spi_device_id tpm_tis_spi_id[] = {
|
||||
{ "attpm20p", (unsigned long)tpm_tis_spi_probe },
|
||||
{ "st33htpm-spi", (unsigned long)tpm_tis_spi_probe },
|
||||
{ "slb9670", (unsigned long)tpm_tis_spi_probe },
|
||||
{ "tpm_tis_spi", (unsigned long)tpm_tis_spi_probe },
|
||||
|
||||
@@ -363,6 +363,43 @@ static int gdsc_disable(struct generic_pm_domain *domain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gdsc_set_hwmode(struct generic_pm_domain *domain, struct device *dev, bool mode)
|
||||
{
|
||||
struct gdsc *sc = domain_to_gdsc(domain);
|
||||
int ret;
|
||||
|
||||
ret = gdsc_hwctrl(sc, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Wait for the GDSC to go through a power down and
|
||||
* up cycle. If we poll the status register before the
|
||||
* power cycle is finished we might read incorrect values.
|
||||
*/
|
||||
udelay(1);
|
||||
|
||||
/*
|
||||
* When the GDSC is switched to HW mode, HW can disable the GDSC.
|
||||
* When the GDSC is switched back to SW mode, the GDSC will be enabled
|
||||
* again, hence we need to poll for GDSC to complete the power up.
|
||||
*/
|
||||
if (!mode)
|
||||
return gdsc_poll_status(sc, GDSC_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool gdsc_get_hwmode(struct generic_pm_domain *domain, struct device *dev)
|
||||
{
|
||||
struct gdsc *sc = domain_to_gdsc(domain);
|
||||
u32 val;
|
||||
|
||||
regmap_read(sc->regmap, sc->gdscr, &val);
|
||||
|
||||
return !!(val & HW_CONTROL_MASK);
|
||||
}
|
||||
|
||||
static int gdsc_init(struct gdsc *sc)
|
||||
{
|
||||
u32 mask, val;
|
||||
@@ -451,6 +488,10 @@ static int gdsc_init(struct gdsc *sc)
|
||||
sc->pd.power_off = gdsc_disable;
|
||||
if (!sc->pd.power_on)
|
||||
sc->pd.power_on = gdsc_enable;
|
||||
if (sc->flags & HW_CTRL_TRIGGER) {
|
||||
sc->pd.set_hwmode_dev = gdsc_set_hwmode;
|
||||
sc->pd.get_hwmode_dev = gdsc_get_hwmode;
|
||||
}
|
||||
|
||||
ret = pm_genpd_init(&sc->pd, NULL, !on);
|
||||
if (ret)
|
||||
|
||||
@@ -67,6 +67,7 @@ struct gdsc {
|
||||
#define ALWAYS_ON BIT(6)
|
||||
#define RETAIN_FF_ENABLE BIT(7)
|
||||
#define NO_RET_PERIPH BIT(8)
|
||||
#define HW_CTRL_TRIGGER BIT(9)
|
||||
struct reset_controller_dev *rcdev;
|
||||
unsigned int *resets;
|
||||
unsigned int reset_count;
|
||||
|
||||
@@ -236,7 +236,7 @@ static struct gdsc mvs0_gdsc = {
|
||||
.name = "mvs0_gdsc",
|
||||
},
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
.flags = HW_CTRL | RETAIN_FF_ENABLE,
|
||||
.flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
|
||||
};
|
||||
|
||||
static struct gdsc mvsc_gdsc = {
|
||||
|
||||
@@ -293,7 +293,7 @@ static struct gdsc mvs0_gdsc = {
|
||||
.pd = {
|
||||
.name = "mvs0_gdsc",
|
||||
},
|
||||
.flags = HW_CTRL,
|
||||
.flags = HW_CTRL_TRIGGER,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
};
|
||||
|
||||
@@ -302,7 +302,7 @@ static struct gdsc mvs1_gdsc = {
|
||||
.pd = {
|
||||
.name = "mvs1_gdsc",
|
||||
},
|
||||
.flags = HW_CTRL,
|
||||
.flags = HW_CTRL_TRIGGER,
|
||||
.pwrsts = PWRSTS_OFF_ON,
|
||||
};
|
||||
|
||||
|
||||
@@ -465,7 +465,7 @@ static int stm32_count_events_configure(struct counter_device *counter)
|
||||
ret = stm32_count_capture_configure(counter, event_node->channel, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
dier |= TIM_DIER_CC_IE(event_node->channel);
|
||||
dier |= TIM_DIER_CCxIE(event_node->channel + 1);
|
||||
break;
|
||||
default:
|
||||
/* should never reach this path */
|
||||
@@ -478,7 +478,7 @@ static int stm32_count_events_configure(struct counter_device *counter)
|
||||
|
||||
/* check for disabled capture events */
|
||||
for (i = 0 ; i < priv->nchannels; i++) {
|
||||
if (!(dier & TIM_DIER_CC_IE(i))) {
|
||||
if (!(dier & TIM_DIER_CCxIE(i + 1))) {
|
||||
ret = stm32_count_capture_configure(counter, i, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -131,4 +131,5 @@ static struct coreboot_driver cbmem_entry_driver = {
|
||||
module_coreboot_driver(cbmem_entry_driver);
|
||||
|
||||
MODULE_AUTHOR("Jack Rosenthal <jrosenth@chromium.org>");
|
||||
MODULE_DESCRIPTION("Driver for exporting CBMEM entries in sysfs");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -255,4 +255,5 @@ module_init(coreboot_table_driver_init);
|
||||
module_exit(coreboot_table_driver_exit);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("Module providing coreboot table access");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -97,4 +97,5 @@ static struct coreboot_driver framebuffer_driver = {
|
||||
module_coreboot_driver(framebuffer_driver);
|
||||
|
||||
MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
|
||||
MODULE_DESCRIPTION("Memory based framebuffer accessed through coreboot table");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1090,4 +1090,5 @@ module_init(gsmi_init);
|
||||
module_exit(gsmi_exit);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("EFI SMI interface for Google platforms");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -113,4 +113,5 @@ static struct coreboot_driver memconsole_driver = {
|
||||
module_coreboot_driver(memconsole_driver);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("Memory based BIOS console accessed through coreboot table");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -154,4 +154,5 @@ module_init(memconsole_x86_init);
|
||||
module_exit(memconsole_x86_exit);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("EBDA specific parts of the memory based BIOS console.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -50,4 +50,5 @@ void memconsole_exit(void)
|
||||
EXPORT_SYMBOL(memconsole_exit);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("Architecture-independent parts of the memory based BIOS console");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -323,4 +323,5 @@ static struct coreboot_driver vpd_driver = {
|
||||
module_coreboot_driver(vpd_driver);
|
||||
|
||||
MODULE_AUTHOR("Google, Inc.");
|
||||
MODULE_DESCRIPTION("Driver for exporting Vital Product Data content to sysfs");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
+43
-24
@@ -105,18 +105,6 @@ config SENSORS_AD7418
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ad7418.
|
||||
|
||||
config SENSORS_ADM1021
|
||||
tristate "Analog Devices ADM1021 and compatibles"
|
||||
depends on I2C
|
||||
depends on SENSORS_LM90=n
|
||||
help
|
||||
If you say yes here you get support for Analog Devices ADM1021
|
||||
and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
|
||||
Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adm1021.
|
||||
|
||||
config SENSORS_ADM1025
|
||||
tristate "Analog Devices ADM1025 and compatibles"
|
||||
depends on I2C
|
||||
@@ -506,6 +494,17 @@ config SENSORS_CORSAIR_PSU
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called corsair-psu.
|
||||
|
||||
config SENSORS_CROS_EC
|
||||
tristate "ChromeOS Embedded Controller sensors"
|
||||
depends on MFD_CROS_EC_DEV
|
||||
default MFD_CROS_EC_DEV
|
||||
help
|
||||
If you say yes here you get support for ChromeOS Embedded Controller
|
||||
sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called cros_ec_hwmon.
|
||||
|
||||
config SENSORS_DRIVETEMP
|
||||
tristate "Hard disk drives with temperature sensors"
|
||||
depends on SCSI && ATA
|
||||
@@ -1241,18 +1240,6 @@ config SENSORS_MAX6639
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6639.
|
||||
|
||||
config SENSORS_MAX6642
|
||||
tristate "Maxim MAX6642 sensor chip"
|
||||
depends on I2C
|
||||
depends on SENSORS_LM90=n
|
||||
help
|
||||
If you say yes here you get support for MAX6642 sensor chip.
|
||||
MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
|
||||
with Overtemperature Alarm from Maxim.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6642.
|
||||
|
||||
config SENSORS_MAX6650
|
||||
tristate "Maxim MAX6650 sensor chip"
|
||||
depends on I2C
|
||||
@@ -2127,6 +2114,7 @@ config SENSORS_ADS7871
|
||||
config SENSORS_AMC6821
|
||||
tristate "Texas Instruments AMC6821"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the Texas Instruments
|
||||
AMC6821 hardware monitoring chips.
|
||||
@@ -2181,6 +2169,37 @@ config SENSORS_INA3221
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ina3221.
|
||||
|
||||
config SENSORS_SPD5118
|
||||
tristate "SPD5118 Compliant Temperature Sensors"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for SPD5118 (JEDEC JESD300)
|
||||
compliant temperature sensors. Such sensors are found on DDR5 memory
|
||||
modules.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called spd5118.
|
||||
|
||||
config SENSORS_SPD5118_DETECT
|
||||
bool "Enable detect function"
|
||||
depends on SENSORS_SPD5118
|
||||
default (!DMI || !X86)
|
||||
help
|
||||
If enabled, the driver auto-detects if a chip in the SPD address
|
||||
range is compliant to the SPD51888 standard and auto-instantiates
|
||||
if that is the case. If disabled, SPD5118 compliant devices have
|
||||
to be instantiated by other means. On X86 systems with DMI support
|
||||
this will typically be done from DMI DDR detection code in the
|
||||
I2C SMBus subsystem. Devicetree based systems will instantiate
|
||||
attached devices if the DIMMs are listed in the devicetree file.
|
||||
|
||||
Disabling the detect function will speed up boot time and reduce
|
||||
the risk of mis-detecting SPD5118 compliant devices. However, it
|
||||
may result in missed DIMMs under some circumstances.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config SENSORS_TC74
|
||||
tristate "Microchip TC74"
|
||||
depends on I2C
|
||||
|
||||
@@ -31,7 +31,6 @@ obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
|
||||
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
|
||||
obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o
|
||||
obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o
|
||||
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
||||
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
||||
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
|
||||
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
|
||||
@@ -64,6 +63,7 @@ obj-$(CONFIG_SENSORS_CHIPCAP2) += chipcap2.o
|
||||
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
|
||||
obj-$(CONFIG_SENSORS_CORSAIR_CPRO) += corsair-cpro.o
|
||||
obj-$(CONFIG_SENSORS_CORSAIR_PSU) += corsair-psu.o
|
||||
obj-$(CONFIG_SENSORS_CROS_EC) += cros_ec_hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o
|
||||
@@ -154,7 +154,6 @@ obj-$(CONFIG_SENSORS_MAX31760) += max31760.o
|
||||
obj-$(CONFIG_SENSORS_MAX6620) += max6620.o
|
||||
obj-$(CONFIG_SENSORS_MAX6621) += max6621.o
|
||||
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
|
||||
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
|
||||
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
||||
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
|
||||
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
|
||||
@@ -207,6 +206,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
||||
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
|
||||
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
|
||||
obj-$(CONFIG_SENSORS_SPD5118) += spd5118.o
|
||||
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
|
||||
obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
|
||||
obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
|
||||
|
||||
@@ -230,8 +230,6 @@ static void ad7418_init_client(struct i2c_client *client)
|
||||
}
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ad7418_id[];
|
||||
|
||||
static int ad7418_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
@@ -252,10 +250,7 @@ static int ad7418_probe(struct i2c_client *client)
|
||||
|
||||
mutex_init(&data->lock);
|
||||
data->client = client;
|
||||
if (dev->of_node)
|
||||
data->type = (uintptr_t)of_device_get_match_data(dev);
|
||||
else
|
||||
data->type = i2c_match_id(ad7418_id, client)->driver_data;
|
||||
data->type = (uintptr_t)i2c_get_match_data(client);
|
||||
|
||||
switch (data->type) {
|
||||
case ad7416:
|
||||
|
||||
@@ -175,7 +175,7 @@ static ssize_t adc128_in_store(struct device *dev,
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* 10 mV LSB on limit registers */
|
||||
regval = clamp_val(DIV_ROUND_CLOSEST(val, 10), 0, 255);
|
||||
regval = DIV_ROUND_CLOSEST(clamp_val(val, 0, 2550), 10);
|
||||
data->in[index][nr] = regval << 4;
|
||||
reg = index == 1 ? ADC128_REG_IN_MIN(nr) : ADC128_REG_IN_MAX(nr);
|
||||
i2c_smbus_write_byte_data(data->client, reg, regval);
|
||||
@@ -213,7 +213,7 @@ static ssize_t adc128_temp_store(struct device *dev,
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
regval = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
|
||||
regval = DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
|
||||
data->temp[index] = regval << 1;
|
||||
i2c_smbus_write_byte_data(data->client,
|
||||
index == 1 ? ADC128_REG_TEMP_MAX
|
||||
|
||||
@@ -1,505 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
* monitoring
|
||||
* Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
|
||||
* Philip Edelbrock <phil@netroedge.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = {
|
||||
0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
|
||||
|
||||
enum chips {
|
||||
adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066 };
|
||||
|
||||
/* adm1021 constants specified below */
|
||||
|
||||
/* The adm1021 registers */
|
||||
/* Read-only */
|
||||
/* For nr in 0-1 */
|
||||
#define ADM1021_REG_TEMP(nr) (nr)
|
||||
#define ADM1021_REG_STATUS 0x02
|
||||
/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
|
||||
#define ADM1021_REG_MAN_ID 0xFE
|
||||
/* ADM1021 = 0x0X, ADM1023 = 0x3X */
|
||||
#define ADM1021_REG_DEV_ID 0xFF
|
||||
/* These use different addresses for reading/writing */
|
||||
#define ADM1021_REG_CONFIG_R 0x03
|
||||
#define ADM1021_REG_CONFIG_W 0x09
|
||||
#define ADM1021_REG_CONV_RATE_R 0x04
|
||||
#define ADM1021_REG_CONV_RATE_W 0x0A
|
||||
/* These are for the ADM1023's additional precision on the remote temp sensor */
|
||||
#define ADM1023_REG_REM_TEMP_PREC 0x10
|
||||
#define ADM1023_REG_REM_OFFSET 0x11
|
||||
#define ADM1023_REG_REM_OFFSET_PREC 0x12
|
||||
#define ADM1023_REG_REM_TOS_PREC 0x13
|
||||
#define ADM1023_REG_REM_THYST_PREC 0x14
|
||||
/* limits */
|
||||
/* For nr in 0-1 */
|
||||
#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr))
|
||||
#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr))
|
||||
#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr))
|
||||
#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr))
|
||||
/* write-only */
|
||||
#define ADM1021_REG_ONESHOT 0x0F
|
||||
|
||||
/* Initial values */
|
||||
|
||||
/*
|
||||
* Note: Even though I left the low and high limits named os and hyst,
|
||||
* they don't quite work like a thermostat the way the LM75 does. I.e.,
|
||||
* a lower temp than THYST actually triggers an alarm instead of
|
||||
* clearing it. Weird, ey? --Phil
|
||||
*/
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct adm1021_data {
|
||||
struct i2c_client *client;
|
||||
enum chips type;
|
||||
|
||||
const struct attribute_group *groups[3];
|
||||
|
||||
struct mutex update_lock;
|
||||
bool valid; /* true if following fields are valid */
|
||||
char low_power; /* !=0 if device in low power mode */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
int temp_max[2]; /* Register values */
|
||||
int temp_min[2];
|
||||
int temp[2];
|
||||
u8 alarms;
|
||||
/* Special values for ADM1023 only */
|
||||
u8 remote_temp_offset;
|
||||
u8 remote_temp_offset_prec;
|
||||
};
|
||||
|
||||
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
|
||||
static bool read_only;
|
||||
|
||||
static struct adm1021_data *adm1021_update_device(struct device *dev)
|
||||
{
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "Starting adm1021 update\n");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
data->temp[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TEMP(i));
|
||||
data->temp_max[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_TOS_R(i));
|
||||
if (data->type != lm84) {
|
||||
data->temp_min[i] = 1000 *
|
||||
(s8) i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_THYST_R(i));
|
||||
}
|
||||
}
|
||||
data->alarms = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_STATUS) & 0x7c;
|
||||
if (data->type == adm1023) {
|
||||
/*
|
||||
* The ADM1023 provides 3 extra bits of precision for
|
||||
* the remote sensor in extra registers.
|
||||
*/
|
||||
data->temp[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TEMP_PREC) >> 5);
|
||||
data->temp_max[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_TOS_PREC) >> 5);
|
||||
data->temp_min[1] += 125 * (i2c_smbus_read_byte_data(
|
||||
client, ADM1023_REG_REM_THYST_PREC) >> 5);
|
||||
data->remote_temp_offset =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET);
|
||||
data->remote_temp_offset_prec =
|
||||
i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_OFFSET_PREC);
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp[index]);
|
||||
}
|
||||
|
||||
static ssize_t temp_max_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp_max[index]);
|
||||
}
|
||||
|
||||
static ssize_t temp_min_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", data->temp_min[index]);
|
||||
}
|
||||
|
||||
static ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int index = to_sensor_dev_attr(attr)->index;
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
|
||||
}
|
||||
|
||||
static ssize_t alarms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
|
||||
static ssize_t temp_max_store(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
int reg_val, err;
|
||||
|
||||
err = kstrtol(buf, 10, &temp);
|
||||
if (err)
|
||||
return err;
|
||||
temp /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
reg_val = clamp_val(temp, -128, 127);
|
||||
data->temp_max[index] = reg_val * 1000;
|
||||
if (!read_only)
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
|
||||
reg_val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t temp_min_store(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long temp;
|
||||
int reg_val, err;
|
||||
|
||||
err = kstrtol(buf, 10, &temp);
|
||||
if (err)
|
||||
return err;
|
||||
temp /= 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
reg_val = clamp_val(temp, -128, 127);
|
||||
data->temp_min[index] = reg_val * 1000;
|
||||
if (!read_only)
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
|
||||
reg_val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t low_power_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct adm1021_data *data = adm1021_update_device(dev);
|
||||
return sprintf(buf, "%d\n", data->low_power);
|
||||
}
|
||||
|
||||
static ssize_t low_power_store(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adm1021_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
char low_power;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &val);
|
||||
if (err)
|
||||
return err;
|
||||
low_power = val != 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (low_power != data->low_power) {
|
||||
int config = i2c_smbus_read_byte_data(
|
||||
client, ADM1021_REG_CONFIG_R);
|
||||
data->low_power = low_power;
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
|
||||
(config & 0xBF) | (low_power << 6));
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 6);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 5);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, 4);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, alarm, 3);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 2);
|
||||
|
||||
static DEVICE_ATTR_RO(alarms);
|
||||
static DEVICE_ATTR_RW(low_power);
|
||||
|
||||
static struct attribute *adm1021_attributes[] = {
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&dev_attr_alarms.attr,
|
||||
&dev_attr_low_power.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1021_group = {
|
||||
.attrs = adm1021_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *adm1021_min_attributes[] = {
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adm1021_min_group = {
|
||||
.attrs = adm1021_min_attributes,
|
||||
};
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int adm1021_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
const char *type_name;
|
||||
int reg, conv_rate, status, config, man_id, dev_id;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
pr_debug("detect failed, smbus byte data not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
|
||||
conv_rate = i2c_smbus_read_byte_data(client,
|
||||
ADM1021_REG_CONV_RATE_R);
|
||||
config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
|
||||
|
||||
/* Check unused bits */
|
||||
if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
|
||||
pr_debug("detect failed, chip not detected!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Determine the chip type. */
|
||||
man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
|
||||
dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
|
||||
|
||||
if (man_id < 0 || dev_id < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (man_id == 0x4d && dev_id == 0x01) {
|
||||
/*
|
||||
* dev_id 0x01 matches MAX6680, MAX6695, MAX6696, and possibly
|
||||
* others. Read register which is unsupported on MAX1617 but
|
||||
* exists on all those chips and compare with the dev_id
|
||||
* register. If it matches, it may be a MAX1617A.
|
||||
*/
|
||||
reg = i2c_smbus_read_byte_data(client,
|
||||
ADM1023_REG_REM_TEMP_PREC);
|
||||
if (reg != dev_id)
|
||||
return -ENODEV;
|
||||
type_name = "max1617a";
|
||||
} else if (man_id == 0x41) {
|
||||
if ((dev_id & 0xF0) == 0x30)
|
||||
type_name = "adm1023";
|
||||
else if ((dev_id & 0xF0) == 0x00)
|
||||
type_name = "adm1021";
|
||||
else
|
||||
return -ENODEV;
|
||||
} else if (man_id == 0x49)
|
||||
type_name = "thmc10";
|
||||
else if (man_id == 0x23)
|
||||
type_name = "gl523sm";
|
||||
else if (man_id == 0x54)
|
||||
type_name = "mc1066";
|
||||
else {
|
||||
int lte, rte, lhi, rhi, llo, rlo;
|
||||
|
||||
/* extra checks for LM84 and MAX1617 to avoid misdetections */
|
||||
|
||||
llo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(0));
|
||||
rlo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(1));
|
||||
|
||||
/* fail if any of the additional register reads failed */
|
||||
if (llo < 0 || rlo < 0)
|
||||
return -ENODEV;
|
||||
|
||||
lte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(0));
|
||||
rte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(1));
|
||||
lhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(0));
|
||||
rhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(1));
|
||||
|
||||
/*
|
||||
* Fail for negative temperatures and negative high limits.
|
||||
* This check also catches read errors on the tested registers.
|
||||
*/
|
||||
if ((s8)lte < 0 || (s8)rte < 0 || (s8)lhi < 0 || (s8)rhi < 0)
|
||||
return -ENODEV;
|
||||
|
||||
/* fail if all registers hold the same value */
|
||||
if (lte == rte && lte == lhi && lte == rhi && lte == llo
|
||||
&& lte == rlo)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* LM84 Mfr ID is in a different place,
|
||||
* and it has more unused bits. Registers at 0xfe and 0xff
|
||||
* are undefined and return the most recently read value,
|
||||
* here the value of the configuration register.
|
||||
*/
|
||||
if (conv_rate == 0x00
|
||||
&& man_id == config && dev_id == config
|
||||
&& (config & 0x7F) == 0x00
|
||||
&& (status & 0xAB) == 0x00) {
|
||||
type_name = "lm84";
|
||||
} else {
|
||||
if ((config & 0x3f) || (status & 0x03))
|
||||
return -ENODEV;
|
||||
/* fail if low limits are larger than high limits */
|
||||
if ((s8)llo > lhi || (s8)rlo > rhi)
|
||||
return -ENODEV;
|
||||
type_name = "max1617";
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
|
||||
type_name, i2c_adapter_id(adapter), client->addr);
|
||||
strscpy(info->type, type_name, I2C_NAME_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adm1021_init_client(struct i2c_client *client)
|
||||
{
|
||||
/* Enable ADC and disable suspend mode */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
|
||||
i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
|
||||
/* Set Conversion rate to 1/sec (this can be tinkered with) */
|
||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1021_id[];
|
||||
|
||||
static int adm1021_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct adm1021_data *data;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct adm1021_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
data->type = i2c_match_id(adm1021_id, client)->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the ADM1021 chip */
|
||||
if (data->type != lm84 && !read_only)
|
||||
adm1021_init_client(client);
|
||||
|
||||
data->groups[0] = &adm1021_group;
|
||||
if (data->type != lm84)
|
||||
data->groups[1] = &adm1021_min_group;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, data->groups);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1021_id[] = {
|
||||
{ "adm1021", adm1021 },
|
||||
{ "adm1023", adm1023 },
|
||||
{ "max1617", max1617 },
|
||||
{ "max1617a", max1617a },
|
||||
{ "thmc10", thmc10 },
|
||||
{ "lm84", lm84 },
|
||||
{ "gl523sm", gl523sm },
|
||||
{ "mc1066", mc1066 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adm1021_id);
|
||||
|
||||
static struct i2c_driver adm1021_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "adm1021",
|
||||
},
|
||||
.probe = adm1021_probe,
|
||||
.id_table = adm1021_id,
|
||||
.detect = adm1021_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(adm1021_driver);
|
||||
|
||||
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
|
||||
"Philip Edelbrock <phil@netroedge.com>");
|
||||
MODULE_DESCRIPTION("adm1021 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param(read_only, bool, 0);
|
||||
MODULE_PARM_DESC(read_only, "Don't set any values, read only mode");
|
||||
@@ -1021,8 +1021,6 @@ static void adm1031_init_client(struct i2c_client *client)
|
||||
data->update_interval = update_intervals[i];
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adm1031_id[];
|
||||
|
||||
static int adm1031_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
@@ -1035,7 +1033,7 @@ static int adm1031_probe(struct i2c_client *client)
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
data->chip_type = i2c_match_id(adm1031_id, client)->driver_data;
|
||||
data->chip_type = (uintptr_t)i2c_get_match_data(client);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
if (data->chip_type == adm1030)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user