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 <[email protected]>
Cc: Alan Stern <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
 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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to