Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5c3834e authored by Dan Williams's avatar Dan Williams Committed by Greg Kroah-Hartman
Browse files

usb: make usb_port flags atomic, rename did_runtime_put to child_usage



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: default avatarDan Williams <dan.j.williams@intel.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b7e38eac
Loading
Loading
Loading
Loading
+20 −19
Original line number Diff line number Diff line
@@ -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;
	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);
@@ -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");
@@ -2430,6 +2432,7 @@ int usb_new_device(struct usb_device *udev)
			goto fail;
		}

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

@@ -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;
@@ -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);
+3 −4
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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) \
+2 −2
Original line number Diff line number Diff line
@@ -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;