blob: 0ad734a3473bfa3449033a6652943babaae8ce97 [file] [log] [blame]
Mohit Khannabda5d432016-05-11 11:09:21 -07001/*
Nirav Shahd9dce6e2018-02-26 14:50:25 +05302 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
Mohit Khannabda5d432016-05-11 11:09:21 -07003 *
Mohit Khannabda5d432016-05-11 11:09:21 -07004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Mohit Khannabda5d432016-05-11 11:09:21 -070019#define ATH_MODULE_NAME hif
20#include "a_debug.h"
21#include "hif_usb_internal.h"
22#include "if_usb.h"
23#include "cds_api.h"
24#include "hif_debug.h"
25
26#define IS_BULK_EP(attr) (((attr) & 3) == 0x02)
27#define IS_INT_EP(attr) (((attr) & 3) == 0x03)
28#define IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
29#define IS_DIR_IN(addr) ((addr) & 0x80)
30
31#define IS_FW_CRASH_DUMP(x)(((x == FW_ASSERT_PATTERN) || \
32 (x == FW_REG_PATTERN) || \
33 ((x & FW_RAMDUMP_PATTERN_MASK) == \
34 FW_RAMDUMP_PATTERN)) ? 1 : 0)
35
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070036static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
Mohit Khannabda5d432016-05-11 11:09:21 -070037 int buffer_length);
38static void usb_hif_post_recv_bundle_transfers
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070039 (struct HIF_USB_PIPE *recv_pipe,
Mohit Khannabda5d432016-05-11 11:09:21 -070040 int buffer_length);
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070041static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context);
Mohit Khannabda5d432016-05-11 11:09:21 -070042
43
44/**
45 * usb_hif_free_urb_to_pipe() - add urb back to urb list of a pipe
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070046 * @pipe: pointer to struct HIF_USB_PIPE
47 * @urb_context: pointer to struct HIF_URB_CONTEXT
Mohit Khannabda5d432016-05-11 11:09:21 -070048 *
49 * Return: none
50 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070051static void usb_hif_free_urb_to_pipe(struct HIF_USB_PIPE *pipe,
52 struct HIF_URB_CONTEXT *urb_context)
Mohit Khannabda5d432016-05-11 11:09:21 -070053{
54 qdf_spin_lock_irqsave(&pipe->device->cs_lock);
55 pipe->urb_cnt++;
56 DL_ListAdd(&pipe->urb_list_head, &urb_context->link);
57 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
58}
59
60/**
61 * usb_hif_alloc_urb_from_pipe() - remove urb back from urb list of a pipe
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070062 * @pipe: pointer to struct HIF_USB_PIPE
Mohit Khannabda5d432016-05-11 11:09:21 -070063 *
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070064 * Return: struct HIF_URB_CONTEXT urb context removed from the urb list
Mohit Khannabda5d432016-05-11 11:09:21 -070065 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070066struct HIF_URB_CONTEXT *usb_hif_alloc_urb_from_pipe(struct HIF_USB_PIPE *pipe)
Mohit Khannabda5d432016-05-11 11:09:21 -070067{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070068 struct HIF_URB_CONTEXT *urb_context = NULL;
Mohit Khannabda5d432016-05-11 11:09:21 -070069 DL_LIST *item;
70
71 qdf_spin_lock_irqsave(&pipe->device->cs_lock);
72 item = dl_list_remove_item_from_head(&pipe->urb_list_head);
73 if (item != NULL) {
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070074 urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
75 link);
Mohit Khannabda5d432016-05-11 11:09:21 -070076 pipe->urb_cnt--;
77 }
78 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
79
80 return urb_context;
81}
82
83/**
84 * usb_hif_dequeue_pending_transfer() - remove urb from pending xfer list
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070085 * @pipe: pointer to struct HIF_USB_PIPE
Mohit Khannabda5d432016-05-11 11:09:21 -070086 *
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070087 * Return: struct HIF_URB_CONTEXT urb context removed from the pending xfer list
Mohit Khannabda5d432016-05-11 11:09:21 -070088 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070089static struct HIF_URB_CONTEXT *usb_hif_dequeue_pending_transfer
90 (struct HIF_USB_PIPE *pipe)
Mohit Khannabda5d432016-05-11 11:09:21 -070091{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070092 struct HIF_URB_CONTEXT *urb_context = NULL;
Mohit Khannabda5d432016-05-11 11:09:21 -070093 DL_LIST *item;
94
95 qdf_spin_lock_irqsave(&pipe->device->cs_lock);
96 item = dl_list_remove_item_from_head(&pipe->urb_pending_list);
97 if (item != NULL)
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -070098 urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
99 link);
Mohit Khannabda5d432016-05-11 11:09:21 -0700100 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
101
102 return urb_context;
103}
104
105/**
106 * usb_hif_enqueue_pending_transfer() - add urb to pending xfer list
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700107 * @pipe: pointer to struct HIF_USB_PIPE
108 * @urb_context: pointer to struct HIF_URB_CONTEXT to be added to the xfer list
Mohit Khannabda5d432016-05-11 11:09:21 -0700109 *
110 * Return: none
111 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700112void usb_hif_enqueue_pending_transfer(struct HIF_USB_PIPE *pipe,
113 struct HIF_URB_CONTEXT *urb_context)
Mohit Khannabda5d432016-05-11 11:09:21 -0700114{
115 qdf_spin_lock_irqsave(&pipe->device->cs_lock);
116 dl_list_insert_tail(&pipe->urb_pending_list, &urb_context->link);
117 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
118}
119
120
121/**
122 * usb_hif_remove_pending_transfer() - remove urb from its own list
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700123 * @urb_context: pointer to struct HIF_URB_CONTEXT to be removed
Mohit Khannabda5d432016-05-11 11:09:21 -0700124 *
125 * Return: none
126 */
127void
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700128usb_hif_remove_pending_transfer(struct HIF_URB_CONTEXT *urb_context)
Mohit Khannabda5d432016-05-11 11:09:21 -0700129{
130 qdf_spin_lock_irqsave(&urb_context->pipe->device->cs_lock);
131 dl_list_remove(&urb_context->link);
132 qdf_spin_unlock_irqrestore(&urb_context->pipe->device->cs_lock);
133}
134
135/**
136 * usb_hif_alloc_pipe_resources() - allocate urb_cnt urbs to a HIF pipe
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700137 * @pipe: pointer to struct HIF_USB_PIPE to which resources will be allocated
Mohit Khannabda5d432016-05-11 11:09:21 -0700138 * @urb_cnt: number of urbs to be added to the HIF pipe
139 *
140 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
141 */
142static QDF_STATUS usb_hif_alloc_pipe_resources
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700143 (struct HIF_USB_PIPE *pipe, int urb_cnt)
Mohit Khannabda5d432016-05-11 11:09:21 -0700144{
145 QDF_STATUS status = QDF_STATUS_SUCCESS;
146 int i;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700147 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700148
149 DL_LIST_INIT(&pipe->urb_list_head);
150 DL_LIST_INIT(&pipe->urb_pending_list);
151
152 for (i = 0; i < urb_cnt; i++) {
153 urb_context = qdf_mem_malloc(sizeof(*urb_context));
154 if (NULL == urb_context) {
155 status = QDF_STATUS_E_NOMEM;
156 HIF_ERROR("urb_context is null");
157 break;
158 }
159 urb_context->pipe = pipe;
160 urb_context->urb = usb_alloc_urb(0, GFP_KERNEL);
161
162 if (NULL == urb_context->urb) {
163 status = QDF_STATUS_E_NOMEM;
164 qdf_mem_free(urb_context);
165 HIF_ERROR("urb_context->urb is null");
166 break;
167 }
168
169 /* note we are only allocate the urb contexts here, the actual
170 * URB is
171 * allocated from the kernel as needed to do a transaction
172 */
173 pipe->urb_alloc++;
174
175 usb_hif_free_urb_to_pipe(pipe, urb_context);
176 }
177
178 HIF_DBG("athusb: alloc resources lpipe:%d hpipe:0x%X urbs:%d",
179 pipe->logical_pipe_num,
180 pipe->usb_pipe_handle,
181 pipe->urb_alloc);
182 return status;
183}
184
185/**
186 * usb_hif_free_pipe_resources() - free urb resources allocated to a HIF pipe
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700187 * @pipe: pointer to struct HIF_USB_PIPE
Mohit Khannabda5d432016-05-11 11:09:21 -0700188 *
189 * Return: none
190 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700191static void usb_hif_free_pipe_resources(struct HIF_USB_PIPE *pipe)
Mohit Khannabda5d432016-05-11 11:09:21 -0700192{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700193 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700194
195 if (NULL == pipe->device) {
196 /* nothing allocated for this pipe */
197 HIF_ERROR("pipe->device is null");
198 return;
199 }
200
201 HIF_TRACE("athusb: free resources lpipe:%d hpipe:0x%X urbs:%d avail:%d",
202 pipe->logical_pipe_num,
203 pipe->usb_pipe_handle, pipe->urb_alloc,
204 pipe->urb_cnt);
205
206 if (pipe->urb_alloc != pipe->urb_cnt) {
207 HIF_ERROR("athusb: urb leak! lpipe:%d hpipe:0x%X urbs:%d avail:%d",
208 pipe->logical_pipe_num,
209 pipe->usb_pipe_handle, pipe->urb_alloc,
210 pipe->urb_cnt);
211 }
212
213 while (true) {
214 urb_context = usb_hif_alloc_urb_from_pipe(pipe);
215 if (NULL == urb_context)
216 break;
217
218 if (urb_context->buf) {
219 qdf_nbuf_free(urb_context->buf);
220 urb_context->buf = NULL;
221 }
222
223 usb_free_urb(urb_context->urb);
224 urb_context->urb = NULL;
225 qdf_mem_free(urb_context);
226 }
227
228}
229
Ajit Pal Singhd1698b62018-12-19 12:08:31 +0530230#ifdef QCN7605_SUPPORT
Ajit Pal Singh97302492018-06-19 15:40:33 +0530231/**
232 * usb_hif_get_logical_pipe_num() - get pipe number for a particular enpoint
233 * @device: pointer to HIF_DEVICE_USB structure
234 * @ep_address: endpoint address
235 * @urb_count: number of urb resources to be allocated to the pipe
236 *
237 * Return: uint8_t pipe number corresponding to ep_address
238 */
239static uint8_t usb_hif_get_logical_pipe_num(struct HIF_DEVICE_USB *device,
240 uint8_t ep_address,
241 int *urb_count)
242{
243 uint8_t pipe_num = HIF_USB_PIPE_INVALID;
244
245 switch (ep_address) {
246 case USB_EP_ADDR_APP_CTRL_IN:
247 pipe_num = HIF_RX_CTRL_PIPE;
248 *urb_count = RX_URB_COUNT;
249 break;
250 case USB_EP_ADDR_APP_DATA_IN:
251 pipe_num = HIF_RX_DATA_PIPE;
252 *urb_count = RX_URB_COUNT;
253 break;
254 break;
255 case USB_EP_ADDR_APP_CTRL_OUT:
256 pipe_num = HIF_TX_CTRL_PIPE;
257 *urb_count = TX_URB_COUNT;
258 break;
259 case USB_EP_ADDR_APP_DATA_OUT:
260 pipe_num = HIF_TX_DATA_LP_PIPE;
261 *urb_count = TX_URB_COUNT;
262 break;
263 default:
264 /* note: there may be endpoints not currently used */
265 break;
266 }
267
268 return pipe_num;
269}
270#else
Mohit Khannabda5d432016-05-11 11:09:21 -0700271/**
272 * usb_hif_get_logical_pipe_num() - get pipe number for a particular enpoint
273 * @device: pointer to HIF_DEVICE_USB structure
274 * @ep_address: endpoint address
275 * @urb_count: number of urb resources to be allocated to the pipe
276 *
277 * Return: uint8_t pipe number corresponding to ep_address
278 */
279static uint8_t usb_hif_get_logical_pipe_num
Nirav Shahd9dce6e2018-02-26 14:50:25 +0530280 (struct HIF_DEVICE_USB *device,
Mohit Khannabda5d432016-05-11 11:09:21 -0700281 uint8_t ep_address,
282 int *urb_count)
283{
284 uint8_t pipe_num = HIF_USB_PIPE_INVALID;
285
286 switch (ep_address) {
287 case USB_EP_ADDR_APP_CTRL_IN:
288 pipe_num = HIF_RX_CTRL_PIPE;
289 *urb_count = RX_URB_COUNT;
290 break;
291 case USB_EP_ADDR_APP_DATA_IN:
292 pipe_num = HIF_RX_DATA_PIPE;
293 *urb_count = RX_URB_COUNT;
294 break;
295 case USB_EP_ADDR_APP_INT_IN:
296 pipe_num = HIF_RX_INT_PIPE;
297 *urb_count = RX_URB_COUNT;
298 break;
299 case USB_EP_ADDR_APP_DATA2_IN:
300 pipe_num = HIF_RX_DATA2_PIPE;
301 *urb_count = RX_URB_COUNT;
302 break;
303 case USB_EP_ADDR_APP_CTRL_OUT:
304 pipe_num = HIF_TX_CTRL_PIPE;
305 *urb_count = TX_URB_COUNT;
306 break;
307 case USB_EP_ADDR_APP_DATA_LP_OUT:
308 pipe_num = HIF_TX_DATA_LP_PIPE;
309 *urb_count = TX_URB_COUNT;
310 break;
311 case USB_EP_ADDR_APP_DATA_MP_OUT:
312 pipe_num = HIF_TX_DATA_MP_PIPE;
313 *urb_count = TX_URB_COUNT;
314 break;
315 case USB_EP_ADDR_APP_DATA_HP_OUT:
316 pipe_num = HIF_TX_DATA_HP_PIPE;
317 *urb_count = TX_URB_COUNT;
318 break;
319 default:
320 /* note: there may be endpoints not currently used */
321 break;
322 }
323
324 return pipe_num;
325}
Ajit Pal Singhd1698b62018-12-19 12:08:31 +0530326#endif /* QCN7605_SUPPORT */
Mohit Khannabda5d432016-05-11 11:09:21 -0700327
328/**
329 * usb_hif_get_logical_pipe_num() - setup urb resources for all pipes
330 * @device: pointer to HIF_DEVICE_USB structure
331 *
332 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
333 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +0530334QDF_STATUS usb_hif_setup_pipe_resources(struct HIF_DEVICE_USB *device)
Mohit Khannabda5d432016-05-11 11:09:21 -0700335{
336 struct usb_interface *interface = device->interface;
337 struct usb_host_interface *iface_desc = interface->cur_altsetting;
338 struct usb_endpoint_descriptor *endpoint;
339 int i;
340 int urbcount;
341 QDF_STATUS status = QDF_STATUS_SUCCESS;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700342 struct HIF_USB_PIPE *pipe;
Mohit Khannabda5d432016-05-11 11:09:21 -0700343 uint8_t pipe_num;
344
345 /* walk decriptors and setup pipes */
346 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
347 endpoint = &iface_desc->endpoint[i].desc;
348
349 if (IS_BULK_EP(endpoint->bmAttributes)) {
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700350 HIF_DBG("%s Bulk Ep:0x%2.2X maxpktsz:%d",
Mohit Khannabda5d432016-05-11 11:09:21 -0700351 IS_DIR_IN(endpoint->bEndpointAddress) ?
352 "RX" : "TX",
353 endpoint->bEndpointAddress,
354 qdf_le16_to_cpu(endpoint->wMaxPacketSize));
355 } else if (IS_INT_EP(endpoint->bmAttributes)) {
356 HIF_DBG("%s Int Ep:0x%2.2X maxpktsz:%d interval:%d",
357 IS_DIR_IN(endpoint->bEndpointAddress) ?
358 "RX" : "TX",
359 endpoint->bEndpointAddress,
360 qdf_le16_to_cpu(endpoint->wMaxPacketSize),
361 endpoint->bInterval);
362 } else if (IS_ISOC_EP(endpoint->bmAttributes)) {
363 /* TODO for ISO */
364 HIF_DBG("%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d",
365 IS_DIR_IN(endpoint->bEndpointAddress) ?
366 "RX" : "TX",
367 endpoint->bEndpointAddress,
368 qdf_le16_to_cpu(endpoint->wMaxPacketSize),
369 endpoint->bInterval);
370 }
371 urbcount = 0;
372
373 pipe_num = usb_hif_get_logical_pipe_num(device,
374 endpoint->bEndpointAddress,
375 &urbcount);
376 if (HIF_USB_PIPE_INVALID == pipe_num)
377 continue;
378
379 pipe = &device->pipes[pipe_num];
380 if (pipe->device != NULL) {
381 /*pipe was already setup */
382 continue;
383 }
384
385 pipe->device = device;
386 pipe->logical_pipe_num = pipe_num;
387 pipe->ep_address = endpoint->bEndpointAddress;
388 pipe->max_packet_size =
389 qdf_le16_to_cpu(endpoint->wMaxPacketSize);
390
391 if (IS_BULK_EP(endpoint->bmAttributes)) {
392 if (IS_DIR_IN(pipe->ep_address)) {
393 pipe->usb_pipe_handle =
394 usb_rcvbulkpipe(device->udev,
395 pipe->ep_address);
396 } else {
397 pipe->usb_pipe_handle =
398 usb_sndbulkpipe(device->udev,
399 pipe->ep_address);
400 }
401 } else if (IS_INT_EP(endpoint->bmAttributes)) {
402 if (IS_DIR_IN(pipe->ep_address)) {
403 pipe->usb_pipe_handle =
404 usb_rcvintpipe(device->udev,
405 pipe->ep_address);
406 } else {
407 pipe->usb_pipe_handle =
408 usb_sndintpipe(device->udev,
409 pipe->ep_address);
410 }
411 } else if (IS_ISOC_EP(endpoint->bmAttributes)) {
412 /* TODO for ISO */
413 if (IS_DIR_IN(pipe->ep_address)) {
414 pipe->usb_pipe_handle =
415 usb_rcvisocpipe(device->udev,
416 pipe->ep_address);
417 } else {
418 pipe->usb_pipe_handle =
419 usb_sndisocpipe(device->udev,
420 pipe->ep_address);
421 }
422 }
423 pipe->ep_desc = endpoint;
424
425 if (!IS_DIR_IN(pipe->ep_address))
426 pipe->flags |= HIF_USB_PIPE_FLAG_TX;
427
428 status = usb_hif_alloc_pipe_resources(pipe, urbcount);
429
430 if (!QDF_IS_STATUS_SUCCESS(status))
431 break;
432
433 }
434
435 return status;
436}
437
438
439/**
440 * usb_hif_cleanup_pipe_resources() - free urb resources for all pipes
441 * @device: pointer to HIF_DEVICE_USB structure
442 *
443 * Return: none
444 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +0530445void usb_hif_cleanup_pipe_resources(struct HIF_DEVICE_USB *device)
Mohit Khannabda5d432016-05-11 11:09:21 -0700446{
447 int i;
448
449 for (i = 0; i < HIF_USB_PIPE_MAX; i++)
450 usb_hif_free_pipe_resources(&device->pipes[i]);
451}
452
453/**
454 * usb_hif_flush_pending_transfers() - kill pending urbs for a pipe
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700455 * @pipe: pointer to struct HIF_USB_PIPE structure
Mohit Khannabda5d432016-05-11 11:09:21 -0700456 *
457 * Return: none
458 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700459static void usb_hif_flush_pending_transfers(struct HIF_USB_PIPE *pipe)
Mohit Khannabda5d432016-05-11 11:09:21 -0700460{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700461 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700462
463 HIF_TRACE("+%s pipe : %d", __func__, pipe->logical_pipe_num);
464
465 while (1) {
466 urb_context = usb_hif_dequeue_pending_transfer(pipe);
467 if (NULL == urb_context) {
468 HIF_WARN("urb_context is NULL");
469 break;
470 }
Jeff Johnsonb9450212017-09-18 10:12:38 -0700471 HIF_TRACE(" pending urb ctxt: 0x%pK", urb_context);
Mohit Khannabda5d432016-05-11 11:09:21 -0700472 if (urb_context->urb != NULL) {
Jeff Johnsonb9450212017-09-18 10:12:38 -0700473 HIF_TRACE(" killing urb: 0x%pK", urb_context->urb);
Mohit Khannabda5d432016-05-11 11:09:21 -0700474 /* killing the URB will cause the completion routines to
475 * run
476 */
477 usb_kill_urb(urb_context->urb);
478 }
479 }
480 HIF_TRACE("-%s", __func__);
481}
482
483/**
484 * usb_hif_flush_all() - flush pending transfers for all pipes for a usb bus
485 * @device: pointer to HIF_DEVICE_USB structure
486 *
487 * Return: none
488 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +0530489void usb_hif_flush_all(struct HIF_DEVICE_USB *device)
Mohit Khannabda5d432016-05-11 11:09:21 -0700490{
491 int i;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700492 struct HIF_USB_PIPE *pipe;
493
Mohit Khannabda5d432016-05-11 11:09:21 -0700494 HIF_TRACE("+%s", __func__);
495
496 for (i = 0; i < HIF_USB_PIPE_MAX; i++) {
497 if (device->pipes[i].device != NULL) {
498 usb_hif_flush_pending_transfers(&device->pipes[i]);
499 pipe = &device->pipes[i];
500
501 HIF_USB_FLUSH_WORK(pipe);
502 }
503 }
504
505 HIF_TRACE("-%s", __func__);
506}
507
508/**
509 * usb_hif_cleanup_recv_urb() - cleanup recv urb
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700510 * @urb_context: pointer to struct HIF_URB_CONTEXT structure
Mohit Khannabda5d432016-05-11 11:09:21 -0700511 *
512 * Return: none
513 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700514static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context)
Mohit Khannabda5d432016-05-11 11:09:21 -0700515{
516 HIF_TRACE("+%s", __func__);
517
518 if (urb_context->buf != NULL) {
519 qdf_nbuf_free(urb_context->buf);
520 urb_context->buf = NULL;
521 }
522
523 usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
524 HIF_TRACE("-%s", __func__);
525}
526
527/**
528 * usb_hif_cleanup_transmit_urb() - cleanup transmit urb
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700529 * @urb_context: pointer to struct HIF_URB_CONTEXT structure
Mohit Khannabda5d432016-05-11 11:09:21 -0700530 *
531 * Return: none
532 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700533void usb_hif_cleanup_transmit_urb(struct HIF_URB_CONTEXT *urb_context)
Mohit Khannabda5d432016-05-11 11:09:21 -0700534{
535 usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
536}
537
538/**
539 * usb_hif_usb_recv_prestart_complete() - completion routine for prestart rx urb
540 * @urb: urb for which the completion routine is being called
541 *
542 * Return: none
543 */
544static void usb_hif_usb_recv_prestart_complete
545 (struct urb *urb)
546{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700547 struct HIF_URB_CONTEXT *urb_context =
548 (struct HIF_URB_CONTEXT *) urb->context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700549 QDF_STATUS status = QDF_STATUS_SUCCESS;
550 qdf_nbuf_t buf = NULL;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700551 struct HIF_USB_PIPE *pipe = urb_context->pipe;
Mohit Khannabda5d432016-05-11 11:09:21 -0700552
Jeff Johnsonb9450212017-09-18 10:12:38 -0700553 HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -0700554 __func__,
555 pipe->logical_pipe_num,
556 urb->status, urb->actual_length,
557 urb);
558
559 /* this urb is not pending anymore */
560 usb_hif_remove_pending_transfer(urb_context);
Mohit Khannabda5d432016-05-11 11:09:21 -0700561 do {
562 if (urb->status != 0) {
563 status = A_ECOMM;
564 switch (urb->status) {
565 case -ECONNRESET:
566 case -ENOENT:
567 case -ESHUTDOWN:
568 /* NOTE: no need to spew these errors when
569 * device is removed
570 * or urb is killed due to driver shutdown
571 */
572 status = A_ECANCELED;
573 break;
574 default:
575 HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
576 __func__,
577 pipe->logical_pipe_num,
578 pipe->ep_address,
579 urb->status);
580 break;
581 }
582 break;
583 }
Mohit Khannabda5d432016-05-11 11:09:21 -0700584 if (urb->actual_length == 0)
585 break;
Mohit Khannabda5d432016-05-11 11:09:21 -0700586 buf = urb_context->buf;
587 /* we are going to pass it up */
588 urb_context->buf = NULL;
589 qdf_nbuf_put_tail(buf, urb->actual_length);
590
591 if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
592 uint8_t *data;
593 uint32_t len;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700594
Mohit Khannabda5d432016-05-11 11:09:21 -0700595 qdf_nbuf_peek_header(buf, &data, &len);
596 debug_dump_bytes(data, len, "hif recv data");
597 }
598 /* note: queue implements a lock */
599 skb_queue_tail(&pipe->io_comp_queue, buf);
600
601 HIF_USB_SCHEDULE_WORK(pipe);
602 } while (false);
603
604 usb_hif_cleanup_recv_urb(urb_context);
605
606 /* Prestart URBs runs out and now start working receive pipe. */
607 if (--pipe->urb_prestart_cnt == 0)
608 usb_hif_start_recv_pipes(pipe->device);
609
610 HIF_DBG("-%s", __func__);
611}
612
613/**
614 * usb_hif_usb_recv_complete() - completion routine for rx urb
615 * @urb: urb for which the completion routine is being called
616 *
617 * Return: none
618 */
619static void usb_hif_usb_recv_complete(struct urb *urb)
620{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700621 struct HIF_URB_CONTEXT *urb_context =
622 (struct HIF_URB_CONTEXT *) urb->context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700623 QDF_STATUS status = QDF_STATUS_SUCCESS;
624 qdf_nbuf_t buf = NULL;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700625 struct HIF_USB_PIPE *pipe = urb_context->pipe;
Mohit Khannabda5d432016-05-11 11:09:21 -0700626 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
627
Jeff Johnsonb9450212017-09-18 10:12:38 -0700628 HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -0700629 __func__,
630 pipe->logical_pipe_num,
631 urb->status, urb->actual_length,
632 urb);
633
634 /* this urb is not pending anymore */
635 usb_hif_remove_pending_transfer(urb_context);
636
637 do {
638
639 if (urb->status != 0) {
640 status = A_ECOMM;
641 switch (urb->status) {
642#ifdef RX_SG_SUPPORT
643 case -EOVERFLOW:
644 urb->actual_length = HIF_USB_RX_BUFFER_SIZE;
645 status = QDF_STATUS_SUCCESS;
646 break;
647#endif
648 case -ECONNRESET:
649 case -ENOENT:
650 case -ESHUTDOWN:
651 /* NOTE: no need to spew these errors when
652 * device is removed
653 * or urb is killed due to driver shutdown
654 */
655 status = A_ECANCELED;
656 break;
657 default:
658 HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
659 __func__,
660 pipe->logical_pipe_num,
661 pipe->ep_address,
662 urb->status);
663 break;
664 }
665 break;
666 }
Mohit Khannabda5d432016-05-11 11:09:21 -0700667 if (urb->actual_length == 0)
668 break;
Mohit Khannabda5d432016-05-11 11:09:21 -0700669 buf = urb_context->buf;
670 /* we are going to pass it up */
671 urb_context->buf = NULL;
672 qdf_nbuf_put_tail(buf, urb->actual_length);
673 if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
674 uint8_t *data;
675 uint32_t len;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700676
Mohit Khannabda5d432016-05-11 11:09:21 -0700677 qdf_nbuf_peek_header(buf, &data, &len);
678 debug_dump_bytes(data, len, "hif recv data");
679 }
Mohit Khannabda5d432016-05-11 11:09:21 -0700680 /* note: queue implements a lock */
681 skb_queue_tail(&pipe->io_comp_queue, buf);
682 HIF_USB_SCHEDULE_WORK(pipe);
683 } while (false);
684
685 usb_hif_cleanup_recv_urb(urb_context);
686
687 /* Only re-submit URB when STATUS is success and HIF is not at the
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700688 * suspend state.
Mohit Khannabda5d432016-05-11 11:09:21 -0700689 */
690 if (QDF_IS_STATUS_SUCCESS(status) && !sc->suspend_state) {
691 if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
692 /* our free urbs are piling up, post more transfers */
693 usb_hif_post_recv_transfers(pipe,
694 HIF_USB_RX_BUFFER_SIZE);
695 }
696 } else {
697 HIF_ERROR("%s: pipe: %d, fail to post URB: status(%d) suspend (%d)",
698 __func__,
699 pipe->logical_pipe_num,
700 urb->status,
701 sc->suspend_state);
702 }
703
704 HIF_DBG("-%s", __func__);
705}
706
707/**
708 * usb_hif_usb_recv_bundle_complete() - completion routine for rx bundling urb
709 * @urb: urb for which the completion routine is being called
710 *
711 * Return: none
712 */
713static void usb_hif_usb_recv_bundle_complete(struct urb *urb)
714{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700715 struct HIF_URB_CONTEXT *urb_context =
716 (struct HIF_URB_CONTEXT *) urb->context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700717 QDF_STATUS status = QDF_STATUS_SUCCESS;
718 qdf_nbuf_t buf = NULL;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700719 struct HIF_USB_PIPE *pipe = urb_context->pipe;
Mohit Khannabda5d432016-05-11 11:09:21 -0700720 uint8_t *netdata, *netdata_new;
721 uint32_t netlen, netlen_new;
722 HTC_FRAME_HDR *HtcHdr;
723 uint16_t payloadLen;
724 qdf_nbuf_t new_skb = NULL;
725
Jeff Johnsonb9450212017-09-18 10:12:38 -0700726 HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -0700727 __func__,
728 pipe->logical_pipe_num,
729 urb->status, urb->actual_length,
730 urb);
731
732 /* this urb is not pending anymore */
733 usb_hif_remove_pending_transfer(urb_context);
734
735 do {
736
737 if (urb->status != 0) {
738 status = A_ECOMM;
739 switch (urb->status) {
740 case -ECONNRESET:
741 case -ENOENT:
742 case -ESHUTDOWN:
743 /* NOTE: no need to spew these errors when
744 * device is removed
745 * or urb is killed due to driver shutdown
746 */
747 status = A_ECANCELED;
748 break;
749 default:
750 HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
751 __func__,
752 pipe->logical_pipe_num,
753 pipe->ep_address,
754 urb->status);
755 break;
756 }
757 break;
758 }
Mohit Khannabda5d432016-05-11 11:09:21 -0700759 if (urb->actual_length == 0)
760 break;
Mohit Khannabda5d432016-05-11 11:09:21 -0700761 buf = urb_context->buf;
Mohit Khannabda5d432016-05-11 11:09:21 -0700762 if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
763 uint8_t *data;
764 uint32_t len;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700765
Mohit Khannabda5d432016-05-11 11:09:21 -0700766 qdf_nbuf_peek_header(buf, &data, &len);
767 debug_dump_bytes(data, len, "hif recv data");
768 }
769
770 qdf_nbuf_peek_header(buf, &netdata, &netlen);
771 netlen = urb->actual_length;
772
773 do {
774 uint16_t frame_len;
775
776 if (IS_FW_CRASH_DUMP(*(uint32_t *) netdata))
777 frame_len = netlen;
778 else {
779 /* Hack into HTC header for bundle processing */
780 HtcHdr = (HTC_FRAME_HDR *) netdata;
781 if (HtcHdr->EndpointID >= ENDPOINT_MAX) {
782 HIF_ERROR("athusb: Rx: invalid EndpointID=%d",
783 HtcHdr->EndpointID);
784 break;
785 }
786
787 payloadLen = HtcHdr->PayloadLen;
788 payloadLen = qdf_le16_to_cpu(payloadLen);
789
790 if (payloadLen > HIF_USB_RX_BUFFER_SIZE) {
791 HIF_ERROR("athusb: payloadLen too long %u",
792 payloadLen);
793 break;
794 }
795 frame_len = (HTC_HDR_LENGTH + payloadLen);
796 }
797
798 if (netlen < frame_len) {
799 HIF_ERROR("athusb: subframe length %d not fitted into bundle packet length %d"
800 , netlen, frame_len);
801 break;
802 }
803
804 /* allocate a new skb and copy */
805 new_skb =
806 qdf_nbuf_alloc(NULL, frame_len, 0, 4, false);
807 if (new_skb == NULL) {
808 HIF_ERROR("athusb: allocate skb (len=%u) failed"
809 , frame_len);
810 break;
811 }
812
813 qdf_nbuf_peek_header(new_skb, &netdata_new,
814 &netlen_new);
815 qdf_mem_copy(netdata_new, netdata, frame_len);
816 qdf_nbuf_put_tail(new_skb, frame_len);
817 skb_queue_tail(&pipe->io_comp_queue, new_skb);
818 new_skb = NULL;
819 netdata += frame_len;
820 netlen -= frame_len;
821 } while (netlen);
822 HIF_USB_SCHEDULE_WORK(pipe);
823 } while (false);
824
825 if (urb_context->buf == NULL)
826 HIF_ERROR("athusb: buffer in urb_context is NULL");
827
828 /* reset urb_context->buf ==> seems not necessary */
829 usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
830
831 if (QDF_IS_STATUS_SUCCESS(status)) {
832 if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
833 /* our free urbs are piling up, post more transfers */
834 usb_hif_post_recv_bundle_transfers(pipe,
835 pipe->device->rx_bundle_buf_len);
836 }
837 }
838
839 HIF_DBG("-%s", __func__);
840}
841
842/**
843 * usb_hif_post_recv_prestart_transfers() - post prestart recv urbs for a pipe
844 * @recv_pipe: rx data pipe
845 * @prestart_urb: number of prestart recv urbs to be posted
846 *
847 * Return: none
848 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700849static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe,
Mohit Khannabda5d432016-05-11 11:09:21 -0700850 int prestart_urb)
851{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700852 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700853 uint8_t *data;
854 uint32_t len;
855 struct urb *urb;
856 int i, usb_status, buffer_length = HIF_USB_RX_BUFFER_SIZE;
857
858 HIF_TRACE("+%s", __func__);
859
860 for (i = 0; i < prestart_urb; i++) {
861 urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
862 if (NULL == urb_context)
863 break;
864
865 urb_context->buf =
866 qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
867 if (NULL == urb_context->buf) {
868 usb_hif_cleanup_recv_urb(urb_context);
869 break;
870 }
871
872 qdf_nbuf_peek_header(urb_context->buf, &data, &len);
873
874 urb = urb_context->urb;
875
876 usb_fill_bulk_urb(urb,
877 recv_pipe->device->udev,
878 recv_pipe->usb_pipe_handle,
879 data,
880 buffer_length,
881 usb_hif_usb_recv_prestart_complete,
882 urb_context);
883
Jeff Johnsonb9450212017-09-18 10:12:38 -0700884 HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -0700885 recv_pipe->logical_pipe_num,
886 recv_pipe->usb_pipe_handle,
887 recv_pipe->ep_address, buffer_length,
888 urb_context->buf);
889
890 usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
891
892 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
893
894 if (usb_status) {
895 HIF_ERROR("athusb : usb bulk recv failed %d",
896 usb_status);
897 usb_hif_remove_pending_transfer(urb_context);
898 usb_hif_cleanup_recv_urb(urb_context);
899 break;
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700900 }
901 recv_pipe->urb_prestart_cnt++;
Mohit Khannabda5d432016-05-11 11:09:21 -0700902 }
903
904 HIF_TRACE("-%s", __func__);
905}
906
907/**
908 * usb_hif_post_recv_transfers() - post recv urbs for a given pipe
909 * @recv_pipe: recv pipe for which urbs need to be posted
910 * @buffer_length: buffer length of the recv urbs
911 *
912 * Return: none
913 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700914static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
Mohit Khannabda5d432016-05-11 11:09:21 -0700915 int buffer_length)
916{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700917 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700918 uint8_t *data;
919 uint32_t len;
920 struct urb *urb;
921 int usb_status;
922
923 HIF_TRACE("+%s", __func__);
924
925 while (1) {
926
927 urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
928 if (NULL == urb_context)
929 break;
930
931 urb_context->buf = qdf_nbuf_alloc(NULL, buffer_length, 0,
932 4, false);
933 if (NULL == urb_context->buf) {
934 usb_hif_cleanup_recv_urb(urb_context);
935 break;
936 }
937
938 qdf_nbuf_peek_header(urb_context->buf, &data, &len);
939
940 urb = urb_context->urb;
941
942 usb_fill_bulk_urb(urb,
943 recv_pipe->device->udev,
944 recv_pipe->usb_pipe_handle,
945 data,
946 buffer_length,
947 usb_hif_usb_recv_complete, urb_context);
948
Jeff Johnsonb9450212017-09-18 10:12:38 -0700949 HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -0700950 recv_pipe->logical_pipe_num,
951 recv_pipe->usb_pipe_handle,
952 recv_pipe->ep_address, buffer_length,
953 urb_context->buf);
954
955 usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
956
957 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
958
959 if (usb_status) {
960 HIF_ERROR("athusb : usb bulk recv failed %d",
961 usb_status);
962 usb_hif_remove_pending_transfer(urb_context);
963 usb_hif_cleanup_recv_urb(urb_context);
964 break;
965 }
966 }
967
968 HIF_TRACE("-%s", __func__);
969
970}
971
972/**
973 * usb_hif_post_recv_bundle_transfers() - post recv urbs for a given pipe
974 * @recv_pipe: recv pipe for which urbs need to be posted
975 * @buffer_length: maximum length of rx bundle
976 *
977 * Return: none
978 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700979static void usb_hif_post_recv_bundle_transfers(struct HIF_USB_PIPE *recv_pipe,
Mohit Khannabda5d432016-05-11 11:09:21 -0700980 int buffer_length)
981{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -0700982 struct HIF_URB_CONTEXT *urb_context;
Mohit Khannabda5d432016-05-11 11:09:21 -0700983 uint8_t *data;
984 uint32_t len;
985 struct urb *urb;
986 int usb_status;
987
988 HIF_TRACE("+%s", __func__);
989
990 while (1) {
991
992 urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
993 if (NULL == urb_context)
994 break;
995
996 if (NULL == urb_context->buf) {
997 urb_context->buf =
998 qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
999 if (NULL == urb_context->buf) {
1000 usb_hif_cleanup_recv_urb(urb_context);
1001 break;
1002 }
1003 }
1004
1005 qdf_nbuf_peek_header(urb_context->buf, &data, &len);
1006
1007 urb = urb_context->urb;
1008 usb_fill_bulk_urb(urb,
1009 recv_pipe->device->udev,
1010 recv_pipe->usb_pipe_handle,
1011 data,
1012 buffer_length,
1013 usb_hif_usb_recv_bundle_complete,
1014 urb_context);
1015
Jeff Johnsonb9450212017-09-18 10:12:38 -07001016 HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
Mohit Khannabda5d432016-05-11 11:09:21 -07001017 recv_pipe->logical_pipe_num,
1018 recv_pipe->usb_pipe_handle,
1019 recv_pipe->ep_address, buffer_length,
1020 urb_context->buf);
1021
1022 usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
1023
1024 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
1025
1026 if (usb_status) {
1027 HIF_ERROR("athusb : usb bulk recv failed %d",
1028 usb_status);
1029 usb_hif_remove_pending_transfer(urb_context);
1030 usb_hif_free_urb_to_pipe(urb_context->pipe,
1031 urb_context);
1032 break;
1033 }
1034
1035 }
1036
1037 HIF_TRACE("-%s", __func__);
1038
1039}
1040
1041/**
1042 * usb_hif_prestart_recv_pipes() - post prestart recv urbs
1043 * @device: HIF device for which prestart recv urbs need to be posted
1044 *
1045 * Return: none
1046 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301047void usb_hif_prestart_recv_pipes(struct HIF_DEVICE_USB *device)
Mohit Khannabda5d432016-05-11 11:09:21 -07001048{
Ajit Pal Singhcd4a1c42018-06-13 12:25:16 +05301049 struct HIF_USB_PIPE *pipe;
1050 int prestart_cnt = 8;
Mohit Khannabda5d432016-05-11 11:09:21 -07001051
Ajit Pal Singhcd4a1c42018-06-13 12:25:16 +05301052 if (device->rx_ctrl_pipe_supported) {
1053 pipe = &device->pipes[HIF_RX_CTRL_PIPE];
1054 prestart_cnt = 4;
1055 usb_hif_post_recv_prestart_transfers(pipe, prestart_cnt);
1056 }
Mohit Khannabda5d432016-05-11 11:09:21 -07001057 /*
1058 * USB driver learn to support bundle or not until the firmware
1059 * download and ready. Only allocate some URBs for control message
1060 * communication during the initial phase then start the final
1061 * working pipe after all information understood.
1062 */
Ajit Pal Singhcd4a1c42018-06-13 12:25:16 +05301063 pipe = &device->pipes[HIF_RX_DATA_PIPE];
1064 usb_hif_post_recv_prestart_transfers(pipe, prestart_cnt);
Mohit Khannabda5d432016-05-11 11:09:21 -07001065}
1066
1067/**
1068 * usb_hif_start_recv_pipes() - start recv urbs
1069 * @device: HIF device for which recv urbs need to be posted
1070 *
1071 * This function is called after all prestart recv urbs are exhausted
1072 *
1073 * Return: none
1074 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301075void usb_hif_start_recv_pipes(struct HIF_DEVICE_USB *device)
Mohit Khannabda5d432016-05-11 11:09:21 -07001076{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001077 struct HIF_USB_PIPE *pipe;
Mohit Khannabda5d432016-05-11 11:09:21 -07001078 uint32_t buf_len;
1079
1080 HIF_ENTER();
1081 pipe = &device->pipes[HIF_RX_DATA_PIPE];
1082 pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1083
1084 HIF_TRACE("Post URBs to RX_DATA_PIPE: %d",
1085 device->pipes[HIF_RX_DATA_PIPE].urb_cnt);
1086 if (device->is_bundle_enabled) {
1087 usb_hif_post_recv_bundle_transfers(pipe,
1088 pipe->device->rx_bundle_buf_len);
1089 } else {
1090 buf_len = HIF_USB_RX_BUFFER_SIZE;
1091 usb_hif_post_recv_transfers(pipe, buf_len);
1092 }
1093
1094 HIF_DBG("athusb bulk recv len %d", buf_len);
1095
1096 if (!hif_usb_disable_rxdata2) {
1097 HIF_TRACE("Post URBs to RX_DATA2_PIPE: %d",
1098 device->pipes[HIF_RX_DATA2_PIPE].urb_cnt);
1099
1100 pipe = &device->pipes[HIF_RX_DATA2_PIPE];
1101 pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1102 usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE);
1103 }
1104
Ajit Pal Singhcd4a1c42018-06-13 12:25:16 +05301105 if (device->rx_ctrl_pipe_supported) {
1106 HIF_TRACE("Post URBs to RX_CONTROL_PIPE: %d",
1107 device->pipes[HIF_RX_CTRL_PIPE].urb_cnt);
1108
1109 pipe = &device->pipes[HIF_RX_CTRL_PIPE];
1110 pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1111 usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE);
1112 }
Mohit Khannabda5d432016-05-11 11:09:21 -07001113 HIF_EXIT();
1114}
1115
1116/**
1117 * usb_hif_submit_ctrl_out() - send out a ctrl urb
1118 * @device: HIF device for which urb needs to be posted
1119 * @req: request value for the ctrl message
1120 * @value: USB message value
1121 * @index: USB message index value
1122 * @data: pointer to data containing ctrl message to send
1123 * @size: size of the control message to send
1124 *
1125 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1126 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301127QDF_STATUS usb_hif_submit_ctrl_out(struct HIF_DEVICE_USB *device,
1128 uint8_t req, uint16_t value, uint16_t index,
1129 void *data, uint32_t size)
Mohit Khannabda5d432016-05-11 11:09:21 -07001130{
1131 int32_t result = 0;
1132 QDF_STATUS ret = QDF_STATUS_SUCCESS;
1133 uint8_t *buf = NULL;
1134
1135 do {
1136
1137 if (size > 0) {
1138 buf = qdf_mem_malloc(size);
1139 if (NULL == buf) {
1140 ret = QDF_STATUS_E_NOMEM;
1141 break;
1142 }
1143 qdf_mem_copy(buf, (uint8_t *) data, size);
1144 }
1145
1146 HIF_DBG("ctrl-out req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1147 req, value, index, size);
1148
1149 result = usb_control_msg(device->udev,
1150 usb_sndctrlpipe(device->udev, 0),
1151 req,
1152 USB_DIR_OUT | USB_TYPE_VENDOR |
1153 USB_RECIP_DEVICE, value, index, buf,
1154 size, 2 * HZ);
1155
1156 if (result < 0) {
1157 HIF_ERROR("%s failed,result = %d", __func__, result);
1158 ret = QDF_STATUS_E_FAILURE;
1159 }
1160
1161 } while (false);
1162
1163 if (buf != NULL)
1164 qdf_mem_free(buf);
1165
1166 return ret;
1167}
1168
1169/**
1170 * usb_hif_submit_ctrl_in() - recv a resonse to the ctrl message sent out
1171 * @device: HIF device for which urb needs to be received
1172 * @req: request value for the ctrl message
1173 * @value: USB message value
1174 * @index: USB message index value
1175 * @data: pointer to data containing ctrl message to be received
1176 * @size: size of the control message to be received
1177 *
1178 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1179 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301180QDF_STATUS usb_hif_submit_ctrl_in(struct HIF_DEVICE_USB *device,
1181 uint8_t req, uint16_t value, uint16_t index,
1182 void *data, uint32_t size)
Mohit Khannabda5d432016-05-11 11:09:21 -07001183{
1184 int32_t result = 0;
1185 QDF_STATUS ret = QDF_STATUS_SUCCESS;
1186 uint8_t *buf = NULL;
1187
1188 do {
1189
1190 if (size > 0) {
1191 buf = qdf_mem_malloc(size);
1192 if (NULL == buf) {
1193 ret = QDF_STATUS_E_NOMEM;
1194 break;
1195 }
1196 }
1197
1198 HIF_DBG("ctrl-in req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1199 req, value, index, size);
1200
1201 result = usb_control_msg(device->udev,
1202 usb_rcvctrlpipe(device->udev, 0),
1203 req,
1204 USB_DIR_IN | USB_TYPE_VENDOR |
1205 USB_RECIP_DEVICE, value, index, buf,
1206 size, 2 * HZ);
1207
1208 if (result < 0) {
1209 HIF_ERROR("%s failed, result = %d", __func__, result);
1210 ret = QDF_STATUS_E_FAILURE;
1211 break;
1212 }
1213
1214 qdf_mem_copy((uint8_t *) data, buf, size);
1215
1216 } while (false);
1217
1218 if (buf != NULL)
1219 qdf_mem_free(buf);
1220
1221 return ret;
1222}
1223
1224/**
1225 * usb_hif_io_complete() - transmit call back for tx urb
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001226 * @pipe: pointer to struct HIF_USB_PIPE
Mohit Khannabda5d432016-05-11 11:09:21 -07001227 *
1228 * Return: none
1229 */
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301230static void usb_hif_io_complete(struct HIF_USB_PIPE *pipe)
Mohit Khannabda5d432016-05-11 11:09:21 -07001231{
1232 qdf_nbuf_t buf;
Nirav Shahd9dce6e2018-02-26 14:50:25 +05301233 struct HIF_DEVICE_USB *device;
Mohit Khannabda5d432016-05-11 11:09:21 -07001234 HTC_FRAME_HDR *HtcHdr;
1235 uint8_t *data;
1236 uint32_t len;
1237 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001238
Mohit Khannabda5d432016-05-11 11:09:21 -07001239 device = pipe->device;
Mohit Khannabda5d432016-05-11 11:09:21 -07001240 HIF_ENTER();
Mohit Khannabda5d432016-05-11 11:09:21 -07001241 while ((buf = skb_dequeue(&pipe->io_comp_queue))) {
1242 if (pipe->flags & HIF_USB_PIPE_FLAG_TX) {
Jeff Johnsonb9450212017-09-18 10:12:38 -07001243 HIF_DBG("+athusb xmit callback buf:0x%pK", buf);
Mohit Khannabda5d432016-05-11 11:09:21 -07001244 HtcHdr = (HTC_FRAME_HDR *)
1245 qdf_nbuf_get_frag_vaddr(buf, 0);
1246
1247#ifdef ATH_11AC_TXCOMPACT
1248/* ATH_11AC_TXCOMPACT does not support High Latency mode */
1249#else
1250 device->htc_callbacks.txCompletionHandler(device->
1251 htc_callbacks.
1252 Context, buf,
1253 HtcHdr->
1254 EndpointID, 0);
1255#endif
1256 HIF_DBG("-athusb xmit callback");
1257 } else {
Jeff Johnsonb9450212017-09-18 10:12:38 -07001258 HIF_DBG("+athusb recv callback buf: 0x%pK", buf);
Mohit Khannabda5d432016-05-11 11:09:21 -07001259 qdf_nbuf_peek_header(buf, &data, &len);
1260
1261 if (IS_FW_CRASH_DUMP(*((uint32_t *) data))) {
1262 sc->fw_data = data;
1263 sc->fw_data_len = len;
1264 device->htc_callbacks.fwEventHandler(
1265 device->htc_callbacks.Context,
1266 QDF_STATUS_E_USB_ERROR);
1267 qdf_nbuf_free(buf);
1268 } else {
1269 device->htc_callbacks.rxCompletionHandler(
1270 device->htc_callbacks.Context, buf,
1271 pipe->logical_pipe_num);
1272 }
1273 HIF_DBG("-athusb recv callback");
1274 }
1275 }
1276
1277 HIF_EXIT();
1278}
1279
1280#ifdef HIF_USB_TASKLET
1281/**
1282 * usb_hif_io_comp_tasklet() - per pipe tasklet routine
1283 * @context: pointer to HIF USB pipe
1284 *
1285 * Return: none
1286 */
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001287void usb_hif_io_comp_tasklet(unsigned long context)
Mohit Khannabda5d432016-05-11 11:09:21 -07001288{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001289 struct HIF_USB_PIPE *pipe = (struct HIF_USB_PIPE *) context;
1290
Mohit Khannabda5d432016-05-11 11:09:21 -07001291 usb_hif_io_complete(pipe);
1292}
1293
1294#else
1295/**
1296 * usb_hif_io_comp_work() - per pipe work queue
1297 * @work: pointer to struct work_struct
1298 *
1299 * Return: none
1300 */
1301void usb_hif_io_comp_work(struct work_struct *work)
1302{
Manikandan Mohanaf3fb2c2017-04-10 12:08:48 -07001303 struct HIF_USB_PIPE *pipe = container_of(work, struct HIF_USB_PIPE,
1304 io_complete_work);
1305
Mohit Khannabda5d432016-05-11 11:09:21 -07001306 usb_hif_io_complete(pipe);
1307}
1308#endif