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