Skip to content

Commit

Permalink
Merge tag 'acpi-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/rafael/linux-pm

Pull ACPI updates from Rafael Wysocki:
 "The ACPICA code in the kernel gets updated as usual (included is
  upstream revision 20160930 and a few commits from the next one, with
  the rest waiting for an issue discovered in linux-next to be
  addressed) which brings in a couple of fixes and cleanups

  On top of that initial support for APEI on ARM64 is added, two new
  pieces of documentation are introduced, the properties-parsing code is
  updated to follow changes in the (external) documentation it is based
  on and there are a few updates of SoC drivers, some new blacklist
  entries, plus some assorted fixes and cleanups

  Specifics:

   - ACPICA update including upstream revision 20160930 and several
     commits beyond it (Bob Moore, Lv Zheng)

   - Initial support for ACPI APEI on ARM64 (Tomasz Nowicki)

   - New document describing the handling of _OSI and _REV in Linux (Len
     Brown)

   - New document describing the usage rules for _DSD properties (Rafael
     Wysocki)

   - Update of the ACPI properties-parsing code to reflect recent
     changes in the (external) documentation it is based on (Rafael
     Wysocki)

   - Updates of the ACPI LPSS and ACPI APD SoC drivers for additional
     hardware support (Andy Shevchenko, Nehal Shah)

   - New blacklist entries for _REV and video handling (Alex Hung, Hans
     de Goede, Michael Pobega)

   - ACPI battery driver fix to fall back to _BIF if _BIX fails (Dave
     Lambley)

   - NMI notifications handling fix for APEI (Prarit Bhargava)

   - Error code path fix for the ACPI CPPC library (Dan Carpenter)

   - Assorted cleanups (Andy Shevchenko, Longpeng Mike)"

* tag 'acpi-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (31 commits)
  ACPICA: Utilities: Add new decode function for parser values
  ACPI / osl: Refactor acpi_os_get_root_pointer() to drop 'else':s
  ACPI / osl: Propagate actual error code for kstrtoul()
  ACPI / property: Document usage rules for _DSD properties
  ACPI: Document _OSI and _REV for Linux BIOS writers
  ACPI / APEI / ARM64: APEI initial support for ARM64
  ACPI / APEI: Fix NMI notification handling
  ACPICA: Tables: Add an error message complaining driver bugs
  ACPICA: Tables: Add acpi_tb_unload_table()
  ACPICA: Tables: Cleanup acpi_tb_install_and_load_table()
  ACPICA: Events: Fix acpi_ev_initialize_region() return value
  ACPICA: Back port of "ACPICA: Dispatcher: Tune interpreter lock around AcpiEvInitializeRegion()"
  ACPICA: Namespace: Add acpi_ns_handle_to_name()
  ACPI / CPPC: set an error code on probe error path
  ACPI / video: Add force_native quirk for HP Pavilion dv6
  ACPI / video: Add force_native quirk for Dell XPS 17 L702X
  ACPI / property: Hierarchical properties support update
  ACPI / LPSS: enable hard LLP for DMA
  ACPI / battery: If _BIX fails, retry with _BIF
  ACPI / video: Move ACPI_VIDEO_NOTIFY_* defines to acpi/video.h
  ..
  • Loading branch information
Linus Torvalds committed Dec 13, 2016
2 parents 7b9dc3f + 80f1b3d commit a67485d
Show file tree
Hide file tree
Showing 41 changed files with 800 additions and 318 deletions.
97 changes: 97 additions & 0 deletions Documentation/acpi/DSD-properties-rules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
_DSD Device Properties Usage Rules
----------------------------------

Properties, Property Sets and Property Subsets
----------------------------------------------

The _DSD (Device Specific Data) configuration object, introduced in ACPI 5.1,
allows any type of device configuration data to be provided via the ACPI
namespace. In principle, the format of the data may be arbitrary, but it has to
be identified by a UUID which must be recognized by the driver processing the
_DSD output. However, there are generic UUIDs defined for _DSD recognized by
the ACPI subsystem in the Linux kernel which automatically processes the data
packages associated with them and makes those data available to device drivers
as "device properties".

A device property is a data item consisting of a string key and a value (of a
specific type) associated with it.

In the ACPI _DSD context it is an element of the sub-package following the
generic Device Properties UUID in the _DSD return package as specified in the
Device Properties UUID definition document [1].

It also may be regarded as the definition of a key and the associated data type
that can be returned by _DSD in the Device Properties UUID sub-package for a
given device.

