net: rtlwifi: Replace in_interrupt() for context detection
rtl_lps_enter() and rtl_lps_leave() are using in_interrupt() to detect
whether it is safe to acquire a mutex or if it is required to defer to a
workqueue.
The usage of in_interrupt() in drivers is phased out and Linus clearly
requested that code which changes behaviour depending on context should
either be seperated or the context be conveyed in an argument passed by the
caller, which usually knows the context.
in_interrupt() also is only partially correct because it fails to chose the
correct code path when just preemption or interrupts are disabled.
Add an argument 'may_block' to both functions and adjust the callers to
pass the context information.
The following call chains were analyzed to be safe to block:
rtl_watchdog_wq_callback()
rlf_lps_leave/enter()
rtl_op_suspend()
rtl_lps_leave()
rtl_op_bss_info_changed()
rtl_lps_leave()
rtl_op_sw_scan_start()
rtl_lps_leave()
The following call chains were analyzed to be unsafe to block:
_rtl_pci_interrupt()
_rtl_pci_rx_interrupt()
rtl_lps_leave()
_rtl_pci_interrupt()
_rtl_pci_rx_interrupt()
rtl_is_special_data()
rtl_lps_leave()
_rtl_pci_interrupt()
_rtl_pci_rx_interrupt()
rtl_is_special_data()
setup_special_tx()
rtl_lps_leave()
_rtl_pci_interrupt()
_rtl_pci_tx_isr
rtl_lps_leave()
halbtc_leave_lps()
rtl_lps_leave()
This leaves four callers of rtl_lps_enter/leave() where the analyzis
stopped dead in the maze of several nested pointer based callchains and
lack of rtlwifi hardware to debug this via tracing:
halbtc_leave_lps(), halbtc_enter_lps(), halbtc_normal_lps(),
halbtc_pre_normal_lps()
These four have been cautionally marked to be unable to block which is the
safe option, but the rtwifi wizards should be able to clarify that.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Kalle Valo <kvalo@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
index c08ec22..6e8bd99 100644
--- a/drivers/net/wireless/realtek/rtlwifi/base.c
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
@@ -1456,7 +1456,7 @@ static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc,
if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
rtlpriv, type);
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, false);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1546,7 +1546,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
if (is_tx) {
rtlpriv->ra.is_special_data = true;
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, false);
ppsc->last_delaylps_stamp_jiffies = jiffies;
setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL);
@@ -2147,9 +2147,9 @@ static void rtl_watchdog_wq_callback(struct work_struct *work)
if (rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod > 8 ||
rtlpriv->link_info.num_rx_inperiod > 2)
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, true);
else
- rtl_lps_enter(hw);
+ rtl_lps_enter(hw, true);
label_lps_done:
;
diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
index fa44866..2c05369 100644
--- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
+++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
@@ -285,7 +285,8 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist)
btcoexist->bt_info.bt_ctrl_lps = true;
btcoexist->bt_info.bt_lps_on = false;
- rtl_lps_leave(rtlpriv->mac80211.hw);
+ /* FIXME: Context is unclear. Is it allowed to block? */
+ rtl_lps_leave(rtlpriv->mac80211.hw, false);
}
static void halbtc_enter_lps(struct btc_coexist *btcoexist)
@@ -306,7 +307,8 @@ static void halbtc_enter_lps(struct btc_coexist *btcoexist)
btcoexist->bt_info.bt_ctrl_lps = true;
btcoexist->bt_info.bt_lps_on = true;
- rtl_lps_enter(rtlpriv->mac80211.hw);
+ /* FIXME: Context is unclear. Is it allowed to block? */
+ rtl_lps_enter(rtlpriv->mac80211.hw, false);
}
static void halbtc_normal_lps(struct btc_coexist *btcoexist)
@@ -317,7 +319,8 @@ static void halbtc_normal_lps(struct btc_coexist *btcoexist)
if (btcoexist->bt_info.bt_ctrl_lps) {
btcoexist->bt_info.bt_lps_on = false;
- rtl_lps_leave(rtlpriv->mac80211.hw);
+ /* FIXME: Context is unclear. Is it allowed to block? */
+ rtl_lps_leave(rtlpriv->mac80211.hw, false);
btcoexist->bt_info.bt_ctrl_lps = false;
}
}
@@ -328,7 +331,8 @@ static void halbtc_pre_normal_lps(struct btc_coexist *btcoexist)
if (btcoexist->bt_info.bt_ctrl_lps) {
btcoexist->bt_info.bt_lps_on = false;
- rtl_lps_leave(rtlpriv->mac80211.hw);
+ /* FIXME: Context is unclear. Is it allowed to block? */
+ rtl_lps_leave(rtlpriv->mac80211.hw, false);
}
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
index 2529b6e..a7259db 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -544,7 +544,7 @@ static int rtl_op_suspend(struct ieee80211_hw *hw,
rtlhal->driver_is_goingto_unload = true;
rtlhal->enter_pnp_sleep = true;
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, true);
rtl_op_stop(hw);
device_set_wakeup_enable(wiphy_dev(hw->wiphy), true);
return 0;
@@ -1151,7 +1151,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mstatus = RT_MEDIA_DISCONNECT;
if (mac->link_state == MAC80211_LINKED)
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, true);
if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK;
@@ -1448,7 +1448,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw,
}
if (mac->link_state == MAC80211_LINKED) {
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, true);
mac->link_state = MAC80211_LINKED_SCANNING;
} else {
rtl_ips_nic_on(hw);
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
index d9f9011..3776495 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -621,7 +621,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
rtlpriv->link_info.num_rx_inperiod > 2)
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, false);
}
static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
@@ -874,7 +874,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
rtlpriv->link_info.num_rx_inperiod > 2)
- rtl_lps_leave(hw);
+ rtl_lps_leave(hw, false);
skb = new_skb;
no_new:
if (rtlpriv->use_new_trx_flow) {
diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c
index 377af66..f9988225 100644
--- a/drivers/net/wireless/realtek/rtlwifi/ps.c
+++ b/drivers/net/wireless/realtek/rtlwifi/ps.c
@@ -653,22 +653,22 @@ void rtl_lps_change_work_callback(struct work_struct *work)
}
EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
-void rtl_lps_enter(struct ieee80211_hw *hw)
+void rtl_lps_enter(struct ieee80211_hw *hw, bool may_block)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- if (!in_interrupt())
+ if (may_block)
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)
+void rtl_lps_leave(struct ieee80211_hw *hw, bool may_block)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- if (!in_interrupt())
+ if (may_block)
return rtl_lps_leave_core(hw);
rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work);
diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.h b/drivers/net/wireless/realtek/rtlwifi/ps.h
index 87aacf8..b37a929 100644
--- a/drivers/net/wireless/realtek/rtlwifi/ps.h
+++ b/drivers/net/wireless/realtek/rtlwifi/ps.h
@@ -11,8 +11,8 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw);
void rtl_ips_nic_off(struct ieee80211_hw *hw);
void rtl_ips_nic_on(struct ieee80211_hw *hw);
void rtl_ips_nic_off_wq_callback(struct work_struct *work);
-void rtl_lps_enter(struct ieee80211_hw *hw);
-void rtl_lps_leave(struct ieee80211_hw *hw);
+void rtl_lps_enter(struct ieee80211_hw *hw, bool may_block);
+void rtl_lps_leave(struct ieee80211_hw *hw, bool may_block);
void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode);