diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 190 |
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 | ||
940 | static void iwl_irq_tasklet(struct iwl_priv *priv) | 940 | static 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 */ | ||
1125 | static 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 | ||
2540 | static void iwl_cancel_deferred_work(struct iwl_priv *priv) | 2716 | static 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 | ||