Commit 3db34747 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'for-net-next-2023-08-24' of...

Merge tag 'for-net-next-2023-08-24' 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:

 - Introduce HCI_QUIRK_BROKEN_LE_CODED
 - Add support for PA/BIG sync
 - Add support for NXP IW624 chipset
 - Add support for Qualcomm WCN7850

* tag 'for-net-next-2023-08-24' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next:
  Bluetooth: btusb: Do not call kfree_skb() under spin_lock_irqsave()
  Bluetooth: btusb: Fix quirks table naming
  Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED
  Bluetooth: btintel: Send new command for PPAG
  Bluetooth: ISO: Add support for periodic adv reports processing
  Bluetooth: hci_conn: fail SCO/ISO via hci_conn_failed if ACL gone early
  Bluetooth: hci_core: Fix missing instances using HCI_MAX_AD_LENGTH
  Bluetooth: ISO: Use defer setup to separate PA sync and BIG sync
  Bluetooth: qca: add support for WCN7850
  Bluetooth: qca: use switch case for soc type behavior
  dt-bindings: net: bluetooth: qualcomm: document WCN7850 chipset
  Bluetooth: hci_conn: Fix sending BT_HCI_CMD_LE_CREATE_CONN_CANCEL
  Bluetooth: hci_sync: Fix UAF in hci_disconnect_all_sync
  Bluetooth: btnxpuart: Improve inband Independent Reset handling
  Bluetooth: btnxpuart: Add support for IW624 chipset
  Bluetooth: btnxpuart: Remove check for CTS low after FW download
====================

Link: https://lore.kernel.org/r/20230824201458.2577-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents b38460bc 2a05334d
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ properties:
      - qcom,qca6390-bt
      - qcom,wcn6750-bt
      - qcom,wcn6855-bt
      - qcom,wcn7850-bt

  enable-gpios:
    maxItems: 1
@@ -58,6 +59,9 @@ properties:
  vddaon-supply:
    description: VDD_AON supply regulator handle

  vdddig-supply:
    description: VDD_DIG supply regulator handle

  vddbtcxmx-supply:
    description: VDD_BT_CXMX supply regulator handle

@@ -73,6 +77,9 @@ properties:
  vddrfa1p2-supply:
    description: VDD_RFA_1P2 supply regulator handle

  vddrfa1p9-supply:
    description: VDD_RFA_1P9 supply regulator handle

  vddrfa2p2-supply:
    description: VDD_RFA_2P2 supply regulator handle

@@ -157,6 +164,22 @@ allOf:
        - vddrfa0p8-supply
        - vddrfa1p2-supply
        - vddrfa1p7-supply
  - if:
      properties:
        compatible:
          contains:
            enum:
              - qcom,wcn7850-bt
    then:
      required:
        - enable-gpios
        - swctrl-gpios
        - vddio-supply
        - vddaon-supply
        - vdddig-supply
        - vddrfa0p8-supply
        - vddrfa1p2-supply
        - vddrfa1p9-supply

examples:
  - |
+22 −9
Original line number Diff line number Diff line
@@ -2401,7 +2401,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
{
	struct btintel_ppag ppag;
	struct sk_buff *skb;
	struct btintel_loc_aware_reg ppag_cmd;
	struct hci_ppag_enable_cmd ppag_cmd;
	acpi_handle handle;

	/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
@@ -2409,6 +2409,8 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
	case 0x504:     /* Hrp2 */
	case 0x202:     /* Jfp2 */
	case 0x201:     /* Jfp1 */
		bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)",
			   ver->cnvr_top & 0xFFF);
		return;
	}

@@ -2434,24 +2436,29 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
	}

	if (ppag.domain != 0x12) {
		bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
		bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
		return;
	}

	/* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
	if (!(ppag.mode & BIT(0))) {
		bt_dev_dbg(hdev, "PPAG-BT: disabled");
	/* PPAG mode
	 * BIT 0 : 0 Disabled in EU
	 *         1 Enabled in EU
	 * BIT 1 : 0 Disabled in China
	 *         1 Enabled in China
	 */
	if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
		bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
		return;
	}

	ppag_cmd.mcc = cpu_to_le32(0);
	ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */
	ppag_cmd.delta = cpu_to_le32(0);
	skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
	ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);

	skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
	if (IS_ERR(skb)) {
		bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
		return;
	}
	bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
	kfree_skb(skb);
}

