summaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_event.c
diff options
context:
space:
mode:
authorManish Mandlik <mmandlik@google.com>2021-04-29 10:24:22 -0700
committerMarcel Holtmann <marcel@holtmann.org>2021-06-26 07:12:27 +0200
commitde75cd0d9b2f3250d5f25846bb5632ccce6275f4 (patch)
tree538b084560833bee3d1147cc7fd7d88c269f7b17 /net/bluetooth/hci_event.c
parent59f90f1351282ea2dbd0c59098fd9bb2634e920e (diff)
downloadlwn-de75cd0d9b2f3250d5f25846bb5632ccce6275f4.tar.gz
lwn-de75cd0d9b2f3250d5f25846bb5632ccce6275f4.zip
Bluetooth: Add ncmd=0 recovery handling
During command status or command complete event, the controller may set ncmd=0 indicating that it is not accepting any more commands. In such a case, host holds off sending any more commands to the controller. If the controller doesn't recover from such condition, host will wait forever, until the user decides that the Bluetooth is broken and may power cycles the Bluetooth. This patch triggers the hardware error to reset the controller and driver when it gets into such state as there is no other wat out. Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org> Signed-off-by: Manish Mandlik <mmandlik@google.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r--net/bluetooth/hci_event.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 59c5329354e1..18339ebc5959 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3268,6 +3268,23 @@ unlock:
hci_dev_unlock(hdev);
}
+static inline void handle_cmd_cnt_and_timer(struct hci_dev *hdev,
+ u16 opcode, u8 ncmd)
+{
+ if (opcode != HCI_OP_NOP)
+ cancel_delayed_work(&hdev->cmd_timer);
+
+ if (!test_bit(HCI_RESET, &hdev->flags)) {
+ if (ncmd) {
+ cancel_delayed_work(&hdev->ncmd_timer);
+ atomic_set(&hdev->cmd_cnt, 1);
+ } else {
+ schedule_delayed_work(&hdev->ncmd_timer,
+ HCI_NCMD_TIMEOUT);
+ }
+ }
+}
+
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
u16 *opcode, u8 *status,
hci_req_complete_t *req_complete,
@@ -3630,11 +3647,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
break;
}
- if (*opcode != HCI_OP_NOP)
- cancel_delayed_work(&hdev->cmd_timer);
-
- if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags))
- atomic_set(&hdev->cmd_cnt, 1);
+ handle_cmd_cnt_and_timer(hdev, *opcode, ev->ncmd);
hci_req_cmd_complete(hdev, *opcode, *status, req_complete,
req_complete_skb);
@@ -3735,11 +3748,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
break;
}
- if (*opcode != HCI_OP_NOP)
- cancel_delayed_work(&hdev->cmd_timer);
-
- if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags))
- atomic_set(&hdev->cmd_cnt, 1);
+ handle_cmd_cnt_and_timer(hdev, *opcode, ev->ncmd);
/* Indicate request completion if the command failed. Also, if
* we're not waiting for a special event and we get a success