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>
This commit is contained in:
		
							parent
							
								
									cf28369c63
								
							
						
					
					
						commit
						a4d6a2989d
					
				
							
								
								
									
										27
									
								
								Documentation/ABI/testing/usb-uevent
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Documentation/ABI/testing/usb-uevent
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user