cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

wil_crash_dump.c (2845B)


      1// SPDX-License-Identifier: ISC
      2/*
      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 function
    118	 * after 5 min
    119	 */
    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}