Re: [PATCH v4 3/3] firmware: qcom: scm: Fix tzmem state on probe retry

From: Marek Szyprowski

Date: Thu Aug 06 2026 - 05:33:25 EST


On 24.07.2026 11:49, Mukesh Ojha wrote:
> qcom_tzmem_enable() returns -EBUSY if called a second time, but this
> causes probe retries to fail permanently if a later step in
> qcom_scm_probe() defers after qcom_tzmem_enable() has already succeeded.
>
> Use DO_ONCE() to ensure qcom_tzmem_init() runs exactly once across all
> calls in a thread-safe manner. qcom_tzmem_dev is set on every call since
> probe retries use the same device pointer. The result of the first
> initialisation is cached and returned to every subsequent caller.
>
> Fixes: 40289e35ca52 ("firmware: qcom: scm: enable the TZ mem allocator")
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@xxxxxxxxxxxxxxxx>
> Signed-off-by: Mukesh Ojha <mukesh.ojha@xxxxxxxxxxxxxxxx>
> ---
> drivers/firmware/qcom/qcom_tzmem.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qcom_tzmem.c
> index 0635cbeacfc8..0fd9581275f1 100644
> --- a/drivers/firmware/qcom/qcom_tzmem.c
> +++ b/drivers/firmware/qcom/qcom_tzmem.c
> @@ -15,6 +15,7 @@
> #include <linux/kernel.h>
> #include <linux/list.h>
> #include <linux/mm.h>
> +#include <linux/once.h>
> #include <linux/radix-tree.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> @@ -507,14 +508,18 @@ phys_addr_t qcom_tzmem_to_phys(void *vaddr)
> }
> EXPORT_SYMBOL_GPL(qcom_tzmem_to_phys);
>
> +static void qcom_tzmem_do_init(int *result)
> +{
> + *result = qcom_tzmem_init();
> +}
> +
> int qcom_tzmem_enable(struct device *dev)
> {
> - if (qcom_tzmem_dev)
> - return -EBUSY;
> + static int result;
>
> qcom_tzmem_dev = dev;
> -
> - return qcom_tzmem_init();
> + DO_ONCE(qcom_tzmem_do_init, &result);
One should use DO_ONCE_SLEEPABLE() here, otherwise it triggers a warning during
boot on some on my test systems. Here is a log captured with
CONFIG_DEBUG_ATOMIC_SLEEP=y on recent linux-next releases, where this patch is
applied as commit 9941fe8a04f3 ("firmware: qcom: scm: Fix tzmem state on probe
retry"):

qcom_scm: convention: smc arm 64
BUG: sleeping function called from invalid context at drivers/firmware/qcom/qcom_scm.c:334
in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 49, name: kworker/u16:2
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
locks held by kworker/u16:2/49: 4, last CPU#3:
 #0: ffff000000032140 ((wq_completion)events_unbound){+.+.}-{0:0}, at: process_one_work+0x6b4/0x840
 #1: ffff800080563d90 (deferred_probe_work){+.+.}-{0:0}, at: process_one_work+0x1fc/0x840
 #2: ffff00000036f938 (&dev->mutex){....}-{4:4}, at: __device_attach+0x3c/0x190
 #3: ffffa83e89fe4af0 (once_lock){....}-{3:3}, at: __do_once_start+0x2c/0x74
irq event stamp: 80794
hardirqs last  enabled at (80793): [<ffffa83e87faa600>] _raw_spin_unlock_irqrestore+0x6c/0x70
hardirqs last disabled at (80794): [<ffffa83e87fa9a6c>] _raw_spin_lock_irqsave+0x84/0x88
softirqs last  enabled at (80780): [<ffffa83e86ccc050>] handle_softirqs+0x5dc/0x5f4
softirqs last disabled at (80755): [<ffffa83e86c10700>] __do_softirq+0x14/0x20
CPU: 3 UID: 0 PID: 49 Comm: kworker/u16:2 Not tainted 7.2.0-rc6-next-20260805+ #13357 PREEMPT
Hardware name: Arduino UnoQ (DT)
Workqueue: events_unbound deferred_probe_work_func
Call trace:
 show_stack+0x18/0x24 (C)
 dump_stack_lvl+0x8c/0xcc
 dump_stack+0x18/0x24
 __might_resched+0x148/0x24c
 __might_sleep+0x48/0x7c
 qcom_scm_call+0x30/0xc0
 __qcom_scm_is_call_available+0x98/0x100
 qcom_scm_shm_bridge_enable+0x60/0xbc
 qcom_tzmem_enable+0xf8/0x118
 qcom_scm_probe+0x2d0/0x680
 platform_probe+0x5c/0x9c
 really_probe+0xbc/0x29c
 __driver_probe_device+0x16c/0x19c
 driver_probe_device+0xb8/0x118
 __device_attach_driver+0xb8/0x118
 bus_for_each_drv+0x88/0xe8
 __device_attach+0xa0/0x190
 device_initial_probe+0x50/0x54
 bus_probe_device+0x38/0xa8
 deferred_probe_work_func+0x8c/0xc8
 process_one_work+0x24c/0x840
 worker_thread+0x1bc/0x368
 kthread+0x134/0x140
 ret_from_fork+0x10/0x20

=============================
[ BUG: Invalid wait context ]
7.2.0-rc6-next-20260805+ #13357 Tainted: G        W
-----------------------------
kworker/u16:2/49 is trying to lock:
ffffa83e8a485e38 (qcom_scm_lock){....}-{4:4}, at: __scm_smc_do+0x70/0x488
other info that might help us debug this:
context-{5:5}
locks held by kworker/u16:2/49: 4, last CPU#3:
 #0: ffff000000032140 ((wq_completion)events_unbound){+.+.}-{0:0}, at: process_one_work+0x6b4/0x840
 #1: ffff800080563d90 (deferred_probe_work){+.+.}-{0:0}, at: process_one_work+0x1fc/0x840
 #2: ffff00000036f938 (&dev->mutex){....}-{4:4}, at: __device_attach+0x3c/0x190
 #3: ffffa83e89fe4af0 (once_lock){....}-{3:3}, at: __do_once_start+0x2c/0x74
stack backtrace:
CPU: 3 UID: 0 PID: 49 Comm: kworker/u16:2 Tainted: G        W           7.2.0-rc6-next-20260805+ #13357 PREEMPT
Tainted: [W]=WARN
Hardware name: Arduino UnoQ (DT)
Workqueue: events_unbound deferred_probe_work_func
Call trace:
 show_stack+0x18/0x24 (C)
 dump_stack_lvl+0x8c/0xcc
 dump_stack+0x18/0x24
 __lock_acquire+0x928/0x1f90
 lock_acquire+0x2b8/0x3ec
 __mutex_lock+0xbc/0x860
 mutex_lock_nested+0x24/0x30
 __scm_smc_do+0x70/0x488
 __scm_smc_call+0xd4/0x444
 qcom_scm_call+0x64/0xc0
 __qcom_scm_is_call_available+0x98/0x100
 qcom_scm_shm_bridge_enable+0x60/0xbc
 qcom_tzmem_enable+0xf8/0x118
 qcom_scm_probe+0x2d0/0x680
 platform_probe+0x5c/0x9c
 really_probe+0xbc/0x29c
 __driver_probe_device+0x16c/0x19c
 driver_probe_device+0xb8/0x118
 __device_attach_driver+0xb8/0x118
 bus_for_each_drv+0x88/0xe8
 __device_attach+0xa0/0x190
 device_initial_probe+0x50/0x54
 bus_probe_device+0x38/0xa8
 deferred_probe_work_func+0x8c/0xc8
 process_one_work+0x24c/0x840
 worker_thread+0x1bc/0x368
 kthread+0x134/0x140
 ret_from_fork+0x10/0x20
qcom_scm firmware:scm: qseecom: found qseecom with version 0x1402000
qcom_scm firmware:scm: qseecom: untested machine, skipping


> + return result;
> }
> EXPORT_SYMBOL_GPL(qcom_tzmem_enable);
>

Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland