Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1368110 > unrolled thread

[RFC PATCH 00/10] ACPI overlays

Started byOctavian Purdila <octavian.purdila@intel.com>
First post2016-03-31 11:40 +0200
Last post2016-03-31 11:50 +0200
Articles 7 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [RFC PATCH 00/10] ACPI overlays Octavian Purdila <octavian.purdila@intel.com> - 2016-03-31 11:40 +0200
    [RFC PATCH 08/10] configfs: fix CONFIGFS_BIN_ATTR_[RW]O definitions Octavian Purdila <octavian.purdila@intel.com> - 2016-03-31 11:40 +0200
    [RFC PATCH 02/10] acpi: install SSDT tables from initrd Octavian Purdila <octavian.purdila@intel.com> - 2016-03-31 11:50 +0200
      RE: [RFC PATCH 02/10] acpi: install SSDT tables from initrd "Zheng, Lv" <lv.zheng@intel.com> - 2016-04-01 07:10 +0200
        Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd Octavian Purdila <octavian.purdila@intel.com> - 2016-04-01 12:20 +0200
    [RFC PATCH 05/10] i2c: add support for ACPI reconfigure notifications Octavian Purdila <octavian.purdila@intel.com> - 2016-03-31 11:50 +0200
    [RFC PATCH 07/10] efi: load SSTDs from EFI variables Octavian Purdila <octavian.purdila@intel.com> - 2016-03-31 11:50 +0200

#1368110 — [RFC PATCH 00/10] ACPI overlays

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-03-31 11:40 +0200
Subject[RFC PATCH 00/10] ACPI overlays
Message-ID<riHf4-2VE-13@gated-at.bofh.it>
This patch set enables custom ACPI board configuration by adding
mechanisms in the Linux kernel for loading user defined SSDTs.

In order to support ACPI open-ended hardware configurations we need a
way to augment the ACPI configuration provided by the firmware
image. A common example is connecting sensors on I2C / SPI buses on
development boards.

Although this can be accomplished by creating a kernel platform driver
or recompiling the firmware image with updated ACPI tables, neither is
practical: the former proliferates board specific kernel code while
the latter requires access to firmware tools which are often not
publicly available.

Because ACPI supports external references in AML code a more practical
way to augment firmware ACPI configuration is by dynamically loading
user defined SSDT tables that contain the board specific information.

This patch sets provides three methods for loading custom SSDTs:

* From an EFI variable

  This is the preferred method, when EFI is supported on the platform,
  because it allows a persistent, OS independent way of storing and
  updating the user defined SSDTs. There is also work underway to
  implement EFI support for loading user defined SSDTs and using this
  method will make it easier to convert to the EFI loading mechanism
  when that will arrive.

* From the first uncompressed initrd (similar with the override
  functionality)

  This is useful when EFI is not supported on the platform and when it
  is not possible to defer the loading to userspace.

* From userspace via configfs 

  This is useful when we want to defer the operation to userspace for
  platform detection, loading the SSDTs from a custom partition, etc.

Octavian Purdila (10):
  kernel: add TAINT_OVERLAY_ACPI_TABLE
  acpi: install SSDT tables from initrd
  acpi: add support for ACPI reconfiguration notifiers
  acpi: fix enumeration (visited) flags for bus rescans
  i2c: add support for ACPI reconfigure notifications
  spi: add support for ACPI reconfigure notifications
  efi: load SSTDs from EFI variables
  configfs: fix CONFIGFS_BIN_ATTR_[RW]O definitions
  acpi: add support for configfs
  acpi: add support for loading SSDTs via configfs

 Documentation/ABI/testing/configfs-acpi |  23 +++++
 Documentation/acpi/ssdt-overlays.txt    | 174 ++++++++++++++++++++++++++++++++
 Documentation/kernel-parameters.txt     |   7 ++
 Documentation/oops-tracing.txt          |   2 +
 Documentation/sysctl/kernel.txt         |   1 +
 MAINTAINERS                             |   1 +
 drivers/acpi/Kconfig                    |   9 ++
 drivers/acpi/Makefile                   |   1 +
 drivers/acpi/bus.c                      |  72 +++++++++++++
 drivers/acpi/configfs.c                 | 143 ++++++++++++++++++++++++++
 drivers/acpi/internal.h                 |   3 +
 drivers/acpi/scan.c                     |  73 +++++++++++++-
 drivers/acpi/sysfs.c                    |   6 +-
 drivers/firmware/efi/efi.c              | 107 ++++++++++++++++++++
 drivers/i2c/i2c-core.c                  |  38 ++++++-
 drivers/spi/spi.c                       |  36 ++++++-
 include/acpi/acpi_bus.h                 |   8 ++
 include/linux/configfs.h                |   4 +-
 include/linux/kernel.h                  |   1 +
 kernel/panic.c                          |   2 +
 20 files changed, 699 insertions(+), 12 deletions(-)
 create mode 100644 Documentation/ABI/testing/configfs-acpi
 create mode 100644 Documentation/acpi/ssdt-overlays.txt
 create mode 100644 drivers/acpi/configfs.c

-- 
1.9.1

[toc] | [next] | [standalone]


#1368112 — [RFC PATCH 08/10] configfs: fix CONFIGFS_BIN_ATTR_[RW]O definitions

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-03-31 11:40 +0200
Subject[RFC PATCH 08/10] configfs: fix CONFIGFS_BIN_ATTR_[RW]O definitions
Message-ID<riHf6-2VE-53@gated-at.bofh.it>
In reply to#1368110
The type should be struct configfs_bin_attribute and not struct
configfs_attribute.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 include/linux/configfs.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index f8165c1..ada0613 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -181,7 +181,7 @@ static struct configfs_bin_attribute _pfx##attr_##_name = {	\
 }
 
 #define CONFIGFS_BIN_ATTR_RO(_pfx, _name, _priv, _maxsz)	\
-static struct configfs_attribute _pfx##attr_##_name = {		\
+static struct configfs_bin_attribute _pfx##attr_##_name = {	\
 	.cb_attr = {						\
 		.ca_name	= __stringify(_name),		\
 		.ca_mode	= S_IRUGO,			\
@@ -193,7 +193,7 @@ static struct configfs_attribute _pfx##attr_##_name = {		\
 }
 
 #define CONFIGFS_BIN_ATTR_WO(_pfx, _name, _priv, _maxsz)	\
