On 10/11/2023 8:47 AM, Shyam Sundar S K wrote: > > > On 10/10/2023 9:56 PM, Mario Limonciello wrote: >> On 10/10/2023 07:59, Shyam Sundar S K wrote: >>> PMF Policy binary is a encrypted and signed binary that will be part >>> of the BIOS. PMF driver via the ACPI interface checks the existence >>> of Smart PC bit. If the advertised bit is found, PMF driver walks >>> the acpi namespace to find out the policy binary size and the address >>> which has to be passed to the TA during the TA init sequence. >>> >>> The policy binary is comprised of inputs (or the events) and outputs >>> (or the actions). With the PMF ecosystem, OEMs generate the policy >>> binary (or could be multiple binaries) that contains a supported set >>> of inputs and outputs which could be specifically carved out for each >>> usage segment (or for each user also) that could influence the system >>> behavior either by enriching the user experience or/and boost/throttle >>> power limits. >>> >>> Once the TA init command succeeds, the PMF driver sends the changing >>> events in the current environment to the TA for a constant sampling >>> frequency time (the event here could be a lid close or open) and >>> if the policy binary has corresponding action built within it, the >>> TA sends the action for it in the subsequent enact command. >>> >>> If the inputs sent to the TA has no output defined in the policy >>> binary generated by OEMs, there will be no action to be performed >>> by the PMF driver. >>> >>> Example policies: >>> >>> 1) if slider is performance ; set the SPL to 40W >>> Here PMF driver registers with the platform profile interface and >>> when the slider position is changed, PMF driver lets the TA know >>> about this. TA sends back an action to update the Sustained >>> Power Limit (SPL). PMF driver updates this limit via the PMFW mailbox. >>> >>> 2) if user_away ; then lock the system >>> Here PMF driver hooks to the AMD SFH driver to know the user presence >>> and send the inputs to TA and if the condition is met, the TA sends >>> the action of locking the system. PMF driver generates a uevent and >>> based on the udev rule in the userland the system gets locked with >>> systemctl. >>> >>> The intent here is to provide the OEM's to make a policy to lock the >>> system when the user is away ; but the userland can make a choice to >>> ignore it. >>> >>> and so on. >>> >>> The OEMs will have an utility to create numerous such policies and >>> the policies shall be reviewed by AMD before signing and encrypting >>> them. Policies are shared between operating systems to have seemless >>> user >>> experience. >>> >>> Since all this action has to happen via the "amdtee" driver, currently >>> there is no caller for it in the kernel which can load the amdtee >>> driver. >>> Without amdtee driver loading onto the system the "tee" calls shall >>> fail >>> from the PMF driver. Hence an explicit "request_module" has been added >>> to address this. >>> >>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@xxxxxxx> >>> --- >>> drivers/platform/x86/amd/pmf/Kconfig | 2 +- >>> drivers/platform/x86/amd/pmf/acpi.c | 37 +++++++ >>> drivers/platform/x86/amd/pmf/core.c | 13 +++ >>> drivers/platform/x86/amd/pmf/pmf.h | 136 ++++++++++++++++++++++++ >>> drivers/platform/x86/amd/pmf/tee-if.c | 146 >>> +++++++++++++++++++++++++- >>> 5 files changed, 331 insertions(+), 3 deletions(-) >>> >>> diff --git a/drivers/platform/x86/amd/pmf/Kconfig >>> b/drivers/platform/x86/amd/pmf/Kconfig >>> index 32a029e8db80..f246252bddd8 100644 >>> --- a/drivers/platform/x86/amd/pmf/Kconfig >>> +++ b/drivers/platform/x86/amd/pmf/Kconfig >>> @@ -9,7 +9,7 @@ config AMD_PMF >>> depends on POWER_SUPPLY >>> depends on AMD_NB >>> select ACPI_PLATFORM_PROFILE >>> - depends on TEE >>> + depends on TEE && AMDTEE >>> help >>> This driver provides support for the AMD Platform Management >>> Framework. >>> The goal is to enhance end user experience by making AMD PCs >>> smarter, >>> diff --git a/drivers/platform/x86/amd/pmf/acpi.c >>> b/drivers/platform/x86/amd/pmf/acpi.c >>> index 3fc5e4547d9f..d0512af2cd42 100644 >>> --- a/drivers/platform/x86/amd/pmf/acpi.c >>> +++ b/drivers/platform/x86/amd/pmf/acpi.c >>> @@ -286,6 +286,43 @@ int apmf_install_handler(struct amd_pmf_dev >>> *pmf_dev) >>> return 0; >>> } >>> +static acpi_status apmf_walk_resources(struct acpi_resource *res, >>> void *data) >>> +{ >>> + struct amd_pmf_dev *dev = data; >>> + >>> + switch (res->type) { >>> + case ACPI_RESOURCE_TYPE_ADDRESS64: >>> + dev->policy_addr = res->data.address64.address.minimum; >>> + dev->policy_sz = res->data.address64.address.address_length; >>> + break; >>> + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: >>> + dev->policy_addr = res->data.fixed_memory32.address; >>> + dev->policy_sz = res->data.fixed_memory32.address_length; >>> + break; >>> + } >>> + >>> + if (!dev->policy_addr || dev->policy_sz > POLICY_BUF_MAX_SZ || >>> dev->policy_sz == 0) { >>> + pr_err("Incorrect Policy params, possibly a SBIOS bug\n"); >>> + return AE_ERROR; >>> + } >>> + >>> + return AE_OK; >>> +} >>> + >>> +int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev) >>> +{ >>> + acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); >>> + acpi_status status; >>> + >>> + status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, >>> apmf_walk_resources, pmf_dev); >>> + if (ACPI_FAILURE(status)) { >>> + dev_err(pmf_dev->dev, "acpi_walk_resources failed\n"); >>> + return status; >> >> You're returning acpi_status here, but the return for the function is >> int. It "happens to work" but I think it would be better to do >> something like: >> >> dev_err(pmf_dev->dev, "acpi_walk_resources failed: %d\n, status); >> return -EINVAL; > > OK, I will change this. > >> >>> + } >>> + >>> + return 0; >>> +} >>> + >>> void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev) >>> { >>> acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); >>> diff --git a/drivers/platform/x86/amd/pmf/core.c >>> b/drivers/platform/x86/amd/pmf/core.c >>> index ffb78e9709d9..96a41e7d4e7d 100644 >>> --- a/drivers/platform/x86/amd/pmf/core.c >>> +++ b/drivers/platform/x86/amd/pmf/core.c >>> @@ -395,6 +395,19 @@ static int amd_pmf_probe(struct platform_device >>> *pdev) >>> return -ENOMEM; >>> dev->dev = &pdev->dev; >>> + err = apmf_check_smart_pc(dev); >>> + if (!err) { >> >> Rather than just failing to init smart PC solution builder, shouldn't >> you fail probe entirely if an err is set from probing the BIOS >> resources? This seems fairly fatal. >> >> For example I'd think that setting up static slider is relatively >> pointless on a system intending to use smart PC solution builder if >> smart PC solution builder isn't working. >> > > What if - the BIOS advertises the smart PC bit and forgets to add > resources (or a buggy ACPI thing)? > > Atleast that way if the static slider is enabled, atleast some amount > of power saving can happen. > > Note that, I have tried the fallback to static slider if the smart pc > fails and that's working with the current we have in place. > > >>> + /* >>> + * In order for Smart PC solution to work it has a hard >>> dependency >>> + * on the amdtee driver to be loaded first even before the >>> PMF driver >>> + * loads. PMF ASL has a _CRS method that advertises the >>> existence >>> + * of Smart PC bit. If this information is present, use >>> this to >>> + * explicitly probe the amdtee driver, so that "tee" >>> plumbing is done >>> + * before the PMF Smart PC init happens. >>> + */ >>> + if (request_module("amdtee")) >>> + pr_err("Failed to load amdtee. PMF Smart PC not >>> enabled!\n"); >> >> Did that softdep thing Ilpo mentioned not work for modprobe? >> Hopefully that generally works for everything except the insmod case >> so this code path is unlikely to be hit in the wild. >> > > unfortunately no. Hence that's the reason I had to retain back the > request_module() here. Apologies for creating confusion here. The system which I was using had some modules blacklisted and that lead to softdep not working. I tried on couple of other systems and softdep is working. I will remove request_module() and change it to softdep in v4. Thanks, Shyam > >>> + } >>> rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); >>> if (!rdev || !pci_match_id(pmf_pci_ids, rdev)) { >>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h >>> b/drivers/platform/x86/amd/pmf/pmf.h >>> index a91c22d9b532..51c0e17f7720 100644 >>> --- a/drivers/platform/x86/amd/pmf/pmf.h >>> +++ b/drivers/platform/x86/amd/pmf/pmf.h >>> @@ -14,6 +14,11 @@ >>> #include <linux/acpi.h> >>> #include <linux/platform_profile.h> >>> +#define POLICY_BUF_MAX_SZ 0x4b000 >>> +#define POLICY_SIGN_COOKIE 0x31535024 >>> +#define POLICY_COOKIE_OFFSET 0x10 >>> +#define POLICY_COOKIE_LEN 0x14 >>> + >>> /* APMF Functions */ >>> #define APMF_FUNC_VERIFY_INTERFACE 0 >>> #define APMF_FUNC_GET_SYS_PARAMS 1 >>> @@ -59,8 +64,21 @@ >>> #define ARG_NONE 0 >>> #define AVG_SAMPLE_SIZE 3 >>> +/* Policy Actions */ >>> +#define PMF_POLICY_SPL 2 >>> +#define PMF_POLICY_SPPT 3 >>> +#define PMF_POLICY_FPPT 4 >>> +#define PMF_POLICY_SPPT_APU_ONLY 5 >>> +#define PMF_POLICY_STT_MIN 6 >>> +#define PMF_POLICY_STT_SKINTEMP_APU 7 >>> +#define PMF_POLICY_STT_SKINTEMP_HS2 8 >>> + >>> /* TA macros */ >>> #define PMF_TA_IF_VERSION_MAJOR 1 >>> +#define TA_PMF_ACTION_MAX 32 >>> +#define TA_PMF_UNDO_MAX 8 >>> +#define TA_OUTPUT_RESERVED_MEM 906 >>> +#define MAX_OPERATION_PARAMS 4 >>> /* AMD PMF BIOS interfaces */ >>> struct apmf_verify_interface { >>> @@ -183,11 +201,16 @@ struct amd_pmf_dev { >>> bool cnqf_supported; >>> struct notifier_block pwr_src_notifier; >>> /* Smart PC solution builder */ >>> + unsigned char *policy_buf; >>> + u32 policy_sz; >>> struct tee_context *tee_ctx; >>> struct tee_shm *fw_shm_pool; >>> u32 session_id; >>> void *shbuf; >>> struct delayed_work pb_work; >>> + struct pmf_action_table *prev_data; >>> + u64 policy_addr; >>> + void *policy_base; >>> bool smart_pc_enabled; >>> }; >>> @@ -399,17 +422,129 @@ struct apmf_dyn_slider_output { >>> struct apmf_cnqf_power_set ps[APMF_CNQF_MAX]; >>> } __packed; >>> +/* Smart PC - TA internals */ >>> +enum ta_slider { >>> + TA_BEST_BATTERY, /* Best Battery */ >>> + TA_BETTER_BATTERY, /* Better Battery */ >>> + TA_BETTER_PERFORMANCE, /* Better Performance */ >>> + TA_BEST_PERFORMANCE, /* Best Performance */ >>> + TA_MAX, >>> +}; >> >> The comments above at end of the line don't add any value. > > OK. > > Thanks, > Shyam > >> >>> + >>> /* cmd ids for TA communication */ >>> enum ta_pmf_command { >>> TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE, >>> TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES, >>> }; >>> +enum ta_pmf_error_type { >>> + TA_PMF_TYPE_SUCCESS, >>> + TA_PMF_ERROR_TYPE_GENERIC, >>> + TA_PMF_ERROR_TYPE_CRYPTO, >>> + TA_PMF_ERROR_TYPE_CRYPTO_VALIDATE, >>> + TA_PMF_ERROR_TYPE_CRYPTO_VERIFY_OEM, >>> + TA_PMF_ERROR_TYPE_POLICY_BUILDER, >>> + TA_PMF_ERROR_TYPE_PB_CONVERT, >>> + TA_PMF_ERROR_TYPE_PB_SETUP, >>> + TA_PMF_ERROR_TYPE_PB_ENACT, >>> + TA_PMF_ERROR_TYPE_ASD_GET_DEVICE_INFO, >>> + TA_PMF_ERROR_TYPE_ASD_GET_DEVICE_PCIE_INFO, >>> + TA_PMF_ERROR_TYPE_SYS_DRV_FW_VALIDATION, >>> + TA_PMF_ERROR_TYPE_MAX, >>> +}; >>> + >>> +struct pmf_action_table { >>> + u32 spl; /* in mW */ >>> + u32 sppt; /* in mW */ >>> + u32 sppt_apuonly; /* in mW */ >>> + u32 fppt; /* in mW */ >>> + u32 stt_minlimit; /* in mW */ >>> + u32 stt_skintemp_apu; /* in C */ >>> + u32 stt_skintemp_hs2; /* in C */ >>> +}; >>> + >>> +/* Input conditions */ >>> +struct ta_pmf_condition_info { >>> + u32 power_source; >>> + u32 bat_percentage; >>> + u32 power_slider; >>> + u32 lid_state; >>> + bool user_present; >>> + u32 rsvd1[2]; >>> + u32 monitor_count; >>> + u32 rsvd2[2]; >>> + u32 bat_design; >>> + u32 full_charge_capacity; >>> + int drain_rate; >>> + bool user_engaged; >>> + u32 device_state; >>> + u32 socket_power; >>> + u32 skin_temperature; >>> + u32 rsvd3[5]; >>> + u32 ambient_light; >>> + u32 length; >>> + u32 avg_c0residency; >>> + u32 max_c0residency; >>> + u32 s0i3_entry; >>> + u32 gfx_busy; >>> + u32 rsvd4[7]; >>> + bool camera_state; >>> + u32 workload_type; >>> + u32 display_type; >>> + u32 display_state; >>> + u32 rsvd5[150]; >>> +}; >>> + >>> +struct ta_pmf_load_policy_table { >>> + u32 table_size; >>> + u8 table[POLICY_BUF_MAX_SZ]; >>> +}; >>> + >>> +/* TA initialization params */ >>> +struct ta_pmf_init_table { >>> + u32 frequency; /* SMU sampling frequency */ >>> + bool validate; >>> + bool sku_check; >>> + bool metadata_macrocheck; >>> + struct ta_pmf_load_policy_table policies_table; >>> +}; >>> + >>> +/* Everything the TA needs to Enact Policies */ >>> +struct ta_pmf_enact_table { >>> + struct ta_pmf_condition_info ev_info; >>> + u32 name; >>> +}; >>> + >>> +struct ta_pmf_action { >>> + u32 action_index; >>> + u32 value; >>> +}; >>> + >>> +/* output actions from TA */ >>> +struct ta_pmf_enact_result { >>> + u32 actions_count; >>> + struct ta_pmf_action actions_list[TA_PMF_ACTION_MAX]; >>> + u32 undo_count; >>> + struct ta_pmf_action undo_list[TA_PMF_UNDO_MAX]; >>> +}; >>> + >>> +union ta_pmf_input { >>> + struct ta_pmf_enact_table enact_table; >>> + struct ta_pmf_init_table init_table; >>> +}; >>> + >>> +union ta_pmf_output { >>> + struct ta_pmf_enact_result policy_apply_table; >>> + u32 rsvd[TA_OUTPUT_RESERVED_MEM]; >>> +}; >>> + >>> struct ta_pmf_shared_memory { >>> int command_id; >>> int resp_id; >>> u32 pmf_result; >>> u32 if_version; >>> + union ta_pmf_output pmf_output; >>> + union ta_pmf_input pmf_input; >>> }; >>> /* Core Layer */ >>> @@ -460,4 +595,5 @@ 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); >>> +int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev); >>> #endif /* PMF_H */ >>> diff --git a/drivers/platform/x86/amd/pmf/tee-if.c >>> b/drivers/platform/x86/amd/pmf/tee-if.c >>> index 4036f435f1e2..38f02676261d 100644 >>> --- a/drivers/platform/x86/amd/pmf/tee-if.c >>> +++ b/drivers/platform/x86/amd/pmf/tee-if.c >>> @@ -42,9 +42,77 @@ static void amd_pmf_prepare_args(struct >>> amd_pmf_dev *dev, int cmd, >>> param[0].u.memref.shm_offs = 0; >>> } >>> +static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, >>> struct ta_pmf_enact_result *out) >>> +{ >>> + u32 val; >>> + int idx; >>> + >>> + for (idx = 0; idx < out->actions_count; idx++) { >>> + val = out->actions_list[idx].value; >>> + switch (out->actions_list[idx].action_index) { >>> + case PMF_POLICY_SPL: >>> + if (dev->prev_data->spl != val) { >>> + amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL); >>> + dev_dbg(dev->dev, "update SPL : %u\n", val); >>> + dev->prev_data->spl = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_SPPT: >>> + if (dev->prev_data->sppt != val) { >>> + amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL); >>> + dev_dbg(dev->dev, "update SPPT : %u\n", val); >>> + dev->prev_data->sppt = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_FPPT: >>> + if (dev->prev_data->fppt != val) { >>> + amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL); >>> + dev_dbg(dev->dev, "update FPPT : %u\n", val); >>> + dev->prev_data->fppt = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_SPPT_APU_ONLY: >>> + if (dev->prev_data->sppt_apuonly != val) { >>> + amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, >>> val, NULL); >>> + dev_dbg(dev->dev, "update SPPT_APU_ONLY : %u\n", val); >>> + dev->prev_data->sppt_apuonly = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_STT_MIN: >>> + if (dev->prev_data->stt_minlimit != val) { >>> + amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, >>> val, NULL); >>> + dev_dbg(dev->dev, "update STT_MIN : %u\n", val); >>> + dev->prev_data->stt_minlimit = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_STT_SKINTEMP_APU: >>> + if (dev->prev_data->stt_skintemp_apu != val) { >>> + amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, >>> val, NULL); >>> + dev_dbg(dev->dev, "update STT_SKINTEMP_APU : %u\n", >>> val); >>> + dev->prev_data->stt_skintemp_apu = val; >>> + } >>> + break; >>> + >>> + case PMF_POLICY_STT_SKINTEMP_HS2: >>> + if (dev->prev_data->stt_skintemp_hs2 != val) { >>> + amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, >>> val, NULL); >>> + dev_dbg(dev->dev, "update STT_SKINTEMP_HS2 : %u\n", >>> val); >>> + dev->prev_data->stt_skintemp_hs2 = val; >>> + } >>> + break; >>> + } >>> + } >>> +} >>> + >>> static int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev) >>> { >>> struct ta_pmf_shared_memory *ta_sm = NULL; >>> + struct ta_pmf_enact_result *out = NULL; >>> struct tee_param param[MAX_TEE_PARAM]; >>> struct tee_ioctl_invoke_arg arg; >>> int ret = 0; >>> @@ -52,7 +120,10 @@ static int amd_pmf_invoke_cmd_enact(struct >>> amd_pmf_dev *dev) >>> if (!dev->tee_ctx) >>> return -ENODEV; >>> + memset(dev->shbuf, 0, dev->policy_sz); >>> ta_sm = dev->shbuf; >>> + out = &ta_sm->pmf_output.policy_apply_table; >>> + >>> memset(ta_sm, 0, sizeof(*ta_sm)); >>> ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_ENACT_POLICIES; >>> ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR; >>> @@ -65,6 +136,12 @@ static int amd_pmf_invoke_cmd_enact(struct >>> amd_pmf_dev *dev) >>> return ret; >>> } >>> + if (ta_sm->pmf_result == TA_PMF_TYPE_SUCCESS && >>> out->actions_count) { >>> + dev_dbg(dev->dev, "action count:%u result:%x\n", >>> out->actions_count, >>> + ta_sm->pmf_result); >>> + amd_pmf_apply_policies(dev, out); >>> + } >>> + >>> return 0; >>> } >>> @@ -72,6 +149,7 @@ static int amd_pmf_invoke_cmd_init(struct >>> amd_pmf_dev *dev) >>> { >>> struct ta_pmf_shared_memory *ta_sm = NULL; >>> struct tee_param param[MAX_TEE_PARAM]; >>> + struct ta_pmf_init_table *in = NULL; >>> struct tee_ioctl_invoke_arg arg; >>> int ret = 0; >>> @@ -80,10 +158,21 @@ static int amd_pmf_invoke_cmd_init(struct >>> amd_pmf_dev *dev) >>> return -ENODEV; >>> } >>> + dev_dbg(dev->dev, "Policy Binary size: %u bytes\n", >>> dev->policy_sz); >>> + memset(dev->shbuf, 0, dev->policy_sz); >>> ta_sm = dev->shbuf; >>> + in = &ta_sm->pmf_input.init_table; >>> + >>> ta_sm->command_id = TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE; >>> ta_sm->if_version = PMF_TA_IF_VERSION_MAJOR; >>> + in->metadata_macrocheck = false; >>> + in->sku_check = false; >>> + in->validate = true; >>> + in->frequency = pb_actions_ms; >>> + in->policies_table.table_size = dev->policy_sz; >>> + >>> + memcpy(in->policies_table.table, dev->policy_buf, dev->policy_sz); >>> amd_pmf_prepare_args(dev, >>> TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE, &arg, param); >>> ret = tee_client_invoke_func(dev->tee_ctx, &arg, param); >>> @@ -103,6 +192,51 @@ static void amd_pmf_invoke_cmd(struct >>> work_struct *work) >>> schedule_delayed_work(&dev->pb_work, >>> msecs_to_jiffies(pb_actions_ms)); >>> } >>> +static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev) >>> +{ >>> + u32 cookie, length; >>> + int res; >>> + >>> + cookie = readl(dev->policy_buf + POLICY_COOKIE_OFFSET); >>> + length = readl(dev->policy_buf + POLICY_COOKIE_LEN); >>> + >>> + if (cookie != POLICY_SIGN_COOKIE || !length) >>> + return -EINVAL; >>> + >>> + /* update the actual length */ >>> + dev->policy_sz = length + 512; >>> + res = amd_pmf_invoke_cmd_init(dev); >>> + if (res == TA_PMF_TYPE_SUCCESS) { >>> + /* now its safe to announce that smart pc is enabled */ >>> + dev->smart_pc_enabled = 1; >>> + /* >>> + * Start collecting the data from PMFW after a small delay >>> + * or else, we might end up getting stale values. >>> + */ >>> + schedule_delayed_work(&dev->pb_work, >>> msecs_to_jiffies(pb_actions_ms * 3)); >>> + } else { >>> + dev_err(dev->dev, "ta invoke cmd init failed err: %x\n", res); >>> + return res; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static int amd_pmf_get_bios_buffer(struct amd_pmf_dev *dev) >>> +{ >>> + dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL); >>> + if (!dev->policy_buf) >>> + return -ENOMEM; >>> + >>> + dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, >>> dev->policy_sz); >>> + if (!dev->policy_base) >>> + return -ENOMEM; >>> + >>> + memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz); >>> + >>> + return amd_pmf_start_policy_engine(dev); >>> +} >>> + >>> static int amd_pmf_amdtee_ta_match(struct tee_ioctl_version_data >>> *ver, const void *data) >>> { >>> return ver->impl_id == TEE_IMPL_ID_AMDTEE; >>> @@ -146,7 +280,7 @@ static int amd_pmf_tee_init(struct amd_pmf_dev >>> *dev) >>> goto out_ctx; >>> } >>> - size = sizeof(struct ta_pmf_shared_memory); >>> + size = sizeof(struct ta_pmf_shared_memory) + dev->policy_sz; >>> 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"); >>> @@ -190,11 +324,19 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev >>> *dev) >>> return ret; >>> INIT_DELAYED_WORK(&dev->pb_work, amd_pmf_invoke_cmd); >>> - return 0; >>> + amd_pmf_set_dram_addr(dev); >>> + amd_pmf_get_bios_buffer(dev); >>> + dev->prev_data = kzalloc(sizeof(*dev->prev_data), GFP_KERNEL); >>> + if (!dev->prev_data) >>> + return -ENOMEM; >>> + >>> + return dev->smart_pc_enabled; >>> } >>> void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev) >>> { >>> + kfree(dev->prev_data); >>> + kfree(dev->policy_buf); >>> cancel_delayed_work_sync(&dev->pb_work); >>> amd_pmf_tee_deinit(dev); >>> } >>