mac802154: add interframe spacing time handling
authorAlexander Aring <alex.aring@gmail.com>
Wed, 12 Nov 2014 18:51:56 +0000 (19:51 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 13 Nov 2014 03:51:58 +0000 (04:51 +0100)
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.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/net/ieee802154/at86rf230.c
include/linux/ieee802154.h
include/net/cfg802154.h
include/net/mac802154.h
net/mac802154/ieee802154_i.h
net/mac802154/iface.c
net/mac802154/main.c
net/mac802154/tx.c
net/mac802154/util.c

index 31d62f9c6ce8a7037c38d56d1e02c6f971998433..46e50295710a31479d1fbcedba05515967a14d46 100644 (file)
@@ -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
index ce0f96a559768d4ad95e6868b42242d59e4a3367..5a40c0418438786f8aa622d77d8a1e9eca0d329e 100644 (file)
@@ -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 */
index fa0a9e5195232a00c964fb971d35fd983e7b891b..17b4fc0705b2d8027ee3f13752494fa29634c822 100644 (file)
@@ -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);
index 632f6566adb5894c8c164f4d0380d2167e490873..c823d910b46ca7da89866226ba5e1be7c7c93529 100644 (file)
@@ -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 */
index 69cb585e162f3e49dd452c485405ea2c73403fe5..c5b231047b60aae3fa512b4ad36edb946a96c7d2 100644 (file)
@@ -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);
index ec92b48d1b0bfa40a7fafc148ff6f1d0bd9d3a1f..feb064715d1f9632d16dc308967ea01a68520cef 100644 (file)
@@ -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--;
 
index 46c76e005446cada59c5f1eb5f683eecc83b55ea..0af1be64e8ad440a42760a91b04bacbbb525628e 100644 (file)
@@ -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;
index cc37b77f26321ca9a5f4f960a0f72608d48c1013..c62e95695c7843947c8643cb268f95f2e64c3da9 100644 (file)
@@ -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;
index 9a04e4a8e50f5591fe46fdffc717808d495dd145..5fc979027919749a604a47bcd45148fbe5505f03 100644 (file)
@@ -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);