@@ -214,8 +214,9 @@ struct wpan_phy {
/* the network namespace this phy lives in currently */
possible_net_t _net;
- /* Transmission monitoring */
+ /* Transmission monitoring and control */
atomic_t ongoing_txs;
+ atomic_t hold_txs;
char priv[] __aligned(NETDEV_ALIGN);
};
@@ -46,6 +46,7 @@ static int ieee802154_suspend(struct wpan_phy *wpan_phy)
if (!local->open_count)
goto suspend;
+ atomic_inc(&wpan_phy->hold_txs);
ieee802154_stop_queue(&local->hw);
synchronize_net();
@@ -72,7 +73,8 @@ static int ieee802154_resume(struct wpan_phy *wpan_phy)
return ret;
wake_up:
- ieee802154_wake_queue(&local->hw);
+ if (!atomic_dec_and_test(&wpan_phy->hold_txs))
+ ieee802154_wake_queue(&local->hw);
local->suspended = false;
return 0;
}
@@ -190,6 +190,11 @@ void mac802154_unlock_table(struct net_device *dev);
int mac802154_wpan_update_llsec(struct net_device *dev);
+static inline bool mac802154_queue_is_stopped(struct ieee802154_local *local)
+{
+ return atomic_read(&local->phy->hold_txs);
+}
+
/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
@@ -43,7 +43,9 @@ void ieee802154_xmit_sync_worker(struct work_struct *work)
err_tx:
/* Restart the netif queue on each sub_if_data object. */
- ieee802154_wake_queue(&local->hw);
+ if (!mac802154_queue_is_stopped(local))
+ ieee802154_wake_queue(&local->hw);
+
kfree_skb(skb);
atomic_dec(&local->phy->ongoing_txs);
netdev_dbg(dev, "transmission failed\n");
@@ -87,7 +89,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
ret = drv_xmit_async(local, skb);
if (ret) {
- ieee802154_wake_queue(&local->hw);
+ if (!mac802154_queue_is_stopped(local))
+ ieee802154_wake_queue(&local->hw);
goto err_tx;
}
@@ -87,7 +87,12 @@ ieee802154_wakeup_after_xmit_done(struct ieee802154_hw *hw, bool ifs_handling,
static void ieee802154_xmit_end(struct ieee802154_hw *hw, bool ifs_handling,
unsigned int skb_len)
{
- ieee802154_wakeup_after_xmit_done(hw, ifs_handling, skb_len);
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ /* Avoid waking-up a transmit queue which needs to remain stopped */
+ if (!mac802154_queue_is_stopped(local))
+ ieee802154_wakeup_after_xmit_done(hw, ifs_handling, skb_len);
+
atomic_dec(&hw->phy->ongoing_txs);
}
Let's create a hold_txs atomic variable and increment/decrement it when relevant. A current use is during a suspend. Very soon we will also use this feature during scans. When the variable is incremented, any further call to helpers usually waking up the queue will skip this part because it is the core responsibility to wake up the queue when relevant. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> --- include/net/cfg802154.h | 3 ++- net/mac802154/cfg.c | 4 +++- net/mac802154/ieee802154_i.h | 5 +++++ net/mac802154/tx.c | 7 +++++-- net/mac802154/util.c | 7 ++++++- 5 files changed, 21 insertions(+), 5 deletions(-)