Commit 3d382936 authored by David S. Miller's avatar David S. Miller
Browse files

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

Merge tag 'for-net-next-2023-08-11' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

bluetooth-next pull request for net-next:

 - Add new VID/PID for Mediatek MT7922
 - Add support multiple BIS/BIG
 - Add support for Intel Gale Peak
 - Add support for Qualcomm WCN3988
 - Add support for BT_PKT_STATUS for ISO sockets
 - Various fixes for experimental ISO support
 - Load FW v2 for RTL8852C
 - Add support for NXP AW693 chipset
 - Add support for Mediatek MT2925
parents 2f4503f9 b5793de3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ properties:
      - qcom,qca2066-bt
      - qcom,qca6174-bt
      - qcom,qca9377-bt
      - qcom,wcn3988-bt
      - qcom,wcn3990-bt
      - qcom,wcn3991-bt
      - qcom,wcn3998-bt
@@ -111,6 +112,7 @@ allOf:
        compatible:
          contains:
            enum:
              - qcom,wcn3988-bt
              - qcom,wcn3990-bt
              - qcom,wcn3991-bt
              - qcom,wcn3998-bt
+5 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}})
#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}})
#define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}})
#define BDADDR_BCM43430A1 (&(bdaddr_t) {{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}})
#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
#define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
@@ -115,6 +116,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
	 *
	 * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller
	 * with no configured address.
	 *
	 * The address AA:AA:AA:AA:AA:AA indicates a BCM43430A1 controller
	 * with no configured address.
	 */
	if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
	    !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) ||
@@ -124,6 +128,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
	    !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) ||
	    !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
	    !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
	    !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) ||
	    !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
		/* Try falling back to BDADDR EFI variable */
		if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
+198 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/firmware.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <asm/unaligned.h>

#include <net/bluetooth/bluetooth.h>
@@ -27,6 +28,11 @@

#define BTINTEL_PPAG_NAME   "PPAG"

enum {
	DSM_SET_WDISABLE2_DELAY = 1,
	DSM_SET_RESET_METHOD = 3,
};

/* structure to store the PPAG data read from ACPI table */
struct btintel_ppag {
	u32	domain;
@@ -49,6 +55,10 @@ static struct {
	u32        fw_build_num;
} coredump_info;

static const guid_t btintel_guid_dsm =
	GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,
		  0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);

int btintel_check_bdaddr(struct hci_dev *hdev)
{
	struct hci_rp_read_bd_addr *bda;
@@ -470,6 +480,7 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
	case 0x18:	/* Slr */
	case 0x19:	/* Slr-F */
	case 0x1b:      /* Mgr */
	case 0x1c:	/* Gale Peak (GaP) */
		break;
	default:
		bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",
@@ -2444,6 +2455,116 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
	kfree_skb(skb);
}

static int btintel_acpi_reset_method(struct hci_dev *hdev)
{
	int ret = 0;
	acpi_status status;
	union acpi_object *p, *ref;
	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

	status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer);
	if (ACPI_FAILURE(status)) {
		bt_dev_err(hdev, "Failed to run _PRR method");
		ret = -ENODEV;
		return ret;
	}
	p = buffer.pointer;

	if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) {
		bt_dev_err(hdev, "Invalid arguments");
		ret = -EINVAL;
		goto exit_on_error;
	}

	ref = &p->package.elements[0];
	if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) {
		bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type);
		ret = -EINVAL;
		goto exit_on_error;
	}

	status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL);
	if (ACPI_FAILURE(status)) {
		bt_dev_err(hdev, "Failed to run_RST method");
		ret = -ENODEV;
		goto exit_on_error;
	}

exit_on_error:
	kfree(buffer.pointer);
	return ret;
}

static void btintel_set_dsm_reset_method(struct hci_dev *hdev,
					 struct intel_version_tlv *ver_tlv)
{
	struct btintel_data *data = hci_get_priv(hdev);
	acpi_handle handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
	u8 reset_payload[4] = {0x01, 0x00, 0x01, 0x00};
	union acpi_object *obj, argv4;
	enum {
		RESET_TYPE_WDISABLE2,
		RESET_TYPE_VSEC
	};

	handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));

	if (!handle) {
		bt_dev_dbg(hdev, "No support for bluetooth device in ACPI firmware");
		return;
	}

	if (!acpi_has_method(handle, "_PRR")) {
		bt_dev_err(hdev, "No support for _PRR ACPI method");
		return;
	}

	switch (ver_tlv->cnvi_top & 0xfff) {
	case 0x910: /* GalePeak2 */
		reset_payload[2] = RESET_TYPE_VSEC;
		break;
	default:
		/* WDISABLE2 is the default reset method */
		reset_payload[2] = RESET_TYPE_WDISABLE2;

		if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
				    BIT(DSM_SET_WDISABLE2_DELAY))) {
			bt_dev_err(hdev, "No dsm support to set reset delay");
			return;
		}
		argv4.integer.type = ACPI_TYPE_INTEGER;
		/* delay required to toggle BT power */
		argv4.integer.value = 160;
		obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
					DSM_SET_WDISABLE2_DELAY, &argv4);
		if (!obj) {
			bt_dev_err(hdev, "Failed to call dsm to set reset delay");
			return;
		}
		ACPI_FREE(obj);
	}

	bt_dev_info(hdev, "DSM reset method type: 0x%02x", reset_payload[2]);

	if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
			    DSM_SET_RESET_METHOD)) {
		bt_dev_warn(hdev, "No support for dsm to set reset method");
		return;
	}
	argv4.buffer.type = ACPI_TYPE_BUFFER;
	argv4.buffer.length = sizeof(reset_payload);
	argv4.buffer.pointer = reset_payload;

	obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
				DSM_SET_RESET_METHOD, &argv4);
	if (!obj) {
		bt_dev_err(hdev, "Failed to call dsm to set reset method");
		return;
	}
	ACPI_FREE(obj);
	data->acpi_reset_method = btintel_acpi_reset_method;
}

static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
					struct intel_version_tlv *ver)
{
@@ -2528,6 +2649,7 @@ static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
	case 0x18:
	case 0x19:
	case 0x1b:
	case 0x1c:
		hci_set_msft_opcode(hdev, 0xFC1E);
		break;
	default:
@@ -2742,6 +2864,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
	case 0x18:
	case 0x19:
	case 0x1b:
	case 0x1c:
		/* Display version information of TLV type */
		btintel_version_info_tlv(hdev, &ver_tlv);

@@ -2757,6 +2880,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
		/* Setup MSFT Extension support */
		btintel_set_msft_opcode(hdev,
					INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
		btintel_set_dsm_reset_method(hdev, &ver_tlv);

		err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
		btintel_register_devcoredump_support(hdev);
@@ -2824,6 +2948,80 @@ 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)
{
	struct intel_tlv *tlv = (void *)&skb->data[5];

	/* The first event is always an event type TLV */
	if (tlv->type != INTEL_TLV_TYPE_ID)
		goto recv_frame;

	switch (tlv->val[0]) {
	case INTEL_TLV_SYSTEM_EXCEPTION:
	case INTEL_TLV_FATAL_EXCEPTION:
	case INTEL_TLV_DEBUG_EXCEPTION:
	case INTEL_TLV_TEST_EXCEPTION:
		/* Generate devcoredump from exception */
		if (!hci_devcd_init(hdev, skb->len)) {
			hci_devcd_append(hdev, skb);
			hci_devcd_complete(hdev);
		} else {
			bt_dev_err(hdev, "Failed to generate devcoredump");
			kfree_skb(skb);
		}
		return 0;
	default:
		bt_dev_err(hdev, "Invalid exception type %02X", tlv->val[0]);
	}

recv_frame:
	return hci_recv_frame(hdev, skb);
}

int btintel_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 };

	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);
				break;
			case 0x06:
				/* When the firmware loading completes the
				 * device sends out a vendor specific event
				 * indicating the result of the firmware
				 * loading.
				 */
				btintel_secure_send_result(hdev, ptr, len);
				break;
			}
		}

		/* 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);
		}
	}

	return hci_recv_frame(hdev, skb);
}
EXPORT_SYMBOL_GPL(btintel_recv_event);

void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len)
{
	const struct intel_bootup *evt = ptr;
+3 −0
Original line number Diff line number Diff line
@@ -166,12 +166,14 @@ enum {
	INTEL_BROKEN_SHUTDOWN_LED,
	INTEL_ROM_LEGACY,
	INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
	INTEL_ACPI_RESET_ACTIVE,

	__INTEL_NUM_FLAGS,
};

struct btintel_data {
	DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
	int (*acpi_reset_method)(struct hci_dev *hdev);
};

#define btintel_set_flag(hdev, nr)					\
@@ -220,6 +222,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
			      const struct firmware *fw, u32 *boot_param);
int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name);
int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
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);
+133 −0
Original line number Diff line number Diff line
@@ -53,10 +53,61 @@ struct btmtk_section_map {
	};
} __packed;

static void btmtk_coredump(struct hci_dev *hdev)
{
	int err;

	err = __hci_cmd_send(hdev, 0xfd5b, 0, NULL);
	if (err < 0)
		bt_dev_err(hdev, "Coredump failed (%d)", err);
}

static void btmtk_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct btmediatek_data *data = hci_get_priv(hdev);
	char buf[80];

	snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
		 data->dev_id);
	skb_put_data(skb, buf, strlen(buf));

	snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
		 data->cd_info.fw_version);
	skb_put_data(skb, buf, strlen(buf));

	snprintf(buf, sizeof(buf), "Driver: %s\n",
		 data->cd_info.driver_name);
	skb_put_data(skb, buf, strlen(buf));

	snprintf(buf, sizeof(buf), "Vendor: MediaTek\n");
	skb_put_data(skb, buf, strlen(buf));
}

static void btmtk_coredump_notify(struct hci_dev *hdev, int state)
{
	struct btmediatek_data *data = hci_get_priv(hdev);

	switch (state) {
	case HCI_DEVCOREDUMP_IDLE:
		data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
		break;
	case HCI_DEVCOREDUMP_ACTIVE:
		data->cd_info.state = HCI_DEVCOREDUMP_ACTIVE;
		break;
	case HCI_DEVCOREDUMP_TIMEOUT:
	case HCI_DEVCOREDUMP_ABORT:
	case HCI_DEVCOREDUMP_DONE:
		data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
		btmtk_reset_sync(hdev);
		break;
	}
}

int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
			      wmt_cmd_sync_func_t wmt_cmd_sync)
{
	struct btmtk_hci_wmt_params wmt_params;
	struct btmtk_patch_header *hdr;
	struct btmtk_global_desc *globaldesc = NULL;
	struct btmtk_section_map *sectionmap;
	const struct firmware *fw;
@@ -75,9 +126,13 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,

	fw_ptr = fw->data;
	fw_bin_ptr = fw_ptr;
	hdr = (struct btmtk_patch_header *)fw_ptr;
	globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
	section_num = le32_to_cpu(globaldesc->section_num);

	bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
		    le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);

	for (i = 0; i < section_num; i++) {
		first_block = 1;
		fw_ptr = fw_bin_ptr;
@@ -280,6 +335,83 @@ int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
}
EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);

void btmtk_reset_sync(struct hci_dev *hdev)
{
	struct btmediatek_data *reset_work = hci_get_priv(hdev);
	int err;

	hci_dev_lock(hdev);

	err = hci_cmd_sync_queue(hdev, reset_work->reset_sync, NULL, NULL);
	if (err)
		bt_dev_err(hdev, "failed to reset (%d)", err);

	hci_dev_unlock(hdev);
}
EXPORT_SYMBOL_GPL(btmtk_reset_sync);

int btmtk_register_coredump(struct hci_dev *hdev, const char *name,
			    u32 fw_version)
{
	struct btmediatek_data *data = hci_get_priv(hdev);

	if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
		return -EOPNOTSUPP;

	data->cd_info.fw_version = fw_version;
	data->cd_info.state = HCI_DEVCOREDUMP_IDLE;
	data->cd_info.driver_name = name;

	return hci_devcd_register(hdev, btmtk_coredump, btmtk_coredump_hdr,
				  btmtk_coredump_notify);
}
EXPORT_SYMBOL_GPL(btmtk_register_coredump);

int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct btmediatek_data *data = hci_get_priv(hdev);
	int err;

	if (!IS_ENABLED(CONFIG_DEV_COREDUMP))
		return 0;

	switch (data->cd_info.state) {
	case HCI_DEVCOREDUMP_IDLE:
		err = hci_devcd_init(hdev, MTK_COREDUMP_SIZE);
		if (err < 0)
			break;
		data->cd_info.cnt = 0;

		/* It is supposed coredump can be done within 5 seconds */
		schedule_delayed_work(&hdev->dump.dump_timeout,
				      msecs_to_jiffies(5000));
		fallthrough;
	case HCI_DEVCOREDUMP_ACTIVE:
	default:
		err = hci_devcd_append(hdev, skb);
		if (err < 0)
			break;
		data->cd_info.cnt++;

		/* Mediatek coredump data would be more than MTK_COREDUMP_NUM */
		if (data->cd_info.cnt > MTK_COREDUMP_NUM &&
		    skb->len > MTK_COREDUMP_END_LEN)
			if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN],
				    MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) {
				bt_dev_info(hdev, "Mediatek coredump end");
				hci_devcd_complete(hdev);
			}

		break;
	}

	if (err < 0)
		kfree_skb(skb);

	return err;
}
EXPORT_SYMBOL_GPL(btmtk_process_coredump);

MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
@@ -289,3 +421,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7622);
MODULE_FIRMWARE(FIRMWARE_MT7663);
MODULE_FIRMWARE(FIRMWARE_MT7668);
MODULE_FIRMWARE(FIRMWARE_MT7961);
MODULE_FIRMWARE(FIRMWARE_MT7925);
Loading