mirror of https://github.com/torvalds/linux.git
ACPI updates for 6.17-rc1
- Printing the address in acpi_ex_trace_point() is either incorrect
during early kernel boot or not really useful later when pathnames
resolve properly, so stop doing it (Mario Limonciello)
- Address several minor issues in the legacy ACPI proc interface (Andy
Shevchenko)
- Fix acpi_object union initialization in the ACPI processor driver to
avoid using memory that contains leftover data (Sebastian Ott)
- Make the ACPI processor perflib driver take the initial _PPC limit
into account as appropriate (Jiayi Li)
- Fix message formatting in the ACPI processor throttling driver and
in the ACPI PCI link driver (Colin Ian King)
- Clean up general ACPI PM domain handling (Rafael Wysocki)
- Fix iomem-related sparse warnings in the APEI EINJ driver (Zaid
Alali, Tony Luck)
- Add EINJv2 error injection support to the APEI EINJ driver (Zaid
Alali)
- Fix memory corruption in error_type_set() in the APEI EINJ driver (Dan
Carpenter)
- Fix less than zero comparison on a size_t variable in the APEI EINJ
driver (Colin Ian King)
- Fix check and iounmap of an uninitialized pointer in the APEI EINJ
driver (Colin Ian King)
- Add TAINT_MACHINE_CHECK to the GHES panic path in APEI to improve
diagnostics and post-mortem analysis (Breno Leitao)
- Update APEI reviewer records and other ACPI-related information in
MAINTAINERS as well as the contact information in the ACPI ABI
documentation (Rafael Wysocki)
- Fix the handling of synchronous uncorrected memory errors in APEI
(Shuai Xue)
- Remove an AudioDSP-related ID from the ACPI LPSS driver (Andy
Shevchenko)
- Replace sprintf()/scnprintf() with sysfs_emit() in the ACPI fan
driver and update a debug message in fan_get_state_acpi4() (Eslam
Khafagy, Abdelrahman Fekry, Sumeet Pawnikar)
- Add Intel Wildcat Lake support to the ACPI DPTF driver (Srinivas
Pandruvada)
- Add more debug information regarding failing firmware updates to the
ACPI pfr_update driver (Chen Yu)
- Reduce the verbosity of the ACPI PRM (platform runtime mechanism)
driver to avoid user confusion (Zhu Qiyu)
- Replace sprintf() with sysfs_emit() in the ACPI TAD (time and alarm
device) driver (Sukrut Heroorkar)
- Enable CONFIG_ACPI_DEBUG by default to make it easier to get ACPI
debug messages from OEM platforms (Mario Limonciello)
- Fix parent device references in ASL examples in the ACPI
documentation and fix spelling and style in the gpio-properties
documentation in firmware-guide (Andy Shevchenko)
- Fix typos in ACPI documentation and comments (Bjorn Helgaas)
-----BEGIN PGP SIGNATURE-----
iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmh/qzQSHHJqd0Byand5
c29ja2kubmV0AAoJEO5fvZ0v1OO1wMgH/2vklBeGYjxSIIn0qfiv/SnSW5B1jEE4
5vDuCpafesm7tZtwFB9v2mRf/8SvmJey2jfYgGnBMBlTW0JUP8eCVpRASvx1SCGH
QwJFN3GCs3IjIvT2KlXeDIyQdfITIl3SNTXwTFl/ezYT0vo7VBeFtofeL9szaxlP
rM1KeLE7lksjY9djT8PRwxOQ+EzuJ8uUGXYcHu797u0x5XB9ZiBDuKqngDicQONI
DaRU3zXwOKPkQhldFN+9HPsDPvm7+8f1yiOEWzLnToTDggQDH4x2wdXJOOpAogoN
qIYBIZG90drNj9USsWZvp0q/fT3OVbuHLuruDGieOCYUByBYddY9WHM=
=5h+J
-----END PGP SIGNATURE-----
Merge tag 'acpi-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"These update APEI (new EINJv2 error injection, assorted fixes), fix
the ACPI processor driver, update the legacy ACPI /proc interface
(multiple assorted fixes of minor issues) and several assorted ACPI
drivers (minor fixes and cleanups):
- Printing the address in acpi_ex_trace_point() is either incorrect
during early kernel boot or not really useful later when pathnames
resolve properly, so stop doing it (Mario Limonciello)
- Address several minor issues in the legacy ACPI proc interface
(Andy Shevchenko)
- Fix acpi_object union initialization in the ACPI processor driver
to avoid using memory that contains leftover data (Sebastian Ott)
- Make the ACPI processor perflib driver take the initial _PPC limit
into account as appropriate (Jiayi Li)
- Fix message formatting in the ACPI processor throttling driver and
in the ACPI PCI link driver (Colin Ian King)
- Clean up general ACPI PM domain handling (Rafael Wysocki)
- Fix iomem-related sparse warnings in the APEI EINJ driver (Zaid
Alali, Tony Luck)
- Add EINJv2 error injection support to the APEI EINJ driver (Zaid
Alali)
- Fix memory corruption in error_type_set() in the APEI EINJ driver
(Dan Carpenter)
- Fix less than zero comparison on a size_t variable in the APEI EINJ
driver (Colin Ian King)
- Fix check and iounmap of an uninitialized pointer in the APEI EINJ
driver (Colin Ian King)
- Add TAINT_MACHINE_CHECK to the GHES panic path in APEI to improve
diagnostics and post-mortem analysis (Breno Leitao)
- Update APEI reviewer records and other ACPI-related information in
MAINTAINERS as well as the contact information in the ACPI ABI
documentation (Rafael Wysocki)
- Fix the handling of synchronous uncorrected memory errors in APEI
(Shuai Xue)
- Remove an AudioDSP-related ID from the ACPI LPSS driver (Andy
Shevchenko)
- Replace sprintf()/scnprintf() with sysfs_emit() in the ACPI fan
driver and update a debug message in fan_get_state_acpi4() (Eslam
Khafagy, Abdelrahman Fekry, Sumeet Pawnikar)
- Add Intel Wildcat Lake support to the ACPI DPTF driver (Srinivas
Pandruvada)
- Add more debug information regarding failing firmware updates to
the ACPI pfr_update driver (Chen Yu)
- Reduce the verbosity of the ACPI PRM (platform runtime mechanism)
driver to avoid user confusion (Zhu Qiyu)
- Replace sprintf() with sysfs_emit() in the ACPI TAD (time and alarm
device) driver (Sukrut Heroorkar)
- Enable CONFIG_ACPI_DEBUG by default to make it easier to get ACPI
debug messages from OEM platforms (Mario Limonciello)
- Fix parent device references in ASL examples in the ACPI
documentation and fix spelling and style in the gpio-properties
documentation in firmware-guide (Andy Shevchenko)
- Fix typos in ACPI documentation and comments (Bjorn Helgaas)"
* tag 'acpi-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (39 commits)
ACPI: Fix typos
ACPI/PCI: Remove space before newline
ACPI: processor: throttling: Remove space before newline
ACPI: processor: perflib: Fix initial _PPC limit application
ACPI/PNP: Use my kernel.org address in MAINTAINERS and ABI docs
ACPI: TAD: Replace sprintf() with sysfs_emit()
ACPI: APEI: handle synchronous exceptions in task work
ACPI: APEI: send SIGBUS to current task if synchronous memory error not recovered
ACPI: APEI: MAINTAINERS: Update reviewers for APEI
Documentation: ACPI: Fix parent device references
ACPI: fan: Update debug message in fan_get_state_acpi4()
ACPI: PRM: Reduce unnecessary printing to avoid user confusion
ACPI: fan: Replace sprintf() with sysfs_emit()
ACPI: APEI: EINJ: Fix trigger actions
ACPI: processor: fix acpi_object initialization
ACPI: APEI: GHES: add TAINT_MACHINE_CHECK on GHES panic path
ACPI: LPSS: Remove AudioDSP related ID
Documentation: firmware-guide: gpio-properties: Spelling and style fixes
ACPI: fan: Replace sprintf()/scnprintf() with sysfs_emit() in show() functions
ACPI: PM: Set .detach in acpi_general_pm_domain definition
...
This commit is contained in:
commit
9bbf8e17d8
|
|
@ -1,6 +1,6 @@
|
||||||
What: /sys/bus/acpi/devices/.../path
|
What: /sys/bus/acpi/devices/.../path
|
||||||
Date: December 2006
|
Date: December 2006
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute indicates the full path of ACPI namespace
|
This attribute indicates the full path of ACPI namespace
|
||||||
object associated with the device object. For example,
|
object associated with the device object. For example,
|
||||||
|
|
@ -12,7 +12,7 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../modalias
|
What: /sys/bus/acpi/devices/.../modalias
|
||||||
Date: July 2007
|
Date: July 2007
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute indicates the PNP IDs of the device object.
|
This attribute indicates the PNP IDs of the device object.
|
||||||
That is acpi:HHHHHHHH:[CCCCCCC:]. Where each HHHHHHHH or
|
That is acpi:HHHHHHHH:[CCCCCCC:]. Where each HHHHHHHH or
|
||||||
|
|
@ -20,7 +20,7 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../hid
|
What: /sys/bus/acpi/devices/.../hid
|
||||||
Date: April 2005
|
Date: April 2005
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute indicates the hardware ID (_HID) of the
|
This attribute indicates the hardware ID (_HID) of the
|
||||||
device object. For example, PNP0103.
|
device object. For example, PNP0103.
|
||||||
|
|
@ -29,14 +29,14 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../description
|
What: /sys/bus/acpi/devices/.../description
|
||||||
Date: October 2012
|
Date: October 2012
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute contains the output of the device object's
|
This attribute contains the output of the device object's
|
||||||
_STR control method, if present.
|
_STR control method, if present.
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../adr
|
What: /sys/bus/acpi/devices/.../adr
|
||||||
Date: October 2012
|
Date: October 2012
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute contains the output of the device object's
|
This attribute contains the output of the device object's
|
||||||
_ADR control method, which is present for ACPI device
|
_ADR control method, which is present for ACPI device
|
||||||
|
|
@ -45,14 +45,14 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../uid
|
What: /sys/bus/acpi/devices/.../uid
|
||||||
Date: October 2012
|
Date: October 2012
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
This attribute contains the output of the device object's
|
This attribute contains the output of the device object's
|
||||||
_UID control method, if present.
|
_UID control method, if present.
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../eject
|
What: /sys/bus/acpi/devices/.../eject
|
||||||
Date: December 2006
|
Date: December 2006
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
Writing 1 to this attribute will trigger hot removal of
|
Writing 1 to this attribute will trigger hot removal of
|
||||||
this device object. This file exists for every device
|
this device object. This file exists for every device
|
||||||
|
|
@ -60,7 +60,7 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../status
|
What: /sys/bus/acpi/devices/.../status
|
||||||
Date: Jan, 2014
|
Date: Jan, 2014
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
(RO) Returns the ACPI device status: enabled, disabled or
|
(RO) Returns the ACPI device status: enabled, disabled or
|
||||||
functioning or present, if the method _STA is present.
|
functioning or present, if the method _STA is present.
|
||||||
|
|
@ -90,7 +90,7 @@ Description:
|
||||||
|
|
||||||
What: /sys/bus/acpi/devices/.../hrv
|
What: /sys/bus/acpi/devices/.../hrv
|
||||||
Date: Apr, 2016
|
Date: Apr, 2016
|
||||||
Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
|
Contact: Rafael J. Wysocki <rafael@kernel.org>
|
||||||
Description:
|
Description:
|
||||||
(RO) Allows users to read the hardware version of non-PCI
|
(RO) Allows users to read the hardware version of non-PCI
|
||||||
hardware, if the _HRV control method is present. It is mostly
|
hardware, if the _HRV control method is present. It is mostly
|
||||||
|
|
|
||||||
|
|
@ -108,15 +108,15 @@ Description:
|
||||||
number of a "General Purpose Events" (GPE).
|
number of a "General Purpose Events" (GPE).
|
||||||
|
|
||||||
A GPE vectors to a specified handler in AML, which
|
A GPE vectors to a specified handler in AML, which
|
||||||
can do a anything the BIOS writer wants from
|
can do anything the BIOS writer wants from
|
||||||
OS context. GPE 0x12, for example, would vector
|
OS context. GPE 0x12, for example, would vector
|
||||||
to a level or edge handler called _L12 or _E12.
|
to a level or edge handler called _L12 or _E12.
|
||||||
The handler may do its business and return.
|
The handler may do its business and return.
|
||||||
Or the handler may send send a Notify event
|
Or the handler may send a Notify event
|
||||||
to a Linux device driver registered on an ACPI device,
|
to a Linux device driver registered on an ACPI device,
|
||||||
such as a battery, or a processor.
|
such as a battery, or a processor.
|
||||||
|
|
||||||
To figure out where all the SCI's are coming from,
|
To figure out where all the SCIs are coming from,
|
||||||
/sys/firmware/acpi/interrupts contains a file listing
|
/sys/firmware/acpi/interrupts contains a file listing
|
||||||
every possible source, and the count of how many
|
every possible source, and the count of how many
|
||||||
times it has triggered::
|
times it has triggered::
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,9 @@ The following files belong to it:
|
||||||
0x00000200 Platform Correctable
|
0x00000200 Platform Correctable
|
||||||
0x00000400 Platform Uncorrectable non-fatal
|
0x00000400 Platform Uncorrectable non-fatal
|
||||||
0x00000800 Platform Uncorrectable fatal
|
0x00000800 Platform Uncorrectable fatal
|
||||||
|
V2_0x00000001 EINJV2 Processor Error
|
||||||
|
V2_0x00000002 EINJV2 Memory Error
|
||||||
|
V2_0x00000004 EINJV2 PCI Express Error
|
||||||
================ ===================================
|
================ ===================================
|
||||||
|
|
||||||
The format of the file contents are as above, except present are only
|
The format of the file contents are as above, except present are only
|
||||||
|
|
@ -88,6 +91,8 @@ The following files belong to it:
|
||||||
Memory address and mask valid (param1 and param2).
|
Memory address and mask valid (param1 and param2).
|
||||||
Bit 2
|
Bit 2
|
||||||
PCIe (seg,bus,dev,fn) valid (see param4 below).
|
PCIe (seg,bus,dev,fn) valid (see param4 below).
|
||||||
|
Bit 3
|
||||||
|
EINJv2 extension structure is valid
|
||||||
|
|
||||||
If set to zero, legacy behavior is mimicked where the type of
|
If set to zero, legacy behavior is mimicked where the type of
|
||||||
injection specifies just one bit set, and param1 is multiplexed.
|
injection specifies just one bit set, and param1 is multiplexed.
|
||||||
|
|
@ -122,6 +127,13 @@ The following files belong to it:
|
||||||
this actually works depends on what operations the BIOS actually
|
this actually works depends on what operations the BIOS actually
|
||||||
includes in the trigger phase.
|
includes in the trigger phase.
|
||||||
|
|
||||||
|
- component_id0 .. component_idN, component_syndrome0 .. component_syndromeN
|
||||||
|
|
||||||
|
These files are used to set the "Component Array" field
|
||||||
|
of the EINJv2 Extension Structure. Each holds a 128-bit
|
||||||
|
hex value. Writing just a newline to any of these files
|
||||||
|
sets an invalid (all-ones) value.
|
||||||
|
|
||||||
CXL error types are supported from ACPI 6.5 onwards (given a CXL port
|
CXL error types are supported from ACPI 6.5 onwards (given a CXL port
|
||||||
is present). The EINJ user interface for CXL error types is at
|
is present). The EINJ user interface for CXL error types is at
|
||||||
<debugfs mount point>/cxl. The following files belong to it:
|
<debugfs mount point>/cxl. The following files belong to it:
|
||||||
|
|
@ -194,6 +206,27 @@ An error injection example::
|
||||||
# echo 0x8 > error_type # Choose correctable memory error
|
# echo 0x8 > error_type # Choose correctable memory error
|
||||||
# echo 1 > error_inject # Inject now
|
# echo 1 > error_inject # Inject now
|
||||||
|
|
||||||
|
An EINJv2 error injection example::
|
||||||
|
|
||||||
|
# cd /sys/kernel/debug/apei/einj
|
||||||
|
# cat available_error_type # See which errors can be injected
|
||||||
|
0x00000002 Processor Uncorrectable non-fatal
|
||||||
|
0x00000008 Memory Correctable
|
||||||
|
0x00000010 Memory Uncorrectable non-fatal
|
||||||
|
V2_0x00000001 EINJV2 Processor Error
|
||||||
|
V2_0x00000002 EINJV2 Memory Error
|
||||||
|
|
||||||
|
# echo 0x12345000 > param1 # Set memory address for injection
|
||||||
|
# echo 0xfffffffffffff000 > param2 # Range - anywhere in this page
|
||||||
|
# echo 0x1 > component_id0 # First device ID
|
||||||
|
# echo 0x4 > component_syndrome0 # First error syndrome
|
||||||
|
# echo 0x2 > component_id1 # Second device ID
|
||||||
|
# echo 0x4 > component_syndrome1 # Second error syndrome
|
||||||
|
# echo '' > component_id2 # Mark id2 invalid to terminate list
|
||||||
|
# echo V2_0x2 > error_type # Choose EINJv2 memory error
|
||||||
|
# echo 0xa > flags # set flags to indicate EINJv2
|
||||||
|
# echo 1 > error_inject # Inject now
|
||||||
|
|
||||||
You should see something like this in dmesg::
|
You should see something like this in dmesg::
|
||||||
|
|
||||||
[22715.830801] EDAC sbridge MC3: HANDLING MCE MEMORY ERROR
|
[22715.830801] EDAC sbridge MC3: HANDLING MCE MEMORY ERROR
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ _DSD Device Properties Related to GPIO
|
||||||
|
|
||||||
With the release of ACPI 5.1, the _DSD configuration object finally
|
With the release of ACPI 5.1, the _DSD configuration object finally
|
||||||
allows names to be given to GPIOs (and other things as well) returned
|
allows names to be given to GPIOs (and other things as well) returned
|
||||||
by _CRS. Previously, we were only able to use an integer index to find
|
by _CRS. Previously we were only able to use an integer index to find
|
||||||
the corresponding GPIO, which is pretty error prone (it depends on
|
the corresponding GPIO, which is pretty error prone (it depends on
|
||||||
the _CRS output ordering, for example).
|
the _CRS output ordering, for example).
|
||||||
|
|
||||||
|
|
@ -49,11 +49,11 @@ index
|
||||||
pin
|
pin
|
||||||
Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
|
Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
|
||||||
active_low
|
active_low
|
||||||
If 1, the GPIO is marked as active_low.
|
If 1, the GPIO is marked as active-low.
|
||||||
|
|
||||||
Since ACPI GpioIo() resource does not have a field saying whether it is
|
Since ACPI GpioIo() resource does not have a field saying whether it is
|
||||||
active low or high, the "active_low" argument can be used here. Setting
|
active-low or active-high, the "active_low" argument can be used here.
|
||||||
it to 1 marks the GPIO as active low.
|
Setting it to 1 marks the GPIO as active-low.
|
||||||
|
|
||||||
Note, active_low in _DSD does not make sense for GpioInt() resource and
|
Note, active_low in _DSD does not make sense for GpioInt() resource and
|
||||||
must be 0. GpioInt() resource has its own means of defining it.
|
must be 0. GpioInt() resource has its own means of defining it.
|
||||||
|
|
@ -92,8 +92,8 @@ and polarity settings. The table below shows the expectations:
|
||||||
| | Low | as low, assuming active |
|
| | Low | as low, assuming active |
|
||||||
+-------------+-------------+-----------------------------------------------+
|
+-------------+-------------+-----------------------------------------------+
|
||||||
|
|
||||||
That said, for our above example the both GPIOs, since the bias setting
|
That said, for our above example, since the bias setting is explicit and
|
||||||
is explicit and _DSD is present, will be treated as active with a high
|
_DSD is present, both GPIOs will be treated as active with a high
|
||||||
polarity and Linux will configure the pins in this state until a driver
|
polarity and Linux will configure the pins in this state until a driver
|
||||||
reprograms them differently.
|
reprograms them differently.
|
||||||
|
|
||||||
|
|
@ -231,8 +231,8 @@ In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
|
||||||
available to the driver can be used to identify the device and that is supposed
|
available to the driver can be used to identify the device and that is supposed
|
||||||
to be sufficient to determine the meaning and purpose of all of the GPIO lines
|
to be sufficient to determine the meaning and purpose of all of the GPIO lines
|
||||||
listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
|
listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
|
||||||
the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
|
the driver is supposed to know what to use from the GpioIo()/GpioInt() resources
|
||||||
once it has identified the device. Having done that, it can simply assign names
|
for once it has identified the device. Having done that, it can simply assign names
|
||||||
to the GPIO lines it is going to use and provide the GPIO subsystem with a
|
to the GPIO lines it is going to use and provide the GPIO subsystem with a
|
||||||
mapping between those names and the ACPI GPIO resources corresponding to them.
|
mapping between those names and the ACPI GPIO resources corresponding to them.
|
||||||
|
|
||||||
|
|
@ -252,9 +252,9 @@ question would look like this::
|
||||||
static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
|
static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
|
||||||
|
|
||||||
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
|
static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
|
||||||
{ "reset-gpios", &reset_gpio, 1 },
|
{ "reset-gpios", &reset_gpio, 1 },
|
||||||
{ "shutdown-gpios", &shutdown_gpio, 1 },
|
{ "shutdown-gpios", &shutdown_gpio, 1 },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
Next, the mapping table needs to be passed as the second argument to
|
Next, the mapping table needs to be passed as the second argument to
|
||||||
|
|
@ -270,7 +270,7 @@ Using the _CRS fallback
|
||||||
|
|
||||||
If a device does not have _DSD or the driver does not create ACPI GPIO
|
If a device does not have _DSD or the driver does not create ACPI GPIO
|
||||||
mapping, the Linux GPIO framework refuses to return any GPIOs. This is
|
mapping, the Linux GPIO framework refuses to return any GPIOs. This is
|
||||||
because the driver does not know what it actually gets. For example if we
|
because the driver does not know what it actually gets. For example, if we
|
||||||
have a device like below::
|
have a device like below::
|
||||||
|
|
||||||
Device (BTH)
|
Device (BTH)
|
||||||
|
|
@ -292,7 +292,7 @@ The driver might expect to get the right GPIO when it does::
|
||||||
...error handling...
|
...error handling...
|
||||||
|
|
||||||
but since there is no way to know the mapping between "reset" and
|
but since there is no way to know the mapping between "reset" and
|
||||||
the GpioIo() in _CRS desc will hold ERR_PTR(-ENOENT).
|
the GpioIo() in _CRS the desc will hold ERR_PTR(-ENOENT).
|
||||||
|
|
||||||
The driver author can solve this by passing the mapping explicitly
|
The driver author can solve this by passing the mapping explicitly
|
||||||
(this is the recommended way and it's documented in the above chapter).
|
(this is the recommended way and it's documented in the above chapter).
|
||||||
|
|
@ -318,15 +318,15 @@ Case 1::
|
||||||
desc = gpiod_get(dev, "non-null-connection-id", flags);
|
desc = gpiod_get(dev, "non-null-connection-id", flags);
|
||||||
desc = gpiod_get_index(dev, "non-null-connection-id", index, flags);
|
desc = gpiod_get_index(dev, "non-null-connection-id", index, flags);
|
||||||
|
|
||||||
|
Case 1 assumes that corresponding ACPI device description must have
|
||||||
|
defined device properties and will prevent from getting any GPIO resources
|
||||||
|
otherwise.
|
||||||
|
|
||||||
Case 2::
|
Case 2::
|
||||||
|
|
||||||
desc = gpiod_get(dev, NULL, flags);
|
desc = gpiod_get(dev, NULL, flags);
|
||||||
desc = gpiod_get_index(dev, NULL, index, flags);
|
desc = gpiod_get_index(dev, NULL, index, flags);
|
||||||
|
|
||||||
Case 1 assumes that corresponding ACPI device description must have
|
|
||||||
defined device properties and will prevent to getting any GPIO resources
|
|
||||||
otherwise.
|
|
||||||
|
|
||||||
Case 2 explicitly tells GPIO core to look for resources in _CRS.
|
Case 2 explicitly tells GPIO core to look for resources in _CRS.
|
||||||
|
|
||||||
Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
|
Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Consider this topology::
|
||||||
| | | 0x70 |--CH01--> i2c client B (0x50)
|
| | | 0x70 |--CH01--> i2c client B (0x50)
|
||||||
+------+ +------+
|
+------+ +------+
|
||||||
|
|
||||||
which corresponds to the following ASL::
|
which corresponds to the following ASL (in the scope of \_SB)::
|
||||||
|
|
||||||
Device (SMB1)
|
Device (SMB1)
|
||||||
{
|
{
|
||||||
|
|
@ -24,7 +24,7 @@ which corresponds to the following ASL::
|
||||||
Name (_HID, ...)
|
Name (_HID, ...)
|
||||||
Name (_CRS, ResourceTemplate () {
|
Name (_CRS, ResourceTemplate () {
|
||||||
I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
|
I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
|
||||||
AddressingMode7Bit, "^SMB1", 0x00,
|
AddressingMode7Bit, "\\_SB.SMB1", 0x00,
|
||||||
ResourceConsumer,,)
|
ResourceConsumer,,)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ which corresponds to the following ASL::
|
||||||
Name (_HID, ...)
|
Name (_HID, ...)
|
||||||
Name (_CRS, ResourceTemplate () {
|
Name (_CRS, ResourceTemplate () {
|
||||||
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
|
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
|
||||||
AddressingMode7Bit, "^CH00", 0x00,
|
AddressingMode7Bit, "\\_SB.SMB1.CH00", 0x00,
|
||||||
ResourceConsumer,,)
|
ResourceConsumer,,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ which corresponds to the following ASL::
|
||||||
Name (_HID, ...)
|
Name (_HID, ...)
|
||||||
Name (_CRS, ResourceTemplate () {
|
Name (_CRS, ResourceTemplate () {
|
||||||
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
|
I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
|
||||||
AddressingMode7Bit, "^CH01", 0x00,
|
AddressingMode7Bit, "\\_SB.SMB1.CH01", 0x00,
|
||||||
ResourceConsumer,,)
|
ResourceConsumer,,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,16 +306,17 @@ F: tools/power/acpi/
|
||||||
|
|
||||||
ACPI APEI
|
ACPI APEI
|
||||||
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||||
R: Len Brown <lenb@kernel.org>
|
|
||||||
R: James Morse <james.morse@arm.com>
|
|
||||||
R: Tony Luck <tony.luck@intel.com>
|
R: Tony Luck <tony.luck@intel.com>
|
||||||
R: Borislav Petkov <bp@alien8.de>
|
R: Borislav Petkov <bp@alien8.de>
|
||||||
|
R: Hanjun Guo <guohanjun@huawei.com>
|
||||||
|
R: Mauro Carvalho Chehab <mchehab@kernel.org>
|
||||||
|
R: Shuai Xue <xueshuai@linux.alibaba.com>
|
||||||
L: linux-acpi@vger.kernel.org
|
L: linux-acpi@vger.kernel.org
|
||||||
F: drivers/acpi/apei/
|
F: drivers/acpi/apei/
|
||||||
|
|
||||||
ACPI COMPONENT ARCHITECTURE (ACPICA)
|
ACPI COMPONENT ARCHITECTURE (ACPICA)
|
||||||
|
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||||
M: Robert Moore <robert.moore@intel.com>
|
M: Robert Moore <robert.moore@intel.com>
|
||||||
M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
|
|
||||||
L: linux-acpi@vger.kernel.org
|
L: linux-acpi@vger.kernel.org
|
||||||
L: acpica-devel@lists.linux.dev
|
L: acpica-devel@lists.linux.dev
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
@ -19768,7 +19769,7 @@ F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.yaml
|
||||||
F: drivers/iio/magnetometer/rm3100*
|
F: drivers/iio/magnetometer/rm3100*
|
||||||
|
|
||||||
PNP SUPPORT
|
PNP SUPPORT
|
||||||
M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
|
M: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||||
L: linux-acpi@vger.kernel.org
|
L: linux-acpi@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/pnp/
|
F: drivers/pnp/
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,7 @@ config ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD
|
||||||
|
|
||||||
config ACPI_DEBUG
|
config ACPI_DEBUG
|
||||||
bool "Debug Statements"
|
bool "Debug Statements"
|
||||||
|
default y
|
||||||
help
|
help
|
||||||
The ACPI subsystem can produce debug output. Saying Y enables this
|
The ACPI subsystem can produce debug output. Saying Y enables this
|
||||||
output and increases the kernel size by around 50K.
|
output and increases the kernel size by around 50K.
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ static inline int acpi_processor_hotadd_init(struct acpi_processor *pr,
|
||||||
|
|
||||||
static int acpi_processor_get_info(struct acpi_device *device)
|
static int acpi_processor_get_info(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
union acpi_object object = { 0 };
|
union acpi_object object = { .processor = { 0 } };
|
||||||
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
|
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
|
||||||
struct acpi_processor *pr = acpi_driver_data(device);
|
struct acpi_processor *pr = acpi_driver_data(device);
|
||||||
int device_declaration = 0;
|
int device_declaration = 0;
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ static ssize_t time_show(struct device *dev, struct device_attribute *attr,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
|
return sysfs_emit(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
|
||||||
rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
|
rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
|
||||||
rt.tz, rt.daylight);
|
rt.tz, rt.daylight);
|
||||||
}
|
}
|
||||||
|
|
@ -428,7 +428,7 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
|
||||||
{
|
{
|
||||||
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
|
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return sprintf(buf, "0x%02X\n", dd->capabilities);
|
return sysfs_emit(buf, "0x%02X\n", dd->capabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_RO(caps);
|
static DEVICE_ATTR_RO(caps);
|
||||||
|
|
|
||||||
|
|
@ -136,9 +136,9 @@ acpi_ex_trace_point(acpi_trace_event_type type,
|
||||||
|
|
||||||
if (pathname) {
|
if (pathname) {
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
|
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
|
||||||
"%s %s [0x%p:%s] execution.\n",
|
"%s %s [%s] execution.\n",
|
||||||
acpi_ex_get_trace_event_name(type),
|
acpi_ex_get_trace_event_name(type),
|
||||||
begin ? "Begin" : "End", aml, pathname));
|
begin ? "Begin" : "End", pathname));
|
||||||
} else {
|
} else {
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
|
ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
|
||||||
"%s %s [0x%p] execution.\n",
|
"%s %s [0x%p] execution.\n",
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus)
|
||||||
|
|
||||||
int apei_osc_setup(void);
|
int apei_osc_setup(void);
|
||||||
|
|
||||||
int einj_get_available_error_type(u32 *type);
|
int einj_get_available_error_type(u32 *type, int einj_action);
|
||||||
int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
|
int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
|
||||||
u64 param4);
|
u64 param4);
|
||||||
int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@
|
||||||
#define SLEEP_UNIT_MAX 5000 /* 5ms */
|
#define SLEEP_UNIT_MAX 5000 /* 5ms */
|
||||||
/* Firmware should respond within 1 seconds */
|
/* Firmware should respond within 1 seconds */
|
||||||
#define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC)
|
#define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC)
|
||||||
|
#define COMPONENT_LEN 16
|
||||||
|
#define ACPI65_EINJV2_SUPP BIT(30)
|
||||||
#define ACPI5_VENDOR_BIT BIT(31)
|
#define ACPI5_VENDOR_BIT BIT(31)
|
||||||
#define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \
|
#define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \
|
||||||
ACPI_EINJ_MEMORY_UNCORRECTABLE | \
|
ACPI_EINJ_MEMORY_UNCORRECTABLE | \
|
||||||
|
|
@ -49,6 +51,28 @@
|
||||||
*/
|
*/
|
||||||
static int acpi5;
|
static int acpi5;
|
||||||
|
|
||||||
|
struct syndrome_array {
|
||||||
|
union {
|
||||||
|
u8 acpi_id[COMPONENT_LEN];
|
||||||
|
u8 device_id[COMPONENT_LEN];
|
||||||
|
u8 pcie_sbdf[COMPONENT_LEN];
|
||||||
|
u8 vendor_id[COMPONENT_LEN];
|
||||||
|
} comp_id;
|
||||||
|
union {
|
||||||
|
u8 proc_synd[COMPONENT_LEN];
|
||||||
|
u8 mem_synd[COMPONENT_LEN];
|
||||||
|
u8 pcie_synd[COMPONENT_LEN];
|
||||||
|
u8 vendor_synd[COMPONENT_LEN];
|
||||||
|
} comp_synd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct einjv2_extension_struct {
|
||||||
|
u32 length;
|
||||||
|
u16 revision;
|
||||||
|
u16 component_arr_count;
|
||||||
|
struct syndrome_array component_arr[] __counted_by(component_arr_count);
|
||||||
|
};
|
||||||
|
|
||||||
struct set_error_type_with_address {
|
struct set_error_type_with_address {
|
||||||
u32 type;
|
u32 type;
|
||||||
u32 vendor_extension;
|
u32 vendor_extension;
|
||||||
|
|
@ -57,11 +81,13 @@ struct set_error_type_with_address {
|
||||||
u64 memory_address;
|
u64 memory_address;
|
||||||
u64 memory_address_range;
|
u64 memory_address_range;
|
||||||
u32 pcie_sbdf;
|
u32 pcie_sbdf;
|
||||||
|
struct einjv2_extension_struct einjv2_struct;
|
||||||
};
|
};
|
||||||
enum {
|
enum {
|
||||||
SETWA_FLAGS_APICID = 1,
|
SETWA_FLAGS_APICID = 1,
|
||||||
SETWA_FLAGS_MEM = 2,
|
SETWA_FLAGS_MEM = 2,
|
||||||
SETWA_FLAGS_PCIE_SBDF = 4,
|
SETWA_FLAGS_PCIE_SBDF = 4,
|
||||||
|
SETWA_FLAGS_EINJV2 = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -83,7 +109,10 @@ static struct debugfs_blob_wrapper vendor_blob;
|
||||||
static struct debugfs_blob_wrapper vendor_errors;
|
static struct debugfs_blob_wrapper vendor_errors;
|
||||||
static char vendor_dev[64];
|
static char vendor_dev[64];
|
||||||
|
|
||||||
|
static u32 max_nr_components;
|
||||||
static u32 available_error_type;
|
static u32 available_error_type;
|
||||||
|
static u32 available_error_type_v2;
|
||||||
|
static struct syndrome_array *syndrome_data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
|
* Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
|
||||||
|
|
@ -151,7 +180,9 @@ static DEFINE_MUTEX(einj_mutex);
|
||||||
*/
|
*/
|
||||||
bool einj_initialized __ro_after_init;
|
bool einj_initialized __ro_after_init;
|
||||||
|
|
||||||
static void *einj_param;
|
static void __iomem *einj_param;
|
||||||
|
static u32 v5param_size;
|
||||||
|
static bool is_v2;
|
||||||
|
|
||||||
static void einj_exec_ctx_init(struct apei_exec_context *ctx)
|
static void einj_exec_ctx_init(struct apei_exec_context *ctx)
|
||||||
{
|
{
|
||||||
|
|
@ -159,13 +190,13 @@ static void einj_exec_ctx_init(struct apei_exec_context *ctx)
|
||||||
EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);
|
EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __einj_get_available_error_type(u32 *type)
|
static int __einj_get_available_error_type(u32 *type, int einj_action)
|
||||||
{
|
{
|
||||||
struct apei_exec_context ctx;
|
struct apei_exec_context ctx;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
einj_exec_ctx_init(&ctx);
|
einj_exec_ctx_init(&ctx);
|
||||||
rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE);
|
rc = apei_exec_run(&ctx, einj_action);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
*type = apei_exec_ctx_get_output(&ctx);
|
*type = apei_exec_ctx_get_output(&ctx);
|
||||||
|
|
@ -174,17 +205,34 @@ static int __einj_get_available_error_type(u32 *type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get error injection capabilities of the platform */
|
/* Get error injection capabilities of the platform */
|
||||||
int einj_get_available_error_type(u32 *type)
|
int einj_get_available_error_type(u32 *type, int einj_action)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&einj_mutex);
|
mutex_lock(&einj_mutex);
|
||||||
rc = __einj_get_available_error_type(type);
|
rc = __einj_get_available_error_type(type, einj_action);
|
||||||
mutex_unlock(&einj_mutex);
|
mutex_unlock(&einj_mutex);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int einj_get_available_error_types(u32 *type1, u32 *type2)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = einj_get_available_error_type(type1, ACPI_EINJ_GET_ERROR_TYPE);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
if (*type1 & ACPI65_EINJV2_SUPP) {
|
||||||
|
rc = einj_get_available_error_type(type2,
|
||||||
|
ACPI_EINJV2_GET_ERROR_TYPE);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int einj_timedout(u64 *t)
|
static int einj_timedout(u64 *t)
|
||||||
{
|
{
|
||||||
if ((s64)*t < SLEEP_UNIT_MIN) {
|
if ((s64)*t < SLEEP_UNIT_MIN) {
|
||||||
|
|
@ -216,24 +264,26 @@ static void check_vendor_extension(u64 paddr,
|
||||||
struct set_error_type_with_address *v5param)
|
struct set_error_type_with_address *v5param)
|
||||||
{
|
{
|
||||||
int offset = v5param->vendor_extension;
|
int offset = v5param->vendor_extension;
|
||||||
struct vendor_error_type_extension *v;
|
struct vendor_error_type_extension v;
|
||||||
|
struct vendor_error_type_extension __iomem *p;
|
||||||
u32 sbdf;
|
u32 sbdf;
|
||||||
|
|
||||||
if (!offset)
|
if (!offset)
|
||||||
return;
|
return;
|
||||||
v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
|
p = acpi_os_map_iomem(paddr + offset, sizeof(*p));
|
||||||
if (!v)
|
if (!p)
|
||||||
return;
|
return;
|
||||||
get_oem_vendor_struct(paddr, offset, v);
|
memcpy_fromio(&v, p, sizeof(v));
|
||||||
sbdf = v->pcie_sbdf;
|
get_oem_vendor_struct(paddr, offset, &v);
|
||||||
|
sbdf = v.pcie_sbdf;
|
||||||
sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",
|
sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",
|
||||||
sbdf >> 24, (sbdf >> 16) & 0xff,
|
sbdf >> 24, (sbdf >> 16) & 0xff,
|
||||||
(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
|
(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
|
||||||
v->vendor_id, v->device_id, v->rev_id);
|
v.vendor_id, v.device_id, v.rev_id);
|
||||||
acpi_os_unmap_iomem(v, sizeof(*v));
|
acpi_os_unmap_iomem(p, sizeof(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *einj_get_parameter_address(void)
|
static void __iomem *einj_get_parameter_address(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u64 pa_v4 = 0, pa_v5 = 0;
|
u64 pa_v4 = 0, pa_v5 = 0;
|
||||||
|
|
@ -254,26 +304,50 @@ static void *einj_get_parameter_address(void)
|
||||||
entry++;
|
entry++;
|
||||||
}
|
}
|
||||||
if (pa_v5) {
|
if (pa_v5) {
|
||||||
struct set_error_type_with_address *v5param;
|
struct set_error_type_with_address v5param;
|
||||||
|
struct set_error_type_with_address __iomem *p;
|
||||||
|
|
||||||
v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));
|
v5param_size = sizeof(v5param);
|
||||||
if (v5param) {
|
p = acpi_os_map_iomem(pa_v5, sizeof(*p));
|
||||||
|
if (p) {
|
||||||
|
int offset, len;
|
||||||
|
|
||||||
|
memcpy_fromio(&v5param, p, v5param_size);
|
||||||
acpi5 = 1;
|
acpi5 = 1;
|
||||||
check_vendor_extension(pa_v5, v5param);
|
check_vendor_extension(pa_v5, &v5param);
|
||||||
return v5param;
|
if (available_error_type & ACPI65_EINJV2_SUPP) {
|
||||||
|
len = v5param.einjv2_struct.length;
|
||||||
|
offset = offsetof(struct einjv2_extension_struct, component_arr);
|
||||||
|
max_nr_components = (len - offset) /
|
||||||
|
sizeof(v5param.einjv2_struct.component_arr[0]);
|
||||||
|
/*
|
||||||
|
* The first call to acpi_os_map_iomem above does not include the
|
||||||
|
* component array, instead it is used to read and calculate maximum
|
||||||
|
* number of components supported by the system. Below, the mapping
|
||||||
|
* is expanded to include the component array.
|
||||||
|
*/
|
||||||
|
acpi_os_unmap_iomem(p, v5param_size);
|
||||||
|
offset = offsetof(struct set_error_type_with_address, einjv2_struct);
|
||||||
|
v5param_size = offset + struct_size(&v5param.einjv2_struct,
|
||||||
|
component_arr, max_nr_components);
|
||||||
|
p = acpi_os_map_iomem(pa_v5, v5param_size);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (param_extension && pa_v4) {
|
if (param_extension && pa_v4) {
|
||||||
struct einj_parameter *v4param;
|
struct einj_parameter v4param;
|
||||||
|
struct einj_parameter __iomem *p;
|
||||||
|
|
||||||
v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));
|
p = acpi_os_map_iomem(pa_v4, sizeof(*p));
|
||||||
if (!v4param)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (v4param->reserved1 || v4param->reserved2) {
|
memcpy_fromio(&v4param, p, sizeof(v4param));
|
||||||
acpi_os_unmap_iomem(v4param, sizeof(*v4param));
|
if (v4param.reserved1 || v4param.reserved2) {
|
||||||
|
acpi_os_unmap_iomem(p, sizeof(v4param));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return v4param;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -319,7 +393,8 @@ static struct acpi_generic_address *einj_get_trigger_parameter_region(
|
||||||
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
|
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
|
||||||
u64 param1, u64 param2)
|
u64 param1, u64 param2)
|
||||||
{
|
{
|
||||||
struct acpi_einj_trigger *trigger_tab = NULL;
|
struct acpi_einj_trigger trigger_tab;
|
||||||
|
struct acpi_einj_trigger *full_trigger_tab;
|
||||||
struct apei_exec_context trigger_ctx;
|
struct apei_exec_context trigger_ctx;
|
||||||
struct apei_resources trigger_resources;
|
struct apei_resources trigger_resources;
|
||||||
struct acpi_whea_header *trigger_entry;
|
struct acpi_whea_header *trigger_entry;
|
||||||
|
|
@ -327,54 +402,60 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
|
||||||
u32 table_size;
|
u32 table_size;
|
||||||
int rc = -EIO;
|
int rc = -EIO;
|
||||||
struct acpi_generic_address *trigger_param_region = NULL;
|
struct acpi_generic_address *trigger_param_region = NULL;
|
||||||
|
struct acpi_einj_trigger __iomem *p = NULL;
|
||||||
|
|
||||||
r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
|
r = request_mem_region(trigger_paddr, sizeof(trigger_tab),
|
||||||
"APEI EINJ Trigger Table");
|
"APEI EINJ Trigger Table");
|
||||||
if (!r) {
|
if (!r) {
|
||||||
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n",
|
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n",
|
||||||
(unsigned long long)trigger_paddr,
|
(unsigned long long)trigger_paddr,
|
||||||
(unsigned long long)trigger_paddr +
|
(unsigned long long)trigger_paddr +
|
||||||
sizeof(*trigger_tab) - 1);
|
sizeof(trigger_tab) - 1);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
|
p = ioremap_cache(trigger_paddr, sizeof(*p));
|
||||||
if (!trigger_tab) {
|
if (!p) {
|
||||||
pr_err("Failed to map trigger table!\n");
|
pr_err("Failed to map trigger table!\n");
|
||||||
goto out_rel_header;
|
goto out_rel_header;
|
||||||
}
|
}
|
||||||
rc = einj_check_trigger_header(trigger_tab);
|
memcpy_fromio(&trigger_tab, p, sizeof(trigger_tab));
|
||||||
|
rc = einj_check_trigger_header(&trigger_tab);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_warn(FW_BUG "Invalid trigger error action table.\n");
|
pr_warn(FW_BUG "Invalid trigger error action table.\n");
|
||||||
goto out_rel_header;
|
goto out_rel_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No action structures in the TRIGGER_ERROR table, nothing to do */
|
/* No action structures in the TRIGGER_ERROR table, nothing to do */
|
||||||
if (!trigger_tab->entry_count)
|
if (!trigger_tab.entry_count)
|
||||||
goto out_rel_header;
|
goto out_rel_header;
|
||||||
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
table_size = trigger_tab->table_size;
|
table_size = trigger_tab.table_size;
|
||||||
r = request_mem_region(trigger_paddr + sizeof(*trigger_tab),
|
full_trigger_tab = kmalloc(table_size, GFP_KERNEL);
|
||||||
table_size - sizeof(*trigger_tab),
|
if (!full_trigger_tab)
|
||||||
|
goto out_rel_header;
|
||||||
|
r = request_mem_region(trigger_paddr + sizeof(trigger_tab),
|
||||||
|
table_size - sizeof(trigger_tab),
|
||||||
"APEI EINJ Trigger Table");
|
"APEI EINJ Trigger Table");
|
||||||
if (!r) {
|
if (!r) {
|
||||||
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
|
pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
|
||||||
(unsigned long long)trigger_paddr + sizeof(*trigger_tab),
|
(unsigned long long)trigger_paddr + sizeof(trigger_tab),
|
||||||
(unsigned long long)trigger_paddr + table_size - 1);
|
(unsigned long long)trigger_paddr + table_size - 1);
|
||||||
goto out_rel_header;
|
goto out_free_trigger_tab;
|
||||||
}
|
}
|
||||||
iounmap(trigger_tab);
|
iounmap(p);
|
||||||
trigger_tab = ioremap_cache(trigger_paddr, table_size);
|
p = ioremap_cache(trigger_paddr, table_size);
|
||||||
if (!trigger_tab) {
|
if (!p) {
|
||||||
pr_err("Failed to map trigger table!\n");
|
pr_err("Failed to map trigger table!\n");
|
||||||
goto out_rel_entry;
|
goto out_rel_entry;
|
||||||
}
|
}
|
||||||
|
memcpy_fromio(full_trigger_tab, p, table_size);
|
||||||
trigger_entry = (struct acpi_whea_header *)
|
trigger_entry = (struct acpi_whea_header *)
|
||||||
((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
|
((char *)full_trigger_tab + sizeof(struct acpi_einj_trigger));
|
||||||
apei_resources_init(&trigger_resources);
|
apei_resources_init(&trigger_resources);
|
||||||
apei_exec_ctx_init(&trigger_ctx, einj_ins_type,
|
apei_exec_ctx_init(&trigger_ctx, einj_ins_type,
|
||||||
ARRAY_SIZE(einj_ins_type),
|
ARRAY_SIZE(einj_ins_type),
|
||||||
trigger_entry, trigger_tab->entry_count);
|
trigger_entry, trigger_tab.entry_count);
|
||||||
rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);
|
rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_fini;
|
goto out_fini;
|
||||||
|
|
@ -392,7 +473,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
|
||||||
|
|
||||||
apei_resources_init(&addr_resources);
|
apei_resources_init(&addr_resources);
|
||||||
trigger_param_region = einj_get_trigger_parameter_region(
|
trigger_param_region = einj_get_trigger_parameter_region(
|
||||||
trigger_tab, param1, param2);
|
full_trigger_tab, param1, param2);
|
||||||
if (trigger_param_region) {
|
if (trigger_param_region) {
|
||||||
rc = apei_resources_add(&addr_resources,
|
rc = apei_resources_add(&addr_resources,
|
||||||
trigger_param_region->address,
|
trigger_param_region->address,
|
||||||
|
|
@ -421,23 +502,33 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type,
|
||||||
out_fini:
|
out_fini:
|
||||||
apei_resources_fini(&trigger_resources);
|
apei_resources_fini(&trigger_resources);
|
||||||
out_rel_entry:
|
out_rel_entry:
|
||||||
release_mem_region(trigger_paddr + sizeof(*trigger_tab),
|
release_mem_region(trigger_paddr + sizeof(trigger_tab),
|
||||||
table_size - sizeof(*trigger_tab));
|
table_size - sizeof(trigger_tab));
|
||||||
|
out_free_trigger_tab:
|
||||||
|
kfree(full_trigger_tab);
|
||||||
out_rel_header:
|
out_rel_header:
|
||||||
release_mem_region(trigger_paddr, sizeof(*trigger_tab));
|
release_mem_region(trigger_paddr, sizeof(trigger_tab));
|
||||||
out:
|
out:
|
||||||
if (trigger_tab)
|
if (p)
|
||||||
iounmap(trigger_tab);
|
iounmap(p);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_end_of_list(u8 *val)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < COMPONENT_LEN; ++i) {
|
||||||
|
if (val[i] != 0xFF)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||||
u64 param3, u64 param4)
|
u64 param3, u64 param4)
|
||||||
{
|
{
|
||||||
struct apei_exec_context ctx;
|
struct apei_exec_context ctx;
|
||||||
u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
|
u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
|
||||||
int rc;
|
int i, rc;
|
||||||
|
|
||||||
einj_exec_ctx_init(&ctx);
|
einj_exec_ctx_init(&ctx);
|
||||||
|
|
||||||
|
|
@ -446,8 +537,10 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||||
return rc;
|
return rc;
|
||||||
apei_exec_ctx_set_input(&ctx, type);
|
apei_exec_ctx_set_input(&ctx, type);
|
||||||
if (acpi5) {
|
if (acpi5) {
|
||||||
struct set_error_type_with_address *v5param = einj_param;
|
struct set_error_type_with_address *v5param;
|
||||||
|
|
||||||
|
v5param = kmalloc(v5param_size, GFP_KERNEL);
|
||||||
|
memcpy_fromio(v5param, einj_param, v5param_size);
|
||||||
v5param->type = type;
|
v5param->type = type;
|
||||||
if (type & ACPI5_VENDOR_BIT) {
|
if (type & ACPI5_VENDOR_BIT) {
|
||||||
switch (vendor_flags) {
|
switch (vendor_flags) {
|
||||||
|
|
@ -467,8 +560,21 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||||
v5param->flags = flags;
|
v5param->flags = flags;
|
||||||
v5param->memory_address = param1;
|
v5param->memory_address = param1;
|
||||||
v5param->memory_address_range = param2;
|
v5param->memory_address_range = param2;
|
||||||
v5param->apicid = param3;
|
|
||||||
v5param->pcie_sbdf = param4;
|
if (is_v2) {
|
||||||
|
for (i = 0; i < max_nr_components; i++) {
|
||||||
|
if (is_end_of_list(syndrome_data[i].comp_id.acpi_id))
|
||||||
|
break;
|
||||||
|
v5param->einjv2_struct.component_arr[i].comp_id =
|
||||||
|
syndrome_data[i].comp_id;
|
||||||
|
v5param->einjv2_struct.component_arr[i].comp_synd =
|
||||||
|
syndrome_data[i].comp_synd;
|
||||||
|
}
|
||||||
|
v5param->einjv2_struct.component_arr_count = i;
|
||||||
|
} else {
|
||||||
|
v5param->apicid = param3;
|
||||||
|
v5param->pcie_sbdf = param4;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ACPI_EINJ_PROCESSOR_CORRECTABLE:
|
case ACPI_EINJ_PROCESSOR_CORRECTABLE:
|
||||||
|
|
@ -492,15 +598,19 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
memcpy_toio(einj_param, v5param, v5param_size);
|
||||||
|
kfree(v5param);
|
||||||
} else {
|
} else {
|
||||||
rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
|
rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
if (einj_param) {
|
if (einj_param) {
|
||||||
struct einj_parameter *v4param = einj_param;
|
struct einj_parameter v4param;
|
||||||
|
|
||||||
v4param->param1 = param1;
|
memcpy_fromio(&v4param, einj_param, sizeof(v4param));
|
||||||
v4param->param2 = param2;
|
v4param.param1 = param1;
|
||||||
|
v4param.param2 = param2;
|
||||||
|
memcpy_toio(einj_param, &v4param, sizeof(v4param));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
|
rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
|
||||||
|
|
@ -551,10 +661,15 @@ int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,
|
||||||
u64 base_addr, size;
|
u64 base_addr, size;
|
||||||
|
|
||||||
/* If user manually set "flags", make sure it is legal */
|
/* If user manually set "flags", make sure it is legal */
|
||||||
if (flags && (flags &
|
if (flags && (flags & ~(SETWA_FLAGS_APICID | SETWA_FLAGS_MEM |
|
||||||
~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF)))
|
SETWA_FLAGS_PCIE_SBDF | SETWA_FLAGS_EINJV2)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* check if type is a valid EINJv2 error type */
|
||||||
|
if (is_v2) {
|
||||||
|
if (!(type & available_error_type_v2))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We need extra sanity checks for memory errors.
|
* We need extra sanity checks for memory errors.
|
||||||
* Other types leap directly to injection.
|
* Other types leap directly to injection.
|
||||||
|
|
@ -632,6 +747,8 @@ static u64 error_param2;
|
||||||
static u64 error_param3;
|
static u64 error_param3;
|
||||||
static u64 error_param4;
|
static u64 error_param4;
|
||||||
static struct dentry *einj_debug_dir;
|
static struct dentry *einj_debug_dir;
|
||||||
|
static char einj_buf[32];
|
||||||
|
static bool einj_v2_enabled;
|
||||||
static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
|
static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
|
||||||
{ BIT(0), "Processor Correctable" },
|
{ BIT(0), "Processor Correctable" },
|
||||||
{ BIT(1), "Processor Uncorrectable non-fatal" },
|
{ BIT(1), "Processor Uncorrectable non-fatal" },
|
||||||
|
|
@ -648,6 +765,12 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
|
||||||
{ BIT(31), "Vendor Defined Error Types" },
|
{ BIT(31), "Vendor Defined Error Types" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct { u32 mask; const char *str; } const einjv2_error_type_string[] = {
|
||||||
|
{ BIT(0), "EINJV2 Processor Error" },
|
||||||
|
{ BIT(1), "EINJV2 Memory Error" },
|
||||||
|
{ BIT(2), "EINJV2 PCI Express Error" },
|
||||||
|
};
|
||||||
|
|
||||||
static int available_error_type_show(struct seq_file *m, void *v)
|
static int available_error_type_show(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -655,17 +778,22 @@ static int available_error_type_show(struct seq_file *m, void *v)
|
||||||
if (available_error_type & einj_error_type_string[pos].mask)
|
if (available_error_type & einj_error_type_string[pos].mask)
|
||||||
seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,
|
seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,
|
||||||
einj_error_type_string[pos].str);
|
einj_error_type_string[pos].str);
|
||||||
|
if ((available_error_type & ACPI65_EINJV2_SUPP) && einj_v2_enabled) {
|
||||||
|
for (int pos = 0; pos < ARRAY_SIZE(einjv2_error_type_string); pos++) {
|
||||||
|
if (available_error_type_v2 & einjv2_error_type_string[pos].mask)
|
||||||
|
seq_printf(m, "V2_0x%08x\t%s\n", einjv2_error_type_string[pos].mask,
|
||||||
|
einjv2_error_type_string[pos].str);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SHOW_ATTRIBUTE(available_error_type);
|
DEFINE_SHOW_ATTRIBUTE(available_error_type);
|
||||||
|
|
||||||
static int error_type_get(void *data, u64 *val)
|
static ssize_t error_type_get(struct file *file, char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
*val = error_type;
|
return simple_read_from_buffer(buf, count, ppos, einj_buf, strlen(einj_buf));
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool einj_is_cxl_error_type(u64 type)
|
bool einj_is_cxl_error_type(u64 type)
|
||||||
|
|
@ -692,15 +820,35 @@ int einj_validate_error_type(u64 type)
|
||||||
if (tval & (tval - 1))
|
if (tval & (tval - 1))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!vendor)
|
if (!vendor)
|
||||||
if (!(type & available_error_type))
|
if (!(type & (available_error_type | available_error_type_v2)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error_type_set(void *data, u64 val)
|
static ssize_t error_type_set(struct file *file, const char __user *buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
u64 val;
|
||||||
|
|
||||||
|
/* Leave the last character for the NUL terminator */
|
||||||
|
if (count > sizeof(einj_buf) - 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memset(einj_buf, 0, sizeof(einj_buf));
|
||||||
|
if (copy_from_user(einj_buf, buf, count))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (strncmp(einj_buf, "V2_", 3) == 0) {
|
||||||
|
if (!sscanf(einj_buf, "V2_%llx", &val))
|
||||||
|
return -EINVAL;
|
||||||
|
is_v2 = true;
|
||||||
|
} else {
|
||||||
|
if (!sscanf(einj_buf, "%llx", &val))
|
||||||
|
return -EINVAL;
|
||||||
|
is_v2 = false;
|
||||||
|
}
|
||||||
|
|
||||||
rc = einj_validate_error_type(val);
|
rc = einj_validate_error_type(val);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|
@ -708,17 +856,24 @@ static int error_type_set(void *data, u64 val)
|
||||||
|
|
||||||
error_type = val;
|
error_type = val;
|
||||||
|
|
||||||
return 0;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set,
|
static const struct file_operations error_type_fops = {
|
||||||
"0x%llx\n");
|
.read = error_type_get,
|
||||||
|
.write = error_type_set,
|
||||||
|
};
|
||||||
|
|
||||||
static int error_inject_set(void *data, u64 val)
|
static int error_inject_set(void *data, u64 val)
|
||||||
{
|
{
|
||||||
if (!error_type)
|
if (!error_type)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (is_v2)
|
||||||
|
error_flags |= SETWA_FLAGS_EINJV2;
|
||||||
|
else
|
||||||
|
error_flags &= ~SETWA_FLAGS_EINJV2;
|
||||||
|
|
||||||
return einj_error_inject(error_type, error_flags, error_param1, error_param2,
|
return einj_error_inject(error_type, error_flags, error_param1, error_param2,
|
||||||
error_param3, error_param4);
|
error_param3, error_param4);
|
||||||
}
|
}
|
||||||
|
|
@ -741,6 +896,98 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t u128_read(struct file *f, char __user *buf, size_t count, loff_t *off)
|
||||||
|
{
|
||||||
|
char output[2 * COMPONENT_LEN + 1];
|
||||||
|
u8 *data = f->f_inode->i_private;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (*off >= sizeof(output))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < COMPONENT_LEN; i++)
|
||||||
|
sprintf(output + 2 * i, "%.02x", data[COMPONENT_LEN - i - 1]);
|
||||||
|
output[2 * COMPONENT_LEN] = '\n';
|
||||||
|
|
||||||
|
return simple_read_from_buffer(buf, count, off, output, sizeof(output));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t u128_write(struct file *f, const char __user *buf, size_t count, loff_t *off)
|
||||||
|
{
|
||||||
|
char input[2 + 2 * COMPONENT_LEN + 2];
|
||||||
|
u8 *save = f->f_inode->i_private;
|
||||||
|
u8 tmp[COMPONENT_LEN];
|
||||||
|
char byte[3] = {};
|
||||||
|
char *s, *e;
|
||||||
|
ssize_t c;
|
||||||
|
long val;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Require that user supply whole input line in one write(2) syscall */
|
||||||
|
if (*off)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
c = simple_write_to_buffer(input, sizeof(input), off, buf, count);
|
||||||
|
if (c < 0)
|
||||||
|
return c;
|
||||||
|
|
||||||
|
if (c < 1 || input[c - 1] != '\n')
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Empty line means invalidate this entry */
|
||||||
|
if (c == 1) {
|
||||||
|
memset(save, 0xff, COMPONENT_LEN);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input[0] == '0' && (input[1] == 'x' || input[1] == 'X'))
|
||||||
|
s = input + 2;
|
||||||
|
else
|
||||||
|
s = input;
|
||||||
|
e = input + c - 1;
|
||||||
|
|
||||||
|
for (i = 0; i < COMPONENT_LEN; i++) {
|
||||||
|
byte[1] = *--e;
|
||||||
|
byte[0] = e > s ? *--e : '0';
|
||||||
|
if (kstrtol(byte, 16, &val))
|
||||||
|
return -EINVAL;
|
||||||
|
tmp[i] = val;
|
||||||
|
if (e <= s)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (++i < COMPONENT_LEN)
|
||||||
|
tmp[i] = 0;
|
||||||
|
|
||||||
|
memcpy(save, tmp, COMPONENT_LEN);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations u128_fops = {
|
||||||
|
.read = u128_read,
|
||||||
|
.write = u128_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool setup_einjv2_component_files(void)
|
||||||
|
{
|
||||||
|
char name[32];
|
||||||
|
|
||||||
|
syndrome_data = kcalloc(max_nr_components, sizeof(syndrome_data[0]), GFP_KERNEL);
|
||||||
|
if (!syndrome_data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < max_nr_components; i++) {
|
||||||
|
sprintf(name, "component_id%d", i);
|
||||||
|
debugfs_create_file(name, 0600, einj_debug_dir,
|
||||||
|
&syndrome_data[i].comp_id, &u128_fops);
|
||||||
|
sprintf(name, "component_syndrome%d", i);
|
||||||
|
debugfs_create_file(name, 0600, einj_debug_dir,
|
||||||
|
&syndrome_data[i].comp_synd, &u128_fops);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init einj_probe(struct faux_device *fdev)
|
static int __init einj_probe(struct faux_device *fdev)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
@ -764,7 +1011,7 @@ static int __init einj_probe(struct faux_device *fdev)
|
||||||
goto err_put_table;
|
goto err_put_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = einj_get_available_error_type(&available_error_type);
|
rc = einj_get_available_error_types(&available_error_type, &available_error_type_v2);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_put_table;
|
goto err_put_table;
|
||||||
|
|
||||||
|
|
@ -812,6 +1059,8 @@ static int __init einj_probe(struct faux_device *fdev)
|
||||||
&error_param4);
|
&error_param4);
|
||||||
debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
|
debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
|
||||||
einj_debug_dir, ¬rigger);
|
einj_debug_dir, ¬rigger);
|
||||||
|
if (available_error_type & ACPI65_EINJV2_SUPP)
|
||||||
|
einj_v2_enabled = setup_einjv2_component_files();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vendor_dev[0]) {
|
if (vendor_dev[0]) {
|
||||||
|
|
@ -848,7 +1097,7 @@ static void __exit einj_remove(struct faux_device *fdev)
|
||||||
|
|
||||||
if (einj_param) {
|
if (einj_param) {
|
||||||
acpi_size size = (acpi5) ?
|
acpi_size size = (acpi5) ?
|
||||||
sizeof(struct set_error_type_with_address) :
|
v5param_size :
|
||||||
sizeof(struct einj_parameter);
|
sizeof(struct einj_parameter);
|
||||||
|
|
||||||
acpi_os_unmap_iomem(einj_param, size);
|
acpi_os_unmap_iomem(einj_param, size);
|
||||||
|
|
@ -860,6 +1109,7 @@ static void __exit einj_remove(struct faux_device *fdev)
|
||||||
apei_resources_release(&einj_resources);
|
apei_resources_release(&einj_resources);
|
||||||
apei_resources_fini(&einj_resources);
|
apei_resources_fini(&einj_resources);
|
||||||
debugfs_remove_recursive(einj_debug_dir);
|
debugfs_remove_recursive(einj_debug_dir);
|
||||||
|
kfree(syndrome_data);
|
||||||
acpi_put_table((struct acpi_table_header *)einj_tab);
|
acpi_put_table((struct acpi_table_header *)einj_tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ int einj_cxl_available_error_type_show(struct seq_file *m, void *v)
|
||||||
int cxl_err, rc;
|
int cxl_err, rc;
|
||||||
u32 available_error_type = 0;
|
u32 available_error_type = 0;
|
||||||
|
|
||||||
rc = einj_get_available_error_type(&available_error_type);
|
rc = einj_get_available_error_type(&available_error_type, ACPI_EINJ_GET_ERROR_TYPE);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -464,28 +464,41 @@ static void ghes_clear_estatus(struct ghes *ghes,
|
||||||
ghes_ack_error(ghes->generic_v2);
|
ghes_ack_error(ghes->generic_v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Called as task_work before returning to user-space.
|
* struct ghes_task_work - for synchronous RAS event
|
||||||
* Ensure any queued work has been done before we return to the context that
|
*
|
||||||
* triggered the notification.
|
* @twork: callback_head for task work
|
||||||
|
* @pfn: page frame number of corrupted page
|
||||||
|
* @flags: work control flags
|
||||||
|
*
|
||||||
|
* Structure to pass task work to be handled before
|
||||||
|
* returning to user-space via task_work_add().
|
||||||
*/
|
*/
|
||||||
static void ghes_kick_task_work(struct callback_head *head)
|
struct ghes_task_work {
|
||||||
|
struct callback_head twork;
|
||||||
|
u64 pfn;
|
||||||
|
int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void memory_failure_cb(struct callback_head *twork)
|
||||||
{
|
{
|
||||||
struct acpi_hest_generic_status *estatus;
|
struct ghes_task_work *twcb = container_of(twork, struct ghes_task_work, twork);
|
||||||
struct ghes_estatus_node *estatus_node;
|
int ret;
|
||||||
u32 node_len;
|
|
||||||
|
|
||||||
estatus_node = container_of(head, struct ghes_estatus_node, task_work);
|
ret = memory_failure(twcb->pfn, twcb->flags);
|
||||||
if (IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
|
gen_pool_free(ghes_estatus_pool, (unsigned long)twcb, sizeof(*twcb));
|
||||||
memory_failure_queue_kick(estatus_node->task_work_cpu);
|
|
||||||
|
|
||||||
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
if (!ret || ret == -EHWPOISON || ret == -EOPNOTSUPP)
|
||||||
node_len = GHES_ESTATUS_NODE_LEN(cper_estatus_len(estatus));
|
return;
|
||||||
gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, node_len);
|
|
||||||
|
pr_err("%#llx: Sending SIGBUS to %s:%d due to hardware memory corruption\n",
|
||||||
|
twcb->pfn, current->comm, task_pid_nr(current));
|
||||||
|
force_sig(SIGBUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ghes_do_memory_failure(u64 physical_addr, int flags)
|
static bool ghes_do_memory_failure(u64 physical_addr, int flags)
|
||||||
{
|
{
|
||||||
|
struct ghes_task_work *twcb;
|
||||||
unsigned long pfn;
|
unsigned long pfn;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
|
if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
|
||||||
|
|
@ -499,6 +512,18 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags == MF_ACTION_REQUIRED && current->mm) {
|
||||||
|
twcb = (void *)gen_pool_alloc(ghes_estatus_pool, sizeof(*twcb));
|
||||||
|
if (!twcb)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
twcb->pfn = pfn;
|
||||||
|
twcb->flags = flags;
|
||||||
|
init_task_work(&twcb->twork, memory_failure_cb);
|
||||||
|
task_work_add(current, &twcb->twork, TWA_RESUME);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
memory_failure_queue(pfn, flags);
|
memory_failure_queue(pfn, flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -842,7 +867,7 @@ int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL");
|
EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL");
|
||||||
|
|
||||||
static bool ghes_do_proc(struct ghes *ghes,
|
static void ghes_do_proc(struct ghes *ghes,
|
||||||
const struct acpi_hest_generic_status *estatus)
|
const struct acpi_hest_generic_status *estatus)
|
||||||
{
|
{
|
||||||
int sev, sec_sev;
|
int sev, sec_sev;
|
||||||
|
|
@ -902,7 +927,16 @@ static bool ghes_do_proc(struct ghes *ghes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return queued;
|
/*
|
||||||
|
* If no memory failure work is queued for abnormal synchronous
|
||||||
|
* errors, do a force kill.
|
||||||
|
*/
|
||||||
|
if (sync && !queued) {
|
||||||
|
dev_err(ghes->dev,
|
||||||
|
HW_ERR GHES_PFX "%s:%d: synchronous unrecoverable error (SIGBUS)\n",
|
||||||
|
current->comm, task_pid_nr(current));
|
||||||
|
force_sig(SIGBUS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __ghes_print_estatus(const char *pfx,
|
static void __ghes_print_estatus(const char *pfx,
|
||||||
|
|
@ -1088,6 +1122,8 @@ static void __ghes_panic(struct ghes *ghes,
|
||||||
|
|
||||||
__ghes_print_estatus(KERN_EMERG, ghes->generic, estatus);
|
__ghes_print_estatus(KERN_EMERG, ghes->generic, estatus);
|
||||||
|
|
||||||
|
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK);
|
||||||
|
|
||||||
ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
|
ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
|
||||||
|
|
||||||
if (!panic_timeout)
|
if (!panic_timeout)
|
||||||
|
|
@ -1206,9 +1242,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
|
||||||
struct ghes_estatus_node *estatus_node;
|
struct ghes_estatus_node *estatus_node;
|
||||||
struct acpi_hest_generic *generic;
|
struct acpi_hest_generic *generic;
|
||||||
struct acpi_hest_generic_status *estatus;
|
struct acpi_hest_generic_status *estatus;
|
||||||
bool task_work_pending;
|
|
||||||
u32 len, node_len;
|
u32 len, node_len;
|
||||||
int ret;
|
|
||||||
|
|
||||||
llnode = llist_del_all(&ghes_estatus_llist);
|
llnode = llist_del_all(&ghes_estatus_llist);
|
||||||
/*
|
/*
|
||||||
|
|
@ -1223,25 +1257,16 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
|
||||||
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
||||||
len = cper_estatus_len(estatus);
|
len = cper_estatus_len(estatus);
|
||||||
node_len = GHES_ESTATUS_NODE_LEN(len);
|
node_len = GHES_ESTATUS_NODE_LEN(len);
|
||||||
task_work_pending = ghes_do_proc(estatus_node->ghes, estatus);
|
|
||||||
|
ghes_do_proc(estatus_node->ghes, estatus);
|
||||||
|
|
||||||
if (!ghes_estatus_cached(estatus)) {
|
if (!ghes_estatus_cached(estatus)) {
|
||||||
generic = estatus_node->generic;
|
generic = estatus_node->generic;
|
||||||
if (ghes_print_estatus(NULL, generic, estatus))
|
if (ghes_print_estatus(NULL, generic, estatus))
|
||||||
ghes_estatus_cache_add(generic, estatus);
|
ghes_estatus_cache_add(generic, estatus);
|
||||||
}
|
}
|
||||||
|
gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
|
||||||
if (task_work_pending && current->mm) {
|
node_len);
|
||||||
estatus_node->task_work.func = ghes_kick_task_work;
|
|
||||||
estatus_node->task_work_cpu = smp_processor_id();
|
|
||||||
ret = task_work_add(current, &estatus_node->task_work,
|
|
||||||
TWA_RESUME);
|
|
||||||
if (ret)
|
|
||||||
estatus_node->task_work.func = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!estatus_node->task_work.func)
|
|
||||||
gen_pool_free(ghes_estatus_pool,
|
|
||||||
(unsigned long)estatus_node, node_len);
|
|
||||||
|
|
||||||
llnode = next;
|
llnode = next;
|
||||||
}
|
}
|
||||||
|
|
@ -1302,7 +1327,6 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
|
||||||
|
|
||||||
estatus_node->ghes = ghes;
|
estatus_node->ghes = ghes;
|
||||||
estatus_node->generic = ghes->generic;
|
estatus_node->generic = ghes->generic;
|
||||||
estatus_node->task_work.func = NULL;
|
|
||||||
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
|
||||||
|
|
||||||
if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
|
if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
|
||||||
|
|
|
||||||
|
|
@ -1406,7 +1406,7 @@ static int __init acpi_bus_init(void)
|
||||||
goto error1;
|
goto error1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register the for all standard device notifications.
|
* Register for all standard device notifications.
|
||||||
*/
|
*/
|
||||||
status =
|
status =
|
||||||
acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
|
acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY,
|
||||||
|
|
|
||||||
|
|
@ -1366,6 +1366,8 @@ static int acpi_subsys_poweroff_noirq(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
static void acpi_dev_pm_detach(struct device *dev, bool power_off);
|
||||||
|
|
||||||
static struct dev_pm_domain acpi_general_pm_domain = {
|
static struct dev_pm_domain acpi_general_pm_domain = {
|
||||||
.ops = {
|
.ops = {
|
||||||
.runtime_suspend = acpi_subsys_runtime_suspend,
|
.runtime_suspend = acpi_subsys_runtime_suspend,
|
||||||
|
|
@ -1386,6 +1388,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
|
||||||
.restore_early = acpi_subsys_restore_early,
|
.restore_early = acpi_subsys_restore_early,
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
.detach = acpi_dev_pm_detach,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1469,7 +1472,6 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
|
||||||
acpi_device_wakeup_disable(adev);
|
acpi_device_wakeup_disable(adev);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->pm_domain->detach = acpi_dev_pm_detach;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
|
EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,8 @@ static const struct acpi_device_id int3407_device_ids[] = {
|
||||||
{"INTC10A5", 0},
|
{"INTC10A5", 0},
|
||||||
{"INTC10D8", 0},
|
{"INTC10D8", 0},
|
||||||
{"INTC10D9", 0},
|
{"INTC10D9", 0},
|
||||||
|
{"INTC1100", 0},
|
||||||
|
{"INTC1101", 0},
|
||||||
{"", 0},
|
{"", 0},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
|
MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,13 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
|
||||||
{"INTC10D7"},
|
{"INTC10D7"},
|
||||||
{"INTC10D8"},
|
{"INTC10D8"},
|
||||||
{"INTC10D9"},
|
{"INTC10D9"},
|
||||||
|
{"INTC10FC"},
|
||||||
|
{"INTC10FD"},
|
||||||
|
{"INTC10FE"},
|
||||||
|
{"INTC10FF"},
|
||||||
|
{"INTC1100"},
|
||||||
|
{"INTC1101"},
|
||||||
|
{"INTC1102"},
|
||||||
{""},
|
{""},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
{"INTC106A", }, /* Fan for Lunar Lake generation */ \
|
{"INTC106A", }, /* Fan for Lunar Lake generation */ \
|
||||||
{"INTC10A2", }, /* Fan for Raptor Lake generation */ \
|
{"INTC10A2", }, /* Fan for Raptor Lake generation */ \
|
||||||
{"INTC10D6", }, /* Fan for Panther Lake generation */ \
|
{"INTC10D6", }, /* Fan for Panther Lake generation */ \
|
||||||
|
{"INTC10FE", }, /* Fan for Wildcat Lake generation */ \
|
||||||
{"PNP0C0B", } /* Generic ACPI fan */
|
{"PNP0C0B", } /* Generic ACPI fan */
|
||||||
|
|
||||||
#define ACPI_FPS_NAME_LEN 20
|
#define ACPI_FPS_NAME_LEN 20
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ static ssize_t show_state(struct device *dev, struct device_attribute *attr, cha
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (fps->control == 0xFFFFFFFF || fps->control > 100)
|
if (fps->control == 0xFFFFFFFF || fps->control > 100)
|
||||||
count = scnprintf(buf, PAGE_SIZE, "not-defined:");
|
count = sysfs_emit(buf, "not-defined:");
|
||||||
else
|
else
|
||||||
count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
|
count = sysfs_emit(buf, "%lld:", fps->control);
|
||||||
|
|
||||||
if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
|
if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
|
||||||
count += sysfs_emit_at(buf, count, "not-defined:");
|
count += sysfs_emit_at(buf, count, "not-defined:");
|
||||||
|
|
@ -59,7 +59,7 @@ static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr,
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return sprintf(buf, "%lld\n", fst.speed);
|
return sysfs_emit(buf, "%lld\n", fst.speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_fine_grain_control(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_fine_grain_control(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
|
@ -67,7 +67,7 @@ static ssize_t show_fine_grain_control(struct device *dev, struct device_attribu
|
||||||
struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);
|
struct acpi_device *acpi_dev = container_of(dev, struct acpi_device, dev);
|
||||||
struct acpi_fan *fan = acpi_driver_data(acpi_dev);
|
struct acpi_fan *fan = acpi_driver_data(acpi_dev);
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", fan->fif.fine_grain_ctrl);
|
return sysfs_emit(buf, "%d\n", fan->fif.fine_grain_ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
int acpi_fan_create_attributes(struct acpi_device *device)
|
int acpi_fan_create_attributes(struct acpi_device *device)
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i == fan->fps_count) {
|
if (i == fan->fps_count) {
|
||||||
dev_dbg(&device->dev, "Invalid control value returned\n");
|
dev_dbg(&device->dev, "No matching fps control value\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
|
||||||
|
|
||||||
link->irq.active = irq;
|
link->irq.active = irq;
|
||||||
|
|
||||||
acpi_handle_debug(handle, "Link at IRQ %d \n", link->irq.active);
|
acpi_handle_debug(handle, "Link at IRQ %d\n", link->irq.active);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,11 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
|
||||||
pfru_dev->rev_id,
|
pfru_dev->rev_id,
|
||||||
PFRU_FUNC_QUERY_UPDATE_CAP,
|
PFRU_FUNC_QUERY_UPDATE_CAP,
|
||||||
NULL, ACPI_TYPE_PACKAGE);
|
NULL, ACPI_TYPE_PACKAGE);
|
||||||
if (!out_obj)
|
if (!out_obj) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Query cap failed with no object\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (out_obj->package.count < CAP_NR_IDX ||
|
if (out_obj->package.count < CAP_NR_IDX ||
|
||||||
out_obj->package.elements[CAP_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[CAP_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
|
|
@ -141,13 +144,17 @@ static int query_capability(struct pfru_update_cap_info *cap_hdr,
|
||||||
out_obj->package.elements[CAP_DRV_SVN_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[CAP_DRV_SVN_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[CAP_PLAT_ID_IDX].type != ACPI_TYPE_BUFFER ||
|
out_obj->package.elements[CAP_PLAT_ID_IDX].type != ACPI_TYPE_BUFFER ||
|
||||||
out_obj->package.elements[CAP_OEM_ID_IDX].type != ACPI_TYPE_BUFFER ||
|
out_obj->package.elements[CAP_OEM_ID_IDX].type != ACPI_TYPE_BUFFER ||
|
||||||
out_obj->package.elements[CAP_OEM_INFO_IDX].type != ACPI_TYPE_BUFFER)
|
out_obj->package.elements[CAP_OEM_INFO_IDX].type != ACPI_TYPE_BUFFER) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Query cap failed with invalid package count/type\n");
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
cap_hdr->status = out_obj->package.elements[CAP_STATUS_IDX].integer.value;
|
cap_hdr->status = out_obj->package.elements[CAP_STATUS_IDX].integer.value;
|
||||||
if (cap_hdr->status != DSM_SUCCEED) {
|
if (cap_hdr->status != DSM_SUCCEED) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
dev_dbg(pfru_dev->parent_dev, "Error Status:%d\n", cap_hdr->status);
|
dev_dbg(pfru_dev->parent_dev, "Query cap Error Status:%d\n",
|
||||||
|
cap_hdr->status);
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,24 +200,32 @@ static int query_buffer(struct pfru_com_buf_info *info,
|
||||||
out_obj = acpi_evaluate_dsm_typed(handle, &pfru_guid,
|
out_obj = acpi_evaluate_dsm_typed(handle, &pfru_guid,
|
||||||
pfru_dev->rev_id, PFRU_FUNC_QUERY_BUF,
|
pfru_dev->rev_id, PFRU_FUNC_QUERY_BUF,
|
||||||
NULL, ACPI_TYPE_PACKAGE);
|
NULL, ACPI_TYPE_PACKAGE);
|
||||||
if (!out_obj)
|
if (!out_obj) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Query buf failed with no object\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (out_obj->package.count < BUF_NR_IDX ||
|
if (out_obj->package.count < BUF_NR_IDX ||
|
||||||
out_obj->package.elements[BUF_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[BUF_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[BUF_EXT_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[BUF_EXT_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[BUF_ADDR_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[BUF_ADDR_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[BUF_ADDR_HI_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[BUF_ADDR_HI_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[BUF_SIZE_IDX].type != ACPI_TYPE_INTEGER)
|
out_obj->package.elements[BUF_SIZE_IDX].type != ACPI_TYPE_INTEGER) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Query buf failed with invalid package count/type\n");
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
info->status = out_obj->package.elements[BUF_STATUS_IDX].integer.value;
|
info->status = out_obj->package.elements[BUF_STATUS_IDX].integer.value;
|
||||||
info->ext_status =
|
info->ext_status =
|
||||||
out_obj->package.elements[BUF_EXT_STATUS_IDX].integer.value;
|
out_obj->package.elements[BUF_EXT_STATUS_IDX].integer.value;
|
||||||
if (info->status != DSM_SUCCEED) {
|
if (info->status != DSM_SUCCEED) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
dev_dbg(pfru_dev->parent_dev, "Error Status:%d\n", info->status);
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
dev_dbg(pfru_dev->parent_dev, "Error Extended Status:%d\n", info->ext_status);
|
"Query buf failed with Error Status:%d\n", info->status);
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Query buf failed with Error Extended Status:%d\n", info->ext_status);
|
||||||
|
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
}
|
}
|
||||||
|
|
@ -295,12 +310,16 @@ static bool applicable_image(const void *data, struct pfru_update_cap_info *cap,
|
||||||
m_img_hdr = data + size;
|
m_img_hdr = data + size;
|
||||||
|
|
||||||
type = get_image_type(m_img_hdr, pfru_dev);
|
type = get_image_type(m_img_hdr, pfru_dev);
|
||||||
if (type < 0)
|
if (type < 0) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev, "Invalid image type\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size = adjust_efi_size(m_img_hdr, size);
|
size = adjust_efi_size(m_img_hdr, size);
|
||||||
if (size < 0)
|
if (size < 0) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev, "Invalid image size\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auth = data + size;
|
auth = data + size;
|
||||||
size += sizeof(u64) + auth->auth_info.hdr.len;
|
size += sizeof(u64) + auth->auth_info.hdr.len;
|
||||||
|
|
@ -346,8 +365,11 @@ static int start_update(int action, struct pfru_device *pfru_dev)
|
||||||
out_obj = acpi_evaluate_dsm_typed(handle, &pfru_guid,
|
out_obj = acpi_evaluate_dsm_typed(handle, &pfru_guid,
|
||||||
pfru_dev->rev_id, PFRU_FUNC_START,
|
pfru_dev->rev_id, PFRU_FUNC_START,
|
||||||
&in_obj, ACPI_TYPE_PACKAGE);
|
&in_obj, ACPI_TYPE_PACKAGE);
|
||||||
if (!out_obj)
|
if (!out_obj) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Update failed to start with no object\n");
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (out_obj->package.count < UPDATE_NR_IDX ||
|
if (out_obj->package.count < UPDATE_NR_IDX ||
|
||||||
out_obj->package.elements[UPDATE_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[UPDATE_STATUS_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
|
|
@ -355,8 +377,11 @@ static int start_update(int action, struct pfru_device *pfru_dev)
|
||||||
out_obj->package.elements[UPDATE_AUTH_TIME_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[UPDATE_AUTH_TIME_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[UPDATE_AUTH_TIME_HI_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[UPDATE_AUTH_TIME_HI_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[UPDATE_EXEC_TIME_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
out_obj->package.elements[UPDATE_EXEC_TIME_LOW_IDX].type != ACPI_TYPE_INTEGER ||
|
||||||
out_obj->package.elements[UPDATE_EXEC_TIME_HI_IDX].type != ACPI_TYPE_INTEGER)
|
out_obj->package.elements[UPDATE_EXEC_TIME_HI_IDX].type != ACPI_TYPE_INTEGER) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Update failed with invalid package count/type\n");
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
update_result.status =
|
update_result.status =
|
||||||
out_obj->package.elements[UPDATE_STATUS_IDX].integer.value;
|
out_obj->package.elements[UPDATE_STATUS_IDX].integer.value;
|
||||||
|
|
@ -365,8 +390,10 @@ static int start_update(int action, struct pfru_device *pfru_dev)
|
||||||
|
|
||||||
if (update_result.status != DSM_SUCCEED) {
|
if (update_result.status != DSM_SUCCEED) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
dev_dbg(pfru_dev->parent_dev, "Error Status:%d\n", update_result.status);
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
dev_dbg(pfru_dev->parent_dev, "Error Extended Status:%d\n",
|
"Update failed with Error Status:%d\n", update_result.status);
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Update failed with Error Extended Status:%d\n",
|
||||||
update_result.ext_status);
|
update_result.ext_status);
|
||||||
|
|
||||||
goto free_acpi_buffer;
|
goto free_acpi_buffer;
|
||||||
|
|
@ -450,8 +477,10 @@ static ssize_t pfru_write(struct file *file, const char __user *buf,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (len > buf_info.buf_size)
|
if (len > buf_info.buf_size) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev, "Capsule image size too large\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
iov.iov_base = (void __user *)buf;
|
iov.iov_base = (void __user *)buf;
|
||||||
iov.iov_len = len;
|
iov.iov_len = len;
|
||||||
|
|
@ -460,10 +489,14 @@ static ssize_t pfru_write(struct file *file, const char __user *buf,
|
||||||
/* map the communication buffer */
|
/* map the communication buffer */
|
||||||
phy_addr = (phys_addr_t)((buf_info.addr_hi << 32) | buf_info.addr_lo);
|
phy_addr = (phys_addr_t)((buf_info.addr_hi << 32) | buf_info.addr_lo);
|
||||||
buf_ptr = memremap(phy_addr, buf_info.buf_size, MEMREMAP_WB);
|
buf_ptr = memremap(phy_addr, buf_info.buf_size, MEMREMAP_WB);
|
||||||
if (!buf_ptr)
|
if (!buf_ptr) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev, "Failed to remap the buffer\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
if (!copy_from_iter_full(buf_ptr, len, &iter)) {
|
if (!copy_from_iter_full(buf_ptr, len, &iter)) {
|
||||||
|
dev_dbg(pfru_dev->parent_dev,
|
||||||
|
"Failed to copy the data from the user space buffer\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unmap;
|
goto unmap;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,6 @@ static u64 efi_pa_va_lookup(efi_guid_t *guid, u64 pa)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_warn("Failed to find VA for GUID: %pUL, PA: 0x%llx", guid, pa);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,13 +152,37 @@ acpi_parse_prmt(union acpi_subtable_headers *header, const unsigned long end)
|
||||||
guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
|
guid_copy(&th->guid, (guid_t *)handler_info->handler_guid);
|
||||||
th->handler_addr =
|
th->handler_addr =
|
||||||
(void *)efi_pa_va_lookup(&th->guid, handler_info->handler_address);
|
(void *)efi_pa_va_lookup(&th->guid, handler_info->handler_address);
|
||||||
|
/*
|
||||||
|
* Print a warning message if handler_addr is zero which is not expected to
|
||||||
|
* ever happen.
|
||||||
|
*/
|
||||||
|
if (unlikely(!th->handler_addr))
|
||||||
|
pr_warn("Failed to find VA of handler for GUID: %pUL, PA: 0x%llx",
|
||||||
|
&th->guid, handler_info->handler_address);
|
||||||
|
|
||||||
th->static_data_buffer_addr =
|
th->static_data_buffer_addr =
|
||||||
efi_pa_va_lookup(&th->guid, handler_info->static_data_buffer_address);
|
efi_pa_va_lookup(&th->guid, handler_info->static_data_buffer_address);
|
||||||
|
/*
|
||||||
|
* According to the PRM specification, static_data_buffer_address can be zero,
|
||||||
|
* so avoid printing a warning message in that case. Otherwise, if the
|
||||||
|
* return value of efi_pa_va_lookup() is zero, print the message.
|
||||||
|
*/
|
||||||
|
if (unlikely(!th->static_data_buffer_addr && handler_info->static_data_buffer_address))
|
||||||
|
pr_warn("Failed to find VA of static data buffer for GUID: %pUL, PA: 0x%llx",
|
||||||
|
&th->guid, handler_info->static_data_buffer_address);
|
||||||
|
|
||||||
th->acpi_param_buffer_addr =
|
th->acpi_param_buffer_addr =
|
||||||
efi_pa_va_lookup(&th->guid, handler_info->acpi_param_buffer_address);
|
efi_pa_va_lookup(&th->guid, handler_info->acpi_param_buffer_address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to the PRM specification, acpi_param_buffer_address can be zero,
|
||||||
|
* so avoid printing a warning message in that case. Otherwise, if the
|
||||||
|
* return value of efi_pa_va_lookup() is zero, print the message.
|
||||||
|
*/
|
||||||
|
if (unlikely(!th->acpi_param_buffer_addr && handler_info->acpi_param_buffer_address))
|
||||||
|
pr_warn("Failed to find VA of acpi param buffer for GUID: %pUL, PA: 0x%llx",
|
||||||
|
&th->guid, handler_info->acpi_param_buffer_address);
|
||||||
|
|
||||||
} while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
|
} while (++cur_handler < tm->handler_count && (handler_info = get_next_handler(handler_info)));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/export.h>
|
#include <linux/string_choices.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/bcd.h>
|
#include <linux/bcd.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
|
@ -30,17 +30,16 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
|
||||||
if (!dev->wakeup.flags.valid)
|
if (!dev->wakeup.flags.valid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
seq_printf(seq, "%s\t S%d\t",
|
seq_printf(seq, "%s\t S%llu\t",
|
||||||
dev->pnp.bus_id,
|
dev->pnp.bus_id,
|
||||||
(u32) dev->wakeup.sleep_state);
|
dev->wakeup.sleep_state);
|
||||||
|
|
||||||
mutex_lock(&dev->physical_node_lock);
|
mutex_lock(&dev->physical_node_lock);
|
||||||
|
|
||||||
if (!dev->physical_node_count) {
|
if (!dev->physical_node_count) {
|
||||||
seq_printf(seq, "%c%-8s\n",
|
seq_printf(seq, "%c%-8s\n",
|
||||||
dev->wakeup.flags.valid ? '*' : ' ',
|
dev->wakeup.flags.valid ? '*' : ' ',
|
||||||
device_may_wakeup(&dev->dev) ?
|
str_enabled_disabled(device_may_wakeup(&dev->dev)));
|
||||||
"enabled" : "disabled");
|
|
||||||
} else {
|
} else {
|
||||||
struct device *ldev;
|
struct device *ldev;
|
||||||
list_for_each_entry(entry, &dev->physical_node_list,
|
list_for_each_entry(entry, &dev->physical_node_list,
|
||||||
|
|
@ -55,9 +54,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
|
||||||
|
|
||||||
seq_printf(seq, "%c%-8s %s:%s\n",
|
seq_printf(seq, "%c%-8s %s:%s\n",
|
||||||
dev->wakeup.flags.valid ? '*' : ' ',
|
dev->wakeup.flags.valid ? '*' : ' ',
|
||||||
(device_may_wakeup(&dev->dev) ||
|
str_enabled_disabled(device_may_wakeup(ldev) ||
|
||||||
device_may_wakeup(ldev)) ?
|
device_may_wakeup(&dev->dev)),
|
||||||
"enabled" : "disabled",
|
|
||||||
ldev->bus ? ldev->bus->name :
|
ldev->bus ? ldev->bus->name :
|
||||||
"no-bus", dev_name(ldev));
|
"no-bus", dev_name(ldev));
|
||||||
put_device(ldev);
|
put_device(ldev);
|
||||||
|
|
@ -141,6 +139,5 @@ static const struct proc_ops acpi_system_wakeup_device_proc_ops = {
|
||||||
void __init acpi_sleep_proc_init(void)
|
void __init acpi_sleep_proc_init(void)
|
||||||
{
|
{
|
||||||
/* 'wakeup device' [R/W] */
|
/* 'wakeup device' [R/W] */
|
||||||
proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
|
proc_create("wakeup", 0644, acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
|
||||||
acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,11 +173,14 @@ void acpi_processor_ppc_init(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
unsigned int cpu;
|
unsigned int cpu;
|
||||||
|
|
||||||
|
if (ignore_ppc == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
for_each_cpu(cpu, policy->related_cpus) {
|
for_each_cpu(cpu, policy->related_cpus) {
|
||||||
struct acpi_processor *pr = per_cpu(processors, cpu);
|
struct acpi_processor *pr = per_cpu(processors, cpu);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!pr)
|
if (!pr || !pr->performance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -193,6 +196,11 @@ void acpi_processor_ppc_init(struct cpufreq_policy *policy)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
pr_err("Failed to add freq constraint for CPU%d (%d)\n",
|
pr_err("Failed to add freq constraint for CPU%d (%d)\n",
|
||||||
cpu, ret);
|
cpu, ret);
|
||||||
|
|
||||||
|
ret = acpi_processor_get_platform_limit(pr);
|
||||||
|
if (ret)
|
||||||
|
pr_err("Failed to update freq constraint for CPU%d (%d)\n",
|
||||||
|
cpu, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ static int acpi_processor_throttling_notifier(unsigned long event, void *data)
|
||||||
if (pr->throttling_platform_limit > target_state)
|
if (pr->throttling_platform_limit > target_state)
|
||||||
target_state = pr->throttling_platform_limit;
|
target_state = pr->throttling_platform_limit;
|
||||||
if (target_state >= p_throttling->state_count) {
|
if (target_state >= p_throttling->state_count) {
|
||||||
pr_warn("Exceed the limit of T-state \n");
|
pr_warn("Exceed the limit of T-state\n");
|
||||||
target_state = p_throttling->state_count - 1;
|
target_state = p_throttling->state_count - 1;
|
||||||
}
|
}
|
||||||
p_tstate->target_state = target_state;
|
p_tstate->target_state = target_state;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ void acpi_enable_wakeup_devices(u8 sleep_state)
|
||||||
list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
|
list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
|
||||||
wakeup_list) {
|
wakeup_list) {
|
||||||
if (!dev->wakeup.flags.valid
|
if (!dev->wakeup.flags.valid
|
||||||
|| sleep_state > (u32) dev->wakeup.sleep_state
|
|| sleep_state > dev->wakeup.sleep_state
|
||||||
|| !(device_may_wakeup(&dev->dev)
|
|| !(device_may_wakeup(&dev->dev)
|
||||||
|| dev->wakeup.prepare_count))
|
|| dev->wakeup.prepare_count))
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -67,7 +67,7 @@ void acpi_disable_wakeup_devices(u8 sleep_state)
|
||||||
list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
|
list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
|
||||||
wakeup_list) {
|
wakeup_list) {
|
||||||
if (!dev->wakeup.flags.valid
|
if (!dev->wakeup.flags.valid
|
||||||
|| sleep_state > (u32) dev->wakeup.sleep_state
|
|| sleep_state > dev->wakeup.sleep_state
|
||||||
|| !(device_may_wakeup(&dev->dev)
|
|| !(device_may_wakeup(&dev->dev)
|
||||||
|| dev->wakeup.prepare_count))
|
|| dev->wakeup.prepare_count))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -387,9 +387,6 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
|
||||||
{ "INT3435", LPSS_ADDR(lpt_uart_dev_desc) },
|
{ "INT3435", LPSS_ADDR(lpt_uart_dev_desc) },
|
||||||
{ "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
|
{ "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
|
||||||
|
|
||||||
/* Wildcat Point LPSS devices */
|
|
||||||
{ "INT3438", LPSS_ADDR(lpt_spi_dev_desc) },
|
|
||||||
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -690,6 +690,7 @@ static const struct acpi_device_id int3400_thermal_match[] = {
|
||||||
{"INTC1068", 0},
|
{"INTC1068", 0},
|
||||||
{"INTC10A0", 0},
|
{"INTC10A0", 0},
|
||||||
{"INTC10D4", 0},
|
{"INTC10D4", 0},
|
||||||
|
{"INTC10FC", 0},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -276,6 +276,7 @@ static const struct acpi_device_id int3403_device_ids[] = {
|
||||||
{"INTC1069", 0},
|
{"INTC1069", 0},
|
||||||
{"INTC10A1", 0},
|
{"INTC10A1", 0},
|
||||||
{"INTC10D5", 0},
|
{"INTC10D5", 0},
|
||||||
|
{"INTC10FD", 0},
|
||||||
{"", 0},
|
{"", 0},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
|
MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,6 @@ struct ghes_estatus_node {
|
||||||
struct llist_node llnode;
|
struct llist_node llnode;
|
||||||
struct acpi_hest_generic *generic;
|
struct acpi_hest_generic *generic;
|
||||||
struct ghes *ghes;
|
struct ghes *ghes;
|
||||||
|
|
||||||
int task_work_cpu;
|
|
||||||
struct callback_head task_work;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ghes_estatus_cache {
|
struct ghes_estatus_cache {
|
||||||
|
|
|
||||||
|
|
@ -3901,7 +3901,6 @@ enum mf_flags {
|
||||||
int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index,
|
int mf_dax_kill_procs(struct address_space *mapping, pgoff_t index,
|
||||||
unsigned long count, int mf_flags);
|
unsigned long count, int mf_flags);
|
||||||
extern int memory_failure(unsigned long pfn, int flags);
|
extern int memory_failure(unsigned long pfn, int flags);
|
||||||
extern void memory_failure_queue_kick(int cpu);
|
|
||||||
extern int unpoison_memory(unsigned long pfn);
|
extern int unpoison_memory(unsigned long pfn);
|
||||||
extern atomic_long_t num_poisoned_pages __read_mostly;
|
extern atomic_long_t num_poisoned_pages __read_mostly;
|
||||||
extern int soft_offline_page(unsigned long pfn, int flags);
|
extern int soft_offline_page(unsigned long pfn, int flags);
|
||||||
|
|
|
||||||
|
|
@ -2507,19 +2507,6 @@ static void memory_failure_work_func(struct work_struct *work)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process memory_failure work queued on the specified CPU.
|
|
||||||
* Used to avoid return-to-userspace racing with the memory_failure workqueue.
|
|
||||||
*/
|
|
||||||
void memory_failure_queue_kick(int cpu)
|
|
||||||
{
|
|
||||||
struct memory_failure_cpu *mf_cpu;
|
|
||||||
|
|
||||||
mf_cpu = &per_cpu(memory_failure_cpu, cpu);
|
|
||||||
cancel_work_sync(&mf_cpu->work);
|
|
||||||
memory_failure_work_func(&mf_cpu->work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init memory_failure_init(void)
|
static int __init memory_failure_init(void)
|
||||||
{
|
{
|
||||||
struct memory_failure_cpu *mf_cpu;
|
struct memory_failure_cpu *mf_cpu;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue