ipq806x: 6.12: backport patch to handle CPUFreq with no SMEM

The Google OnHub doesn't init the SMEM in SBL causing the CPUFreq driver
to fail probe. This is caused by the fact that new CPUFreq driver makes
use of SMEM to identify the SoC variant and on Google OnHub this is not
available.

Backport patch to detect this state and fallback to compatible
matching fixing the CPUFreq driver.

Link: https://github.com/openwrt/openwrt/pull/20587
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
Christian Marangi
2025-10-29 14:35:18 +01:00
parent 1b48ebd31c
commit 60a71083ca
3 changed files with 217 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
From 652a86b24c5ac444afaf7625c9340d55aab7f105 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Fri, 31 Oct 2025 14:08:32 +0100
Subject: [PATCH 1/2] err.h: add INIT_ERR_PTR() macro
Add INIT_ERR_PTR() macro to initialize static variables with error
pointers. This might be useful for specific case where there is a static
variable initialized to an error condition and then later set to the
real handle once probe finish/completes.
This is to handle compilation problems like:
error: initializer element is not constant
where ERR_PTR() can't be used.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20251031130835.7953-2-ansuelsmth@gmail.com
[bjorn: Added () suffix on macro references]
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
---
include/linux/err.h | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -41,6 +41,14 @@ static inline void * __must_check ERR_PT
return (void *) error;
}
+/**
+ * INIT_ERR_PTR - Init a const error pointer.
+ * @error: A negative error code.
+ *
+ * Like ERR_PTR(), but usable to initialize static variables.
+ */
+#define INIT_ERR_PTR(error) ((void *)(error))
+
/* Return the pointer in the percpu address space. */
#define ERR_PTR_PCPU(error) ((void __percpu *)(unsigned long)ERR_PTR(error))

View File

