Skip to contentSkip to conversation

ieee802154: introduce new interframe spacing time handling

PATCH In review Alexander Aring 2 participants 4 messages Nov 12, 2014 – Nov 13, 2014

Subsystems (3)
lore
Share & tools
lore

Alexander Aring

author maintainer
#0 lore raw

cover ieee802154: introduce new interframe spacing time handling

This patch series contains patches for introducing and use of interframe spacing time handling. The interframe spacing time handling depends on transceiver if it's done at transceiver level or need to be done at SoftMAC (mac802154) level. On the at86rf2xx transceiver this is done at transceiver when max frame retries is above 0.

The mac802154 solution is to run a hrtimer which start at complete function. When the timer expires we wake the queue again. This stops the transmit queue after a transmit for a specific time.

Currently all drivers except the at86rf230 cares about interframe spacing time. I think nobody hit the issue because the latency of workqueue. If we don't making interframe spacing time with async xmit handler we run into fragmentation issues while 802.15.4 6LoWPAN.

Alexander Aring (2):
mac802154: add interframe spacing time handling
at86rf230: remove interframe spacing time workaround

 drivers/net/ieee802154/at86rf230.c | 60 +++++++++++++++++++++++---------------
 include/linux/ieee802154.h         |  3 ++
 include/net/cfg802154.h            |  8 +++++
 include/net/mac802154.h            |  3 +-
 net/mac802154/ieee802154_i.h       |  4 +++
 net/mac802154/iface.c              |  2 ++
 net/mac802154/main.c               | 17 +++++++++++
 net/mac802154/tx.c                 |  2 +-
 net/mac802154/util.c               | 32 ++++++++++++++++++--
 9 files changed, 103 insertions(+), 28 deletions(-)
Signature · 1 line
2.1.3
author maintainer
#1 lore raw

PATCH 1/2 mac802154: add interframe spacing time handling

This patch adds a new interframe spacing time handling into mac802154 layer. Interframe spacing time is a time period between each transmit. This patch adds a high resolution timer into mac802154 and starts on xmit complete with corresponding interframe spacing expire time if ifs_handling is true. We make it variable because it depends if interframe spacing time is handled by transceiver or mac802154. At the timer complete function we wake the netdev queue again. This avoids new frame transmit in range of interframe spacing time.

For synced driver we add no handling of interframe spacing time. This is currently a lack of support in all synced xmit drivers. I suppose it's working because the latency of workqueue which is needed to call spi_sync.

---
 drivers/net/ieee802154/at86rf230.c |  2 +-
 include/linux/ieee802154.h         |  3 +++
 include/net/cfg802154.h            |  8 ++++++++
 include/net/mac802154.h            |  3 ++-
 net/mac802154/ieee802154_i.h       |  4 ++++
 net/mac802154/iface.c              |  2 ++
 net/mac802154/main.c               | 17 +++++++++++++++++
 net/mac802154/tx.c                 |  2 +-
 net/mac802154/util.c               | 32 +++++++++++++++++++++++++++++---
 9 files changed, 67 insertions(+), 6 deletions(-)
drivers/net/ieee802154/at86rf230.c +1 -1
index 31d62f9..46e5029 100644
@@ -731,7 +731,7 @@ at86rf230_tx_complete(void *context)
 			udelay(lp->data->t_sifs);
 	}
 
-	ieee802154_xmit_complete(lp->hw, skb);
+	ieee802154_xmit_complete(lp->hw, skb, false);
 }
 
 static void
include/linux/ieee802154.h +3 -0
index ce0f96a..5a40c04 100644
@@ -36,6 +36,9 @@
 
 #define IEEE802154_EXTENDED_ADDR_LEN	8
 
+#define IEEE802154_LIFS_PERIOD		40
+#define IEEE802154_SIFS_PERIOD		12
+
 #define IEEE802154_FC_TYPE_BEACON	0x0	/* Frame is beacon */
 #define	IEEE802154_FC_TYPE_DATA		0x1	/* Frame is data */
 #define IEEE802154_FC_TYPE_ACK		0x2	/* Frame is acknowledgment */
include/net/cfg802154.h +8 -0
index fa0a9e5..17b4fc0 100644
@@ -81,6 +81,14 @@ struct wpan_phy {
 
 	s32 cca_ed_level;
 
+	/* PHY depended MAC PIB values */
+
+	/* 802.15.4 acronym: Tdsym in usec */
+	u8 symbol_duration;
+	/* lifs and sifs periods timing */
+	u16 lifs_period;
+	u16 sifs_period;
+
 	struct device dev;
 
 	char priv[0] __aligned(NETDEV_ALIGN);
include/net/mac802154.h +2 -1
index 632f656..c823d91 100644
@@ -260,6 +260,7 @@ void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb,
 
 void ieee802154_wake_queue(struct ieee802154_hw *hw);
 void ieee802154_stop_queue(struct ieee802154_hw *hw);
-void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb);
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
+			      bool ifs_handling);
 
 #endif /* NET_MAC802154_H */
net/mac802154/ieee802154_i.h +4 -0
index 69cb585..c5b2310 100644
@@ -20,6 +20,7 @@
 #define __IEEE802154_I_H
 
 #include <linux/mutex.h>
+#include <linux/hrtimer.h>
 #include <net/cfg802154.h>
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
@@ -51,6 +52,8 @@ struct ieee802154_local {
 	 */
 	struct workqueue_struct	*workqueue;
 
+	struct hrtimer ifs_timer;
+
 	bool started;
 
 	struct tasklet_struct tasklet;
@@ -127,6 +130,7 @@ ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 void mac802154_wpan_setup(struct net_device *dev);
 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);
 
 /* MIB callbacks */
 void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
net/mac802154/iface.c +2 -0
index ec92b48..feb0647 100644
@@ -246,6 +246,8 @@ static int mac802154_slave_close(struct net_device *dev)
 
 	ASSERT_RTNL();
 
+	hrtimer_cancel(&local->ifs_timer);
+
 	netif_stop_queue(dev);
 	local->open_count--;
 
net/mac802154/main.c +17 -0
index 46c76e0..0af1be6 100644
@@ -125,6 +125,18 @@ void ieee802154_free_hw(struct ieee802154_hw *hw)
 }
 EXPORT_SYMBOL(ieee802154_free_hw);
 
+static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy)
+{
+	/* TODO warn on empty symbol_duration
+	 * Should be done when all drivers sets this value.
+	 */
+
+	wpan_phy->lifs_period = IEEE802154_LIFS_PERIOD *
+				wpan_phy->symbol_duration;
+	wpan_phy->sifs_period = IEEE802154_SIFS_PERIOD *
+				wpan_phy->symbol_duration;
+}
+
 int ieee802154_register_hw(struct ieee802154_hw *hw)
 {
 	struct ieee802154_local *local = hw_to_local(hw);
@@ -138,8 +150,13 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)
 		goto out;
 	}
 
+	hrtimer_init(&local->ifs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	local->ifs_timer.function = ieee802154_xmit_ifs_timer;
+
 	wpan_phy_set_dev(local->phy, local->hw.parent);
 
+	ieee802154_setup_wpan_phy_pib(local->phy);
+
 	rc = wpan_phy_register(local->phy);
 	if (rc < 0)
 		goto out_wq;
net/mac802154/tx.c +1 -1
index cc37b77..c62e956 100644
@@ -60,7 +60,7 @@ static void ieee802154_xmit_worker(struct work_struct *work)
 	if (res)
 		goto err_tx;
 
-	ieee802154_xmit_complete(&local->hw, skb);
+	ieee802154_xmit_complete(&local->hw, skb, false);
 
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
net/mac802154/util.c +29 -3
index 9a04e4a..5fc9790 100644
@@ -50,9 +50,35 @@ void ieee802154_stop_queue(struct ieee802154_hw *hw)
 }
 EXPORT_SYMBOL(ieee802154_stop_queue);
 
-void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb)
+enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer)
 {
-	ieee802154_wake_queue(hw);
-	consume_skb(skb);
+	struct ieee802154_local *local =
+		container_of(timer, struct ieee802154_local, ifs_timer);
+
+	ieee802154_wake_queue(&local->hw);
+
+	return HRTIMER_NORESTART;
+}
+
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
+			      bool ifs_handling)
+{
+	if (ifs_handling) {
+		struct ieee802154_local *local = hw_to_local(hw);
+
+		if (skb->len > 18)
+			hrtimer_start(&local->ifs_timer,
+				      ktime_set(0, hw->phy->lifs_period * NSEC_PER_USEC),
+				      HRTIMER_MODE_REL);
+		else
+			hrtimer_start(&local->ifs_timer,
+				      ktime_set(0, hw->phy->sifs_period * NSEC_PER_USEC),
+				      HRTIMER_MODE_REL);
+
+		consume_skb(skb);
+	} else {
+		ieee802154_wake_queue(hw);
+		consume_skb(skb);
+	}
 }
 EXPORT_SYMBOL(ieee802154_xmit_complete);
Signature · 1 line
2.1.3
author maintainer
#2 lore raw

PATCH 2/2 at86rf230: remove interframe spacing time workaround

In reply to Alexander Aring

This patch removes the interframe spacing time workaround from at86rf230 driver and use the mac802154 one. The interframe spacing time differs at at86rf212 and channel setting. This patch fix this handling which is also a new workaround and should be moved into mac802154 while channel setting.

---
 drivers/net/ieee802154/at86rf230.c | 60 +++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 23 deletions(-)
drivers/net/ieee802154/at86rf230.c +37 -23
index 46e5029..7278e18 100644
@@ -46,10 +46,6 @@ struct at86rf2xx_chip_data {
 	u16 t_off_to_tx_on;
 	u16 t_frame;
 	u16 t_p_ack;
-	/* short interframe spacing time */
-	u16 t_sifs;
-	/* long interframe spacing time */
-	u16 t_lifs;
 	/* completion timeout for tx in msecs */
 	u16 t_tx_timeout;
 	int rssi_base_val;
@@ -719,19 +715,10 @@ at86rf230_tx_complete(void *context)
 
 	enable_irq(lp->spi->irq);
 
-	if (lp->max_frame_retries <= 0) {
-		/* Interfame spacing time, which is phy depend.
-		 * TODO
-		 * Move this handling in MAC 802.15.4 layer.
-		 * This is currently a workaround to avoid fragmenation issues.
-		 */
-		if (skb->len > 18)
-			udelay(lp->data->t_lifs);
-		else
-			udelay(lp->data->t_sifs);
-	}
-
-	ieee802154_xmit_complete(lp->hw, skb, false);
+	if (lp->max_frame_retries <= 0)
+		ieee802154_xmit_complete(lp->hw, skb, true);
+	else
+		ieee802154_xmit_complete(lp->hw, skb, false);
 }
 
 static void
@@ -1038,6 +1025,36 @@ at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
 	if (rc < 0)
 		return rc;
 
+	/* This sets the symbol_duration according frequency on the 212.
+	 * TODO move this handling while set channel and page in cfg802154.
+	 * We can do that, this timings are according 802.15.4 standard.
+	 * If we do that in cfg802154, this is a more generic calculation.
+	 *
+	 * This should also protected from ifs_timer. Means cancel timer and
+	 * init with a new value. For now, this is okay.
+	 */
+	if (channel == 0) {
+		if (page == 0) {
+			/* SUB:0 and BPSK:0 -> BPSK-20 */
+			lp->hw->phy->symbol_duration = 50;
+		} else {
+			/* SUB:1 and BPSK:0 -> BPSK-40 */
+			lp->hw->phy->symbol_duration = 25;
+		}
+	} else {
+		if (page == 0)
+			/* SUB:0 and BPSK:1 -> BPSK-20 */
+			lp->hw->phy->symbol_duration = 40;
+		else
+			/* SUB:1 and BPSK:1 -> BPSK-20 */
+			lp->hw->phy->symbol_duration = 16;
+	}
+
+	lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD *
+				   lp->hw->phy->symbol_duration;
+	lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD *
+				   lp->hw->phy->symbol_duration;
+
 	return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
 }
 
@@ -1245,8 +1262,6 @@ static struct at86rf2xx_chip_data at86rf233_data = {
 	.t_off_to_tx_on = 80,
 	.t_frame = 4096,
 	.t_p_ack = 545,
-	.t_sifs = 192,
-	.t_lifs = 640,
 	.t_tx_timeout = 2000,
 	.rssi_base_val = -91,
 	.set_channel = at86rf23x_set_channel,
@@ -1261,8 +1276,6 @@ static struct at86rf2xx_chip_data at86rf231_data = {
 	.t_off_to_tx_on = 110,
 	.t_frame = 4096,
 	.t_p_ack = 545,
-	.t_sifs = 192,
-	.t_lifs = 640,
 	.t_tx_timeout = 2000,
 	.rssi_base_val = -91,
 	.set_channel = at86rf23x_set_channel,
@@ -1277,8 +1290,6 @@ static struct at86rf2xx_chip_data at86rf212_data = {
 	.t_off_to_tx_on = 200,
 	.t_frame = 4096,
 	.t_p_ack = 545,
-	.t_sifs = 192,
-	.t_lifs = 640,
 	.t_tx_timeout = 2000,
 	.rssi_base_val = -100,
 	.set_channel = at86rf212_set_channel,
@@ -1414,6 +1425,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
 		lp->data = &at86rf231_data;
 		lp->hw->phy->channels_supported[0] = 0x7FFF800;
 		lp->hw->phy->current_channel = 11;
+		lp->hw->phy->symbol_duration = 16;
 		break;
 	case 7:
 		chip = "at86rf212";
@@ -1423,6 +1435,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
 			lp->hw->phy->channels_supported[0] = 0x00007FF;
 			lp->hw->phy->channels_supported[2] = 0x00007FF;
 			lp->hw->phy->current_channel = 5;
+			lp->hw->phy->symbol_duration = 25;
 		} else {
 			rc = -ENOTSUPP;
 		}
@@ -1432,6 +1445,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
 		lp->data = &at86rf233_data;
 		lp->hw->phy->channels_supported[0] = 0x7FFF800;
 		lp->hw->phy->current_channel = 13;
+		lp->hw->phy->symbol_duration = 16;
 		break;
 	default:
 		chip = "unkown";
Signature · 1 line
2.1.3
#3 lore raw
In reply to Alexander Aring

Hi Alex,

Quoted 19 lines

This patch series contains patches for introducing and use of interframe spacing time handling. The interframe spacing time handling depends on transceiver if it's done at transceiver level or need to be done at SoftMAC (mac802154) level. On the at86rf2xx transceiver this is done at transceiver when max frame retries is above 0.

The mac802154 solution is to run a hrtimer which start at complete function. When the timer expires we wake the queue again. This stops the transmit queue after a transmit for a specific time.

Currently all drivers except the at86rf230 cares about interframe spacing time. I think nobody hit the issue because the latency of workqueue. If we don't making interframe spacing time with async xmit handler we run into fragmentation issues while 802.15.4 6LoWPAN.

Alexander Aring (2):
mac802154: add interframe spacing time handling
at86rf230: remove interframe spacing time workaround

Quoted 10 lines
drivers/net/ieee802154/at86rf230.c | 60 +++++++++++++++++++++++---------------
include/linux/ieee802154.h         |  3 ++
include/net/cfg802154.h            |  8 +++++
include/net/mac802154.h            |  3 +-
net/mac802154/ieee802154_i.h       |  4 +++
net/mac802154/iface.c              |  2 ++
net/mac802154/main.c               | 17 +++++++++++
net/mac802154/tx.c                 |  2 +-
net/mac802154/util.c               | 32 ++++++++++++++++++--
9 files changed, 103 insertions(+), 28 deletions(-)

both patches have been applied to bluetooth-next tree.

Regards

Marcel