Commit 920872e0 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by David S. Miller

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: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Acked-by: default avatarKalle Valo <kvalo@codeaurora.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e741751b
...@@ -1456,7 +1456,7 @@ static void setup_special_tx(struct rtl_priv *rtlpriv, struct rtl_ps_ctl *ppsc, ...@@ -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()) if (rtlpriv->cfg->ops->get_btc_status())
rtlpriv->btcoexist.btc_ops->btc_special_packet_notify( rtlpriv->btcoexist.btc_ops->btc_special_packet_notify(
rtlpriv, type); rtlpriv, type);
rtl_lps_leave(hw); rtl_lps_leave(hw, false);
ppsc->last_delaylps_stamp_jiffies = jiffies; 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, ...@@ -1546,7 +1546,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx,
if (is_tx) { if (is_tx) {
rtlpriv->ra.is_special_data = true; rtlpriv->ra.is_special_data = true;
rtl_lps_leave(hw); rtl_lps_leave(hw, false);
ppsc->last_delaylps_stamp_jiffies = jiffies; ppsc->last_delaylps_stamp_jiffies = jiffies;
setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL); setup_special_tx(rtlpriv, ppsc, PACKET_EAPOL);
...@@ -2147,9 +2147,9 @@ static void rtl_watchdog_wq_callback(struct work_struct *work) ...@@ -2147,9 +2147,9 @@ static void rtl_watchdog_wq_callback(struct work_struct *work)
if (rtlpriv->link_info.num_rx_inperiod + if (rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod > 8 || rtlpriv->link_info.num_tx_inperiod > 8 ||
rtlpriv->link_info.num_rx_inperiod > 2) rtlpriv->link_info.num_rx_inperiod > 2)
rtl_lps_leave(hw); rtl_lps_leave(hw, true);
else else
rtl_lps_enter(hw); rtl_lps_enter(hw, true);
label_lps_done: label_lps_done:
; ;
......
...@@ -285,7 +285,8 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist) ...@@ -285,7 +285,8 @@ static void halbtc_leave_lps(struct btc_coexist *btcoexist)
btcoexist->bt_info.bt_ctrl_lps = true; btcoexist->bt_info.bt_ctrl_lps = true;
btcoexist->bt_info.bt_lps_on = false; 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) static void halbtc_enter_lps(struct btc_coexist *btcoexist)
...@@ -306,7 +307,8 @@ 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_ctrl_lps = true;
btcoexist->bt_info.bt_lps_on = 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) static void halbtc_normal_lps(struct btc_coexist *btcoexist)
...@@ -317,7 +319,8 @@ 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) { if (btcoexist->bt_info.bt_ctrl_lps) {
btcoexist->bt_info.bt_lps_on = false; 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; btcoexist->bt_info.bt_ctrl_lps = false;
} }
} }
...@@ -328,7 +331,8 @@ static void halbtc_pre_normal_lps(struct btc_coexist *btcoexist) ...@@ -328,7 +331,8 @@ static void halbtc_pre_normal_lps(struct btc_coexist *btcoexist)
if (btcoexist->bt_info.bt_ctrl_lps) { if (btcoexist->bt_info.bt_ctrl_lps) {
btcoexist->bt_info.bt_lps_on = false; 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);
} }
} }
......
...@@ -544,7 +544,7 @@ static int rtl_op_suspend(struct ieee80211_hw *hw, ...@@ -544,7 +544,7 @@ static int rtl_op_suspend(struct ieee80211_hw *hw,
rtlhal->driver_is_goingto_unload = true; rtlhal->driver_is_goingto_unload = true;
rtlhal->enter_pnp_sleep = true; rtlhal->enter_pnp_sleep = true;
rtl_lps_leave(hw); rtl_lps_leave(hw, true);
rtl_op_stop(hw); rtl_op_stop(hw);
device_set_wakeup_enable(wiphy_dev(hw->wiphy), true); device_set_wakeup_enable(wiphy_dev(hw->wiphy), true);
return 0; return 0;
...@@ -1151,7 +1151,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, ...@@ -1151,7 +1151,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mstatus = RT_MEDIA_DISCONNECT; mstatus = RT_MEDIA_DISCONNECT;
if (mac->link_state == MAC80211_LINKED) 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) if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE); rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK; mac->link_state = MAC80211_NOLINK;
...@@ -1448,7 +1448,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw, ...@@ -1448,7 +1448,7 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw,
} }
if (mac->link_state == MAC80211_LINKED) { if (mac->link_state == MAC80211_LINKED) {
rtl_lps_leave(hw); rtl_lps_leave(hw, true);
mac->link_state = MAC80211_LINKED_SCANNING; mac->link_state = MAC80211_LINKED_SCANNING;
} else { } else {
rtl_ips_nic_on(hw); rtl_ips_nic_on(hw);
......
...@@ -621,7 +621,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) ...@@ -621,7 +621,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
if (((rtlpriv->link_info.num_rx_inperiod + if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) || rtlpriv->link_info.num_tx_inperiod) > 8) ||
rtlpriv->link_info.num_rx_inperiod > 2) 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, 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) ...@@ -874,7 +874,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
if (((rtlpriv->link_info.num_rx_inperiod + if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) || rtlpriv->link_info.num_tx_inperiod) > 8) ||
rtlpriv->link_info.num_rx_inperiod > 2) rtlpriv->link_info.num_rx_inperiod > 2)
rtl_lps_leave(hw); rtl_lps_leave(hw, false);
skb = new_skb; skb = new_skb;
no_new: no_new:
if (rtlpriv->use_new_trx_flow) { if (rtlpriv->use_new_trx_flow) {
......
...@@ -653,22 +653,22 @@ void rtl_lps_change_work_callback(struct work_struct *work) ...@@ -653,22 +653,22 @@ void rtl_lps_change_work_callback(struct work_struct *work)
} }
EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback); 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); struct rtl_priv *rtlpriv = rtl_priv(hw);
if (!in_interrupt()) if (may_block)
return rtl_lps_enter_core(hw); return rtl_lps_enter_core(hw);
rtlpriv->enter_ps = true; rtlpriv->enter_ps = true;
schedule_work(&rtlpriv->works.lps_change_work); schedule_work(&rtlpriv->works.lps_change_work);
} }
EXPORT_SYMBOL_GPL(rtl_lps_enter); 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); struct rtl_priv *rtlpriv = rtl_priv(hw);
if (!in_interrupt()) if (may_block)
return rtl_lps_leave_core(hw); return rtl_lps_leave_core(hw);
rtlpriv->enter_ps = false; rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work); schedule_work(&rtlpriv->works.lps_change_work);
......
...@@ -11,8 +11,8 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw); ...@@ -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_off(struct ieee80211_hw *hw);
void rtl_ips_nic_on(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_ips_nic_off_wq_callback(struct work_struct *work);
void rtl_lps_enter(struct ieee80211_hw *hw); void rtl_lps_enter(struct ieee80211_hw *hw, bool may_block);
void rtl_lps_leave(struct ieee80211_hw *hw); void rtl_lps_leave(struct ieee80211_hw *hw, bool may_block);
void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode); void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment