Commit 57670ee8 authored by Amitkumar Karwar's avatar Amitkumar Karwar Committed by Kalle Valo

mwifiex: device dump support via devcoredump framework

Currently device dump generated in the driver is retrieved
using ethtool set/get dump commands. We will get rid of
ethtool approach and use devcoredump framework.

Device dump can be trigger by
cat /debugfs/mwifiex/mlanX/device_dump
and when the dump operation is completed, data can be read by
cat /sys/class/devcoredump/devcdX/data

We have prepared following script to split device dump data
into multiple files.

 [root]# cat mwifiex_split_dump_data.sh
 #!/bin/bash
 # usage: ./mwifiex_split_dump_data.sh dump_data

 fw_dump_data=$1

 mem_type="driverinfo ITCM DTCM SQRAM APU CIU ICU MAC"

 for name in ${mem_type[@]}
 do
     sed -n "/Start dump $name/,/End dump/p" $fw_dump_data  > tmp.$name.log
     if [ ! -s tmp.$name.log ]
     then
         rm -rf tmp.$name.log
     else
         #Remove the describle info "Start dump" and "End dump"
         sed '1d' tmp.$name.log | sed '$d' > /data/$name.log
         if [ -s /data/$name.log ]
         then
             echo "generate /data/$name.log"
         else
             sed '1d' tmp.$name.log | sed '$d' > /var/$name.log
             echo "generate /var/$name.log"
         fi
         rm -rf tmp.$name.log
     fi
 done
Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent fc697159
......@@ -12,6 +12,7 @@ config MWIFIEX_SDIO
tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897"
depends on MWIFIEX && MMC
select FW_LOADER
select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8786/8787/8797/8887/8897 chipsets with SDIO interface.
......@@ -23,6 +24,7 @@ config MWIFIEX_PCIE
tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897"
depends on MWIFIEX && PCI
select FW_LOADER
select WANT_DEV_COREDUMP
---help---
This adds support for wireless adapters based on Marvell
8766/8897 chipsets with PCIe interface.
......
......@@ -64,106 +64,7 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev,
return 0;
}
static int
mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_adapter *adapter = priv->adapter;
struct memory_type_mapping *entry;
if (!adapter->if_ops.device_dump)
return -ENOTSUPP;
dump->flag = adapter->curr_mem_idx;
dump->version = 1;
if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
dump->len = adapter->drv_info_size;
} else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
dump->len = entry->mem_size;
} else {
dump->len = 0;
}
return 0;
}
static int
mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
void *buffer)
{
u8 *p = buffer;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_adapter *adapter = priv->adapter;
struct memory_type_mapping *entry;
if (!adapter->if_ops.device_dump)
return -ENOTSUPP;
if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
if (!adapter->drv_info_dump)
return -EFAULT;
memcpy(p, adapter->drv_info_dump, adapter->drv_info_size);
return 0;
}
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
mwifiex_dbg(adapter, ERROR,
"device dump in progress!!\n");
return -EBUSY;
}
entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
if (!entry->mem_ptr)
return -EFAULT;
memcpy(p, entry->mem_ptr, entry->mem_size);
entry->mem_size = 0;
vfree(entry->mem_ptr);
entry->mem_ptr = NULL;
return 0;
}
static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct mwifiex_adapter *adapter = priv->adapter;
if (!adapter->if_ops.device_dump)
return -ENOTSUPP;
if (val->flag == MWIFIEX_DRV_INFO_IDX) {
adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX;
return 0;
}
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
mwifiex_dbg(adapter, ERROR,
"device dump in progress!!\n");
return -EBUSY;
}
if (val->flag == MWIFIEX_FW_DUMP_IDX) {
adapter->curr_mem_idx = val->flag;
adapter->if_ops.device_dump(adapter);
return 0;
}
if (val->flag < 0 || val->flag >= adapter->num_mem_types)
return -EINVAL;
adapter->curr_mem_idx = val->flag;
return 0;
}
const struct ethtool_ops mwifiex_ethtool_ops = {
.get_wol = mwifiex_ethtool_get_wol,
.set_wol = mwifiex_ethtool_set_wol,
.get_dump_flag = mwifiex_get_dump_flag,
.get_dump_data = mwifiex_get_dump_data,
.set_dump = mwifiex_set_dump,
};
......@@ -982,6 +982,96 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter)
}
EXPORT_SYMBOL_GPL(mwifiex_drv_info_dump);
void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter)
{
u8 idx, *dump_data, *fw_dump_ptr;
u32 dump_len;
dump_len = (strlen("========Start dump driverinfo========\n") +
adapter->drv_info_size +
strlen("\n========End dump========\n"));
for (idx = 0; idx < adapter->num_mem_types; idx++) {
struct memory_type_mapping *entry =
&adapter->mem_type_mapping_tbl[idx];
if (entry->mem_ptr) {
dump_len += (strlen("========Start dump ") +
strlen(entry->mem_name) +
strlen("========\n") +
(entry->mem_size + 1) +
strlen("\n========End dump========\n"));
}
}
dump_data = vzalloc(dump_len + 1);
if (!dump_data)
goto done;
fw_dump_ptr = dump_data;
/* Dump all the memory data into single file, a userspace script will
* be used to split all the memory data to multiple files
*/
mwifiex_dbg(adapter, MSG,
"== mwifiex dump information to /sys/class/devcoredump start");
strcpy(fw_dump_ptr, "========Start dump driverinfo========\n");
fw_dump_ptr += strlen("========Start dump driverinfo========\n");
memcpy(fw_dump_ptr, adapter->drv_info_dump, adapter->drv_info_size);
fw_dump_ptr += adapter->drv_info_size;
strcpy(fw_dump_ptr, "\n========End dump========\n");
fw_dump_ptr += strlen("\n========End dump========\n");
for (idx = 0; idx < adapter->num_mem_types; idx++) {
struct memory_type_mapping *entry =
&adapter->mem_type_mapping_tbl[idx];
if (entry->mem_ptr) {
strcpy(fw_dump_ptr, "========Start dump ");
fw_dump_ptr += strlen("========Start dump ");
strcpy(fw_dump_ptr, entry->mem_name);
fw_dump_ptr += strlen(entry->mem_name);
strcpy(fw_dump_ptr, "========\n");
fw_dump_ptr += strlen("========\n");
memcpy(fw_dump_ptr, entry->mem_ptr, entry->mem_size);
fw_dump_ptr += entry->mem_size;
strcpy(fw_dump_ptr, "\n========End dump========\n");
fw_dump_ptr += strlen("\n========End dump========\n");
}
}
/* device dump data will be free in device coredump release function
* after 5 min
*/
dev_coredumpv(adapter->dev, dump_data, dump_len, GFP_KERNEL);
mwifiex_dbg(adapter, MSG,
"== mwifiex dump information to /sys/class/devcoredump end");
done:
for (idx = 0; idx < adapter->num_mem_types; idx++) {
struct memory_type_mapping *entry =
&adapter->mem_type_mapping_tbl[idx];
if (entry->mem_ptr) {
vfree(entry->mem_ptr);
entry->mem_ptr = NULL;
}
entry->mem_size = 0;
}
if (adapter->drv_info_dump) {
vfree(adapter->drv_info_dump);
adapter->drv_info_dump = NULL;
adapter->drv_info_size = 0;
}
}
EXPORT_SYMBOL_GPL(mwifiex_upload_device_dump);
/*
* CFG802.11 network device handler for statistics retrieval.
*/
......
......@@ -36,6 +36,7 @@
#include <linux/of.h>
#include <linux/idr.h>
#include <linux/inetdevice.h>
#include <linux/devcoredump.h>
#include "decl.h"
#include "ioctl.h"
......@@ -950,7 +951,6 @@ struct mwifiex_adapter {
u8 key_api_major_ver, key_api_minor_ver;
struct memory_type_mapping *mem_type_mapping_tbl;
u8 num_mem_types;
u8 curr_mem_idx;
void *drv_info_dump;
u32 drv_info_size;
bool scan_chan_gap_enabled;
......@@ -1485,6 +1485,7 @@ u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
u8 rx_rate, u8 ht_info);
void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter);
void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
......
......@@ -2314,7 +2314,6 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
enum rdwr_status stat;
u32 memory_size;
int ret;
static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL };
if (!card->pcie.can_dump_fw)
return;
......@@ -2334,7 +2333,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
/* Read the number of the memories which will dump */
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
return;
reg = creg->fw_dump_start;
mwifiex_read_reg_byte(adapter, reg, &dump_num);
......@@ -2345,7 +2344,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (stat == RDWR_STATUS_FAILURE)
goto done;
return;
memory_size = 0;
reg = creg->fw_dump_start;
......@@ -2361,7 +2360,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
FW_DUMP_READ_DONE);
if (ret) {
mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
goto done;
return;
}
break;
}
......@@ -2373,7 +2372,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
if (!entry->mem_ptr) {
mwifiex_dbg(adapter, ERROR,
"Vmalloc %s failed\n", entry->mem_name);
goto done;
return;
}
dbg_ptr = entry->mem_ptr;
end_ptr = dbg_ptr + memory_size;
......@@ -2385,7 +2384,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
do {
stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
if (RDWR_STATUS_FAILURE == stat)
goto done;
return;
reg_start = creg->fw_dump_start;
reg_end = creg->fw_dump_end;
......@@ -2396,7 +2395,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
} else {
mwifiex_dbg(adapter, ERROR,
"Allocated buf not enough\n");
goto done;
return;
}
}
......@@ -2409,18 +2408,14 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
break;
} while (true);
}
mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
done:
adapter->curr_mem_idx = 0;
mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n");
}
static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
{
mwifiex_drv_info_dump(adapter);
mwifiex_pcie_fw_dump(adapter);
mwifiex_upload_device_dump(adapter);
}
static unsigned long iface_work_flags;
......
......@@ -2185,7 +2185,6 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
enum rdwr_status stat;
u32 memory_size;
static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
if (!card->can_dump_fw)
return;
......@@ -2297,17 +2296,15 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
}
mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
done:
sdio_release_host(card->func);
adapter->curr_mem_idx = 0;
}
static void mwifiex_sdio_device_dump_work(struct mwifiex_adapter *adapter)
{
mwifiex_drv_info_dump(adapter);
mwifiex_sdio_fw_dump(adapter);
mwifiex_upload_device_dump(adapter);
}
static void mwifiex_sdio_work(struct work_struct *work)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment