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