We want to manipulate ->did_runtime_put in usb_port_runtime_resume(), but we don't want that to collide with other updates. Move usb_port flags to new port-bitmap fields in usb_hub. "did_runtime_put" is renamed "child_usage_bits" to reflect that it is strictly standing in for the fact that usb_devices are not the device_model children of their parent port. Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx> --- drivers/usb/core/hub.c | 34 ++++++++++++++++++---------------- drivers/usb/core/hub.h | 8 ++++---- drivers/usb/core/port.c | 4 ++-- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7050560e0f9b..bd39c7d44564 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -751,16 +751,20 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub, int port1, bool set) { int ret; - struct usb_port *port_dev = hub->ports[port1 - 1]; if (set) ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); else ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); - if (!ret) - port_dev->power_is_on = set; - return ret; + if (ret) + return ret; + + if (set) + set_bit(port1, hub->power_bits); + else + clear_bit(port1, hub->power_bits); + return 0; } /** @@ -839,7 +843,7 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); for (port1 = 1; port1 <= hub->hdev->maxchild; port1++) - if (hub->ports[port1 - 1]->power_is_on) + if (test_bit(port1, hub->power_bits)) set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); else usb_clear_port_feature(hub->hdev, port1, @@ -1180,15 +1184,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) set_bit(port1, hub->change_bits); } else if (udev->persist_enabled) { - struct usb_port *port_dev = hub->ports[port1 - 1]; - #ifdef CONFIG_PM udev->reset_resume = 1; #endif /* Don't set the change_bits when the device * was powered off. */ - if (port_dev->power_is_on) + if (test_bit(port1, hub->power_bits)) set_bit(port1, hub->change_bits); } else { @@ -2096,16 +2098,15 @@ 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[udev->portnum - 1]; + struct usb_port *port_dev = hub->ports[port1 - 1]; sysfs_remove_link(&udev->dev.kobj, "port"); sysfs_remove_link(&port_dev->dev.kobj, "device"); - if (!port_dev->did_runtime_put) + if (test_and_clear_bit(port1, hub->child_usage_bits)) pm_runtime_put(&port_dev->dev); - else - port_dev->did_runtime_put = false; } usb_remove_ep_devs(&udev->ep0); @@ -3101,8 +3102,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { + clear_bit(port1, hub->child_usage_bits); pm_runtime_put_sync(&port_dev->dev); - port_dev->did_runtime_put = true; } usb_mark_last_busy(hub->hdev); @@ -3245,9 +3246,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; - if (port_dev->did_runtime_put) { + if (!test_and_set_bit(port1, hub->child_usage_bits)) { status = pm_runtime_get_sync(&port_dev->dev); - port_dev->did_runtime_put = false; if (status < 0) { dev_dbg(&udev->dev, "can't resume usb port, status %d\n", status); @@ -4628,8 +4628,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, spin_lock_irq(&device_state_lock); if (hdev->state == USB_STATE_NOTATTACHED) status = -ENOTCONN; - else + else { port_dev->child = udev; + set_bit(port1, hub->child_usage_bits); + } spin_unlock_irq(&device_state_lock); mutex_unlock(&usb_port_peer_mutex); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 048c797f394c..b3432deb8355 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -51,6 +51,10 @@ struct usb_hub { device present */ unsigned long wakeup_bits[1]; /* ports that have signaled remote wakeup */ + unsigned long power_bits[1]; /* ports that are powered */ + unsigned long child_usage_bits[1]; /* child pm_runtime + active */ + #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif @@ -86,8 +90,6 @@ struct usb_hub { * @connect_type: port's connect type * @location: opaque representation of platform connector location * @portnum: port index num based one - * @power_is_on: port's power state - * @did_runtime_put: port has done pm_runtime_put(). */ struct usb_port { struct usb_device *child; @@ -97,8 +99,6 @@ struct usb_port { enum usb_port_connect_type connect_type; usb_port_location_t location; u8 portnum; - unsigned power_is_on:1; - unsigned did_runtime_put:1; }; #define to_usb_port(_dev) \ diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 40c3ac173e9e..795778c71e31 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -82,7 +82,7 @@ static int usb_port_runtime_resume(struct device *dev) if (!hub) return -EINVAL; if (hub->in_reset) { - port_dev->power_is_on = 1; + set_bit(port1, hub->power_bits); return 0; } @@ -320,7 +320,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) hub->ports[port1 - 1] = port_dev; port_dev->portnum = port1; - port_dev->power_is_on = true; + set_bit(port1, hub->power_bits); port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; -- 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