diff options
author | Jakub Kicinski <kuba@kernel.org> | 2024-05-14 09:07:37 -0700 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-05-14 09:07:38 -0700 |
commit | 79982e8f8a01b2e2bfcae17aa7cd55586e172564 (patch) | |
tree | ac466be74174512bc700c304d0cea4c599a65280 | |
parent | 5c1672705a1a2389f5ad78e0fea6f08ed32d6f18 (diff) | |
parent | 6a486c1361ea588938898ae812b32dcfbd4022f2 (diff) | |
download | linux-stable-79982e8f8a01b2e2bfcae17aa7cd55586e172564.tar.gz linux-stable-79982e8f8a01b2e2bfcae17aa7cd55586e172564.tar.bz2 linux-stable-79982e8f8a01b2e2bfcae17aa7cd55586e172564.zip |
Merge tag 'for-net-next-2024-05-14' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Luiz Augusto von Dentz says:
====================
bluetooth-next pull request for net-next:
- Add support MediaTek MT7921S SDIO
- Various fixes for -Wflex-array-member-not-at-end and -Wfamnae
- Add USB HW IDs for MT7921/MT7922/MT7925
- Add support for Intel BlazarI and Filmore Peak2 (BE201)
- Add initial support for Intel PCIe driver
- Remove HCI_AMP support
* tag 'for-net-next-2024-05-14' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (47 commits)
Bluetooth: btintel_pcie: Refactor and code cleanup
Bluetooth: btintel_pcie: Fix warning reported by sparse
Bluetooth: hci_core: Fix not handling hdev->le_num_of_adv_sets=1
Bluetooth: btintel: Fix compiler warning for multi_v7_defconfig config
Bluetooth: btintel_pcie: Fix compiler warnings
Bluetooth: btintel_pcie: Add *setup* function to download firmware
Bluetooth: btintel_pcie: Add support for PCIe transport
Bluetooth: btintel: Export few static functions
Bluetooth: HCI: Remove HCI_AMP support
Bluetooth: L2CAP: Fix div-by-zero in l2cap_le_flowctl_init()
Bluetooth: qca: Fix error code in qca_read_fw_build_info()
Bluetooth: hci_conn: Use __counted_by() and avoid -Wfamnae warning
Bluetooth: btintel: Add support for Filmore Peak2 (BE201)
Bluetooth: btintel: Add support for BlazarI
LE Create Connection command timeout increased to 20 secs
dt-bindings: net: bluetooth: Add MediaTek MT7921S SDIO Bluetooth
Bluetooth: compute LE flow credits based on recvbuf space
Bluetooth: hci_sync: Use cmd->num_cis instead of magic number
Bluetooth: hci_conn: Use struct_size() in hci_le_big_create_sync()
Bluetooth: qca: clean up defines
...
====================
Link: https://lore.kernel.org/r/20240514150206.606432-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
42 files changed, 2651 insertions, 1141 deletions
diff --git a/Documentation/devicetree/bindings/net/bluetooth/mediatek,mt7921s-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/mediatek,mt7921s-bluetooth.yaml new file mode 100644 index 000000000000..67ff7caad599 --- /dev/null +++ b/Documentation/devicetree/bindings/net/bluetooth/mediatek,mt7921s-bluetooth.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/bluetooth/mediatek,mt7921s-bluetooth.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7921S Bluetooth + +maintainers: + - Sean Wang <sean.wang@mediatek.com> + +description: + MT7921S is an SDIO-attached dual-radio WiFi+Bluetooth Combo chip; each + function is its own SDIO function on a shared SDIO interface. The chip + has two dedicated reset lines, one for each function core. + This binding only covers the Bluetooth SDIO function, with one device + node describing only this SDIO function. + +allOf: + - $ref: bluetooth-controller.yaml# + +properties: + compatible: + enum: + - mediatek,mt7921s-bluetooth + + reg: + const: 2 + + reset-gpios: + maxItems: 1 + description: + An active-low reset line for the Bluetooth core; on typical M.2 + key E modules this is the W_DISABLE2# pin. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + mmc { + #address-cells = <1>; + #size-cells = <0>; + + bluetooth@2 { + compatible = "mediatek,mt7921s-bluetooth"; + reg = <2>; + reset-gpios = <&pio 8 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml b/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml index cc70b00c6ce5..4a1bfc2b3584 100644 --- a/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/broadcom-bluetooth.yaml @@ -14,20 +14,25 @@ description: properties: compatible: - enum: - - brcm,bcm20702a1 - - brcm,bcm4329-bt - - brcm,bcm4330-bt - - brcm,bcm4334-bt - - brcm,bcm43430a0-bt - - brcm,bcm43430a1-bt - - brcm,bcm43438-bt - - brcm,bcm4345c5 - - brcm,bcm43540-bt - - brcm,bcm4335a0 - - brcm,bcm4349-bt - - cypress,cyw4373a0-bt - - infineon,cyw55572-bt + oneOf: + - items: + - enum: + - infineon,cyw43439-bt + - const: brcm,bcm4329-bt + - enum: + - brcm,bcm20702a1 + - brcm,bcm4329-bt + - brcm,bcm4330-bt + - brcm,bcm4334-bt + - brcm,bcm43430a0-bt + - brcm,bcm43430a1-bt + - brcm,bcm43438-bt + - brcm,bcm4345c5 + - brcm,bcm43540-bt + - brcm,bcm4335a0 + - brcm,bcm4349-bt + - cypress,cyw4373a0-bt + - infineon,cyw55572-bt shutdown-gpios: maxItems: 1 diff --git a/MAINTAINERS b/MAINTAINERS index b4ed6480e919..c4c6ffbc6d10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13763,6 +13763,7 @@ M: Sean Wang <sean.wang@mediatek.com> L: linux-bluetooth@vger.kernel.org L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained +F: Documentation/devicetree/bindings/net/bluetooth/mediatek,mt7921s-bluetooth.yaml F: Documentation/devicetree/bindings/net/mediatek-bluetooth.txt F: drivers/bluetooth/btmtkuart.c diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index bc211c324206..0b5f218ac505 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -478,5 +478,16 @@ config BT_NXPUART Say Y here to compile support for NXP Bluetooth UART device into the kernel, or say M here to compile as a module (btnxpuart). +config BT_INTEL_PCIE + tristate "Intel HCI PCIe driver" + depends on PCI + select BT_INTEL + select FW_LOADER + help + Intel Bluetooth transport driver for PCIe. + This driver is required if you want to use Intel Bluetooth device + with PCIe interface. + Say Y here to compiler support for Intel Bluetooth PCIe device into + the kernel or say M to compile it as module (btintel_pcie) endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 7a5967e9ac48..0730d6684d1a 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_INTEL) += btintel.o +obj-$(CONFIG_BT_INTEL_PCIE) += btintel_pcie.o btintel.o obj-$(CONFIG_BT_ATH3K) += ath3k.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 88262d3a9392..ce97b336fbfb 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -3,7 +3,6 @@ * Copyright (c) 2008-2009 Atheros Communications Inc. */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -128,7 +127,6 @@ MODULE_DEVICE_TABLE(usb, ath3k_table); * for AR3012 */ static const struct usb_device_id ath3k_blist_tbl[] = { - /* Atheros AR3012 with sflash firmware*/ { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 }, @@ -202,7 +200,7 @@ static inline void ath3k_log_failed_loading(int err, int len, int size, #define TIMEGAP_USEC_MAX 100 static int ath3k_load_firmware(struct usb_device *udev, - const struct firmware *firmware) + const struct firmware *firmware) { u8 *send_buf; int len = 0; @@ -237,9 +235,9 @@ static int ath3k_load_firmware(struct usb_device *udev, memcpy(send_buf, firmware->data + sent, size); err = usb_bulk_msg(udev, pipe, send_buf, size, - &len, 3000); + &len, 3000); - if (err || (len != size)) { + if (err || len != size) { ath3k_log_failed_loading(err, len, size, count); goto error; } @@ -262,7 +260,7 @@ static int ath3k_get_state(struct usb_device *udev, unsigned char *state) } static int ath3k_get_version(struct usb_device *udev, - struct ath3k_version *version) + struct ath3k_version *version) { return usb_control_msg_recv(udev, 0, ATH3K_GETVERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, @@ -271,7 +269,7 @@ static int ath3k_get_version(struct usb_device *udev, } static int ath3k_load_fwfile(struct usb_device *udev, - const struct firmware *firmware) + const struct firmware *firmware) { u8 *send_buf; int len = 0; @@ -310,8 +308,8 @@ static int ath3k_load_fwfile(struct usb_device *udev, memcpy(send_buf, firmware->data + sent, size); err = usb_bulk_msg(udev, pipe, send_buf, size, - &len, 3000); - if (err || (len != size)) { + &len, 3000); + if (err || len != size) { ath3k_log_failed_loading(err, len, size, count); kfree(send_buf); return err; @@ -425,7 +423,6 @@ static int ath3k_load_syscfg(struct usb_device *udev) } switch (fw_version.ref_clock) { - case ATH3K_XTAL_FREQ_26M: clk_value = 26; break; @@ -441,7 +438,7 @@ static int ath3k_load_syscfg(struct usb_device *udev) } snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s", - le32_to_cpu(fw_version.rom_version), clk_value, ".dfu"); + le32_to_cpu(fw_version.rom_version), clk_value, ".dfu"); ret = request_firmware(&firmware, filename, &udev->dev); if (ret < 0) { @@ -456,7 +453,7 @@ static int ath3k_load_syscfg(struct usb_device *udev) } static int ath3k_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { const struct firmware *firmware; struct usb_device *udev = interface_to_usbdev(intf); @@ -505,10 +502,10 @@ static int ath3k_probe(struct usb_interface *intf, if (ret < 0) { if (ret == -ENOENT) BT_ERR("Firmware file \"%s\" not found", - ATH3K_FIRMWARE); + ATH3K_FIRMWARE); else BT_ERR("Firmware file \"%s\" request failed (err=%d)", - ATH3K_FIRMWARE, ret); + ATH3K_FIRMWARE, ret); return ret; } diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 6ba7f5d1b837..0c855c3ee1c1 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -245,7 +245,7 @@ static int btintel_set_diag_combined(struct hci_dev *hdev, bool enable) return ret; } -static void btintel_hw_error(struct hci_dev *hdev, u8 code) +void btintel_hw_error(struct hci_dev *hdev, u8 code) { struct sk_buff *skb; u8 type = 0x00; @@ -277,6 +277,7 @@ static void btintel_hw_error(struct hci_dev *hdev, u8 code) kfree_skb(skb); } +EXPORT_SYMBOL_GPL(btintel_hw_error); int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) { @@ -455,8 +456,8 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver) } EXPORT_SYMBOL_GPL(btintel_read_version); -static int btintel_version_info_tlv(struct hci_dev *hdev, - struct intel_version_tlv *version) +int btintel_version_info_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version) { const char *variant; @@ -481,6 +482,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, case 0x19: /* Slr-F */ case 0x1b: /* Mgr */ case 0x1c: /* Gale Peak (GaP) */ + case 0x1e: /* BlazarI (Bzr) */ break; default: bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)", @@ -489,7 +491,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, } switch (version->img_type) { - case 0x01: + case BTINTEL_IMG_BOOTLOADER: variant = "Bootloader"; /* It is required that every single firmware fragment is acknowledged * with a command complete event. If the boot parameters indicate @@ -521,7 +523,10 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, version->min_fw_build_nn, version->min_fw_build_cw, 2000 + version->min_fw_build_yy); break; - case 0x03: + case BTINTEL_IMG_IML: + variant = "Intermediate loader"; + break; + case BTINTEL_IMG_OP: variant = "Firmware"; break; default: @@ -535,15 +540,16 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant, 2000 + (version->timestamp >> 8), version->timestamp & 0xff, version->build_type, version->build_num); - if (version->img_type == 0x03) + if (version->img_type == BTINTEL_IMG_OP) bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x", version->git_sha1); return 0; } +EXPORT_SYMBOL_GPL(btintel_version_info_tlv); -static int btintel_parse_version_tlv(struct hci_dev *hdev, - struct intel_version_tlv *version, - struct sk_buff *skb) +int btintel_parse_version_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version, + struct sk_buff *skb) { /* Consume Command Complete Status field */ skb_pull(skb, 1); @@ -645,6 +651,7 @@ static int btintel_parse_version_tlv(struct hci_dev *hdev, return 0; } +EXPORT_SYMBOL_GPL(btintel_parse_version_tlv); static int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version) @@ -1172,7 +1179,7 @@ static int btintel_download_fw_tlv(struct hci_dev *hdev, * If the firmware version has changed that means it needs to be reset * to bootloader when operational so the new firmware can be loaded. */ - if (ver->img_type == 0x03) + if (ver->img_type == BTINTEL_IMG_OP) return -EINVAL; /* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support @@ -2194,10 +2201,26 @@ static void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver, char *fw_name, size_t len, const char *suffix) { + const char *format; /* The firmware file name for new generation controllers will be * ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step> */ - snprintf(fw_name, len, "intel/ibt-%04x-%04x.%s", + switch (ver->cnvi_top & 0xfff) { + /* Only Blazar product supports downloading of intermediate loader + * image + */ + case BTINTEL_CNVI_BLAZARI: + if (ver->img_type == BTINTEL_IMG_BOOTLOADER) + format = "intel/ibt-%04x-%04x-iml.%s"; + else + format = "intel/ibt-%04x-%04x.%s"; + break; + default: + format = "intel/ibt-%04x-%04x.%s"; + break; + } + + snprintf(fw_name, len, format, INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top), INTEL_CNVX_TOP_STEP(ver->cnvi_top)), INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top), @@ -2230,7 +2253,7 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev, * It is not possible to use the Secure Boot Parameters in this * case since that command is only available in bootloader mode. */ - if (ver->img_type == 0x03) { + if (ver->img_type == BTINTEL_IMG_OP) { btintel_clear_flag(hdev, INTEL_BOOTLOADER); btintel_check_bdaddr(hdev); } else { @@ -2577,8 +2600,8 @@ static void btintel_set_dsm_reset_method(struct hci_dev *hdev, data->acpi_reset_method = btintel_acpi_reset_method; } -static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, - struct intel_version_tlv *ver) +int btintel_bootloader_setup_tlv(struct hci_dev *hdev, + struct intel_version_tlv *ver) { u32 boot_param; char ddcname[64]; @@ -2600,13 +2623,30 @@ static int btintel_bootloader_setup_tlv(struct hci_dev *hdev, return err; /* check if controller is already having an operational firmware */ - if (ver->img_type == 0x03) + if (ver->img_type == BTINTEL_IMG_OP) goto finish; err = btintel_boot(hdev, boot_param); if (err) return err; + err = btintel_read_version_tlv(hdev, ver); + if (err) + return err; + + /* If image type returned is BTINTEL_IMG_IML, then controller supports + * intermediae loader image + */ + if (ver->img_type == BTINTEL_IMG_IML) { + err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param); + if (err) + return err; + + err = btintel_boot(hdev, boot_param); + if (err) + return err; + } + btintel_clear_flag(hdev, INTEL_BOOTLOADER); btintel_get_fw_name_tlv(ver, ddcname, sizeof(ddcname), "ddc"); @@ -2645,8 +2685,9 @@ finish: return 0; } +EXPORT_SYMBOL_GPL(btintel_bootloader_setup_tlv); -static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) +void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) { switch (hw_variant) { /* Legacy bootloader devices that supports MSFT Extension */ @@ -2662,6 +2703,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x19: case 0x1b: case 0x1c: + case 0x1e: hci_set_msft_opcode(hdev, 0xFC1E); break; default: @@ -2669,6 +2711,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) break; } } +EXPORT_SYMBOL_GPL(btintel_set_msft_opcode); static void btintel_print_fseq_info(struct hci_dev *hdev) { @@ -2920,6 +2963,11 @@ static int btintel_setup_combined(struct hci_dev *hdev) err = -EINVAL; } + hci_set_hw_info(hdev, + "INTEL platform=%u variant=%u revision=%u", + ver.hw_platform, ver.hw_variant, + ver.hw_revision); + goto exit_error; } @@ -2996,6 +3044,7 @@ static int btintel_setup_combined(struct hci_dev *hdev) case 0x19: case 0x1b: case 0x1c: + case 0x1e: /* Display version information of TLV type */ btintel_version_info_tlv(hdev, &ver_tlv); @@ -3024,13 +3073,17 @@ static int btintel_setup_combined(struct hci_dev *hdev) break; } + hci_set_hw_info(hdev, "INTEL platform=%u variant=%u", + INTEL_HW_PLATFORM(ver_tlv.cnvi_bt), + INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); + exit_error: kfree_skb(skb); return err; } -static int btintel_shutdown_combined(struct hci_dev *hdev) +int btintel_shutdown_combined(struct hci_dev *hdev) { struct sk_buff *skb; int ret; @@ -3064,6 +3117,7 @@ static int btintel_shutdown_combined(struct hci_dev *hdev) return 0; } +EXPORT_SYMBOL_GPL(btintel_shutdown_combined); int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name) { diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index d19fcdb9ff0b..b5fea735e260 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -51,6 +51,12 @@ struct intel_tlv { u8 val[]; } __packed; +#define BTINTEL_CNVI_BLAZARI 0x900 + +#define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */ +#define BTINTEL_IMG_IML 0x02 /* Intermediate image */ +#define BTINTEL_IMG_OP 0x03 /* Operational image */ + struct intel_version_tlv { u32 cnvi_top; u32 cnvr_top; @@ -203,7 +209,7 @@ struct btintel_data { #define btintel_wait_on_flag_timeout(hdev, nr, m, to) \ wait_on_bit_timeout(btintel_get_flag(hdev), (nr), m, to) -#if IS_ENABLED(CONFIG_BT_INTEL) +#if IS_ENABLED(CONFIG_BT_INTEL) || IS_ENABLED(CONFIG_BT_INTEL_PCIE) int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_enter_mfg(struct hci_dev *hdev); @@ -228,6 +234,16 @@ 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); int btintel_set_quality_report(struct hci_dev *hdev, bool enable); +int btintel_version_info_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version); +int btintel_parse_version_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version, + struct sk_buff *skb); +void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant); +int btintel_bootloader_setup_tlv(struct hci_dev *hdev, + struct intel_version_tlv *ver); +int btintel_shutdown_combined(struct hci_dev *hdev); +void btintel_hw_error(struct hci_dev *hdev, u8 code); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -324,4 +340,37 @@ static inline int btintel_set_quality_report(struct hci_dev *hdev, bool enable) { return -ENODEV; } + +static inline int btintel_version_info_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version) +{ + return -EOPNOTSUPP; +} + +static inline int btintel_parse_version_tlv(struct hci_dev *hdev, + struct intel_version_tlv *version, + struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static inline void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) + +{ +} + +static inline int btintel_bootloader_setup_tlv(struct hci_dev *hdev, + struct intel_version_tlv *ver) +{ + return -ENODEV; +} + +static inline int btintel_shutdown_combined(struct hci_dev *hdev) +{ + return -ENODEV; +} + +static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) +{ +} #endif diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c new file mode 100644 index 000000000000..5b6805d87fcf --- /dev/null +++ b/drivers/bluetooth/btintel_pcie.c @@ -0,0 +1,1357 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * + * Bluetooth support for Intel PCIe devices + * + * Copyright (C) 2024 Intel Corporation + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/unaligned.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "btintel.h" +#include "btintel_pcie.h" + +#define VERSION "0.1" + +#define BTINTEL_PCI_DEVICE(dev, subdev) \ + .vendor = PCI_VENDOR_ID_INTEL, \ + .device = (dev), \ + .subvendor = PCI_ANY_ID, \ + .subdevice = (subdev), \ + .driver_data = 0 + +#define POLL_INTERVAL_US 10 + +/* Intel Bluetooth PCIe device id table */ +static const struct pci_device_id btintel_pcie_table[] = { + { BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, btintel_pcie_table); + +/* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */ +#define BTINTEL_PCIE_HCI_TYPE_LEN 4 +#define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001 +#define BTINTEL_PCIE_HCI_ACL_PKT 0x00000002 +#define BTINTEL_PCIE_HCI_SCO_PKT 0x00000003 +#define BTINTEL_PCIE_HCI_EVT_PKT 0x00000004 + +static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia, + u16 queue_num) +{ + bt_dev_dbg(hdev, "IA: %s: tr-h:%02u tr-t:%02u cr-h:%02u cr-t:%02u", + queue_num == BTINTEL_PCIE_TXQ_NUM ? "TXQ" : "RXQ", + ia->tr_hia[queue_num], ia->tr_tia[queue_num], + ia->cr_hia[queue_num], ia->cr_tia[queue_num]); +} + +static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1, + u16 index) +{ + bt_dev_dbg(hdev, "RXQ:urbd1(%u) frbd_tag:%u status: 0x%x fixed:0x%x", + index, urbd1->frbd_tag, urbd1->status, urbd1->fixed); +} + +static int btintel_pcie_poll_bit(struct btintel_pcie_data *data, u32 offset, + u32 bits, u32 mask, int timeout_us) +{ + int t = 0; + u32 reg; + + do { + reg = btintel_pcie_rd_reg32(data, offset); + + if ((reg & mask) == (bits & mask)) + return t; + udelay(POLL_INTERVAL_US); + t += POLL_INTERVAL_US; + } while (t < timeout_us); + + return -ETIMEDOUT; +} + +static struct btintel_pcie_data *btintel_pcie_get_data(struct msix_entry *entry) +{ + u8 queue = entry->entry; + struct msix_entry *entries = entry - queue; + + return container_of(entries, struct btintel_pcie_data, msix_entries[0]); +} + +/* Set the doorbell for TXQ to notify the device that @index (actually index-1) + * of the TFD is updated and ready to transmit. + */ +static void btintel_pcie_set_tx_db(struct btintel_pcie_data *data, u16 index) +{ + u32 val; + + val = index; + val |= (BTINTEL_PCIE_TX_DB_VEC << 16); + + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR, val); +} + +/* Copy the data to next(@tfd_index) data buffer and update the TFD(transfer + * descriptor) with the data length and the DMA address of the data buffer. + */ +static void btintel_pcie_prepare_tx(struct txq *txq, u16 tfd_index, + struct sk_buff *skb) +{ + struct data_buf *buf; + struct tfd *tfd; + + tfd = &txq->tfds[tfd_index]; + memset(tfd, 0, sizeof(*tfd)); + + buf = &txq->bufs[tfd_index]; + + tfd->size = skb->len; + tfd->addr = buf->data_p_addr; + + /* Copy the outgoing data to DMA buffer */ + memcpy(buf->data, skb->data, tfd->size); +} + +static int btintel_pcie_send_sync(struct btintel_pcie_data *data, + struct sk_buff *skb) +{ + int ret; + u16 tfd_index; + struct txq *txq = &data->txq; + + tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM]; + + if (tfd_index > txq->count) + return -ERANGE; + + /* Prepare for TX. It updates the TFD with the length of data and + * address of the DMA buffer, and copy the data to the DMA buffer + */ + btintel_pcie_prepare_tx(txq, tfd_index, skb); + + tfd_index = (tfd_index + 1) % txq->count; + data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM] = tfd_index; + + /* Arm wait event condition */ + data->tx_wait_done = false; + + /* Set the doorbell to notify the device */ + btintel_pcie_set_tx_db(data, tfd_index); + + /* Wait for the complete interrupt - URBD0 */ + ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done, + msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS)); + if (!ret) + return -ETIME; + + return 0; +} + +/* Set the doorbell for RXQ to notify the device that @index (actually index-1) + * is available to receive the data + */ +static void btintel_pcie_set_rx_db(struct btintel_pcie_data *data, u16 index) +{ + u32 val; + + val = index; + val |= (BTINTEL_PCIE_RX_DB_VEC << 16); + + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR, val); +} + +/* Update the FRBD (free buffer descriptor) with the @frbd_index and the + * DMA address of the free buffer. + */ +static void btintel_pcie_prepare_rx(struct rxq *rxq, u16 frbd_index) +{ + struct data_buf *buf; + struct frbd *frbd; + + /* Get the buffer of the FRBD for DMA */ + buf = &rxq->bufs[frbd_index]; + + frbd = &rxq->frbds[frbd_index]; + memset(frbd, 0, sizeof(*frbd)); + + /* Update FRBD */ + frbd->tag = frbd_index; + frbd->addr = buf->data_p_addr; +} + +static int btintel_pcie_submit_rx(struct btintel_pcie_data *data) +{ + u16 frbd_index; + struct rxq *rxq = &data->rxq; + + frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM]; + + if (frbd_index > rxq->count) + return -ERANGE; + + /* Prepare for RX submit. It updates the FRBD with the address of DMA + * buffer + */ + btintel_pcie_prepare_rx(rxq, frbd_index); + + frbd_index = (frbd_index + 1) % rxq->count; + data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM] = frbd_index; + ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_RXQ_NUM); + + /* Set the doorbell to notify the device */ + btintel_pcie_set_rx_db(data, frbd_index); + + return 0; +} + +static int btintel_pcie_start_rx(struct btintel_pcie_data *data) +{ + int i, ret; + + for (i = 0; i < BTINTEL_PCIE_RX_MAX_QUEUE; i++) { + ret = btintel_pcie_submit_rx(data); + if (ret) + return ret; + } + + return 0; +} + +static void btintel_pcie_reset_ia(struct btintel_pcie_data *data) +{ + memset(data->ia.tr_hia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES); + memset(data->ia.tr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES); + memset(data->ia.cr_hia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES); + memset(data->ia.cr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES); +} + +static void btintel_pcie_reset_bt(struct btintel_pcie_data *data) +{ + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, + BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET); +} + +/* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in + * BTINTEL_PCIE_CSR_FUNC_CTRL_REG register and wait for MSI-X with + * BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0. + * Then the host reads firmware version from BTINTEL_CSR_F2D_MBX and the boot stage + * from BTINTEL_PCIE_CSR_BOOT_STAGE_REG. + */ +static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) +{ + int err; + + data->gp0_received = false; + + /* Update the DMA address of CI struct to CSR */ + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG, + data->ci_p_addr & 0xffffffff); + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG, + (u64)data->ci_p_addr >> 32); + + /* Reset the cached value of boot stage. it is updated by the MSI-X + * gp0 interrupt handler. + */ + data->boot_stage_cache = 0x0; + + /* Set MAC_INIT bit to start primary bootloader */ + btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT); + + /* Wait until MAC_ACCESS is granted */ + err = btintel_pcie_poll_bit(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS, + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS, + BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US); + if (err < 0) + return -ENODEV; + + /* MAC is ready. Enable BT FUNC */ + btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, + BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | + BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT); + + btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + /* wait for interrupt from the device after booting up to primary + * bootloader. + */ + err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT)); + if (!err) + return -ETIME; + + /* Check cached boot stage is BTINTEL_PCIE_CSR_BOOT_STAGE_ROM(BIT(0)) */ + if (~data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM) + return -ENODEV; + + return 0; +} + +/* This function handles the MSI-X interrupt for gp0 cause (bit 0 in + * BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES) which is sent for boot stage and image response. + */ +static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) +{ + u32 reg; + + /* This interrupt is for three different causes and it is not easy to + * know what causes the interrupt. So, it compares each register value + * with cached value and update it before it wake up the queue. + */ + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG); + if (reg != data->boot_stage_cache) + data->boot_stage_cache = reg; + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IMG_RESPONSE_REG); + if (reg != data->img_resp_cache) + data->img_resp_cache = reg; + + data->gp0_received = true; + + /* If the boot stage is OP or IML, reset IA and start RX again */ + if (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW || + data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) { + btintel_pcie_reset_ia(data); + btintel_pcie_start_rx(data); + } + + wake_up(&data->gp0_wait_q); +} + +/* This function handles the MSX-X interrupt for rx queue 0 which is for TX + */ +static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) +{ + u16 cr_tia, cr_hia; + struct txq *txq; + struct urbd0 *urbd0; + + cr_tia = data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM]; + cr_hia = data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM]; + + if (cr_tia == cr_hia) + return; + + txq = &data->txq; + + while (cr_tia != cr_hia) { + data->tx_wait_done = true; + wake_up(&data->tx_wait_q); + + urbd0 = &txq->urbd0s[cr_tia]; + + if (urbd0->tfd_index > txq->count) + return; + + cr_tia = (cr_tia + 1) % txq->count; + data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] = cr_tia; + ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_TXQ_NUM); + } +} + +/* Process the received rx data + * It check the frame header to identify the data type and create skb + * and calling HCI API + */ +static int btintel_pcie_recv_frame(struct btintel_pcie_data *data, + struct sk_buff *skb) +{ + int ret; + u8 pkt_type; + u16 plen; + u32 pcie_pkt_type; + struct sk_buff *new_skb; + void *pdata; + struct hci_dev *hdev = data->hdev; + + spin_lock(&data->hci_rx_lock); + + /* The first 4 bytes indicates the Intel PCIe specific packet type */ + pdata = skb_pull_data(skb, BTINTEL_PCIE_HCI_TYPE_LEN); + if (!data) { + bt_dev_err(hdev, "Corrupted packet received"); + ret = -EILSEQ; + goto exit_error; + } + + pcie_pkt_type = get_unaligned_le32(pdata); + + switch (pcie_pkt_type) { + case BTINTEL_PCIE_HCI_ACL_PKT: + if (skb->len >= HCI_ACL_HDR_SIZE) { + plen = HCI_ACL_HDR_SIZE + __le16_to_cpu(hci_acl_hdr(skb)->dlen); + pkt_type = HCI_ACLDATA_PKT; + } else { + bt_dev_err(hdev, "ACL packet is too short"); + ret = -EILSEQ; + goto exit_error; + } + break; + + case BTINTEL_PCIE_HCI_SCO_PKT: + if (skb->len >= HCI_SCO_HDR_SIZE) { + plen = HCI_SCO_HDR_SIZE + hci_sco_hdr(skb)->dlen; + pkt_type = HCI_SCODATA_PKT; + } else { + bt_dev_err(hdev, "SCO packet is too short"); + ret = -EILSEQ; + goto exit_error; + } + break; + + case BTINTEL_PCIE_HCI_EVT_PKT: + if (skb->len >= HCI_EVENT_HDR_SIZE) { + plen = HCI_EVENT_HDR_SIZE + hci_event_hdr(skb)->plen; + pkt_type = HCI_EVENT_PKT; + } else { + bt_dev_err(hdev, "Event packet is too short"); + ret = -EILSEQ; + goto exit_error; + } + break; + default: + bt_dev_err(hdev, "Invalid packet type received: 0x%4.4x", + pcie_pkt_type); + ret = -EINVAL; + goto exit_error; + } + + if (skb->len < plen) { + bt_dev_err(hdev, "Received corrupted packet. type: 0x%2.2x", + pkt_type); + ret = -EILSEQ; + goto exit_error; + } + + bt_dev_dbg(hdev, "pkt_type: 0x%2.2x len: %u", pkt_type, plen); + + new_skb = bt_skb_alloc(plen, GFP_ATOMIC); + if (!new_skb) { + bt_dev_err(hdev, "Failed to allocate memory for skb of len: %u", + skb->len); + ret = -ENOMEM; + goto exit_error; + } + + hci_skb_pkt_type(new_skb) = pkt_type; + skb_put_data(new_skb, skb->data, plen); + hdev->stat.byte_rx += plen; + + if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT) + ret = btintel_recv_event(hdev, new_skb); + else + ret = hci_recv_frame(hdev, new_skb); + +exit_error: + if (ret) + hdev->stat.err_rx++; + + spin_unlock(&data->hci_rx_lock); + + return ret; +} + +static void btintel_pcie_rx_work(struct work_struct *work) +{ + struct btintel_pcie_data *data = container_of(work, + struct btintel_pcie_data, rx_work); + struct sk_buff *skb; + int err; + struct hci_dev *hdev = data->hdev; + + /* Process the sk_buf in queue and send to the HCI layer */ + while ((skb = skb_dequeue(&data->rx_skb_q))) { + err = btintel_pcie_recv_frame(data, skb); + if (err) + bt_dev_err(hdev, "Failed to send received frame: %d", + err); + kfree_skb(skb); + } +} + +/* create sk_buff with data and save it to queue and start RX work */ +static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status, + void *buf) +{ + int ret, len; + struct rfh_hdr *rfh_hdr; + struct sk_buff *skb; + + rfh_hdr = buf; + + len = rfh_hdr->packet_len; + if (len <= 0) { + ret = -EINVAL; + goto resubmit; + } + + /* Remove RFH header */ + buf += sizeof(*rfh_hdr); + + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + ret = -ENOMEM; + goto resubmit; + } + + skb_put_data(skb, buf, len); + skb_queue_tail(&data->rx_skb_q, skb); + queue_work(data->workqueue, &data->rx_work); + +resubmit: + ret = btintel_pcie_submit_rx(data); + + return ret; +} + +/* Handles the MSI-X interrupt for rx queue 1 which is for RX */ +static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data) +{ + u16 cr_hia, cr_tia; + struct rxq *rxq; + struct urbd1 *urbd1; + struct data_buf *buf; + int ret; + struct hci_dev *hdev = data->hdev; + + cr_hia = data->ia.cr_hia[BTINTEL_PCIE_RXQ_NUM]; + cr_tia = data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM]; + + bt_dev_dbg(hdev, "RXQ: cr_hia: %u cr_tia: %u", cr_hia, cr_tia); + + /* Check CR_TIA and CR_HIA for change */ + if (cr_tia == cr_hia) { + bt_dev_warn(hdev, "RXQ: no new CD found"); + return; + } + + rxq = &data->rxq; + + /* The firmware sends multiple CD in a single MSI-X and it needs to + * process all received CDs in this interrupt. + */ + while (cr_tia != cr_hia) { + urbd1 = &rxq->urbd1s[cr_tia]; + ipc_print_urbd1(data->hdev, urbd1, cr_tia); + + buf = &rxq->bufs[urbd1->frbd_tag]; + if (!buf) { + bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d", + urbd1->frbd_tag); + return; + } + + ret = btintel_pcie_submit_rx_work(data, urbd1->status, + buf->data); + if (ret) { + bt_dev_err(hdev, "RXQ: failed to submit rx request"); + return; + } + + cr_tia = (cr_tia + 1) % rxq->count; + data->ia.cr_tia[BTINTEL_PCIE_RXQ_NUM] = cr_tia; + ipc_print_ia_ring(data->hdev, &data->ia, BTINTEL_PCIE_RXQ_NUM); + } +} + +static irqreturn_t btintel_pcie_msix_isr(int irq, void *data) +{ + return IRQ_WAKE_THREAD; +} + +static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id) +{ + struct msix_entry *entry = dev_id; + struct btintel_pcie_data *data = btintel_pcie_get_data(entry); + u32 intr_fh, intr_hw; + + spin_lock(&data->irq_lock); + intr_fh = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES); + intr_hw = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES); + + /* Clear causes registers to avoid being handling the same cause */ + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES, intr_fh); + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES, intr_hw); + spin_unlock(&data->irq_lock); + + if (unlikely(!(intr_fh | intr_hw))) { + /* Ignore interrupt, inta == 0 */ + return IRQ_NONE; + } + + /* This interrupt is triggered by the firmware after updating + * boot_stage register and image_response register + */ + if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0) + btintel_pcie_msix_gp0_handler(data); + + /* For TX */ + if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) + btintel_pcie_msix_tx_handle(data); + + /* For RX */ + if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1) + btintel_pcie_msix_rx_handle(data); + + /* + * Before sending the interrupt the HW disables it to prevent a nested + * interrupt. This is done by writing 1 to the corresponding bit in + * the mask register. After handling the interrupt, it should be + * re-enabled by clearing this bit. This register is defined as write 1 + * clear (W1C) register, meaning that it's cleared by writing 1 + * to the bit. + */ + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_MSIX_AUTOMASK_ST, + BIT(entry->entry)); + + return IRQ_HANDLED; +} + +/* This function requests the irq for MSI-X and registers the handlers per irq. + * Currently, it requests only 1 irq for all interrupt causes. + */ +static int btintel_pcie_setup_irq(struct btintel_pcie_data *data) +{ + int err; + int num_irqs, i; + + for (i = 0; i < BTINTEL_PCIE_MSIX_VEC_MAX; i++) + data->msix_entries[i].entry = i; + + num_irqs = pci_alloc_irq_vectors(data->pdev, BTINTEL_PCIE_MSIX_VEC_MIN, + BTINTEL_PCIE_MSIX_VEC_MAX, PCI_IRQ_MSIX); + if (num_irqs < 0) + return num_irqs; + + data->alloc_vecs = num_irqs; + data->msix_enabled = 1; + data->def_irq = 0; + + /* setup irq handler */ + for (i = 0; i < data->alloc_vecs; i++) { + struct msix_entry *msix_entry; + + msix_entry = &data->msix_entries[i]; + msix_entry->vector = pci_irq_vector(data->pdev, i); + + err = devm_request_threaded_irq(&data->pdev->dev, + msix_entry->vector, + btintel_pcie_msix_isr, + btintel_pcie_irq_msix_handler, + IRQF_SHARED, + KBUILD_MODNAME, + msix_entry); + if (err) { + pci_free_irq_vectors(data->pdev); + data->alloc_vecs = 0; + return err; + } + } + return 0; +} + +struct btintel_pcie_causes_list { + u32 cause; + u32 mask_reg; + u8 cause_num; +}; + +static struct btintel_pcie_causes_list causes_list[] = { + { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x00 }, + { BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK, 0x01 }, + { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK, 0x20 }, +}; + +/* This function configures the interrupt masks for both HW_INT_CAUSES and + * FH_INT_CAUSES which are meaningful to us. + * + * After resetting BT function via PCIE FLR or FUNC_CTRL reset, the driver + * need to call this function again to configure since the masks + * are reset to 0xFFFFFFFF after reset. + */ +static void btintel_pcie_config_msix(struct btintel_pcie_data *data) +{ + int i; + int val = data->def_irq | BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE; + + /* Set Non Auto Clear Cause */ + for (i = 0; i < ARRAY_SIZE(causes_list); i++) { + btintel_pcie_wr_reg8(data, + BTINTEL_PCIE_CSR_MSIX_IVAR(causes_list[i].cause_num), + val); + btintel_pcie_clr_reg_bits(data, + causes_list[i].mask_reg, + causes_list[i].cause); + } + + /* Save the initial interrupt mask */ + data->fh_init_mask = ~btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK); + data->hw_init_mask = ~btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK); +} + +static int btintel_pcie_config_pcie(struct pci_dev *pdev, + struct btintel_pcie_data *data) +{ + int err; + + err = pcim_enable_device(pdev); + if (err) + return err; + + pci_set_master(pdev); + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return err; + } + + err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); + if (err) + return err; + + data->base_addr = pcim_iomap_table(pdev)[0]; + if (!data->base_addr) + return -ENODEV; + + err = btintel_pcie_setup_irq(data); + if (err) + return err; + + /* Configure MSI-X with causes list */ + btintel_pcie_config_msix(data); + + return 0; +} + +static void btintel_pcie_init_ci(struct btintel_pcie_data *data, + struct ctx_info *ci) +{ + ci->version = 0x1; + ci->size = sizeof(*ci); + ci->config = 0x0000; + ci->addr_cr_hia = data->ia.cr_hia_p_addr; + ci->addr_tr_tia = data->ia.tr_tia_p_addr; + ci->addr_cr_tia = data->ia.cr_tia_p_addr; + ci->addr_tr_hia = data->ia.tr_hia_p_addr; + ci->num_cr_ia = BTINTEL_PCIE_NUM_QUEUES; + ci->num_tr_ia = BTINTEL_PCIE_NUM_QUEUES; + ci->addr_urbdq0 = data->txq.urbd0s_p_addr; + ci->addr_tfdq = data->txq.tfds_p_addr; + ci->num_tfdq = data->txq.count; + ci->num_urbdq0 = data->txq.count; + ci->tfdq_db_vec = BTINTEL_PCIE_TXQ_NUM; + ci->urbdq0_db_vec = BTINTEL_PCIE_TXQ_NUM; + ci->rbd_size = BTINTEL_PCIE_RBD_SIZE_4K; + ci->addr_frbdq = data->rxq.frbds_p_addr; + ci->num_frbdq = data->rxq.count; + ci->frbdq_db_vec = BTINTEL_PCIE_RXQ_NUM; + ci->addr_urbdq1 = data->rxq.urbd1s_p_addr; + ci->num_urbdq1 = data->rxq.count; + ci->urbdq_db_vec = BTINTEL_PCIE_RXQ_NUM; +} + +static void btintel_pcie_free_txq_bufs(struct btintel_pcie_data *data, + struct txq *txq) +{ + /* Free data buffers first */ + dma_free_coherent(&data->pdev->dev, txq->count * BTINTEL_PCIE_BUFFER_SIZE, + txq->buf_v_addr, txq->buf_p_addr); + kfree(txq->bufs); +} + +static int btintel_pcie_setup_txq_bufs(struct btintel_pcie_data *data, + struct txq *txq) +{ + int i; + struct data_buf *buf; + + /* Allocate the same number of buffers as the descriptor */ + txq->bufs = kmalloc_array(txq->count, sizeof(*buf), GFP_KERNEL); + if (!txq->bufs) + return -ENOMEM; + + /* Allocate full chunk of data buffer for DMA first and do indexing and + * initialization next, so it can be freed easily + */ + txq->buf_v_addr = dma_alloc_coherent(&data->pdev->dev, + txq->count * BTINTEL_PCIE_BUFFER_SIZE, + &txq->buf_p_addr, + GFP_KERNEL | __GFP_NOWARN); + if (!txq->buf_v_addr) { + kfree(txq->bufs); + return -ENOMEM; + } + memset(txq->buf_v_addr, 0, txq->count * BTINTEL_PCIE_BUFFER_SIZE); + + /* Setup the allocated DMA buffer to bufs. Each data_buf should + * have virtual address and physical address + */ + for (i = 0; i < txq->count; i++) { + buf = &txq->bufs[i]; + buf->data_p_addr = txq->buf_p_addr + (i * BTINTEL_PCIE_BUFFER_SIZE); + buf->data = txq->buf_v_addr + (i * BTINTEL_PCIE_BUFFER_SIZE); + } + + return 0; +} + +static void btintel_pcie_free_rxq_bufs(struct btintel_pcie_data *data, + struct rxq *rxq) +{ + /* Free data buffers first */ + dma_free_coherent(&data->pdev->dev, rxq->count * BTINTEL_PCIE_BUFFER_SIZE, + rxq->buf_v_addr, rxq->buf_p_addr); + kfree(rxq->bufs); +} + +static int btintel_pcie_setup_rxq_bufs(struct btintel_pcie_data *data, + struct rxq *rxq) +{ + int i; + struct data_buf *buf; + + /* Allocate the same number of buffers as the descriptor */ + rxq->bufs = kmalloc_array(rxq->count, sizeof(*buf), GFP_KERNEL); + if (!rxq->bufs) + return -ENOMEM; + + /* Allocate full chunk of data buffer for DMA first and do indexing and + * initialization next, so it can be freed easily + */ + rxq->buf_v_addr = dma_alloc_coherent(&data->pdev->dev, + rxq->count * BTINTEL_PCIE_BUFFER_SIZE, + &rxq->buf_p_addr, + GFP_KERNEL | __GFP_NOWARN); + if (!rxq->buf_v_addr) { + kfree(rxq->bufs); + return -ENOMEM; + } + memset(rxq->buf_v_addr, 0, rxq->count * BTINTEL_PCIE_BUFFER_SIZE); + + /* Setup the allocated DMA buffer to bufs. Each data_buf should + * have virtual address and physical address + */ + for (i = 0; i < rxq->count; i++) { + buf = &rxq->bufs[i]; + buf->data_p_addr = rxq->buf_p_addr + (i * BTINTEL_PCIE_BUFFER_SIZE); + buf->data = rxq->buf_v_addr + (i * BTINTEL_PCIE_BUFFER_SIZE); + } + + return 0; +} + +static void btintel_pcie_setup_ia(struct btintel_pcie_data *data, + dma_addr_t p_addr, void *v_addr, + struct ia *ia) +{ + /* TR Head Index Array */ + ia->tr_hia_p_addr = p_addr; + ia->tr_hia = v_addr; + + /* TR Tail Index Array */ + ia->tr_tia_p_addr = p_addr + sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES; + ia->tr_tia = v_addr + sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES; + + /* CR Head index Array */ + ia->cr_hia_p_addr = p_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 2); + ia->cr_hia = v_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 2); + + /* CR Tail Index Array */ + ia->cr_tia_p_addr = p_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 3); + ia->cr_tia = v_addr + (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 3); +} + +static void btintel_pcie_free(struct btintel_pcie_data *data) +{ + btintel_pcie_free_rxq_bufs(data, &data->rxq); + btintel_pcie_free_txq_bufs(data, &data->txq); + + dma_pool_free(data->dma_pool, data->dma_v_addr, data->dma_p_addr); + dma_pool_destroy(data->dma_pool); +} + +/* Allocate tx and rx queues, any related data structures and buffers. + */ +static int btintel_pcie_alloc(struct btintel_pcie_data *data) +{ + int err = 0; + size_t total; + dma_addr_t p_addr; + void *v_addr; + + /* Allocate the chunk of DMA memory for descriptors, index array, and + * context information, instead of allocating individually. + * The DMA memory for data buffer is allocated while setting up the + * each queue. + * + * Total size is sum of the following + * + size of TFD * Number of descriptors in queue + * + size of URBD0 * Number of descriptors in queue + * + size of FRBD * Number of descriptors in queue + * + size of URBD1 * Number of descriptors in queue + * + size of index * Number of queues(2) * type of index array(4) + * + size of context information + */ + total = (sizeof(struct tfd) + sizeof(struct urbd0) + sizeof(struct frbd) + + sizeof(struct urbd1)) * BTINTEL_DESCS_COUNT; + + /* Add the sum of size of index array and size of ci struct */ + total += (sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4) + sizeof(struct ctx_info); + + /* Allocate DMA Pool */ + data->dma_pool = dma_pool_create(KBUILD_MODNAME, &data->pdev->dev, + total, BTINTEL_PCIE_DMA_POOL_ALIGNMENT, 0); + if (!data->dma_pool) { + err = -ENOMEM; + goto exit_error; + } + + v_addr = dma_pool_zalloc(data->dma_pool, GFP_KERNEL | __GFP_NOWARN, + &p_addr); + if (!v_addr) { + dma_pool_destroy(data->dma_pool); + err = -ENOMEM; + goto exit_error; + } + + data->dma_p_addr = p_addr; + data->dma_v_addr = v_addr; + + /* Setup descriptor count */ + data->txq.count = BTINTEL_DESCS_COUNT; + data->rxq.count = BTINTEL_DESCS_COUNT; + + /* Setup tfds */ + data->txq.tfds_p_addr = p_addr; + data->txq.tfds = v_addr; + + p_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); + v_addr += (sizeof(struct tfd) * BTINTEL_DESCS_COUNT); + + /* Setup urbd0 */ + data->txq.urbd0s_p_addr = p_addr; + data->txq.urbd0s = v_addr; + + p_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); + v_addr += (sizeof(struct urbd0) * BTINTEL_DESCS_COUNT); + + /* Setup FRBD*/ + data->rxq.frbds_p_addr = p_addr; + data->rxq.frbds = v_addr; + + p_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); + v_addr += (sizeof(struct frbd) * BTINTEL_DESCS_COUNT); + + /* Setup urbd1 */ + data->rxq.urbd1s_p_addr = p_addr; + data->rxq.urbd1s = v_addr; + + p_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); + v_addr += (sizeof(struct urbd1) * BTINTEL_DESCS_COUNT); + + /* Setup data buffers for txq */ + err = btintel_pcie_setup_txq_bufs(data, &data->txq); + if (err) + goto exit_error_pool; + + /* Setup data buffers for rxq */ + err = btintel_pcie_setup_rxq_bufs(data, &data->rxq); + if (err) + goto exit_error_txq; + + /* Setup Index Array */ + btintel_pcie_setup_ia(data, p_addr, v_addr, &data->ia); + + /* Setup Context Information */ + p_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4; + v_addr += sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES * 4; + + data->ci = v_addr; + data->ci_p_addr = p_addr; + + /* Initialize the CI */ + btintel_pcie_init_ci(data, data->ci); + + return 0; + +exit_error_txq: + btintel_pcie_free_txq_bufs(data, &data->txq); +exit_error_pool: + dma_pool_free(data->dma_pool, data->dma_v_addr, data->dma_p_addr); + dma_pool_destroy(data->dma_pool); +exit_error: + return err; +} + +static int btintel_pcie_open(struct hci_dev *hdev) +{ + bt_dev_dbg(hdev, ""); + + return 0; +} + +static int btintel_pcie_close(struct hci_dev *hdev) +{ + bt_dev_dbg(hdev, ""); + + return 0; +} + +static int btintel_pcie_inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) +{ + struct sk_buff *skb; + struct hci_event_hdr *hdr; + struct hci_ev_cmd_complete *evt; + + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr->evt = HCI_EV_CMD_COMPLETE; + hdr->plen = sizeof(*evt) + 1; + + evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt->ncmd = 0x01; + evt->opcode = cpu_to_le16(opcode); + + *(u8 *)skb_put(skb, 1) = 0x00; + + hci_skb_pkt_type(skb) = HCI_EVENT_PKT; + + return hci_recv_frame(hdev, skb); +} + +static int btintel_pcie_send_frame(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + int ret; + u32 type; + + /* Due to the fw limitation, the type header of the packet should be + * 4 bytes unlike 1 byte for UART. In UART, the firmware can read + * the first byte to get the packet type and redirect the rest of data + * packet to the right handler. + * + * But for PCIe, THF(Transfer Flow Handler) fetches the 4 bytes of data + * from DMA memory and by the time it reads the first 4 bytes, it has + * already consumed some part of packet. Thus the packet type indicator + * for iBT PCIe is 4 bytes. + * + * Luckily, when HCI core creates the skb, it allocates 8 bytes of + * head room for profile and driver use, and before sending the data + * to the device, append the iBT PCIe packet type in the front. + */ + switch (hci_skb_pkt_type(skb)) { + case HCI_COMMAND_PKT: + type = BTINTEL_PCIE_HCI_CMD_PKT; + if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { + struct hci_command_hdr *cmd = (void *)skb->data; + __u16 opcode = le16_to_cpu(cmd->opcode); + + /* When the 0xfc01 command is issued to boot into + * the operational firmware, it will actually not + * send a command complete event. To keep the flow + * control working inject that event here. + */ + if (opcode == 0xfc01) + btintel_pcie_inject_cmd_complete(hdev, opcode); + } + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + type = BTINTEL_PCIE_HCI_ACL_PKT; + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + type = BTINTEL_PCIE_HCI_SCO_PKT; + hdev->stat.sco_tx++; + break; + default: + bt_dev_err(hdev, "Unknown HCI packet type"); + return -EILSEQ; + } + memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &type, + BTINTEL_PCIE_HCI_TYPE_LEN); + + ret = btintel_pcie_send_sync(data, skb); + if (ret) { + hdev->stat.err_tx++; + bt_dev_err(hdev, "Failed to send frame (%d)", ret); + goto exit_error; + } + hdev->stat.byte_tx += skb->len; + kfree_skb(skb); + +exit_error: + return ret; +} + +static void btintel_pcie_release_hdev(struct btintel_pcie_data *data) +{ + struct hci_dev *hdev; + + hdev = data->hdev; + hci_unregister_dev(hdev); + hci_free_dev(hdev); + data->hdev = NULL; +} + +static int btintel_pcie_setup(struct hci_dev *hdev) +{ + const u8 param[1] = { 0xFF }; + struct intel_version_tlv ver_tlv; + struct sk_buff *skb; + int err; + + BT_DBG("%s", hdev->name); + + skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Reading Intel version command failed (%ld)", + PTR_ERR(skb)); + return PTR_ERR(skb); + } + + /* Check the status */ + if (skb->data[0]) { + bt_dev_err(hdev, "Intel Read Version command failed (%02x)", + skb->data[0]); + err = -EIO; + goto exit_error; + } + + /* Apply the common HCI quirks for Intel device */ + 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); + + /* Set up the quality report callback for Intel devices */ + hdev->set_quality_report = btintel_set_quality_report; + + memset(&ver_tlv, 0, sizeof(ver_tlv)); + /* For TLV type device, parse the tlv data */ + err = btintel_parse_version_tlv(hdev, &ver_tlv, skb); + if (err) { + bt_dev_err(hdev, "Failed to parse TLV version information"); + goto exit_error; + } + + switch (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt)) { + case 0x37: + break; + default: + bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)", + INTEL_HW_PLATFORM(ver_tlv.cnvi_bt)); + err = -EINVAL; + goto exit_error; + } + + /* Check for supported iBT hardware variants of this firmware + * loading method. + * + * This check has been put in place to ensure correct forward + * compatibility options when newer hardware variants come + * along. + */ + switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) { + case 0x1e: /* BzrI */ + /* Display version information of TLV type */ + btintel_version_info_tlv(hdev, &ver_tlv); + + /* Apply the device specific HCI quirks for TLV based devices + * + * All TLV based devices support WBS + */ + set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); + + /* Apply LE States quirk from solar onwards */ + set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks); + + /* Setup MSFT Extension support */ + btintel_set_msft_opcode(hdev, + INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); + + err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); + if (err) + goto exit_error; + break; + default: + bt_dev_err(hdev, "Unsupported Intel hw variant (%u)", + INTEL_HW_VARIANT(ver_tlv.cnvi_bt)); + err = -EINVAL; + break; + } + +exit_error: + kfree_skb(skb); + + return err; +} + +static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) +{ + int err; + struct hci_dev *hdev; + + hdev = hci_alloc_dev(); + if (!hdev) + return -ENOMEM; + + hdev->bus = HCI_PCI; + hci_set_drvdata(hdev, data); + + data->hdev = hdev; + SET_HCIDEV_DEV(hdev, &data->pdev->dev); + + hdev->manufacturer = 2; + hdev->open = btintel_pcie_open; + hdev->close = btintel_pcie_close; + hdev->send = btintel_pcie_send_frame; + hdev->setup = btintel_pcie_setup; + hdev->shutdown = btintel_shutdown_combined; + hdev->hw_error = btintel_hw_error; + hdev->set_diag = btintel_set_diag; + hdev->set_bdaddr = btintel_set_bdaddr; + + err = hci_register_dev(hdev); + if (err < 0) { + BT_ERR("Failed to register to hdev (%d)", err); + goto exit_error; + } + + return 0; + +exit_error: + hci_free_dev(hdev); + return err; +} + +static int btintel_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct btintel_pcie_data *data; + + if (!pdev) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->pdev = pdev; + + spin_lock_init(&data->irq_lock); + spin_lock_init(&data->hci_rx_lock); + + init_waitqueue_head(&data->gp0_wait_q); + data->gp0_received = false; + + init_waitqueue_head(&data->tx_wait_q); + data->tx_wait_done = false; + + data->workqueue = alloc_ordered_workqueue(KBUILD_MODNAME, WQ_HIGHPRI); + if (!data->workqueue) + return -ENOMEM; + + skb_queue_head_init(&data->rx_skb_q); + INIT_WORK(&data->rx_work, btintel_pcie_rx_work); + + data->boot_stage_cache = 0x00; + data->img_resp_cache = 0x00; + + err = btintel_pcie_config_pcie(pdev, data); + if (err) + goto exit_error; + + pci_set_drvdata(pdev, data); + + err = btintel_pcie_alloc(data); + if (err) + goto exit_error; + + err = btintel_pcie_enable_bt(data); + if (err) + goto exit_error; + + /* CNV information (CNVi and CNVr) is in CSR */ + data->cnvi = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_HW_REV_REG); + + data->cnvr = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_RF_ID_REG); + + err = btintel_pcie_start_rx(data); + if (err) + goto exit_error; + + err = btintel_pcie_setup_hdev(data); + if (err) + goto exit_error; + + bt_dev_dbg(data->hdev, "cnvi: 0x%8.8x cnvr: 0x%8.8x", data->cnvi, + data->cnvr); + return 0; + +exit_error: + /* reset device before exit */ + btintel_pcie_reset_bt(data); + + pci_clear_master(pdev); + + pci_set_drvdata(pdev, NULL); + + return err; +} + +static void btintel_pcie_remove(struct pci_dev *pdev) +{ + struct btintel_pcie_data *data; + + data = pci_get_drvdata(pdev); + + btintel_pcie_reset_bt(data); + + pci_free_irq_vectors(pdev); + + btintel_pcie_release_hdev(data); + + flush_work(&data->rx_work); + + destroy_workqueue(data->workqueue); + + btintel_pcie_free(data); + + pci_clear_master(pdev); + + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver btintel_pcie_driver = { + .name = KBUILD_MODNAME, + .id_table = btintel_pcie_table, + .probe = btintel_pcie_probe, + .remove = btintel_pcie_remove, +}; +module_pci_driver(btintel_pcie_driver); + +MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>"); +MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h new file mode 100644 index 000000000000..baaff70420f5 --- /dev/null +++ b/drivers/bluetooth/btintel_pcie.h @@ -0,0 +1,430 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * + * Bluetooth support for Intel PCIe devices + * + * Copyright (C) 2024 Intel Corporation + */ + +/* Control and Status Register(BTINTEL_PCIE_CSR) */ +#define BTINTEL_PCIE_CSR_BASE (0x000) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_REG (BTINTEL_PCIE_CSR_BASE + 0x024) +#define BTINTEL_PCIE_CSR_HW_REV_REG (BTINTEL_PCIE_CSR_BASE + 0x028) +#define BTINTEL_PCIE_CSR_RF_ID_REG (BTINTEL_PCIE_CSR_BASE + 0x09C) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_REG (BTINTEL_PCIE_CSR_BASE + 0x108) +#define BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG (BTINTEL_PCIE_CSR_BASE + 0x118) +#define BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG (BTINTEL_PCIE_CSR_BASE + 0x11C) +#define BTINTEL_PCIE_CSR_IMG_RESPONSE_REG (BTINTEL_PCIE_CSR_BASE + 0x12C) +#define BTINTEL_PCIE_CSR_HBUS_TARG_WRPTR (BTINTEL_PCIE_CSR_BASE + 0x460) + +/* BTINTEL_PCIE_CSR Function Control Register */ +#define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA (BIT(0)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT (BIT(6)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT (BIT(7)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET (BIT(31)) + +/* Value for BTINTEL_PCIE_CSR_BOOT_STAGE register */ +#define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM (BIT(0)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_IML (BIT(1)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW (BIT(2)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM_LOCKDOWN (BIT(10)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN (BIT(11)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23)) + +/* Registers for MSI-X */ +#define BTINTEL_PCIE_CSR_MSIX_BASE (0x2000) +#define BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0800) +#define BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0804) +#define BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0808) +#define BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK (BTINTEL_PCIE_CSR_MSIX_BASE + 0x080C) +#define BTINTEL_PCIE_CSR_MSIX_AUTOMASK_ST (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0810) +#define BTINTEL_PCIE_CSR_MSIX_AUTOMASK_EN (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0814) +#define BTINTEL_PCIE_CSR_MSIX_IVAR_BASE (BTINTEL_PCIE_CSR_MSIX_BASE + 0x0880) +#define BTINTEL_PCIE_CSR_MSIX_IVAR(cause) (BTINTEL_PCIE_CSR_MSIX_IVAR_BASE + (cause)) + +/* Causes for the FH register interrupts */ +enum msix_fh_int_causes { + BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0 = BIT(0), /* cause 0 */ + BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1 = BIT(1), /* cause 1 */ +}; + +/* Causes for the HW register interrupts */ +enum msix_hw_int_causes { + BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0 = BIT(0), /* cause 32 */ +}; + +#define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) + +/* Minimum and Maximum number of MSI-X Vector + * Intel Bluetooth PCIe support only 1 vector + */ +#define BTINTEL_PCIE_MSIX_VEC_MAX 1 +#define BTINTEL_PCIE_MSIX_VEC_MIN 1 + +/* Default poll time for MAC access during init */ +#define BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US 200000 + +/* Default interrupt timeout in msec */ +#define BTINTEL_DEFAULT_INTR_TIMEOUT 3000 + +/* The number of descriptors in TX/RX queues */ +#define BTINTEL_DESCS_COUNT 16 + +/* Number of Queue for TX and RX + * It indicates the index of the IA(Index Array) + */ +enum { + BTINTEL_PCIE_TXQ_NUM = 0, + BTINTEL_PCIE_RXQ_NUM = 1, + BTINTEL_PCIE_NUM_QUEUES = 2, +}; + +/* The size of DMA buffer for TX and RX in bytes */ +#define BTINTEL_PCIE_BUFFER_SIZE 4096 + +/* DMA allocation alignment */ +#define BTINTEL_PCIE_DMA_POOL_ALIGNMENT 256 + +#define BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS 500 + +/* Doorbell vector for TFD */ +#define BTINTEL_PCIE_TX_DB_VEC 0 + +/* Number of pending RX requests for downlink */ +#define BTINTEL_PCIE_RX_MAX_QUEUE 6 + +/* Doorbell vector for FRBD */ +#define BTINTEL_PCIE_RX_DB_VEC 513 + +/* RBD buffer size mapping */ +#define BTINTEL_PCIE_RBD_SIZE_4K 0x04 + +/* + * Struct for Context Information (v2) + * + * All members are write-only for host and read-only for device. + * + * @version: Version of context information + * @size: Size of context information + * @config: Config with which host wants peripheral to execute + * Subset of capability register published by device + * @addr_tr_hia: Address of TR Head Index Array + * @addr_tr_tia: Address of TR Tail Index Array + * @addr_cr_hia: Address of CR Head Index Array + * @addr_cr_tia: Address of CR Tail Index Array + * @num_tr_ia: Number of entries in TR Index Arrays + * @num_cr_ia: Number of entries in CR Index Arrays + * @rbd_siz: RBD Size { 0x4=4K } + * @addr_tfdq: Address of TFD Queue(tx) + * @addr_urbdq0: Address of URBD Queue(tx) + * @num_tfdq: Number of TFD in TFD Queue(tx) + * @num_urbdq0: Number of URBD in URBD Queue(tx) + * @tfdq_db_vec: Queue number of TFD + * @urbdq0_db_vec: Queue number of URBD + * @addr_frbdq: Address of FRBD Queue(rx) + * @addr_urbdq1: Address of URBD Queue(rx) + * @num_frbdq: Number of FRBD in FRBD Queue(rx) + * @frbdq_db_vec: Queue number of FRBD + * @num_urbdq1: Number of URBD in URBD Queue(rx) + * @urbdq_db_vec: Queue number of URBDQ1 + * @tr_msi_vec: Transfer Ring MSI-X Vector + * @cr_msi_vec: Completion Ring MSI-X Vector + * @dbgc_addr: DBGC first fragment address + * @dbgc_size: DBGC buffer size + * @early_enable: Enarly debug enable + * @dbg_output_mode: Debug output mode + * Bit[4] DBGC O/P { 0=SRAM, 1=DRAM(not relevant for NPK) } + * Bit[5] DBGC I/P { 0=BDBG, 1=DBGI } + * Bits[6:7] DBGI O/P(relevant if bit[5] = 1) + * 0=BT DBGC, 1=WiFi DBGC, 2=NPK } + * @dbg_preset: Debug preset + * @ext_addr: Address of context information extension + * @ext_size: Size of context information part + * + * Total 38 DWords + */ +struct ctx_info { + u16 version; + u16 size; + u32 config; + u32 reserved_dw02; + u32 reserved_dw03; + u64 addr_tr_hia; + u64 addr_tr_tia; + u64 addr_cr_hia; + u64 addr_cr_tia; + u16 num_tr_ia; + u16 num_cr_ia; + u32 rbd_size:4, + reserved_dw13:28; + u64 addr_tfdq; + u64 addr_urbdq0; + u16 num_tfdq; + u16 num_urbdq0; + u16 tfdq_db_vec; + u16 urbdq0_db_vec; + u64 addr_frbdq; + u64 addr_urbdq1; + u16 num_frbdq; + u16 frbdq_db_vec; + u16 num_urbdq1; + u16 urbdq_db_vec; + u16 tr_msi_vec; + u16 cr_msi_vec; + u32 reserved_dw27; + u64 dbgc_addr; + u32 dbgc_size; + u32 early_enable:1, + reserved_dw31:3, + dbg_output_mode:4, + dbg_preset:8, + reserved2_dw31:16; + u64 ext_addr; + u32 ext_size; + u32 test_param; + u32 reserved_dw36; + u32 reserved_dw37; +} __packed; + +/* Transfer Descriptor for TX + * @type: Not in use. Set to 0x0 + * @size: Size of data in the buffer + * @addr: DMA Address of buffer + */ +struct tfd { + u8 type; + u16 size; + u8 reserved; + u64 addr; + u32 reserved1; +} __packed; + +/* URB Descriptor for TX + * @tfd_index: Index of TFD in TFDQ + 1 + * @num_txq: Queue index of TFD Queue + * @cmpl_count: Completion count. Always 0x01 + * @immediate_cmpl: Immediate completion flag: Always 0x01 + */ +struct urbd0 { + u32 tfd_index:16, + num_txq:8, + cmpl_count:4, + reserved:3, + immediate_cmpl:1; +} __packed; + +/* FRB Descriptor for RX + * @tag: RX buffer tag (index of RX buffer queue) + * @addr: Address of buffer + */ +struct frbd { + u32 tag:16, + reserved:16; + u32 reserved2; + u64 addr; +} __packed; + +/* URB Descriptor for RX + * @frbd_tag: Tag from FRBD + * @status: Status + */ +struct urbd1 { + u32 frbd_tag:16, + status:1, + reserved:14, + fixed:1; +} __packed; + +/* RFH header in RX packet + * @packet_len: Length of the data in the buffer + * @rxq: RX Queue number + * @cmd_id: Command ID. Not in Use + */ +struct rfh_hdr { + u64 packet_len:16, + rxq:6, + reserved:10, + cmd_id:16, + reserved1:16; +} __packed; + +/* Internal data buffer + * @data: pointer to the data buffer + * @p_addr: physical address of data buffer + */ +struct data_buf { + u8 *data; + dma_addr_t data_p_addr; +}; + +/* Index Array */ +struct ia { + dma_addr_t tr_hia_p_addr; + u16 *tr_hia; + dma_addr_t tr_tia_p_addr; + u16 *tr_tia; + dma_addr_t cr_hia_p_addr; + u16 *cr_hia; + dma_addr_t cr_tia_p_addr; + u16 *cr_tia; +}; + +/* Structure for TX Queue + * @count: Number of descriptors + * @tfds: Array of TFD + * @urbd0s: Array of URBD0 + * @buf: Array of data_buf structure + */ +struct txq { + u16 count; + + dma_addr_t tfds_p_addr; + struct tfd *tfds; + + dma_addr_t urbd0s_p_addr; + struct urbd0 *urbd0s; + + dma_addr_t buf_p_addr; + void *buf_v_addr; + struct data_buf *bufs; +}; + +/* Structure for RX Queue + * @count: Number of descriptors + * @frbds: Array of FRBD + * @urbd1s: Array of URBD1 + * @buf: Array of data_buf structure + */ +struct rxq { + u16 count; + + dma_addr_t frbds_p_addr; + struct frbd *frbds; + + dma_addr_t urbd1s_p_addr; + struct urbd1 *urbd1s; + + dma_addr_t buf_p_addr; + void *buf_v_addr; + struct data_buf *bufs; +}; + +/* struct btintel_pcie_data + * @pdev: pci device + * @hdev: hdev device + * @flags: driver state + * @irq_lock: spinlock for MSI-X + * @hci_rx_lock: spinlock for HCI RX flow + * @base_addr: pci base address (from BAR) + * @msix_entries: array of MSI-X entries + * @msix_enabled: true if MSI-X is enabled; + * @alloc_vecs: number of interrupt vectors allocated + * @def_irq: default irq for all causes + * @fh_init_mask: initial unmasked rxq causes + * @hw_init_mask: initial unmaksed hw causes + * @boot_stage_cache: cached value of boot stage register + * @img_resp_cache: cached value of image response register + * @cnvi: CNVi register value + * @cnvr: CNVr register value + * @gp0_received: condition for gp0 interrupt + * @gp0_wait_q: wait_q for gp0 interrupt + * @tx_wait_done: condition for tx interrupt + * @tx_wait_q: wait_q for tx interrupt + * @workqueue: workqueue for RX work + * @rx_skb_q: SKB queue for RX packet + * @rx_work: RX work struct to process the RX packet in @rx_skb_q + * @dma_pool: DMA pool for descriptors, index array and ci + * @dma_p_addr: DMA address for pool + * @dma_v_addr: address of pool + * @ci_p_addr: DMA address for CI struct + * @ci: CI struct + * @ia: Index Array struct + * @txq: TX Queue struct + * @rxq: RX Queue struct + */ +struct btintel_pcie_data { + struct pci_dev *pdev; + struct hci_dev *hdev; + + unsigned long flags; + /* lock used in MSI-X interrupt */ + spinlock_t irq_lock; + /* lock to serialize rx events */ + spinlock_t hci_rx_lock; + + void __iomem *base_addr; + + struct msix_entry msix_entries[BTINTEL_PCIE_MSIX_VEC_MAX]; + bool msix_enabled; + u32 alloc_vecs; + u32 def_irq; + + u32 fh_init_mask; + u32 hw_init_mask; + + u32 boot_stage_cache; + u32 img_resp_cache; + + u32 cnvi; + u32 cnvr; + + bool gp0_received; + wait_queue_head_t gp0_wait_q; + + bool tx_wait_done; + wait_queue_head_t tx_wait_q; + + struct workqueue_struct *workqueue; + struct sk_buff_head rx_skb_q; + struct work_struct rx_work; + + struct dma_pool *dma_pool; + dma_addr_t dma_p_addr; + void *dma_v_addr; + + dma_addr_t ci_p_addr; + struct ctx_info *ci; + struct ia ia; + struct txq txq; + struct rxq rxq; +}; + +static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data, + u32 offset) +{ + return ioread32(data->base_addr + offset); +} + +static inline void btintel_pcie_wr_reg8(struct btintel_pcie_data *data, + u32 offset, u8 val) +{ + iowrite8(val, data->base_addr + offset); +} + +static inline void btintel_pcie_wr_reg32(struct btintel_pcie_data *data, + u32 offset, u32 val) +{ + iowrite32(val, data->base_addr + offset); +} + +static inline void btintel_pcie_set_reg_bits(struct btintel_pcie_data *data, + u32 offset, u32 bits) +{ + u32 r; + + r = ioread32(data->base_addr + offset); + r |= bits; + iowrite32(r, data->base_addr + offset); +} + +static inline void btintel_pcie_clr_reg_bits(struct btintel_pcie_data *data, + u32 offset, u32 bits) +{ + u32 r; + + r = ioread32(data->base_addr + offset); + r &= ~bits; + iowrite32(r, data->base_addr + offset); +} diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 9658b33c824a..18f34998a120 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -121,13 +121,6 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb) ((event->data[2] == MODULE_BROUGHT_UP) || (event->data[2] == MODULE_ALREADY_UP)) ? "Bring-up succeed" : "Bring-up failed"); - - if (event->length > 3 && event->data[3]) - priv->btmrvl_dev.dev_type = HCI_AMP; - else - priv->btmrvl_dev.dev_type = HCI_PRIMARY; - - BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type); } else if (priv->btmrvl_dev.sendcmdflag && event->data[1] == MODULE_SHUTDOWN_REQ) { BT_DBG("EVENT:%s", (event->data[2]) ? @@ -686,8 +679,6 @@ int btmrvl_register_hdev(struct btmrvl_private *priv) hdev->wakeup = btmrvl_wakeup; SET_HCIDEV_DEV(hdev, &card->func->dev); - hdev->dev_type = priv->btmrvl_dev.dev_type; - ret = hci_register_dev(hdev); if (ret < 0) { BT_ERR("Can not register HCI device"); diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 638074992c82..dfbbac92242a 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -13,8 +13,6 @@ #include "btqca.h" -#define VERSION "0.1" - int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver, enum qca_btsoc_type soc_type) { @@ -55,11 +53,6 @@ int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver, } edl = (struct edl_event_hdr *)(skb->data); - if (!edl) { - bt_dev_err(hdev, "QCA TLV with no header"); - err = -EILSEQ; - goto out; - } if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) { @@ -121,11 +114,6 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) } edl = (struct edl_event_hdr *)(skb->data); - if (!edl) { - bt_dev_err(hdev, "QCA read fw build info with no header"); - err = -EILSEQ; - goto out; - } if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != EDL_GET_BUILD_INFO_CMD) { @@ -148,8 +136,10 @@ static int qca_read_fw_build_info(struct hci_dev *hdev) } build_label = kstrndup(&edl->data[1], build_lbl_len, GFP_KERNEL); - if (!build_label) + if (!build_label) { + err = -ENOMEM; goto out; + } hci_set_fw_info(hdev, "%s", build_label); @@ -183,11 +173,6 @@ static int qca_send_patch_config_cmd(struct hci_dev *hdev) } edl = (struct edl_event_hdr *)(skb->data); - if (!edl) { - bt_dev_err(hdev, "QCA Patch config with no header"); - err = -EILSEQ; - goto out; - } if (edl->cresp != EDL_PATCH_CONFIG_RES_EVT || edl->rtype != EDL_PATCH_CONFIG_CMD) { bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp, @@ -502,11 +487,6 @@ static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, } edl = (struct edl_event_hdr *)(skb->data); - if (!edl) { - bt_dev_err(hdev, "TLV with no header"); - err = -EILSEQ; - goto out; - } if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != rtype) { bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x", @@ -737,6 +717,19 @@ static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size, snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid); } +static inline void qca_get_nvm_name_generic(struct qca_fw_config *cfg, + const char *stem, u8 rom_ver, u16 bid) +{ + if (bid == 0x0) + snprintf(cfg->fwname, sizeof(cfg->fwname), "qca/%snv%02x.bin", stem, rom_ver); + else if (bid & 0xff00) + snprintf(cfg->fwname, sizeof(cfg->fwname), + "qca/%snv%02x.b%x", stem, rom_ver, bid); + else + snprintf(cfg->fwname, sizeof(cfg->fwname), + "qca/%snv%02x.b%02x", stem, rom_ver, bid); +} + int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, enum qca_btsoc_type soc_type, struct qca_btsoc_version ver, const char *firmware_name) @@ -817,7 +810,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, /* Give the controller some time to get ready to receive the NVM */ msleep(10); - if (soc_type == QCA_QCA2066) + if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850) qca_read_fw_board_id(hdev, &boardid); /* Download NVM configuration */ @@ -859,8 +852,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, "qca/hpnv%02x.bin", rom_ver); break; case QCA_WCN7850: - snprintf(config.fwname, sizeof(config.fwname), - "qca/hmtnv%02x.bin", rom_ver); + qca_get_nvm_name_generic(&config, "hmt", rom_ver, boardid); break; default: @@ -961,6 +953,5 @@ EXPORT_SYMBOL_GPL(qca_set_bdaddr); MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); -MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); -MODULE_VERSION(VERSION); +MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family"); MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 215433fd76a1..bb5207d7a8c7 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -5,33 +5,33 @@ * Copyright (c) 2015 The Linux Foundation. All rights reserved. */ -#define EDL_PATCH_CMD_OPCODE (0xFC00) -#define EDL_NVM_ACCESS_OPCODE (0xFC0B) -#define EDL_WRITE_BD_ADDR_OPCODE (0xFC14) -#define EDL_PATCH_CMD_LEN (1) -#define EDL_PATCH_VER_REQ_CMD (0x19) -#define EDL_PATCH_TLV_REQ_CMD (0x1E) -#define EDL_GET_BUILD_INFO_CMD (0x20) -#define EDL_GET_BID_REQ_CMD (0x23) -#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01) -#define EDL_PATCH_CONFIG_CMD (0x28) -#define MAX_SIZE_PER_TLV_SEGMENT (243) -#define QCA_PRE_SHUTDOWN_CMD (0xFC08) -#define QCA_DISABLE_LOGGING (0xFC17) - -#define EDL_CMD_REQ_RES_EVT (0x00) -#define EDL_PATCH_VER_RES_EVT (0x19) -#define EDL_APP_VER_RES_EVT (0x02) -#define EDL_TVL_DNLD_RES_EVT (0x04) -#define EDL_CMD_EXE_STATUS_EVT (0x00) -#define EDL_SET_BAUDRATE_RSP_EVT (0x92) -#define EDL_NVM_ACCESS_CODE_EVT (0x0B) -#define EDL_PATCH_CONFIG_RES_EVT (0x00) -#define QCA_DISABLE_LOGGING_SUB_OP (0x14) +#define EDL_PATCH_CMD_OPCODE 0xFC00 +#define EDL_NVM_ACCESS_OPCODE 0xFC0B +#define EDL_WRITE_BD_ADDR_OPCODE 0xFC14 +#define EDL_PATCH_CMD_LEN 1 +#define EDL_PATCH_VER_REQ_CMD 0x19 +#define EDL_PATCH_TLV_REQ_CMD 0x1E +#define EDL_GET_BUILD_INFO_CMD 0x20 +#define EDL_GET_BID_REQ_CMD 0x23 +#define EDL_NVM_ACCESS_SET_REQ_CMD 0x01 +#define EDL_PATCH_CONFIG_CMD 0x28 +#define MAX_SIZE_PER_TLV_SEGMENT 243 +#define QCA_PRE_SHUTDOWN_CMD 0xFC08 +#define QCA_DISABLE_LOGGING 0xFC17 + +#define EDL_CMD_REQ_RES_EVT 0x00 +#define EDL_PATCH_VER_RES_EVT 0x19 +#define EDL_APP_VER_RES_EVT 0x02 +#define EDL_TVL_DNLD_RES_EVT 0x04 +#define EDL_CMD_EXE_STATUS_EVT 0x00 +#define EDL_SET_BAUDRATE_RSP_EVT 0x92 +#define EDL_NVM_ACCESS_CODE_EVT 0x0B +#define EDL_PATCH_CONFIG_RES_EVT 0x00 +#define QCA_DISABLE_LOGGING_SUB_OP 0x14 #define EDL_TAG_ID_BD_ADDR 2 -#define EDL_TAG_ID_HCI (17) -#define EDL_TAG_ID_DEEP_SLEEP (27) +#define EDL_TAG_ID_HCI 17 +#define EDL_TAG_ID_DEEP_SLEEP 27 #define QCA_WCN3990_POWERON_PULSE 0xFC #define QCA_WCN3990_POWEROFF_PULSE 0xC0 @@ -39,7 +39,7 @@ #define QCA_HCI_CC_OPCODE 0xFC00 #define QCA_HCI_CC_SUCCESS 0x00 -#define QCA_WCN3991_SOC_ID (0x40014320) +#define QCA_WCN3991_SOC_ID 0x40014320 /* QCA chipset version can be decided by patch and SoC * version, combination with upper 2 bytes from SoC @@ -48,11 +48,11 @@ #define get_soc_ver(soc_id, rom_ver) \ ((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver))) -#define QCA_HSP_GF_SOC_ID 0x1200 -#define QCA_HSP_GF_SOC_MASK 0x0000ff00 +#define QCA_HSP_GF_SOC_ID 0x1200 +#define QCA_HSP_GF_SOC_MASK 0x0000ff00 enum qca_baudrate { - QCA_BAUDRATE_115200 = 0, + QCA_BAUDRATE_115200 = 0, QCA_BAUDRATE_57600, QCA_BAUDRATE_38400, QCA_BAUDRATE_19200, @@ -71,7 +71,7 @@ enum qca_baudrate { QCA_BAUDRATE_1600000, QCA_BAUDRATE_3200000, QCA_BAUDRATE_3500000, - QCA_BAUDRATE_AUTO = 0xFE, + QCA_BAUDRATE_AUTO = 0xFE, QCA_BAUDRATE_RESERVED }; diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 11c7e04bf394..88dbb2f3fabf 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -197,7 +197,7 @@ destroy_acl_channel: return ret; } -static int btqcomsmd_remove(struct platform_device *pdev) +static void btqcomsmd_remove(struct platform_device *pdev) { struct btqcomsmd *btq = platform_get_drvdata(pdev); @@ -206,8 +206,6 @@ static int btqcomsmd_remove(struct platform_device *pdev) rpmsg_destroy_ept(btq->cmd_channel); rpmsg_destroy_ept(btq->acl_channel); - - return 0; } static const struct of_device_id btqcomsmd_of_match[] = { @@ -218,7 +216,7 @@ MODULE_DEVICE_TABLE(of, btqcomsmd_of_match); static struct platform_driver btqcomsmd_driver = { .probe = btqcomsmd_probe, - .remove = btqcomsmd_remove, + .remove_new = btqcomsmd_remove, .driver = { .name = "btqcomsmd", .of_match_table = btqcomsmd_of_match, diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c index 634cf8f5ed2d..0c91d7635ac3 100644 --- a/drivers/bluetooth/btrsi.c +++ b/drivers/bluetooth/btrsi.c @@ -134,7 +134,6 @@ static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) hdev->bus = HCI_USB; hci_set_drvdata(hdev, h_adapter); - hdev->dev_type = HCI_PRIMARY; hdev->open = rsi_hci_open; hdev->close = rsi_hci_close; hdev->flush = rsi_hci_flush; diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index cc50de69e8dc..4f1e37b4f780 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -1339,6 +1339,13 @@ int btrtl_setup_realtek(struct hci_dev *hdev) btrtl_set_quirks(hdev, btrtl_dev); + hci_set_hw_info(hdev, + "RTL lmp_subver=%u hci_rev=%u hci_ver=%u hci_bus=%u", + btrtl_dev->ic_info->lmp_subver, + btrtl_dev->ic_info->hci_rev, + btrtl_dev->ic_info->hci_ver, + btrtl_dev->ic_info->hci_bus); + btrtl_free(btrtl_dev); return ret; } diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index f19d31ee37ea..fdcfe9c50313 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -32,9 +32,6 @@ static const struct sdio_device_id btsdio_table[] = { /* Generic Bluetooth Type-B SDIO device */ { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) }, - /* Generic Bluetooth AMP controller */ - { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) }, - { } /* Terminating entry */ }; @@ -319,11 +316,6 @@ static int btsdio_probe(struct sdio_func *func, hdev->bus = HCI_SDIO; hci_set_drvdata(hdev, data); - if (id->class == SDIO_CLASS_BT_AMP) - hdev->dev_type = HCI_AMP; - else - hdev->dev_type = HCI_PRIMARY; - data->hdev = hdev; SET_HCIDEV_DEV(hdev, &func->dev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e3946f7b736e..e384ef6ff050 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -477,6 +477,7 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED }, + { USB_DEVICE(0x8087, 0x0037), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0038), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED | @@ -588,6 +589,9 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x0489, 0xe0e0), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -597,6 +601,9 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x13d3, 0x3563), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -612,10 +619,12 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x13d3, 0x3583), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | + { USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK | + + /* MediaTek MT7922 Bluetooth devices */ + { USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -626,12 +635,6 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, @@ -656,14 +659,38 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3605), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3607), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3614), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3615), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, /* Additional MediaTek MT7925 Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe113), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, { USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH | BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, /* Additional Realtek 8723AE Bluetooth devices */ { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, @@ -2951,7 +2978,7 @@ static int btusb_mtk_uhw_reg_read(struct btusb_data *data, u32 reg, u32 *val) err = usb_control_msg(data->udev, pipe, 0x01, 0xDE, reg >> 16, reg & 0xffff, - buf, 4, USB_CTRL_SET_TIMEOUT); + buf, 4, USB_CTRL_GET_TIMEOUT); if (err < 0) { bt_dev_err(hdev, "Failed to read uhw reg(%d)", err); goto err_free_buf; @@ -2979,7 +3006,7 @@ static int btusb_mtk_reg_read(struct btusb_data *data, u32 reg, u32 *val) err = usb_control_msg(data->udev, pipe, 0x63, USB_TYPE_VENDOR | USB_DIR_IN, reg >> 16, reg & 0xffff, - buf, size, USB_CTRL_SET_TIMEOUT); + buf, size, USB_CTRL_GET_TIMEOUT); if (err < 0) goto err_free_buf; @@ -3118,6 +3145,7 @@ static int btusb_mtk_setup(struct hci_dev *hdev) bt_dev_err(hdev, "Failed to get fw flavor (%d)", err); return err; } + fw_flavor = (fw_flavor & 0x00000080) >> 7; } mediatek = hci_get_priv(hdev); @@ -3693,7 +3721,7 @@ static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request, */ pipe = usb_rcvctrlpipe(udev, 0); err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN, - 0, 0, buf, size, USB_CTRL_SET_TIMEOUT); + 0, 0, buf, size, USB_CTRL_GET_TIMEOUT); if (err < 0) { dev_err(&udev->dev, "Failed to access otp area (%d)", err); goto done; @@ -4331,11 +4359,6 @@ static int btusb_probe(struct usb_interface *intf, hdev->bus = HCI_USB; hci_set_drvdata(hdev, data); - if (id->driver_info & BTUSB_AMP) - hdev->dev_type = HCI_AMP; - else - hdev->dev_type = HCI_PRIMARY; - data->hdev = hdev; SET_HCIDEV_DEV(hdev, &intf->dev); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 874d23089b39..89d4c2224546 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -1293,7 +1293,7 @@ static int bcm_probe(struct platform_device *pdev) return 0; } -static int bcm_remove(struct platform_device *pdev) +static void bcm_remove(struct platform_device *pdev) { struct bcm_device *dev = platform_get_drvdata(pdev); @@ -1302,8 +1302,6 @@ static int bcm_remove(struct platform_device *pdev) mutex_unlock(&bcm_device_lock); dev_info(&pdev->dev, "%s device unregistered.\n", dev->name); - - return 0; } static const struct hci_uart_proto bcm_proto = { @@ -1487,7 +1485,7 @@ static const struct acpi_device_id bcm_acpi_match[] = { { "BCM2EA1" }, { "BCM2EA2", (long)&bcm43430_device_data }, { "BCM2EA3", (long)&bcm43430_device_data }, - { "BCM2EA4" }, + { "BCM2EA4", (long)&bcm43430_device_data }, /* bcm43455 */ { "BCM2EA5" }, { "BCM2EA6" }, { "BCM2EA7" }, @@ -1509,7 +1507,7 @@ static const struct dev_pm_ops bcm_pm_ops = { static struct platform_driver bcm_driver = { .probe = bcm_probe, - .remove = bcm_remove, + .remove_new = bcm_remove, .driver = { .name = "hci_bcm", .acpi_match_table = ACPI_PTR(bcm_acpi_match), diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c index 9a7243d5db71..0c2f15235b4c 100644 --- a/drivers/bluetooth/hci_bcm4377.c +++ b/drivers/bluetooth/hci_bcm4377.c @@ -2361,7 +2361,6 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id) bcm4377->hdev = hdev; hdev->bus = HCI_PCI; - hdev->dev_type = HCI_PRIMARY; hdev->open = bcm4377_hci_open; hdev->close = bcm4377_hci_close; hdev->send = bcm4377_hci_send_frame; diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 78afb9a348e7..999ccd5bb4f2 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -537,7 +537,7 @@ static int intel_setup(struct hci_uart *hu) int speed_change = 0; int err; - bt_dev_dbg(hdev, "start intel_setup"); + bt_dev_dbg(hdev, ""); hu->hdev->set_diag = btintel_set_diag; hu->hdev->set_bdaddr = btintel_set_bdaddr; @@ -591,12 +591,12 @@ static int intel_setup(struct hci_uart *hu) return -EINVAL; } - /* Check for supported iBT hardware variants of this firmware - * loading method. - * - * This check has been put in place to ensure correct forward - * compatibility options when newer hardware variants come along. - */ + /* Check for supported iBT hardware variants of this firmware + * loading method. + * + * This check has been put in place to ensure correct forward + * compatibility options when newer hardware variants come along. + */ switch (ver.hw_variant) { case 0x0b: /* LnP */ case 0x0c: /* WsP */ @@ -777,7 +777,7 @@ static int intel_setup(struct hci_uart *hu) rettime = ktime_get(); delta = ktime_sub(rettime, calltime); - duration = (unsigned long long) ktime_to_ns(delta) >> 10; + duration = (unsigned long long)ktime_to_ns(delta) >> 10; bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration); @@ -822,7 +822,7 @@ done: rettime = ktime_get(); delta = ktime_sub(rettime, calltime); - duration = (unsigned long long) ktime_to_ns(delta) >> 10; + duration = (unsigned long long)ktime_to_ns(delta) >> 10; bt_dev_info(hdev, "Device booted in %llu usecs", duration); @@ -977,6 +977,7 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count) ARRAY_SIZE(intel_recv_pkts)); if (IS_ERR(intel->rx_skb)) { int err = PTR_ERR(intel->rx_skb); + bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err); intel->rx_skb = NULL; return err; @@ -1190,7 +1191,7 @@ no_irq: return 0; } -static int intel_remove(struct platform_device *pdev) +static void intel_remove(struct platform_device *pdev) { struct intel_device *idev = platform_get_drvdata(pdev); @@ -1201,13 +1202,11 @@ static int intel_remove(struct platform_device *pdev) mutex_unlock(&intel_device_list_lock); dev_info(&pdev->dev, "unregistered.\n"); - - return 0; } static struct platform_driver intel_driver = { .probe = intel_probe, - .remove = intel_remove, + .remove_new = intel_remove, .driver = { .name = "hci_intel", .acpi_match_table = ACPI_PTR(intel_acpi_match), diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index a26367e9fb19..17a2f158a0df 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -667,11 +667,6 @@ static int hci_uart_register_dev(struct hci_uart *hu) if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); - if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) - hdev->dev_type = HCI_AMP; - else - hdev->dev_type = HCI_PRIMARY; - /* Only call open() for the protocol after hdev is fully initialized as * open() (or a timer/workqueue it starts) may attempt to reference it. */ @@ -722,7 +717,6 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) { unsigned long valid_flags = BIT(HCI_UART_RAW_DEVICE) | BIT(HCI_UART_RESET_ON_INIT) | - BIT(HCI_UART_CREATE_AMP) | BIT(HCI_UART_INIT_PENDING) | BIT(HCI_UART_EXT_CONFIG) | BIT(HCI_UART_VND_DETECT); diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 85c0d9b68f5f..89a22e9b3253 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -366,11 +366,6 @@ int hci_uart_register_device_priv(struct hci_uart *hu, if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags)) set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks); - if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) - hdev->dev_type = HCI_AMP; - else - hdev->dev_type = HCI_PRIMARY; - if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) return 0; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 68c8c7e95d64..00bf7ae82c5b 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -37,7 +37,6 @@ #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 -#define HCI_UART_CREATE_AMP 2 #define HCI_UART_INIT_PENDING 3 #define HCI_UART_EXT_CONFIG 4 #define HCI_UART_VND_DETECT 5 diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 572d68d52965..28750a40f0ed 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -384,17 +384,10 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) { struct hci_dev *hdev; struct sk_buff *skb; - __u8 dev_type; if (data->hdev) return -EBADFD; - /* bits 0-1 are dev_type (Primary or AMP) */ - dev_type = opcode & 0x03; - - if (dev_type != HCI_PRIMARY && dev_type != HCI_AMP) - return -EINVAL; - /* bits 2-5 are reserved (must be zero) */ if (opcode & 0x3c) return -EINVAL; @@ -412,7 +405,6 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode) data->hdev = hdev; hdev->bus = HCI_VIRTUAL; - hdev->dev_type = dev_type; hci_set_drvdata(hdev, data); hdev->open = vhci_open_dev; @@ -634,7 +626,7 @@ static void vhci_open_timeout(struct work_struct *work) struct vhci_data *data = container_of(work, struct vhci_data, open_timeout.work); - vhci_create_device(data, amp ? HCI_AMP : HCI_PRIMARY); + vhci_create_device(data, 0x00); } static int vhci_open(struct inode *inode, struct file *file) diff --git a/drivers/bluetooth/virtio_bt.c b/drivers/bluetooth/virtio_bt.c index 2ac70b560c46..18208e152a36 100644 --- a/drivers/bluetooth/virtio_bt.c +++ b/drivers/bluetooth/virtio_bt.c @@ -274,7 +274,6 @@ static int virtbt_probe(struct virtio_device *vdev) switch (type) { case VIRTIO_BT_CONFIG_TYPE_PRIMARY: - case VIRTIO_BT_CONFIG_TYPE_AMP: break; default: return -EINVAL; @@ -303,7 +302,6 @@ static int virtbt_probe(struct virtio_device *vdev) vbt->hdev = hdev; hdev->bus = HCI_VIRTIO; - hdev->dev_type = type; hci_set_drvdata(hdev, vbt); hdev->open = virtbt_open; diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index eaec5d6caa29..b3228bd6cd6b 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -285,7 +285,7 @@ void bt_err_ratelimited(const char *fmt, ...); bt_err_ratelimited("%s: " fmt, bt_dev_name(hdev), ##__VA_ARGS__) /* Connection and socket states */ -enum { +enum bt_sock_state { BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ BT_OPEN, BT_BOUND, diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 5c12761cbc0e..fe932ca3bc8c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -33,9 +33,6 @@ #define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) #define HCI_LINK_KEY_SIZE 16 -#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE) - -#define HCI_MAX_AMP_ASSOC_SIZE 672 #define HCI_MAX_CPB_DATA_SIZE 252 @@ -71,26 +68,6 @@ #define HCI_SMD 9 #define HCI_VIRTIO 10 -/* HCI controller types */ -#define HCI_PRIMARY 0x00 -#define HCI_AMP 0x01 - -/* First BR/EDR Controller shall have ID = 0 */ -#define AMP_ID_BREDR 0x00 - -/* AMP controller types */ -#define AMP_TYPE_BREDR 0x00 -#define AMP_TYPE_80211 0x01 - -/* AMP controller status */ -#define AMP_STATUS_POWERED_DOWN 0x00 -#define AMP_STATUS_BLUETOOTH_ONLY 0x01 -#define AMP_STATUS_NO_CAPACITY 0x02 -#define AMP_STATUS_LOW_CAPACITY 0x03 -#define AMP_STATUS_MEDIUM_CAPACITY 0x04 -#define AMP_STATUS_HIGH_CAPACITY 0x05 -#define AMP_STATUS_FULL_CAPACITY 0x06 - /* HCI device quirks */ enum { /* When this quirk is set, the HCI Reset command is send when @@ -456,7 +433,6 @@ enum { #define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 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 */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 @@ -528,7 +504,6 @@ enum { #define ESCO_LINK 0x02 /* Low Energy links do not have defined link type. Use invented one */ #define LE_LINK 0x80 -#define AMP_LINK 0x81 #define ISO_LINK 0x82 #define INVALID_LINK 0xff @@ -944,56 +919,6 @@ struct hci_cp_io_capability_neg_reply { __u8 reason; } __packed; -#define HCI_OP_CREATE_PHY_LINK 0x0435 -struct hci_cp_create_phy_link { - __u8 phy_handle; - __u8 key_len; - __u8 key_type; - __u8 key[HCI_AMP_LINK_KEY_SIZE]; -} __packed; - -#define HCI_OP_ACCEPT_PHY_LINK 0x0436 -struct hci_cp_accept_phy_link { - __u8 phy_handle; - __u8 key_len; - __u8 key_type; - __u8 key[HCI_AMP_LINK_KEY_SIZE]; -} __packed; - -#define HCI_OP_DISCONN_PHY_LINK 0x0437 -struct hci_cp_disconn_phy_link { - __u8 phy_handle; - __u8 reason; -} __packed; - -struct ext_flow_spec { - __u8 id; - __u8 stype; - __le16 msdu; - __le32 sdu_itime; - __le32 acc_lat; - __le32 flush_to; -} __packed; - -#define HCI_OP_CREATE_LOGICAL_LINK 0x0438 -#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439 -struct hci_cp_create_accept_logical_link { - __u8 phy_handle; - struct ext_flow_spec tx_flow_spec; - struct ext_flow_spec rx_flow_spec; -} __packed; - -#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a -struct hci_cp_disconn_logical_link { - __le16 log_handle; -} __packed; - -#define HCI_OP_LOGICAL_LINK_CANCEL 0x043b -struct hci_cp_logical_link_cancel { - __u8 phy_handle; - __u8 flow_spec_id; -} __packed; - #define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d struct hci_coding_format { __u8 id; @@ -1615,46 +1540,6 @@ struct hci_rp_read_enc_key_size { __u8 key_size; } __packed; -#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 -struct hci_rp_read_local_amp_info { - __u8 status; - __u8 amp_status; - __le32 total_bw; - __le32 max_bw; - __le32 min_latency; - __le32 max_pdu; - __u8 amp_type; - __le16 pal_cap; - __le16 max_assoc_size; - __le32 max_flush_to; - __le32 be_flush_to; -} __packed; - -#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a -struct hci_cp_read_local_amp_assoc { - __u8 phy_handle; - __le16 len_so_far; - __le16 max_len; -} __packed; -struct hci_rp_read_local_amp_assoc { - __u8 status; - __u8 phy_handle; - __le16 rem_len; - __u8 frag[]; -} __packed; - -#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b -struct hci_cp_write_remote_amp_assoc { - __u8 phy_handle; - __le16 len_so_far; - __le16 rem_len; - __u8 frag[]; -} __packed; -struct hci_rp_write_remote_amp_assoc { - __u8 status; - __u8 phy_handle; -} __packed; - #define HCI_OP_GET_MWS_TRANSPORT_CONFIG 0x140c #define HCI_OP_ENABLE_DUT_MODE 0x1803 @@ -1666,6 +1551,15 @@ struct hci_cp_le_set_event_mask { __u8 mask[8]; } __packed; +/* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E + * 7.8.2 LE Read Buffer Size command + * MAX_LE_MTU is 0xffff. + * 0 is also valid. It means that no dedicated LE Buffer exists. + * It should use the HCI_Read_Buffer_Size command and mtu is shared + * between BR/EDR and LE. + */ +#define HCI_MIN_LE_MTU 0x001b + #define HCI_OP_LE_READ_BUFFER_SIZE 0x2002 struct hci_rp_le_read_buffer_size { __u8 status; @@ -2026,7 +1920,7 @@ struct hci_cp_le_set_ext_adv_data { __u8 operation; __u8 frag_pref; __u8 length; - __u8 data[]; + __u8 data[] __counted_by(length); } __packed; #define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038 @@ -2035,7 +1929,7 @@ struct hci_cp_le_set_ext_scan_rsp_data { __u8 operation; __u8 frag_pref; __u8 length; - __u8 data[]; + __u8 data[] __counted_by(length); } __packed; #define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039 @@ -2061,7 +1955,7 @@ struct hci_cp_le_set_per_adv_data { __u8 handle; __u8 operation; __u8 length; - __u8 data[]; + __u8 data[] __counted_by(length); } __packed; #define HCI_OP_LE_SET_PER_ADV_ENABLE 0x2040 @@ -2144,7 +2038,7 @@ struct hci_cp_le_set_cig_params { __le16 c_latency; __le16 p_latency; __u8 num_cis; - struct hci_cis_params cis[]; + struct hci_cis_params cis[] __counted_by(num_cis); } __packed; struct hci_rp_le_set_cig_params { @@ -2162,7 +2056,7 @@ struct hci_cis { struct hci_cp_le_create_cis { __u8 num_cis; - struct hci_cis cis[]; + struct hci_cis cis[] __counted_by(num_cis); } __packed; #define HCI_OP_LE_REMOVE_CIG 0x2065 @@ -2216,7 +2110,7 @@ struct hci_cp_le_big_create_sync { __u8 mse; __le16 timeout; __u8 num_bis; - __u8 bis[]; + __u8 bis[] __counted_by(num_bis); } __packed; #define HCI_OP_LE_BIG_TERM_SYNC 0x206c diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index e8f581f3f3ce..9231396fe96f 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,7 +126,6 @@ enum suspended_state { struct hci_conn_hash { struct list_head list; unsigned int acl_num; - unsigned int amp_num; unsigned int sco_num; unsigned int iso_num; unsigned int le_num; @@ -247,6 +246,7 @@ struct adv_info { bool periodic; __u8 mesh; __u8 instance; + __u8 handle; __u32 flags; __u16 timeout; __u16 remaining_time; @@ -341,14 +341,6 @@ struct adv_monitor { /* Default authenticated payload timeout 30s */ #define DEFAULT_AUTH_PAYLOAD_TIMEOUT 0x0bb8 -struct amp_assoc { - __u16 len; - __u16 offset; - __u16 rem_len; - __u16 len_so_far; - __u8 data[HCI_MAX_AMP_ASSOC_SIZE]; -}; - #define HCI_MAX_PAGES 3 struct hci_dev { @@ -361,7 +353,6 @@ struct hci_dev { unsigned long flags; __u16 id; __u8 bus; - __u8 dev_type; bdaddr_t bdaddr; bdaddr_t setup_addr; bdaddr_t public_addr; @@ -467,21 +458,6 @@ struct hci_dev { __u16 sniff_min_interval; __u16 sniff_max_interval; - __u8 amp_status; - __u32 amp_total_bw; - __u32 amp_max_bw; - __u32 amp_min_latency; - __u32 amp_max_pdu; - __u8 amp_type; - __u16 amp_pal_cap; - __u16 amp_assoc_size; - __u32 amp_max_flush_to; - __u32 amp_be_flush_to; - - struct amp_assoc loc_assoc; - - __u8 flow_ctl_mode; - unsigned int auto_accept_delay; unsigned long quirks; @@ -501,11 +477,6 @@ struct hci_dev { unsigned int le_pkts; unsigned int iso_pkts; - __u16 block_len; - __u16 block_mtu; - __u16 num_blocks; - __u16 block_cnt; - unsigned long acl_last_tx; unsigned long sco_last_tx; unsigned long le_last_tx; @@ -706,6 +677,7 @@ struct hci_conn { __u16 handle; __u16 sync_handle; __u16 state; + __u16 mtu; __u8 mode; __u8 type; __u8 role; @@ -777,7 +749,6 @@ struct hci_conn { void *l2cap_data; void *sco_data; void *iso_data; - struct amp_mgr *amp_mgr; struct list_head link_list; struct hci_conn *parent; @@ -804,7 +775,6 @@ struct hci_chan { struct sk_buff_head data_q; unsigned int sent; __u8 state; - bool amp; }; struct hci_conn_params { @@ -1013,9 +983,6 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) case ACL_LINK: h->acl_num++; break; - case AMP_LINK: - h->amp_num++; - break; case LE_LINK: h->le_num++; if (c->role == HCI_ROLE_SLAVE) @@ -1042,9 +1009,6 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) case ACL_LINK: h->acl_num--; break; - case AMP_LINK: - h->amp_num--; - break; case LE_LINK: h->le_num--; if (c->role == HCI_ROLE_SLAVE) @@ -1066,8 +1030,6 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) switch (type) { case ACL_LINK: return h->acl_num; - case AMP_LINK: - return h->amp_num; case LE_LINK: return h->le_num; case SCO_LINK: @@ -1084,7 +1046,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev) { struct hci_conn_hash *c = &hdev->conn_hash; - return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num; + return c->acl_num + c->sco_num + c->le_num + c->iso_num; } static inline bool hci_conn_valid(struct hci_dev *hdev, struct hci_conn *conn) @@ -1373,8 +1335,7 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle) rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { - if (c->type != ISO_LINK || - !test_bit(HCI_CONN_PA_SYNC, &c->flags)) + if (c->type != ISO_LINK) continue; if (c->sync_handle == sync_handle) { @@ -1610,10 +1571,6 @@ static inline void hci_conn_drop(struct hci_conn *conn) } break; - case AMP_LINK: - timeo = conn->disc_timeout; - break; - default: timeo = 0; break; @@ -2235,8 +2192,22 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c); /* These LE scan and inquiry parameters were chosen according to LE General * Discovery Procedure specification. */ -#define DISCOV_LE_SCAN_WIN 0x12 -#define DISCOV_LE_SCAN_INT 0x12 +#define DISCOV_LE_SCAN_WIN 0x0012 /* 11.25 msec */ +#define DISCOV_LE_SCAN_INT 0x0012 /* 11.25 msec */ +#define DISCOV_LE_SCAN_INT_FAST 0x0060 /* 60 msec */ +#define DISCOV_LE_SCAN_WIN_FAST 0x0030 /* 30 msec */ +#define DISCOV_LE_SCAN_INT_CONN 0x0060 /* 60 msec */ +#define DISCOV_LE_SCAN_WIN_CONN 0x0060 /* 60 msec */ +#define DISCOV_LE_SCAN_INT_SLOW1 0x0800 /* 1.28 sec */ +#define DISCOV_LE_SCAN_WIN_SLOW1 0x0012 /* 11.25 msec */ +#define DISCOV_LE_SCAN_INT_SLOW2 0x1000 /* 2.56 sec */ +#define DISCOV_LE_SCAN_WIN_SLOW2 0x0024 /* 22.5 msec */ +#define DISCOV_CODED_SCAN_INT_FAST 0x0120 /* 180 msec */ +#define DISCOV_CODED_SCAN_WIN_FAST 0x0090 /* 90 msec */ +#define DISCOV_CODED_SCAN_INT_SLOW1 0x1800 /* 3.84 sec */ +#define DISCOV_CODED_SCAN_WIN_SLOW1 0x0036 /* 33.75 msec */ +#define DISCOV_CODED_SCAN_INT_SLOW2 0x3000 /* 7.68 sec */ +#define DISCOV_CODED_SCAN_WIN_SLOW2 0x006c /* 67.5 msec */ #define DISCOV_LE_TIMEOUT 10240 /* msec */ #define DISCOV_INTERLEAVED_TIMEOUT 5120 /* msec */ #define DISCOV_INTERLEAVED_INQUIRY_LEN 0x04 diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a4278aa618ab..5cfdc813491a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -463,18 +463,24 @@ struct l2cap_le_credits { #define L2CAP_ECRED_MAX_CID 5 struct l2cap_ecred_conn_req { - __le16 psm; - __le16 mtu; - __le16 mps; - __le16 credits; + /* New members must be added within the struct_group() macro below. */ + __struct_group(l2cap_ecred_conn_req_hdr, hdr, __packed, + __le16 psm; + __le16 mtu; + __le16 mps; + __le16 credits; + ); __le16 scid[]; } __packed; struct l2cap_ecred_conn_rsp { - __le16 mtu; - __le16 mps; - __le16 credits; - __le16 result; + /* New members must be added within the struct_group() macro below. */ + struct_group_tagged(l2cap_ecred_conn_rsp_hdr, hdr, + __le16 mtu; + __le16 mps; + __le16 credits; + __le16 result; + ); __le16 dcid[]; }; @@ -548,6 +554,9 @@ struct l2cap_chan { __u16 tx_credits; __u16 rx_credits; + /* estimated available receive buffer space or -1 if unknown */ + ssize_t rx_avail; + __u8 tx_state; __u8 rx_state; @@ -682,10 +691,15 @@ struct l2cap_user { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) +struct l2cap_rx_busy { + struct list_head list; + struct sk_buff *skb; +}; + struct l2cap_pinfo { struct bt_sock bt; struct l2cap_chan *chan; - struct sk_buff *rx_busy_skb; + struct list_head rx_busy; }; enum { @@ -943,6 +957,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); +void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail); int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator); void l2cap_chan_set_defaults(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan); diff --git a/include/uapi/linux/virtio_bt.h b/include/uapi/linux/virtio_bt.h index af798f4c9680..3cc7d633456b 100644 --- a/include/uapi/linux/virtio_bt.h +++ b/include/uapi/linux/virtio_bt.h @@ -13,7 +13,6 @@ enum virtio_bt_config_type { VIRTIO_BT_CONFIG_TYPE_PRIMARY = 0, - VIRTIO_BT_CONFIG_TYPE_AMP = 1, }; enum virtio_bt_config_vendor { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 05346250f719..0c76dcde5361 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -241,13 +241,13 @@ static int configure_datapath_sync(struct hci_dev *hdev, struct bt_codec *codec) __u8 vnd_len, *vnd_data = NULL; struct hci_op_configure_data_path *cmd = NULL; + /* Do not take below 2 checks as error since the 1st means user do not + * want to use HFP offload mode and the 2nd means the vendor controller + * do not need to send below HCI command for offload mode. + */ if (!codec->data_path || !hdev->get_codec_config_data) return 0; - /* Do not take me as error */ - if (!hdev->get_codec_config_data) - return 0; - err = hdev->get_codec_config_data(hdev, ESCO_LINK, codec, &vnd_len, &vnd_data); if (err < 0) @@ -664,11 +664,6 @@ static void le_conn_timeout(struct work_struct *work) hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM); } -struct iso_cig_params { - struct hci_cp_le_set_cig_params cp; - struct hci_cis_params cis[0x1f]; -}; - struct iso_list_data { union { u8 cig; @@ -909,11 +904,37 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, { struct hci_conn *conn; + switch (type) { + case ACL_LINK: + if (!hdev->acl_mtu) + return ERR_PTR(-ECONNREFUSED); + break; + case ISO_LINK: + if (hdev->iso_mtu) + /* Dedicated ISO Buffer exists */ + break; + fallthrough; + case LE_LINK: + if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) + return ERR_PTR(-ECONNREFUSED); + if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU) + return ERR_PTR(-ECONNREFUSED); + break; + case SCO_LINK: + case ESCO_LINK: + if (!hdev->sco_pkts) + /* Controller does not support SCO or eSCO over HCI */ + return ERR_PTR(-ECONNREFUSED); + break; + default: + return ERR_PTR(-ECONNREFUSED); + } + bt_dev_dbg(hdev, "dst %pMR handle 0x%4.4x", dst, handle); conn = kzalloc(sizeof(*conn), GFP_KERNEL); if (!conn) - return NULL; + return ERR_PTR(-ENOMEM); bacpy(&conn->dst, dst); bacpy(&conn->src, &hdev->bdaddr); @@ -944,10 +965,12 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, switch (type) { case ACL_LINK: conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK; + conn->mtu = hdev->acl_mtu; break; case LE_LINK: /* conn->src should reflect the local identity address */ hci_copy_identity_address(hdev, &conn->src, &conn->src_type); + conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; break; case ISO_LINK: /* conn->src should reflect the local identity address */ @@ -959,6 +982,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, else if (conn->role == HCI_ROLE_MASTER) conn->cleanup = cis_cleanup; + conn->mtu = hdev->iso_mtu ? hdev->iso_mtu : + hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu; break; case SCO_LINK: if (lmp_esco_capable(hdev)) @@ -966,9 +991,12 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, (hdev->esco_type & EDR_ESCO_MASK); else conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; + + conn->mtu = hdev->sco_mtu; break; case ESCO_LINK: conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK; + conn->mtu = hdev->sco_mtu; break; } @@ -1011,7 +1039,7 @@ struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type, handle = hci_conn_hash_alloc_unset(hdev); if (unlikely(handle < 0)) - return NULL; + return ERR_PTR(-ECONNREFUSED); return hci_conn_add(hdev, type, dst, role, handle); } @@ -1140,8 +1168,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, uint8_t src_type) list_for_each_entry(d, &hci_dev_list, list) { if (!test_bit(HCI_UP, &d->flags) || - hci_dev_test_flag(d, HCI_USER_CHANNEL) || - d->dev_type != HCI_PRIMARY) + hci_dev_test_flag(d, HCI_USER_CHANNEL)) continue; /* Simple routing: @@ -1317,8 +1344,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, bacpy(&conn->dst, dst); } else { conn = hci_conn_add_unset(hdev, LE_LINK, dst, role); - if (!conn) - return ERR_PTR(-ENOMEM); + if (IS_ERR(conn)) + return conn; hci_conn_hold(conn); conn->pending_sec_level = sec_level; } @@ -1494,8 +1521,8 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst, return ERR_PTR(-EADDRINUSE); conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); - if (!conn) - return ERR_PTR(-ENOMEM); + if (IS_ERR(conn)) + return conn; conn->state = BT_CONNECT; @@ -1538,8 +1565,8 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, BT_DBG("requesting refresh of dst_addr"); conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER); - if (!conn) - return ERR_PTR(-ENOMEM); + if (IS_ERR(conn)) + return conn; if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0) { hci_conn_del(conn); @@ -1586,8 +1613,8 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); if (!acl) { acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER); - if (!acl) - return ERR_PTR(-ENOMEM); + if (IS_ERR(acl)) + return acl; } hci_conn_hold(acl); @@ -1655,9 +1682,9 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, sco = hci_conn_hash_lookup_ba(hdev, type, dst); if (!sco) { sco = hci_conn_add_unset(hdev, type, dst, HCI_ROLE_MASTER); - if (!sco) { + if (IS_ERR(sco)) { hci_conn_drop(acl); - return ERR_PTR(-ENOMEM); + return sco; } } @@ -1722,34 +1749,33 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos) static int set_cig_params_sync(struct hci_dev *hdev, void *data) { + DEFINE_FLEX(struct hci_cp_le_set_cig_params, pdu, cis, num_cis, 0x1f); u8 cig_id = PTR_UINT(data); struct hci_conn *conn; struct bt_iso_qos *qos; - struct iso_cig_params pdu; + u8 aux_num_cis = 0; u8 cis_id; conn = hci_conn_hash_lookup_cig(hdev, cig_id); if (!conn) return 0; - memset(&pdu, 0, sizeof(pdu)); - qos = &conn->iso_qos; - pdu.cp.cig_id = cig_id; - hci_cpu_to_le24(qos->ucast.out.interval, pdu.cp.c_interval); - hci_cpu_to_le24(qos->ucast.in.interval, pdu.cp.p_interval); - pdu.cp.sca = qos->ucast.sca; - pdu.cp.packing = qos->ucast.packing; - pdu.cp.framing = qos->ucast.framing; - pdu.cp.c_latency = cpu_to_le16(qos->ucast.out.latency); - pdu.cp.p_latency = cpu_to_le16(qos->ucast.in.latency); + pdu->cig_id = cig_id; + hci_cpu_to_le24(qos->ucast.out.interval, pdu->c_interval); + hci_cpu_to_le24(qos->ucast.in.interval, pdu->p_interval); + pdu->sca = qos->ucast.sca; + pdu->packing = qos->ucast.packing; + pdu->framing = qos->ucast.framing; + pdu->c_latency = cpu_to_le16(qos->ucast.out.latency); + pdu->p_latency = cpu_to_le16(qos->ucast.in.latency); /* Reprogram all CIS(s) with the same CIG, valid range are: * num_cis: 0x00 to 0x1F * cis_id: 0x00 to 0xEF */ for (cis_id = 0x00; cis_id < 0xf0 && - pdu.cp.num_cis < ARRAY_SIZE(pdu.cis); cis_id++) { + aux_num_cis < pdu->num_cis; cis_id++) { struct hci_cis_params *cis; conn = hci_conn_hash_lookup_cis(hdev, NULL, 0, cig_id, cis_id); @@ -1758,7 +1784,7 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data) qos = &conn->iso_qos; - cis = &pdu.cis[pdu.cp.num_cis++]; + cis = &pdu->cis[aux_num_cis++]; cis->cis_id = cis_id; cis->c_sdu = cpu_to_le16(conn->iso_qos.ucast.out.sdu); cis->p_sdu = cpu_to_le16(conn->iso_qos.ucast.in.sdu); @@ -1769,14 +1795,14 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data) cis->c_rtn = qos->ucast.out.rtn; cis->p_rtn = qos->ucast.in.rtn; } + pdu->num_cis = aux_num_cis; - if (!pdu.cp.num_cis) + if (!pdu->num_cis) return 0; return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_CIG_PARAMS, - sizeof(pdu.cp) + - pdu.cp.num_cis * sizeof(pdu.cis[0]), &pdu, - HCI_CMD_TIMEOUT); + struct_size(pdu, cis, pdu->num_cis), + pdu, HCI_CMD_TIMEOUT); } static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos) @@ -1847,8 +1873,8 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst, qos->ucast.cis); if (!cis) { cis = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER); - if (!cis) - return ERR_PTR(-ENOMEM); + if (IS_ERR(cis)) + return cis; cis->cleanup = cis_cleanup; cis->dst_type = dst_type; cis->iso_qos.ucast.cig = BT_ISO_QOS_CIG_UNSET; @@ -1983,14 +2009,8 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn, struct bt_iso_io_qos *qos, __u8 phy) { /* Only set MTU if PHY is enabled */ - if (!qos->sdu && qos->phy) { - if (hdev->iso_mtu > 0) - qos->sdu = hdev->iso_mtu; - else if (hdev->le_mtu > 0) - qos->sdu = hdev->le_mtu; - else - qos->sdu = hdev->acl_mtu; - } + if (!qos->sdu && qos->phy) + qos->sdu = conn->mtu; /* Use the same PHY as ACL if set to any */ if (qos->phy == BT_ISO_PHY_ANY) @@ -2071,8 +2091,8 @@ struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, return ERR_PTR(-EBUSY); conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_SLAVE); - if (!conn) - return ERR_PTR(-ENOMEM); + if (IS_ERR(conn)) + return conn; conn->iso_qos = *qos; conn->state = BT_LISTEN; @@ -2109,13 +2129,10 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon, struct bt_iso_qos *qos, __u16 sync_handle, __u8 num_bis, __u8 bis[]) { - struct _packed { - struct hci_cp_le_big_create_sync cp; - __u8 bis[0x11]; - } pdu; + DEFINE_FLEX(struct hci_cp_le_big_create_sync, pdu, bis, num_bis, 0x11); int err; - if (num_bis < 0x01 || num_bis > sizeof(pdu.bis)) + if (num_bis < 0x01 || num_bis > pdu->num_bis) return -EINVAL; err = qos_set_big(hdev, qos); @@ -2125,18 +2142,17 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon, if (hcon) hcon->iso_qos.bcast.big = qos->bcast.big; - memset(&pdu, 0, sizeof(pdu)); - pdu.cp.handle = qos->bcast.big; - pdu.cp.sync_handle = cpu_to_le16(sync_handle); - pdu.cp.encryption = qos->bcast.encryption; - memcpy(pdu.cp.bcode, qos->bcast.bcode, sizeof(pdu.cp.bcode)); - pdu.cp.mse = qos->bcast.mse; - pdu.cp.timeout = cpu_to_le16(qos->bcast.timeout); - pdu.cp.num_bis = num_bis; - memcpy(pdu.bis, bis, num_bis); + pdu->handle = qos->bcast.big; + pdu->sync_handle = cpu_to_le16(sync_handle); + pdu->encryption = qos->bcast.encryption; + memcpy(pdu->bcode, qos->bcast.bcode, sizeof(pdu->bcode)); + pdu->mse = qos->bcast.mse; + pdu->timeout = cpu_to_le16(qos->bcast.timeout); + pdu->num_bis = num_bis; + memcpy(pdu->bis, bis, num_bis); return hci_send_cmd(hdev, HCI_OP_LE_BIG_CREATE_SYNC, - sizeof(pdu.cp) + num_bis, &pdu); + struct_size(pdu, bis, num_bis), pdu); } static void create_big_complete(struct hci_dev *hdev, void *data, int err) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bc5086423ab8..dd3b0f501018 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -149,8 +149,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) { int old_state = hdev->discovery.state; - BT_DBG("%s state %u -> %u", hdev->name, hdev->discovery.state, state); - if (old_state == state) return; @@ -166,6 +164,13 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STARTING: break; case DISCOVERY_FINDING: + /* If discovery was not started then it was initiated by the + * MGMT interface so no MGMT event shall be generated either + */ + if (old_state != DISCOVERY_STARTING) { + hdev->discovery.state = old_state; + return; + } mgmt_discovering(hdev, 1); break; case DISCOVERY_RESOLVING: @@ -173,6 +178,8 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STOPPING: break; } + + bt_dev_dbg(hdev, "state %u -> %u", old_state, state); } void hci_inquiry_cache_flush(struct hci_dev *hdev) @@ -395,11 +402,6 @@ int hci_inquiry(void __user *arg) goto done; } - if (hdev->dev_type != HCI_PRIMARY) { - err = -EOPNOTSUPP; - goto done; - } - if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { err = -EOPNOTSUPP; goto done; @@ -752,11 +754,6 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) goto done; } - if (hdev->dev_type != HCI_PRIMARY) { - err = -EOPNOTSUPP; - goto done; - } - if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { err = -EOPNOTSUPP; goto done; @@ -910,7 +907,7 @@ int hci_get_dev_info(void __user *arg) strscpy(di.name, hdev->name, sizeof(di.name)); di.bdaddr = hdev->bdaddr; - di.type = (hdev->bus & 0x0f) | ((hdev->dev_type & 0x03) << 4); + di.type = (hdev->bus & 0x0f); di.flags = flags; di.pkt_type = hdev->pkt_type; if (lmp_bredr_capable(hdev)) { @@ -1026,8 +1023,7 @@ static void hci_power_on(struct work_struct *work) */ if (hci_dev_test_flag(hdev, HCI_RFKILLED) || hci_dev_test_flag(hdev, HCI_UNCONFIGURED) || - (hdev->dev_type == HCI_PRIMARY && - !bacmp(&hdev->bdaddr, BDADDR_ANY) && + (!bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY))) { hci_dev_clear_flag(hdev, HCI_AUTO_OFF); hci_dev_do_close(hdev); @@ -1769,6 +1765,15 @@ struct adv_info *hci_add_adv_instance(struct hci_dev *hdev, u8 instance, adv->pending = true; adv->instance = instance; + + /* If controller support only one set and the instance is set to + * 1 then there is no option other than using handle 0x00. + */ + if (hdev->le_num_of_adv_sets == 1 && instance == 1) + adv->handle = 0x00; + else + adv->handle = instance; + list_add(&adv->list, &hdev->adv_instances); hdev->adv_instance_cnt++; } @@ -2523,16 +2528,16 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) hdev->le_adv_channel_map = 0x07; hdev->le_adv_min_interval = 0x0800; hdev->le_adv_max_interval = 0x0800; - hdev->le_scan_interval = 0x0060; - hdev->le_scan_window = 0x0030; - hdev->le_scan_int_suspend = 0x0400; - hdev->le_scan_window_suspend = 0x0012; + hdev->le_scan_interval = DISCOV_LE_SCAN_INT_FAST; + hdev->le_scan_window = DISCOV_LE_SCAN_WIN_FAST; + hdev->le_scan_int_suspend = DISCOV_LE_SCAN_INT_SLOW1; + hdev->le_scan_window_suspend = DISCOV_LE_SCAN_WIN_SLOW1; hdev->le_scan_int_discovery = DISCOV_LE_SCAN_INT; hdev->le_scan_window_discovery = DISCOV_LE_SCAN_WIN; - hdev->le_scan_int_adv_monitor = 0x0060; - hdev->le_scan_window_adv_monitor = 0x0030; - hdev->le_scan_int_connect = 0x0060; - hdev->le_scan_window_connect = 0x0060; + hdev->le_scan_int_adv_monitor = DISCOV_LE_SCAN_INT_FAST; + hdev->le_scan_window_adv_monitor = DISCOV_LE_SCAN_WIN_FAST; + hdev->le_scan_int_connect = DISCOV_LE_SCAN_INT_CONN; + hdev->le_scan_window_connect = DISCOV_LE_SCAN_WIN_CONN; hdev->le_conn_min_interval = 0x0018; hdev->le_conn_max_interval = 0x0028; hdev->le_conn_latency = 0x0000; @@ -2549,7 +2554,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) hdev->le_rx_def_phys = HCI_LE_SET_PHY_1M; hdev->le_num_of_adv_sets = HCI_MAX_ADV_INSTANCES; hdev->def_multi_adv_rotation_duration = HCI_DEFAULT_ADV_DURATION; - hdev->def_le_autoconnect_timeout = HCI_LE_AUTOCONN_TIMEOUT; + hdev->def_le_autoconnect_timeout = HCI_LE_CONN_TIMEOUT; hdev->min_le_tx_power = HCI_TX_POWER_INVALID; hdev->max_le_tx_power = HCI_TX_POWER_INVALID; @@ -2635,21 +2640,7 @@ int hci_register_dev(struct hci_dev *hdev) if (!hdev->open || !hdev->close || !hdev->send) return -EINVAL; - /* Do not allow HCI_AMP devices to register at index 0, - * so the index can be used as the AMP controller ID. - */ - switch (hdev->dev_type) { - case HCI_PRIMARY: - id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL); - break; - case HCI_AMP: - id = ida_alloc_range(&hci_index_ida, 1, HCI_MAX_ID - 1, - GFP_KERNEL); - break; - default: - return -EINVAL; - } - + id = ida_alloc_max(&hci_index_ida, HCI_MAX_ID - 1, GFP_KERNEL); if (id < 0) return id; @@ -2701,12 +2692,10 @@ int hci_register_dev(struct hci_dev *hdev) hci_dev_set_flag(hdev, HCI_SETUP); hci_dev_set_flag(hdev, HCI_AUTO_OFF); - if (hdev->dev_type == HCI_PRIMARY) { - /* Assume BR/EDR support until proven otherwise (such as - * through reading supported features during init. - */ - hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); - } + /* Assume BR/EDR support until proven otherwise (such as + * through reading supported features during init. + */ + hci_dev_set_flag(hdev, HCI_BREDR_ENABLED); write_lock(&hci_dev_list_lock); list_add(&hdev->list, &hci_dev_list); @@ -3242,17 +3231,7 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT; - switch (hdev->dev_type) { - case HCI_PRIMARY: - hci_add_acl_hdr(skb, conn->handle, flags); - break; - case HCI_AMP: - hci_add_acl_hdr(skb, chan->handle, flags); - break; - default: - bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type); - return; - } + hci_add_acl_hdr(skb, conn->handle, flags); list = skb_shinfo(skb)->frag_list; if (!list) { @@ -3412,9 +3391,6 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) case ACL_LINK: cnt = hdev->acl_cnt; break; - case AMP_LINK: - cnt = hdev->block_cnt; - break; case SCO_LINK: case ESCO_LINK: cnt = hdev->sco_cnt; @@ -3612,12 +3588,6 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) } -static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) -{ - /* Calculate count of blocks used by this packet */ - return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); -} - static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) { unsigned long last_tx; @@ -3731,81 +3701,15 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) hci_prio_recalculate(hdev, ACL_LINK); } -static void hci_sched_acl_blk(struct hci_dev *hdev) -{ - unsigned int cnt = hdev->block_cnt; - struct hci_chan *chan; - struct sk_buff *skb; - int quote; - u8 type; - - BT_DBG("%s", hdev->name); - - if (hdev->dev_type == HCI_AMP) - type = AMP_LINK; - else - type = ACL_LINK; - - __check_timeout(hdev, cnt, type); - - while (hdev->block_cnt > 0 && - (chan = hci_chan_sent(hdev, type, "e))) { - u32 priority = (skb_peek(&chan->data_q))->priority; - while (quote > 0 && (skb = skb_peek(&chan->data_q))) { - int blocks; - - BT_DBG("chan %p skb %p len %d priority %u", chan, skb, - skb->len, skb->priority); - - /* Stop if priority has changed */ - if (skb->priority < priority) - break; - - skb = skb_dequeue(&chan->data_q); - - blocks = __get_blocks(hdev, skb); - if (blocks > hdev->block_cnt) - return; - - hci_conn_enter_active_mode(chan->conn, - bt_cb(skb)->force_active); - - hci_send_frame(hdev, skb); - hdev->acl_last_tx = jiffies; - - hdev->block_cnt -= blocks; - quote -= blocks; - - chan->sent += blocks; - chan->conn->sent += blocks; - } - } - - if (cnt != hdev->block_cnt) - hci_prio_recalculate(hdev, type); -} - static void hci_sched_acl(struct hci_dev *hdev) { BT_DBG("%s", hdev->name); /* No ACL link over BR/EDR controller */ - if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_PRIMARY) - return; - - /* No AMP link over AMP controller */ - if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP) + if (!hci_conn_num(hdev, ACL_LINK)) return; - switch (hdev->flow_ctl_mode) { - case HCI_FLOW_CTL_MODE_PACKET_BASED: - hci_sched_acl_pkt(hdev); - break; - - case HCI_FLOW_CTL_MODE_BLOCK_BASED: - hci_sched_acl_blk(hdev); - break; - } + hci_sched_acl_pkt(hdev); } static void hci_sched_le(struct hci_dev *hdev) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d72d238c1656..a487f9df8145 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1,7 +1,7 @@ /* BlueZ - Bluetooth protocol stack for Linux Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. - Copyright 2023 NXP + Copyright 2023-2024 NXP Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> @@ -913,21 +913,6 @@ static u8 hci_cc_read_local_ext_features(struct hci_dev *hdev, void *data, return rp->status; } -static u8 hci_cc_read_flow_control_mode(struct hci_dev *hdev, void *data, - struct sk_buff *skb) -{ - struct hci_rp_read_flow_control_mode *rp = data; - - bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); - - if (rp->status) - return rp->status; - - hdev->flow_ctl_mode = rp->mode; - - return rp->status; -} - static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -954,6 +939,9 @@ static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data, BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu, hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts); + if (!hdev->acl_mtu || !hdev->acl_pkts) + return HCI_ERROR_INVALID_PARAMETERS; + return rp->status; } @@ -1068,28 +1056,6 @@ static u8 hci_cc_write_page_scan_type(struct hci_dev *hdev, void *data, return rp->status; } -static u8 hci_cc_read_data_block_size(struct hci_dev *hdev, void *data, - struct sk_buff *skb) -{ - struct hci_rp_read_data_block_size *rp = data; - - bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); - - if (rp->status) - return rp->status; - - hdev->block_mtu = __le16_to_cpu(rp->max_acl_len); - hdev->block_len = __le16_to_cpu(rp->block_len); - hdev->num_blocks = __le16_to_cpu(rp->num_blocks); - - hdev->block_cnt = hdev->num_blocks; - - BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu, - hdev->block_cnt, hdev->block_len); - - return rp->status; -} - static u8 hci_cc_read_clock(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -1124,30 +1090,6 @@ unlock: return rp->status; } -static u8 hci_cc_read_local_amp_info(struct hci_dev *hdev, void *data, - struct sk_buff *skb) -{ - struct hci_rp_read_local_amp_info *rp = data; - - bt_dev_dbg(hdev, "status 0x%2.2x", rp->status); - - if (rp->status) - return rp->status; - - hdev->amp_status = rp->amp_status; - hdev->amp_total_bw = __le32_to_cpu(rp->total_bw); - hdev->amp_max_bw = __le32_to_cpu(rp->max_bw); - hdev->amp_min_latency = __le32_to_cpu(rp->min_latency); - hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu); - hdev->amp_type = rp->amp_type; - hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap); - hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size); - hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to); - hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to); - - return rp->status; -} - static u8 hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -1263,6 +1205,9 @@ static u8 hci_cc_le_read_buffer_size(struct hci_dev *hdev, void *data, BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts); + if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) + return HCI_ERROR_INVALID_PARAMETERS; + return rp->status; } @@ -1779,8 +1724,7 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable) hci_dev_set_flag(hdev, HCI_LE_SCAN); if (hdev->le_scan_type == LE_SCAN_ACTIVE) clear_pending_adv_report(hdev); - if (hci_dev_test_flag(hdev, HCI_MESH)) - hci_discovery_set_state(hdev, DISCOVERY_FINDING); + hci_discovery_set_state(hdev, DISCOVERY_FINDING); break; case LE_SCAN_DISABLE: @@ -2342,8 +2286,8 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) if (!conn) { conn = hci_conn_add_unset(hdev, ACL_LINK, &cp->bdaddr, HCI_ROLE_MASTER); - if (!conn) - bt_dev_err(hdev, "no memory for new connection"); + if (IS_ERR(conn)) + bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn)); } } @@ -3154,8 +3098,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, BDADDR_BREDR)) { conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr, HCI_ROLE_SLAVE); - if (!conn) { - bt_dev_err(hdev, "no memory for new conn"); + if (IS_ERR(conn)) { + bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn)); goto unlock; } } else { @@ -3343,8 +3287,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data, if (!conn) { conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr, HCI_ROLE_SLAVE); - if (!conn) { - bt_dev_err(hdev, "no memory for new connection"); + if (IS_ERR(conn)) { + bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn)); goto unlock; } } @@ -3821,6 +3765,9 @@ static u8 hci_cc_le_read_buffer_size_v2(struct hci_dev *hdev, void *data, BT_DBG("%s acl mtu %d:%d iso mtu %d:%d", hdev->name, hdev->acl_mtu, hdev->acl_pkts, hdev->iso_mtu, hdev->iso_pkts); + if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU) + return HCI_ERROR_INVALID_PARAMETERS; + return rp->status; } @@ -4112,12 +4059,6 @@ static const struct hci_cc { HCI_CC(HCI_OP_READ_PAGE_SCAN_TYPE, hci_cc_read_page_scan_type, sizeof(struct hci_rp_read_page_scan_type)), HCI_CC_STATUS(HCI_OP_WRITE_PAGE_SCAN_TYPE, hci_cc_write_page_scan_type), - HCI_CC(HCI_OP_READ_DATA_BLOCK_SIZE, hci_cc_read_data_block_size, - sizeof(struct hci_rp_read_data_block_size)), - HCI_CC(HCI_OP_READ_FLOW_CONTROL_MODE, hci_cc_read_flow_control_mode, - sizeof(struct hci_rp_read_flow_control_mode)), - HCI_CC(HCI_OP_READ_LOCAL_AMP_INFO, hci_cc_read_local_amp_info, - sizeof(struct hci_rp_read_local_amp_info)), HCI_CC(HCI_OP_READ_CLOCK, hci_cc_read_clock, sizeof(struct hci_rp_read_clock)), HCI_CC(HCI_OP_READ_ENC_KEY_SIZE, hci_cc_read_enc_key_size, @@ -4308,7 +4249,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) hci_dev_lock(hdev); /* Remove connection if command failed */ - for (i = 0; cp->num_cis; cp->num_cis--, i++) { + for (i = 0; i < cp->num_cis; i++) { struct hci_conn *conn; u16 handle; @@ -4324,6 +4265,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status) hci_conn_del(conn); } } + cp->num_cis = 0; if (pending) hci_le_create_cis_pending(hdev); @@ -4452,11 +4394,6 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, flex_array_size(ev, handles, ev->num))) return; - if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) { - bt_dev_err(hdev, "wrong event for mode %d", hdev->flow_ctl_mode); - return; - } - bt_dev_dbg(hdev, "num %d", ev->num); for (i = 0; i < ev->num; i++) { @@ -4524,78 +4461,6 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, queue_work(hdev->workqueue, &hdev->tx_work); } -static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev, - __u16 handle) -{ - struct hci_chan *chan; - - switch (hdev->dev_type) { - case HCI_PRIMARY: - return hci_conn_hash_lookup_handle(hdev, handle); - case HCI_AMP: - chan = hci_chan_lookup_handle(hdev, handle); - if (chan) - return chan->conn; - break; - default: - bt_dev_err(hdev, "unknown dev_type %d", hdev->dev_type); - break; - } - - return NULL; -} - -static void hci_num_comp_blocks_evt(struct hci_dev *hdev, void *data, - struct sk_buff *skb) -{ - struct hci_ev_num_comp_blocks *ev = data; - int i; - - if (!hci_ev_skb_pull(hdev, skb, HCI_EV_NUM_COMP_BLOCKS, - flex_array_size(ev, handles, ev->num_hndl))) - return; - - if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_BLOCK_BASED) { - bt_dev_err(hdev, "wrong event for mode %d", - hdev->flow_ctl_mode); - return; - } - - bt_dev_dbg(hdev, "num_blocks %d num_hndl %d", ev->num_blocks, - ev->num_hndl); - - for (i = 0; i < ev->num_hndl; i++) { - struct hci_comp_blocks_info *info = &ev->handles[i]; - struct hci_conn *conn = NULL; - __u16 handle, block_count; - - handle = __le16_to_cpu(info->handle); - block_count = __le16_to_cpu(info->blocks); - - conn = __hci_conn_lookup_handle(hdev, handle); - if (!conn) - continue; - - conn->sent -= block_count; - - switch (conn->type) { - case ACL_LINK: - case AMP_LINK: - hdev->block_cnt += block_count; - if (hdev->block_cnt > hdev->num_blocks) - hdev->block_cnt = hdev->num_blocks; - break; - - default: - bt_dev_err(hdev, "unknown type %d conn %p", - conn->type, conn); - break; - } - } - - queue_work(hdev->workqueue, &hdev->tx_work); -} - static void hci_mode_change_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { @@ -5768,8 +5633,8 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, goto unlock; conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, role); - if (!conn) { - bt_dev_err(hdev, "no memory for new connection"); + if (IS_ERR(conn)) { + bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn)); goto unlock; } @@ -6493,14 +6358,16 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, if (!(flags & HCI_PROTO_DEFER)) goto unlock; - if (ev->status) { - /* Add connection to indicate the failed PA sync event */ - pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY, - HCI_ROLE_SLAVE); + /* Add connection to indicate PA sync event */ + pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY, + HCI_ROLE_SLAVE); - if (!pa_sync) - goto unlock; + if (IS_ERR(pa_sync)) + goto unlock; + pa_sync->sync_handle = le16_to_cpu(ev->handle); + + if (ev->status) { set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags); /* Notify iso layer */ @@ -6517,6 +6384,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data, struct hci_ev_le_per_adv_report *ev = data; int mask = hdev->link_mode; __u8 flags = 0; + struct hci_conn *pa_sync; bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle)); @@ -6524,8 +6392,28 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data, mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags); if (!(mask & HCI_LM_ACCEPT)) - hci_le_pa_term_sync(hdev, ev->sync_handle); + goto unlock; + + if (!(flags & HCI_PROTO_DEFER)) + goto unlock; + + pa_sync = hci_conn_hash_lookup_pa_sync_handle + (hdev, + le16_to_cpu(ev->sync_handle)); + + if (!pa_sync) + goto unlock; + + if (ev->data_status == LE_PA_DATA_COMPLETE && + !test_and_set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags)) { + /* Notify iso layer */ + hci_connect_cfm(pa_sync, 0); + + /* Notify MGMT layer */ + mgmt_device_connected(hdev, pa_sync, NULL, 0); + } +unlock: hci_dev_unlock(hdev); } @@ -6898,7 +6786,7 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data, if (!cis) { cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE, cis_handle); - if (!cis) { + if (IS_ERR(cis)) { hci_le_reject_cis(hdev, ev->cis_handle); goto unlock; } @@ -7007,7 +6895,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data, if (!bis) { bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY, HCI_ROLE_SLAVE, handle); - if (!bis) + if (IS_ERR(bis)) continue; } @@ -7060,10 +6948,8 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, hci_dev_lock(hdev); mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags); - if (!(mask & HCI_LM_ACCEPT)) { - hci_le_pa_term_sync(hdev, ev->sync_handle); + if (!(mask & HCI_LM_ACCEPT)) goto unlock; - } if (!(flags & HCI_PROTO_DEFER)) goto unlock; @@ -7072,24 +6958,11 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data, (hdev, le16_to_cpu(ev->sync_handle)); - if (pa_sync) - goto unlock; - - /* Add connection to indicate the PA sync event */ - pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY, - HCI_ROLE_SLAVE); - if (!pa_sync) goto unlock; - pa_sync->sync_handle = le16_to_cpu(ev->sync_handle); - set_bit(HCI_CONN_PA_SYNC, &pa_sync->flags); - /* Notify iso layer */ - hci_connect_cfm(pa_sync, 0x00); - - /* Notify MGMT layer */ - mgmt_device_connected(hdev, pa_sync, NULL, 0); + hci_connect_cfm(pa_sync, 0); unlock: hci_dev_unlock(hdev); @@ -7503,9 +7376,6 @@ static const struct hci_ev { /* [0x3e = HCI_EV_LE_META] */ HCI_EV_REQ_VL(HCI_EV_LE_META, hci_le_meta_evt, sizeof(struct hci_ev_le_meta), HCI_MAX_EVENT_SIZE), - /* [0x48 = HCI_EV_NUM_COMP_BLOCKS] */ - HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt, - sizeof(struct hci_ev_num_comp_blocks)), /* [0xff = HCI_EV_VENDOR] */ HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE), }; diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h index 0be75cf0efed..c91f2838f542 100644 --- a/net/bluetooth/hci_request.h +++ b/net/bluetooth/hci_request.h @@ -29,10 +29,6 @@ #define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock) #define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock) -#define HCI_REQ_DONE 0 -#define HCI_REQ_PEND 1 -#define HCI_REQ_CANCELED 2 - struct hci_request { struct hci_dev *hdev; struct sk_buff_head cmd_q; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 703b84bd48d5..69c2ba1e843e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -485,7 +485,7 @@ static struct sk_buff *create_monitor_event(struct hci_dev *hdev, int event) return NULL; ni = skb_put(skb, HCI_MON_NEW_INDEX_SIZE); - ni->type = hdev->dev_type; + ni->type = 0x00; /* Old hdev->dev_type */ ni->bus = hdev->bus; bacpy(&ni->bdaddr, &hdev->bdaddr); memcpy_and_pad(ni->name, sizeof(ni->name), hdev->name, @@ -1007,9 +1007,6 @@ static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) return -EOPNOTSUPP; - if (hdev->dev_type != HCI_PRIMARY) - return -EOPNOTSUPP; - switch (cmd) { case HCISETRAW: if (!capable(CAP_NET_ADMIN)) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 4c707eb64e6f..16daa79b7981 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -1043,11 +1043,10 @@ static int hci_disable_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) struct hci_cp_ext_adv_set *set; u8 data[sizeof(*cp) + sizeof(*set) * 1]; u8 size; + struct adv_info *adv = NULL; /* If request specifies an instance that doesn't exist, fail */ if (instance > 0) { - struct adv_info *adv; - adv = hci_find_adv_instance(hdev, instance); if (!adv) return -EINVAL; @@ -1066,7 +1065,7 @@ static int hci_disable_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) cp->num_of_sets = !!instance; cp->enable = 0x00; - set->handle = instance; + set->handle = adv ? adv->handle : instance; size = sizeof(*cp) + sizeof(*set) * cp->num_of_sets; @@ -1235,31 +1234,27 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance) static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance) { - struct { - struct hci_cp_le_set_ext_scan_rsp_data cp; - u8 data[HCI_MAX_EXT_AD_LENGTH]; - } pdu; + DEFINE_FLEX(struct hci_cp_le_set_ext_scan_rsp_data, pdu, data, length, + HCI_MAX_EXT_AD_LENGTH); u8 len; struct adv_info *adv = NULL; int err; - memset(&pdu, 0, sizeof(pdu)); - if (instance) { adv = hci_find_adv_instance(hdev, instance); if (!adv || !adv->scan_rsp_changed) return 0; } - len = eir_create_scan_rsp(hdev, instance, pdu.data); + len = eir_create_scan_rsp(hdev, instance, pdu->data); - pdu.cp.handle = instance; - pdu.cp.length = len; - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; - pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; + pdu->handle = adv ? adv->handle : instance; + pdu->length = len; + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; + pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG; err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, - sizeof(pdu.cp) + len, &pdu.cp, + struct_size(pdu, data, len), pdu, HCI_CMD_TIMEOUT); if (err) return err; @@ -1267,7 +1262,7 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance) if (adv) { adv->scan_rsp_changed = false; } else { - memcpy(hdev->scan_rsp_data, pdu.data, len); + memcpy(hdev->scan_rsp_data, pdu->data, len); hdev->scan_rsp_data_len = len; } @@ -1335,7 +1330,7 @@ int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance) memset(set, 0, sizeof(*set)); - set->handle = instance; + set->handle = adv ? adv->handle : instance; /* Set duration per instance since controller is responsible for * scheduling it. @@ -1411,29 +1406,25 @@ static int hci_set_per_adv_params_sync(struct hci_dev *hdev, u8 instance, static int hci_set_per_adv_data_sync(struct hci_dev *hdev, u8 instance) { - struct { - struct hci_cp_le_set_per_adv_data cp; - u8 data[HCI_MAX_PER_AD_LENGTH]; - } pdu; + DEFINE_FLEX(struct hci_cp_le_set_per_adv_data, pdu, data, length, + HCI_MAX_PER_AD_LENGTH); u8 len; - - memset(&pdu, 0, sizeof(pdu)); + struct adv_info *adv = NULL; if (instance) { - struct adv_info *adv = hci_find_adv_instance(hdev, instance); - + adv = hci_find_adv_instance(hdev, instance); if (!adv || !adv->periodic) return 0; } - len = eir_create_per_adv_data(hdev, instance, pdu.data); + len = eir_create_per_adv_data(hdev, instance, pdu->data); - pdu.cp.length = len; - pdu.cp.handle = instance; - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; + pdu->length = len; + pdu->handle = adv ? adv->handle : instance; + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA, - sizeof(pdu.cp) + len, &pdu, + struct_size(pdu, data, len), pdu, HCI_CMD_TIMEOUT); } @@ -1727,31 +1718,27 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason) static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance) { - struct { - struct hci_cp_le_set_ext_adv_data cp; - u8 data[HCI_MAX_EXT_AD_LENGTH]; - } pdu; + DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length, + HCI_MAX_EXT_AD_LENGTH); u8 len; struct adv_info *adv = NULL; int err; - memset(&pdu, 0, sizeof(pdu)); - if (instance) { adv = hci_find_adv_instance(hdev, instance); if (!adv || !adv->adv_data_changed) return 0; } - len = eir_create_adv_data(hdev, instance, pdu.data); + len = eir_create_adv_data(hdev, instance, pdu->data); - pdu.cp.length = len; - pdu.cp.handle = instance; - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; - pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; + pdu->length = len; + pdu->handle = adv ? adv->handle : instance; + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; + pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG; err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA, - sizeof(pdu.cp) + len, &pdu.cp, + struct_size(pdu, data, len), pdu, HCI_CMD_TIMEOUT); if (err) return err; @@ -1760,7 +1747,7 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance) if (adv) { adv->adv_data_changed = false; } else { - memcpy(hdev->adv_data, pdu.data, len); + memcpy(hdev->adv_data, pdu->data, len); hdev->adv_data_len = len; } @@ -3523,10 +3510,6 @@ static int hci_unconf_init_sync(struct hci_dev *hdev) /* Read Local Supported Features. */ static int hci_read_local_features_sync(struct hci_dev *hdev) { - /* Not all AMP controllers support this command */ - if (hdev->dev_type == HCI_AMP && !(hdev->commands[14] & 0x20)) - return 0; - return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL, HCI_CMD_TIMEOUT); } @@ -3561,51 +3544,6 @@ static int hci_read_local_cmds_sync(struct hci_dev *hdev) return 0; } -/* Read Local AMP Info */ -static int hci_read_local_amp_info_sync(struct hci_dev *hdev) -{ - return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_AMP_INFO, - 0, NULL, HCI_CMD_TIMEOUT); -} - -/* Read Data Blk size */ -static int hci_read_data_block_size_sync(struct hci_dev *hdev) -{ - return __hci_cmd_sync_status(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, - 0, NULL, HCI_CMD_TIMEOUT); -} - -/* Read Flow Control Mode */ -static int hci_read_flow_control_mode_sync(struct hci_dev *hdev) -{ - return __hci_cmd_sync_status(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, - 0, NULL, HCI_CMD_TIMEOUT); -} - -/* Read Location Data */ -static int hci_read_location_data_sync(struct hci_dev *hdev) -{ - return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCATION_DATA, - 0, NULL, HCI_CMD_TIMEOUT); -} - -/* AMP Controller init stage 1 command sequence */ -static const struct hci_init_stage amp_init1[] = { - /* HCI_OP_READ_LOCAL_VERSION */ - HCI_INIT(hci_read_local_version_sync), - /* HCI_OP_READ_LOCAL_COMMANDS */ - HCI_INIT(hci_read_local_cmds_sync), - /* HCI_OP_READ_LOCAL_AMP_INFO */ - HCI_INIT(hci_read_local_amp_info_sync), - /* HCI_OP_READ_DATA_BLOCK_SIZE */ - HCI_INIT(hci_read_data_block_size_sync), - /* HCI_OP_READ_FLOW_CONTROL_MODE */ - HCI_INIT(hci_read_flow_control_mode_sync), - /* HCI_OP_READ_LOCATION_DATA */ - HCI_INIT(hci_read_location_data_sync), - {} -}; - static int hci_init1_sync(struct hci_dev *hdev) { int err; @@ -3619,28 +3557,9 @@ static int hci_init1_sync(struct hci_dev *hdev) return err; } - switch (hdev->dev_type) { - case HCI_PRIMARY: - hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; - return hci_init_stage_sync(hdev, br_init1); - case HCI_AMP: - hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; - return hci_init_stage_sync(hdev, amp_init1); - default: - bt_dev_err(hdev, "Unknown device type %d", hdev->dev_type); - break; - } - - return 0; + return hci_init_stage_sync(hdev, br_init1); } -/* AMP Controller init stage 2 command sequence */ -static const struct hci_init_stage amp_init2[] = { - /* HCI_OP_READ_LOCAL_FEATURES */ - HCI_INIT(hci_read_local_features_sync), - {} -}; - /* Read Buffer Size (ACL mtu, max pkt, etc.) */ static int hci_read_buffer_size_sync(struct hci_dev *hdev) { @@ -3898,9 +3817,6 @@ static int hci_init2_sync(struct hci_dev *hdev) bt_dev_dbg(hdev, ""); - if (hdev->dev_type == HCI_AMP) - return hci_init_stage_sync(hdev, amp_init2); - err = hci_init_stage_sync(hdev, hci_init2); if (err) return err; @@ -4728,13 +4644,6 @@ static int hci_init_sync(struct hci_dev *hdev) if (err < 0) return err; - /* HCI_PRIMARY covers both single-mode LE, BR/EDR and dual-mode - * BR/EDR/LE type controllers. AMP controllers only need the - * first two stages of init. - */ - if (hdev->dev_type != HCI_PRIMARY) - return 0; - err = hci_init3_sync(hdev); if (err < 0) return err; @@ -4963,12 +4872,8 @@ int hci_dev_open_sync(struct hci_dev *hdev) * In case of user channel usage, it is not important * if a public address or static random address is * available. - * - * This check is only valid for BR/EDR controllers - * since AMP controllers do not have an address. */ if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && - hdev->dev_type == HCI_PRIMARY && !bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY)) { ret = -EADDRNOTAVAIL; @@ -5003,8 +4908,7 @@ int hci_dev_open_sync(struct hci_dev *hdev) !hci_dev_test_flag(hdev, HCI_CONFIG) && !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) && !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && - hci_dev_test_flag(hdev, HCI_MGMT) && - hdev->dev_type == HCI_PRIMARY) { + hci_dev_test_flag(hdev, HCI_MGMT)) { ret = hci_powered_update_sync(hdev); mgmt_power_on(hdev, ret); } @@ -5149,8 +5053,7 @@ int hci_dev_close_sync(struct hci_dev *hdev) auto_off = hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF); - if (!auto_off && hdev->dev_type == HCI_PRIMARY && - !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && + if (!auto_off && !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) && hci_dev_test_flag(hdev, HCI_MGMT)) __mgmt_power_off(hdev); @@ -5212,9 +5115,6 @@ int hci_dev_close_sync(struct hci_dev *hdev) hdev->flags &= BIT(HCI_RAW); hci_dev_clear_volatile_flags(hdev); - /* Controller radio is available but is currently powered down */ - hdev->amp_status = AMP_STATUS_POWERED_DOWN; - memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); bacpy(&hdev->random_addr, BDADDR_ANY); @@ -5251,8 +5151,7 @@ static int hci_power_on_sync(struct hci_dev *hdev) */ if (hci_dev_test_flag(hdev, HCI_RFKILLED) || hci_dev_test_flag(hdev, HCI_UNCONFIGURED) || - (hdev->dev_type == HCI_PRIMARY && - !bacmp(&hdev->bdaddr, BDADDR_ANY) && + (!bacmp(&hdev->bdaddr, BDADDR_ANY) && !bacmp(&hdev->static_addr, BDADDR_ANY))) { hci_dev_clear_flag(hdev, HCI_AUTO_OFF); hci_dev_close_sync(hdev); @@ -5354,27 +5253,11 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) return 0; } -static int hci_disconnect_phy_link_sync(struct hci_dev *hdev, u16 handle, - u8 reason) -{ - struct hci_cp_disconn_phy_link cp; - - memset(&cp, 0, sizeof(cp)); - cp.phy_handle = HCI_PHY_HANDLE(handle); - cp.reason = reason; - - return __hci_cmd_sync_status(hdev, HCI_OP_DISCONN_PHY_LINK, - sizeof(cp), &cp, HCI_CMD_TIMEOUT); -} - static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason) { struct hci_cp_disconnect cp; - if (conn->type == AMP_LINK) - return hci_disconnect_phy_link_sync(hdev, conn->handle, reason); - if (test_bit(HCI_CONN_BIG_CREATED, &conn->flags)) { /* This is a BIS connection, hci_conn_del will * do the necessary cleanup. @@ -6493,10 +6376,8 @@ done: int hci_le_create_cis_sync(struct hci_dev *hdev) { - struct { - struct hci_cp_le_create_cis cp; - struct hci_cis cis[0x1f]; - } cmd; + DEFINE_FLEX(struct hci_cp_le_create_cis, cmd, cis, num_cis, 0x1f); + size_t aux_num_cis = 0; struct hci_conn *conn; u8 cig = BT_ISO_QOS_CIG_UNSET; @@ -6523,8 +6404,6 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) * remains pending. */ - memset(&cmd, 0, sizeof(cmd)); - hci_dev_lock(hdev); rcu_read_lock(); @@ -6561,7 +6440,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) goto done; list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { - struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis]; + struct hci_cis *cis = &cmd->cis[aux_num_cis]; if (hci_conn_check_create_cis(conn) || conn->iso_qos.ucast.cig != cig) @@ -6570,25 +6449,25 @@ int hci_le_create_cis_sync(struct hci_dev *hdev) set_bit(HCI_CONN_CREATE_CIS, &conn->flags); cis->acl_handle = cpu_to_le16(conn->parent->handle); cis->cis_handle = cpu_to_le16(conn->handle); - cmd.cp.num_cis++; + aux_num_cis++; - if (cmd.cp.num_cis >= ARRAY_SIZE(cmd.cis)) + if (aux_num_cis >= cmd->num_cis) break; } + cmd->num_cis = aux_num_cis; done: rcu_read_unlock(); hci_dev_unlock(hdev); - if (!cmd.cp.num_cis) + if (!aux_num_cis) return 0; /* Wait for HCI_LE_CIS_Established */ return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS, - sizeof(cmd.cp) + sizeof(cmd.cis[0]) * - cmd.cp.num_cis, &cmd, - HCI_EVT_LE_CIS_ESTABLISHED, + struct_size(cmd, cis, cmd->num_cis), + cmd, HCI_EVT_LE_CIS_ESTABLISHED, conn->conn_timeout, NULL); } diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index ef0cc80b4c0c..00c0d8413c63 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -54,7 +54,6 @@ static void iso_sock_kill(struct sock *sk); enum { BT_SK_BIG_SYNC, BT_SK_PA_SYNC, - BT_SK_PA_SYNC_TERM, }; struct iso_pinfo { @@ -81,12 +80,14 @@ static bool check_ucast_qos(struct bt_iso_qos *qos); static bool check_bcast_qos(struct bt_iso_qos *qos); static bool iso_match_sid(struct sock *sk, void *data); static bool iso_match_sync_handle(struct sock *sk, void *data); +static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data); static void iso_sock_disconn(struct sock *sk); typedef bool (*iso_sock_match_t)(struct sock *sk, void *data); -static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst, - iso_sock_match_t match, void *data); +static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst, + enum bt_sock_state state, + iso_sock_match_t match, void *data); /* ---- ISO timers ---- */ #define ISO_CONN_TIMEOUT (HZ * 40) @@ -196,21 +197,10 @@ static void iso_chan_del(struct sock *sk, int err) sock_set_flag(sk, SOCK_ZAPPED); } -static bool iso_match_conn_sync_handle(struct sock *sk, void *data) -{ - struct hci_conn *hcon = data; - - if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) - return false; - - return hcon->sync_handle == iso_pi(sk)->sync_handle; -} - static void iso_conn_del(struct hci_conn *hcon, int err) { struct iso_conn *conn = hcon->iso_data; struct sock *sk; - struct sock *parent; if (!conn) return; @@ -226,25 +216,6 @@ static void iso_conn_del(struct hci_conn *hcon, int err) if (sk) { lock_sock(sk); - - /* While a PA sync hcon is in the process of closing, - * mark parent socket with a flag, so that any residual - * BIGInfo adv reports that arrive before PA sync is - * terminated are not processed anymore. - */ - if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { - parent = iso_get_sock_listen(&hcon->src, - &hcon->dst, - iso_match_conn_sync_handle, - hcon); - - if (parent) { - set_bit(BT_SK_PA_SYNC_TERM, - &iso_pi(parent)->flags); - sock_put(parent); - } - } - iso_sock_clear_timer(sk); iso_chan_del(sk, err); release_sock(sk); @@ -581,22 +552,23 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc, return NULL; } -/* Find socket listening: +/* Find socket in given state: * source bdaddr (Unicast) * destination bdaddr (Broadcast only) * match func - pass NULL to ignore * match func data - pass -1 to ignore * Returns closest match. */ -static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst, - iso_sock_match_t match, void *data) +static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst, + enum bt_sock_state state, + iso_sock_match_t match, void *data) { struct sock *sk = NULL, *sk1 = NULL; read_lock(&iso_sk_list.lock); sk_for_each(sk, &iso_sk_list.head) { - if (sk->sk_state != BT_LISTEN) + if (sk->sk_state != state) continue; /* Match Broadcast destination */ @@ -857,6 +829,7 @@ static struct sock *iso_sock_alloc(struct net *net, struct socket *sock, iso_pi(sk)->src_type = BDADDR_LE_PUBLIC; iso_pi(sk)->qos = default_qos; + iso_pi(sk)->sync_handle = -1; bt_sock_link(&iso_sk_list, sk); return sk; @@ -904,7 +877,6 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr *addr, return -EINVAL; iso_pi(sk)->dst_type = sa->iso_bc->bc_bdaddr_type; - iso_pi(sk)->sync_handle = -1; if (sa->iso_bc->bc_sid > 0x0f) return -EINVAL; @@ -981,7 +953,8 @@ static int iso_sock_bind(struct socket *sock, struct sockaddr *addr, /* Allow the user to bind a PA sync socket to a number * of BISes to sync to. */ - if (sk->sk_state == BT_CONNECT2 && + if ((sk->sk_state == BT_CONNECT2 || + sk->sk_state == BT_CONNECTED) && test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { err = iso_sock_bind_pa_sk(sk, sa, addr_len); goto done; @@ -1285,7 +1258,7 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg, return -ENOTCONN; } - mtu = iso_pi(sk)->conn->hcon->hdev->iso_mtu; + mtu = iso_pi(sk)->conn->hcon->mtu; release_sock(sk); @@ -1393,6 +1366,16 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, } release_sock(sk); return 0; + case BT_CONNECTED: + if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { + iso_conn_big_sync(sk); + sk->sk_state = BT_LISTEN; + release_sock(sk); + return 0; + } + + release_sock(sk); + break; case BT_CONNECT: release_sock(sk); return iso_connect_cis(sk); @@ -1538,7 +1521,9 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname, case BT_ISO_QOS: if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && - sk->sk_state != BT_CONNECT2) { + sk->sk_state != BT_CONNECT2 && + (!test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags) || + sk->sk_state != BT_CONNECTED)) { err = -EINVAL; break; } @@ -1759,7 +1744,7 @@ static void iso_conn_ready(struct iso_conn *conn) struct sock *sk = conn->sk; struct hci_ev_le_big_sync_estabilished *ev = NULL; struct hci_ev_le_pa_sync_established *ev2 = NULL; - struct hci_evt_le_big_info_adv_report *ev3 = NULL; + struct hci_ev_le_per_adv_report *ev3 = NULL; struct hci_conn *hcon; BT_DBG("conn %p", conn); @@ -1777,32 +1762,37 @@ static void iso_conn_ready(struct iso_conn *conn) HCI_EVT_LE_BIG_SYNC_ESTABILISHED); /* Get reference to PA sync parent socket, if it exists */ - parent = iso_get_sock_listen(&hcon->src, - &hcon->dst, - iso_match_pa_sync_flag, NULL); + parent = iso_get_sock(&hcon->src, &hcon->dst, + BT_LISTEN, + iso_match_pa_sync_flag, + NULL); if (!parent && ev) - parent = iso_get_sock_listen(&hcon->src, - &hcon->dst, - iso_match_big, ev); + parent = iso_get_sock(&hcon->src, + &hcon->dst, + BT_LISTEN, + iso_match_big, ev); } else if (test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) { ev2 = hci_recv_event_data(hcon->hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); if (ev2) - parent = iso_get_sock_listen(&hcon->src, - &hcon->dst, - iso_match_sid, ev2); + parent = iso_get_sock(&hcon->src, + &hcon->dst, + BT_LISTEN, + iso_match_sid, ev2); } else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags)) { ev3 = hci_recv_event_data(hcon->hdev, - HCI_EVT_LE_BIG_INFO_ADV_REPORT); + HCI_EV_LE_PER_ADV_REPORT); if (ev3) - parent = iso_get_sock_listen(&hcon->src, - &hcon->dst, - iso_match_sync_handle, ev3); + parent = iso_get_sock(&hcon->src, + &hcon->dst, + BT_LISTEN, + iso_match_sync_handle_pa_report, + ev3); } if (!parent) - parent = iso_get_sock_listen(&hcon->src, - BDADDR_ANY, NULL, NULL); + parent = iso_get_sock(&hcon->src, BDADDR_ANY, + BT_LISTEN, NULL, NULL); if (!parent) return; @@ -1839,7 +1829,6 @@ static void iso_conn_ready(struct iso_conn *conn) if (ev3) { iso_pi(sk)->qos = iso_pi(parent)->qos; - iso_pi(sk)->qos.bcast.encryption = ev3->encryption; hcon->iso_qos = iso_pi(sk)->qos; iso_pi(sk)->bc_num_bis = iso_pi(parent)->bc_num_bis; memcpy(iso_pi(sk)->bc_bis, iso_pi(parent)->bc_bis, ISO_MAX_NUM_BIS); @@ -1923,8 +1912,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) */ ev1 = hci_recv_event_data(hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED); if (ev1) { - sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, iso_match_sid, - ev1); + sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN, + iso_match_sid, ev1); if (sk && !ev1->status) iso_pi(sk)->sync_handle = le16_to_cpu(ev1->handle); @@ -1933,26 +1922,29 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT); if (ev2) { - /* Try to get PA sync listening socket, if it exists */ - sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, - iso_match_pa_sync_flag, NULL); - - if (!sk) { - sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, - iso_match_sync_handle, ev2); - - /* If PA Sync is in process of terminating, - * do not handle any more BIGInfo adv reports. - */ - - if (sk && test_bit(BT_SK_PA_SYNC_TERM, - &iso_pi(sk)->flags)) - return 0; + /* Check if BIGInfo report has already been handled */ + sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_CONNECTED, + iso_match_sync_handle, ev2); + if (sk) { + sock_put(sk); + sk = NULL; + goto done; } + /* Try to get PA sync socket, if it exists */ + sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_CONNECT2, + iso_match_sync_handle, ev2); + if (!sk) + sk = iso_get_sock(&hdev->bdaddr, bdaddr, + BT_LISTEN, + iso_match_sync_handle, + ev2); + if (sk) { int err; + iso_pi(sk)->qos.bcast.encryption = ev2->encryption; + if (ev2->num_bis < iso_pi(sk)->bc_num_bis) iso_pi(sk)->bc_num_bis = ev2->num_bis; @@ -1971,6 +1963,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) } } } + + goto done; } ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT); @@ -1979,8 +1973,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) u8 *base; struct hci_conn *hcon; - sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, - iso_match_sync_handle_pa_report, ev3); + sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN, + iso_match_sync_handle_pa_report, ev3); if (!sk) goto done; @@ -2029,7 +2023,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags) hcon->le_per_adv_data_len = 0; } } else { - sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL); + sk = iso_get_sock(&hdev->bdaddr, BDADDR_ANY, + BT_LISTEN, NULL, NULL); } done: diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9223b1a698e3..5b509b767557 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -457,6 +457,9 @@ struct l2cap_chan *l2cap_chan_create(void) /* Set default lock nesting level */ atomic_set(&chan->nesting, L2CAP_NESTING_NORMAL); + /* Available receive buffer space is initially unknown */ + chan->rx_avail = -1; + write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); write_unlock(&chan_list_lock); @@ -538,6 +541,28 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) } EXPORT_SYMBOL_GPL(l2cap_chan_set_defaults); +static __u16 l2cap_le_rx_credits(struct l2cap_chan *chan) +{ + size_t sdu_len = chan->sdu ? chan->sdu->len : 0; + + if (chan->mps == 0) + return 0; + + /* If we don't know the available space in the receiver buffer, give + * enough credits for a full packet. + */ + if (chan->rx_avail == -1) + return (chan->imtu / chan->mps) + 1; + + /* If we know how much space is available in the receive buffer, give + * out as many credits as would fill the buffer. + */ + if (chan->rx_avail <= sdu_len) + return 0; + + return DIV_ROUND_UP(chan->rx_avail - sdu_len, chan->mps); +} + static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits) { chan->sdu = NULL; @@ -546,8 +571,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits) chan->tx_credits = tx_credits; /* Derive MPS from connection MTU to stop HCI fragmentation */ chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE); - /* Give enough credits for a full packet */ - chan->rx_credits = (chan->imtu / chan->mps) + 1; + chan->rx_credits = l2cap_le_rx_credits(chan); skb_queue_head_init(&chan->tx_q); } @@ -559,7 +583,7 @@ static void l2cap_ecred_init(struct l2cap_chan *chan, u16 tx_credits) /* L2CAP implementations shall support a minimum MPS of 64 octets */ if (chan->mps < L2CAP_ECRED_MIN_MPS) { chan->mps = L2CAP_ECRED_MIN_MPS; - chan->rx_credits = (chan->imtu / chan->mps) + 1; + chan->rx_credits = l2cap_le_rx_credits(chan); } } @@ -1260,7 +1284,7 @@ static void l2cap_le_connect(struct l2cap_chan *chan) struct l2cap_ecred_conn_data { struct { - struct l2cap_ecred_conn_req req; + struct l2cap_ecred_conn_req_hdr req; __le16 scid[5]; } __packed pdu; struct l2cap_chan *chan; @@ -3740,7 +3764,7 @@ static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data) struct l2cap_ecred_rsp_data { struct { - struct l2cap_ecred_conn_rsp rsp; + struct l2cap_ecred_conn_rsp_hdr rsp; __le16 scid[L2CAP_ECRED_MAX_CID]; } __packed pdu; int count; @@ -3749,6 +3773,8 @@ struct l2cap_ecred_rsp_data { static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data) { struct l2cap_ecred_rsp_data *rsp = data; + struct l2cap_ecred_conn_rsp *rsp_flex = + container_of(&rsp->pdu.rsp, struct l2cap_ecred_conn_rsp, hdr); if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags)) return; @@ -3758,7 +3784,7 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data) /* Include all channels pending with the same ident */ if (!rsp->pdu.rsp.result) - rsp->pdu.rsp.dcid[rsp->count++] = cpu_to_le16(chan->scid); + rsp_flex->dcid[rsp->count++] = cpu_to_le16(chan->scid); else l2cap_chan_del(chan, ECONNRESET); } @@ -3906,7 +3932,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, } static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, - u8 *data, u8 rsp_code, u8 amp_id) + u8 *data, u8 rsp_code) { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; @@ -3985,17 +4011,8 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, status = L2CAP_CS_AUTHOR_PEND; chan->ops->defer(chan); } else { - /* Force pending result for AMP controllers. - * The connection will succeed after the - * physical link is up. - */ - if (amp_id == AMP_ID_BREDR) { - l2cap_state_change(chan, BT_CONFIG); - result = L2CAP_CR_SUCCESS; - } else { - l2cap_state_change(chan, BT_CONNECT2); - result = L2CAP_CR_PEND; - } + l2cap_state_change(chan, BT_CONNECT2); + result = L2CAP_CR_PEND; status = L2CAP_CS_NO_INFO; } } else { @@ -4060,7 +4077,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn, mgmt_device_connected(hdev, hcon, NULL, 0); hci_dev_unlock(hdev); - l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0); + l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP); return 0; } @@ -4996,10 +5013,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, u8 *data) { struct l2cap_ecred_conn_req *req = (void *) data; - struct { - struct l2cap_ecred_conn_rsp rsp; - __le16 dcid[L2CAP_ECRED_MAX_CID]; - } __packed pdu; + DEFINE_RAW_FLEX(struct l2cap_ecred_conn_rsp, pdu, dcid, L2CAP_ECRED_MAX_CID); struct l2cap_chan *chan, *pchan; u16 mtu, mps; __le16 psm; @@ -5018,7 +5032,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, cmd_len -= sizeof(*req); num_scid = cmd_len / sizeof(u16); - if (num_scid > ARRAY_SIZE(pdu.dcid)) { + if (num_scid > L2CAP_ECRED_MAX_CID) { result = L2CAP_CR_LE_INVALID_PARAMS; goto response; } @@ -5047,7 +5061,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, BT_DBG("psm 0x%2.2x mtu %u mps %u", __le16_to_cpu(psm), mtu, mps); - memset(&pdu, 0, sizeof(pdu)); + memset(pdu, 0, sizeof(*pdu)); /* Check if we have socket listening on psm */ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src, @@ -5073,8 +5087,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, BT_DBG("scid[%d] 0x%4.4x", i, scid); - pdu.dcid[i] = 0x0000; - len += sizeof(*pdu.dcid); + pdu->dcid[i] = 0x0000; + len += sizeof(*pdu->dcid); /* Check for valid dynamic CID range */ if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) { @@ -5108,13 +5122,13 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, l2cap_ecred_init(chan, __le16_to_cpu(req->credits)); /* Init response */ - if (!pdu.rsp.credits) { - pdu.rsp.mtu = cpu_to_le16(chan->imtu); - pdu.rsp.mps = cpu_to_le16(chan->mps); - pdu.rsp.credits = cpu_to_le16(chan->rx_credits); + if (!pdu->credits) { + pdu->mtu = cpu_to_le16(chan->imtu); + pdu->mps = cpu_to_le16(chan->mps); + pdu->credits = cpu_to_le16(chan->rx_credits); } - pdu.dcid[i] = cpu_to_le16(chan->scid); + pdu->dcid[i] = cpu_to_le16(chan->scid); __set_chan_timer(chan, chan->ops->get_sndtimeo(chan)); @@ -5136,13 +5150,13 @@ unlock: l2cap_chan_put(pchan); response: - pdu.rsp.result = cpu_to_le16(result); + pdu->result = cpu_to_le16(result); if (defer) return 0; l2cap_send_cmd(conn, cmd->ident, L2CAP_ECRED_CONN_RSP, - sizeof(pdu.rsp) + len, &pdu); + sizeof(*pdu) + len, pdu); return 0; } @@ -6241,7 +6255,7 @@ static int l2cap_finish_move(struct l2cap_chan *chan) BT_DBG("chan %p", chan); chan->rx_state = L2CAP_RX_STATE_RECV; - chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + chan->conn->mtu = chan->conn->hcon->mtu; return l2cap_resegment(chan); } @@ -6308,7 +6322,7 @@ static int l2cap_rx_state_wait_f(struct l2cap_chan *chan, */ chan->next_tx_seq = control->reqseq; chan->unacked_frames = 0; - chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu; + chan->conn->mtu = chan->conn->hcon->mtu; err = l2cap_resegment(chan); @@ -6513,9 +6527,7 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; struct l2cap_le_credits pkt; - u16 return_credits; - - return_credits = (chan->imtu / chan->mps) + 1; + u16 return_credits = l2cap_le_rx_credits(chan); if (chan->rx_credits >= return_credits) return; @@ -6534,6 +6546,19 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt); } +void l2cap_chan_rx_avail(struct l2cap_chan *chan, ssize_t rx_avail) +{ + if (chan->rx_avail == rx_avail) + return; + + BT_DBG("chan %p has %zd bytes avail for rx", chan, rx_avail); + + chan->rx_avail = rx_avail; + + if (chan->state == BT_CONNECTED) + l2cap_chan_le_send_credits(chan); +} + static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb) { int err; @@ -6543,6 +6568,12 @@ static int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb) /* Wait recv to confirm reception before updating the credits */ err = chan->ops->recv(chan, skb); + if (err < 0 && chan->rx_avail != -1) { + BT_ERR("Queueing received LE L2CAP data failed"); + l2cap_send_disconn_req(chan, ECONNRESET); + return err; + } + /* Update credits whenever an SDU is received */ l2cap_chan_le_send_credits(chan); @@ -6565,7 +6596,8 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) } chan->rx_credits--; - BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits); + BT_DBG("chan %p: rx_credits %u -> %u", + chan, chan->rx_credits + 1, chan->rx_credits); /* Update if remote had run out of credits, this should only happens * if the remote is not using the entire MPS. @@ -6848,18 +6880,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon) BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); - switch (hcon->type) { - case LE_LINK: - if (hcon->hdev->le_mtu) { - conn->mtu = hcon->hdev->le_mtu; - break; - } - fallthrough; - default: - conn->mtu = hcon->hdev->acl_mtu; - break; - } - + conn->mtu = hcon->mtu; conn->feat_mask = 0; conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS; @@ -7113,14 +7134,11 @@ EXPORT_SYMBOL_GPL(l2cap_chan_connect); static void l2cap_ecred_reconfigure(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; - struct { - struct l2cap_ecred_reconf_req req; - __le16 scid; - } pdu; + DEFINE_RAW_FLEX(struct l2cap_ecred_reconf_req, pdu, scid, 1); - pdu.req.mtu = cpu_to_le16(chan->imtu); - pdu.req.mps = cpu_to_le16(chan->mps); - pdu.scid = cpu_to_le16(chan->scid); + pdu->mtu = cpu_to_le16(chan->imtu); + pdu->mps = cpu_to_le16(chan->mps); + pdu->scid[0] = cpu_to_le16(chan->scid); chan->ident = l2cap_get_ident(conn); @@ -7464,10 +7482,6 @@ void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) struct l2cap_conn *conn = hcon->l2cap_data; int len; - /* For AMP controller do not create l2cap conn */ - if (!conn && hcon->hdev->dev_type != HCI_PRIMARY) - goto drop; - if (!conn) conn = l2cap_conn_add(hcon); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 5cc83f906c12..8645461d45e8 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1131,6 +1131,34 @@ static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, return err; } +static void l2cap_publish_rx_avail(struct l2cap_chan *chan) +{ + struct sock *sk = chan->data; + ssize_t avail = sk->sk_rcvbuf - atomic_read(&sk->sk_rmem_alloc); + int expected_skbs, skb_overhead; + + if (avail <= 0) { + l2cap_chan_rx_avail(chan, 0); + return; + } + + if (!chan->mps) { + l2cap_chan_rx_avail(chan, -1); + return; + } + + /* Correct available memory by estimated sk_buff overhead. + * This is significant due to small transfer sizes. However, accept + * at least one full packet if receive space is non-zero. + */ + expected_skbs = DIV_ROUND_UP(avail, chan->mps); + skb_overhead = expected_skbs * sizeof(struct sk_buff); + if (skb_overhead < avail) + l2cap_chan_rx_avail(chan, avail - skb_overhead); + else + l2cap_chan_rx_avail(chan, -1); +} + static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -1167,28 +1195,33 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, else err = bt_sock_recvmsg(sock, msg, len, flags); - if (pi->chan->mode != L2CAP_MODE_ERTM) + if (pi->chan->mode != L2CAP_MODE_ERTM && + pi->chan->mode != L2CAP_MODE_LE_FLOWCTL && + pi->chan->mode != L2CAP_MODE_EXT_FLOWCTL) return err; - /* Attempt to put pending rx data in the socket buffer */ - lock_sock(sk); - if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state)) - goto done; + l2cap_publish_rx_avail(pi->chan); - if (pi->rx_busy_skb) { - if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb)) - pi->rx_busy_skb = NULL; - else + /* Attempt to put pending rx data in the socket buffer */ + while (!list_empty(&pi->rx_busy)) { + struct l2cap_rx_busy *rx_busy = + list_first_entry(&pi->rx_busy, + struct l2cap_rx_busy, + list); + if (__sock_queue_rcv_skb(sk, rx_busy->skb) < 0) goto done; + list_del(&rx_busy->list); + kfree(rx_busy); } /* Restore data flow when half of the receive buffer is * available. This avoids resending large numbers of * frames. */ - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) + if (test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state) && + atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) l2cap_chan_busy(pi->chan, 0); done: @@ -1449,17 +1482,20 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { struct sock *sk = chan->data; + struct l2cap_pinfo *pi = l2cap_pi(sk); int err; lock_sock(sk); - if (l2cap_pi(sk)->rx_busy_skb) { + if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) { err = -ENOMEM; goto done; } if (chan->mode != L2CAP_MODE_ERTM && - chan->mode != L2CAP_MODE_STREAMING) { + chan->mode != L2CAP_MODE_STREAMING && + chan->mode != L2CAP_MODE_LE_FLOWCTL && + chan->mode != L2CAP_MODE_EXT_FLOWCTL) { /* Even if no filter is attached, we could potentially * get errors from security modules, etc. */ @@ -1470,7 +1506,9 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) err = __sock_queue_rcv_skb(sk, skb); - /* For ERTM, handle one skb that doesn't fit into the recv + l2cap_publish_rx_avail(chan); + + /* For ERTM and LE, handle a skb that doesn't fit into the recv * buffer. This is important to do because the data frames * have already been acked, so the skb cannot be discarded. * @@ -1479,8 +1517,18 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) * acked and reassembled until there is buffer space * available. */ - if (err < 0 && chan->mode == L2CAP_MODE_ERTM) { - l2cap_pi(sk)->rx_busy_skb = skb; + if (err < 0 && + (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_LE_FLOWCTL || + chan->mode == L2CAP_MODE_EXT_FLOWCTL)) { + struct l2cap_rx_busy *rx_busy = + kmalloc(sizeof(*rx_busy), GFP_KERNEL); + if (!rx_busy) { + err = -ENOMEM; + goto done; + } + rx_busy->skb = skb; + list_add_tail(&rx_busy->list, &pi->rx_busy); l2cap_chan_busy(chan, 1); err = 0; } @@ -1706,6 +1754,8 @@ static const struct l2cap_ops l2cap_chan_ops = { static void l2cap_sock_destruct(struct sock *sk) { + struct l2cap_rx_busy *rx_busy, *next; + BT_DBG("sk %p", sk); if (l2cap_pi(sk)->chan) { @@ -1713,9 +1763,10 @@ static void l2cap_sock_destruct(struct sock *sk) l2cap_chan_put(l2cap_pi(sk)->chan); } - if (l2cap_pi(sk)->rx_busy_skb) { - kfree_skb(l2cap_pi(sk)->rx_busy_skb); - l2cap_pi(sk)->rx_busy_skb = NULL; + list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) { + kfree_skb(rx_busy->skb); + list_del(&rx_busy->list); + kfree(rx_busy); } skb_queue_purge(&sk->sk_receive_queue); @@ -1799,6 +1850,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->data = sk; chan->ops = &l2cap_chan_ops; + + l2cap_publish_rx_avail(chan); } static struct proto l2cap_proto = { @@ -1820,6 +1873,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, sk->sk_destruct = l2cap_sock_destruct; sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; + INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy); + chan = l2cap_chan_create(); if (!chan) { sk_free(sk); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 965f621ef865..80f220b7e19d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -443,8 +443,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, count = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (d->dev_type == HCI_PRIMARY && - !hci_dev_test_flag(d, HCI_UNCONFIGURED)) + if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) count++; } @@ -468,8 +467,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) continue; - if (d->dev_type == HCI_PRIMARY && - !hci_dev_test_flag(d, HCI_UNCONFIGURED)) { + if (!hci_dev_test_flag(d, HCI_UNCONFIGURED)) { rp->index[count++] = cpu_to_le16(d->id); bt_dev_dbg(hdev, "Added hci%u", d->id); } @@ -503,8 +501,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, count = 0; list_for_each_entry(d, &hci_dev_list, list) { - if (d->dev_type == HCI_PRIMARY && - hci_dev_test_flag(d, HCI_UNCONFIGURED)) + if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) count++; } @@ -528,8 +525,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) continue; - if (d->dev_type == HCI_PRIMARY && - hci_dev_test_flag(d, HCI_UNCONFIGURED)) { + if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) { rp->index[count++] = cpu_to_le16(d->id); bt_dev_dbg(hdev, "Added hci%u", d->id); } @@ -561,10 +557,8 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, read_lock(&hci_dev_list_lock); count = 0; - list_for_each_entry(d, &hci_dev_list, list) { - if (d->dev_type == HCI_PRIMARY || d->dev_type == HCI_AMP) - count++; - } + list_for_each_entry(d, &hci_dev_list, list) + count++; rp = kmalloc(struct_size(rp, entry, count), GFP_ATOMIC); if (!rp) { @@ -585,16 +579,10 @@ static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev, if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks)) continue; - if (d->dev_type == HCI_PRIMARY) { - if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) - rp->entry[count].type = 0x01; - else - rp->entry[count].type = 0x00; - } else if (d->dev_type == HCI_AMP) { - rp->entry[count].type = 0x02; - } else { - continue; - } + if (hci_dev_test_flag(d, HCI_UNCONFIGURED)) + rp->entry[count].type = 0x01; + else + rp->entry[count].type = 0x00; rp->entry[count].bus = d->bus; rp->entry[count++].index = cpu_to_le16(d->id); @@ -9331,23 +9319,14 @@ void mgmt_index_added(struct hci_dev *hdev) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) return; - switch (hdev->dev_type) { - case HCI_PRIMARY: - if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { - mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, - NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS); - ev.type = 0x01; - } else { - mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, - HCI_MGMT_INDEX_EVENTS); - ev.type = 0x00; - } - break; - case HCI_AMP: - ev.type = 0x02; - break; - default: - return; + if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { + mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, + HCI_MGMT_UNCONF_INDEX_EVENTS); + ev.type = 0x01; + } else { + mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, + HCI_MGMT_INDEX_EVENTS); + ev.type = 0x00; } ev.bus = hdev->bus; @@ -9364,25 +9343,16 @@ void mgmt_index_removed(struct hci_dev *hdev) if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) return; - switch (hdev->dev_type) { - case HCI_PRIMARY: - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); + mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); - if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { - mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, - NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS); - ev.type = 0x01; - } else { - mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, - HCI_MGMT_INDEX_EVENTS); - ev.type = 0x00; - } - break; - case HCI_AMP: - ev.type = 0x02; - break; - default: - return; + if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { + mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, + HCI_MGMT_UNCONF_INDEX_EVENTS); + ev.type = 0x01; + } else { + mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, + HCI_MGMT_INDEX_EVENTS); + ev.type = 0x00; } ev.bus = hdev->bus; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index e0ad30862ee4..71d36582d4ef 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -126,7 +126,6 @@ static void sco_sock_clear_timer(struct sock *sk) /* ---- SCO connections ---- */ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) { - struct hci_dev *hdev = hcon->hdev; struct sco_conn *conn = hcon->sco_data; if (conn) { @@ -144,9 +143,10 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) hcon->sco_data = conn; conn->hcon = hcon; + conn->mtu = hcon->mtu; - if (hdev->sco_mtu > 0) - conn->mtu = hdev->sco_mtu; + if (hcon->mtu > 0) + conn->mtu = hcon->mtu; else conn->mtu = 60; |