-static struct configfs_attribute _pfx##attr_##_name = {		\
+static struct configfs_bin_attribute _pfx##attr_##_name = {	\
 	.cb_attr = {						\
 		.ca_name	= __stringify(_name),		\
 		.ca_mode	= S_IWUSR,			\
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1368115 — [RFC PATCH 02/10] acpi: install SSDT tables from initrd

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-03-31 11:50 +0200
Subject[RFC PATCH 02/10] acpi: install SSDT tables from initrd
Message-ID<riHoK-2Z1-7@gated-at.bofh.it>
In reply to#1368110
This patch allows loading user defined SSDTs from the first,
uncompressed, initrd. The SSDT aml code must be stored in files under
the /kernel/firmware/acpi/overlay path.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/acpi/ssdt-overlays.txt | 94 ++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                   | 63 ++++++++++++++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 Documentation/acpi/ssdt-overlays.txt

diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt
new file mode 100644
index 0000000..a94c3f9
--- /dev/null
+++ b/Documentation/acpi/ssdt-overlays.txt
@@ -0,0 +1,94 @@
+
+In order to support ACPI open-ended hardware configurations (e.g. development
+boards) we need a way to augment the ACPI configuration provided by the firmware
+image. A common example is connecting sensors on I2C / SPI buses on development
+boards.
+
+Although this can be accomplished by creating a kernel platform driver or
+recompiling the firmware image with updated ACPI tables, neither is practical:
+the former proliferates board specific kernel code while the latter requires
+access to firmware tools which are often not publicly available.
+
+Because ACPI supports external references in AML code a more practical
+way to augment firmware ACPI configuration is by dynamically loading
+user defined SSDT tables that contain the board specific information.
+
+For example, to enumerate a Bosch BMA222E accelerometer on the I2C bus of the
+Minnowboard MAX development board exposed via the LSE connector [1], the
+following ASL code can be used:
+
+DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003)
+{
+    External (\_SB.I2C6, DeviceObj)
+
+    Scope (\_SB.I2C6)
+    {
+        Device (STAC)
+        {
+            Name (_ADR, Zero)
+            Name (_HID, "BMA222E")
+
+            Method (_CRS, 0, Serialized)
+            {
+                Name (RBUF, ResourceTemplate ()
+                {
+                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
+                                  AddressingMode7Bit, "\\_SB.I2C6", 0x00,
+                                  ResourceConsumer, ,)
+                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
+                             "\\_SB.GPO2", 0x00, ResourceConsumer, , )
+                    { // Pin list
+                        0
+                    }
+                })
+                Return (RBUF)
+            }
+        }
+    }
+}
+
+which can then be compiled to AML binary format:
+
+$ iasl minnowmax.asl
+
+Intel ACPI Component Architecture
+ASL Optimizing Compiler version 20140214-64 [Mar 29 2014]
+Copyright (c) 2000 - 2014 Intel Corporation
+
+ASL Input:     minnomax.asl - 30 lines, 614 bytes, 7 keywords
+AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes
+
+[1] http://wiki.minnowboard.org/MinnowBoard_MAX#Low_Speed_Expansion_Connector_.28Top.29
+
+The resulting AML code can then be loaded by the kernel using one of the methods
+below.
+
+== Loading ACPI SSDTs from initrd ==
+
+This option allows loading of user defined SSDTs from initrd and it is useful
+when the system does not support EFI or when there is not enough EFI storage.
+
+It works in a similar way with initrd based ACPI tables overrides: SSDT aml code
+must be placed in the first, uncompressed, initrd under the
+"kernel/firmware/acpi/overlay" path. We use a different path than the initrd
+tables override to avoid conflicts with the override feature.
+
+Multiple files can be used and this will translate in loading multiple
+tables. Only tables with the SSDT signature will be loaded.
+
+Here is an example:
+
+# Add the raw ACPI tables to an uncompressed cpio archive.
+# They must be put into a /kernel/firmware/acpi/overlay directory inside the
+# cpio archive.
+# The uncompressed cpio archive must be the first.
+# Other, typically compressed cpio archives, must be
+# concatenated on top of the uncompressed one.
+mkdir -p kernel/firmware/acpi
+cp ssdt.aml kernel/firmware/acpi
+
+# Create the uncompressed cpio archive and concatenate the original initrd
+# on top:
+find kernel | cpio -H newc --create > /boot/instrumented_initrd
+cat /boot/initrd >>/boot/instrumented_initrd
+
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 891c42d..5e0d076 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,9 +37,14 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/initrd.h>
+#include <linux/earlycpio.h>
 
 #include "internal.h"
 
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI: " fmt
+
 #define _COMPONENT		ACPI_BUS_COMPONENT
 ACPI_MODULE_NAME("bus");
 
@@ -863,6 +868,62 @@ static int __init acpi_bus_init_irq(void)
 	return 0;
 }
 
