2022-01-21 20:51:01

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 00/14] ieee802154: Synchronous Tx API

The idea here is to provide a fully synchronous Tx API and also be able
to be sure that a transfer as finished. This will be used later by
another series.

The first patches create an error helper and then use it in order to
have only two "end of transmission" helpers that are always called.

Then, a bit of cleanup regarding the naming and the locations of certain
peaces of code is done.

Finally, we create a hot and a slow path, add the necessary logic to be
able to track ongoing transfers and when the queue must be kept on hold,
until we finally create a helper to stop emitting after the last
transfer, which we then use to create a synchronous MLME API.

(Caution: I haven't fully tested that part yet, but as Alexander and me
are on very different time slots I prefer to provide this tonight and
eventually fix it tomorrow)

Miquel Raynal (14):
net: ieee802154: Move the logic restarting the queue upon transmission
net: mac802154: Create a transmit error helper
net: ieee802154: at86rf230: Call _xmit_error() when a transmission
fails
net: ieee802154: atusb: Call _xmit_error() when a transmission fails
net: ieee802154: ca8210: Call _xmit_error() when a transmission fails
net: mac802154: Stop exporting ieee802154_wake/stop_queue()
net: mac802154: Rename the synchronous xmit worker
net: mac802154: Rename the main tx_work struct
net: mac802154: Follow the count of ongoing transmissions
net: mac802154: Hold the transmit queue when relevant
net: mac802154: Create a hot tx path
net: mac802154: Add a warning in the hot path
net: mac802154: Introduce a tx queue flushing mechanism
net: mac802154: Introduce a synchronous API for MLME commands

drivers/net/ieee802154/at86rf230.c | 3 +-
drivers/net/ieee802154/atusb.c | 4 +--
drivers/net/ieee802154/ca8210.c | 12 ++++----
include/net/cfg802154.h | 5 ++++
include/net/mac802154.h | 37 +++++++----------------
net/ieee802154/core.c | 1 +
net/mac802154/cfg.c | 5 ++--
net/mac802154/ieee802154_i.h | 35 ++++++++++++++++++++--
net/mac802154/main.c | 2 +-
net/mac802154/tx.c | 48 +++++++++++++++++++++++++-----
net/mac802154/util.c | 34 ++++++++++++++++++---
11 files changed, 132 insertions(+), 54 deletions(-)

--
2.27.0


2022-01-21 20:51:18

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 03/14] net: ieee802154: at86rf230: Call _xmit_error() when a transmission fails

ieee802154_xmit_error() is the right helper to call when a transmission
has failed. Let's use it instead of open-coding it.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/at86rf230.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index ee75505477e8..a39d314fff7e 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -343,8 +343,7 @@ at86rf230_async_error_recover_complete(void *context)
if (ctx->free)
kfree(ctx);

- ieee802154_wake_queue(lp->hw);
- dev_kfree_skb_any(lp->tx_skb);
+ ieee802154_xmit_error(lp->hw, lp->tx_skb, false);
}

static void
--
2.27.0

2022-01-21 20:51:20

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 04/14] net: ieee802154: atusb: Call _xmit_error() when a transmission fails

ieee802154_xmit_error() is the right helper to call when a transmission
has failed. Let's use it instead of open-coding it.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/atusb.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
index 1a56073c1c52..c9664a57e2f0 100644
--- a/drivers/net/ieee802154/atusb.c
+++ b/drivers/net/ieee802154/atusb.c
@@ -271,9 +271,7 @@ static void atusb_tx_done(struct atusb *atusb, u8 seq)
* unlikely case now that seq == expect is then true, but can
* happen and fail with a tx_skb = NULL;
*/
- ieee802154_wake_queue(atusb->hw);
- if (atusb->tx_skb)
- dev_kfree_skb_irq(atusb->tx_skb);
+ ieee802154_xmit_error(atusb->hw, atusb->tx_skb, false);
}
}

--
2.27.0

