diff options
author | Raul E Rangel <rrangel@chromium.org> | 2019-04-19 18:30:22 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-04-25 12:07:09 +0300 |
commit | a4d6a2989dc3f2f2bcd25ca53dd187a1de68ffac (patch) | |
tree | be1cc927a84425028d072fbe6a4d95c63b84a403 | |
parent | cf28369c634fafb5f4e81750cba6988cdb4b4490 (diff) | |
download | linux-a4d6a2989dc3f2f2bcd25ca53dd187a1de68ffac.tar.xz |
usb/hcd: Send a uevent signaling that the host controller had died
This change will send an OFFLINE event to udev with the ERROR=DEAD
environment variable set when the HC dies.
By notifying user space the appropriate policies can be applied.
i.e.,
* Collect error logs.
* Notify the user that USB is no longer functional.
* Perform a graceful reboot.
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/ABI/testing/usb-uevent | 27 | ||||
-rw-r--r-- | drivers/usb/core/hcd.c | 24 | ||||
-rw-r--r-- | include/linux/usb/hcd.h | 1 |
3 files changed, 52 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/usb-uevent b/Documentation/ABI/testing/usb-uevent new file mode 100644 index 000000000000..d35c3cad892c --- /dev/null +++ b/Documentation/ABI/testing/usb-uevent @@ -0,0 +1,27 @@ +What: Raise a uevent when a USB Host Controller has died +Date: 2019-04-17 +KernelVersion: 5.2 +Contact: linux-usb@vger.kernel.org +Description: When the USB Host Controller has entered a state where it is no + longer functional a uevent will be raised. The uevent will + contain ACTION=offline and ERROR=DEAD. + + Here is an example taken using udevadm monitor -p: + + KERNEL[130.428945] offline /devices/pci0000:00/0000:00:10.0/usb2 (usb) + ACTION=offline + BUSNUM=002 + DEVNAME=/dev/bus/usb/002/001 + DEVNUM=001 + DEVPATH=/devices/pci0000:00/0000:00:10.0/usb2 + DEVTYPE=usb_device + DRIVER=usb + ERROR=DEAD + MAJOR=189 + MINOR=128 + PRODUCT=1d6b/2/414 + SEQNUM=2168 + SUBSYSTEM=usb + TYPE=9/0/1 + +Users: chromium-os-dev@chromium.org diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 00655424baf5..94d22551fc1b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2435,6 +2435,19 @@ EXPORT_SYMBOL_GPL(usb_hcd_irq); /*-------------------------------------------------------------------------*/ +/* Workqueue routine for when the root-hub has died. */ +static void hcd_died_work(struct work_struct *work) +{ + struct usb_hcd *hcd = container_of(work, struct usb_hcd, died_work); + static char *env[] = { + "ERROR=DEAD", + NULL + }; + + /* Notify user space that the host controller has died */ + kobject_uevent_env(&hcd->self.root_hub->dev.kobj, KOBJ_OFFLINE, env); +} + /** * usb_hc_died - report abnormal shutdown of a host controller (bus glue) * @hcd: pointer to the HCD representing the controller @@ -2475,6 +2488,13 @@ void usb_hc_died (struct usb_hcd *hcd) usb_kick_hub_wq(hcd->self.root_hub); } } + + /* Handle the case where this function gets called with a shared HCD */ + if (usb_hcd_is_primary_hcd(hcd)) + schedule_work(&hcd->died_work); + else + schedule_work(&hcd->primary_hcd->died_work); + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); /* Make sure that the other roothub is also deallocated. */ } @@ -2542,6 +2562,8 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif + INIT_WORK(&hcd->died_work, hcd_died_work); + hcd->driver = driver; hcd->speed = driver->flags & HCD_MASK; hcd->product_desc = (driver->product_desc) ? driver->product_desc : @@ -2895,6 +2917,7 @@ error_create_attr_group: #ifdef CONFIG_PM cancel_work_sync(&hcd->wakeup_work); #endif + cancel_work_sync(&hcd->died_work); mutex_lock(&usb_bus_idr_lock); usb_disconnect(&rhdev); /* Sets rhdev to NULL */ mutex_unlock(&usb_bus_idr_lock); @@ -2955,6 +2978,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) #ifdef CONFIG_PM cancel_work_sync(&hcd->wakeup_work); #endif + cancel_work_sync(&hcd->died_work); mutex_lock(&usb_bus_idr_lock); usb_disconnect(&rhdev); /* Sets rhdev to NULL */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 695931b03684..66a24b13e2ab 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -98,6 +98,7 @@ struct usb_hcd { #ifdef CONFIG_PM struct work_struct wakeup_work; /* for remote wakeup */ #endif + struct work_struct died_work; /* for when the device dies */ /* * hardware info/state |