OSDN Git Service

zd1211rw: use irqsave() in USB's complete callback
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Wed, 20 Jun 2018 19:36:48 +0000 (21:36 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 27 Jun 2018 16:12:43 +0000 (19:12 +0300)
The USB completion callback does not disable interrupts while acquiring
the lock. We want to remove the local_irq_disable() invocation from
__usb_hcd_giveback_urb() and therefore it is required for the callback
handler to disable the interrupts while acquiring the lock.
The callback may be invoked either in IRQ or BH context depending on the
USB host controller.
Use the _irqsave() variant of the locking primitives.

Cc: Daniel Drake <dsd@gentoo.org>
Cc: Ulrich Kunitz <kune@deine-taler.de>
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-wireless@vger.kernel.org
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/zydas/zd1211rw/zd_usb.c

index c30bf11..c2cda3a 100644 (file)
@@ -371,25 +371,27 @@ static inline void handle_regs_int_override(struct urb *urb)
 {
        struct zd_usb *usb = urb->context;
        struct zd_usb_interrupt *intr = &usb->intr;
+       unsigned long flags;
 
-       spin_lock(&intr->lock);
+       spin_lock_irqsave(&intr->lock, flags);
        if (atomic_read(&intr->read_regs_enabled)) {
                atomic_set(&intr->read_regs_enabled, 0);
                intr->read_regs_int_overridden = 1;
                complete(&intr->read_regs.completion);
        }
-       spin_unlock(&intr->lock);
+       spin_unlock_irqrestore(&intr->lock, flags);
 }
 
 static inline void handle_regs_int(struct urb *urb)
 {
        struct zd_usb *usb = urb->context;
        struct zd_usb_interrupt *intr = &usb->intr;
+       unsigned long flags;
        int len;
        u16 int_num;
 
        ZD_ASSERT(in_interrupt());
-       spin_lock(&intr->lock);
+       spin_lock_irqsave(&intr->lock, flags);
 
        int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2));
        if (int_num == CR_INTERRUPT) {
@@ -425,7 +427,7 @@ static inline void handle_regs_int(struct urb *urb)
        }
 
 out:
-       spin_unlock(&intr->lock);
+       spin_unlock_irqrestore(&intr->lock, flags);
 
        /* CR_INTERRUPT might override read_reg too. */
        if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled))
@@ -665,6 +667,7 @@ static void rx_urb_complete(struct urb *urb)
        struct zd_usb_rx *rx;
        const u8 *buffer;
        unsigned int length;
+       unsigned long flags;
 
        switch (urb->status) {
        case 0:
@@ -693,14 +696,14 @@ static void rx_urb_complete(struct urb *urb)
                /* If there is an old first fragment, we don't care. */
                dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
                ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
-               spin_lock(&rx->lock);
+               spin_lock_irqsave(&rx->lock, flags);
                memcpy(rx->fragment, buffer, length);
                rx->fragment_length = length;
-               spin_unlock(&rx->lock);
+               spin_unlock_irqrestore(&rx->lock, flags);
                goto resubmit;
        }
 
-       spin_lock(&rx->lock);
+       spin_lock_irqsave(&rx->lock, flags);
        if (rx->fragment_length > 0) {
                /* We are on a second fragment, we believe */
                ZD_ASSERT(length + rx->fragment_length <=
@@ -710,9 +713,9 @@ static void rx_urb_complete(struct urb *urb)
                handle_rx_packet(usb, rx->fragment,
                                 rx->fragment_length + length);
                rx->fragment_length = 0;
-               spin_unlock(&rx->lock);
+               spin_unlock_irqrestore(&rx->lock, flags);
        } else {
-               spin_unlock(&rx->lock);
+               spin_unlock_irqrestore(&rx->lock, flags);
                handle_rx_packet(usb, buffer, length);
        }