aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2014-11-20 10:33:43 -0500
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-12-28 13:00:18 -0500
commit7616f334e6d441aa9824221b1352ebec9de57ad7 (patch)
treefb5806f182791d19c932fe2f790a7c400d57a53d /drivers/net/wireless/iwlwifi
parenta549b296228497cec90d3a5f5ecaa1934cec4bf1 (diff)
iwlwifi: pcie: add basic reference accounting
Implement the ref/unref trans ops and track both tx and host command queues (and hold references while they are not empty). Signed-off-by: Eliad Peller <eliadx.peller@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h8
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c39
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c34
5 files changed, 83 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index afa63f7b2d3e..0381dc495b1c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -1362,6 +1362,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
1362 .bt_coex_active = true, 1362 .bt_coex_active = true,
1363 .power_level = IWL_POWER_INDEX_1, 1363 .power_level = IWL_POWER_INDEX_1,
1364 .wd_disable = true, 1364 .wd_disable = true,
1365 .d0i3_disable = true,
1365#ifndef CONFIG_IWLWIFI_UAPSD 1366#ifndef CONFIG_IWLWIFI_UAPSD
1366 .uapsd_disable = true, 1367 .uapsd_disable = true,
1367#endif /* CONFIG_IWLWIFI_UAPSD */ 1368#endif /* CONFIG_IWLWIFI_UAPSD */
@@ -1478,6 +1479,10 @@ MODULE_PARM_DESC(wd_disable,
1478module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); 1479module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
1479MODULE_PARM_DESC(nvm_file, "NVM file name"); 1480MODULE_PARM_DESC(nvm_file, "NVM file name");
1480 1481
1482module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
1483 bool, S_IRUGO);
1484MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
1485
1481module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, 1486module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
1482 bool, S_IRUGO); 1487 bool, S_IRUGO);
1483#ifdef CONFIG_IWLWIFI_UAPSD 1488#ifdef CONFIG_IWLWIFI_UAPSD
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 71507cf490e6..2a8cf4b2445c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -103,6 +103,7 @@ enum iwl_disable_11n {
103 * @power_level: power level, default = 1 103 * @power_level: power level, default = 1
104 * @debug_level: levels are IWL_DL_* 104 * @debug_level: levels are IWL_DL_*
105 * @ant_coupling: antenna coupling in dB, default = 0 105 * @ant_coupling: antenna coupling in dB, default = 0
106 * @d0i3_disable: disable d0i3, default = 1,
106 * @fw_monitor: allow to use firmware monitor 107 * @fw_monitor: allow to use firmware monitor
107 */ 108 */
108struct iwl_mod_params { 109struct iwl_mod_params {
@@ -121,6 +122,7 @@ struct iwl_mod_params {
121 int ant_coupling; 122 int ant_coupling;
122 char *nvm_file; 123 char *nvm_file;
123 bool uapsd_disable; 124 bool uapsd_disable;
125 bool d0i3_disable;
124 bool fw_monitor; 126 bool fw_monitor;
125}; 127};
126 128
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 1aea6b66c594..e5652d82d79e 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -318,6 +318,11 @@ struct iwl_trans_pcie {
318 /*protect hw register */ 318 /*protect hw register */
319 spinlock_t reg_lock; 319 spinlock_t reg_lock;
320 bool cmd_in_flight; 320 bool cmd_in_flight;
321 bool ref_cmd_in_flight;
322
323 /* protect ref counter */
324 spinlock_t ref_lock;
325 u32 ref_count;
321 326
322 dma_addr_t fw_mon_phys; 327 dma_addr_t fw_mon_phys;
323 struct page *fw_mon_page; 328 struct page *fw_mon_page;
@@ -381,6 +386,9 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
381 struct sk_buff_head *skbs); 386 struct sk_buff_head *skbs);
382void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); 387void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
383 388
389void iwl_trans_pcie_ref(struct iwl_trans *trans);
390void iwl_trans_pcie_unref(struct iwl_trans *trans);
391
384static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) 392static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
385{ 393{
386 struct iwl_tfd_tb *tb = &tfd->tbs[idx]; 394 struct iwl_tfd_tb *tb = &tfd->tbs[idx];
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 4b42de3b0674..fbdbec89ad70 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -931,6 +931,7 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
931static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, 931static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
932 const struct fw_img *fw, bool run_in_rfkill) 932 const struct fw_img *fw, bool run_in_rfkill)
933{ 933{
934 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
934 int ret; 935 int ret;
935 bool hw_rfkill; 936 bool hw_rfkill;
936 937
@@ -960,6 +961,9 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
960 return ret; 961 return ret;
961 } 962 }
962 963
964 /* init ref_count to 1 (should be cleared when ucode is loaded) */
965 trans_pcie->ref_count = 1;
966
963 /* make sure rfkill handshake bits are cleared */ 967 /* make sure rfkill handshake bits are cleared */
964 iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); 968 iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
965 iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, 969 iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
@@ -1550,6 +1554,38 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
1550 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); 1554 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
1551} 1555}
1552 1556
1557void iwl_trans_pcie_ref(struct iwl_trans *trans)
1558{
1559 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1560 unsigned long flags;
1561
1562 if (iwlwifi_mod_params.d0i3_disable)
1563 return;
1564
1565 spin_lock_irqsave(&trans_pcie->ref_lock, flags);
1566 IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
1567 trans_pcie->ref_count++;
1568 spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
1569}
1570
1571void iwl_trans_pcie_unref(struct iwl_trans *trans)
1572{
1573 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
1574 unsigned long flags;
1575
1576 if (iwlwifi_mod_params.d0i3_disable)
1577 return;
1578
1579 spin_lock_irqsave(&trans_pcie->ref_lock, flags);
1580 IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
1581 if (WARN_ON_ONCE(trans_pcie->ref_count == 0)) {
1582 spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
1583 return;
1584 }
1585 trans_pcie->ref_count--;
1586 spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
1587}
1588
1553static const char *get_csr_string(int cmd) 1589static const char *get_csr_string(int cmd)
1554{ 1590{
1555#define IWL_CMD(x) case x: return #x 1591#define IWL_CMD(x) case x: return #x
@@ -2274,6 +2310,9 @@ static const struct iwl_trans_ops trans_ops_pcie = {
2274 .release_nic_access = iwl_trans_pcie_release_nic_access, 2310 .release_nic_access = iwl_trans_pcie_release_nic_access,
2275 .set_bits_mask = iwl_trans_pcie_set_bits_mask, 2311 .set_bits_mask = iwl_trans_pcie_set_bits_mask,
2276 2312
2313 .ref = iwl_trans_pcie_ref,
2314 .unref = iwl_trans_pcie_unref,
2315
2277 .dump_data = iwl_trans_pcie_dump_data, 2316 .dump_data = iwl_trans_pcie_dump_data,
2278}; 2317};
2279 2318
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 8a6c7a084aa1..c1c4c75026b2 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -985,17 +985,31 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
985 985
986 if (iwl_queue_space(&txq->q) > txq->q.low_mark) 986 if (iwl_queue_space(&txq->q) > txq->q.low_mark)
987 iwl_wake_queue(trans, txq); 987 iwl_wake_queue(trans, txq);
988
989 if (q->read_ptr == q->write_ptr) {
990 IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
991 iwl_trans_pcie_unref(trans);
992 }
993
988out: 994out:
989 spin_unlock_bh(&txq->lock); 995 spin_unlock_bh(&txq->lock);
990} 996}
991 997
992static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans) 998static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
999 const struct iwl_host_cmd *cmd)
993{ 1000{
994 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 1001 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
995 int ret; 1002 int ret;
996 1003
997 lockdep_assert_held(&trans_pcie->reg_lock); 1004 lockdep_assert_held(&trans_pcie->reg_lock);
998 1005
1006 if (!(cmd->flags & CMD_SEND_IN_IDLE) &&
1007 !trans_pcie->ref_cmd_in_flight) {
1008 trans_pcie->ref_cmd_in_flight = true;
1009 IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n");
1010 iwl_trans_pcie_ref(trans);
1011 }
1012
999 if (trans_pcie->cmd_in_flight) 1013 if (trans_pcie->cmd_in_flight)
1000 return 0; 1014 return 0;
1001 1015
@@ -1036,6 +1050,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
1036 1050
1037 lockdep_assert_held(&trans_pcie->reg_lock); 1051 lockdep_assert_held(&trans_pcie->reg_lock);
1038 1052
1053 if (trans_pcie->ref_cmd_in_flight) {
1054 trans_pcie->ref_cmd_in_flight = false;
1055 IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n");
1056 iwl_trans_pcie_unref(trans);
1057 }
1058
1039 if (WARN_ON(!trans_pcie->cmd_in_flight)) 1059 if (WARN_ON(!trans_pcie->cmd_in_flight))
1040 return 0; 1060 return 0;
1041 1061
@@ -1473,7 +1493,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
1473 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); 1493 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
1474 1494
1475 spin_lock_irqsave(&trans_pcie->reg_lock, flags); 1495 spin_lock_irqsave(&trans_pcie->reg_lock, flags);
1476 ret = iwl_pcie_set_cmd_in_flight(trans); 1496 ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
1477 if (ret < 0) { 1497 if (ret < 0) {
1478 idx = ret; 1498 idx = ret;
1479 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); 1499 spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
@@ -1819,9 +1839,13 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1819 wait_write_ptr = ieee80211_has_morefrags(fc); 1839 wait_write_ptr = ieee80211_has_morefrags(fc);
1820 1840
1821 /* start timer if queue currently empty */ 1841 /* start timer if queue currently empty */
1822 if (txq->need_update && q->read_ptr == q->write_ptr && 1842 if (q->read_ptr == q->write_ptr) {
1823 trans_pcie->wd_timeout) 1843 if (txq->need_update && trans_pcie->wd_timeout)
1824 mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); 1844 mod_timer(&txq->stuck_timer,
1845 jiffies + trans_pcie->wd_timeout);
1846 IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
1847 iwl_trans_pcie_ref(trans);
1848 }
1825 1849
1826 /* Tell device the write index *just past* this latest filled TFD */ 1850 /* Tell device the write index *just past* this latest filled TFD */
1827 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr); 1851 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr);