]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
ipq806x: 6.12: backport patch to handle CPUFreq with no SMEM 20587/head
authorChristian Marangi <ansuelsmth@gmail.com>
Wed, 29 Oct 2025 13:35:18 +0000 (14:35 +0100)
committerChristian Marangi <ansuelsmth@gmail.com>
Tue, 4 Nov 2025 18:24:34 +0000 (19:24 +0100)
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>
target/linux/ipq806x/patches-6.12/001-01-v6.19-err.h-add-INIT_ERR_PTR-macro.patch [new file with mode: 0644]
target/linux/ipq806x/patches-6.12/001-02-v6.19-soc-qcom-smem-better-track-SMEM-uninitialized-state.patch [new file with mode: 0644]
target/linux/ipq806x/patches-6.12/002-v6.19-cpufreq-qcom-nvmem-add-compatible-fallback-for-ipq80.patch [new file with mode: 0644]

diff --git a/target/linux/ipq806x/patches-6.12/001-01-v6.19-err.h-add-INIT_ERR_PTR-macro.patch b/target/linux/ipq806x/patches-6.12/001-01-v6.19-err.h-add-INIT_ERR_PTR-macro.patch
new file mode 100644 (file)
index 0000000..a6440b7
--- /dev/null
@@ -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))
diff --git a/target/linux/ipq806x/patches-6.12/001-02-v6.19-soc-qcom-smem-better-track-SMEM-uninitialized-state.patch b/target/linux/ipq806x/patches-6.12/001-02-v6.19-soc-qcom-smem-better-track-SMEM-uninitialized-state.patch
new file mode 100644 (file)
index 0000000..e93950a
--- /dev/null
@@ -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);
diff --git a/target/linux/ipq806x/patches-6.12/002-v6.19-cpufreq-qcom-nvmem-add-compatible-fallback-for-ipq80.patch b/target/linux/ipq806x/patches-6.12/002-v6.19-cpufreq-qcom-nvmem-add-compatible-fallback-for-ipq80.patch
new file mode 100644 (file)
index 0000000..e8ca396
--- /dev/null
@@ -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: