diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2010-08-08 23:06:53 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-18 14:07:54 -0500 |
commit | b78752cc71d86998d3b77d873c61d6ffdb7a2142 (patch) | |
tree | d1db8a501d3db581adea616621dbe2963f018ca0 | |
parent | 416dc94baa4a0de6904707d17522f7eae7778c8e (diff) |
Bluetooth: Process recv path in a workqueue instead of a tasklet
Run recv process in workqueue helps a lot with our processing as the recv
path will also be in the process context, i.e., now all our tx and rx are
in process context.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 3 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 19 |
2 files changed, 12 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 6a1ac2c2489c..1e28be45c4f2 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -194,8 +194,9 @@ struct hci_dev { | |||
194 | struct delayed_work discov_off; | 194 | struct delayed_work discov_off; |
195 | 195 | ||
196 | struct timer_list cmd_timer; | 196 | struct timer_list cmd_timer; |
197 | |||
198 | struct work_struct rx_work; | ||
197 | struct tasklet_struct cmd_task; | 199 | struct tasklet_struct cmd_task; |
198 | struct tasklet_struct rx_task; | ||
199 | struct tasklet_struct tx_task; | 200 | struct tasklet_struct tx_task; |
200 | 201 | ||
201 | struct sk_buff_head rx_q; | 202 | struct sk_buff_head rx_q; |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 700d0abdf2b1..4f15722c56dc 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -56,8 +56,8 @@ | |||
56 | 56 | ||
57 | int enable_hs; | 57 | int enable_hs; |
58 | 58 | ||
59 | static void hci_rx_work(struct work_struct *work); | ||
59 | static void hci_cmd_task(unsigned long arg); | 60 | static void hci_cmd_task(unsigned long arg); |
60 | static void hci_rx_task(unsigned long arg); | ||
61 | static void hci_tx_task(unsigned long arg); | 61 | static void hci_tx_task(unsigned long arg); |
62 | 62 | ||
63 | static DEFINE_RWLOCK(hci_task_lock); | 63 | static DEFINE_RWLOCK(hci_task_lock); |
@@ -547,9 +547,9 @@ int hci_dev_open(__u16 dev) | |||
547 | } | 547 | } |
548 | } else { | 548 | } else { |
549 | /* Init failed, cleanup */ | 549 | /* Init failed, cleanup */ |
550 | tasklet_kill(&hdev->rx_task); | ||
551 | tasklet_kill(&hdev->tx_task); | 550 | tasklet_kill(&hdev->tx_task); |
552 | tasklet_kill(&hdev->cmd_task); | 551 | tasklet_kill(&hdev->cmd_task); |
552 | flush_work(&hdev->rx_work); | ||
553 | 553 | ||
554 | skb_queue_purge(&hdev->cmd_q); | 554 | skb_queue_purge(&hdev->cmd_q); |
555 | skb_queue_purge(&hdev->rx_q); | 555 | skb_queue_purge(&hdev->rx_q); |
@@ -586,8 +586,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
586 | } | 586 | } |
587 | 587 | ||
588 | /* Kill RX and TX tasks */ | 588 | /* Kill RX and TX tasks */ |
589 | tasklet_kill(&hdev->rx_task); | ||
590 | tasklet_kill(&hdev->tx_task); | 589 | tasklet_kill(&hdev->tx_task); |
590 | flush_work(&hdev->rx_work); | ||
591 | 591 | ||
592 | if (hdev->discov_timeout > 0) { | 592 | if (hdev->discov_timeout > 0) { |
593 | cancel_delayed_work(&hdev->discov_off); | 593 | cancel_delayed_work(&hdev->discov_off); |
@@ -1456,8 +1456,9 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1456 | hdev->sniff_max_interval = 800; | 1456 | hdev->sniff_max_interval = 800; |
1457 | hdev->sniff_min_interval = 80; | 1457 | hdev->sniff_min_interval = 80; |
1458 | 1458 | ||
1459 | tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); | 1459 | INIT_WORK(&hdev->rx_work, hci_rx_work); |
1460 | tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); | 1460 | |
1461 | tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); | ||
1461 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); | 1462 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); |
1462 | 1463 | ||
1463 | skb_queue_head_init(&hdev->rx_q); | 1464 | skb_queue_head_init(&hdev->rx_q); |
@@ -1623,9 +1624,8 @@ int hci_recv_frame(struct sk_buff *skb) | |||
1623 | /* Time stamp */ | 1624 | /* Time stamp */ |
1624 | __net_timestamp(skb); | 1625 | __net_timestamp(skb); |
1625 | 1626 | ||
1626 | /* Queue frame for rx task */ | ||
1627 | skb_queue_tail(&hdev->rx_q, skb); | 1627 | skb_queue_tail(&hdev->rx_q, skb); |
1628 | tasklet_schedule(&hdev->rx_task); | 1628 | queue_work(hdev->workqueue, &hdev->rx_work); |
1629 | 1629 | ||
1630 | return 0; | 1630 | return 0; |
1631 | } | 1631 | } |
@@ -2486,9 +2486,9 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
2486 | kfree_skb(skb); | 2486 | kfree_skb(skb); |
2487 | } | 2487 | } |
2488 | 2488 | ||
2489 | static void hci_rx_task(unsigned long arg) | 2489 | static void hci_rx_work(struct work_struct *work) |
2490 | { | 2490 | { |
2491 | struct hci_dev *hdev = (struct hci_dev *) arg; | 2491 | struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work); |
2492 | struct sk_buff *skb; | 2492 | struct sk_buff *skb; |
2493 | 2493 | ||
2494 | BT_DBG("%s", hdev->name); | 2494 | BT_DBG("%s", hdev->name); |
@@ -2519,6 +2519,7 @@ static void hci_rx_task(unsigned long arg) | |||
2519 | /* Process frame */ | 2519 | /* Process frame */ |
2520 | switch (bt_cb(skb)->pkt_type) { | 2520 | switch (bt_cb(skb)->pkt_type) { |
2521 | case HCI_EVENT_PKT: | 2521 | case HCI_EVENT_PKT: |
2522 | BT_DBG("%s Event packet", hdev->name); | ||
2522 | hci_event_packet(hdev, skb); | 2523 | hci_event_packet(hdev, skb); |
2523 | break; | 2524 | break; |
2524 | 2525 | ||