Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752231AbbE0CtY (ORCPT ); Tue, 26 May 2015 22:49:24 -0400 Received: from mga01.intel.com ([192.55.52.88]:65091 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751504AbbE0CtW (ORCPT ); Tue, 26 May 2015 22:49:22 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,502,1427785200"; d="scan'208";a="735801263" Message-ID: <556530AF.4050108@linux.intel.com> Date: Wed, 27 May 2015 10:49:19 +0800 From: "Zhang, Yanmin" User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: linux-kernel@vger.kernel.org, xinhuix.pan@intel.com, gregkh@linuxfoundation.org, alan@linux.intel.com Subject: [PATCH V2 1/3] usb: add function usb_autopm_get_interface_upgrade Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4569 Lines: 115 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 --- drivers/usb/core/driver.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb.h | 3 +++ 2 files changed, 57 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 818369a..5d6f9ee 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -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 * diff --git a/include/linux/usb.h b/include/linux/usb.h index 447fe29..0a8a44a 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -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; } -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/