+void __init acpi_load_initrd_ssdts(void)
+{
+	void *data = (void *)initrd_start;
+	int size = initrd_end - initrd_start;
+	const char *path = "kernel/firmware/acpi/overlay";
+	long offset = 0;
+	struct cpio_data file;
+	struct acpi_table_header *header;
+	void *table;
+	acpi_status status;
+
+	while (true) {
+		file = find_cpio_data(path, data, size, &offset);
+		if (!file.data)
+			break;
+
+		data += offset;
+		size -= offset;
+
+		if (file.size < sizeof(struct acpi_table_header)) {
+			pr_err("initrd table smaller than ACPI header [%s%s]\n",
+			       path, file.name);
+			continue;
+		}
+
+		header = file.data;
+
+		if (file.size != header->length) {
+			pr_err("initrd file / table length mismatch [%s%s]\n",
+			       path, file.name);
+			continue;
+		}
+
+		if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
+			pr_warn("skipping non-SSDT initrd table [%s%s]\n",
+				path, file.name);
+			continue;
+		}
+
+		table = kmemdup(file.data, file.size, GFP_KERNEL);
+		if (!table)
+			continue;
+
+		status = acpi_install_table((uintptr_t)table, 0);
+		if (ACPI_FAILURE(status)) {
+			pr_err("failed to install SSDT from initrd [%s%s]\n",
+			       path, file.name);
+			kfree(table);
+		}
+
+		pr_info("installed SSDT table found in initrd [%s%s][0x%x]\n",
+			path, file.name, header->length);
+		add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
+	}
+}
+
 /**
  * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
  *
@@ -911,6 +972,8 @@ void __init acpi_early_init(void)
 		goto error0;
 	}
 
+	acpi_load_initrd_ssdts();
+
 	status = acpi_load_tables();
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1369003 — RE: [RFC PATCH 02/10] acpi: install SSDT tables from initrd

From"Zheng, Lv" <lv.zheng@intel.com>
Date2016-04-01 07:10 +0200
SubjectRE: [RFC PATCH 02/10] acpi: install SSDT tables from initrd
Message-ID<riZvk-84e-3@gated-at.bofh.it>
In reply to#1368115
Hi,

IMO, there is already a similar function upstreamed:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85cc81
Could it work for your use case?

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> owner@vger.kernel.org] On Behalf Of Octavian Purdila
> Subject: [RFC PATCH 02/10] acpi: install SSDT tables from initrd
> 
> This patch allows loading user defined SSDTs from the first,
> uncompressed, initrd. The SSDT aml code must be stored in files under
> the /kernel/firmware/acpi/overlay path.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  Documentation/acpi/ssdt-overlays.txt | 94
> ++++++++++++++++++++++++++++++++++++
>  drivers/acpi/bus.c                   | 63 ++++++++++++++++++++++++
>  2 files changed, 157 insertions(+)
>  create mode 100644 Documentation/acpi/ssdt-overlays.txt
> 
> diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-
> overlays.txt
> new file mode 100644
> index 0000000..a94c3f9
> --- /dev/null
> +++ b/Documentation/acpi/ssdt-overlays.txt
> @@ -0,0 +1,94 @@
> +
> +In order to support ACPI open-ended hardware configurations (e.g.
> development
> +boards) we need a way to augment the ACPI configuration provided by the
> firmware
> +image. A common example is connecting sensors on I2C / SPI buses on
> development
> +boards.
> +
> +Although this can be accomplished by creating a kernel platform driver or
> +recompiling the firmware image with updated ACPI tables, neither is practical:
> +the former proliferates board specific kernel code while the latter requires
> +access to firmware tools which are often not publicly available.
> +
> +Because ACPI supports external references in AML code a more practical
> +way to augment firmware ACPI configuration is by dynamically loading
> +user defined SSDT tables that contain the board specific information.
> +
> +For example, to enumerate a Bosch BMA222E accelerometer on the I2C bus
> of the
> +Minnowboard MAX development board exposed via the LSE connector [1],
> the
> +following ASL code can be used:
> +
> +DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003)
> +{
> +    External (\_SB.I2C6, DeviceObj)
> +
> +    Scope (\_SB.I2C6)
> +    {
> +        Device (STAC)
> +        {
> +            Name (_ADR, Zero)
> +            Name (_HID, "BMA222E")
> +
> +            Method (_CRS, 0, Serialized)
> +            {
> +                Name (RBUF, ResourceTemplate ()
> +                {
> +                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
> +                                  AddressingMode7Bit, "\\_SB.I2C6", 0x00,
> +                                  ResourceConsumer, ,)
> +                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
> +                             "\\_SB.GPO2", 0x00, ResourceConsumer, , )
> +                    { // Pin list
> +                        0
> +                    }
> +                })
> +                Return (RBUF)
> +            }
> +        }
> +    }
> +}
> +
> +which can then be compiled to AML binary format:
> +
> +$ iasl minnowmax.asl
> +
> +Intel ACPI Component Architecture
> +ASL Optimizing Compiler version 20140214-64 [Mar 29 2014]
> +Copyright (c) 2000 - 2014 Intel Corporation
> +
> +ASL Input:     minnomax.asl - 30 lines, 614 bytes, 7 keywords
> +AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable
> opcodes
> +
> +[1]
> http://wiki.minnowboard.org/MinnowBoard_MAX#Low_Speed_Expansion_Co
> nnector_.28Top.29
> +
> +The resulting AML code can then be loaded by the kernel using one of the
> methods
> +below.
> +
> +== Loading ACPI SSDTs from initrd ==
> +
> +This option allows loading of user defined SSDTs from initrd and it is useful
> +when the system does not support EFI or when there is not enough EFI
> storage.
> +
> +It works in a similar way with initrd based ACPI tables overrides: SSDT aml
> code
> +must be placed in the first, uncompressed, initrd under the
> +"kernel/firmware/acpi/overlay" path. We use a different path than the initrd
> +tables override to avoid conflicts with the override feature.
> +
> +Multiple files can be used and this will translate in loading multiple
> +tables. Only tables with the SSDT signature will be loaded.
> +
> +Here is an example:
> +
> +# Add the raw ACPI tables to an uncompressed cpio archive.
> +# They must be put into a /kernel/firmware/acpi/overlay directory inside the
> +# cpio archive.
> +# The uncompressed cpio archive must be the first.
> +# Other, typically compressed cpio archives, must be
> +# concatenated on top of the uncompressed one.
> +mkdir -p kernel/firmware/acpi
> +cp ssdt.aml kernel/firmware/acpi
> +
> +# Create the uncompressed cpio archive and concatenate the original initrd
> +# on top:
> +find kernel | cpio -H newc --create > /boot/instrumented_initrd
> +cat /boot/initrd >>/boot/instrumented_initrd
> +
> diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
> index 891c42d..5e0d076 100644
> --- a/drivers/acpi/bus.c
> +++ b/drivers/acpi/bus.c
> @@ -37,9 +37,14 @@
>  #include <acpi/apei.h>
>  #include <linux/dmi.h>
>  #include <linux/suspend.h>
> +#include <linux/initrd.h>
> +#include <linux/earlycpio.h>
> 
>  #include "internal.h"
> 
> +#undef pr_fmt
> +#define pr_fmt(fmt) "ACPI: " fmt
> +
>  #define _COMPONENT		ACPI_BUS_COMPONENT
>  ACPI_MODULE_NAME("bus");
> 
> @@ -863,6 +868,62 @@ static int __init acpi_bus_init_irq(void)
>  	return 0;
>  }
> 
> +void __init acpi_load_initrd_ssdts(void)
> +{
> +	void *data = (void *)initrd_start;
> +	int size = initrd_end - initrd_start;
> +	const char *path = "kernel/firmware/acpi/overlay";
> +	long offset = 0;
> +	struct cpio_data file;
> +	struct acpi_table_header *header;
> +	void *table;
> +	acpi_status status;
> +
> +	while (true) {
> +		file = find_cpio_data(path, data, size, &offset);
> +		if (!file.data)
> +			break;
> +
> +		data += offset;
> +		size -= offset;
> +
> +		if (file.size < sizeof(struct acpi_table_header)) {
> +			pr_err("initrd table smaller than ACPI header
> [%s%s]\n",
> +			       path, file.name);
> +			continue;
> +		}
> +
> +		header = file.data;
> +
> +		if (file.size != header->length) {
> +			pr_err("initrd file / table length mismatch [%s%s]\n",
> +			       path, file.name);
> +			continue;
> +		}
> +
> +		if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
> +			pr_warn("skipping non-SSDT initrd table [%s%s]\n",
> +				path, file.name);
> +			continue;
> +		}
> +
> +		table = kmemdup(file.data, file.size, GFP_KERNEL);
> +		if (!table)
> +			continue;
> +
> +		status = acpi_install_table((uintptr_t)table, 0);
> +		if (ACPI_FAILURE(status)) {
> +			pr_err("failed to install SSDT from initrd [%s%s]\n",
> +			       path, file.name);
> +			kfree(table);
> +		}
> +
> +		pr_info("installed SSDT table found in initrd [%s%s][0x%x]\n",
> +			path, file.name, header->length);
> +		add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
> +	}
> +}
> +
[Lv Zheng] 
I can see that this is so similar to the acpi_initrd_initialize_tables() which is in the drivers/acpi/osl.c.
Please check.

Thanks and best regards
-Lv

>  /**
>   * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
>   *
> @@ -911,6 +972,8 @@ void __init acpi_early_init(void)
>  		goto error0;
>  	}
> 
> +	acpi_load_initrd_ssdts();
> +
>  	status = acpi_load_tables();
>  	if (ACPI_FAILURE(status)) {
>  		printk(KERN_ERR PREFIX
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[toc] | [prev] | [next] | [standalone]


#1369156 — Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-04-01 12:20 +0200
SubjectRe: [RFC PATCH 02/10] acpi: install SSDT tables from initrd
Message-ID<rj4lk-2Pw-11@gated-at.bofh.it>
In reply to#1369003
On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:
> Hi,
>
> IMO, there is already a similar function upstreamed:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85cc81
> Could it work for your use case?

Yes, it is basically the same.

The only difference is on how we handle taint. I think we should use a
new taint for overlays and that we don't need to disable lockdep.

BTW, why is lockdep disabled when we override?

[toc] | [prev] | [next] | [standalone]


#1368120 — [RFC PATCH 05/10] i2c: add support for ACPI reconfigure notifications

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-03-31 11:50 +0200
Subject[RFC PATCH 05/10] i2c: add support for ACPI reconfigure notifications
Message-ID<riHoK-2Z1-23@gated-at.bofh.it>
In reply to#1368110
This allows the i2c core to enumerate devices from ACPI tables that
are dynamically loaded after the i2c adapter has been probed.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 drivers/i2c/i2c-core.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ffe715d..7a6f741 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -150,7 +150,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
 
 	if (acpi_bus_get_device(handle, &adev))
 		return AE_OK;
-	if (acpi_bus_get_status(adev) || !adev->status.present)
+	if (acpi_bus_get_status(adev) || !adev->status.present ||
+	    acpi_device_enumerated(adev))
 		return AE_OK;
 
 	memset(&info, 0, sizeof(info));
@@ -189,6 +190,9 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
 
 	adev->power.flags.ignore_parent = true;
 	strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
+
+	adev->flags.visited = true;
+
 	if (!i2c_new_device(adapter, &info)) {
 		adev->power.flags.ignore_parent = false;
 		dev_err(&adapter->dev,
@@ -224,8 +228,36 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap)
 		dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
 }
 
+static int acpi_i2c_table_load(struct device *dev, void *data)
+{
+	struct i2c_adapter *adapter = i2c_verify_adapter(dev);
+
+	if (!adapter)
+		return 0;
+
+	acpi_i2c_register_devices(adapter);
+	return 0;
+}
+
+static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value,
+			   void *arg)
+{
+	switch (value) {
+	case ACPI_RECONFIG_TABLE_LOAD:
+		bus_find_device(&i2c_bus_type, NULL, NULL,
+				acpi_i2c_table_load);
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block i2c_acpi_notifier = {
+	.notifier_call = acpi_i2c_notify,
+};
 #else /* CONFIG_ACPI */
 static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
