1 /*
2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <qdf_time.h>
21 #include <qdf_lock.h>
22 #include <qdf_mem.h>
23 #include <qdf_util.h>
24 #include <qdf_defer.h>
25 #include <qdf_atomic.h>
26 #include <qdf_nbuf.h>
27 #include "qdf_net_types.h"
28 #include <hif_usb_internal.h>
29 #include <htc_services.h>
30 #include <hif_debug.h>
31 #define ATH_MODULE_NAME hif
32 #include <a_debug.h>
33 #include "qdf_module.h"
34 #include "hif_usb_internal.h"
35 #include "if_usb.h"
36 #include "usb_api.h"
37 #include "target_type.h"
38
39 #if defined(WLAN_DEBUG) || defined(DEBUG)
40 static ATH_DEBUG_MASK_DESCRIPTION g_hif_debug_description[] = {
41 {USB_HIF_DEBUG_CTRL_TRANS, "Control Transfers"},
42 {USB_HIF_DEBUG_BULK_IN, "BULK In Transfers"},
43 {USB_HIF_DEBUG_BULK_OUT, "BULK Out Transfers"},
44 {USB_HIF_DEBUG_DUMP_DATA, "Dump data"},
45 {USB_HIF_DEBUG_ENUM, "Enumeration"},
46 };
47
48 ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif,
49 "hif",
50 "USB Host Interface",
51 ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO |
52 USB_HIF_DEBUG_ENUM,
53 ATH_DEBUG_DESCRIPTION_COUNT
54 (g_hif_debug_description),
55 g_hif_debug_description);
56
57 #endif
58
59 #ifdef USB_ISOC_SUPPORT
60 unsigned int hif_usb_isoch_vo = 1;
61 #else
62 unsigned int hif_usb_isoch_vo;
63 #endif
64 unsigned int hif_usb_disable_rxdata2 = 1;
65
66 /**
67 * usb_hif_usb_transmit_complete() - completion routing for tx urb's
68 * @urb: pointer to urb for which tx completion is called
69 *
70 * Return: none
71 */
usb_hif_usb_transmit_complete(struct urb * urb)72 static void usb_hif_usb_transmit_complete(struct urb *urb)
73 {
74 struct HIF_URB_CONTEXT *urb_context =
75 (struct HIF_URB_CONTEXT *)urb->context;
76 qdf_nbuf_t buf;
77 struct HIF_USB_PIPE *pipe = urb_context->pipe;
78 struct hif_usb_send_context *send_context;
79
80 hif_debug("+: pipe: %d, stat:%d, len:%d",
81 pipe->logical_pipe_num, urb->status, urb->actual_length);
82
83 /* this urb is not pending anymore */
84 usb_hif_remove_pending_transfer(urb_context);
85
86 if (urb->status != 0) {
87 hif_err("pipe: %d, failed: %d", pipe->logical_pipe_num,
88 urb->status);
89 }
90
91 buf = urb_context->buf;
92 send_context = urb_context->send_context;
93
94 if (send_context->new_alloc)
95 qdf_mem_free(send_context);
96 else
97 qdf_nbuf_pull_head(buf, send_context->head_data_len);
98
99 urb_context->buf = NULL;
100 usb_hif_cleanup_transmit_urb(urb_context);
101
102 /* note: queue implements a lock */
103 skb_queue_tail(&pipe->io_comp_queue, buf);
104 HIF_USB_SCHEDULE_WORK(pipe);
105
106 hif_debug("-");
107 }
108
109 /**
110 * hif_send_internal() - HIF internal routine to prepare and submit tx urbs
111 * @hif_usb_device: pointer to HIF_DEVICE_USB structure
112 * @pipe_id: HIF pipe on which data is to be sent
113 * @hdr_buf: any header buf to be prepended, currently ignored
114 * @buf: qdf_nbuf_t containing data to be transmitted
115 * @nbytes: number of bytes to be transmitted
116 *
117 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure
118 */
hif_send_internal(struct HIF_DEVICE_USB * hif_usb_device,uint8_t pipe_id,qdf_nbuf_t hdr_buf,qdf_nbuf_t buf,unsigned int nbytes)119 static QDF_STATUS hif_send_internal(struct HIF_DEVICE_USB *hif_usb_device,
120 uint8_t pipe_id,
121 qdf_nbuf_t hdr_buf,
122 qdf_nbuf_t buf, unsigned int nbytes)
123 {
124 QDF_STATUS status = QDF_STATUS_SUCCESS;
125 struct HIF_DEVICE_USB *device = hif_usb_device;
126 struct HIF_USB_PIPE *pipe = &device->pipes[pipe_id];
127 struct HIF_URB_CONTEXT *urb_context;
128 uint8_t *data;
129 uint32_t len;
130 struct urb *urb;
131 int usb_status;
132 int i;
133 struct hif_usb_send_context *send_context;
134 uint8_t frag_count;
135 uint32_t head_data_len, tmp_frag_count = 0;
136 unsigned char *data_ptr;
137
138 hif_debug("+ pipe : %d, buf:0x%pK nbytes %u",
139 pipe_id, buf, nbytes);
140
141 frag_count = qdf_nbuf_get_num_frags(buf);
142 if (frag_count == 1) {
143 /*
144 * | hif_usb_send_context | netbuf->data
145 */
146 head_data_len = sizeof(struct hif_usb_send_context);
147 } else if ((frag_count - 1) <= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS) {
148 /*
149 * means have extra fragment buf in skb
150 * header data length should be total sending length subtract
151 * internal data length of netbuf
152 * | hif_usb_send_context | fragments except internal buffer |
153 * netbuf->data
154 */
155 head_data_len = sizeof(struct hif_usb_send_context);
156 while (tmp_frag_count < (frag_count - 1)) {
157 head_data_len =
158 head_data_len + qdf_nbuf_get_frag_len(buf,
159 tmp_frag_count);
160 tmp_frag_count = tmp_frag_count + 1;
161 }
162 } else {
163 /* Extra fragments overflow */
164 hif_err("Extra fragments count overflow : %d", frag_count);
165 status = QDF_STATUS_E_RESOURCES;
166 goto err;
167 }
168
169 /* Check whether head room is enough to save extra head data */
170 if (head_data_len <= qdf_nbuf_headroom(buf)) {
171 send_context = (struct hif_usb_send_context *)
172 qdf_nbuf_push_head(buf, head_data_len);
173 send_context->new_alloc = false;
174 } else {
175 send_context =
176 qdf_mem_malloc(sizeof(struct hif_usb_send_context)
177 + head_data_len + nbytes);
178 if (!send_context) {
179 status = QDF_STATUS_E_NOMEM;
180 goto err;
181 }
182 send_context->new_alloc = true;
183 }
184 send_context->netbuf = buf;
185 send_context->hif_usb_device = hif_usb_device;
186 send_context->transfer_id = pipe_id;
187 send_context->head_data_len = head_data_len;
188 /*
189 * Copy data to head part of netbuf or head of allocated buffer.
190 * if buffer is new allocated, the last buffer should be copied also.
191 * It assume last fragment is internal buffer of netbuf
192 * sometime total length of fragments larger than nbytes
193 */
194 data_ptr = (unsigned char *)send_context +
195 sizeof(struct hif_usb_send_context);
196 for (i = 0;
197 i < (send_context->new_alloc ? frag_count : frag_count - 1); i++) {
198 int frag_len = qdf_nbuf_get_frag_len(buf, i);
199 unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i);
200
201 qdf_mem_copy(data_ptr, frag_addr, frag_len);
202 data_ptr += frag_len;
203 }
204 /* Reset pData pointer and send out */
205 data_ptr = (unsigned char *)send_context +
206 sizeof(struct hif_usb_send_context);
207
208 urb_context = usb_hif_alloc_urb_from_pipe(pipe);
209 if (!urb_context) {
210 /* TODO : note, it is possible to run out of urbs if 2
211 * endpoints map to the same pipe ID
212 */
213 hif_err("pipe: %d no urbs left. URB Cnt: %d",
214 pipe_id, pipe->urb_cnt);
215 status = QDF_STATUS_E_RESOURCES;
216 goto err;
217 }
218 urb_context->send_context = send_context;
219 urb = urb_context->urb;
220 urb_context->buf = buf;
221 data = data_ptr;
222 len = nbytes;
223
224 usb_fill_bulk_urb(urb,
225 device->udev,
226 pipe->usb_pipe_handle,
227 data,
228 (len % pipe->max_packet_size) ==
229 0 ? (len + 1) : len,
230 usb_hif_usb_transmit_complete, urb_context);
231
232 if ((len % pipe->max_packet_size) == 0)
233 /* hit a max packet boundary on this pipe */
234
235 hif_debug("athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes",
236 pipe->logical_pipe_num, pipe->usb_pipe_handle,
237 pipe->ep_address, nbytes);
238
239 usb_hif_enqueue_pending_transfer(pipe, urb_context);
240 usb_status = usb_submit_urb(urb, GFP_ATOMIC);
241 if (usb_status) {
242 if (send_context->new_alloc)
243 qdf_mem_free(send_context);
244 else
245 qdf_nbuf_pull_head(buf, head_data_len);
246 urb_context->buf = NULL;
247 hif_err("athusb: usb bulk transmit failed %d", usb_status);
248 usb_hif_remove_pending_transfer(urb_context);
249 usb_hif_cleanup_transmit_urb(urb_context);
250 status = QDF_STATUS_E_FAILURE;
251 goto err;
252 }
253
254 err:
255 if (!QDF_IS_STATUS_SUCCESS(status) &&
256 (status != QDF_STATUS_E_RESOURCES)) {
257 hif_err("athusb send failed %d", status);
258 }
259
260 hif_debug("- pipe: %d", pipe_id);
261
262 return status;
263 }
264
265 /**
266 * hif_send_head() - HIF routine exposed to upper layers to send data
267 * @scn: pointer to hif_opaque_softc structure
268 * @pipe_id: HIF pipe on which data is to be sent
269 * @transfer_id: endpoint ID on which data is to be sent
270 * @nbytes: number of bytes to be transmitted
271 * @wbuf: qdf_nbuf_t containing data to be transmitted
272 * @data_attr: data_attr field from cvg_nbuf_cb of wbuf
273 *
274 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure
275 */
hif_send_head(struct hif_opaque_softc * scn,uint8_t pipe_id,uint32_t transfer_id,uint32_t nbytes,qdf_nbuf_t wbuf,uint32_t data_attr)276 QDF_STATUS hif_send_head(struct hif_opaque_softc *scn, uint8_t pipe_id,
277 uint32_t transfer_id, uint32_t nbytes,
278 qdf_nbuf_t wbuf, uint32_t data_attr)
279 {
280 QDF_STATUS status = QDF_STATUS_SUCCESS;
281 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
282
283 status = hif_send_internal(device, pipe_id, NULL, wbuf, nbytes);
284 return status;
285 }
286
287 /**
288 * hif_get_free_queue_number() - get # of free TX resources in a given HIF pipe
289 * @scn: pointer to hif_opaque_softc structure
290 * @pipe_id: HIF pipe which is being polled for free resources
291 *
292 * Return: # of free resources in pipe_id
293 */
hif_get_free_queue_number(struct hif_opaque_softc * scn,uint8_t pipe_id)294 uint16_t hif_get_free_queue_number(struct hif_opaque_softc *scn,
295 uint8_t pipe_id)
296 {
297 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
298 struct HIF_USB_PIPE *pipe = &device->pipes[pipe_id];
299 u16 urb_cnt;
300
301 qdf_spin_lock_irqsave(&pipe->device->cs_lock);
302 urb_cnt = pipe->urb_cnt;
303 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
304
305 return urb_cnt;
306 }
307
308 /**
309 * hif_post_init() - copy HTC callbacks to HIF
310 * @scn: pointer to hif_opaque_softc structure
311 * @target: pointer to HTC_TARGET structure
312 * @callbacks: htc callbacks
313 *
314 * Return: none
315 */
hif_post_init(struct hif_opaque_softc * scn,void * target,struct hif_msg_callbacks * callbacks)316 void hif_post_init(struct hif_opaque_softc *scn, void *target,
317 struct hif_msg_callbacks *callbacks)
318 {
319 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
320
321 qdf_mem_copy(&device->htc_callbacks, callbacks,
322 sizeof(device->htc_callbacks));
323 }
324
325 /**
326 * hif_detach_htc() - remove HTC callbacks from HIF
327 * @scn: pointer to hif_opaque_softc structure
328 *
329 * Return: none
330 */
hif_detach_htc(struct hif_opaque_softc * scn)331 void hif_detach_htc(struct hif_opaque_softc *scn)
332 {
333 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
334
335 usb_hif_flush_all(device);
336 qdf_mem_zero(&device->htc_callbacks, sizeof(device->htc_callbacks));
337 }
338
339 /**
340 * hif_usb_device_deinit() - de- init HIF_DEVICE_USB, cleanup pipe resources
341 * @sc: pointer to hif_usb_softc structure
342 *
343 * Return: None
344 */
hif_usb_device_deinit(struct hif_usb_softc * sc)345 void hif_usb_device_deinit(struct hif_usb_softc *sc)
346 {
347 struct HIF_DEVICE_USB *device = &sc->hif_hdl;
348
349 hif_info("+");
350
351 usb_hif_cleanup_pipe_resources(device);
352
353 if (device->diag_cmd_buffer)
354 qdf_mem_free(device->diag_cmd_buffer);
355
356 if (device->diag_resp_buffer)
357 qdf_mem_free(device->diag_resp_buffer);
358
359 hif_info("-");
360 }
361
362 /**
363 * hif_usb_device_init() - init HIF_DEVICE_USB, setup pipe resources
364 * @sc: pointer to hif_usb_softc structure
365 *
366 * Return: QDF_STATUS_SUCCESS on success or a QDF error
367 */
hif_usb_device_init(struct hif_usb_softc * sc)368 QDF_STATUS hif_usb_device_init(struct hif_usb_softc *sc)
369 {
370 int i;
371 struct HIF_DEVICE_USB *device = &sc->hif_hdl;
372 struct usb_interface *interface = sc->interface;
373 struct usb_device *dev = interface_to_usbdev(interface);
374 QDF_STATUS status = QDF_STATUS_SUCCESS;
375 struct HIF_USB_PIPE *pipe;
376
377 hif_info("+");
378
379 do {
380
381 qdf_spinlock_create(&(device->cs_lock));
382 qdf_spinlock_create(&(device->rx_lock));
383 qdf_spinlock_create(&(device->tx_lock));
384 qdf_spinlock_create(&device->rx_prestart_lock);
385 device->udev = dev;
386 device->interface = interface;
387
388 hif_err("device %pK device->udev %pK device->interface %pK",
389 device,
390 device->udev,
391 device->interface);
392
393 for (i = 0; i < HIF_USB_PIPE_MAX; i++) {
394 pipe = &device->pipes[i];
395
396 HIF_USB_INIT_WORK(pipe);
397 skb_queue_head_init(&pipe->io_comp_queue);
398 }
399
400 device->diag_cmd_buffer =
401 qdf_mem_malloc(USB_CTRL_MAX_DIAG_CMD_SIZE);
402 if (!device->diag_cmd_buffer) {
403 status = QDF_STATUS_E_NOMEM;
404 break;
405 }
406 device->diag_resp_buffer =
407 qdf_mem_malloc(USB_CTRL_MAX_DIAG_RESP_SIZE);
408 if (!device->diag_resp_buffer) {
409 status = QDF_STATUS_E_NOMEM;
410 break;
411 }
412
413 status = usb_hif_setup_pipe_resources(device);
414
415 } while (false);
416
417 if (hif_is_supported_rx_ctrl_pipe(HIF_GET_SOFTC(sc)))
418 device->rx_ctrl_pipe_supported = 1;
419
420 if (status != QDF_STATUS_SUCCESS)
421 hif_err("abnormal condition (status=%d)", status);
422
423 hif_info("+");
424 return status;
425 }
426
427 /**
428 * hif_start() - Enable HIF TX and RX
429 * @scn: pointer to hif_opaque_softc structure
430 *
431 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
432 */
hif_start(struct hif_opaque_softc * scn)433 QDF_STATUS hif_start(struct hif_opaque_softc *scn)
434 {
435 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
436 int i;
437
438 hif_info("+");
439 usb_hif_prestart_recv_pipes(device);
440
441 /* set the TX resource avail threshold for each TX pipe */
442 for (i = HIF_TX_CTRL_PIPE; i <= HIF_TX_DATA_HP_PIPE; i++) {
443 device->pipes[i].urb_cnt_thresh =
444 device->pipes[i].urb_alloc / 2;
445 }
446
447 hif_info("-");
448 return QDF_STATUS_SUCCESS;
449 }
450
451 /**
452 * hif_usb_stop_device() - Stop/flush all HIF communication
453 * @hif_sc: pointer to hif_opaque_softc structure
454 *
455 * Return: none
456 */
hif_usb_stop_device(struct hif_softc * hif_sc)457 void hif_usb_stop_device(struct hif_softc *hif_sc)
458 {
459 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_sc);
460
461 hif_info("+");
462
463 usb_hif_flush_all(device);
464
465 hif_info("-");
466 }
467
468 /**
469 * hif_get_default_pipe() - get default pipes for HIF TX/RX
470 * @scn: pointer to hif_opaque_softc structure
471 * @ul_pipe: pointer to TX pipe
472 * @dl_pipe: pointer to RX pipe
473 *
474 * Return: none
475 */
hif_get_default_pipe(struct hif_opaque_softc * scn,uint8_t * ul_pipe,uint8_t * dl_pipe)476 void hif_get_default_pipe(struct hif_opaque_softc *scn, uint8_t *ul_pipe,
477 uint8_t *dl_pipe)
478 {
479 *ul_pipe = HIF_TX_CTRL_PIPE;
480 *dl_pipe = HIF_RX_CTRL_PIPE;
481 }
482
483 #if defined(USB_MULTI_IN_TEST) || defined(USB_ISOC_TEST)
484 /**
485 * hif_map_service_to_pipe() - maps ul/dl pipe to service id.
486 * @scn: HIF context
487 * @svc_id: service index
488 * @ul_pipe: pointer to uplink pipe id
489 * @dl_pipe: pointer to down-linklink pipe id
490 * @ul_is_polled: if ul is polling based
491 * @dl_is_polled: if dl is polling based
492 *
493 * Return: status
494 */
hif_map_service_to_pipe(struct hif_opaque_softc * scn,uint16_t svc_id,uint8_t * ul_pipe,uint8_t * dl_pipe,int * ul_is_polled,int * dl_is_polled)495 int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id,
496 uint8_t *ul_pipe, uint8_t *dl_pipe,
497 int *ul_is_polled, int *dl_is_polled)
498 {
499 QDF_STATUS status = QDF_STATUS_SUCCESS;
500
501 switch (svc_id) {
502 case HTC_CTRL_RSVD_SVC:
503 case WMI_CONTROL_SVC:
504 case HTC_RAW_STREAMS_SVC:
505 *ul_pipe = HIF_TX_CTRL_PIPE;
506 *dl_pipe = HIF_RX_DATA_PIPE;
507 break;
508 case WMI_DATA_BE_SVC:
509 *ul_pipe = HIF_TX_DATA_LP_PIPE;
510 *dl_pipe = HIF_RX_DATA_PIPE;
511 break;
512 case WMI_DATA_BK_SVC:
513 *ul_pipe = HIF_TX_DATA_MP_PIPE;
514 *dl_pipe = HIF_RX_DATA2_PIPE;
515 break;
516 case WMI_DATA_VI_SVC:
517 *ul_pipe = HIF_TX_DATA_HP_PIPE;
518 *dl_pipe = HIF_RX_DATA_PIPE;
519 break;
520 case WMI_DATA_VO_SVC:
521 *ul_pipe = HIF_TX_DATA_LP_PIPE;
522 *dl_pipe = HIF_RX_DATA_PIPE;
523 break;
524 default:
525 status = QDF_STATUS_E_FAILURE;
526 break;
527 }
528
529 return qdf_status_to_os_return(status);
530 }
531 #else
532
533 #ifdef QCA_TX_HTT2_SUPPORT
534 #define USB_TX_CHECK_HTT2_SUPPORT 1
535 #else
536 #define USB_TX_CHECK_HTT2_SUPPORT 0
537 #endif
538
539 /**
540 * hif_map_service_to_pipe() - maps ul/dl pipe to service id.
541 * @scn: HIF context
542 * @svc_id: service index
543 * @ul_pipe: pointer to uplink pipe id
544 * @dl_pipe: pointer to down-linklink pipe id
545 * @ul_is_polled: if ul is polling based
546 * @dl_is_polled: if dl is polling based
547 *
548 * Return: status
549 */
hif_map_service_to_pipe(struct hif_opaque_softc * scn,uint16_t svc_id,uint8_t * ul_pipe,uint8_t * dl_pipe,int * ul_is_polled,int * dl_is_polled)550 int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id,
551 uint8_t *ul_pipe, uint8_t *dl_pipe,
552 int *ul_is_polled, int *dl_is_polled)
553 {
554 QDF_STATUS status = QDF_STATUS_SUCCESS;
555 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
556
557 switch (svc_id) {
558 case HTC_CTRL_RSVD_SVC:
559 case WMI_CONTROL_SVC:
560 *ul_pipe = HIF_TX_CTRL_PIPE;
561 if (device->rx_ctrl_pipe_supported)
562 *dl_pipe = HIF_RX_CTRL_PIPE;
563 else
564 *dl_pipe = HIF_RX_DATA_PIPE;
565 break;
566 case WMI_DATA_BE_SVC:
567 case WMI_DATA_BK_SVC:
568 *ul_pipe = HIF_TX_DATA_LP_PIPE;
569 if (hif_usb_disable_rxdata2)
570 *dl_pipe = HIF_RX_DATA_PIPE;
571 else
572 *dl_pipe = HIF_RX_DATA2_PIPE;
573 break;
574 case WMI_DATA_VI_SVC:
575 *ul_pipe = HIF_TX_DATA_MP_PIPE;
576 if (hif_usb_disable_rxdata2)
577 *dl_pipe = HIF_RX_DATA_PIPE;
578 else
579 *dl_pipe = HIF_RX_DATA2_PIPE;
580 break;
581 case WMI_DATA_VO_SVC:
582 *ul_pipe = HIF_TX_DATA_HP_PIPE;
583 if (hif_usb_disable_rxdata2)
584 *dl_pipe = HIF_RX_DATA_PIPE;
585 else
586 *dl_pipe = HIF_RX_DATA2_PIPE;
587 break;
588 case HTC_RAW_STREAMS_SVC:
589 *ul_pipe = HIF_TX_CTRL_PIPE;
590 *dl_pipe = HIF_RX_DATA_PIPE;
591 break;
592 case HTT_DATA_MSG_SVC:
593 *ul_pipe = HIF_TX_DATA_LP_PIPE;
594 if (hif_usb_disable_rxdata2)
595 *dl_pipe = HIF_RX_DATA_PIPE;
596 else
597 *dl_pipe = HIF_RX_DATA2_PIPE;
598 break;
599 case HTT_DATA2_MSG_SVC:
600 if (USB_TX_CHECK_HTT2_SUPPORT) {
601 *ul_pipe = HIF_TX_DATA_HP_PIPE;
602 if (hif_usb_disable_rxdata2)
603 *dl_pipe = HIF_RX_DATA_PIPE;
604 else
605 *dl_pipe = HIF_RX_DATA2_PIPE;
606 }
607 break;
608 default:
609 status = QDF_STATUS_E_FAILURE;
610 break;
611 }
612
613 return qdf_status_to_os_return(status);
614 }
615 #endif
616
617 /**
618 * hif_ctrl_msg_exchange() - send usb ctrl message and receive response
619 * @macp: pointer to HIF_DEVICE_USB
620 * @send_req_val: USB send message request value
621 * @send_msg: pointer to data to send
622 * @len: length in bytes of the data to send
623 * @response_req_val: USB response message request value
624 * @response_msg: pointer to response msg
625 * @response_len: length of the response message
626 *
627 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
628 */
hif_ctrl_msg_exchange(struct HIF_DEVICE_USB * macp,uint8_t send_req_val,uint8_t * send_msg,uint32_t len,uint8_t response_req_val,uint8_t * response_msg,uint32_t * response_len)629 static QDF_STATUS hif_ctrl_msg_exchange(struct HIF_DEVICE_USB *macp,
630 uint8_t send_req_val,
631 uint8_t *send_msg,
632 uint32_t len,
633 uint8_t response_req_val,
634 uint8_t *response_msg,
635 uint32_t *response_len)
636 {
637 QDF_STATUS status;
638
639 do {
640
641 /* send command */
642 status = usb_hif_submit_ctrl_out(macp, send_req_val, 0, 0,
643 send_msg, len);
644
645 if (!QDF_IS_STATUS_SUCCESS(status))
646 break;
647
648 if (!response_msg) {
649 /* no expected response */
650 break;
651 }
652
653 /* get response */
654 status = usb_hif_submit_ctrl_in(macp, response_req_val, 0, 0,
655 response_msg, *response_len);
656
657 if (!QDF_IS_STATUS_SUCCESS(status))
658 break;
659
660 } while (false);
661
662 return status;
663 }
664
665 #ifdef WLAN_FEATURE_BMI
666 /**
667 * hif_exchange_bmi_msg() - send/recev ctrl message of type BMI_CMD/BMI_RESP
668 * @scn: pointer to hif_opaque_softc
669 * @cmd:
670 * @rsp:
671 * @bmi_request: pointer to data to send
672 * @request_length: length in bytes of the data to send
673 * @bmi_response: pointer to response msg
674 * @bmi_response_lengthp: length of the response message
675 * @timeout_ms: timeout to wait for response (ignored in current implementation)
676 *
677 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
678 */
679
hif_exchange_bmi_msg(struct hif_opaque_softc * scn,qdf_dma_addr_t cmd,qdf_dma_addr_t rsp,uint8_t * bmi_request,uint32_t request_length,uint8_t * bmi_response,uint32_t * bmi_response_lengthp,uint32_t timeout_ms)680 QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *scn,
681 qdf_dma_addr_t cmd, qdf_dma_addr_t rsp,
682 uint8_t *bmi_request,
683 uint32_t request_length,
684 uint8_t *bmi_response,
685 uint32_t *bmi_response_lengthp,
686 uint32_t timeout_ms)
687 {
688 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn);
689
690 return hif_ctrl_msg_exchange(macp,
691 USB_CONTROL_REQ_SEND_BMI_CMD,
692 bmi_request,
693 request_length,
694 USB_CONTROL_REQ_RECV_BMI_RESP,
695 bmi_response, bmi_response_lengthp);
696 }
697
hif_register_bmi_callbacks(struct hif_opaque_softc * hif_ctx)698 void hif_register_bmi_callbacks(struct hif_opaque_softc *hif_ctx)
699 {
700 }
701 #endif /* WLAN_FEATURE_BMI */
702
703 /**
704 * hif_diag_read_access() - Read data from target memory or register
705 * @scn: pointer to hif_opaque_softc
706 * @address: register address to read from
707 * @data: pointer to buffer to store the value read from the register
708 *
709 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
710 */
hif_diag_read_access(struct hif_opaque_softc * scn,uint32_t address,uint32_t * data)711 QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *scn, uint32_t address,
712 uint32_t *data)
713 {
714 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn);
715 QDF_STATUS status;
716 USB_CTRL_DIAG_CMD_READ *cmd;
717 uint32_t respLength;
718
719 cmd = (USB_CTRL_DIAG_CMD_READ *) macp->diag_cmd_buffer;
720
721 qdf_mem_zero(cmd, sizeof(*cmd));
722 cmd->Cmd = USB_CTRL_DIAG_CC_READ;
723 cmd->Address = address;
724 respLength = sizeof(USB_CTRL_DIAG_RESP_READ);
725
726 status = hif_ctrl_msg_exchange(macp,
727 USB_CONTROL_REQ_DIAG_CMD,
728 (uint8_t *) cmd,
729 sizeof(*cmd),
730 USB_CONTROL_REQ_DIAG_RESP,
731 macp->diag_resp_buffer, &respLength);
732
733 if (QDF_IS_STATUS_SUCCESS(status)) {
734 USB_CTRL_DIAG_RESP_READ *pResp =
735 (USB_CTRL_DIAG_RESP_READ *) macp->diag_resp_buffer;
736 *data = pResp->ReadValue;
737 status = QDF_STATUS_SUCCESS;
738 } else {
739 status = QDF_STATUS_E_FAILURE;
740 }
741
742 return status;
743 }
744
745 /**
746 * hif_diag_write_access() - write data to target memory or register
747 * @scn: pointer to hif_opaque_softc
748 * @address: register address to write to
749 * @data: value to be written to the address
750 *
751 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
752 */
hif_diag_write_access(struct hif_opaque_softc * scn,uint32_t address,uint32_t data)753 QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *scn,
754 uint32_t address,
755 uint32_t data)
756 {
757 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn);
758 USB_CTRL_DIAG_CMD_WRITE *cmd;
759
760 cmd = (USB_CTRL_DIAG_CMD_WRITE *) macp->diag_cmd_buffer;
761
762 qdf_mem_zero(cmd, sizeof(*cmd));
763 cmd->Cmd = USB_CTRL_DIAG_CC_WRITE;
764 cmd->Address = address;
765 cmd->Value = data;
766
767 return hif_ctrl_msg_exchange(macp,
768 USB_CONTROL_REQ_DIAG_CMD,
769 (uint8_t *) cmd,
770 sizeof(*cmd), 0, NULL, 0);
771 }
772
773 /**
774 * hif_dump_info() - dump info about all HIF pipes and endpoints
775 * @scn: pointer to hif_opaque_softc
776 *
777 * Return: none
778 */
hif_dump_info(struct hif_opaque_softc * scn)779 void hif_dump_info(struct hif_opaque_softc *scn)
780 {
781 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
782 struct HIF_USB_PIPE *pipe = NULL;
783 struct usb_host_interface *iface_desc = NULL;
784 struct usb_endpoint_descriptor *ep_desc;
785 uint8_t i = 0;
786
787 for (i = 0; i < HIF_USB_PIPE_MAX; i++) {
788 pipe = &device->pipes[i];
789 hif_err("PipeIndex: %d URB Cnt: %d PipeHandle: %x",
790 i, pipe->urb_cnt,
791 pipe->usb_pipe_handle);
792 if (usb_pipeisoc(pipe->usb_pipe_handle))
793 hif_info("Pipe Type ISOC");
794 else if (usb_pipebulk(pipe->usb_pipe_handle))
795 hif_info("Pipe Type BULK");
796 else if (usb_pipeint(pipe->usb_pipe_handle))
797 hif_info("Pipe Type INT");
798 else if (usb_pipecontrol(pipe->usb_pipe_handle))
799 hif_info("Pipe Type control");
800 }
801
802 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
803 ep_desc = &iface_desc->endpoint[i].desc;
804 if (ep_desc) {
805 hif_info(
806 "ep_desc: %pK Index: %d: DescType: %d Addr: %d Maxp: %d Atrrib: %d",
807 ep_desc, i, ep_desc->bDescriptorType,
808 ep_desc->bEndpointAddress,
809 ep_desc->wMaxPacketSize,
810 ep_desc->bmAttributes);
811 if ((ep_desc) && (usb_endpoint_type(ep_desc) ==
812 USB_ENDPOINT_XFER_ISOC)) {
813 hif_info("ISOC EP Detected");
814 }
815 }
816 }
817
818 }
819
820 /**
821 * hif_flush_surprise_remove() - Cleanup residual buffers for device shutdown
822 * @scn: HIF context
823 *
824 * Not applicable to USB bus
825 *
826 * Return: none
827 */
hif_flush_surprise_remove(struct hif_opaque_softc * scn)828 void hif_flush_surprise_remove(struct hif_opaque_softc *scn)
829 {
830 /* TO DO... */
831 }
832
833 /**
834 * hif_diag_read_mem() -read nbytes of data from target memory or register
835 * @scn: pointer to hif_opaque_softc
836 * @address: register address to read from
837 * @data: buffer to store the value read
838 * @nbytes: number of bytes to be read from 'address'
839 *
840 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
841 */
hif_diag_read_mem(struct hif_opaque_softc * scn,uint32_t address,uint8_t * data,int nbytes)842 QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn,
843 uint32_t address, uint8_t *data,
844 int nbytes)
845 {
846 QDF_STATUS status = QDF_STATUS_SUCCESS;
847
848 hif_info("+");
849
850 if ((address & 0x3) || ((uintptr_t)data & 0x3))
851 return QDF_STATUS_E_IO;
852
853 while ((nbytes >= 4) &&
854 QDF_IS_STATUS_SUCCESS(status =
855 hif_diag_read_access(scn,
856 address,
857 (uint32_t *)data))) {
858
859 nbytes -= sizeof(uint32_t);
860 address += sizeof(uint32_t);
861 data += sizeof(uint32_t);
862
863 }
864 hif_info("-");
865 return status;
866 }
867 qdf_export_symbol(hif_diag_read_mem);
868
869 /**
870 * hif_diag_write_mem() -write nbytes of data to target memory or register
871 * @scn: pointer to hif_opaque_softc
872 * @address: register address to write to
873 * @data: buffer containing data to be written
874 * @nbytes: number of bytes to be written
875 *
876 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
877 */
hif_diag_write_mem(struct hif_opaque_softc * scn,uint32_t address,uint8_t * data,int nbytes)878 QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn,
879 uint32_t address,
880 uint8_t *data, int nbytes)
881 {
882 QDF_STATUS status = QDF_STATUS_SUCCESS;
883
884 hif_info("+");
885 if ((address & 0x3) || ((uintptr_t)data & 0x3))
886 return QDF_STATUS_E_IO;
887
888 while (nbytes >= 4 &&
889 QDF_IS_STATUS_SUCCESS(status =
890 hif_diag_write_access(scn,
891 address,
892 *((uint32_t *)data)))) {
893
894 nbytes -= sizeof(uint32_t);
895 address += sizeof(uint32_t);
896 data += sizeof(uint32_t);
897
898 }
899 hif_info("-");
900 return status;
901 }
902
hif_send_complete_check(struct hif_opaque_softc * scn,uint8_t PipeID,int force)903 void hif_send_complete_check(struct hif_opaque_softc *scn,
904 uint8_t PipeID, int force)
905 {
906 /* NO-OP*/
907 }
908
909 /* diagnostic command definitions */
910 #define USB_CTRL_DIAG_CC_READ 0
911 #define USB_CTRL_DIAG_CC_WRITE 1
912 #define USB_CTRL_DIAG_CC_WARM_RESET 2
913
hif_suspend_wow(struct hif_opaque_softc * scn)914 void hif_suspend_wow(struct hif_opaque_softc *scn)
915 {
916 hif_info("HIFsuspendwow - TODO");
917 }
918
919 /**
920 * hif_usb_set_bundle_mode() - enable bundling and set default rx bundle cnt
921 * @scn: pointer to hif_opaque_softc structure
922 * @enabled: flag to enable/disable bundling
923 * @rx_bundle_cnt: bundle count to be used for RX
924 *
925 * Return: none
926 */
hif_usb_set_bundle_mode(struct hif_softc * scn,bool enabled,int rx_bundle_cnt)927 void hif_usb_set_bundle_mode(struct hif_softc *scn,
928 bool enabled, int rx_bundle_cnt)
929 {
930 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn);
931
932 device->is_bundle_enabled = enabled;
933 device->rx_bundle_cnt = rx_bundle_cnt;
934 if (device->is_bundle_enabled && (device->rx_bundle_cnt == 0))
935 device->rx_bundle_cnt = 1;
936
937 device->rx_bundle_buf_len = device->rx_bundle_cnt *
938 HIF_USB_RX_BUNDLE_ONE_PKT_SIZE;
939
940 hif_debug("athusb bundle %s cnt %d", enabled ? "enabled" : "disabled",
941 rx_bundle_cnt);
942 }
943
944 /**
945 * hif_is_supported_rx_ctrl_pipe() - return true if device supports exclusive
946 * control pipe in the RX direction.
947 * @scn: hif context
948 *
949 * Return: true if device supports RX control pipe.
950 */
hif_is_supported_rx_ctrl_pipe(struct hif_softc * scn)951 bool hif_is_supported_rx_ctrl_pipe(struct hif_softc *scn)
952 {
953 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn);
954 struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl);
955
956 switch (tgt_info->target_type) {
957 case TARGET_TYPE_QCN7605:
958 return true;
959 default:
960 return false;
961 }
962 }
963