net: rtlwifi: Replace in_interrupt() for context detection
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Tue, 29 Sep 2020 20:25:45 +0000 (22:25 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 29 Sep 2020 21:02:55 +0000 (14:02 -0700)
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>
drivers/net/wireless/realtek/rtlwifi/base.c
drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
drivers/net/wireless/realtek/rtlwifi/core.c
drivers/net/wireless/realtek/rtlwifi/pci.c
drivers/net/wireless/realtek/rtlwifi/ps.c
drivers/net/wireless/realtek/rtlwifi/ps.h

index c08ec227650f4acb47226eac426733bcb465c2c5..6e8bd99e8911ddec8cde8f9d8603c800580634b2 100644 (file)
@@ -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:
                ;
index fa4486669d9a3c061affc0742c77afb5ed385e97..2c05369b79e4dd25b9d821ada121825ed36eb8c7 100644 (file)
@@ -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);
        }
 }
 
index 2529b6e0fd767ff3c3110329bd992d956acf9054..a7259dbc953da7a0158b6f8398ef8eff4df02e28 100644 (file)
@@ -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);
index d9f901111e58c50f31bb961b92525ace3dbd0b0a..3776495fd9d03f024abb5a6487af1147397358d9 100644 (file)
@@ -621,7 +621,7 @@ tx_status_ok:
        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 @@ new_trx_end:
                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) {
index 377af66d6131fa00c3dbc28cbbc0c4d8f5a55bf7..f99882255d4800b7bc462e6314dca2e4acd769d3 100644 (file)
@@ -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);
index 87aacf8c753f0fb05c6bfd4d4b86ebe07fd10793..b37a929def825df9e66b6e510a2bcc6c19935ad3 100644 (file)
@@ -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);