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>
This commit is contained in:
Alexander Aring
2014-10-27 17:13:30 +01:00
committed by Marcel Holtmann
parent 61a2281458
commit c5c47e67bc
5 changed files with 47 additions and 41 deletions

View File

@@ -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);