diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 76dc1538e321..9a56a4084482 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -2384,18 +2384,19 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) | |||
2384 | 2384 | ||
2385 | } | 2385 | } |
2386 | 2386 | ||
2387 | static inline void hci_sched_acl(struct hci_dev *hdev) | 2387 | static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) |
2388 | { | ||
2389 | /* Calculate count of blocks used by this packet */ | ||
2390 | return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); | ||
2391 | } | ||
2392 | |||
2393 | static inline void hci_sched_acl_pkt(struct hci_dev *hdev) | ||
2388 | { | 2394 | { |
2389 | struct hci_chan *chan; | 2395 | struct hci_chan *chan; |
2390 | struct sk_buff *skb; | 2396 | struct sk_buff *skb; |
2391 | int quote; | 2397 | int quote; |
2392 | unsigned int cnt; | 2398 | unsigned int cnt; |
2393 | 2399 | ||
2394 | BT_DBG("%s", hdev->name); | ||
2395 | |||
2396 | if (!hci_conn_num(hdev, ACL_LINK)) | ||
2397 | return; | ||
2398 | |||
2399 | if (!test_bit(HCI_RAW, &hdev->flags)) { | 2400 | if (!test_bit(HCI_RAW, &hdev->flags)) { |
2400 | /* ACL tx timeout must be longer than maximum | 2401 | /* ACL tx timeout must be longer than maximum |
2401 | * link supervision timeout (40.9 seconds) */ | 2402 | * link supervision timeout (40.9 seconds) */ |
@@ -2435,6 +2436,78 @@ static inline void hci_sched_acl(struct hci_dev *hdev) | |||
2435 | hci_prio_recalculate(hdev, ACL_LINK); | 2436 | hci_prio_recalculate(hdev, ACL_LINK); |
2436 | } | 2437 | } |
2437 | 2438 | ||
2439 | static inline void hci_sched_acl_blk(struct hci_dev *hdev) | ||
2440 | { | ||
2441 | struct hci_chan *chan; | ||
2442 | struct sk_buff *skb; | ||
2443 | int quote; | ||
2444 | unsigned int cnt; | ||
2445 | |||
2446 | if (!test_bit(HCI_RAW, &hdev->flags)) { | ||
2447 | /* ACL tx timeout must be longer than maximum | ||
2448 | * link supervision timeout (40.9 seconds) */ | ||
2449 | if (!hdev->block_cnt && time_after(jiffies, hdev->acl_last_tx + | ||
2450 | msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) | ||
2451 | hci_link_tx_to(hdev, ACL_LINK); | ||
2452 | } | ||
2453 | |||
2454 | cnt = hdev->block_cnt; | ||
2455 | |||
2456 | while (hdev->block_cnt > 0 && | ||
2457 | (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { | ||
2458 | u32 priority = (skb_peek(&chan->data_q))->priority; | ||
2459 | while (quote > 0 && (skb = skb_peek(&chan->data_q))) { | ||
2460 | int blocks; | ||
2461 | |||
2462 | BT_DBG("chan %p skb %p len %d priority %u", chan, skb, | ||
2463 | skb->len, skb->priority); | ||
2464 | |||
2465 | /* Stop if priority has changed */ | ||
2466 | if (skb->priority < priority) | ||
2467 | break; | ||
2468 | |||
2469 | skb = skb_dequeue(&chan->data_q); | ||
2470 | |||
2471 | blocks = __get_blocks(hdev, skb); | ||
2472 | if (blocks > hdev->block_cnt) | ||
2473 | return; | ||
2474 | |||
2475 | hci_conn_enter_active_mode(chan->conn, | ||
2476 | bt_cb(skb)->force_active); | ||
2477 | |||
2478 | hci_send_frame(skb); | ||
2479 | hdev->acl_last_tx = jiffies; | ||
2480 | |||
2481 | hdev->block_cnt -= blocks; | ||
2482 | quote -= blocks; | ||
2483 | |||
2484 | chan->sent += blocks; | ||
2485 | chan->conn->sent += blocks; | ||
2486 | } | ||
2487 | } | ||
2488 | |||
2489 | if (cnt != hdev->block_cnt) | ||
2490 | hci_prio_recalculate(hdev, ACL_LINK); | ||
2491 | } | ||
2492 | |||
2493 | static inline void hci_sched_acl(struct hci_dev *hdev) | ||
2494 | { | ||
2495 | BT_DBG("%s", hdev->name); | ||
2496 | |||
2497 | if (!hci_conn_num(hdev, ACL_LINK)) | ||
2498 | return; | ||
2499 | |||
2500 | switch (hdev->flow_ctl_mode) { | ||
2501 | case HCI_FLOW_CTL_MODE_PACKET_BASED: | ||
2502 | hci_sched_acl_pkt(hdev); | ||
2503 | break; | ||
2504 | |||
2505 | case HCI_FLOW_CTL_MODE_BLOCK_BASED: | ||
2506 | hci_sched_acl_blk(hdev); | ||
2507 | break; | ||
2508 | } | ||
2509 | } | ||
2510 | |||
2438 | /* Schedule SCO */ | 2511 | /* Schedule SCO */ |
2439 | static inline void hci_sched_sco(struct hci_dev *hdev) | 2512 | static inline void hci_sched_sco(struct hci_dev *hdev) |
2440 | { | 2513 | { |