Skip to content

Commit 1321845

Browse files
committed
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: 7fedd3b ("Bluetooth: Prioritize SCO traffic") Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Tested-by: Pauli Virtanen <pav@iki.fi>
1 parent 42c6c7a commit 1321845

5 files changed

Lines changed: 68 additions & 34 deletions

File tree

include/net/bluetooth/hci.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@ enum {
208208
*/
209209
HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
210210

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+
211218
/* When this quirk is set, the LE states reported through the
212219
* HCI_LE_READ_SUPPORTED_STATES are invalid/broken.
213220
*
@@ -448,6 +455,7 @@ enum {
448455
HCI_WIDEBAND_SPEECH_ENABLED,
449456
HCI_EVENT_FILTER_CONFIGURED,
450457
HCI_PA_SYNC,
458+
HCI_SCO_FLOWCTL,
451459

452460
HCI_DUT_MODE,
453461
HCI_VENDOR_DIAG,
@@ -1544,6 +1552,11 @@ struct hci_rp_read_tx_power {
15441552
__s8 tx_power;
15451553
} __packed;
15461554

1555+
#define HCI_OP_WRITE_SYNC_FLOWCTL 0x0c2f
1556+
struct hci_cp_write_sync_flowctl {
1557+
__u8 enable;
1558+
} __packed;
1559+
15471560
#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
15481561
struct hci_rp_read_page_scan_type {
15491562
__u8 status;

include/net/bluetooth/hci_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
18581858
#define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD)
18591859
#define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF)
18601860
#define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK)
1861+
#define lmp_sco_capable(dev) ((dev)->features[0][1] & LMP_SCO)
18611862
#define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ)
18621863
#define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO)
18631864
#define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))

net/bluetooth/hci_core.c

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,51 +3552,45 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
35523552
}
35533553

35543554
/* Schedule SCO */
3555-
static void hci_sched_sco(struct hci_dev *hdev)
3555+
static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
35563556
{
35573557
struct hci_conn *conn;
35583558
struct sk_buff *skb;
3559-
int quote;
3559+
int quote, *cnt;
3560+
unsigned int pkts = hdev->sco_pkts;
35603561

3561-
BT_DBG("%s", hdev->name);
3562+
bt_dev_dbg(hdev, "type %u", type);
35623563

3563-
if (!hci_conn_num(hdev, SCO_LINK))
3564+
if (!hci_conn_num(hdev, type) || !pkts)
35643565
return;
35653566

3566-
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
3567-
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
3568-
BT_DBG("skb %p len %d", skb, skb->len);
3569-
hci_send_frame(hdev, skb);
3570-
3571-
conn->sent++;
3572-
if (conn->sent == ~0)
3573-
conn->sent = 0;
3574-
}
3575-
}
3576-
}
3577-
3578-
static void hci_sched_esco(struct hci_dev *hdev)
3579-
{
3580-
struct hci_conn *conn;
3581-
struct sk_buff *skb;
3582-
int quote;
3583-
3584-
BT_DBG("%s", hdev->name);
3585-
3586-
if (!hci_conn_num(hdev, ESCO_LINK))
3587-
return;
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;
35883574

3589-
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
3590-
&quote))) {
3575+
while (*cnt && (conn = hci_low_sent(hdev, type, &quote))) {
35913576
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
35923577
BT_DBG("skb %p len %d", skb, skb->len);
35933578
hci_send_frame(hdev, skb);
35943579

35953580
conn->sent++;
35963581
if (conn->sent == ~0)
35973582
conn->sent = 0;
3583+
(*cnt)--;
35983584
}
35993585
}
3586+
3587+
/* Rescheduled if all packets were sent and flow control is not enabled
3588+
* as there could be more packets queued that could not be sent and
3589+
* since no HCI_EV_NUM_COMP_PKTS event will be generated the reschedule
3590+
* needs to be forced.
3591+
*/
3592+
if (!pkts && !hci_dev_test_flag(hdev, HCI_SCO_FLOWCTL))
3593+
queue_work(hdev->workqueue, &hdev->tx_work);
36003594
}
36013595

36023596
static void hci_sched_acl_pkt(struct hci_dev *hdev)
@@ -3632,8 +3626,8 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
36323626
chan->conn->sent++;
36333627

36343628
/* Send pending SCO packets right away */
3635-
hci_sched_sco(hdev);
3636-
hci_sched_esco(hdev);
3629+
hci_sched_sco(hdev, SCO_LINK);
3630+
hci_sched_sco(hdev, ESCO_LINK);
36373631
}
36383632
}
36393633

@@ -3688,8 +3682,8 @@ static void hci_sched_le(struct hci_dev *hdev)
36883682
chan->conn->sent++;
36893683

36903684
/* Send pending SCO packets right away */
3691-
hci_sched_sco(hdev);
3692-
hci_sched_esco(hdev);
3685+
hci_sched_sco(hdev, SCO_LINK);
3686+
hci_sched_sco(hdev, ESCO_LINK);
36933687
}
36943688
}
36953689

@@ -3734,8 +3728,8 @@ static void hci_tx_work(struct work_struct *work)
37343728

37353729
if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
37363730
/* Schedule queues and send stuff to HCI driver */
3737-
hci_sched_sco(hdev);
3738-
hci_sched_esco(hdev);
3731+
hci_sched_sco(hdev, SCO_LINK);
3732+
hci_sched_sco(hdev, ESCO_LINK);
37393733
hci_sched_iso(hdev);
37403734
hci_sched_acl(hdev);
37413735
hci_sched_le(hdev);

net/bluetooth/hci_event.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4445,9 +4445,11 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
44454445
break;
44464446

44474447
case SCO_LINK:
4448+
case ESCO_LINK:
44484449
hdev->sco_cnt += count;
44494450
if (hdev->sco_cnt > hdev->sco_pkts)
44504451
hdev->sco_cnt = hdev->sco_pkts;
4452+
44514453
break;
44524454

44534455
case ISO_LINK:

net/bluetooth/hci_sync.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3769,6 +3769,28 @@ static int hci_write_ca_timeout_sync(struct hci_dev *hdev)
37693769
sizeof(param), &param, HCI_CMD_TIMEOUT);
37703770
}
37713771

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+
37723794
/* BR Controller init stage 2 command sequence */
37733795
static const struct hci_init_stage br_init2[] = {
37743796
/* HCI_OP_READ_BUFFER_SIZE */
@@ -3787,6 +3809,8 @@ static const struct hci_init_stage br_init2[] = {
37873809
HCI_INIT(hci_clear_event_filter_sync),
37883810
/* HCI_OP_WRITE_CA_TIMEOUT */
37893811
HCI_INIT(hci_write_ca_timeout_sync),
3812+
/* HCI_OP_WRITE_SYNC_FLOWCTL */
3813+
HCI_INIT(hci_write_sync_flowctl_sync),
37903814
{}
37913815
};
37923816

0 commit comments

Comments
 (0)