aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/rx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-27 15:43:48 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-05 08:39:12 -0500
commit2bfb50924c7e92362ac937aef2ab56bc7bd3ca52 (patch)
tree26518070c19eb9cfb38ab48cda31fe16c1235433 /drivers/net/wireless/iwlwifi/pcie/rx.c
parentc9f7a8ab7792b48259af6e94706a5d02dd74caef (diff)
iwlwifi: use threaded interrupt handler
With new transports coming up, move to threaded interrupt handling now. This has the advantage that we can use the same locking scheme with all different transports we may need to implement. Note that the TX path obviously still runs in a tasklet, so some spin_lock() calls need to change to spin_lock_bh() calls to properly lock out the TX path. In my test on a Calpella platform this has no impact on throughput or latency. Also add lockdep annotations to avoid lockups due to catch sending synchronous commands or using locks that connect with them from the irq thread. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c40
1 files changed, 25 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index a9ca1d35fa93..b0ae06d2456f 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -81,10 +81,10 @@
81 * 'processed' and 'read' driver indexes as well) 81 * 'processed' and 'read' driver indexes as well)
82 * + A received packet is processed and handed to the kernel network stack, 82 * + A received packet is processed and handed to the kernel network stack,
83 * detached from the iwl->rxq. The driver 'processed' index is updated. 83 * detached from the iwl->rxq. The driver 'processed' index is updated.
84 * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free 84 * + The Host/Firmware iwl->rxq is replenished at irq thread time from the
85 * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ 85 * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free,
86 * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there 86 * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set.
87 * were enough free buffers and RX_STALLED is set it is cleared. 87 * If there were enough free buffers and RX_STALLED is set it is cleared.
88 * 88 *
89 * 89 *
90 * Driver sequence: 90 * Driver sequence:
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
214 /* 214 /*
215 * If the device isn't enabled - not need to try to add buffers... 215 * If the device isn't enabled - not need to try to add buffers...
216 * This can happen when we stop the device and still have an interrupt 216 * This can happen when we stop the device and still have an interrupt
217 * pending. We stop the APM before we sync the interrupts / tasklets 217 * pending. We stop the APM before we sync the interrupts because we
218 * because we have to (see comment there). On the other hand, since 218 * have to (see comment there). On the other hand, since the APM is
219 * the APM is stopped, we cannot access the HW (in particular not prph). 219 * stopped, we cannot access the HW (in particular not prph).
220 * So don't try to restock if the APM has been already stopped. 220 * So don't try to restock if the APM has been already stopped.
221 */ 221 */
222 if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) 222 if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status))
@@ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
796 clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); 796 clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
797 wake_up(&trans_pcie->wait_command_queue); 797 wake_up(&trans_pcie->wait_command_queue);
798 798
799 local_bh_disable();
799 iwl_op_mode_nic_error(trans->op_mode); 800 iwl_op_mode_nic_error(trans->op_mode);
801 local_bh_enable();
800} 802}
801 803
802void iwl_pcie_tasklet(struct iwl_trans *trans) 804irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
803{ 805{
806 struct iwl_trans *trans = dev_id;
804 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 807 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
805 struct isr_statistics *isr_stats = &trans_pcie->isr_stats; 808 struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
806 u32 inta = 0; 809 u32 inta = 0;
@@ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
811 u32 inta_mask; 814 u32 inta_mask;
812#endif 815#endif
813 816
817 lock_map_acquire(&trans->sync_cmd_lockdep_map);
818
814 spin_lock_irqsave(&trans_pcie->irq_lock, flags); 819 spin_lock_irqsave(&trans_pcie->irq_lock, flags);
815 820
816 /* Ack/clear/reset pending uCode interrupts. 821 /* Ack/clear/reset pending uCode interrupts.
@@ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
855 860
856 handled |= CSR_INT_BIT_HW_ERR; 861 handled |= CSR_INT_BIT_HW_ERR;
857 862
858 return; 863 goto out;
859 } 864 }
860 865
861#ifdef CONFIG_IWLWIFI_DEBUG 866#ifdef CONFIG_IWLWIFI_DEBUG
@@ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans)
1005 /* Re-enable RF_KILL if it occurred */ 1010 /* Re-enable RF_KILL if it occurred */
1006 else if (handled & CSR_INT_BIT_RF_KILL) 1011 else if (handled & CSR_INT_BIT_RF_KILL)
1007 iwl_enable_rfkill_int(trans); 1012 iwl_enable_rfkill_int(trans);
1013
1014out:
1015 lock_map_release(&trans->sync_cmd_lockdep_map);
1016 return IRQ_HANDLED;
1008} 1017}
1009 1018
1010/****************************************************************************** 1019/******************************************************************************
@@ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
1127 1136
1128 /* Disable (but don't clear!) interrupts here to avoid 1137 /* Disable (but don't clear!) interrupts here to avoid
1129 * back-to-back ISRs and sporadic interrupts from our NIC. 1138 * back-to-back ISRs and sporadic interrupts from our NIC.
1130 * If we have something to service, the tasklet will re-enable ints. 1139 * If we have something to service, the irq thread will re-enable ints.
1131 * If we *don't* have something, we'll re-enable before leaving here. */ 1140 * If we *don't* have something, we'll re-enable before leaving here. */
1132 inta_mask = iwl_read32(trans, CSR_INT_MASK); 1141 inta_mask = iwl_read32(trans, CSR_INT_MASK);
1133 iwl_write32(trans, CSR_INT_MASK, 0x00000000); 1142 iwl_write32(trans, CSR_INT_MASK, 0x00000000);
@@ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
1167#endif 1176#endif
1168 1177
1169 trans_pcie->inta |= inta; 1178 trans_pcie->inta |= inta;
1170 /* iwl_pcie_tasklet() will service interrupts and re-enable them */ 1179 /* the thread will service interrupts and re-enable them */
1171 if (likely(inta)) 1180 if (likely(inta))
1172 tasklet_schedule(&trans_pcie->irq_tasklet); 1181 return IRQ_WAKE_THREAD;
1173 else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && 1182 else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
1174 !trans_pcie->inta) 1183 !trans_pcie->inta)
1175 iwl_enable_interrupts(trans); 1184 iwl_enable_interrupts(trans);
@@ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
1277 trans_pcie->inta |= inta; 1286 trans_pcie->inta |= inta;
1278 1287
1279 /* iwl_pcie_tasklet() will service interrupts and re-enable them */ 1288 /* iwl_pcie_tasklet() will service interrupts and re-enable them */
1280 if (likely(inta)) 1289 if (likely(inta)) {
1281 tasklet_schedule(&trans_pcie->irq_tasklet); 1290 spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
1282 else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && 1291 return IRQ_WAKE_THREAD;
1292 } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
1283 !trans_pcie->inta) { 1293 !trans_pcie->inta) {
1284 /* Allow interrupt if was disabled by this handler and 1294 /* Allow interrupt if was disabled by this handler and
1285 * no tasklet was schedules, We should not enable interrupt, 1295 * no tasklet was schedules, We should not enable interrupt,