Commit d2002ccb authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'for-net-next-2025-07-23' of...

Merge tag 'for-net-next-2025-07-23' 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:

core:

 - hci_sync: fix double free in 'hci_discovery_filter_clear()'
 - hci_event: Mask data status from LE ext adv reports
 - hci_devcd_dump: fix out-of-bounds via dev_coredumpv
 - ISO: add socket option to report packet seqnum via CMSG
 - hci_event: Add support for handling LE BIG Sync Lost event
 - ISO: Support SCM_TIMESTAMPING for ISO TS
 - hci_core: Add PA_LINK to distinguish BIG sync and PA sync connections
 - hci_sock: Reset cookie to zero in hci_sock_free_cookie()

drivers:

 - btusb: Add new VID/PID 0489/e14e for MT7925
 - btusb: Add a new VID/PID 2c7c/7009 for MT7925
 - btusb: Add RTL8852BE device 0x13d3:0x3618
 - btusb: Add support for variant of RTL8851BE (USB ID 13d3:3601)
 - btusb: Add USB ID 3625:010b for TP-LINK Archer TX10UB Nano
 - btusb: QCA: Support downloading custom-made firmwares
 - btusb: Add one more ID 0x28de:0x1401 for Qualcomm WCN6855
 - nxp: add support for supply and reset
 - btnxpuart: Add support for 4M baudrate
 - btnxpuart: Correct the Independent Reset handling after FW dump
 - btnxpuart: Add uevents for FW dump and FW download complete
 - btintel: Define a macro for Intel Reset vendor command
 - btintel_pcie: Support Function level reset
 - btintel_pcie: Add support for device 0x4d76
 - btintel_pcie: Make driver wait for alive interrupt
 - btintel_pcie: Fix Alive Context State Handling
 - hci_qca: Enable ISO data packet RX

* tag 'for-net-next-2025-07-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (42 commits)
  Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections
  Bluetooth: hci_event: Mask data status from LE ext adv reports
  Bluetooth: btintel_pcie: Fix Alive Context State Handling
  Bluetooth: btintel_pcie: Make driver wait for alive interrupt
  Bluetooth: hci_devcd_dump: fix out-of-bounds via dev_coredumpv
  Bluetooth: hci_sync: fix double free in 'hci_discovery_filter_clear()'
  Bluetooth: btusb: Add one more ID 0x28de:0x1401 for Qualcomm WCN6855
  Bluetooth: btusb: Sort WCN6855 device IDs by VID and PID
  Bluetooth: btusb: QCA: Support downloading custom-made firmwares
  Bluetooth: btnxpuart: Add uevents for FW dump and FW download complete
  Bluetooth: btnxpuart: Correct the Independent Reset handling after FW dump
  Bluetooth: ISO: Support SCM_TIMESTAMPING for ISO TS
  Bluetooth: ISO: add socket option to report packet seqnum via CMSG
  Bluetooth: btintel: Define a macro for Intel Reset vendor command
  Bluetooth: Fix typos in comments
  Bluetooth: RFCOMM: Fix typos in comments
  Bluetooth: aosp: Fix typo in comment
  Bluetooth: hci_bcm4377: Fix typo in comment
  Bluetooth: btrtl: Fix typo in comment
  Bluetooth: btmtk: Fix typo in log string
  ...
====================

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


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents a4f5759b a7bcffc6
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -34,6 +34,13 @@ properties:
      This property depends on the module vendor's
      configuration.

  max-speed:
    $ref: /schemas/types.yaml#/definitions/uint32
    enum:
      - 3000000
      - 4000000
    default: 3000000

  firmware-name:
    maxItems: 1

@@ -65,6 +72,14 @@ properties:
    description:
      The GPIO number of the NXP chipset used for BT_WAKE_OUT.

  vcc-supply:
    description:
      phandle of the regulator that provides the supply voltage.

  reset-gpios:
    description:
      Chip powerdown/reset signal (PDn).

required:
  - compatible

@@ -78,10 +93,13 @@ examples:
        bluetooth {
            compatible = "nxp,88w8987-bt";
            fw-init-baudrate = <3000000>;
            max-speed = <4000000>;
            firmware-name = "uartuart8987_bt_v0.bin";
            device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
            nxp,wakein-pin = /bits/ 8 <18>;
            nxp,wakeout-pin = /bits/ 8 <19>;
            vcc-supply = <&nxp_iw612_supply>;
            reset-gpios = <&gpioctrl 2 GPIO_ACTIVE_LOW>;
            local-bd-address = [66 55 44 33 22 11];
            interrupt-parent = <&gpio>;
            interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
+3 −3
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
	/* Consume Command Complete Status field */
	skb_pull(skb, 1);

	/* Event parameters contatin multiple TLVs. Read each of them
	/* Event parameters contain multiple TLVs. Read each of them
	 * and only keep the required data. Also, it use existing legacy
	 * version field like hw_platform, hw_variant, and fw_variant
	 * to keep the existing setup flow
@@ -889,7 +889,7 @@ int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param)

	params.boot_param = cpu_to_le32(boot_param);

	skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), &params,
	skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), &params,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		bt_dev_err(hdev, "Failed to send Intel Reset command");
@@ -1287,7 +1287,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
	params.boot_option = 0x00;
	params.boot_param = cpu_to_le32(0x00000000);

	skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params),
	skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params),
			     &params, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		bt_dev_err(hdev, "FW download error recovery failed (%ld)",
+2 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ struct intel_tlv {
	u8 val[];
} __packed;

#define BTINTEL_HCI_OP_RESET	0xfc01

#define BTINTEL_CNVI_BLAZARI		0x900
#define BTINTEL_CNVI_BLAZARIW		0x901
#define BTINTEL_CNVI_GAP		0x910
+288 −59
Original line number Diff line number Diff line
@@ -35,12 +35,20 @@

/* Intel Bluetooth PCIe device id table */
static const struct pci_device_id btintel_pcie_table[] = {
	{ BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) },
	{ BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) },
	{ BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) },
	{ 0 }
};
MODULE_DEVICE_TABLE(pci, btintel_pcie_table);

struct btintel_pcie_dev_recovery {
	struct list_head list;
	u8 count;
	time64_t last_error;
	char name[];
};

/* 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
@@ -62,6 +70,9 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
#define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER	0x17A2
#define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT		0x1E61

#define BTINTEL_PCIE_RESET_WINDOW_SECS		5
#define BTINTEL_PCIE_FLR_MAX_RETRY	1

/* Alive interrupt context */
enum {
	BTINTEL_PCIE_ROM,
@@ -99,6 +110,36 @@ struct btintel_pcie_dbgc_ctxt {
	struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT];
};

struct btintel_pcie_removal {
	struct pci_dev *pdev;
	struct work_struct work;
};

static LIST_HEAD(btintel_pcie_recovery_list);
static DEFINE_SPINLOCK(btintel_pcie_recovery_lock);

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 initializes the memory for DBGC buffers and formats the
 * DBGC fragment which consists header info and DBGC buffer's LSB, MSB and
 * size as the payload
@@ -299,10 +340,14 @@ static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev)
}

static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
				  struct sk_buff *skb)
				  struct sk_buff *skb, u32 pkt_type, u16 opcode)
{
	int ret;
	u16 tfd_index;
	u32 old_ctxt;
	bool wait_on_alive = false;
	struct hci_dev *hdev = data->hdev;

	struct txq *txq = &data->txq;

	tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];
@@ -310,6 +355,26 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
	if (tfd_index > txq->count)
		return -ERANGE;

	/* Firmware raises alive interrupt on HCI_OP_RESET or
	 * BTINTEL_HCI_OP_RESET
	 */
	wait_on_alive = (pkt_type == BTINTEL_PCIE_HCI_CMD_PKT &&
		(opcode == BTINTEL_HCI_OP_RESET || opcode == HCI_OP_RESET));

	if (wait_on_alive) {
		data->gp0_received = false;
		old_ctxt = data->alive_intr_ctxt;
		data->alive_intr_ctxt =
			(opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
				BTINTEL_PCIE_HCI_RESET);
		bt_dev_dbg(data->hdev, "sending cmd: 0x%4.4x alive context changed: %s  ->  %s",
			   opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
			   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
	}

	memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &pkt_type,
	       BTINTEL_PCIE_HCI_TYPE_LEN);

	/* 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
	 */
@@ -328,11 +393,24 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
	ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done,
				 msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS));
	if (!ret) {
		bt_dev_err(data->hdev, "tx completion timeout");
		bt_dev_err(data->hdev, "Timeout (%u ms) on tx completion",
			   BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS);
		btintel_pcie_dump_debug_registers(data->hdev);
		return -ETIME;
	}

	if (wait_on_alive) {
		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, "Timeout (%u ms)  on alive interrupt, alive context: %s",
				   BTINTEL_DEFAULT_INTR_TIMEOUT_MS,
				   btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
			return  -ETIME;
		}
	}
	return 0;
}

@@ -811,28 +889,6 @@ static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
	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";
	}
}

static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data,
					void *buf, u32 dev_addr, int len)
{
@@ -928,11 +984,13 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
	case BTINTEL_PCIE_INTEL_HCI_RESET1:
		if (btintel_pcie_in_op(data)) {
			submit_rx = true;
			signal_waitq = true;
			break;
		}

		if (btintel_pcie_in_iml(data)) {
			submit_rx = true;
			signal_waitq = true;
			data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
			break;
		}
@@ -1930,7 +1988,9 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
	__u16 opcode = ~0;
	int ret;
	u32 type;
	u32 old_ctxt;

	if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
		return -ENODEV;

	/* 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
@@ -1955,17 +2015,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
			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
			/* When the BTINTEL_HCI_OP_RESET 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)
			if (opcode == BTINTEL_HCI_OP_RESET)
				btintel_pcie_inject_cmd_complete(hdev, opcode);
		}
		/* Firmware raises alive interrupt on HCI_OP_RESET */
		if (opcode == HCI_OP_RESET)
			data->gp0_received = false;

		hdev->stat.cmd_tx++;
		break;
@@ -1984,38 +2041,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
		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);
	ret = btintel_pcie_send_sync(data, skb, type, opcode);
	if (ret) {
		hdev->stat.err_tx++;
		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) {
			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);

@@ -2192,9 +2225,191 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
		}
		btintel_pcie_start_rx(data);
	}

	if (!err)
		set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags);
	return err;
}

static struct btintel_pcie_dev_recovery *
btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev)
{
	struct btintel_pcie_dev_recovery *tmp, *data = NULL;
	const char *name = pci_name(pdev);
	struct hci_dev *hdev = to_hci_dev(dev);

	spin_lock(&btintel_pcie_recovery_lock);
	list_for_each_entry(tmp, &btintel_pcie_recovery_list, list) {
		if (strcmp(tmp->name, name))
			continue;
		data = tmp;
		break;
	}
	spin_unlock(&btintel_pcie_recovery_lock);

	if (data) {
		bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name);
		return data;
	}

	data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC);
	if (!data)
		return NULL;

	strscpy_pad(data->name, name, strlen(name) + 1);
	spin_lock(&btintel_pcie_recovery_lock);
	list_add_tail(&data->list, &btintel_pcie_recovery_list);
	spin_unlock(&btintel_pcie_recovery_lock);

	return data;
}

static void btintel_pcie_free_restart_list(void)
{
	struct btintel_pcie_dev_recovery *tmp;

	while ((tmp = list_first_entry_or_null(&btintel_pcie_recovery_list,
					       typeof(*tmp), list))) {
		list_del(&tmp->list);
		kfree(tmp);
	}
}

static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev,
					    struct device *dev)
{
	struct btintel_pcie_dev_recovery *data;
	time64_t retry_window;

	data = btintel_pcie_get_recovery(pdev, dev);
	if (!data)
		return;

	retry_window = ktime_get_boottime_seconds() - data->last_error;
	if (data->count == 0) {
		data->last_error = ktime_get_boottime_seconds();
		data->count++;
	} else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
		   data->count <= BTINTEL_PCIE_FLR_MAX_RETRY) {
		data->count++;
	} else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) {
		data->last_error = 0;
		data->count = 0;
	}
}

static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data);

static void btintel_pcie_removal_work(struct work_struct *wk)
{
	struct btintel_pcie_removal *removal =
		container_of(wk, struct btintel_pcie_removal, work);
	struct pci_dev *pdev = removal->pdev;
	struct btintel_pcie_data *data;
	int err;

	pci_lock_rescan_remove();

	if (!pdev->bus)
		goto error;

	data = pci_get_drvdata(pdev);

	btintel_pcie_disable_interrupts(data);
	btintel_pcie_synchronize_irqs(data);

	flush_work(&data->rx_work);
	flush_work(&data->hdev->dump.dump_rx);

	bt_dev_dbg(data->hdev, "Release bluetooth interface");
	btintel_pcie_release_hdev(data);

	err = pci_reset_function(pdev);
	if (err) {
		BT_ERR("Failed resetting the pcie device (%d)", err);
		goto error;
	}

	btintel_pcie_enable_interrupts(data);
	btintel_pcie_config_msix(data);

	err = btintel_pcie_enable_bt(data);
	if (err) {
		BT_ERR("Failed to enable bluetooth hardware after reset (%d)",
		       err);
		goto error;
	}

	btintel_pcie_reset_ia(data);
	btintel_pcie_start_rx(data);
	data->flags = 0;

	err = btintel_pcie_setup_hdev(data);
	if (err) {
		BT_ERR("Failed registering hdev (%d)", err);
		goto error;
	}
error:
	pci_dev_put(pdev);
	pci_unlock_rescan_remove();
	kfree(removal);
}

static void btintel_pcie_reset(struct hci_dev *hdev)
{
	struct btintel_pcie_removal *removal;
	struct btintel_pcie_data *data;

	data = hci_get_drvdata(hdev);

	if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags))
		return;

	if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
		return;

	removal = kzalloc(sizeof(*removal), GFP_ATOMIC);
	if (!removal)
		return;

	removal->pdev = data->pdev;
	INIT_WORK(&removal->work, btintel_pcie_removal_work);
	pci_dev_get(removal->pdev);
	schedule_work(&removal->work);
}

static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
{
	struct btintel_pcie_dev_recovery *data;
	struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev);
	struct pci_dev *pdev = dev_data->pdev;
	time64_t retry_window;

	if (code == 0x13) {
		bt_dev_err(hdev, "Encountered top exception");
		return;
	}

	data = btintel_pcie_get_recovery(pdev, &hdev->dev);
	if (!data)
		return;

	retry_window = ktime_get_boottime_seconds() - data->last_error;

	if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
	    data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
		bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d",
			   BTINTEL_PCIE_FLR_MAX_RETRY, data->count);
		bt_dev_dbg(hdev, "Boot time: %lld seconds",
			   ktime_get_boottime_seconds());
		bt_dev_dbg(hdev, "last error at: %lld seconds",
			   data->last_error);
		return;
	}
	btintel_pcie_inc_recovery_count(pdev, &hdev->dev);
	btintel_pcie_reset(hdev);
}

static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
{
	int err;
@@ -2216,9 +2431,10 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
	hdev->send = btintel_pcie_send_frame;
	hdev->setup = btintel_pcie_setup;
	hdev->shutdown = btintel_shutdown_combined;
	hdev->hw_error = btintel_hw_error;
	hdev->hw_error = btintel_pcie_hw_error;
	hdev->set_diag = btintel_set_diag;
	hdev->set_bdaddr = btintel_set_bdaddr;
	hdev->reset = btintel_pcie_reset;

	err = hci_register_dev(hdev);
	if (err < 0) {
@@ -2366,7 +2582,20 @@ static struct pci_driver btintel_pcie_driver = {
	.driver.coredump = btintel_pcie_coredump
#endif
};
module_pci_driver(btintel_pcie_driver);

static int __init btintel_pcie_init(void)
{
	return pci_register_driver(&btintel_pcie_driver);
}

static void __exit btintel_pcie_exit(void)
{
	pci_unregister_driver(&btintel_pcie_driver);
	btintel_pcie_free_restart_list();
}

module_init(btintel_pcie_init);
module_exit(btintel_pcie_exit);

MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>");
MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION);
+3 −1
Original line number Diff line number Diff line
@@ -117,7 +117,9 @@ enum {
enum {
	BTINTEL_PCIE_CORE_HALTED,
	BTINTEL_PCIE_HWEXP_INPROGRESS,
	BTINTEL_PCIE_COREDUMP_INPROGRESS
	BTINTEL_PCIE_COREDUMP_INPROGRESS,
	BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
	BTINTEL_PCIE_SETUP_DONE
};

enum btintel_pcie_tlv_type {
Loading