Re: [PATCH 4.9 003/116] rtlwifi: Fix enter/exit power_save

From: Larry Finger
Date: Tue Jan 10 2017 - 20:53:58 EST


On 01/10/2017 11:40 AM, Dmitry Osipenko wrote:
Hello, this patch causes a kernel panic with the rtl8192cu driver.

<6>[ 20.847025] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
<1>[ 21.699551] BUG: unable to handle kernel NULL pointer dereference at
0000000000000048
<1>[ 21.699626] IP: [<ffffffffc037de33>] rtl_lps_leave+0x13/0x40 [rtlwifi]
<4>[ 21.699681] PGD 20cf47067
<4>[ 21.699702] PUD 20cf42067
<4>[ 21.699725] PMD 0
<4>[ 21.699732]
<4>[ 21.699759] Oops: 0000 [#1] PREEMPT SMP
<4>[ 21.699794] Modules linked in: rtl8192cu rtl_usb rtl8192c_common rtlwifi
snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec
snd_hwdep snd_hda_core dm_mod thermal
<4>[ 21.699985] CPU: 0 PID: 2656 Comm: ntpdate Not tainted 4.9.2 #1
<4>[ 21.700036] Hardware name: Gigabyte Technology Co., Ltd. To be filled by
O.E.M./Z77-DS3H, BIOS F11a 11/13/2013
<4>[ 21.700118] task: ffff9ce2509ca4c0 task.stack: ffffa41003eac000
<4>[ 21.700168] RIP: 0010:[<ffffffffc037de33>] [<ffffffffc037de33>]
rtl_lps_leave+0x13/0x40 [rtlwifi]
<4>[ 21.700250] RSP: 0018:ffffa41003eaf520 EFLAGS: 00010206
<4>[ 21.700296] RAX: 0000000080000802 RBX: ffff9ce251371420 RCX: ffff9ce254ff4640
<4>[ 21.700356] RDX: 0000000000000806 RSI: ffff9ce25137afb8 RDI: 0000000000000000
<4>[ 21.700416] RBP: ffff9ce25137afb8 R08: ffffffffc0382d00 R09: ffff9ce254e38c31
<4>[ 21.700475] R10: 0000000000000000 R11: ffff9ce251370700 R12: 0000000000000000
<4>[ 21.700535] R13: 0000000000000000 R14: ffff9ce251371420 R15: ffff9ce254e38c00
<4>[ 21.700595] FS: 00007f22f6da8700(0000) GS:ffff9ce25f200000(0000)
knlGS:0000000000000000
<4>[ 21.700662] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[ 21.700711] CR2: 0000000000000048 CR3: 000000020cf65000 CR4: 00000000001406f0
<4>[ 21.700770] Stack:
<4>[ 21.700790] ffffffffc0375088 0000000000000008 ffff9ce251370700
0000000000000001
<4>[ 21.700867] ffffffffc03751c7 0100000000000000 ffffa41003eaf618
ffff9ce252b5a800
<4>[ 21.700944] 0000000000000000 ffff9ce251371420 0000000000000000
ffff9ce254e38c00
<4>[ 21.701021] Call Trace:
<4>[ 21.701048] [<ffffffffc0375088>] ? setup_arp_tx.isra.20+0x48/0x60 [rtlwifi]
<4>[ 21.701110] [<ffffffffc03751c7>] ? rtl_is_special_data+0x127/0x210 [rtlwifi]
<4>[ 21.701171] [<ffffffffc037e8c7>] ? rtl_get_rate+0x97/0x210 [rtlwifi]
<4>[ 21.701228] [<ffffffff9a87deb6>] ? rate_control_get_rate+0xb6/0x140
<4>[ 21.701283] [<ffffffff9a88cf30>] ? ieee80211_tx_h_rate_ctrl+0x1e0/0x3f0
<4>[ 21.701340] [<ffffffff9a88fcc2>] ? invoke_tx_handlers_early+0x222/0x5a0
<4>[ 21.701397] [<ffffffff9a89186e>] ? ieee80211_tx+0x6e/0x130
<4>[ 21.701446] [<ffffffff9a892661>] ? __ieee80211_subif_start_xmit+0x4d1/0x9d0
<4>[ 21.701506] [<ffffffff9a741874>] ? nf_conntrack_tuple_taken+0x1c4/0x1d0
<4>[ 21.701565] [<ffffffff9a749779>] ? get_unique_tuple+0xe9/0x510
<4>[ 21.701617] [<ffffffff9a892b6c>] ? ieee80211_subif_start_xmit+0xc/0x10
<4>[ 21.701675] [<ffffffff9a6e606a>] ? dev_hard_start_xmit+0x9a/0x210
<4>[ 21.701729] [<ffffffff9a708a46>] ? sch_direct_xmit+0xd6/0x1a0
<4>[ 21.701780] [<ffffffff9a6e66d2>] ? __dev_queue_xmit+0x422/0x620
<4>[ 21.701832] [<ffffffff9a79859f>] ? arp_xmit+0x9f/0xb0
<4>[ 21.701878] [<ffffffff9a798220>] ? arp_create+0x250/0x250
<4>[ 21.701926] [<ffffffff9a7986ee>] ? arp_solicit+0xee/0x240
<4>[ 21.701974] [<ffffffff9a1335cd>] ? mod_timer+0x1ad/0x360
<4>[ 21.702022] [<ffffffff9a6edf12>] ? neigh_probe+0x42/0x60
<4>[ 21.702071] [<ffffffff9a6ef2f2>] ? __neigh_event_send+0x1e2/0x230
<4>[ 21.702124] [<ffffffff9a6ef520>] ? neigh_resolve_output+0x120/0x1b0
<4>[ 21.702179] [<ffffffff9a76ac37>] ? ip_finish_output2+0x127/0x300
<4>[ 21.702231] [<ffffffff9a76c524>] ? ip_output+0x64/0x100
<4>[ 21.702277] [<ffffffff9a76b9b0>] ?
__ip_flush_pending_frames.isra.46+0x80/0x80
<4>[ 21.702339] [<ffffffff9a76ceb5>] ? ip_send_skb+0x15/0x40
<4>[ 21.702386] [<ffffffff9a79308f>] ? udp_send_skb+0x15f/0x240
<4>[ 21.702436] [<ffffffff9a7944e6>] ? udp_sendmsg+0x2b6/0x840
<4>[ 21.702485] [<ffffffff9a0e10ba>] ? __local_bh_enable_ip+0x8a/0x90
<4>[ 21.702538] [<ffffffff9a76ac4a>] ? ip_finish_output2+0x13a/0x300
<4>[ 21.702592] [<ffffffff9a1fda33>] ? rw_copy_check_uvector+0x53/0x110
<4>[ 21.702648] [<ffffffff9a382b37>] ? import_iovec+0x27/0xc0
<4>[ 21.702698] [<ffffffff9a6c8d01>] ? ___sys_sendmsg+0x111/0x2a0
<4>[ 21.702749] [<ffffffff9a20fa50>] ? poll_select_copy_remaining+0x130/0x130
<4>[ 21.702808] [<ffffffff9a7944f5>] ? udp_sendmsg+0x2c5/0x840
<4>[ 21.702857] [<ffffffff9a79b2b1>] ? __ip_dev_find+0x111/0x130
<4>[ 21.702908] [<ffffffff9a764885>] ? __ip_route_output_key_hash+0x2c5/0x870
<4>[ 21.702968] [<ffffffff9a6c94e9>] ? __sys_sendmmsg+0x89/0x160
<4>[ 21.703018] [<ffffffff9a6c8490>] ? SYSC_connect+0x50/0xa0
<4>[ 21.703066] [<ffffffff9a6c626a>] ? sock_alloc_file+0x9a/0x110
<4>[ 21.703119] [<ffffffff9a6c95ce>] ? SyS_sendmmsg+0xe/0x20
<4>[ 21.703166] [<ffffffff9a8c8837>] ? entry_SYSCALL_64_fastpath+0x1a/0xa9
<4>[ 21.703222] Code: 05 e9 32 ff ff ff e9 2d fe ff ff 0f 1f 00 66 2e 0f 1f 84
00 00 00 00 00 0f 1f 44 00 00 65 8b 05 24 f4 c8 3f a9 00 ff 1f 00 74 23 <48> 8b
57 48 bf 40 00 00 00 48 8b 35 3d ba b7 da c6 82 ad a2 00
<1>[ 21.709488] RIP [<ffffffffc037de33>] rtl_lps_leave+0x13/0x40 [rtlwifi]
<4>[ 21.712533] RSP <ffffa41003eaf520>
<4>[ 21.715589] CR2: 0000000000000048
<4>[ 21.735721] ---[ end trace f6ce402401b0b86a ]---

4.9-stable review patch. If anyone has any objections, please let me know.

------------------

From: Larry Finger <Larry.Finger@xxxxxxxxxxxx>

commit ba9f93f82abafe2552eac942ebb11c2df4f8dd7f upstream.

In commit a5ffbe0a1993 ("rtlwifi: Fix scheduling while atomic bug") and
commit a269913c52ad ("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: a269913c52ad ("rtlwifi: Rework rtl_lps_leave() and rtl_lps_enter() to use work queue")
Reported-by: Ping-Ke Shih <pkshih@xxxxxxxxxxx>
Signed-off-by: Larry Finger <Larry.Finger@xxxxxxxxxxxx>
Signed-off-by: Kalle Valo <kvalo@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/net/wireless/realtek/rtlwifi/base.c | 8 +++---
drivers/net/wireless/realtek/rtlwifi/core.c | 9 ++-----
drivers/net/wireless/realtek/rtlwifi/pci.c | 14 +++-------
drivers/net/wireless/realtek/rtlwifi/ps.c | 36 +++++++++++++++++++++-------
4 files changed, 40 insertions(+), 27 deletions(-)

--- a/drivers/net/wireless/realtek/rtlwifi/base.c
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
@@ -1303,12 +1303,13 @@ EXPORT_SYMBOL_GPL(rtl_action_proc);

static void setup_arp_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc)
{
+ struct ieee80211_hw *hw = rtlpriv->hw;
+
rtlpriv->ra.is_special_data = true;
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
rtlpriv, 1);
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
+ rtl_lps_leave(hw);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}

@@ -1381,8 +1382,7 @@ u8 rtl_is_special_data(struct ieee80211_

if (is_tx) {
rtlpriv->ra.is_special_data = true;
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
+ rtl_lps_leave(hw);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}

--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -1150,10 +1150,8 @@ static void rtl_op_bss_info_changed(stru
} else {
mstatus = RT_MEDIA_DISCONNECT;

- if (mac->link_state == MAC80211_LINKED) {
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
- }
+ if (mac->link_state == MAC80211_LINKED)
+ rtl_lps_leave(hw);
if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK;
@@ -1431,8 +1429,7 @@ static void rtl_op_sw_scan_start(struct
}

if (mac->link_state == MAC80211_LINKED) {
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
+ rtl_lps_leave(hw);
mac->link_state = MAC80211_LINKED_SCANNING;
} else {
rtl_ips_nic_on(hw);
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -663,11 +663,9 @@ tx_status_ok:
}

if (((rtlpriv->link_info.num_rx_inperiod +
- rtlpriv->link_info.num_tx_inperiod) > 8) ||
- (rtlpriv->link_info.num_rx_inperiod > 2)) {
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
- }
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2))
+ rtl_lps_leave(hw);
}

static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
@@ -918,10 +916,8 @@ new_trx_end:
}
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
- (rtlpriv->link_info.num_rx_inperiod > 2)) {
- rtlpriv->enter_ps = false;
- schedule_work(&rtlpriv->works.lps_change_work);
- }
+ (rtlpriv->link_info.num_rx_inperiod > 2))
+ rtl_lps_leave(hw);
skb = new_skb;
no_new:
if (rtlpriv->use_new_trx_flow) {
--- a/drivers/net/wireless/realtek/rtlwifi/ps.c
+++ b/drivers/net/wireless/realtek/rtlwifi/ps.c
@@ -407,8 +407,8 @@ void rtl_lps_set_psmode(struct ieee80211
}
}

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

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

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

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

if (rtlpriv->enter_ps)
- rtl_lps_enter(hw);
+ rtl_lps_enter_core(hw);
else
- rtl_lps_leave(hw);
+ rtl_lps_leave_core(hw);
}
EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);

+void rtl_lps_enter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (!in_interrupt())
+ return rtl_lps_enter_core(hw);
+ rtlpriv->enter_ps = true;
+ schedule_work(&rtlpriv->works.lps_change_work);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_enter);
+
+void rtl_lps_leave(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (!in_interrupt())
+ return rtl_lps_leave_core(hw);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_leave);
+
void rtl_swlps_wq_callback(void *data)
{
struct rtl_works *rtlworks = container_of_dwork_rtl(data,

The fix is being merged into mainline. The reference is http://marc.info/?l=linux-wireless&m=148234081512703&w=2.

Larry