Skip to content

Commit

Permalink
net: wwan: t7xx: Fix FSM command timeout issue
Browse files Browse the repository at this point in the history
[ Upstream commit 4f619d5 ]

When driver processes the internal state change command, it use an
asynchronous thread to process the command operation. If the main
thread detects that the task has timed out, the asynchronous thread
will panic when executing the completion notification because the
main thread completion object has been released.

BUG: unable to handle page fault for address: fffffffffffffff8
PGD 1f283a067 P4D 1f283a067 PUD 1f283c067 PMD 0
Oops: 0000 [#1] PREEMPT SMP NOPTI
RIP: 0010:complete_all+0x3e/0xa0
[...]
Call Trace:
 <TASK>
 ? __die_body+0x68/0xb0
 ? page_fault_oops+0x379/0x3e0
 ? exc_page_fault+0x69/0xa0
 ? asm_exc_page_fault+0x22/0x30
 ? complete_all+0x3e/0xa0
 fsm_main_thread+0xa3/0x9c0 [mtk_t7xx (HASH:1400 5)]
 ? __pfx_autoremove_wake_function+0x10/0x10
 kthread+0xd8/0x110
 ? __pfx_fsm_main_thread+0x10/0x10 [mtk_t7xx (HASH:1400 5)]
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x38/0x50
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1b/0x30
 </TASK>
[...]
CR2: fffffffffffffff8
---[ end trace 0000000000000000 ]---

Use the reference counter to ensure safe release as Sergey suggests:
https://lore.kernel.org/all/[email protected]/

Fixes: 13e920d ("net: wwan: t7xx: Add core components")
Signed-off-by: Jinjian Song <[email protected]>
Acked-by: Sergey Ryazanov <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
Jinjian-Song authored and gregkh committed Jan 9, 2025
1 parent 6dfa451 commit e6e6882
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
26 changes: 17 additions & 9 deletions drivers/net/wwan/t7xx/t7xx_state_monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,21 @@ void t7xx_fsm_broadcast_state(struct t7xx_fsm_ctl *ctl, enum md_state state)
fsm_state_notify(ctl->md, state);
}

static void fsm_release_command(struct kref *ref)
{
struct t7xx_fsm_command *cmd = container_of(ref, typeof(*cmd), refcnt);

kfree(cmd);
}

static void fsm_finish_command(struct t7xx_fsm_ctl *ctl, struct t7xx_fsm_command *cmd, int result)
{
if (cmd->flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
*cmd->ret = result;
complete_all(cmd->done);
cmd->result = result;
complete_all(&cmd->done);
}

kfree(cmd);
kref_put(&cmd->refcnt, fsm_release_command);
}

static void fsm_del_kf_event(struct t7xx_fsm_event *event)
Expand Down Expand Up @@ -475,7 +482,6 @@ static int fsm_main_thread(void *data)

int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id, unsigned int flag)
{
DECLARE_COMPLETION_ONSTACK(done);
struct t7xx_fsm_command *cmd;
unsigned long flags;
int ret;
Expand All @@ -487,11 +493,13 @@ int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id
INIT_LIST_HEAD(&cmd->entry);
cmd->cmd_id = cmd_id;
cmd->flag = flag;
kref_init(&cmd->refcnt);
if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
cmd->done = &done;
cmd->ret = &ret;
init_completion(&cmd->done);
kref_get(&cmd->refcnt);
}

kref_get(&cmd->refcnt);
spin_lock_irqsave(&ctl->command_lock, flags);
list_add_tail(&cmd->entry, &ctl->command_queue);
spin_unlock_irqrestore(&ctl->command_lock, flags);
Expand All @@ -501,11 +509,11 @@ int t7xx_fsm_append_cmd(struct t7xx_fsm_ctl *ctl, enum t7xx_fsm_cmd_state cmd_id
if (flag & FSM_CMD_FLAG_WAIT_FOR_COMPLETION) {
unsigned long wait_ret;

wait_ret = wait_for_completion_timeout(&done,
wait_ret = wait_for_completion_timeout(&cmd->done,
msecs_to_jiffies(FSM_CMD_TIMEOUT_MS));
if (!wait_ret)
return -ETIMEDOUT;

ret = wait_ret ? cmd->result : -ETIMEDOUT;
kref_put(&cmd->refcnt, fsm_release_command);
return ret;
}

Expand Down
5 changes: 3 additions & 2 deletions drivers/net/wwan/t7xx/t7xx_state_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ struct t7xx_fsm_command {
struct list_head entry;
enum t7xx_fsm_cmd_state cmd_id;
unsigned int flag;
struct completion *done;
int *ret;
struct completion done;
int result;
struct kref refcnt;
};

struct t7xx_fsm_notifier {
Expand Down

0 comments on commit e6e6882

Please sign in to comment.