mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-28 09:22:08 +00:00
firmware: qcom: scm: Cleanup global '__scm' on probe failures
If SCM driver fails the probe, it should not leave global '__scm'
variable assigned, because external users of this driver will assume the
probe finished successfully. For example TZMEM parts ('__scm->mempool')
are initialized later in the probe, but users of it (__scm_smc_call())
rely on the '__scm' variable.
This fixes theoretical NULL pointer exception, triggered via introducing
probe deferral in SCM driver with call trace:
qcom_tzmem_alloc+0x70/0x1ac (P)
qcom_tzmem_alloc+0x64/0x1ac (L)
qcom_scm_assign_mem+0x78/0x194
qcom_rmtfs_mem_probe+0x2d4/0x38c
platform_probe+0x68/0xc8
Fixes: 40289e35ca
("firmware: qcom: scm: enable the TZ mem allocator")
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20241209-qcom-scm-missing-barriers-and-all-sort-of-srap-v2-4-9061013c8d92@linaro.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
This commit is contained in:
parent
b628510397
commit
1e76b546e6
@ -2038,13 +2038,17 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
irq = platform_get_irq_optional(pdev, 0);
|
irq = platform_get_irq_optional(pdev, 0);
|
||||||
if (irq < 0) {
|
if (irq < 0) {
|
||||||
if (irq != -ENXIO)
|
if (irq != -ENXIO) {
|
||||||
return irq;
|
ret = irq;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
|
ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
|
||||||
IRQF_ONESHOT, "qcom-scm", __scm);
|
IRQF_ONESHOT, "qcom-scm", __scm);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
|
dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__get_convention();
|
__get_convention();
|
||||||
@ -2063,14 +2067,18 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
qcom_scm_disable_sdi();
|
qcom_scm_disable_sdi();
|
||||||
|
|
||||||
ret = of_reserved_mem_device_init(__scm->dev);
|
ret = of_reserved_mem_device_init(__scm->dev);
|
||||||
if (ret && ret != -ENODEV)
|
if (ret && ret != -ENODEV) {
|
||||||
return dev_err_probe(__scm->dev, ret,
|
dev_err_probe(__scm->dev, ret,
|
||||||
"Failed to setup the reserved memory region for TZ mem\n");
|
"Failed to setup the reserved memory region for TZ mem\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
ret = qcom_tzmem_enable(__scm->dev);
|
ret = qcom_tzmem_enable(__scm->dev);
|
||||||
if (ret)
|
if (ret) {
|
||||||
return dev_err_probe(__scm->dev, ret,
|
dev_err_probe(__scm->dev, ret,
|
||||||
"Failed to enable the TrustZone memory allocator\n");
|
"Failed to enable the TrustZone memory allocator\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&pool_config, 0, sizeof(pool_config));
|
memset(&pool_config, 0, sizeof(pool_config));
|
||||||
pool_config.initial_size = 0;
|
pool_config.initial_size = 0;
|
||||||
@ -2078,9 +2086,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
pool_config.max_size = SZ_256K;
|
pool_config.max_size = SZ_256K;
|
||||||
|
|
||||||
__scm->mempool = devm_qcom_tzmem_pool_new(__scm->dev, &pool_config);
|
__scm->mempool = devm_qcom_tzmem_pool_new(__scm->dev, &pool_config);
|
||||||
if (IS_ERR(__scm->mempool))
|
if (IS_ERR(__scm->mempool)) {
|
||||||
return dev_err_probe(__scm->dev, PTR_ERR(__scm->mempool),
|
dev_err_probe(__scm->dev, PTR_ERR(__scm->mempool),
|
||||||
"Failed to create the SCM memory pool\n");
|
"Failed to create the SCM memory pool\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the QSEECOM interface.
|
* Initialize the QSEECOM interface.
|
||||||
@ -2096,6 +2106,12 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|||||||
WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
|
WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
/* Paired with smp_load_acquire() in qcom_scm_is_available(). */
|
||||||
|
smp_store_release(&__scm, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qcom_scm_shutdown(struct platform_device *pdev)
|
static void qcom_scm_shutdown(struct platform_device *pdev)
|
||||||
|
Loading…
Reference in New Issue
Block a user