Skip to content

Commit

Permalink
usb: make usb_port flags atomic, rename did_runtime_put to child_usage
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Alan Stern <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
djbw authored and gregkh committed May 27, 2014
1 parent b7e38ea commit d5c3834
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 25 deletions.
39 changes: 20 additions & 19 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2416,7 +2417,8 @@ int usb_new_device(struct usb_device *udev)
/* Create link files between child device and usb port device. */
if (udev->parent) {
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
struct usb_port *port_dev = hub->ports[udev->portnum - 1];
int port1 = udev->portnum;
struct usb_port *port_dev = hub->ports[port1 - 1];

err = sysfs_create_link(&udev->dev.kobj,
&port_dev->dev.kobj, "port");
Expand All @@ -2430,7 +2432,8 @@ int usb_new_device(struct usb_device *udev)
goto fail;
}

pm_runtime_get_sync(&port_dev->dev);
if (!test_and_set_bit(port1, hub->child_usage_bits))
pm_runtime_get_sync(&port_dev->dev);
}

(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
Expand Down Expand Up @@ -3100,10 +3103,9 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
usb_set_device_state(udev, USB_STATE_SUSPENDED);
}

if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled
&& test_and_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);
return status;
Expand Down Expand Up @@ -3245,9 +3247,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);
Expand Down
7 changes: 3 additions & 4 deletions drivers/usb/core/hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ 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]; /* ports powered on for
children */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
Expand Down Expand Up @@ -86,8 +89,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;
Expand All @@ -97,8 +98,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) \
Expand Down
4 changes: 2 additions & 2 deletions drivers/usb/core/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit d5c3834

Please sign in to comment.