platform/x86/amd/pmf: Add PMF TEE interface
authorShyam Sundar S K <Shyam-sundar.S-k@amd.com>
Tue, 12 Dec 2023 01:46:54 +0000 (07:16 +0530)
committerHans de Goede <hdegoede@redhat.com>
Mon, 18 Dec 2023 11:47:45 +0000 (12:47 +0100)
AMD PMF driver loads the PMF TA (Trusted Application) into the AMD
ASP's (AMD Security Processor) TEE (Trusted Execution Environment).

PMF Trusted Application is a secured firmware placed under
/lib/firmware/amdtee gets loaded only when the TEE environment is
initialized. Add the initial code path to build these pipes.

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://lore.kernel.org/r/20231212014705.2017474-2-Shyam-sundar.S-k@amd.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/amd/pmf/Kconfig
drivers/platform/x86/amd/pmf/Makefile
drivers/platform/x86/amd/pmf/core.c
drivers/platform/x86/amd/pmf/pmf.h
drivers/platform/x86/amd/pmf/tee-if.c [new file with mode: 0644]

index 3064bc8..32a029e 100644 (file)
@@ -9,6 +9,7 @@ config AMD_PMF
        depends on POWER_SUPPLY
        depends on AMD_NB
        select ACPI_PLATFORM_PROFILE
+       depends on TEE
        help
          This driver provides support for the AMD Platform Management Framework.
          The goal is to enhance end user experience by making AMD PCs smarter,
index fdededf..d2746ee 100644 (file)
@@ -6,4 +6,5 @@
 
 obj-$(CONFIG_AMD_PMF) += amd-pmf.o
 amd-pmf-objs := core.o acpi.o sps.o \
-               auto-mode.o cnqf.o
+               auto-mode.o cnqf.o \
+               tee-if.o
index 78ed3ee..ec92d1c 100644 (file)
@@ -309,13 +309,13 @@ static void amd_pmf_init_features(struct amd_pmf_dev *dev)
                dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
        }
 
-       /* Enable Auto Mode */
-       if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
+       if (!amd_pmf_init_smart_pc(dev)) {
+               dev_dbg(dev->dev, "Smart PC Solution Enabled\n");
+       } else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
                amd_pmf_init_auto_mode(dev);
                dev_dbg(dev->dev, "Auto Mode Init done\n");
        } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
                          is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
-               /* Enable Cool n Quiet Framework (CnQF) */
                ret = amd_pmf_init_cnqf(dev);
                if (ret)
                        dev_warn(dev->dev, "CnQF Init failed\n");
@@ -330,7 +330,9 @@ static void amd_pmf_deinit_features(struct amd_pmf_dev *dev)
                amd_pmf_deinit_sps(dev);
        }
 
-       if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
+       if (!dev->smart_pc_enabled) {
+               amd_pmf_deinit_smart_pc(dev);
+       } else if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
                amd_pmf_deinit_auto_mode(dev);
        } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
                          is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
index deba88e..bd40458 100644 (file)
@@ -179,6 +179,12 @@ struct amd_pmf_dev {
        bool cnqf_enabled;
        bool cnqf_supported;
        struct notifier_block pwr_src_notifier;
+       /* Smart PC solution builder */
+       struct tee_context *tee_ctx;
+       struct tee_shm *fw_shm_pool;
+       u32 session_id;
+       void *shbuf;
+       bool smart_pc_enabled;
 };
 
 struct apmf_sps_prop_granular {
@@ -389,6 +395,13 @@ struct apmf_dyn_slider_output {
        struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
 } __packed;
 
+struct ta_pmf_shared_memory {
+       int command_id;
+       int resp_id;
+       u32 pmf_result;
+       u32 if_version;
+};
+
 /* Core Layer */
 int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
 void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
@@ -433,4 +446,7 @@ void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev);
 int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms);
 extern const struct attribute_group cnqf_feature_attribute_group;
 
+/* Smart PC builder Layer */
+int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev);
+void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev);
 #endif /* PMF_H */
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
new file mode 100644 (file)
index 0000000..6ec8c37
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Platform Management Framework Driver - TEE Interface
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+#include "pmf.h"
+
+#define MAX_TEE_PARAM  4
+static const uuid_t amd_pmf_ta_uuid = UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d,
+                                               0xb1, 0x2d, 0xc5, 0x29, 0xb1, 0x3d, 0x85, 0x43);
+
+static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+       return ver->impl_id == TEE_IMPL_ID_AMDTEE;
+}
+
+static int amd_pmf_ta_open_session(struct tee_context *ctx, u32 *id)
+{
+       struct tee_ioctl_open_session_arg sess_arg = {};
+       int rc;
+
+       export_uuid(sess_arg.uuid, &amd_pmf_ta_uuid);
+       sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
+       sess_arg.num_params = 0;
+
+       rc = tee_client_open_session(ctx, &sess_arg, NULL);
+       if (rc < 0 || sess_arg.ret != 0) {
+               pr_err("Failed to open TEE session err:%#x, rc:%d\n", sess_arg.ret, rc);
+               return rc;
+       }
+
+       *id = sess_arg.session;
+
+       return rc;
+}
+
+static int amd_pmf_tee_init(struct amd_pmf_dev *dev)
+{
+       u32 size;
+       int ret;
+
+       dev->tee_ctx = tee_client_open_context(NULL, amd_pmf_amdtee_ta_match, NULL, NULL);
+       if (IS_ERR(dev->tee_ctx)) {
+               dev_err(dev->dev, "Failed to open TEE context\n");
+               return PTR_ERR(dev->tee_ctx);
+       }
+
+       ret = amd_pmf_ta_open_session(dev->tee_ctx, &dev->session_id);
+       if (ret) {
+               dev_err(dev->dev, "Failed to open TA session (%d)\n", ret);
+               ret = -EINVAL;
+               goto out_ctx;
+       }
+
+       size = sizeof(struct ta_pmf_shared_memory);
+       dev->fw_shm_pool = tee_shm_alloc_kernel_buf(dev->tee_ctx, size);
+       if (IS_ERR(dev->fw_shm_pool)) {
+               dev_err(dev->dev, "Failed to alloc TEE shared memory\n");
+               ret = PTR_ERR(dev->fw_shm_pool);
+               goto out_sess;
+       }
+
+       dev->shbuf = tee_shm_get_va(dev->fw_shm_pool, 0);
+       if (IS_ERR(dev->shbuf)) {
+               dev_err(dev->dev, "Failed to get TEE virtual address\n");
+               ret = PTR_ERR(dev->shbuf);
+               goto out_shm;
+       }
+       dev_dbg(dev->dev, "TEE init done\n");
+
+       return 0;
+
+out_shm:
+       tee_shm_free(dev->fw_shm_pool);
+out_sess:
+       tee_client_close_session(dev->tee_ctx, dev->session_id);
+out_ctx:
+       tee_client_close_context(dev->tee_ctx);
+
+       return ret;
+}
+
+static void amd_pmf_tee_deinit(struct amd_pmf_dev *dev)
+{
+       tee_shm_free(dev->fw_shm_pool);
+       tee_client_close_session(dev->tee_ctx, dev->session_id);
+       tee_client_close_context(dev->tee_ctx);
+}
+
+int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
+{
+       return amd_pmf_tee_init(dev);
+}
+
+void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)
+{
+       amd_pmf_tee_deinit(dev);
+}