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>
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 3c0a824..ff0de0f 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -222,6 +222,29 @@
 	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 @@
 	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 @@
 	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);