usb: add function usb_autopm_get_interface_upgrade
PATCH v3 1/3 usb: add function usb_autopm_get_interface_upgrade
From: Zhang Yanmin <[email protected]>
Some usb driver has a specific requirement. Their critical functions might be called under both atomic environment and non-atomic environment.
If it's under atomic environment, the driver can wake up the device by calling pm_runtime_get_sync directly.
If it's under non-atomic environment, the function's caller need wake up the device before the function accesses the device.
The patch adds usb_autopm_get_interface_upgrade, a new function to support above capability.
Signed-off-by Zhang Yanmin <[email protected]>
--- drivers/usb/core/driver.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 3 +++ 2 files changed, 57 insertions(+)
drivers/usb/core/driver.c +54 -0
@@ -1684,6 +1684,60 @@ int usb_autopm_get_interface(struct usb_interface *intf)EXPORT_SYMBOL_GPL (usb_autopm_get_interface);/** +* usb_autopm_get_interface_upgrade - increment a USB interface's PM-usage +* counter +* @intf: the usb_interface whose counter should be incremented +* +* This routine should be called by an interface driver when it wants to +* use @intf and needs to guarantee that it is not suspended. In addition, +* the routine prevents @intf from being autosuspended subsequently. (Note +* that this will not prevent suspend events originating in the PM core.) +* This prevention will persist until usb_autopm_put_interface() is called +* or @intf is unbound. A typical example would be a character-device +* driver when its device file is opened. +* +* Comparing with usb_autopm_get_interface, usb_autopm_get_interface_upgrade +* is more careful when resuming the device. +* 1) The caller's caller already resumes resume the device and hold spinlocks. +* usb_autopm_get_interface_upgrade couldn't call pm_runtime_get_sync; +* 2) The caller's caller doesn't resume the device. +* usb_autopm_get_interface_upgrade has to resume the device before going ahead. +* +* @intf's usage counter is incremented to prevent subsequent autosuspends. +* However if the autoresume fails then the counter is re-decremented. +* +* This routine can run only in process context. +* +* Return: 0 on success. +*/ +int usb_autopm_get_interface_upgrade (struct usb_interface *intf) +{ +int status =0 ; + +pm_runtime_get (&intf->dev); +if (!pm_runtime_active (&intf->dev)) { +/* If not active, next _get_sync wakes device up*/ + status =pm_runtime_get_sync (&intf->dev); +/* +* If it's active, next _put_sync wouldn't +* really put it to sleep as the 1st _get +* keeps the device active. +*/ +pm_runtime_put_sync (&intf->dev); +if (status <0 ) +pm_runtime_put (&intf->dev); + }else +atomic_inc (&intf->pm_usage_cnt); +dev_vdbg (&intf->dev,"%s: cnt %d -> %d\n" , + __func__,atomic_read (&intf->dev.power.usage_count), + status); +if (status >0 ) + status =0 ; +return status; +} +EXPORT_SYMBOL_GPL (usb_autopm_get_interface_upgrade); + +/** * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter * @intf: the usb_interface whose counter should be incremented *
include/linux/usb.h +3 -0
@@ -663,6 +663,7 @@ extern void usb_enable_autosuspend(struct usb_device *udev);extern void usb_disable_autosuspend (struct usb_device *udev);extern int usb_autopm_get_interface (struct usb_interface *intf); +extern int usb_autopm_get_interface_upgrade (struct usb_interface *intf);extern void usb_autopm_put_interface (struct usb_interface *intf);extern int usb_autopm_get_interface_async (struct usb_interface *intf);extern void usb_autopm_put_interface_async (struct usb_interface *intf);
@@ -683,6 +684,8 @@ static inline int usb_disable_autosuspend(struct usb_device *udev)static inline int usb_autopm_get_interface (struct usb_interface *intf) {return 0 ; } +static inline int usb_autopm_get_interface_upgrade (struct usb_interface *intf) +{return 0 ; }static inline int usb_autopm_get_interface_async (struct usb_interface *intf) {return 0 ; }
Signature · 1 line
1.9.1