Skip to content

Commit

Permalink
net: rtlwifi: Replace in_interrupt() for context detection
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sebastian Andrzej Siewior authored and David S. Miller committed Sep 29, 2020
1 parent e741751 commit 920872e
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 19 deletions.
8 changes: 4 additions & 4 deletions drivers/net/wireless/realtek/rtlwifi/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
;
Expand Down
12 changes: 8 additions & 4 deletions drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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;
}
}
Expand All @@ -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);
}
}

Expand Down
6 changes: 3 additions & 3 deletions drivers/net/wireless/realtek/rtlwifi/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/realtek/rtlwifi/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/wireless/realtek/rtlwifi/ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/realtek/rtlwifi/ps.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 920872e

Please sign in to comment.