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