When a PCI device is unplugged reading from the register will return the value from the state of just before the device is unplugged. When a rt61pci device was removed while the txdone handler was running it ended in a endless loop because it would run the txdone handler from the same frame (the one last indicated by STA_CSR4) over and over again. Check in the loop if the freshly read register value is the same as the previously one and bail out if this is the case. Signed-off-by: Ivo van Doorn <IvDoorn@xxxxxxxxx> --- drivers/net/wireless/rt2x00/rt61pci.c | 22 ++++++++++++++++++---- 1 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 6199606..0c53b61 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1801,23 +1801,37 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) struct data_desc *txd; u32 word; u32 reg; + u32 old_reg; + int type; int index; int tx_status; int retry; + /* + * During each loop we will compare the freshly read + * STA_CSR4 register value with the value read from + * the previous loop. If the 2 values are equal then + * we should stop processing because the chance it + * quite big that the device has been unplugged and + * we risk going into an endless loop. + */ + old_reg = 0; + while (1) { rt2x00pci_register_read(rt2x00dev, STA_CSR4, ®); if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) break; + if (old_reg == reg) + break; + old_reg = reg; + /* * Skip this entry when it contains an invalid * ring identication number. */ - ring = - rt2x00lib_get_ring(rt2x00dev, - rt2x00_get_field32(reg, - STA_CSR4_PID_TYPE)); + type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); + ring = rt2x00lib_get_ring(rt2x00dev, type); if (unlikely(!ring)) continue; -- 1.5.3 - To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html