xref: /freebsd/sys/contrib/dev/rtw88/usb.c (revision 90aac0d83bc9645f51ef0c2aeae6f9c0540bb031)
1*90aac0d8SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*90aac0d8SBjoern A. Zeeb /* Copyright(c) 2018-2019  Realtek Corporation
3*90aac0d8SBjoern A. Zeeb  */
4*90aac0d8SBjoern A. Zeeb 
5*90aac0d8SBjoern A. Zeeb #include <linux/module.h>
6*90aac0d8SBjoern A. Zeeb #include <linux/usb.h>
7*90aac0d8SBjoern A. Zeeb #include <linux/mutex.h>
8*90aac0d8SBjoern A. Zeeb #include "main.h"
9*90aac0d8SBjoern A. Zeeb #include "debug.h"
10*90aac0d8SBjoern A. Zeeb #include "reg.h"
11*90aac0d8SBjoern A. Zeeb #include "tx.h"
12*90aac0d8SBjoern A. Zeeb #include "rx.h"
13*90aac0d8SBjoern A. Zeeb #include "fw.h"
14*90aac0d8SBjoern A. Zeeb #include "ps.h"
15*90aac0d8SBjoern A. Zeeb #include "usb.h"
16*90aac0d8SBjoern A. Zeeb 
17*90aac0d8SBjoern A. Zeeb #define RTW_USB_MAX_RXQ_LEN	512
18*90aac0d8SBjoern A. Zeeb 
19*90aac0d8SBjoern A. Zeeb struct rtw_usb_txcb {
20*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev;
21*90aac0d8SBjoern A. Zeeb 	struct sk_buff_head tx_ack_queue;
22*90aac0d8SBjoern A. Zeeb };
23*90aac0d8SBjoern A. Zeeb 
24*90aac0d8SBjoern A. Zeeb static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb,
25*90aac0d8SBjoern A. Zeeb 				     struct sk_buff *skb, int agg_num)
26*90aac0d8SBjoern A. Zeeb {
27*90aac0d8SBjoern A. Zeeb 	struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data;
28*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = rtwusb->rtwdev;
29*90aac0d8SBjoern A. Zeeb 	struct rtw_tx_pkt_info pkt_info;
30*90aac0d8SBjoern A. Zeeb 
31*90aac0d8SBjoern A. Zeeb 	le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM);
32*90aac0d8SBjoern A. Zeeb 	pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET);
33*90aac0d8SBjoern A. Zeeb 	rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data);
34*90aac0d8SBjoern A. Zeeb }
35*90aac0d8SBjoern A. Zeeb 
36*90aac0d8SBjoern A. Zeeb static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len)
37*90aac0d8SBjoern A. Zeeb {
38*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
39*90aac0d8SBjoern A. Zeeb 	struct usb_device *udev = rtwusb->udev;
40*90aac0d8SBjoern A. Zeeb 	__le32 *data;
41*90aac0d8SBjoern A. Zeeb 	unsigned long flags;
42*90aac0d8SBjoern A. Zeeb 	int idx, ret;
43*90aac0d8SBjoern A. Zeeb 	static int count;
44*90aac0d8SBjoern A. Zeeb 
45*90aac0d8SBjoern A. Zeeb 	spin_lock_irqsave(&rtwusb->usb_lock, flags);
46*90aac0d8SBjoern A. Zeeb 
47*90aac0d8SBjoern A. Zeeb 	idx = rtwusb->usb_data_index;
48*90aac0d8SBjoern A. Zeeb 	rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
49*90aac0d8SBjoern A. Zeeb 
50*90aac0d8SBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
51*90aac0d8SBjoern A. Zeeb 
52*90aac0d8SBjoern A. Zeeb 	data = &rtwusb->usb_data[idx];
53*90aac0d8SBjoern A. Zeeb 
54*90aac0d8SBjoern A. Zeeb 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
55*90aac0d8SBjoern A. Zeeb 			      RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr,
56*90aac0d8SBjoern A. Zeeb 			      RTW_USB_VENQT_CMD_IDX, data, len, 1000);
57*90aac0d8SBjoern A. Zeeb 	if (ret < 0 && ret != -ENODEV && count++ < 4)
58*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "read register 0x%x failed with %d\n",
59*90aac0d8SBjoern A. Zeeb 			addr, ret);
60*90aac0d8SBjoern A. Zeeb 
61*90aac0d8SBjoern A. Zeeb 	return le32_to_cpu(*data);
62*90aac0d8SBjoern A. Zeeb }
63*90aac0d8SBjoern A. Zeeb 
64*90aac0d8SBjoern A. Zeeb static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr)
65*90aac0d8SBjoern A. Zeeb {
66*90aac0d8SBjoern A. Zeeb 	return (u8)rtw_usb_read(rtwdev, addr, 1);
67*90aac0d8SBjoern A. Zeeb }
68*90aac0d8SBjoern A. Zeeb 
69*90aac0d8SBjoern A. Zeeb static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr)
70*90aac0d8SBjoern A. Zeeb {
71*90aac0d8SBjoern A. Zeeb 	return (u16)rtw_usb_read(rtwdev, addr, 2);
72*90aac0d8SBjoern A. Zeeb }
73*90aac0d8SBjoern A. Zeeb 
74*90aac0d8SBjoern A. Zeeb static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr)
75*90aac0d8SBjoern A. Zeeb {
76*90aac0d8SBjoern A. Zeeb 	return (u32)rtw_usb_read(rtwdev, addr, 4);
77*90aac0d8SBjoern A. Zeeb }
78*90aac0d8SBjoern A. Zeeb 
79*90aac0d8SBjoern A. Zeeb static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len)
80*90aac0d8SBjoern A. Zeeb {
81*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv;
82*90aac0d8SBjoern A. Zeeb 	struct usb_device *udev = rtwusb->udev;
83*90aac0d8SBjoern A. Zeeb 	unsigned long flags;
84*90aac0d8SBjoern A. Zeeb 	__le32 *data;
85*90aac0d8SBjoern A. Zeeb 	int idx, ret;
86*90aac0d8SBjoern A. Zeeb 	static int count;
87*90aac0d8SBjoern A. Zeeb 
88*90aac0d8SBjoern A. Zeeb 	spin_lock_irqsave(&rtwusb->usb_lock, flags);
89*90aac0d8SBjoern A. Zeeb 
90*90aac0d8SBjoern A. Zeeb 	idx = rtwusb->usb_data_index;
91*90aac0d8SBjoern A. Zeeb 	rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1);
92*90aac0d8SBjoern A. Zeeb 
93*90aac0d8SBjoern A. Zeeb 	spin_unlock_irqrestore(&rtwusb->usb_lock, flags);
94*90aac0d8SBjoern A. Zeeb 
95*90aac0d8SBjoern A. Zeeb 	data = &rtwusb->usb_data[idx];
96*90aac0d8SBjoern A. Zeeb 
97*90aac0d8SBjoern A. Zeeb 	*data = cpu_to_le32(val);
98*90aac0d8SBjoern A. Zeeb 
99*90aac0d8SBjoern A. Zeeb 	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
100*90aac0d8SBjoern A. Zeeb 			      RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE,
101*90aac0d8SBjoern A. Zeeb 			      addr, 0, data, len, 30000);
102*90aac0d8SBjoern A. Zeeb 	if (ret < 0 && ret != -ENODEV && count++ < 4)
103*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "write register 0x%x failed with %d\n",
104*90aac0d8SBjoern A. Zeeb 			addr, ret);
105*90aac0d8SBjoern A. Zeeb }
106*90aac0d8SBjoern A. Zeeb 
107*90aac0d8SBjoern A. Zeeb static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val)
108*90aac0d8SBjoern A. Zeeb {
109*90aac0d8SBjoern A. Zeeb 	rtw_usb_write(rtwdev, addr, val, 1);
110*90aac0d8SBjoern A. Zeeb }
111*90aac0d8SBjoern A. Zeeb 
112*90aac0d8SBjoern A. Zeeb static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val)
113*90aac0d8SBjoern A. Zeeb {
114*90aac0d8SBjoern A. Zeeb 	rtw_usb_write(rtwdev, addr, val, 2);
115*90aac0d8SBjoern A. Zeeb }
116*90aac0d8SBjoern A. Zeeb 
117*90aac0d8SBjoern A. Zeeb static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val)
118*90aac0d8SBjoern A. Zeeb {
119*90aac0d8SBjoern A. Zeeb 	rtw_usb_write(rtwdev, addr, val, 4);
120*90aac0d8SBjoern A. Zeeb }
121*90aac0d8SBjoern A. Zeeb 
122*90aac0d8SBjoern A. Zeeb static int dma_mapping_to_ep(enum rtw_dma_mapping dma_mapping)
123*90aac0d8SBjoern A. Zeeb {
124*90aac0d8SBjoern A. Zeeb 	switch (dma_mapping) {
125*90aac0d8SBjoern A. Zeeb 	case RTW_DMA_MAPPING_HIGH:
126*90aac0d8SBjoern A. Zeeb 		return 0;
127*90aac0d8SBjoern A. Zeeb 	case RTW_DMA_MAPPING_NORMAL:
128*90aac0d8SBjoern A. Zeeb 		return 1;
129*90aac0d8SBjoern A. Zeeb 	case RTW_DMA_MAPPING_LOW:
130*90aac0d8SBjoern A. Zeeb 		return 2;
131*90aac0d8SBjoern A. Zeeb 	case RTW_DMA_MAPPING_EXTRA:
132*90aac0d8SBjoern A. Zeeb 		return 3;
133*90aac0d8SBjoern A. Zeeb 	default:
134*90aac0d8SBjoern A. Zeeb 		return -EINVAL;
135*90aac0d8SBjoern A. Zeeb 	}
136*90aac0d8SBjoern A. Zeeb }
137*90aac0d8SBjoern A. Zeeb 
138*90aac0d8SBjoern A. Zeeb static int rtw_usb_parse(struct rtw_dev *rtwdev,
139*90aac0d8SBjoern A. Zeeb 			 struct usb_interface *interface)
140*90aac0d8SBjoern A. Zeeb {
141*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
142*90aac0d8SBjoern A. Zeeb 	struct usb_host_interface *host_interface = &interface->altsetting[0];
143*90aac0d8SBjoern A. Zeeb 	struct usb_interface_descriptor *interface_desc = &host_interface->desc;
144*90aac0d8SBjoern A. Zeeb 	struct usb_endpoint_descriptor *endpoint;
145*90aac0d8SBjoern A. Zeeb 	int num_out_pipes = 0;
146*90aac0d8SBjoern A. Zeeb 	int i;
147*90aac0d8SBjoern A. Zeeb 	u8 num;
148*90aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
149*90aac0d8SBjoern A. Zeeb 	const struct rtw_rqpn *rqpn;
150*90aac0d8SBjoern A. Zeeb 
151*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < interface_desc->bNumEndpoints; i++) {
152*90aac0d8SBjoern A. Zeeb 		endpoint = &host_interface->endpoint[i].desc;
153*90aac0d8SBjoern A. Zeeb 		num = usb_endpoint_num(endpoint);
154*90aac0d8SBjoern A. Zeeb 
155*90aac0d8SBjoern A. Zeeb 		if (usb_endpoint_dir_in(endpoint) &&
156*90aac0d8SBjoern A. Zeeb 		    usb_endpoint_xfer_bulk(endpoint)) {
157*90aac0d8SBjoern A. Zeeb 			if (rtwusb->pipe_in) {
158*90aac0d8SBjoern A. Zeeb 				rtw_err(rtwdev, "IN pipes overflow\n");
159*90aac0d8SBjoern A. Zeeb 				return -EINVAL;
160*90aac0d8SBjoern A. Zeeb 			}
161*90aac0d8SBjoern A. Zeeb 
162*90aac0d8SBjoern A. Zeeb 			rtwusb->pipe_in = num;
163*90aac0d8SBjoern A. Zeeb 		}
164*90aac0d8SBjoern A. Zeeb 
165*90aac0d8SBjoern A. Zeeb 		if (usb_endpoint_dir_in(endpoint) &&
166*90aac0d8SBjoern A. Zeeb 		    usb_endpoint_xfer_int(endpoint)) {
167*90aac0d8SBjoern A. Zeeb 			if (rtwusb->pipe_interrupt) {
168*90aac0d8SBjoern A. Zeeb 				rtw_err(rtwdev, "INT pipes overflow\n");
169*90aac0d8SBjoern A. Zeeb 				return -EINVAL;
170*90aac0d8SBjoern A. Zeeb 			}
171*90aac0d8SBjoern A. Zeeb 
172*90aac0d8SBjoern A. Zeeb 			rtwusb->pipe_interrupt = num;
173*90aac0d8SBjoern A. Zeeb 		}
174*90aac0d8SBjoern A. Zeeb 
175*90aac0d8SBjoern A. Zeeb 		if (usb_endpoint_dir_out(endpoint) &&
176*90aac0d8SBjoern A. Zeeb 		    usb_endpoint_xfer_bulk(endpoint)) {
177*90aac0d8SBjoern A. Zeeb 			if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) {
178*90aac0d8SBjoern A. Zeeb 				rtw_err(rtwdev, "OUT pipes overflow\n");
179*90aac0d8SBjoern A. Zeeb 				return -EINVAL;
180*90aac0d8SBjoern A. Zeeb 			}
181*90aac0d8SBjoern A. Zeeb 
182*90aac0d8SBjoern A. Zeeb 			rtwusb->out_ep[num_out_pipes++] = num;
183*90aac0d8SBjoern A. Zeeb 		}
184*90aac0d8SBjoern A. Zeeb 	}
185*90aac0d8SBjoern A. Zeeb 
186*90aac0d8SBjoern A. Zeeb 	rtwdev->hci.bulkout_num = num_out_pipes;
187*90aac0d8SBjoern A. Zeeb 
188*90aac0d8SBjoern A. Zeeb 	if (num_out_pipes < 1 || num_out_pipes > 4) {
189*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "invalid number of endpoints %d\n", num_out_pipes);
190*90aac0d8SBjoern A. Zeeb 		return -EINVAL;
191*90aac0d8SBjoern A. Zeeb 	}
192*90aac0d8SBjoern A. Zeeb 
193*90aac0d8SBjoern A. Zeeb 	rqpn = &chip->rqpn_table[num_out_pipes];
194*90aac0d8SBjoern A. Zeeb 
195*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = dma_mapping_to_ep(rqpn->dma_map_be);
196*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = dma_mapping_to_ep(rqpn->dma_map_bk);
197*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = dma_mapping_to_ep(rqpn->dma_map_bk);
198*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = dma_mapping_to_ep(rqpn->dma_map_be);
199*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = dma_mapping_to_ep(rqpn->dma_map_vi);
200*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = dma_mapping_to_ep(rqpn->dma_map_vi);
201*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = dma_mapping_to_ep(rqpn->dma_map_vo);
202*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = dma_mapping_to_ep(rqpn->dma_map_vo);
203*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID8] = -EINVAL;
204*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID9] = -EINVAL;
205*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID10] = -EINVAL;
206*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID11] = -EINVAL;
207*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID12] = -EINVAL;
208*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID13] = -EINVAL;
209*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID14] = -EINVAL;
210*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_TID15] = -EINVAL;
211*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_BEACON] = dma_mapping_to_ep(rqpn->dma_map_hi);
212*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_HIGH] = dma_mapping_to_ep(rqpn->dma_map_hi);
213*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_MGMT] = dma_mapping_to_ep(rqpn->dma_map_mg);
214*90aac0d8SBjoern A. Zeeb 	rtwusb->qsel_to_ep[TX_DESC_QSEL_H2C] = dma_mapping_to_ep(rqpn->dma_map_hi);
215*90aac0d8SBjoern A. Zeeb 
216*90aac0d8SBjoern A. Zeeb 	return 0;
217*90aac0d8SBjoern A. Zeeb }
218*90aac0d8SBjoern A. Zeeb 
219*90aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_tx_complete(struct urb *urb)
220*90aac0d8SBjoern A. Zeeb {
221*90aac0d8SBjoern A. Zeeb 	struct rtw_usb_txcb *txcb = urb->context;
222*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = txcb->rtwdev;
223*90aac0d8SBjoern A. Zeeb 	struct ieee80211_hw *hw = rtwdev->hw;
224*90aac0d8SBjoern A. Zeeb 
225*90aac0d8SBjoern A. Zeeb 	while (true) {
226*90aac0d8SBjoern A. Zeeb 		struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue);
227*90aac0d8SBjoern A. Zeeb 		struct ieee80211_tx_info *info;
228*90aac0d8SBjoern A. Zeeb 		struct rtw_usb_tx_data *tx_data;
229*90aac0d8SBjoern A. Zeeb 
230*90aac0d8SBjoern A. Zeeb 		if (!skb)
231*90aac0d8SBjoern A. Zeeb 			break;
232*90aac0d8SBjoern A. Zeeb 
233*90aac0d8SBjoern A. Zeeb 		info = IEEE80211_SKB_CB(skb);
234*90aac0d8SBjoern A. Zeeb 		tx_data = rtw_usb_get_tx_data(skb);
235*90aac0d8SBjoern A. Zeeb 
236*90aac0d8SBjoern A. Zeeb 		/* enqueue to wait for tx report */
237*90aac0d8SBjoern A. Zeeb 		if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
238*90aac0d8SBjoern A. Zeeb 			rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn);
239*90aac0d8SBjoern A. Zeeb 			continue;
240*90aac0d8SBjoern A. Zeeb 		}
241*90aac0d8SBjoern A. Zeeb 
242*90aac0d8SBjoern A. Zeeb 		/* always ACK for others, then they won't be marked as drop */
243*90aac0d8SBjoern A. Zeeb 		ieee80211_tx_info_clear_status(info);
244*90aac0d8SBjoern A. Zeeb 		if (info->flags & IEEE80211_TX_CTL_NO_ACK)
245*90aac0d8SBjoern A. Zeeb 			info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
246*90aac0d8SBjoern A. Zeeb 		else
247*90aac0d8SBjoern A. Zeeb 			info->flags |= IEEE80211_TX_STAT_ACK;
248*90aac0d8SBjoern A. Zeeb 
249*90aac0d8SBjoern A. Zeeb 		ieee80211_tx_status_irqsafe(hw, skb);
250*90aac0d8SBjoern A. Zeeb 	}
251*90aac0d8SBjoern A. Zeeb 
252*90aac0d8SBjoern A. Zeeb 	kfree(txcb);
253*90aac0d8SBjoern A. Zeeb }
254*90aac0d8SBjoern A. Zeeb 
255*90aac0d8SBjoern A. Zeeb static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel)
256*90aac0d8SBjoern A. Zeeb {
257*90aac0d8SBjoern A. Zeeb 	if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep))
258*90aac0d8SBjoern A. Zeeb 		return -EINVAL;
259*90aac0d8SBjoern A. Zeeb 
260*90aac0d8SBjoern A. Zeeb 	return rtwusb->qsel_to_ep[qsel];
261*90aac0d8SBjoern A. Zeeb }
262*90aac0d8SBjoern A. Zeeb 
263*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb,
264*90aac0d8SBjoern A. Zeeb 			      usb_complete_t cb, void *context)
265*90aac0d8SBjoern A. Zeeb {
266*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
267*90aac0d8SBjoern A. Zeeb 	struct usb_device *usbd = rtwusb->udev;
268*90aac0d8SBjoern A. Zeeb 	struct urb *urb;
269*90aac0d8SBjoern A. Zeeb 	unsigned int pipe;
270*90aac0d8SBjoern A. Zeeb 	int ret;
271*90aac0d8SBjoern A. Zeeb 	int ep = qsel_to_ep(rtwusb, qsel);
272*90aac0d8SBjoern A. Zeeb 
273*90aac0d8SBjoern A. Zeeb 	if (ep < 0)
274*90aac0d8SBjoern A. Zeeb 		return ep;
275*90aac0d8SBjoern A. Zeeb 
276*90aac0d8SBjoern A. Zeeb 	pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]);
277*90aac0d8SBjoern A. Zeeb 	urb = usb_alloc_urb(0, GFP_ATOMIC);
278*90aac0d8SBjoern A. Zeeb 	if (!urb)
279*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
280*90aac0d8SBjoern A. Zeeb 
281*90aac0d8SBjoern A. Zeeb 	usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context);
282*90aac0d8SBjoern A. Zeeb 	urb->transfer_flags |= URB_ZERO_PACKET;
283*90aac0d8SBjoern A. Zeeb 	ret = usb_submit_urb(urb, GFP_ATOMIC);
284*90aac0d8SBjoern A. Zeeb 
285*90aac0d8SBjoern A. Zeeb 	usb_free_urb(urb);
286*90aac0d8SBjoern A. Zeeb 
287*90aac0d8SBjoern A. Zeeb 	return ret;
288*90aac0d8SBjoern A. Zeeb }
289*90aac0d8SBjoern A. Zeeb 
290*90aac0d8SBjoern A. Zeeb static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list)
291*90aac0d8SBjoern A. Zeeb {
292*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = rtwusb->rtwdev;
293*90aac0d8SBjoern A. Zeeb 	struct rtw_tx_desc *tx_desc;
294*90aac0d8SBjoern A. Zeeb 	struct rtw_usb_txcb *txcb;
295*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb_head;
296*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb_iter;
297*90aac0d8SBjoern A. Zeeb 	int agg_num = 0;
298*90aac0d8SBjoern A. Zeeb 	unsigned int align_next = 0;
299*90aac0d8SBjoern A. Zeeb 	u8 qsel;
300*90aac0d8SBjoern A. Zeeb 
301*90aac0d8SBjoern A. Zeeb 	if (skb_queue_empty(list))
302*90aac0d8SBjoern A. Zeeb 		return false;
303*90aac0d8SBjoern A. Zeeb 
304*90aac0d8SBjoern A. Zeeb 	txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC);
305*90aac0d8SBjoern A. Zeeb 	if (!txcb)
306*90aac0d8SBjoern A. Zeeb 		return false;
307*90aac0d8SBjoern A. Zeeb 
308*90aac0d8SBjoern A. Zeeb 	txcb->rtwdev = rtwdev;
309*90aac0d8SBjoern A. Zeeb 	skb_queue_head_init(&txcb->tx_ack_queue);
310*90aac0d8SBjoern A. Zeeb 
311*90aac0d8SBjoern A. Zeeb 	skb_iter = skb_dequeue(list);
312*90aac0d8SBjoern A. Zeeb 
313*90aac0d8SBjoern A. Zeeb 	if (skb_queue_empty(list)) {
314*90aac0d8SBjoern A. Zeeb 		skb_head = skb_iter;
315*90aac0d8SBjoern A. Zeeb 		goto queue;
316*90aac0d8SBjoern A. Zeeb 	}
317*90aac0d8SBjoern A. Zeeb 
318*90aac0d8SBjoern A. Zeeb 	skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ);
319*90aac0d8SBjoern A. Zeeb 	if (!skb_head) {
320*90aac0d8SBjoern A. Zeeb 		skb_head = skb_iter;
321*90aac0d8SBjoern A. Zeeb 		goto queue;
322*90aac0d8SBjoern A. Zeeb 	}
323*90aac0d8SBjoern A. Zeeb 
324*90aac0d8SBjoern A. Zeeb 	while (skb_iter) {
325*90aac0d8SBjoern A. Zeeb 		unsigned long flags;
326*90aac0d8SBjoern A. Zeeb 
327*90aac0d8SBjoern A. Zeeb 		skb_put(skb_head, align_next);
328*90aac0d8SBjoern A. Zeeb 		skb_put_data(skb_head, skb_iter->data, skb_iter->len);
329*90aac0d8SBjoern A. Zeeb 
330*90aac0d8SBjoern A. Zeeb 		align_next = ALIGN(skb_iter->len, 8) - skb_iter->len;
331*90aac0d8SBjoern A. Zeeb 
332*90aac0d8SBjoern A. Zeeb 		agg_num++;
333*90aac0d8SBjoern A. Zeeb 
334*90aac0d8SBjoern A. Zeeb 		skb_queue_tail(&txcb->tx_ack_queue, skb_iter);
335*90aac0d8SBjoern A. Zeeb 
336*90aac0d8SBjoern A. Zeeb 		spin_lock_irqsave(&list->lock, flags);
337*90aac0d8SBjoern A. Zeeb 
338*90aac0d8SBjoern A. Zeeb 		skb_iter = skb_peek(list);
339*90aac0d8SBjoern A. Zeeb 
340*90aac0d8SBjoern A. Zeeb 		if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ)
341*90aac0d8SBjoern A. Zeeb 			__skb_unlink(skb_iter, list);
342*90aac0d8SBjoern A. Zeeb 		else
343*90aac0d8SBjoern A. Zeeb 			skb_iter = NULL;
344*90aac0d8SBjoern A. Zeeb 		spin_unlock_irqrestore(&list->lock, flags);
345*90aac0d8SBjoern A. Zeeb 	}
346*90aac0d8SBjoern A. Zeeb 
347*90aac0d8SBjoern A. Zeeb 	if (agg_num > 1)
348*90aac0d8SBjoern A. Zeeb 		rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num);
349*90aac0d8SBjoern A. Zeeb 
350*90aac0d8SBjoern A. Zeeb queue:
351*90aac0d8SBjoern A. Zeeb 	skb_queue_tail(&txcb->tx_ack_queue, skb_head);
352*90aac0d8SBjoern A. Zeeb 	tx_desc = (struct rtw_tx_desc *)skb_head->data;
353*90aac0d8SBjoern A. Zeeb 	qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL);
354*90aac0d8SBjoern A. Zeeb 
355*90aac0d8SBjoern A. Zeeb 	rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb);
356*90aac0d8SBjoern A. Zeeb 
357*90aac0d8SBjoern A. Zeeb 	return true;
358*90aac0d8SBjoern A. Zeeb }
359*90aac0d8SBjoern A. Zeeb 
360*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_handler(struct work_struct *work)
361*90aac0d8SBjoern A. Zeeb {
362*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work);
363*90aac0d8SBjoern A. Zeeb 	int i, limit;
364*90aac0d8SBjoern A. Zeeb 
365*90aac0d8SBjoern A. Zeeb 	for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) {
366*90aac0d8SBjoern A. Zeeb 		for (limit = 0; limit < 200; limit++) {
367*90aac0d8SBjoern A. Zeeb 			struct sk_buff_head *list = &rtwusb->tx_queue[i];
368*90aac0d8SBjoern A. Zeeb 
369*90aac0d8SBjoern A. Zeeb 			if (!rtw_usb_tx_agg_skb(rtwusb, list))
370*90aac0d8SBjoern A. Zeeb 				break;
371*90aac0d8SBjoern A. Zeeb 		}
372*90aac0d8SBjoern A. Zeeb 	}
373*90aac0d8SBjoern A. Zeeb }
374*90aac0d8SBjoern A. Zeeb 
375*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb)
376*90aac0d8SBjoern A. Zeeb {
377*90aac0d8SBjoern A. Zeeb 	int i;
378*90aac0d8SBjoern A. Zeeb 
379*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
380*90aac0d8SBjoern A. Zeeb 		skb_queue_purge(&rtwusb->tx_queue[i]);
381*90aac0d8SBjoern A. Zeeb }
382*90aac0d8SBjoern A. Zeeb 
383*90aac0d8SBjoern A. Zeeb static void rtw_usb_write_port_complete(struct urb *urb)
384*90aac0d8SBjoern A. Zeeb {
385*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb = urb->context;
386*90aac0d8SBjoern A. Zeeb 
387*90aac0d8SBjoern A. Zeeb 	dev_kfree_skb_any(skb);
388*90aac0d8SBjoern A. Zeeb }
389*90aac0d8SBjoern A. Zeeb 
390*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data(struct rtw_dev *rtwdev,
391*90aac0d8SBjoern A. Zeeb 			      struct rtw_tx_pkt_info *pkt_info,
392*90aac0d8SBjoern A. Zeeb 			      u8 *buf)
393*90aac0d8SBjoern A. Zeeb {
394*90aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
395*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb;
396*90aac0d8SBjoern A. Zeeb 	unsigned int desclen, headsize, size;
397*90aac0d8SBjoern A. Zeeb 	u8 qsel;
398*90aac0d8SBjoern A. Zeeb 	int ret = 0;
399*90aac0d8SBjoern A. Zeeb 
400*90aac0d8SBjoern A. Zeeb 	size = pkt_info->tx_pkt_size;
401*90aac0d8SBjoern A. Zeeb 	qsel = pkt_info->qsel;
402*90aac0d8SBjoern A. Zeeb 	desclen = chip->tx_pkt_desc_sz;
403*90aac0d8SBjoern A. Zeeb 	headsize = pkt_info->offset ? pkt_info->offset : desclen;
404*90aac0d8SBjoern A. Zeeb 
405*90aac0d8SBjoern A. Zeeb 	skb = dev_alloc_skb(headsize + size);
406*90aac0d8SBjoern A. Zeeb 	if (unlikely(!skb))
407*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
408*90aac0d8SBjoern A. Zeeb 
409*90aac0d8SBjoern A. Zeeb 	skb_reserve(skb, headsize);
410*90aac0d8SBjoern A. Zeeb 	skb_put_data(skb, buf, size);
411*90aac0d8SBjoern A. Zeeb 	skb_push(skb, headsize);
412*90aac0d8SBjoern A. Zeeb 	memset(skb->data, 0, headsize);
413*90aac0d8SBjoern A. Zeeb 	rtw_tx_fill_tx_desc(pkt_info, skb);
414*90aac0d8SBjoern A. Zeeb 	rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
415*90aac0d8SBjoern A. Zeeb 
416*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_write_port(rtwdev, qsel, skb,
417*90aac0d8SBjoern A. Zeeb 				 rtw_usb_write_port_complete, skb);
418*90aac0d8SBjoern A. Zeeb 	if (unlikely(ret))
419*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
420*90aac0d8SBjoern A. Zeeb 
421*90aac0d8SBjoern A. Zeeb 	return ret;
422*90aac0d8SBjoern A. Zeeb }
423*90aac0d8SBjoern A. Zeeb 
424*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf,
425*90aac0d8SBjoern A. Zeeb 					u32 size)
426*90aac0d8SBjoern A. Zeeb {
427*90aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
428*90aac0d8SBjoern A. Zeeb 	struct rtw_tx_pkt_info pkt_info = {0};
429*90aac0d8SBjoern A. Zeeb 
430*90aac0d8SBjoern A. Zeeb 	pkt_info.tx_pkt_size = size;
431*90aac0d8SBjoern A. Zeeb 	pkt_info.qsel = TX_DESC_QSEL_BEACON;
432*90aac0d8SBjoern A. Zeeb 	pkt_info.offset = chip->tx_pkt_desc_sz;
433*90aac0d8SBjoern A. Zeeb 
434*90aac0d8SBjoern A. Zeeb 	return rtw_usb_write_data(rtwdev, &pkt_info, buf);
435*90aac0d8SBjoern A. Zeeb }
436*90aac0d8SBjoern A. Zeeb 
437*90aac0d8SBjoern A. Zeeb static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size)
438*90aac0d8SBjoern A. Zeeb {
439*90aac0d8SBjoern A. Zeeb 	struct rtw_tx_pkt_info pkt_info = {0};
440*90aac0d8SBjoern A. Zeeb 
441*90aac0d8SBjoern A. Zeeb 	pkt_info.tx_pkt_size = size;
442*90aac0d8SBjoern A. Zeeb 	pkt_info.qsel = TX_DESC_QSEL_H2C;
443*90aac0d8SBjoern A. Zeeb 
444*90aac0d8SBjoern A. Zeeb 	return rtw_usb_write_data(rtwdev, &pkt_info, buf);
445*90aac0d8SBjoern A. Zeeb }
446*90aac0d8SBjoern A. Zeeb 
447*90aac0d8SBjoern A. Zeeb static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb)
448*90aac0d8SBjoern A. Zeeb {
449*90aac0d8SBjoern A. Zeeb 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
450*90aac0d8SBjoern A. Zeeb 	__le16 fc = hdr->frame_control;
451*90aac0d8SBjoern A. Zeeb 	u8 qsel;
452*90aac0d8SBjoern A. Zeeb 
453*90aac0d8SBjoern A. Zeeb 	if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)))
454*90aac0d8SBjoern A. Zeeb 		qsel = TX_DESC_QSEL_MGMT;
455*90aac0d8SBjoern A. Zeeb 	else if (is_broadcast_ether_addr(hdr->addr1) ||
456*90aac0d8SBjoern A. Zeeb 		 is_multicast_ether_addr(hdr->addr1))
457*90aac0d8SBjoern A. Zeeb 		qsel = TX_DESC_QSEL_HIGH;
458*90aac0d8SBjoern A. Zeeb 	else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK)
459*90aac0d8SBjoern A. Zeeb 		qsel = skb->priority;
460*90aac0d8SBjoern A. Zeeb 	else
461*90aac0d8SBjoern A. Zeeb 		qsel = TX_DESC_QSEL_BEACON;
462*90aac0d8SBjoern A. Zeeb 
463*90aac0d8SBjoern A. Zeeb 	return qsel;
464*90aac0d8SBjoern A. Zeeb }
465*90aac0d8SBjoern A. Zeeb 
466*90aac0d8SBjoern A. Zeeb static int rtw_usb_tx_write(struct rtw_dev *rtwdev,
467*90aac0d8SBjoern A. Zeeb 			    struct rtw_tx_pkt_info *pkt_info,
468*90aac0d8SBjoern A. Zeeb 			    struct sk_buff *skb)
469*90aac0d8SBjoern A. Zeeb {
470*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
471*90aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
472*90aac0d8SBjoern A. Zeeb 	struct rtw_usb_tx_data *tx_data;
473*90aac0d8SBjoern A. Zeeb 	u8 *pkt_desc;
474*90aac0d8SBjoern A. Zeeb 	int ep;
475*90aac0d8SBjoern A. Zeeb 
476*90aac0d8SBjoern A. Zeeb 	pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb);
477*90aac0d8SBjoern A. Zeeb 	pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz);
478*90aac0d8SBjoern A. Zeeb 	memset(pkt_desc, 0, chip->tx_pkt_desc_sz);
479*90aac0d8SBjoern A. Zeeb 	ep = qsel_to_ep(rtwusb, pkt_info->qsel);
480*90aac0d8SBjoern A. Zeeb 	rtw_tx_fill_tx_desc(pkt_info, skb);
481*90aac0d8SBjoern A. Zeeb 	rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data);
482*90aac0d8SBjoern A. Zeeb 	tx_data = rtw_usb_get_tx_data(skb);
483*90aac0d8SBjoern A. Zeeb 	tx_data->sn = pkt_info->sn;
484*90aac0d8SBjoern A. Zeeb 
485*90aac0d8SBjoern A. Zeeb 	skb_queue_tail(&rtwusb->tx_queue[ep], skb);
486*90aac0d8SBjoern A. Zeeb 
487*90aac0d8SBjoern A. Zeeb 	return 0;
488*90aac0d8SBjoern A. Zeeb }
489*90aac0d8SBjoern A. Zeeb 
490*90aac0d8SBjoern A. Zeeb static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev)
491*90aac0d8SBjoern A. Zeeb {
492*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
493*90aac0d8SBjoern A. Zeeb 
494*90aac0d8SBjoern A. Zeeb 	queue_work(rtwusb->txwq, &rtwusb->tx_work);
495*90aac0d8SBjoern A. Zeeb }
496*90aac0d8SBjoern A. Zeeb 
497*90aac0d8SBjoern A. Zeeb static void rtw_usb_rx_handler(struct work_struct *work)
498*90aac0d8SBjoern A. Zeeb {
499*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work);
500*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = rtwusb->rtwdev;
501*90aac0d8SBjoern A. Zeeb 	const struct rtw_chip_info *chip = rtwdev->chip;
502*90aac0d8SBjoern A. Zeeb 	struct rtw_rx_pkt_stat pkt_stat;
503*90aac0d8SBjoern A. Zeeb 	struct ieee80211_rx_status rx_status;
504*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb;
505*90aac0d8SBjoern A. Zeeb 	u32 pkt_desc_sz = chip->rx_pkt_desc_sz;
506*90aac0d8SBjoern A. Zeeb 	u32 pkt_offset;
507*90aac0d8SBjoern A. Zeeb 	u8 *rx_desc;
508*90aac0d8SBjoern A. Zeeb 	int limit;
509*90aac0d8SBjoern A. Zeeb 
510*90aac0d8SBjoern A. Zeeb 	for (limit = 0; limit < 200; limit++) {
511*90aac0d8SBjoern A. Zeeb 		skb = skb_dequeue(&rtwusb->rx_queue);
512*90aac0d8SBjoern A. Zeeb 		if (!skb)
513*90aac0d8SBjoern A. Zeeb 			break;
514*90aac0d8SBjoern A. Zeeb 
515*90aac0d8SBjoern A. Zeeb 		rx_desc = skb->data;
516*90aac0d8SBjoern A. Zeeb 		chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat,
517*90aac0d8SBjoern A. Zeeb 					 &rx_status);
518*90aac0d8SBjoern A. Zeeb 		pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz +
519*90aac0d8SBjoern A. Zeeb 			     pkt_stat.shift;
520*90aac0d8SBjoern A. Zeeb 
521*90aac0d8SBjoern A. Zeeb 		if (pkt_stat.is_c2h) {
522*90aac0d8SBjoern A. Zeeb 			skb_put(skb, pkt_stat.pkt_len + pkt_offset);
523*90aac0d8SBjoern A. Zeeb 			rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb);
524*90aac0d8SBjoern A. Zeeb 			continue;
525*90aac0d8SBjoern A. Zeeb 		}
526*90aac0d8SBjoern A. Zeeb 
527*90aac0d8SBjoern A. Zeeb 		if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) {
528*90aac0d8SBjoern A. Zeeb 			dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n");
529*90aac0d8SBjoern A. Zeeb 			dev_kfree_skb_any(skb);
530*90aac0d8SBjoern A. Zeeb 			continue;
531*90aac0d8SBjoern A. Zeeb 		}
532*90aac0d8SBjoern A. Zeeb 
533*90aac0d8SBjoern A. Zeeb 		skb_put(skb, pkt_stat.pkt_len);
534*90aac0d8SBjoern A. Zeeb 		skb_reserve(skb, pkt_offset);
535*90aac0d8SBjoern A. Zeeb 		memcpy(skb->cb, &rx_status, sizeof(rx_status));
536*90aac0d8SBjoern A. Zeeb 		ieee80211_rx_irqsafe(rtwdev->hw, skb);
537*90aac0d8SBjoern A. Zeeb 	}
538*90aac0d8SBjoern A. Zeeb }
539*90aac0d8SBjoern A. Zeeb 
540*90aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb);
541*90aac0d8SBjoern A. Zeeb 
542*90aac0d8SBjoern A. Zeeb static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb)
543*90aac0d8SBjoern A. Zeeb {
544*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = rtwusb->rtwdev;
545*90aac0d8SBjoern A. Zeeb 	int error;
546*90aac0d8SBjoern A. Zeeb 
547*90aac0d8SBjoern A. Zeeb 	rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC);
548*90aac0d8SBjoern A. Zeeb 	if (!rxcb->rx_skb)
549*90aac0d8SBjoern A. Zeeb 		return;
550*90aac0d8SBjoern A. Zeeb 
551*90aac0d8SBjoern A. Zeeb 	usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev,
552*90aac0d8SBjoern A. Zeeb 			  usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in),
553*90aac0d8SBjoern A. Zeeb 			  rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ,
554*90aac0d8SBjoern A. Zeeb 			  rtw_usb_read_port_complete, rxcb);
555*90aac0d8SBjoern A. Zeeb 
556*90aac0d8SBjoern A. Zeeb 	error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC);
557*90aac0d8SBjoern A. Zeeb 	if (error) {
558*90aac0d8SBjoern A. Zeeb 		kfree_skb(rxcb->rx_skb);
559*90aac0d8SBjoern A. Zeeb 		if (error != -ENODEV)
560*90aac0d8SBjoern A. Zeeb 			rtw_err(rtwdev, "Err sending rx data urb %d\n",
561*90aac0d8SBjoern A. Zeeb 				error);
562*90aac0d8SBjoern A. Zeeb 	}
563*90aac0d8SBjoern A. Zeeb }
564*90aac0d8SBjoern A. Zeeb 
565*90aac0d8SBjoern A. Zeeb static void rtw_usb_read_port_complete(struct urb *urb)
566*90aac0d8SBjoern A. Zeeb {
567*90aac0d8SBjoern A. Zeeb 	struct rx_usb_ctrl_block *rxcb = urb->context;
568*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev = rxcb->rtwdev;
569*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
570*90aac0d8SBjoern A. Zeeb 	struct sk_buff *skb = rxcb->rx_skb;
571*90aac0d8SBjoern A. Zeeb 
572*90aac0d8SBjoern A. Zeeb 	if (urb->status == 0) {
573*90aac0d8SBjoern A. Zeeb 		if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ ||
574*90aac0d8SBjoern A. Zeeb 		    urb->actual_length < 24) {
575*90aac0d8SBjoern A. Zeeb 			rtw_err(rtwdev, "failed to get urb length:%d\n",
576*90aac0d8SBjoern A. Zeeb 				urb->actual_length);
577*90aac0d8SBjoern A. Zeeb 			if (skb)
578*90aac0d8SBjoern A. Zeeb 				dev_kfree_skb_any(skb);
579*90aac0d8SBjoern A. Zeeb 		} else {
580*90aac0d8SBjoern A. Zeeb 			skb_queue_tail(&rtwusb->rx_queue, skb);
581*90aac0d8SBjoern A. Zeeb 			queue_work(rtwusb->rxwq, &rtwusb->rx_work);
582*90aac0d8SBjoern A. Zeeb 		}
583*90aac0d8SBjoern A. Zeeb 		rtw_usb_rx_resubmit(rtwusb, rxcb);
584*90aac0d8SBjoern A. Zeeb 	} else {
585*90aac0d8SBjoern A. Zeeb 		switch (urb->status) {
586*90aac0d8SBjoern A. Zeeb 		case -EINVAL:
587*90aac0d8SBjoern A. Zeeb 		case -EPIPE:
588*90aac0d8SBjoern A. Zeeb 		case -ENODEV:
589*90aac0d8SBjoern A. Zeeb 		case -ESHUTDOWN:
590*90aac0d8SBjoern A. Zeeb 		case -ENOENT:
591*90aac0d8SBjoern A. Zeeb 		case -EPROTO:
592*90aac0d8SBjoern A. Zeeb 		case -EILSEQ:
593*90aac0d8SBjoern A. Zeeb 		case -ETIME:
594*90aac0d8SBjoern A. Zeeb 		case -ECOMM:
595*90aac0d8SBjoern A. Zeeb 		case -EOVERFLOW:
596*90aac0d8SBjoern A. Zeeb 		case -EINPROGRESS:
597*90aac0d8SBjoern A. Zeeb 			break;
598*90aac0d8SBjoern A. Zeeb 		default:
599*90aac0d8SBjoern A. Zeeb 			rtw_err(rtwdev, "status %d\n", urb->status);
600*90aac0d8SBjoern A. Zeeb 			break;
601*90aac0d8SBjoern A. Zeeb 		}
602*90aac0d8SBjoern A. Zeeb 		if (skb)
603*90aac0d8SBjoern A. Zeeb 			dev_kfree_skb_any(skb);
604*90aac0d8SBjoern A. Zeeb 	}
605*90aac0d8SBjoern A. Zeeb }
606*90aac0d8SBjoern A. Zeeb 
607*90aac0d8SBjoern A. Zeeb static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb)
608*90aac0d8SBjoern A. Zeeb {
609*90aac0d8SBjoern A. Zeeb 	struct rx_usb_ctrl_block *rxcb;
610*90aac0d8SBjoern A. Zeeb 	int i;
611*90aac0d8SBjoern A. Zeeb 
612*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
613*90aac0d8SBjoern A. Zeeb 		rxcb = &rtwusb->rx_cb[i];
614*90aac0d8SBjoern A. Zeeb 		if (rxcb->rx_urb)
615*90aac0d8SBjoern A. Zeeb 			usb_kill_urb(rxcb->rx_urb);
616*90aac0d8SBjoern A. Zeeb 	}
617*90aac0d8SBjoern A. Zeeb }
618*90aac0d8SBjoern A. Zeeb 
619*90aac0d8SBjoern A. Zeeb static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb)
620*90aac0d8SBjoern A. Zeeb {
621*90aac0d8SBjoern A. Zeeb 	struct rx_usb_ctrl_block *rxcb;
622*90aac0d8SBjoern A. Zeeb 	int i;
623*90aac0d8SBjoern A. Zeeb 
624*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
625*90aac0d8SBjoern A. Zeeb 		rxcb = &rtwusb->rx_cb[i];
626*90aac0d8SBjoern A. Zeeb 		if (rxcb->rx_urb) {
627*90aac0d8SBjoern A. Zeeb 			usb_kill_urb(rxcb->rx_urb);
628*90aac0d8SBjoern A. Zeeb 			usb_free_urb(rxcb->rx_urb);
629*90aac0d8SBjoern A. Zeeb 		}
630*90aac0d8SBjoern A. Zeeb 	}
631*90aac0d8SBjoern A. Zeeb }
632*90aac0d8SBjoern A. Zeeb 
633*90aac0d8SBjoern A. Zeeb static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb)
634*90aac0d8SBjoern A. Zeeb {
635*90aac0d8SBjoern A. Zeeb 	int i;
636*90aac0d8SBjoern A. Zeeb 
637*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
638*90aac0d8SBjoern A. Zeeb 		struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
639*90aac0d8SBjoern A. Zeeb 
640*90aac0d8SBjoern A. Zeeb 		rxcb->rtwdev = rtwusb->rtwdev;
641*90aac0d8SBjoern A. Zeeb 		rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
642*90aac0d8SBjoern A. Zeeb 		if (!rxcb->rx_urb)
643*90aac0d8SBjoern A. Zeeb 			goto err;
644*90aac0d8SBjoern A. Zeeb 	}
645*90aac0d8SBjoern A. Zeeb 
646*90aac0d8SBjoern A. Zeeb 	return 0;
647*90aac0d8SBjoern A. Zeeb err:
648*90aac0d8SBjoern A. Zeeb 	rtw_usb_free_rx_bufs(rtwusb);
649*90aac0d8SBjoern A. Zeeb 	return -ENOMEM;
650*90aac0d8SBjoern A. Zeeb }
651*90aac0d8SBjoern A. Zeeb 
652*90aac0d8SBjoern A. Zeeb static int rtw_usb_setup(struct rtw_dev *rtwdev)
653*90aac0d8SBjoern A. Zeeb {
654*90aac0d8SBjoern A. Zeeb 	/* empty function for rtw_hci_ops */
655*90aac0d8SBjoern A. Zeeb 	return 0;
656*90aac0d8SBjoern A. Zeeb }
657*90aac0d8SBjoern A. Zeeb 
658*90aac0d8SBjoern A. Zeeb static int rtw_usb_start(struct rtw_dev *rtwdev)
659*90aac0d8SBjoern A. Zeeb {
660*90aac0d8SBjoern A. Zeeb 	return 0;
661*90aac0d8SBjoern A. Zeeb }
662*90aac0d8SBjoern A. Zeeb 
663*90aac0d8SBjoern A. Zeeb static void rtw_usb_stop(struct rtw_dev *rtwdev)
664*90aac0d8SBjoern A. Zeeb {
665*90aac0d8SBjoern A. Zeeb }
666*90aac0d8SBjoern A. Zeeb 
667*90aac0d8SBjoern A. Zeeb static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter)
668*90aac0d8SBjoern A. Zeeb {
669*90aac0d8SBjoern A. Zeeb 	/* empty function for rtw_hci_ops */
670*90aac0d8SBjoern A. Zeeb }
671*90aac0d8SBjoern A. Zeeb 
672*90aac0d8SBjoern A. Zeeb static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter)
673*90aac0d8SBjoern A. Zeeb {
674*90aac0d8SBjoern A. Zeeb 	/* empty function for rtw_hci_ops */
675*90aac0d8SBjoern A. Zeeb }
676*90aac0d8SBjoern A. Zeeb 
677*90aac0d8SBjoern A. Zeeb static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev)
678*90aac0d8SBjoern A. Zeeb {
679*90aac0d8SBjoern A. Zeeb 	/* empty function for rtw_hci_ops */
680*90aac0d8SBjoern A. Zeeb }
681*90aac0d8SBjoern A. Zeeb 
682*90aac0d8SBjoern A. Zeeb static struct rtw_hci_ops rtw_usb_ops = {
683*90aac0d8SBjoern A. Zeeb 	.tx_write = rtw_usb_tx_write,
684*90aac0d8SBjoern A. Zeeb 	.tx_kick_off = rtw_usb_tx_kick_off,
685*90aac0d8SBjoern A. Zeeb 	.setup = rtw_usb_setup,
686*90aac0d8SBjoern A. Zeeb 	.start = rtw_usb_start,
687*90aac0d8SBjoern A. Zeeb 	.stop = rtw_usb_stop,
688*90aac0d8SBjoern A. Zeeb 	.deep_ps = rtw_usb_deep_ps,
689*90aac0d8SBjoern A. Zeeb 	.link_ps = rtw_usb_link_ps,
690*90aac0d8SBjoern A. Zeeb 	.interface_cfg = rtw_usb_interface_cfg,
691*90aac0d8SBjoern A. Zeeb 
692*90aac0d8SBjoern A. Zeeb 	.write8  = rtw_usb_write8,
693*90aac0d8SBjoern A. Zeeb 	.write16 = rtw_usb_write16,
694*90aac0d8SBjoern A. Zeeb 	.write32 = rtw_usb_write32,
695*90aac0d8SBjoern A. Zeeb 	.read8	= rtw_usb_read8,
696*90aac0d8SBjoern A. Zeeb 	.read16 = rtw_usb_read16,
697*90aac0d8SBjoern A. Zeeb 	.read32 = rtw_usb_read32,
698*90aac0d8SBjoern A. Zeeb 
699*90aac0d8SBjoern A. Zeeb 	.write_data_rsvd_page = rtw_usb_write_data_rsvd_page,
700*90aac0d8SBjoern A. Zeeb 	.write_data_h2c = rtw_usb_write_data_h2c,
701*90aac0d8SBjoern A. Zeeb };
702*90aac0d8SBjoern A. Zeeb 
703*90aac0d8SBjoern A. Zeeb static int rtw_usb_init_rx(struct rtw_dev *rtwdev)
704*90aac0d8SBjoern A. Zeeb {
705*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
706*90aac0d8SBjoern A. Zeeb 	int i;
707*90aac0d8SBjoern A. Zeeb 
708*90aac0d8SBjoern A. Zeeb 	rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq");
709*90aac0d8SBjoern A. Zeeb 	if (!rtwusb->rxwq) {
710*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to create RX work queue\n");
711*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
712*90aac0d8SBjoern A. Zeeb 	}
713*90aac0d8SBjoern A. Zeeb 
714*90aac0d8SBjoern A. Zeeb 	skb_queue_head_init(&rtwusb->rx_queue);
715*90aac0d8SBjoern A. Zeeb 
716*90aac0d8SBjoern A. Zeeb 	INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler);
717*90aac0d8SBjoern A. Zeeb 
718*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < RTW_USB_RXCB_NUM; i++) {
719*90aac0d8SBjoern A. Zeeb 		struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i];
720*90aac0d8SBjoern A. Zeeb 
721*90aac0d8SBjoern A. Zeeb 		rtw_usb_rx_resubmit(rtwusb, rxcb);
722*90aac0d8SBjoern A. Zeeb 	}
723*90aac0d8SBjoern A. Zeeb 
724*90aac0d8SBjoern A. Zeeb 	return 0;
725*90aac0d8SBjoern A. Zeeb }
726*90aac0d8SBjoern A. Zeeb 
727*90aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev)
728*90aac0d8SBjoern A. Zeeb {
729*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
730*90aac0d8SBjoern A. Zeeb 
731*90aac0d8SBjoern A. Zeeb 	skb_queue_purge(&rtwusb->rx_queue);
732*90aac0d8SBjoern A. Zeeb 
733*90aac0d8SBjoern A. Zeeb 	flush_workqueue(rtwusb->rxwq);
734*90aac0d8SBjoern A. Zeeb 	destroy_workqueue(rtwusb->rxwq);
735*90aac0d8SBjoern A. Zeeb }
736*90aac0d8SBjoern A. Zeeb 
737*90aac0d8SBjoern A. Zeeb static int rtw_usb_init_tx(struct rtw_dev *rtwdev)
738*90aac0d8SBjoern A. Zeeb {
739*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
740*90aac0d8SBjoern A. Zeeb 	int i;
741*90aac0d8SBjoern A. Zeeb 
742*90aac0d8SBjoern A. Zeeb 	rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq");
743*90aac0d8SBjoern A. Zeeb 	if (!rtwusb->txwq) {
744*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to create TX work queue\n");
745*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
746*90aac0d8SBjoern A. Zeeb 	}
747*90aac0d8SBjoern A. Zeeb 
748*90aac0d8SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++)
749*90aac0d8SBjoern A. Zeeb 		skb_queue_head_init(&rtwusb->tx_queue[i]);
750*90aac0d8SBjoern A. Zeeb 
751*90aac0d8SBjoern A. Zeeb 	INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler);
752*90aac0d8SBjoern A. Zeeb 
753*90aac0d8SBjoern A. Zeeb 	return 0;
754*90aac0d8SBjoern A. Zeeb }
755*90aac0d8SBjoern A. Zeeb 
756*90aac0d8SBjoern A. Zeeb static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev)
757*90aac0d8SBjoern A. Zeeb {
758*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
759*90aac0d8SBjoern A. Zeeb 
760*90aac0d8SBjoern A. Zeeb 	rtw_usb_tx_queue_purge(rtwusb);
761*90aac0d8SBjoern A. Zeeb 	flush_workqueue(rtwusb->txwq);
762*90aac0d8SBjoern A. Zeeb 	destroy_workqueue(rtwusb->txwq);
763*90aac0d8SBjoern A. Zeeb }
764*90aac0d8SBjoern A. Zeeb 
765*90aac0d8SBjoern A. Zeeb static int rtw_usb_intf_init(struct rtw_dev *rtwdev,
766*90aac0d8SBjoern A. Zeeb 			     struct usb_interface *intf)
767*90aac0d8SBjoern A. Zeeb {
768*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
769*90aac0d8SBjoern A. Zeeb 	struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
770*90aac0d8SBjoern A. Zeeb 	int ret;
771*90aac0d8SBjoern A. Zeeb 
772*90aac0d8SBjoern A. Zeeb 	rtwusb->udev = udev;
773*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_parse(rtwdev, intf);
774*90aac0d8SBjoern A. Zeeb 	if (ret)
775*90aac0d8SBjoern A. Zeeb 		return ret;
776*90aac0d8SBjoern A. Zeeb 
777*90aac0d8SBjoern A. Zeeb 	rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32),
778*90aac0d8SBjoern A. Zeeb 				   GFP_KERNEL);
779*90aac0d8SBjoern A. Zeeb 	if (!rtwusb->usb_data)
780*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
781*90aac0d8SBjoern A. Zeeb 
782*90aac0d8SBjoern A. Zeeb 	usb_set_intfdata(intf, rtwdev->hw);
783*90aac0d8SBjoern A. Zeeb 
784*90aac0d8SBjoern A. Zeeb 	SET_IEEE80211_DEV(rtwdev->hw, &intf->dev);
785*90aac0d8SBjoern A. Zeeb 	spin_lock_init(&rtwusb->usb_lock);
786*90aac0d8SBjoern A. Zeeb 
787*90aac0d8SBjoern A. Zeeb 	return 0;
788*90aac0d8SBjoern A. Zeeb }
789*90aac0d8SBjoern A. Zeeb 
790*90aac0d8SBjoern A. Zeeb static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev,
791*90aac0d8SBjoern A. Zeeb 				struct usb_interface *intf)
792*90aac0d8SBjoern A. Zeeb {
793*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev);
794*90aac0d8SBjoern A. Zeeb 
795*90aac0d8SBjoern A. Zeeb 	usb_put_dev(rtwusb->udev);
796*90aac0d8SBjoern A. Zeeb 	kfree(rtwusb->usb_data);
797*90aac0d8SBjoern A. Zeeb 	usb_set_intfdata(intf, NULL);
798*90aac0d8SBjoern A. Zeeb }
799*90aac0d8SBjoern A. Zeeb 
800*90aac0d8SBjoern A. Zeeb int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
801*90aac0d8SBjoern A. Zeeb {
802*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev;
803*90aac0d8SBjoern A. Zeeb 	struct ieee80211_hw *hw;
804*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb;
805*90aac0d8SBjoern A. Zeeb 	int drv_data_size;
806*90aac0d8SBjoern A. Zeeb 	int ret;
807*90aac0d8SBjoern A. Zeeb 
808*90aac0d8SBjoern A. Zeeb 	drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb);
809*90aac0d8SBjoern A. Zeeb 	hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops);
810*90aac0d8SBjoern A. Zeeb 	if (!hw)
811*90aac0d8SBjoern A. Zeeb 		return -ENOMEM;
812*90aac0d8SBjoern A. Zeeb 
813*90aac0d8SBjoern A. Zeeb 	rtwdev = hw->priv;
814*90aac0d8SBjoern A. Zeeb 	rtwdev->hw = hw;
815*90aac0d8SBjoern A. Zeeb 	rtwdev->dev = &intf->dev;
816*90aac0d8SBjoern A. Zeeb 	rtwdev->chip = (struct rtw_chip_info *)id->driver_info;
817*90aac0d8SBjoern A. Zeeb 	rtwdev->hci.ops = &rtw_usb_ops;
818*90aac0d8SBjoern A. Zeeb 	rtwdev->hci.type = RTW_HCI_TYPE_USB;
819*90aac0d8SBjoern A. Zeeb 
820*90aac0d8SBjoern A. Zeeb 	rtwusb = rtw_get_usb_priv(rtwdev);
821*90aac0d8SBjoern A. Zeeb 	rtwusb->rtwdev = rtwdev;
822*90aac0d8SBjoern A. Zeeb 
823*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_alloc_rx_bufs(rtwusb);
824*90aac0d8SBjoern A. Zeeb 	if (ret)
825*90aac0d8SBjoern A. Zeeb 		goto err_release_hw;
826*90aac0d8SBjoern A. Zeeb 
827*90aac0d8SBjoern A. Zeeb 	ret = rtw_core_init(rtwdev);
828*90aac0d8SBjoern A. Zeeb 	if (ret)
829*90aac0d8SBjoern A. Zeeb 		goto err_release_hw;
830*90aac0d8SBjoern A. Zeeb 
831*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_intf_init(rtwdev, intf);
832*90aac0d8SBjoern A. Zeeb 	if (ret) {
833*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to init USB interface\n");
834*90aac0d8SBjoern A. Zeeb 		goto err_deinit_core;
835*90aac0d8SBjoern A. Zeeb 	}
836*90aac0d8SBjoern A. Zeeb 
837*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_init_tx(rtwdev);
838*90aac0d8SBjoern A. Zeeb 	if (ret) {
839*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to init USB TX\n");
840*90aac0d8SBjoern A. Zeeb 		goto err_destroy_usb;
841*90aac0d8SBjoern A. Zeeb 	}
842*90aac0d8SBjoern A. Zeeb 
843*90aac0d8SBjoern A. Zeeb 	ret = rtw_usb_init_rx(rtwdev);
844*90aac0d8SBjoern A. Zeeb 	if (ret) {
845*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to init USB RX\n");
846*90aac0d8SBjoern A. Zeeb 		goto err_destroy_txwq;
847*90aac0d8SBjoern A. Zeeb 	}
848*90aac0d8SBjoern A. Zeeb 
849*90aac0d8SBjoern A. Zeeb 	ret = rtw_chip_info_setup(rtwdev);
850*90aac0d8SBjoern A. Zeeb 	if (ret) {
851*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to setup chip information\n");
852*90aac0d8SBjoern A. Zeeb 		goto err_destroy_rxwq;
853*90aac0d8SBjoern A. Zeeb 	}
854*90aac0d8SBjoern A. Zeeb 
855*90aac0d8SBjoern A. Zeeb 	ret = rtw_register_hw(rtwdev, rtwdev->hw);
856*90aac0d8SBjoern A. Zeeb 	if (ret) {
857*90aac0d8SBjoern A. Zeeb 		rtw_err(rtwdev, "failed to register hw\n");
858*90aac0d8SBjoern A. Zeeb 		goto err_destroy_rxwq;
859*90aac0d8SBjoern A. Zeeb 	}
860*90aac0d8SBjoern A. Zeeb 
861*90aac0d8SBjoern A. Zeeb 	return 0;
862*90aac0d8SBjoern A. Zeeb 
863*90aac0d8SBjoern A. Zeeb err_destroy_rxwq:
864*90aac0d8SBjoern A. Zeeb 	rtw_usb_deinit_rx(rtwdev);
865*90aac0d8SBjoern A. Zeeb 
866*90aac0d8SBjoern A. Zeeb err_destroy_txwq:
867*90aac0d8SBjoern A. Zeeb 	rtw_usb_deinit_tx(rtwdev);
868*90aac0d8SBjoern A. Zeeb 
869*90aac0d8SBjoern A. Zeeb err_destroy_usb:
870*90aac0d8SBjoern A. Zeeb 	rtw_usb_intf_deinit(rtwdev, intf);
871*90aac0d8SBjoern A. Zeeb 
872*90aac0d8SBjoern A. Zeeb err_deinit_core:
873*90aac0d8SBjoern A. Zeeb 	rtw_core_deinit(rtwdev);
874*90aac0d8SBjoern A. Zeeb 
875*90aac0d8SBjoern A. Zeeb err_release_hw:
876*90aac0d8SBjoern A. Zeeb 	ieee80211_free_hw(hw);
877*90aac0d8SBjoern A. Zeeb 
878*90aac0d8SBjoern A. Zeeb 	return ret;
879*90aac0d8SBjoern A. Zeeb }
880*90aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_probe);
881*90aac0d8SBjoern A. Zeeb 
882*90aac0d8SBjoern A. Zeeb void rtw_usb_disconnect(struct usb_interface *intf)
883*90aac0d8SBjoern A. Zeeb {
884*90aac0d8SBjoern A. Zeeb 	struct ieee80211_hw *hw = usb_get_intfdata(intf);
885*90aac0d8SBjoern A. Zeeb 	struct rtw_dev *rtwdev;
886*90aac0d8SBjoern A. Zeeb 	struct rtw_usb *rtwusb;
887*90aac0d8SBjoern A. Zeeb 
888*90aac0d8SBjoern A. Zeeb 	if (!hw)
889*90aac0d8SBjoern A. Zeeb 		return;
890*90aac0d8SBjoern A. Zeeb 
891*90aac0d8SBjoern A. Zeeb 	rtwdev = hw->priv;
892*90aac0d8SBjoern A. Zeeb 	rtwusb = rtw_get_usb_priv(rtwdev);
893*90aac0d8SBjoern A. Zeeb 
894*90aac0d8SBjoern A. Zeeb 	rtw_usb_cancel_rx_bufs(rtwusb);
895*90aac0d8SBjoern A. Zeeb 
896*90aac0d8SBjoern A. Zeeb 	rtw_unregister_hw(rtwdev, hw);
897*90aac0d8SBjoern A. Zeeb 	rtw_usb_deinit_tx(rtwdev);
898*90aac0d8SBjoern A. Zeeb 	rtw_usb_deinit_rx(rtwdev);
899*90aac0d8SBjoern A. Zeeb 
900*90aac0d8SBjoern A. Zeeb 	if (rtwusb->udev->state != USB_STATE_NOTATTACHED)
901*90aac0d8SBjoern A. Zeeb 		usb_reset_device(rtwusb->udev);
902*90aac0d8SBjoern A. Zeeb 
903*90aac0d8SBjoern A. Zeeb 	rtw_usb_free_rx_bufs(rtwusb);
904*90aac0d8SBjoern A. Zeeb 
905*90aac0d8SBjoern A. Zeeb 	rtw_usb_intf_deinit(rtwdev, intf);
906*90aac0d8SBjoern A. Zeeb 	rtw_core_deinit(rtwdev);
907*90aac0d8SBjoern A. Zeeb 	ieee80211_free_hw(hw);
908*90aac0d8SBjoern A. Zeeb }
909*90aac0d8SBjoern A. Zeeb EXPORT_SYMBOL(rtw_usb_disconnect);
910*90aac0d8SBjoern A. Zeeb 
911*90aac0d8SBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation");
912*90aac0d8SBjoern A. Zeeb MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
913*90aac0d8SBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
914*90aac0d8SBjoern A. Zeeb #if defined(__FreeBSD__)
915*90aac0d8SBjoern A. Zeeb MODULE_VERSION(rtw88_usb, 1);
916*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, rtw88_core, 1, 1, 1);
917*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi, 1, 1, 1);
918*90aac0d8SBjoern A. Zeeb MODULE_DEPEND(rtw88_usb, linuxkpi_wlan, 1, 1, 1);
919*90aac0d8SBjoern A. Zeeb #endif
920