aboutsummaryrefslogtreecommitdiffstats
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
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>
-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 8bed0445ff5d..fd65e1c3e055 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 7df41163ded2..a0b29411a4b3 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 bec5f8c6841f..89e1477b5143 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 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index a15f7955845b..12f018392a44 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 a0ed4156e25d..cbd87afbf9ae 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 3d50ef99f88d..34c123ea1d3e 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 1310c4122199..2076742effdd 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 8e68803cdc62..639893d7808b 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;