A property set is a collection of properties applicable to a hardware entity
like a device. In the ACPI _DSD context it is the set of all properties that
can be returned in the Device Properties UUID sub-package for the device in
question.

Property subsets are nested collections of properties. Each of them is
associated with an additional key (name) allowing the subset to be referred
to as a whole (and to be treated as a separate entity). The canonical
representation of property subsets is via the mechanism specified in the
Hierarchical Properties Extension UUID definition document [2].

Property sets may be hierarchical. That is, a property set may contain
multiple property subsets that each may contain property subsets of its
own and so on.

General Validity Rule for Property Sets
---------------------------------------

Valid property sets must follow the guidance given by the Device Properties UUID
definition document [1].

_DSD properties are intended to be used in addition to, and not instead of, the
existing mechanisms defined by the ACPI specification. Therefore, as a rule,
they should only be used if the ACPI specification does not make direct
provisions for handling the underlying use case. It generally is invalid to
return property sets which do not follow that rule from _DSD in data packages
associated with the Device Properties UUID.

Additional Considerations
-------------------------

There are cases in which, even if the general rule given above is followed in
principle, the property set may still not be regarded as a valid one.

For example, that applies to device properties which may cause kernel code
(either a device driver or a library/subsystem) to access hardware in a way
possibly leading to a conflict with AML methods in the ACPI namespace. In
particular, that may happen if the kernel code uses device properties to
manipulate hardware normally controlled by ACPI methods related to power
management, like _PSx and _DSW (for device objects) or _ON and _OFF (for power
resource objects), or by ACPI device disabling/enabling methods, like _DIS and
_SRS.

In all cases in which kernel code may do something that will confuse AML as a
result of using device properties, the device properties in question are not
suitable for the ACPI environment and consequently they cannot belong to a valid
property set.

Property Sets and Device Tree Bindings
--------------------------------------

It often is useful to make _DSD return property sets that follow Device Tree
bindings.

In those cases, however, the above validity considerations must be taken into
account in the first place and returning invalid property sets from _DSD must be
avoided. For this reason, it may not be possible to make _DSD return a property
set following the given DT binding literally and completely. Still, for the
sake of code re-use, it may make sense to provide as much of the configuration
data as possible in the form of device properties and complement that with an
ACPI-specific mechanism suitable for the use case at hand.

In any case, property sets following DT bindings literally should not be
expected to automatically work in the ACPI environment regardless of their
contents.

References
----------

[1] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
[2] http://www.uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
9 changes: 9 additions & 0 deletions Documentation/acpi/enumeration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -415,3 +415,12 @@ the "compatible" property in the _DSD or a _CID as long as one of their
ancestors provides a _DSD with a valid "compatible" property. Such device
objects are then simply regarded as additional "blocks" providing hierarchical
configuration information to the driver of the composite ancestor device.

However, PRP0001 can only be returned from either _HID or _CID of a device
object if all of the properties returned by the _DSD associated with it (either
the _DSD of the device object itself or the _DSD of its ancestor in the
"composite device" case described above) can be used in the ACPI environment.
Otherwise, the _DSD itself is regarded as invalid and therefore the "compatible"
property returned by it is meaningless.

Refer to DSD-properties-rules.txt for more information.
187 changes: 187 additions & 0 deletions Documentation/acpi/osi.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
ACPI _OSI and _REV methods
--------------------------

An ACPI BIOS can use the "Operating System Interfaces" method (_OSI)
to find out what the operating system supports. Eg. If BIOS
AML code includes _OSI("XYZ"), the kernel's AML interpreter
can evaluate that method, look to see if it supports 'XYZ'
and answer YES or NO to the BIOS.

The ACPI _REV method returns the "Revision of the ACPI specification
that OSPM supports"

This document explains how and why the BIOS and Linux should use these methods.
It also explains how and why they are widely misused.

How to use _OSI
---------------

Linux runs on two groups of machines -- those that are tested by the OEM
to be compatible with Linux, and those that were never tested with Linux,
but where Linux was installed to replace the original OS (Windows or OSX).

The larger group is the systems tested to run only Windows. Not only that,
but many were tested to run with just one specific version of Windows.
So even though the BIOS may use _OSI to query what version of Windows is running,
only a single path through the BIOS has actually been tested.
Experience shows that taking untested paths through the BIOS
exposes Linux to an entire category of BIOS bugs.
For this reason, Linux _OSI defaults must continue to claim compatibility
with all versions of Windows.

But Linux isn't actually compatible with Windows, and the Linux community
has also been hurt with regressions when Linux adds the latest version of
Windows to its list of _OSI strings. So it is possible that additional strings
will be more thoroughly vetted before shipping upstream in the future.
But it is likely that they will all eventually be added.

What should an OEM do if they want to support Linux and Windows
using the same BIOS image? Often they need to do something different
for Linux to deal with how Linux is different from Windows.
Here the BIOS should ask exactly what it wants to know:

_OSI("Linux-OEM-my_interface_name")
where 'OEM' is needed if this is an OEM-specific hook,
and 'my_interface_name' describes the hook, which could be a
quirk, a bug, or a bug-fix.

In addition, the OEM should send a patch to upstream Linux
via the linux-acpi@vger.kernel.org mailing list. When that patch
is checked into Linux, the OS will answer "YES" when the BIOS
on the OEM's system uses _OSI to ask if the interface is supported
by the OS. Linux distributors can back-port that patch for Linux
pre-installs, and it will be included by all distributions that
re-base to upstream. If the distribution can not update the kernel binary,
they can also add an acpi_osi=Linux-OEM-my_interface_name
cmdline parameter to the boot loader, as needed.

If the string refers to a feature where the upstream kernel
eventually grows support, a patch should be sent to remove
the string when that support is added to the kernel.

That was easy. Read on, to find out how to do it wrong.

Before _OSI, there was _OS
--------------------------

ACPI 1.0 specified "_OS" as an
"object that evaluates to a string that identifies the operating system."

The ACPI BIOS flow would include an evaluation of _OS, and the AML
interpreter in the kernel would return to it a string identifying the OS:

Windows 98, SE: "Microsoft Windows"
Windows ME: "Microsoft WindowsME:Millenium Edition"
Windows NT: "Microsoft Windows NT"

The idea was on a platform tasked with running multiple OS's,
the BIOS could use _OS to enable devices that an OS
might support, or enable quirks or bug workarounds
necessary to make the platform compatible with that pre-existing OS.

But _OS had fundamental problems. First, the BIOS needed to know the name
of every possible version of the OS that would run on it, and needed to know
all the quirks of those OS's. Certainly it would make more sense
for the BIOS to ask *specific* things of the OS, such
"do you support a specific interface", and thus in ACPI 3.0,
_OSI was born to replace _OS.

_OS was abandoned, though even today, many BIOS look for
_OS "Microsoft Windows NT", though it seems somewhat far-fetched
that anybody would install those old operating systems
over what came with the machine.

Linux answers "Microsoft Windows NT" to please that BIOS idiom.
That is the *only* viable strategy, as that is what modern Windows does,
and so doing otherwise could steer the BIOS down an untested path.

_OSI is born, and immediately misused
--------------------------------------

With _OSI, the *BIOS* provides the string describing an interface,
and asks the OS: "YES/NO, are you compatible with this interface?"

eg. _OSI("3.0 Thermal Model") would return TRUE if the OS knows how
to deal with the thermal extensions made to the ACPI 3.0 specification.
An old OS that doesn't know about those extensions would answer FALSE,
and a new OS may be able to return TRUE.

For an OS-specific interface, the ACPI spec said that the BIOS and the OS
were to agree on a string of the form such as "Windows-interface_name".

But two bad things happened. First, the Windows ecosystem used _OSI
not as designed, but as a direct replacement for _OS -- identifying
the OS version, rather than an OS supported interface. Indeed, right
from the start, the ACPI 3.0 spec itself codified this misuse
in example code using _OSI("Windows 2001").

This misuse was adopted and continues today.

Linux had no choice but to also return TRUE to _OSI("Windows 2001")
and its successors. To do otherwise would virtually guarantee breaking
a BIOS that has been tested only with that _OSI returning TRUE.

This strategy is problematic, as Linux is never completely compatible with
the latest version of Windows, and sometimes it takes more than a year
to iron out incompatibilities.

Not to be out-done, the Linux community made things worse by returning TRUE
to _OSI("Linux"). Doing so is even worse than the Windows misuse
of _OSI, as "Linux" does not even contain any version information.
_OSI("Linux") led to some BIOS' malfunctioning due to BIOS writer's
using it in untested BIOS flows. But some OEM's used _OSI("Linux")
in tested flows to support real Linux features. In 2009, Linux
removed _OSI("Linux"), and added a cmdline parameter to restore it
for legacy systems still needed it. Further a BIOS_BUG warning prints
for all BIOS's that invoke it.

No BIOS should use _OSI("Linux").

The result is a strategy for Linux to maximize compatibility with
ACPI BIOS that are tested on Windows machines. There is a real risk
of over-stating that compatibility; but the alternative has often been
catastrophic failure resulting from the BIOS taking paths that
were never validated under *any* OS.

