| From 913fa423a0b726960d4822e5da7ed81b2af61797 Mon Sep 17 00:00:00 2001 |
| From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Date: Thu, 23 Jul 2020 16:02:46 +0300 |
| Subject: [PATCH] mfd: dln2: Run event handler loop under spinlock |
| |
| commit 3d858942250820b9adc35f963a257481d6d4c81d upstream. |
| |
| The event handler loop must be run with interrupts disabled. |
| Otherwise we will have a warning: |
| |
| [ 1970.785649] irq 31 handler lineevent_irq_handler+0x0/0x20 enabled interrupts |
| [ 1970.792739] WARNING: CPU: 0 PID: 0 at kernel/irq/handle.c:159 __handle_irq_event_percpu+0x162/0x170 |
| [ 1970.860732] RIP: 0010:__handle_irq_event_percpu+0x162/0x170 |
| ... |
| [ 1970.946994] Call Trace: |
| [ 1970.949446] <IRQ> |
| [ 1970.951471] handle_irq_event_percpu+0x2c/0x80 |
| [ 1970.955921] handle_irq_event+0x23/0x43 |
| [ 1970.959766] handle_simple_irq+0x57/0x70 |
| [ 1970.963695] generic_handle_irq+0x42/0x50 |
| [ 1970.967717] dln2_rx+0xc1/0x210 [dln2] |
| [ 1970.971479] ? usb_hcd_unmap_urb_for_dma+0xa6/0x1c0 |
| [ 1970.976362] __usb_hcd_giveback_urb+0x77/0xe0 |
| [ 1970.980727] usb_giveback_urb_bh+0x8e/0xe0 |
| [ 1970.984837] tasklet_action_common.isra.0+0x4a/0xe0 |
| ... |
| |
| Recently xHCI driver switched to tasklets in the commit 36dc01657b49 |
| ("usb: host: xhci: Support running urb giveback in tasklet context"). |
| |
| The handle_irq_event_* functions are expected to be called with interrupts |
| disabled and they rightfully complain here because we run in tasklet context |
| with interrupts enabled. |
| |
| Use a event spinlock to protect event handler from being interrupted. |
| |
| Note, that there are only two users of this GPIO and ADC drivers and both of |
| them are using generic_handle_irq() which makes above happen. |
| |
| Fixes: 338a12814297 ("mfd: Add support for Diolan DLN-2 devices") |
| Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Signed-off-by: Lee Jones <lee.jones@linaro.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c |
| index 4faa8d2e5d04..707f4287ab4a 100644 |
| --- a/drivers/mfd/dln2.c |
| +++ b/drivers/mfd/dln2.c |
| @@ -287,7 +287,11 @@ static void dln2_rx(struct urb *urb) |
| len = urb->actual_length - sizeof(struct dln2_header); |
| |
| if (handle == DLN2_HANDLE_EVENT) { |
| + unsigned long flags; |
| + |
| + spin_lock_irqsave(&dln2->event_cb_lock, flags); |
| dln2_run_event_callbacks(dln2, id, echo, data, len); |
| + spin_unlock_irqrestore(&dln2->event_cb_lock, flags); |
| } else { |
| /* URB will be re-submitted in _dln2_transfer (free_rx_slot) */ |
| if (dln2_transfer_complete(dln2, urb, handle, echo)) |
| -- |
| 2.27.0 |
| |