diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2013-03-24 23:06:41 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-01 16:20:00 -0400 |
commit | a269913c52ad37952a4d9953bb6d748f7299c304 (patch) | |
tree | 8f15190009b592607ea25fd6971cad4ef8dc55a8 /drivers | |
parent | 3a16b41240aa893b2c397ea3bd07d86e95e7694b (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.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/core.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/pci.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/rtlwifi/wifi.h | 3 |
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 | ||
1008 | static void rtl_lps_leave_work_callback(struct work_struct *work) | 1010 | static 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 | ||
1017 | static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw) | 1023 | static 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 | ||
1081 | static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, | 1088 | static 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 | ||
1802 | struct rtl_debug { | 1802 | struct 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 |