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