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 #include <linux/usb.h> 29 #include <linux/usb/hcd.h> 30 #include "if_usb.h" 31 #include "hif_usb_internal.h" 32 #include "target_type.h" /* TARGET_TYPE_ */ 33 #include "regtable_usb.h" 34 #include "ol_fw.h" 35 #include "hif_debug.h" 36 #include "epping_main.h" 37 #include "hif_main.h" 38 #include "qwlan_version.h" 39 #include "usb_api.h" 40 41 #define DELAY_FOR_TARGET_READY 200 /* 200ms */ 42 43 /* Save memory addresses where we save FW ram dump, and then we could obtain 44 * them by symbol table. 45 */ 46 uint32_t fw_stack_addr; 47 void *fw_ram_seg_addr[FW_RAM_SEG_CNT]; 48 49 50 51 static int hif_usb_unload_dev_num = -1; 52 struct hif_usb_softc *g_usb_sc; 53 54 /** 55 * hif_usb_diag_write_cold_reset() - reset SOC by sending a diag command 56 * @scn: pointer to ol_softc structure 57 * 58 * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error 59 */ 60 static inline QDF_STATUS 61 hif_usb_diag_write_cold_reset(struct hif_softc *scn) 62 { 63 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); 64 65 66 HIF_DBG("%s: resetting SOC", __func__); 67 68 return hif_diag_write_access(hif_hdl, 69 (ROME_USB_SOC_RESET_CONTROL_COLD_RST_LSB | 70 ROME_USB_RTC_SOC_BASE_ADDRESS), 71 SOC_RESET_CONTROL_COLD_RST_SET(1)); 72 } 73 74 /** 75 * hif_usb_procfs_init() - create init procfs 76 * @scn: pointer to hif_usb_softc structure 77 * 78 * Return: int 0 if success else an appropriate error number 79 */ 80 static int 81 hif_usb_procfs_init(struct hif_softc *scn) 82 { 83 int ret = 0; 84 85 HIF_ENTER(); 86 87 if (athdiag_procfs_init(scn) != 0) { 88 HIF_ERROR("athdiag_procfs_init failed"); 89 ret = A_ERROR; 90 } 91 92 scn->athdiag_procfs_inited = true; 93 94 HIF_EXIT(); 95 return ret; 96 } 97 98 /** 99 * hif_nointrs(): disable IRQ 100 * @scn: pointer to struct hif_softc 101 * 102 * This function stops interrupt(s) 103 * 104 * Return: none 105 */ 106 void hif_usb_nointrs(struct hif_softc *scn) 107 { 108 109 } 110 111 /** 112 * hif_usb_reboot() - called at reboot time to reset WLAN SOC 113 * @nb: pointer to notifier_block registered during register_reboot_notifier 114 * @val: code indicating reboot reason 115 * @v: unused pointer 116 * 117 * Return: int 0 if success else an appropriate error number 118 */ 119 static int hif_usb_reboot(struct notifier_block *nb, unsigned long val, 120 void *v) 121 { 122 struct hif_usb_softc *sc; 123 124 HIF_ENTER(); 125 sc = container_of(nb, struct hif_usb_softc, reboot_notifier); 126 /* do cold reset */ 127 hif_usb_diag_write_cold_reset(HIF_GET_SOFTC(sc)); 128 HIF_EXIT(); 129 return NOTIFY_DONE; 130 } 131 132 /** 133 * hif_usb_disable_lpm() - Disable lpm feature of usb2.0 134 * @udev: pointer to usb_device for which LPM is to be disabled 135 * 136 * LPM needs to be disabled to avoid usb2.0 probe timeout 137 * 138 * Return: int 0 if success else an appropriate error number 139 */ 140 static int hif_usb_disable_lpm(struct usb_device *udev) 141 { 142 struct usb_hcd *hcd; 143 int ret = -EPERM; 144 145 HIF_ENTER(); 146 147 if (!udev || !udev->bus) { 148 HIF_ERROR("Invalid input parameters"); 149 goto exit; 150 } 151 152 hcd = bus_to_hcd(udev->bus); 153 if (udev->usb2_hw_lpm_enabled) { 154 if (hcd->driver->set_usb2_hw_lpm) { 155 ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, false); 156 if (!ret) { 157 udev->usb2_hw_lpm_enabled = false; 158 udev->usb2_hw_lpm_capable = false; 159 HIF_TRACE("%s: LPM is disabled", __func__); 160 } else { 161 HIF_TRACE("%s: Fail to disable LPM", 162 __func__); 163 } 164 } else { 165 HIF_TRACE("%s: hcd doesn't support LPM", 166 __func__); 167 } 168 } else { 169 HIF_TRACE("%s: LPM isn't enabled", __func__); 170 } 171 exit: 172 HIF_EXIT(); 173 return ret; 174 } 175 176 /** 177 * hif_usb_enable_bus() - enable usb bus 178 * @ol_sc: hif_softc struct 179 * @dev: device pointer 180 * @bdev: bus dev pointer 181 * @bid: bus id pointer 182 * @type: enum hif_enable_type such as HIF_ENABLE_TYPE_PROBE 183 * 184 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure 185 */ 186 QDF_STATUS hif_usb_enable_bus(struct hif_softc *scn, 187 struct device *dev, void *bdev, 188 const struct hif_bus_id *bid, 189 enum hif_enable_type type) 190 191 { 192 struct usb_interface *interface = (struct usb_interface *)bdev; 193 struct usb_device_id *id = (struct usb_device_id *)bid; 194 int ret = 0; 195 struct hif_usb_softc *sc; 196 struct usb_device *usbdev = interface_to_usbdev(interface); 197 int vendor_id, product_id; 198 199 usb_get_dev(usbdev); 200 201 if (!scn) { 202 HIF_ERROR("%s: hif_ctx is NULL", __func__); 203 goto err_usb; 204 } 205 206 sc = HIF_GET_USB_SOFTC(scn); 207 208 HIF_INFO("%s hif_softc %pK usbdev %pK interface %pK\n", 209 __func__, 210 scn, 211 usbdev, 212 interface); 213 214 vendor_id = qdf_le16_to_cpu(usbdev->descriptor.idVendor); 215 product_id = qdf_le16_to_cpu(usbdev->descriptor.idProduct); 216 217 HIF_ERROR("%s: con_mode = 0x%x, vendor_id = 0x%x product_id = 0x%x", 218 __func__, hif_get_conparam(scn), vendor_id, product_id); 219 220 sc->pdev = (void *)usbdev; 221 sc->dev = &usbdev->dev; 222 sc->devid = id->idProduct; 223 224 if ((usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 225 USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0, 226 HZ)) < 0) { 227 HIF_ERROR("%s[%d]", __func__, __LINE__); 228 goto err_usb; 229 } 230 231 usb_set_interface(usbdev, 0, 0); 232 /* disable lpm to avoid usb2.0 probe timeout */ 233 hif_usb_disable_lpm(usbdev); 234 235 /* params need to be added - TODO 236 * scn->enableuartprint = 1; 237 * scn->enablefwlog = 0; 238 * scn->max_no_of_peers = 1; 239 */ 240 241 sc->interface = interface; 242 sc->reboot_notifier.notifier_call = hif_usb_reboot; 243 register_reboot_notifier(&sc->reboot_notifier); 244 245 if (hif_usb_device_init(sc) != QDF_STATUS_SUCCESS) { 246 HIF_ERROR("ath: %s: hif_usb_device_init failed", __func__); 247 goto err_reset; 248 } 249 250 if (hif_usb_procfs_init(scn)) 251 goto err_reset; 252 253 hif_usb_unload_dev_num = usbdev->devnum; 254 g_usb_sc = sc; 255 HIF_EXIT(); 256 return 0; 257 258 err_reset: 259 hif_usb_diag_write_cold_reset(scn); 260 g_usb_sc = NULL; 261 hif_usb_unload_dev_num = -1; 262 unregister_reboot_notifier(&sc->reboot_notifier); 263 err_usb: 264 ret = QDF_STATUS_E_FAILURE; 265 usb_put_dev(usbdev); 266 return ret; 267 } 268 269 270 /** 271 * hif_usb_close(): close bus, delete hif_sc 272 * @ol_sc: soft_sc struct 273 * 274 * Return: none 275 */ 276 void hif_usb_close(struct hif_softc *scn) 277 { 278 g_usb_sc = NULL; 279 } 280 281 /** 282 * hif_usb_disable_bus(): This function disables usb bus 283 * @hif_ctx: pointer to struct hif_softc 284 * 285 * Return: none 286 */ 287 void hif_usb_disable_bus(struct hif_softc *hif_ctx) 288 { 289 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); 290 struct usb_interface *interface = sc->interface; 291 struct usb_device *udev = interface_to_usbdev(interface); 292 293 HIF_TRACE("%s: trying to remove hif_usb!", __func__); 294 295 /* disable lpm to avoid following cold reset will 296 * cause xHCI U1/U2 timeout 297 */ 298 usb_disable_lpm(udev); 299 300 /* wait for disable lpm */ 301 set_current_state(TASK_INTERRUPTIBLE); 302 schedule_timeout(msecs_to_jiffies(DELAY_FOR_TARGET_READY)); 303 set_current_state(TASK_RUNNING); 304 305 /* do cold reset */ 306 hif_usb_diag_write_cold_reset(hif_ctx); 307 308 if (g_usb_sc->suspend_state) 309 hif_bus_resume(GET_HIF_OPAQUE_HDL(hif_ctx)); 310 311 unregister_reboot_notifier(&sc->reboot_notifier); 312 usb_put_dev(interface_to_usbdev(interface)); 313 314 hif_usb_device_deinit(sc); 315 316 HIF_TRACE("%s hif_usb removed !!!!!!", __func__); 317 } 318 319 /** 320 * hif_usb_bus_suspend() - suspend the bus 321 * @hif_ctx: hif_ctx 322 * 323 * This function suspends the bus, but usb doesn't need to suspend. 324 * Therefore just remove all the pending urb transactions 325 * 326 * Return: 0 for success and non-zero for failure 327 */ 328 int hif_usb_bus_suspend(struct hif_softc *hif_ctx) 329 { 330 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); 331 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_ctx); 332 333 HIF_ENTER(); 334 sc->suspend_state = 1; 335 usb_hif_flush_all(device); 336 HIF_EXIT(); 337 return 0; 338 } 339 340 /** 341 * hif_usb_bus_resume() - hif resume API 342 * @hif_ctx: struct hif_opaque_softc 343 * 344 * This function resumes the bus. but usb doesn't need to resume. 345 * Post recv urbs for RX data pipe 346 * 347 * Return: 0 for success and non-zero for failure 348 */ 349 int hif_usb_bus_resume(struct hif_softc *hif_ctx) 350 { 351 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); 352 struct HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_ctx); 353 354 HIF_ENTER(); 355 sc->suspend_state = 0; 356 usb_hif_start_recv_pipes(device); 357 358 HIF_EXIT(); 359 return 0; 360 } 361 362 /** 363 * hif_usb_bus_reset_resume() - resume the bus after reset 364 * @scn: struct hif_opaque_softc 365 * 366 * This function is called to tell the driver that USB device has been resumed 367 * and it has also been reset. The driver should redo any necessary 368 * initialization. This function resets WLAN SOC. 369 * 370 * Return: int 0 for success, non zero for failure 371 */ 372 int hif_usb_bus_reset_resume(struct hif_softc *hif_ctx) 373 { 374 int ret = 0; 375 376 HIF_ENTER(); 377 if (hif_usb_diag_write_cold_reset(hif_ctx) != QDF_STATUS_SUCCESS) 378 ret = 1; 379 380 HIF_EXIT(); 381 return ret; 382 } 383 384 /** 385 * hif_usb_open()- initialization routine for usb bus 386 * @ol_sc: ol_sc 387 * @bus_type: bus type 388 * 389 * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure 390 */ 391 QDF_STATUS hif_usb_open(struct hif_softc *hif_ctx, 392 enum qdf_bus_type bus_type) 393 { 394 hif_ctx->bus_type = bus_type; 395 return QDF_STATUS_SUCCESS; 396 } 397 398 /** 399 * hif_usb_disable_isr(): disable isr 400 * @hif_ctx: struct hif_softc 401 * 402 * Return: void 403 */ 404 void hif_usb_disable_isr(struct hif_softc *hif_ctx) 405 { 406 /* TODO */ 407 } 408 409 /** 410 * hif_usb_reg_tbl_attach()- attach hif, target register tables 411 * @scn: pointer to ol_softc structure 412 * 413 * Attach host and target register tables based on target_type, target_version 414 * 415 * Return: none 416 */ 417 void hif_usb_reg_tbl_attach(struct hif_softc *scn) 418 { 419 u_int32_t hif_type, target_type; 420 int32_t ret = 0; 421 uint32_t chip_id; 422 QDF_STATUS rv; 423 struct hif_target_info *tgt_info = &scn->target_info; 424 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); 425 426 if (scn->hostdef == NULL && scn->targetdef == NULL) { 427 switch (tgt_info->target_type) { 428 case TARGET_TYPE_AR6320: 429 switch (tgt_info->target_version) { 430 case AR6320_REV1_VERSION: 431 case AR6320_REV1_1_VERSION: 432 case AR6320_REV1_3_VERSION: 433 hif_type = HIF_TYPE_AR6320; 434 target_type = TARGET_TYPE_AR6320; 435 break; 436 case AR6320_REV2_1_VERSION: 437 case AR6320_REV3_VERSION: 438 case QCA9377_REV1_1_VERSION: 439 case QCA9379_REV1_VERSION: 440 hif_type = HIF_TYPE_AR6320V2; 441 target_type = TARGET_TYPE_AR6320V2; 442 break; 443 default: 444 ret = -1; 445 break; 446 } 447 break; 448 default: 449 ret = -1; 450 break; 451 } 452 453 if (ret) 454 return; 455 456 /* assign target register table if we find 457 * corresponding type 458 */ 459 hif_register_tbl_attach(scn, hif_type); 460 target_register_tbl_attach(scn, target_type); 461 /* read the chip revision*/ 462 rv = hif_diag_read_access(hif_hdl, 463 (CHIP_ID_ADDRESS | 464 RTC_SOC_BASE_ADDRESS), 465 &chip_id); 466 if (rv != QDF_STATUS_SUCCESS) { 467 HIF_ERROR("%s: get chip id val (%d)", __func__, 468 rv); 469 } 470 tgt_info->target_revision = 471 CHIP_ID_REVISION_GET(chip_id); 472 } 473 } 474 475 /** 476 * hif_usb_get_hw_info()- attach register table for USB 477 * @hif_ctx: pointer to hif_softc structure 478 479 * This function is used to attach the host and target register tables. 480 * Ideally, we should not attach register tables as a part of this function. 481 * There is scope of cleanup to move register table attach during 482 * initialization for USB bus. 483 * 484 * The reason we are doing register table attach for USB here is that, it relies 485 * on target_info->target_type and target_info->target_version, 486 * which get populated during bmi_firmware_download. "hif_get_fw_info" is the 487 * only initialization related call into HIF there after. 488 * 489 * To fix this, we can move the "get target info, functionality currently in 490 * bmi_firmware_download into hif initialization functions. This change will 491 * affect all buses. Can be taken up as a part of convergence. 492 * 493 * Return: none 494 */ 495 void hif_usb_get_hw_info(struct hif_softc *hif_ctx) 496 { 497 hif_usb_reg_tbl_attach(hif_ctx); 498 } 499 500 501 /** 502 * hif_bus_configure() - configure the bus 503 * @scn: pointer to the hif context. 504 * 505 * return: 0 for success. nonzero for failure. 506 */ 507 int hif_usb_bus_configure(struct hif_softc *scn) 508 { 509 return 0; 510 } 511 512 /** 513 * hif_usb_irq_enable() - hif_usb_irq_enable 514 * @scn: hif_softc 515 * @ce_id: ce_id 516 * 517 * Return: void 518 */ 519 void hif_usb_irq_enable(struct hif_softc *scn, int ce_id) 520 { 521 } 522 523 /** 524 * hif_usb_irq_disable() - hif_usb_irq_disable 525 * @scn: hif_softc 526 * @ce_id: ce_id 527 * 528 * Return: void 529 */ 530 void hif_usb_irq_disable(struct hif_softc *scn, int ce_id) 531 { 532 } 533 534 /** 535 * hif_usb_shutdown_bus_device() - This function shuts down the device 536 * @scn: hif opaque pointer 537 * 538 * Return: void 539 */ 540 void hif_usb_shutdown_bus_device(struct hif_softc *scn) 541 { 542 } 543 544 /** 545 * hif_trigger_dump() - trigger various dump cmd 546 * @scn: struct hif_opaque_softc 547 * @cmd_id: dump command id 548 * @start: start/stop dump 549 * 550 * Return: None 551 */ 552 void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start) 553 { 554 } 555 556 /** 557 * hif_wlan_disable() - call the platform driver to disable wlan 558 * @scn: scn 559 * 560 * Return: void 561 */ 562 void hif_wlan_disable(struct hif_softc *scn) 563 { 564 } 565 566 /** 567 * hif_fw_assert_ramdump_pattern() - handle firmware assert with ramdump pattern 568 * @sc: pointer to hif_usb_softc structure 569 * 570 * Return: void 571 */ 572 573 void hif_fw_assert_ramdump_pattern(struct hif_usb_softc *sc) 574 { 575 uint32_t *reg, pattern, i = 0; 576 uint32_t len; 577 uint8_t *data; 578 uint8_t *ram_ptr = NULL; 579 char *fw_ram_seg_name[FW_RAM_SEG_CNT] = {"DRAM", "IRAM", "AXI"}; 580 size_t fw_ram_reg_size[FW_RAM_SEG_CNT] = { 581 FW_RAMDUMP_DRAMSIZE, 582 FW_RAMDUMP_IRAMSIZE, 583 FW_RAMDUMP_AXISIZE }; 584 585 data = sc->fw_data; 586 len = sc->fw_data_len; 587 pattern = *((A_UINT32 *) data); 588 589 qdf_assert(sc->ramdump_index < FW_RAM_SEG_CNT); 590 i = sc->ramdump_index; 591 reg = (uint32_t *) (data + 4); 592 if (sc->fw_ram_dumping == 0) { 593 sc->fw_ram_dumping = 1; 594 HIF_ERROR("Firmware %s dump:\n", fw_ram_seg_name[i]); 595 sc->ramdump[i] = 596 qdf_mem_malloc(sizeof(struct fw_ramdump) + 597 fw_ram_reg_size[i]); 598 if (!sc->ramdump[i]) { 599 pr_err("Fail to allocate memory for ram dump"); 600 QDF_BUG(0); 601 } 602 (sc->ramdump[i])->mem = (uint8_t *) (sc->ramdump[i] + 1); 603 fw_ram_seg_addr[i] = (sc->ramdump[i])->mem; 604 HIF_ERROR("FW %s start addr = %#08x\n", 605 fw_ram_seg_name[i], *reg); 606 HIF_ERROR("Memory addr for %s = %pK\n", 607 fw_ram_seg_name[i], 608 (sc->ramdump[i])->mem); 609 (sc->ramdump[i])->start_addr = *reg; 610 (sc->ramdump[i])->length = 0; 611 } 612 reg++; 613 ram_ptr = (sc->ramdump[i])->mem + (sc->ramdump[i])->length; 614 (sc->ramdump[i])->length += (len - 8); 615 if (sc->ramdump[i]->length <= fw_ram_reg_size[i]) { 616 qdf_mem_copy(ram_ptr, (A_UINT8 *) reg, len - 8); 617 } else { 618 HIF_ERROR("memory copy overlap\n"); 619 QDF_BUG(0); 620 } 621 622 if (pattern == FW_RAMDUMP_END_PATTERN) { 623 HIF_ERROR("%s memory size = %d\n", fw_ram_seg_name[i], 624 (sc->ramdump[i])->length); 625 if (i == (FW_RAM_SEG_CNT - 1)) 626 QDF_BUG(0); 627 628 sc->ramdump_index++; 629 sc->fw_ram_dumping = 0; 630 } 631 } 632 633 /** 634 * hif_usb_ramdump_handler(): dump bus debug registers 635 * @scn: struct hif_opaque_softc 636 * 637 * This function is to receive information of firmware crash dump, and 638 * save it in host memory. It consists of 5 parts: registers, call stack, 639 * DRAM dump, IRAM dump, and AXI dump, and they are reported to host in order. 640 * 641 * registers: wrapped in a USB packet by starting as FW_ASSERT_PATTERN and 642 * 60 registers. 643 * call stack: wrapped in multiple USB packets, and each of them starts as 644 * FW_REG_PATTERN and contains multiple double-words. The tail 645 * of the last packet is FW_REG_END_PATTERN. 646 * DRAM dump: wrapped in multiple USB pakcets, and each of them start as 647 * FW_RAMDUMP_PATTERN and contains multiple double-wors. The tail 648 * of the last packet is FW_RAMDUMP_END_PATTERN; 649 * IRAM dump and AXI dump are with the same format as DRAM dump. 650 * 651 * Return: 0 for success or error code 652 */ 653 654 void hif_usb_ramdump_handler(struct hif_opaque_softc *scn) 655 { 656 uint32_t *reg, pattern, i, start_addr = 0; 657 uint32_t len; 658 uint8_t *data; 659 uint8_t str_buf[128]; 660 uint32_t remaining; 661 struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(scn); 662 struct hif_softc *hif_ctx = HIF_GET_SOFTC(scn); 663 struct hif_target_info *tgt_info = &hif_ctx->target_info; 664 665 data = sc->fw_data; 666 len = sc->fw_data_len; 667 pattern = *((A_UINT32 *) data); 668 669 if (pattern == FW_ASSERT_PATTERN) { 670 HIF_ERROR("Firmware crash detected...\n"); 671 HIF_ERROR("Host SW version: %s\n", QWLAN_VERSIONSTR); 672 HIF_ERROR("target_type: %d.target_version %d. target_revision%d.", 673 tgt_info->target_type, 674 tgt_info->target_version, 675 tgt_info->target_revision); 676 677 reg = (uint32_t *) (data + 4); 678 print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, 16, 4, reg, 679 min_t(A_UINT32, len - 4, FW_REG_DUMP_CNT * 4), 680 false); 681 sc->fw_ram_dumping = 0; 682 683 } else if (pattern == FW_REG_PATTERN) { 684 reg = (uint32_t *) (data + 4); 685 start_addr = *reg++; 686 if (sc->fw_ram_dumping == 0) { 687 pr_err("Firmware stack dump:"); 688 sc->fw_ram_dumping = 1; 689 fw_stack_addr = start_addr; 690 } 691 remaining = len - 8; 692 /* len is in byte, but it's printed in double-word. */ 693 for (i = 0; i < (len - 8); i += 16) { 694 if ((*reg == FW_REG_END_PATTERN) && (i == len - 12)) { 695 sc->fw_ram_dumping = 0; 696 pr_err("Stack start address = %#08x\n", 697 fw_stack_addr); 698 break; 699 } 700 hex_dump_to_buffer(reg, remaining, 16, 4, str_buf, 701 sizeof(str_buf), false); 702 pr_err("%#08x: %s\n", start_addr + i, str_buf); 703 remaining -= 16; 704 reg += 4; 705 } 706 } else if ((!sc->enable_self_recovery) && 707 ((pattern & FW_RAMDUMP_PATTERN_MASK) == 708 FW_RAMDUMP_PATTERN)) { 709 hif_fw_assert_ramdump_pattern(sc); 710 } 711 } 712 713 #ifndef QCA_WIFI_3_0 714 /** 715 * hif_check_fw_reg(): hif_check_fw_reg 716 * @scn: scn 717 * @state: 718 * 719 * Return: int 720 */ 721 int hif_check_fw_reg(struct hif_opaque_softc *scn) 722 { 723 return 0; 724 } 725 #endif 726 727 /** 728 * hif_usb_needs_bmi() - return true if the soc needs bmi through the driver 729 * @scn: hif context 730 * 731 * Return: true if soc needs driver bmi otherwise false 732 */ 733 bool hif_usb_needs_bmi(struct hif_softc *scn) 734 { 735 return true; 736 } 737