Skip to content

Commit

Permalink
mac802154: rx: use tasklet instead workqueue
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alexander Aring authored and Marcel Holtmann committed Oct 27, 2014
1 parent 61a2281 commit c5c47e6
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 41 deletions.
1 change: 1 addition & 0 deletions include/net/mac802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ void ieee802154_free_hw(struct ieee802154_hw *hw);
int ieee802154_register_hw(struct ieee802154_hw *hw);
void ieee802154_unregister_hw(struct ieee802154_hw *hw);

void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb,
u8 lqi);

Expand Down
7 changes: 7 additions & 0 deletions net/mac802154/ieee802154_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,18 @@ struct ieee802154_local {
* read them using any of protection methods.
*/
bool running;

struct tasklet_struct tasklet;
struct sk_buff_head skb_queue;
};

#define MAC802154_DEVICE_STOPPED 0x00
#define MAC802154_DEVICE_RUN 0x01

enum {
IEEE802154_RX_MSG = 1,
};

/* Slave interface definition.
*
* Slaves represent typical network interfaces available from userspace.
Expand Down
2 changes: 1 addition & 1 deletion net/mac802154/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ void mac802154_wpan_setup(struct net_device *dev)

static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
{
return netif_rx_ni(skb);
return netif_receive_skb(skb);
}

static int
Expand Down
30 changes: 30 additions & 0 deletions net/mac802154/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
48 changes: 8 additions & 40 deletions net/mac802154/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/netdevice.h>
#include <linux/crc-ccitt.h>

Expand All @@ -28,30 +27,11 @@

#include "ieee802154_i.h"

/* The IEEE 802.15.4 standard defines 4 MAC packet types:
* - beacon frame
* - MAC command frame
* - acknowledgement frame
* - data frame
*
* and only the data frame should be pushed to the upper layers, other types
* are just internal MAC layer management information. So only data packets
* are going to be sent to the networking queue, all other will be processed
* right here by using the device workqueue.
*/
struct rx_work {
struct sk_buff *skb;
struct work_struct work;
struct ieee802154_hw *hw;
u8 lqi;
};

static void
mac802154_subif_rx(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
mac802154_subif_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct ieee802154_local *local = hw_to_local(hw);

mac_cb(skb)->lqi = lqi;
skb->protocol = htons(ETH_P_IEEE802154);
skb_reset_mac_header(skb);

Expand Down Expand Up @@ -79,32 +59,20 @@ mac802154_subif_rx(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
kfree_skb(skb);
}

static void mac802154_rx_worker(struct work_struct *work)
void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
{
struct rx_work *rw = container_of(work, struct rx_work, work);

mac802154_subif_rx(rw->hw, rw->skb, rw->lqi);
kfree(rw);
mac802154_subif_rx(hw, skb);
}
EXPORT_SYMBOL(ieee802154_rx);

void
ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
{
struct ieee802154_local *local = hw_to_local(hw);
struct rx_work *work;

if (!skb)
return;

work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return;

INIT_WORK(&work->work, mac802154_rx_worker);
work->skb = skb;
work->hw = hw;
work->lqi = lqi;

queue_work(local->workqueue, &work->work);
mac_cb(skb)->lqi = lqi;
skb->pkt_type = IEEE802154_RX_MSG;
skb_queue_tail(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
}
EXPORT_SYMBOL(ieee802154_rx_irqsafe);

0 comments on commit c5c47e6

Please sign in to comment.