+extern struct notifier_block i2c_acpi_notifier;
 #endif /* CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI_I2C_OPREGION
@@ -2117,6 +2149,8 @@ static int __init i2c_init(void)
 
 	if (IS_ENABLED(CONFIG_OF_DYNAMIC))
 		WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));
+	if (IS_ENABLED(CONFIG_ACPI))
+		WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier));
 
 	return 0;
 
@@ -2131,6 +2165,8 @@ bus_err:
 
 static void __exit i2c_exit(void)
 {
+	if (IS_ENABLED(CONFIG_ACPI))
+		WARN_ON(acpi_reconfig_notifier_unregister(&i2c_acpi_notifier));
 	if (IS_ENABLED(CONFIG_OF_DYNAMIC))
 		WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
 	i2c_del_driver(&dummy_driver);
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1368121 — [RFC PATCH 07/10] efi: load SSTDs from EFI variables

FromOctavian Purdila <octavian.purdila@intel.com>
Date2016-03-31 11:50 +0200
Subject[RFC PATCH 07/10] efi: load SSTDs from EFI variables
Message-ID<riHoK-2Z1-29@gated-at.bofh.it>
In reply to#1368110
This patch allows SSDTs to be loaded from EFI variables. It works by
specifying the EFI variable name containing the SSDT to be loaded. All
variables with the same name (regardless of the vendor GUID) will be
loaded.

Note that we can't use acpi_install_table and we must rely on the
dynamic ACPI table loading and bus re-scanning mechanisms. That is
because I2C/SPI controllers are initialized earlier then the EFI
subsystems and all I2C/SPI ACPI devices are enumerated when the
I2C/SPI controllers are initialized.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/acpi/ssdt-overlays.txt |  66 +++++++++++++++++++++
 Documentation/kernel-parameters.txt  |   7 +++
 drivers/firmware/efi/efi.c           | 107 +++++++++++++++++++++++++++++++++++
 3 files changed, 180 insertions(+)

diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt
index a94c3f9..7c588be 100644
--- a/Documentation/acpi/ssdt-overlays.txt
+++ b/Documentation/acpi/ssdt-overlays.txt
@@ -92,3 +92,69 @@ cp ssdt.aml kernel/firmware/acpi
 find kernel | cpio -H newc --create > /boot/instrumented_initrd
 cat /boot/initrd >>/boot/instrumented_initrd
 
+== Loading ACPI SSDTs from EFI variables ==
+
+This is the preferred method, when EFI is supported on the platform, because it
+allows a persistent, OS independent way of storing the user defined SSDTs. There
+is also work underway to implement EFI support for loading user defined SSDTs
+and using this method will make it easier to convert to the EFI loading
+mechanism when that will arrive.
+
+In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line
+parameter can be used. The argument for the option is the variable name to
+use. If there are multiple variables with the same name but with different
+vendor GUIDs, all of them will be loaded.
+
+In order to store the AML code in an EFI variable the efivarfs filesystem can be
+used. It is enabled and mounted by default in /sys/firmware/efi/efivars in all
+recent distribution.
+
+Creating a new file in /sys/firmware/efi/efivars will automatically create a new
+EFI variable. Updating a file in /sys/firmware/efi/efivars will update the EFI
+variable. Please note that the file name needs to be specially formatted as
+"Name-GUID" and that the first 4 bytes in the file (little-endian format)
+represent the attributes of the EFI variable (see EFI_VARIABLE_MASK in
+include/linux/efi.h). Writing to the file must also be done with one write
+operation.
+
+For example, you can use the following bash script to create/update an EFI
+variable with the content from a given file:
+
+#!/bin/sh -e
+
+while ! [ -z "$1" ]; do
+        case "$1" in
+        "-f") filename="$2"; shift;;
+        "-g") guid="$2"; shift;;
+        *) name="$1";;
+        esac
+        shift
+done
+
+if [ -z "$name" ] || [ -z "$filename" ]; then
+    echo "Syntax: ${0##*/} -f filename [ -g guid ] name"
+    exit 1
+fi
+
+EFIVARFS='/sys/firmware/efi/efivars'
+
+[ -d "$EFIVARFS" ] || exit 2
+
+if stat -tf $EFIVARFS | grep -q -v de5e81e4; then
+        mount -t efivarfs none $EFIVARFS
+fi
+
+# try to pick up an existing GUID
+if [ -z "$guid" ]; then
+        guid=$(find "$EFIVARFS" -name "$name-*" | head -n1 | cut -f2- -d-)
+fi
+
+# use a randomly generated GUID
+if [ -z "$guid" ]; then
+        guid="$(cat /proc/sys/kernel/random/uuid)"
+fi
+
+tmp=$(mktemp)
+/bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp
+dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp)
+rm $tmp
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a53c92..fe89cda 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1144,6 +1144,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Address Range Mirroring feature even if your box
 			doesn't support it.
 
