Re: [PATCH v2 3/4] Bluetooth: hci_conn: Only do ACL connections sequentially

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jonas,

On Mon, Jan 8, 2024 at 1:39 PM Jonas Dreßler <verdre@xxxxxxx> wrote:
>
> Pretty much all bluetooth chipsets only support paging a single device at
> a time, and if they don't reject a secondary "Create Connection" request
> while another is still ongoing, they'll most likely serialize those
> requests in the firware.
>
> With commit 4c67bc74f016 ("[Bluetooth] Support concurrent connect
> requests") we started adding some serialization of our own in case the
> adapter returns "Command Disallowed" HCI error.
>
> This commit was using the BT_CONNECT2 state for the serialization, this
> state is also used for a few more things (most notably to indicate we're
> waiting for an inquiry to cancel) and therefore a bit unreliable. Also
> not all BT firwares would respond with "Command Disallowed" on too many
> connection requests, some will also respond with "Hardware Failure"
> (BCM4378), and others will error out later and send a "Connect Complete"
> event with error "Rejected Limited Resources" (Marvell 88W8897).
>
> We can clean things up a bit and also make the serialization more reliable
> by using our hci_sync machinery to always do "Create Connection" requests
> in a sequential manner.
>
> This is very similar to what we're already doing for establishing LE
> connections, and it works well there.
> ---
>  include/net/bluetooth/hci.h |  1 +
>  net/bluetooth/hci_conn.c    | 37 ++++++++++++++++++++++++++-----------
>  2 files changed, 27 insertions(+), 11 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index fef723afd..f2bbc0a14 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -427,6 +427,7 @@ enum {
>  #define HCI_ACL_TX_TIMEOUT     msecs_to_jiffies(45000) /* 45 seconds */
>  #define HCI_AUTO_OFF_TIMEOUT   msecs_to_jiffies(2000)  /* 2 seconds */
>  #define HCI_POWER_OFF_TIMEOUT  msecs_to_jiffies(5000)  /* 5 seconds */
> +#define HCI_ACL_CONN_TIMEOUT   msecs_to_jiffies(20000) /* 20 seconds */
>  #define HCI_LE_CONN_TIMEOUT    msecs_to_jiffies(20000) /* 20 seconds */
>  #define HCI_LE_AUTOCONN_TIMEOUT        msecs_to_jiffies(4000)  /* 4 seconds */
>
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 76222565e..541d55301 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -229,11 +229,12 @@ static void hci_connect_le_scan_remove(struct hci_conn *conn)
>         schedule_work(&conn->le_scan_cleanup);
>  }
>
> -static void hci_acl_create_connection(struct hci_conn *conn)
> +static int hci_acl_create_connection_sync(struct hci_dev *hdev, void *data)

Move the above function to hci_sync.c so it is simpler to reuse it in
the future.

>  {
> -       struct hci_dev *hdev = conn->hdev;
> +       struct hci_conn *conn = data;
>         struct inquiry_entry *ie;
>         struct hci_cp_create_conn cp;
> +       int err;
>
>         BT_DBG("hcon %p", conn);
>
> @@ -246,12 +247,10 @@ static void hci_acl_create_connection(struct hci_conn *conn)
>          * request for discovery again when this flag becomes false.
>          */
>         if (test_bit(HCI_INQUIRY, &hdev->flags)) {
> -               /* Put this connection to "pending" state so that it will be
> -                * executed after the inquiry cancel command complete event.
> -                */
> -               conn->state = BT_CONNECT2;
> -               hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
> -               return;
> +               err = __hci_cmd_sync_status(hdev, HCI_OP_INQUIRY_CANCEL, 0,
> +                                           NULL, HCI_CMD_TIMEOUT);
> +               if (err)
> +                       bt_dev_warn(hdev, "Failed to cancel inquiry %d", err);
>         }
>
>         conn->state = BT_CONNECT;
> @@ -284,7 +283,15 @@ static void hci_acl_create_connection(struct hci_conn *conn)
>         else
>                 cp.role_switch = 0x00;
>
> -       hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
> +       err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
> +                                      sizeof(cp), &cp,
> +                                      HCI_EV_CONN_COMPLETE,
> +                                      HCI_ACL_CONN_TIMEOUT, NULL);
> +
> +       if (err == -ETIMEDOUT)
> +               hci_abort_conn(conn, HCI_ERROR_LOCAL_HOST_TERM);
> +
> +       return err;
>  }
>
>  int hci_disconnect(struct hci_conn *conn, __u8 reason)
> @@ -1622,10 +1629,18 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
>
>         acl->conn_reason = conn_reason;
>         if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
> +               int err;
> +
>                 acl->sec_level = BT_SECURITY_LOW;
>                 acl->pending_sec_level = sec_level;
>                 acl->auth_type = auth_type;
> -               hci_acl_create_connection(acl);
> +
> +               err = hci_cmd_sync_queue(hdev, hci_acl_create_connection_sync,
> +                                        acl, NULL);
> +               if (err) {
> +                       hci_conn_del(acl);
> +                       return ERR_PTR(err);
> +               }
>         }
>
>         return acl;
> @@ -2530,7 +2545,7 @@ void hci_conn_check_pending(struct hci_dev *hdev)
>
>         conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
>         if (conn)
> -               hci_acl_create_connection(conn);
> +               hci_cmd_sync_queue(hdev, hci_acl_create_connection_sync, conn, NULL);
>
>         hci_dev_unlock(hdev);
>  }
> --
> 2.43.0
>


-- 
Luiz Augusto von Dentz





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux