Hi Ville, On Mon, Oct 25, 2010 at 10:21 AM, Ville Tervo <ville.tervo@xxxxxxxxx> wrote: > 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@xxxxxxxxx> > --- > Âinclude/net/bluetooth/hci.h   Â|  Â1 + > Âinclude/net/bluetooth/hci_core.h |  Â5 +++ > Ânet/bluetooth/hci_conn.c     |  Â5 +++ > Ânet/bluetooth/hci_core.c     |  74 +++++++++++++++++++++++++++++++++++-- > Ânet/bluetooth/hci_event.c    Â|  40 +++++++++++++++++++- > Â5 files changed, 119 insertions(+), 6 deletions(-) > > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h > index 02055b9..2103731 100644 > --- a/include/net/bluetooth/hci.h > +++ b/include/net/bluetooth/hci.h > @@ -189,6 +189,7 @@ enum { > > Â#define LMP_EV4        Â0x01 > Â#define LMP_EV5        Â0x02 > +#define LMP_LE     0x40 > > Â#define LMP_SNIFF_SUBR 0x02 > Â#define LMP_EDR_ESCO_2M    Â0x20 > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h > index 2b7f94a..e2d857a 100644 > --- a/include/net/bluetooth/hci_core.h > +++ b/include/net/bluetooth/hci_core.h > @@ -103,15 +103,19 @@ struct hci_dev { >    Âatomic_t    Âcmd_cnt; >    Âunsigned int  Âacl_cnt; >    Âunsigned int  Âsco_cnt; > +    unsigned int  Âle_cnt; > >    Âunsigned int  Âacl_mtu; >    Âunsigned int  Âsco_mtu; > +    unsigned int  Âle_mtu; >    Âunsigned int  Âacl_pkts; >    Âunsigned int  Âsco_pkts; > +    unsigned int  Âle_pkts; > >    Âunsigned long  cmd_last_tx; >    Âunsigned long  acl_last_tx; >    Âunsigned long  sco_last_tx; > +    unsigned long  le_last_tx; > >    Âstruct workqueue_struct *workqueue; > > @@ -473,6 +477,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); > Â#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) > Â#define lmp_esco_capable(dev)   Â((dev)->features[3] & LMP_ESCO) > Â#define lmp_ssp_capable(dev)    ((dev)->features[6] & LMP_SIMPLE_PAIR) > +#define lmp_le_capable(dev)    Â((dev)->features[4] & LMP_LE) > > Â/* ----- HCI protocols ----- */ > Âstruct hci_proto { > diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c > index 0944c0c..ddc2e5e 100644 > --- a/net/bluetooth/hci_conn.c > +++ b/net/bluetooth/hci_conn.c > @@ -324,6 +324,11 @@ int hci_conn_del(struct hci_conn *conn) > >        Â/* Unacked frames */ >        Âhdev->acl_cnt += conn->sent; > +    } else if (conn->type == LE_LINK) { > +        if (hdev->le_pkts) > +            hdev->le_cnt += conn->sent; > +        else > +            hdev->acl_cnt += conn->sent; >    Â} else { >        Âstruct hci_conn *acl = conn->link; >        Âif (acl) { > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c > index bc2a052..45c78c2 100644 > --- a/net/bluetooth/hci_core.c > +++ b/net/bluetooth/hci_core.c > @@ -254,6 +254,14 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) >    Âhci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); > Â} > > +static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt) > +{ > +    BT_DBG("%s", hdev->name); > + > +    /* Read LE buffer size */ > +    hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL); > +} > + > Âstatic void hci_scan_req(struct hci_dev *hdev, unsigned long opt) > Â{ >    Â__u8 scan = opt; > @@ -509,6 +517,10 @@ int hci_dev_open(__u16 dev) >        Âret = __hci_request(hdev, hci_init_req, 0, >                    Âmsecs_to_jiffies(HCI_INIT_TIMEOUT)); > > +        if (lmp_le_capable(hdev)) > +            ret = __hci_request(hdev, hci_le_init_req, 0, > +                    msecs_to_jiffies(HCI_INIT_TIMEOUT)); > + >        Âclear_bit(HCI_INIT, &hdev->flags); >    Â} > > @@ -645,7 +657,7 @@ int hci_dev_reset(__u16 dev) >        Âhdev->flush(hdev); > >    Âatomic_set(&hdev->cmd_cnt, 1); > -    hdev->acl_cnt = 0; hdev->sco_cnt = 0; > +    hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; > >    Âif (!test_bit(HCI_RAW, &hdev->flags)) >        Âret = __hci_request(hdev, hci_reset_req, 0, > @@ -1456,8 +1468,25 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int >    Â} > >    Âif (conn) { > -        int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); > -        int q = cnt / num; > +        int cnt, q; > + > +        switch (conn->type) { > +        case ACL_LINK: > +            cnt = hdev->acl_cnt; > +            break; > +        case SCO_LINK: > +        case ESCO_LINK: > +            cnt = hdev->sco_cnt; > +            break; > +        case LE_LINK: > +            cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt; > +            break; > +        default: > +            cnt = 0; > +            BT_ERR("Unknown link type"); > +        } > + > +        q = cnt / num; >        Â*quote = q ? q : 1; >    Â} else >        Â*quote = 0; > @@ -1556,6 +1585,40 @@ static inline void hci_sched_esco(struct hci_dev *hdev) >    Â} > Â} > > +static inline void hci_sched_le(struct hci_dev *hdev) > +{ > +    struct hci_conn *conn; > +    struct sk_buff *skb; > +    int quote, cnt; > + > +    BT_DBG("%s", hdev->name); > + > +    if (!test_bit(HCI_RAW, &hdev->flags)) { > +        /* ACL tx timeout must be longer than maximum > +        Â* link supervision timeout (40.9 seconds) */ > +        if (!hdev->le_cnt && > +          time_after(jiffies, hdev->le_last_tx + HZ * 45)) > +            hci_acl_tx_to(hdev); > +    } It seems that the ACL tx timeout is causing some problems: BR/EDR and LE connections are not working properly on macbooks! Don't ask me why on macbooks only! But I double checked. I tested your branch and also bluetooth-next + LE patches and both are not working as expected. I didn't have time to investigate it, do you have any clue? For BR/EDR I am receiving "killing stalled ACL connection" messages for all connections. Regards, Claudio > + > +    cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt; > +    while (cnt && (conn = hci_low_sent(hdev, LE_LINK, "e))) { > +        while (quote-- && (skb = skb_dequeue(&conn->data_q))) { > +            BT_DBG("skb %p len %d", skb, skb->len); > + > +            hci_send_frame(skb); > +            hdev->le_last_tx = jiffies; > + > +            cnt--; > +            conn->sent++; > +        } > +    } > +    if (hdev->le_pkts) > +        hdev->le_cnt = cnt; > +    else > +        hdev->acl_cnt = cnt; > +} > + > Âstatic void hci_tx_task(unsigned long arg) > Â{ >    Âstruct hci_dev *hdev = (struct hci_dev *) arg; > @@ -1563,7 +1626,8 @@ static void hci_tx_task(unsigned long arg) > >    Âread_lock(&hci_task_lock); > > -    BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); > +    BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, > +        hdev->sco_cnt, hdev->le_cnt); > >    Â/* Schedule queues and send stuff to HCI driver */ > > @@ -1573,6 +1637,8 @@ static void hci_tx_task(unsigned long arg) > >    Âhci_sched_esco(hdev); > > +    hci_sched_le(hdev); > + >    Â/* Send next queued raw (unknown type) packet */ >    Âwhile ((skb = skb_dequeue(&hdev->raw_q))) >        Âhci_send_frame(skb); > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c > index 92c8621..da23502 100644 > --- a/net/bluetooth/hci_event.c > +++ b/net/bluetooth/hci_event.c > @@ -539,6 +539,26 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) >    Âhci_req_complete(hdev, rp->status); > Â} > > +static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, > +                   Âstruct sk_buff *skb) > +{ > +    struct hci_rp_le_read_buffer_size *rp = (void *) skb->data; > + > +    BT_DBG("%s status 0x%x", hdev->name, rp->status); > + > +    if (rp->status) > +        return; > + > +    hdev->le_mtu = __le16_to_cpu(rp->le_mtu); > +    hdev->le_pkts = rp->le_max_pkt; > + > +    hdev->le_cnt = hdev->le_pkts; > + > +    BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts); > + > +    hci_req_complete(hdev, rp->status); > +} > + > Âstatic inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) > Â{ >    ÂBT_DBG("%s status 0x%x", hdev->name, status); > @@ -1353,6 +1373,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk >        Âhci_cc_read_bd_addr(hdev, skb); >        Âbreak; > > +    case HCI_OP_LE_READ_BUFFER_SIZE: > +        hci_cc_le_read_buffer_size(hdev, skb); > +        break; > + >    Âdefault: >        ÂBT_DBG("%s opcode 0x%x", hdev->name, opcode); >        Âbreak; > @@ -1490,10 +1514,22 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s >            Âconn->sent -= count; > >            Âif (conn->type == ACL_LINK) { > -                if ((hdev->acl_cnt += count) > hdev->acl_pkts) > +                hdev->acl_cnt += count; > +                if (hdev->acl_cnt > hdev->acl_pkts) >                    Âhdev->acl_cnt = hdev->acl_pkts; > +            } else if (conn->type == LE_LINK) { > +                if (hdev->le_pkts) { > +                    hdev->le_cnt += count; > +                    if (hdev->le_cnt > hdev->le_pkts) > +                        hdev->le_cnt = hdev->le_pkts; > +                } else { > +                    hdev->acl_cnt += count; > +                    if (hdev->acl_cnt > hdev->acl_pkts) > +                        hdev->acl_cnt = hdev->acl_pkts; > +                } >            Â} else { > -                if ((hdev->sco_cnt += count) > hdev->sco_pkts) > +                hdev->sco_cnt += count; > +                if (hdev->sco_cnt > hdev->sco_pkts) >                    Âhdev->sco_cnt = hdev->sco_pkts; >            Â} >        Â} > -- > 1.7.1 > ÿô.nÇ·®+%˱é¥wÿº{.nÇ·¥{±ý¶â^nr¡öë¨è&£ûz¹Þúzf£¢·h§~Ûÿÿïÿê_èæ+v¨þ)ßø