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
hif_usb_diag_write_cold_reset(struct hif_softc * scn)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
hif_usb_procfs_init(struct hif_softc * scn)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 */
hif_usb_nointrs(struct hif_softc * scn)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 */
hif_usb_reboot(struct notifier_block * nb,unsigned long val,void * v)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 */
hif_usb_disable_lpm(struct usb_device * udev)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 */
hif_usb_enable_bus(struct hif_softc * scn,struct device * dev,void * bdev,const struct hif_bus_id * bid,enum hif_enable_type type)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 */
hif_usb_close(struct hif_softc * scn)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 */
hif_usb_disable_bus(struct hif_softc * hif_ctx)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 */
hif_usb_bus_suspend(struct hif_softc * hif_ctx)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 */
hif_usb_bus_resume(struct hif_softc * hif_ctx)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 */
hif_usb_bus_reset_resume(struct hif_softc * hif_ctx)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 */
hif_usb_open(struct hif_softc * hif_ctx,enum qdf_bus_type bus_type)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 */
hif_usb_disable_isr(struct hif_softc * hif_ctx)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 */
hif_usb_reg_tbl_attach(struct hif_softc * scn)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 */
hif_usb_get_hw_info(struct hif_softc * hif_ctx)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 */
hif_usb_bus_configure(struct hif_softc * scn)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 */
hif_usb_bus_configure(struct hif_softc * scn)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 */
hif_usb_irq_enable(struct hif_softc * scn,int ce_id)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 */
hif_usb_irq_disable(struct hif_softc * scn,int ce_id)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 */
hif_usb_shutdown_bus_device(struct hif_softc * scn)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 */
hif_trigger_dump(struct hif_opaque_softc * scn,uint8_t cmd_id,bool start)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 */
hif_wlan_disable(struct hif_softc * scn)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
hif_fw_assert_ramdump_pattern(struct hif_usb_softc * sc)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
hif_usb_ramdump_handler(struct hif_opaque_softc * scn)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 */
hif_check_fw_reg(struct hif_opaque_softc * scn)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 */
hif_usb_needs_bmi(struct hif_softc * scn)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