FAILED: patch "[PATCH] usb: typec: tcpm: fix tcpm unregister port but leave a" failed to apply to 5.10-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ca4d8344a72b91fb9d4c8bfbc22204b4c09c5d8f Mon Sep 17 00:00:00 2001
From: Xu Yang <[email protected]>
Date: Thu, 9 Dec 2021 18:15:07 +0800
Subject: [PATCH] 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.
drivers/usb/typec/tcpm/tcpm.c +13 -5
@@ -324,6 +324,7 @@ struct tcpm_port {bool attached;bool connected; +bool registered;bool pd_supported;enum typec_port_type port_type;
@@ -6291,7 +6292,8 @@ static enum hrtimer_restart state_machine_timer_handler(struct hrtimer *timer) { struct tcpm_port *port = container_of(timer, struct tcpm_port, state_machine_timer); -kthread_queue_work (port->wq, &port->state_machine); +if (port->registered) +kthread_queue_work (port->wq, &port->state_machine);return HRTIMER_NORESTART ; }
@@ -6299,7 +6301,8 @@ static enum hrtimer_restart vdm_state_machine_timer_handler(struct hrtimer *time { struct tcpm_port *port = container_of(timer, struct tcpm_port, vdm_state_machine_timer); -kthread_queue_work (port->wq, &port->vdm_state_machine); +if (port->registered) +kthread_queue_work (port->wq, &port->vdm_state_machine);return HRTIMER_NORESTART ; }
@@ -6307,7 +6310,8 @@ static enum hrtimer_restart enable_frs_timer_handler(struct hrtimer *timer) { struct tcpm_port *port = container_of(timer, struct tcpm_port, enable_frs_timer); -kthread_queue_work (port->wq, &port->enable_frs); +if (port->registered) +kthread_queue_work (port->wq, &port->enable_frs);return HRTIMER_NORESTART ; }
@@ -6315,7 +6319,8 @@ static enum hrtimer_restart send_discover_timer_handler(struct hrtimer *timer) { struct tcpm_port *port = container_of(timer, struct tcpm_port, send_discover_timer); -kthread_queue_work (port->wq, &port->send_discover_work); +if (port->registered) +kthread_queue_work (port->wq, &port->send_discover_work);return HRTIMER_NORESTART ; }
@@ -6403,6 +6408,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)typec_port_register_altmodes (port->typec_port, &tcpm_altmode_ops, port, port->port_altmode,ALTMODE_DISCOVERY_MAX ); + port->registered = true;mutex_lock (&port->lock);tcpm_init (port);
@@ -6424,6 +6430,9 @@ void tcpm_unregister_port(struct tcpm_port *port) {int i; + port->registered = false; +kthread_destroy_worker (port->wq); +hrtimer_cancel (&port->send_discover_timer);hrtimer_cancel (&port->enable_frs_timer);hrtimer_cancel (&port->vdm_state_machine_timer);
@@ -6435,7 +6444,6 @@ void tcpm_unregister_port(struct tcpm_port *port)typec_unregister_port (port->typec_port);usb_role_switch_put (port->role_sw);tcpm_debugfs_exit (port); -kthread_destroy_worker (port->wq); }EXPORT_SYMBOL_GPL (tcpm_unregister_port);