[PATCH v9 09/19] usb: make usb_port flags atomic, rename did_runtime_put to child_usage

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

 



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




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

  Powered by Linux