diff options
-rw-r--r-- | include/net/bluetooth/hci_core.h | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 30 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 6 |
3 files changed, 27 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 96e7d466b9e..d3da8048652 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -95,6 +95,7 @@ struct hci_dev { unsigned long quirks; atomic_t cmd_cnt; + atomic_t cmd_not_ack; unsigned int acl_cnt; unsigned int sco_cnt; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2f768de8701..d51b79aaba1 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -503,6 +503,7 @@ int hci_dev_open(__u16 dev) if (!test_bit(HCI_RAW, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); + atomic_set(&hdev->cmd_not_ack, 0); set_bit(HCI_INIT, &hdev->flags); //__hci_request(hdev, hci_reset_req, 0, HZ); @@ -572,6 +573,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Reset device */ skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); + atomic_set(&hdev->cmd_not_ack, 0); if (!test_bit(HCI_RAW, &hdev->flags)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, @@ -645,6 +647,7 @@ int hci_dev_reset(__u16 dev) hdev->flush(hdev); atomic_set(&hdev->cmd_cnt, 1); + atomic_set(&hdev->cmd_not_ack, 0); hdev->acl_cnt = 0; hdev->sco_cnt = 0; if (!test_bit(HCI_RAW, &hdev->flags)) @@ -1633,24 +1636,31 @@ static void hci_cmd_task(unsigned long arg) struct hci_dev *hdev = (struct hci_dev *) arg; struct sk_buff *skb; - BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); + BT_DBG("%s cnt %d not_ack %d", hdev->name, atomic_read(&hdev->cmd_cnt), + atomic_read(&hdev->cmd_not_ack)); if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) { BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); + atomic_add_unless(&hdev->cmd_not_ack, -1, 0); } /* Send queued commands */ - if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { - kfree_skb(hdev->sent_cmd); + if (atomic_read(&hdev->cmd_cnt) > atomic_read(&hdev->cmd_not_ack)) { + skb = skb_dequeue(&hdev->cmd_q); + if (skb) { + kfree_skb(hdev->sent_cmd); - if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) { - atomic_dec(&hdev->cmd_cnt); - hci_send_frame(skb); - hdev->cmd_last_tx = jiffies; - } else { - skb_queue_head(&hdev->cmd_q, skb); - tasklet_schedule(&hdev->cmd_task); + hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC); + if (hdev->sent_cmd) { + atomic_dec(&hdev->cmd_cnt); + atomic_inc(&hdev->cmd_not_ack); + hci_send_frame(skb); + hdev->cmd_last_tx = jiffies; + } else { + skb_queue_head(&hdev->cmd_q, skb); + tasklet_schedule(&hdev->cmd_task); + } } } } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 23bedb7467c..0cb609ad72b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1319,6 +1319,9 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk break; } + if (opcode != 0x0000) + atomic_add_unless(&hdev->cmd_not_ack, -1, 0); + if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) @@ -1385,6 +1388,9 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) break; } + if (opcode != 0x0000) + atomic_add_unless(&hdev->cmd_not_ack, -1, 0); + if (ev->ncmd) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) |