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 /net/bluetooth | |
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>
Diffstat (limited to 'net/bluetooth')
-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 |
3 files changed, 108 insertions, 4 deletions
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) |