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