xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/usb/usbdrv.c (revision c8e2987f9325baadee03d0265544a08c4a0217b0)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 #define ATH_MODULE_NAME hif
29 #include "a_debug.h"
30 #include "hif_usb_internal.h"
31 #include "if_usb.h"
32 #include "cds_api.h"
33 #include "hif_debug.h"
34 
35 #define IS_BULK_EP(attr) (((attr) & 3) == 0x02)
36 #define IS_INT_EP(attr) (((attr) & 3) == 0x03)
37 #define IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
38 #define IS_DIR_IN(addr) ((addr) & 0x80)
39 
40 #define IS_FW_CRASH_DUMP(x)(((x == FW_ASSERT_PATTERN) || \
41 				(x == FW_REG_PATTERN) || \
42 				((x & FW_RAMDUMP_PATTERN_MASK) ==  \
43 						FW_RAMDUMP_PATTERN)) ? 1 : 0)
44 
45 static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
46 					int buffer_length);
47 static void usb_hif_post_recv_bundle_transfers
48 						(struct HIF_USB_PIPE *recv_pipe,
49 						int buffer_length);
50 static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context);
51 
52 
53 /**
54  * usb_hif_free_urb_to_pipe() - add urb back to urb list of a pipe
55  * @pipe: pointer to struct HIF_USB_PIPE
56  * @urb_context: pointer to struct HIF_URB_CONTEXT
57  *
58  * Return: none
59  */
60 static void usb_hif_free_urb_to_pipe(struct HIF_USB_PIPE *pipe,
61 					struct HIF_URB_CONTEXT *urb_context)
62 {
63 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
64 	pipe->urb_cnt++;
65 	DL_ListAdd(&pipe->urb_list_head, &urb_context->link);
66 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
67 }
68 
69 /**
70  * usb_hif_alloc_urb_from_pipe() - remove urb back from urb list of a pipe
71  * @pipe: pointer to struct HIF_USB_PIPE
72  *
73  * Return: struct HIF_URB_CONTEXT urb context removed from the urb list
74  */
75 struct HIF_URB_CONTEXT *usb_hif_alloc_urb_from_pipe(struct HIF_USB_PIPE *pipe)
76 {
77 	struct HIF_URB_CONTEXT *urb_context = NULL;
78 	DL_LIST *item;
79 
80 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
81 	item = dl_list_remove_item_from_head(&pipe->urb_list_head);
82 	if (item != NULL) {
83 		urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
84 						  link);
85 		pipe->urb_cnt--;
86 	}
87 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
88 
89 	return urb_context;
90 }
91 
92 /**
93  * usb_hif_dequeue_pending_transfer() - remove urb from pending xfer list
94  * @pipe: pointer to struct HIF_USB_PIPE
95  *
96  * Return: struct HIF_URB_CONTEXT urb context removed from the pending xfer list
97  */
98 static struct HIF_URB_CONTEXT *usb_hif_dequeue_pending_transfer
99 						(struct HIF_USB_PIPE *pipe)
100 {
101 	struct HIF_URB_CONTEXT *urb_context = NULL;
102 	DL_LIST *item;
103 
104 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
105 	item = dl_list_remove_item_from_head(&pipe->urb_pending_list);
106 	if (item != NULL)
107 		urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
108 						  link);
109 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
110 
111 	return urb_context;
112 }
113 
114 /**
115  * usb_hif_enqueue_pending_transfer() - add urb to pending xfer list
116  * @pipe: pointer to struct HIF_USB_PIPE
117  * @urb_context: pointer to struct HIF_URB_CONTEXT to be added to the xfer list
118  *
119  * Return: none
120  */
121 void usb_hif_enqueue_pending_transfer(struct HIF_USB_PIPE *pipe,
122 					struct HIF_URB_CONTEXT *urb_context)
123 {
124 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
125 	dl_list_insert_tail(&pipe->urb_pending_list, &urb_context->link);
126 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
127 }
128 
129 
130 /**
131  * usb_hif_remove_pending_transfer() - remove urb from its own list
132  * @urb_context: pointer to struct HIF_URB_CONTEXT to be removed
133  *
134  * Return: none
135  */
136 void
137 usb_hif_remove_pending_transfer(struct HIF_URB_CONTEXT *urb_context)
138 {
139 	qdf_spin_lock_irqsave(&urb_context->pipe->device->cs_lock);
140 	dl_list_remove(&urb_context->link);
141 	qdf_spin_unlock_irqrestore(&urb_context->pipe->device->cs_lock);
142 }
143 
144 /**
145  * usb_hif_alloc_pipe_resources() - allocate urb_cnt urbs to a HIF pipe
146  * @pipe: pointer to struct HIF_USB_PIPE to which resources will be allocated
147  * @urb_cnt: number of urbs to be added to the HIF pipe
148  *
149  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
150  */
151 static QDF_STATUS usb_hif_alloc_pipe_resources
152 					(struct HIF_USB_PIPE *pipe, int urb_cnt)
153 {
154 	QDF_STATUS status = QDF_STATUS_SUCCESS;
155 	int i;
156 	struct HIF_URB_CONTEXT *urb_context;
157 
158 	DL_LIST_INIT(&pipe->urb_list_head);
159 	DL_LIST_INIT(&pipe->urb_pending_list);
160 
161 	for (i = 0; i < urb_cnt; i++) {
162 		urb_context = qdf_mem_malloc(sizeof(*urb_context));
163 		if (NULL == urb_context) {
164 			status = QDF_STATUS_E_NOMEM;
165 			HIF_ERROR("urb_context is null");
166 			break;
167 		}
168 		urb_context->pipe = pipe;
169 		urb_context->urb = usb_alloc_urb(0, GFP_KERNEL);
170 
171 		if (NULL == urb_context->urb) {
172 			status = QDF_STATUS_E_NOMEM;
173 			qdf_mem_free(urb_context);
174 			HIF_ERROR("urb_context->urb is null");
175 			break;
176 		}
177 
178 		/* note we are only allocate the urb contexts here, the actual
179 		 * URB is
180 		 * allocated from the kernel as needed to do a transaction
181 		 */
182 		pipe->urb_alloc++;
183 
184 		usb_hif_free_urb_to_pipe(pipe, urb_context);
185 	}
186 
187 	HIF_DBG("athusb: alloc resources lpipe:%d hpipe:0x%X urbs:%d",
188 		pipe->logical_pipe_num,
189 		pipe->usb_pipe_handle,
190 		pipe->urb_alloc);
191 	return status;
192 }
193 
194 /**
195  * usb_hif_free_pipe_resources() - free urb resources allocated to a HIF pipe
196  * @pipe: pointer to struct HIF_USB_PIPE
197  *
198  * Return: none
199  */
200 static void usb_hif_free_pipe_resources(struct HIF_USB_PIPE *pipe)
201 {
202 	struct HIF_URB_CONTEXT *urb_context;
203 
204 	if (NULL == pipe->device) {
205 		/* nothing allocated for this pipe */
206 		HIF_ERROR("pipe->device is null");
207 		return;
208 	}
209 
210 	HIF_TRACE("athusb: free resources lpipe:%d hpipe:0x%X urbs:%d avail:%d",
211 			 pipe->logical_pipe_num,
212 			 pipe->usb_pipe_handle, pipe->urb_alloc,
213 			 pipe->urb_cnt);
214 
215 	if (pipe->urb_alloc != pipe->urb_cnt) {
216 		HIF_ERROR("athusb: urb leak! lpipe:%d hpipe:0x%X urbs:%d avail:%d",
217 				 pipe->logical_pipe_num,
218 				 pipe->usb_pipe_handle, pipe->urb_alloc,
219 				 pipe->urb_cnt);
220 	}
221 
222 	while (true) {
223 		urb_context = usb_hif_alloc_urb_from_pipe(pipe);
224 		if (NULL == urb_context)
225 			break;
226 
227 		if (urb_context->buf) {
228 			qdf_nbuf_free(urb_context->buf);
229 			urb_context->buf = NULL;
230 		}
231 
232 		usb_free_urb(urb_context->urb);
233 		urb_context->urb = NULL;
234 		qdf_mem_free(urb_context);
235 	}
236 
237 }
238 
239 /**
240  * usb_hif_get_logical_pipe_num() - get pipe number for a particular enpoint
241  * @device: pointer to HIF_DEVICE_USB structure
242  * @ep_address: endpoint address
243  * @urb_count: number of urb resources to be allocated to the pipe
244  *
245  * Return: uint8_t pipe number corresponding to ep_address
246  */
247 static uint8_t usb_hif_get_logical_pipe_num
248 					(struct HIF_DEVICE_USB *device,
249 					uint8_t ep_address,
250 					int *urb_count)
251 {
252 	uint8_t pipe_num = HIF_USB_PIPE_INVALID;
253 
254 	switch (ep_address) {
255 	case USB_EP_ADDR_APP_CTRL_IN:
256 		pipe_num = HIF_RX_CTRL_PIPE;
257 		*urb_count = RX_URB_COUNT;
258 		break;
259 	case USB_EP_ADDR_APP_DATA_IN:
260 		pipe_num = HIF_RX_DATA_PIPE;
261 		*urb_count = RX_URB_COUNT;
262 		break;
263 	case USB_EP_ADDR_APP_INT_IN:
264 		pipe_num = HIF_RX_INT_PIPE;
265 		*urb_count = RX_URB_COUNT;
266 		break;
267 	case USB_EP_ADDR_APP_DATA2_IN:
268 		pipe_num = HIF_RX_DATA2_PIPE;
269 		*urb_count = RX_URB_COUNT;
270 		break;
271 	case USB_EP_ADDR_APP_CTRL_OUT:
272 		pipe_num = HIF_TX_CTRL_PIPE;
273 		*urb_count = TX_URB_COUNT;
274 		break;
275 	case USB_EP_ADDR_APP_DATA_LP_OUT:
276 		pipe_num = HIF_TX_DATA_LP_PIPE;
277 		*urb_count = TX_URB_COUNT;
278 		break;
279 	case USB_EP_ADDR_APP_DATA_MP_OUT:
280 		pipe_num = HIF_TX_DATA_MP_PIPE;
281 		*urb_count = TX_URB_COUNT;
282 		break;
283 	case USB_EP_ADDR_APP_DATA_HP_OUT:
284 		pipe_num = HIF_TX_DATA_HP_PIPE;
285 		*urb_count = TX_URB_COUNT;
286 		break;
287 	default:
288 		/* note: there may be endpoints not currently used */
289 		break;
290 	}
291 
292 	return pipe_num;
293 }
294 
295 /**
296  * usb_hif_get_logical_pipe_num() - setup urb resources for all pipes
297  * @device: pointer to HIF_DEVICE_USB structure
298  *
299  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
300  */
301 QDF_STATUS usb_hif_setup_pipe_resources(struct HIF_DEVICE_USB *device)
302 {
303 	struct usb_interface *interface = device->interface;
304 	struct usb_host_interface *iface_desc = interface->cur_altsetting;
305 	struct usb_endpoint_descriptor *endpoint;
306 	int i;
307 	int urbcount;
308 	QDF_STATUS status = QDF_STATUS_SUCCESS;
309 	struct HIF_USB_PIPE *pipe;
310 	uint8_t pipe_num;
311 
312 	/* walk decriptors and setup pipes */
313 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
314 		endpoint = &iface_desc->endpoint[i].desc;
315 
316 		if (IS_BULK_EP(endpoint->bmAttributes)) {
317 			HIF_DBG("%s Bulk Ep:0x%2.2X maxpktsz:%d",
318 				IS_DIR_IN(endpoint->bEndpointAddress) ?
319 								"RX" : "TX",
320 				endpoint->bEndpointAddress,
321 				qdf_le16_to_cpu(endpoint->wMaxPacketSize));
322 		} else if (IS_INT_EP(endpoint->bmAttributes)) {
323 			HIF_DBG("%s Int Ep:0x%2.2X maxpktsz:%d interval:%d",
324 				IS_DIR_IN(endpoint->bEndpointAddress) ?
325 								"RX" : "TX",
326 				endpoint->bEndpointAddress,
327 				qdf_le16_to_cpu(endpoint->wMaxPacketSize),
328 				endpoint->bInterval);
329 		} else if (IS_ISOC_EP(endpoint->bmAttributes)) {
330 			/* TODO for ISO */
331 			HIF_DBG("%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d",
332 				IS_DIR_IN(endpoint->bEndpointAddress) ?
333 								"RX" : "TX",
334 				endpoint->bEndpointAddress,
335 				qdf_le16_to_cpu(endpoint->wMaxPacketSize),
336 				endpoint->bInterval);
337 		}
338 		urbcount = 0;
339 
340 		pipe_num = usb_hif_get_logical_pipe_num(device,
341 						endpoint->bEndpointAddress,
342 						&urbcount);
343 		if (HIF_USB_PIPE_INVALID == pipe_num)
344 			continue;
345 
346 		pipe = &device->pipes[pipe_num];
347 		if (pipe->device != NULL) {
348 			/*pipe was already setup */
349 			continue;
350 		}
351 
352 		pipe->device = device;
353 		pipe->logical_pipe_num = pipe_num;
354 		pipe->ep_address = endpoint->bEndpointAddress;
355 		pipe->max_packet_size =
356 			qdf_le16_to_cpu(endpoint->wMaxPacketSize);
357 
358 		if (IS_BULK_EP(endpoint->bmAttributes)) {
359 			if (IS_DIR_IN(pipe->ep_address)) {
360 				pipe->usb_pipe_handle =
361 					usb_rcvbulkpipe(device->udev,
362 							pipe->ep_address);
363 			} else {
364 				pipe->usb_pipe_handle =
365 					usb_sndbulkpipe(device->udev,
366 						pipe->ep_address);
367 			}
368 		} else if (IS_INT_EP(endpoint->bmAttributes)) {
369 			if (IS_DIR_IN(pipe->ep_address)) {
370 				pipe->usb_pipe_handle =
371 					usb_rcvintpipe(device->udev,
372 						pipe->ep_address);
373 			} else {
374 				pipe->usb_pipe_handle =
375 					usb_sndintpipe(device->udev,
376 						pipe->ep_address);
377 			}
378 		} else if (IS_ISOC_EP(endpoint->bmAttributes)) {
379 			/* TODO for ISO */
380 			if (IS_DIR_IN(pipe->ep_address)) {
381 				pipe->usb_pipe_handle =
382 					usb_rcvisocpipe(device->udev,
383 						pipe->ep_address);
384 			} else {
385 				pipe->usb_pipe_handle =
386 					usb_sndisocpipe(device->udev,
387 						pipe->ep_address);
388 			}
389 		}
390 		pipe->ep_desc = endpoint;
391 
392 		if (!IS_DIR_IN(pipe->ep_address))
393 			pipe->flags |= HIF_USB_PIPE_FLAG_TX;
394 
395 		status = usb_hif_alloc_pipe_resources(pipe, urbcount);
396 
397 		if (!QDF_IS_STATUS_SUCCESS(status))
398 			break;
399 
400 	}
401 
402 	return status;
403 }
404 
405 
406 /**
407  * usb_hif_cleanup_pipe_resources() - free urb resources for all pipes
408  * @device: pointer to HIF_DEVICE_USB structure
409  *
410  * Return: none
411  */
412 void usb_hif_cleanup_pipe_resources(struct HIF_DEVICE_USB *device)
413 {
414 	int i;
415 
416 	for (i = 0; i < HIF_USB_PIPE_MAX; i++)
417 		usb_hif_free_pipe_resources(&device->pipes[i]);
418 }
419 
420 /**
421  * usb_hif_flush_pending_transfers() - kill pending urbs for a pipe
422  * @pipe: pointer to struct HIF_USB_PIPE structure
423  *
424  * Return: none
425  */
426 static void usb_hif_flush_pending_transfers(struct HIF_USB_PIPE *pipe)
427 {
428 	struct HIF_URB_CONTEXT *urb_context;
429 
430 	HIF_TRACE("+%s pipe : %d", __func__, pipe->logical_pipe_num);
431 
432 	while (1) {
433 		urb_context = usb_hif_dequeue_pending_transfer(pipe);
434 		if (NULL == urb_context) {
435 			HIF_WARN("urb_context is NULL");
436 			break;
437 		}
438 		HIF_TRACE("  pending urb ctxt: 0x%pK", urb_context);
439 		if (urb_context->urb != NULL) {
440 			HIF_TRACE("  killing urb: 0x%pK", urb_context->urb);
441 			/* killing the URB will cause the completion routines to
442 			 * run
443 			 */
444 			usb_kill_urb(urb_context->urb);
445 		}
446 	}
447 	HIF_TRACE("-%s", __func__);
448 }
449 
450 /**
451  * usb_hif_flush_all() - flush pending transfers for all pipes for a usb bus
452  * @device: pointer to HIF_DEVICE_USB structure
453  *
454  * Return: none
455  */
456 void usb_hif_flush_all(struct HIF_DEVICE_USB *device)
457 {
458 	int i;
459 	struct HIF_USB_PIPE *pipe;
460 
461 	HIF_TRACE("+%s", __func__);
462 
463 	for (i = 0; i < HIF_USB_PIPE_MAX; i++) {
464 		if (device->pipes[i].device != NULL) {
465 			usb_hif_flush_pending_transfers(&device->pipes[i]);
466 			pipe = &device->pipes[i];
467 
468 		HIF_USB_FLUSH_WORK(pipe);
469 		}
470 	}
471 
472 	HIF_TRACE("-%s", __func__);
473 }
474 
475 /**
476  * usb_hif_cleanup_recv_urb() - cleanup recv urb
477  * @urb_context: pointer to struct HIF_URB_CONTEXT structure
478  *
479  * Return: none
480  */
481 static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context)
482 {
483 	HIF_TRACE("+%s", __func__);
484 
485 	if (urb_context->buf != NULL) {
486 		qdf_nbuf_free(urb_context->buf);
487 		urb_context->buf = NULL;
488 	}
489 
490 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
491 	HIF_TRACE("-%s", __func__);
492 }
493 
494 /**
495  * usb_hif_cleanup_transmit_urb() - cleanup transmit urb
496  * @urb_context: pointer to struct HIF_URB_CONTEXT structure
497  *
498  * Return: none
499  */
500 void usb_hif_cleanup_transmit_urb(struct HIF_URB_CONTEXT *urb_context)
501 {
502 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
503 }
504 
505 /**
506  * usb_hif_usb_recv_prestart_complete() - completion routine for prestart rx urb
507  * @urb: urb for which the completion routine is being called
508  *
509  * Return: none
510  */
511 static void usb_hif_usb_recv_prestart_complete
512 							(struct urb *urb)
513 {
514 	struct HIF_URB_CONTEXT *urb_context =
515 					(struct HIF_URB_CONTEXT *) urb->context;
516 	QDF_STATUS status = QDF_STATUS_SUCCESS;
517 	qdf_nbuf_t buf = NULL;
518 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
519 
520 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
521 		__func__,
522 		pipe->logical_pipe_num,
523 		urb->status, urb->actual_length,
524 		urb);
525 
526 	/* this urb is not pending anymore */
527 	usb_hif_remove_pending_transfer(urb_context);
528 	do {
529 		if (urb->status != 0) {
530 			status = A_ECOMM;
531 			switch (urb->status) {
532 			case -ECONNRESET:
533 			case -ENOENT:
534 			case -ESHUTDOWN:
535 				/* NOTE: no need to spew these errors when
536 				 * device is removed
537 				 * or urb is killed due to driver shutdown
538 				 */
539 				status = A_ECANCELED;
540 				break;
541 			default:
542 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
543 					__func__,
544 					pipe->logical_pipe_num,
545 					pipe->ep_address,
546 					urb->status);
547 				break;
548 			}
549 			break;
550 		}
551 		if (urb->actual_length == 0)
552 			break;
553 		buf = urb_context->buf;
554 		/* we are going to pass it up */
555 		urb_context->buf = NULL;
556 		qdf_nbuf_put_tail(buf, urb->actual_length);
557 
558 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
559 			uint8_t *data;
560 			uint32_t len;
561 
562 			qdf_nbuf_peek_header(buf, &data, &len);
563 			debug_dump_bytes(data, len, "hif recv data");
564 		}
565 		/* note: queue implements a lock */
566 		skb_queue_tail(&pipe->io_comp_queue, buf);
567 
568 		HIF_USB_SCHEDULE_WORK(pipe);
569 	} while (false);
570 
571 	usb_hif_cleanup_recv_urb(urb_context);
572 
573 	/* Prestart URBs runs out and now start working receive pipe. */
574 	if (--pipe->urb_prestart_cnt == 0)
575 		usb_hif_start_recv_pipes(pipe->device);
576 
577 	HIF_DBG("-%s", __func__);
578 }
579 
580 /**
581  * usb_hif_usb_recv_complete() - completion routine for rx urb
582  * @urb: urb for which the completion routine is being called
583  *
584  * Return: none
585  */
586 static void usb_hif_usb_recv_complete(struct urb *urb)
587 {
588 	struct HIF_URB_CONTEXT *urb_context =
589 					(struct HIF_URB_CONTEXT *) urb->context;
590 	QDF_STATUS status = QDF_STATUS_SUCCESS;
591 	qdf_nbuf_t buf = NULL;
592 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
593 	struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
594 
595 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
596 		__func__,
597 		pipe->logical_pipe_num,
598 		urb->status, urb->actual_length,
599 		urb);
600 
601 	/* this urb is not pending anymore */
602 	usb_hif_remove_pending_transfer(urb_context);
603 
604 	do {
605 
606 		if (urb->status != 0) {
607 			status = A_ECOMM;
608 			switch (urb->status) {
609 #ifdef RX_SG_SUPPORT
610 			case -EOVERFLOW:
611 				urb->actual_length = HIF_USB_RX_BUFFER_SIZE;
612 				status = QDF_STATUS_SUCCESS;
613 				break;
614 #endif
615 			case -ECONNRESET:
616 			case -ENOENT:
617 			case -ESHUTDOWN:
618 				/* NOTE: no need to spew these errors when
619 				 * device is removed
620 				 * or urb is killed due to driver shutdown
621 				 */
622 				status = A_ECANCELED;
623 				break;
624 			default:
625 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
626 					__func__,
627 					pipe->logical_pipe_num,
628 					pipe->ep_address,
629 					urb->status);
630 				break;
631 			}
632 			break;
633 		}
634 		if (urb->actual_length == 0)
635 			break;
636 		buf = urb_context->buf;
637 		/* we are going to pass it up */
638 		urb_context->buf = NULL;
639 		qdf_nbuf_put_tail(buf, urb->actual_length);
640 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
641 			uint8_t *data;
642 			uint32_t len;
643 
644 			qdf_nbuf_peek_header(buf, &data, &len);
645 			debug_dump_bytes(data, len, "hif recv data");
646 		}
647 		/* note: queue implements a lock */
648 		skb_queue_tail(&pipe->io_comp_queue, buf);
649 		HIF_USB_SCHEDULE_WORK(pipe);
650 	} while (false);
651 
652 	usb_hif_cleanup_recv_urb(urb_context);
653 
654 	/* Only re-submit URB when STATUS is success and HIF is not at the
655 	 * suspend state.
656 	 */
657 	if (QDF_IS_STATUS_SUCCESS(status) && !sc->suspend_state) {
658 		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
659 			/* our free urbs are piling up, post more transfers */
660 			usb_hif_post_recv_transfers(pipe,
661 						HIF_USB_RX_BUFFER_SIZE);
662 		}
663 	} else {
664 		HIF_ERROR("%s:  pipe: %d, fail to post URB: status(%d) suspend (%d)",
665 				__func__,
666 				pipe->logical_pipe_num,
667 				urb->status,
668 				sc->suspend_state);
669 	}
670 
671 	HIF_DBG("-%s", __func__);
672 }
673 
674 /**
675  * usb_hif_usb_recv_bundle_complete() - completion routine for rx bundling urb
676  * @urb: urb for which the completion routine is being called
677  *
678  * Return: none
679  */
680 static void usb_hif_usb_recv_bundle_complete(struct urb *urb)
681 {
682 	struct HIF_URB_CONTEXT *urb_context =
683 					(struct HIF_URB_CONTEXT *) urb->context;
684 	QDF_STATUS status = QDF_STATUS_SUCCESS;
685 	qdf_nbuf_t buf = NULL;
686 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
687 	uint8_t *netdata, *netdata_new;
688 	uint32_t netlen, netlen_new;
689 	HTC_FRAME_HDR *HtcHdr;
690 	uint16_t payloadLen;
691 	qdf_nbuf_t new_skb = NULL;
692 
693 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
694 		__func__,
695 		pipe->logical_pipe_num,
696 		urb->status, urb->actual_length,
697 		urb);
698 
699 	/* this urb is not pending anymore */
700 	usb_hif_remove_pending_transfer(urb_context);
701 
702 	do {
703 
704 		if (urb->status != 0) {
705 			status = A_ECOMM;
706 			switch (urb->status) {
707 			case -ECONNRESET:
708 			case -ENOENT:
709 			case -ESHUTDOWN:
710 				/* NOTE: no need to spew these errors when
711 				 * device is removed
712 				 * or urb is killed due to driver shutdown
713 				 */
714 				status = A_ECANCELED;
715 				break;
716 			default:
717 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
718 					__func__,
719 					pipe->logical_pipe_num,
720 					pipe->ep_address,
721 					urb->status);
722 				break;
723 			}
724 			break;
725 		}
726 		if (urb->actual_length == 0)
727 			break;
728 		buf = urb_context->buf;
729 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
730 			uint8_t *data;
731 			uint32_t len;
732 
733 			qdf_nbuf_peek_header(buf, &data, &len);
734 			debug_dump_bytes(data, len, "hif recv data");
735 		}
736 
737 		qdf_nbuf_peek_header(buf, &netdata, &netlen);
738 		netlen = urb->actual_length;
739 
740 		do {
741 			uint16_t frame_len;
742 
743 			if (IS_FW_CRASH_DUMP(*(uint32_t *) netdata))
744 				frame_len = netlen;
745 			else {
746 				/* Hack into HTC header for bundle processing */
747 				HtcHdr = (HTC_FRAME_HDR *) netdata;
748 				if (HtcHdr->EndpointID >= ENDPOINT_MAX) {
749 					HIF_ERROR("athusb: Rx: invalid EndpointID=%d",
750 						HtcHdr->EndpointID);
751 					break;
752 				}
753 
754 				payloadLen = HtcHdr->PayloadLen;
755 				payloadLen = qdf_le16_to_cpu(payloadLen);
756 
757 				if (payloadLen > HIF_USB_RX_BUFFER_SIZE) {
758 					HIF_ERROR("athusb: payloadLen too long %u",
759 						payloadLen);
760 					break;
761 				}
762 				frame_len = (HTC_HDR_LENGTH + payloadLen);
763 			}
764 
765 			if (netlen < frame_len) {
766 				HIF_ERROR("athusb: subframe length %d not fitted into bundle packet length %d"
767 					, netlen, frame_len);
768 				break;
769 			}
770 
771 			/* allocate a new skb and copy */
772 			new_skb =
773 				qdf_nbuf_alloc(NULL, frame_len, 0, 4, false);
774 			if (new_skb == NULL) {
775 				HIF_ERROR("athusb: allocate skb (len=%u) failed"
776 						, frame_len);
777 				break;
778 			}
779 
780 			qdf_nbuf_peek_header(new_skb, &netdata_new,
781 						&netlen_new);
782 			qdf_mem_copy(netdata_new, netdata, frame_len);
783 			qdf_nbuf_put_tail(new_skb, frame_len);
784 			skb_queue_tail(&pipe->io_comp_queue, new_skb);
785 			new_skb = NULL;
786 			netdata += frame_len;
787 			netlen -= frame_len;
788 		} while (netlen);
789 		HIF_USB_SCHEDULE_WORK(pipe);
790 	} while (false);
791 
792 	if (urb_context->buf == NULL)
793 		HIF_ERROR("athusb: buffer in urb_context is NULL");
794 
795 	/* reset urb_context->buf ==> seems not necessary */
796 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
797 
798 	if (QDF_IS_STATUS_SUCCESS(status)) {
799 		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
800 			/* our free urbs are piling up, post more transfers */
801 			usb_hif_post_recv_bundle_transfers(pipe,
802 					pipe->device->rx_bundle_buf_len);
803 		}
804 	}
805 
806 	HIF_DBG("-%s", __func__);
807 }
808 
809 /**
810  * usb_hif_post_recv_prestart_transfers() - post prestart recv urbs for a pipe
811  * @recv_pipe: rx data pipe
812  * @prestart_urb: number of prestart recv urbs to be posted
813  *
814  * Return: none
815  */
816 static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe,
817 						int prestart_urb)
818 {
819 	struct HIF_URB_CONTEXT *urb_context;
820 	uint8_t *data;
821 	uint32_t len;
822 	struct urb *urb;
823 	int i, usb_status, buffer_length = HIF_USB_RX_BUFFER_SIZE;
824 
825 	HIF_TRACE("+%s", __func__);
826 
827 	for (i = 0; i < prestart_urb; i++) {
828 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
829 		if (NULL == urb_context)
830 			break;
831 
832 		urb_context->buf =
833 			qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
834 		if (NULL == urb_context->buf) {
835 			usb_hif_cleanup_recv_urb(urb_context);
836 			break;
837 		}
838 
839 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
840 
841 		urb = urb_context->urb;
842 
843 		usb_fill_bulk_urb(urb,
844 				recv_pipe->device->udev,
845 				recv_pipe->usb_pipe_handle,
846 				data,
847 				buffer_length,
848 				usb_hif_usb_recv_prestart_complete,
849 				urb_context);
850 
851 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
852 			recv_pipe->logical_pipe_num,
853 			recv_pipe->usb_pipe_handle,
854 			recv_pipe->ep_address, buffer_length,
855 			urb_context->buf);
856 
857 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
858 
859 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
860 
861 		if (usb_status) {
862 			HIF_ERROR("athusb : usb bulk recv failed %d",
863 				usb_status);
864 			usb_hif_remove_pending_transfer(urb_context);
865 			usb_hif_cleanup_recv_urb(urb_context);
866 			break;
867 		}
868 		recv_pipe->urb_prestart_cnt++;
869 	}
870 
871 	HIF_TRACE("-%s", __func__);
872 }
873 
874 /**
875  * usb_hif_post_recv_transfers() - post recv urbs for a given pipe
876  * @recv_pipe: recv pipe for which urbs need to be posted
877  * @buffer_length: buffer length of the recv urbs
878  *
879  * Return: none
880  */
881 static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
882 							int buffer_length)
883 {
884 	struct HIF_URB_CONTEXT *urb_context;
885 	uint8_t *data;
886 	uint32_t len;
887 	struct urb *urb;
888 	int usb_status;
889 
890 	HIF_TRACE("+%s", __func__);
891 
892 	while (1) {
893 
894 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
895 		if (NULL == urb_context)
896 			break;
897 
898 		urb_context->buf = qdf_nbuf_alloc(NULL, buffer_length, 0,
899 						4, false);
900 		if (NULL == urb_context->buf) {
901 			usb_hif_cleanup_recv_urb(urb_context);
902 			break;
903 		}
904 
905 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
906 
907 		urb = urb_context->urb;
908 
909 		usb_fill_bulk_urb(urb,
910 				recv_pipe->device->udev,
911 				recv_pipe->usb_pipe_handle,
912 				data,
913 				buffer_length,
914 				usb_hif_usb_recv_complete, urb_context);
915 
916 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
917 			recv_pipe->logical_pipe_num,
918 			recv_pipe->usb_pipe_handle,
919 			recv_pipe->ep_address, buffer_length,
920 			urb_context->buf);
921 
922 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
923 
924 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
925 
926 		if (usb_status) {
927 			HIF_ERROR("athusb : usb bulk recv failed %d",
928 				usb_status);
929 			usb_hif_remove_pending_transfer(urb_context);
930 			usb_hif_cleanup_recv_urb(urb_context);
931 			break;
932 		}
933 	}
934 
935 	HIF_TRACE("-%s", __func__);
936 
937 }
938 
939 /**
940  * usb_hif_post_recv_bundle_transfers() - post recv urbs for a given pipe
941  * @recv_pipe: recv pipe for which urbs need to be posted
942  * @buffer_length: maximum length of rx bundle
943  *
944  * Return: none
945  */
946 static void usb_hif_post_recv_bundle_transfers(struct HIF_USB_PIPE *recv_pipe,
947 						int buffer_length)
948 {
949 	struct HIF_URB_CONTEXT *urb_context;
950 	uint8_t *data;
951 	uint32_t len;
952 	struct urb *urb;
953 	int usb_status;
954 
955 	HIF_TRACE("+%s", __func__);
956 
957 	while (1) {
958 
959 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
960 		if (NULL == urb_context)
961 			break;
962 
963 		if (NULL == urb_context->buf) {
964 			urb_context->buf =
965 			qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
966 			if (NULL == urb_context->buf) {
967 				usb_hif_cleanup_recv_urb(urb_context);
968 				break;
969 			}
970 		}
971 
972 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
973 
974 		urb = urb_context->urb;
975 		usb_fill_bulk_urb(urb,
976 				recv_pipe->device->udev,
977 				recv_pipe->usb_pipe_handle,
978 				data,
979 				buffer_length,
980 				usb_hif_usb_recv_bundle_complete,
981 				urb_context);
982 
983 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
984 			recv_pipe->logical_pipe_num,
985 			recv_pipe->usb_pipe_handle,
986 			recv_pipe->ep_address, buffer_length,
987 			urb_context->buf);
988 
989 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
990 
991 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
992 
993 		if (usb_status) {
994 			HIF_ERROR("athusb : usb bulk recv failed %d",
995 				usb_status);
996 			usb_hif_remove_pending_transfer(urb_context);
997 			usb_hif_free_urb_to_pipe(urb_context->pipe,
998 						urb_context);
999 			break;
1000 		}
1001 
1002 	}
1003 
1004 	HIF_TRACE("-%s", __func__);
1005 
1006 }
1007 
1008 /**
1009  * usb_hif_prestart_recv_pipes() - post prestart recv urbs
1010  * @device: HIF device for which prestart recv urbs need to be posted
1011  *
1012  * Return: none
1013  */
1014 void usb_hif_prestart_recv_pipes(struct HIF_DEVICE_USB *device)
1015 {
1016 	struct HIF_USB_PIPE *pipe = &device->pipes[HIF_RX_DATA_PIPE];
1017 
1018 	/*
1019 	 * USB driver learn to support bundle or not until the firmware
1020 	 * download and ready. Only allocate some URBs for control message
1021 	 * communication during the initial phase then start the final
1022 	 * working pipe after all information understood.
1023 	 */
1024 	usb_hif_post_recv_prestart_transfers(pipe, 8);
1025 }
1026 
1027 /**
1028  * usb_hif_start_recv_pipes() - start recv urbs
1029  * @device: HIF device for which recv urbs need to be posted
1030  *
1031  * This function is called after all prestart recv urbs are exhausted
1032  *
1033  * Return: none
1034  */
1035 void usb_hif_start_recv_pipes(struct HIF_DEVICE_USB *device)
1036 {
1037 	struct HIF_USB_PIPE *pipe;
1038 	uint32_t buf_len;
1039 
1040 	HIF_ENTER();
1041 	pipe = &device->pipes[HIF_RX_DATA_PIPE];
1042 	pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1043 
1044 	HIF_TRACE("Post URBs to RX_DATA_PIPE: %d",
1045 		device->pipes[HIF_RX_DATA_PIPE].urb_cnt);
1046 	if (device->is_bundle_enabled) {
1047 		usb_hif_post_recv_bundle_transfers(pipe,
1048 					pipe->device->rx_bundle_buf_len);
1049 	} else {
1050 		buf_len = HIF_USB_RX_BUFFER_SIZE;
1051 		usb_hif_post_recv_transfers(pipe, buf_len);
1052 	}
1053 
1054 	HIF_DBG("athusb bulk recv len %d", buf_len);
1055 
1056 	if (!hif_usb_disable_rxdata2) {
1057 		HIF_TRACE("Post URBs to RX_DATA2_PIPE: %d",
1058 			device->pipes[HIF_RX_DATA2_PIPE].urb_cnt);
1059 
1060 		pipe = &device->pipes[HIF_RX_DATA2_PIPE];
1061 		pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1062 		usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE);
1063 	}
1064 
1065 	HIF_EXIT();
1066 }
1067 
1068 /**
1069  * usb_hif_submit_ctrl_out() - send out a ctrl urb
1070  * @device: HIF device for which urb needs to be posted
1071  * @req: request value for the ctrl message
1072  * @value: USB message value
1073  * @index: USB message index value
1074  * @data: pointer to data containing ctrl message to send
1075  * @size: size of the control message to send
1076  *
1077  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1078  */
1079 QDF_STATUS usb_hif_submit_ctrl_out(struct HIF_DEVICE_USB *device,
1080 				   uint8_t req, uint16_t value, uint16_t index,
1081 				   void *data, uint32_t size)
1082 {
1083 	int32_t result = 0;
1084 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1085 	uint8_t *buf = NULL;
1086 
1087 	do {
1088 
1089 		if (size > 0) {
1090 			buf = qdf_mem_malloc(size);
1091 			if (NULL == buf) {
1092 				ret = QDF_STATUS_E_NOMEM;
1093 				break;
1094 			}
1095 			qdf_mem_copy(buf, (uint8_t *) data, size);
1096 		}
1097 
1098 		HIF_DBG("ctrl-out req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1099 				req, value, index, size);
1100 
1101 		result = usb_control_msg(device->udev,
1102 					usb_sndctrlpipe(device->udev, 0),
1103 					req,
1104 					USB_DIR_OUT | USB_TYPE_VENDOR |
1105 					USB_RECIP_DEVICE, value, index, buf,
1106 					size, 2 * HZ);
1107 
1108 		if (result < 0) {
1109 			HIF_ERROR("%s failed,result = %d", __func__, result);
1110 			ret = QDF_STATUS_E_FAILURE;
1111 		}
1112 
1113 	} while (false);
1114 
1115 	if (buf != NULL)
1116 		qdf_mem_free(buf);
1117 
1118 	return ret;
1119 }
1120 
1121 /**
1122  * usb_hif_submit_ctrl_in() - recv a resonse to the ctrl message sent out
1123  * @device: HIF device for which urb needs to be received
1124  * @req: request value for the ctrl message
1125  * @value: USB message value
1126  * @index: USB message index value
1127  * @data: pointer to data containing ctrl message to be received
1128  * @size: size of the control message to be received
1129  *
1130  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1131  */
1132 QDF_STATUS usb_hif_submit_ctrl_in(struct HIF_DEVICE_USB *device,
1133 				  uint8_t req, uint16_t value, uint16_t index,
1134 				  void *data, uint32_t size)
1135 {
1136 	int32_t result = 0;
1137 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1138 	uint8_t *buf = NULL;
1139 
1140 	do {
1141 
1142 		if (size > 0) {
1143 			buf = qdf_mem_malloc(size);
1144 			if (NULL == buf) {
1145 				ret = QDF_STATUS_E_NOMEM;
1146 				break;
1147 			}
1148 		}
1149 
1150 		HIF_DBG("ctrl-in req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1151 				 req, value, index, size);
1152 
1153 		result = usb_control_msg(device->udev,
1154 					usb_rcvctrlpipe(device->udev, 0),
1155 					req,
1156 					USB_DIR_IN | USB_TYPE_VENDOR |
1157 					USB_RECIP_DEVICE, value, index, buf,
1158 					size, 2 * HZ);
1159 
1160 		if (result < 0) {
1161 			HIF_ERROR("%s failed, result = %d", __func__, result);
1162 			ret = QDF_STATUS_E_FAILURE;
1163 			break;
1164 		}
1165 
1166 		qdf_mem_copy((uint8_t *) data, buf, size);
1167 
1168 	} while (false);
1169 
1170 	if (buf != NULL)
1171 		qdf_mem_free(buf);
1172 
1173 	return ret;
1174 }
1175 
1176 /**
1177  * usb_hif_io_complete() - transmit call back for tx urb
1178  * @pipe: pointer to struct HIF_USB_PIPE
1179  *
1180  * Return: none
1181  */
1182 static void usb_hif_io_complete(struct HIF_USB_PIPE *pipe)
1183 {
1184 	qdf_nbuf_t buf;
1185 	struct HIF_DEVICE_USB *device;
1186 	HTC_FRAME_HDR *HtcHdr;
1187 	uint8_t *data;
1188 	uint32_t len;
1189 	struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
1190 
1191 	device = pipe->device;
1192 	HIF_ENTER();
1193 	while ((buf = skb_dequeue(&pipe->io_comp_queue))) {
1194 		if (pipe->flags & HIF_USB_PIPE_FLAG_TX) {
1195 			HIF_DBG("+athusb xmit callback buf:0x%pK", buf);
1196 			HtcHdr = (HTC_FRAME_HDR *)
1197 					qdf_nbuf_get_frag_vaddr(buf, 0);
1198 
1199 #ifdef ATH_11AC_TXCOMPACT
1200 /* ATH_11AC_TXCOMPACT does not support High Latency mode */
1201 #else
1202 			device->htc_callbacks.txCompletionHandler(device->
1203 								htc_callbacks.
1204 								Context, buf,
1205 								HtcHdr->
1206 								EndpointID, 0);
1207 #endif
1208 			HIF_DBG("-athusb xmit callback");
1209 		} else {
1210 			HIF_DBG("+athusb recv callback buf: 0x%pK", buf);
1211 			qdf_nbuf_peek_header(buf, &data, &len);
1212 
1213 			if (IS_FW_CRASH_DUMP(*((uint32_t *) data))) {
1214 				sc->fw_data = data;
1215 				sc->fw_data_len = len;
1216 				device->htc_callbacks.fwEventHandler(
1217 					device->htc_callbacks.Context,
1218 					QDF_STATUS_E_USB_ERROR);
1219 				qdf_nbuf_free(buf);
1220 			} else {
1221 				device->htc_callbacks.rxCompletionHandler(
1222 				device->htc_callbacks.Context, buf,
1223 				pipe->logical_pipe_num);
1224 			}
1225 			HIF_DBG("-athusb recv callback");
1226 		}
1227 	}
1228 
1229 	HIF_EXIT();
1230 }
1231 
1232 #ifdef HIF_USB_TASKLET
1233 /**
1234  * usb_hif_io_comp_tasklet() - per pipe tasklet routine
1235  * @context: pointer to HIF USB pipe
1236  *
1237  * Return: none
1238  */
1239 void usb_hif_io_comp_tasklet(unsigned long context)
1240 {
1241 	struct HIF_USB_PIPE *pipe = (struct HIF_USB_PIPE *) context;
1242 
1243 	usb_hif_io_complete(pipe);
1244 }
1245 
1246 #else
1247 /**
1248  * usb_hif_io_comp_work() - per pipe work queue
1249  * @work: pointer to struct work_struct
1250  *
1251  * Return: none
1252  */
1253 void usb_hif_io_comp_work(struct work_struct *work)
1254 {
1255 	struct HIF_USB_PIPE *pipe = container_of(work, struct HIF_USB_PIPE,
1256 						 io_complete_work);
1257 
1258 	usb_hif_io_complete(pipe);
1259 }
1260 #endif
1261