Do not use _REV
---------------

Since _OSI("Linux") went away, some BIOS writers used _REV
to support Linux and Windows differences in the same BIOS.

_REV was defined in ACPI 1.0 to return the version of ACPI
supported by the OS and the OS AML interpreter.

Modern Windows returns _REV = 2. Linux used ACPI_CA_SUPPORT_LEVEL,
which would increment, based on the version of the spec supported.

Unfortunately, _REV was also misused. eg. some BIOS would check
for _REV = 3, and do something for Linux, but when Linux returned
_REV = 4, that support broke.

In response to this problem, Linux returns _REV = 2 always,
from mid-2015 onward. The ACPI specification will also be updated
to reflect that _REV is deprecated, and always returns 2.

Apple Mac and _OSI("Darwin")
----------------------------

On Apple's Mac platforms, the ACPI BIOS invokes _OSI("Darwin")
to determine if the machine is running Apple OSX.

Like Linux's _OSI("*Windows*") strategy, Linux defaults to
answering YES to _OSI("Darwin") to enable full access
to the hardware and validated BIOS paths seen by OSX.
Just like on Windows-tested platforms, this strategy has risks.

Starting in Linux-3.18, the kernel answered YES to _OSI("Darwin")
for the purpose of enabling Mac Thunderbolt support. Further,
if the kernel noticed _OSI("Darwin") being invoked, it additionally
disabled all _OSI("*Windows*") to keep poorly written Mac BIOS
from going down untested combinations of paths.

The Linux-3.18 change in default caused power regressions on Mac
laptops, and the 3.18 implementation did not allow changing
the default via cmdline "acpi_osi=!Darwin". Linux-4.7 fixed
the ability to use acpi_osi=!Darwin as a workaround, and
we hope to see Mac Thunderbolt power management support in Linux-4.11.
1 change: 1 addition & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ config ARM64
select GENERIC_TIME_VSYSCALL
select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND
select HAVE_ACPI_APEI if (ACPI && EFI)
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_BITREVERSE
Expand Down
23 changes: 22 additions & 1 deletion arch/arm64/include/asm/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <asm/cputype.h>
#include <asm/smp_plat.h>
#include <asm/tlbflush.h>

/* Macros for consistency checks of the GICC subtable of MADT */
#define ACPI_MADT_GICC_LENGTH \
Expand Down Expand Up @@ -114,8 +115,28 @@ static inline const char *acpi_get_enable_method(int cpu)
}

#ifdef CONFIG_ACPI_APEI
/*
* acpi_disable_cmcff is used in drivers/acpi/apei/hest.c for disabling
* IA-32 Architecture Corrected Machine Check (CMC) Firmware-First mode
* with a kernel command line parameter "acpi=nocmcoff". But we don't
* have this IA-32 specific feature on ARM64, this definition is only
* for compatibility.
*/
#define acpi_disable_cmcff 1
pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr);
#endif

/*
* Despite its name, this function must still broadcast the TLB
* invalidation in order to ensure other CPUs don't end up with junk
* entries as a result of speculation. Unusually, its also called in
* IRQ context (ghes_iounmap_irq) so if we ever need to use IPIs for
* TLB broadcasting, then we're in trouble here.
*/
static inline void arch_apei_flush_tlb_one(unsigned long addr)
{
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
}
#endif /* CONFIG_ACPI_APEI */

#ifdef CONFIG_ACPI_NUMA
int arm64_acpi_numa_init(void);
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/kernel/acpi/apei.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ int arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, void *data)
struct acpi_hest_ia_corrected *cmc;
struct acpi_hest_ia_error_bank *mc_bank;

if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
return 0;

cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
if (!cmc->enabled)
return 0;
Expand Down
7 changes: 6 additions & 1 deletion drivers/acpi/acpi_apd.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ static const struct apd_device_desc cz_i2c_desc = {
.fixed_clk_rate = 133000000,
};

static const struct apd_device_desc wt_i2c_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 150000000,
};

static struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
Expand Down Expand Up @@ -156,7 +161,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
/* Generic apd devices */
#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
{ "AMD0010", APD_ADDR(cz_i2c_desc) },
{ "AMDI0010", APD_ADDR(cz_i2c_desc) },
{ "AMDI0010", APD_ADDR(wt_i2c_desc) },
{ "AMD0020", APD_ADDR(cz_uart_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
{ "AMD0030", },
Expand Down
Loading

0 comments on commit a67485d

Please sign in to comment.