1 /* 2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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 */ 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 */ 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 * @hdr_buf: any header buf to be prepended, currently ignored 273 * @data_attr: data_attr field from cvg_nbuf_cb of wbuf 274 * 275 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure 276 */ 277 QDF_STATUS hif_send_head(struct hif_opaque_softc *scn, uint8_t pipe_id, 278 uint32_t transfer_id, uint32_t nbytes, 279 qdf_nbuf_t wbuf, uint32_t data_attr) 280 { 281 QDF_STATUS status = QDF_STATUS_SUCCESS; 282 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 283 284 status = hif_send_internal(device, pipe_id, NULL, wbuf, nbytes); 285 return status; 286 } 287 288 /** 289 * hif_get_free_queue_number() - get # of free TX resources in a given HIF pipe 290 * @scn: pointer to hif_opaque_softc structure 291 * @pipe_id: HIF pipe which is being polled for free resources 292 * 293 * Return: # of free resources in pipe_id 294 */ 295 uint16_t hif_get_free_queue_number(struct hif_opaque_softc *scn, 296 uint8_t pipe_id) 297 { 298 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 299 struct HIF_USB_PIPE *pipe = &device->pipes[pipe_id]; 300 u16 urb_cnt; 301 302 qdf_spin_lock_irqsave(&pipe->device->cs_lock); 303 urb_cnt = pipe->urb_cnt; 304 qdf_spin_unlock_irqrestore(&pipe->device->cs_lock); 305 306 return urb_cnt; 307 } 308 309 /** 310 * hif_post_init() - copy HTC callbacks to HIF 311 * @scn: pointer to hif_opaque_softc structure 312 * @target: pointer to HTC_TARGET structure 313 * @callbacks: htc callbacks 314 * 315 * Return: none 316 */ 317 void hif_post_init(struct hif_opaque_softc *scn, void *target, 318 struct hif_msg_callbacks *callbacks) 319 { 320 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 321 322 qdf_mem_copy(&device->htc_callbacks, callbacks, 323 sizeof(device->htc_callbacks)); 324 } 325 326 /** 327 * hif_detach_htc() - remove HTC callbacks from HIF 328 * @scn: pointer to hif_opaque_softc structure 329 * 330 * Return: none 331 */ 332 void hif_detach_htc(struct hif_opaque_softc *scn) 333 { 334 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 335 336 usb_hif_flush_all(device); 337 qdf_mem_zero(&device->htc_callbacks, sizeof(device->htc_callbacks)); 338 } 339 340 /** 341 * hif_usb_device_deinit() - de- init HIF_DEVICE_USB, cleanup pipe resources 342 * @sc: pointer to hif_usb_softc structure 343 * 344 * Return: None 345 */ 346 void hif_usb_device_deinit(struct hif_usb_softc *sc) 347 { 348 struct HIF_DEVICE_USB *device = &sc->hif_hdl; 349 350 hif_info("+"); 351 352 usb_hif_cleanup_pipe_resources(device); 353 354 if (device->diag_cmd_buffer) 355 qdf_mem_free(device->diag_cmd_buffer); 356 357 if (device->diag_resp_buffer) 358 qdf_mem_free(device->diag_resp_buffer); 359 360 hif_info("-"); 361 } 362 363 /** 364 * hif_usb_device_init() - init HIF_DEVICE_USB, setup pipe resources 365 * @sc: pointer to hif_usb_softc structure 366 * 367 * Return: QDF_STATUS_SUCCESS on success or a QDF error 368 */ 369 QDF_STATUS hif_usb_device_init(struct hif_usb_softc *sc) 370 { 371 int i; 372 struct HIF_DEVICE_USB *device = &sc->hif_hdl; 373 struct usb_interface *interface = sc->interface; 374 struct usb_device *dev = interface_to_usbdev(interface); 375 QDF_STATUS status = QDF_STATUS_SUCCESS; 376 struct HIF_USB_PIPE *pipe; 377 378 hif_info("+"); 379 380 do { 381 382 qdf_spinlock_create(&(device->cs_lock)); 383 qdf_spinlock_create(&(device->rx_lock)); 384 qdf_spinlock_create(&(device->tx_lock)); 385 qdf_spinlock_create(&device->rx_prestart_lock); 386 device->udev = dev; 387 device->interface = interface; 388 389 hif_err("device %pK device->udev %pK device->interface %pK", 390 device, 391 device->udev, 392 device->interface); 393 394 for (i = 0; i < HIF_USB_PIPE_MAX; i++) { 395 pipe = &device->pipes[i]; 396 397 HIF_USB_INIT_WORK(pipe); 398 skb_queue_head_init(&pipe->io_comp_queue); 399 } 400 401 device->diag_cmd_buffer = 402 qdf_mem_malloc(USB_CTRL_MAX_DIAG_CMD_SIZE); 403 if (!device->diag_cmd_buffer) { 404 status = QDF_STATUS_E_NOMEM; 405 break; 406 } 407 device->diag_resp_buffer = 408 qdf_mem_malloc(USB_CTRL_MAX_DIAG_RESP_SIZE); 409 if (!device->diag_resp_buffer) { 410 status = QDF_STATUS_E_NOMEM; 411 break; 412 } 413 414 status = usb_hif_setup_pipe_resources(device); 415 416 } while (false); 417 418 if (hif_is_supported_rx_ctrl_pipe(HIF_GET_SOFTC(sc))) 419 device->rx_ctrl_pipe_supported = 1; 420 421 if (status != QDF_STATUS_SUCCESS) 422 hif_err("abnormal condition (status=%d)", status); 423 424 hif_info("+"); 425 return status; 426 } 427 428 /** 429 * hif_start() - Enable HIF TX and RX 430 * @scn: pointer to hif_opaque_softc structure 431 * 432 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 433 */ 434 QDF_STATUS hif_start(struct hif_opaque_softc *scn) 435 { 436 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 437 int i; 438 439 hif_info("+"); 440 usb_hif_prestart_recv_pipes(device); 441 442 /* set the TX resource avail threshold for each TX pipe */ 443 for (i = HIF_TX_CTRL_PIPE; i <= HIF_TX_DATA_HP_PIPE; i++) { 444 device->pipes[i].urb_cnt_thresh = 445 device->pipes[i].urb_alloc / 2; 446 } 447 448 hif_info("-"); 449 return QDF_STATUS_SUCCESS; 450 } 451 452 /** 453 * hif_usb_stop_device() - Stop/flush all HIF communication 454 * @scn: pointer to hif_opaque_softc structure 455 * 456 * Return: none 457 */ 458 void hif_usb_stop_device(struct hif_softc *hif_sc) 459 { 460 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_sc); 461 462 hif_info("+"); 463 464 usb_hif_flush_all(device); 465 466 hif_info("-"); 467 } 468 469 /** 470 * hif_get_default_pipe() - get default pipes for HIF TX/RX 471 * @scn: pointer to hif_opaque_softc structure 472 * @ul_pipe: pointer to TX pipe 473 * @ul_pipe: pointer to TX pipe 474 * 475 * Return: none 476 */ 477 void hif_get_default_pipe(struct hif_opaque_softc *scn, uint8_t *ul_pipe, 478 uint8_t *dl_pipe) 479 { 480 *ul_pipe = HIF_TX_CTRL_PIPE; 481 *dl_pipe = HIF_RX_CTRL_PIPE; 482 } 483 484 #if defined(USB_MULTI_IN_TEST) || defined(USB_ISOC_TEST) 485 /** 486 * hif_map_service_to_pipe() - maps ul/dl pipe to service id. 487 * @scn: HIF context 488 * @svc_id: service index 489 * @ul_pipe: pointer to uplink pipe id 490 * @dl_pipe: pointer to down-linklink pipe id 491 * @ul_is_polled: if ul is polling based 492 * @ul_is_polled: if dl is polling based 493 * 494 * Return: status 495 */ 496 int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id, 497 uint8_t *ul_pipe, uint8_t *dl_pipe, 498 int *ul_is_polled, int *dl_is_polled) 499 { 500 QDF_STATUS status = QDF_STATUS_SUCCESS; 501 502 switch (svc_id) { 503 case HTC_CTRL_RSVD_SVC: 504 case WMI_CONTROL_SVC: 505 case HTC_RAW_STREAMS_SVC: 506 *ul_pipe = HIF_TX_CTRL_PIPE; 507 *dl_pipe = HIF_RX_DATA_PIPE; 508 break; 509 case WMI_DATA_BE_SVC: 510 *ul_pipe = HIF_TX_DATA_LP_PIPE; 511 *dl_pipe = HIF_RX_DATA_PIPE; 512 break; 513 case WMI_DATA_BK_SVC: 514 *ul_pipe = HIF_TX_DATA_MP_PIPE; 515 *dl_pipe = HIF_RX_DATA2_PIPE; 516 break; 517 case WMI_DATA_VI_SVC: 518 *ul_pipe = HIF_TX_DATA_HP_PIPE; 519 *dl_pipe = HIF_RX_DATA_PIPE; 520 break; 521 case WMI_DATA_VO_SVC: 522 *ul_pipe = HIF_TX_DATA_LP_PIPE; 523 *dl_pipe = HIF_RX_DATA_PIPE; 524 break; 525 default: 526 status = QDF_STATUS_E_FAILURE; 527 break; 528 } 529 530 return qdf_status_to_os_return(status); 531 } 532 #else 533 534 #ifdef QCA_TX_HTT2_SUPPORT 535 #define USB_TX_CHECK_HTT2_SUPPORT 1 536 #else 537 #define USB_TX_CHECK_HTT2_SUPPORT 0 538 #endif 539 540 /** 541 * hif_map_service_to_pipe() - maps ul/dl pipe to service id. 542 * @scn: HIF context 543 * @svc_id: service index 544 * @ul_pipe: pointer to uplink pipe id 545 * @dl_pipe: pointer to down-linklink pipe id 546 * @ul_is_polled: if ul is polling based 547 * @ul_is_polled: if dl is polling based 548 * 549 * Return: status 550 */ 551 int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id, 552 uint8_t *ul_pipe, uint8_t *dl_pipe, 553 int *ul_is_polled, int *dl_is_polled) 554 { 555 QDF_STATUS status = QDF_STATUS_SUCCESS; 556 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 557 558 switch (svc_id) { 559 case HTC_CTRL_RSVD_SVC: 560 case WMI_CONTROL_SVC: 561 *ul_pipe = HIF_TX_CTRL_PIPE; 562 if (device->rx_ctrl_pipe_supported) 563 *dl_pipe = HIF_RX_CTRL_PIPE; 564 else 565 *dl_pipe = HIF_RX_DATA_PIPE; 566 break; 567 case WMI_DATA_BE_SVC: 568 case WMI_DATA_BK_SVC: 569 *ul_pipe = HIF_TX_DATA_LP_PIPE; 570 if (hif_usb_disable_rxdata2) 571 *dl_pipe = HIF_RX_DATA_PIPE; 572 else 573 *dl_pipe = HIF_RX_DATA2_PIPE; 574 break; 575 case WMI_DATA_VI_SVC: 576 *ul_pipe = HIF_TX_DATA_MP_PIPE; 577 if (hif_usb_disable_rxdata2) 578 *dl_pipe = HIF_RX_DATA_PIPE; 579 else 580 *dl_pipe = HIF_RX_DATA2_PIPE; 581 break; 582 case WMI_DATA_VO_SVC: 583 *ul_pipe = HIF_TX_DATA_HP_PIPE; 584 if (hif_usb_disable_rxdata2) 585 *dl_pipe = HIF_RX_DATA_PIPE; 586 else 587 *dl_pipe = HIF_RX_DATA2_PIPE; 588 break; 589 case HTC_RAW_STREAMS_SVC: 590 *ul_pipe = HIF_TX_CTRL_PIPE; 591 *dl_pipe = HIF_RX_DATA_PIPE; 592 break; 593 case HTT_DATA_MSG_SVC: 594 *ul_pipe = HIF_TX_DATA_LP_PIPE; 595 if (hif_usb_disable_rxdata2) 596 *dl_pipe = HIF_RX_DATA_PIPE; 597 else 598 *dl_pipe = HIF_RX_DATA2_PIPE; 599 break; 600 case HTT_DATA2_MSG_SVC: 601 if (USB_TX_CHECK_HTT2_SUPPORT) { 602 *ul_pipe = HIF_TX_DATA_HP_PIPE; 603 if (hif_usb_disable_rxdata2) 604 *dl_pipe = HIF_RX_DATA_PIPE; 605 else 606 *dl_pipe = HIF_RX_DATA2_PIPE; 607 } 608 break; 609 default: 610 status = QDF_STATUS_E_FAILURE; 611 break; 612 } 613 614 return qdf_status_to_os_return(status); 615 } 616 #endif 617 618 /** 619 * hif_ctrl_msg_exchange() - send usb ctrl message and receive response 620 * @macp: pointer to HIF_DEVICE_USB 621 * @send_req_val: USB send message request value 622 * @send_msg: pointer to data to send 623 * @len: length in bytes of the data to send 624 * @response_req_val: USB response message request value 625 * @response_msg: pointer to response msg 626 * @response_len: length of the response message 627 * 628 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 629 */ 630 static QDF_STATUS hif_ctrl_msg_exchange(struct HIF_DEVICE_USB *macp, 631 uint8_t send_req_val, 632 uint8_t *send_msg, 633 uint32_t len, 634 uint8_t response_req_val, 635 uint8_t *response_msg, 636 uint32_t *response_len) 637 { 638 QDF_STATUS status; 639 640 do { 641 642 /* send command */ 643 status = usb_hif_submit_ctrl_out(macp, send_req_val, 0, 0, 644 send_msg, len); 645 646 if (!QDF_IS_STATUS_SUCCESS(status)) 647 break; 648 649 if (!response_msg) { 650 /* no expected response */ 651 break; 652 } 653 654 /* get response */ 655 status = usb_hif_submit_ctrl_in(macp, response_req_val, 0, 0, 656 response_msg, *response_len); 657 658 if (!QDF_IS_STATUS_SUCCESS(status)) 659 break; 660 661 } while (false); 662 663 return status; 664 } 665 666 #ifdef WLAN_FEATURE_BMI 667 /** 668 * hif_exchange_bmi_msg() - send/recev ctrl message of type BMI_CMD/BMI_RESP 669 * @scn: pointer to hif_opaque_softc 670 * @bmi_request: pointer to data to send 671 * @request_length: length in bytes of the data to send 672 * @bmi_response: pointer to response msg 673 * @bmi_response_length: length of the response message 674 * @timeout_ms: timeout to wait for response (ignored in current implementation) 675 * 676 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 677 */ 678 679 QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *scn, 680 qdf_dma_addr_t cmd, qdf_dma_addr_t rsp, 681 uint8_t *bmi_request, 682 uint32_t request_length, 683 uint8_t *bmi_response, 684 uint32_t *bmi_response_lengthp, 685 uint32_t timeout_ms) 686 { 687 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); 688 689 return hif_ctrl_msg_exchange(macp, 690 USB_CONTROL_REQ_SEND_BMI_CMD, 691 bmi_request, 692 request_length, 693 USB_CONTROL_REQ_RECV_BMI_RESP, 694 bmi_response, bmi_response_lengthp); 695 } 696 697 void hif_register_bmi_callbacks(struct hif_opaque_softc *hif_ctx) 698 { 699 } 700 #endif /* WLAN_FEATURE_BMI */ 701 702 /** 703 * hif_diag_read_access() - Read data from target memory or register 704 * @scn: pointer to hif_opaque_softc 705 * @address: register address to read from 706 * @data: pointer to buffer to store the value read from the register 707 * 708 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 709 */ 710 QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *scn, uint32_t address, 711 uint32_t *data) 712 { 713 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); 714 QDF_STATUS status; 715 USB_CTRL_DIAG_CMD_READ *cmd; 716 uint32_t respLength; 717 718 cmd = (USB_CTRL_DIAG_CMD_READ *) macp->diag_cmd_buffer; 719 720 qdf_mem_zero(cmd, sizeof(*cmd)); 721 cmd->Cmd = USB_CTRL_DIAG_CC_READ; 722 cmd->Address = address; 723 respLength = sizeof(USB_CTRL_DIAG_RESP_READ); 724 725 status = hif_ctrl_msg_exchange(macp, 726 USB_CONTROL_REQ_DIAG_CMD, 727 (uint8_t *) cmd, 728 sizeof(*cmd), 729 USB_CONTROL_REQ_DIAG_RESP, 730 macp->diag_resp_buffer, &respLength); 731 732 if (QDF_IS_STATUS_SUCCESS(status)) { 733 USB_CTRL_DIAG_RESP_READ *pResp = 734 (USB_CTRL_DIAG_RESP_READ *) macp->diag_resp_buffer; 735 *data = pResp->ReadValue; 736 status = QDF_STATUS_SUCCESS; 737 } else { 738 status = QDF_STATUS_E_FAILURE; 739 } 740 741 return status; 742 } 743 744 /** 745 * hif_diag_write_access() - write data to target memory or register 746 * @scn: pointer to hif_opaque_softc 747 * @address: register address to write to 748 * @data: value to be written to the address 749 * 750 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 751 */ 752 QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *scn, 753 uint32_t address, 754 uint32_t data) 755 { 756 struct HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); 757 USB_CTRL_DIAG_CMD_WRITE *cmd; 758 759 cmd = (USB_CTRL_DIAG_CMD_WRITE *) macp->diag_cmd_buffer; 760 761 qdf_mem_zero(cmd, sizeof(*cmd)); 762 cmd->Cmd = USB_CTRL_DIAG_CC_WRITE; 763 cmd->Address = address; 764 cmd->Value = data; 765 766 return hif_ctrl_msg_exchange(macp, 767 USB_CONTROL_REQ_DIAG_CMD, 768 (uint8_t *) cmd, 769 sizeof(*cmd), 0, NULL, 0); 770 } 771 772 /** 773 * hif_dump_info() - dump info about all HIF pipes and endpoints 774 * @scn: pointer to hif_opaque_softc 775 * 776 * Return: none 777 */ 778 void hif_dump_info(struct hif_opaque_softc *scn) 779 { 780 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 781 struct HIF_USB_PIPE *pipe = NULL; 782 struct usb_host_interface *iface_desc = NULL; 783 struct usb_endpoint_descriptor *ep_desc; 784 uint8_t i = 0; 785 786 for (i = 0; i < HIF_USB_PIPE_MAX; i++) { 787 pipe = &device->pipes[i]; 788 hif_err("PipeIndex: %d URB Cnt: %d PipeHandle: %x", 789 i, pipe->urb_cnt, 790 pipe->usb_pipe_handle); 791 if (usb_pipeisoc(pipe->usb_pipe_handle)) 792 hif_info("Pipe Type ISOC"); 793 else if (usb_pipebulk(pipe->usb_pipe_handle)) 794 hif_info("Pipe Type BULK"); 795 else if (usb_pipeint(pipe->usb_pipe_handle)) 796 hif_info("Pipe Type INT"); 797 else if (usb_pipecontrol(pipe->usb_pipe_handle)) 798 hif_info("Pipe Type control"); 799 } 800 801 for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { 802 ep_desc = &iface_desc->endpoint[i].desc; 803 if (ep_desc) { 804 hif_info( 805 "ep_desc: %pK Index: %d: DescType: %d Addr: %d Maxp: %d Atrrib: %d", 806 ep_desc, i, ep_desc->bDescriptorType, 807 ep_desc->bEndpointAddress, 808 ep_desc->wMaxPacketSize, 809 ep_desc->bmAttributes); 810 if ((ep_desc) && (usb_endpoint_type(ep_desc) == 811 USB_ENDPOINT_XFER_ISOC)) { 812 hif_info("ISOC EP Detected"); 813 } 814 } 815 } 816 817 } 818 819 /** 820 * hif_flush_surprise_remove() - Cleanup residual buffers for device shutdown 821 * @scn: HIF context 822 * 823 * Not applicable to USB bus 824 * 825 * Return: none 826 */ 827 void hif_flush_surprise_remove(struct hif_opaque_softc *scn) 828 { 829 /* TO DO... */ 830 } 831 832 /** 833 * hif_diag_read_mem() -read nbytes of data from target memory or register 834 * @scn: pointer to hif_opaque_softc 835 * @address: register address to read from 836 * @data: buffer to store the value read 837 * @nbytes: number of bytes to be read from 'address' 838 * 839 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 840 */ 841 QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn, 842 uint32_t address, uint8_t *data, 843 int nbytes) 844 { 845 QDF_STATUS status = QDF_STATUS_SUCCESS; 846 847 hif_info("+"); 848 849 if ((address & 0x3) || ((uintptr_t)data & 0x3)) 850 return QDF_STATUS_E_IO; 851 852 while ((nbytes >= 4) && 853 QDF_IS_STATUS_SUCCESS(status = 854 hif_diag_read_access(scn, 855 address, 856 (uint32_t *)data))) { 857 858 nbytes -= sizeof(uint32_t); 859 address += sizeof(uint32_t); 860 data += sizeof(uint32_t); 861 862 } 863 hif_info("-"); 864 return status; 865 } 866 qdf_export_symbol(hif_diag_read_mem); 867 868 /** 869 * hif_diag_write_mem() -write nbytes of data to target memory or register 870 * @scn: pointer to hif_opaque_softc 871 * @address: register address to write to 872 * @data: buffer containing data to be written 873 * @nbytes: number of bytes to be written 874 * 875 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 876 */ 877 QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn, 878 uint32_t address, 879 uint8_t *data, int nbytes) 880 { 881 QDF_STATUS status = QDF_STATUS_SUCCESS; 882 883 hif_info("+"); 884 if ((address & 0x3) || ((uintptr_t)data & 0x3)) 885 return QDF_STATUS_E_IO; 886 887 while (nbytes >= 4 && 888 QDF_IS_STATUS_SUCCESS(status = 889 hif_diag_write_access(scn, 890 address, 891 *((uint32_t *)data)))) { 892 893 nbytes -= sizeof(uint32_t); 894 address += sizeof(uint32_t); 895 data += sizeof(uint32_t); 896 897 } 898 hif_info("-"); 899 return status; 900 } 901 902 void hif_send_complete_check(struct hif_opaque_softc *scn, 903 uint8_t PipeID, int force) 904 { 905 /* NO-OP*/ 906 } 907 908 /* diagnostic command definitions */ 909 #define USB_CTRL_DIAG_CC_READ 0 910 #define USB_CTRL_DIAG_CC_WRITE 1 911 #define USB_CTRL_DIAG_CC_WARM_RESET 2 912 913 void hif_suspend_wow(struct hif_opaque_softc *scn) 914 { 915 hif_info("HIFsuspendwow - TODO"); 916 } 917 918 /** 919 * hif_usb_set_bundle_mode() - enable bundling and set default rx bundle cnt 920 * @scn: pointer to hif_opaque_softc structure 921 * @enabled: flag to enable/disable bundling 922 * @rx_bundle_cnt: bundle count to be used for RX 923 * 924 * Return: none 925 */ 926 void hif_usb_set_bundle_mode(struct hif_softc *scn, 927 bool enabled, int rx_bundle_cnt) 928 { 929 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); 930 931 device->is_bundle_enabled = enabled; 932 device->rx_bundle_cnt = rx_bundle_cnt; 933 if (device->is_bundle_enabled && (device->rx_bundle_cnt == 0)) 934 device->rx_bundle_cnt = 1; 935 936 device->rx_bundle_buf_len = device->rx_bundle_cnt * 937 HIF_USB_RX_BUNDLE_ONE_PKT_SIZE; 938 939 hif_debug("athusb bundle %s cnt %d", enabled ? "enabled" : "disabled", 940 rx_bundle_cnt); 941 } 942 943 /** 944 * hif_is_supported_rx_ctrl_pipe() - return true if device supports exclusive 945 * control pipe in the RX direction. 946 * @scn: hif context 947 * 948 * Return: true if device supports RX control pipe. 949 */ 950 bool hif_is_supported_rx_ctrl_pipe(struct hif_softc *scn) 951 { 952 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); 953 struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); 954 955 switch (tgt_info->target_type) { 956 case TARGET_TYPE_QCN7605: 957 return true; 958 default: 959 return false; 960 } 961 } 962