@@ -0,0 +1,97 @@
From 7a94d5f31b549e18f908cb669c59f066f45a21c7 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Fri, 31 Oct 2025 14:08:33 +0100
Subject: [PATCH 2/2] soc: qcom: smem: better track SMEM uninitialized state
There is currently a problem where, in the specific case of SMEM not
initialized by SBL, any SMEM API wrongly returns PROBE_DEFER
communicating wrong info to any user of this API.
A better way to handle this would be to track the SMEM state and return
a different kind of error than PROBE_DEFER.
Rework the __smem handle to always init it to the error pointer
-EPROBE_DEFER following what is already done by the SMEM API.
If we detect that the SBL didn't initialized SMEM, set the __smem handle
to the error pointer -ENODEV.
Also rework the SMEM API to handle the __smem handle to be an error
pointer and return it appropriately.
This way user of the API can react and return a proper error or use
fallback way for the failing API.
While at it, change the return error when SMEM is not initialized by SBL
also to -ENODEV to make it consistent with the __smem handle and use
dev_err_probe() helper to return the message.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Link: https://lore.kernel.org/r/20251031130835.7953-3-ansuelsmth@gmail.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
---
drivers/soc/qcom/smem.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -353,8 +353,12 @@ static void *cached_entry_to_item(struct
return p - le32_to_cpu(e->size);
}
-/* Pointer to the one and only smem handle */
-static struct qcom_smem *__smem;
+/*
+ * Pointer to the one and only smem handle.
+ * Init to -EPROBE_DEFER to signal SMEM still has to be probed.
+ * Can be set to -ENODEV if SMEM is not initialized by SBL.
+ */
+static struct qcom_smem *__smem = INIT_ERR_PTR(-EPROBE_DEFER);
/* Timeout (ms) for the trylock of remote spinlocks */
#define HWSPINLOCK_TIMEOUT 1000
@@ -506,8 +510,8 @@ int qcom_smem_alloc(unsigned host, unsig
unsigned long flags;
int ret;
- if (!__smem)
- return -EPROBE_DEFER;
+ if (IS_ERR(__smem))
+ return PTR_ERR(__smem);
if (item < SMEM_ITEM_LAST_FIXED) {
dev_err(__smem->dev,
@@ -681,10 +685,10 @@ invalid_canary:
void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
{
struct smem_partition *part;
- void *ptr = ERR_PTR(-EPROBE_DEFER);
+ void *ptr;
- if (!__smem)
- return ptr;
+ if (IS_ERR(__smem))
+ return __smem;
if (WARN_ON(item >= __smem->item_count))
return ERR_PTR(-EINVAL);
@@ -717,8 +721,8 @@ int qcom_smem_get_free_space(unsigned ho
struct smem_header *header;
unsigned ret;
- if (!__smem)
- return -EPROBE_DEFER;
+ if (IS_ERR(__smem))
+ return PTR_ERR(__smem);
if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) {
part = &__smem->partitions[host];
@@ -1175,8 +1179,8 @@ static int qcom_smem_probe(struct platfo
header = smem->regions[0].virt_base;
if (le32_to_cpu(header->initialized) != 1 ||
le32_to_cpu(header->reserved)) {
- dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
- return -EINVAL;
+ __smem = ERR_PTR(-ENODEV);
+ return dev_err_probe(&pdev->dev, PTR_ERR(__smem), "SMEM is not initialized by SBL\n");
}
hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);

View File

@@ -0,0 +1,78 @@
From a2e7c46ca61dbfac25b0c1bf566d459f609bfe64 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 29 Oct 2025 13:38:24 +0100
Subject: [PATCH] cpufreq: qcom-nvmem: add compatible fallback for ipq806x for
no SMEM
On some IPQ806x SoC SMEM might be not initialized by SBL. This is the
case for some Google devices (the OnHub family) that can't make use of
SMEM to detect the SoC ID.
To handle these specific case, check if the SMEM is not initialized (by
checking if the qcom_smem_get_soc_id returns -ENODEV) and fallback to
OF machine compatible checking to identify the SoC variant.
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/cpufreq/qcom-cpufreq-nvmem.c | 35 ++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -251,13 +251,22 @@ len_error:
return ret;
}
+static const struct of_device_id qcom_cpufreq_ipq806x_match_list[] = {
+ { .compatible = "qcom,ipq8062", .data = (const void *)QCOM_ID_IPQ8062 },
+ { .compatible = "qcom,ipq8064", .data = (const void *)QCOM_ID_IPQ8064 },
+ { .compatible = "qcom,ipq8065", .data = (const void *)QCOM_ID_IPQ8065 },
+ { .compatible = "qcom,ipq8066", .data = (const void *)QCOM_ID_IPQ8066 },
+ { .compatible = "qcom,ipq8068", .data = (const void *)QCOM_ID_IPQ8068 },
+ { .compatible = "qcom,ipq8069", .data = (const void *)QCOM_ID_IPQ8069 },
+};
+
static int qcom_cpufreq_ipq8064_name_version(struct device *cpu_dev,
struct nvmem_cell *speedbin_nvmem,
char **pvs_name,
struct qcom_cpufreq_drv *drv)
{
+ int msm_id = -1, ret = 0;
int speed = 0, pvs = 0;
- int msm_id, ret = 0;
u8 *speedbin;
size_t len;
@@ -274,8 +283,30 @@ static int qcom_cpufreq_ipq8064_name_ver
get_krait_bin_format_a(cpu_dev, &speed, &pvs, speedbin);
ret = qcom_smem_get_soc_id(&msm_id);
- if (ret)
+ if (ret == -ENODEV) {
+ const struct of_device_id *match;
+ struct device_node *root;
+
+ root = of_find_node_by_path("/");
+ if (!root) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /* Fallback to compatible match with no SMEM initialized */
+ match = of_match_node(qcom_cpufreq_ipq806x_match_list, root);
+ of_node_put(root);
+ if (!match) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /* We found a matching device, get the msm_id from the data entry */
+ msm_id = (int)match->data;
+ ret = 0;
+ } else if (ret) {
goto exit;
+ }
switch (msm_id) {
case QCOM_ID_IPQ8062: