From e9753eff1b875d579dc04d675e72d6e31e866927 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 14 Sep 2014 08:49:34 +0300 Subject: Bluetooth: btusb: Use GFP_KERNEL in btusb_send_frame() All hdev->send() calls are these days done through a work queue. For the btusb driver this means the btusb_send_frame() function. Because of this we can safely use GFP_KERNEL for all memory allocations in this code path. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a79d657c084..d696e68f326 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -769,11 +769,11 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + dr = kmalloc(sizeof(*dr), GFP_KERNEL); if (!dr) { usb_free_urb(urb); return -ENOMEM; @@ -797,7 +797,7 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) if (!data->bulk_tx_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; @@ -814,7 +814,7 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1) return -ENODEV; - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); if (!urb) return -ENOMEM; @@ -848,7 +848,7 @@ static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) skip_waking: usb_anchor_urb(urb, &data->tx_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", -- cgit v1.2.3-70-g09d2 From 047b2ec8d3778a046d6985d4ad410c85211a86a4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 14 Sep 2014 09:11:06 +0200 Subject: Bluetooth: btusb: Separate TX URB allocation and submission The complete TX URB handling is done via a switch statement in the btusb_send_frame function. To allow for more clear separation between control, bulk and isoc URBs, split them into allocation and submission. Previously the inc_tx function has been used for tracking in-flight URB for HCI commands and ACL data packets. Convert that into a common function that either submits the URB or queues it when needed. This provides the flexibility to allow vendor specific hdev->send_frame callbacks without having to duplicate the whole URB handling logic. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 206 ++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index d696e68f326..c89b330cfa9 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -296,20 +296,6 @@ struct btusb_data { int suspend_count; }; -static int inc_tx(struct btusb_data *data) -{ - unsigned long flags; - int rv; - - spin_lock_irqsave(&data->txlock, flags); - rv = test_bit(BTUSB_SUSPENDING, &data->flags); - if (!rv) - data->tx_in_flight++; - spin_unlock_irqrestore(&data->txlock, flags); - - return rv; -} - static void btusb_intr_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; @@ -752,100 +738,96 @@ static int btusb_flush(struct hci_dev *hdev) return 0; } -static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); struct usb_ctrlrequest *dr; struct urb *urb; unsigned int pipe; - int err; - BT_DBG("%s", hdev->name); + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; + dr = kmalloc(sizeof(*dr), GFP_KERNEL); + if (!dr) { + usb_free_urb(urb); + return ERR_PTR(-ENOMEM); + } - skb->dev = (void *) hdev; + dr->bRequestType = data->cmdreq_type; + dr->bRequest = 0; + dr->wIndex = 0; + dr->wValue = 0; + dr->wLength = __cpu_to_le16(skb->len); - switch (bt_cb(skb)->pkt_type) { - case HCI_COMMAND_PKT: - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - dr = kmalloc(sizeof(*dr), GFP_KERNEL); - if (!dr) { - usb_free_urb(urb); - return -ENOMEM; - } + pipe = usb_sndctrlpipe(data->udev, 0x00); - dr->bRequestType = data->cmdreq_type; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = __cpu_to_le16(skb->len); + usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, + skb->data, skb->len, btusb_tx_complete, skb); - pipe = usb_sndctrlpipe(data->udev, 0x00); + skb->dev = (void *) hdev; - usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, - skb->data, skb->len, btusb_tx_complete, skb); + return urb; +} - hdev->stat.cmd_tx++; - break; +static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct urb *urb; + unsigned int pipe; - case HCI_ACLDATA_PKT: - if (!data->bulk_tx_ep) - return -ENODEV; + if (!data->bulk_tx_ep) + return ERR_PTR(-ENODEV); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); - pipe = usb_sndbulkpipe(data->udev, - data->bulk_tx_ep->bEndpointAddress); + pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); - usb_fill_bulk_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_tx_complete, skb); + usb_fill_bulk_urb(urb, data->udev, pipe, + skb->data, skb->len, btusb_tx_complete, skb); - hdev->stat.acl_tx++; - break; + skb->dev = (void *) hdev; - case HCI_SCODATA_PKT: - if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1) - return -ENODEV; + return urb; +} - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); - if (!urb) - return -ENOMEM; +static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct urb *urb; + unsigned int pipe; - pipe = usb_sndisocpipe(data->udev, - data->isoc_tx_ep->bEndpointAddress); + if (!data->isoc_tx_ep) + return ERR_PTR(-ENODEV); - usb_fill_int_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_isoc_tx_complete, - skb, data->isoc_tx_ep->bInterval); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); - urb->transfer_flags = URB_ISO_ASAP; + pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); - __fill_isoc_descriptor(urb, skb->len, - le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); + usb_fill_int_urb(urb, data->udev, pipe, + skb->data, skb->len, btusb_isoc_tx_complete, + skb, data->isoc_tx_ep->bInterval); - hdev->stat.sco_tx++; - goto skip_waking; + urb->transfer_flags = URB_ISO_ASAP; - default: - return -EILSEQ; - } + __fill_isoc_descriptor(urb, skb->len, + le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); - err = inc_tx(data); - if (err) { - usb_anchor_urb(urb, &data->deferred); - schedule_work(&data->waker); - err = 0; - goto done; - } + skb->dev = (void *) hdev; + + return urb; +} + +static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + int err; -skip_waking: usb_anchor_urb(urb, &data->tx_anchor); err = usb_submit_urb(urb, GFP_KERNEL); @@ -859,11 +841,73 @@ skip_waking: usb_mark_last_busy(data->udev); } -done: usb_free_urb(urb); return err; } +static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + unsigned long flags; + bool suspending; + + spin_lock_irqsave(&data->txlock, flags); + suspending = test_bit(BTUSB_SUSPENDING, &data->flags); + if (!suspending) + data->tx_in_flight++; + spin_unlock_irqrestore(&data->txlock, flags); + + if (!suspending) + return submit_tx_urb(hdev, urb); + + usb_anchor_urb(urb, &data->deferred); + schedule_work(&data->waker); + + usb_free_urb(urb); + return 0; +} + +static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct urb *urb; + + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + urb = alloc_ctrl_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.cmd_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_ACLDATA_PKT: + urb = alloc_bulk_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.acl_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_SCODATA_PKT: + if (hci_conn_num(hdev, SCO_LINK) < 1) + return -ENODEV; + + urb = alloc_isoc_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.sco_tx++; + return submit_tx_urb(hdev, urb); + } + + return -EILSEQ; +} + static void btusb_notify(struct hci_dev *hdev, unsigned int evt) { struct btusb_data *data = hci_get_drvdata(hdev); -- cgit v1.2.3-70-g09d2 From 89e7533d0a96860f8aa24d05c9e35b18fdc28a61 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 16 Sep 2014 04:44:50 +0200 Subject: Bluetooth: btusb: Fix old coding style issues The btusb driver has been around for a while now and it is time to bring its coding style in sync with what has been done for the Bluetooth subsystem and other drivers. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 114 +++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c89b330cfa9..cf07fef65fd 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -302,8 +302,8 @@ static void btusb_intr_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -312,8 +312,8 @@ static void btusb_intr_complete(struct urb *urb) hdev->stat.byte_rx += urb->actual_length; if (hci_recv_fragment(hdev, HCI_EVENT_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted event packet", hdev->name); hdev->stat.err_rx++; } @@ -334,7 +334,7 @@ static void btusb_intr_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -367,8 +367,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, buf, size, - btusb_intr_complete, hdev, - data->intr_ep->bInterval); + btusb_intr_complete, hdev, data->intr_ep->bInterval); urb->transfer_flags |= URB_FREE_BUFFER; @@ -378,7 +377,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -393,8 +392,8 @@ static void btusb_bulk_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -403,8 +402,8 @@ static void btusb_bulk_complete(struct urb *urb) hdev->stat.byte_rx += urb->actual_length; if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted ACL packet", hdev->name); hdev->stat.err_rx++; } @@ -425,7 +424,7 @@ static void btusb_bulk_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -455,8 +454,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress); - usb_fill_bulk_urb(urb, data->udev, pipe, - buf, size, btusb_bulk_complete, hdev); + usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, + btusb_bulk_complete, hdev); urb->transfer_flags |= URB_FREE_BUFFER; @@ -467,7 +466,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -482,8 +481,8 @@ static void btusb_isoc_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int i, err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -499,8 +498,8 @@ static void btusb_isoc_complete(struct urb *urb) hdev->stat.byte_rx += length; if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, - urb->transfer_buffer + offset, - length) < 0) { + urb->transfer_buffer + offset, + length) < 0) { BT_ERR("%s corrupted SCO packet", hdev->name); hdev->stat.err_rx++; } @@ -521,7 +520,7 @@ static void btusb_isoc_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -576,12 +575,12 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete, - hdev, data->isoc_rx_ep->bInterval); + hdev, data->isoc_rx_ep->bInterval); - urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; + urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; __fill_isoc_descriptor(urb, size, - le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); + le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); usb_anchor_urb(urb, &data->isoc_anchor); @@ -589,7 +588,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -601,11 +600,11 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) static void btusb_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_dev *hdev = (struct hci_dev *)skb->dev; struct btusb_data *data = hci_get_drvdata(hdev); - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done; @@ -628,10 +627,10 @@ done: static void btusb_isoc_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_dev *hdev = (struct hci_dev *)skb->dev; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done; @@ -763,10 +762,10 @@ static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb) pipe = usb_sndctrlpipe(data->udev, 0x00); - usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, + usb_fill_control_urb(urb, data->udev, pipe, (void *)dr, skb->data, skb->len, btusb_tx_complete, skb); - skb->dev = (void *) hdev; + skb->dev = (void *)hdev; return urb; } @@ -789,7 +788,7 @@ static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb) usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len, btusb_tx_complete, skb); - skb->dev = (void *) hdev; + skb->dev = (void *)hdev; return urb; } @@ -818,7 +817,7 @@ static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb) __fill_isoc_descriptor(urb, skb->len, le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); - skb->dev = (void *) hdev; + skb->dev = (void *)hdev; return urb; } @@ -834,7 +833,7 @@ static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); kfree(urb->setup_packet); usb_unanchor_urb(urb); } else { @@ -984,6 +983,7 @@ static void btusb_work(struct work_struct *work) if (hdev->voice_setting & 0x0020) { static const int alts[3] = { 2, 4, 5 }; + new_alts = alts[data->sco_num - 1]; } else { new_alts = data->sco_num; @@ -1056,7 +1056,7 @@ static int btusb_setup_csr(struct hci_dev *hdev) return -PTR_ERR(skb); } - rp = (struct hci_rp_read_local_version *) skb->data; + rp = (struct hci_rp_read_local_version *)skb->data; if (!rp->status) { if (le16_to_cpu(rp->manufacturer) != 10) { @@ -1094,7 +1094,7 @@ struct intel_version { } __packed; static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, - struct intel_version *ver) + struct intel_version *ver) { const struct firmware *fw; char fwname[64]; @@ -1270,7 +1270,7 @@ static int btusb_check_bdaddr_intel(struct hci_dev *hdev) return -EIO; } - rp = (struct hci_rp_read_bd_addr *) skb->data; + rp = (struct hci_rp_read_bd_addr *)skb->data; if (rp->status) { BT_ERR("%s Intel device address result failed (%02x)", hdev->name, rp->status); @@ -1400,6 +1400,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) if (skb->data[0]) { u8 evt_status = skb->data[0]; + BT_ERR("%s enable Intel manufacturer mode event failed (%02x)", hdev->name, evt_status); kfree_skb(skb); @@ -1509,7 +1510,7 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: changing Intel device address failed (%ld)", - hdev->name, ret); + hdev->name, ret); return ret; } kfree_skb(skb); @@ -1584,19 +1585,19 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - ver = (struct hci_rp_read_local_version *) skb->data; + ver = (struct hci_rp_read_local_version *)skb->data; BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); @@ -1607,7 +1608,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto reset_fw; } kfree_skb(skb); @@ -1619,13 +1620,13 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) fw_size = fw->size; while (fw_size >= sizeof(*cmd)) { - cmd = (struct hci_command_hdr *) fw_ptr; + cmd = (struct hci_command_hdr *)fw_ptr; fw_ptr += sizeof(*cmd); fw_size -= sizeof(*cmd); if (fw_size < cmd->plen) { BT_ERR("%s: BCM: patch %s is corrupted", - hdev->name, fw_name); + hdev->name, fw_name); ret = -EINVAL; goto reset_fw; } @@ -1641,7 +1642,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: patch command %04x failed (%ld)", - hdev->name, opcode, ret); + hdev->name, opcode, ret); goto reset_fw; } kfree_skb(skb); @@ -1666,19 +1667,19 @@ reset_fw: if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - ver = (struct hci_rp_read_local_version *) skb->data; + ver = (struct hci_rp_read_local_version *)skb->data; BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); @@ -1690,19 +1691,19 @@ reset_fw: if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*bda)) { BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - bda = (struct hci_rp_read_bd_addr *) skb->data; + bda = (struct hci_rp_read_bd_addr *)skb->data; if (bda->status) { BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", hdev->name, bda->status); @@ -1737,7 +1738,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Change address command failed (%ld)", - hdev->name, ret); + hdev->name, ret); return ret; } kfree_skb(skb); @@ -1746,7 +1747,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) } static int btusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep_desc; struct btusb_data *data; @@ -1761,6 +1762,7 @@ static int btusb_probe(struct usb_interface *intf, if (!id->driver_info) { const struct usb_device_id *match; + match = usb_match_id(intf, blacklist_table); if (match) id = match; @@ -1911,7 +1913,7 @@ static int btusb_probe(struct usb_interface *intf, if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, - data->isoc, data); + data->isoc, data); if (err < 0) { hci_free_dev(hdev); return err; -- cgit v1.2.3-70-g09d2 From 1ffa4ad042c3151b57ba3f316d5582166f964537 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 16 Sep 2014 05:33:33 +0200 Subject: Bluetooth: btusb: Split fragement receiption into separate functions The actual packet reassembly should be done inside the driver. To allow this to happen cleanly in future patches, split the fragment reception into its own functions. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cf07fef65fd..df585ab064f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -296,6 +296,21 @@ struct btusb_data { int suspend_count; }; +static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) +{ + return hci_recv_fragment(data->hdev, HCI_EVENT_PKT, buffer, count); +} + +static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count) +{ + return hci_recv_fragment(data->hdev, HCI_ACLDATA_PKT, buffer, count); +} + +static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) +{ + return hci_recv_fragment(data->hdev, HCI_SCODATA_PKT, buffer, count); +} + static void btusb_intr_complete(struct urb *urb) { struct hci_dev *hdev = urb->context; @@ -311,9 +326,8 @@ static void btusb_intr_complete(struct urb *urb) if (urb->status == 0) { hdev->stat.byte_rx += urb->actual_length; - if (hci_recv_fragment(hdev, HCI_EVENT_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + if (btusb_recv_intr(data, urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted event packet", hdev->name); hdev->stat.err_rx++; } @@ -401,9 +415,8 @@ static void btusb_bulk_complete(struct urb *urb) if (urb->status == 0) { hdev->stat.byte_rx += urb->actual_length; - if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + if (btusb_recv_bulk(data, urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted ACL packet", hdev->name); hdev->stat.err_rx++; } @@ -497,9 +510,8 @@ static void btusb_isoc_complete(struct urb *urb) hdev->stat.byte_rx += length; - if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, - urb->transfer_buffer + offset, - length) < 0) { + if (btusb_recv_isoc(data, urb->transfer_buffer + offset, + length) < 0) { BT_ERR("%s corrupted SCO packet", hdev->name); hdev->stat.err_rx++; } -- cgit v1.2.3-70-g09d2 From 803b58367ffb7ae89397637122f9a71b2ee40687 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 16 Sep 2014 08:00:29 +0200 Subject: Bluetooth: btusb: Implement driver internal packet reassembly When receiving USB interrupt, bulk or isochronous packet, they normally come in fragments. So far the driver just handed each fragment off to the hci_recv_fragment function of the Bluetooth core. That function is however so specific that is does not belong in the core. This patch implements the same reassembly logic in the driver. In addition this fixes a long standing bug where multiple complete packets are received within a single USB packet. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 197 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index df585ab064f..a423b84a0ed 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -275,13 +275,19 @@ struct btusb_data { struct work_struct work; struct work_struct waker; + struct usb_anchor deferred; struct usb_anchor tx_anchor; + int tx_in_flight; + spinlock_t txlock; + struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; - struct usb_anchor deferred; - int tx_in_flight; - spinlock_t txlock; + spinlock_t rxlock; + + struct sk_buff *evt_skb; + struct sk_buff *acl_skb; + struct sk_buff *sco_skb; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; @@ -296,19 +302,189 @@ struct btusb_data { int suspend_count; }; +static inline void btusb_free_frags(struct btusb_data *data) +{ + unsigned long flags; + + spin_lock_irqsave(&data->rxlock, flags); + + kfree_skb(data->evt_skb); + data->evt_skb = NULL; + + kfree_skb(data->acl_skb); + data->acl_skb = NULL; + + kfree_skb(data->sco_skb); + data->sco_skb = NULL; + + spin_unlock_irqrestore(&data->rxlock, flags); +} + static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) { - return hci_recv_fragment(data->hdev, HCI_EVENT_PKT, buffer, count); + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->evt_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_EVENT_HDR_SIZE) { + /* Complete event header */ + bt_cb(skb)->expect = hci_event_hdr(skb)->plen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->evt_skb = skb; + spin_unlock(&data->rxlock); + + return err; } static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count) { - return hci_recv_fragment(data->hdev, HCI_ACLDATA_PKT, buffer, count); + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->acl_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; + bt_cb(skb)->expect = HCI_ACL_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_ACL_HDR_SIZE) { + __le16 dlen = hci_acl_hdr(skb)->dlen; + + /* Complete ACL header */ + bt_cb(skb)->expect = __le16_to_cpu(dlen); + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->acl_skb = skb; + spin_unlock(&data->rxlock); + + return err; } static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) { - return hci_recv_fragment(data->hdev, HCI_SCODATA_PKT, buffer, count); + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->sco_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; + bt_cb(skb)->expect = HCI_SCO_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_SCO_HDR_SIZE) { + /* Complete SCO header */ + bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->sco_skb = skb; + spin_unlock(&data->rxlock); + + return err; } static void btusb_intr_complete(struct urb *urb) @@ -726,6 +902,8 @@ static int btusb_close(struct hci_dev *hdev) clear_bit(BTUSB_INTR_RUNNING, &data->flags); btusb_stop_traffic(data); + btusb_free_frags(data); + err = usb_autopm_get_interface(data->intf); if (err < 0) goto failed; @@ -745,6 +923,7 @@ static int btusb_flush(struct hci_dev *hdev) BT_DBG("%s", hdev->name); usb_kill_anchored_urbs(&data->tx_anchor); + btusb_free_frags(data); return 0; } @@ -1827,13 +2006,14 @@ static int btusb_probe(struct usb_interface *intf, INIT_WORK(&data->work, btusb_work); INIT_WORK(&data->waker, btusb_waker); + init_usb_anchor(&data->deferred); + init_usb_anchor(&data->tx_anchor); spin_lock_init(&data->txlock); - init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); - init_usb_anchor(&data->deferred); + spin_lock_init(&data->rxlock); hdev = hci_alloc_dev(); if (!hdev) @@ -1966,6 +2146,7 @@ static void btusb_disconnect(struct usb_interface *intf) else if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); + btusb_free_frags(data); hci_free_dev(hdev); } -- cgit v1.2.3-70-g09d2 From 529160dc73a1cb4bb377887f5453d33b6d84d18f Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 24 Sep 2014 12:21:30 +0200 Subject: mrf24j40: fix Missing a blank line after declarations Signed-off-by: Varka Bhadram Acked-by: Alan Ott Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 9e6a124b13f..466da572e3f 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -412,6 +412,7 @@ static void mrf24j40_stop(struct ieee802154_dev *dev) struct mrf24j40 *devrec = dev->priv; u8 val; int ret; + dev_dbg(printdev(devrec), "stop\n"); ret = read_short_reg(devrec, REG_INTCON, &val); @@ -465,6 +466,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_SADDR_CHANGED) { /* Short Addr */ u8 addrh, addrl; + addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff; addrl = le16_to_cpu(filt->short_addr) & 0xff; @@ -493,6 +495,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_PANID_CHANGED) { /* PAN ID */ u8 panidl, panidh; + panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff; panidl = le16_to_cpu(filt->pan_id) & 0xff; write_short_reg(devrec, REG_PANIDH, panidh); -- cgit v1.2.3-70-g09d2 From 3d920f06e2f2f8f601084718da6c55f8885d7a7f Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 24 Sep 2014 12:21:31 +0200 Subject: mrf24j40: remove unnecessary return statement Remove the return statement in the void function. Signed-off-by: Varka Bhadram Acked-by: Alan Ott Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 466da572e3f..2c617e368dc 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -420,8 +420,6 @@ static void mrf24j40_stop(struct ieee802154_dev *dev) return; val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */ write_short_reg(devrec, REG_INTCON, val); - - return; } static int mrf24j40_set_channel(struct ieee802154_dev *dev, -- cgit v1.2.3-70-g09d2 From ca079ad6af0d9948101992d03e7145ab8b426f66 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 24 Sep 2014 12:21:32 +0200 Subject: mrf24j40: use pr_* / dev_* instead of printk() Replace printk() with dev_*() pr_*(). Signed-off-by: Varka Bhadram Acked-by: Alan Ott Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/mrf24j40.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 2c617e368dc..07e0b887c35 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -323,8 +323,8 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, #ifdef DEBUG print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ", DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); - printk(KERN_DEBUG "mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", - lqi_rssi[0], lqi_rssi[1]); + pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", + lqi_rssi[0], lqi_rssi[1]); #endif out: @@ -385,7 +385,7 @@ err: static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level) { /* TODO: */ - printk(KERN_WARNING "mrf24j40: ed not implemented\n"); + pr_warn("mrf24j40: ed not implemented\n"); *level = 0; return 0; } @@ -483,10 +483,10 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, write_short_reg(devrec, REG_EADR0 + i, addr[i]); #ifdef DEBUG - printk(KERN_DEBUG "Set long addr to: "); + pr_debug("Set long addr to: "); for (i = 0; i < 8; i++) - printk("%02hhx ", addr[7 - i]); - printk(KERN_DEBUG "\n"); + pr_debug("%02hhx ", addr[7 - i]); + pr_debug("\n"); #endif } @@ -702,7 +702,7 @@ static int mrf24j40_probe(struct spi_device *spi) int ret = -ENOMEM; struct mrf24j40 *devrec; - printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq); + dev_info(&spi->dev, "probe(). IRQ: %d\n", spi->irq); devrec = devm_kzalloc(&spi->dev, sizeof(struct mrf24j40), GFP_KERNEL); if (!devrec) -- cgit v1.2.3-70-g09d2