Combine tx link types which use the same tx buffers. So SCO and ESCO links are scheduled together and also schedule LE links with ACL links *if* the controller uses shared ACL buffers for LE tx. This also fixes tx timeouts if the controller uses shared ACL buffers for LE tx. Signed-off-by: Peter Hurley <peter@xxxxxxxxxxxxxxxxxx> --- include/net/bluetooth/hci.h | 10 ++++++ net/bluetooth/hci_core.c | 72 +++++++++++++++++------------------------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 0c20227..c8319e5 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -174,6 +174,16 @@ enum { /* Low Energy links do not have defined link type. Use invented one */ #define LE_LINK 0x80 +#define LE_MASK 0x80 +#define SCO_MASK 0x01 +#define ACL_MASK 0x02 +#define ESCO_MASK 0x04 + +static inline __u8 link_mask(__u8 type) +{ + return type < LE_LINK ? 1 << type : LE_MASK; +} + /* LMP features */ #define LMP_3SLOT 0x01 #define LMP_5SLOT 0x02 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 668088f..a82aa52 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1798,7 +1798,8 @@ EXPORT_SYMBOL(hci_send_sco); /* ---- HCI TX task (outgoing data) ---- */ /* HCI Connection scheduler */ -static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) +static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, + __u8 select, int *quote) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL; @@ -1811,7 +1812,10 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int struct hci_conn *c; c = list_entry(p, struct hci_conn, list); - if (c->type != type || skb_queue_empty(&c->data_q)) + if (link_mask(c->type) & ~select) + continue; + + if (skb_queue_empty(&c->data_q)) continue; if (c->state != BT_CONNECTED && c->state != BT_CONFIG) @@ -1832,7 +1836,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int return conn; } -static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) +static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 select) { struct hci_conn_hash *h = &hdev->conn_hash; struct list_head *p; @@ -1843,7 +1847,7 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) /* Kill stalled connections */ list_for_each(p, &h->list) { c = list_entry(p, struct hci_conn, list); - if (c->type == type && c->sent) { + if (link_mask(c->type) & select && c->sent) { BT_ERR("%s killing stalled connection %s", hdev->name, batostr(&c->dst)); hci_acl_disconn(c, 0x13); @@ -1856,21 +1860,27 @@ static inline void hci_sched_acl(struct hci_dev *hdev) struct hci_conn *conn; struct sk_buff *skb; int quote = hdev->acl_cnt; + __u8 select = ACL_MASK; + + /* Also select LE links if ACL buffers are shared */ + if (!hdev->le_pkts) + select |= LE_MASK; BT_DBG("%s", hdev->name); if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) - hci_link_tx_to(hdev, ACL_LINK); + if (!quote && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) + hci_link_tx_to(hdev, select); } - while (quote && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { + while (quote && (conn = hci_low_sent(hdev, select, "e))) { while (quote && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); - hci_conn_enter_active_mode(conn); + if (conn->type == ACL_LINK) + hci_conn_enter_active_mode(conn); hci_send_frame(skb); hdev->acl_last_tx = jiffies; @@ -1888,31 +1898,11 @@ static inline void hci_sched_sco(struct hci_dev *hdev) struct hci_conn *conn; struct sk_buff *skb; int quote = hdev->sco_cnt; + __u8 select = SCO_MASK | ESCO_MASK; BT_DBG("%s", hdev->name); - while (quote && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { - while (quote && (skb = skb_dequeue(&conn->data_q))) { - BT_DBG("skb %p len %d", skb, skb->len); - hci_send_frame(skb); - - quote--; - conn->sent++; - if (conn->sent == ~0) - conn->sent = 0; - } - } -} - -static inline void hci_sched_esco(struct hci_dev *hdev) -{ - struct hci_conn *conn; - struct sk_buff *skb; - int quote = hdev->sco_cnt; - - BT_DBG("%s", hdev->name); - - while (quote && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { + while (quote && (conn = hci_low_sent(hdev, select, "e))) { while (quote && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); hci_send_frame(skb); @@ -1929,19 +1919,18 @@ static inline void hci_sched_le(struct hci_dev *hdev) { struct hci_conn *conn; struct sk_buff *skb; - int quote = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; + int quote = hdev->le_cnt; BT_DBG("%s", hdev->name); if (!test_bit(HCI_RAW, &hdev->flags)) { /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->le_cnt && hdev->le_pkts && - time_after(jiffies, hdev->le_last_tx + HZ * 45)) - hci_link_tx_to(hdev, LE_LINK); + if (!quote && time_after(jiffies, hdev->le_last_tx + HZ * 45)) + hci_link_tx_to(hdev, LE_MASK); } - while (quote && (conn = hci_low_sent(hdev, LE_LINK, "e))) { + while (quote && (conn = hci_low_sent(hdev, LE_MASK, "e))) { while (quote && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -1952,10 +1941,7 @@ static inline void hci_sched_le(struct hci_dev *hdev) conn->sent++; } } - if (hdev->le_pkts) - hdev->le_cnt = quote; - else - hdev->acl_cnt = quote; + hdev->le_cnt = quote; } static void hci_tx_task(unsigned long arg) @@ -1970,14 +1956,14 @@ static void hci_tx_task(unsigned long arg) /* Schedule queues and send stuff to HCI driver */ + /* Also schedules LE links if acl buffers are shared */ hci_sched_acl(hdev); + /* Also schedules esco links */ hci_sched_sco(hdev); - hci_sched_esco(hdev); - - /* Only schedule le links if device is le-capable */ - if (lmp_le_capable(hdev)) + /* Only schedule LE links here if acl buffers are not shared */ + if (hdev->le_pkts) hci_sched_le(hdev); /* Send next queued raw (unknown type) packet */ -- 1.7.4.1 ��.n��������+%������w��{.n�����{����^n�r������&��z�ޗ�zf���h���~����������_��+v���)ߣ