+	efivar_ssdt=	[EFI; X86] Name of an EFI variable that contains an SSDT
+			that is to be dynamically loaded by Linux. If there are
+			multiple variables with the same name but with different
+			vendor GUIDs, all of them will be loaded. See
+			Documentation/acpi/ssdt-overlays.txt for details.
+
+
 	eisa_irq_edge=	[PARISC,HW]
 			See header of drivers/parisc/eisa.c.
 
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 2cd37da..dda4778 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -24,6 +24,8 @@
 #include <linux/of_fdt.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
 
 #include <asm/early_ioremap.h>
 
@@ -193,6 +195,108 @@ static void generic_ops_unregister(void)
 	efivars_unregister(&generic_efivars);
 }
 
+#if IS_ENABLED(CONFIG_ACPI)
+#define EFIVAR_SSDT_NAME_MAX	16
+static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX];
+static int __init efivar_ssdt_setup(char *str)
+{
+	if (strlen(str) < sizeof(efivar_ssdt))
+		memcpy(efivar_ssdt, str, strlen(str));
+	else
+		pr_warn("efivar_ssdt: name too long: %s\n", str);
+	return 0;
+}
+__setup("efivar_ssdt=", efivar_ssdt_setup);
+
+static LIST_HEAD(efivar_ssdts);
+
+static inline void pr_efivar_name(efi_char16_t *name16)
+{
+	char name[EFIVAR_SSDT_NAME_MAX];
+	int i;
+
+	for (i = 0; i < EFIVAR_SSDT_NAME_MAX - 1; i++)
+		name[i] = name16[i] & 0xFF;
+	name[i] = 0;
+	pr_cont("%s", name);
+}
+
+static __init int efivar_acpi_iter(efi_char16_t *name, efi_guid_t vendor,
+				   unsigned long name_size, void *data)
+{
+	int i;
+	int str_len = name_size / sizeof(efi_char16_t);
+	struct efivar_entry *entry;
+
+	if (str_len != strlen(efivar_ssdt) + 1)
+		return 0;
+
+	for (i = 0; i < str_len; i++)
+		if ((name[i] & 0xFF) != efivar_ssdt[i])
+			return 0;
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	memcpy(entry->var.VariableName, name, name_size);
+	memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t));
+
+	efivar_entry_add(entry, &efivar_ssdts);
+
+	return 0;
+}
+
+static __init int efivar_ssdt_load(void)
+{
+	struct efivar_entry *i;
+	int err;
+
+	err = efivar_init(efivar_acpi_iter, NULL, false, false,
+			  &efivar_ssdts);
+	if (err) {
+		pr_err("%s: efivar_init failed: %d\n", __func__, err);
+		return err;
+	}
+
+	list_for_each_entry(i, &efivar_ssdts, list) {
+		void *data;
+		unsigned long size;
+
+		pr_info("loading SSDT from EFI variable ");
+		pr_efivar_name(i->var.VariableName); pr_cont("\n");
+
+		err = efivar_entry_size(i, &size);
+		if (err) {
+			pr_err("failed to get size\n");
+			continue;
+		}
+
+		data = kmalloc(size, GFP_KERNEL);
+		if (!data)
+			continue;
+
+		err = efivar_entry_get(i, NULL, &size, data);
+		if (err) {
+			pr_err("failed to get data\n");
+			kfree(data);
+			continue;
+		}
+
+		err = acpi_load_table(data);
+		if (err) {
+			pr_err("failed to load table: %d\n", err);
+			kfree(data);
+			continue;
+		}
+
+		add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
+	}
+
+	return 0;
+}
+#endif
+
 /*
  * We register the efi subsystem with the firmware subsystem and the
  * efivars subsystem with the efi subsystem, if the system was booted with
@@ -216,6 +320,9 @@ static int __init efisubsys_init(void)
 	if (error)
 		goto err_put;
 
+	if (IS_ENABLED(CONFIG_ACPI))
+		efivar_ssdt_load();
+
 	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
 	if (error) {
 		pr_err("efi: Sysfs attribute export failed with error %d.\n",
-- 
1.9.1

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web