From patchwork Tue Jul 27 23:51:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tedd Ho-Jeong An X-Patchwork-Id: 486863 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2418C4338F for ; Tue, 27 Jul 2021 23:51:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9931860F9C for ; Tue, 27 Jul 2021 23:51:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232956AbhG0Xvn (ORCPT ); Tue, 27 Jul 2021 19:51:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232766AbhG0Xvn (ORCPT ); Tue, 27 Jul 2021 19:51:43 -0400 Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A4F5AC061757 for ; Tue, 27 Jul 2021 16:51:41 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id b6so2383335pji.4 for ; Tue, 27 Jul 2021 16:51:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RoMZyv4TQqJ9vQuH666cg9xWrRSijabmEdIpEtBdFco=; b=POhH4LVo/oBvuJU8aDTo18xUeW70bVNR5e6y21+jHjPczCy2M8UtMACgCAwSY/RA/B P2UOuZEJcVcXKVJV1LNLvJvNFv1yw0mrmuRxeTXnrk2L/ZADL4U4N/8BDcG8YySdy2V/ /vvo9mvn5IVm2zuq7UhqWGvv+ulrB89CGo57mUnCtK5x8nzijCaCyyloaUqkgEewZIqi /xw6P5ek4giJab5N0rW5m2cjOCokINbwHEvS6Dykcwd/jQVHyFsSbq0Jx65YPq2U3LSu pSLpmRC7o2fQmoASkgR3ZDTyvTdaws2TaAJON9uueQ4uWIT7wT1DBRz7UIOpENh3os1K TB0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RoMZyv4TQqJ9vQuH666cg9xWrRSijabmEdIpEtBdFco=; b=OzJMunToZobqY68e8nvYhRRRg4qBdRXTYDuvKZhl2saKExvoWwNacTdUstAYhtIoHI +I9ooZl0CexYpwk+eHO/vSQU3FOCkiHWZ18qazLfYAIhGTe3LmBYcYObTIdUOeW8h3ZW G+TYKA5G09CsPCwgdsCe9jDXKPM6lA+ApNu8PRGVip4Qy7v80OUlPsMSPAdGYwKSdFTk e9YkoiOKxu9OFIGDVu/Y3VAWJwv+2+FTsvyf3KR8J0W2NxUylZfXDUCy0HPePdM3t5k8 0v2GyX3gt+IkyWGYCe2hiChwwId5WaWTjtud/rIrzLXraiRzjZonJcDCbMD2PnctaB+4 wvEA== X-Gm-Message-State: AOAM532S6ZP/rEK7eGI39KVFB9KuoklqZGh+5gho51yofmaSvsvUHqjO YxhEgplboiCRf95QMc79dZf6J5laiOo= X-Google-Smtp-Source: ABdhPJwtM0WmuUX++26D1AB5h9UOeri4GxvDQtMrLl+0XCY8ovjDSJYY/E6nk2B5wG6GJsmsMIWPqQ== X-Received: by 2002:a17:90a:fa1:: with SMTP id 30mr6609866pjz.42.1627429900886; Tue, 27 Jul 2021 16:51:40 -0700 (PDT) Received: from localhost.localdomain ([2601:1c0:6a01:d830::7cb2]) by smtp.gmail.com with ESMTPSA id y9sm1545332pfq.199.2021.07.27.16.51.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jul 2021 16:51:40 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Cc: Tedd Ho-Jeong An Subject: [RFC PATCH v4 01/11] Bluetooth: Add support hdev to allocate private data Date: Tue, 27 Jul 2021 16:51:17 -0700 Message-Id: <20210727235127.173149-2-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210727235127.173149-1-hj.tedd.an@gmail.com> References: <20210727235127.173149-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An This patch adds support hdev to allocate extra size for private data. The size of private data is specified in the hdev_alloc_size(priv_size) and the allocated buffer can be accessed with hci_get_priv(hdev). Signed-off-by: Tedd Ho-Jeong An --- drivers/bluetooth/bfusb.c | 2 +- drivers/bluetooth/bluecard_cs.c | 2 +- drivers/bluetooth/bpa10x.c | 2 +- drivers/bluetooth/bt3c_cs.c | 2 +- drivers/bluetooth/btmrvl_main.c | 2 +- drivers/bluetooth/btmtksdio.c | 2 +- drivers/bluetooth/btmtkuart.c | 2 +- drivers/bluetooth/btqcomsmd.c | 2 +- drivers/bluetooth/btrsi.c | 2 +- drivers/bluetooth/btsdio.c | 2 +- drivers/bluetooth/btusb.c | 2 +- drivers/bluetooth/dtl1_cs.c | 2 +- drivers/bluetooth/hci_ldisc.c | 2 +- drivers/bluetooth/hci_serdev.c | 2 +- drivers/bluetooth/hci_vhci.c | 2 +- drivers/bluetooth/virtio_bt.c | 2 +- include/net/bluetooth/hci_core.h | 7 ++++++- net/bluetooth/hci_core.c | 11 +++++++++-- 18 files changed, 31 insertions(+), 19 deletions(-) diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 5a321b4076aa..430e230999fa 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -651,7 +651,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i release_firmware(firmware); /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); goto done; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 36eabf61717f..d62b878aff7e 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -694,7 +694,7 @@ static int bluecard_open(struct bluecard_info *info) info->rx_skb = NULL; /* Initialize HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 1fa58c059cbf..bd670352a336 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -380,7 +380,7 @@ static int bpa10x_probe(struct usb_interface *intf, init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->rx_anchor); - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) return -ENOMEM; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 54713833951a..cd135a736688 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -550,7 +550,7 @@ static int bt3c_open(struct bt3c_info *info) info->rx_skb = NULL; /* Initialize HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 8b9d78ce6bb2..0157fa4ce528 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -680,7 +680,7 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; int ret; - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can not allocate HCI device"); goto err_hdev; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 9872ef18f9fe..b48aec25c09d 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -959,7 +959,7 @@ static int btmtksdio_probe(struct sdio_func *func, skb_queue_head_init(&bdev->txq); /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { dev_err(&func->dev, "Can't allocate HCI device\n"); return -ENOMEM; diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index e9d91d7c0db4..96ee364507c5 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -987,7 +987,7 @@ static int btmtkuart_probe(struct serdev_device *serdev) skb_queue_head_init(&bdev->txq); /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { dev_err(&serdev->dev, "Can't allocate HCI device\n"); return -ENOMEM; diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 2acb719e596f..47aaffceb8c1 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -147,7 +147,7 @@ static int btqcomsmd_probe(struct platform_device *pdev) goto destroy_acl_channel; } - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { ret = -ENOMEM; goto destroy_cmd_channel; diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c index 8646b6dd11e9..2f8d186e4807 100644 --- a/drivers/bluetooth/btrsi.c +++ b/drivers/bluetooth/btrsi.c @@ -121,7 +121,7 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) ops->set_bt_context(priv, h_adapter); h_adapter->proto_ops = ops; - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Failed to alloc HCI device"); goto err; diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index 199e8f7d426d..69d2a26ed5db 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -310,7 +310,7 @@ static int btsdio_probe(struct sdio_func *func, skb_queue_head_init(&data->txq); - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) return -ENOMEM; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 1876a960b3dc..baf0934657d8 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4575,7 +4575,7 @@ static int btusb_probe(struct usb_interface *intf, data->recv_bulk = btusb_recv_bulk; } - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) return -ENOMEM; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 2adfe4fade76..f06c8151f0ea 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -449,7 +449,7 @@ static int dtl1_open(struct dtl1_info *info) set_bit(XMIT_WAITING, &(info->tx_state)); /* Initialize HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 5ed2cfa7da1d..89eb9d7685ae 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -627,7 +627,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) BT_DBG(""); /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 3b00d82d36cf..327fa2ecc5e7 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -313,7 +313,7 @@ int hci_uart_register_device(struct hci_uart *hu, set_bit(HCI_UART_PROTO_READY, &hu->flags); /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { BT_ERR("Can't allocate HCI device"); err = -ENOMEM; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 8ab26dec5f6e..5486aa3945da 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -96,7 +96,7 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) if (!skb) return -ENOMEM; - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { kfree_skb(skb); return -ENOMEM; diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c index 57908ce4fae8..28576ec4860e 100644 --- a/drivers/bluetooth/virtio_bt.c +++ b/drivers/bluetooth/virtio_bt.c @@ -283,7 +283,7 @@ static int virtbt_probe(struct virtio_device *vdev) if (err) return err; - hdev = hci_alloc_dev(); + hdev = hci_alloc_dev(0); if (!hdev) { err = -ENOMEM; goto failed; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a53e94459ecd..5c689c5dc089 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1223,10 +1223,15 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data) dev_set_drvdata(&hdev->dev, data); } +static inline void *hci_get_priv(struct hci_dev *hdev) +{ + return (char *)hdev + sizeof(*hdev); +} + struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, u8 src_type); -struct hci_dev *hci_alloc_dev(void); +struct hci_dev *hci_alloc_dev(int sizeof_priv); void hci_free_dev(struct hci_dev *hdev); int hci_register_dev(struct hci_dev *hdev); void hci_unregister_dev(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2560ed2f144d..66b72c7efa3d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3751,11 +3751,18 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action, } /* Alloc HCI device */ -struct hci_dev *hci_alloc_dev(void) +struct hci_dev *hci_alloc_dev(int sizeof_priv) { struct hci_dev *hdev; + unsigned int alloc_size; - hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + alloc_size = sizeof(*hdev); + if (sizeof_priv) { + /* Fixme: May need ALIGN-ment? */ + alloc_size += sizeof_priv; + } + + hdev = kzalloc(alloc_size, GFP_KERNEL); if (!hdev) return NULL; From patchwork Tue Jul 27 23:51:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tedd Ho-Jeong An X-Patchwork-Id: 486862 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8A333C4320A for ; Tue, 27 Jul 2021 23:51:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 68BB960F93 for ; Tue, 27 Jul 2021 23:51:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233132AbhG0Xvp (ORCPT ); Tue, 27 Jul 2021 19:51:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37196 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232983AbhG0Xvo (ORCPT ); Tue, 27 Jul 2021 19:51:44 -0400 Received: from mail-pj1-x1036.google.com (mail-pj1-x1036.google.com [IPv6:2607:f8b0:4864:20::1036]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1A544C061757 for ; Tue, 27 Jul 2021 16:51:43 -0700 (PDT) Received: by mail-pj1-x1036.google.com with SMTP id b6so2383414pji.4 for ; Tue, 27 Jul 2021 16:51:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=uybIKVPM4hp9SywafLYCli1GHjZzX15ud3br2iWGeUU=; b=H87g7gerkRMb824X13goNJ95X97gh92MvaYYiVt7GvKiTarlh6U6DeeeCY4Hf7ozvi 4KedmNoLI8Z0HrCNR5XNGZxZXjUTQAH0HOy368w8zEgXwsHH5WRW8xDlzMAhl2zSYN6N l9HhmJvLnNsPH2NJculFVaNQFSj5jhqfC0wv+n/7iLODmXI6wiI2G32efZpWXXMqgDQf oHxNnzhFr4uVhluwKiCZ7w48ZhXboWllD+wXk04s3ERqXbEgGAfjVVEMIut0gZH67cLz ylt7sfqsau98Jxbw+60xwWaxyMW3tHGKPWftRI/Xa1rcqUsa2QAVv22bU1z+vwIfDokZ qa7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=uybIKVPM4hp9SywafLYCli1GHjZzX15ud3br2iWGeUU=; b=Wq0mYstBTni/pO3JlwGORvR6AYk5pqSFLcoCEOjni3RtRjlC3eJDfThoPdteJyCjFw CfSYjewZd7zBk8sVdCoryRQCCRQoT1dJWm8D88as/f1aZH0schRHRfY2qX9egqS6swK/ NHCAkr+y6jSPLVdvaejN4zdn+LQbuz6225m9rp0mZdVwxbY+Tu1tZtN8kQsGx/FHooJ1 OGHjXJ+yYpThsSDDKfR/bIUjtgvTQD9mOb2vygDZ1TLCDsHPwO/YBBUGUiYzR+8eAQEp b9owS6Tk3s/WxtPErJ95M5+o6JOLAPAJhV7AMiOG1Wr2N1Qi7WWpXQ/X5oXJiv0nFHPF XebQ== X-Gm-Message-State: AOAM532T3BEo2xPmU/FwHX5ZXSyp7+ppIQIHZgQuPGev0+sfvgL3vRtt 2AQhIuv4uXeZTIQ5V1ME2aPxpnJV7jw= X-Google-Smtp-Source: ABdhPJz/IApKKAXYV1p0M/DJZRkdTvbBcH9wptfn69axHrO/LjuTqYUJA5YreaM9BcZ2g/cWUBHg+A== X-Received: by 2002:a05:6a00:882:b029:354:a616:7fbb with SMTP id q2-20020a056a000882b0290354a6167fbbmr25209422pfj.2.1627429902258; Tue, 27 Jul 2021 16:51:42 -0700 (PDT) Received: from localhost.localdomain ([2601:1c0:6a01:d830::7cb2]) by smtp.gmail.com with ESMTPSA id y9sm1545332pfq.199.2021.07.27.16.51.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jul 2021 16:51:41 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Cc: Tedd Ho-Jeong An Subject: [RFC PATCH v4 03/11] Bluetooth: btintel: Refactoring setup routine for legacy ROM sku Date: Tue, 27 Jul 2021 16:51:19 -0700 Message-Id: <20210727235127.173149-4-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210727235127.173149-1-hj.tedd.an@gmail.com> References: <20210727235127.173149-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An This patch refactors the setup routines for legacy ROM product into combined setup, and move the related functions from btusb to btintel. Signed-off-by: Tedd Ho-Jeong An --- drivers/bluetooth/btintel.c | 287 +++++++++++++++++++++++++++- drivers/bluetooth/btusb.c | 362 +----------------------------------- 2 files changed, 294 insertions(+), 355 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index a23304435814..cfc097694b53 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1372,6 +1372,291 @@ int btintel_set_debug_features(struct hci_dev *hdev, } EXPORT_SYMBOL_GPL(btintel_set_debug_features); +static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev, + struct intel_version *ver) +{ + const struct firmware *fw; + char fwname[64]; + int ret; + + snprintf(fwname, sizeof(fwname), + "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq", + ver->hw_platform, ver->hw_variant, ver->hw_revision, + ver->fw_variant, ver->fw_revision, ver->fw_build_num, + ver->fw_build_ww, ver->fw_build_yy); + + ret = request_firmware(&fw, fwname, &hdev->dev); + if (ret < 0) { + if (ret == -EINVAL) { + bt_dev_err(hdev, "Intel firmware file request failed (%d)", + ret); + return NULL; + } + + bt_dev_err(hdev, "failed to open Intel firmware file: %s (%d)", + fwname, ret); + + /* If the correct firmware patch file is not found, use the + * default firmware patch file instead + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq", + ver->hw_platform, ver->hw_variant); + if (request_firmware(&fw, fwname, &hdev->dev) < 0) { + bt_dev_err(hdev, "failed to open default fw file: %s", + fwname); + return NULL; + } + } + + bt_dev_info(hdev, "Intel Bluetooth firmware file: %s", fwname); + + return fw; +} + +static int btintel_legacy_rom_patching(struct hci_dev *hdev, + const struct firmware *fw, + const u8 **fw_ptr, int *disable_patch) +{ + struct sk_buff *skb; + struct hci_command_hdr *cmd; + const u8 *cmd_param; + struct hci_event_hdr *evt = NULL; + const u8 *evt_param = NULL; + int remain = fw->size - (*fw_ptr - fw->data); + + /* The first byte indicates the types of the patch command or event. + * 0x01 means HCI command and 0x02 is HCI event. If the first bytes + * in the current firmware buffer doesn't start with 0x01 or + * the size of remain buffer is smaller than HCI command header, + * the firmware file is corrupted and it should stop the patching + * process. + */ + if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) { + bt_dev_err(hdev, "Intel fw corrupted: invalid cmd read"); + return -EINVAL; + } + (*fw_ptr)++; + remain--; + + cmd = (struct hci_command_hdr *)(*fw_ptr); + *fw_ptr += sizeof(*cmd); + remain -= sizeof(*cmd); + + /* Ensure that the remain firmware data is long enough than the length + * of command parameter. If not, the firmware file is corrupted. + */ + if (remain < cmd->plen) { + bt_dev_err(hdev, "Intel fw corrupted: invalid cmd len"); + return -EFAULT; + } + + /* If there is a command that loads a patch in the firmware + * file, then enable the patch upon success, otherwise just + * disable the manufacturer mode, for example patch activation + * is not required when the default firmware patch file is used + * because there are no patch data to load. + */ + if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e) + *disable_patch = 0; + + cmd_param = *fw_ptr; + *fw_ptr += cmd->plen; + remain -= cmd->plen; + + /* This reads the expected events when the above command is sent to the + * device. Some vendor commands expects more than one events, for + * example command status event followed by vendor specific event. + * For this case, it only keeps the last expected event. so the command + * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of + * last expected event. + */ + while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) { + (*fw_ptr)++; + remain--; + + evt = (struct hci_event_hdr *)(*fw_ptr); + *fw_ptr += sizeof(*evt); + remain -= sizeof(*evt); + + if (remain < evt->plen) { + bt_dev_err(hdev, "Intel fw corrupted: invalid evt len"); + return -EFAULT; + } + + evt_param = *fw_ptr; + *fw_ptr += evt->plen; + remain -= evt->plen; + } + + /* Every HCI commands in the firmware file has its correspond event. + * If event is not found or remain is smaller than zero, the firmware + * file is corrupted. + */ + if (!evt || !evt_param || remain < 0) { + bt_dev_err(hdev, "Intel fw corrupted: invalid evt read"); + return -EFAULT; + } + + skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen, + cmd_param, evt->evt, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "sending Intel patch command (0x%4.4x) failed (%ld)", + cmd->opcode, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + /* It ensures that the returned event matches the event data read from + * the firmware file. At fist, it checks the length and then + * the contents of the event. + */ + if (skb->len != evt->plen) { + bt_dev_err(hdev, "mismatch event length (opcode 0x%4.4x)", + le16_to_cpu(cmd->opcode)); + kfree_skb(skb); + return -EFAULT; + } + + if (memcmp(skb->data, evt_param, evt->plen)) { + bt_dev_err(hdev, "mismatch event parameter (opcode 0x%4.4x)", + le16_to_cpu(cmd->opcode)); + kfree_skb(skb); + return -EFAULT; + } + kfree_skb(skb); + + return 0; +} + +static int btintel_legacy_rom_setup(struct hci_dev *hdev, + struct intel_version *ver) +{ + const struct firmware *fw; + const u8 *fw_ptr; + int disable_patch, err; + struct intel_version new_ver; + + BT_DBG("%s", hdev->name); + + /* fw_patch_num indicates the version of patch the device currently + * have. If there is no patch data in the device, it is always 0x00. + * So, if it is other than 0x00, no need to patch the device again. + */ + if (ver->fw_patch_num) { + bt_dev_info(hdev, + "Intel device is already patched. patch num: %02x", + ver->fw_patch_num); + goto complete; + } + + /* Opens the firmware patch file based on the firmware version read + * from the controller. If it fails to open the matching firmware + * patch file, it tries to open the default firmware patch file. + * If no patch file is found, allow the device to operate without + * a patch. + */ + fw = btintel_legacy_rom_get_fw(hdev, ver); + if (!fw) + goto complete; + fw_ptr = fw->data; + + /* Enable the manufacturer mode of the controller. + * Only while this mode is enabled, the driver can download the + * firmware patch data and configuration parameters. + */ + err = btintel_enter_mfg(hdev); + if (err) { + release_firmware(fw); + return err; + } + + disable_patch = 1; + + /* The firmware data file consists of list of Intel specific HCI + * commands and its expected events. The first byte indicates the + * type of the message, either HCI command or HCI event. + * + * It reads the command and its expected event from the firmware file, + * and send to the controller. Once __hci_cmd_sync_ev() returns, + * the returned event is compared with the event read from the firmware + * file and it will continue until all the messages are downloaded to + * the controller. + * + * Once the firmware patching is completed successfully, + * the manufacturer mode is disabled with reset and activating the + * downloaded patch. + * + * If the firmware patching fails, the manufacturer mode is + * disabled with reset and deactivating the patch. + * + * If the default patch file is used, no reset is done when disabling + * the manufacturer. + */ + while (fw->size > fw_ptr - fw->data) { + int ret; + + ret = btintel_legacy_rom_patching(hdev, fw, &fw_ptr, + &disable_patch); + if (ret < 0) + goto exit_mfg_deactivate; + } + + release_firmware(fw); + + if (disable_patch) + goto exit_mfg_disable; + + /* Patching completed successfully and disable the manufacturer mode + * with reset and activate the downloaded firmware patches. + */ + err = btintel_exit_mfg(hdev, true, true); + if (err) + return err; + + /* Need build number for downloaded fw patches in + * every power-on boot + */ + err = btintel_read_version(hdev, &new_ver); + if (err) + return err; + + bt_dev_info(hdev, "Intel BT fw patch 0x%02x completed & activated", + new_ver.fw_patch_num); + + goto complete; + +exit_mfg_disable: + /* Disable the manufacturer mode without reset */ + err = btintel_exit_mfg(hdev, false, false); + if (err) + return err; + + bt_dev_info(hdev, "Intel firmware patch completed"); + + goto complete; + +exit_mfg_deactivate: + release_firmware(fw); + + /* Patching failed. Disable the manufacturer mode with reset and + * deactivate the downloaded firmware patches. + */ + err = btintel_exit_mfg(hdev, true, false); + if (err) + return err; + + bt_dev_info(hdev, "Intel firmware patch completed and deactivated"); + +complete: + /* Set the event mask for Intel specific vendor events. This enables + * a few extra events that are useful during general operation. + */ + btintel_set_event_mask_mfg(hdev, false); + + btintel_check_bdaddr(hdev); + + return 0; +} + int btintel_setup_combined(struct hci_dev *hdev) { const u8 param[1] = { 0xFF }; @@ -1417,7 +1702,7 @@ int btintel_setup_combined(struct hci_dev *hdev) case 0x07: /* WP */ case 0x08: /* StP */ /* Legacy ROM product */ - /* TODO: call setup routine for legacy rom product */ + err = btintel_legacy_rom_setup(hdev, &ver); break; case 0x0b: /* SfP */ case 0x0c: /* WsP */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index baf0934657d8..3382d75b1969 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -61,6 +61,7 @@ static struct usb_driver btusb_driver; #define BTUSB_VALID_LE_STATES 0x800000 #define BTUSB_QCA_WCN6855 0x1000000 #define BTUSB_INTEL_NEWGEN 0x2000000 +#define BTUSB_INTEL_COMBINED 0x4000000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -375,11 +376,11 @@ static const struct usb_device_id blacklist_table[] = { BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, - { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, - { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL | + { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW | BTUSB_WIDEBAND_SPEECH | @@ -1962,319 +1963,6 @@ static int btusb_setup_csr(struct hci_dev *hdev) return 0; } -static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, - struct intel_version *ver) -{ - const struct firmware *fw; - char fwname[64]; - int ret; - - snprintf(fwname, sizeof(fwname), - "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq", - ver->hw_platform, ver->hw_variant, ver->hw_revision, - ver->fw_variant, ver->fw_revision, ver->fw_build_num, - ver->fw_build_ww, ver->fw_build_yy); - - ret = request_firmware(&fw, fwname, &hdev->dev); - if (ret < 0) { - if (ret == -EINVAL) { - bt_dev_err(hdev, "Intel firmware file request failed (%d)", - ret); - return NULL; - } - - bt_dev_err(hdev, "failed to open Intel firmware file: %s (%d)", - fwname, ret); - - /* If the correct firmware patch file is not found, use the - * default firmware patch file instead - */ - snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq", - ver->hw_platform, ver->hw_variant); - if (request_firmware(&fw, fwname, &hdev->dev) < 0) { - bt_dev_err(hdev, "failed to open default fw file: %s", - fwname); - return NULL; - } - } - - bt_dev_info(hdev, "Intel Bluetooth firmware file: %s", fwname); - - return fw; -} - -static int btusb_setup_intel_patching(struct hci_dev *hdev, - const struct firmware *fw, - const u8 **fw_ptr, int *disable_patch) -{ - struct sk_buff *skb; - struct hci_command_hdr *cmd; - const u8 *cmd_param; - struct hci_event_hdr *evt = NULL; - const u8 *evt_param = NULL; - int remain = fw->size - (*fw_ptr - fw->data); - - /* The first byte indicates the types of the patch command or event. - * 0x01 means HCI command and 0x02 is HCI event. If the first bytes - * in the current firmware buffer doesn't start with 0x01 or - * the size of remain buffer is smaller than HCI command header, - * the firmware file is corrupted and it should stop the patching - * process. - */ - if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) { - bt_dev_err(hdev, "Intel fw corrupted: invalid cmd read"); - return -EINVAL; - } - (*fw_ptr)++; - remain--; - - cmd = (struct hci_command_hdr *)(*fw_ptr); - *fw_ptr += sizeof(*cmd); - remain -= sizeof(*cmd); - - /* Ensure that the remain firmware data is long enough than the length - * of command parameter. If not, the firmware file is corrupted. - */ - if (remain < cmd->plen) { - bt_dev_err(hdev, "Intel fw corrupted: invalid cmd len"); - return -EFAULT; - } - - /* If there is a command that loads a patch in the firmware - * file, then enable the patch upon success, otherwise just - * disable the manufacturer mode, for example patch activation - * is not required when the default firmware patch file is used - * because there are no patch data to load. - */ - if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e) - *disable_patch = 0; - - cmd_param = *fw_ptr; - *fw_ptr += cmd->plen; - remain -= cmd->plen; - - /* This reads the expected events when the above command is sent to the - * device. Some vendor commands expects more than one events, for - * example command status event followed by vendor specific event. - * For this case, it only keeps the last expected event. so the command - * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of - * last expected event. - */ - while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) { - (*fw_ptr)++; - remain--; - - evt = (struct hci_event_hdr *)(*fw_ptr); - *fw_ptr += sizeof(*evt); - remain -= sizeof(*evt); - - if (remain < evt->plen) { - bt_dev_err(hdev, "Intel fw corrupted: invalid evt len"); - return -EFAULT; - } - - evt_param = *fw_ptr; - *fw_ptr += evt->plen; - remain -= evt->plen; - } - - /* Every HCI commands in the firmware file has its correspond event. - * If event is not found or remain is smaller than zero, the firmware - * file is corrupted. - */ - if (!evt || !evt_param || remain < 0) { - bt_dev_err(hdev, "Intel fw corrupted: invalid evt read"); - return -EFAULT; - } - - skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen, - cmd_param, evt->evt, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - bt_dev_err(hdev, "sending Intel patch command (0x%4.4x) failed (%ld)", - cmd->opcode, PTR_ERR(skb)); - return PTR_ERR(skb); - } - - /* It ensures that the returned event matches the event data read from - * the firmware file. At fist, it checks the length and then - * the contents of the event. - */ - if (skb->len != evt->plen) { - bt_dev_err(hdev, "mismatch event length (opcode 0x%4.4x)", - le16_to_cpu(cmd->opcode)); - kfree_skb(skb); - return -EFAULT; - } - - if (memcmp(skb->data, evt_param, evt->plen)) { - bt_dev_err(hdev, "mismatch event parameter (opcode 0x%4.4x)", - le16_to_cpu(cmd->opcode)); - kfree_skb(skb); - return -EFAULT; - } - kfree_skb(skb); - - return 0; -} - -static int btusb_setup_intel(struct hci_dev *hdev) -{ - struct sk_buff *skb; - const struct firmware *fw; - const u8 *fw_ptr; - int disable_patch, err; - struct intel_version ver; - - BT_DBG("%s", hdev->name); - - /* The controller has a bug with the first HCI command sent to it - * returning number of completed commands as zero. This would stall the - * command processing in the Bluetooth core. - * - * As a workaround, send HCI Reset command first which will reset the - * number of completed commands and allow normal command processing - * from now on. - */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - bt_dev_err(hdev, "sending initial HCI reset command failed (%ld)", - PTR_ERR(skb)); - return PTR_ERR(skb); - } - kfree_skb(skb); - - /* Read Intel specific controller version first to allow selection of - * which firmware file to load. - * - * The returned information are hardware variant and revision plus - * firmware variant, revision and build number. - */ - err = btintel_read_version(hdev, &ver); - if (err) - return err; - - bt_dev_info(hdev, "read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x", - ver.hw_platform, ver.hw_variant, ver.hw_revision, - ver.fw_variant, ver.fw_revision, ver.fw_build_num, - ver.fw_build_ww, ver.fw_build_yy, ver.fw_patch_num); - - /* fw_patch_num indicates the version of patch the device currently - * have. If there is no patch data in the device, it is always 0x00. - * So, if it is other than 0x00, no need to patch the device again. - */ - if (ver.fw_patch_num) { - bt_dev_info(hdev, "Intel device is already patched. " - "patch num: %02x", ver.fw_patch_num); - goto complete; - } - - /* Opens the firmware patch file based on the firmware version read - * from the controller. If it fails to open the matching firmware - * patch file, it tries to open the default firmware patch file. - * If no patch file is found, allow the device to operate without - * a patch. - */ - fw = btusb_setup_intel_get_fw(hdev, &ver); - if (!fw) - goto complete; - fw_ptr = fw->data; - - /* Enable the manufacturer mode of the controller. - * Only while this mode is enabled, the driver can download the - * firmware patch data and configuration parameters. - */ - err = btintel_enter_mfg(hdev); - if (err) { - release_firmware(fw); - return err; - } - - disable_patch = 1; - - /* The firmware data file consists of list of Intel specific HCI - * commands and its expected events. The first byte indicates the - * type of the message, either HCI command or HCI event. - * - * It reads the command and its expected event from the firmware file, - * and send to the controller. Once __hci_cmd_sync_ev() returns, - * the returned event is compared with the event read from the firmware - * file and it will continue until all the messages are downloaded to - * the controller. - * - * Once the firmware patching is completed successfully, - * the manufacturer mode is disabled with reset and activating the - * downloaded patch. - * - * If the firmware patching fails, the manufacturer mode is - * disabled with reset and deactivating the patch. - * - * If the default patch file is used, no reset is done when disabling - * the manufacturer. - */ - while (fw->size > fw_ptr - fw->data) { - int ret; - - ret = btusb_setup_intel_patching(hdev, fw, &fw_ptr, - &disable_patch); - if (ret < 0) - goto exit_mfg_deactivate; - } - - release_firmware(fw); - - if (disable_patch) - goto exit_mfg_disable; - - /* Patching completed successfully and disable the manufacturer mode - * with reset and activate the downloaded firmware patches. - */ - err = btintel_exit_mfg(hdev, true, true); - if (err) - return err; - - /* Need build number for downloaded fw patches in - * every power-on boot - */ - err = btintel_read_version(hdev, &ver); - if (err) - return err; - bt_dev_info(hdev, "Intel BT fw patch 0x%02x completed & activated", - ver.fw_patch_num); - - goto complete; - -exit_mfg_disable: - /* Disable the manufacturer mode without reset */ - err = btintel_exit_mfg(hdev, false, false); - if (err) - return err; - - bt_dev_info(hdev, "Intel firmware patch completed"); - - goto complete; - -exit_mfg_deactivate: - release_firmware(fw); - - /* Patching failed. Disable the manufacturer mode with reset and - * deactivate the downloaded firmware patches. - */ - err = btintel_exit_mfg(hdev, true, false); - if (err) - return err; - - bt_dev_info(hdev, "Intel firmware patch completed and deactivated"); - -complete: - /* Set the event mask for Intel specific vendor events. This enables - * a few extra events that are useful during general operation. - */ - btintel_set_event_mask_mfg(hdev, false); - - btintel_check_bdaddr(hdev); - return 0; -} - static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) { struct sk_buff *skb; @@ -3042,41 +2730,6 @@ static int btusb_setup_intel_newgen(struct hci_dev *hdev) return 0; } -static int btusb_shutdown_intel(struct hci_dev *hdev) -{ - struct sk_buff *skb; - long ret; - - /* In the shutdown sequence where Bluetooth is turned off followed - * by WiFi being turned off, turning WiFi back on causes issue with - * the RF calibration. - * - * To ensure that any RF activity has been stopped, issue HCI Reset - * command to clear all ongoing activity including advertising, - * scanning etc. - */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - bt_dev_err(hdev, "HCI reset during shutdown failed"); - return ret; - } - kfree_skb(skb); - - /* Some platforms have an issue with BT LED when the interface is - * down or BT radio is turned off, which takes 5 seconds to BT LED - * goes off. This command turns off the BT LED immediately. - */ - skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - bt_dev_err(hdev, "turning off Intel device LED failed"); - return ret; - } - kfree_skb(skb); - - return 0; -} static int btusb_shutdown_intel_new(struct hci_dev *hdev) { @@ -4649,10 +4302,11 @@ static int btusb_probe(struct usb_interface *intf, data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2); } - if (id->driver_info & BTUSB_INTEL) { + /* Combined Intel Device setup to support multiple setup routine */ + if (id->driver_info & BTUSB_INTEL_COMBINED) { hdev->manufacturer = 2; - hdev->setup = btusb_setup_intel; - hdev->shutdown = btusb_shutdown_intel; + hdev->setup = btintel_setup_combined; + hdev->shutdown = btintel_shutdown_combined; hdev->set_diag = btintel_set_diag_mfg; hdev->set_bdaddr = btintel_set_bdaddr; hdev->cmd_timeout = btusb_intel_cmd_timeout; From patchwork Tue Jul 27 23:51:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tedd Ho-Jeong An X-Patchwork-Id: 486861 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 53724C4320E for ; Tue, 27 Jul 2021 23:51:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 392A260FD8 for ; Tue, 27 Jul 2021 23:51:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233449AbhG0Xvs (ORCPT ); Tue, 27 Jul 2021 19:51:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37208 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233412AbhG0Xvp (ORCPT ); Tue, 27 Jul 2021 19:51:45 -0400 Received: from mail-pj1-x102f.google.com (mail-pj1-x102f.google.com [IPv6:2607:f8b0:4864:20::102f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA720C061757 for ; Tue, 27 Jul 2021 16:51:44 -0700 (PDT) Received: by mail-pj1-x102f.google.com with SMTP id mz5-20020a17090b3785b0290176ecf64922so7223234pjb.3 for ; Tue, 27 Jul 2021 16:51:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ylIJAmp+yr1bvyYwwG8PQSq7oO8H0eUvt5uuIq7+q+4=; b=Oi5Ojwywb/uI7I2MdJPBNyXegskfjr58cAFmnL7qzzgLXUj6WfAyM5jyS53YduERYs 5RciH5I8gw0wJW3hkagK44q0mV9TwArBNYEtiCPGhcdutnuG3jJMMIZZ/lqYDTkdeOiB qFydUwhRwphtXTLQ759ajUGZPl+J6u4OIk0e8+Czb5+ggefyavnKvPGEzKRox6NNNAv2 Gp476CEEek5Y3hlYBBDkFQVEnYLJLeh9SYIfSfH86L6sddt4VHS8wau+4BMEMwU0M+RC jrCaHgSqPz0jsP7bR8zqsRzaN6trvkSRDUqAvIk59N9gRFi1uWjlh3IV/yKAvukar0yY AIDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ylIJAmp+yr1bvyYwwG8PQSq7oO8H0eUvt5uuIq7+q+4=; b=el6IIfa27lAnTKD1AmZZiC2oqLA/BAQL8o4HZ05oFXLx5T4FwxGroM3foToLjltOIW H7G4E9h2K93Q+F9Gs2lPmDDzB9xBL3CJHZerHCWqD6BB8SKQ1LobG0Hn8lbog7E7zsU0 HLaM9PwreZPtRntnUsVp7ib/22rF7Dh2P9bQV3yLq2OULiC6KAoVGZ5CRzDxnPqObhRB G2DoJXwZwdCicHTGgx0Z0Yoo5mDCCwNxU4uME8ioTZZEEfi4PtlZdoij6yOgoV8RN/8c panOd3dtcwYw7PHiMEMc0v5Qr6WQjOTPmYMZpjLZt6Lx8Y7cFkveT3R+x5HesWmBqpzT B7/g== X-Gm-Message-State: AOAM530c/8ITnZQtKh0ACkxWKbRxHOYHJflhDoiCZF0FPi1xJJkx8n4B PkNIl9n/c9DatXNqaPRGLm822cqljsw= X-Google-Smtp-Source: ABdhPJwp3XIOG5Out2IzQUk0rJmFWo0d7PhN3F8EuFc8dNzt4NliRDhj7dCheDjuAVwLtIaiDFjKxw== X-Received: by 2002:a17:902:e843:b029:129:acb4:2464 with SMTP id t3-20020a170902e843b0290129acb42464mr20736770plg.77.1627429904036; Tue, 27 Jul 2021 16:51:44 -0700 (PDT) Received: from localhost.localdomain ([2601:1c0:6a01:d830::7cb2]) by smtp.gmail.com with ESMTPSA id y9sm1545332pfq.199.2021.07.27.16.51.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jul 2021 16:51:43 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Cc: Tedd Ho-Jeong An Subject: [RFC PATCH v4 05/11] Bluetooth: btintel: Fix the first HCI command not work with ROM device. Date: Tue, 27 Jul 2021 16:51:21 -0700 Message-Id: <20210727235127.173149-6-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210727235127.173149-1-hj.tedd.an@gmail.com> References: <20210727235127.173149-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An The some legacy ROM controllers have a bug with the first HCI command sent to it returning number of completed commands as zero, which would stall the command processing in the Bluetooth core. As a workaround, send HCI Rest command first which will reset the controller to fix the issue. Signed-off-by: Tedd Ho-Jeong An --- drivers/bluetooth/btintel.c | 21 +++++++++++++++++++++ drivers/bluetooth/btintel.h | 1 + drivers/bluetooth/btusb.c | 16 ++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index bf0ad05b80fe..65ecf2ae9a10 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1659,6 +1659,7 @@ static int btintel_legacy_rom_setup(struct hci_dev *hdev, int btintel_setup_combined(struct hci_dev *hdev) { + struct btintel_data *intel = hci_get_priv(hdev); const u8 param[1] = { 0xFF }; struct intel_version ver; struct intel_version_tlv ver_tlv; @@ -1667,6 +1668,26 @@ int btintel_setup_combined(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + /* The some controllers have a bug with the first HCI command sent to it + * returning number of completed commands as zero. This would stall the + * command processing in the Bluetooth core. + * + * As a workaround, send HCI Reset command first which will reset the + * number of completed commands and allow normal command processing + * from now on. + */ + if (test_bit(INTEL_BROKEN_READ_VERSION, &intel->flags)) { + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, + "sending initial HCI reset failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + } + /* Starting from TyP device, the command parameter and response are * changed even though the OCF for HCI_Intel_Read_Version command * remains same. The legacy devices can handle even if the diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index df7aa30142b4..29b678364a79 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -143,6 +143,7 @@ struct intel_debug_features { #define INTEL_FIRMWARE_LOADED 2 #define INTEL_FIRMWARE_FAILED 3 #define INTEL_BOOTING 4 +#define INTEL_BROKEN_READ_VERSION 5 struct btintel_data { unsigned long flags; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 4cd49a758bb0..28ad13d6c032 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -62,6 +62,7 @@ static struct usb_driver btusb_driver; #define BTUSB_QCA_WCN6855 0x1000000 #define BTUSB_INTEL_NEWGEN 0x2000000 #define BTUSB_INTEL_COMBINED 0x4000000 +#define BTUSB_INTEL_BROKEN_READ_VERSION 0x8000000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -376,11 +377,14 @@ static const struct usb_device_id blacklist_table[] = { BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, - { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED }, - { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED }, + { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED | + BTUSB_INTEL_BROKEN_READ_VERSION }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED | + BTUSB_INTEL_BROKEN_READ_VERSION }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED | + BTUSB_INTEL_BROKEN_READ_VERSION | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW | BTUSB_WIDEBAND_SPEECH | @@ -4221,6 +4225,11 @@ static int btusb_probe(struct usb_interface *intf, priv_size = 0; + if (id->driver_info & BTUSB_INTEL_COMBINED) { + /* Allocate extra space for Intel device */ + priv_size += sizeof(struct btintel_data); + } + if (id->driver_info & BTUSB_INTEL_NEW) { data->recv_event = btusb_recv_event_intel; data->recv_bulk = btusb_recv_bulk_intel; @@ -4315,6 +4324,9 @@ static int btusb_probe(struct usb_interface *intf, set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); + + if (id->driver_info & BTUSB_INTEL_BROKEN_READ_VERSION) + btintel_set_flags(hdev, INTEL_BROKEN_READ_VERSION); } if (id->driver_info & BTUSB_INTEL_NEW) { From patchwork Tue Jul 27 23:51:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tedd Ho-Jeong An X-Patchwork-Id: 486859 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A3FCFC4320E for ; Tue, 27 Jul 2021 23:51:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8786760FA0 for ; Tue, 27 Jul 2021 23:51:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233865AbhG0Xvw (ORCPT ); Tue, 27 Jul 2021 19:51:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233693AbhG0Xvt (ORCPT ); Tue, 27 Jul 2021 19:51:49 -0400 Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A0B0C061757 for ; Tue, 27 Jul 2021 16:51:46 -0700 (PDT) Received: by mail-pl1-x635.google.com with SMTP id a20so538339plm.0 for ; Tue, 27 Jul 2021 16:51:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=naa9yAoIxU7KV0k4nabBW+sJrEj5izmp7EoZzkTLf8I=; b=QPfKi4LP+XLYOHRgz2b5fNKPIoNndUo6FScqCzRpEyRAbeXHzSw1aM7mbWuI5sFu87 4W0d2ubAl5W4HGydC+SYoUcAGSaKEOg0rd+x/1SVf0iih9Jokb1cV7qapn+K9qjkb9Y+ FQA3l99JghJe9pqzPNhbGqgM2He6LFpCGoNQDnZnDUenY2EWsDbsneXEmXqflbtG5H8e t7BjrHfumVtLW0vGOcQKRpma0kTJDQ2NAsqC9MRNGwqeFiamLMFlBZht2o1Zn7b55Sie xCd3ZzG+WV/OJc1hlCQJ4uUW/TKPw2gwx5yOPwMHZIdXdgj9+zakcwip0wXUWrXD6FQl pQIg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=naa9yAoIxU7KV0k4nabBW+sJrEj5izmp7EoZzkTLf8I=; b=SvjY1nVkkT5Ro1hm8IigCVL+oimns64cld3eoc6gBZ0fFxQQV9+/vfgBbXjlZOB8iW t2vQm8EjxgnP1QORxjhGOq3byL5FSIrl7ELowPZ5of0TgZ1p0w8h0P77cqOQhO+8LgQp f3YaNsQmn04ZSa8laN1MlleJFimije8ivl1kJGr8DTZo2yIrVIgZKaoVzoMCGi/g4VUO cUT0+kHf+2Y8X+y3OLWRuRDoXEPpI4RoLM2jrkpl9lD2ONXP+7KwcToP04Stmz/W35LC 27tKsymU5Ji9uJUYiAC/howUbzIwOg3rovZVRhDNNCX+yqS4aBoz5xfZ8EAT1WfLUyNF sNZA== X-Gm-Message-State: AOAM530+OHqCgJoBlgSXlmCh7tH2IMvILQbXA9qE8pH/NBRl815zoZjU 7erhpsYZMzMFkvYBgo40VElyaDSDjww= X-Google-Smtp-Source: ABdhPJz3AVkxz+ZU0xG+rpNlxAymh4zoFcavPaLb5NpBitfIOfT9lI2L/yDD41dQF3hiAWotGscUIg== X-Received: by 2002:a62:7d16:0:b029:32d:cfc4:279c with SMTP id y22-20020a627d160000b029032dcfc4279cmr25384650pfc.8.1627429905502; Tue, 27 Jul 2021 16:51:45 -0700 (PDT) Received: from localhost.localdomain ([2601:1c0:6a01:d830::7cb2]) by smtp.gmail.com with ESMTPSA id y9sm1545332pfq.199.2021.07.27.16.51.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jul 2021 16:51:45 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Cc: Tedd Ho-Jeong An Subject: [RFC PATCH v4 07/11] Bluetooth: btintel: Add combined set_diag functions Date: Tue, 27 Jul 2021 16:51:23 -0700 Message-Id: <20210727235127.173149-8-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210727235127.173149-1-hj.tedd.an@gmail.com> References: <20210727235127.173149-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An This patch adds a combined set_diag functions. It also changes the btintel_set_diag_mfg() to static since it is no longer used by others. Signed-off-by: Tedd Ho-Jeong An --- drivers/bluetooth/btintel.c | 23 +++++++++++++++++++++-- drivers/bluetooth/btintel.h | 5 +++-- drivers/bluetooth/btusb.c | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 4e72d806387c..24b79f449527 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -164,7 +164,7 @@ int btintel_set_diag(struct hci_dev *hdev, bool enable) } EXPORT_SYMBOL_GPL(btintel_set_diag); -int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) +static int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) { int err, ret; @@ -180,7 +180,25 @@ int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) return ret; } -EXPORT_SYMBOL_GPL(btintel_set_diag_mfg); + +int btintel_set_diag_combined(struct hci_dev *hdev, bool enable) +{ + struct btintel_data *intel = hci_get_priv(hdev); + int ret; + + /* Legacy ROM device needs to be in the manufacturer mode to apply + * diagnostic setting + * + * This flag is set after reading the Intel version. + */ + if (test_bit(INTEL_ROM_LEGACY, &intel->flags)) + ret = btintel_set_diag_mfg(hdev, enable); + else + ret = btintel_set_diag(hdev, enable); + + return ret; +} +EXPORT_SYMBOL_GPL(btintel_set_diag_combined); void btintel_hw_error(struct hci_dev *hdev, u8 code) { @@ -1723,6 +1741,7 @@ int btintel_setup_combined(struct hci_dev *hdev) case 0x07: /* WP */ case 0x08: /* StP */ /* Legacy ROM product */ + set_bit(INTEL_ROM_LEGACY, &intel->flags); err = btintel_legacy_rom_setup(hdev, &ver); break; case 0x0b: /* SfP */ diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 4a35762c3220..abc438b9c62e 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -145,6 +145,7 @@ struct intel_debug_features { #define INTEL_BOOTING 4 #define INTEL_BROKEN_READ_VERSION 5 #define INTEL_BROKEN_LED 6 +#define INTEL_ROM_LEGACY 7 struct btintel_data { unsigned long flags; @@ -157,7 +158,7 @@ int btintel_enter_mfg(struct hci_dev *hdev); int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); int btintel_set_diag(struct hci_dev *hdev, bool enable); -int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable); +int btintel_set_diag_combined(struct hci_dev *hdev, bool enable); void btintel_hw_error(struct hci_dev *hdev, u8 code); int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver); @@ -217,7 +218,7 @@ static inline int btintel_set_diag(struct hci_dev *hdev, bool enable) return -EOPNOTSUPP; } -static inline int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) +static inline int btintel_set_diag_combined(struct hci_dev *hdev, bool enable) { return -EOPNOTSUPP; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 542fe0196ac7..e83df93faed6 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4322,7 +4322,7 @@ static int btusb_probe(struct usb_interface *intf, hdev->manufacturer = 2; hdev->setup = btintel_setup_combined; hdev->shutdown = btintel_shutdown_combined; - hdev->set_diag = btintel_set_diag_mfg; + hdev->set_diag = btintel_set_diag_combined; hdev->set_bdaddr = btintel_set_bdaddr; hdev->cmd_timeout = btusb_intel_cmd_timeout; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); From patchwork Tue Jul 27 23:51:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tedd Ho-Jeong An X-Patchwork-Id: 486860 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1685EC4338F for ; Tue, 27 Jul 2021 23:51:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F022260F93 for ; Tue, 27 Jul 2021 23:51:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233654AbhG0Xvt (ORCPT ); Tue, 27 Jul 2021 19:51:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37224 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233553AbhG0Xvs (ORCPT ); Tue, 27 Jul 2021 19:51:48 -0400 Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D13FC061764 for ; Tue, 27 Jul 2021 16:51:47 -0700 (PDT) Received: by mail-pj1-x102e.google.com with SMTP id j1so2396339pjv.3 for ; Tue, 27 Jul 2021 16:51:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kiU4qkKTxqLRQZua0UpbtywphpRbroeK8KZoUoUZELg=; b=nUcT6FOWrwnSO10l8Ib61NR9iWAnuGO9O2SLn1wE6Y4/0Lbaz5HM2uXy95xvwHqdwM 2PWv0R1ZYYZEgLGtPjyA09vTNn51Z+1bEKV4Dy/U28ptVPGXsb6zxySf4KxycZp0oPwP uS5pT7YlbBbnjoo+RBVjxdyM7/w8ew8X74JtWogBY3unOTINoXgZCOCxDOoSKM5Ny1OD 45foP3W8vgunjjfJhh3AngAJBFe1xsgAKJ7dCqNFJouqbD7Qfz+MnKSKL90lQdRVIiLm Ak5obTG97N5uNST/TPIWhpQTASqMDaEeZQLeL+IBsv2D/+QmZCOEk2En+yU/vNws+Efd dA6A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kiU4qkKTxqLRQZua0UpbtywphpRbroeK8KZoUoUZELg=; b=b0dMkshYZ1pGjlvtLyfwW2yaGkbDdD2zS5BUyP/Xgx3mrrpcc2Hepdhz+U6gA3CfV5 /PZPHjxa25sstgQB+FdMTSdvjV8ae17+bSqLBai+3fJLkHRW5Vp0BqH0Z6s2s21sy7ys zREIbC5PVEm4+WxLy13eOy4XslFhx8AjfcCi6jl9N+29YsQtaD+kfdhC3uPkYD5qN5CN xyQ6hlj5Ev0QNZRIL3N0MxLny/jnT1qTX8+mwJWmPfZR8nisvWYUtCz8hF9y1ryOGrZg YQKtvTfziuEVjD3HX0WJV5OFzBzMAsk5WW9paI7DrB41q2sisRACaVFZ+mbTrt1zyGRS YhYw== X-Gm-Message-State: AOAM5333HjuKi5KBFffCuJAVCyWr/ozvlpvo4AlHDQoQyNd2s9YoBDGk lmSR35L7VOul5uDCYDn+SVWMVfaovK0= X-Google-Smtp-Source: ABdhPJw+5w9NgiUA3XJIdnXTGicP3oVMj4kThn4bB1R7kXGcnuk2OsMHZZiphnO7DVYqJs1ysMZf0w== X-Received: by 2002:a17:902:e851:b029:12b:c50a:1ebc with SMTP id t17-20020a170902e851b029012bc50a1ebcmr18608639plg.84.1627429906376; Tue, 27 Jul 2021 16:51:46 -0700 (PDT) Received: from localhost.localdomain ([2601:1c0:6a01:d830::7cb2]) by smtp.gmail.com with ESMTPSA id y9sm1545332pfq.199.2021.07.27.16.51.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jul 2021 16:51:46 -0700 (PDT) From: Tedd Ho-Jeong An To: linux-bluetooth@vger.kernel.org Cc: Tedd Ho-Jeong An Subject: [RFC PATCH v4 08/11] Bluetooth: btintel: Refactoring setup routine for legacy bootloader Date: Tue, 27 Jul 2021 16:51:24 -0700 Message-Id: <20210727235127.173149-9-hj.tedd.an@gmail.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210727235127.173149-1-hj.tedd.an@gmail.com> References: <20210727235127.173149-1-hj.tedd.an@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Tedd Ho-Jeong An This patch refactors the setup routines for legacy bootloader devices into combined setup, and move the related functions from btusb to btintel. Signed-off-by: Tedd Ho-Jeong An --- drivers/bluetooth/btintel.c | 419 +++++++++++++++++++++++++++++++++++- drivers/bluetooth/btintel.h | 12 ++ drivers/bluetooth/btusb.c | 377 +++++--------------------------- 3 files changed, 479 insertions(+), 329 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 24b79f449527..944203cae8e0 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1675,6 +1675,392 @@ static int btintel_legacy_rom_setup(struct hci_dev *hdev, return 0; } +static int btintel_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec) +{ + struct btintel_data *intel = hci_get_priv(hdev); + ktime_t delta, rettime; + unsigned long long duration; + int err; + + set_bit(INTEL_FIRMWARE_LOADED, &intel->flags); + + bt_dev_info(hdev, "Waiting for firmware download to complete"); + + err = wait_on_bit_timeout(&intel->flags, INTEL_DOWNLOADING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(msec)); + if (err == -EINTR) { + bt_dev_err(hdev, "Firmware loading interrupted"); + return err; + } + + if (err) { + bt_dev_err(hdev, "Firmware loading timeout"); + return -ETIMEDOUT; + } + + if (test_bit(INTEL_FIRMWARE_FAILED, &intel->flags)) { + bt_dev_err(hdev, "Firmware loading failed"); + return -ENOEXEC; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long)ktime_to_ns(delta) >> 10; + + bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration); + + return 0; +} + +static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec) +{ + struct btintel_data *intel = hci_get_priv(hdev); + ktime_t delta, rettime; + unsigned long long duration; + int err; + + bt_dev_info(hdev, "Waiting for device to boot"); + + err = wait_on_bit_timeout(&intel->flags, INTEL_BOOTING, + TASK_INTERRUPTIBLE, msecs_to_jiffies(msec)); + if (err == -EINTR) { + bt_dev_err(hdev, "Device boot interrupted"); + return -EINTR; + } + + if (err) { + bt_dev_err(hdev, "Device boot timeout"); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + bt_dev_info(hdev, "Device booted in %llu usecs", duration); + + return 0; +} + +static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) +{ + struct btintel_data *intel = hci_get_priv(hdev); + ktime_t calltime; + int err; + + calltime = ktime_get(); + + set_bit(INTEL_BOOTING, &intel->flags); + + err = btintel_send_intel_reset(hdev, boot_addr); + if (err) { + bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err); + btintel_reset_to_bootloader(hdev); + return err; + } + + /* The bootloader will not indicate when the device is ready. This + * is done by the operational firmware sending bootup notification. + * + * Booting into operational firmware should not take longer than + * 1 second. However if that happens, then just fail the setup + * since something went wrong. + */ + err = btintel_boot_wait(hdev, calltime, 1000); + if (err == -ETIMEDOUT) + btintel_reset_to_bootloader(hdev); + + return err; +} + +static int btintel_get_fw_name(struct intel_version *ver, + struct intel_boot_params *params, + char *fw_name, size_t len, + const char *suffix) +{ + switch (ver->hw_variant) { + case 0x0b: /* SfP */ + case 0x0c: /* WsP */ + snprintf(fw_name, len, "intel/ibt-%u-%u.%s", + le16_to_cpu(ver->hw_variant), + le16_to_cpu(params->dev_revid), + suffix); + break; + case 0x11: /* JfP */ + case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* CcP */ + snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", + le16_to_cpu(ver->hw_variant), + le16_to_cpu(ver->hw_revision), + le16_to_cpu(ver->fw_revision), + suffix); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int btintel_download_fw(struct hci_dev *hdev, + struct intel_version *ver, + struct intel_boot_params *params, + u32 *boot_param) +{ + const struct firmware *fw; + char fwname[64]; + int err; + struct btintel_data *intel = hci_get_priv(hdev); + ktime_t calltime; + + if (!ver || !params) + return -EINVAL; + + /* The firmware variant determines if the device is in bootloader + * mode or is running operational firmware. The value 0x06 identifies + * the bootloader and the value 0x23 identifies the operational + * firmware. + * + * When the operational firmware is already present, then only + * the check for valid Bluetooth device address is needed. This + * determines if the device will be added as configured or + * unconfigured controller. + * + * It is not possible to use the Secure Boot Parameters in this + * case since that command is only available in bootloader mode. + */ + if (ver->fw_variant == 0x23) { + clear_bit(INTEL_BOOTLOADER, &intel->flags); + btintel_check_bdaddr(hdev); + + /* SfP and WsP don't seem to update the firmware version on file + * so version checking is currently possible. + */ + switch (ver->hw_variant) { + case 0x0b: /* SfP */ + case 0x0c: /* WsP */ + return 0; + } + + /* Proceed to download to check if the version matches */ + goto download; + } + + /* Read the secure boot parameters to identify the operating + * details of the bootloader. + */ + err = btintel_read_boot_params(hdev, params); + if (err) + return err; + + /* It is required that every single firmware fragment is acknowledged + * with a command complete event. If the boot parameters indicate + * that this bootloader does not send them, then abort the setup. + */ + if (params->limited_cce != 0x00) { + bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)", + params->limited_cce); + return -EINVAL; + } + + /* If the OTP has no valid Bluetooth device address, then there will + * also be no valid address for the operational firmware. + */ + if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + bt_dev_info(hdev, "No device address configured"); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + +download: + /* With this Intel bootloader only the hardware variant and device + * revision information are used to select the right firmware for SfP + * and WsP. + * + * The firmware filename is ibt--.sfi. + * + * Currently the supported hardware variants are: + * 11 (0x0b) for iBT3.0 (LnP/SfP) + * 12 (0x0c) for iBT3.5 (WsP) + * + * For ThP/JfP and for future SKU's, the FW name varies based on HW + * variant, HW revision and FW revision, as these are dependent on CNVi + * and RF Combination. + * + * 17 (0x11) for iBT3.5 (JfP) + * 18 (0x12) for iBT3.5 (ThP) + * + * The firmware file name for these will be + * ibt---.sfi. + * + */ + err = btintel_get_fw_name(ver, params, fwname, sizeof(fwname), "sfi"); + if (err < 0) { + if (!test_bit(INTEL_BOOTLOADER, &intel->flags)) { + /* Firmware has already been loaded */ + set_bit(INTEL_FIRMWARE_LOADED, &intel->flags); + return 0; + } + + bt_dev_err(hdev, "Unsupported Intel firmware naming"); + return -EINVAL; + } + + err = firmware_request_nowarn(&fw, fwname, &hdev->dev); + if (err < 0) { + if (!test_bit(INTEL_BOOTLOADER, &intel->flags)) { + /* Firmware has already been loaded */ + set_bit(INTEL_FIRMWARE_LOADED, &intel->flags); + return 0; + } + + bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)", + fwname, err); + return err; + } + + bt_dev_info(hdev, "Found device firmware: %s", fwname); + + if (fw->size < 644) { + bt_dev_err(hdev, "Invalid size of firmware file (%zu)", + fw->size); + err = -EBADF; + goto done; + } + + calltime = ktime_get(); + + set_bit(INTEL_DOWNLOADING, &intel->flags); + + /* Start firmware downloading and get boot parameter */ + err = btintel_download_firmware(hdev, ver, fw, boot_param); + if (err < 0) { + if (err == -EALREADY) { + /* Firmware has already been loaded */ + set_bit(INTEL_FIRMWARE_LOADED, &intel->flags); + err = 0; + goto done; + } + + /* When FW download fails, send Intel Reset to retry + * FW download. + */ + btintel_reset_to_bootloader(hdev); + goto done; + } + + /* Before switching the device into operational mode and with that + * booting the loaded firmware, wait for the bootloader notification + * that all fragments have been successfully received. + * + * When the event processing receives the notification, then the + * INTEL_DOWNLOADING flag will be cleared. + * + * The firmware loading should not take longer than 5 seconds + * and thus just timeout if that happens and fail the setup + * of this device. + */ + err = btintel_download_wait(hdev, calltime, 5000); + if (err == -ETIMEDOUT) + btintel_reset_to_bootloader(hdev); + +done: + release_firmware(fw); + return err; +} + +static int btintel_bootloader_setup(struct hci_dev *hdev, + struct intel_version *ver) +{ + struct btintel_data *intel = hci_get_priv(hdev); + struct intel_version new_ver; + struct intel_boot_params params; + u32 boot_param; + char ddcname[64]; + int err; + struct intel_debug_features features; + + BT_DBG("%s", hdev->name); + + /* Set the default boot parameter to 0x0 and it is updated to + * SKU specific boot parameter after reading Intel_Write_Boot_Params + * command while downloading the firmware. + */ + boot_param = 0x00000000; + + set_bit(INTEL_BOOTLOADER, &intel->flags); + + err = btintel_download_fw(hdev, ver, ¶ms, &boot_param); + if (err) + return err; + + /* controller is already having an operational firmware */ + if (ver->fw_variant == 0x23) + goto finish; + + err = btintel_boot(hdev, boot_param); + if (err) + return err; + + clear_bit(INTEL_BOOTLOADER, &intel->flags); + + err = btintel_get_fw_name(ver, ¶ms, ddcname, + sizeof(ddcname), "ddc"); + + if (err < 0) { + bt_dev_err(hdev, "Unsupported Intel firmware naming"); + } else { + /* Once the device is running in operational mode, it needs to + * apply the device configuration (DDC) parameters. + * + * The device can work without DDC parameters, so even if it + * fails to load the file, no need to fail the setup. + */ + btintel_load_ddc_config(hdev, ddcname); + } + + /* Read the Intel supported features and if new exception formats + * supported, need to load the additional DDC config to enable. + */ + err = btintel_read_debug_features(hdev, &features); + if (!err) { + /* Set DDC mask for available debug features */ + btintel_set_debug_features(hdev, &features); + } + + /* Read the Intel version information after loading the FW */ + err = btintel_read_version(hdev, &new_ver); + if (err) + return err; + + btintel_version_info(hdev, &new_ver); + +finish: + /* All Intel controllers that support the Microsoft vendor + * extension are using 0xFC1E for VsMsftOpCode. + */ + switch (ver->hw_variant) { + case 0x11: /* JfP */ + case 0x12: /* ThP */ + case 0x13: /* HrP */ + case 0x14: /* CcP */ + hci_set_msft_opcode(hdev, 0xFC1E); + break; + } + + /* Set the event mask for Intel specific vendor events. This enables + * a few extra events that are useful during general operation. It + * does not enable any debugging related events. + * + * The device will function correctly without these events enabled + * and thus no need to fail the setup. + */ + btintel_set_event_mask(hdev, false); + + return 0; +} + int btintel_setup_combined(struct hci_dev *hdev) { struct btintel_data *intel = hci_get_priv(hdev); @@ -1750,7 +2136,7 @@ int btintel_setup_combined(struct hci_dev *hdev) case 0x12: /* ThP */ case 0x13: /* HrP */ case 0x14: /* CcP */ - /* TODO: call setup routine for bootloader product */ + err = btintel_bootloader_setup(hdev, &ver); break; default: bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", @@ -1818,6 +2204,37 @@ void btintel_set_flags(struct hci_dev *hdev, unsigned int flag) } EXPORT_SYMBOL_GPL(btintel_set_flags); +void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len) +{ + struct btintel_data *intel = hci_get_priv(hdev); + const struct intel_bootup *evt = ptr; + + if (len != sizeof(*evt)) + return; + + if (test_and_clear_bit(INTEL_BOOTING, &intel->flags)) + wake_up_bit(&intel->flags, INTEL_BOOTING); +} +EXPORT_SYMBOL_GPL(btintel_bootup); + +void btintel_secure_send_result(struct hci_dev *hdev, + const void *ptr, unsigned int len) +{ + struct btintel_data *intel = hci_get_priv(hdev); + const struct intel_secure_send_result *evt = ptr; + + if (len != sizeof(*evt)) + return; + + if (evt->result) + set_bit(INTEL_FIRMWARE_FAILED, &intel->flags); + + if (test_and_clear_bit(INTEL_DOWNLOADING, &intel->flags) && + test_bit(INTEL_FIRMWARE_LOADED, &intel->flags)) + wake_up_bit(&intel->flags, INTEL_DOWNLOADING); +} +EXPORT_SYMBOL_GPL(btintel_secure_send_result); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index abc438b9c62e..f02ccd7e76fb 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -191,6 +191,9 @@ int btintel_read_debug_features(struct hci_dev *hdev, struct intel_debug_features *features); int btintel_set_debug_features(struct hci_dev *hdev, const struct intel_debug_features *features); +void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len); +void btintel_secure_send_result(struct hci_dev *hdev, + const void *ptr, unsigned int len); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -337,4 +340,13 @@ static inline int btintel_set_debug_features(struct hci_dev *hdev, return -EOPNOTSUPP; } +static inline void btintel_bootup(struct hci_dev *hdev, + const void *ptr, unsigned int len) +{ +} + +static inline void btintel_secure_send_result(struct hci_dev *hdev, + const void *ptr, unsigned int len) +{ +} #endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e83df93faed6..189820b92c5e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -365,12 +365,12 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, /* Intel Bluetooth devices */ - { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_NEW | + { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_NEW | + { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_NEW | + { USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_NEWGEN | BTUSB_WIDEBAND_SPEECH}, @@ -384,13 +384,13 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_INTEL_BROKEN_READ_VERSION | BTUSB_INTEL_BROKEN_LED }, - { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW | + { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_INTEL_BROKEN_READ_VERSION | BTUSB_INTEL_BROKEN_LED | BTUSB_WIDEBAND_SPEECH }, - { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW | + { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_COMBINED | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -1999,11 +1999,14 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer, int count) { + struct btintel_data *intel = hci_get_priv(data->hdev); + /* When the device is in bootloader mode, then it can send * events via the bulk endpoint. These events are treated the * same way as the ones received from the interrupt endpoint. */ - if (test_bit(BTUSB_BOOTLOADER, &data->flags)) + if (test_bit(BTUSB_BOOTLOADER, &data->flags) || + test_bit(INTEL_BOOTLOADER, &intel->flags)) return btusb_recv_intr(data, buffer, count); return btusb_recv_bulk(data, buffer, count); @@ -2040,6 +2043,7 @@ static void btusb_intel_secure_send_result(struct btusb_data *data, static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); + struct btintel_data *intel = hci_get_priv(hdev); if (test_bit(BTUSB_BOOTLOADER, &data->flags)) { struct hci_event_hdr *hdr = (void *)skb->data; @@ -2069,19 +2073,49 @@ static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) } } + if (test_bit(INTEL_BOOTLOADER, &intel->flags)) { + struct hci_event_hdr *hdr = (void *)skb->data; + + if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && + hdr->plen > 0) { + const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; + unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; + + switch (skb->data[2]) { + case 0x02: + /* When switching to the operational firmware + * the device sends a vendor specific event + * indicating that the bootup completed. + */ + btintel_bootup(hdev, ptr, len); + break; + case 0x06: + /* When the firmware loading completes the + * device sends out a vendor specific event + * indicating the result of the firmware + * loading. + */ + btintel_secure_send_result(hdev, ptr, len); + break; + } + } + } + return hci_recv_frame(hdev, skb); } static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); + struct btintel_data *intel = hci_get_priv(hdev); struct urb *urb; BT_DBG("%s", hdev->name); switch (hci_skb_pkt_type(skb)) { case HCI_COMMAND_PKT: - if (test_bit(BTUSB_BOOTLOADER, &data->flags)) { + if (test_bit(BTUSB_BOOTLOADER, &data->flags) || + test_bit(INTEL_BOOTLOADER, &intel->flags)) { struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); @@ -2133,36 +2167,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } -static int btusb_setup_intel_new_get_fw_name(struct intel_version *ver, - struct intel_boot_params *params, - char *fw_name, size_t len, - const char *suffix) -{ - switch (ver->hw_variant) { - case 0x0b: /* SfP */ - case 0x0c: /* WsP */ - snprintf(fw_name, len, "intel/ibt-%u-%u.%s", - le16_to_cpu(ver->hw_variant), - le16_to_cpu(params->dev_revid), - suffix); - break; - case 0x11: /* JfP */ - case 0x12: /* ThP */ - case 0x13: /* HrP */ - case 0x14: /* CcP */ - snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s", - le16_to_cpu(ver->hw_variant), - le16_to_cpu(ver->hw_revision), - le16_to_cpu(ver->fw_revision), - suffix); - break; - default: - return -EINVAL; - } - - return 0; -} - static void btusb_setup_intel_newgen_get_fw_name(const struct intel_version_tlv *ver_tlv, char *fw_name, size_t len, const char *suffix) @@ -2322,173 +2326,6 @@ static int btusb_intel_download_firmware_newgen(struct hci_dev *hdev, return err; } -static int btusb_intel_download_firmware(struct hci_dev *hdev, - struct intel_version *ver, - struct intel_boot_params *params, - u32 *boot_param) -{ - const struct firmware *fw; - char fwname[64]; - int err; - struct btusb_data *data = hci_get_drvdata(hdev); - ktime_t calltime; - - if (!ver || !params) - return -EINVAL; - - /* The firmware variant determines if the device is in bootloader - * mode or is running operational firmware. The value 0x06 identifies - * the bootloader and the value 0x23 identifies the operational - * firmware. - * - * When the operational firmware is already present, then only - * the check for valid Bluetooth device address is needed. This - * determines if the device will be added as configured or - * unconfigured controller. - * - * It is not possible to use the Secure Boot Parameters in this - * case since that command is only available in bootloader mode. - */ - if (ver->fw_variant == 0x23) { - clear_bit(BTUSB_BOOTLOADER, &data->flags); - btintel_check_bdaddr(hdev); - - /* SfP and WsP don't seem to update the firmware version on file - * so version checking is currently possible. - */ - switch (ver->hw_variant) { - case 0x0b: /* SfP */ - case 0x0c: /* WsP */ - return 0; - } - - /* Proceed to download to check if the version matches */ - goto download; - } - - /* Read the secure boot parameters to identify the operating - * details of the bootloader. - */ - err = btintel_read_boot_params(hdev, params); - if (err) - return err; - - /* It is required that every single firmware fragment is acknowledged - * with a command complete event. If the boot parameters indicate - * that this bootloader does not send them, then abort the setup. - */ - if (params->limited_cce != 0x00) { - bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)", - params->limited_cce); - return -EINVAL; - } - - /* If the OTP has no valid Bluetooth device address, then there will - * also be no valid address for the operational firmware. - */ - if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { - bt_dev_info(hdev, "No device address configured"); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); - } - -download: - /* With this Intel bootloader only the hardware variant and device - * revision information are used to select the right firmware for SfP - * and WsP. - * - * The firmware filename is ibt--.sfi. - * - * Currently the supported hardware variants are: - * 11 (0x0b) for iBT3.0 (LnP/SfP) - * 12 (0x0c) for iBT3.5 (WsP) - * - * For ThP/JfP and for future SKU's, the FW name varies based on HW - * variant, HW revision and FW revision, as these are dependent on CNVi - * and RF Combination. - * - * 17 (0x11) for iBT3.5 (JfP) - * 18 (0x12) for iBT3.5 (ThP) - * - * The firmware file name for these will be - * ibt---.sfi. - * - */ - err = btusb_setup_intel_new_get_fw_name(ver, params, fwname, - sizeof(fwname), "sfi"); - if (err < 0) { - if (!test_bit(BTUSB_BOOTLOADER, &data->flags)) { - /* Firmware has already been loaded */ - set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); - return 0; - } - - bt_dev_err(hdev, "Unsupported Intel firmware naming"); - return -EINVAL; - } - - err = firmware_request_nowarn(&fw, fwname, &hdev->dev); - if (err < 0) { - if (!test_bit(BTUSB_BOOTLOADER, &data->flags)) { - /* Firmware has already been loaded */ - set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); - return 0; - } - - bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)", - fwname, err); - return err; - } - - bt_dev_info(hdev, "Found device firmware: %s", fwname); - - if (fw->size < 644) { - bt_dev_err(hdev, "Invalid size of firmware file (%zu)", - fw->size); - err = -EBADF; - goto done; - } - - calltime = ktime_get(); - - set_bit(BTUSB_DOWNLOADING, &data->flags); - - /* Start firmware downloading and get boot parameter */ - err = btintel_download_firmware(hdev, ver, fw, boot_param); - if (err < 0) { - if (err == -EALREADY) { - /* Firmware has already been loaded */ - set_bit(BTUSB_FIRMWARE_LOADED, &data->flags); - err = 0; - goto done; - } - - /* When FW download fails, send Intel Reset to retry - * FW download. - */ - btintel_reset_to_bootloader(hdev); - goto done; - } - - /* Before switching the device into operational mode and with that - * booting the loaded firmware, wait for the bootloader notification - * that all fragments have been successfully received. - * - * When the event processing receives the notification, then the - * BTUSB_DOWNLOADING flag will be cleared. - * - * The firmware loading should not take longer than 5 seconds - * and thus just timeout if that happens and fail the setup - * of this device. - */ - err = btusb_download_wait(hdev, calltime, 5000); - if (err == -ETIMEDOUT) - btintel_reset_to_bootloader(hdev); - -done: - release_firmware(fw); - return err; -} - static int btusb_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2551,109 +2388,6 @@ static int btusb_intel_boot(struct hci_dev *hdev, u32 boot_addr) return err; } -static int btusb_setup_intel_new(struct hci_dev *hdev) -{ - struct btusb_data *data = hci_get_drvdata(hdev); - struct intel_version ver; - struct intel_boot_params params; - u32 boot_param; - char ddcname[64]; - int err; - struct intel_debug_features features; - - BT_DBG("%s", hdev->name); - - /* Set the default boot parameter to 0x0 and it is updated to - * SKU specific boot parameter after reading Intel_Write_Boot_Params - * command while downloading the firmware. - */ - boot_param = 0x00000000; - - /* Read the Intel version information to determine if the device - * is in bootloader mode or if it already has operational firmware - * loaded. - */ - err = btintel_read_version(hdev, &ver); - if (err) { - bt_dev_err(hdev, "Intel Read version failed (%d)", err); - btintel_reset_to_bootloader(hdev); - return err; - } - - err = btintel_version_info(hdev, &ver); - if (err) - return err; - - err = btusb_intel_download_firmware(hdev, &ver, ¶ms, &boot_param); - if (err) - return err; - - /* controller is already having an operational firmware */ - if (ver.fw_variant == 0x23) - goto finish; - - err = btusb_intel_boot(hdev, boot_param); - if (err) - return err; - - clear_bit(BTUSB_BOOTLOADER, &data->flags); - - err = btusb_setup_intel_new_get_fw_name(&ver, ¶ms, ddcname, - sizeof(ddcname), "ddc"); - - if (err < 0) { - bt_dev_err(hdev, "Unsupported Intel firmware naming"); - } else { - /* Once the device is running in operational mode, it needs to - * apply the device configuration (DDC) parameters. - * - * The device can work without DDC parameters, so even if it - * fails to load the file, no need to fail the setup. - */ - btintel_load_ddc_config(hdev, ddcname); - } - - /* Read the Intel supported features and if new exception formats - * supported, need to load the additional DDC config to enable. - */ - err = btintel_read_debug_features(hdev, &features); - if (!err) { - /* Set DDC mask for available debug features */ - btintel_set_debug_features(hdev, &features); - } - - /* Read the Intel version information after loading the FW */ - err = btintel_read_version(hdev, &ver); - if (err) - return err; - - btintel_version_info(hdev, &ver); - -finish: - /* All Intel controllers that support the Microsoft vendor - * extension are using 0xFC1E for VsMsftOpCode. - */ - switch (ver.hw_variant) { - case 0x11: /* JfP */ - case 0x12: /* ThP */ - case 0x13: /* HrP */ - case 0x14: /* CcP */ - hci_set_msft_opcode(hdev, 0xFC1E); - break; - } - - /* Set the event mask for Intel specific vendor events. This enables - * a few extra events that are useful during general operation. It - * does not enable any debugging related events. - * - * The device will function correctly without these events enabled - * and thus no need to fail the setup. - */ - btintel_set_event_mask(hdev, false); - - return 0; -} - static int btusb_setup_intel_newgen(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -4229,18 +3963,17 @@ static int btusb_probe(struct usb_interface *intf, priv_size = 0; - if (id->driver_info & BTUSB_INTEL_COMBINED) { + data->recv_event = hci_recv_frame; + data->recv_bulk = btusb_recv_bulk; + + if (id->driver_info & BTUSB_INTEL_COMBINED || + id->driver_info & BTUSB_INTEL_NEW) { /* Allocate extra space for Intel device */ priv_size += sizeof(struct btintel_data); - } - if (id->driver_info & BTUSB_INTEL_NEW) { + /* Override the rx handlers */ data->recv_event = btusb_recv_event_intel; data->recv_bulk = btusb_recv_bulk_intel; - set_bit(BTUSB_BOOTLOADER, &data->flags); - } else { - data->recv_event = hci_recv_frame; - data->recv_bulk = btusb_recv_bulk; } hdev = hci_alloc_dev(priv_size); @@ -4320,8 +4053,10 @@ static int btusb_probe(struct usb_interface *intf, /* Combined Intel Device setup to support multiple setup routine */ if (id->driver_info & BTUSB_INTEL_COMBINED) { hdev->manufacturer = 2; + hdev->send = btusb_send_frame_intel; hdev->setup = btintel_setup_combined; hdev->shutdown = btintel_shutdown_combined; + hdev->hw_error = btintel_hw_error; hdev->set_diag = btintel_set_diag_combined; hdev->set_bdaddr = btintel_set_bdaddr; hdev->cmd_timeout = btusb_intel_cmd_timeout; @@ -4336,20 +4071,6 @@ static int btusb_probe(struct usb_interface *intf, btintel_set_flags(hdev, INTEL_BROKEN_LED); } - if (id->driver_info & BTUSB_INTEL_NEW) { - hdev->manufacturer = 2; - hdev->send = btusb_send_frame_intel; - hdev->setup = btusb_setup_intel_new; - hdev->shutdown = btusb_shutdown_intel_new; - hdev->hw_error = btintel_hw_error; - hdev->set_diag = btintel_set_diag; - hdev->set_bdaddr = btintel_set_bdaddr; - hdev->cmd_timeout = btusb_intel_cmd_timeout; - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); - set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); - set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks); - } - if (id->driver_info & BTUSB_INTEL_NEWGEN) { hdev->manufacturer = 2; hdev->send = btusb_send_frame_intel;