This patch kills atomic_inc/atomic_dec operations on urb->use_count in URB submit/complete path. The urb->use_count is only used for unlinking URB, and it isn't necessary defined as atomic counter, so the variable is renamed as urb->use_flag for this purpose, then reading/writing the flag is still kept as atomic but ARCH's atomic operations(atomic_inc/ atomic_dec) are saved. Cc: Oliver Neukum <oliver@xxxxxxxxxx> Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxxxxx> --- drivers/usb/core/hcd.c | 14 +++++++++----- drivers/usb/core/urb.c | 8 ++++++-- drivers/usb/core/usb.h | 5 +++++ include/linux/usb.h | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0b4d1ae..9457c4e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1555,7 +1555,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) * an error or calls giveback(), but not both. */ usb_get_urb(urb); - atomic_inc(&urb->use_count); + atomic_set(&urb->use_flag, URB_USING); this_cpu_inc(*urb->dev->urbnum); usbmon_urb_submit(&hcd->self, urb); @@ -1582,7 +1582,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) usbmon_urb_submit_error(&hcd->self, urb, status); urb->hcpriv = NULL; INIT_LIST_HEAD(&urb->urb_list); - atomic_dec(&urb->use_count); + atomic_set(&urb->use_flag, URB_UNUSED); this_cpu_dec(*urb->dev->urbnum); if (atomic_read(&urb->reject)) wake_up(&usb_kill_urb_queue); @@ -1628,11 +1628,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) /* Prevent the device and bus from going away while * the unlink is carried out. If they are already gone - * then urb->use_count must be 0, since disconnected + * then urb->use_flag must be URB_UNUSED, since disconnected * devices can't have any active URBs. */ spin_lock_irqsave(&hcd_urb_unlink_lock, flags); - if (atomic_read(&urb->use_count) > 0) { + if (atomic_read(&urb->use_flag) != URB_UNUSED) { retval = 0; usb_get_dev(urb->dev); } @@ -1672,6 +1672,8 @@ static void __usb_hcd_giveback_urb(struct urb *urb) /* pass ownership to the completion handler */ urb->status = status; + atomic_set(&urb->use_flag, URB_UNUSING); + /* * We disable local IRQs here avoid possible deadlock because * drivers may call spin_lock() to hold lock which might be @@ -1686,7 +1688,9 @@ static void __usb_hcd_giveback_urb(struct urb *urb) urb->complete(urb); local_irq_restore(flags); - atomic_dec(&urb->use_count); + if (atomic_read(&urb->use_flag) == URB_UNUSING) + atomic_set(&urb->use_flag, URB_UNUSED); + if (unlikely(atomic_read(&urb->reject))) wake_up(&usb_kill_urb_queue); usb_put_urb(urb); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c12bc79..79d2534 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -9,6 +9,8 @@ #include <linux/usb/hcd.h> #include <linux/scatterlist.h> +#include "usb.h" + #define to_urb(d) container_of(d, struct urb, kref) @@ -661,7 +663,8 @@ void usb_kill_urb(struct urb *urb) atomic_inc(&urb->reject); usb_hcd_unlink_urb(urb, -ENOENT); - wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); + wait_event(usb_kill_urb_queue, + atomic_read(&urb->use_flag) == URB_UNUSED); atomic_dec(&urb->reject); } @@ -705,7 +708,8 @@ void usb_poison_urb(struct urb *urb) return; usb_hcd_unlink_urb(urb, -ENOENT); - wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); + wait_event(usb_kill_urb_queue, + atomic_read(&urb->use_flag) == URB_UNUSED); } EXPORT_SYMBOL_GPL(usb_poison_urb); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 12a0181..bbdcf93 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -5,6 +5,11 @@ struct usb_hub_descriptor; struct dev_state; +/* urb use flag*/ +#define URB_UNUSED 0 +#define URB_USING 1 +#define URB_UNUSING 2 + /* Functions local to drivers/usb/core/ */ extern int usb_create_sysfs_dev_files(struct usb_device *dev); diff --git a/include/linux/usb.h b/include/linux/usb.h index 75332dc..7f5f629 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1408,7 +1408,7 @@ struct urb { /* private: usb core and host controller only fields in the urb */ struct kref kref; /* reference count of the URB */ void *hcpriv; /* private data for host controller */ - atomic_t use_count; /* concurrent submissions counter */ + atomic_t use_flag; /* urb using flag */ atomic_t reject; /* submissions will fail */ int unlinked; /* unlink error code */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html