aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2013-03-24 23:06:41 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-01 16:20:00 -0400
commita269913c52ad37952a4d9953bb6d748f7299c304 (patch)
tree8f15190009b592607ea25fd6971cad4ef8dc55a8 /drivers
parent3a16b41240aa893b2c397ea3bd07d86e95e7694b (diff)
rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue
In commit a5ffbe0, some of the calls to rtl_lps_leave() were switched to be called from a work queue to avoid a scheduling while atomic bug. This patch converts the remaining calls to use the work queue. In addition, the call to rtl_lps_enter() is also switched to the work queue. None of these newly converted calls had triggered the bug (yet), but this change make all of them fit a single pattern. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: jcheung@suse.com Cc: machen@suse.com Cc: mmarek@suse.cz Cc: zhiyuan_yang@realsil.com.cn Cc: page_he@realsil.com.cn Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/rtlwifi/base.c19
-rw-r--r--drivers/net/wireless/rtlwifi/core.c9
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c27
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h3
4 files changed, 34 insertions, 24 deletions
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 270b27a06905..f8a2d9f28e46 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -1088,8 +1088,9 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
1088 is_tx ? "Tx" : "Rx"); 1088 is_tx ? "Tx" : "Rx");
1089 1089
1090 if (is_tx) { 1090 if (is_tx) {
1091 rtlpriv->enter_ps = false;
1091 schedule_work(&rtlpriv-> 1092 schedule_work(&rtlpriv->
1092 works.lps_leave_work); 1093 works.lps_change_work);
1093 ppsc->last_delaylps_stamp_jiffies = 1094 ppsc->last_delaylps_stamp_jiffies =
1094 jiffies; 1095 jiffies;
1095 } 1096 }
@@ -1099,7 +1100,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
1099 } 1100 }
1100 } else if (ETH_P_ARP == ether_type) { 1101 } else if (ETH_P_ARP == ether_type) {
1101 if (is_tx) { 1102 if (is_tx) {
1102 schedule_work(&rtlpriv->works.lps_leave_work); 1103 rtlpriv->enter_ps = false;
1104 schedule_work(&rtlpriv->works.lps_change_work);
1103 ppsc->last_delaylps_stamp_jiffies = jiffies; 1105 ppsc->last_delaylps_stamp_jiffies = jiffies;
1104 } 1106 }
1105 1107
@@ -1109,7 +1111,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
1109 "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"); 1111 "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
1110 1112
1111 if (is_tx) { 1113 if (is_tx) {
1112 schedule_work(&rtlpriv->works.lps_leave_work); 1114 rtlpriv->enter_ps = false;
1115 schedule_work(&rtlpriv->works.lps_change_work);
1113 ppsc->last_delaylps_stamp_jiffies = jiffies; 1116 ppsc->last_delaylps_stamp_jiffies = jiffies;
1114 } 1117 }
1115 1118
@@ -1318,7 +1321,6 @@ void rtl_watchdog_wq_callback(void *data)
1318 u32 aver_tx_cnt_inperiod = 0; 1321 u32 aver_tx_cnt_inperiod = 0;
1319 u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; 1322 u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
1320 u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; 1323 u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
1321 bool enter_ps = false;
1322 1324
1323 if (is_hal_stop(rtlhal)) 1325 if (is_hal_stop(rtlhal))
1324 return; 1326 return;
@@ -1400,15 +1402,12 @@ void rtl_watchdog_wq_callback(void *data)
1400 if (((rtlpriv->link_info.num_rx_inperiod + 1402 if (((rtlpriv->link_info.num_rx_inperiod +
1401 rtlpriv->link_info.num_tx_inperiod) > 8) || 1403 rtlpriv->link_info.num_tx_inperiod) > 8) ||
1402 (rtlpriv->link_info.num_rx_inperiod > 2)) 1404 (rtlpriv->link_info.num_rx_inperiod > 2))
1403 enter_ps = false; 1405 rtlpriv->enter_ps = true;
1404 else 1406 else
1405 enter_ps = true; 1407 rtlpriv->enter_ps = false;
1406 1408
1407 /* LeisurePS only work in infra mode. */ 1409 /* LeisurePS only work in infra mode. */
1408 if (enter_ps) 1410 schedule_work(&rtlpriv->works.lps_change_work);
1409 rtl_lps_enter(hw);
1410 else
1411 schedule_work(&rtlpriv->works.lps_leave_work);
1412 } 1411 }
1413 1412
1414 rtlpriv->link_info.num_rx_inperiod = 0; 1413 rtlpriv->link_info.num_rx_inperiod = 0;
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 3338cf311062..2201b5cee08f 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -742,8 +742,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
742 RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, 742 RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
743 "BSS_CHANGED_ASSOC\n"); 743 "BSS_CHANGED_ASSOC\n");
744 } else { 744 } else {
745 if (mac->link_state == MAC80211_LINKED) 745 if (mac->link_state == MAC80211_LINKED) {
746 schedule_work(&rtlpriv->works.lps_leave_work); 746 rtlpriv->enter_ps = false;
747 schedule_work(&rtlpriv->works.lps_change_work);
748 }
747 749
748 if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE) 750 if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
749 rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); 751 rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
@@ -1018,7 +1020,8 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
1018 rtlpriv->cfg->ops->chk_switch_dmdp(hw); 1020 rtlpriv->cfg->ops->chk_switch_dmdp(hw);
1019 } 1021 }
1020 if (mac->link_state == MAC80211_LINKED) { 1022 if (mac->link_state == MAC80211_LINKED) {
1021 schedule_work(&rtlpriv->works.lps_leave_work); 1023 rtlpriv->enter_ps = false;
1024 schedule_work(&rtlpriv->works.lps_change_work);
1022 mac->link_state = MAC80211_LINKED_SCANNING; 1025 mac->link_state = MAC80211_LINKED_SCANNING;
1023 } else { 1026 } else {
1024 rtl_ips_nic_on(hw); 1027 rtl_ips_nic_on(hw);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 4af6abd1491c..b449d41a3084 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -654,7 +654,8 @@ tx_status_ok:
654 if (((rtlpriv->link_info.num_rx_inperiod + 654 if (((rtlpriv->link_info.num_rx_inperiod +
655 rtlpriv->link_info.num_tx_inperiod) > 8) || 655 rtlpriv->link_info.num_tx_inperiod) > 8) ||
656 (rtlpriv->link_info.num_rx_inperiod > 2)) { 656 (rtlpriv->link_info.num_rx_inperiod > 2)) {
657 schedule_work(&rtlpriv->works.lps_leave_work); 657 rtlpriv->enter_ps = false;
658 schedule_work(&rtlpriv->works.lps_change_work);
658 } 659 }
659} 660}
660 661
@@ -783,9 +784,10 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
783 _rtl_receive_one(hw, skb, rx_status); 784 _rtl_receive_one(hw, skb, rx_status);
784 785
785 if (((rtlpriv->link_info.num_rx_inperiod + 786 if (((rtlpriv->link_info.num_rx_inperiod +
786 rtlpriv->link_info.num_tx_inperiod) > 8) || 787 rtlpriv->link_info.num_tx_inperiod) > 8) ||
787 (rtlpriv->link_info.num_rx_inperiod > 2)) { 788 (rtlpriv->link_info.num_rx_inperiod > 2)) {
788 schedule_work(&rtlpriv->works.lps_leave_work); 789 rtlpriv->enter_ps = false;
790 schedule_work(&rtlpriv->works.lps_change_work);
789 } 791 }
790 792
791 dev_kfree_skb_any(skb); 793 dev_kfree_skb_any(skb);
@@ -1005,13 +1007,17 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
1005 return; 1007 return;
1006} 1008}
1007 1009
1008static void rtl_lps_leave_work_callback(struct work_struct *work) 1010static void rtl_lps_change_work_callback(struct work_struct *work)
1009{ 1011{
1010 struct rtl_works *rtlworks = 1012 struct rtl_works *rtlworks =
1011 container_of(work, struct rtl_works, lps_leave_work); 1013 container_of(work, struct rtl_works, lps_change_work);
1012 struct ieee80211_hw *hw = rtlworks->hw; 1014 struct ieee80211_hw *hw = rtlworks->hw;
1015 struct rtl_priv *rtlpriv = rtl_priv(hw);
1013 1016
1014 rtl_lps_leave(hw); 1017 if (rtlpriv->enter_ps)
1018 rtl_lps_enter(hw);
1019 else
1020 rtl_lps_leave(hw);
1015} 1021}
1016 1022
1017static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) 1023static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
@@ -1075,7 +1081,8 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
1075 tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, 1081 tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
1076 (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, 1082 (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
1077 (unsigned long)hw); 1083 (unsigned long)hw);
1078 INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback); 1084 INIT_WORK(&rtlpriv->works.lps_change_work,
1085 rtl_lps_change_work_callback);
1079} 1086}
1080 1087
1081static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, 1088static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1561,7 +1568,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
1561 1568
1562 synchronize_irq(rtlpci->pdev->irq); 1569 synchronize_irq(rtlpci->pdev->irq);
1563 tasklet_kill(&rtlpriv->works.irq_tasklet); 1570 tasklet_kill(&rtlpriv->works.irq_tasklet);
1564 cancel_work_sync(&rtlpriv->works.lps_leave_work); 1571 cancel_work_sync(&rtlpriv->works.lps_change_work);
1565 1572
1566 flush_workqueue(rtlpriv->works.rtl_wq); 1573 flush_workqueue(rtlpriv->works.rtl_wq);
1567 destroy_workqueue(rtlpriv->works.rtl_wq); 1574 destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1636,7 +1643,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
1636 set_hal_stop(rtlhal); 1643 set_hal_stop(rtlhal);
1637 1644
1638 rtlpriv->cfg->ops->disable_interrupt(hw); 1645 rtlpriv->cfg->ops->disable_interrupt(hw);
1639 cancel_work_sync(&rtlpriv->works.lps_leave_work); 1646 cancel_work_sync(&rtlpriv->works.lps_change_work);
1640 1647
1641 spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); 1648 spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
1642 while (ppsc->rfchange_inprogress) { 1649 while (ppsc->rfchange_inprogress) {
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 7ec95cb1ee1b..70193a519547 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -1796,7 +1796,7 @@ struct rtl_works {
1796 struct delayed_work ps_rfon_wq; 1796 struct delayed_work ps_rfon_wq;
1797 struct delayed_work fwevt_wq; 1797 struct delayed_work fwevt_wq;
1798 1798
1799 struct work_struct lps_leave_work; 1799 struct work_struct lps_change_work;
1800}; 1800};
1801 1801
1802struct rtl_debug { 1802struct rtl_debug {
@@ -1966,6 +1966,7 @@ struct rtl_priv {
1966 bool bt_operation_on; 1966 bool bt_operation_on;
1967 }; 1967 };
1968 }; 1968 };
1969 bool enter_ps; /* true when entering PS */
1969 1970
1970 /*This must be the last item so 1971 /*This must be the last item so
1971 that it points to the data allocated 1972 that it points to the data allocated