xref: /freebsd/sys/contrib/dev/rtw88/usb.c (revision 11c53278a8a3e86e14377f09bbaa7bad193d3713)
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