]> git.itanic.dy.fi Git - linux-stable/commitdiff
ACPI: Implement a generic FFH Opregion handler
authorSudeep Holla <sudeep.holla@arm.com>
Thu, 10 Nov 2022 13:45:04 +0000 (13:45 +0000)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 14 Nov 2022 18:09:07 +0000 (19:09 +0100)
This registers the FFH OpRegion handler before ACPI tables are
loaded. The platform support for the same is checked via Platform-Wide
OSPM Capabilities(OSC) before registering the OpRegion handler.

It relies on the special context data passed to offset and the length.
However the interpretation of the values is platform/architecture
specific. This generic handler just passed all the information to
the platform/architecture specific callback. It also implements the
default callbacks which return as not supported.

Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_ffh.c [new file with mode: 0644]
drivers/acpi/bus.c
include/linux/acpi.h

index 473241b5193fa1dc7f20a8def9fb1bfa9c2f8130..06508674a30bfb8af625019c8ac420671241bd29 100644 (file)
@@ -564,6 +564,16 @@ config ACPI_PCC
          Enable this feature if you want to set up and install the PCC Address
          Space handler to handle PCC OpRegion in the firmware.
 
+config ACPI_FFH
+       bool "ACPI FFH Address Space"
+       default n
+       help
+         The FFH(Fixed Function Hardware) Address Space also referred as FFH
+         Operation Region allows to define platform specific opregion.
+
+         Enable this feature if you want to set up and install the FFH Address
+         Space handler to handle FFH OpRegion in the firmware.
+
 source "drivers/acpi/pmic/Kconfig"
 
 config ACPI_VIOT
index 0002eecbf870a074ec4bb07bba33aeeef9c6ee89..feb36c0b9446052158655648aea3a62f5f3d97eb 100644 (file)
@@ -68,6 +68,7 @@ acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o
 acpi-$(CONFIG_ACPI_WATCHDOG)   += acpi_watchdog.o
 acpi-$(CONFIG_ACPI_PRMT)       += prmt.o
 acpi-$(CONFIG_ACPI_PCC)                += acpi_pcc.o
+acpi-$(CONFIG_ACPI_FFH)                += acpi_ffh.o
 
 # Address translation
 acpi-$(CONFIG_ACPI_ADXL)       += acpi_adxl.o
diff --git a/drivers/acpi/acpi_ffh.c b/drivers/acpi/acpi_ffh.c
new file mode 100644 (file)
index 0000000..19aff80
--- /dev/null
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Author: Sudeep Holla <sudeep.holla@arm.com>
+ * Copyright 2022 Arm Limited
+ */
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/completion.h>
+#include <linux/idr.h>
+#include <linux/io.h>
+
+#include <linux/arm-smccc.h>
+
+static struct acpi_ffh_info ffh_ctx;
+
+int __weak acpi_ffh_address_space_arch_setup(void *handler_ctxt,
+                                            void **region_ctxt)
+{
+       return -EOPNOTSUPP;
+}
+
+int __weak acpi_ffh_address_space_arch_handler(acpi_integer *value,
+                                              void *region_context)
+{
+       return -EOPNOTSUPP;
+}
+
+static acpi_status
+acpi_ffh_address_space_setup(acpi_handle region_handle, u32 function,
+                            void *handler_context,  void **region_context)
+{
+       return acpi_ffh_address_space_arch_setup(handler_context,
+                                                region_context);
+}
+
+static acpi_status
+acpi_ffh_address_space_handler(u32 function, acpi_physical_address addr,
+                              u32 bits, acpi_integer *value,
+                              void *handler_context, void *region_context)
+{
+       return acpi_ffh_address_space_arch_handler(value, region_context);
+}
+
+void __init acpi_init_ffh(void)
+{
+       acpi_status status;
+
+       status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
+                                                   ACPI_ADR_SPACE_FIXED_HARDWARE,
+                                                   &acpi_ffh_address_space_handler,
+                                                   &acpi_ffh_address_space_setup,
+                                                   &ffh_ctx);
+       if (ACPI_FAILURE(status))
+               pr_alert("OperationRegion handler could not be installed\n");
+}
index d466c81953146b92acd6a1ac4615d7f471f8fd9c..245fb0828e473684130a3e52d6fde552fde3a697 100644 (file)
@@ -300,6 +300,8 @@ EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
 
 bool osc_sb_cppc2_support_acked;
 
+bool osc_sb_ffh_opregion_support_confirmed;
+
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_negotiate_platform_control(void)
 {
@@ -383,6 +385,8 @@ static void acpi_bus_osc_negotiate_platform_control(void)
                        capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT;
                osc_cpc_flexible_adr_space_confirmed =
                        capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_CPC_FLEXIBLE_ADR_SPACE;
+               osc_sb_ffh_opregion_support_confirmed =
+                       capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_FFH_OPR_SUPPORT;
        }
 
        kfree(context.ret.pointer);
@@ -1408,6 +1412,8 @@ static int __init acpi_init(void)
                disable_acpi();
                return result;
        }
+       if (osc_sb_ffh_opregion_support_confirmed)
+               acpi_init_ffh();
 
        pci_mmcfg_late_init();
        acpi_iort_init();
index 3015235d65e317b4e53c93030fce27816f902b26..c026c1129cba3d2e76ae92f3e8dabf08eb257eb7 100644 (file)
@@ -586,6 +586,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 #define OSC_SB_CPC_FLEXIBLE_ADR_SPACE          0x00004000
 #define OSC_SB_NATIVE_USB4_SUPPORT             0x00040000
 #define OSC_SB_PRM_SUPPORT                     0x00200000
+#define OSC_SB_FFH_OPR_SUPPORT                 0x00400000
 
 extern bool osc_sb_apei_support_acked;
 extern bool osc_pc_lpi_support_confirmed;
@@ -1488,6 +1489,12 @@ void acpi_init_pcc(void);
 static inline void acpi_init_pcc(void) { }
 #endif
 
+#ifdef CONFIG_ACPI_FFH
+void acpi_init_ffh(void);
+#else
+static inline void acpi_init_ffh(void) { }
+#endif
+
 #ifdef CONFIG_ACPI
 extern void acpi_device_notify(struct device *dev);
 extern void acpi_device_notify_remove(struct device *dev);