Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 commit
4ba7d9997869d25bd223dea7536fc1ce9fab3b3b "rt2800pci: handle spurious
interrupts", but it was reverted in commit
82e5fc2a34fa9ffea38f00c4066b7e600a0ca5e6
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>

authored by

Stanislaw Gruszka and committed by
John W. Linville
dfd00c4c 92c1ff1f

+8 -20
+8 -20
drivers/net/wireless/rt2x00/rt2800pci.c
··· 422 422 static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, 423 423 enum dev_state state) 424 424 { 425 - int mask = (state == STATE_RADIO_IRQ_ON); 426 425 u32 reg; 427 426 unsigned long flags; 428 427 ··· 435 436 } 436 437 437 438 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); 438 - rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg); 439 - rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0); 440 - rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0); 441 - rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask); 442 - rt2x00_set_field32(&reg, INT_MASK_CSR_AC0_DMA_DONE, 0); 443 - rt2x00_set_field32(&reg, INT_MASK_CSR_AC1_DMA_DONE, 0); 444 - rt2x00_set_field32(&reg, INT_MASK_CSR_AC2_DMA_DONE, 0); 445 - rt2x00_set_field32(&reg, INT_MASK_CSR_AC3_DMA_DONE, 0); 446 - rt2x00_set_field32(&reg, INT_MASK_CSR_HCCA_DMA_DONE, 0); 447 - rt2x00_set_field32(&reg, INT_MASK_CSR_MGMT_DMA_DONE, 0); 448 - rt2x00_set_field32(&reg, INT_MASK_CSR_MCU_COMMAND, 0); 449 - rt2x00_set_field32(&reg, INT_MASK_CSR_RXTX_COHERENT, 0); 450 - rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, mask); 451 - rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, mask); 452 - rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, mask); 453 - rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, mask); 454 - rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0); 455 - rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0); 456 - rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0); 439 + reg = 0; 440 + if (state == STATE_RADIO_IRQ_ON) { 441 + rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, 1); 442 + rt2x00_set_field32(&reg, INT_MASK_CSR_TBTT, 1); 443 + rt2x00_set_field32(&reg, INT_MASK_CSR_PRE_TBTT, 1); 444 + rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1); 445 + rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, 1); 446 + } 457 447 rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); 458 448 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); 459 449