Commit 6cd663f0 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'for-net-next-2024-11-14' of...

Merge tag 'for-net-next-2024-11-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:

 - btusb: add Foxconn 0xe0fc for Qualcomm WCN785x
 - btmtk: Fix ISO interface handling
 - Add quirk for ATS2851
 - btusb: Add RTL8852BE device 0489:e123
 - ISO: Do not emit LE PA/BIG Create Sync if previous is pending
 - btusb: Add USB HW IDs for MT7920/MT7925
 - btintel_pcie: Add handshake between driver and firmware
 - btintel_pcie: Add recovery mechanism
 - hci_conn: Use disable_delayed_work_sync
 - SCO: Use kref to track lifetime of sco_conn
 - ISO: Use kref to track lifetime of iso_conn
 - btnxpuart: Add GPIO support to power save feature
 - btusb: Add 0x0489:0xe0f3 and 0x13d3:0x3623 for Qualcomm WCN785x

* tag 'for-net-next-2024-11-14' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (51 commits)
  Bluetooth: MGMT: Add initial implementation of MGMT_OP_HCI_CMD_SYNC
  Bluetooth: fix use-after-free in device_for_each_child()
  Bluetooth: btintel: Direct exception event to bluetooth stack
  Bluetooth: hci_core: Fix calling mgmt_device_connected
  Bluetooth: hci_bcm: Use the devm_clk_get_optional() helper
  Bluetooth: ISO: Send BIG Create Sync via hci_sync
  Bluetooth: hci_conn: Remove alloc from critical section
  Bluetooth: ISO: Use kref to track lifetime of iso_conn
  Bluetooth: SCO: Use kref to track lifetime of sco_conn
  Bluetooth: HCI: Add IPC(11) bus type
  Bluetooth: btusb: Add 3 HWIDs for MT7925
  Bluetooth: btusb: Add new VID/PID 0489/e124 for MT7925
  Bluetooth: ISO: Update hci_conn_hash_lookup_big for Broadcast slave
  Bluetooth: ISO: Do not emit LE BIG Create Sync if previous is pending
  Bluetooth: ISO: Fix matching parent socket for BIS slave
  Bluetooth: ISO: Do not emit LE PA Create Sync if previous is pending
  Bluetooth: btrtl: Decrease HCI_OP_RESET timeout from 10 s to 2 s
  Bluetooth: btbcm: fix missing of_node_put() in btbcm_get_board_name()
  Bluetooth: btusb: Add new VID/PID 0489/e111 for MT7925
  Bluetooth: btmtk: adjust the position to init iso data anchor
  ...
====================

Link: https://patch.msgid.link/20241114214731.1994446-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 26a3beee 827af478
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -34,6 +34,12 @@ properties:
  firmware-name:
    maxItems: 1

  device-wakeup-gpios:
    maxItems: 1
    description:
      Host-To-Chip power save mechanism is driven by this GPIO
      connected to BT_WAKE_IN pin of the NXP chipset.

required:
  - compatible

@@ -41,10 +47,12 @@ additionalProperties: false

examples:
  - |
    #include <dt-bindings/gpio/gpio.h>
    serial {
        bluetooth {
            compatible = "nxp,88w8987-bt";
            fw-init-baudrate = <3000000>;
            firmware-name = "uartuart8987_bt_v0.bin";
            device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
        };
    };
