Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: hci_core: Enable buffer flow control for SCO/eSCO

This enables buffer flow control for SCO/eSCO
(see: Bluetooth Core 6.0 spec: 6.22. Synchronous Flow Control Enable),
recently this has caused the following problem and is actually a nice
addition for the likes of Socket TX complete:

< HCI Command: Read Buffer Size (0x04|0x0005) plen 0
> HCI Event: Command Complete (0x0e) plen 11
Read Buffer Size (0x04|0x0005) ncmd 1
Status: Success (0x00)
ACL MTU: 1021 ACL max packet: 5
SCO MTU: 240 SCO max packet: 8
...
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
> HCI Event: Hardware Error (0x10) plen 1
Code: 0x0a

To fix the code will now attempt to enable buffer flow control when
HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED is set by the driver:

< HCI Command: Write Sync Fl.. (0x03|0x002f) plen 1
Flow control: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4
Write Sync Flow Control Enable (0x03|0x002f) ncmd 1
Status: Success (0x00)

On success then HCI_SCO_FLOWCTL would be set which indicates sco_cnt
shall be used for flow contro.

Fixes: 7fedd3bb6b77 ("Bluetooth: Prioritize SCO traffic")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tested-by: Pauli Virtanen <pav@iki.fi>

+68 -34
+13
include/net/bluetooth/hci.h
··· 208 208 */ 209 209 HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, 210 210 211 + /* When this quirk is set consider Sync Flow Control as supported by 212 + * the driver. 213 + * 214 + * This quirk must be set before hci_register_dev is called. 215 + */ 216 + HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED, 217 + 211 218 /* When this quirk is set, the LE states reported through the 212 219 * HCI_LE_READ_SUPPORTED_STATES are invalid/broken. 213 220 * ··· 455 448 HCI_WIDEBAND_SPEECH_ENABLED, 456 449 HCI_EVENT_FILTER_CONFIGURED, 457 450 HCI_PA_SYNC, 451 + HCI_SCO_FLOWCTL, 458 452 459 453 HCI_DUT_MODE, 460 454 HCI_VENDOR_DIAG, ··· 1550 1542 __u8 status; 1551 1543 __le16 handle; 1552 1544 __s8 tx_power; 1545 + } __packed; 1546 + 1547 + #define HCI_OP_WRITE_SYNC_FLOWCTL 0x0c2f 1548 + struct hci_cp_write_sync_flowctl { 1549 + __u8 enable; 1553 1550 } __packed; 1554 1551 1555 1552 #define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
+1
include/net/bluetooth/hci_core.h
··· 1858 1858 #define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD) 1859 1859 #define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF) 1860 1860 #define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK) 1861 + #define lmp_sco_capable(dev) ((dev)->features[0][1] & LMP_SCO) 1861 1862 #define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ) 1862 1863 #define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO) 1863 1864 #define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
+28 -34
net/bluetooth/hci_core.c
··· 3552 3552 } 3553 3553 3554 3554 /* Schedule SCO */ 3555 - static void hci_sched_sco(struct hci_dev *hdev) 3555 + static void hci_sched_sco(struct hci_dev *hdev, __u8 type) 3556 3556 { 3557 3557 struct hci_conn *conn; 3558 3558 struct sk_buff *skb; 3559 - int quote; 3559 + int quote, *cnt; 3560 + unsigned int pkts = hdev->sco_pkts; 3560 3561 3561 - BT_DBG("%s", hdev->name); 3562 + bt_dev_dbg(hdev, "type %u", type); 3562 3563 3563 - if (!hci_conn_num(hdev, SCO_LINK)) 3564 + if (!hci_conn_num(hdev, type) || !pkts) 3564 3565 return; 3565 3566 3566 - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) { 3567 + /* Use sco_pkts if flow control has not been enabled which will limit 3568 + * the amount of buffer sent in a row. 3569 + */ 3570 + if (!hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL)) 3571 + cnt = &pkts; 3572 + else 3573 + cnt = &hdev->sco_cnt; 3574 + 3575 + while (*cnt && (conn = hci_low_sent(hdev, type, &quote))) { 3567 3576 while (quote-- && (skb = skb_dequeue(&conn->data_q))) { 3568 3577 BT_DBG("skb %p len %d", skb, skb->len); 3569 3578 hci_send_frame(hdev, skb); ··· 3580 3571 conn->sent++; 3581 3572 if (conn->sent == ~0) 3582 3573 conn->sent = 0; 3574 + (*cnt)--; 3583 3575 } 3584 3576 } 3585 - } 3586 3577 3587 - static void hci_sched_esco(struct hci_dev *hdev) 3588 - { 3589 - struct hci_conn *conn; 3590 - struct sk_buff *skb; 3591 - int quote; 3592 - 3593 - BT_DBG("%s", hdev->name); 3594 - 3595 - if (!hci_conn_num(hdev, ESCO_LINK)) 3596 - return; 3597 - 3598 - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, 3599 - &quote))) { 3600 - while (quote-- && (skb = skb_dequeue(&conn->data_q))) { 3601 - BT_DBG("skb %p len %d", skb, skb->len); 3602 - hci_send_frame(hdev, skb); 3603 - 3604 - conn->sent++; 3605 - if (conn->sent == ~0) 3606 - conn->sent = 0; 3607 - } 3608 - } 3578 + /* Rescheduled if all packets were sent and flow control is not enabled 3579 + * as there could be more packets queued that could not be sent and 3580 + * since no HCI_EV_NUM_COMP_PKTS event will be generated the reschedule 3581 + * needs to be forced. 3582 + */ 3583 + if (!pkts && !hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL)) 3584 + queue_work(hdev->workqueue, &hdev->tx_work); 3609 3585 } 3610 3586 3611 3587 static void hci_sched_acl_pkt(struct hci_dev *hdev) ··· 3626 3632 chan->conn->sent++; 3627 3633 3628 3634 /* Send pending SCO packets right away */ 3629 - hci_sched_sco(hdev); 3630 - hci_sched_esco(hdev); 3635 + hci_sched_sco(hdev, SCO_LINK); 3636 + hci_sched_sco(hdev, ESCO_LINK); 3631 3637 } 3632 3638 } 3633 3639 ··· 3682 3688 chan->conn->sent++; 3683 3689 3684 3690 /* Send pending SCO packets right away */ 3685 - hci_sched_sco(hdev); 3686 - hci_sched_esco(hdev); 3691 + hci_sched_sco(hdev, SCO_LINK); 3692 + hci_sched_sco(hdev, ESCO_LINK); 3687 3693 } 3688 3694 } 3689 3695 ··· 3728 3734 3729 3735 if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { 3730 3736 /* Schedule queues and send stuff to HCI driver */ 3731 - hci_sched_sco(hdev); 3732 - hci_sched_esco(hdev); 3737 + hci_sched_sco(hdev, SCO_LINK); 3738 + hci_sched_sco(hdev, ESCO_LINK); 3733 3739 hci_sched_iso(hdev); 3734 3740 hci_sched_acl(hdev); 3735 3741 hci_sched_le(hdev);
+2
net/bluetooth/hci_event.c
··· 4445 4445 break; 4446 4446 4447 4447 case SCO_LINK: 4448 + case ESCO_LINK: 4448 4449 hdev->sco_cnt += count; 4449 4450 if (hdev->sco_cnt > hdev->sco_pkts) 4450 4451 hdev->sco_cnt = hdev->sco_pkts; 4452 + 4451 4453 break; 4452 4454 4453 4455 case ISO_LINK:
+24
net/bluetooth/hci_sync.c
··· 3769 3769 sizeof(param), &param, HCI_CMD_TIMEOUT); 3770 3770 } 3771 3771 3772 + /* Enable SCO flow control if supported */ 3773 + static int hci_write_sync_flowctl_sync(struct hci_dev *hdev) 3774 + { 3775 + struct hci_cp_write_sync_flowctl cp; 3776 + int err; 3777 + 3778 + /* Check if the controller supports SCO and HCI_OP_WRITE_SYNC_FLOWCTL */ 3779 + if (!lmp_sco_capable(hdev) || !(hdev->commands[10] & BIT(4)) || 3780 + !test_bit(HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED, &hdev->quirks)) 3781 + return 0; 3782 + 3783 + memset(&cp, 0, sizeof(cp)); 3784 + cp.enable = 0x01; 3785 + 3786 + err = __hci_cmd_sync_status(hdev, HCI_OP_WRITE_SYNC_FLOWCTL, 3787 + sizeof(cp), &cp, HCI_CMD_TIMEOUT); 3788 + if (!err) 3789 + hci_dev_set_flag(hdev, HCI_SCO_FLOWCTL); 3790 + 3791 + return err; 3792 + } 3793 + 3772 3794 /* BR Controller init stage 2 command sequence */ 3773 3795 static const struct hci_init_stage br_init2[] = { 3774 3796 /* HCI_OP_READ_BUFFER_SIZE */ ··· 3809 3787 HCI_INIT(hci_clear_event_filter_sync), 3810 3788 /* HCI_OP_WRITE_CA_TIMEOUT */ 3811 3789 HCI_INIT(hci_write_ca_timeout_sync), 3790 + /* HCI_OP_WRITE_SYNC_FLOWCTL */ 3791 + HCI_INIT(hci_write_sync_flowctl_sync), 3812 3792 {} 3813 3793 }; 3814 3794