From e871d01b01de16704bb979fbbbe6d23707a3c58c Mon Sep 17 00:00:00 2001 From: Patil Rajesh Reddy Date: Thu, 11 Sep 2025 20:21:32 +0530 Subject: [PATCH 4/7] platform/x86/amd/pmf: Store custom BIOS input data in the ring buffer Add ring buffer to store the custom BIOS input values, inorder to avoid loss of BIOS input data when power modes changing from the UI. Signed-off-by: Patil Rajesh Reddy --- drivers/platform/x86/amd/pmf/acpi.c | 44 +++++++++++++++++++++++++++ drivers/platform/x86/amd/pmf/core.c | 2 ++ drivers/platform/x86/amd/pmf/pmf.h | 15 +++++++++ drivers/platform/x86/amd/pmf/spc.c | 25 +++++++++------ drivers/platform/x86/amd/pmf/tee-if.c | 2 ++ 5 files changed, 79 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index 13c4fec2c7ef..37f9ebc7d000 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -331,6 +331,46 @@ int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req req, sizeof(*req)); } +/* Store custom BIOS inputs data in ring buffer */ +static int amd_pmf_custom_bios_inputs_rb(struct amd_pmf_dev *pmf_dev) +{ + struct cbi_ring_buffer *rb = &pmf_dev->cbi_buf; + struct bios_input_entry entry = { }; + int i; + + guard(mutex)(&pmf_dev->rb_mutex); + + switch (pmf_dev->cpu_id) { + case AMD_CPU_ID_PS: + for (i = 0; i < ARRAY_SIZE(custom_bios_inputs_v1); i++) + entry.val[i] = pmf_dev->req1.custom_policy[i]; + entry.preq = pmf_dev->req1.pending_req; + break; + case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT: + case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT: + for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) + entry.val[i] = pmf_dev->req.custom_policy[i]; + entry.preq = pmf_dev->req.pending_req; + break; + default: + dev_err(pmf_dev->dev, "CPU id not valid\n"); + return -EINVAL; + } + + if (CIRC_SPACE(rb->head, rb->tail, CUSTOM_BIOS_INPUT_RB_SIZE) > 0) { + rb->data[rb->head] = entry; + rb->head = (rb->head + 1) & (CUSTOM_BIOS_INPUT_RB_SIZE - 1); + } else { + /* Buffer full, overwrite oldest */ + rb->data[rb->head] = entry; + rb->head = (rb->head + 1) & (CUSTOM_BIOS_INPUT_RB_SIZE - 1); + rb->tail = (rb->tail + 1) & (CUSTOM_BIOS_INPUT_RB_SIZE - 1); + dev_warn(pmf_dev->dev, "BIOS ring buffer overflow, overwriting oldest entry!\n"); + } + + return 0; +} + static void amd_pmf_handle_early_preq(struct amd_pmf_dev *pdev) { if (!pdev->cb_flag) @@ -356,6 +396,8 @@ static void apmf_event_handler_v2(acpi_handle handle, u32 event, void *data) dev_dbg(pmf_dev->dev, "Pending request (preq): 0x%x\n", pmf_dev->req.pending_req); amd_pmf_handle_early_preq(pmf_dev); + + amd_pmf_custom_bios_inputs_rb(pmf_dev); } static void apmf_event_handler_v1(acpi_handle handle, u32 event, void *data) @@ -374,6 +416,8 @@ static void apmf_event_handler_v1(acpi_handle handle, u32 event, void *data) dev_dbg(pmf_dev->dev, "Pending request (preq1): 0x%x\n", pmf_dev->req1.pending_req); amd_pmf_handle_early_preq(pmf_dev); + + amd_pmf_custom_bios_inputs_rb(pmf_dev); } static void apmf_event_handler(acpi_handle handle, u32 event, void *data) diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 028aeda6d855..78a883abe446 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -517,6 +517,7 @@ static int amd_pmf_probe(struct platform_device *pdev) mutex_init(&dev->lock); mutex_init(&dev->update_mutex); mutex_init(&dev->cb_mutex); + mutex_init(&dev->rb_mutex); apmf_acpi_init(dev); platform_set_drvdata(pdev, dev); @@ -543,6 +544,7 @@ static void amd_pmf_remove(struct platform_device *pdev) mutex_destroy(&dev->lock); mutex_destroy(&dev->update_mutex); mutex_destroy(&dev->cb_mutex); + mutex_destroy(&dev->rb_mutex); } static const struct attribute_group *amd_pmf_driver_groups[] = { diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index bc75bda7d6fc..6d4650d89a98 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -120,6 +121,7 @@ struct cookie_header { #define APTS_MAX_STATES 16 #define CUSTOM_BIOS_INPUT_BITS GENMASK(16, 7) +#define CUSTOM_BIOS_INPUT_RB_SIZE 64 /* Must be power of two for CIRC_* macros */ typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data); @@ -359,6 +361,17 @@ struct pmf_bios_inputs_prev { u32 custom_bios_inputs[10]; }; +struct bios_input_entry { + u32 val[10]; + u32 preq; +}; + +struct cbi_ring_buffer { + struct bios_input_entry data[CUSTOM_BIOS_INPUT_RB_SIZE]; + u16 head; + u16 tail; +}; + struct amd_pmf_dev { void __iomem *regbase; void __iomem *smu_virt_addr; @@ -407,6 +420,8 @@ struct amd_pmf_dev { struct apmf_sbios_req_v1 req1; struct pmf_bios_inputs_prev cb_prev; /* To preserve custom BIOS inputs */ bool cb_flag; /* To handle first custom BIOS input */ + struct cbi_ring_buffer cbi_buf; + struct mutex rb_mutex; /* Protects ring buffer access */ }; struct apmf_sps_prop_granular_v2 { diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c index 85192c7536b8..4b9eb85b4638 100644 --- a/drivers/platform/x86/amd/pmf/spc.c +++ b/drivers/platform/x86/amd/pmf/spc.c @@ -150,13 +150,26 @@ static void amd_pmf_update_bios_inputs(struct amd_pmf_dev *pdev, u32 pending_req static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev, struct ta_pmf_enact_table *in) { + struct cbi_ring_buffer *rb = &pdev->cbi_buf; + struct bios_input_entry entry = { }; unsigned int i; + guard(mutex)(&pdev->rb_mutex); + for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++) amd_pmf_set_ta_custom_bios_input(in, i, pdev->cb_prev.custom_bios_inputs[i]); - if (!(pdev->req.pending_req || pdev->req1.pending_req)) + if (CIRC_CNT(rb->head, rb->tail, CUSTOM_BIOS_INPUT_RB_SIZE) == 0) { + dev_dbg(pdev->dev, "Custom BIOS input ring buffer empty\n"); return; + } + + entry = rb->data[rb->tail]; + + if (!entry.preq) + return; + + rb->tail = (rb->tail + 1) & (CUSTOM_BIOS_INPUT_RB_SIZE - 1); if (!pdev->smart_pc_enabled) return; @@ -165,20 +178,14 @@ static void amd_pmf_get_custom_bios_inputs(struct amd_pmf_dev *pdev, case PMF_IF_V1: if (!is_apmf_bios_input_notifications_supported(pdev)) return; - amd_pmf_update_bios_inputs(pdev, pdev->req1.pending_req, custom_bios_inputs_v1, - pdev->req1.custom_policy, in); + amd_pmf_update_bios_inputs(pdev, entry.preq, custom_bios_inputs_v1, entry.val, in); break; case PMF_IF_V2: - amd_pmf_update_bios_inputs(pdev, pdev->req.pending_req, custom_bios_inputs, - pdev->req.custom_policy, in); + amd_pmf_update_bios_inputs(pdev, entry.preq, custom_bios_inputs, entry.val, in); break; default: break; } - - /* Clear pending requests after handling */ - memset(&pdev->req, 0, sizeof(pdev->req)); - memset(&pdev->req1, 0, sizeof(pdev->req1)); } static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in) diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c index 6e8116bef4f6..add742e33e1e 100644 --- a/drivers/platform/x86/amd/pmf/tee-if.c +++ b/drivers/platform/x86/amd/pmf/tee-if.c @@ -579,6 +579,8 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) status = ret == TA_PMF_TYPE_SUCCESS; if (status) { dev->cb_flag = true; + dev->cbi_buf.head = 0; + dev->cbi_buf.tail = 0; break; } amd_pmf_tee_deinit(dev); -- 2.34.1