[PATCH v8 08/18] usb: make usb_port flags atomic

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Before we add another 2 bitfields to the port state, convert it to an
unsigned long and use bitops helpers to manipulate it.  This later
enables setting bits to request action without worrying about colliding
updates.  In particular, a flag to request that the child device be
woken up when the port restores power is added in a later patch.

Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
---
 drivers/usb/core/hub.c  |   26 +++++++++++++++-----------
 drivers/usb/core/hub.h  |    8 ++++----
 drivers/usb/core/port.c |    2 +-
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 783acfca6c51..5ab8ce870f5b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -758,9 +758,14 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,
 	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(USB_PORTDEV_POWER, &port_dev->flags);
+	else
+		clear_bit(USB_PORTDEV_POWER, &port_dev->flags);
+	return 0;
 }
 
 /**
@@ -839,7 +844,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(USB_PORTDEV_POWER, &hub->ports[port1 - 1]->flags))
 			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
 		else
 			usb_clear_port_feature(hub->hdev, port1,
@@ -1188,7 +1193,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 			/* Don't set the change_bits when the device
 			 * was powered off.
 			 */
-			if (port_dev->power_is_on)
+			if (test_bit(USB_PORTDEV_POWER, &port_dev->flags))
 				set_bit(port1, hub->change_bits);
 
 		} else {
@@ -2090,10 +2095,10 @@ void usb_disconnect(struct usb_device **pdev)
 		sysfs_remove_link(&udev->dev.kobj, "port");
 		sysfs_remove_link(&port_dev->dev.kobj, "device");
 
-		if (!port_dev->did_runtime_put)
+		/* if we didn't do it at "runtime" we need to do it now */
+		if (!test_and_clear_bit(USB_PORTDEV_DID_RUNTIME_PUT,
+					&port_dev->flags))
 			pm_runtime_put(&port_dev->dev);
-		else
-			port_dev->did_runtime_put = false;
 	}
 
 	usb_remove_ep_devs(&udev->ep0);
@@ -3090,7 +3095,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 
 	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) {
 		pm_runtime_put_sync(&port_dev->dev);
-		port_dev->did_runtime_put = true;
+		set_bit(USB_PORTDEV_DID_RUNTIME_PUT, &port_dev->flags);
 	}
 
 	usb_mark_last_busy(hub->hdev);
@@ -3233,9 +3238,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_clear_bit(USB_PORTDEV_DID_RUNTIME_PUT, &port_dev->flags)) {
 		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);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 0d8c5b0cdf09..fabf05ea3de6 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -85,8 +85,7 @@ 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().
+ * @flags: operational state, and requests
  */
 struct usb_port {
 	struct usb_device *child;
@@ -96,8 +95,9 @@ 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 USB_PORTDEV_POWER 0
+	#define USB_PORTDEV_DID_RUNTIME_PUT 1
+	unsigned long flags;
 };
 
 #define to_usb_port(_dev) \
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index b7f5225cee2b..99de5acb1240 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -314,7 +314,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(USB_PORTDEV_POWER, &port_dev->flags);
 	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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux