On Wed, 5 Nov 2014, Sebastian Andrzej Siewior wrote: > On 11/04/2014 08:10 PM, Alan Stern wrote: > > Now, maybe something went wrong somewhere. Perhaps the kernel thought > > that after the system resume, the root hub was still in runtime > > suspend. If that's true, we need to find out why and fix it. > > This is what I have so far (I have no idea what is correct / wrong I > just document what I figured out): > - good case no wakeup active. > - usb_suspend() => choose_wakeup() > "if (udev->state == USB_STATE_SUSPENDED && w != > udev->do_remote_wakeup)" > w is 0 and do_remote_wakeup is 1. This means pm_runtime_resume() is > invoked. > - device status goes RPM_SUSPENDED => RPM_RESUMING => RPM_ACTIVE > - after we are in usb_suspend_both() and udev->state is 7 > (USB_STATE_CONFIGURED), hub_suspend() is beeing invoked. > The status urb is dequeued, RPM of usb1 is still RPM_ACTIVE > > - in the bad case (wakeup active) > - usb_suspend => choose_wakeup() > - in the check above we do nothing because w and …do_remote_wakeup > is 1 > - usb_suspend_both() does nothing because udev->state is 8 > (USB_STATE_SUSPENDED) so we leave. RPM of both devices (hub and > usb1 is RPM_SUSPENDED) All of that is good; that's the way it is supposed to work. > > --- now get back out of suspend --- > - usb_resume() is invoked with different RPM status. > - hub_activate() is invoked. The status URB is enqueued again, RPM > remains unchanged. > - aaaaand we are done Ah. In usb_resume(), what happened after usb_resume_both() returned? The code says this: status = usb_resume_both(udev, msg); if (status == 0) { pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); unbind_marked_interfaces(udev); } So if usb_resume_both() returns 0, the runtime PM status is supposed to get changed to RPM_ACTIVE by the pm_runtime_set_active() call. > - we get a HUB event, khubd is kicked. > - the hub invokes usb_autopm_get_interface() on the interface which is > suspended. The hub device is suspended and has > dev->power.no_callbacks set. Now: > - in the "good" case it sees that the parent (usb1) is still > RPM_ACTIVE so it sets the status of the status of hub to RPM_ACTIVE > and leaves without doing anything. > - in the bad case the ave RPM still set to RPM_SUSPENDED so we call > resume for usb1 again which leads to the second status URB enqueue The status should be RPM_ACTIVE in both cases. > So that is the history. I *think* that we shouldn't to hub_suspend() + > hub_resume() without changing the RPM status (the choose_wakeup() > difference). This might also fix the RPM status for usb1 which is in > RPM_SUSPENDED while it should be active (shouldn't it?) since it has > remote_wakeup active. Can you figure out why the status didn't get changed to RPM_ACTIVE? 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