Skip to content

Commit ca4d834

Browse files
Xu Yanggregkh
authored andcommitted
usb: typec: tcpm: fix tcpm unregister port but leave a pending timer
In current design, when the tcpm port is unregisterd, the kthread_worker will be destroyed in the last step. Inside the kthread_destroy_worker(), the worker will flush all the works and wait for them to end. However, if one of the works calls hrtimer_start(), this hrtimer will be pending until timeout even though tcpm port is removed. Once the hrtimer timeout, many strange kernel dumps appear. Thus, we can first complete kthread_destroy_worker(), then cancel all the hrtimers. This will guarantee that no hrtimer is pending at the end. Fixes: 3ed8e1c ("usb: typec: tcpm: Migrate workqueue to RT priority for processing events") cc: <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Acked-by: Heikki Krogerus <[email protected]> Signed-off-by: Xu Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 4c4e162 commit ca4d834

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

drivers/usb/typec/tcpm/tcpm.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ struct tcpm_port {
324324

325325
bool attached;
326326
bool connected;
327+
bool registered;
327328
bool pd_supported;
328329
enum typec_port_type port_type;
329330

@@ -6291,31 +6292,35 @@ static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer)
62916292
{
62926293
struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer);
62936294

6294-
kthread_queue_work(port->wq, &port->state_machine);
6295+
if (port->registered)
6296+
kthread_queue_work(port->wq, &port->state_machine);
62956297
return HRTIMER_NORESTART;
62966298
}
62976299

62986300
static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *timer)
62996301
{
63006302
struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer);
63016303

6302-
kthread_queue_work(port->wq, &port->vdm_state_machine);
6304+
if (port->registered)
6305+
kthread_queue_work(port->wq, &port->vdm_state_machine);
63036306
return HRTIMER_NORESTART;
63046307
}
63056308

63066309
static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer)
63076310
{
63086311
struct tcpm_port *port = container_of(timer, struct tcpm_port, enable_frs_timer);
63096312

6310-
kthread_queue_work(port->wq, &port->enable_frs);
6313+
if (port->registered)
6314+
kthread_queue_work(port->wq, &port->enable_frs);
63116315
return HRTIMER_NORESTART;
63126316
}
63136317

63146318
static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer)
63156319
{
63166320
struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer);
63176321

6318-
kthread_queue_work(port->wq, &port->send_discover_work);
6322+
if (port->registered)
6323+
kthread_queue_work(port->wq, &port->send_discover_work);
63196324
return HRTIMER_NORESTART;
63206325
}
63216326

@@ -6403,6 +6408,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
64036408
typec_port_register_altmodes(port->typec_port,
64046409
&tcpm_altmode_ops, port,
64056410
port->port_altmode, ALTMODE_DISCOVERY_MAX);
6411+
port->registered = true;
64066412

64076413
mutex_lock(&port->lock);
64086414
tcpm_init(port);
@@ -6424,6 +6430,9 @@ void tcpm_unregister_port(struct tcpm_port *port)
64246430
{
64256431
int i;
64266432

6433+
port->registered = false;
6434+
kthread_destroy_worker(port->wq);
6435+
64276436
hrtimer_cancel(&port->send_discover_timer);
64286437
hrtimer_cancel(&port->enable_frs_timer);
64296438
hrtimer_cancel(&port->vdm_state_machine_timer);
@@ -6435,7 +6444,6 @@ void tcpm_unregister_port(struct tcpm_port *port)
64356444
typec_unregister_port(port->typec_port);
64366445
usb_role_switch_put(port->role_sw);
64376446
tcpm_debugfs_exit(port);
6438-
kthread_destroy_worker(port->wq);
64396447
}
64406448
EXPORT_SYMBOL_GPL(tcpm_unregister_port);
64416449

0 commit comments

Comments
 (0)