rt2800pci: fix spurious interrupts generation
Same devices can generate interrupt without properly setting bit in INT_SOURCE_CSR register (spurious interrupt), what will cause IRQ line will be disabled by interrupts controller driver. We discovered that clearing INT_MASK_CSR stops such behaviour. We previously first read that register, and then clear all know interrupt sources bits and do not touch reserved bits. After this patch, we write to all register content (I believe writing to reserved bits on that register will not cause any problems, I tested that on my rt2800pci device). This fix very bad performance problem, practically making device unusable (since worked without interrupts), reported in: https://bugzilla.redhat.com/show_bug.cgi?id=658451 We previously tried to workaround that issue in commit4ba7d99978
"rt2800pci: handle spurious interrupts", but it was reverted in commit82e5fc2a34
as thing, that will prevent to detect real spurious interrupts. Reported-and-tested-by: Amir Hedayaty <hedayaty@gmail.com> Cc: stable@vger.kernel.org Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Acked-by: Gertjan van Wingerde <gwingerde@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
92c1ff1fa7
commit
dfd00c4c8f
|
@ -422,7 +422,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
|
|||
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
||||
enum dev_state state)
|
||||
{
|
||||
int mask = (state == STATE_RADIO_IRQ_ON);
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -436,25 +435,14 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
|||
}
|
||||
|
||||
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
|
||||
rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AC0_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AC1_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AC2_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AC3_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_HCCA_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_MGMT_DMA_DONE, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_MCU_COMMAND, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RXTX_COHERENT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TBTT, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_PRE_TBTT, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AUTO_WAKEUP, mask);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0);
|
||||
reg = 0;
|
||||
if (state == STATE_RADIO_IRQ_ON) {
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, 1);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TBTT, 1);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_PRE_TBTT, 1);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, 1);
|
||||
rt2x00_set_field32(®, INT_MASK_CSR_AUTO_WAKEUP, 1);
|
||||
}
|
||||
rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
|
||||
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
|
||||
|
||||
|
|
Loading…
Reference in a new issue