root/drivers/net/wireless/ath/wil6210/wil_crash_dump.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wil_fw_get_crash_dump_bounds
  2. wil_fw_copy_crash_dump
  3. wil_fw_core_dump

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

/* [<][>][^][v][top][bottom][index][help] */