diff options
| author | Ville Tervo <ville.tervo@nokia.com> | 2011-02-10 20:38:48 -0500 |
|---|---|---|
| committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-02-16 14:32:51 -0500 |
| commit | 6ed58ec520ad2b2fe3f955c8a5fd0eecafccebdf (patch) | |
| tree | 5e53b20a64214c811dda8625c14af394a7800718 | |
| parent | fcd89c09a59a054fb986861e0862aa2fff7d7c40 (diff) | |
Bluetooth: Use LE buffers for LE traffic
Bluetooth chips may have separate buffers for LE traffic.
This patch add support to use LE buffers provided by the chip.
Signed-off-by: Ville Tervo <ville.tervo@nokia.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 | 5 | ||||
| -rw-r--r-- | net/bluetooth/hci_conn.c | 5 | ||||
| -rw-r--r-- | net/bluetooth/hci_core.c | 74 | ||||
| -rw-r--r-- | net/bluetooth/hci_event.c | 33 |
4 files changed, 113 insertions, 4 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f434e96ce020..d30b93c82fd4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
| @@ -123,15 +123,19 @@ struct hci_dev { | |||
| 123 | atomic_t cmd_cnt; | 123 | atomic_t cmd_cnt; |
| 124 | unsigned int acl_cnt; | 124 | unsigned int acl_cnt; |
| 125 | unsigned int sco_cnt; | 125 | unsigned int sco_cnt; |
| 126 | unsigned int le_cnt; | ||
| 126 | 127 | ||
| 127 | unsigned int acl_mtu; | 128 | unsigned int acl_mtu; |
| 128 | unsigned int sco_mtu; | 129 | unsigned int sco_mtu; |
| 130 | unsigned int le_mtu; | ||
| 129 | unsigned int acl_pkts; | 131 | unsigned int acl_pkts; |
| 130 | unsigned int sco_pkts; | 132 | unsigned int sco_pkts; |
| 133 | unsigned int le_pkts; | ||
| 131 | 134 | ||
| 132 | unsigned long cmd_last_tx; | 135 | unsigned long cmd_last_tx; |
| 133 | unsigned long acl_last_tx; | 136 | unsigned long acl_last_tx; |
| 134 | unsigned long sco_last_tx; | 137 | unsigned long sco_last_tx; |
| 138 | unsigned long le_last_tx; | ||
| 135 | 139 | ||
| 136 | struct workqueue_struct *workqueue; | 140 | struct workqueue_struct *workqueue; |
| 137 | 141 | ||
| @@ -521,6 +525,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); | |||
| 521 | #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) | 525 | #define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) |
| 522 | #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) | 526 | #define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR) |
| 523 | #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) | 527 | #define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH) |
| 528 | #define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE) | ||
| 524 | 529 | ||
| 525 | /* ----- HCI protocols ----- */ | 530 | /* ----- HCI protocols ----- */ |
| 526 | struct hci_proto { | 531 | struct hci_proto { |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d0c470c18f9d..aecd78e6cceb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
| @@ -326,6 +326,11 @@ int hci_conn_del(struct hci_conn *conn) | |||
| 326 | 326 | ||
| 327 | /* Unacked frames */ | 327 | /* Unacked frames */ |
| 328 | hdev->acl_cnt += conn->sent; | 328 | hdev->acl_cnt += conn->sent; |
| 329 | } else if (conn->type == LE_LINK) { | ||
| 330 | if (hdev->le_pkts) | ||
| 331 | hdev->le_cnt += conn->sent; | ||
| 332 | else | ||
| 333 | hdev->acl_cnt += conn->sent; | ||
| 329 | } else { | 334 | } else { |
| 330 | struct hci_conn *acl = conn->link; | 335 | struct hci_conn *acl = conn->link; |
| 331 | if (acl) { | 336 | if (acl) { |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2f003224d2ea..92960532dea4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
| @@ -263,6 +263,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) | |||
| 263 | hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); | 263 | hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp); |
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) | ||
| 267 | { | ||
| 268 | BT_DBG("%s", hdev->name); | ||
| 269 | |||
| 270 | /* Read LE buffer size */ | ||
| 271 | hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); | ||
| 272 | } | ||
| 273 | |||
| 266 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) | 274 | static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) |
| 267 | { | 275 | { |
| 268 | __u8 scan = opt; | 276 | __u8 scan = opt; |
| @@ -529,6 +537,10 @@ int hci_dev_open(__u16 dev) | |||
| 529 | ret = __hci_request(hdev, hci_init_req, 0, | 537 | ret = __hci_request(hdev, hci_init_req, 0, |
| 530 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | 538 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); |
| 531 | 539 | ||
| 540 | if (lmp_le_capable(hdev)) | ||
| 541 | ret = __hci_request(hdev, hci_le_init_req, 0, | ||
| 542 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | ||
| 543 | |||
| 532 | clear_bit(HCI_INIT, &hdev->flags); | 544 | clear_bit(HCI_INIT, &hdev->flags); |
| 533 | } | 545 | } |
| 534 | 546 | ||
| @@ -671,7 +683,7 @@ int hci_dev_reset(__u16 dev) | |||
| 671 | hdev->flush(hdev); | 683 | hdev->flush(hdev); |
| 672 | 684 | ||
| 673 | atomic_set(&hdev->cmd_cnt, 1); | 685 | atomic_set(&hdev->cmd_cnt, 1); |
| 674 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; | 686 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; |
| 675 | 687 | ||
| 676 | if (!test_bit(HCI_RAW, &hdev->flags)) | 688 | if (!test_bit(HCI_RAW, &hdev->flags)) |
| 677 | ret = __hci_request(hdev, hci_reset_req, 0, | 689 | ret = __hci_request(hdev, hci_reset_req, 0, |
| @@ -1672,8 +1684,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int | |||
| 1672 | } | 1684 | } |
| 1673 | 1685 | ||
| 1674 | if (conn) { | 1686 | if (conn) { |
| 1675 | int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); | 1687 | int cnt, q; |
| 1676 | int q = cnt / num; | 1688 | |
| 1689 | switch (conn->type) { | ||
| 1690 | case ACL_LINK: | ||
| 1691 | cnt = hdev->acl_cnt; | ||
| 1692 | break; | ||
| 1693 | case SCO_LINK: | ||
| 1694 | case ESCO_LINK: | ||
| 1695 | cnt = hdev->sco_cnt; | ||
| 1696 | break; | ||
| 1697 | case LE_LINK: | ||
| 1698 | cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; | ||
| 1699 | break; | ||
| 1700 | default: | ||
| 1701 | cnt = 0; | ||
| 1702 | BT_ERR("Unknown link type"); | ||
| 1703 | } | ||
| 1704 | |||
| 1705 | q = cnt / num; | ||
| 1677 | *quote = q ? q : 1; | 1706 | *quote = q ? q : 1; |
| 1678 | } else | 1707 | } else |
| 1679 | *quote = 0; | 1708 | *quote = 0; |
| @@ -1772,6 +1801,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev) | |||
| 1772 | } | 1801 | } |
| 1773 | } | 1802 | } |
| 1774 | 1803 | ||
| 1804 | static inline void hci_sched_le(struct hci_dev *hdev) | ||
| 1805 | { | ||
| 1806 | struct hci_conn *conn; | ||
| 1807 | struct sk_buff *skb; | ||
| 1808 | int quote, cnt; | ||
| 1809 | |||
| 1810 | BT_DBG("%s", hdev->name); | ||
| 1811 | |||
| 1812 | if (!test_bit(HCI_RAW, &hdev->flags)) { | ||
| 1813 | /* LE tx timeout must be longer than maximum | ||
| 1814 | * link supervision timeout (40.9 seconds) */ | ||
| 1815 | if (!hdev->le_cnt && | ||
| 1816 | time_after(jiffies, hdev->le_last_tx + HZ * 45)) | ||
| 1817 | hci_acl_tx_to(hdev); | ||
| 1818 | } | ||
| 1819 | |||
| 1820 | cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; | ||
| 1821 | while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) { | ||
| 1822 | while (quote-- && (skb = skb_dequeue(&conn->data_q))) { | ||
| 1823 | BT_DBG("skb %p len %d", skb, skb->len); | ||
| 1824 | |||
| 1825 | hci_send_frame(skb); | ||
| 1826 | hdev->le_last_tx = jiffies; | ||
| 1827 | |||
| 1828 | cnt--; | ||
| 1829 | conn->sent++; | ||
| 1830 | } | ||
| 1831 | } | ||
| 1832 | if (hdev->le_pkts) | ||
| 1833 | hdev->le_cnt = cnt; | ||
| 1834 | else | ||
| 1835 | hdev->acl_cnt = cnt; | ||
| 1836 | } | ||
| 1837 | |||
| 1775 | static void hci_tx_task(unsigned long arg) | 1838 | static void hci_tx_task(unsigned long arg) |
| 1776 | { | 1839 | { |
| 1777 | struct hci_dev *hdev = (struct hci_dev *) arg; | 1840 | struct hci_dev *hdev = (struct hci_dev *) arg; |
| @@ -1779,7 +1842,8 @@ static void hci_tx_task(unsigned long arg) | |||
| 1779 | 1842 | ||
| 1780 | read_lock(&hci_task_lock); | 1843 | read_lock(&hci_task_lock); |
| 1781 | 1844 | ||
| 1782 | BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); | 1845 | BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, |
| 1846 | hdev->sco_cnt, hdev->le_cnt); | ||
| 1783 | 1847 | ||
| 1784 | /* Schedule queues and send stuff to HCI driver */ | 1848 | /* Schedule queues and send stuff to HCI driver */ |
| 1785 | 1849 | ||
| @@ -1789,6 +1853,8 @@ static void hci_tx_task(unsigned long arg) | |||
| 1789 | 1853 | ||
| 1790 | hci_sched_esco(hdev); | 1854 | hci_sched_esco(hdev); |
| 1791 | 1855 | ||
| 1856 | hci_sched_le(hdev); | ||
| 1857 | |||
| 1792 | /* Send next queued raw (unknown type) packet */ | 1858 | /* Send next queued raw (unknown type) packet */ |
| 1793 | while ((skb = skb_dequeue(&hdev->raw_q))) | 1859 | while ((skb = skb_dequeue(&hdev->raw_q))) |
| 1794 | hci_send_frame(skb); | 1860 | hci_send_frame(skb); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 47c6e9316ce8..3155ad588076 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
| @@ -776,6 +776,25 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) | |||
| 776 | mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr, | 776 | mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr, |
| 777 | rp->status); | 777 | rp->status); |
| 778 | } | 778 | } |
| 779 | static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, | ||
| 780 | struct sk_buff *skb) | ||
| 781 | { | ||
| 782 | struct hci_rp_le_read_buffer_size *rp = (void *) skb->data; | ||
| 783 | |||
| 784 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | ||
| 785 | |||
| 786 | if (rp->status) | ||
| 787 | return; | ||
| 788 | |||
| 789 | hdev->le_mtu = __le16_to_cpu(rp->le_mtu); | ||
| 790 | hdev->le_pkts = rp->le_max_pkt; | ||
| 791 | |||
| 792 | hdev->le_cnt = hdev->le_pkts; | ||
| 793 | |||
| 794 | BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts); | ||
| 795 | |||
| 796 | hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status); | ||
| 797 | } | ||
| 779 | 798 | ||
| 780 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 799 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
| 781 | { | 800 | { |
| @@ -1704,6 +1723,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
| 1704 | hci_cc_pin_code_neg_reply(hdev, skb); | 1723 | hci_cc_pin_code_neg_reply(hdev, skb); |
| 1705 | break; | 1724 | break; |
| 1706 | 1725 | ||
| 1726 | case HCI_OP_LE_READ_BUFFER_SIZE: | ||
| 1727 | hci_cc_le_read_buffer_size(hdev, skb); | ||
| 1728 | break; | ||
| 1729 | |||
| 1707 | default: | 1730 | default: |
| 1708 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1731 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
| 1709 | break; | 1732 | break; |
| @@ -1849,6 +1872,16 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s | |||
| 1849 | hdev->acl_cnt += count; | 1872 | hdev->acl_cnt += count; |
| 1850 | if (hdev->acl_cnt > hdev->acl_pkts) | 1873 | if (hdev->acl_cnt > hdev->acl_pkts) |
| 1851 | hdev->acl_cnt = hdev->acl_pkts; | 1874 | hdev->acl_cnt = hdev->acl_pkts; |
| 1875 | } else if (conn->type == LE_LINK) { | ||
| 1876 | if (hdev->le_pkts) { | ||
| 1877 | hdev->le_cnt += count; | ||
| 1878 | if (hdev->le_cnt > hdev->le_pkts) | ||
| 1879 | hdev->le_cnt = hdev->le_pkts; | ||
| 1880 | } else { | ||
| 1881 | hdev->acl_cnt += count; | ||
| 1882 | if (hdev->acl_cnt > hdev->acl_pkts) | ||
| 1883 | hdev->acl_cnt = hdev->acl_pkts; | ||
| 1884 | } | ||
| 1852 | } else { | 1885 | } else { |
| 1853 | hdev->sco_cnt += count; | 1886 | hdev->sco_cnt += count; |
| 1854 | if (hdev->sco_cnt > hdev->sco_pkts) | 1887 | if (hdev->sco_cnt > hdev->sco_pkts) |
