aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c190
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c266
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c4
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
2877static struct iwl_cfg iwl3945_abg_cfg = { 2879static 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
2889struct pci_device_id iwl3945_hw_card_ids[] = { 2892struct 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
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
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
44MODULE_DESCRIPTION("iwl core"); 45MODULE_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
63static 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}
1502EXPORT_SYMBOL(iwl_enable_interrupts); 1505EXPORT_SYMBOL(iwl_enable_interrupts);
1503 1506
1504irqreturn_t iwl_isr(int irq, void *data) 1507
1508#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
1509
1510/* Free dram table */
1511void 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}
1520EXPORT_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 */
1526int 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}
1559EXPORT_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 */
1564int 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}
1595EXPORT_SYMBOL(iwl_reset_ict);
1596
1597/* Device is going down disable ict interrupt usage */
1598void 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}
1606EXPORT_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 */
1616irqreturn_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}
1698EXPORT_SYMBOL(iwl_isr_ict);
1699
1700
1701static 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
1766irqreturn_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}
1561EXPORT_SYMBOL(iwl_isr); 1823EXPORT_SYMBOL(iwl_isr_legacy);
1562 1824
1563int iwl_send_bt_config(struct iwl_priv *priv) 1825int 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 *****************************************************/
467void iwl_disable_interrupts(struct iwl_priv *priv); 469void iwl_disable_interrupts(struct iwl_priv *priv);
468void iwl_enable_interrupts(struct iwl_priv *priv); 470void iwl_enable_interrupts(struct iwl_priv *priv);
469irqreturn_t iwl_isr(int irq, void *data); 471irqreturn_t iwl_isr_legacy(int irq, void *data);
472int iwl_reset_ict(struct iwl_priv *priv);
473void iwl_disable_ict(struct iwl_priv *priv);
474int iwl_alloc_isr_ict(struct iwl_priv *priv);
475void iwl_free_isr_ict(struct iwl_priv *priv);
476irqreturn_t iwl_isr_ict(int irq, void *data);
477
470static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) 478static 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;