Commit 81454b84 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Kalle Valo

zd1211rw: use irqsave() in USB's complete callback

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: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent a3128fee
...@@ -371,25 +371,27 @@ static inline void handle_regs_int_override(struct urb *urb) ...@@ -371,25 +371,27 @@ static inline void handle_regs_int_override(struct urb *urb)
{ {
struct zd_usb *usb = urb->context; struct zd_usb *usb = urb->context;
struct zd_usb_interrupt *intr = &usb->intr; 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)) { if (atomic_read(&intr->read_regs_enabled)) {
atomic_set(&intr->read_regs_enabled, 0); atomic_set(&intr->read_regs_enabled, 0);
intr->read_regs_int_overridden = 1; intr->read_regs_int_overridden = 1;
complete(&intr->read_regs.completion); complete(&intr->read_regs.completion);
} }
spin_unlock(&intr->lock); spin_unlock_irqrestore(&intr->lock, flags);
} }
static inline void handle_regs_int(struct urb *urb) static inline void handle_regs_int(struct urb *urb)
{ {
struct zd_usb *usb = urb->context; struct zd_usb *usb = urb->context;
struct zd_usb_interrupt *intr = &usb->intr; struct zd_usb_interrupt *intr = &usb->intr;
unsigned long flags;
int len; int len;
u16 int_num; u16 int_num;
ZD_ASSERT(in_interrupt()); ZD_ASSERT(in_interrupt());
spin_lock(&intr->lock); spin_lock_irqsave(&intr->lock, flags);
int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2)); int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2));
if (int_num == CR_INTERRUPT) { if (int_num == CR_INTERRUPT) {
...@@ -425,7 +427,7 @@ static inline void handle_regs_int(struct urb *urb) ...@@ -425,7 +427,7 @@ static inline void handle_regs_int(struct urb *urb)
} }
out: out:
spin_unlock(&intr->lock); spin_unlock_irqrestore(&intr->lock, flags);
/* CR_INTERRUPT might override read_reg too. */ /* CR_INTERRUPT might override read_reg too. */
if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled))
...@@ -665,6 +667,7 @@ static void rx_urb_complete(struct urb *urb) ...@@ -665,6 +667,7 @@ static void rx_urb_complete(struct urb *urb)
struct zd_usb_rx *rx; struct zd_usb_rx *rx;
const u8 *buffer; const u8 *buffer;
unsigned int length; unsigned int length;
unsigned long flags;
switch (urb->status) { switch (urb->status) {
case 0: case 0:
...@@ -693,14 +696,14 @@ static void rx_urb_complete(struct urb *urb) ...@@ -693,14 +696,14 @@ static void rx_urb_complete(struct urb *urb)
/* If there is an old first fragment, we don't care. */ /* If there is an old first fragment, we don't care. */
dev_dbg_f(urb_dev(urb), "*** first fragment ***\n"); dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment)); ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
spin_lock(&rx->lock); spin_lock_irqsave(&rx->lock, flags);
memcpy(rx->fragment, buffer, length); memcpy(rx->fragment, buffer, length);
rx->fragment_length = length; rx->fragment_length = length;
spin_unlock(&rx->lock); spin_unlock_irqrestore(&rx->lock, flags);
goto resubmit; goto resubmit;
} }
spin_lock(&rx->lock); spin_lock_irqsave(&rx->lock, flags);
if (rx->fragment_length > 0) { if (rx->fragment_length > 0) {
/* We are on a second fragment, we believe */ /* We are on a second fragment, we believe */
ZD_ASSERT(length + rx->fragment_length <= ZD_ASSERT(length + rx->fragment_length <=
...@@ -710,9 +713,9 @@ static void rx_urb_complete(struct urb *urb) ...@@ -710,9 +713,9 @@ static void rx_urb_complete(struct urb *urb)
handle_rx_packet(usb, rx->fragment, handle_rx_packet(usb, rx->fragment,
rx->fragment_length + length); rx->fragment_length + length);
rx->fragment_length = 0; rx->fragment_length = 0;
spin_unlock(&rx->lock); spin_unlock_irqrestore(&rx->lock, flags);
} else { } else {
spin_unlock(&rx->lock); spin_unlock_irqrestore(&rx->lock, flags);
handle_rx_packet(usb, buffer, length); handle_rx_packet(usb, buffer, length);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment