aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrzej Kaczmarek <andrzej.kaczmarek@tieto.com>2011-02-16 10:43:20 +0100
committerHenrik hman <henrik.ohman@stericsson.com>2011-03-15 14:23:13 +0100
commit58921a2040d45ebb21aec653ca9867ba79c88e88 (patch)
treea039f63c61283c33320a2538a2fbf13df6c98ae5
parent0754bb60108af169297c0b31444d473cdb162402 (diff)
downloadlinux-2.6.35-ux500-58921a2040d45ebb21aec653ca9867ba79c88e88.tar.gz
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>
-rw-r--r--include/net/bluetooth/hci_core.h1
-rw-r--r--net/bluetooth/hci_core.c30
-rw-r--r--net/bluetooth/hci_event.c6
3 files changed, 27 insertions, 10 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 96e7d46..d3da804 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 2f768de..d51b79a 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 23bedb7..0cb609a 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))