linux/drivers/net/wireless/ath/wil6210/wil_crash_dump.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Qualcomm Atheros, Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include "wil6210.h"
  18#include <linux/devcoredump.h>
  19
  20static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil,
  21                                        u32 *out_dump_size, u32 *out_host_min)
  22{
  23        int i;
  24        const struct fw_map *map;
  25        u32 host_min, host_max, tmp_max;
  26
  27        if (!out_dump_size)
  28                return -EINVAL;
  29
  30        /* calculate the total size of the unpacked crash dump */
  31        BUILD_BUG_ON(ARRAY_SIZE(fw_mapping) == 0);
  32        map = &fw_mapping[0];
  33        host_min = map->host;
  34        host_max = map->host + (map->to - map->from);
  35
  36        for (i = 1; i < ARRAY_SIZE(fw_mapping); i++) {
  37                map = &fw_mapping[i];
  38
  39                if (map->host < host_min)
  40                        host_min = map->host;
  41
  42                tmp_max = map->host + (map->to - map->from);
  43                if (tmp_max > host_max)
  44                        host_max = tmp_max;
  45        }
  46
  47        *out_dump_size = host_max - host_min;
  48        if (out_host_min)
  49                *out_host_min = host_min;
  50
  51        return 0;
  52}
  53
  54int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
  55{
  56        int i;
  57        const struct fw_map *map;
  58        void *data;
  59        u32 host_min, dump_size, offset, len;
  60
  61        if (wil_fw_get_crash_dump_bounds(wil, &dump_size, &host_min)) {
  62                wil_err(wil, "%s: fail to obtain crash dump size\n", __func__);
  63                return -EINVAL;
  64        }
  65
  66        if (dump_size > size) {
  67                wil_err(wil, "%s: not enough space for dump. Need %d have %d\n",
  68                        __func__, dump_size, size);
  69                return -EINVAL;
  70        }
  71
  72        /* copy to crash dump area */
  73        for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
  74                map = &fw_mapping[i];
  75
  76                data = (void * __force)wil->csr + HOSTADDR(map->host);
  77                len = map->to - map->from;
  78                offset = map->host - host_min;
  79
  80                wil_dbg_misc(wil, "%s() - dump %s, size %d, offset %d\n",
  81                             __func__, fw_mapping[i].name, len, offset);
  82
  83                wil_memcpy_fromio_32((void * __force)(dest + offset),
  84                                     (const void __iomem * __force)data, len);
  85        }
  86
  87        return 0;
  88}
  89
  90void wil_fw_core_dump(struct wil6210_priv *wil)
  91{
  92        void *fw_dump_data;
  93        u32 fw_dump_size;
  94
  95        if (wil_fw_get_crash_dump_bounds(wil, &fw_dump_size, NULL)) {
  96                wil_err(wil, "%s: fail to get fw dump size\n", __func__);
  97                return;
  98        }
  99
 100        fw_dump_data = vzalloc(fw_dump_size);
 101        if (!fw_dump_data)
 102                return;
 103
 104        if (wil_fw_copy_crash_dump(wil, fw_dump_data, fw_dump_size)) {
 105                vfree(fw_dump_data);
 106                return;
 107        }
 108        /* fw_dump_data will be free in device coredump release function
 109         * after 5 min
 110         */
 111        dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL);
 112        wil_info(wil, "%s: fw core dumped, size %d bytes\n", __func__,
 113                 fw_dump_size);
 114}
 115