diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2011-11-02 09:52:01 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-11-07 14:24:56 -0500 |
commit | 73d80deb7bdf0171f22e76dc2429c1f99eff90e2 (patch) | |
tree | 17a65f2bf28e1e5a107503f361a7fb061e2ad2f4 | |
parent | 3c32fa93e5a54cd54e52541892857b0c7164a61e (diff) |
Bluetooth: prioritizing data over HCI
This implement priority based scheduler using skbuffer priority set via
SO_PRIORITY socket option.
It introduces hci_chan_hash (list of HCI Channel/hci_chan) per connection,
each item in this list refer to a L2CAP connection and it is used to
queue the data for transmission.
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>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 43 | ||||
-rw-r--r-- | include/net/bluetooth/l2cap.h | 1 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 53 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 143 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 63 | ||||
-rw-r--r-- | net/bluetooth/smp.c | 3 |
6 files changed, 251 insertions, 55 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 5a9db9a4b439..f97792c972f3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -67,6 +67,12 @@ struct hci_conn_hash { | |||
67 | unsigned int le_num; | 67 | unsigned int le_num; |
68 | }; | 68 | }; |
69 | 69 | ||
70 | struct hci_chan_hash { | ||
71 | struct list_head list; | ||
72 | spinlock_t lock; | ||
73 | unsigned int num; | ||
74 | }; | ||
75 | |||
70 | struct bdaddr_list { | 76 | struct bdaddr_list { |
71 | struct list_head list; | 77 | struct list_head list; |
72 | bdaddr_t bdaddr; | 78 | bdaddr_t bdaddr; |
@@ -287,6 +293,7 @@ struct hci_conn { | |||
287 | unsigned int sent; | 293 | unsigned int sent; |
288 | 294 | ||
289 | struct sk_buff_head data_q; | 295 | struct sk_buff_head data_q; |
296 | struct hci_chan_hash chan_hash; | ||
290 | 297 | ||
291 | struct timer_list disc_timer; | 298 | struct timer_list disc_timer; |
292 | struct timer_list idle_timer; | 299 | struct timer_list idle_timer; |
@@ -309,6 +316,14 @@ struct hci_conn { | |||
309 | void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason); | 316 | void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason); |
310 | }; | 317 | }; |
311 | 318 | ||
319 | struct hci_chan { | ||
320 | struct list_head list; | ||
321 | |||
322 | struct hci_conn *conn; | ||
323 | struct sk_buff_head data_q; | ||
324 | unsigned int sent; | ||
325 | }; | ||
326 | |||
312 | extern struct hci_proto *hci_proto[]; | 327 | extern struct hci_proto *hci_proto[]; |
313 | extern struct list_head hci_dev_list; | 328 | extern struct list_head hci_dev_list; |
314 | extern struct list_head hci_cb_list; | 329 | extern struct list_head hci_cb_list; |
@@ -469,6 +484,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, | |||
469 | return NULL; | 484 | return NULL; |
470 | } | 485 | } |
471 | 486 | ||
487 | static inline void hci_chan_hash_init(struct hci_conn *c) | ||
488 | { | ||
489 | struct hci_chan_hash *h = &c->chan_hash; | ||
490 | INIT_LIST_HEAD(&h->list); | ||
491 | spin_lock_init(&h->lock); | ||
492 | h->num = 0; | ||
493 | } | ||
494 | |||
495 | static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan) | ||
496 | { | ||
497 | struct hci_chan_hash *h = &c->chan_hash; | ||
498 | list_add(&chan->list, &h->list); | ||
499 | h->num++; | ||
500 | } | ||
501 | |||
502 | static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan) | ||
503 | { | ||
504 | struct hci_chan_hash *h = &c->chan_hash; | ||
505 | list_del(&chan->list); | ||
506 | h->num--; | ||
507 | } | ||
508 | |||
472 | void hci_acl_connect(struct hci_conn *conn); | 509 | void hci_acl_connect(struct hci_conn *conn); |
473 | void hci_acl_disconn(struct hci_conn *conn, __u8 reason); | 510 | void hci_acl_disconn(struct hci_conn *conn, __u8 reason); |
474 | void hci_add_sco(struct hci_conn *conn, __u16 handle); | 511 | void hci_add_sco(struct hci_conn *conn, __u16 handle); |
@@ -480,6 +517,10 @@ int hci_conn_del(struct hci_conn *conn); | |||
480 | void hci_conn_hash_flush(struct hci_dev *hdev); | 517 | void hci_conn_hash_flush(struct hci_dev *hdev); |
481 | void hci_conn_check_pending(struct hci_dev *hdev); | 518 | void hci_conn_check_pending(struct hci_dev *hdev); |
482 | 519 | ||
520 | struct hci_chan *hci_chan_create(struct hci_conn *conn); | ||
521 | int hci_chan_del(struct hci_chan *chan); | ||
522 | void hci_chan_hash_flush(struct hci_conn *conn); | ||
523 | |||
483 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | 524 | struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, |
484 | __u8 sec_level, __u8 auth_type); | 525 | __u8 sec_level, __u8 auth_type); |
485 | int hci_conn_check_link_mode(struct hci_conn *conn); | 526 | int hci_conn_check_link_mode(struct hci_conn *conn); |
@@ -849,7 +890,7 @@ int hci_register_notifier(struct notifier_block *nb); | |||
849 | int hci_unregister_notifier(struct notifier_block *nb); | 890 | int hci_unregister_notifier(struct notifier_block *nb); |
850 | 891 | ||
851 | int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); | 892 | int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); |
852 | void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); | 893 | void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); |
853 | void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); | 894 | void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); |
854 | 895 | ||
855 | void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); | 896 | void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode); |
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c10bf1db0abb..6ae9492ec564 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -451,6 +451,7 @@ struct l2cap_ops { | |||
451 | 451 | ||
452 | struct l2cap_conn { | 452 | struct l2cap_conn { |
453 | struct hci_conn *hcon; | 453 | struct hci_conn *hcon; |
454 | struct hci_chan *hchan; | ||
454 | 455 | ||
455 | bdaddr_t *dst; | 456 | bdaddr_t *dst; |
456 | bdaddr_t *src; | 457 | bdaddr_t *src; |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6e98ff3da2a4..e545376379c5 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -374,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
374 | 374 | ||
375 | skb_queue_head_init(&conn->data_q); | 375 | skb_queue_head_init(&conn->data_q); |
376 | 376 | ||
377 | hci_chan_hash_init(conn); | ||
378 | |||
377 | setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); | 379 | setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); |
378 | setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); | 380 | setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); |
379 | setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, | 381 | setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, |
@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn) | |||
432 | 434 | ||
433 | tasklet_disable(&hdev->tx_task); | 435 | tasklet_disable(&hdev->tx_task); |
434 | 436 | ||
437 | hci_chan_hash_flush(conn); | ||
438 | |||
435 | hci_conn_hash_del(hdev, conn); | 439 | hci_conn_hash_del(hdev, conn); |
436 | if (hdev->notify) | 440 | if (hdev->notify) |
437 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); | 441 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); |
@@ -950,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg) | |||
950 | 954 | ||
951 | return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; | 955 | return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0; |
952 | } | 956 | } |
957 | |||
958 | struct hci_chan *hci_chan_create(struct hci_conn *conn) | ||
959 | { | ||
960 | struct hci_dev *hdev = conn->hdev; | ||
961 | struct hci_chan *chan; | ||
962 | |||
963 | BT_DBG("%s conn %p", hdev->name, conn); | ||
964 | |||
965 | chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC); | ||
966 | if (!chan) | ||
967 | return NULL; | ||
968 | |||
969 | chan->conn = conn; | ||
970 | skb_queue_head_init(&chan->data_q); | ||
971 | |||
972 | tasklet_disable(&hdev->tx_task); | ||
973 | hci_chan_hash_add(conn, chan); | ||
974 | tasklet_enable(&hdev->tx_task); | ||
975 | |||
976 | return chan; | ||
977 | } | ||
978 | |||
979 | int hci_chan_del(struct hci_chan *chan) | ||
980 | { | ||
981 | struct hci_conn *conn = chan->conn; | ||
982 | struct hci_dev *hdev = conn->hdev; | ||
983 | |||
984 | BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); | ||
985 | |||
986 | tasklet_disable(&hdev->tx_task); | ||
987 | hci_chan_hash_del(conn, chan); | ||
988 | tasklet_enable(&hdev->tx_task); | ||
989 | |||
990 | skb_queue_purge(&chan->data_q); | ||
991 | kfree(chan); | ||
992 | |||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | void hci_chan_hash_flush(struct hci_conn *conn) | ||
997 | { | ||
998 | struct hci_chan_hash *h = &conn->chan_hash; | ||
999 | struct hci_chan *chan, *tmp; | ||
1000 | |||
1001 | BT_DBG("conn %p", conn); | ||
1002 | |||
1003 | list_for_each_entry_safe(chan, tmp, &h->list, list) | ||
1004 | hci_chan_del(chan); | ||
1005 | } | ||
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f2ec434971f6..631327dc7fed 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1937,23 +1937,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) | |||
1937 | hdr->dlen = cpu_to_le16(len); | 1937 | hdr->dlen = cpu_to_le16(len); |
1938 | } | 1938 | } |
1939 | 1939 | ||
1940 | void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) | 1940 | static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, |
1941 | struct sk_buff *skb, __u16 flags) | ||
1941 | { | 1942 | { |
1942 | struct hci_dev *hdev = conn->hdev; | 1943 | struct hci_dev *hdev = conn->hdev; |
1943 | struct sk_buff *list; | 1944 | struct sk_buff *list; |
1944 | 1945 | ||
1945 | BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags); | ||
1946 | |||
1947 | skb->dev = (void *) hdev; | ||
1948 | bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; | ||
1949 | hci_add_acl_hdr(skb, conn->handle, flags); | ||
1950 | |||
1951 | list = skb_shinfo(skb)->frag_list; | 1946 | list = skb_shinfo(skb)->frag_list; |
1952 | if (!list) { | 1947 | if (!list) { |
1953 | /* Non fragmented */ | 1948 | /* Non fragmented */ |
1954 | BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); | 1949 | BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); |
1955 | 1950 | ||
1956 | skb_queue_tail(&conn->data_q, skb); | 1951 | skb_queue_tail(queue, skb); |
1957 | } else { | 1952 | } else { |
1958 | /* Fragmented */ | 1953 | /* Fragmented */ |
1959 | BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); | 1954 | BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); |
@@ -1961,9 +1956,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) | |||
1961 | skb_shinfo(skb)->frag_list = NULL; | 1956 | skb_shinfo(skb)->frag_list = NULL; |
1962 | 1957 | ||
1963 | /* Queue all fragments atomically */ | 1958 | /* Queue all fragments atomically */ |
1964 | spin_lock_bh(&conn->data_q.lock); | 1959 | spin_lock_bh(&queue->lock); |
1965 | 1960 | ||
1966 | __skb_queue_tail(&conn->data_q, skb); | 1961 | __skb_queue_tail(queue, skb); |
1967 | 1962 | ||
1968 | flags &= ~ACL_START; | 1963 | flags &= ~ACL_START; |
1969 | flags |= ACL_CONT; | 1964 | flags |= ACL_CONT; |
@@ -1976,11 +1971,25 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags) | |||
1976 | 1971 | ||
1977 | BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); | 1972 | BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); |
1978 | 1973 | ||
1979 | __skb_queue_tail(&conn->data_q, skb); | 1974 | __skb_queue_tail(queue, skb); |
1980 | } while (list); | 1975 | } while (list); |
1981 | 1976 | ||
1982 | spin_unlock_bh(&conn->data_q.lock); | 1977 | spin_unlock_bh(&queue->lock); |
1983 | } | 1978 | } |
1979 | } | ||
1980 | |||
1981 | void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) | ||
1982 | { | ||
1983 | struct hci_conn *conn = chan->conn; | ||
1984 | struct hci_dev *hdev = conn->hdev; | ||
1985 | |||
1986 | BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags); | ||
1987 | |||
1988 | skb->dev = (void *) hdev; | ||
1989 | bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; | ||
1990 | hci_add_acl_hdr(skb, conn->handle, flags); | ||
1991 | |||
1992 | hci_queue_acl(conn, &chan->data_q, skb, flags); | ||
1984 | 1993 | ||
1985 | tasklet_schedule(&hdev->tx_task); | 1994 | tasklet_schedule(&hdev->tx_task); |
1986 | } | 1995 | } |
@@ -2083,11 +2092,90 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) | |||
2083 | } | 2092 | } |
2084 | } | 2093 | } |
2085 | 2094 | ||
2086 | static inline void hci_sched_acl(struct hci_dev *hdev) | 2095 | static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, |
2096 | int *quote) | ||
2087 | { | 2097 | { |
2098 | struct hci_conn_hash *h = &hdev->conn_hash; | ||
2099 | struct hci_chan *chan = NULL; | ||
2100 | int num = 0, min = ~0, cur_prio = 0; | ||
2088 | struct hci_conn *conn; | 2101 | struct hci_conn *conn; |
2102 | int cnt, q, conn_num = 0; | ||
2103 | |||
2104 | BT_DBG("%s", hdev->name); | ||
2105 | |||
2106 | list_for_each_entry(conn, &h->list, list) { | ||
2107 | struct hci_chan_hash *ch; | ||
2108 | struct hci_chan *tmp; | ||
2109 | |||
2110 | if (conn->type != type) | ||
2111 | continue; | ||
2112 | |||
2113 | if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG) | ||
2114 | continue; | ||
2115 | |||
2116 | conn_num++; | ||
2117 | |||
2118 | ch = &conn->chan_hash; | ||
2119 | |||
2120 | list_for_each_entry(tmp, &ch->list, list) { | ||
2121 | struct sk_buff *skb; | ||
2122 | |||
2123 | if (skb_queue_empty(&tmp->data_q)) | ||
2124 | continue; | ||
2125 | |||
2126 | skb = skb_peek(&tmp->data_q); | ||
2127 | if (skb->priority < cur_prio) | ||
2128 | continue; | ||
2129 | |||
2130 | if (skb->priority > cur_prio) { | ||
2131 | num = 0; | ||
2132 | min = ~0; | ||
2133 | cur_prio = skb->priority; | ||
2134 | } | ||
2135 | |||
2136 | num++; | ||
2137 | |||
2138 | if (conn->sent < min) { | ||
2139 | min = conn->sent; | ||
2140 | chan = tmp; | ||
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | if (hci_conn_num(hdev, type) == conn_num) | ||
2145 | break; | ||
2146 | } | ||
2147 | |||
2148 | if (!chan) | ||
2149 | return NULL; | ||
2150 | |||
2151 | switch (chan->conn->type) { | ||
2152 | case ACL_LINK: | ||
2153 | cnt = hdev->acl_cnt; | ||
2154 | break; | ||
2155 | case SCO_LINK: | ||
2156 | case ESCO_LINK: | ||
2157 | cnt = hdev->sco_cnt; | ||
2158 | break; | ||
2159 | case LE_LINK: | ||
2160 | cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; | ||
2161 | break; | ||
2162 | default: | ||
2163 | cnt = 0; | ||
2164 | BT_ERR("Unknown link type"); | ||
2165 | } | ||
2166 | |||
2167 | q = cnt / num; | ||
2168 | *quote = q ? q : 1; | ||
2169 | BT_DBG("chan %p quote %d", chan, *quote); | ||
2170 | return chan; | ||
2171 | } | ||
2172 | |||
2173 | static inline void hci_sched_acl(struct hci_dev *hdev) | ||
2174 | { | ||
2175 | struct hci_chan *chan; | ||
2089 | struct sk_buff *skb; | 2176 | struct sk_buff *skb; |
2090 | int quote; | 2177 | int quote; |
2178 | unsigned int cnt; | ||
2091 | 2179 | ||
2092 | BT_DBG("%s", hdev->name); | 2180 | BT_DBG("%s", hdev->name); |
2093 | 2181 | ||
@@ -2101,17 +2189,23 @@ static inline void hci_sched_acl(struct hci_dev *hdev) | |||
2101 | hci_link_tx_to(hdev, ACL_LINK); | 2189 | hci_link_tx_to(hdev, ACL_LINK); |
2102 | } | 2190 | } |
2103 | 2191 | ||
2104 | while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { | 2192 | cnt = hdev->acl_cnt; |
2105 | while (quote-- && (skb = skb_dequeue(&conn->data_q))) { | ||
2106 | BT_DBG("skb %p len %d", skb, skb->len); | ||
2107 | 2193 | ||
2108 | hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active); | 2194 | while (hdev->acl_cnt && |
2195 | (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { | ||
2196 | while (quote-- && (skb = skb_dequeue(&chan->data_q))) { | ||
2197 | BT_DBG("chan %p skb %p len %d priority %u", chan, skb, | ||
2198 | skb->len, skb->priority); | ||
2199 | |||
2200 | hci_conn_enter_active_mode(chan->conn, | ||
2201 | bt_cb(skb)->force_active); | ||
2109 | 2202 | ||
2110 | hci_send_frame(skb); | 2203 | hci_send_frame(skb); |
2111 | hdev->acl_last_tx = jiffies; | 2204 | hdev->acl_last_tx = jiffies; |
2112 | 2205 | ||
2113 | hdev->acl_cnt--; | 2206 | hdev->acl_cnt--; |
2114 | conn->sent++; | 2207 | chan->sent++; |
2208 | chan->conn->sent++; | ||
2115 | } | 2209 | } |
2116 | } | 2210 | } |
2117 | } | 2211 | } |
@@ -2165,7 +2259,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev) | |||
2165 | 2259 | ||
2166 | static inline void hci_sched_le(struct hci_dev *hdev) | 2260 | static inline void hci_sched_le(struct hci_dev *hdev) |
2167 | { | 2261 | { |
2168 | struct hci_conn *conn; | 2262 | struct hci_chan *chan; |
2169 | struct sk_buff *skb; | 2263 | struct sk_buff *skb; |
2170 | int quote, cnt; | 2264 | int quote, cnt; |
2171 | 2265 | ||
@@ -2183,17 +2277,20 @@ static inline void hci_sched_le(struct hci_dev *hdev) | |||
2183 | } | 2277 | } |
2184 | 2278 | ||
2185 | cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; | 2279 | cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; |
2186 | while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) { | 2280 | while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { |
2187 | while (quote-- && (skb = skb_dequeue(&conn->data_q))) { | 2281 | while (quote-- && (skb = skb_dequeue(&chan->data_q))) { |
2188 | BT_DBG("skb %p len %d", skb, skb->len); | 2282 | BT_DBG("chan %p skb %p len %d priority %u", chan, skb, |
2283 | skb->len, skb->priority); | ||
2189 | 2284 | ||
2190 | hci_send_frame(skb); | 2285 | hci_send_frame(skb); |
2191 | hdev->le_last_tx = jiffies; | 2286 | hdev->le_last_tx = jiffies; |
2192 | 2287 | ||
2193 | cnt--; | 2288 | cnt--; |
2194 | conn->sent++; | 2289 | chan->sent++; |
2290 | chan->conn->sent++; | ||
2195 | } | 2291 | } |
2196 | } | 2292 | } |
2293 | |||
2197 | if (hdev->le_pkts) | 2294 | if (hdev->le_pkts) |
2198 | hdev->le_cnt = cnt; | 2295 | hdev->le_cnt = cnt; |
2199 | else | 2296 | else |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ac2c41ada0fe..15751fa5e914 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -566,7 +566,25 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, | |||
566 | bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON; | 566 | bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON; |
567 | skb->priority = HCI_PRIO_MAX; | 567 | skb->priority = HCI_PRIO_MAX; |
568 | 568 | ||
569 | hci_send_acl(conn->hcon, skb, flags); | 569 | hci_send_acl(conn->hchan, skb, flags); |
570 | } | ||
571 | |||
572 | static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | ||
573 | { | ||
574 | struct hci_conn *hcon = chan->conn->hcon; | ||
575 | u16 flags; | ||
576 | |||
577 | BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, | ||
578 | skb->priority); | ||
579 | |||
580 | if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && | ||
581 | lmp_no_flush_capable(hcon->hdev)) | ||
582 | flags = ACL_START_NO_FLUSH; | ||
583 | else | ||
584 | flags = ACL_START; | ||
585 | |||
586 | bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); | ||
587 | hci_send_acl(chan->conn->hchan, skb, flags); | ||
570 | } | 588 | } |
571 | 589 | ||
572 | static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) | 590 | static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) |
@@ -575,7 +593,6 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) | |||
575 | struct l2cap_hdr *lh; | 593 | struct l2cap_hdr *lh; |
576 | struct l2cap_conn *conn = chan->conn; | 594 | struct l2cap_conn *conn = chan->conn; |
577 | int count, hlen; | 595 | int count, hlen; |
578 | u8 flags; | ||
579 | 596 | ||
580 | if (chan->state != BT_CONNECTED) | 597 | if (chan->state != BT_CONNECTED) |
581 | return; | 598 | return; |
@@ -615,14 +632,8 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) | |||
615 | put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); | 632 | put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); |
616 | } | 633 | } |
617 | 634 | ||
618 | if (lmp_no_flush_capable(conn->hcon->hdev)) | 635 | skb->priority = HCI_PRIO_MAX; |
619 | flags = ACL_START_NO_FLUSH; | 636 | l2cap_do_send(chan, skb); |
620 | else | ||
621 | flags = ACL_START; | ||
622 | |||
623 | bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); | ||
624 | |||
625 | hci_send_acl(chan->conn->hcon, skb, flags); | ||
626 | } | 637 | } |
627 | 638 | ||
628 | static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) | 639 | static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) |
@@ -1002,6 +1013,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) | |||
1002 | chan->ops->close(chan->data); | 1013 | chan->ops->close(chan->data); |
1003 | } | 1014 | } |
1004 | 1015 | ||
1016 | hci_chan_del(conn->hchan); | ||
1017 | |||
1005 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) | 1018 | if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) |
1006 | del_timer_sync(&conn->info_timer); | 1019 | del_timer_sync(&conn->info_timer); |
1007 | 1020 | ||
@@ -1024,18 +1037,26 @@ static void security_timeout(unsigned long arg) | |||
1024 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) | 1037 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) |
1025 | { | 1038 | { |
1026 | struct l2cap_conn *conn = hcon->l2cap_data; | 1039 | struct l2cap_conn *conn = hcon->l2cap_data; |
1040 | struct hci_chan *hchan; | ||
1027 | 1041 | ||
1028 | if (conn || status) | 1042 | if (conn || status) |
1029 | return conn; | 1043 | return conn; |
1030 | 1044 | ||
1045 | hchan = hci_chan_create(hcon); | ||
1046 | if (!hchan) | ||
1047 | return NULL; | ||
1048 | |||
1031 | conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); | 1049 | conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); |
1032 | if (!conn) | 1050 | if (!conn) { |
1051 | hci_chan_del(hchan); | ||
1033 | return NULL; | 1052 | return NULL; |
1053 | } | ||
1034 | 1054 | ||
1035 | hcon->l2cap_data = conn; | 1055 | hcon->l2cap_data = conn; |
1036 | conn->hcon = hcon; | 1056 | conn->hcon = hcon; |
1057 | conn->hchan = hchan; | ||
1037 | 1058 | ||
1038 | BT_DBG("hcon %p conn %p", hcon, conn); | 1059 | BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); |
1039 | 1060 | ||
1040 | if (hcon->hdev->le_mtu && hcon->type == LE_LINK) | 1061 | if (hcon->hdev->le_mtu && hcon->type == LE_LINK) |
1041 | conn->mtu = hcon->hdev->le_mtu; | 1062 | conn->mtu = hcon->hdev->le_mtu; |
@@ -1261,24 +1282,6 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) | |||
1261 | __clear_retrans_timer(chan); | 1282 | __clear_retrans_timer(chan); |
1262 | } | 1283 | } |
1263 | 1284 | ||
1264 | static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) | ||
1265 | { | ||
1266 | struct hci_conn *hcon = chan->conn->hcon; | ||
1267 | u16 flags; | ||
1268 | |||
1269 | BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, | ||
1270 | skb->priority); | ||
1271 | |||
1272 | if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && | ||
1273 | lmp_no_flush_capable(hcon->hdev)) | ||
1274 | flags = ACL_START_NO_FLUSH; | ||
1275 | else | ||
1276 | flags = ACL_START; | ||
1277 | |||
1278 | bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); | ||
1279 | hci_send_acl(hcon, skb, flags); | ||
1280 | } | ||
1281 | |||
1282 | static void l2cap_streaming_send(struct l2cap_chan *chan) | 1285 | static void l2cap_streaming_send(struct l2cap_chan *chan) |
1283 | { | 1286 | { |
1284 | struct sk_buff *skb; | 1287 | struct sk_buff *skb; |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 759b63572641..94e94ca35384 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -181,7 +181,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) | |||
181 | if (!skb) | 181 | if (!skb) |
182 | return; | 182 | return; |
183 | 183 | ||
184 | hci_send_acl(conn->hcon, skb, 0); | 184 | skb->priority = HCI_PRIO_MAX; |
185 | hci_send_acl(conn->hchan, skb, 0); | ||
185 | 186 | ||
186 | mod_timer(&conn->security_timer, jiffies + | 187 | mod_timer(&conn->security_timer, jiffies + |
187 | msecs_to_jiffies(SMP_TIMEOUT)); | 188 | msecs_to_jiffies(SMP_TIMEOUT)); |