diff options
author | Ville Tervo <ville.tervo@nokia.com> | 2011-02-16 09:32:41 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-16 14:33:26 -0500 |
commit | 6bd32326cdaa9b14794416150c88e4832fb7e592 (patch) | |
tree | 4c48387761df0207bb50952dda7fd5c980893351 /net/bluetooth | |
parent | 7f4b2b04c88377af30c022f36c060190182850fb (diff) |
Bluetooth: Use proper timer for hci command timout
Use proper timer instead of hci command flow control to timeout
failed hci commands. Otherwise stack ends up sending commands
when flow control is used to block new commands.
2010-09-01 18:29:41.592132 < HCI Command: Remote Name Request (0x01|0x0019) plen 10
bdaddr 00:16:CF:E1:C7:D7 mode 2 clkoffset 0x0000
2010-09-01 18:29:41.592681 > HCI Event: Command Status (0x0f) plen 4
Remote Name Request (0x01|0x0019) status 0x00 ncmd 0
2010-09-01 18:29:51.022033 < HCI Command: Remote Name Request Cancel (0x01|0x001a) plen 6
bdaddr 00:16:CF:E1:C7:D7
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_core.c | 22 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 6 |
2 files changed, 22 insertions, 6 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c01415bc8946..702d5651c656 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
42 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
43 | #include <linux/rfkill.h> | 43 | #include <linux/rfkill.h> |
44 | #include <linux/timer.h> | ||
44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
45 | 46 | ||
46 | #include <asm/system.h> | 47 | #include <asm/system.h> |
@@ -623,6 +624,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
623 | 624 | ||
624 | /* Drop last sent command */ | 625 | /* Drop last sent command */ |
625 | if (hdev->sent_cmd) { | 626 | if (hdev->sent_cmd) { |
627 | del_timer_sync(&hdev->cmd_timer); | ||
626 | kfree_skb(hdev->sent_cmd); | 628 | kfree_skb(hdev->sent_cmd); |
627 | hdev->sent_cmd = NULL; | 629 | hdev->sent_cmd = NULL; |
628 | } | 630 | } |
@@ -1066,6 +1068,16 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) | |||
1066 | return 0; | 1068 | return 0; |
1067 | } | 1069 | } |
1068 | 1070 | ||
1071 | /* HCI command timer function */ | ||
1072 | static void hci_cmd_timer(unsigned long arg) | ||
1073 | { | ||
1074 | struct hci_dev *hdev = (void *) arg; | ||
1075 | |||
1076 | BT_ERR("%s command tx timeout", hdev->name); | ||
1077 | atomic_set(&hdev->cmd_cnt, 1); | ||
1078 | tasklet_schedule(&hdev->cmd_task); | ||
1079 | } | ||
1080 | |||
1069 | /* Register HCI device */ | 1081 | /* Register HCI device */ |
1070 | int hci_register_dev(struct hci_dev *hdev) | 1082 | int hci_register_dev(struct hci_dev *hdev) |
1071 | { | 1083 | { |
@@ -1112,6 +1124,8 @@ int hci_register_dev(struct hci_dev *hdev) | |||
1112 | skb_queue_head_init(&hdev->cmd_q); | 1124 | skb_queue_head_init(&hdev->cmd_q); |
1113 | skb_queue_head_init(&hdev->raw_q); | 1125 | skb_queue_head_init(&hdev->raw_q); |
1114 | 1126 | ||
1127 | setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); | ||
1128 | |||
1115 | for (i = 0; i < NUM_REASSEMBLY; i++) | 1129 | for (i = 0; i < NUM_REASSEMBLY; i++) |
1116 | hdev->reassembly[i] = NULL; | 1130 | hdev->reassembly[i] = NULL; |
1117 | 1131 | ||
@@ -2004,11 +2018,6 @@ static void hci_cmd_task(unsigned long arg) | |||
2004 | 2018 | ||
2005 | BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); | 2019 | BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); |
2006 | 2020 | ||
2007 | if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) { | ||
2008 | BT_ERR("%s command tx timeout", hdev->name); | ||
2009 | atomic_set(&hdev->cmd_cnt, 1); | ||
2010 | } | ||
2011 | |||
2012 | /* Send queued commands */ | 2021 | /* Send queued commands */ |
2013 | if (atomic_read(&hdev->cmd_cnt)) { | 2022 | if (atomic_read(&hdev->cmd_cnt)) { |
2014 | skb = skb_dequeue(&hdev->cmd_q); | 2023 | skb = skb_dequeue(&hdev->cmd_q); |
@@ -2021,7 +2030,8 @@ static void hci_cmd_task(unsigned long arg) | |||
2021 | if (hdev->sent_cmd) { | 2030 | if (hdev->sent_cmd) { |
2022 | atomic_dec(&hdev->cmd_cnt); | 2031 | atomic_dec(&hdev->cmd_cnt); |
2023 | hci_send_frame(skb); | 2032 | hci_send_frame(skb); |
2024 | hdev->cmd_last_tx = jiffies; | 2033 | mod_timer(&hdev->cmd_timer, |
2034 | jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); | ||
2025 | } else { | 2035 | } else { |
2026 | skb_queue_head(&hdev->cmd_q, skb); | 2036 | skb_queue_head(&hdev->cmd_q, skb); |
2027 | tasklet_schedule(&hdev->cmd_task); | 2037 | tasklet_schedule(&hdev->cmd_task); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 74f04a27734d..09cb29e8713a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -1732,6 +1732,9 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1732 | break; | 1732 | break; |
1733 | } | 1733 | } |
1734 | 1734 | ||
1735 | if (ev->opcode != HCI_OP_NOP) | ||
1736 | del_timer(&hdev->cmd_timer); | ||
1737 | |||
1735 | if (ev->ncmd) { | 1738 | if (ev->ncmd) { |
1736 | atomic_set(&hdev->cmd_cnt, 1); | 1739 | atomic_set(&hdev->cmd_cnt, 1); |
1737 | if (!skb_queue_empty(&hdev->cmd_q)) | 1740 | if (!skb_queue_empty(&hdev->cmd_q)) |
@@ -1807,6 +1810,9 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
1807 | break; | 1810 | break; |
1808 | } | 1811 | } |
1809 | 1812 | ||
1813 | if (ev->opcode != HCI_OP_NOP) | ||
1814 | del_timer(&hdev->cmd_timer); | ||
1815 | |||
1810 | if (ev->ncmd) { | 1816 | if (ev->ncmd) { |
1811 | atomic_set(&hdev->cmd_cnt, 1); | 1817 | atomic_set(&hdev->cmd_cnt, 1); |
1812 | if (!skb_queue_empty(&hdev->cmd_q)) | 1818 | if (!skb_queue_empty(&hdev->cmd_q)) |