Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp2047963ybh; Fri, 13 Mar 2020 12:01:40 -0700 (PDT) X-Google-Smtp-Source: ADFU+vu+8pPREDWQ6v1phyh8QM8tCWOCeHfJNsDRDr/oD7WsDkwNgNBU44UyVnDUBi6GvYjT6XVR X-Received: by 2002:a05:6808:abb:: with SMTP id r27mr8389179oij.92.1584126100635; Fri, 13 Mar 2020 12:01:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584126100; cv=none; d=google.com; s=arc-20160816; b=qyM3q5UJFbBsdWrQngGnWNkuwwRdTEeFiCgWgWh16rhtdEH4XlN62uYngI9M8uM7vO Gprufvysz65LKsHdHx+/5FQWpzhxWuBGeQjsSG1AWhZnp0jFzrvRDZ6H6zYshnEGPQ9y 92F8VdMICxcXLtGBJvaknAxqcXqbhiH5jMChC90O1P0gpUsvny9AEYFa5/CjA2U8hp+m VYQoLWQ2bViNStVBMQKHJaby5u9gXzY31nik9U98RxlgvG7YAwimqoBl1sYgMk3AylhK ZTYnctqOXzDgA1UyXKjZb4wm7KJerSazCV6rGmaR/e5upOJ5t5nHAJVBhUAyGsrNw2ck 3Gcg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:to:references:message-id :content-transfer-encoding:cc:date:in-reply-to:from:subject :mime-version; bh=kvFJ/8Ccji/HisjMRfUFfq1b1tETYlqsyEzQC9hByyM=; b=mczUfy/dgCr8XULlKbbWnHKHTIXgEEGa1owpHLX6lXJke0/w/4VPzUHaTJuuZ9uN2u gcqVBUfVEtMIyXnn/8FJUrlUAXpmAmNCZF6cYfU6CA4S7L4MlFa+DZhNFzfRPHyO+SFJ SQL2xd/17pVGMGn6pUaGAHTKQOHCpRX+J0LGrRlr9NM9nqq/i7k/5LnCvc8AWWeXbSVL cn0F16Ws5XlxFJw3PpdmHcc5qWMxFeZjS45rcshbWQGNoIiIxuKRZEPzWTLbMcCu9FsV 3Z8DJcgBeYALxFW7GCq44yPAyQKSf+VwPLgRpKD5pVQVceg+8l4jFNrYStP3gUJSjkcJ t9tA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-bluetooth-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j64si4692064oif.49.2020.03.13.12.01.19; Fri, 13 Mar 2020 12:01:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-bluetooth-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-bluetooth-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-bluetooth-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726480AbgCMTBQ convert rfc822-to-8bit (ORCPT + 99 others); Fri, 13 Mar 2020 15:01:16 -0400 Received: from coyote.holtmann.net ([212.227.132.17]:41544 "EHLO mail.holtmann.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726477AbgCMTBP (ORCPT ); Fri, 13 Mar 2020 15:01:15 -0400 Received: from marcel-macbook.fritz.box (p4FEFC5A7.dip0.t-ipconnect.de [79.239.197.167]) by mail.holtmann.org (Postfix) with ESMTPSA id 429C8CED08; Fri, 13 Mar 2020 20:10:42 +0100 (CET) Content-Type: text/plain; charset=us-ascii Mime-Version: 1.0 (Mac OS X Mail 13.0 \(3608.60.0.2.5\)) Subject: Re: [PATCH 1/1] Bluetooth: Prioritize SCO traffic on slow interfaces From: Marcel Holtmann In-Reply-To: <20200312111036.1.I17e2220fd0c0822c76a15ef89b882fb4cfe3fe89@changeid> Date: Fri, 13 Mar 2020 20:01:12 +0100 Cc: Bluez mailing list , chromeos-bluetooth-upstreaming@chromium.org, "David S. Miller" , Johan Hedberg , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Jakub Kicinski Content-Transfer-Encoding: 8BIT Message-Id: References: <20200312181055.94038-1-abhishekpandit@chromium.org> <20200312111036.1.I17e2220fd0c0822c76a15ef89b882fb4cfe3fe89@changeid> To: Abhishek Pandit-Subedi X-Mailer: Apple Mail (2.3608.60.0.2.5) Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org Hi Abhishek, > When scheduling TX packets, send all SCO/eSCO packets first and then > send only 1 ACL/LE packet in a loop while checking that there are no SCO > packets pending. This is done to make sure that we can meet SCO > deadlines on slow interfaces like UART. If we were to queue up multiple > ACL packets without checking for a SCO packet, we might miss the SCO > timing. For example: > > The time it takes to send a maximum size ACL packet (1024 bytes): > t = 10/8 * 1024 bytes * 8 bits/byte * 1 packet / baudrate > where 10/8 is uart overhead due to start/stop bits per byte > > Replace t = 3.75ms (SCO deadline), which gives us a baudrate of 2730666 > and is pretty close to a common baudrate of 3000000 used for BT. At this > baudrate, if we sent two 1024 byte ACL packets, we would miss the 3.75ms > timing window. > > Signed-off-by: Abhishek Pandit-Subedi > --- > > include/net/bluetooth/hci_core.h | 1 + > net/bluetooth/hci_core.c | 91 +++++++++++++++++++++++++------- > 2 files changed, 73 insertions(+), 19 deletions(-) > > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h > index d4e28773d378..f636c89f1fe1 100644 > --- a/include/net/bluetooth/hci_core.h > +++ b/include/net/bluetooth/hci_core.h > @@ -315,6 +315,7 @@ struct hci_dev { > __u8 ssp_debug_mode; > __u8 hw_error_code; > __u32 clock; > + __u8 sched_limit; why do you need this parameter? > > __u16 devid_source; > __u16 devid_vendor; > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c > index dbd2ad3a26ed..00a72265cd96 100644 > --- a/net/bluetooth/hci_core.c > +++ b/net/bluetooth/hci_core.c > @@ -4239,18 +4239,32 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) > } > } > > -static void hci_sched_acl_pkt(struct hci_dev *hdev) > +/* Limit packets in flight when SCO/eSCO links are active. */ > +static bool hci_sched_limit(struct hci_dev *hdev) > +{ > + return hdev->sched_limit && hci_conn_num(hdev, SCO_LINK); > +} > + > +static bool hci_sched_acl_pkt(struct hci_dev *hdev) > { > unsigned int cnt = hdev->acl_cnt; > struct hci_chan *chan; > struct sk_buff *skb; > int quote; > + bool sched_limit = hci_sched_limit(hdev); > + bool resched = false; > > __check_timeout(hdev, cnt); > > while (hdev->acl_cnt && > (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { > u32 priority = (skb_peek(&chan->data_q))->priority; > + > + if (sched_limit && quote > 0) { > + resched = true; > + quote = 1; > + } > + > while (quote-- && (skb = skb_peek(&chan->data_q))) { > BT_DBG("chan %p skb %p len %d priority %u", chan, skb, > skb->len, skb->priority); > @@ -4271,19 +4285,26 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) > chan->sent++; > chan->conn->sent++; > } > + > + if (resched && cnt != hdev->acl_cnt) > + break; > } > > - if (cnt != hdev->acl_cnt) > + if (hdev->acl_cnt == 0 && cnt != hdev->acl_cnt) > hci_prio_recalculate(hdev, ACL_LINK); > + > + return resched; > } > > -static void hci_sched_acl_blk(struct hci_dev *hdev) > +static bool hci_sched_acl_blk(struct hci_dev *hdev) > { > unsigned int cnt = hdev->block_cnt; > struct hci_chan *chan; > struct sk_buff *skb; > int quote; > u8 type; > + bool sched_limit = hci_sched_limit(hdev); > + bool resched = false; > > __check_timeout(hdev, cnt); > > @@ -4297,6 +4318,12 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) > while (hdev->block_cnt > 0 && > (chan = hci_chan_sent(hdev, type, "e))) { > u32 priority = (skb_peek(&chan->data_q))->priority; > + > + if (sched_limit && quote > 0) { > + resched = true; > + quote = 1; > + } > + > while (quote > 0 && (skb = skb_peek(&chan->data_q))) { > int blocks; > > @@ -4311,7 +4338,7 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) > > blocks = __get_blocks(hdev, skb); > if (blocks > hdev->block_cnt) > - return; > + return false; > > hci_conn_enter_active_mode(chan->conn, > bt_cb(skb)->force_active); > @@ -4325,33 +4352,39 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) > chan->sent += blocks; > chan->conn->sent += blocks; > } > + > + if (resched && cnt != hdev->block_cnt) > + break; > } > > - if (cnt != hdev->block_cnt) > + if (hdev->block_cnt == 0 && cnt != hdev->block_cnt) > hci_prio_recalculate(hdev, type); > + > + return resched; > } > > -static void hci_sched_acl(struct hci_dev *hdev) > +static bool hci_sched_acl(struct hci_dev *hdev) > { > BT_DBG("%s", hdev->name); > > /* No ACL link over BR/EDR controller */ > if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_PRIMARY) > - return; > + goto done; Style wise the goto done is overkill. Just return false. > > /* No AMP link over AMP controller */ > if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP) > - return; > + goto done; > > switch (hdev->flow_ctl_mode) { > case HCI_FLOW_CTL_MODE_PACKET_BASED: > - hci_sched_acl_pkt(hdev); > - break; > + return hci_sched_acl_pkt(hdev); > > case HCI_FLOW_CTL_MODE_BLOCK_BASED: > - hci_sched_acl_blk(hdev); > - break; > + return hci_sched_acl_blk(hdev); So the block based mode is for AMP controllers and not used on BR/EDR controllers. Since AMP controllers only transport ACL packet and no SCO/eSCO packets, we can ignore this here. > } > + > +done: > + return false; > } > > /* Schedule SCO */ > @@ -4402,16 +4435,18 @@ static void hci_sched_esco(struct hci_dev *hdev) > } > } > > -static void hci_sched_le(struct hci_dev *hdev) > +static bool hci_sched_le(struct hci_dev *hdev) > { > struct hci_chan *chan; > struct sk_buff *skb; > int quote, cnt, tmp; > + bool sched_limit = hci_sched_limit(hdev); > + bool resched = false; > > BT_DBG("%s", hdev->name); > > if (!hci_conn_num(hdev, LE_LINK)) > - return; > + return resched; > > cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; > > @@ -4420,6 +4455,12 @@ static void hci_sched_le(struct hci_dev *hdev) > tmp = cnt; > while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { > u32 priority = (skb_peek(&chan->data_q))->priority; > + > + if (sched_limit && quote > 0) { > + resched = true; > + quote = 1; > + } > + > while (quote-- && (skb = skb_peek(&chan->data_q))) { > BT_DBG("chan %p skb %p len %d priority %u", chan, skb, > skb->len, skb->priority); > @@ -4437,6 +4478,9 @@ static void hci_sched_le(struct hci_dev *hdev) > chan->sent++; > chan->conn->sent++; > } > + > + if (resched && cnt != tmp) > + break; > } > > if (hdev->le_pkts) > @@ -4444,24 +4488,33 @@ static void hci_sched_le(struct hci_dev *hdev) > else > hdev->acl_cnt = cnt; > > - if (cnt != tmp) > + if (cnt == 0 && cnt != tmp) > hci_prio_recalculate(hdev, LE_LINK); > + > + return resched; > } > > static void hci_tx_work(struct work_struct *work) > { > struct hci_dev *hdev = container_of(work, struct hci_dev, tx_work); > struct sk_buff *skb; > + bool resched; > > BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, > hdev->sco_cnt, hdev->le_cnt); > > if (!hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) { > /* Schedule queues and send stuff to HCI driver */ > - hci_sched_acl(hdev); > - hci_sched_sco(hdev); > - hci_sched_esco(hdev); > - hci_sched_le(hdev); > + do { > + /* SCO and eSCO send all packets until emptied */ > + hci_sched_sco(hdev); > + hci_sched_esco(hdev); > + > + /* Acl and Le send based on quota (priority on ACL per > + * loop) > + */ > + resched = hci_sched_acl(hdev) || hci_sched_le(hdev); > + } while (resched); > } I am not in favor of this busy loop. We might want to re-think the whole scheduling by connection type and really only focus on scheduling ACL (BR/EDR and LE) and audio packets (SCO/eSCO and ISO). In addition, we also need to check that SCO scheduling and A2DP media channel ACL packets do work together. I think that generally it would be best to have a clear rate at which SCO packets are require to pushed down to the hardware. So you really reserve bandwidth and not blindly prioritize them via a busy loop. Regards Marcel