Sync RK3326 + 6.12-LTS bugfixes from ROCKNIX

mali-bifrost (RK3326): replace patch 003 with the clean RK3576-style
version. Drops the dead BSP-style probe-defer dance, balances the
regulator refcount during probe (mirrors the clock prepare/enable),
and removes the regulator_is_enabled guard that was silently skipping
the disable on suspend. Frees the kernel log of the "missed warnings"
sunshineinabox flagged.

iwd (network): ControlPortOverNL80211=true so 802.1X EAPOL frames go
through nl80211 instead of the legacy raw socket. Some clones with
modern wifi firmware fail association otherwise.

linux 6.12-LTS: add 0020-usb-gadget-u_ether-guard-NULL-gadget upstream
fix. Without it, querying ethtool on the surviving NCM interface
during gadget detach dereferences a NULL dev->gadget pointer and
panics. Affects anyone who flips USB gadget mode at runtime.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Douglas Teles
2026-06-23 14:16:13 -03:00
parent a495eb10a9
commit 5805267f90
3 changed files with 80 additions and 189 deletions
@@ -1,199 +1,39 @@
From 5b1c50b3e181a57f5ce0a7d8c50f0f0823ac1609 Mon Sep 17 00:00:00 2001
From: Paul Reioux <reioux@gmail.com>
Date: Wed, 12 Jun 2024 07:36:52 -0700
Subject: [PATCH] midgard: refactor power init and fixed unbalanced runtime PM
calls
midgard: balance mali probe regulator refcount + drop regulator is_enabled guard
Signed-off-by: Paul Reioux <reioux@gmail.com>
---
.../gpu/arm/midgard/mali_kbase_core_linux.c | 124 ++++++++++++------
.../platform/meson/mali_kbase_runtime_pm.c | 11 +-
2 files changed, 88 insertions(+), 47 deletions(-)
diff --git a/product/kernel/drivers/gpu/arm/midgard/mali_kbase_core_linux.c b/product/kernel/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
index 0ad8a70..8db0c13 100644
--- a/product/kernel/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
+++ b/product/kernel/drivers/gpu/arm/midgard/mali_kbase_core_linux.c
@@ -4507,31 +4507,44 @@ int power_control_init(struct kbase_device *kbdev)
pdev = to_platform_device(kbdev->dev);
-#if defined(CONFIG_REGULATOR)
- /* Since the error code EPROBE_DEFER causes the entire probing
- * procedure to be restarted from scratch at a later time,
- * all regulators will be released before returning.
- *
- * Any other error is ignored and the driver will continue
- * operating with a partial initialization of regulators.
- */
- for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
- kbdev->regulators[i] = regulator_get_optional(kbdev->dev, regulator_names[i]);
- if (IS_ERR(kbdev->regulators[i])) {
- err = PTR_ERR(kbdev->regulators[i]);
- kbdev->regulators[i] = NULL;
- break;
- }
- }
- if (err == -EPROBE_DEFER) {
- while (i > 0)
- regulator_put(kbdev->regulators[--i]);
- return err;
+// #if defined(CONFIG_REGULATOR)
+// /* Since the error code EPROBE_DEFER causes the entire probing
+// * procedure to be restarted from scratch at a later time,
+// * all regulators will be released before returning.
+// *
+// * Any other error is ignored and the driver will continue
+// * operating with a partial initialization of regulators.
+// */
+// for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
+// kbdev->regulators[i] = regulator_get_optional(kbdev->dev, regulator_names[i]);
+// if (IS_ERR(kbdev->regulators[i])) {
+// err = PTR_ERR(kbdev->regulators[i]);
+// kbdev->regulators[i] = NULL;
+// break;
+// }
+// }
+// if (err == -EPROBE_DEFER) {
+// while (i > 0)
+// regulator_put(kbdev->regulators[--i]);
+// return err;
+// }
+ kbdev->regulators[0] = devm_regulator_get_optional(kbdev->dev, regulator_names[0]);
+
+ if (IS_ERR(kbdev->regulators[0])) {
+ err = PTR_ERR(kbdev->regulators[0]);
+ kbdev->regulators[0] = NULL;
+ kbdev->nr_regulators = 0;
+ } else {
+ kbdev->nr_regulators = 1;
+
+ err = regulator_enable(kbdev->regulators[0]);
+ if (err)
+ dev_dbg(&pdev->dev, "regulator_enable failed\n");
}
- kbdev->nr_regulators = i;
@@ -4607,6 +4607,15 @@
kbdev->nr_regulators = i;
dev_dbg(&pdev->dev, "Regulators probed: %u\n", kbdev->nr_regulators);
-#endif
+
+// #endif
+ /* Enable regulators during probe to balance the first runtime suspend's
+ * regulator_disable() call — mirrors what clocks already do with
+ * clk_prepare_enable() below.
+ */
+ for (i = 0; i < kbdev->nr_regulators; i++) {
+ if (kbdev->regulators[i])
+ WARN_ON(regulator_enable(kbdev->regulators[i]));
+ }
#endif
/* Having more clocks than regulators is acceptable, while the
* opposite shall not happen.
@@ -4543,30 +4556,55 @@ int power_control_init(struct kbase_device *kbdev)
* Any other error is ignored and the driver will continue
* operating with a partial initialization of clocks.
*/
- for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
- kbdev->clocks[i] = of_clk_get_by_name(kbdev->dev->of_node, "bus");
- if (IS_ERR(kbdev->clocks[i])) {
- err = PTR_ERR(kbdev->clocks[i]);
- kbdev->clocks[i] = NULL;
- break;
- }
- err = clk_prepare_enable(kbdev->clocks[i]);
- if (err) {
- dev_err(kbdev->dev, "Failed to prepare and enable clock (%d)\n", err);
- clk_put(kbdev->clocks[i]);
- break;
- }
- }
- if (err == -EPROBE_DEFER) {
- while (i > 0) {
- clk_disable_unprepare(kbdev->clocks[--i]);
- clk_put(kbdev->clocks[i]);
- }
- goto clocks_probe_defer;
+ kbdev->clocks[0] = devm_clk_get_optional(kbdev->dev, NULL);
+ if (!IS_ERR(kbdev->clocks[0]))
+ dev_dbg(kbdev->dev, "clk_get: %s\n", __clk_get_name(kbdev->clocks[0]));
+ else
+ dev_err(kbdev->dev, "clk_get: is NULL");
+
+ /* if platform device is enabled, disable it now */
+ //if (__clk_is_enabled(kbdev->clocks[0])) {
+ // clk_disable(kbdev->clocks[0]);
+ //}
+ /* delete from clk tree */
+ //clk_unprepare(kbdev->clocks[0]);
+ //clk_put(kbdev->clocks[0]);
+
+ /* now grab the gpu clock node from device tree definition */
+ //kbdev->clocks[0] = of_clk_get_by_name(kbdev->dev->of_node, "gpu");
+
+ /* we are kinda commited here.. if this fails, the system will lock up */
+ err = clk_prepare_enable(kbdev->clocks[0]);
+ if (err) {
+ dev_err(kbdev->dev, "Failed to prepare and enable clock (%d)\n", err);
+ clk_put(kbdev->clocks[0]);
}
- kbdev->nr_clocks = i;
+ // for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
+ // kbdev->clocks[i] = of_clk_get(kbdev->dev->of_node, (int)i);
+ // if (IS_ERR(kbdev->clocks[i])) {
+ // err = PTR_ERR(kbdev->clocks[i]);
+ // kbdev->clocks[i] = NULL;
+ // break;
+ // }
+
+ // err = clk_prepare_enable(kbdev->clocks[i]);
+ // if (err) {
+ // dev_err(kbdev->dev, "Failed to prepare and enable clock (%d)\n", err);
+ // clk_put(kbdev->clocks[i]);
+ // break;
+ // }
+ // }
+ // if (err == -EPROBE_DEFER) {
+ // while (i > 0) {
+ // clk_disable_unprepare(kbdev->clocks[--i]);
+ // clk_put(kbdev->clocks[i]);
+ // }
+ // goto clocks_probe_defer;
+ // }
+
+ kbdev->nr_clocks = 1;
dev_dbg(&pdev->dev, "Clocks probed: %u\n", kbdev->nr_clocks);
/* Any error in parsing the OPP table from the device file
diff --git a/product/kernel/drivers/gpu/arm/midgard/platform/meson/mali_kbase_runtime_pm.c b/product/kernel/drivers/gpu/arm/midgard/platform/meson/mali_kbase_runtime_pm.c
index bd3b4b5..33a24bb 100644
--- a/product/kernel/drivers/gpu/arm/midgard/platform/meson/mali_kbase_runtime_pm.c
+++ b/product/kernel/drivers/gpu/arm/midgard/platform/meson/mali_kbase_runtime_pm.c
@@ -113,7 +113,8 @@ static void enable_gpu_power_control(struct kbase_device *kbdev)
if (WARN_ON(kbdev->clocks[i] == NULL))
;
else if (!__clk_is_enabled(kbdev->clocks[i]))
- WARN_ON(clk_prepare_enable(kbdev->clocks[i]));
+ //WARN_ON(clk_prepare_enable(kbdev->clocks[i]));
+ ;
}
}
@@ -125,8 +126,9 @@ static void disable_gpu_power_control(struct kbase_device *kbdev)
if (WARN_ON(kbdev->clocks[i] == NULL))
;
else if (__clk_is_enabled(kbdev->clocks[i])) {
- clk_disable_unprepare(kbdev->clocks[i]);
- WARN_ON(__clk_is_enabled(kbdev->clocks[i]));
+ //clk_disable_unprepare(kbdev->clocks[i]);
+ //WARN_ON(__clk_is_enabled(kbdev->clocks[i]));
+ ;
@@ -4731,6 +4740,7 @@
#if defined(CONFIG_OF) && defined(CONFIG_REGULATOR)
for (i = 0; i < BASE_MAX_NR_CLOCKS_REGULATORS; i++) {
if (kbdev->regulators[i]) {
+ regulator_disable(kbdev->regulators[i]);
regulator_put(kbdev->regulators[i]);
kbdev->regulators[i] = NULL;
}
}
@@ -135,7 +137,8 @@ static void disable_gpu_power_control(struct kbase_device *kbdev)
--- a/product/kernel/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_runtime_pm.c
+++ b/product/kernel/drivers/gpu/arm/midgard/platform/devicetree/mali_kbase_runtime_pm.c
@@ -38,7 +38,7 @@ static void enable_gpu_power_control(struct kbase_device *kbdev)
for (i = 0; i < kbdev->nr_regulators; i++) {
if (WARN_ON(kbdev->regulators[i] == NULL))
;
else if (regulator_is_enabled(kbdev->regulators[i]))
- WARN_ON(regulator_disable(kbdev->regulators[i]));
+ //WARN_ON(regulator_disable(kbdev->regulators[i]));
+ ;
- else if (!regulator_is_enabled(kbdev->regulators[i]))
+ else
WARN_ON(regulator_enable(kbdev->regulators[i]));
}
#endif
}
--
2.34.1
@@ -0,0 +1,51 @@
From: Kuen-Han Tsai <khtsai@google.com>
Date: Mon, 16 Mar 2026 15:49:09 +0800
Subject: [PATCH] usb: gadget: u_ether: Fix NULL pointer deref in eth_get_drvinfo
Commit ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with
device_move") reparents the gadget device to /sys/devices/virtual during
unbind, clearing the gadget pointer. If the userspace tool queries on
the surviving interface during this detached window, this leads to a
NULL pointer dereference.
Unable to handle kernel NULL pointer dereference
Call trace:
eth_get_drvinfo+0x50/0x90
ethtool_get_drvinfo+0x5c/0x1f0
__dev_ethtool+0xaec/0x1fe0
dev_ethtool+0x134/0x2e0
dev_ioctl+0x338/0x560
Add a NULL check for dev->gadget in eth_get_drvinfo(). When detached,
skip copying the fw_version and bus_info strings, which is natively
handled by ethtool_get_drvinfo for empty strings.
Suggested-by: Val Packett <val@packett.cool>
Reported-by: Val Packett <val@packett.cool>
Closes: https://lore.kernel.org/linux-usb/10890524-cf83-4a71-b879-93e2b2cc1fcc@packett.cool/
Fixes: ec35c1969650 ("usb: gadget: f_ncm: Fix net_device lifecycle with device_move")
Cc: stable@vger.kernel.org
Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
Link: https://lore.kernel.org/linux-usb/20260316-eth-null-deref-v1-1-07005f33be85@google.com/
---
drivers/usb/gadget/function/u_ether.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 1a9e7c495e2e..a653fae9c0cb 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -113,8 +113,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
strscpy(p->driver, "g_ether", sizeof(p->driver));
strscpy(p->version, UETH__VERSION, sizeof(p->version));
- strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
- strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+ if (dev->gadget) {
+ strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
+ strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
+ }
}
/* REVISIT can also support:
@@ -1,7 +1,7 @@
# use built-in dhcp client
[General]
EnableNetworkConfiguration=true
ControlPortOverNL80211=false
ControlPortOverNL80211=true
UseDefaultInterface=true
AddressRandomization=disabled
AddressRandomizationRange=full