aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn.c
diff options
context:
space:
mode:
authorMohamed Abbas <mohamed.abbas@intel.com>2009-05-22 14:01:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-22 14:06:05 -0400
commitef850d7cb301bda9155c096269557a4586b58071 (patch)
treee9dc0190a2a575a9515511043805fbdb73ac02e6 /drivers/net/wireless/iwlwifi/iwl-agn.c
parenta2b0f02e4795bfde5f11720a10af8923cb98b654 (diff)
iwlcore: support ICT interrupt
Add ICT interrupt handler support, ICT should improve CPU utilization since it does not require target read which is very expensive. This interrupt handler only added to 5000 cards and newer. Device will write interrupts to ICT shared table to inform driver about its interrupts. These patches will not touch 3945 and 4965 interrupt handlers and tasklet. Signed-off-by: Mohamed Abbas <mohamed.abbas@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c190
1 files changed, 185 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 4e41038a92c1..fa24b019c62c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -937,7 +937,7 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
937 tasklet_kill(&priv->irq_tasklet); 937 tasklet_kill(&priv->irq_tasklet);
938} 938}
939 939
940static void iwl_irq_tasklet(struct iwl_priv *priv) 940static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
941{ 941{
942 u32 inta, handled = 0; 942 u32 inta, handled = 0;
943 u32 inta_fh; 943 u32 inta_fh;
@@ -1121,6 +1121,174 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
1121 spin_unlock_irqrestore(&priv->lock, flags); 1121 spin_unlock_irqrestore(&priv->lock, flags);
1122} 1122}
1123 1123
1124/* tasklet for iwlagn interrupt */
1125static void iwl_irq_tasklet(struct iwl_priv *priv)
1126{
1127 u32 inta = 0;
1128 u32 handled = 0;
1129 unsigned long flags;
1130#ifdef CONFIG_IWLWIFI_DEBUG
1131 u32 inta_mask;
1132#endif
1133
1134 spin_lock_irqsave(&priv->lock, flags);
1135
1136 /* Ack/clear/reset pending uCode interrupts.
1137 * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
1138 */
1139 iwl_write32(priv, CSR_INT, priv->inta);
1140
1141 inta = priv->inta;
1142
1143#ifdef CONFIG_IWLWIFI_DEBUG
1144 if (priv->debug_level & IWL_DL_ISR) {
1145 /* just for debug */
1146 inta_mask = iwl_read32(priv, CSR_INT_MASK);
1147 IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
1148 inta, inta_mask);
1149 }
1150#endif
1151 /* saved interrupt in inta variable now we can reset priv->inta */
1152 priv->inta = 0;
1153
1154 /* Now service all interrupt bits discovered above. */
1155 if (inta & CSR_INT_BIT_HW_ERR) {
1156 IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
1157
1158 /* Tell the device to stop sending interrupts */
1159 iwl_disable_interrupts(priv);
1160
1161 priv->isr_stats.hw++;
1162 iwl_irq_handle_error(priv);
1163
1164 handled |= CSR_INT_BIT_HW_ERR;
1165
1166 spin_unlock_irqrestore(&priv->lock, flags);
1167
1168 return;
1169 }
1170
1171#ifdef CONFIG_IWLWIFI_DEBUG
1172 if (priv->debug_level & (IWL_DL_ISR)) {
1173 /* NIC fires this, but we don't use it, redundant with WAKEUP */
1174 if (inta & CSR_INT_BIT_SCD) {
1175 IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
1176 "the frame/frames.\n");
1177 priv->isr_stats.sch++;
1178 }
1179
1180 /* Alive notification via Rx interrupt will do the real work */
1181 if (inta & CSR_INT_BIT_ALIVE) {
1182 IWL_DEBUG_ISR(priv, "Alive interrupt\n");
1183 priv->isr_stats.alive++;
1184 }
1185 }
1186#endif
1187 /* Safely ignore these bits for debug checks below */
1188 inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
1189
1190 /* HW RF KILL switch toggled */
1191 if (inta & CSR_INT_BIT_RF_KILL) {
1192 int hw_rf_kill = 0;
1193 if (!(iwl_read32(priv, CSR_GP_CNTRL) &
1194 CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
1195 hw_rf_kill = 1;
1196
1197 IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
1198 hw_rf_kill ? "disable radio" : "enable radio");
1199
1200 priv->isr_stats.rfkill++;
1201
1202 /* driver only loads ucode once setting the interface up.
1203 * the driver allows loading the ucode even if the radio
1204 * is killed. Hence update the killswitch state here. The
1205 * rfkill handler will care about restarting if needed.
1206 */
1207 if (!test_bit(STATUS_ALIVE, &priv->status)) {
1208 if (hw_rf_kill)
1209 set_bit(STATUS_RF_KILL_HW, &priv->status);
1210 else
1211 clear_bit(STATUS_RF_KILL_HW, &priv->status);
1212 queue_work(priv->workqueue, &priv->rf_kill);
1213 }
1214
1215 handled |= CSR_INT_BIT_RF_KILL;
1216 }
1217
1218 /* Chip got too hot and stopped itself */
1219 if (inta & CSR_INT_BIT_CT_KILL) {
1220 IWL_ERR(priv, "Microcode CT kill error detected.\n");
1221 priv->isr_stats.ctkill++;
1222 handled |= CSR_INT_BIT_CT_KILL;
1223 }
1224
1225 /* Error detected by uCode */
1226 if (inta & CSR_INT_BIT_SW_ERR) {
1227 IWL_ERR(priv, "Microcode SW error detected. "
1228 " Restarting 0x%X.\n", inta);
1229 priv->isr_stats.sw++;
1230 priv->isr_stats.sw_err = inta;
1231 iwl_irq_handle_error(priv);
1232 handled |= CSR_INT_BIT_SW_ERR;
1233 }
1234
1235 /* uCode wakes up after power-down sleep */
1236 if (inta & CSR_INT_BIT_WAKEUP) {
1237 IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
1238 iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
1239 iwl_txq_update_write_ptr(priv, &priv->txq[0]);
1240 iwl_txq_update_write_ptr(priv, &priv->txq[1]);
1241 iwl_txq_update_write_ptr(priv, &priv->txq[2]);
1242 iwl_txq_update_write_ptr(priv, &priv->txq[3]);
1243 iwl_txq_update_write_ptr(priv, &priv->txq[4]);
1244 iwl_txq_update_write_ptr(priv, &priv->txq[5]);
1245
1246 priv->isr_stats.wakeup++;
1247
1248 handled |= CSR_INT_BIT_WAKEUP;
1249 }
1250
1251 /* All uCode command responses, including Tx command responses,
1252 * Rx "responses" (frame-received notification), and other
1253 * notifications from uCode come through here*/
1254 if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
1255 IWL_DEBUG_ISR(priv, "Rx interrupt\n");
1256 iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_RX_MASK);
1257 iwl_rx_handle(priv);
1258 priv->isr_stats.rx++;
1259 handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
1260 }
1261
1262 if (inta & CSR_INT_BIT_FH_TX) {
1263 iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK);
1264 IWL_DEBUG_ISR(priv, "Tx interrupt\n");
1265 priv->isr_stats.tx++;
1266 handled |= CSR_INT_BIT_FH_TX;
1267 /* FH finished to write, send event */
1268 priv->ucode_write_complete = 1;
1269 wake_up_interruptible(&priv->wait_command_queue);
1270 }
1271
1272 if (inta & ~handled) {
1273 IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
1274 priv->isr_stats.unhandled++;
1275 }
1276
1277 if (inta & ~CSR_INI_SET_MASK) {
1278 IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
1279 inta & ~CSR_INI_SET_MASK);
1280 }
1281
1282
1283 /* Re-enable all interrupts */
1284 /* only Re-enable if diabled by irq */
1285 if (test_bit(STATUS_INT_ENABLED, &priv->status))
1286 iwl_enable_interrupts(priv);
1287
1288 spin_unlock_irqrestore(&priv->lock, flags);
1289
1290}
1291
1124 1292
1125/****************************************************************************** 1293/******************************************************************************
1126 * 1294 *
@@ -1550,6 +1718,8 @@ static void __iwl_down(struct iwl_priv *priv)
1550 test_bit(STATUS_EXIT_PENDING, &priv->status) << 1718 test_bit(STATUS_EXIT_PENDING, &priv->status) <<
1551 STATUS_EXIT_PENDING; 1719 STATUS_EXIT_PENDING;
1552 1720
1721 /* device going down, Stop using ICT table */
1722 iwl_disable_ict(priv);
1553 spin_lock_irqsave(&priv->lock, flags); 1723 spin_lock_irqsave(&priv->lock, flags);
1554 iwl_clear_bit(priv, CSR_GP_CNTRL, 1724 iwl_clear_bit(priv, CSR_GP_CNTRL,
1555 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); 1725 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -1633,6 +1803,8 @@ static int __iwl_up(struct iwl_priv *priv)
1633 1803
1634 /* clear (again), then enable host interrupts */ 1804 /* clear (again), then enable host interrupts */
1635 iwl_write32(priv, CSR_INT, 0xFFFFFFFF); 1805 iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
1806 /* enable dram interrupt */
1807 iwl_reset_ict(priv);
1636 iwl_enable_interrupts(priv); 1808 iwl_enable_interrupts(priv);
1637 1809
1638 /* really make sure rfkill handshake bits are cleared */ 1810 /* really make sure rfkill handshake bits are cleared */
@@ -2533,8 +2705,12 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
2533 priv->statistics_periodic.data = (unsigned long)priv; 2705 priv->statistics_periodic.data = (unsigned long)priv;
2534 priv->statistics_periodic.function = iwl_bg_statistics_periodic; 2706 priv->statistics_periodic.function = iwl_bg_statistics_periodic;
2535 2707
2536 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) 2708 if (!priv->cfg->use_isr_legacy)
2537 iwl_irq_tasklet, (unsigned long)priv); 2709 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
2710 iwl_irq_tasklet, (unsigned long)priv);
2711 else
2712 tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
2713 iwl_irq_tasklet_legacy, (unsigned long)priv);
2538} 2714}
2539 2715
2540static void iwl_cancel_deferred_work(struct iwl_priv *priv) 2716static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -2735,8 +2911,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2735 2911
2736 pci_enable_msi(priv->pci_dev); 2912 pci_enable_msi(priv->pci_dev);
2737 2913
2738 err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, 2914 iwl_alloc_isr_ict(priv);
2739 DRV_NAME, priv); 2915 err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr,
2916 IRQF_SHARED, DRV_NAME, priv);
2740 if (err) { 2917 if (err) {
2741 IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); 2918 IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
2742 goto out_disable_msi; 2919 goto out_disable_msi;
@@ -2793,6 +2970,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2793 sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); 2970 sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
2794 out_free_irq: 2971 out_free_irq:
2795 free_irq(priv->pci_dev->irq, priv); 2972 free_irq(priv->pci_dev->irq, priv);
2973 iwl_free_isr_ict(priv);
2796 out_disable_msi: 2974 out_disable_msi:
2797 pci_disable_msi(priv->pci_dev); 2975 pci_disable_msi(priv->pci_dev);
2798 iwl_uninit_drv(priv); 2976 iwl_uninit_drv(priv);
@@ -2874,6 +3052,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
2874 3052
2875 iwl_uninit_drv(priv); 3053 iwl_uninit_drv(priv);
2876 3054
3055 iwl_free_isr_ict(priv);
3056
2877 if (priv->ibss_beacon) 3057 if (priv->ibss_beacon)
2878 dev_kfree_skb(priv->ibss_beacon); 3058 dev_kfree_skb(priv->ibss_beacon);
2879 3059