diff mbox series

[v4] Bluetooth: btusb: Work around for spotty SCO quality

Message ID 20221223085742.2482-1-hildawu@realtek.com
State Superseded
Headers show
Series [v4] Bluetooth: btusb: Work around for spotty SCO quality | expand

Commit Message

Hilda Wu Dec. 23, 2022, 8:57 a.m. UTC
From: Hilda Wu <hildawu@realtek.com>

When streaming HFP, every few minutes a brief pause in audio can be
heard on some platforms with Realtek Bluetooth. Linux based products
may be encountered, but because of the different implementation of
upper-level SCO services, the situation would not necessarily impact
customer experience. But when the issue occurs, the system will see
the SCO packet for unknown connection handle messages.

Note: This issue affects (e)SCO only, does not affect ACLs.
The duplicate data affected the invalid connection handle only
occurs in Realtek BT.
This is to filter out the duplicate packet for avoiding influence.

The btmon trace give a better idea of what we're filtering.
The following excerpts are part of SCO packets in the HCI log:

> SCO Data RX: Handle 11 flags 0x00 dlen 72      #23327 [hci0] 132.343418
        8c a3 55 4f 8a d5 56 e9 35 56 37 8d 55 87 53 55  ..UO..V.5V7.U.SU
        59 66 d5 57 1d b5 54 00 01 08 ad 00 00 e0 10 00  Yf.W..T.........
        00 00 85 c6 d5 60 e9 b5 52 94 6d 54 e4 9b 55 b1  .....`..R.mT..U.
        b6 d5 62 91 b5 57 84 6d 56 e4 5b 55 75 c6 d5 51  ..b..W.mV.[Uu..Q
        2d b5 53 9a 6d 54 a5 1b                          -.S.mT..
< SCO Data TX: Handle 11 flags 0x00 dlen 72      #23328 [hci0] 132.343600
        01 c8 ad 00 00 aa db ba aa a9 72 b4 d9 5d af 14  ..........r..]..
        53 0c 75 b0 a6 f3 8a 51 b3 54 17 b1 a6 d5 62 c5  S.u....Q.T....b.
        d5 6b 35 29 8d c5 1c 56 4c 24 96 9b 8d b5 d7 1a  .k5)...VL$......
        b2 8d bc da 3b 8c 46 ae 1d 4d a4 04 01 f8 ad 00  ....;.F..M......
        00 3d ec bb a9 98 8b 28                          .=.....(
> SCO Data RX: Handle 11 flags 0x00 dlen 72      #23329 [hci0] 132.353419
        55 55 c6 d5 62 29 b5 57 b2 6d 54 00 01 38 ad 00  UU..b).W.mT..8..
        00 e0 10 00 00 00 0b 00 d5 62 55 c6 57 b2 29 b5  .........bU.W.).
        00 01 6d 54 00 00 38 ad 00 00 e0 10 00 00 00 92  ..mT..8.........
        36 d5 5a ed b5 58 6c 6d 55 b3 1b 55 6b 26 d5 52  6.Z..XlmU..Uk&.R
        d1 b5 54 23 6d 56 82 db                          ..T#mV..
< SCO Data TX: Handle 11 flags 0x00 dlen 72      #23330 [hci0] 132.353581
        6d 5b be db 89 34 66 e9 fa 99 a6 6e e5 6d 9f 1a  m[...4f....n.m..
        1c 57 d2 66 92 63 98 99 a9 3b 8a 6c 3e 5b 5a 34  .W.f.c...;.l>[Z4
        a4 96 e2 21 21 8c f8 88 0f 3d e0 52 48 85 18 00  ...!!....=.RH...
        01 08 ad 00 00 0c eb ba a9 a8 28 ca 9a d0 3c 33  ..........(...<3
        45 4a f9 90 fb ca 4b 39                          EJ....K9
> SCO Data RX: Handle 2901 flags 0x0a dlen 54    #23331 [hci0] 132.373416
        d5 48 a9 b5 56 aa 6d 56 d2 db 55 75 36 d5 56 2d  .H..V.mV..Uu6.V-
        b5 57 5b 6d 54 00 0b 00 48 01 c8 ad 00 00 e0 10  .W[mT...H.......
        00 00 00 5e c6 d5 56 e1 b5 56 43 6d 55 ca db 55  ...^..V..VCmU..U
        7d c6 d5 5b 31 b5

We handle is HCI SCO Data RX packets.
The packet 23327 was a normal HCI SCO Data RX packet.
The packet 23329 was the abnormal HCI SCO Data RX packet.
The packet 23331 was the invalid connection handle affected by the
packet 23329 abnormal HCI SCO Data RX packet.

So we expect to filter is the packet 23329 SCO data RX packet case.
As you can see the packet 23329, packet's connection handle (0x0B 00/11)
and length (0x48/72) is normal.
This btmon trace is SCO packets in USB alternate setting 3, payload
length is 72 bytes that is consist of three SCO data packets.
After our investigation, we found that the anomaly is due to the
intermediate composition data.
There is duplicate data in the intermediate composition data, but it
affects packets combination. The system parses the next packet of the
connection handle mistake, so the system see unknown connection
handle messages.

This commit can estimate and find out its abnormal rule to filter the
duplicate packet out for avoiding influence.
Check franments and filtering out the abnormal packet and then it will
not affect the system parsing of the conenction handle subsequent.
This commit can filter out the invalid connection handle, avoid the
spotty SCO quality.

Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
Signed-off-by: Hilda Wu <hildawu@realtek.com>
---
Changes in v4:
 - Fix typos and add more in commit description.
 - Modify comparison method.

Changes in v3:
 - Use the vendor function to replace btus_recv_isoc
 - Additional info: The comparison of btrtl_usb_recv_isoc here is
   for invalid handle, the invalid handle shouldn't appear.
   So we try to find out the rule and filter out this.

Changes in v2:
 - Seperate commits for functions
---
---
 drivers/bluetooth/btrtl.c | 33 ++++++++++++++++
 drivers/bluetooth/btrtl.h |  7 ++++
 drivers/bluetooth/btusb.c | 80 ++++++++++++++++++++++++++++++++++++++-
 3 files changed, 119 insertions(+), 1 deletion(-)

Comments

bluez.test.bot@gmail.com Dec. 23, 2022, 9:35 a.m. UTC | #1
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=706705

---Test result---

Test Summary:
CheckPatch                    PASS      1.21 seconds
GitLint                       PASS      0.21 seconds
SubjectPrefix                 PASS      0.05 seconds
BuildKernel                   PASS      38.85 seconds
CheckAllWarning               PASS      42.62 seconds
CheckSparse                   PASS      47.92 seconds
BuildKernel32                 PASS      39.61 seconds
TestRunnerSetup               PASS      549.90 seconds
TestRunner_l2cap-tester       PASS      19.61 seconds
TestRunner_iso-tester         PASS      21.62 seconds
TestRunner_bnep-tester        PASS      7.01 seconds
TestRunner_mgmt-tester        PASS      133.72 seconds
TestRunner_rfcomm-tester      PASS      11.18 seconds
TestRunner_sco-tester         PASS      10.18 seconds
TestRunner_ioctl-tester       PASS      12.15 seconds
TestRunner_mesh-tester        PASS      9.09 seconds
TestRunner_smp-tester         PASS      10.09 seconds
TestRunner_userchan-tester    PASS      7.42 seconds
IncrementalBuild              PASS      37.98 seconds



---
Regards,
Linux Bluetooth
Paul Menzel Dec. 24, 2022, 8:17 a.m. UTC | #2
Dear Hilda,


Thank you for the patch. For the subject the *for* is superfluous:

Work around spotty SCO quality

Am 23.12.22 um 09:57 schrieb hildawu@realtek.com:
> From: Hilda Wu <hildawu@realtek.com>
> 
> When streaming HFP, every few minutes a brief pause in audio can be
> heard on some platforms with Realtek Bluetooth. Linux based products
> may be encountered, but because of the different implementation of
> upper-level SCO services, the situation would not necessarily impact
> customer experience. But when the issue occurs, the system will see
> the SCO packet for unknown connection handle messages.
> 
> Note: This issue affects (e)SCO only, does not affect ACLs.
> The duplicate data affected the invalid connection handle only
> occurs in Realtek BT.
> This is to filter out the duplicate packet for avoiding influence.
> 
> The btmon trace give a better idea of what we're filtering.

give*s*

> The following excerpts are part of SCO packets in the HCI log:
> 
>> SCO Data RX: Handle 11 flags 0x00 dlen 72      #23327 [hci0] 132.343418
>          8c a3 55 4f 8a d5 56 e9 35 56 37 8d 55 87 53 55  ..UO..V.5V7.U.SU
>          59 66 d5 57 1d b5 54 00 01 08 ad 00 00 e0 10 00  Yf.W..T.........
>          00 00 85 c6 d5 60 e9 b5 52 94 6d 54 e4 9b 55 b1  .....`..R.mT..U.
>          b6 d5 62 91 b5 57 84 6d 56 e4 5b 55 75 c6 d5 51  ..b..W.mV.[Uu..Q
>          2d b5 53 9a 6d 54 a5 1b                          -.S.mT..
> < SCO Data TX: Handle 11 flags 0x00 dlen 72      #23328 [hci0] 132.343600
>          01 c8 ad 00 00 aa db ba aa a9 72 b4 d9 5d af 14  ..........r..]..
>          53 0c 75 b0 a6 f3 8a 51 b3 54 17 b1 a6 d5 62 c5  S.u....Q.T....b.
>          d5 6b 35 29 8d c5 1c 56 4c 24 96 9b 8d b5 d7 1a  .k5)...VL$......
>          b2 8d bc da 3b 8c 46 ae 1d 4d a4 04 01 f8 ad 00  ....;.F..M......
>          00 3d ec bb a9 98 8b 28                          .=.....(
>> SCO Data RX: Handle 11 flags 0x00 dlen 72      #23329 [hci0] 132.353419
>          55 55 c6 d5 62 29 b5 57 b2 6d 54 00 01 38 ad 00  UU..b).W.mT..8..
>          00 e0 10 00 00 00 0b 00 d5 62 55 c6 57 b2 29 b5  .........bU.W.).
>          00 01 6d 54 00 00 38 ad 00 00 e0 10 00 00 00 92  ..mT..8.........
>          36 d5 5a ed b5 58 6c 6d 55 b3 1b 55 6b 26 d5 52  6.Z..XlmU..Uk&.R
>          d1 b5 54 23 6d 56 82 db                          ..T#mV..
> < SCO Data TX: Handle 11 flags 0x00 dlen 72      #23330 [hci0] 132.353581
>          6d 5b be db 89 34 66 e9 fa 99 a6 6e e5 6d 9f 1a  m[...4f....n.m..
>          1c 57 d2 66 92 63 98 99 a9 3b 8a 6c 3e 5b 5a 34  .W.f.c...;.l>[Z4
>          a4 96 e2 21 21 8c f8 88 0f 3d e0 52 48 85 18 00  ...!!....=.RH...
>          01 08 ad 00 00 0c eb ba a9 a8 28 ca 9a d0 3c 33  ..........(...<3
>          45 4a f9 90 fb ca 4b 39                          EJ....K9
>> SCO Data RX: Handle 2901 flags 0x0a dlen 54    #23331 [hci0] 132.373416
>          d5 48 a9 b5 56 aa 6d 56 d2 db 55 75 36 d5 56 2d  .H..V.mV..Uu6.V-
>          b5 57 5b 6d 54 00 0b 00 48 01 c8 ad 00 00 e0 10  .W[mT...H.......
>          00 00 00 5e c6 d5 56 e1 b5 56 43 6d 55 ca db 55  ...^..V..VCmU..U
>          7d c6 d5 5b 31 b5
> 
> We handle is HCI SCO Data RX packets.
> The packet 23327 was a normal HCI SCO Data RX packet.
> The packet 23329 was the abnormal HCI SCO Data RX packet.
> The packet 23331 was the invalid connection handle affected by the
> packet 23329 abnormal HCI SCO Data RX packet.
> 
> So we expect to filter is the packet 23329 SCO data RX packet case.
> As you can see the packet 23329, packet's connection handle (0x0B 00/11)
> and length (0x48/72) is normal.
> This btmon trace is SCO packets in USB alternate setting 3, payload
> length is 72 bytes that is consist of three SCO data packets.
> After our investigation, we found that the anomaly is due to the
> intermediate composition data.
> There is duplicate data in the intermediate composition data, but it
> affects packets combination. The system parses the next packet of the
> connection handle mistake, so the system see unknown connection
> handle messages.
> 
> This commit can estimate and find out its abnormal rule to filter the
> duplicate packet out for avoiding influence.
> Check franments and filtering out the abnormal packet and then it will

fragments

> not affect the system parsing of the conenction handle subsequent.

connection

> This commit can filter out the invalid connection handle, avoid the

handle, and avoid …

> spotty SCO quality.
> 
> Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
> Signed-off-by: Hilda Wu <hildawu@realtek.com>

[…]


Kind regards,

Paul
diff mbox series

Patch

diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 69c3fe649ca7..a0a33d2467ef 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -944,6 +944,39 @@  int btrtl_get_uart_settings(struct hci_dev *hdev,
 }
 EXPORT_SYMBOL_GPL(btrtl_get_uart_settings);
 
+int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *p, u16 wMaxPacketSize)
+{
+	u8 *prev;
+	u8 tmp[8];
+	u8 zero[1] = {0};
+	u32 *prev_frag_a;
+	u32 *prev_frag_b;
+
+	/* Issue was found when alt was set to 3 or bigger */
+	if (wMaxPacketSize < 25)
+		return 0;
+
+	/* The first fragment is always correct. */
+	if (pos < wMaxPacketSize)
+		return 0;
+
+	if (memcmp(p, zero, sizeof(zero))) {
+		prev = data + (pos - wMaxPacketSize);
+		memcpy(tmp, prev + 4, 8);
+		prev_frag_a = (u32 *)(tmp);
+		prev_frag_b = (u32 *)(tmp + 4);
+		*prev_frag_a = swahw32(*prev_frag_a);
+		*prev_frag_b = swahw32(*prev_frag_b);
+
+		/* Check the current fragment with the previous one. */
+		if (!memcmp(p, prev, 2) && !memcmp(p + 2, tmp, 8))
+			return -1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(btrtl_usb_recv_isoc);
+
 MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
 MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION);
 MODULE_VERSION(VERSION);
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index ebf0101c959b..893f1eae57e2 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -83,6 +83,7 @@  int btrtl_get_uart_settings(struct hci_dev *hdev,
 			    struct btrtl_device_info *btrtl_dev,
 			    unsigned int *controller_baudrate,
 			    u32 *device_baudrate, bool *flow_control);
+int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *buffer, u16 wMaxPacketSize);
 
 #else
 
@@ -126,4 +127,10 @@  static inline int btrtl_get_uart_settings(struct hci_dev *hdev,
 	return -ENOENT;
 }
 
+static inline int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *buffer,
+					u16 wMaxPacketSize)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index afd2f08ffe30..47e4dcaec948 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -792,6 +792,7 @@  struct btusb_data {
 	int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
 	int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
 	int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
+	int (*recv_isoc)(struct btusb_data *data, void *buffer, int count);
 
 	int (*setup_on_usb)(struct hci_dev *hdev);
 
@@ -1394,7 +1395,7 @@  static void btusb_isoc_complete(struct urb *urb)
 
 			hdev->stat.byte_rx += length;
 
-			if (btusb_recv_isoc(data, urb->transfer_buffer + offset,
+			if (data->recv_isoc(data, urb->transfer_buffer + offset,
 					    length) < 0) {
 				bt_dev_err(hdev, "corrupted SCO packet");
 				hdev->stat.err_rx++;
@@ -2492,6 +2493,80 @@  static int btusb_setup_realtek(struct hci_dev *hdev)
 	return ret;
 }
 
+static int btusb_recv_isoc_realtek(struct btusb_data *data, void *buffer,
+				   int count)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+	int err = 0;
+	u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
+
+	spin_lock_irqsave(&data->rxlock, flags);
+	skb = data->sco_skb;
+
+	while (count) {
+		int len;
+
+		if (!skb) {
+			skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC);
+			if (!skb) {
+				err = -ENOMEM;
+				break;
+			}
+
+			hci_skb_pkt_type(skb) = HCI_SCODATA_PKT;
+			hci_skb_expect(skb) = HCI_SCO_HDR_SIZE;
+		}
+
+		len = min_t(uint, hci_skb_expect(skb), count);
+
+		/* Gaps in audio could be heard while streaming WBS using USB
+		 * alt settings 3 on some platforms, since this is only used
+		 * with RTK chips so let vendor function detect it.
+		 */
+		if (!btusb_find_altsetting(data, 6) &&
+			test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags)) {
+			err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
+						wMaxPacketSize);
+			if (err)
+				break;
+		}
+
+		skb_put_data(skb, buffer, len);
+
+		count -= len;
+		buffer += len;
+		hci_skb_expect(skb) -= len;
+
+		if (skb->len == HCI_SCO_HDR_SIZE) {
+			/* Complete SCO header */
+			struct hci_sco_hdr *hdr = hci_sco_hdr(skb);
+
+			hci_skb_expect(skb) = hdr->dlen;
+
+			if (skb_tailroom(skb) < hci_skb_expect(skb) ||
+			    !btusb_validate_sco_handle(data->hdev, hdr)) {
+				kfree_skb(skb);
+				skb = NULL;
+
+				err = -EILSEQ;
+				break;
+			}
+		}
+
+		if (!hci_skb_expect(skb)) {
+			/* Complete frame */
+			hci_recv_frame(data->hdev, skb);
+			skb = NULL;
+		}
+	}
+
+	data->sco_skb = skb;
+	spin_unlock_irqrestore(&data->rxlock, flags);
+
+	return err;
+}
+
 /* UHW CR mapping */
 #define MTK_BT_MISC		0x70002510
 #define MTK_BT_SUBSYS_RST	0x70002610
@@ -3924,6 +3999,7 @@  static int btusb_probe(struct usb_interface *intf,
 
 	data->recv_event = hci_recv_frame;
 	data->recv_bulk = btusb_recv_bulk;
+	data->recv_isoc = btusb_recv_isoc;
 
 	if (id->driver_info & BTUSB_INTEL_COMBINED) {
 		/* Allocate extra space for Intel device */
@@ -4097,6 +4173,8 @@  static int btusb_probe(struct usb_interface *intf,
 		hdev->shutdown = btrtl_shutdown_realtek;
 		hdev->cmd_timeout = btusb_rtl_cmd_timeout;
 
+		data->recv_isoc = btusb_recv_isoc_realtek;
+
 		/* Realtek devices need to set remote wakeup on auto-suspend */
 		set_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags);
 		set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags);