Merge branch '20260518-qcom-ice-fix-v7-0-2a595382185b@oss.qualcomm.com' into drivers-for-7.2

Merge the fixes for ICE driver race condition through a topic branch, to
allow sharing it with other subsystems as well.
This commit is contained in:
Bjorn Andersson 2026-05-18 09:43:38 -05:00
commit 06b2e78c45
3 changed files with 48 additions and 25 deletions

View File

@ -1918,13 +1918,13 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
return 0;
ice = devm_of_qcom_ice_get(dev);
if (ice == ERR_PTR(-EOPNOTSUPP)) {
dev_warn(dev, "Disabling inline encryption support\n");
ice = NULL;
}
if (IS_ERR(ice)) {
if (ice != ERR_PTR(-EOPNOTSUPP))
return PTR_ERR(ice);
if (IS_ERR_OR_NULL(ice))
return PTR_ERR_OR_ZERO(ice);
dev_warn(dev, "Disabling inline encryption support\n");
return 0;
}
msm_host->ice = ice;

View File

@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/xarray.h>
#include <linux/firmware/qcom/qcom_scm.h>
@ -114,6 +115,9 @@ struct qcom_ice {
u8 hwkm_version;
};
static DEFINE_XARRAY(ice_handles);
static DEFINE_MUTEX(ice_mutex);
static bool qcom_ice_check_supported(struct qcom_ice *ice)
{
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
@ -566,7 +570,7 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
if (!qcom_scm_ice_available()) {
dev_warn(dev, "ICE SCM interface not found\n");
return NULL;
return ERR_PTR(-EOPNOTSUPP);
}
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
@ -644,6 +648,8 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
return qcom_ice_create(&pdev->dev, base);
}
guard(mutex)(&ice_mutex);
/*
* If the consumer node does not provider an 'ice' reg range
* (legacy DT binding), then it must at least provide a phandle
@ -652,20 +658,21 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
"qcom,ice", 0);
if (!node)
return NULL;
return ERR_PTR(-ENODEV);
pdev = of_find_device_by_node(node);
if (!pdev) {
dev_err(dev, "Cannot find device node %s\n", node->name);
return ERR_PTR(-EPROBE_DEFER);
return ERR_PTR(-ENODEV);
}
ice = platform_get_drvdata(pdev);
if (!ice) {
dev_err(dev, "Cannot get ice instance from %s\n",
dev_name(&pdev->dev));
ice = xa_load(&ice_handles, pdev->dev.of_node->phandle);
if (IS_ERR_OR_NULL(ice)) {
platform_device_put(pdev);
return ERR_PTR(-EPROBE_DEFER);
if (!ice)
return ERR_PTR(-EPROBE_DEFER);
else
return ice;
}
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
@ -704,8 +711,7 @@ static void devm_of_qcom_ice_put(struct device *dev, void *res)
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
* be created and so this function will return that instead.
*
* Return: ICE pointer on success, NULL if there is no ICE data provided by the
* consumer or ERR_PTR() on error.
* Return: ICE pointer on success, ERR_PTR() on error.
*/
struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
{
@ -716,7 +722,7 @@ struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
return ERR_PTR(-ENOMEM);
ice = of_qcom_ice_get(dev);
if (!IS_ERR_OR_NULL(ice)) {
if (!IS_ERR(ice)) {
*dr = ice;
devres_add(dev, dr);
} else {
@ -729,24 +735,40 @@ EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);
static int qcom_ice_probe(struct platform_device *pdev)
{
unsigned long phandle = pdev->dev.of_node->phandle;
struct qcom_ice *engine;
void __iomem *base;
guard(mutex)(&ice_mutex);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base)) {
dev_warn(&pdev->dev, "ICE registers not found\n");
/* Store the error pointer for devm_of_qcom_ice_get() */
xa_store(&ice_handles, phandle, (__force void *)base, GFP_KERNEL);
return PTR_ERR(base);
}
engine = qcom_ice_create(&pdev->dev, base);
if (IS_ERR(engine))
if (IS_ERR(engine)) {
/* Store the error pointer for devm_of_qcom_ice_get() */
xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return PTR_ERR(engine);
}
platform_set_drvdata(pdev, engine);
xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
return 0;
}
static void qcom_ice_remove(struct platform_device *pdev)
{
unsigned long phandle = pdev->dev.of_node->phandle;
guard(mutex)(&ice_mutex);
xa_store(&ice_handles, phandle, NULL, GFP_KERNEL);
}
static const struct of_device_id qcom_ice_of_match_table[] = {
{ .compatible = "qcom,inline-crypto-engine" },
{ },
@ -755,6 +777,7 @@ MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
static struct platform_driver qcom_ice_driver = {
.probe = qcom_ice_probe,
.remove = qcom_ice_remove,
.driver = {
.name = "qcom-ice",
.of_match_table = qcom_ice_of_match_table,

View File

@ -177,13 +177,13 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host)
int i;
ice = devm_of_qcom_ice_get(dev);
if (ice == ERR_PTR(-EOPNOTSUPP)) {
dev_warn(dev, "Disabling inline encryption support\n");
ice = NULL;
}
if (IS_ERR(ice)) {
if (ice != ERR_PTR(-EOPNOTSUPP))
return PTR_ERR(ice);
if (IS_ERR_OR_NULL(ice))
return PTR_ERR_OR_ZERO(ice);
dev_warn(dev, "Disabling inline encryption support\n");
return 0;
}
host->ice = ice;