Introduce sb_usage_count and corresponding apis to track sideband usage
on each usb_device. A sideband refers to the co-processor that accesses
the usb_device via shared control on the same USB host controller. To
optimize power usage, it's essential to monitor whether ther sideband is
actively using the usb_device. This information is vital when
determining if a usb_device can be safely suspended during system power
state transitions.
Signed-off-by: Guan-Yu Lin <guanyulin@xxxxxxxxxx>
---
drivers/usb/core/driver.c | 54 +++++++++++++++++++++++++++++++++++++++
include/linux/usb.h | 13 ++++++++++
2 files changed, 67 insertions(+)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 0c3f12daac79..c1ba5ed15214 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1673,6 +1673,60 @@ void usb_disable_autosuspend(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
+/**
+ * usb_sideband_get - notify usb driver there's a new active sideband
+ * @udev: the usb_device which has an active sideband
+ *
+ * An active sideband indicates that another entity is currently using the usb
+ * device. Notify the usb device by increasing the sb_usage_count. This allows
+ * usb driver to adjust power management policy based on sideband activities.
+ */
+void usb_sideband_get(struct usb_device *udev)
+{
+ struct usb_device *parent = udev;
+
+ do {
+ atomic_inc(&parent->sb_usage_count);
+ parent = parent->parent;
+ } while (parent);
+}
+EXPORT_SYMBOL_GPL(usb_sideband_get);
+
+/**
+ * usb_sideband_put - notify usb driver there's a sideband deactivated
+ * @udev: the usb_device which has a sideband deactivated
+ *
+ * The inverse operation of usb_sideband_get, which notifies the usb device by
+ * decreasing the sb_usage_count. This allows usb driver to adjust power
+ * management policy based on sideband activities.
+ */
+void usb_sideband_put(struct usb_device *udev)
+{
+ struct usb_device *parent = udev;
+
+ do {
+ atomic_dec(&parent->sb_usage_count);
+ parent = parent->parent;
+ } while (parent);
+}
+EXPORT_SYMBOL_GPL(usb_sideband_put);
+