2022-01-21 20:51:22

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 01/14] net: ieee802154: Move the logic restarting the queue upon transmission

Create a new helper with the logic restarting the queue upon
transmission, so that we can create a second path for error conditions
which can reuse that code easily.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/util.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index f2078238718b..4c06a6bd391a 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -55,8 +55,9 @@ enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer)
return HRTIMER_NORESTART;
}

-void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
- bool ifs_handling)
+static void
+ieee802154_wakeup_after_xmit_done(struct ieee802154_hw *hw, struct sk_buff *skb,
+ bool ifs_handling)
{
if (ifs_handling) {
struct ieee802154_local *local = hw_to_local(hw);
@@ -83,7 +84,12 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
} else {
ieee802154_wake_queue(hw);
}
+}

+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
+ bool ifs_handling)
+{
+ ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
dev_consume_skb_any(skb);
}
EXPORT_SYMBOL(ieee802154_xmit_complete);
--
2.27.0

2022-01-21 20:51:26

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 02/14] net: mac802154: Create a transmit error helper

So far there is only a helper for successful transmission, which led
device drivers to implement their own handling in case of
error. Unfortunately, we really need all the drivers to give the hand
back to the core once they are done in order to be able to build a
proper synchronous API. So let's create a _xmit_error() helper.

Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/mac802154.h | 10 ++++++++++
net/mac802154/util.c | 9 +++++++++
2 files changed, 19 insertions(+)

diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 94b2e3008e77..e7443e1acde8 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -498,4 +498,14 @@ void ieee802154_stop_queue(struct ieee802154_hw *hw);
void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
bool ifs_handling);

+/**
+ * ieee802154_xmit_error - frame transmission failed
+ *
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ * @skb: buffer for transmission
+ * @ifs_handling: indicate interframe space handling
+ */
+void ieee802154_xmit_error(struct ieee802154_hw *hw, struct sk_buff *skb,
+ bool ifs_handling);
+
#endif /* NET_MAC802154_H */
diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index 4c06a6bd391a..8e7e4cf16fc3 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -94,6 +94,15 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
}
EXPORT_SYMBOL(ieee802154_xmit_complete);

+
+void ieee802154_xmit_error(struct ieee802154_hw *hw, struct sk_buff *skb,
+ bool ifs_handling)
+{
+ ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ieee802154_xmit_error);
+
void ieee802154_stop_device(struct ieee802154_local *local)
{
flush_workqueue(local->workqueue);
--
2.27.0

2022-01-21 20:51:26

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 06/14] net: mac802154: Stop exporting ieee802154_wake/stop_queue()

Individual drivers do not necessarily need to call these helpers
manually. There are other functions, more suited for this purpose, that
will do that for them. The advantage is that, as no more drivers call
these, it eases the tracking of the ongoing transfers that we are about
to introduce while keeping the possibility to bypass thse counters from
core code.

Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/mac802154.h | 27 ---------------------------
net/mac802154/ieee802154_i.h | 24 ++++++++++++++++++++++++
net/mac802154/util.c | 2 --
3 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index e7443e1acde8..9e2e2b2cd65e 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 have either one transmit framebuffer or one framebuffer for both
- * transmitting and receiving. Hence, the core 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 have either one transmit framebuffer or one framebuffer for both
- * transmitting and receiving. Hence, the core 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/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 702560acc8ce..97b66088532b 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -128,6 +128,30 @@ 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_wake_queue - wake ieee802154 queue
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ *
+ * Tranceivers have either one transmit framebuffer or one framebuffer for both
+ * transmitting and receiving. Hence, the core 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.
+ */
+void ieee802154_wake_queue(struct ieee802154_hw *hw);
+
+/**
+ * ieee802154_stop_queue - stop ieee802154 queue
+ * @hw: pointer as obtained from ieee802154_alloc_hw().
+ *
+ * Tranceivers have either one transmit framebuffer or one framebuffer for both
+ * transmitting and receiving. Hence, the core 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.
+ */
+void ieee802154_stop_queue(struct ieee802154_hw *hw);
+
/* MIB callbacks */
void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);

diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index 8e7e4cf16fc3..a5424b559239 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -27,7 +27,6 @@ void ieee802154_wake_queue(struct ieee802154_hw *hw)
}
rcu_read_unlock();
}
-EXPORT_SYMBOL(ieee802154_wake_queue);

void ieee802154_stop_queue(struct ieee802154_hw *hw)
{
@@ -43,7 +42,6 @@ void ieee802154_stop_queue(struct ieee802154_hw *hw)
}
rcu_read_unlock();
}
-EXPORT_SYMBOL(ieee802154_stop_queue);

enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer)
{
--
2.27.0

2022-01-21 20:51:29

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 07/14] net: mac802154: Rename the synchronous xmit worker

There are currently two driver hooks: one is synchronous, the other is
not. We cannot rely on driver implementations to provide a synchronous
API (which is related to the bus medium more than a wish to have a
synchronized implementation) so we are going to introduce a sync API
above any kind of driver transmit function. In order to clarify what
this worker is for (synchronous driver implementation), let's rename it
so that people don't get bothered by the fact that their driver does not
make use of the "xmit worker" which is a too generic name.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/ieee802154_i.h | 2 +-
net/mac802154/main.c | 2 +-
net/mac802154/tx.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 97b66088532b..b4882b2d7688 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -121,7 +121,7 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
extern struct ieee802154_mlme_ops mac802154_mlme_wpan;

void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
-void ieee802154_xmit_worker(struct work_struct *work);
+void ieee802154_xmit_sync_worker(struct work_struct *work);
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index f08c34c27ea9..bfd7c431cdea 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -95,7 +95,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)

skb_queue_head_init(&local->skb_queue);

- INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
+ INIT_WORK(&local->tx_work, ieee802154_xmit_sync_worker);

/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index c829e4a75325..97df5985b830 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -22,7 +22,7 @@
#include "ieee802154_i.h"
#include "driver-ops.h"

-void ieee802154_xmit_worker(struct work_struct *work)
+void ieee802154_xmit_sync_worker(struct work_struct *work)
{
struct ieee802154_local *local =
container_of(work, struct ieee802154_local, tx_work);
--
2.27.0

2022-01-21 20:51:32

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 09/14] net: mac802154: Follow the count of ongoing transmissions

In order to create a synchronous API for MLME command purposes, we need
to be able to track the end of the ongoing transmissions. Let's
introduce an atomic variable which is incremented and decremented when
relevant and now at any moment if a there is an ongoing transmission.

Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 3 +++
net/mac802154/tx.c | 3 +++
net/mac802154/util.c | 2 ++
3 files changed, 8 insertions(+)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 0b8b1812cea1..969cae56b000 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -283,6 +283,9 @@ struct wpan_phy {
/* the network namespace this phy lives in currently */
possible_net_t _net;

+ /* Transmission monitoring */
+ atomic_t ongoing_txs;
+
char priv[] __aligned(NETDEV_ALIGN);
};

diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index a01689ddd547..731e86bfe73f 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -45,6 +45,7 @@ void ieee802154_xmit_sync_worker(struct work_struct *work)
/* Restart the netif queue on each sub_if_data object. */
ieee802154_wake_queue(&local->hw);
kfree_skb(skb);
+ atomic_dec(&local->phy->ongoing_txs);
netdev_dbg(dev, "transmission failed\n");
}

@@ -80,6 +81,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
* cases they only provide a sync callback which we will use as a
* fallback.
*/
+ atomic_inc(&local->phy->ongoing_txs);
if (local->ops->xmit_async) {
unsigned int len = skb->len;

@@ -99,6 +101,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
return NETDEV_TX_OK;

err_tx:
+ atomic_dec(&local->phy->ongoing_txs);
kfree_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index a5424b559239..ae405d995868 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -89,6 +89,7 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
{
ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
dev_consume_skb_any(skb);
+ atomic_dec(&hw->phy->ongoing_txs);
}
EXPORT_SYMBOL(ieee802154_xmit_complete);

@@ -98,6 +99,7 @@ void ieee802154_xmit_error(struct ieee802154_hw *hw, struct sk_buff *skb,
{
ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
dev_kfree_skb_any(skb);
+ atomic_dec(&hw->phy->ongoing_txs);
}
EXPORT_SYMBOL(ieee802154_xmit_error);

--
2.27.0

2022-01-21 20:51:35

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 08/14] net: mac802154: Rename the main tx_work struct

This entry is dedicated to synchronous transmissions done by drivers
without async hook. Make this clearer that this is not a work that any
driver can use by at least prefixing it with "sync_". While at it, let's
enhance the comment explaining why we choose one or the other.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/ieee802154_i.h | 2 +-
net/mac802154/main.c | 2 +-
net/mac802154/tx.c | 9 ++++++---
3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index b4882b2d7688..18d1f6804810 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -55,7 +55,7 @@ struct ieee802154_local {
struct sk_buff_head skb_queue;

struct sk_buff *tx_skb;
- struct work_struct tx_work;
+ struct work_struct sync_tx_work;
};

enum {
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index bfd7c431cdea..0023c6e80725 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -95,7 +95,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)

skb_queue_head_init(&local->skb_queue);

- INIT_WORK(&local->tx_work, ieee802154_xmit_sync_worker);
+ INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker);

/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 97df5985b830..a01689ddd547 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -25,7 +25,7 @@
void ieee802154_xmit_sync_worker(struct work_struct *work)
{
struct ieee802154_local *local =
- container_of(work, struct ieee802154_local, tx_work);
+ container_of(work, struct ieee802154_local, sync_tx_work);
struct sk_buff *skb = local->tx_skb;
struct net_device *dev = skb->dev;
int res;
@@ -76,7 +76,10 @@ 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);

- /* async is priority, otherwise sync is fallback */
+ /* Drivers should preferably implement the async callback. In some rare
+ * cases they only provide a sync callback which we will use as a
+ * fallback.
+ */
if (local->ops->xmit_async) {
unsigned int len = skb->len;

@@ -90,7 +93,7 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
dev->stats.tx_bytes += len;
} else {
local->tx_skb = skb;
- queue_work(local->workqueue, &local->tx_work);
+ queue_work(local->workqueue, &local->sync_tx_work);
}

return NETDEV_TX_OK;
--
2.27.0

2022-01-21 20:51:35

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 05/14] net: ieee802154: ca8210: Call _xmit_error() when a transmission fails

ieee802154_xmit_error() is the right helper to call when a transmission
has failed. Let's use it instead of open-coding it.

Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/ca8210.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index 91456c5e5691..2830e6fdd0fd 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -1765,17 +1765,19 @@ static int ca8210_async_xmit_complete(
priv->nextmsduhandle++;

if (status) {
+ bool ifs_handling =
+ status == MAC_TRANSACTION_OVERFLOW ? true : false;
+
dev_err(
&priv->spi->dev,
"Link transmission unsuccessful, status = %d\n",
status
);
- if (status != MAC_TRANSACTION_OVERFLOW) {
- ieee802154_wake_queue(priv->hw);
- dev_kfree_skb_any(atusb->tx_skb);
- return 0;
- }
+
+ ieee802154_xmit_error(priv->hw, priv->tx_skb, ifs_handling);
+ return 0;
}
+
ieee802154_xmit_complete(priv->hw, priv->tx_skb, true);

return 0;
--
2.27.0

2022-01-21 20:51:38

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 10/14] net: mac802154: Hold the transmit queue when relevant

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 <[email protected]>
---
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 | 14 ++++++++++++--
5 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 969cae56b000..56aa672e1912 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -283,8 +283,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);
};
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index 1e4a9f74ed43..e8aabf215286 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -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;
}
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 18d1f6804810..0291e49058f2 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -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);
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 731e86bfe73f..a8d4d5e175b6 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -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;
}

diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index ae405d995868..e9c8542cfec6 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -87,7 +87,12 @@ ieee802154_wakeup_after_xmit_done(struct ieee802154_hw *hw, struct sk_buff *skb,
void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
bool ifs_handling)
{
- ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ /* Avoid waking-up a queue which needs to remain stopped */
+ if (!mac802154_queue_is_stopped(local))
+ ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
+
dev_consume_skb_any(skb);
atomic_dec(&hw->phy->ongoing_txs);
}
@@ -97,7 +102,12 @@ EXPORT_SYMBOL(ieee802154_xmit_complete);
void ieee802154_xmit_error(struct ieee802154_hw *hw, struct sk_buff *skb,
bool ifs_handling)
{
- ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ /* Avoid waking-up a queue which needs to remain stopped */
+ if (!mac802154_queue_is_stopped(local))
+ ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);
+
dev_kfree_skb_any(skb);
atomic_dec(&hw->phy->ongoing_txs);
}
--
2.27.0

2022-01-21 20:51:42

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 11/14] net: mac802154: Create a hot tx path

Let's rename the current tx path to show that this is the "hot" path. We
will soon introduce a slower path for MLME commands.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/tx.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index a8d4d5e175b6..18ee6fcfcd7f 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -109,6 +109,12 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
return NETDEV_TX_OK;
}

+static netdev_tx_t
+ieee802154_hot_tx(struct ieee802154_local *local, struct sk_buff *skb)
+{
+ return ieee802154_tx(local, skb);
+}
+
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -116,7 +122,7 @@ ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)

skb->skb_iif = dev->ifindex;

- return ieee802154_tx(sdata->local, skb);
+ return ieee802154_hot_tx(sdata->local, skb);
}

netdev_tx_t
@@ -138,5 +144,5 @@ ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev)

skb->skb_iif = dev->ifindex;

- return ieee802154_tx(sdata->local, skb);
+ return ieee802154_hot_tx(sdata->local, skb);
}
--
2.27.0

2022-01-21 20:51:47

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 13/14] net: mac802154: Introduce a tx queue flushing mechanism

Right now we are able to stop a queue but we have no indication if a
transmission is ongoing or not.

Thanks to recent additions, we can track the number of ongoing
transmissions so we know if the last transmission is over. Adding on top
of it an internal wait queue also allows to be woken up asynchronously
when this happens. If, beforehands, we marked the queue to be held and
stopped it, we end up flushing and stopping the tx queue.

Thanks to this feature, we will soon be able to introduce a synchronous
transmit API.

Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 1 +
net/ieee802154/core.c | 1 +
net/mac802154/cfg.c | 5 ++---
net/mac802154/ieee802154_i.h | 1 +
net/mac802154/tx.c | 11 ++++++++++-
net/mac802154/util.c | 3 ++-
6 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 56aa672e1912..0848896120fa 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -286,6 +286,7 @@ struct wpan_phy {
/* Transmission monitoring and control */
atomic_t ongoing_txs;
atomic_t hold_txs;
+ wait_queue_head_t sync_txq;

char priv[] __aligned(NETDEV_ALIGN);
};
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index de259b5170ab..0953cacafbff 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -129,6 +129,7 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
wpan_phy_net_set(&rdev->wpan_phy, &init_net);

init_waitqueue_head(&rdev->dev_wait);
+ init_waitqueue_head(&rdev->wpan_phy.sync_txq);

return &rdev->wpan_phy;
}
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index e8aabf215286..da94aaa32fcb 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -46,8 +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);
+ ieee802154_sync_and_stop_tx(local);
synchronize_net();

/* stop hardware - this must stop RX */
@@ -73,7 +72,7 @@ static int ieee802154_resume(struct wpan_phy *wpan_phy)
return ret;

wake_up:
- if (!atomic_dec_and_test(&wpan_phy->hold_txs))
+ if (!atomic_read(&wpan_phy->hold_txs))
ieee802154_wake_queue(&local->hw);
local->suspended = false;
return 0;
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 0291e49058f2..d9433e07906e 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -122,6 +122,7 @@ extern struct ieee802154_mlme_ops mac802154_mlme_wpan;

void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
void ieee802154_xmit_sync_worker(struct work_struct *work);
+void ieee802154_sync_and_stop_tx(struct ieee802154_local *local);
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index abd9a057521e..06ae2e6cea43 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -47,7 +47,8 @@ void ieee802154_xmit_sync_worker(struct work_struct *work)
ieee802154_wake_queue(&local->hw);

kfree_skb(skb);
- atomic_dec(&local->phy->ongoing_txs);
+ if (!atomic_dec_and_test(&local->phy->ongoing_txs))
+ wake_up(&local->phy->sync_txq);
netdev_dbg(dev, "transmission failed\n");
}

@@ -117,6 +118,14 @@ ieee802154_hot_tx(struct ieee802154_local *local, struct sk_buff *skb)
return ieee802154_tx(local, skb);
}

+void ieee802154_sync_and_stop_tx(struct ieee802154_local *local)
+{
+ atomic_inc(&local->phy->hold_txs);
+ ieee802154_stop_queue(&local->hw);
+ wait_event(local->phy->sync_txq, !atomic_read(&local->phy->ongoing_txs));
+ atomic_dec(&local->phy->hold_txs);
+}
+
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index e9c8542cfec6..949c5035cb07 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -94,7 +94,8 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
ieee802154_wakeup_after_xmit_done(hw, skb, ifs_handling);

dev_consume_skb_any(skb);
- atomic_dec(&hw->phy->ongoing_txs);
+ if (!atomic_dec_and_test(&hw->phy->ongoing_txs))
+ wake_up(&hw->phy->sync_txq);
}
EXPORT_SYMBOL(ieee802154_xmit_complete);

--
2.27.0

2022-01-21 20:51:49

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 12/14] net: mac802154: Add a warning in the hot path

We should never start a transmission after the queue has been stopped.

But because it might work we don't kill the function here but rather
warn loudly the user that something is wrong.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/tx.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 18ee6fcfcd7f..abd9a057521e 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -112,6 +112,8 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
static netdev_tx_t
ieee802154_hot_tx(struct ieee802154_local *local, struct sk_buff *skb)
{
+ WARN_ON_ONCE(mac802154_queue_is_stopped(local));
+
return ieee802154_tx(local, skb);
}

--
2.27.0

2022-01-21 20:52:07

by Miquel Raynal

[permalink] [raw]
Subject: [wpan-next 14/14] net: mac802154: Introduce a synchronous API for MLME commands

This is the slow path, we need to wait for each command to be processed
before continuing so let's introduce an helper which does the
transmission and blocks until it gets notified of its asynchronous
completion. This helper is going to be used when introducing scan
support.

Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/ieee802154_i.h | 1 +
net/mac802154/tx.c | 6 ++++++
2 files changed, 7 insertions(+)

diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index d9433e07906e..bdec3b9229e4 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -123,6 +123,7 @@ extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
void ieee802154_xmit_sync_worker(struct work_struct *work);
void ieee802154_sync_and_stop_tx(struct ieee802154_local *local);
+void ieee802154_mlme_tx(struct ieee802154_local *local, struct sk_buff *skb);
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 06ae2e6cea43..7c281458942e 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -126,6 +126,12 @@ void ieee802154_sync_and_stop_tx(struct ieee802154_local *local)
atomic_dec(&local->phy->hold_txs);
}

+void ieee802154_mlme_tx(struct ieee802154_local *local, struct sk_buff *skb)
+{
+ ieee802154_tx(local, skb);
+ ieee802154_sync_and_stop_tx(local);
+}
+
netdev_tx_t
ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
--
2.27.0