* [PATCH v5 1/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
2026-03-08 6:27 [PATCH v5 0/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 6:27 ` Manivannan Sadhasivam via B4 Relay
2026-03-08 18:21 ` kernel test robot
2026-03-08 6:27 ` [PATCH v5 2/5] soc: qcom: ice: Return -ENODEV if the ICE platform device is not found Manivannan Sadhasivam via B4 Relay
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-03-08 6:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Adrian Hunter, Ulf Hansson,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
Abel Vesa, Abel Vesa
Cc: linux-arm-msm, linux-kernel, linux-mmc, linux-scsi, Sumit Garg,
mani, Neeraj Soni, Manivannan Sadhasivam, stable
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
The current platform driver design causes probe ordering races with
consumers (UFS, eMMC) due to ICE's dependency on SCM firmware calls. If ICE
probe fails (missing ICE SCM or DT registers), devm_of_qcom_ice_get() loops
with -EPROBE_DEFER, leaving consumers non-functional even when ICE should
be gracefully disabled. devm_of_qcom_ice_get() doesn't know if the ICE
driver probe has failed due to above reasons or it is waiting for the SCM
driver.
Moreover, there is no devlink dependency between ICE and consumer drivers
as 'qcom,ice' is not considered as a DT 'supplier'. So the consumer drivers
have no idea of when the ICE driver is going to probe.
To address these issues, store the error pointer in a global xarray with
ice node phandle as a key during probe in addition to the valid ice pointer
and synchronize both qcom_ice_probe() and of_qcom_ice_get() using a mutex.
If the xarray entry is NULL, then it implies that the driver is not
probed yet, so return -EPROBE_DEFER. If it has any error pointer, return
that error pointer directly. Otherwise, add the devlink as usual and return
the valid pointer to the consumer.
Xarray is used instead of platform drvdata, since driver core frees the
drvdata during probe failure. So it cannot be used to pass the error
pointer to the consumers.
Note that this change only fixes the standalone ICE DT node bindings and
not the ones with 'ice' range embedded in the consumer nodes, where there
is no issue.
Cc: <stable@vger.kernel.org> # 6.4
Fixes: 2afbf43a4aec ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver")
Reported-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/soc/qcom/ice.c | 38 +++++++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index b203bc685cad..50da5a3e8073 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -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>
@@ -113,6 +114,9 @@ struct qcom_ice {
u8 hwkm_version;
};
+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);
@@ -631,6 +635,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
@@ -647,12 +653,13 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
return ERR_PTR(-EPROBE_DEFER);
}
- 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);
@@ -716,24 +723,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, 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" },
{ },
@@ -742,6 +765,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,
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v5 1/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
2026-03-08 6:27 ` [PATCH v5 1/5] " Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 18:21 ` kernel test robot
0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2026-03-08 18:21 UTC (permalink / raw)
To: Manivannan Sadhasivam via B4 Relay, Bjorn Andersson,
Konrad Dybcio, Adrian Hunter, Ulf Hansson, Manivannan Sadhasivam,
James E.J. Bottomley, Martin K. Petersen, Abel Vesa
Cc: oe-kbuild-all, linux-arm-msm, linux-kernel, linux-mmc, linux-scsi,
Sumit Garg, Neeraj Soni, stable
Hi Manivannan,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f]
url: https://github.com/intel-lab-lkp/linux/commits/Manivannan-Sadhasivam-via-B4-Relay/soc-qcom-ice-Fix-race-between-qcom_ice_probe-and-of_qcom_ice_get/20260308-143016
base: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
patch link: https://lore.kernel.org/r/20260308-qcom-ice-fix-v5-1-e47e8a44b6c4%40oss.qualcomm.com
patch subject: [PATCH v5 1/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
config: arm-randconfig-r111-20260308 (https://download.01.org/0day-ci/archive/20260309/202603090214.7xup4lZa-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 10.5.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260309/202603090214.7xup4lZa-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603090214.7xup4lZa-lkp@intel.com/
sparse warnings: (new ones prefixed by >>)
>> drivers/soc/qcom/ice.c:117:1: sparse: sparse: symbol 'ice_handles' was not declared. Should it be static?
>> drivers/soc/qcom/ice.c:736:49: sparse: sparse: incorrect type in argument 3 (different address spaces) @@ expected void *entry @@ got void [noderef] __iomem *[assigned] base @@
drivers/soc/qcom/ice.c:736:49: sparse: expected void *entry
drivers/soc/qcom/ice.c:736:49: sparse: got void [noderef] __iomem *[assigned] base
vim +/ice_handles +117 drivers/soc/qcom/ice.c
116
> 117 DEFINE_XARRAY(ice_handles);
118 static DEFINE_MUTEX(ice_mutex);
119
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v5 2/5] soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
2026-03-08 6:27 [PATCH v5 0/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 1/5] " Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 6:27 ` Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 3/5] soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL Manivannan Sadhasivam via B4 Relay
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-03-08 6:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Adrian Hunter, Ulf Hansson,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
Abel Vesa, Abel Vesa
Cc: linux-arm-msm, linux-kernel, linux-mmc, linux-scsi, Sumit Garg,
mani, Neeraj Soni, Manivannan Sadhasivam
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
By the time the consumer driver calls devm_of_qcom_ice_get(), all the
platform devices for ICE nodes would've been created by
of_platform_default_populate().
So for the absence of any platform device, -ENODEV should not returned, not
-EPROBE_DEFER.
Fixes: 2afbf43a4aec ("soc: qcom: Make the Qualcomm UFS/SDCC ICE a dedicated driver")
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/soc/qcom/ice.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index 50da5a3e8073..6fde282584d0 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -650,7 +650,7 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
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 = xa_load(&ice_handles, pdev->dev.of_node->phandle);
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v5 3/5] soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
2026-03-08 6:27 [PATCH v5 0/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 1/5] " Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 2/5] soc: qcom: ice: Return -ENODEV if the ICE platform device is not found Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 6:27 ` Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 4/5] mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 5/5] scsi: ufs: ufs-qcom: " Manivannan Sadhasivam via B4 Relay
4 siblings, 0 replies; 7+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-03-08 6:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Adrian Hunter, Ulf Hansson,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
Abel Vesa, Abel Vesa
Cc: linux-arm-msm, linux-kernel, linux-mmc, linux-scsi, Sumit Garg,
mani, Neeraj Soni, Manivannan Sadhasivam, Konrad Dybcio
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
devm_of_qcom_ice_get() currently returns NULL if ICE SCM is not available
or "qcom,ice" property is not found in DT. But this confuses the clients
since NULL doesn't convey the reason for failure. So return proper error
codes instead of NULL.
Reported-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/soc/qcom/ice.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c
index 6fde282584d0..9faf099e40a3 100644
--- a/drivers/soc/qcom/ice.c
+++ b/drivers/soc/qcom/ice.c
@@ -563,7 +563,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);
@@ -645,7 +645,7 @@ 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) {
@@ -698,8 +698,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)
{
@@ -710,7 +709,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 {
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v5 4/5] mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
2026-03-08 6:27 [PATCH v5 0/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
` (2 preceding siblings ...)
2026-03-08 6:27 ` [PATCH v5 3/5] soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 6:27 ` Manivannan Sadhasivam via B4 Relay
2026-03-08 6:27 ` [PATCH v5 5/5] scsi: ufs: ufs-qcom: " Manivannan Sadhasivam via B4 Relay
4 siblings, 0 replies; 7+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-03-08 6:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Adrian Hunter, Ulf Hansson,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
Abel Vesa, Abel Vesa
Cc: linux-arm-msm, linux-kernel, linux-mmc, linux-scsi, Sumit Garg,
mani, Neeraj Soni, Manivannan Sadhasivam, Konrad Dybcio
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Now since the devm_of_qcom_ice_get() API never returns NULL, remove the
NULL check and also simplify the error handling.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/mmc/host/sdhci-msm.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 3b85233131b3..8d862079cf17 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1906,14 +1906,14 @@ 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)) {
+ if (IS_ERR(ice)) {
+ if (ice != ERR_PTR(-EOPNOTSUPP))
+ return PTR_ERR(ice);
+
dev_warn(dev, "Disabling inline encryption support\n");
- ice = NULL;
+ return 0;
}
- if (IS_ERR_OR_NULL(ice))
- return PTR_ERR_OR_ZERO(ice);
-
if (qcom_ice_get_supported_key_type(ice) != BLK_CRYPTO_KEY_TYPE_RAW) {
dev_warn(dev, "Wrapped keys not supported. Disabling inline encryption support.\n");
return 0;
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v5 5/5] scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
2026-03-08 6:27 [PATCH v5 0/5] soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
` (3 preceding siblings ...)
2026-03-08 6:27 ` [PATCH v5 4/5] mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get() Manivannan Sadhasivam via B4 Relay
@ 2026-03-08 6:27 ` Manivannan Sadhasivam via B4 Relay
4 siblings, 0 replies; 7+ messages in thread
From: Manivannan Sadhasivam via B4 Relay @ 2026-03-08 6:27 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Adrian Hunter, Ulf Hansson,
Manivannan Sadhasivam, James E.J. Bottomley, Martin K. Petersen,
Abel Vesa, Abel Vesa
Cc: linux-arm-msm, linux-kernel, linux-mmc, linux-scsi, Sumit Garg,
mani, Neeraj Soni, Manivannan Sadhasivam, Konrad Dybcio
From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Now since the devm_of_qcom_ice_get() API never returns NULL, remove the
NULL check and also simplify the error handling.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Acked-by: Martin K. Petersen <martin.petersen@oracle.com> # UFS
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
---
drivers/ufs/host/ufs-qcom.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c
index 375fd24ba458..72c24ed65fe1 100644
--- a/drivers/ufs/host/ufs-qcom.c
+++ b/drivers/ufs/host/ufs-qcom.c
@@ -177,14 +177,14 @@ 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)) {
+ if (IS_ERR(ice)) {
+ if (ice != ERR_PTR(-EOPNOTSUPP))
+ return PTR_ERR(ice);
+
dev_warn(dev, "Disabling inline encryption support\n");
- ice = NULL;
+ return 0;
}
- if (IS_ERR_OR_NULL(ice))
- return PTR_ERR_OR_ZERO(ice);
-
host->ice = ice;
/* Initialize the blk_crypto_profile */
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread