On Wed, Oct 09, 2024 at 05:42:57AM +0000, Guan-Yu Lin wrote: > 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); As this is a reference count, use refcount_t please. > + parent = parent->parent; > + } while (parent); Woah, walking up the device chain? That should not be needed, or if so, then each device's "usage count" is pointless. > +} > +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); > + > +/** > + * usb_sideband_check - check sideband activities on the host controller > + * @udev: the usb_device which has a sideband deactivated > + * > + * Check if there are any sideband activity on the USB device right now. This > + * information could be used for power management or other forms or resource > + * management. > + * > + * Returns true on any active sideband existence, false otherwise > + */ > +bool usb_sideband_check(struct usb_device *udev) > +{ > + return !!atomic_read(&udev->sb_usage_count); And what happens if it changes right after you make this call? This feels racy and broken. > +} > +EXPORT_SYMBOL_GPL(usb_sideband_check); > + > /** > * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces > * @udev: the usb_device to autosuspend > diff --git a/include/linux/usb.h b/include/linux/usb.h > index 672d8fc2abdb..5b9fea378960 100644 > --- a/include/linux/usb.h > +++ b/include/linux/usb.h > @@ -645,6 +645,7 @@ struct usb3_lpm_parameters { > * parent->hub_delay + wHubDelay + tTPTransmissionDelay (40ns) > * Will be used as wValue for SetIsochDelay requests. > * @use_generic_driver: ask driver core to reprobe using the generic driver. > + * @sb_usage_count: number of active sideband accessing this usb device. > * > * Notes: > * Usbcore drivers should not set usbdev->state directly. Instead use > @@ -731,6 +732,8 @@ struct usb_device { > > u16 hub_delay; > unsigned use_generic_driver:1; > + > + atomic_t sb_usage_count; Why is this on the device and not the interface that is bound to the driver that is doing this work? thanks, greg k-h