File Index
Files and directories
Sign in
FILE

offload.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/core/offload.c 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 */
 26int usb_offload_get(struct usb_device *udev)
 27{
 28	int ret = 0;
 29
 30	if (!usb_get_dev(udev))
 31		return -ENODEV;
 32
 33	if (pm_runtime_get_if_active(&udev->dev) != 1) {
 34		ret = -EBUSY;
 35		goto err_rpm;
 36	}
 37
 38	spin_lock(&udev->offload_lock);
 39
 40	if (udev->offload_pm_locked) {
 41		ret = -EAGAIN;
 42		goto err;
 43	}
 44
 45	udev->offload_usage++;
 46
 47err:
 48	spin_unlock(&udev->offload_lock);
 49	pm_runtime_put_autosuspend(&udev->dev);
 50err_rpm:
 51	usb_put_dev(udev);
 52
 53	return ret;
 54}
 55EXPORT_SYMBOL_GPL(usb_offload_get);
 56
 57/**
 58 * usb_offload_put - drop the offload_usage of a USB device
 59 * @udev: the USB device to drop its offload_usage
 60 *
 61 * The inverse operation of usb_offload_get, which drops the offload_usage of
 62 * a USB device. This information allows the USB driver to adjust its power
 63 * management policy based on offload activity.
 64 *
 65 * Return: 0 on success. A negative error code otherwise.
 66 */
 67int usb_offload_put(struct usb_device *udev)
 68{
 69	int ret = 0;
 70
 71	if (!usb_get_dev(udev))
 72		return -ENODEV;
 73
 74	if (pm_runtime_get_if_active(&udev->dev) != 1) {
 75		ret = -EBUSY;
 76		goto err_rpm;
 77	}
 78
 79	spin_lock(&udev->offload_lock);
 80
 81	if (udev->offload_pm_locked) {
 82		ret = -EAGAIN;
 83		goto err;
 84	}
 85
 86	/* Drop the count when it wasn't 0, ignore the operation otherwise. */
 87	if (udev->offload_usage)
 88		udev->offload_usage--;
 89
 90err:
 91	spin_unlock(&udev->offload_lock);
 92	pm_runtime_put_autosuspend(&udev->dev);
 93err_rpm:
 94	usb_put_dev(udev);
 95
 96	return ret;
 97}
 98EXPORT_SYMBOL_GPL(usb_offload_put);
 99
100/**
101 * usb_offload_check - check offload activities on a USB device
102 * @udev: the USB device to check its offload activity.
103 *
104 * Check if there are any offload activity on the USB device right now. This
105 * information could be used for power management or other forms of resource
106 * management.
107 *
108 * The caller must hold @udev's device lock. In addition, the caller should
109 * ensure the device itself and the downstream usb devices are all marked as
110 * "offload_pm_locked" to ensure the correctness of the return value.
111 *
112 * Returns true on any offload activity, false otherwise.
113 */
114bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex)
115{
116	struct usb_device *child;
117	bool active = false;
118	int port1;
119
120	if (udev->offload_usage)
121		return true;
122
123	usb_hub_for_each_child(udev, port1, child) {
124		usb_lock_device(child);
125		active = usb_offload_check(child);
126		usb_unlock_device(child);
127
128		if (active)
129			break;
130	}
131
132	return active;
133}
134EXPORT_SYMBOL_GPL(usb_offload_check);
135
136/**
137 * usb_offload_set_pm_locked - set the PM lock state of a USB device
138 * @udev: the USB device to modify
139 * @locked: the new lock state
140 *
141 * Setting @locked to true prevents offload_usage from being modified. This
142 * ensures that offload activities cannot be started or stopped during critical
143 * power management transitions, maintaining a stable state for the duration
144 * of the transition.
145 */
146void usb_offload_set_pm_locked(struct usb_device *udev, bool locked)
147{
148	spin_lock(&udev->offload_lock);
149	udev->offload_pm_locked = locked;
150	spin_unlock(&udev->offload_lock);
151}
152EXPORT_SYMBOL_GPL(usb_offload_set_pm_locked);
~/ Read-only file preview.