Re: [PATCH v9 17/19] usb: resume (wakeup) child device when port is powered on

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 9 May 2014, Dan Williams wrote:

> Testing looks good.  In my objection to this approach I neglected to
> consider that the port_status_lock now protects us from port_event()
> usb_port_{suspend_resume} collisions.  I have updated the changelog
> accordingly.
> 
> 8<-----------
> Subject: usb: resume (wakeup) child device when port is powered on
> 
> From: Dan Williams <dan.j.williams@xxxxxxxxx>
> 
> Unconditionally wake up the child device when the power session is
> recovered.
> 
> This addresses the following scenarios:
> 
> 1/ The device may need a reset on power-session loss, without this
>    change port power-on recovery exposes khubd to scenarios that
>    usb_port_resume() is set to handle.  Prior to port power control the
>    only time a power session would be lost is during dpm_suspend of the
>    hub.  In that scenario usb_port_resume() is guaranteed to be called
>    prior to khubd running for that port.  With this change we wakeup the
>    child device as soon as possible (prior to khubd running again for this
>    port).
> 
>    Although khubd has facilities to wake a child device it will only do
>    so if the portstatus / portchange indicates a suspend state.  In the
>    case of port power control we are not coming from a hub-port-suspend
>    state.  This implementation extends usb_wake_notification() for the
>    port rpm_resume case.

Actually it doesn't any more (extend usb_wake_notification(), that is).

> @@ -2057,9 +2057,11 @@ static void hub_free_dev(struct usb_device *udev)
>   */
>  void usb_disconnect(struct usb_device **pdev)
>  {
> -	struct usb_device	*udev = *pdev;
> -	struct usb_hub		*hub = usb_hub_to_struct_hub(udev);
> -	int			i;
> +	int i;
> +	struct usb_device *udev = *pdev;
> +	int port1 = udev->portnum;
> +	struct usb_port *port_dev = NULL;
> +	struct usb_hub *hub = usb_hub_to_struct_hub(udev);
>  
>  	/* mark the device as inactive, so any further urb submissions for
>  	 * this device (and any of its children) will fail immediately.
> @@ -2086,15 +2088,18 @@ void usb_disconnect(struct usb_device **pdev)
>  	usb_hcd_synchronize_unlinks(udev);
>  
>  	if (udev->parent) {
> -		int port1 = udev->portnum;
>  		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
> -		struct usb_port	*port_dev = hub->ports[port1 - 1];
>  
> +		port_dev = hub->ports[port1 - 1];
>  		sysfs_remove_link(&udev->dev.kobj, "port");
>  		sysfs_remove_link(&port_dev->dev.kobj, "device");
>  
> -		if (test_and_clear_bit(port1, hub->child_usage_bits))
> -			pm_runtime_put(&port_dev->dev);
> +		/*
> +		 * As usb_port_runtime_resume() de-references udev, make
> +		 * sure no resumes occur during removal
> +		 */
> +		if (!test_and_set_bit(port1, hub->child_usage_bits))
> +			pm_runtime_get_sync(&port_dev->dev);
>  	}
>  
>  	usb_remove_ep_devs(&udev->ep0);
> @@ -2116,6 +2121,9 @@ void usb_disconnect(struct usb_device **pdev)
>  	*pdev = NULL;
>  	spin_unlock_irq(&device_state_lock);
>  
> +	if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits))
> +		pm_runtime_put(&port_dev->dev);
> +

There's a nasty bug here.  I'll let you figure it out for yourself.  :-)
Hint: Hiding a variable by declaring another local variable with the 
same name in an inner block often leads to trouble.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux