Skip to contentSkip to conversation

Bluetooth: btusb: MediaTek ISO data transmission

PATCH Superseded Chris Lu 2 participants 6 messages Jun 6, 2024

Subsystems (3)

v3 of 7 Superseded Latest is v7 →

lore
Share & tools
lore

Chris Lu

author
#0 lore raw

v3 cover Bluetooth: btusb: MediaTek ISO data transmission

Since SIG has not yet clearly defined the specification for ISO data transmission over USB, MediaTek has adopted a method of adding an additional interrupt endpoint for ISO data transmission. This approach differs from the current method used in the Bluetooth upstream driver, which utilizes existing bulk endpoints. The interrupt endpoint provides guaranteed bandwidth, sufficient maximum data length for ISO packets and error checking.

Certain new functions related to USB transportation, such as urb allocation and submission, are implemented in btusb.c to leverage existing functions and data structures defined therein. Meanwhile, vendor-specific functions unrelated to transportation have been moved to btmtk.c to streamline btusb.c.

Chris Lu (4):
Bluetooth: net: add hci_iso_hdr function for iso data
Bluetooth: btusb: add callback function in btusb suspend/resume
Bluetooth: btmtk: add macro to get/set/clear MediaTek defined flags
Bluetooth: btusb: mediatek: add ISO data transmission functions

 drivers/bluetooth/btmtk.c   |  92 ++++++++++++
 drivers/bluetooth/btmtk.h   |  61 ++++++++
 drivers/bluetooth/btusb.c   | 276 ++++++++++++++++++++++++++++++++++++
 include/net/bluetooth/hci.h |   5 +
 4 files changed, 434 insertions(+)
Signature · 1 line
2.18.0
author
#1 lore raw

PATCH v3 1/4 Bluetooth: net: add hci_iso_hdr function for iso data

Add function hci_iso_hdr to get skb->data when packet type is ISO.

---
 include/net/bluetooth/hci.h | 5 +++++
 1 file changed, 5 insertions(+)
include/net/bluetooth/hci.h +5 -0
index e372a88e8c3f..b9f8f91f6c7f 100644
@@ -2898,6 +2898,11 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 	return (struct hci_sco_hdr *) skb->data;
 }
 
+static inline struct hci_iso_hdr *hci_iso_hdr(const struct sk_buff *skb)
+{
+	return (struct hci_iso_hdr *) skb->data;
+}
+
 /* Command opcode pack/unpack */
 #define hci_opcode_pack(ogf, ocf)	((__u16) ((ocf & 0x03ff)|(ogf << 10)))
 #define hci_opcode_ogf(op)		(op >> 10)
Signature · 1 line
2.18.0
#2 lore raw

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list. This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=859426

---Test result---

Test Summary:

CheckPatch                    PASS      5.18 seconds
GitLint                       PASS      1.16 seconds
SubjectPrefix                 PASS      0.45 seconds
BuildKernel                   PASS      30.20 seconds
CheckAllWarning               PASS      33.84 seconds
CheckSparse                   WARNING   41.27 seconds
CheckSmatch                   FAIL      34.71 seconds
BuildKernel32                 PASS      29.16 seconds
TestRunnerSetup               PASS      526.28 seconds
TestRunner_l2cap-tester       PASS      20.49 seconds
TestRunner_iso-tester         PASS      28.40 seconds
TestRunner_bnep-tester        PASS      4.77 seconds
TestRunner_mgmt-tester        PASS      113.01 seconds
TestRunner_rfcomm-tester      PASS      8.09 seconds
TestRunner_sco-tester         PASS      14.98 seconds
TestRunner_ioctl-tester       PASS      7.74 seconds
TestRunner_mesh-tester        PASS      5.85 seconds
TestRunner_smp-tester         PASS      6.85 seconds
TestRunner_userchan-tester    PASS      4.95 seconds
IncrementalBuild              PASS      46.45 seconds

Details
##############################
Test: CheckSparse - WARNING
Desc: Run sparse tool with linux kernel
Output:
drivers/bluetooth/btmtk.c:501:45: warning: incorrect type in assignment (different base types)drivers/bluetooth/btmtk.c:501:45: expected unsigned short [usertype] expectdrivers/bluetooth/btmtk.c:501:45: got restricted __le16 [usertype] dlen
##############################
Test: CheckSmatch - FAIL
Desc: Run smatch tool with source
Output:

Segmentation fault (core dumped)
make[4]: *** [scripts/Makefile.build:244: net/bluetooth/hci_core.o] Error 139 make[4]: *** Deleting file 'net/bluetooth/hci_core.o'
make[3]: *** [scripts/Makefile.build:485: net/bluetooth] Error 2 make[2]: *** [scripts/Makefile.build:485: net] Error 2
make[2]: *** Waiting for unfinished jobs....
Segmentation fault (core dumped)
make[4]: *** [scripts/Makefile.build:244: drivers/bluetooth/bcm203x.o] Error 139 make[4]: *** Deleting file 'drivers/bluetooth/bcm203x.o'
make[4]: *** Waiting for unfinished jobs....
make[3]: *** [scripts/Makefile.build:485: drivers/bluetooth] Error 2 make[2]: *** [scripts/Makefile.build:485: drivers] Error 2
make[1]: *** [/github/workspace/src/src/Makefile:1919: .] Error 2
make: *** [Makefile:240: __sub-make] Error 2

---
Regards,
Linux Bluetooth

author
#3 lore raw

PATCH v3 2/4 Bluetooth: btusb: add callback function in btusb suspend/resume

In reply to Chris Lu

Add new function: dev_suspend/dev_resume in btusb_data which are reserved for vendor specific usage during suspend/resume. dev_suspend will be added before stop traffic in btusb_suspend and dev_resume will be added after resubmit urb in btusb_resuem.

---
 drivers/bluetooth/btusb.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/bluetooth/btusb.c +9 -0
index 79aefdb3324d..83765c0c14b4 100644
@@ -891,6 +891,9 @@ struct btusb_data {
 
 	int (*setup_on_usb)(struct hci_dev *hdev);
 
+	int (*dev_suspend)(struct hci_dev *hdev);
+	int (*dev_resume)(struct hci_dev *hdev);
+
 	int oob_wake_irq;   /* irq for out-of-band wake-on-bt */
 	unsigned cmd_timeout_cnt;
 
@@ -4715,6 +4718,9 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
 
 	cancel_work_sync(&data->work);
 
+	if (data->dev_suspend)
+		data->dev_suspend(data->hdev);
+
 	btusb_stop_traffic(data);
 	usb_kill_anchored_urbs(&data->tx_anchor);
 
@@ -4818,6 +4824,9 @@ static int btusb_resume(struct usb_interface *intf)
 			btusb_submit_isoc_urb(hdev, GFP_NOIO);
 	}
 
+	if (data->dev_resume)
+		data->dev_resume(hdev);
+
 	spin_lock_irq(&data->txlock);
 	play_deferred(data);
 	clear_bit(BTUSB_SUSPENDING, &data->flags);
Signature · 1 line
2.18.0
author
#4 lore raw

PATCH v3 3/4 Bluetooth: btmtk: add macro to get/set/clear MediaTek defined flags

In reply to Chris Lu

Define a enumeration to store MediaTek specific flags and macro function to set/test/clear the flags in data structure.

---
 drivers/bluetooth/btmtk.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
drivers/bluetooth/btmtk.h +23 -0
index e76b8a358be8..6a0697a22b16 100644
@@ -128,6 +128,10 @@ struct btmtk_hci_wmt_params {
 
 typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
 
+enum {
+	__BTMTK_NUM_FLAGS,
+};
+
 struct btmtk_coredump_info {
 	const char *driver_name;
 	u32 fw_version;
@@ -136,11 +140,30 @@ struct btmtk_coredump_info {
 };
 
 struct btmediatek_data {
+	DECLARE_BITMAP(flags, __BTMTK_NUM_FLAGS);
+
 	u32 dev_id;
 	btmtk_reset_sync_func_t reset_sync;
 	struct btmtk_coredump_info cd_info;
 };
 
+#define btmtk_set_flag(hdev, nr)						\
+	do {									\
+		struct btmediatek_data *mediatek = hci_get_priv((hdev));	\
+		set_bit((nr), mediatek->flags);					\
+	} while (0)
+
+#define btmtk_clear_flag(hdev, nr)						\
+	do {									\
+		struct btmediatek_data *mediatek = hci_get_priv((hdev));	\
+		clear_bit((nr), mediatek->flags);				\
+	} while (0)
+
+#define btmtk_get_flag(hdev)							\
+	(((struct btmediatek_data *)hci_get_priv(hdev))->flags)
+
+#define btmtk_test_flag(hdev, nr)	test_bit((nr), btmtk_get_flag(hdev))
+
 typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
 				   struct btmtk_hci_wmt_params *);
 
Signature · 1 line
2.18.0
author
#5 lore raw

PATCH v3 4/4 Bluetooth: btusb: mediatek: add ISO data transmission functions

In reply to Chris Lu

This patch implements functions for ISO data send and receive in btusb driver for MediaTek's controller.

MediaTek defines a specific interrupt endpoint for ISO data transmissin because the characteristics of interrupt endpoint are similar to the application of ISO data which can support guaranteed transmissin bandwidth, enough maximum data length and error checking mechanism.

Driver sets up ISO interface and endpoints in btusb_mtk_setup and clears the setup in btusb_mtk_shutdown. ISO packet anchor stops when driver suspend and resubmit iso urb in driver resume.

---
 drivers/bluetooth/btmtk.c |  92 +++++++++++++
 drivers/bluetooth/btmtk.h |  38 ++++++
 drivers/bluetooth/btusb.c | 267 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 397 insertions(+)
drivers/bluetooth/btmtk.c +92 -0
index a27c251bf56e..5cb23c912f45 100644
@@ -19,6 +19,9 @@
 #define MTK_SEC_MAP_COMMON_SIZE	12
 #define MTK_SEC_MAP_NEED_SEND_SIZE	52
 
+/* It is for mt79xx iso data transmission setting */
+#define MTK_ISO_THRESHOLD	264
+
 struct btmtk_patch_header {
 	u8 datetime[16];
 	u8 platform[4];
@@ -431,6 +434,95 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(btmtk_process_coredump);
 
+int btmtk_isointf_setup(struct hci_dev *hdev)
+{
+	u8 iso_param[2] = { 0x08, 0x01 };
+	struct sk_buff *skb;
+
+	skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param,
+			     HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb)) {
+		bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb));
+		return PTR_ERR(skb);
+	}
+	kfree_skb(skb);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(btmtk_isointf_setup);
+
+int btmtk_isopkt_pad(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	if (skb->len > MTK_ISO_THRESHOLD)
+		return -EINVAL;
+
+	if (skb_pad(skb, MTK_ISO_THRESHOLD - skb->len))
+		return -ENOMEM;
+
+	__skb_put(skb, MTK_ISO_THRESHOLD - skb->len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(btmtk_isopkt_pad);
+
+int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
+{
+	struct btmediatek_data *btmtk_data = hci_get_priv(hdev);
+	struct sk_buff *skb;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&btmtk_data->isopkt_info.isorxlock, flags);
+	skb = btmtk_data->isopkt_info.isopkt_skb;
+
+	while (count) {
+		int len;
+
+		if (!skb) {
+			skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC);
+			if (!skb) {
+				err = -ENOMEM;
+				break;
+			}
+
+			hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
+			hci_skb_expect(skb) = HCI_ISO_HDR_SIZE;
+		}
+
+		len = min_t(uint, hci_skb_expect(skb), count);
+		skb_put_data(skb, buffer, len);
+
+		count -= len;
+		buffer += len;
+		hci_skb_expect(skb) -= len;
+
+		if (skb->len == HCI_ISO_HDR_SIZE) {
+			/* Complete ISO header */
+			hci_skb_expect(skb) = hci_iso_hdr(skb)->dlen;
+
+			if (skb_tailroom(skb) < hci_skb_expect(skb)) {
+				kfree_skb(skb);
+				skb = NULL;
+
+				err = -EILSEQ;
+				break;
+			}
+		}
+
+		if (!hci_skb_expect(skb)) {
+			/* Complete frame */
+			hci_recv_frame(hdev, skb);
+			skb = NULL;
+		}
+	}
+
+	btmtk_data->isopkt_info.isopkt_skb = skb;
+	spin_unlock_irqrestore(&btmtk_data->isopkt_info.isorxlock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(btmtk_recv_isopkt);
+
 MODULE_AUTHOR("Sean Wang <[email protected]>");
 MODULE_AUTHOR("Mark Chen <[email protected]>");
 MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
drivers/bluetooth/btmtk.h +38 -0
index 6a0697a22b16..cb9dc4ccc266 100644
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: ISC */
 /* Copyright (C) 2021 MediaTek Inc. */
 
+#include <linux/usb.h>
+
 #define FIRMWARE_MT7622		"mediatek/mt7622pr2h.bin"
 #define FIRMWARE_MT7663		"mediatek/mt7663pr2h.bin"
 #define FIRMWARE_MT7668		"mediatek/mt7668pr2h.bin"
@@ -129,6 +131,9 @@ struct btmtk_hci_wmt_params {
 typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *);
 
 enum {
+	BTMTK_ISOPKT_OVER_INTR,
+	BTMTK_ISOPKT_RUNNING,
+
 	__BTMTK_NUM_FLAGS,
 };
 
@@ -139,12 +144,24 @@ struct btmtk_coredump_info {
 	int state;
 };
 
+struct btmtk_isopkt_info {
+	struct usb_endpoint_descriptor *isopkt_tx_ep;
+	struct usb_endpoint_descriptor *isopkt_rx_ep;
+	struct usb_interface *isopkt_intf;
+	struct usb_anchor isopkt_anchor;
+	struct sk_buff *isopkt_skb;
+
+	/* spinlock for ISO data transmission */
+	spinlock_t isorxlock;
+};
+
 struct btmediatek_data {
 	DECLARE_BITMAP(flags, __BTMTK_NUM_FLAGS);
 
 	u32 dev_id;
 	btmtk_reset_sync_func_t reset_sync;
 	struct btmtk_coredump_info cd_info;
+	struct btmtk_isopkt_info isopkt_info;
 };
 
 #define btmtk_set_flag(hdev, nr)						\
@@ -186,6 +203,12 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb);
 
 void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,
 			   u32 fw_flavor);
+
+int btmtk_isointf_setup(struct hci_dev *hdev);
+
+int btmtk_isopkt_pad(struct hci_dev *hdev, struct sk_buff *skb);
+
+int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count);
 #else
 
 static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
@@ -225,4 +248,19 @@ static void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id,
 				  u32 fw_ver, u32 fw_flavor)
 {
 }
+
+static int btmtk_isointf_setup(struct hci_dev *hdev)
+{
+	return -EOPNOTSUPP;
+}
+
+static int btmtk_isopkt_pad(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	return ERR_PTR(-EOPNOTSUPP);
+}
+
+static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count)
+{
+	return -EOPNOTSUPP;
+}
 #endif
drivers/bluetooth/btusb.c +267 -0

312 lines not on this page · raw message

Signature · 1 line
2.18.0