summaryrefslogtreecommitdiff
path: root/net/mac802154/main.c
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2014-10-27 17:13:30 +0100
committerMarcel Holtmann <marcel@holtmann.org>2014-10-27 18:07:40 +0100
commitc5c47e67bcd24638a059b1b5e9ec18c95f8634ca (patch)
treec57352e1df69afab550d8df129a0bee16b3455a7 /net/mac802154/main.c
parent61a2281458956db519f2c24fa40bf277adea2a67 (diff)
mac802154: rx: use tasklet instead workqueue
Tasklets have much less overhead than workqueues. This patch also removes the heap allocation for the worker on receiving path. Like mac80211 we should prefer use a tasklet here instead a workqueue to getting fast out of interrupt context when ieee802154_rx_irqsafe is called by driver. Like wireless inside the tasklet context we should call netif_receive_skb instead netif_rx_ni anymore. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/mac802154/main.c')
-rw-r--r--net/mac802154/main.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 3c0a824d24ac..ff0de0f990cb 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -222,6 +222,29 @@ static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
return local->ops->set_frame_retries(&local->hw, retries);
}
+static void ieee802154_tasklet_handler(unsigned long data)
+{
+ struct ieee802154_local *local = (struct ieee802154_local *)data;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&local->skb_queue))) {
+ switch (skb->pkt_type) {
+ case IEEE802154_RX_MSG:
+ /* Clear skb->pkt_type in order to not confuse kernel
+ * netstack.
+ */
+ skb->pkt_type = 0;
+ ieee802154_rx(&local->hw, skb);
+ break;
+ default:
+ WARN(1, "mac802154: Packet is of unknown type %d\n",
+ skb->pkt_type);
+ kfree_skb(skb);
+ break;
+ }
+ }
+}
+
struct ieee802154_hw *
ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops)
{
@@ -270,6 +293,12 @@ ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops)
INIT_LIST_HEAD(&local->interfaces);
mutex_init(&local->iflist_mtx);
+ tasklet_init(&local->tasklet,
+ ieee802154_tasklet_handler,
+ (unsigned long)local);
+
+ skb_queue_head_init(&local->skb_queue);
+
return &local->hw;
}
EXPORT_SYMBOL(ieee802154_alloc_hw);
@@ -371,6 +400,7 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw)
struct ieee802154_local *local = hw_to_local(hw);
struct ieee802154_sub_if_data *sdata, *next;
+ tasklet_kill(&local->tasklet);
flush_workqueue(local->workqueue);
destroy_workqueue(local->workqueue);