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