Bluetooth: recalculate priorities when channels are starving
To avoid starvation the priority is recalculated so that the starving channels are promoted to HCI_PRIO_MAX - 1 (6). HCI_PRIO_MAX (7) is considered special, because it requires CAP_NET_ADMIN capability which can be used to provide more guaranties, so it is not used when promoting. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
committed by
Gustavo F. Padovan
parent
ec1cce24d5
commit
02b20f0bb6
@@ -2170,6 +2170,53 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
|
|||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
|
||||||
|
{
|
||||||
|
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
list_for_each_entry(conn, &h->list, list) {
|
||||||
|
struct hci_chan_hash *ch;
|
||||||
|
struct hci_chan *chan;
|
||||||
|
|
||||||
|
if (conn->type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
num++;
|
||||||
|
|
||||||
|
ch = &conn->chan_hash;
|
||||||
|
list_for_each_entry(chan, &ch->list, list) {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (chan->sent) {
|
||||||
|
chan->sent = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skb_queue_empty(&chan->data_q))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
skb = skb_peek(&chan->data_q);
|
||||||
|
if (skb->priority >= HCI_PRIO_MAX - 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
skb->priority = HCI_PRIO_MAX - 1;
|
||||||
|
|
||||||
|
BT_DBG("chan %p skb %p promoted to %d", chan, skb,
|
||||||
|
skb->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hci_conn_num(hdev, type) == num)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void hci_sched_acl(struct hci_dev *hdev)
|
static inline void hci_sched_acl(struct hci_dev *hdev)
|
||||||
{
|
{
|
||||||
struct hci_chan *chan;
|
struct hci_chan *chan;
|
||||||
@@ -2215,6 +2262,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
|
|||||||
chan->conn->sent++;
|
chan->conn->sent++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cnt != hdev->acl_cnt)
|
||||||
|
hci_prio_recalculate(hdev, ACL_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Schedule SCO */
|
/* Schedule SCO */
|
||||||
@@ -2268,7 +2318,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
|
|||||||
{
|
{
|
||||||
struct hci_chan *chan;
|
struct hci_chan *chan;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int quote, cnt;
|
int quote, cnt, tmp;
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
@@ -2284,6 +2334,7 @@ static inline void hci_sched_le(struct hci_dev *hdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
|
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
|
||||||
|
tmp = cnt;
|
||||||
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) {
|
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) {
|
||||||
u32 priority = (skb_peek(&chan->data_q))->priority;
|
u32 priority = (skb_peek(&chan->data_q))->priority;
|
||||||
while (quote-- && (skb = skb_peek(&chan->data_q))) {
|
while (quote-- && (skb = skb_peek(&chan->data_q))) {
|
||||||
@@ -2309,6 +2360,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
|
|||||||
hdev->le_cnt = cnt;
|
hdev->le_cnt = cnt;
|
||||||
else
|
else
|
||||||
hdev->acl_cnt = cnt;
|
hdev->acl_cnt = cnt;
|
||||||
|
|
||||||
|
if (cnt != tmp)
|
||||||
|
hci_prio_recalculate(hdev, LE_LINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_tx_task(unsigned long arg)
|
static void hci_tx_task(unsigned long arg)
|
||||||
|
Reference in New Issue
Block a user