+1 −3
Original line number Diff line number Diff line
@@ -541,11 +541,10 @@ static const struct bcm_subver_table bcm_usb_subver_table[] = {
static const char *btbcm_get_board_name(struct device *dev)
{
#ifdef CONFIG_OF
	struct device_node *root;
	struct device_node *root __free(device_node) = of_find_node_by_path("/");
	char *board_type;
	const char *tmp;

	root = of_find_node_by_path("/");
	if (!root)
		return NULL;

@@ -555,7 +554,6 @@ static const char *btbcm_get_board_name(struct device *dev)
	/* get rid of any '/' in the compatible string */
	board_type = devm_kstrdup(dev, tmp, GFP_KERNEL);
	strreplace(board_type, '/', '-');
	of_node_put(root);

	return board_type;
#else
+92 −16
Original line number Diff line number Diff line
@@ -1040,7 +1040,7 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev,
		 * as needed.
		 *
		 * Send set of commands with 4 byte alignment from the
		 * firmware data buffer as a single Data fragement.
		 * firmware data buffer as a single Data fragment.
		 */
		if (!(frag_len % 4)) {
			err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
@@ -1252,6 +1252,12 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
	struct intel_reset params;
	struct sk_buff *skb;

	/* PCIe transport uses shared hardware reset mechanism for recovery
	 * which gets triggered in pcie *setup* function on error.
	 */
	if (hdev->bus == HCI_PCI)
		return;

	/* Send Intel Reset command. This will result in
	 * re-enumeration of BT controller.
	 *
@@ -1267,6 +1273,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
	 * boot_param:    Boot address
	 *
	 */

	params.reset_type = 0x01;
	params.patch_enable = 0x01;
	params.ddc_reload = 0x01;
@@ -1841,6 +1848,37 @@ static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
	return 0;
}

static int btintel_boot_wait_d0(struct hci_dev *hdev, ktime_t calltime,
				int msec)
{
	ktime_t delta, rettime;
	unsigned long long duration;
	int err;

	bt_dev_info(hdev, "Waiting for device transition to d0");

	err = btintel_wait_on_flag_timeout(hdev, INTEL_WAIT_FOR_D0,
					   TASK_INTERRUPTIBLE,
					   msecs_to_jiffies(msec));
	if (err == -EINTR) {
		bt_dev_err(hdev, "Device d0 move interrupted");
		return -EINTR;
	}

	if (err) {
		bt_dev_err(hdev, "Device d0 move timeout");
		return -ETIMEDOUT;
	}

	rettime = ktime_get();
	delta = ktime_sub(rettime, calltime);
	duration = (unsigned long long)ktime_to_ns(delta) >> 10;

	bt_dev_info(hdev, "Device moved to D0 in %llu usecs", duration);

	return 0;
}

static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
{
	ktime_t calltime;
@@ -1849,6 +1887,7 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
	calltime = ktime_get();

	btintel_set_flag(hdev, INTEL_BOOTING);
	btintel_set_flag(hdev, INTEL_WAIT_FOR_D0);

	err = btintel_send_intel_reset(hdev, boot_addr);
	if (err) {
@@ -1861,13 +1900,28 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
	 * is done by the operational firmware sending bootup notification.
	 *
	 * Booting into operational firmware should not take longer than
	 * 1 second. However if that happens, then just fail the setup
	 * 5 second. However if that happens, then just fail the setup
	 * since something went wrong.
	 */
	err = btintel_boot_wait(hdev, calltime, 1000);
	if (err == -ETIMEDOUT)
	err = btintel_boot_wait(hdev, calltime, 5000);
	if (err == -ETIMEDOUT) {
		btintel_reset_to_bootloader(hdev);
		goto exit_error;
	}

	if (hdev->bus == HCI_PCI) {
		/* In case of PCIe, after receiving bootup event, driver performs
		 * D0 entry by writing 0 to sleep control register (check
		 * btintel_pcie_recv_event())
		 * Firmware acks with alive interrupt indicating host is full ready to
		 * perform BT operation. Lets wait here till INTEL_WAIT_FOR_D0
		 * bit is cleared.
		 */
		calltime = ktime_get();
		err = btintel_boot_wait_d0(hdev, calltime, 2000);
	}

exit_error:
	return err;
}

@@ -2693,20 +2747,32 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver)

	struct btintel_dsbr_cmd cmd;
	struct sk_buff *skb;
	u32 dsbr, cnvi;
	u8 status;
	u32 dsbr;
	bool apply_dsbr;
	int err;

	/* DSBR command needs to be sent for BlazarI + B0 step product after
	 * downloading IML image.
	cnvi = ver->cnvi_top & 0xfff;
	/* DSBR command needs to be sent for,
	 * 1. BlazarI or BlazarIW + B0 step product in IML image.
	 * 2. Gale Peak2 or BlazarU in OP image.
	 */
	apply_dsbr = (ver->img_type == BTINTEL_IMG_IML &&
		((ver->cnvi_top & 0xfff) == BTINTEL_CNVI_BLAZARI) &&
		INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01);

	if (!apply_dsbr)
	switch (cnvi) {
	case BTINTEL_CNVI_BLAZARI:
	case BTINTEL_CNVI_BLAZARIW:
		if (ver->img_type == BTINTEL_IMG_IML &&
		    INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01)
			break;
		return 0;
	case BTINTEL_CNVI_GAP:
	case BTINTEL_CNVI_BLAZARU:
		if (ver->img_type == BTINTEL_IMG_OP &&
		    hdev->bus == HCI_USB)
			break;
		return 0;
	default:
		return 0;
	}

	dsbr = 0;
	err = btintel_uefi_get_dsbr(&dsbr);
@@ -2749,6 +2815,13 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
	 */
	boot_param = 0x00000000;

	/* In case of PCIe, this function might get called multiple times with
	 * same hdev instance if there is any error on firmware download.
	 * Need to clear stale bits of previous firmware download attempt.
	 */
	for (int i = 0; i < __INTEL_NUM_FLAGS; i++)
		btintel_clear_flag(hdev, i);

	btintel_set_flag(hdev, INTEL_BOOTLOADER);

	err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
@@ -2835,7 +2908,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
	case 0x12:	/* ThP */
	case 0x13:	/* HrP */
	case 0x14:	/* CcP */
	/* All Intel new genration controllers support the Microsoft vendor
	/* All Intel new generation controllers support the Microsoft vendor
	 * extension are using 0xFC1E for VsMsftOpCode.
	 */
	case 0x17:
@@ -3273,7 +3346,7 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
}
EXPORT_SYMBOL_GPL(btintel_configure_setup);

static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct intel_tlv *tlv = (void *)&skb->data[5];

@@ -3301,6 +3374,7 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
recv_frame:
	return hci_recv_frame(hdev, skb);
}
EXPORT_SYMBOL_GPL(btintel_diagnostics);

int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -3320,7 +3394,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
				 * indicating that the bootup completed.
				 */
				btintel_bootup(hdev, ptr, len);
				break;
				kfree_skb(skb);
				return 0;
			case 0x06:
				/* When the firmware loading completes the
				 * device sends out a vendor specific event
@@ -3328,7 +3403,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
				 * loading.
				 */
				btintel_secure_send_result(hdev, ptr, len);
				break;
				kfree_skb(skb);
				return 0;
			}
		}

+10 −0
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ struct intel_tlv {
} __packed;

#define BTINTEL_CNVI_BLAZARI		0x900
#define BTINTEL_CNVI_BLAZARIW		0x901
#define BTINTEL_CNVI_GAP		0x910
#define BTINTEL_CNVI_BLAZARU		0x930

#define BTINTEL_IMG_BOOTLOADER		0x01	/* Bootloader image */
#define BTINTEL_IMG_IML			0x02	/* Intermediate image */
@@ -178,6 +181,7 @@ enum {
	INTEL_ROM_LEGACY,
	INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
	INTEL_ACPI_RESET_ACTIVE,
	INTEL_WAIT_FOR_D0,

	__INTEL_NUM_FLAGS,
};
@@ -249,6 +253,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
int btintel_shutdown_combined(struct hci_dev *hdev);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_print_fseq_info(struct hci_dev *hdev);
int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb);
#else

static inline int btintel_check_bdaddr(struct hci_dev *hdev)
@@ -382,4 +387,9 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
static inline void btintel_print_fseq_info(struct hci_dev *hdev)
{
}

static inline int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb)
{
	return -EOPNOTSUPP;
}
#endif
+336 −51
Original line number Diff line number Diff line
@@ -48,6 +48,17 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
#define BTINTEL_PCIE_HCI_EVT_PKT	0x00000004
#define BTINTEL_PCIE_HCI_ISO_PKT	0x00000005

/* Alive interrupt context */
enum {
	BTINTEL_PCIE_ROM,
	BTINTEL_PCIE_FW_DL,
	BTINTEL_PCIE_HCI_RESET,
	BTINTEL_PCIE_INTEL_HCI_RESET1,
	BTINTEL_PCIE_INTEL_HCI_RESET2,
	BTINTEL_PCIE_D0,
	BTINTEL_PCIE_D3
};

static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia,
				     u16 queue_num)
{
@@ -64,24 +75,6 @@ static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1,
		   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;
@@ -237,10 +230,47 @@ static void btintel_pcie_reset_ia(struct btintel_pcie_data *data)
	memset(data->ia.cr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES);
}

static void btintel_pcie_reset_bt(struct btintel_pcie_data *data)
static int 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);
	u32 reg;
	int retry = 3;

	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);

	reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
			BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT |
			BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
	reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON;

	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);

	do {
		reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
		if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS)
			break;
		usleep_range(10000, 12000);

	} while (--retry > 0);
	usleep_range(10000, 12000);

	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);

	reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
			BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT |
			BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT);
	reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET;
	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);
	usleep_range(10000, 12000);

	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
	bt_dev_dbg(data->hdev, "csr register after reset: 0x%8.8x", reg);

	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG);

	/* If shared hardware reset is success then boot stage register shall be
	 * set to 0
	 */
	return reg == 0 ? 0 : -ENODEV;
}

/* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in
@@ -252,6 +282,7 @@ static void btintel_pcie_reset_bt(struct btintel_pcie_data *data)
static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
{
	int err;
	u32 reg;

	data->gp0_received = false;

@@ -267,22 +298,17 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
	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,
	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
	reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT |
			BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON |
			BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET);
	reg |= (BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA |
			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;
	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg);

	/* 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);
@@ -290,8 +316,9 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
	/* wait for interrupt from the device after booting up to primary
	 * bootloader.
	 */
	data->alive_intr_ctxt = BTINTEL_PCIE_ROM;
	err = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
				 msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT));
				 msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
	if (!err)
		return -ETIME;

@@ -302,12 +329,77 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data)
	return 0;
}

/* BIT(0) - ROM, BIT(1) - IML and BIT(3) - OP
 * Sometimes during firmware image switching from ROM to IML or IML to OP image,
 * the previous image bit is not cleared by firmware when alive interrupt is
 * received. Driver needs to take care of these sticky bits when deciding the
 * current image running on controller.
 * Ex: 0x10 and 0x11 - both represents that controller is running IML
 */
static inline bool btintel_pcie_in_rom(struct btintel_pcie_data *data)
{
	return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM &&
		!(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) &&
		!(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
}

static inline bool btintel_pcie_in_op(struct btintel_pcie_data *data)
{
	return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW;
}

static inline bool btintel_pcie_in_iml(struct btintel_pcie_data *data)
{
	return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML &&
		!(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW);
}

static inline bool btintel_pcie_in_d3(struct btintel_pcie_data *data)
{
	return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY;
}

static inline bool btintel_pcie_in_d0(struct btintel_pcie_data *data)
{
	return !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY);
}

static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
					u32 dxstate)
{
	bt_dev_dbg(data->hdev, "writing sleep_ctl_reg: 0x%8.8x", dxstate);
	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate);
}

static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)
{
	switch (alive_intr_ctxt) {
	case BTINTEL_PCIE_ROM:
		return "rom";
	case BTINTEL_PCIE_FW_DL:
		return "fw_dl";
	case BTINTEL_PCIE_D0:
		return "d0";
	case BTINTEL_PCIE_D3:
		return "d3";
	case BTINTEL_PCIE_HCI_RESET:
		return "hci_reset";
	case BTINTEL_PCIE_INTEL_HCI_RESET1:
		return "intel_reset1";
	case BTINTEL_PCIE_INTEL_HCI_RESET2:
		return "intel_reset2";
	default:
		return "unknown";
	}
}

/* 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;
	bool submit_rx, signal_waitq;
	u32 reg, old_ctxt;

	/* This interrupt is for three different causes and it is not easy to
	 * know what causes the interrupt. So, it compares each register value
@@ -317,22 +409,89 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
	if (reg != data->boot_stage_cache)
		data->boot_stage_cache = reg;

	bt_dev_dbg(data->hdev, "Alive context: %s old_boot_stage: 0x%8.8x new_boot_stage: 0x%8.8x",
		   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt),
		   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) {
	old_ctxt = data->alive_intr_ctxt;
	submit_rx = false;
	signal_waitq = false;

	switch (data->alive_intr_ctxt) {
	case BTINTEL_PCIE_ROM:
		data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
		signal_waitq = true;
		break;
	case BTINTEL_PCIE_FW_DL:
		/* Error case is already handled. Ideally control shall not
		 * reach here
		 */
		break;
	case BTINTEL_PCIE_INTEL_HCI_RESET1:
		if (btintel_pcie_in_op(data)) {
			submit_rx = true;
			break;
		}

		if (btintel_pcie_in_iml(data)) {
			submit_rx = true;
			data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
			break;
		}
		break;
	case BTINTEL_PCIE_INTEL_HCI_RESET2:
		if (btintel_test_and_clear_flag(data->hdev, INTEL_WAIT_FOR_D0)) {
			btintel_wake_up_flag(data->hdev, INTEL_WAIT_FOR_D0);
			data->alive_intr_ctxt = BTINTEL_PCIE_D0;
		}
		break;
	case BTINTEL_PCIE_D0:
		if (btintel_pcie_in_d3(data)) {
			data->alive_intr_ctxt = BTINTEL_PCIE_D3;
			signal_waitq = true;
			break;
		}
		break;
	case BTINTEL_PCIE_D3:
		if (btintel_pcie_in_d0(data)) {
			data->alive_intr_ctxt = BTINTEL_PCIE_D0;
			submit_rx = true;
			signal_waitq = true;
			break;
		}
		break;
	case BTINTEL_PCIE_HCI_RESET:
		data->alive_intr_ctxt = BTINTEL_PCIE_D0;
		submit_rx = true;
		signal_waitq = true;
		break;
	default:
		bt_dev_err(data->hdev, "Unknown state: 0x%2.2x",
			   data->alive_intr_ctxt);
		break;
	}

	if (submit_rx) {
		btintel_pcie_reset_ia(data);
		btintel_pcie_start_rx(data);
	}

	if (signal_waitq) {
		bt_dev_dbg(data->hdev, "wake up gp0 wait_q");
		wake_up(&data->gp0_wait_q);
	}

	if (old_ctxt != data->alive_intr_ctxt)
		bt_dev_dbg(data->hdev, "alive context changed: %s  ->  %s",
			   btintel_pcie_alivectxt_state2str(old_ctxt),
			   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
}

/* 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)
@@ -364,6 +523,83 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
	}
}

static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct hci_event_hdr *hdr = (void *)skb->data;
	const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 };
	struct btintel_pcie_data *data = hci_get_drvdata(hdev);

	if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
	    hdr->plen > 0) {
		const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
		unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;

		if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
			switch (skb->data[2]) {
			case 0x02:
				/* When switching to the operational firmware
				 * the device sends a vendor specific event
				 * indicating that the bootup completed.
				 */
				btintel_bootup(hdev, ptr, len);

				/* If bootup event is from operational image,
				 * driver needs to write sleep control register to
				 * move into D0 state
				 */
				if (btintel_pcie_in_op(data)) {
					btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0);
					data->alive_intr_ctxt = BTINTEL_PCIE_INTEL_HCI_RESET2;
					kfree_skb(skb);
					return 0;
				}

				if (btintel_pcie_in_iml(data)) {
					/* In case of IML, there is no concept
					 * of D0 transition. Just mimic as if
					 * IML moved to D0 by clearing INTEL_WAIT_FOR_D0
					 * bit and waking up the task waiting on
					 * INTEL_WAIT_FOR_D0. This is required
					 * as intel_boot() is common function for
					 * both IML and OP image loading.
					 */
					if (btintel_test_and_clear_flag(data->hdev,
									INTEL_WAIT_FOR_D0))
						btintel_wake_up_flag(data->hdev,
								     INTEL_WAIT_FOR_D0);
				}
				kfree_skb(skb);
				return 0;
			case 0x06:
				/* When the firmware loading completes the
				 * device sends out a vendor specific event
				 * indicating the result of the firmware
				 * loading.
				 */
				btintel_secure_send_result(hdev, ptr, len);
				kfree_skb(skb);
				return 0;
			}
		}

		/* Handle all diagnostics events separately. May still call
		 * hci_recv_frame.
		 */
		if (len >= sizeof(diagnostics_hdr) &&
		    memcmp(&skb->data[2], diagnostics_hdr,
			   sizeof(diagnostics_hdr)) == 0) {
			return btintel_diagnostics(hdev, skb);
		}

		/* This is a debug event that comes from IML and OP image when it
		 * starts execution. There is no need pass this event to stack.
		 */
		if (skb->data[2] == 0x97)
			return 0;
	}

	return hci_recv_frame(hdev, skb);
}
/* Process the received rx data
 * It check the frame header to identify the data type and create skb
 * and calling HCI API
@@ -465,7 +701,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
	hdev->stat.byte_rx += plen;

	if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT)
		ret = btintel_recv_event(hdev, new_skb);
		ret = btintel_pcie_recv_event(hdev, new_skb);
	else
		ret = hci_recv_frame(hdev, new_skb);

@@ -516,10 +752,8 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status
	buf += sizeof(*rfh_hdr);

	skb = alloc_skb(len, GFP_ATOMIC);
	if (!skb) {
		ret = -ENOMEM;
	if (!skb)
		goto resubmit;
	}

	skb_put_data(skb, buf, len);
	skb_queue_tail(&data->rx_skb_q, skb);
@@ -734,13 +968,9 @@ static int btintel_pcie_config_pcie(struct pci_dev *pdev,
			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;
	data->base_addr = pcim_iomap_region(pdev, 0, KBUILD_MODNAME);
	if (IS_ERR(data->base_addr))
		return PTR_ERR(data->base_addr);

	err = btintel_pcie_setup_irq(data);
	if (err)
@@ -1053,8 +1283,11 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
				       struct sk_buff *skb)
{
	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
	struct hci_command_hdr *cmd;
	__u16 opcode = ~0;
	int ret;
	u32 type;
	u32 old_ctxt;

	/* 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
@@ -1073,6 +1306,8 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
	switch (hci_skb_pkt_type(skb)) {
	case HCI_COMMAND_PKT:
		type = BTINTEL_PCIE_HCI_CMD_PKT;
		cmd = (void *)skb->data;
		opcode = le16_to_cpu(cmd->opcode);
		if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
			struct hci_command_hdr *cmd = (void *)skb->data;
			__u16 opcode = le16_to_cpu(cmd->opcode);
@@ -1111,6 +1346,30 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
		bt_dev_err(hdev, "Failed to send frame (%d)", ret);
		goto exit_error;
	}

	if (type == BTINTEL_PCIE_HCI_CMD_PKT &&
	    (opcode == HCI_OP_RESET || opcode == 0xfc01)) {
		old_ctxt = data->alive_intr_ctxt;
		data->alive_intr_ctxt =
			(opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
				BTINTEL_PCIE_HCI_RESET);
		bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s  ->  %s",
			   opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
			   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
		if (opcode == HCI_OP_RESET) {
			data->gp0_received = false;
			ret = wait_event_timeout(data->gp0_wait_q,
						 data->gp0_received,
						 msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
			if (!ret) {
				hdev->stat.err_tx++;
				bt_dev_err(hdev, "No alive interrupt received for %s",
					   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
				ret = -ETIME;
				goto exit_error;
			}
		}
	}
	hdev->stat.byte_tx += skb->len;
	kfree_skb(skb);

@@ -1128,7 +1387,7 @@ static void btintel_pcie_release_hdev(struct btintel_pcie_data *data)
	data->hdev = NULL;
}

static int btintel_pcie_setup(struct hci_dev *hdev)
static int btintel_pcie_setup_internal(struct hci_dev *hdev)
{
	const u8 param[1] = { 0xFF };
	struct intel_version_tlv ver_tlv;
@@ -1219,6 +1478,32 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
	return err;
}

static int btintel_pcie_setup(struct hci_dev *hdev)
{
	int err, fw_dl_retry = 0;
	struct btintel_pcie_data *data = hci_get_drvdata(hdev);

	while ((err = btintel_pcie_setup_internal(hdev)) && fw_dl_retry++ < 1) {
		bt_dev_err(hdev, "Firmware download retry count: %d",
			   fw_dl_retry);
		err = btintel_pcie_reset_bt(data);
		if (err) {
			bt_dev_err(hdev, "Failed to do shr reset: %d", err);
			break;
		}
		usleep_range(10000, 12000);
		btintel_pcie_reset_ia(data);
		btintel_pcie_config_msix(data);
		err = btintel_pcie_enable_bt(data);
		if (err) {
			bt_dev_err(hdev, "Failed to enable hardware: %d", err);
			break;
		}
		btintel_pcie_start_rx(data);
	}
	return err;
}

static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
{
	int err;
Loading