brintos

brintos / linux-shallow public Read only

0
0
Text · 2.8 KiB · 89c12cb Raw
123 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2015,2017 Qualcomm Atheros, Inc.4 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.5 */6 7#include "wil6210.h"8#include <linux/devcoredump.h>9 10static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,11					u32 *out_dump_size, u32 *out_host_min)12{13	int i;14	const struct fw_map *map;15	u32 host_min, host_max, tmp_max;16 17	if (!out_dump_size)18		return -EINVAL;19 20	/* calculate the total size of the unpacked crash dump */21	BUILD_BUG_ON(ARRAY_SIZE(fw_mapping) == 0);22	map = &fw_mapping[0];23	host_min = map->host;24	host_max = map->host + (map->to - map->from);25 26	for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) {27		map = &fw_mapping[i];28 29		if (!map->crash_dump)30			continue;31 32		if (map->host < host_min)33			host_min = map->host;34 35		tmp_max = map->host + (map->to - map->from);36		if (tmp_max > host_max)37			host_max = tmp_max;38	}39 40	*out_dump_size = host_max - host_min;41	if (out_host_min)42		*out_host_min = host_min;43 44	return 0;45}46 47int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)48{49	int i;50	const struct fw_map *map;51	void *data;52	u32 host_min, dump_size, offset, len;53 54	if (wil_fw_get_crash_dump_bounds(wil, &dump_size, &host_min)) {55		wil_err(wil, "fail to obtain crash dump size\n");56		return -EINVAL;57	}58 59	if (dump_size > size) {60		wil_err(wil, "not enough space for dump. Need %d have %d\n",61			dump_size, size);62		return -EINVAL;63	}64 65	down_write(&wil->mem_lock);66 67	if (test_bit(wil_status_suspending, wil->status) ||68	    test_bit(wil_status_suspended, wil->status)) {69		wil_err(wil,70			"suspend/resume in progress. cannot copy crash dump\n");71		up_write(&wil->mem_lock);72		return -EBUSY;73	}74 75	/* copy to crash dump area */76	for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {77		map = &fw_mapping[i];78 79		if (!map->crash_dump)80			continue;81 82		data = (void * __force)wil->csr + HOSTADDR(map->host);83		len = map->to - map->from;84		offset = map->host - host_min;85 86		wil_dbg_misc(wil,87			     "fw_copy_crash_dump: - dump %s, size %d, offset %d\n",88			     fw_mapping[i].name, len, offset);89 90		wil_memcpy_fromio_32((void * __force)(dest + offset),91				     (const void __iomem * __force)data, len);92	}93 94	up_write(&wil->mem_lock);95 96	return 0;97}98 99void wil_fw_core_dump(struct wil6210_priv *wil)100{101	void *fw_dump_data;102	u32 fw_dump_size;103 104	if (wil_fw_get_crash_dump_bounds(wil, &fw_dump_size, NULL)) {105		wil_err(wil, "fail to get fw dump size\n");106		return;107	}108 109	fw_dump_data = vzalloc(fw_dump_size);110	if (!fw_dump_data)111		return;112 113	if (wil_fw_copy_crash_dump(wil, fw_dump_data, fw_dump_size)) {114		vfree(fw_dump_data);115		return;116	}117	/* fw_dump_data will be free in device coredump release function118	 * after 5 min119	 */120	dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL);121	wil_info(wil, "fw core dumped, size %d bytes\n", fw_dump_size);122}123