Message ID | 20240704060116.16600-9-chris.lu@mediatek.com |
---|---|
State | Superseded |
Headers | show |
Series | Bluetooth: btmtk: MediaTek ISO data transmission support | expand |
Hi Chris,
kernel test robot noticed the following build errors:
[auto build test ERROR on bluetooth-next/master]
[also build test ERROR on next-20240703]
[cannot apply to bluetooth/master linus/master v6.10-rc6]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chris-Lu/Bluetooth-btusb-mediatek-remove-the-unnecessary-goto-tag/20240705-043833
base: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
patch link: https://lore.kernel.org/r/20240704060116.16600-9-chris.lu%40mediatek.com
patch subject: [PATCH v7 8/8] Bluetooth: btusb: mediatek: add ISO data transmission functions
config: i386-buildonly-randconfig-001-20240705 (https://download.01.org/0day-ci/archive/20240705/202407051652.C743BIjp-lkp@intel.com/config)
compiler: gcc-13 (Ubuntu 13.2.0-4ubuntu3) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240705/202407051652.C743BIjp-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407051652.C743BIjp-lkp@intel.com/
All errors (new ones prefixed by >>):
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_recv_acl':
btmtk.c:(.text+0x749): undefined reference to `usb_disable_autosuspend'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_submit_wmt_recv_urb':
btmtk.c:(.text+0x789): undefined reference to `usb_alloc_urb'
ld: btmtk.c:(.text+0x81d): undefined reference to `usb_anchor_urb'
ld: btmtk.c:(.text+0x829): undefined reference to `usb_submit_urb'
ld: btmtk.c:(.text+0x836): undefined reference to `usb_free_urb'
ld: btmtk.c:(.text+0x880): undefined reference to `usb_unanchor_urb'
ld: btmtk.c:(.text+0x889): undefined reference to `usb_free_urb'
ld: btmtk.c:(.text+0x89e): undefined reference to `usb_free_urb'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_submit_intr_urb':
btmtk.c:(.text+0x8db): undefined reference to `usb_alloc_urb'
ld: btmtk.c:(.text+0x991): undefined reference to `usb_anchor_urb'
ld: btmtk.c:(.text+0x99a): undefined reference to `usb_submit_urb'
ld: btmtk.c:(.text+0x9a7): undefined reference to `usb_free_urb'
ld: btmtk.c:(.text+0xa18): undefined reference to `usb_unanchor_urb'
ld: btmtk.c:(.text+0xa28): undefined reference to `usb_free_urb'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_suspend':
btmtk.c:(.text+0xa92): undefined reference to `usb_kill_anchored_urbs'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_hci_wmt_sync':
btmtk.c:(.text+0xb15): undefined reference to `usb_autopm_get_interface'
ld: btmtk.c:(.text+0xb51): undefined reference to `usb_autopm_put_interface'
ld: btmtk.c:(.text+0xc0f): undefined reference to `usb_autopm_put_interface'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_isointf_init.constprop.0':
btmtk.c:(.text+0xefc): undefined reference to `usb_set_interface'
>> ld: btmtk.c:(.text+0x1063): undefined reference to `usb_kill_anchored_urbs'
ld: drivers/bluetooth/btmtk.o: in function `alloc_mtk_intr_urb':
btmtk.c:(.text+0x113c): undefined reference to `usb_alloc_urb'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_wmt_recv':
btmtk.c:(.text+0x12bb): undefined reference to `usb_anchor_urb'
ld: btmtk.c:(.text+0x12c7): undefined reference to `usb_submit_urb'
ld: btmtk.c:(.text+0x13e6): undefined reference to `usb_unanchor_urb'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_reg_read':
btmtk.c:(.text+0x14cb): undefined reference to `usb_control_msg'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_uhw_reg_write':
btmtk.c:(.text+0x1559): undefined reference to `usb_control_msg'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_usb_uhw_reg_read':
btmtk.c:(.text+0x1609): undefined reference to `usb_control_msg'
ld: drivers/bluetooth/btmtk.o: in function `btmtk_intr_complete':
btmtk.c:(.text+0x170f): undefined reference to `usb_anchor_urb'
ld: btmtk.c:(.text+0x171b): undefined reference to `usb_submit_urb'
ld: btmtk.c:(.text+0x1779): undefined reference to `usb_unanchor_urb'
On Tue, Jul 16, 2024 at 07:59:53AM +0000, Chris Lu (陸稚泓) wrote: > Hi Nicolas, > > Thanks for reporting the crash issue, I've sent another patc to avoid > this crash issue happened. kill anchor function wasn't protect well if > MediaTek Bluetooth failed to setup. Add a flag check when running into > btmtk_usb_suspend function. Hi Chris, thanks for the quick follow up! I see the patch at https://lore.kernel.org/all/20240716074947.23073-1-chris.lu@mediatek.com/ I'll try it and reply there with my results. Thanks, Nícolas > > Thanks a lot, > Chris > > On Mon, 2024-07-15 at 18:36 -0400, Nícolas F. R. A. Prado wrote: > > On Thu, Jul 04, 2024 at 02:01:16PM +0800, Chris Lu wrote: > > > This patch implements functions for ISO data send and receive in > > > btusb > > > driver for MediaTek's controller. > > > > > > MediaTek defines a specific interrupt endpoint for ISO data > > > transmissin > > > because the characteristics of interrupt endpoint are similar to > > > the > > > application of ISO data which can support guaranteed transmissin > > > bandwidth, enough maximum data length and error checking mechanism. > > > > > > Driver sets up ISO interface and endpoints in btusb_mtk_setup and > > > clears > > > the setup in btusb_mtk_shutdown. These flow can't move to btmtk.c > > > due to > > > btusb_driver is only defined in btusb.c when claiming/relaesing > > > interface. > > > ISO packet anchor stops when driver suspending and resubmit > > > interrupt urb > > > for ISO data when driver resuming. > > > > > > Signed-off-by: Chris Lu <chris.lu@mediatek.com> > > > --- > > > > Hi, > > > > KernelCI has identified a boot regression originating from this > > patch. It > > affects the mt8195-cherry-tomato-r2 platform. > > > > Through additional runs I've determined that it only happens when the > > bluetooth > > firmware (BT_RAM_CODE_MT7961_1_2_hdr.bin) isn't present. I realize > > the firmware > > should be present to make proper use of the bluetooth driver, and > > I'll add it to > > our testing images. Still, a panic shouldn't happen when it's > > missing, hence > > this report. > > > > Reverting this patch fixes the issue. > > > > This is the traceback: > > > > [ 6.734214] BUG: spinlock bad magic on CPU#3, kworker/3:1/104 > > [ 6.740002] lock: 0xffff2c7b8655f660, .magic: 00000000, .owner: > > <none>/-1, .owner_cpu: 0 > > [ 6.748207] CPU: 3 UID: 0 PID: 104 Comm: kworker/3:1 Not tainted > > 6.10.0-next-20240715 #1 35893202ca8f99b37129997821441a29d2b23f0a > > [ 6.759874] Hardware name: Acer Tomato (rev2) board (DT) > > [ 6.765195] Workqueue: pm pm_runtime_work > > [ 6.769235] Call trace: > > [ 6.771689] dump_backtrace+0x9c/0x100 > > [ 6.775456] show_stack+0x20/0x38 > > [ 6.778786] dump_stack_lvl+0x80/0xf8 > > [ 6.782463] dump_stack+0x18/0x28 > > [ 6.785791] spin_bug+0x90/0xd8 > > [ 6.788950] do_raw_spin_lock+0xf4/0x128 > > [ 6.792890] _raw_spin_lock_irq+0x30/0x70 > > [ 6.796915] usb_kill_anchored_urbs+0x48/0x1e0 > > [ 6.801378] btmtk_usb_suspend+0x20/0x38 [btmtk > > 5f200a97badbdfda4266773fee49acfc8e0224d5] > > [ 6.809578] btusb_suspend+0xd0/0x210 [btusb > > 0bfbf19a87ff406c83b87268b87ce1e80e9a829b] > > [ 6.817527] usb_suspend_both+0x90/0x288 > > [ 6.821469] usb_runtime_suspend+0x3c/0xa8 > > [ 6.825585] __rpm_callback+0x50/0x1f0 > > [ 6.829351] rpm_callback+0x70/0x88 > > [ 6.832856] rpm_suspend+0xe4/0x5a0 > > [ 6.836361] pm_runtime_work+0xd4/0xe0 > > [ 6.840126] process_one_work+0x18c/0x440 > > [ 6.844156] worker_thread+0x314/0x428 > > [ 6.847923] kthread+0x128/0x138 > > [ 6.851167] ret_from_fork+0x10/0x20 > > [ 6.854769] Unable to handle kernel paging request at virtual > > address ffffffffffffffd8 > > [ 6.862694] Mem abort info: > > [ 6.865494] ESR = 0x0000000096000006 > > [ 6.869249] EC = 0x25: DABT (current EL), IL = 32 bits > > [ 6.874571] SET = 0, FnV = 0 > > [ 6.877632] EA = 0, S1PTW = 0 > > [ 6.880780] FSC = 0x06: level 2 translation fault > > [ 6.885665] Data abort info: > > [ 6.888553] ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000 > > [ 6.894044] CM = 0, WnR = 0, TnD = 0, TagAccess = 0 > > [ 6.899103] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0 > > [ 6.904423] swapper pgtable: 4k pages, 48-bit VAs, > > pgdp=0000000042533000 > > [ 6.911134] [ffffffffffffffd8] pgd=0000000000000000, > > p4d=0000000042e94003, pud=0000000042e95003, pmd=0000000000000000 > > lav[ 6.921781] Internal error: Oops: 0000000096000006 [#1] PREEMPT > > SMP > > [ 6.921794] Modules linked in: mt7921e mt7921_common mt792x_lib > > mt76_connac_lib mt76 mtk_vcodec_dec_hw mac80211 cros_ec_lid_angle > > cros_ec_sensors cros_ec_sensors_core industrialio_triggered_buffer > > cfg80211 kfifo_buf mtk_vcodec_dec mtk_jpeg v4l2_vp9 cros_ec_rpmsg > > mtk_vcodec_enc v4l2_h264 mtk_jpeg_enc_hw btusb mtk_vcodec_dbgfs > > mtk_jpeg_dec_hw mtk_dp mtk_vcodec_common btintel btbcm uvcvideo btmtk > > mtk_mdp3 videobuf2_vmalloc v4l2_mem2mem btrtl uvc joydev > > videobuf2_v4l2 videobuf2_dma_contig bluetooth elan_i2c > > videobuf2_memops ecdh_generic ecc videobuf2_common cros_ec_sensorhub > > cros_kbd_led_backlight mtk_scp snd_sof_mt8195 pcie_mediatek_gen3 > > mtk_rpmsg mtk_svs mtk_adsp_common snd_sof_xtensa_dsp rpmsg_core > > lvts_thermal snd_sof_of mtk_scp_ipi snd_soc_mt8195_afe snd_sof > > snd_sof_utils mtk_wdt mt6577_auxadc mt8195_mt6359 > > [ 6.922087] CPU: 3 UID: 0 PID: 104 Comm: kworker/3:1 Not tainted > > 6.10.0-next-20240715 #1 35893202ca8f99b37129997821441a29d2b23f0a > > [ 6.922106] Hardware name: Acer Tomato (rev2) board (DT) > > [ 6.922114] Workqueue: pm pm_runtime_work > > [ 6.922132] pstate: 804000c9 (Nzcv daIF +PAN -UAO -TCO -DIT -SSBS > > BTYPE=--) > > [ 6.922147] pc : usb_kill_anchored_urbs+0x6c/0x1e0 > > [ 6.922164] lr : usb_kill_anchored_urbs+0x48/0x1e0 > > [ 6.922181] sp : ffff800080903b60 > > [ 6.922187] x29: ffff800080903b60 x28: ffff2c7b85c32b80 x27: > > ffff2c7bbb370930 > > [ 6.922211] x26: 00000000000f4240 x25: 00000000ffffffff x24: > > ffffd49ece2dcb48 > > [ 6.922233] x23: 0000000000000001 x22: ffff2c7b8655f660 x21: > > ffff2c7b8655f628 > > [ 6.922255] x20: ffffffffffffffd8 x19: 0000000000000000 x18: > > 0000000000000006 > > [ 6.922276] x17: 6531656337386238 x16: 3632373862333863 x15: > > ffff800080903480 > > [ 6.922297] x14: 0000000000000000 x13: 303278302f303178 x12: > > ffffd49ecf090e30 > > [ 6.922318] x11: 0000000000000001 x10: 0000000000000001 x9 : > > ffffd49ecd2c5bb4 > > [ 6.922339] x8 : c0000000ffffdfff x7 : ffffd49ecefe0db8 x6 : > > 00000000000affa8 > > [ 6.922360] x5 : ffff2c7bbb35dd48 x4 : 0000000000000000 x3 : > > 0000000000000000 > > [ 6.922379] x2 : 0000000000000000 x1 : 0000000000000003 x0 : > > ffffffffffffffd8 > > [ 6.922400] Call trace: > > [ 6.922405] usb_kill_anchored_urbs+0x6c/0x1e0 > > [ 6.922422] btmtk_usb_suspend+0x20/0x38 [btmtk > > 5f200a97badbdfda4266773fee49acfc8e0224d5] > > [ 6.922444] btusb_suspend+0xd0/0x210 [btusb > > 0bfbf19a87ff406c83b87268b87ce1e80e9a829b] > > [ 6.922469] usb_suspend_both+0x90/0x288 > > [ 6.922487] usb_runtime_suspend+0x3c/0xa8 > > [ 6.922507] __rpm_callback+0x50/0x1f0 > > [ 6.922523] rpm_callback+0x70/0x88 > > [ 6.922538] rpm_suspend+0xe4/0x5a0 > > [ 6.922553] pm_runtime_work+0xd4/0xe0 > > [ 6.922569] process_one_work+0x18c/0x440 > > [ 6.922588] worker_thread+0x314/0x428 > > [ 6.922606] kthread+0x128/0x138 > > [ 6.922621] ret_from_fork+0x10/0x20 > > [ 6.922644] Code: f100a274 54000520 d503201f d100a260 (b8370000) > > [ 6.922654] ---[ end trace 0000000000000000 ]--- > > a-148[ 7.203910] Kernel panic - not syncing: Oops: Fatal exception > > [ 7.209649] SMP: stopping secondary CPUs > > [ 7.213713] Kernel Offset: 0x549e4c400000 from 0xffff800080000000 > > [ 7.219796] PHYS_OFFSET: 0xfff0d38580000000 > > [ 7.223969] CPU features: 0x04,0000000b,80140528,4200720b > > [ 7.229360] Memory Limit: none > > > > Full kernel log: > > https://urldefense.com/v3/__http://0x0.st/X9rx.txt__;!!CTRNKA9wMg0ARbw!g_UleOH6C5AdZoKEVoko3ewb6zKCcWfDGfw3u6LV_x3JCST7WnvMrAzM7wP0A4WkiW4v0EM53wjf8el1gXWfqA$ > > > > Config: > > https://urldefense.com/v3/__http://0x0.st/X9r2.txt__;!!CTRNKA9wMg0ARbw!g_UleOH6C5AdZoKEVoko3ewb6zKCcWfDGfw3u6LV_x3JCST7WnvMrAzM7wP0A4WkiW4v0EM53wjf8enPGJN1sg$ > > > > > > #regzbot introduced: ee6bd4b95c66 > > #regzbot title: usb_kill_anchored_urbs panic during boot on mt8195- > > cherry-tomato-r2 > > > > Thanks, > > Nícolas
On Tue, Jul 16, 2024 at 08:20:46AM -0400, Nícolas F. R. A. Prado wrote: > On Tue, Jul 16, 2024 at 07:59:53AM +0000, Chris Lu (陸稚泓) wrote: > > Hi Nicolas, > > > > Thanks for reporting the crash issue, I've sent another patc to avoid > > this crash issue happened. kill anchor function wasn't protect well if > > MediaTek Bluetooth failed to setup. Add a flag check when running into > > btmtk_usb_suspend function. > > Hi Chris, > > thanks for the quick follow up! I see the patch at > https://lore.kernel.org/all/20240716074947.23073-1-chris.lu@mediatek.com/ That patch was merged without the Closes tag, so manually closing the regression: #regzbot fix: 'Bluetooth: btmtk: Fix kernel crash when entering btmtk_usb_suspend' Thanks, Nícolas
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index fe3b892f6c6e..b7c348687a77 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -22,6 +22,9 @@ #define MTK_SEC_MAP_COMMON_SIZE 12 #define MTK_SEC_MAP_NEED_SEND_SIZE 52 +/* It is for mt79xx iso data transmission setting */ +#define MTK_ISO_THRESHOLD 264 + struct btmtk_patch_header { u8 datetime[16]; u8 platform[4]; @@ -963,6 +966,308 @@ int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(btmtk_usb_recv_acl); +static int btmtk_isopkt_pad(struct hci_dev *hdev, struct sk_buff *skb) +{ + if (skb->len > MTK_ISO_THRESHOLD) + return -EINVAL; + + if (skb_pad(skb, MTK_ISO_THRESHOLD - skb->len)) + return -ENOMEM; + + __skb_put(skb, MTK_ISO_THRESHOLD - skb->len); + + return 0; +} + +static int __set_mtk_intr_interface(struct hci_dev *hdev) +{ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + struct usb_interface *intf = btmtk_data->isopkt_intf; + int i, err; + + if (!btmtk_data->isopkt_intf) + return -ENODEV; + + err = usb_set_interface(btmtk_data->udev, MTK_ISO_IFNUM, 1); + if (err < 0) { + bt_dev_err(hdev, "setting interface failed (%d)", -err); + return err; + } + + btmtk_data->isopkt_tx_ep = NULL; + btmtk_data->isopkt_rx_ep = NULL; + + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { + struct usb_endpoint_descriptor *ep_desc; + + ep_desc = &intf->cur_altsetting->endpoint[i].desc; + + if (!btmtk_data->isopkt_tx_ep && + usb_endpoint_is_int_out(ep_desc)) { + btmtk_data->isopkt_tx_ep = ep_desc; + continue; + } + + if (!btmtk_data->isopkt_rx_ep && + usb_endpoint_is_int_in(ep_desc)) { + btmtk_data->isopkt_rx_ep = ep_desc; + continue; + } + } + + if (!btmtk_data->isopkt_tx_ep || + !btmtk_data->isopkt_rx_ep) { + bt_dev_err(hdev, "invalid interrupt descriptors"); + return -ENODEV; + } + + return 0; +} + +struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb, + usb_complete_t tx_complete) +{ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + struct urb *urb; + unsigned int pipe; + + if (!btmtk_data->isopkt_tx_ep) + return ERR_PTR(-ENODEV); + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); + + if (btmtk_isopkt_pad(hdev, skb)) + return ERR_PTR(-EINVAL); + + pipe = usb_sndintpipe(btmtk_data->udev, + btmtk_data->isopkt_tx_ep->bEndpointAddress); + + usb_fill_int_urb(urb, btmtk_data->udev, pipe, + skb->data, skb->len, tx_complete, + skb, btmtk_data->isopkt_tx_ep->bInterval); + + skb->dev = (void *)hdev; + + return urb; +} +EXPORT_SYMBOL_GPL(alloc_mtk_intr_urb); + +static int btmtk_recv_isopkt(struct hci_dev *hdev, void *buffer, int count) +{ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + struct sk_buff *skb; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&btmtk_data->isorxlock, flags); + skb = btmtk_data->isopkt_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_ISO_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + hci_skb_pkt_type(skb) = HCI_ISODATA_PKT; + hci_skb_expect(skb) = HCI_ISO_HDR_SIZE; + } + + len = min_t(uint, hci_skb_expect(skb), count); + skb_put_data(skb, buffer, len); + + count -= len; + buffer += len; + hci_skb_expect(skb) -= len; + + if (skb->len == HCI_ISO_HDR_SIZE) { + __le16 dlen = ((struct hci_iso_hdr *)skb->data)->dlen; + + /* Complete ISO header */ + hci_skb_expect(skb) = __le16_to_cpu(dlen); + + if (skb_tailroom(skb) < hci_skb_expect(skb)) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (!hci_skb_expect(skb)) { + /* Complete frame */ + hci_recv_frame(hdev, skb); + skb = NULL; + } + } + + btmtk_data->isopkt_skb = skb; + spin_unlock_irqrestore(&btmtk_data->isorxlock, flags); + + return err; +} + +static void btmtk_intr_complete(struct urb *urb) +{ + struct hci_dev *hdev = urb->context; + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + int err; + + 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; + + if (hdev->suspended) + return; + + if (urb->status == 0) { + hdev->stat.byte_rx += urb->actual_length; + + if (btmtk_recv_isopkt(hdev, urb->transfer_buffer, + urb->actual_length) < 0) { + bt_dev_err(hdev, "corrupted iso packet"); + hdev->stat.err_rx++; + } + } else if (urb->status == -ENOENT) { + /* Avoid suspend failed when usb_kill_urb */ + return; + } + + usb_mark_last_busy(btmtk_data->udev); + usb_anchor_urb(urb, &btmtk_data->isopkt_anchor); + + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err < 0) { + /* -EPERM: urb is being killed; + * -ENODEV: device got disconnected + */ + if (err != -EPERM && err != -ENODEV) + bt_dev_err(hdev, "urb %p failed to resubmit (%d)", + urb, -err); + if (err != -EPERM) + hci_cmd_sync_cancel(hdev, -err); + usb_unanchor_urb(urb); + } +} + +static int btmtk_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) +{ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + unsigned char *buf; + unsigned int pipe; + struct urb *urb; + int err, size; + + BT_DBG("%s", hdev->name); + + if (!btmtk_data->isopkt_rx_ep) + return -ENODEV; + + urb = usb_alloc_urb(0, mem_flags); + if (!urb) + return -ENOMEM; + size = le16_to_cpu(btmtk_data->isopkt_rx_ep->wMaxPacketSize); + + buf = kmalloc(size, mem_flags); + if (!buf) { + usb_free_urb(urb); + return -ENOMEM; + } + + pipe = usb_rcvintpipe(btmtk_data->udev, + btmtk_data->isopkt_rx_ep->bEndpointAddress); + + usb_fill_int_urb(urb, btmtk_data->udev, pipe, buf, size, + btmtk_intr_complete, hdev, + btmtk_data->isopkt_rx_ep->bInterval); + + urb->transfer_flags |= URB_FREE_BUFFER; + + usb_mark_last_busy(btmtk_data->udev); + usb_anchor_urb(urb, &btmtk_data->isopkt_anchor); + + err = usb_submit_urb(urb, mem_flags); + if (err < 0) { + if (err != -EPERM && err != -ENODEV) + bt_dev_err(hdev, "urb %p submission failed (%d)", + urb, -err); + usb_unanchor_urb(urb); + } + + usb_free_urb(urb); + + return err; +} + +static int btmtk_usb_isointf_init(struct hci_dev *hdev) +{ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + u8 iso_param[2] = { 0x08, 0x01 }; + struct sk_buff *skb; + int err; + + init_usb_anchor(&btmtk_data->isopkt_anchor); + spin_lock_init(&btmtk_data->isorxlock); + + __set_mtk_intr_interface(hdev); + + err = btmtk_submit_intr_urb(hdev, GFP_KERNEL); + if (err < 0) { + usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor); + bt_dev_err(hdev, "ISO intf not support (%d)", err); + return err; + } + + skb = __hci_cmd_sync(hdev, 0xfd98, sizeof(iso_param), iso_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + bt_dev_err(hdev, "Failed to apply iso setting (%ld)", PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + + return 0; +} + +int btmtk_usb_resume(struct hci_dev *hdev) +{ + /* This function describes the specific additional steps taken by MediaTek + * when Bluetooth usb driver's resume function is called. + */ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + + /* Resubmit urb for iso data transmission */ + if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) { + if (btmtk_submit_intr_urb(hdev, GFP_NOIO) < 0) + clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags); + } + + return 0; +} +EXPORT_SYMBOL_GPL(btmtk_usb_resume); + +int btmtk_usb_suspend(struct hci_dev *hdev) +{ + /* This function describes the specific additional steps taken by MediaTek + * when Bluetooth usb driver's suspend function is called. + */ + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + + /* Stop urb anchor for iso data transmission */ + usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor); + + return 0; +} +EXPORT_SYMBOL_GPL(btmtk_usb_suspend); + int btmtk_usb_setup(struct hci_dev *hdev) { struct btmtk_data *btmtk_data = hci_get_priv(hdev); @@ -1064,6 +1369,12 @@ int btmtk_usb_setup(struct hci_dev *hdev) hci_set_msft_opcode(hdev, 0xFD30); hci_set_aosp_capable(hdev); + /* Set up ISO interface after protocol enabled */ + if (test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) { + if (!btmtk_usb_isointf_init(hdev)) + set_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags); + } + goto done; default: bt_dev_err(hdev, "Unsupported hardware variant (%08x)", diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index 47193b867b9f..453ed5131a37 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -40,6 +40,9 @@ #define MTK_BT_RESET_REG_CONNV3 0x70028610 #define MTK_BT_READ_DEV_ID 0x70010200 +/* MediaTek ISO Interface */ +#define MTK_ISO_IFNUM 2 + enum { BTMTK_WMT_PATCH_DWNLD = 0x1, BTMTK_WMT_TEST = 0x2, @@ -142,6 +145,8 @@ enum { BTMTK_TX_WAIT_VND_EVT, BTMTK_FIRMWARE_LOADED, BTMTK_HW_RESET_ACTIVE, + BTMTK_ISOPKT_OVER_INTR, + BTMTK_ISOPKT_RUNNING, }; typedef int (*btmtk_reset_sync_func_t)(struct hci_dev *, void *); @@ -164,6 +169,14 @@ struct btmtk_data { struct usb_interface *intf; struct usb_anchor *ctrl_anchor; struct sk_buff *evt_skb; + struct usb_endpoint_descriptor *isopkt_tx_ep; + struct usb_endpoint_descriptor *isopkt_rx_ep; + struct usb_interface *isopkt_intf; + struct usb_anchor isopkt_anchor; + struct sk_buff *isopkt_skb; + + /* spinlock for ISO data transmission */ + spinlock_t isorxlock; }; typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *, @@ -193,6 +206,13 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id); int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb); +struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb, + usb_complete_t tx_complete); + +int btmtk_usb_resume(struct hci_dev *hdev); + +int btmtk_usb_suspend(struct hci_dev *hdev); + int btmtk_usb_setup(struct hci_dev *hdev); int btmtk_usb_shutdown(struct hci_dev *hdev); @@ -246,6 +266,22 @@ static int btmtk_usb_recv_acl(struct hci_dev *hdev, struct sk_buff *skb) return -EOPNOTSUPP; } +static struct urb *alloc_mtk_intr_urb(struct hci_dev *hdev, struct sk_buff *skb, + usb_complete_t tx_complete) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static int btmtk_usb_resume(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +static int btmtk_usb_suspend(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + static int btmtk_usb_setup(struct hci_dev *hdev) { return -EOPNOTSUPP; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5de50c835964..1a4ab5619ab5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2641,6 +2641,40 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb) return hci_recv_frame(hdev, skb); } +static void btusb_mtk_claim_iso_intf(struct btusb_data *data) +{ + struct btmtk_data *btmtk_data = hci_get_priv(data->hdev); + int err; + + err = usb_driver_claim_interface(&btusb_driver, + btmtk_data->isopkt_intf, data); + if (err < 0) { + btmtk_data->isopkt_intf = NULL; + bt_dev_err(data->hdev, "Failed to claim iso interface"); + return; + } + + set_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags); +} + +static void btusb_mtk_release_iso_intf(struct btusb_data *data) +{ + struct btmtk_data *btmtk_data = hci_get_priv(data->hdev); + + if (btmtk_data->isopkt_intf) { + usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor); + clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags); + + dev_kfree_skb_irq(btmtk_data->isopkt_skb); + btmtk_data->isopkt_skb = NULL; + usb_set_intfdata(btmtk_data->isopkt_intf, NULL); + usb_driver_release_interface(&btusb_driver, + btmtk_data->isopkt_intf); + } + + clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags); +} + static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2657,6 +2691,9 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) if (err < 0) return err; + if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) + btusb_mtk_release_iso_intf(data); + btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); @@ -2668,6 +2705,23 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) return err; } +static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct urb *urb; + + BT_DBG("%s", hdev->name); + + if (hci_skb_pkt_type(skb) == HCI_ISODATA_PKT) { + urb = alloc_mtk_intr_urb(hdev, skb, btusb_tx_complete); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + return submit_or_queue_tx_urb(hdev, urb); + } else { + return btusb_send_frame(hdev, skb); + } +} + static int btusb_mtk_setup(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2682,11 +2736,22 @@ static int btusb_mtk_setup(struct hci_dev *hdev) btmtk_data->ctrl_anchor = &data->ctrl_anchor; btmtk_data->reset_sync = btusb_mtk_reset; + /* Claim ISO data interface and endpoint */ + btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM); + if (btmtk_data->isopkt_intf) + btusb_mtk_claim_iso_intf(data); + return btmtk_usb_setup(hdev); } static int btusb_mtk_shutdown(struct hci_dev *hdev) { + struct btusb_data *data = hci_get_drvdata(hdev); + struct btmtk_data *btmtk_data = hci_get_priv(hdev); + + if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) + btusb_mtk_release_iso_intf(data); + return btmtk_usb_shutdown(hdev); } @@ -3793,9 +3858,12 @@ static int btusb_probe(struct usb_interface *intf, hdev->manufacturer = 70; hdev->cmd_timeout = btmtk_reset_sync; hdev->set_bdaddr = btmtk_set_bdaddr; + hdev->send = btusb_send_frame_mtk; set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks); set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); data->recv_acl = btmtk_usb_recv_acl; + data->suspend = btmtk_usb_suspend; + data->resume = btmtk_usb_resume; } if (id->driver_info & BTUSB_SWAVE) {
This patch implements functions for ISO data send and receive in btusb driver for MediaTek's controller. MediaTek defines a specific interrupt endpoint for ISO data transmissin because the characteristics of interrupt endpoint are similar to the application of ISO data which can support guaranteed transmissin bandwidth, enough maximum data length and error checking mechanism. Driver sets up ISO interface and endpoints in btusb_mtk_setup and clears the setup in btusb_mtk_shutdown. These flow can't move to btmtk.c due to btusb_driver is only defined in btusb.c when claiming/relaesing interface. ISO packet anchor stops when driver suspending and resubmit interrupt urb for ISO data when driver resuming. Signed-off-by: Chris Lu <chris.lu@mediatek.com> --- drivers/bluetooth/btmtk.c | 311 ++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btmtk.h | 36 +++++ drivers/bluetooth/btusb.c | 68 +++++++++ 3 files changed, 415 insertions(+)