190aac0d8SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 290aac0d8SBjoern A. Zeeb /* Copyright(c) 2018-2019 Realtek Corporation 390aac0d8SBjoern A. Zeeb */ 490aac0d8SBjoern A. Zeeb 590aac0d8SBjoern A. Zeeb #include <linux/module.h> 690aac0d8SBjoern A. Zeeb #include <linux/usb.h> 790aac0d8SBjoern A. Zeeb #include <linux/mutex.h> 890aac0d8SBjoern A. Zeeb #include "main.h" 990aac0d8SBjoern A. Zeeb #include "debug.h" 1090aac0d8SBjoern A. Zeeb #include "reg.h" 1190aac0d8SBjoern A. Zeeb #include "tx.h" 1290aac0d8SBjoern A. Zeeb #include "rx.h" 1390aac0d8SBjoern A. Zeeb #include "fw.h" 1490aac0d8SBjoern A. Zeeb #include "ps.h" 1590aac0d8SBjoern A. Zeeb #include "usb.h" 1690aac0d8SBjoern A. Zeeb 1790aac0d8SBjoern A. Zeeb #define RTW_USB_MAX_RXQ_LEN 512 1890aac0d8SBjoern A. Zeeb 1990aac0d8SBjoern A. Zeeb struct rtw_usb_txcb { 2090aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 2190aac0d8SBjoern A. Zeeb struct sk_buff_head tx_ack_queue; 2290aac0d8SBjoern A. Zeeb }; 2390aac0d8SBjoern A. Zeeb 2490aac0d8SBjoern A. Zeeb static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, 2590aac0d8SBjoern A. Zeeb struct sk_buff *skb, int agg_num) 2690aac0d8SBjoern A. Zeeb { 2790aac0d8SBjoern A. Zeeb struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; 2890aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 2990aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info; 3090aac0d8SBjoern A. Zeeb 3190aac0d8SBjoern A. Zeeb le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM); 3290aac0d8SBjoern A. Zeeb pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET); 3390aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); 3490aac0d8SBjoern A. Zeeb } 3590aac0d8SBjoern A. Zeeb 36*11c53278SBjoern A. Zeeb static void rtw_usb_reg_sec(struct rtw_dev *rtwdev, u32 addr, __le32 *data) 37*11c53278SBjoern A. Zeeb { 38*11c53278SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 39*11c53278SBjoern A. Zeeb struct usb_device *udev = rtwusb->udev; 40*11c53278SBjoern A. Zeeb bool reg_on_section = false; 41*11c53278SBjoern A. Zeeb u16 t_reg = 0x4e0; 42*11c53278SBjoern A. Zeeb u8 t_len = 1; 43*11c53278SBjoern A. Zeeb int status; 44*11c53278SBjoern A. Zeeb 45*11c53278SBjoern A. Zeeb /* There are three sections: 46*11c53278SBjoern A. Zeeb * 1. on (0x00~0xFF; 0x1000~0x10FF): this section is always powered on 47*11c53278SBjoern A. Zeeb * 2. off (< 0xFE00, excluding "on" section): this section could be 48*11c53278SBjoern A. Zeeb * powered off 49*11c53278SBjoern A. Zeeb * 3. local (>= 0xFE00): usb specific registers section 50*11c53278SBjoern A. Zeeb */ 51*11c53278SBjoern A. Zeeb if (addr <= 0xff || (addr >= 0x1000 && addr <= 0x10ff)) 52*11c53278SBjoern A. Zeeb reg_on_section = true; 53*11c53278SBjoern A. Zeeb 54*11c53278SBjoern A. Zeeb if (!reg_on_section) 55*11c53278SBjoern A. Zeeb return; 56*11c53278SBjoern A. Zeeb 57*11c53278SBjoern A. Zeeb status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 58*11c53278SBjoern A. Zeeb RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, 59*11c53278SBjoern A. Zeeb t_reg, 0, data, t_len, 500); 60*11c53278SBjoern A. Zeeb 61*11c53278SBjoern A. Zeeb if (status != t_len && status != -ENODEV) 62*11c53278SBjoern A. Zeeb rtw_err(rtwdev, "%s: reg 0x%x, usb write %u fail, status: %d\n", 63*11c53278SBjoern A. Zeeb __func__, t_reg, t_len, status); 64*11c53278SBjoern A. Zeeb } 65*11c53278SBjoern A. Zeeb 6690aac0d8SBjoern A. Zeeb static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) 6790aac0d8SBjoern A. Zeeb { 6890aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 6990aac0d8SBjoern A. Zeeb struct usb_device *udev = rtwusb->udev; 7090aac0d8SBjoern A. Zeeb __le32 *data; 7190aac0d8SBjoern A. Zeeb unsigned long flags; 7290aac0d8SBjoern A. Zeeb int idx, ret; 7390aac0d8SBjoern A. Zeeb static int count; 7490aac0d8SBjoern A. Zeeb 7590aac0d8SBjoern A. Zeeb spin_lock_irqsave(&rtwusb->usb_lock, flags); 7690aac0d8SBjoern A. Zeeb 7790aac0d8SBjoern A. Zeeb idx = rtwusb->usb_data_index; 7890aac0d8SBjoern A. Zeeb rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 7990aac0d8SBjoern A. Zeeb 8090aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 8190aac0d8SBjoern A. Zeeb 8290aac0d8SBjoern A. Zeeb data = &rtwusb->usb_data[idx]; 8390aac0d8SBjoern A. Zeeb 8490aac0d8SBjoern A. Zeeb ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 8590aac0d8SBjoern A. Zeeb RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr, 8690aac0d8SBjoern A. Zeeb RTW_USB_VENQT_CMD_IDX, data, len, 1000); 8790aac0d8SBjoern A. Zeeb if (ret < 0 && ret != -ENODEV && count++ < 4) 8890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "read register 0x%x failed with %d\n", 8990aac0d8SBjoern A. Zeeb addr, ret); 9090aac0d8SBjoern A. Zeeb 91*11c53278SBjoern A. Zeeb if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || 92*11c53278SBjoern A. Zeeb rtwdev->chip->id == RTW_CHIP_TYPE_8822B || 93*11c53278SBjoern A. Zeeb rtwdev->chip->id == RTW_CHIP_TYPE_8821C) 94*11c53278SBjoern A. Zeeb rtw_usb_reg_sec(rtwdev, addr, data); 95*11c53278SBjoern A. Zeeb 9690aac0d8SBjoern A. Zeeb return le32_to_cpu(*data); 9790aac0d8SBjoern A. Zeeb } 9890aac0d8SBjoern A. Zeeb 9990aac0d8SBjoern A. Zeeb static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr) 10090aac0d8SBjoern A. Zeeb { 10190aac0d8SBjoern A. Zeeb return (u8)rtw_usb_read(rtwdev, addr, 1); 10290aac0d8SBjoern A. Zeeb } 10390aac0d8SBjoern A. Zeeb 10490aac0d8SBjoern A. Zeeb static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr) 10590aac0d8SBjoern A. Zeeb { 10690aac0d8SBjoern A. Zeeb return (u16)rtw_usb_read(rtwdev, addr, 2); 10790aac0d8SBjoern A. Zeeb } 10890aac0d8SBjoern A. Zeeb 10990aac0d8SBjoern A. Zeeb static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr) 11090aac0d8SBjoern A. Zeeb { 11190aac0d8SBjoern A. Zeeb return (u32)rtw_usb_read(rtwdev, addr, 4); 11290aac0d8SBjoern A. Zeeb } 11390aac0d8SBjoern A. Zeeb 11490aac0d8SBjoern A. Zeeb static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) 11590aac0d8SBjoern A. Zeeb { 11690aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv; 11790aac0d8SBjoern A. Zeeb struct usb_device *udev = rtwusb->udev; 11890aac0d8SBjoern A. Zeeb unsigned long flags; 11990aac0d8SBjoern A. Zeeb __le32 *data; 12090aac0d8SBjoern A. Zeeb int idx, ret; 12190aac0d8SBjoern A. Zeeb static int count; 12290aac0d8SBjoern A. Zeeb 12390aac0d8SBjoern A. Zeeb spin_lock_irqsave(&rtwusb->usb_lock, flags); 12490aac0d8SBjoern A. Zeeb 12590aac0d8SBjoern A. Zeeb idx = rtwusb->usb_data_index; 12690aac0d8SBjoern A. Zeeb rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); 12790aac0d8SBjoern A. Zeeb 12890aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&rtwusb->usb_lock, flags); 12990aac0d8SBjoern A. Zeeb 13090aac0d8SBjoern A. Zeeb data = &rtwusb->usb_data[idx]; 13190aac0d8SBjoern A. Zeeb 13290aac0d8SBjoern A. Zeeb *data = cpu_to_le32(val); 13390aac0d8SBjoern A. Zeeb 13490aac0d8SBjoern A. Zeeb ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 13590aac0d8SBjoern A. Zeeb RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, 13690aac0d8SBjoern A. Zeeb addr, 0, data, len, 30000); 13790aac0d8SBjoern A. Zeeb if (ret < 0 && ret != -ENODEV && count++ < 4) 13890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "write register 0x%x failed with %d\n", 13990aac0d8SBjoern A. Zeeb addr, ret); 140*11c53278SBjoern A. Zeeb 141*11c53278SBjoern A. Zeeb if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || 142*11c53278SBjoern A. Zeeb rtwdev->chip->id == RTW_CHIP_TYPE_8822B || 143*11c53278SBjoern A. Zeeb rtwdev->chip->id == RTW_CHIP_TYPE_8821C) 144*11c53278SBjoern A. Zeeb rtw_usb_reg_sec(rtwdev, addr, data); 14590aac0d8SBjoern A. Zeeb } 14690aac0d8SBjoern A. Zeeb 14790aac0d8SBjoern A. Zeeb static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) 14890aac0d8SBjoern A. Zeeb { 14990aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 1); 15090aac0d8SBjoern A. Zeeb } 15190aac0d8SBjoern A. Zeeb 15290aac0d8SBjoern A. Zeeb static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) 15390aac0d8SBjoern A. Zeeb { 15490aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 2); 15590aac0d8SBjoern A. Zeeb } 15690aac0d8SBjoern A. Zeeb 15790aac0d8SBjoern A. Zeeb static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) 15890aac0d8SBjoern A. Zeeb { 15990aac0d8SBjoern A. Zeeb rtw_usb_write(rtwdev, addr, val, 4); 16090aac0d8SBjoern A. Zeeb } 16190aac0d8SBjoern A. Zeeb 16290aac0d8SBjoern A. Zeeb static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping) 16390aac0d8SBjoern A. Zeeb { 16490aac0d8SBjoern A. Zeeb switch (dma_mapping) { 16590aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_HIGH: 16690aac0d8SBjoern A. Zeeb return 0; 16790aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_NORMAL: 16890aac0d8SBjoern A. Zeeb return 1; 16990aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_LOW: 17090aac0d8SBjoern A. Zeeb return 2; 17190aac0d8SBjoern A. Zeeb case RTW_DMA_MAPPING_EXTRA: 17290aac0d8SBjoern A. Zeeb return 3; 17390aac0d8SBjoern A. Zeeb default: 17490aac0d8SBjoern A. Zeeb return -EINVAL; 17590aac0d8SBjoern A. Zeeb } 17690aac0d8SBjoern A. Zeeb } 17790aac0d8SBjoern A. Zeeb 17890aac0d8SBjoern A. Zeeb static int rtw_usb_parse(struct rtw_dev *rtwdev, 17990aac0d8SBjoern A. Zeeb struct usb_interface *interface) 18090aac0d8SBjoern A. Zeeb { 18190aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 18290aac0d8SBjoern A. Zeeb struct usb_host_interface *host_interface = &interface->altsetting[0]; 18390aac0d8SBjoern A. Zeeb struct usb_interface_descriptor *interface_desc = &host_interface->desc; 18490aac0d8SBjoern A. Zeeb struct usb_endpoint_descriptor *endpoint; 18590aac0d8SBjoern A. Zeeb int num_out_pipes = 0; 18690aac0d8SBjoern A. Zeeb int i; 18790aac0d8SBjoern A. Zeeb u8 num; 18890aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 18990aac0d8SBjoern A. Zeeb const struct rtw_rqpn *rqpn; 19090aac0d8SBjoern A. Zeeb 19190aac0d8SBjoern A. Zeeb for (i = 0; i < interface_desc->bNumEndpoints; i++) { 19290aac0d8SBjoern A. Zeeb endpoint = &host_interface->endpoint[i].desc; 19390aac0d8SBjoern A. Zeeb num = usb_endpoint_num(endpoint); 19490aac0d8SBjoern A. Zeeb 19590aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_in(endpoint) && 19690aac0d8SBjoern A. Zeeb usb_endpoint_xfer_bulk(endpoint)) { 19790aac0d8SBjoern A. Zeeb if (rtwusb->pipe_in) { 19890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "IN pipes overflow\n"); 19990aac0d8SBjoern A. Zeeb return -EINVAL; 20090aac0d8SBjoern A. Zeeb } 20190aac0d8SBjoern A. Zeeb 20290aac0d8SBjoern A. Zeeb rtwusb->pipe_in = num; 20390aac0d8SBjoern A. Zeeb } 20490aac0d8SBjoern A. Zeeb 20590aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_in(endpoint) && 20690aac0d8SBjoern A. Zeeb usb_endpoint_xfer_int(endpoint)) { 20790aac0d8SBjoern A. Zeeb if (rtwusb->pipe_interrupt) { 20890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "INT pipes overflow\n"); 20990aac0d8SBjoern A. Zeeb return -EINVAL; 21090aac0d8SBjoern A. Zeeb } 21190aac0d8SBjoern A. Zeeb 21290aac0d8SBjoern A. Zeeb rtwusb->pipe_interrupt = num; 21390aac0d8SBjoern A. Zeeb } 21490aac0d8SBjoern A. Zeeb 21590aac0d8SBjoern A. Zeeb if (usb_endpoint_dir_out(endpoint) && 21690aac0d8SBjoern A. Zeeb usb_endpoint_xfer_bulk(endpoint)) { 21790aac0d8SBjoern A. Zeeb if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) { 21890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "OUT pipes overflow\n"); 21990aac0d8SBjoern A. Zeeb return -EINVAL; 22090aac0d8SBjoern A. Zeeb } 22190aac0d8SBjoern A. Zeeb 22290aac0d8SBjoern A. Zeeb rtwusb->out_ep[num_out_pipes++] = num; 22390aac0d8SBjoern A. Zeeb } 22490aac0d8SBjoern A. Zeeb } 22590aac0d8SBjoern A. Zeeb 22690aac0d8SBjoern A. Zeeb rtwdev->hci.bulkout_num = num_out_pipes; 22790aac0d8SBjoern A. Zeeb 22890aac0d8SBjoern A. Zeeb if (num_out_pipes < 1 || num_out_pipes > 4) { 22990aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "invalid number of endpoints %d\n", num_out_pipes); 23090aac0d8SBjoern A. Zeeb return -EINVAL; 23190aac0d8SBjoern A. Zeeb } 23290aac0d8SBjoern A. Zeeb 23390aac0d8SBjoern A. Zeeb rqpn = &chip->rqpn_table[num_out_pipes]; 23490aac0d8SBjoern A. Zeeb 23590aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = dma_mapping_to_ep(rqpn->dma_map_be); 23690aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = dma_mapping_to_ep(rqpn->dma_map_bk); 23790aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = dma_mapping_to_ep(rqpn->dma_map_bk); 23890aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = dma_mapping_to_ep(rqpn->dma_map_be); 23990aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = dma_mapping_to_ep(rqpn->dma_map_vi); 24090aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = dma_mapping_to_ep(rqpn->dma_map_vi); 24190aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = dma_mapping_to_ep(rqpn->dma_map_vo); 24290aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = dma_mapping_to_ep(rqpn->dma_map_vo); 24390aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID8] = -EINVAL; 24490aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID9] = -EINVAL; 24590aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID10] = -EINVAL; 24690aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID11] = -EINVAL; 24790aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID12] = -EINVAL; 24890aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID13] = -EINVAL; 24990aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID14] = -EINVAL; 25090aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_TID15] = -EINVAL; 25190aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_BEACON] = dma_mapping_to_ep(rqpn->dma_map_hi); 25290aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_HIGH] = dma_mapping_to_ep(rqpn->dma_map_hi); 25390aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_MGMT] = dma_mapping_to_ep(rqpn->dma_map_mg); 25490aac0d8SBjoern A. Zeeb rtwusb->qsel_to_ep[TX_DESC_QSEL_H2C] = dma_mapping_to_ep(rqpn->dma_map_hi); 25590aac0d8SBjoern A. Zeeb 25690aac0d8SBjoern A. Zeeb return 0; 25790aac0d8SBjoern A. Zeeb } 25890aac0d8SBjoern A. Zeeb 25990aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_tx_complete(struct urb *urb) 26090aac0d8SBjoern A. Zeeb { 26190aac0d8SBjoern A. Zeeb struct rtw_usb_txcb *txcb = urb->context; 26290aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = txcb->rtwdev; 26390aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw; 26490aac0d8SBjoern A. Zeeb 26590aac0d8SBjoern A. Zeeb while (true) { 26690aac0d8SBjoern A. Zeeb struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue); 26790aac0d8SBjoern A. Zeeb struct ieee80211_tx_info *info; 26890aac0d8SBjoern A. Zeeb struct rtw_usb_tx_data *tx_data; 26990aac0d8SBjoern A. Zeeb 27090aac0d8SBjoern A. Zeeb if (!skb) 27190aac0d8SBjoern A. Zeeb break; 27290aac0d8SBjoern A. Zeeb 27390aac0d8SBjoern A. Zeeb info = IEEE80211_SKB_CB(skb); 27490aac0d8SBjoern A. Zeeb tx_data = rtw_usb_get_tx_data(skb); 27590aac0d8SBjoern A. Zeeb 276*11c53278SBjoern A. Zeeb skb_pull(skb, rtwdev->chip->tx_pkt_desc_sz); 277*11c53278SBjoern A. Zeeb 27890aac0d8SBjoern A. Zeeb /* enqueue to wait for tx report */ 27990aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { 28090aac0d8SBjoern A. Zeeb rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); 28190aac0d8SBjoern A. Zeeb continue; 28290aac0d8SBjoern A. Zeeb } 28390aac0d8SBjoern A. Zeeb 28490aac0d8SBjoern A. Zeeb /* always ACK for others, then they won't be marked as drop */ 28590aac0d8SBjoern A. Zeeb ieee80211_tx_info_clear_status(info); 28690aac0d8SBjoern A. Zeeb if (info->flags & IEEE80211_TX_CTL_NO_ACK) 28790aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 28890aac0d8SBjoern A. Zeeb else 28990aac0d8SBjoern A. Zeeb info->flags |= IEEE80211_TX_STAT_ACK; 29090aac0d8SBjoern A. Zeeb 29190aac0d8SBjoern A. Zeeb ieee80211_tx_status_irqsafe(hw, skb); 29290aac0d8SBjoern A. Zeeb } 29390aac0d8SBjoern A. Zeeb 29490aac0d8SBjoern A. Zeeb kfree(txcb); 29590aac0d8SBjoern A. Zeeb } 29690aac0d8SBjoern A. Zeeb 29790aac0d8SBjoern A. Zeeb static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel) 29890aac0d8SBjoern A. Zeeb { 29990aac0d8SBjoern A. Zeeb if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep)) 30090aac0d8SBjoern A. Zeeb return -EINVAL; 30190aac0d8SBjoern A. Zeeb 30290aac0d8SBjoern A. Zeeb return rtwusb->qsel_to_ep[qsel]; 30390aac0d8SBjoern A. Zeeb } 30490aac0d8SBjoern A. Zeeb 30590aac0d8SBjoern A. Zeeb static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb, 30690aac0d8SBjoern A. Zeeb usb_complete_t cb, void *context) 30790aac0d8SBjoern A. Zeeb { 30890aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 30990aac0d8SBjoern A. Zeeb struct usb_device *usbd = rtwusb->udev; 31090aac0d8SBjoern A. Zeeb struct urb *urb; 31190aac0d8SBjoern A. Zeeb unsigned int pipe; 31290aac0d8SBjoern A. Zeeb int ret; 31390aac0d8SBjoern A. Zeeb int ep = qsel_to_ep(rtwusb, qsel); 31490aac0d8SBjoern A. Zeeb 31590aac0d8SBjoern A. Zeeb if (ep < 0) 31690aac0d8SBjoern A. Zeeb return ep; 31790aac0d8SBjoern A. Zeeb 31890aac0d8SBjoern A. Zeeb pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]); 31990aac0d8SBjoern A. Zeeb urb = usb_alloc_urb(0, GFP_ATOMIC); 32090aac0d8SBjoern A. Zeeb if (!urb) 32190aac0d8SBjoern A. Zeeb return -ENOMEM; 32290aac0d8SBjoern A. Zeeb 32390aac0d8SBjoern A. Zeeb usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context); 32490aac0d8SBjoern A. Zeeb urb->transfer_flags |= URB_ZERO_PACKET; 32590aac0d8SBjoern A. Zeeb ret = usb_submit_urb(urb, GFP_ATOMIC); 32690aac0d8SBjoern A. Zeeb 32790aac0d8SBjoern A. Zeeb usb_free_urb(urb); 32890aac0d8SBjoern A. Zeeb 32990aac0d8SBjoern A. Zeeb return ret; 33090aac0d8SBjoern A. Zeeb } 33190aac0d8SBjoern A. Zeeb 33290aac0d8SBjoern A. Zeeb static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list) 33390aac0d8SBjoern A. Zeeb { 33490aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 33590aac0d8SBjoern A. Zeeb struct rtw_tx_desc *tx_desc; 33690aac0d8SBjoern A. Zeeb struct rtw_usb_txcb *txcb; 33790aac0d8SBjoern A. Zeeb struct sk_buff *skb_head; 33890aac0d8SBjoern A. Zeeb struct sk_buff *skb_iter; 33990aac0d8SBjoern A. Zeeb int agg_num = 0; 34090aac0d8SBjoern A. Zeeb unsigned int align_next = 0; 34190aac0d8SBjoern A. Zeeb u8 qsel; 34290aac0d8SBjoern A. Zeeb 34390aac0d8SBjoern A. Zeeb if (skb_queue_empty(list)) 34490aac0d8SBjoern A. Zeeb return false; 34590aac0d8SBjoern A. Zeeb 34690aac0d8SBjoern A. Zeeb txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); 34790aac0d8SBjoern A. Zeeb if (!txcb) 34890aac0d8SBjoern A. Zeeb return false; 34990aac0d8SBjoern A. Zeeb 35090aac0d8SBjoern A. Zeeb txcb->rtwdev = rtwdev; 35190aac0d8SBjoern A. Zeeb skb_queue_head_init(&txcb->tx_ack_queue); 35290aac0d8SBjoern A. Zeeb 35390aac0d8SBjoern A. Zeeb skb_iter = skb_dequeue(list); 35490aac0d8SBjoern A. Zeeb 35590aac0d8SBjoern A. Zeeb if (skb_queue_empty(list)) { 35690aac0d8SBjoern A. Zeeb skb_head = skb_iter; 35790aac0d8SBjoern A. Zeeb goto queue; 35890aac0d8SBjoern A. Zeeb } 35990aac0d8SBjoern A. Zeeb 36090aac0d8SBjoern A. Zeeb skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ); 36190aac0d8SBjoern A. Zeeb if (!skb_head) { 36290aac0d8SBjoern A. Zeeb skb_head = skb_iter; 36390aac0d8SBjoern A. Zeeb goto queue; 36490aac0d8SBjoern A. Zeeb } 36590aac0d8SBjoern A. Zeeb 36690aac0d8SBjoern A. Zeeb while (skb_iter) { 36790aac0d8SBjoern A. Zeeb unsigned long flags; 36890aac0d8SBjoern A. Zeeb 36990aac0d8SBjoern A. Zeeb skb_put(skb_head, align_next); 37090aac0d8SBjoern A. Zeeb skb_put_data(skb_head, skb_iter->data, skb_iter->len); 37190aac0d8SBjoern A. Zeeb 37290aac0d8SBjoern A. Zeeb align_next = ALIGN(skb_iter->len, 8) - skb_iter->len; 37390aac0d8SBjoern A. Zeeb 37490aac0d8SBjoern A. Zeeb agg_num++; 37590aac0d8SBjoern A. Zeeb 37690aac0d8SBjoern A. Zeeb skb_queue_tail(&txcb->tx_ack_queue, skb_iter); 37790aac0d8SBjoern A. Zeeb 37890aac0d8SBjoern A. Zeeb spin_lock_irqsave(&list->lock, flags); 37990aac0d8SBjoern A. Zeeb 38090aac0d8SBjoern A. Zeeb skb_iter = skb_peek(list); 38190aac0d8SBjoern A. Zeeb 382*11c53278SBjoern A. Zeeb if (skb_iter && 383*11c53278SBjoern A. Zeeb skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ && 384*11c53278SBjoern A. Zeeb agg_num < rtwdev->chip->usb_tx_agg_desc_num) 38590aac0d8SBjoern A. Zeeb __skb_unlink(skb_iter, list); 38690aac0d8SBjoern A. Zeeb else 38790aac0d8SBjoern A. Zeeb skb_iter = NULL; 38890aac0d8SBjoern A. Zeeb spin_unlock_irqrestore(&list->lock, flags); 38990aac0d8SBjoern A. Zeeb } 39090aac0d8SBjoern A. Zeeb 39190aac0d8SBjoern A. Zeeb if (agg_num > 1) 39290aac0d8SBjoern A. Zeeb rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num); 39390aac0d8SBjoern A. Zeeb 39490aac0d8SBjoern A. Zeeb queue: 39590aac0d8SBjoern A. Zeeb skb_queue_tail(&txcb->tx_ack_queue, skb_head); 39690aac0d8SBjoern A. Zeeb tx_desc = (struct rtw_tx_desc *)skb_head->data; 39790aac0d8SBjoern A. Zeeb qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL); 39890aac0d8SBjoern A. Zeeb 39990aac0d8SBjoern A. Zeeb rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb); 40090aac0d8SBjoern A. Zeeb 40190aac0d8SBjoern A. Zeeb return true; 40290aac0d8SBjoern A. Zeeb } 40390aac0d8SBjoern A. Zeeb 40490aac0d8SBjoern A. Zeeb static void rtw_usb_tx_handler(struct work_struct *work) 40590aac0d8SBjoern A. Zeeb { 40690aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work); 40790aac0d8SBjoern A. Zeeb int i, limit; 40890aac0d8SBjoern A. Zeeb 40990aac0d8SBjoern A. Zeeb for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) { 41090aac0d8SBjoern A. Zeeb for (limit = 0; limit < 200; limit++) { 41190aac0d8SBjoern A. Zeeb struct sk_buff_head *list = &rtwusb->tx_queue[i]; 41290aac0d8SBjoern A. Zeeb 41390aac0d8SBjoern A. Zeeb if (!rtw_usb_tx_agg_skb(rtwusb, list)) 41490aac0d8SBjoern A. Zeeb break; 41590aac0d8SBjoern A. Zeeb } 41690aac0d8SBjoern A. Zeeb } 41790aac0d8SBjoern A. Zeeb } 41890aac0d8SBjoern A. Zeeb 41990aac0d8SBjoern A. Zeeb static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) 42090aac0d8SBjoern A. Zeeb { 42190aac0d8SBjoern A. Zeeb int i; 42290aac0d8SBjoern A. Zeeb 42390aac0d8SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 42490aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwusb->tx_queue[i]); 42590aac0d8SBjoern A. Zeeb } 42690aac0d8SBjoern A. Zeeb 42790aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_complete(struct urb *urb) 42890aac0d8SBjoern A. Zeeb { 42990aac0d8SBjoern A. Zeeb struct sk_buff *skb = urb->context; 43090aac0d8SBjoern A. Zeeb 43190aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 43290aac0d8SBjoern A. Zeeb } 43390aac0d8SBjoern A. Zeeb 43490aac0d8SBjoern A. Zeeb static int rtw_usb_write_data(struct rtw_dev *rtwdev, 43590aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 43690aac0d8SBjoern A. Zeeb u8 *buf) 43790aac0d8SBjoern A. Zeeb { 43890aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 43990aac0d8SBjoern A. Zeeb struct sk_buff *skb; 440*11c53278SBjoern A. Zeeb unsigned int size; 44190aac0d8SBjoern A. Zeeb u8 qsel; 44290aac0d8SBjoern A. Zeeb int ret = 0; 44390aac0d8SBjoern A. Zeeb 44490aac0d8SBjoern A. Zeeb size = pkt_info->tx_pkt_size; 44590aac0d8SBjoern A. Zeeb qsel = pkt_info->qsel; 44690aac0d8SBjoern A. Zeeb 447*11c53278SBjoern A. Zeeb skb = dev_alloc_skb(chip->tx_pkt_desc_sz + size); 44890aac0d8SBjoern A. Zeeb if (unlikely(!skb)) 44990aac0d8SBjoern A. Zeeb return -ENOMEM; 45090aac0d8SBjoern A. Zeeb 451*11c53278SBjoern A. Zeeb skb_reserve(skb, chip->tx_pkt_desc_sz); 45290aac0d8SBjoern A. Zeeb skb_put_data(skb, buf, size); 453*11c53278SBjoern A. Zeeb skb_push(skb, chip->tx_pkt_desc_sz); 454*11c53278SBjoern A. Zeeb memset(skb->data, 0, chip->tx_pkt_desc_sz); 45590aac0d8SBjoern A. Zeeb rtw_tx_fill_tx_desc(pkt_info, skb); 45690aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 45790aac0d8SBjoern A. Zeeb 45890aac0d8SBjoern A. Zeeb ret = rtw_usb_write_port(rtwdev, qsel, skb, 45990aac0d8SBjoern A. Zeeb rtw_usb_write_port_complete, skb); 46090aac0d8SBjoern A. Zeeb if (unlikely(ret)) 46190aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret); 46290aac0d8SBjoern A. Zeeb 46390aac0d8SBjoern A. Zeeb return ret; 46490aac0d8SBjoern A. Zeeb } 46590aac0d8SBjoern A. Zeeb 46690aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, 46790aac0d8SBjoern A. Zeeb u32 size) 46890aac0d8SBjoern A. Zeeb { 46990aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 47090aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {0}; 47190aac0d8SBjoern A. Zeeb 47290aac0d8SBjoern A. Zeeb pkt_info.tx_pkt_size = size; 47390aac0d8SBjoern A. Zeeb pkt_info.qsel = TX_DESC_QSEL_BEACON; 47490aac0d8SBjoern A. Zeeb pkt_info.offset = chip->tx_pkt_desc_sz; 47590aac0d8SBjoern A. Zeeb 47690aac0d8SBjoern A. Zeeb return rtw_usb_write_data(rtwdev, &pkt_info, buf); 47790aac0d8SBjoern A. Zeeb } 47890aac0d8SBjoern A. Zeeb 47990aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) 48090aac0d8SBjoern A. Zeeb { 48190aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info pkt_info = {0}; 48290aac0d8SBjoern A. Zeeb 48390aac0d8SBjoern A. Zeeb pkt_info.tx_pkt_size = size; 48490aac0d8SBjoern A. Zeeb pkt_info.qsel = TX_DESC_QSEL_H2C; 48590aac0d8SBjoern A. Zeeb 48690aac0d8SBjoern A. Zeeb return rtw_usb_write_data(rtwdev, &pkt_info, buf); 48790aac0d8SBjoern A. Zeeb } 48890aac0d8SBjoern A. Zeeb 48990aac0d8SBjoern A. Zeeb static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb) 49090aac0d8SBjoern A. Zeeb { 49190aac0d8SBjoern A. Zeeb struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 49290aac0d8SBjoern A. Zeeb __le16 fc = hdr->frame_control; 49390aac0d8SBjoern A. Zeeb u8 qsel; 49490aac0d8SBjoern A. Zeeb 49590aac0d8SBjoern A. Zeeb if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) 49690aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_MGMT; 49790aac0d8SBjoern A. Zeeb else if (is_broadcast_ether_addr(hdr->addr1) || 49890aac0d8SBjoern A. Zeeb is_multicast_ether_addr(hdr->addr1)) 49990aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_HIGH; 50090aac0d8SBjoern A. Zeeb else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK) 50190aac0d8SBjoern A. Zeeb qsel = skb->priority; 50290aac0d8SBjoern A. Zeeb else 50390aac0d8SBjoern A. Zeeb qsel = TX_DESC_QSEL_BEACON; 50490aac0d8SBjoern A. Zeeb 50590aac0d8SBjoern A. Zeeb return qsel; 50690aac0d8SBjoern A. Zeeb } 50790aac0d8SBjoern A. Zeeb 50890aac0d8SBjoern A. Zeeb static int rtw_usb_tx_write(struct rtw_dev *rtwdev, 50990aac0d8SBjoern A. Zeeb struct rtw_tx_pkt_info *pkt_info, 51090aac0d8SBjoern A. Zeeb struct sk_buff *skb) 51190aac0d8SBjoern A. Zeeb { 51290aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 51390aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 51490aac0d8SBjoern A. Zeeb struct rtw_usb_tx_data *tx_data; 51590aac0d8SBjoern A. Zeeb u8 *pkt_desc; 51690aac0d8SBjoern A. Zeeb int ep; 51790aac0d8SBjoern A. Zeeb 51890aac0d8SBjoern A. Zeeb pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); 51990aac0d8SBjoern A. Zeeb pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); 52090aac0d8SBjoern A. Zeeb memset(pkt_desc, 0, chip->tx_pkt_desc_sz); 52190aac0d8SBjoern A. Zeeb ep = qsel_to_ep(rtwusb, pkt_info->qsel); 52290aac0d8SBjoern A. Zeeb rtw_tx_fill_tx_desc(pkt_info, skb); 52390aac0d8SBjoern A. Zeeb rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); 52490aac0d8SBjoern A. Zeeb tx_data = rtw_usb_get_tx_data(skb); 52590aac0d8SBjoern A. Zeeb tx_data->sn = pkt_info->sn; 52690aac0d8SBjoern A. Zeeb 52790aac0d8SBjoern A. Zeeb skb_queue_tail(&rtwusb->tx_queue[ep], skb); 52890aac0d8SBjoern A. Zeeb 52990aac0d8SBjoern A. Zeeb return 0; 53090aac0d8SBjoern A. Zeeb } 53190aac0d8SBjoern A. Zeeb 53290aac0d8SBjoern A. Zeeb static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev) 53390aac0d8SBjoern A. Zeeb { 53490aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 53590aac0d8SBjoern A. Zeeb 53690aac0d8SBjoern A. Zeeb queue_work(rtwusb->txwq, &rtwusb->tx_work); 53790aac0d8SBjoern A. Zeeb } 53890aac0d8SBjoern A. Zeeb 53990aac0d8SBjoern A. Zeeb static void rtw_usb_rx_handler(struct work_struct *work) 54090aac0d8SBjoern A. Zeeb { 54190aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work); 54290aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 54390aac0d8SBjoern A. Zeeb const struct rtw_chip_info *chip = rtwdev->chip; 54490aac0d8SBjoern A. Zeeb struct rtw_rx_pkt_stat pkt_stat; 54590aac0d8SBjoern A. Zeeb struct ieee80211_rx_status rx_status; 54690aac0d8SBjoern A. Zeeb struct sk_buff *skb; 54790aac0d8SBjoern A. Zeeb u32 pkt_desc_sz = chip->rx_pkt_desc_sz; 54890aac0d8SBjoern A. Zeeb u32 pkt_offset; 54990aac0d8SBjoern A. Zeeb u8 *rx_desc; 55090aac0d8SBjoern A. Zeeb int limit; 55190aac0d8SBjoern A. Zeeb 55290aac0d8SBjoern A. Zeeb for (limit = 0; limit < 200; limit++) { 55390aac0d8SBjoern A. Zeeb skb = skb_dequeue(&rtwusb->rx_queue); 55490aac0d8SBjoern A. Zeeb if (!skb) 55590aac0d8SBjoern A. Zeeb break; 55690aac0d8SBjoern A. Zeeb 55790aac0d8SBjoern A. Zeeb rx_desc = skb->data; 55890aac0d8SBjoern A. Zeeb chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, 55990aac0d8SBjoern A. Zeeb &rx_status); 56090aac0d8SBjoern A. Zeeb pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + 56190aac0d8SBjoern A. Zeeb pkt_stat.shift; 56290aac0d8SBjoern A. Zeeb 56390aac0d8SBjoern A. Zeeb if (pkt_stat.is_c2h) { 56490aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat.pkt_len + pkt_offset); 56590aac0d8SBjoern A. Zeeb rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); 56690aac0d8SBjoern A. Zeeb continue; 56790aac0d8SBjoern A. Zeeb } 56890aac0d8SBjoern A. Zeeb 56990aac0d8SBjoern A. Zeeb if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { 57090aac0d8SBjoern A. Zeeb dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n"); 57190aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 57290aac0d8SBjoern A. Zeeb continue; 57390aac0d8SBjoern A. Zeeb } 57490aac0d8SBjoern A. Zeeb 57590aac0d8SBjoern A. Zeeb skb_put(skb, pkt_stat.pkt_len); 57690aac0d8SBjoern A. Zeeb skb_reserve(skb, pkt_offset); 57790aac0d8SBjoern A. Zeeb memcpy(skb->cb, &rx_status, sizeof(rx_status)); 57890aac0d8SBjoern A. Zeeb ieee80211_rx_irqsafe(rtwdev->hw, skb); 57990aac0d8SBjoern A. Zeeb } 58090aac0d8SBjoern A. Zeeb } 58190aac0d8SBjoern A. Zeeb 58290aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb); 58390aac0d8SBjoern A. Zeeb 58490aac0d8SBjoern A. Zeeb static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb) 58590aac0d8SBjoern A. Zeeb { 58690aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rtwusb->rtwdev; 58790aac0d8SBjoern A. Zeeb int error; 58890aac0d8SBjoern A. Zeeb 58990aac0d8SBjoern A. Zeeb rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC); 59090aac0d8SBjoern A. Zeeb if (!rxcb->rx_skb) 59190aac0d8SBjoern A. Zeeb return; 59290aac0d8SBjoern A. Zeeb 59390aac0d8SBjoern A. Zeeb usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, 59490aac0d8SBjoern A. Zeeb usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in), 59590aac0d8SBjoern A. Zeeb rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ, 59690aac0d8SBjoern A. Zeeb rtw_usb_read_port_complete, rxcb); 59790aac0d8SBjoern A. Zeeb 59890aac0d8SBjoern A. Zeeb error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC); 59990aac0d8SBjoern A. Zeeb if (error) { 60090aac0d8SBjoern A. Zeeb kfree_skb(rxcb->rx_skb); 60190aac0d8SBjoern A. Zeeb if (error != -ENODEV) 60290aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "Err sending rx data urb %d\n", 60390aac0d8SBjoern A. Zeeb error); 60490aac0d8SBjoern A. Zeeb } 60590aac0d8SBjoern A. Zeeb } 60690aac0d8SBjoern A. Zeeb 60790aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb) 60890aac0d8SBjoern A. Zeeb { 60990aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = urb->context; 61090aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev = rxcb->rtwdev; 61190aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 61290aac0d8SBjoern A. Zeeb struct sk_buff *skb = rxcb->rx_skb; 61390aac0d8SBjoern A. Zeeb 61490aac0d8SBjoern A. Zeeb if (urb->status == 0) { 61590aac0d8SBjoern A. Zeeb if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ || 61690aac0d8SBjoern A. Zeeb urb->actual_length < 24) { 61790aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to get urb length:%d\n", 61890aac0d8SBjoern A. Zeeb urb->actual_length); 61990aac0d8SBjoern A. Zeeb if (skb) 62090aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 62190aac0d8SBjoern A. Zeeb } else { 62290aac0d8SBjoern A. Zeeb skb_queue_tail(&rtwusb->rx_queue, skb); 62390aac0d8SBjoern A. Zeeb queue_work(rtwusb->rxwq, &rtwusb->rx_work); 62490aac0d8SBjoern A. Zeeb } 62590aac0d8SBjoern A. Zeeb rtw_usb_rx_resubmit(rtwusb, rxcb); 62690aac0d8SBjoern A. Zeeb } else { 62790aac0d8SBjoern A. Zeeb switch (urb->status) { 62890aac0d8SBjoern A. Zeeb case -EINVAL: 62990aac0d8SBjoern A. Zeeb case -EPIPE: 63090aac0d8SBjoern A. Zeeb case -ENODEV: 63190aac0d8SBjoern A. Zeeb case -ESHUTDOWN: 63290aac0d8SBjoern A. Zeeb case -ENOENT: 63390aac0d8SBjoern A. Zeeb case -EPROTO: 63490aac0d8SBjoern A. Zeeb case -EILSEQ: 63590aac0d8SBjoern A. Zeeb case -ETIME: 63690aac0d8SBjoern A. Zeeb case -ECOMM: 63790aac0d8SBjoern A. Zeeb case -EOVERFLOW: 63890aac0d8SBjoern A. Zeeb case -EINPROGRESS: 63990aac0d8SBjoern A. Zeeb break; 64090aac0d8SBjoern A. Zeeb default: 64190aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "status %d\n", urb->status); 64290aac0d8SBjoern A. Zeeb break; 64390aac0d8SBjoern A. Zeeb } 64490aac0d8SBjoern A. Zeeb if (skb) 64590aac0d8SBjoern A. Zeeb dev_kfree_skb_any(skb); 64690aac0d8SBjoern A. Zeeb } 64790aac0d8SBjoern A. Zeeb } 64890aac0d8SBjoern A. Zeeb 64990aac0d8SBjoern A. Zeeb static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb) 65090aac0d8SBjoern A. Zeeb { 65190aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb; 65290aac0d8SBjoern A. Zeeb int i; 65390aac0d8SBjoern A. Zeeb 65490aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 65590aac0d8SBjoern A. Zeeb rxcb = &rtwusb->rx_cb[i]; 65690aac0d8SBjoern A. Zeeb usb_kill_urb(rxcb->rx_urb); 65790aac0d8SBjoern A. Zeeb } 65890aac0d8SBjoern A. Zeeb } 65990aac0d8SBjoern A. Zeeb 66090aac0d8SBjoern A. Zeeb static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb) 66190aac0d8SBjoern A. Zeeb { 66290aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb; 66390aac0d8SBjoern A. Zeeb int i; 66490aac0d8SBjoern A. Zeeb 66590aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 66690aac0d8SBjoern A. Zeeb rxcb = &rtwusb->rx_cb[i]; 66790aac0d8SBjoern A. Zeeb usb_kill_urb(rxcb->rx_urb); 66890aac0d8SBjoern A. Zeeb usb_free_urb(rxcb->rx_urb); 66990aac0d8SBjoern A. Zeeb } 67090aac0d8SBjoern A. Zeeb } 67190aac0d8SBjoern A. Zeeb 67290aac0d8SBjoern A. Zeeb static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb) 67390aac0d8SBjoern A. Zeeb { 67490aac0d8SBjoern A. Zeeb int i; 67590aac0d8SBjoern A. Zeeb 67690aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 67790aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 67890aac0d8SBjoern A. Zeeb 67990aac0d8SBjoern A. Zeeb rxcb->rtwdev = rtwusb->rtwdev; 68090aac0d8SBjoern A. Zeeb rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 68190aac0d8SBjoern A. Zeeb if (!rxcb->rx_urb) 68290aac0d8SBjoern A. Zeeb goto err; 68390aac0d8SBjoern A. Zeeb } 68490aac0d8SBjoern A. Zeeb 68590aac0d8SBjoern A. Zeeb return 0; 68690aac0d8SBjoern A. Zeeb err: 68790aac0d8SBjoern A. Zeeb rtw_usb_free_rx_bufs(rtwusb); 68890aac0d8SBjoern A. Zeeb return -ENOMEM; 68990aac0d8SBjoern A. Zeeb } 69090aac0d8SBjoern A. Zeeb 69190aac0d8SBjoern A. Zeeb static int rtw_usb_setup(struct rtw_dev *rtwdev) 69290aac0d8SBjoern A. Zeeb { 69390aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 69490aac0d8SBjoern A. Zeeb return 0; 69590aac0d8SBjoern A. Zeeb } 69690aac0d8SBjoern A. Zeeb 69790aac0d8SBjoern A. Zeeb static int rtw_usb_start(struct rtw_dev *rtwdev) 69890aac0d8SBjoern A. Zeeb { 69990aac0d8SBjoern A. Zeeb return 0; 70090aac0d8SBjoern A. Zeeb } 70190aac0d8SBjoern A. Zeeb 70290aac0d8SBjoern A. Zeeb static void rtw_usb_stop(struct rtw_dev *rtwdev) 70390aac0d8SBjoern A. Zeeb { 70490aac0d8SBjoern A. Zeeb } 70590aac0d8SBjoern A. Zeeb 70690aac0d8SBjoern A. Zeeb static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter) 70790aac0d8SBjoern A. Zeeb { 70890aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 70990aac0d8SBjoern A. Zeeb } 71090aac0d8SBjoern A. Zeeb 71190aac0d8SBjoern A. Zeeb static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter) 71290aac0d8SBjoern A. Zeeb { 71390aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 71490aac0d8SBjoern A. Zeeb } 71590aac0d8SBjoern A. Zeeb 71690aac0d8SBjoern A. Zeeb static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev) 71790aac0d8SBjoern A. Zeeb { 71890aac0d8SBjoern A. Zeeb /* empty function for rtw_hci_ops */ 71990aac0d8SBjoern A. Zeeb } 72090aac0d8SBjoern A. Zeeb 72190aac0d8SBjoern A. Zeeb static struct rtw_hci_ops rtw_usb_ops = { 72290aac0d8SBjoern A. Zeeb .tx_write = rtw_usb_tx_write, 72390aac0d8SBjoern A. Zeeb .tx_kick_off = rtw_usb_tx_kick_off, 72490aac0d8SBjoern A. Zeeb .setup = rtw_usb_setup, 72590aac0d8SBjoern A. Zeeb .start = rtw_usb_start, 72690aac0d8SBjoern A. Zeeb .stop = rtw_usb_stop, 72790aac0d8SBjoern A. Zeeb .deep_ps = rtw_usb_deep_ps, 72890aac0d8SBjoern A. Zeeb .link_ps = rtw_usb_link_ps, 72990aac0d8SBjoern A. Zeeb .interface_cfg = rtw_usb_interface_cfg, 73090aac0d8SBjoern A. Zeeb 73190aac0d8SBjoern A. Zeeb .write8 = rtw_usb_write8, 73290aac0d8SBjoern A. Zeeb .write16 = rtw_usb_write16, 73390aac0d8SBjoern A. Zeeb .write32 = rtw_usb_write32, 73490aac0d8SBjoern A. Zeeb .read8 = rtw_usb_read8, 73590aac0d8SBjoern A. Zeeb .read16 = rtw_usb_read16, 73690aac0d8SBjoern A. Zeeb .read32 = rtw_usb_read32, 73790aac0d8SBjoern A. Zeeb 73890aac0d8SBjoern A. Zeeb .write_data_rsvd_page = rtw_usb_write_data_rsvd_page, 73990aac0d8SBjoern A. Zeeb .write_data_h2c = rtw_usb_write_data_h2c, 74090aac0d8SBjoern A. Zeeb }; 74190aac0d8SBjoern A. Zeeb 74290aac0d8SBjoern A. Zeeb static int rtw_usb_init_rx(struct rtw_dev *rtwdev) 74390aac0d8SBjoern A. Zeeb { 74490aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 74590aac0d8SBjoern A. Zeeb 74690aac0d8SBjoern A. Zeeb rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); 74790aac0d8SBjoern A. Zeeb if (!rtwusb->rxwq) { 74890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to create RX work queue\n"); 74990aac0d8SBjoern A. Zeeb return -ENOMEM; 75090aac0d8SBjoern A. Zeeb } 75190aac0d8SBjoern A. Zeeb 75290aac0d8SBjoern A. Zeeb skb_queue_head_init(&rtwusb->rx_queue); 75390aac0d8SBjoern A. Zeeb 75490aac0d8SBjoern A. Zeeb INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); 75590aac0d8SBjoern A. Zeeb 756*11c53278SBjoern A. Zeeb return 0; 757*11c53278SBjoern A. Zeeb } 758*11c53278SBjoern A. Zeeb 759*11c53278SBjoern A. Zeeb static void rtw_usb_setup_rx(struct rtw_dev *rtwdev) 760*11c53278SBjoern A. Zeeb { 761*11c53278SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 762*11c53278SBjoern A. Zeeb int i; 763*11c53278SBjoern A. Zeeb 76490aac0d8SBjoern A. Zeeb for (i = 0; i < RTW_USB_RXCB_NUM; i++) { 76590aac0d8SBjoern A. Zeeb struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; 76690aac0d8SBjoern A. Zeeb 76790aac0d8SBjoern A. Zeeb rtw_usb_rx_resubmit(rtwusb, rxcb); 76890aac0d8SBjoern A. Zeeb } 76990aac0d8SBjoern A. Zeeb } 77090aac0d8SBjoern A. Zeeb 77190aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) 77290aac0d8SBjoern A. Zeeb { 77390aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 77490aac0d8SBjoern A. Zeeb 77590aac0d8SBjoern A. Zeeb skb_queue_purge(&rtwusb->rx_queue); 77690aac0d8SBjoern A. Zeeb 77790aac0d8SBjoern A. Zeeb flush_workqueue(rtwusb->rxwq); 77890aac0d8SBjoern A. Zeeb destroy_workqueue(rtwusb->rxwq); 77990aac0d8SBjoern A. Zeeb } 78090aac0d8SBjoern A. Zeeb 78190aac0d8SBjoern A. Zeeb static int rtw_usb_init_tx(struct rtw_dev *rtwdev) 78290aac0d8SBjoern A. Zeeb { 78390aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 78490aac0d8SBjoern A. Zeeb int i; 78590aac0d8SBjoern A. Zeeb 78690aac0d8SBjoern A. Zeeb rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq"); 78790aac0d8SBjoern A. Zeeb if (!rtwusb->txwq) { 78890aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to create TX work queue\n"); 78990aac0d8SBjoern A. Zeeb return -ENOMEM; 79090aac0d8SBjoern A. Zeeb } 79190aac0d8SBjoern A. Zeeb 79290aac0d8SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) 79390aac0d8SBjoern A. Zeeb skb_queue_head_init(&rtwusb->tx_queue[i]); 79490aac0d8SBjoern A. Zeeb 79590aac0d8SBjoern A. Zeeb INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler); 79690aac0d8SBjoern A. Zeeb 79790aac0d8SBjoern A. Zeeb return 0; 79890aac0d8SBjoern A. Zeeb } 79990aac0d8SBjoern A. Zeeb 80090aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) 80190aac0d8SBjoern A. Zeeb { 80290aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 80390aac0d8SBjoern A. Zeeb 80490aac0d8SBjoern A. Zeeb rtw_usb_tx_queue_purge(rtwusb); 80590aac0d8SBjoern A. Zeeb flush_workqueue(rtwusb->txwq); 80690aac0d8SBjoern A. Zeeb destroy_workqueue(rtwusb->txwq); 80790aac0d8SBjoern A. Zeeb } 80890aac0d8SBjoern A. Zeeb 80990aac0d8SBjoern A. Zeeb static int rtw_usb_intf_init(struct rtw_dev *rtwdev, 81090aac0d8SBjoern A. Zeeb struct usb_interface *intf) 81190aac0d8SBjoern A. Zeeb { 81290aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 81390aac0d8SBjoern A. Zeeb struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); 81490aac0d8SBjoern A. Zeeb int ret; 81590aac0d8SBjoern A. Zeeb 81690aac0d8SBjoern A. Zeeb rtwusb->udev = udev; 81790aac0d8SBjoern A. Zeeb ret = rtw_usb_parse(rtwdev, intf); 81890aac0d8SBjoern A. Zeeb if (ret) 81990aac0d8SBjoern A. Zeeb return ret; 82090aac0d8SBjoern A. Zeeb 82190aac0d8SBjoern A. Zeeb rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32), 82290aac0d8SBjoern A. Zeeb GFP_KERNEL); 82390aac0d8SBjoern A. Zeeb if (!rtwusb->usb_data) 82490aac0d8SBjoern A. Zeeb return -ENOMEM; 82590aac0d8SBjoern A. Zeeb 82690aac0d8SBjoern A. Zeeb usb_set_intfdata(intf, rtwdev->hw); 82790aac0d8SBjoern A. Zeeb 82890aac0d8SBjoern A. Zeeb SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); 82990aac0d8SBjoern A. Zeeb spin_lock_init(&rtwusb->usb_lock); 83090aac0d8SBjoern A. Zeeb 83190aac0d8SBjoern A. Zeeb return 0; 83290aac0d8SBjoern A. Zeeb } 83390aac0d8SBjoern A. Zeeb 83490aac0d8SBjoern A. Zeeb static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev, 83590aac0d8SBjoern A. Zeeb struct usb_interface *intf) 83690aac0d8SBjoern A. Zeeb { 83790aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); 83890aac0d8SBjoern A. Zeeb 83990aac0d8SBjoern A. Zeeb usb_put_dev(rtwusb->udev); 84090aac0d8SBjoern A. Zeeb kfree(rtwusb->usb_data); 84190aac0d8SBjoern A. Zeeb usb_set_intfdata(intf, NULL); 84290aac0d8SBjoern A. Zeeb } 84390aac0d8SBjoern A. Zeeb 84490aac0d8SBjoern A. Zeeb int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 84590aac0d8SBjoern A. Zeeb { 84690aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 84790aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw; 84890aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb; 84990aac0d8SBjoern A. Zeeb int drv_data_size; 85090aac0d8SBjoern A. Zeeb int ret; 85190aac0d8SBjoern A. Zeeb 85290aac0d8SBjoern A. Zeeb drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb); 85390aac0d8SBjoern A. Zeeb hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); 85490aac0d8SBjoern A. Zeeb if (!hw) 85590aac0d8SBjoern A. Zeeb return -ENOMEM; 85690aac0d8SBjoern A. Zeeb 85790aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 85890aac0d8SBjoern A. Zeeb rtwdev->hw = hw; 85990aac0d8SBjoern A. Zeeb rtwdev->dev = &intf->dev; 86090aac0d8SBjoern A. Zeeb rtwdev->chip = (struct rtw_chip_info *)id->driver_info; 86190aac0d8SBjoern A. Zeeb rtwdev->hci.ops = &rtw_usb_ops; 86290aac0d8SBjoern A. Zeeb rtwdev->hci.type = RTW_HCI_TYPE_USB; 86390aac0d8SBjoern A. Zeeb 86490aac0d8SBjoern A. Zeeb rtwusb = rtw_get_usb_priv(rtwdev); 86590aac0d8SBjoern A. Zeeb rtwusb->rtwdev = rtwdev; 86690aac0d8SBjoern A. Zeeb 86790aac0d8SBjoern A. Zeeb ret = rtw_usb_alloc_rx_bufs(rtwusb); 86890aac0d8SBjoern A. Zeeb if (ret) 86990aac0d8SBjoern A. Zeeb goto err_release_hw; 87090aac0d8SBjoern A. Zeeb 87190aac0d8SBjoern A. Zeeb ret = rtw_core_init(rtwdev); 87290aac0d8SBjoern A. Zeeb if (ret) 873*11c53278SBjoern A. Zeeb goto err_free_rx_bufs; 87490aac0d8SBjoern A. Zeeb 87590aac0d8SBjoern A. Zeeb ret = rtw_usb_intf_init(rtwdev, intf); 87690aac0d8SBjoern A. Zeeb if (ret) { 87790aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB interface\n"); 87890aac0d8SBjoern A. Zeeb goto err_deinit_core; 87990aac0d8SBjoern A. Zeeb } 88090aac0d8SBjoern A. Zeeb 88190aac0d8SBjoern A. Zeeb ret = rtw_usb_init_tx(rtwdev); 88290aac0d8SBjoern A. Zeeb if (ret) { 88390aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB TX\n"); 88490aac0d8SBjoern A. Zeeb goto err_destroy_usb; 88590aac0d8SBjoern A. Zeeb } 88690aac0d8SBjoern A. Zeeb 88790aac0d8SBjoern A. Zeeb ret = rtw_usb_init_rx(rtwdev); 88890aac0d8SBjoern A. Zeeb if (ret) { 88990aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to init USB RX\n"); 89090aac0d8SBjoern A. Zeeb goto err_destroy_txwq; 89190aac0d8SBjoern A. Zeeb } 89290aac0d8SBjoern A. Zeeb 89390aac0d8SBjoern A. Zeeb ret = rtw_chip_info_setup(rtwdev); 89490aac0d8SBjoern A. Zeeb if (ret) { 89590aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to setup chip information\n"); 89690aac0d8SBjoern A. Zeeb goto err_destroy_rxwq; 89790aac0d8SBjoern A. Zeeb } 89890aac0d8SBjoern A. Zeeb 89990aac0d8SBjoern A. Zeeb ret = rtw_register_hw(rtwdev, rtwdev->hw); 90090aac0d8SBjoern A. Zeeb if (ret) { 90190aac0d8SBjoern A. Zeeb rtw_err(rtwdev, "failed to register hw\n"); 90290aac0d8SBjoern A. Zeeb goto err_destroy_rxwq; 90390aac0d8SBjoern A. Zeeb } 90490aac0d8SBjoern A. Zeeb 905*11c53278SBjoern A. Zeeb rtw_usb_setup_rx(rtwdev); 906*11c53278SBjoern A. Zeeb 90790aac0d8SBjoern A. Zeeb return 0; 90890aac0d8SBjoern A. Zeeb 90990aac0d8SBjoern A. Zeeb err_destroy_rxwq: 91090aac0d8SBjoern A. Zeeb rtw_usb_deinit_rx(rtwdev); 91190aac0d8SBjoern A. Zeeb 91290aac0d8SBjoern A. Zeeb err_destroy_txwq: 91390aac0d8SBjoern A. Zeeb rtw_usb_deinit_tx(rtwdev); 91490aac0d8SBjoern A. Zeeb 91590aac0d8SBjoern A. Zeeb err_destroy_usb: 91690aac0d8SBjoern A. Zeeb rtw_usb_intf_deinit(rtwdev, intf); 91790aac0d8SBjoern A. Zeeb 91890aac0d8SBjoern A. Zeeb err_deinit_core: 91990aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 92090aac0d8SBjoern A. Zeeb 921*11c53278SBjoern A. Zeeb err_free_rx_bufs: 922*11c53278SBjoern A. Zeeb rtw_usb_free_rx_bufs(rtwusb); 923*11c53278SBjoern A. Zeeb 92490aac0d8SBjoern A. Zeeb err_release_hw: 92590aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 92690aac0d8SBjoern A. Zeeb 92790aac0d8SBjoern A. Zeeb return ret; 92890aac0d8SBjoern A. Zeeb } 92990aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_probe); 93090aac0d8SBjoern A. Zeeb 93190aac0d8SBjoern A. Zeeb void rtw_usb_disconnect(struct usb_interface *intf) 93290aac0d8SBjoern A. Zeeb { 93390aac0d8SBjoern A. Zeeb struct ieee80211_hw *hw = usb_get_intfdata(intf); 93490aac0d8SBjoern A. Zeeb struct rtw_dev *rtwdev; 93590aac0d8SBjoern A. Zeeb struct rtw_usb *rtwusb; 93690aac0d8SBjoern A. Zeeb 93790aac0d8SBjoern A. Zeeb if (!hw) 93890aac0d8SBjoern A. Zeeb return; 93990aac0d8SBjoern A. Zeeb 94090aac0d8SBjoern A. Zeeb rtwdev = hw->priv; 94190aac0d8SBjoern A. Zeeb rtwusb = rtw_get_usb_priv(rtwdev); 94290aac0d8SBjoern A. Zeeb 94390aac0d8SBjoern A. Zeeb rtw_usb_cancel_rx_bufs(rtwusb); 94490aac0d8SBjoern A. Zeeb 94590aac0d8SBjoern A. Zeeb rtw_unregister_hw(rtwdev, hw); 94690aac0d8SBjoern A. Zeeb rtw_usb_deinit_tx(rtwdev); 94790aac0d8SBjoern A. Zeeb rtw_usb_deinit_rx(rtwdev); 94890aac0d8SBjoern A. Zeeb 94990aac0d8SBjoern A. Zeeb if (rtwusb->udev->state != USB_STATE_NOTATTACHED) 95090aac0d8SBjoern A. Zeeb usb_reset_device(rtwusb->udev); 95190aac0d8SBjoern A. Zeeb 95290aac0d8SBjoern A. Zeeb rtw_usb_free_rx_bufs(rtwusb); 95390aac0d8SBjoern A. Zeeb 95490aac0d8SBjoern A. Zeeb rtw_usb_intf_deinit(rtwdev, intf); 95590aac0d8SBjoern A. Zeeb rtw_core_deinit(rtwdev); 95690aac0d8SBjoern A. Zeeb ieee80211_free_hw(hw); 95790aac0d8SBjoern A. Zeeb } 95890aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_disconnect); 95990aac0d8SBjoern A. Zeeb 96090aac0d8SBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation"); 961*11c53278SBjoern A. Zeeb MODULE_DESCRIPTION("Realtek USB 802.11ac wireless driver"); 96290aac0d8SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL"); 96390aac0d8SBjoern A. Zeeb #if defined(__FreeBSD__) 96490aac0d8SBjoern A. Zeeb MODULE_VERSION(rtw88_usb, 1); 96590aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, rtw88_core, 1, 1, 1); 96690aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi, 1, 1, 1); 96790aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi_wlan, 1, 1, 1); 96890aac0d8SBjoern A. Zeeb #endif 969