Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: offload: add apis for offload usage tracking

Introduce offload_usage and corresponding apis to track offload usage
on each USB device. Offload denotes that there is another co-processor
accessing the USB device via the same USB host controller. To optimize
power usage, it's essential to monitor whether the USB device is
actively used by other co-processor. 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@google.com>
Link: https://lore.kernel.org/r/20250911142051.90822-3-guanyulin@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://lore.kernel.org/r/20250911142051.90822-3-guanyulin@google.com

authored by

Guan-Yu Lin and committed by
Greg Kroah-Hartman
7f70b89b ddb473a5

+156
+1
drivers/usb/core/Makefile
··· 9 9 usbcore-y += phy.o port.o 10 10 11 11 usbcore-$(CONFIG_OF) += of.o 12 + usbcore-$(CONFIG_USB_XHCI_SIDEBAND) += offload.o 12 13 usbcore-$(CONFIG_USB_PCI) += hcd-pci.o 13 14 usbcore-$(CONFIG_ACPI) += usb-acpi.o 14 15
+136
drivers/usb/core/offload.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * offload.c - USB offload related functions 5 + * 6 + * Copyright (c) 2025, Google LLC. 7 + * 8 + * Author: Guan-Yu Lin 9 + */ 10 + 11 + #include <linux/usb.h> 12 + 13 + #include "usb.h" 14 + 15 + /** 16 + * usb_offload_get - increment the offload_usage of a USB device 17 + * @udev: the USB device to increment its offload_usage 18 + * 19 + * Incrementing the offload_usage of a usb_device indicates that offload is 20 + * enabled on this usb_device; that is, another entity is actively handling USB 21 + * transfers. This information allows the USB driver to adjust its power 22 + * management policy based on offload activity. 23 + * 24 + * Return: 0 on success. A negative error code otherwise. 25 + */ 26 + int usb_offload_get(struct usb_device *udev) 27 + { 28 + int ret; 29 + 30 + usb_lock_device(udev); 31 + if (udev->state == USB_STATE_NOTATTACHED) { 32 + usb_unlock_device(udev); 33 + return -ENODEV; 34 + } 35 + 36 + if (udev->state == USB_STATE_SUSPENDED || 37 + udev->offload_at_suspend) { 38 + usb_unlock_device(udev); 39 + return -EBUSY; 40 + } 41 + 42 + /* 43 + * offload_usage could only be modified when the device is active, since 44 + * it will alter the suspend flow of the device. 45 + */ 46 + ret = usb_autoresume_device(udev); 47 + if (ret < 0) { 48 + usb_unlock_device(udev); 49 + return ret; 50 + } 51 + 52 + udev->offload_usage++; 53 + usb_autosuspend_device(udev); 54 + usb_unlock_device(udev); 55 + 56 + return ret; 57 + } 58 + EXPORT_SYMBOL_GPL(usb_offload_get); 59 + 60 + /** 61 + * usb_offload_put - drop the offload_usage of a USB device 62 + * @udev: the USB device to drop its offload_usage 63 + * 64 + * The inverse operation of usb_offload_get, which drops the offload_usage of 65 + * a USB device. This information allows the USB driver to adjust its power 66 + * management policy based on offload activity. 67 + * 68 + * Return: 0 on success. A negative error code otherwise. 69 + */ 70 + int usb_offload_put(struct usb_device *udev) 71 + { 72 + int ret; 73 + 74 + usb_lock_device(udev); 75 + if (udev->state == USB_STATE_NOTATTACHED) { 76 + usb_unlock_device(udev); 77 + return -ENODEV; 78 + } 79 + 80 + if (udev->state == USB_STATE_SUSPENDED || 81 + udev->offload_at_suspend) { 82 + usb_unlock_device(udev); 83 + return -EBUSY; 84 + } 85 + 86 + /* 87 + * offload_usage could only be modified when the device is active, since 88 + * it will alter the suspend flow of the device. 89 + */ 90 + ret = usb_autoresume_device(udev); 91 + if (ret < 0) { 92 + usb_unlock_device(udev); 93 + return ret; 94 + } 95 + 96 + /* Drop the count when it wasn't 0, ignore the operation otherwise. */ 97 + if (udev->offload_usage) 98 + udev->offload_usage--; 99 + usb_autosuspend_device(udev); 100 + usb_unlock_device(udev); 101 + 102 + return ret; 103 + } 104 + EXPORT_SYMBOL_GPL(usb_offload_put); 105 + 106 + /** 107 + * usb_offload_check - check offload activities on a USB device 108 + * @udev: the USB device to check its offload activity. 109 + * 110 + * Check if there are any offload activity on the USB device right now. This 111 + * information could be used for power management or other forms of resource 112 + * management. 113 + * 114 + * The caller must hold @udev's device lock. In addition, the caller should 115 + * ensure downstream usb devices are all either suspended or marked as 116 + * "offload_at_suspend" to ensure the correctness of the return value. 117 + * 118 + * Returns true on any offload activity, false otherwise. 119 + */ 120 + bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex) 121 + { 122 + struct usb_device *child; 123 + bool active; 124 + int port1; 125 + 126 + usb_hub_for_each_child(udev, port1, child) { 127 + usb_lock_device(child); 128 + active = usb_offload_check(child); 129 + usb_unlock_device(child); 130 + if (active) 131 + return true; 132 + } 133 + 134 + return !!udev->offload_usage; 135 + } 136 + EXPORT_SYMBOL_GPL(usb_offload_check);
+1
drivers/usb/core/usb.c
··· 670 670 set_dev_node(&dev->dev, dev_to_node(bus->sysdev)); 671 671 dev->state = USB_STATE_ATTACHED; 672 672 dev->lpm_disable_count = 1; 673 + dev->offload_usage = 0; 673 674 atomic_set(&dev->urbnum, 0); 674 675 675 676 INIT_LIST_HEAD(&dev->ep0.urb_list);
+18
include/linux/usb.h
··· 636 636 * @do_remote_wakeup: remote wakeup should be enabled 637 637 * @reset_resume: needs reset instead of resume 638 638 * @port_is_suspended: the upstream port is suspended (L2 or U3) 639 + * @offload_at_suspend: offload activities during suspend is enabled. 640 + * @offload_usage: number of offload activities happening on this usb device. 639 641 * @slot_id: Slot ID assigned by xHCI 640 642 * @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout. 641 643 * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout. ··· 726 724 unsigned do_remote_wakeup:1; 727 725 unsigned reset_resume:1; 728 726 unsigned port_is_suspended:1; 727 + unsigned offload_at_suspend:1; 728 + int offload_usage; 729 729 enum usb_link_tunnel_mode tunnel_mode; 730 730 struct device_link *usb4_link; 731 731 ··· 843 839 { } 844 840 static inline void usb_mark_last_busy(struct usb_device *udev) 845 841 { } 842 + #endif 843 + 844 + #if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) 845 + int usb_offload_get(struct usb_device *udev); 846 + int usb_offload_put(struct usb_device *udev); 847 + bool usb_offload_check(struct usb_device *udev); 848 + #else 849 + 850 + static inline int usb_offload_get(struct usb_device *udev) 851 + { return 0; } 852 + static inline int usb_offload_put(struct usb_device *udev) 853 + { return 0; } 854 + static inline bool usb_offload_check(struct usb_device *udev) 855 + { return false; } 846 856 #endif 847 857 848 858 extern int usb_disable_lpm(struct usb_device *udev);