Skip to content

Commit ba9f93f

Browse files
lwfingerKalle Valo
authored andcommitted
rtlwifi: Fix enter/exit power_save
In commit a5ffbe0 ("rtlwifi: Fix scheduling while atomic bug") and commit a269913 ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue"), an error was introduced in the power-save routines due to the fact that leaving PS was delayed by the use of a work queue. This problem is fixed by detecting if the enter or leave routines are in interrupt mode. If so, the workqueue is used to place the request. If in normal mode, the enter or leave routines are called directly. Fixes: a269913 ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue") Reported-by: Ping-Ke Shih <pkshih@realtek.com> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: Stable <stable@vger.kernel.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
1 parent 05db221 commit ba9f93f

File tree

4 files changed

+40
-27
lines changed

4 files changed

+40
-27
lines changed

drivers/net/wireless/realtek/rtlwifi/base.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,12 +1303,13 @@ EXPORT_SYMBOL_GPL(rtl_action_proc);
13031303

13041304
static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc)
13051305
{
1306+
struct ieee80211_hw *hw = rtlpriv->hw;
1307+
13061308
rtlpriv->ra.is_special_data = true;
13071309
if (rtlpriv->cfg->ops->get_btc_status())
13081310
rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
13091311
rtlpriv, 1);
1310-
rtlpriv->enter_ps = false;
1311-
schedule_work(&rtlpriv->works.lps_change_work);
1312+
rtl_lps_leave(hw);
13121313
ppsc->last_delaylps_stamp_jiffies = jiffies;
13131314
}
13141315

@@ -1381,8 +1382,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
13811382

13821383
if (is_tx) {
13831384
rtlpriv->ra.is_special_data = true;
1384-
rtlpriv->enter_ps = false;
1385-
schedule_work(&rtlpriv->works.lps_change_work);
1385+
rtl_lps_leave(hw);
13861386
ppsc->last_delaylps_stamp_jiffies = jiffies;
13871387
}
13881388

drivers/net/wireless/realtek/rtlwifi/core.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,10 +1150,8 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
11501150
} else {
11511151
mstatus = RT_MEDIA_DISCONNECT;
11521152

1153-
if (mac->link_state == MAC80211_LINKED) {
1154-
rtlpriv->enter_ps = false;
1155-
schedule_work(&rtlpriv->works.lps_change_work);
1156-
}
1153+
if (mac->link_state == MAC80211_LINKED)
1154+
rtl_lps_leave(hw);
11571155
if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
11581156
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
11591157
mac->link_state = MAC80211_NOLINK;
@@ -1431,8 +1429,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw,
14311429
}
14321430

14331431
if (mac->link_state == MAC80211_LINKED) {
1434-
rtlpriv->enter_ps = false;
1435-
schedule_work(&rtlpriv->works.lps_change_work);
1432+
rtl_lps_leave(hw);
14361433
mac->link_state = MAC80211_LINKED_SCANNING;
14371434
} else {
14381435
rtl_ips_nic_on(hw);

drivers/net/wireless/realtek/rtlwifi/pci.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -659,11 +659,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
659659
}
660660

661661
if (((rtlpriv->link_info.num_rx_inperiod +
662-
rtlpriv->link_info.num_tx_inperiod) > 8) ||
663-
(rtlpriv->link_info.num_rx_inperiod > 2)) {
664-
rtlpriv->enter_ps = false;
665-
schedule_work(&rtlpriv->works.lps_change_work);
666-
}
662+
rtlpriv->link_info.num_tx_inperiod) > 8) ||
663+
(rtlpriv->link_info.num_rx_inperiod > 2))
664+
rtl_lps_leave(hw);
667665
}
668666

669667
static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
@@ -914,10 +912,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
914912
}
915913
if (((rtlpriv->link_info.num_rx_inperiod +
916914
rtlpriv->link_info.num_tx_inperiod) > 8) ||
917-
(rtlpriv->link_info.num_rx_inperiod > 2)) {
918-
rtlpriv->enter_ps = false;
919-
schedule_work(&rtlpriv->works.lps_change_work);
920-
}
915+
(rtlpriv->link_info.num_rx_inperiod > 2))
916+
rtl_lps_leave(hw);
921917
skb = new_skb;
922918
no_new:
923919
if (rtlpriv->use_new_trx_flow) {

drivers/net/wireless/realtek/rtlwifi/ps.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,8 @@ void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
407407
}
408408
}
409409

410-
/*Enter the leisure power save mode.*/
411-
void rtl_lps_enter(struct ieee80211_hw *hw)
410+
/* Interrupt safe routine to enter the leisure power save mode.*/
411+
static void rtl_lps_enter_core(struct ieee80211_hw *hw)
412412
{
413413
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
414414
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -444,10 +444,9 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
444444

445445
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
446446
}
447-
EXPORT_SYMBOL(rtl_lps_enter);
448447

449-
/*Leave the leisure power save mode.*/
450-
void rtl_lps_leave(struct ieee80211_hw *hw)
448+
/* Interrupt safe routine to leave the leisure power save mode.*/
449+
static void rtl_lps_leave_core(struct ieee80211_hw *hw)
451450
{
452451
struct rtl_priv *rtlpriv = rtl_priv(hw);
453452
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -477,7 +476,6 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
477476
}
478477
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
479478
}
480-
EXPORT_SYMBOL(rtl_lps_leave);
481479

482480
/* For sw LPS*/
483481
void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
@@ -670,12 +668,34 @@ void rtl_lps_change_work_callback(struct work_struct *work)
670668
struct rtl_priv *rtlpriv = rtl_priv(hw);
671669

672670
if (rtlpriv->enter_ps)
673-
rtl_lps_enter(hw);
671+
rtl_lps_enter_core(hw);
674672
else
675-
rtl_lps_leave(hw);
673+
rtl_lps_leave_core(hw);
676674
}
677675
EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
678676

677+
void rtl_lps_enter(struct ieee80211_hw *hw)
678+
{
679+
struct rtl_priv *rtlpriv = rtl_priv(hw);
680+
681+
if (!in_interrupt())
682+
return rtl_lps_enter_core(hw);
683+
rtlpriv->enter_ps = true;
684+
schedule_work(&rtlpriv->works.lps_change_work);
685+
}
686+
EXPORT_SYMBOL_GPL(rtl_lps_enter);
687+
688+
void rtl_lps_leave(struct ieee80211_hw *hw)
689+
{
690+
struct rtl_priv *rtlpriv = rtl_priv(hw);
691+
692+
if (!in_interrupt())
693+
return rtl_lps_leave_core(hw);
694+
rtlpriv->enter_ps = false;
695+
schedule_work(&rtlpriv->works.lps_change_work);
696+
}
697+
EXPORT_SYMBOL_GPL(rtl_lps_leave);
698+
679699
void rtl_swlps_wq_callback(void *data)
680700
{
681701
struct rtl_works *rtlworks = container_of_dwork_rtl(data,

0 commit comments

Comments
 (0)