1 /* 2 * Copyright (c) 2019-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_lock.h> 21 #include "adma.h" 22 #include "hif_sdio_internal.h" 23 #include "pld_sdio.h" 24 #include "if_sdio.h" 25 26 /** 27 * hif_dev_get_fifo_address() - get the fifo addresses for dma 28 * @pdev: SDIO HIF object 29 * @c : FIFO address config pointer 30 * 31 * Return : 0 for success, non-zero for error 32 */ 33 int hif_dev_get_fifo_address(struct hif_sdio_dev *pdev, 34 void *c, 35 uint32_t config_len) 36 { 37 /* SDIO AL handles DMA Addresses */ 38 return 0; 39 } 40 41 /** 42 * hif_dev_get_block_size() - get the adma block size for dma 43 * @config : block size config pointer 44 * 45 * Return : NONE 46 */ 47 void hif_dev_get_block_size(void *config) 48 { 49 /* TODO Get block size used by AL Layer in Mission ROM Mode */ 50 *((uint32_t *)config) = HIF_BLOCK_SIZE; /* QCN_SDIO_MROM_BLK_SZ TODO */ 51 } 52 53 /** 54 * hif_dev_configure_pipes() - configure pipes 55 * @pdev: SDIO HIF object 56 * @func: sdio function object 57 * 58 * Return : 0 for success, non-zero for error 59 */ 60 int hif_dev_configure_pipes(struct hif_sdio_dev *pdev, struct sdio_func *func) 61 { 62 /* SDIO AL Configures SDIO Channels */ 63 return 0; 64 } 65 66 /** hif_dev_set_mailbox_swap() - Set the mailbox swap 67 * @pdev : The HIF layer object 68 * 69 * Return: none 70 */ 71 void hif_dev_set_mailbox_swap(struct hif_sdio_dev *pdev) 72 { 73 /* SDIO AL doesn't use mailbox architecture */ 74 } 75 76 /** hif_dev_get_mailbox_swap() - Get the mailbox swap setting 77 * @pdev : The HIF layer object 78 * 79 * Return: true or false 80 */ 81 bool hif_dev_get_mailbox_swap(struct hif_sdio_dev *pdev) 82 { 83 /* SDIO AL doesn't use mailbox architecture */ 84 return false; 85 } 86 87 /** 88 * hif_dev_dsr_handler() - Synchronous interrupt handler 89 * 90 * @context: hif send context 91 * 92 * Return: 0 for success and non-zero for failure 93 */ 94 QDF_STATUS hif_dev_dsr_handler(void *context) 95 { 96 /* SDIO AL handles interrupts */ 97 return QDF_STATUS_SUCCESS; 98 } 99 100 /** 101 * hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id. 102 * @pDev: SDIO HIF object 103 * @ServiceId: service index 104 * @ULPipe: uplink pipe id 105 * @DLPipe: down-linklink pipe id 106 * 107 * Return: 0 on success, error value on invalid map 108 */ 109 QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_dev *pdev, uint16_t svc, 110 uint8_t *ul_pipe, uint8_t *dl_pipe) 111 { 112 QDF_STATUS status = QDF_STATUS_SUCCESS; 113 114 switch (svc) { 115 case HTT_DATA_MSG_SVC: 116 *dl_pipe = 2; 117 *ul_pipe = 3; 118 break; 119 120 case HTC_CTRL_RSVD_SVC: 121 case HTC_RAW_STREAMS_SVC: 122 *dl_pipe = 0; 123 *ul_pipe = 1; 124 break; 125 126 case WMI_DATA_BE_SVC: 127 case WMI_DATA_BK_SVC: 128 case WMI_DATA_VI_SVC: 129 case WMI_DATA_VO_SVC: 130 *dl_pipe = 2; 131 *ul_pipe = 3; 132 break; 133 134 case WMI_CONTROL_SVC: 135 *dl_pipe = 0; 136 *ul_pipe = 1; 137 break; 138 139 default: 140 hif_err("Invalid service: %d", svc); 141 status = QDF_STATUS_E_INVAL; 142 break; 143 } 144 return status; 145 } 146 147 /** 148 * hif_bus_configure() - configure the bus 149 * @hif_sc: pointer to the hif context. 150 * 151 * return: 0 for success. nonzero for failure. 152 */ 153 int hif_sdio_bus_configure(struct hif_softc *hif_sc) 154 { 155 struct pld_wlan_enable_cfg cfg; 156 enum pld_driver_mode mode; 157 uint32_t con_mode = hif_get_conparam(hif_sc); 158 159 if (con_mode == QDF_GLOBAL_FTM_MODE) 160 mode = PLD_FTM; 161 else if (con_mode == QDF_GLOBAL_COLDBOOT_CALIB_MODE) 162 mode = PLD_COLDBOOT_CALIBRATION; 163 else if (QDF_IS_EPPING_ENABLED(con_mode)) 164 mode = PLD_EPPING; 165 else 166 mode = PLD_MISSION; 167 168 return pld_wlan_enable(hif_sc->qdf_dev->dev, &cfg, mode); 169 } 170 171 /** hif_dev_setup_device() - Setup device specific stuff here required for hif 172 * @pdev : HIF layer object 173 * 174 * return 0 on success, error otherwise 175 */ 176 int hif_dev_setup_device(struct hif_sdio_device *pdev) 177 { 178 hif_dev_get_block_size(&pdev->BlockSize); 179 180 return 0; 181 } 182 183 /** hif_dev_mask_interrupts() - Disable the interrupts in the device 184 * @pdev SDIO HIF Object 185 * 186 * Return: NONE 187 */ 188 void hif_dev_mask_interrupts(struct hif_sdio_device *pdev) 189 { 190 /* SDIO AL Handles Interrupts */ 191 } 192 193 /** hif_dev_unmask_interrupts() - Enable the interrupts in the device 194 * @pdev SDIO HIF Object 195 * 196 * Return: NONE 197 */ 198 void hif_dev_unmask_interrupts(struct hif_sdio_device *pdev) 199 { 200 /* SDIO AL Handles Interrupts */ 201 } 202 203 /** 204 * hif_dev_map_pipe_to_adma_chan() - maps pipe id to adma chan 205 * @pdev: The pointer to the hif device object 206 * @pipeid: pipe index 207 * 208 * Return: adma channel handle 209 */ 210 struct sdio_al_channel_handle *hif_dev_map_pipe_to_adma_chan 211 ( 212 struct hif_sdio_device *dev, 213 uint8_t pipeid 214 ) 215 { 216 struct hif_sdio_dev *pdev = dev->HIFDevice; 217 218 HIF_ENTER(); 219 220 if ((pipeid == 0) || (pipeid == 1)) 221 return pdev->al_chan[0]; 222 else if ((pipeid == 2) || (pipeid == 3)) 223 return pdev->al_chan[1]; 224 else 225 return NULL; 226 } 227 228 /** 229 * hif_dev_map_adma_chan_to_pipe() - map adma chan to htc pipe 230 * @pdev: The pointer to the hif device object 231 * @chan: channel number 232 * @upload: boolean to decide upload or download 233 * 234 * Return: Invalid pipe index 235 */ 236 uint8_t hif_dev_map_adma_chan_to_pipe(struct hif_sdio_device *pdev, 237 uint8_t chan, bool upload) 238 { 239 hif_info("chan: %u, %s", chan, upload ? "Upload" : "Download"); 240 241 if (chan == 0) /* chan 0 is mapped to HTT */ 242 return upload ? 1 : 0; 243 else if (chan == 1) /* chan 1 is mapped to WMI */ 244 return upload ? 3 : 2; 245 246 return (uint8_t)-1; /* invalid channel id */ 247 } 248 249 /** 250 * hif_get_send_address() - Get the transfer pipe address 251 * @pdev: The pointer to the hif device object 252 * @pipe: The pipe identifier 253 * 254 * Return 0 for success and non-zero for failure to map 255 */ 256 int hif_get_send_address(struct hif_sdio_device *pdev, 257 uint8_t pipe, unsigned long *addr) 258 { 259 struct sdio_al_channel_handle *chan = NULL; 260 261 if (!addr) 262 return -EINVAL; 263 264 *addr = 0; 265 chan = hif_dev_map_pipe_to_adma_chan(pdev, pipe); 266 267 if (!chan) 268 return -EINVAL; 269 270 *addr = (unsigned long)chan; 271 272 return 0; 273 } 274 275 /** 276 * hif_fixup_write_param() - Tweak the address and length parameters 277 * @pdev: The pointer to the hif device object 278 * @length: The length pointer 279 * @addr: The addr pointer 280 * 281 * Return: None 282 */ 283 void hif_fixup_write_param(struct hif_sdio_dev *pdev, uint32_t req, 284 uint32_t *length, uint32_t *addr) 285 { 286 HIF_ENTER(); 287 HIF_EXIT(); 288 } 289 290 #define HIF_MAX_RX_Q_ALLOC 0 /* TODO */ 291 #define HIF_RX_Q_ALLOC_THRESHOLD 100 292 QDF_STATUS hif_disable_func(struct hif_sdio_dev *device, 293 struct sdio_func *func, 294 bool reset) 295 { 296 QDF_STATUS status = QDF_STATUS_SUCCESS; 297 #if HIF_MAX_RX_Q_ALLOC 298 qdf_list_node_t *node; 299 struct rx_q_entry *rx_q_elem; 300 #endif 301 HIF_ENTER(); 302 303 #if HIF_MAX_RX_Q_ALLOC 304 qdf_spin_lock_irqsave(&device->rx_q_lock); 305 306 for (; device->rx_q.count; ) { 307 qdf_list_remove_back(&device->rx_q, &node); 308 rx_q_elem = container_of(node, struct rx_q_entry, entry); 309 if (rx_q_elem) { 310 if (rx_q_elem->nbuf) 311 qdf_nbuf_free(rx_q_elem->nbuf); 312 qdf_mem_free(rx_q_elem); 313 } 314 } 315 qdf_destroy_work(0, &device->rx_q_alloc_work); 316 317 qdf_spin_unlock_irqrestore(&device->rx_q_lock); 318 319 qdf_spinlock_destroy(&device->rx_q_lock); 320 #endif 321 322 status = hif_sdio_func_disable(device, func, reset); 323 if (status == QDF_STATUS_SUCCESS) 324 device->is_disabled = true; 325 326 cleanup_hif_scatter_resources(device); 327 328 HIF_EXIT(); 329 330 return status; 331 } 332 333 /** 334 * hif_enable_func() - Enable SDIO function 335 * 336 * @ol_sc: HIF object pointer 337 * @device: HIF device pointer 338 * @sdio_func: SDIO function pointer 339 * @resume: If this is called from resume or probe 340 * 341 * Return: 0 in case of success, else error value 342 */ 343 QDF_STATUS hif_enable_func(struct hif_softc *ol_sc, struct hif_sdio_dev *device, 344 struct sdio_func *func, bool resume) 345 { 346 QDF_STATUS ret = QDF_STATUS_SUCCESS; 347 348 if (!device) { 349 hif_err("HIF device is NULL"); 350 return QDF_STATUS_E_INVAL; 351 } 352 353 if (!resume) 354 ret = hif_sdio_probe(ol_sc, func, device); 355 356 #if HIF_MAX_RX_Q_ALLOC 357 if (!ret) { 358 qdf_list_create(&device->rx_q, HIF_MAX_RX_Q_ALLOC); 359 qdf_spinlock_create(&device->rx_q_lock); 360 qdf_create_work(0, &device->rx_q_alloc_work, 361 hif_sdio_rx_q_alloc, (void *)device); 362 device->rx_q_alloc_work_scheduled = true; 363 qdf_sched_work(0, &device->rx_q_alloc_work); 364 } 365 #endif 366 return ret; 367 } 368 369 /** 370 * hif_sdio_get_net_buf() - Get a network buffer from the rx q 371 * @dev - HIF device object 372 * 373 * Return - NULL if out of buffers, else qdf_nbuf_t 374 */ 375 #if HIF_MAX_RX_Q_ALLOC 376 static qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev, uint16_t buf_len) 377 { 378 qdf_list_node_t *node; 379 qdf_nbuf_t nbuf = NULL; 380 qdf_list_t *q = &dev->rx_q; 381 struct rx_q_entry *elem = NULL; 382 383 /* TODO - Alloc nbuf based on buf_len */ 384 qdf_spin_lock_irqsave(&dev->rx_q_lock); 385 386 if (q->count) { 387 qdf_list_remove_front(q, &node); 388 elem = qdf_container_of(node, struct rx_q_entry, entry); 389 nbuf = elem->nbuf; 390 } else { 391 hif_err("no rx q elements"); 392 } 393 394 if (q->count <= HIF_RX_Q_ALLOC_THRESHOLD && 395 !dev->rx_q_alloc_work_scheduled) { 396 dev->rx_q_alloc_work_scheduled = true; 397 qdf_sched_work(0, &dev->rx_q_alloc_work); 398 } 399 400 qdf_spin_unlock_irqrestore(&dev->rx_q_lock); 401 402 qdf_mem_free(elem); 403 404 return nbuf; 405 } 406 #else 407 static qdf_nbuf_t hif_sdio_get_nbuf(struct hif_sdio_dev *dev, uint16_t buf_len) 408 { 409 qdf_nbuf_t nbuf; 410 411 if (!buf_len) 412 buf_len = HIF_SDIO_RX_BUFFER_SIZE; 413 414 nbuf = qdf_nbuf_alloc(NULL, buf_len, 0, 4, false); 415 416 return nbuf; 417 } 418 #endif 419 /** 420 * hif_sdio_rx_q_alloc() - Deferred work for pre-alloc rx q 421 * @ctx - Pointer to context object 422 * 423 * Return NONE 424 */ 425 #if HIF_MAX_RX_Q_ALLOC 426 void hif_sdio_rx_q_alloc(void *ctx) 427 { 428 struct rx_q_entry *rx_q_elem; 429 struct hif_sdio_dev *dev = (struct hif_sdio_dev *)ctx; 430 unsigned int rx_q_count = dev->rx_q.count; 431 432 HIF_ENTER(); 433 qdf_spin_lock_irqsave(&dev->rx_q_lock); 434 435 for (; rx_q_count < dev->rx_q.max_size; rx_q_count++) { 436 rx_q_elem = qdf_mem_malloc(sizeof(struct rx_q_entry)); 437 if (!rx_q_elem) { 438 hif_err("Failed to alloc rx q elem"); 439 break; 440 } 441 442 /* TODO - Alloc nbuf based on payload_len in HTC Header */ 443 rx_q_elem->nbuf = qdf_nbuf_alloc(NULL, HIF_SDIO_RX_BUFFER_SIZE, 444 0, 4, false); 445 if (!rx_q_elem->nbuf) { 446 hif_err("Failed to alloc nbuf for rx"); 447 qdf_mem_free(rx_q_elem); 448 break; 449 } 450 451 qdf_list_insert_back(&dev->rx_q, &rx_q_elem->entry); 452 } 453 dev->rx_q_alloc_work_scheduled = false; 454 455 qdf_spin_unlock_irqrestore(&dev->rx_q_lock); 456 HIF_EXIT(); 457 } 458 #else 459 void hif_sdio_rx_q_alloc(void *ctx) 460 { 461 } 462 #endif 463 464 #include <linux/qcn_sdio_al.h> 465 466 struct sdio_al_channel_data qcn7605_chan[HIF_SDIO_MAX_AL_CHANNELS] = { 467 { 468 .name = "SDIO_AL_WLAN_CH0", /* HTT */ 469 .client_data = NULL, /* populate from client handle */ 470 .ul_xfer_cb = ul_xfer_cb, 471 .dl_xfer_cb = dl_xfer_cb, 472 .dl_data_avail_cb = dl_data_avail_cb, 473 .dl_meta_data_cb = NULL 474 }, 475 { 476 .name = "SDIO_AL_WLAN_CH1", /* WMI */ 477 .client_data = NULL, /* populate from client handle */ 478 .ul_xfer_cb = ul_xfer_cb, 479 .dl_xfer_cb = dl_xfer_cb, 480 .dl_data_avail_cb = dl_data_avail_cb, 481 .dl_meta_data_cb = NULL 482 } 483 }; 484 485 /** 486 * hif_dev_register_channels()- Register transport layer channels 487 * @dev : HIF device object 488 * @func : SDIO function pointer 489 * 490 * Return : success on configuration, else failure 491 */ 492 int hif_dev_register_channels(struct hif_sdio_dev *dev, struct sdio_func *func) 493 { 494 int ret = 0; 495 unsigned int chan; 496 struct sdio_al_channel_data *chan_data[HIF_ADMA_MAX_CHANS]; 497 498 HIF_ENTER(); 499 500 dev->al_client = pld_sdio_get_sdio_al_client_handle(func); 501 if (ret || !dev->al_client) { 502 hif_err("Failed to get get sdio al handle"); 503 return ret; 504 } 505 506 if ((func->device & MANUFACTURER_ID_AR6K_BASE_MASK) == 507 MANUFACTURER_ID_QCN7605_BASE) { 508 dev->adma_chans_used = 2; 509 qcn7605_chan[0].client_data = dev->al_client->client_data; 510 qcn7605_chan[1].client_data = dev->al_client->client_data; 511 chan_data[0] = &qcn7605_chan[0]; 512 chan_data[1] = &qcn7605_chan[1]; 513 } else { 514 dev->adma_chans_used = 0; 515 } 516 517 for (chan = 0; chan < dev->adma_chans_used; chan++) { 518 dev->al_chan[chan] = 519 pld_sdio_register_sdio_al_channel(dev->al_client, 520 chan_data[chan]); 521 if (!dev->al_chan[chan] || IS_ERR(dev->al_chan[chan])) { 522 ret = -EINVAL; 523 hif_err("Channel registration failed"); 524 } else { 525 dev->al_chan[chan]->priv = (void *)dev; 526 hif_info("chan %s : id : %u", 527 chan_data[chan]->name, 528 dev->al_chan[chan]->channel_id); 529 } 530 } 531 532 HIF_EXIT(); 533 534 return ret; 535 } 536 537 /** 538 * hif_dev_unregister_channels()- Register transport layer channels 539 * @dev : HIF device object 540 * @func : SDIO Function pointer 541 * 542 * Return : None 543 */ 544 void hif_dev_unregister_channels(struct hif_sdio_dev *dev, 545 struct sdio_func *func) 546 { 547 unsigned int chan; 548 549 if (!dev) { 550 hif_err("hif_sdio_dev is null"); 551 return; 552 } 553 554 for (chan = 0; chan < dev->adma_chans_used; chan++) { 555 dev->al_chan[chan]->priv = NULL; 556 pld_sdio_unregister_sdio_al_channel(dev->al_chan[chan]); 557 } 558 } 559 560 /** 561 * hif_read_write() - queue a read/write request 562 * @dev: pointer to hif device structure 563 * @address: address to read, actually channel pointer 564 * @buffer: buffer to hold read/write data 565 * @length: length to read/write 566 * @request: read/write/sync/async request 567 * @context: pointer to hold calling context 568 * 569 * Return: 0, pending on success, error number otherwise. 570 */ 571 QDF_STATUS 572 hif_read_write(struct hif_sdio_dev *dev, 573 unsigned long sdio_al_ch_handle, 574 char *cbuffer, uint32_t length, 575 uint32_t request, void *context) 576 { 577 QDF_STATUS status = QDF_STATUS_SUCCESS; 578 struct sdio_al_channel_handle *ch; 579 struct bus_request *bus_req; 580 enum sdio_al_dma_direction dir; 581 struct hif_sdio_device *device; 582 QDF_STATUS (*rx_comp)(void *, qdf_nbuf_t, uint8_t); 583 qdf_nbuf_t nbuf; 584 int ret = 0, payload_len = 0; 585 unsigned char *buffer = (unsigned char *)cbuffer; 586 587 if (!dev || !sdio_al_ch_handle) { 588 hif_err("Device = %pK, addr = %lu", dev, sdio_al_ch_handle); 589 return QDF_STATUS_E_INVAL; 590 } 591 592 if (!(request & HIF_ASYNCHRONOUS) && 593 !(request & HIF_SYNCHRONOUS)) { 594 hif_err("Invalid request mode: %d", request); 595 return QDF_STATUS_E_INVAL; 596 } 597 598 /*sdio r/w action is not needed when suspend, so just return */ 599 if ((dev->is_suspend) && 600 (dev->power_config == HIF_DEVICE_POWER_CUT)) { 601 hif_info("skip in suspend"); 602 return QDF_STATUS_SUCCESS; 603 } 604 605 ch = (struct sdio_al_channel_handle *)sdio_al_ch_handle; 606 607 bus_req = hif_allocate_bus_request(dev); 608 if (!bus_req) { 609 hif_err("Bus alloc failed"); 610 return QDF_STATUS_E_FAILURE; 611 } 612 613 bus_req->address = sdio_al_ch_handle; 614 bus_req->length = length; 615 bus_req->request = request; 616 bus_req->context = context; 617 bus_req->buffer = buffer; 618 619 /* Request SDIO AL to do transfer */ 620 dir = (request & HIF_SDIO_WRITE) ? SDIO_AL_TX : SDIO_AL_RX; 621 622 if (request & HIF_SYNCHRONOUS) { 623 ret = sdio_al_queue_transfer(ch, 624 dir, 625 bus_req->buffer, 626 bus_req->length, 627 1); /* higher priority */ 628 if (ret) { 629 status = QDF_STATUS_E_FAILURE; 630 hif_err("SYNC REQ failed ret: %d", ret); 631 } else { 632 status = QDF_STATUS_SUCCESS; 633 } 634 635 hif_free_bus_request(dev, bus_req); 636 637 if ((status == QDF_STATUS_SUCCESS) && (dir == SDIO_AL_RX)) { 638 nbuf = (qdf_nbuf_t)context; 639 payload_len = HTC_GET_FIELD(bus_req->buffer, 640 HTC_FRAME_HDR, 641 PAYLOADLEN); 642 qdf_nbuf_set_pktlen(nbuf, payload_len + HTC_HDR_LENGTH); 643 device = (struct hif_sdio_device *)dev->htc_context; 644 rx_comp = device->hif_callbacks.rxCompletionHandler; 645 rx_comp(device->hif_callbacks.Context, nbuf, 0); 646 } 647 } else { 648 ret = sdio_al_queue_transfer_async(ch, 649 dir, 650 bus_req->buffer, 651 bus_req->length, 652 1, /* higher priority */ 653 (void *)bus_req); 654 if (ret) { 655 status = QDF_STATUS_E_FAILURE; 656 hif_err("ASYNC REQ fail ret: %d for len: %d ch: %d", 657 ret, length, ch->channel_id); 658 hif_free_bus_request(dev, bus_req); 659 } else { 660 status = QDF_STATUS_E_PENDING; 661 } 662 } 663 return status; 664 } 665 666 /** 667 * ul_xfer_cb() - Completion call back for asynchronous transfer 668 * @ch_handle: The sdio al channel handle 669 * @result: The result of the operation 670 * @context: pointer to request context 671 * 672 * Return: None 673 */ 674 void ul_xfer_cb(struct sdio_al_channel_handle *ch_handle, 675 struct sdio_al_xfer_result *result, 676 void *ctx) 677 { 678 struct bus_request *req = (struct bus_request *)ctx; 679 struct hif_sdio_dev *dev; 680 681 if (!ch_handle || !result) { 682 hif_err("Invalid args"); 683 qdf_assert_always(0); 684 return; 685 } 686 687 dev = (struct hif_sdio_dev *)ch_handle->priv; 688 689 if (result->xfer_status) { 690 req->status = QDF_STATUS_E_FAILURE; 691 hif_err("ASYNC Tx failed status: %d", result->xfer_status); 692 } else { 693 req->status = QDF_STATUS_SUCCESS; 694 } 695 696 dev->htc_callbacks.rw_compl_handler(req->context, req->status); 697 698 hif_free_bus_request(dev, req); 699 } 700 701 /** 702 * dl_data_avail_cb() - Called when data is available on a channel 703 * @ch_handle: The sdio al channel handle 704 * @len: The len of data available to download 705 * 706 * Return: None 707 */ 708 /* Use the asynchronous method of transfer. This will help in 709 * completing READ in the transfer done callback later which 710 * runs in sdio al thread context. If we do the synchronous 711 * transfer here, the thread context won't be available and 712 * perhaps a new thread may be required here. 713 */ 714 void dl_data_avail_cb(struct sdio_al_channel_handle *ch_handle, 715 unsigned int len) 716 { 717 struct hif_sdio_dev *dev; 718 unsigned int chan; 719 qdf_nbuf_t nbuf; 720 721 if (!ch_handle || !len) { 722 hif_err("Invalid args %u", len); 723 qdf_assert_always(0); 724 return; 725 } 726 727 dev = (struct hif_sdio_dev *)ch_handle->priv; 728 chan = ch_handle->channel_id; 729 730 if (chan > HIF_SDIO_MAX_AL_CHANNELS) { 731 hif_err("Invalid Ch ID %d", chan); 732 return; 733 } 734 735 /* allocate a buffer for reading the data from the chip. 736 * Note that this is raw, unparsed buffer and will be 737 * processed in the transfer done callback. 738 */ 739 /* TODO, use global buffer instead of runtime allocations */ 740 nbuf = qdf_nbuf_alloc(NULL, len, 0, 4, false); 741 742 if (!nbuf) { 743 hif_err("Unable to alloc netbuf %u bytes", len); 744 return; 745 } 746 747 hif_read_write(dev, (unsigned long)ch_handle, nbuf->data, len, 748 HIF_RD_ASYNC_BLOCK_FIX, nbuf); 749 } 750 751 #define is_pad_block(buf) (*((uint32_t *)buf) == 0xbabababa) 752 uint16_t g_dbg_payload_len; 753 754 /** 755 * dl_xfer_cb() - Call from lower layer after transfer is completed 756 * @ch_handle: The sdio al channel handle 757 * @result: The xfer result 758 * @ctx: Context passed in the transfer queuing 759 * 760 * Return: None 761 */ 762 void dl_xfer_cb(struct sdio_al_channel_handle *ch_handle, 763 struct sdio_al_xfer_result *result, 764 void *ctx) 765 { 766 unsigned char *buf; 767 qdf_nbuf_t nbuf; 768 uint32_t len; 769 uint16_t payload_len = 0; 770 struct hif_sdio_dev *dev; 771 struct hif_sdio_device *device; 772 struct bus_request *bus_req = (struct bus_request *)ctx; 773 QDF_STATUS (*rx_completion)(void *, qdf_nbuf_t, uint8_t); 774 775 if (!bus_req) { 776 hif_err("Bus Req NULL!!!"); 777 qdf_assert_always(0); 778 return; 779 } 780 781 if (!ch_handle || !result) { 782 hif_err("Invalid args %pK %pK", ch_handle, result); 783 qdf_assert_always(0); 784 return; 785 } 786 787 dev = (struct hif_sdio_dev *)ch_handle->priv; 788 if (result->xfer_status) { 789 hif_err("ASYNC Rx failed %d", result->xfer_status); 790 qdf_nbuf_free((qdf_nbuf_t)bus_req->context); 791 hif_free_bus_request(dev, bus_req); 792 return; 793 } 794 795 device = (struct hif_sdio_device *)dev->htc_context; 796 rx_completion = device->hif_callbacks.rxCompletionHandler; 797 798 buf = (unsigned char *)result->buf_addr; 799 len = (unsigned int)result->xfer_len; 800 801 while (len >= sizeof(HTC_FRAME_HDR)) { 802 if (is_pad_block(buf)) { 803 /* End of Rx Buffer */ 804 break; 805 } 806 807 if (HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID) >= 808 ENDPOINT_MAX) { 809 hif_err("Invalid endpoint id: %u", 810 HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID)); 811 break; 812 } 813 814 /* Copy the HTC frame to the alloc'd packet buffer */ 815 payload_len = HTC_GET_FIELD(buf, HTC_FRAME_HDR, PAYLOADLEN); 816 payload_len = qdf_le16_to_cpu(payload_len); 817 if (!payload_len) { 818 hif_err("Invalid Payload len %d bytes", payload_len); 819 break; 820 } 821 if (payload_len > g_dbg_payload_len) { 822 g_dbg_payload_len = payload_len; 823 hif_err("Max Rx HTC Payload = %d", g_dbg_payload_len); 824 } 825 826 nbuf = hif_sdio_get_nbuf(dev, payload_len + HTC_HEADER_LEN); 827 if (!nbuf) { 828 hif_err("Failed to alloc rx buffer"); 829 break; 830 } 831 832 /* Check if payload fits in skb */ 833 if (qdf_nbuf_tailroom(nbuf) < payload_len + HTC_HEADER_LEN) { 834 hif_err("Payload + HTC_HDR %d > skb tailroom %d", 835 (payload_len + 8), 836 qdf_nbuf_tailroom(nbuf)); 837 qdf_nbuf_free(nbuf); 838 break; 839 } 840 841 qdf_mem_copy((uint8_t *)qdf_nbuf_data(nbuf), buf, 842 payload_len + HTC_HEADER_LEN); 843 844 qdf_nbuf_put_tail(nbuf, payload_len + HTC_HDR_LENGTH); 845 846 rx_completion(device->hif_callbacks.Context, nbuf, 847 0); /* don't care, not used */ 848 849 len -= payload_len + HTC_HDR_LENGTH; 850 buf += payload_len + HTC_HDR_LENGTH; 851 } 852 853 qdf_nbuf_free((qdf_nbuf_t)bus_req->context); 854 hif_free_bus_request(dev, bus_req); 855 } 856