|
@@ -1622,7 +1622,8 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
|
|
|
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
|
|
|
enum dev_state state)
|
|
|
{
|
|
|
- int mask = (state == STATE_RADIO_IRQ_OFF);
|
|
|
+ int mask = (state == STATE_RADIO_IRQ_OFF) ||
|
|
|
+ (state == STATE_RADIO_IRQ_OFF_ISR);
|
|
|
u32 reg;
|
|
|
|
|
|
/*
|
|
@@ -1739,7 +1740,9 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
|
|
|
rt61pci_toggle_rx(rt2x00dev, state);
|
|
|
break;
|
|
|
case STATE_RADIO_IRQ_ON:
|
|
|
+ case STATE_RADIO_IRQ_ON_ISR:
|
|
|
case STATE_RADIO_IRQ_OFF:
|
|
|
+ case STATE_RADIO_IRQ_OFF_ISR:
|
|
|
rt61pci_toggle_irq(rt2x00dev, state);
|
|
|
break;
|
|
|
case STATE_DEEP_SLEEP:
|
|
@@ -2147,27 +2150,11 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
|
|
|
rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
|
|
|
}
|
|
|
|
|
|
-static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
|
|
+static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance)
|
|
|
{
|
|
|
struct rt2x00_dev *rt2x00dev = dev_instance;
|
|
|
- u32 reg_mcu;
|
|
|
- u32 reg;
|
|
|
-
|
|
|
- /*
|
|
|
- * Get the interrupt sources & saved to local variable.
|
|
|
- * Write register value back to clear pending interrupts.
|
|
|
- */
|
|
|
- rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu);
|
|
|
- rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
|
|
|
-
|
|
|
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
|
|
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
|
|
|
-
|
|
|
- if (!reg && !reg_mcu)
|
|
|
- return IRQ_NONE;
|
|
|
-
|
|
|
- if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
|
|
- return IRQ_HANDLED;
|
|
|
+ u32 reg = rt2x00dev->irqvalue[0];
|
|
|
+ u32 reg_mcu = rt2x00dev->irqvalue[1];
|
|
|
|
|
|
/*
|
|
|
* Handle interrupts, walk through all bits
|
|
@@ -2206,9 +2193,45 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
|
|
if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
|
|
|
rt2x00lib_beacondone(rt2x00dev);
|
|
|
|
|
|
+ /* Enable interrupts again. */
|
|
|
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
|
|
+ STATE_RADIO_IRQ_ON_ISR);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
|
|
|
+{
|
|
|
+ struct rt2x00_dev *rt2x00dev = dev_instance;
|
|
|
+ u32 reg_mcu;
|
|
|
+ u32 reg;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Get the interrupt sources & saved to local variable.
|
|
|
+ * Write register value back to clear pending interrupts.
|
|
|
+ */
|
|
|
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu);
|
|
|
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
|
|
|
+
|
|
|
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®);
|
|
|
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
|
|
|
+
|
|
|
+ if (!reg && !reg_mcu)
|
|
|
+ return IRQ_NONE;
|
|
|
+
|
|
|
+ if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
|
|
|
+ return IRQ_HANDLED;
|
|
|
+
|
|
|
+ /* Store irqvalues for use in the interrupt thread. */
|
|
|
+ rt2x00dev->irqvalue[0] = reg;
|
|
|
+ rt2x00dev->irqvalue[1] = reg_mcu;
|
|
|
+
|
|
|
+ /* Disable interrupts, will be enabled again in the interrupt thread. */
|
|
|
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev,
|
|
|
+ STATE_RADIO_IRQ_OFF_ISR);
|
|
|
+ return IRQ_WAKE_THREAD;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Device probe functions.
|
|
|
*/
|
|
@@ -2795,6 +2818,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
|
|
|
|
|
|
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
|
|
|
.irq_handler = rt61pci_interrupt,
|
|
|
+ .irq_handler_thread = rt61pci_interrupt_thread,
|
|
|
.probe_hw = rt61pci_probe_hw,
|
|
|
.get_firmware_name = rt61pci_get_firmware_name,
|
|
|
.check_firmware = rt61pci_check_firmware,
|