xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/usb/if_usb.c (revision 7cbbd39379b4c6f3666de26d3fab0db60241c14b)
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