@@ -2780,6 +2787,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
			set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
				&hdev->quirks);

			/* These variants don't seem to support LE Coded PHY */
			set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);

			/* Setup MSFT Extension support */
			btintel_set_msft_opcode(hdev, ver.hw_variant);

@@ -2851,6 +2861,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
		 */
		set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);

		/* These variants don't seem to support LE Coded PHY */
		set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);

		/* Set Valid LE States quirk */
		set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);

+3 −4
Original line number Diff line number Diff line
@@ -137,10 +137,9 @@ struct intel_offload_use_cases {
	__u8	preset[8];
} __packed;

struct btintel_loc_aware_reg {
	__le32 mcc;
	__le32 sel;
	__le32 delta;
#define INTEL_OP_PPAG_CMD		0xFE0B
struct hci_ppag_enable_cmd {
	__le32	ppag_enable_flags;
} __packed;

#define INTEL_TLV_TYPE_ID		0x01
+127 −89
Original line number Diff line number Diff line
@@ -28,12 +28,18 @@
#define BTNXPUART_FW_DOWNLOADING	2
#define BTNXPUART_CHECK_BOOT_SIGNATURE	3
#define BTNXPUART_SERDEV_OPEN		4
#define BTNXPUART_IR_IN_PROGRESS	5

/* NXP HW err codes */
#define BTNXPUART_IR_HW_ERR		0xb0

#define FIRMWARE_W8987		"nxp/uartuart8987_bt.bin"
#define FIRMWARE_W8997		"nxp/uartuart8997_bt_v4.bin"
#define FIRMWARE_W9098		"nxp/uartuart9098_bt_v1.bin"
#define FIRMWARE_IW416		"nxp/uartiw416_bt_v0.bin"
#define FIRMWARE_IW612		"nxp/uartspi_n61x_v1.bin.se"
#define FIRMWARE_IW624		"nxp/uartiw624_bt.bin"
#define FIRMWARE_SECURE_IW624	"nxp/uartiw624_bt.bin.se"
#define FIRMWARE_AW693		"nxp/uartaw693_bt.bin"
#define FIRMWARE_SECURE_AW693	"nxp/uartaw693_bt.bin.se"
#define FIRMWARE_HELPER		"nxp/helper_uart_3000000.bin"
@@ -41,6 +47,8 @@
#define CHIP_ID_W9098		0x5c03
#define CHIP_ID_IW416		0x7201
#define CHIP_ID_IW612		0x7601
#define CHIP_ID_IW624a		0x8000
#define CHIP_ID_IW624c		0x8001
#define CHIP_ID_AW693		0x8200

#define FW_SECURE_MASK		0xc0
@@ -152,6 +160,7 @@ struct btnxpuart_dev {
	u32 fw_v1_sent_bytes;
	u32 fw_v3_offset_correction;
	u32 fw_v1_expected_len;
	u32 boot_reg_offset;
	wait_queue_head_t fw_dnld_done_wait_q;
	wait_queue_head_t check_boot_sign_wait_q;

@@ -375,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t)
	}
}

static int ps_init_work(struct hci_dev *hdev)
static void ps_setup(struct hci_dev *hdev)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	struct ps_data *psdata = &nxpdev->psdata;

	psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
	psdata->ps_state = PS_STATE_AWAKE;
	psdata->target_ps_mode = DEFAULT_PS_MODE;
	psdata->hdev = hdev;
	psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
	psdata->c2h_wakeup_gpio = 0xff;

	switch (DEFAULT_H2C_WAKEUP_MODE) {
	case WAKEUP_METHOD_DTR:
		psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
		break;
	case WAKEUP_METHOD_BREAK:
	default:
		psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
		break;
	}
	psdata->cur_psmode = PS_MODE_DISABLE;
	psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
	INIT_WORK(&psdata->work, ps_work_func);

	return 0;
}

static void ps_init_timer(struct hci_dev *hdev)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	struct ps_data *psdata = &nxpdev->psdata;

	timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
}

@@ -510,19 +493,31 @@ static void ps_init(struct hci_dev *hdev)
	serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0);
	usleep_range(5000, 10000);

	switch (psdata->h2c_wakeupmode) {
	psdata->ps_state = PS_STATE_AWAKE;
	psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
	psdata->c2h_wakeup_gpio = 0xff;

	psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
	psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
	switch (DEFAULT_H2C_WAKEUP_MODE) {
	case WAKEUP_METHOD_DTR:
		psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
		serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
		serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
		break;
	case WAKEUP_METHOD_BREAK:
	default:
		psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
		serdev_device_break_ctl(nxpdev->serdev, -1);
		usleep_range(5000, 10000);
		serdev_device_break_ctl(nxpdev->serdev, 0);
		usleep_range(5000, 10000);
		break;
	}

	psdata->cur_psmode = PS_MODE_DISABLE;
	psdata->target_ps_mode = DEFAULT_PS_MODE;

	if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
		hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
	if (psdata->cur_psmode != psdata->target_ps_mode)
@@ -538,6 +533,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
	nxpdev->fw_dnld_v1_offset = 0;
	nxpdev->fw_v1_sent_bytes = 0;
	nxpdev->fw_v1_expected_len = HDR_LEN;
	nxpdev->boot_reg_offset = 0;
	nxpdev->fw_v3_offset_correction = 0;
	nxpdev->baudrate_changed = false;
	nxpdev->timeout_changed = false;
@@ -547,7 +543,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
	serdev_device_set_flow_control(nxpdev->serdev, false);
	nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE;

	/* Wait till FW is downloaded and CTS becomes low */
	/* Wait till FW is downloaded */
	err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q,
					       !test_bit(BTNXPUART_FW_DOWNLOADING,
							 &nxpdev->tx_state),
@@ -558,16 +554,11 @@ static int nxp_download_firmware(struct hci_dev *hdev)
	}

	serdev_device_set_flow_control(nxpdev->serdev, true);
	err = serdev_device_wait_for_cts(nxpdev->serdev, 1, 60000);
	if (err < 0) {
		bt_dev_err(hdev, "CTS is still high. FW Download failed.");
		return err;
	}
	release_firmware(nxpdev->fw);
	memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));

	/* Allow the downloaded FW to initialize */
	usleep_range(800 * USEC_PER_MSEC, 1 * USEC_PER_SEC);
	msleep(1200);

	return 0;
}
@@ -591,6 +582,12 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	struct nxp_bootloader_cmd nxp_cmd5;
	struct uart_config uart_config;
	u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset;
	u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset;
	u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset;
	u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset;
	u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset;
	u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset;

	if (req_len == sizeof(nxp_cmd5)) {
		nxp_cmd5.header = __cpu_to_le32(5);
@@ -603,17 +600,17 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
		serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5));
		nxpdev->fw_v3_offset_correction += req_len;
	} else if (req_len == sizeof(uart_config)) {
		uart_config.clkdiv.address = __cpu_to_le32(CLKDIVADDR);
		uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr);
		uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
		uart_config.uartdiv.address = __cpu_to_le32(UARTDIVADDR);
		uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr);
		uart_config.uartdiv.value = __cpu_to_le32(1);
		uart_config.mcr.address = __cpu_to_le32(UARTMCRADDR);
		uart_config.mcr.address = __cpu_to_le32(uartmcraddr);
		uart_config.mcr.value = __cpu_to_le32(MCR);
		uart_config.re_init.address = __cpu_to_le32(UARTREINITADDR);
		uart_config.re_init.address = __cpu_to_le32(uartreinitaddr);
		uart_config.re_init.value = __cpu_to_le32(INIT);
		uart_config.icr.address = __cpu_to_le32(UARTICRADDR);
		uart_config.icr.address = __cpu_to_le32(uarticraddr);
		uart_config.icr.value = __cpu_to_le32(ICR);
		uart_config.fcr.address = __cpu_to_le32(UARTFCRADDR);
		uart_config.fcr.address = __cpu_to_le32(uartfcraddr);
		uart_config.fcr.value = __cpu_to_le32(FCR);
		/* FW expects swapped CRC bytes */
		uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config,
@@ -702,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb)
		goto free_skb;

	chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp);
	if (chip_id == 0xffff) {
	if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) {
		nxpdev->fw_dnld_v1_offset = 0;
		nxpdev->fw_v1_sent_bytes = 0;
		nxpdev->fw_v1_expected_len = HDR_LEN;
@@ -827,6 +824,7 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
					 u8 loader_ver)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	char *fw_name = NULL;

	switch (chipid) {
@@ -839,6 +837,16 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
	case CHIP_ID_IW612:
		fw_name = FIRMWARE_IW612;
		break;
	case CHIP_ID_IW624a:
	case CHIP_ID_IW624c:
		nxpdev->boot_reg_offset = 1;
		if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
			fw_name = FIRMWARE_IW624;
		else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
			fw_name = FIRMWARE_SECURE_IW624;
		else
			bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
		break;
	case CHIP_ID_AW693:
		if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
			fw_name = FIRMWARE_AW693;
@@ -969,44 +977,12 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
	return 0;
}

static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	struct sk_buff *skb;
	u8 *status;
	u8 pcmd = 0;
	int err = 0;

	skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	status = skb_pull_data(skb, 1);
	if (!status || *status)
		goto free_skb;

	set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
	err = nxp_download_firmware(hdev);
	if (err < 0)
		goto free_skb;
	serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
	nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
	if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
		nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
		nxp_set_baudrate_cmd(hdev, NULL);
	}
	hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
	hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL);

free_skb:
	kfree_skb(skb);
	return err;
}

/* NXP protocol */
static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
{
	serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
	if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
		serdev_device_set_flow_control(nxpdev->serdev, false);
	else
		serdev_device_set_flow_control(nxpdev->serdev, true);
	set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state);

@@ -1016,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
					       msecs_to_jiffies(1000));
}

static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
{
	static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
					0x01, BTNXPUART_IR_HW_ERR };
	struct sk_buff *skb;

	skb = bt_skb_alloc(3, GFP_ATOMIC);
	if (!skb)
		return -ENOMEM;

	hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
	skb_put_data(skb, ir_hw_err, 3);

	/* Inject Hardware Error to upper stack */
	return hci_recv_frame(hdev, skb);
}

/* NXP protocol */
static int nxp_setup(struct hci_dev *hdev)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	int err = 0;

	set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
	init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
	init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);

	if (nxp_check_boot_sign(nxpdev)) {
		bt_dev_dbg(hdev, "Need FW Download.");
		err = nxp_download_firmware(hdev);
@@ -1035,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev)
		clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
	}

	device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
				 &nxpdev->fw_init_baudrate);
	if (!nxpdev->fw_init_baudrate)
		nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
	serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
	nxpdev->current_baudrate = nxpdev->fw_init_baudrate;

@@ -1049,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev)

	ps_init(hdev);

	if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
		hci_dev_clear_flag(hdev, HCI_SETUP);

	return 0;
}

static void nxp_hw_err(struct hci_dev *hdev, u8 code)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);

	switch (code) {
	case BTNXPUART_IR_HW_ERR:
		set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state);
		hci_dev_set_flag(hdev, HCI_SETUP);
		break;
	default:
		break;
	}
}

static int nxp_shutdown(struct hci_dev *hdev)
{
	struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
	struct sk_buff *skb;
	u8 *status;
	u8 pcmd = 0;

	if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) {
		skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
		if (IS_ERR(skb))
			return PTR_ERR(skb);

		status = skb_pull_data(skb, 1);
		if (status) {
			serdev_device_set_flow_control(nxpdev->serdev, false);
			set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
		}
		kfree_skb(skb);
	}

	return 0;
}

@@ -1256,6 +1282,7 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
		nxpdev->rx_skb = NULL;
		return err;
	}
	if (!is_fw_downloading(nxpdev))
		nxpdev->hdev->stat.byte_rx += count;
	return count;
}
@@ -1289,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
	INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work);
	skb_queue_head_init(&nxpdev->txq);

	init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
	init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);

	device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
				 &nxpdev->fw_init_baudrate);
	if (!nxpdev->fw_init_baudrate)
		nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;

	set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);

	crc8_populate_msb(crc8_table, POLYNOMIAL8);

	/* Initialize and register HCI device */
@@ -1309,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
	hdev->flush = btnxpuart_flush;
	hdev->setup = nxp_setup;
	hdev->send  = nxp_enqueue;
	hdev->hw_error = nxp_hw_err;
	hdev->shutdown = nxp_shutdown;
	SET_HCIDEV_DEV(hdev, &serdev->dev);

	if (hci_register_dev(hdev) < 0) {
@@ -1317,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
		return -ENODEV;
	}

	ps_init_work(hdev);
	ps_init_timer(hdev);
	ps_setup(hdev);

	return 0;
}
+67 −30
Original line number Diff line number Diff line
@@ -604,26 +604,38 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,

	/* Download rampatch file */
	config.type = TLV_TYPE_PATCH;
	if (soc_type == QCA_WCN3988) {
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/apbtfw%02x.tlv", rom_ver);
	} else if (qca_is_wcn399x(soc_type)) {
	switch (soc_type) {
	case QCA_WCN3990:
	case QCA_WCN3991:
	case QCA_WCN3998:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/crbtfw%02x.tlv", rom_ver);
	} else if (soc_type == QCA_QCA6390) {
		break;
	case QCA_WCN3988:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/apbtfw%02x.tlv", rom_ver);
		break;
	case QCA_QCA6390:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/htbtfw%02x.tlv", rom_ver);
	} else if (soc_type == QCA_WCN6750) {
		break;
	case QCA_WCN6750:
		/* Choose mbn file by default.If mbn file is not found
		 * then choose tlv file
		 */
		config.type = ELF_TYPE_PATCH;
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/msbtfw%02x.mbn", rom_ver);
	} else if (soc_type == QCA_WCN6855) {
		break;
	case QCA_WCN6855:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/hpbtfw%02x.tlv", rom_ver);
	} else {
		break;
	case QCA_WCN7850:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/hmtbtfw%02x.tlv", rom_ver);
		break;
	default:
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/rampatch_%08x.bin", soc_ver);
	}
@@ -639,13 +651,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,

	/* Download NVM configuration */
	config.type = TLV_TYPE_NVM;
	if (firmware_name)
	if (firmware_name) {
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/%s", firmware_name);
	else if (soc_type == QCA_WCN3988)
		snprintf(config.fwname, sizeof(config.fwname),
			 "qca/apnv%02x.bin", rom_ver);
	else if (qca_is_wcn399x(soc_type)) {
	} else {
		switch (soc_type) {
		case QCA_WCN3990:
		case QCA_WCN3991:
		case QCA_WCN3998:
			if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
				snprintf(config.fwname, sizeof(config.fwname),
					 "qca/crnv%02xu.bin", rom_ver);
@@ -653,19 +666,33 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
				snprintf(config.fwname, sizeof(config.fwname),
					 "qca/crnv%02x.bin", rom_ver);
			}
	}
	else if (soc_type == QCA_QCA6390)
			break;
		case QCA_WCN3988:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/apnv%02x.bin", rom_ver);
			break;
		case QCA_QCA6390:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/htnv%02x.bin", rom_ver);
	else if (soc_type == QCA_WCN6750)
			break;
		case QCA_WCN6750:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/msnv%02x.bin", rom_ver);
	else if (soc_type == QCA_WCN6855)
			break;
		case QCA_WCN6855:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/hpnv%02x.bin", rom_ver);
	else
			break;
		case QCA_WCN7850:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/hmtnv%02x.bin", rom_ver);
			break;

		default:
			snprintf(config.fwname, sizeof(config.fwname),
				 "qca/nvm_%08x.bin", soc_ver);
		}
	}

	err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
	if (err < 0) {
@@ -673,16 +700,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
		return err;
	}

	if (soc_type >= QCA_WCN3991) {
	switch (soc_type) {
	case QCA_WCN3991:
	case QCA_QCA6390:
	case QCA_WCN6750:
	case QCA_WCN6855:
	case QCA_WCN7850:
		err = qca_disable_soc_logging(hdev);
		if (err < 0)
			return err;
		break;
	default:
		break;
	}

	/* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
	 * VsMsftOpCode.
	 */
	switch (soc_type) {
	case QCA_WCN3988:
	case QCA_WCN3990:
	case QCA_WCN3991:
	case QCA_WCN3998:
@@ -704,6 +740,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
	case QCA_WCN3991:
	case QCA_WCN6750:
	case QCA_WCN6855:
	case QCA_WCN7850:
		/* get fw build info */
		err = qca_read_fw_build_info(hdev);
		if (err < 0)
Loading