Qualcomm driver fixes for v7.1

The Qualcomm ICE driver suffers from race conditions between probe() and
 get() and will in certain cases return the wrong error code, which
 results in storage drivers failing to probe. Fix these issues.
 
 Also correct the DeviceTree binding, to ensure that relevant clocks are
 described and voted for, to prevent the driver from accessing unclocked
 hardware during boot.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCgAsFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmoVsj8OHGJqb3JuQGty
 eW8uc2UACgkQCx85Pw2ZrcVLlhAAjW6WvbknpvjbJEwVjsFCdi9wtplLibtTBU+q
 7HcPCdtN+kWSu1H1F6b/B5ugpfdroy+UK0P6tV2glOQW5h5JIVwCktT4ucPgSrld
 UyAcx9EuupyYFy/qCLz6gZ82JMAjzKyFDa2F4IEp3VbAUFneVOgg87XXDPvD8tmU
 9VsbLsXJYUaFGixFqpuG2fzSZGH6GSSd493HziyKZL43kskfH4cJOQ6LiQL5RhhE
 GuEs9Oqerv+uisS3dq4nqf7pbZEP+SetlQOuj/LcGP0gibZf4W0gvx0RuN9gj0oJ
 THeOdn1cf3mEY3wnCwrCTm4t5qn+k85EP5nVN2gmQTSgU/QIkDYNeNUydFn0rvPJ
 LlaSMaU5zDI68s+xXfm+8uGZecdRV97VLifUc0OBBh2pdy3gXgNlmctyEKES/lYR
 kUVakLcFszElfdsChRNw230MzM5wm9wjsag3KtBua5pqiGiMsfVgU59ejBR9tI6C
 tQZrPZotk4mMcljO1f9GO5swJKt5mznQ1XVabTz8NzNHJycBkCJSIA1IDxzjATt0
 9IQqtK8fULVtD5gPpwF1tEigIEy0mL1QDv4qDZWS2KkElYOrRWQVwRoP1Ba3ZqSI
 gnBTVlULNftodxbLW32ujgBDBQoEAeNBkA9Nfy9HTiYapbCqrlr7fne29+YTj2lz
 dR7+CXw=
 =QdJR
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmoYt/4ACgkQmmx57+YA
 GNkgIA//S0tL8vyZ4kVKetG1ZUSSTZkX1IzmNLyiroaIk1mIFIepnaLI37MU6Yiq
 RZUZsXPsHX2mPOVXSqIA0imwKn5fAVR8HgoQE8Tng0U2t9KTEW9NCgvPjLWlwpPe
 kKZlxnk3wxoD+tlEBYisjc44MLLo2pS+lrrFGd9Ki03r+Gt+jnfb/icxMnHYRSIu
 fBrsPaAzPsGuIzGUrNJcm0FzDMcLq2SJ9cIka8QUQSJR0+rugvC0thZxExAo1zt8
 UnlMrpTDcuCTzxgVdiQMj9ThhplvAqobOrgadq6h91OQtPKwGaFQ8cXnTBvX1ILk
 tFhNKTNp3hOxbPYy4km5+TCfmjI1X4b6i9hQGeP/3FTsB8L/twYQd135SDeV6Mmy
 /zgDWFd2ZyEI/DtMauOTFs8bt3Cq9Lpq0wzwOxXdknZapXDbhdidIJloX+bAmS0D
 BI6uRXEnEJQPWeHd452gJSJ9tJLqYRbSiw0KH0T430YnhwN4wx5owMyFPmGawVUj
 D6AuGaWwpTtX1velVQD6cGGMxjw2RYfMw4tNWsxB9c6BoB8dR+K5jXGi0vfE5Hk0
 6Lh09zvsc2hfIlT5gELMEkiKbEyrkAD48wUh9ZAZ1LMwIChZ6sq2JnTtaZzufetX
 HdnsUDOVCgcrjb4UEMDUq6VNwXM2M/7PKmS2q/rRdDrU7OP7hhM=
 =o97B
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/fixes

Qualcomm driver fixes for v7.1

The Qualcomm ICE driver suffers from race conditions between probe() and
get() and will in certain cases return the wrong error code, which
results in storage drivers failing to probe. Fix these issues.

Also correct the DeviceTree binding, to ensure that relevant clocks are
described and voted for, to prevent the driver from accessing unclocked
hardware during boot.

* tag 'qcom-drivers-fixes-for-7.1' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux:
  soc: qcom: ice: Fix the error code when 'qcom,ice' property is not found
  scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
  mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
  soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
  soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
  soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
  soc: qcom: ice: Allow explicit votes on 'iface' clock for ICE
  dt-bindings: crypto: qcom,ice: Fix missing power-domain and iface clk

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2026-05-28 23:47:31 +02:00
commit a3a7c05272
4 changed files with 97 additions and 28 deletions

View File

@ -30,6 +30,16 @@ properties:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
items:
- const: core
- const: iface
power-domains:
maxItems: 1
operating-points-v2: true
@ -44,6 +54,25 @@ required:
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,eliza-inline-crypto-engine
- qcom,milos-inline-crypto-engine
then:
required:
- power-domains
- clock-names
properties:
clocks:
minItems: 2
clock-names:
minItems: 2
examples:
- |
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
@ -52,7 +81,11 @@ examples:
compatible = "qcom,sm8550-inline-crypto-engine",
"qcom,inline-crypto-engine";
reg = <0x01d88000 0x8000>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
<&gcc GCC_UFS_PHY_AHB_CLK>;
clock-names = "core",
"iface";
power-domains = <&gcc UFS_PHY_GDSC>;
operating-points-v2 = <&ice_opp_table>;

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>
@ -108,11 +109,15 @@ struct qcom_ice {
void __iomem *base;
struct clk *core_clk;
struct clk *iface_clk;
bool use_hwkm;
bool hwkm_init_complete;
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);
@ -312,8 +317,13 @@ int qcom_ice_resume(struct qcom_ice *ice)
err = clk_prepare_enable(ice->core_clk);
if (err) {
dev_err(dev, "failed to enable core clock (%d)\n",
err);
dev_err(dev, "Failed to enable core clock: %d\n", err);
return err;
}
err = clk_prepare_enable(ice->iface_clk);
if (err) {
dev_err(dev, "Failed to enable iface clock: %d\n", err);
return err;
}
qcom_ice_hwkm_init(ice);
@ -323,6 +333,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume);
int qcom_ice_suspend(struct qcom_ice *ice)
{
clk_disable_unprepare(ice->iface_clk);
clk_disable_unprepare(ice->core_clk);
ice->hwkm_init_complete = false;
@ -559,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);
@ -579,11 +590,17 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_optional_enabled(dev, "core");
if (!engine->core_clk)
engine->core_clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(engine->core_clk))
return ERR_CAST(engine->core_clk);
engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface");
if (IS_ERR(engine->iface_clk))
return ERR_CAST(engine->iface_clk);
if (!qcom_ice_check_supported(engine))
return ERR_PTR(-EOPNOTSUPP);
@ -631,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
@ -639,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(-EOPNOTSUPP);
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);
@ -691,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)
{
@ -703,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 {
@ -716,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" },
{ },
@ -742,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;