lkml.org 
[lkml]   [2018]   [Nov]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    Subject[PATCH v3 3/5] Bluetooth: Reset Bluetooth chip after multiple command timeouts
    From
    Add a quirk and a hook to allow the HCI core to reset the BT chip
    if needed (after a number of timed out commands). Use that new hook to
    initiate BT chip reset if the controller fails to respond to certain
    number of commands (currently 5) including the HCI reset commands.
    This is done based on a newly introduced quirk. This is done based
    on some initial work by Intel.

    Signed-off-by: Rajat Jain <rajatja@google.com>
    ---
    v3: same as v1
    v2: same as v1

    include/net/bluetooth/hci.h | 8 ++++++++
    include/net/bluetooth/hci_core.h | 2 ++
    net/bluetooth/hci_core.c | 15 +++++++++++++--
    3 files changed, 23 insertions(+), 2 deletions(-)

    diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
    index c36dc1e20556..af02fa5ffe54 100644
    --- a/include/net/bluetooth/hci.h
    +++ b/include/net/bluetooth/hci.h
    @@ -192,6 +192,14 @@ enum {
    *
    */
    HCI_QUIRK_NON_PERSISTENT_SETUP,
    +
    + /* When this quirk is set, hw_reset() would be run to reset the
    + * hardware, after a certain number of commands (currently 5)
    + * time out because the device fails to respond.
    + *
    + * This quirk should be set before hci_register_dev is called.
    + */
    + HCI_QUIRK_HW_RESET_ON_TIMEOUT,
    };

    /* HCI device flags */
    diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
    index e5ea633ea368..b86218304b80 100644
    --- a/include/net/bluetooth/hci_core.h
    +++ b/include/net/bluetooth/hci_core.h
    @@ -313,6 +313,7 @@ struct hci_dev {
    unsigned int acl_cnt;
    unsigned int sco_cnt;
    unsigned int le_cnt;
    + unsigned int timeout_cnt;

    unsigned int acl_mtu;
    unsigned int sco_mtu;
    @@ -437,6 +438,7 @@ struct hci_dev {
    int (*post_init)(struct hci_dev *hdev);
    int (*set_diag)(struct hci_dev *hdev, bool enable);
    int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
    + void (*hw_reset)(struct hci_dev *hdev);
    };

    #define HCI_PHY_HANDLE(handle) (handle & 0xff)
    diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
    index 7352fe85674b..ab3a6a8b7ba6 100644
    --- a/net/bluetooth/hci_core.c
    +++ b/net/bluetooth/hci_core.c
    @@ -2569,13 +2569,24 @@ static void hci_cmd_timeout(struct work_struct *work)
    struct hci_dev *hdev = container_of(work, struct hci_dev,
    cmd_timer.work);

    + hdev->timeout_cnt++;
    if (hdev->sent_cmd) {
    struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
    u16 opcode = __le16_to_cpu(sent->opcode);

    - bt_dev_err(hdev, "command 0x%4.4x tx timeout", opcode);
    + bt_dev_err(hdev, "command 0x%4.4x tx timeout (cnt = %u)",
    + opcode, hdev->timeout_cnt);
    } else {
    - bt_dev_err(hdev, "command tx timeout");
    + bt_dev_err(hdev, "command tx timeout (cnt = %u)",
    + hdev->timeout_cnt);
    + }
    +
    + if (test_bit(HCI_QUIRK_HW_RESET_ON_TIMEOUT, &hdev->quirks) &&
    + hdev->timeout_cnt >= 5) {
    + hdev->timeout_cnt = 0;
    + if (hdev->hw_reset)
    + hdev->hw_reset(hdev);
    + return;
    }

    atomic_set(&hdev->cmd_cnt, 1);
    --
    2.19.1.1215.g8438c0b245-goog
    \
     
     \ /
      Last update: 2018-11-22 00:51    [W:4.057 / U:0.704 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site