Hi Alex, aahringo@xxxxxxxxxx wrote on Tue, 17 May 2022 20:37:38 -0400: > Hi, > > On Tue, May 17, 2022 at 12:35 PM Miquel Raynal > <miquel.raynal@xxxxxxxxxxx> wrote: > > > > Create a hold_txs atomic variable and increment/decrement it when > > relevant, ie. when we want to hold the queue or release it: currently > > all the "stopped" situations are suitable, but very soon we will more > > extensively use this feature for MLME purposes. > > > > Upon release, the atomic counter is decremented and checked. If it is > > back to 0, then the netif queue gets woken up. This makes the whole > > process fully transparent, provided that all the users of > > ieee802154_wake/stop_queue() now call ieee802154_hold/release_queue() > > instead. > > > > In no situation individual drivers should call any of these helpers > > manually in order to avoid messing with the counters. There are other > > functions more suited for this purpose which have been introduced, such > > as the _xmit_complete() and _xmit_error() helpers which will handle all > > that for them. > > > > One advantage is that, as no more drivers call the stop/wake helpers > > directly, we can safely stop exporting them and only declare the > > hold/release ones in a header only accessible to the core. > > > > Signed-off-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx> > > --- > > include/net/cfg802154.h | 6 +++-- > > include/net/mac802154.h | 27 ------------------- > > net/ieee802154/core.c | 2 ++ > > net/mac802154/cfg.c | 4 +-- > > net/mac802154/ieee802154_i.h | 19 +++++++++++++ > > net/mac802154/tx.c | 6 ++--- > > net/mac802154/util.c | 52 +++++++++++++++++++++++++++++++----- > > 7 files changed, 75 insertions(+), 41 deletions(-) > > > > diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h > > index 473ebcb9b155..7a191418f258 100644 > > --- a/include/net/cfg802154.h > > +++ b/include/net/cfg802154.h > > @@ -11,7 +11,7 @@ > > > > #include <linux/ieee802154.h> > > #include <linux/netdevice.h> > > -#include <linux/mutex.h> > > +#include <linux/spinlock.h> > > #include <linux/bug.h> > > > > #include <net/nl802154.h> > > @@ -214,8 +214,10 @@ struct wpan_phy { > > /* the network namespace this phy lives in currently */ > > possible_net_t _net; > > > > - /* Transmission monitoring */ > > + /* Transmission monitoring and control */ > > + spinlock_t queue_lock; > > atomic_t ongoing_txs; > > + atomic_t hold_txs; > > > > char priv[] __aligned(NETDEV_ALIGN); > > }; > > diff --git a/include/net/mac802154.h b/include/net/mac802154.h > > index bdac0ddbdcdb..357d25ef627a 100644 > > --- a/include/net/mac802154.h > > +++ b/include/net/mac802154.h > > @@ -460,33 +460,6 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw); > > */ > > void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, > > u8 lqi); > > -/** > > - * ieee802154_wake_queue - wake ieee802154 queue > > - * @hw: pointer as obtained from ieee802154_alloc_hw(). > > - * > > - * Tranceivers usually have either one transmit framebuffer or one framebuffer > > - * for both transmitting and receiving. Hence, the core currently only handles > > - * one frame at a time for each phy, which means we had to stop the queue to > > - * avoid new skb to come during the transmission. The queue then needs to be > > - * woken up after the operation. > > - * > > - * Drivers should use this function instead of netif_wake_queue. > > - */ > > -void ieee802154_wake_queue(struct ieee802154_hw *hw); > > - > > -/** > > - * ieee802154_stop_queue - stop ieee802154 queue > > - * @hw: pointer as obtained from ieee802154_alloc_hw(). > > - * > > - * Tranceivers usually have either one transmit framebuffer or one framebuffer > > - * for both transmitting and receiving. Hence, the core currently only handles > > - * one frame at a time for each phy, which means we need to tell upper layers to > > - * stop giving us new skbs while we are busy with the transmitted one. The queue > > - * must then be stopped before transmitting. > > - * > > - * Drivers should use this function instead of netif_stop_queue. > > - */ > > -void ieee802154_stop_queue(struct ieee802154_hw *hw); > > > > /** > > * ieee802154_xmit_complete - frame transmission complete > > diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c > > index de259b5170ab..47a4de6df88b 100644 > > --- a/net/ieee802154/core.c > > +++ b/net/ieee802154/core.c > > @@ -130,6 +130,8 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) > > > > init_waitqueue_head(&rdev->dev_wait); > > > > + spin_lock_init(&rdev->wpan_phy.queue_lock); > > + > > return &rdev->wpan_phy; > > } > > EXPORT_SYMBOL(wpan_phy_new); > > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c > > index 1e4a9f74ed43..b51100fd9e3f 100644 > > --- a/net/mac802154/cfg.c > > +++ b/net/mac802154/cfg.c > > @@ -46,7 +46,7 @@ static int ieee802154_suspend(struct wpan_phy *wpan_phy) > > if (!local->open_count) > > goto suspend; > > > > - ieee802154_stop_queue(&local->hw); > > + ieee802154_hold_queue(local); > > synchronize_net(); > > > > /* stop hardware - this must stop RX */ > > @@ -72,7 +72,7 @@ static int ieee802154_resume(struct wpan_phy *wpan_phy) > > return ret; > > > > wake_up: > > - ieee802154_wake_queue(&local->hw); > > + ieee802154_release_queue(local); > > local->suspended = false; > > return 0; > > } > > diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h > > index a8b7b9049f14..0c7ff9e0b632 100644 > > --- a/net/mac802154/ieee802154_i.h > > +++ b/net/mac802154/ieee802154_i.h > > @@ -130,6 +130,25 @@ netdev_tx_t > > ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); > > enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer); > > > > +/** > > + * ieee802154_hold_queue - hold ieee802154 queue > > + * @local: main mac object > > + * > > + * Hold a queue by incrementing an atomic counter and requesting the netif > > + * queues to be stopped. The queues cannot be woken up while the counter has not > > + * been reset with as any ieee802154_release_queue() calls as needed. > > + */ > > +void ieee802154_hold_queue(struct ieee802154_local *local); > > + > > +/** > > + * ieee802154_release_queue - release ieee802154 queue > > + * @local: main mac object > > + * > > + * Release a queue which is held by decrementing an atomic counter and wake it > > + * up only if the counter reaches 0. > > + */ > > +void ieee802154_release_queue(struct ieee802154_local *local); > > + > > /* MIB callbacks */ > > void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); > > > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c > > index 33f64ecd96c7..6a53c83cf039 100644 > > --- a/net/mac802154/tx.c > > +++ b/net/mac802154/tx.c > > @@ -43,7 +43,7 @@ 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); > > + ieee802154_release_queue(local); > > atomic_dec(&local->phy->ongoing_txs); > > kfree_skb(skb); > > netdev_dbg(dev, "transmission failed\n"); > > @@ -75,7 +75,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb) > > } > > > > /* Stop the netif queue on each sub_if_data object. */ > > - ieee802154_stop_queue(&local->hw); > > + ieee802154_hold_queue(local); > > atomic_inc(&local->phy->ongoing_txs); > > > > /* Drivers should preferably implement the async callback. In some rare > > @@ -99,7 +99,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb) > > return NETDEV_TX_OK; > > > > err_wake_netif_queue: > > - ieee802154_wake_queue(&local->hw); > > + ieee802154_release_queue(local); > > atomic_dec(&local->phy->ongoing_txs); > > err_free_skb: > > kfree_skb(skb); > > diff --git a/net/mac802154/util.c b/net/mac802154/util.c > > index 76dc663e2af4..6176cc40df91 100644 > > --- a/net/mac802154/util.c > > +++ b/net/mac802154/util.c > > @@ -13,7 +13,17 @@ > > /* privid for wpan_phys to determine whether they belong to us or not */ > > const void *const mac802154_wpan_phy_privid = &mac802154_wpan_phy_privid; > > > > -void ieee802154_wake_queue(struct ieee802154_hw *hw) > > +/** > > + * ieee802154_wake_queue - wake ieee802154 queue > > + * @local: main mac object > > + * > > + * Tranceivers usually have either one transmit framebuffer or one framebuffer > > + * for both transmitting and receiving. Hence, the core currently only handles > > + * one frame at a time for each phy, which means we had to stop the queue to > > + * avoid new skb to come during the transmission. The queue then needs to be > > + * woken up after the operation. > > + */ > > +static void ieee802154_wake_queue(struct ieee802154_hw *hw) > > { > > struct ieee802154_local *local = hw_to_local(hw); > > struct ieee802154_sub_if_data *sdata; > > @@ -27,9 +37,18 @@ void ieee802154_wake_queue(struct ieee802154_hw *hw) > > } > > rcu_read_unlock(); > > } > > -EXPORT_SYMBOL(ieee802154_wake_queue); > > > > -void ieee802154_stop_queue(struct ieee802154_hw *hw) > > +/** > > + * ieee802154_stop_queue - stop ieee802154 queue > > + * @local: main mac object > > + * > > + * Tranceivers usually have either one transmit framebuffer or one framebuffer > > + * for both transmitting and receiving. Hence, the core currently only handles > > + * one frame at a time for each phy, which means we need to tell upper layers to > > + * stop giving us new skbs while we are busy with the transmitted one. The queue > > + * must then be stopped before transmitting. > > + */ > > +static void ieee802154_stop_queue(struct ieee802154_hw *hw) > > { > > struct ieee802154_local *local = hw_to_local(hw); > > struct ieee802154_sub_if_data *sdata; > > @@ -43,14 +62,33 @@ void ieee802154_stop_queue(struct ieee802154_hw *hw) > > } > > rcu_read_unlock(); > > } > > -EXPORT_SYMBOL(ieee802154_stop_queue); > > + > > +void ieee802154_hold_queue(struct ieee802154_local *local) > > +{ > > + unsigned long flags; > > + > > + spin_lock_irqsave(&local->phy->queue_lock, flags); > > + ieee802154_stop_queue(&local->hw); > > + atomic_inc(&local->phy->hold_txs); > > + spin_unlock_irqrestore(&local->phy->queue_lock, flags); > > +} > > I think that works, but I would expect something like: > > if (!atomic_fetch_inc(hold_txs)) > ieee802154_stop_queue(&local->hw); I didn't know about the _fetch_ alternative, that looks much better this way!