[PATCH v3 4/4] firmware: stratix10-svc: enable Agilex5 SMMU support in probe
From: Adrian Ng Ho Yin <adrian.ho.yin.ng@altera.com>
Date: 2026-09-07 08:29:30
Also in:
lkml
Subsystem:
intel stratix10 firmware drivers, the rest · Maintainers:
Dinh Nguyen, Linus Torvalds
Wire up the Agilex5-specific path in stratix10_svc_drv_probe(). Add INTEL_SIP_SMC_SDM_REMAPPER_CONFIG to stratix10-smc.h and issue INTEL_SIP_SMC_SDM_REMAPPER_BYPASS from probe. On Agilex5 REV B the hardware SDM address remapper must be bypassed when the SMMU is active so no extra offset is applied on top of the IOVA translation. Extend stratix10_svc_pdata with use_dma_mem and add intel,agilex5-svc to the of_device_id match table with that flag set. Probe reads the flag via of_device_get_match_data() so it shares the same pdata mechanism used for needs_psci_cpu_off. On Agilex5, DDR starts at 0x8000_0000 which is outside the SDM's addressable range, making the SMMU mandatory. Fail probe with -ENODEV if no IOMMU domain is attached to the device. Register svc_data_mem_cleanup() as a devm action on the DMA path to free any buffers leaked by service clients on driver unbind. Guard err_destroy_pool against NULL genpool for the early-exit DMA path. Signed-off-by: Adrian Ng Ho Yin <adrian.ho.yin.ng@altera.com> --- drivers/firmware/stratix10-svc.c | 83 +++++++++++++++++--- include/linux/firmware/intel/stratix10-smc.h | 23 ++++++ 2 files changed, 94 insertions(+), 12 deletions(-)
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index d790ae239cf4..fa2335378536 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c@@ -122,12 +122,17 @@ struct stratix10_svc_pdata { bool needs_psci_cpu_off; + bool use_dma_mem; }; static const struct stratix10_svc_pdata psci_cpu_off_pdata = { .needs_psci_cpu_off = true, }; +static const struct stratix10_svc_pdata agilex5_pdata = { + .use_dma_mem = true, +}; + typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long,
@@ -2169,6 +2174,7 @@ static void psci_cpu_off_teardown(struct stratix10_svc_controller *ctrl) static const struct of_device_id stratix10_svc_drv_match[] = { { .compatible = "intel,stratix10-svc", .data = &psci_cpu_off_pdata }, { .compatible = "intel,agilex-svc", .data = &psci_cpu_off_pdata }, + { .compatible = "intel,agilex5-svc", .data = &agilex5_pdata }, {}, };
@@ -2179,14 +2185,38 @@ static const char * const chan_names[SVC_NUM_CHANNEL] = { SVC_CLIENT_HWMON }; +static void svc_data_mem_cleanup(void *data) +{ + struct stratix10_svc_controller *ctrl = data; + struct stratix10_svc_data_mem *pmem, *tmp; + + guard(mutex)(&svc_mem_lock); + + list_for_each_entry_safe(pmem, tmp, &svc_data_mem, node) { + dev_warn(ctrl->dev, "leaked svc buffer %p, freeing on unbind\n", + pmem->vaddr); + if (ctrl->use_dma_mem) { + dma_free_coherent(ctrl->dev, pmem->size, + pmem->vaddr, pmem->dma_addr); + } else { + gen_pool_free(ctrl->genpool, + (unsigned long)pmem->vaddr, pmem->size); + } + list_del(&pmem->node); + kfree(pmem); + } +} + static int stratix10_svc_drv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct stratix10_svc_controller *controller; - struct gen_pool *genpool; + struct gen_pool *genpool = NULL; struct stratix10_svc_sh_memory *sh_memory; struct stratix10_svc *svc = NULL; const struct stratix10_svc_pdata *pdata = of_device_get_match_data(dev); + struct arm_smccc_res res; + bool use_dma_mem = false; svc_invoke_fn *invoke_fn; size_t fifo_size;
@@ -2197,18 +2227,38 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) if (IS_ERR(invoke_fn)) return -EINVAL; - sh_memory = devm_kzalloc(dev, sizeof(*sh_memory), GFP_KERNEL); - if (!sh_memory) - return -ENOMEM; + use_dma_mem = pdata && pdata->use_dma_mem; - sh_memory->invoke_fn = invoke_fn; - ret = svc_get_sh_memory(pdev, sh_memory); - if (ret) - return ret; + if (use_dma_mem) { + if (!iommu_get_domain_for_dev(dev)) { + dev_err(dev, + "SMMU is required for agilex5-svc but no IOMMU domain found\n"); + dev_err(dev, + "Ensure the SMMU node is enabled in the device tree and 'iommus' is set for this node\n"); + return -ENODEV; + } + + invoke_fn(INTEL_SIP_SMC_SDM_REMAPPER_CONFIG, + INTEL_SIP_SMC_SDM_REMAPPER_BYPASS, + 0, 0, 0, 0, 0, 0, &res); + + ret = svc_setup_dma_memory(pdev); + if (ret) + return ret; + } else { + sh_memory = devm_kzalloc(dev, sizeof(*sh_memory), GFP_KERNEL); + if (!sh_memory) + return -ENOMEM; - genpool = svc_create_memory_pool(pdev, sh_memory); - if (IS_ERR(genpool)) - return PTR_ERR(genpool); + sh_memory->invoke_fn = invoke_fn; + ret = svc_get_sh_memory(pdev, sh_memory); + if (ret) + return ret; + + genpool = svc_create_memory_pool(pdev, sh_memory); + if (IS_ERR(genpool)) + return PTR_ERR(genpool); + } /* allocate service controller and supporting channel */ controller = devm_kzalloc(dev, struct_size(controller, chans, SVC_NUM_CHANNEL),
@@ -2223,9 +2273,17 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) controller->num_active_client = 0; controller->genpool = genpool; controller->invoke_fn = invoke_fn; + controller->use_dma_mem = use_dma_mem; + controller->dma_addr_offset = use_dma_mem ? SVC_SDM_DMA_ADDR_OFFSET : 0; INIT_LIST_HEAD(&controller->node); init_completion(&controller->complete_status); + if (use_dma_mem) { + ret = devm_add_action_or_reset(dev, svc_data_mem_cleanup, controller); + if (ret) + goto err_destroy_pool; + } + if (pdata && pdata->needs_psci_cpu_off) { controller->psci_reboot_nb.notifier_call = psci_cpu_off_reboot_notifier;
@@ -2333,7 +2391,8 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev) err_free_notifier: psci_cpu_off_teardown(controller); err_destroy_pool: - gen_pool_destroy(genpool); + if (genpool) + gen_pool_destroy(genpool); return ret; }
diff --git a/include/linux/firmware/intel/stratix10-smc.h b/include/linux/firmware/intel/stratix10-smc.h
index 366309260121..b0d42d585a75 100644
--- a/include/linux/firmware/intel/stratix10-smc.h
+++ b/include/linux/firmware/intel/stratix10-smc.h@@ -813,4 +813,27 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE) #define INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_NOTIFY (0xEC) #define INTEL_SIP_SMC_ASYNC_RSU_NOTIFY \ INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_RSU_NOTIFY) + +/** + * Request INTEL_SIP_SMC_SDM_REMAPPER_CONFIG + * + * Sync call to configure the SDM address remapper. On Agilex5, the remapper + * must be bypassed when the SMMU is active to avoid conflicts with IOMMU + * address translation. + * + * Call register usage: + * a0: INTEL_SIP_SMC_SDM_REMAPPER_CONFIG + * a1: INTEL_SIP_SMC_SDM_REMAPPER_ENABLE or INTEL_SIP_SMC_SDM_REMAPPER_BYPASS + * a2-7: not used + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK + * a1-3: not used + */ +#define INTEL_SIP_SMC_FUNCID_SDM_REMAPPER_CONFIG 513 +#define INTEL_SIP_SMC_SDM_REMAPPER_CONFIG \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_SDM_REMAPPER_CONFIG) +#define INTEL_SIP_SMC_SDM_REMAPPER_ENABLE 0 +#define INTEL_SIP_SMC_SDM_REMAPPER_BYPASS 1 + #endif
--
2.49.GIT