diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2011-11-02 09:52:03 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-11-07 14:24:57 -0500 |
commit | 02b20f0bb661829cbd431e5deb2474e909e65cec (patch) | |
tree | de363e727b52bf1cdea266fd013b28ccec7a75e1 /net/bluetooth/hci_core.c | |
parent | ec1cce24d5950e797f10650abf7890ead67c6e64 (diff) |
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>
Diffstat (limited to 'net/bluetooth/hci_core.c')
-rw-r--r-- | net/bluetooth/hci_core.c | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 19e44533fb01..4221fd5b1f4b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -2170,6 +2170,53 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, | |||
2170 | return chan; | 2170 | return chan; |
2171 | } | 2171 | } |
2172 | 2172 | ||
2173 | static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) | ||
2174 | { | ||
2175 | struct hci_conn_hash *h = &hdev->conn_hash; | ||
2176 | struct hci_conn *conn; | ||
2177 | int num = 0; | ||
2178 | |||
2179 | BT_DBG("%s", hdev->name); | ||
2180 | |||
2181 | list_for_each_entry(conn, &h->list, list) { | ||
2182 | struct hci_chan_hash *ch; | ||
2183 | struct hci_chan *chan; | ||
2184 | |||
2185 | if (conn->type != type) | ||
2186 | continue; | ||
2187 | |||
2188 | if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) | ||
2189 | continue; | ||
2190 | |||
2191 | num++; | ||
2192 | |||
2193 | ch = &conn->chan_hash; | ||
2194 | list_for_each_entry(chan, &ch->list, list) { | ||
2195 | struct sk_buff *skb; | ||
2196 | |||
2197 | if (chan->sent) { | ||
2198 | chan->sent = 0; | ||
2199 | continue; | ||
2200 | } | ||
2201 | |||
2202 | if (skb_queue_empty(&chan->data_q)) | ||
2203 | continue; | ||
2204 | |||
2205 | skb = skb_peek(&chan->data_q); | ||
2206 | if (skb->priority >= HCI_PRIO_MAX - 1) | ||
2207 | continue; | ||
2208 | |||
2209 | skb->priority = HCI_PRIO_MAX - 1; | ||
2210 | |||
2211 | BT_DBG("chan %p skb %p promoted to %d", chan, skb, | ||
2212 | skb->priority); | ||
2213 | } | ||
2214 | |||
2215 | if (hci_conn_num(hdev, type) == num) | ||
2216 | break; | ||
2217 | } | ||
2218 | } | ||
2219 | |||
2173 | static inline void hci_sched_acl(struct hci_dev *hdev) | 2220 | static inline void hci_sched_acl(struct hci_dev *hdev) |
2174 | { | 2221 | { |
2175 | struct hci_chan *chan; | 2222 | struct hci_chan *chan; |
@@ -2215,6 +2262,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) | |||
2215 | chan->conn->sent++; | 2262 | chan->conn->sent++; |
2216 | } | 2263 | } |
2217 | } | 2264 | } |
2265 | |||
2266 | if (cnt != hdev->acl_cnt) | ||
2267 | hci_prio_recalculate(hdev, ACL_LINK); | ||
2218 | } | 2268 | } |
2219 | 2269 | ||
2220 | /* Schedule SCO */ | 2270 | /* Schedule SCO */ |
@@ -2268,7 +2318,7 @@ static inline void hci_sched_le(struct hci_dev *hdev) | |||
2268 | { | 2318 | { |
2269 | struct hci_chan *chan; | 2319 | struct hci_chan *chan; |
2270 | struct sk_buff *skb; | 2320 | struct sk_buff *skb; |
2271 | int quote, cnt; | 2321 | int quote, cnt, tmp; |
2272 | 2322 | ||
2273 | BT_DBG("%s", hdev->name); | 2323 | BT_DBG("%s", hdev->name); |
2274 | 2324 | ||
@@ -2284,6 +2334,7 @@ static inline void hci_sched_le(struct hci_dev *hdev) | |||
2284 | } | 2334 | } |
2285 | 2335 | ||
2286 | cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; | 2336 | cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; |
2337 | tmp = cnt; | ||
2287 | while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { | 2338 | while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { |
2288 | u32 priority = (skb_peek(&chan->data_q))->priority; | 2339 | u32 priority = (skb_peek(&chan->data_q))->priority; |
2289 | while (quote-- && (skb = skb_peek(&chan->data_q))) { | 2340 | while (quote-- && (skb = skb_peek(&chan->data_q))) { |
@@ -2309,6 +2360,9 @@ static inline void hci_sched_le(struct hci_dev *hdev) | |||
2309 | hdev->le_cnt = cnt; | 2360 | hdev->le_cnt = cnt; |
2310 | else | 2361 | else |
2311 | hdev->acl_cnt = cnt; | 2362 | hdev->acl_cnt = cnt; |
2363 | |||
2364 | if (cnt != tmp) | ||
2365 | hci_prio_recalculate(hdev, LE_LINK); | ||
2312 | } | 2366 | } |
2313 | 2367 | ||
2314 | static void hci_tx_task(unsigned long arg) | 2368 | static void hci_tx_task(unsigned long arg) |