diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-5000.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 190 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 266 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-csr.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 |
9 files changed, 483 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8bed0445ff5..fd65e1c3e05 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -2838,6 +2838,7 @@ static struct iwl_lib_ops iwl3945_lib = { | |||
2838 | .send_tx_power = iwl3945_send_tx_power, | 2838 | .send_tx_power = iwl3945_send_tx_power, |
2839 | .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, | 2839 | .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, |
2840 | .post_associate = iwl3945_post_associate, | 2840 | .post_associate = iwl3945_post_associate, |
2841 | .isr = iwl_isr_legacy, | ||
2841 | .config_ap = iwl3945_config_ap, | 2842 | .config_ap = iwl3945_config_ap, |
2842 | }; | 2843 | }; |
2843 | 2844 | ||
@@ -2871,7 +2872,8 @@ static struct iwl_cfg iwl3945_bg_cfg = { | |||
2871 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, | 2872 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, |
2872 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, | 2873 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, |
2873 | .ops = &iwl3945_ops, | 2874 | .ops = &iwl3945_ops, |
2874 | .mod_params = &iwl3945_mod_params | 2875 | .mod_params = &iwl3945_mod_params, |
2876 | .use_isr_legacy = true | ||
2875 | }; | 2877 | }; |
2876 | 2878 | ||
2877 | static struct iwl_cfg iwl3945_abg_cfg = { | 2879 | static struct iwl_cfg iwl3945_abg_cfg = { |
@@ -2883,7 +2885,8 @@ static struct iwl_cfg iwl3945_abg_cfg = { | |||
2883 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, | 2885 | .eeprom_size = IWL3945_EEPROM_IMG_SIZE, |
2884 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, | 2886 | .eeprom_ver = EEPROM_3945_EEPROM_VERSION, |
2885 | .ops = &iwl3945_ops, | 2887 | .ops = &iwl3945_ops, |
2886 | .mod_params = &iwl3945_mod_params | 2888 | .mod_params = &iwl3945_mod_params, |
2889 | .use_isr_legacy = true | ||
2887 | }; | 2890 | }; |
2888 | 2891 | ||
2889 | struct pci_device_id iwl3945_hw_card_ids[] = { | 2892 | struct pci_device_id iwl3945_hw_card_ids[] = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 7df41163ded..a0b29411a4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -2286,6 +2286,7 @@ static struct iwl_lib_ops iwl4965_lib = { | |||
2286 | .update_chain_flags = iwl_update_chain_flags, | 2286 | .update_chain_flags = iwl_update_chain_flags, |
2287 | .post_associate = iwl_post_associate, | 2287 | .post_associate = iwl_post_associate, |
2288 | .config_ap = iwl_config_ap, | 2288 | .config_ap = iwl_config_ap, |
2289 | .isr = iwl_isr_legacy, | ||
2289 | .temp_ops = { | 2290 | .temp_ops = { |
2290 | .temperature = iwl4965_temperature_calib, | 2291 | .temperature = iwl4965_temperature_calib, |
2291 | .set_ct_kill = iwl4965_set_ct_threshold, | 2292 | .set_ct_kill = iwl4965_set_ct_threshold, |
@@ -2310,6 +2311,7 @@ struct iwl_cfg iwl4965_agn_cfg = { | |||
2310 | .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, | 2311 | .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, |
2311 | .ops = &iwl4965_ops, | 2312 | .ops = &iwl4965_ops, |
2312 | .mod_params = &iwl4965_mod_params, | 2313 | .mod_params = &iwl4965_mod_params, |
2314 | .use_isr_legacy = true | ||
2313 | }; | 2315 | }; |
2314 | 2316 | ||
2315 | /* Module firmware */ | 2317 | /* Module firmware */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index bec5f8c6841..89e1477b514 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -1487,6 +1487,7 @@ struct iwl_lib_ops iwl5000_lib = { | |||
1487 | .query_addr = iwl5000_eeprom_query_addr, | 1487 | .query_addr = iwl5000_eeprom_query_addr, |
1488 | }, | 1488 | }, |
1489 | .post_associate = iwl_post_associate, | 1489 | .post_associate = iwl_post_associate, |
1490 | .isr = iwl_isr_ict, | ||
1490 | .config_ap = iwl_config_ap, | 1491 | .config_ap = iwl_config_ap, |
1491 | .temp_ops = { | 1492 | .temp_ops = { |
1492 | .temperature = iwl5000_temperature, | 1493 | .temperature = iwl5000_temperature, |
@@ -1536,6 +1537,7 @@ static struct iwl_lib_ops iwl5150_lib = { | |||
1536 | .query_addr = iwl5000_eeprom_query_addr, | 1537 | .query_addr = iwl5000_eeprom_query_addr, |
1537 | }, | 1538 | }, |
1538 | .post_associate = iwl_post_associate, | 1539 | .post_associate = iwl_post_associate, |
1540 | .isr = iwl_isr_ict, | ||
1539 | .config_ap = iwl_config_ap, | 1541 | .config_ap = iwl_config_ap, |
1540 | .temp_ops = { | 1542 | .temp_ops = { |
1541 | .temperature = iwl5150_temperature, | 1543 | .temperature = iwl5150_temperature, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 4e41038a92c..fa24b019c62 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 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index a15f7955845..12f018392a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "iwl-rfkill.h" | 39 | #include "iwl-rfkill.h" |
40 | #include "iwl-power.h" | 40 | #include "iwl-power.h" |
41 | #include "iwl-sta.h" | 41 | #include "iwl-sta.h" |
42 | #include "iwl-helpers.h" | ||
42 | 43 | ||
43 | 44 | ||
44 | MODULE_DESCRIPTION("iwl core"); | 45 | MODULE_DESCRIPTION("iwl core"); |
@@ -59,6 +60,8 @@ MODULE_LICENSE("GPL"); | |||
59 | IWL_RATE_##pp##M_INDEX, \ | 60 | IWL_RATE_##pp##M_INDEX, \ |
60 | IWL_RATE_##np##M_INDEX } | 61 | IWL_RATE_##np##M_INDEX } |
61 | 62 | ||
63 | static irqreturn_t iwl_isr(int irq, void *data); | ||
64 | |||
62 | /* | 65 | /* |
63 | * Parameter order: | 66 | * Parameter order: |
64 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate | 67 | * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate |
@@ -1501,7 +1504,266 @@ void iwl_enable_interrupts(struct iwl_priv *priv) | |||
1501 | } | 1504 | } |
1502 | EXPORT_SYMBOL(iwl_enable_interrupts); | 1505 | EXPORT_SYMBOL(iwl_enable_interrupts); |
1503 | 1506 | ||
1504 | irqreturn_t iwl_isr(int irq, void *data) | 1507 | |
1508 | #define ICT_COUNT (PAGE_SIZE/sizeof(u32)) | ||
1509 | |||
1510 | /* Free dram table */ | ||
1511 | void iwl_free_isr_ict(struct iwl_priv *priv) | ||
1512 | { | ||
1513 | if (priv->ict_tbl_vir) { | ||
1514 | pci_free_consistent(priv->pci_dev, (sizeof(u32) * ICT_COUNT) + | ||
1515 | PAGE_SIZE, priv->ict_tbl_vir, | ||
1516 | priv->ict_tbl_dma); | ||
1517 | priv->ict_tbl_vir = NULL; | ||
1518 | } | ||
1519 | } | ||
1520 | EXPORT_SYMBOL(iwl_free_isr_ict); | ||
1521 | |||
1522 | |||
1523 | /* allocate dram shared table it is a PAGE_SIZE aligned | ||
1524 | * also reset all data related to ICT table interrupt. | ||
1525 | */ | ||
1526 | int iwl_alloc_isr_ict(struct iwl_priv *priv) | ||
1527 | { | ||
1528 | |||
1529 | if (priv->cfg->use_isr_legacy) | ||
1530 | return 0; | ||
1531 | /* allocate shrared data table */ | ||
1532 | priv->ict_tbl_vir = pci_alloc_consistent(priv->pci_dev, (sizeof(u32) * | ||
1533 | ICT_COUNT) + PAGE_SIZE, | ||
1534 | &priv->ict_tbl_dma); | ||
1535 | if (!priv->ict_tbl_vir) | ||
1536 | return -ENOMEM; | ||
1537 | |||
1538 | /* align table to PAGE_SIZE boundry */ | ||
1539 | priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE); | ||
1540 | |||
1541 | IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", | ||
1542 | (unsigned long long)priv->ict_tbl_dma, | ||
1543 | (unsigned long long)priv->aligned_ict_tbl_dma, | ||
1544 | (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); | ||
1545 | |||
1546 | priv->ict_tbl = priv->ict_tbl_vir + | ||
1547 | (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma); | ||
1548 | |||
1549 | IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n", | ||
1550 | priv->ict_tbl, priv->ict_tbl_vir, | ||
1551 | (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma)); | ||
1552 | |||
1553 | /* reset table and index to all 0 */ | ||
1554 | memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); | ||
1555 | priv->ict_index = 0; | ||
1556 | |||
1557 | return 0; | ||
1558 | } | ||
1559 | EXPORT_SYMBOL(iwl_alloc_isr_ict); | ||
1560 | |||
1561 | /* Device is going up inform it about using ICT interrupt table, | ||
1562 | * also we need to tell the driver to start using ICT interrupt. | ||
1563 | */ | ||
1564 | int iwl_reset_ict(struct iwl_priv *priv) | ||
1565 | { | ||
1566 | u32 val; | ||
1567 | unsigned long flags; | ||
1568 | |||
1569 | if (!priv->ict_tbl_vir) | ||
1570 | return 0; | ||
1571 | |||
1572 | spin_lock_irqsave(&priv->lock, flags); | ||
1573 | iwl_disable_interrupts(priv); | ||
1574 | |||
1575 | memset(&priv->ict_tbl[0],0, sizeof(u32) * ICT_COUNT); | ||
1576 | |||
1577 | val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; | ||
1578 | |||
1579 | val |= CSR_DRAM_INT_TBL_ENABLE; | ||
1580 | val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; | ||
1581 | |||
1582 | IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X " | ||
1583 | "aligned dma address %Lx\n", | ||
1584 | val, (unsigned long long)priv->aligned_ict_tbl_dma); | ||
1585 | |||
1586 | iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); | ||
1587 | priv->use_ict = true; | ||
1588 | priv->ict_index = 0; | ||
1589 | iwl_write32(priv, CSR_INT, CSR_INI_SET_MASK); | ||
1590 | iwl_enable_interrupts(priv); | ||
1591 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1592 | |||
1593 | return 0; | ||
1594 | } | ||
1595 | EXPORT_SYMBOL(iwl_reset_ict); | ||
1596 | |||
1597 | /* Device is going down disable ict interrupt usage */ | ||
1598 | void iwl_disable_ict(struct iwl_priv *priv) | ||
1599 | { | ||
1600 | unsigned long flags; | ||
1601 | |||
1602 | spin_lock_irqsave(&priv->lock, flags); | ||
1603 | priv->use_ict = false; | ||
1604 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1605 | } | ||
1606 | EXPORT_SYMBOL(iwl_disable_ict); | ||
1607 | |||
1608 | /* interrupt handler using ict table, with this interrupt driver will | ||
1609 | * stop using INTA register to get device's interrupt, reading this register | ||
1610 | * is expensive, device will write interrupts in ICT dram table, increment | ||
1611 | * index then will fire interrupt to driver, driver will OR all ICT table | ||
1612 | * entries from current index up to table entry with 0 value. the result is | ||
1613 | * the interrupt we need to service, driver will set the entries back to 0 and | ||
1614 | * set index. | ||
1615 | */ | ||
1616 | irqreturn_t iwl_isr_ict(int irq, void *data) | ||
1617 | { | ||
1618 | struct iwl_priv *priv = data; | ||
1619 | u32 inta, inta_mask; | ||
1620 | u32 val = 0; | ||
1621 | |||
1622 | if (!priv) | ||
1623 | return IRQ_NONE; | ||
1624 | |||
1625 | /* dram interrupt table not set yet, | ||
1626 | * use legacy interrupt. | ||
1627 | */ | ||
1628 | if (!priv->use_ict) | ||
1629 | return iwl_isr(irq, data); | ||
1630 | |||
1631 | spin_lock(&priv->lock); | ||
1632 | |||
1633 | /* Disable (but don't clear!) interrupts here to avoid | ||
1634 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1635 | * If we have something to service, the tasklet will re-enable ints. | ||
1636 | * If we *don't* have something, we'll re-enable before leaving here. | ||
1637 | */ | ||
1638 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1639 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1640 | |||
1641 | |||
1642 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1643 | * This may be due to IRQ shared with another device, | ||
1644 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1645 | if (!priv->ict_tbl[priv->ict_index]) { | ||
1646 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); | ||
1647 | goto none; | ||
1648 | } | ||
1649 | |||
1650 | /* read all entries that not 0 start with ict_index */ | ||
1651 | while (priv->ict_tbl[priv->ict_index]) { | ||
1652 | |||
1653 | val |= priv->ict_tbl[priv->ict_index]; | ||
1654 | IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", | ||
1655 | priv->ict_index, | ||
1656 | priv->ict_tbl[priv->ict_index]); | ||
1657 | priv->ict_tbl[priv->ict_index] = 0; | ||
1658 | priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, | ||
1659 | ICT_COUNT); | ||
1660 | |||
1661 | } | ||
1662 | |||
1663 | /* We should not get this value, just ignore it. */ | ||
1664 | if (val == 0xffffffff) | ||
1665 | val = 0; | ||
1666 | |||
1667 | inta = (0xff & val) | ((0xff00 & val) << 16); | ||
1668 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", | ||
1669 | inta, inta_mask, val); | ||
1670 | |||
1671 | inta &= CSR_INI_SET_MASK; | ||
1672 | priv->inta |= inta; | ||
1673 | |||
1674 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1675 | if (likely(inta)) | ||
1676 | tasklet_schedule(&priv->irq_tasklet); | ||
1677 | else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) { | ||
1678 | /* Allow interrupt if was disabled by this handler and | ||
1679 | * no tasklet was schedules, We should not enable interrupt, | ||
1680 | * tasklet will enable it. | ||
1681 | */ | ||
1682 | iwl_enable_interrupts(priv); | ||
1683 | } | ||
1684 | |||
1685 | spin_unlock(&priv->lock); | ||
1686 | return IRQ_HANDLED; | ||
1687 | |||
1688 | none: | ||
1689 | /* re-enable interrupts here since we don't have anything to service. | ||
1690 | * only Re-enable if disabled by irq. | ||
1691 | */ | ||
1692 | if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1693 | iwl_enable_interrupts(priv); | ||
1694 | |||
1695 | spin_unlock(&priv->lock); | ||
1696 | return IRQ_NONE; | ||
1697 | } | ||
1698 | EXPORT_SYMBOL(iwl_isr_ict); | ||
1699 | |||
1700 | |||
1701 | static irqreturn_t iwl_isr(int irq, void *data) | ||
1702 | { | ||
1703 | struct iwl_priv *priv = data; | ||
1704 | u32 inta, inta_mask; | ||
1705 | u32 inta_fh; | ||
1706 | |||
1707 | if (!priv) | ||
1708 | return IRQ_NONE; | ||
1709 | |||
1710 | spin_lock(&priv->lock); | ||
1711 | |||
1712 | /* Disable (but don't clear!) interrupts here to avoid | ||
1713 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1714 | * If we have something to service, the tasklet will re-enable ints. | ||
1715 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
1716 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1717 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1718 | |||
1719 | /* Discover which interrupts are active/pending */ | ||
1720 | inta = iwl_read32(priv, CSR_INT); | ||
1721 | |||
1722 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1723 | * This may be due to IRQ shared with another device, | ||
1724 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1725 | if (!inta) { | ||
1726 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); | ||
1727 | goto none; | ||
1728 | } | ||
1729 | |||
1730 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
1731 | /* Hardware disappeared. It might have already raised | ||
1732 | * an interrupt */ | ||
1733 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
1734 | goto unplugged; | ||
1735 | } | ||
1736 | |||
1737 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1738 | if (priv->debug_level & (IWL_DL_ISR)) { | ||
1739 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
1740 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " | ||
1741 | "fh 0x%08x\n", inta, inta_mask, inta_fh); | ||
1742 | } | ||
1743 | #endif | ||
1744 | |||
1745 | priv->inta |= inta; | ||
1746 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1747 | if (likely(inta)) | ||
1748 | tasklet_schedule(&priv->irq_tasklet); | ||
1749 | else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1750 | iwl_enable_interrupts(priv); | ||
1751 | |||
1752 | unplugged: | ||
1753 | spin_unlock(&priv->lock); | ||
1754 | return IRQ_HANDLED; | ||
1755 | |||
1756 | none: | ||
1757 | /* re-enable interrupts here since we don't have anything to service. */ | ||
1758 | /* only Re-enable if diabled by irq and no schedules tasklet. */ | ||
1759 | if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) | ||
1760 | iwl_enable_interrupts(priv); | ||
1761 | |||
1762 | spin_unlock(&priv->lock); | ||
1763 | return IRQ_NONE; | ||
1764 | } | ||
1765 | |||
1766 | irqreturn_t iwl_isr_legacy(int irq, void *data) | ||
1505 | { | 1767 | { |
1506 | struct iwl_priv *priv = data; | 1768 | struct iwl_priv *priv = data; |
1507 | u32 inta, inta_mask; | 1769 | u32 inta, inta_mask; |
@@ -1558,7 +1820,7 @@ irqreturn_t iwl_isr(int irq, void *data) | |||
1558 | spin_unlock(&priv->lock); | 1820 | spin_unlock(&priv->lock); |
1559 | return IRQ_NONE; | 1821 | return IRQ_NONE; |
1560 | } | 1822 | } |
1561 | EXPORT_SYMBOL(iwl_isr); | 1823 | EXPORT_SYMBOL(iwl_isr_legacy); |
1562 | 1824 | ||
1563 | int iwl_send_bt_config(struct iwl_priv *priv) | 1825 | int iwl_send_bt_config(struct iwl_priv *priv) |
1564 | { | 1826 | { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index a0ed4156e25..cbd87afbf9a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -170,6 +170,7 @@ struct iwl_lib_ops { | |||
170 | void (*update_chain_flags)(struct iwl_priv *priv); | 170 | void (*update_chain_flags)(struct iwl_priv *priv); |
171 | void (*post_associate) (struct iwl_priv *priv); | 171 | void (*post_associate) (struct iwl_priv *priv); |
172 | void (*config_ap) (struct iwl_priv *priv); | 172 | void (*config_ap) (struct iwl_priv *priv); |
173 | irqreturn_t (*isr) (int irq, void *data); | ||
173 | 174 | ||
174 | /* eeprom operations (as defined in iwl-eeprom.h) */ | 175 | /* eeprom operations (as defined in iwl-eeprom.h) */ |
175 | struct iwl_eeprom_ops eeprom_ops; | 176 | struct iwl_eeprom_ops eeprom_ops; |
@@ -239,6 +240,7 @@ struct iwl_cfg { | |||
239 | u8 valid_tx_ant; | 240 | u8 valid_tx_ant; |
240 | u8 valid_rx_ant; | 241 | u8 valid_rx_ant; |
241 | bool need_pll_cfg; | 242 | bool need_pll_cfg; |
243 | bool use_isr_legacy; | ||
242 | }; | 244 | }; |
243 | 245 | ||
244 | /*************************** | 246 | /*************************** |
@@ -466,7 +468,13 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, | |||
466 | *****************************************************/ | 468 | *****************************************************/ |
467 | void iwl_disable_interrupts(struct iwl_priv *priv); | 469 | void iwl_disable_interrupts(struct iwl_priv *priv); |
468 | void iwl_enable_interrupts(struct iwl_priv *priv); | 470 | void iwl_enable_interrupts(struct iwl_priv *priv); |
469 | irqreturn_t iwl_isr(int irq, void *data); | 471 | irqreturn_t iwl_isr_legacy(int irq, void *data); |
472 | int iwl_reset_ict(struct iwl_priv *priv); | ||
473 | void iwl_disable_ict(struct iwl_priv *priv); | ||
474 | int iwl_alloc_isr_ict(struct iwl_priv *priv); | ||
475 | void iwl_free_isr_ict(struct iwl_priv *priv); | ||
476 | irqreturn_t iwl_isr_ict(int irq, void *data); | ||
477 | |||
470 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) | 478 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) |
471 | { | 479 | { |
472 | int pos; | 480 | int pos; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 3d50ef99f88..34c123ea1d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -97,6 +97,7 @@ | |||
97 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) | 97 | #define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) |
98 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) | 98 | #define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) |
99 | #define CSR_LED_REG (CSR_BASE+0x094) | 99 | #define CSR_LED_REG (CSR_BASE+0x094) |
100 | #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) | ||
100 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) | 101 | #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) |
101 | 102 | ||
102 | /* Analog phase-lock-loop configuration */ | 103 | /* Analog phase-lock-loop configuration */ |
@@ -256,6 +257,11 @@ | |||
256 | 257 | ||
257 | /* HPET MEM debug */ | 258 | /* HPET MEM debug */ |
258 | #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) | 259 | #define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000) |
260 | |||
261 | /* DRAM INT TABLE */ | ||
262 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) | ||
263 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) | ||
264 | |||
259 | /*=== HBUS (Host-side Bus) ===*/ | 265 | /*=== HBUS (Host-side Bus) ===*/ |
260 | #define HBUS_BASE (0x400) | 266 | #define HBUS_BASE (0x400) |
261 | /* | 267 | /* |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 1310c412219..2076742effd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -1048,6 +1048,14 @@ struct iwl_priv { | |||
1048 | /*End*/ | 1048 | /*End*/ |
1049 | struct iwl_hw_params hw_params; | 1049 | struct iwl_hw_params hw_params; |
1050 | 1050 | ||
1051 | /* INT ICT Table */ | ||
1052 | u32 *ict_tbl; | ||
1053 | dma_addr_t ict_tbl_dma; | ||
1054 | dma_addr_t aligned_ict_tbl_dma; | ||
1055 | int ict_index; | ||
1056 | void *ict_tbl_vir; | ||
1057 | u32 inta; | ||
1058 | bool use_ict; | ||
1051 | 1059 | ||
1052 | /* Current association information needed to configure the | 1060 | /* Current association information needed to configure the |
1053 | * hardware */ | 1061 | * hardware */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8e68803cdc6..639893d7808 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -4290,8 +4290,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
4290 | 4290 | ||
4291 | pci_enable_msi(priv->pci_dev); | 4291 | pci_enable_msi(priv->pci_dev); |
4292 | 4292 | ||
4293 | err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, | 4293 | err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, |
4294 | DRV_NAME, priv); | 4294 | IRQF_SHARED, DRV_NAME, priv); |
4295 | if (err) { | 4295 | if (err) { |
4296 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 4296 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
4297 | goto out_disable_msi; | 4297 | goto out_disable_msi; |