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