On Tue, 11 Dec 2012, Lan Tianyu wrote: > >> @@ -108,11 +109,14 @@ MODULE_PARM_DESC(use_both_schemes, > >> DECLARE_RWSEM(ehci_cf_port_reset_rwsem); > >> EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); > >> > >> +#define HUB_PORT_RECONNECT_TRIES 20 > > > > 20 is an awful lot. Do you really need any more than one try? The > > debounce routine already does its own looping. > I tested a usb ssd which consumes about 1s to makes usb port status > enter into connect status after powering off and powering on the port. > So I set the tries 20 and the longest latency is larger than 2s. > The debounce routine only guarantees port status stable rather than > enter into connect status. Then a better solution would be to first wait (up to 2 seconds) for a connect status and then call the debounce routine. > >> @@ -718,13 +722,26 @@ int usb_hub_set_port_power(struct usb_device > >> *hdev, int port1, > >> bool set) > >> { > >> int ret; > >> + struct usb_hub *hub = hdev_to_hub(hdev); > >> + struct usb_port *port_dev > >> + = hub->ports[port1 - 1]; > >> + > >> + if (set) { > >> + if (port_dev->power_is_on) > >> + return 0; > >> > >> - if (set) > >> ret = set_port_feature(hdev, port1, > >> USB_PORT_FEAT_POWER); > >> - else > >> + } else { > >> + if (!port_dev->power_is_on) > >> + return 0; > >> + > >> ret = clear_port_feature(hdev, port1, > >> USB_PORT_FEAT_POWER); > >> + } > > > > Do we need these shortcuts? How often will this routine be called when > > the port is already in the right state > When the PM Qos NO_POWER_OFF is changed, > pm_runtime_get_sync/put(port_dev) will be invoked. This routine will be > called during port resume and suspend. If one device was suspended and > power off, the port's usage_count would be 0. After then, the port will > be resumed and suspend every time pm qos NO_POWER_OFF flag being > changed. So this depends on the user space. You did not understand my question. When usb_hub_set_port_power is called, won't the Set-Feature request almost always be necessary? For example, how often will it happen that set and port_dev->power_is_on are both true? Or both false? It seems to me that this will almost never happen. So why bother testing for it? > >> @@ -2862,6 +2884,18 @@ int usb_port_suspend(struct usb_device *udev, > >> pm_message_t msg) > >> udev->port_is_suspended = 1; > >> msleep(10); > >> } > >> + > >> + /* > >> + * Check whether current status is meeting requirement of > >> + * usb port power off mechanism > >> + */ > >> + if (!udev->do_remote_wakeup > >> + && (dev_pm_qos_flags(&port_dev->dev, > >> + PM_QOS_FLAG_NO_POWER_OFF) != PM_QOS_FLAGS_ALL) > >> + && udev->persist_enabled > >> + && !status) > >> + pm_runtime_put_sync(&port_dev->dev); > > > > You need to store somewhere the fact that you made this call, so that > > you will know whether or not to make the corresponding > > pm_runtime_get_sync call in usb_port_resume. > You mean I should add a new flag to keep the > pm_runtime_put_sync/put(port_dev) being called paired, right? > How about "needs_resume"? What you need isn't a resume; it's pm_runtime_get_sync. > >> @@ -2982,10 +3035,39 @@ static int finish_port_resume(struct usb_device > >> *udev) > >> int usb_port_resume(struct usb_device *udev, pm_message_t msg) > >> { > >> struct usb_hub *hub = hdev_to_hub(udev->parent); > >> + struct usb_port *port_dev = hub->ports[udev->portnum - 1]; > >> int port1 = udev->portnum; > >> int status; > >> u16 portchange, portstatus; > >> > >> + > >> + set_bit(port1, hub->busy_bits); > >> + > >> + if (!port_dev->power_is_on) { > > > > This test is wrong. It's possible that the port power is still on even > > though you called pm_runtime_put_sync. > Above, we need to check the new flag, right? Yes. > >> + status = pm_runtime_get_sync(&port_dev->dev); > >> + if (status < 0) { > >> + dev_dbg(&udev->dev, "can't resume usb port, status %d\n", > >> + status); > >> + clear_bit(port1, hub->busy_bits); > >> + return status; > >> + } > > > > Don't you want to call usb_port_wait_for_connected right here? > > > >> + } > >> + > >> + > >> + /* > >> + * Wait for usb hub port to be reconnected in order to make > >> + * the resume procedure successful. > >> + */ > >> + if (port_dev->needs_debounce) { > >> + status = usb_port_wait_for_connected(hub, port1); > > > > If you move this call earlier then you won't have to test > > needs_debounce. > The port may have been power on when device is resumed. One case, after > device being suspended and power off, user may set the NO_POWER_OFF flag > and port will be power on before device being resumed. For this case, > port doesn't need to be resumed in the usb_port_resume() since port > already power on and "wait for connected" is enough. So I divide resume > port and wait for connected into two pieces. You are confusing pm_runtime_get_sync with resume. They are not the same thing. You always need to call pm_runtime_get_sync here if pm_runtime_put_sync was called earlier, even if the port is already powered on. > But from your rely, I > realize we should paired call pm_runtime_get_sync/put(port_dev). Now I > think this should be put earlier. > Something like this > > if(port_dev->needs_resume) { > status = pm_runtime_get_sync(&port_dev->dev); > if (status < 0) { > dev_dbg(&udev->dev, "can't resume usb port, status %d\n", status); > clear_bit(port1, hub->busy_bits); > return status; > } > > status = usb_port_wait_for_connected(hub, port1); > if (status < 0) { > dev_dbg(&udev->dev, "can't get reconnection after setting port power > on, status %d\n", status); > clear_bit(port1, hub->busy_bits); > return status; > } > > } Actually, it looks like you will want to call wait_for_connected in the port's runtime-resume routine. After all, if the user changes the PM QOS flag while the port is powered off, you will need to start paying attention to the connect status. > >> @@ -4175,6 +4256,11 @@ static void hub_port_connect_change(struct > >> usb_hub *hub, int port1, > >> } > >> } > >> > >> + if (!port_dev->power_is_on || port_dev->needs_debounce) { > >> + clear_bit(port1, hub->change_bits); > >> + return; > >> + } > > > > Doesn't the busy_bits flag take care of this for you already? > When port is power off or power on during PM Qos NO_POWER_OFF flag > changing , there is also an connect change event and busy_bits is not > set at that time. This means you should set busy_bits in the port's runtime-resume routine and keep it set until wait_for_connected is finished. > > Also, what if the port is ganged, so even though you think you turned > > off the power, it really is still on? When that happens you probably > > don't want to ignore port events. > Even the power is still on but the PORT_POWER feature has been cleared. > So there should be no event from port, right? "should be" -- but buggy hardware might send an event anyway. Also, many root hubs don't pay attention to the power feature. If this happens, you probably should handle the connect change properly. I don't see any point in ignoring it. One other thing to watch out for: If the device is unplugged while it is suspended, you may need to call pm_runtime_get_sync from somewhere in the device-removal path. 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