diff options
author | Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com> | 2011-02-16 10:43:20 +0100 |
---|---|---|
committer | Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | 2011-03-05 15:18:03 +0100 |
commit | 1e3ebaff77171038d48441d1df264bc5450e0be9 (patch) | |
tree | b481003e08b618ccc25b295b4a70d7059c6c7450 /net | |
parent | ef45647492d3bd0adf0d3132efffef5a9d5af680 (diff) |
Bluetooth: Add counter for not acked HCI commands
Adds counter for HCI commands which were sent but are not yet acked.
This is to prevent race conditions in scenarios where HCI commands
are sent between complete event and command status event, i.e.
last sent HCI command is not accounted in credits number returned
by command status event.
ST-Ericsson Linux next: not tested, ER?
ST-Ericsson ID: 323271
ST-Ericsson FOSS-OUT-ID: Trivial
Change-Id: I74d1f31ab79ee07406858451c94273301eee6e64
Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/16344
Reviewed-by: Lukasz RYMANOWSKI <lukasz.rymanowski@stericsson.com>
Reviewed-by: Par-Gunnar HJALMDAHL <par-gunnar.p.hjalmdahl@stericsson.com>
Reviewed-by: Henrik POSSUNG <henrik.possung@stericsson.com>
Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 30 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 6 |
2 files changed, 26 insertions, 10 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e500fc3be16..62717e1b451 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)) @@ -1635,24 +1638,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 b53e24d7412..c56cb5a73a3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1317,6 +1317,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)) @@ -1383,6 +1386,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)) |