aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2014-06-20 00:38:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-06-25 15:32:46 -0400
commit92c2538f55132d8e0e53945204cfb137e7d64b6b (patch)
treed9f22d8e73487b306740fa3653af85243235d8cc
parent5f4ef7197db98a40e43904806612a8ccf609c0a3 (diff)
mwifiex: add firmware dump feature for PCIe
Firmware dump feature is added for PCIe based chipsets which can be used with the help of ethtool commands. 1) Trigger firmware dump operation: ethtool --set-dump mlan0 0xff When the operation is completed, udev event will be sent to trigger external application. 2) Following udev rule can be used to get the data from ethtool: DRIVER=="mwifiex_pcie", ACTION=="change", RUN+="/sbin/mwifiex_pcie_fw_dump.sh" mwifiex_pcie_fw_dump.sh: #!/bin/bash ethtool --set-dump mlan0 0 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/ITCM.log ethtool --set-dump mlan0 1 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/DTCM.log ethtool --set-dump mlan0 2 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/SQRAM.log ethtool --set-dump mlan0 3 ethtool --get-dump mlan0 ethtool --get-dump mlan0 data /tmp/IRAM.log Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c3
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c83
-rw-r--r--drivers/net/wireless/mwifiex/init.c13
-rw-r--r--drivers/net/wireless/mwifiex/main.c2
-rw-r--r--drivers/net/wireless/mwifiex/main.h29
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c193
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h10
7 files changed, 332 insertions, 1 deletions
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 8dee6c86f4f1..421322f5e5fb 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -960,6 +960,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
960 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) 960 if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
961 mwifiex_init_fw_complete(adapter); 961 mwifiex_init_fw_complete(adapter);
962 962
963 if (adapter->if_ops.fw_dump)
964 adapter->if_ops.fw_dump(adapter);
965
963 if (adapter->if_ops.card_reset) 966 if (adapter->if_ops.card_reset)
964 adapter->if_ops.card_reset(adapter); 967 adapter->if_ops.card_reset(adapter);
965} 968}
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
index bfb39908b2c6..528bdfa6c60c 100644
--- a/drivers/net/wireless/mwifiex/ethtool.c
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -64,7 +64,90 @@ static int mwifiex_ethtool_set_wol(struct net_device *dev,
64 return 0; 64 return 0;
65} 65}
66 66
67static int
68mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
69{
70 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
71 struct mwifiex_adapter *adapter = priv->adapter;
72 struct memory_type_mapping *entry;
73
74 if (!adapter->if_ops.fw_dump)
75 return -ENOTSUPP;
76
77 dump->flag = adapter->curr_mem_idx;
78 dump->version = 1;
79 if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
80 entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
81 dump->len = entry->mem_size;
82 } else {
83 dump->len = 0;
84 }
85
86 return 0;
87}
88
89static int
90mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
91 void *buffer)
92{
93 u8 *p = buffer;
94 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
95 struct mwifiex_adapter *adapter = priv->adapter;
96 struct memory_type_mapping *entry;
97
98 if (!adapter->if_ops.fw_dump)
99 return -ENOTSUPP;
100
101 if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
102 dev_err(adapter->dev, "firmware dump in progress!!\n");
103 return -EBUSY;
104 }
105
106 entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
107
108 if (!entry->mem_ptr)
109 return -EFAULT;
110
111 memcpy(p, entry->mem_ptr, entry->mem_size);
112
113 entry->mem_size = 0;
114 vfree(entry->mem_ptr);
115 entry->mem_ptr = NULL;
116
117 return 0;
118}
119
120static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
121{
122 struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
123 struct mwifiex_adapter *adapter = priv->adapter;
124
125 if (!adapter->if_ops.fw_dump)
126 return -ENOTSUPP;
127
128 if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
129 dev_err(adapter->dev, "firmware dump in progress!!\n");
130 return -EBUSY;
131 }
132
133 if (val->flag == MWIFIEX_FW_DUMP_IDX) {
134 adapter->curr_mem_idx = val->flag;
135 adapter->if_ops.fw_dump(adapter);
136 return 0;
137 }
138
139 if (val->flag < 0 || val->flag >= adapter->num_mem_types)
140 return -EINVAL;
141
142 adapter->curr_mem_idx = val->flag;
143
144 return 0;
145}
146
67const struct ethtool_ops mwifiex_ethtool_ops = { 147const struct ethtool_ops mwifiex_ethtool_ops = {
68 .get_wol = mwifiex_ethtool_get_wol, 148 .get_wol = mwifiex_ethtool_get_wol,
69 .set_wol = mwifiex_ethtool_set_wol, 149 .set_wol = mwifiex_ethtool_set_wol,
150 .get_dump_flag = mwifiex_get_dump_flag,
151 .get_dump_data = mwifiex_get_dump_data,
152 .set_dump = mwifiex_set_dump,
70}; 153};
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 4ecd0b208ac6..2b68cf3aa336 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -382,6 +382,8 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
382static void 382static void
383mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) 383mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
384{ 384{
385 int idx;
386
385 if (!adapter) { 387 if (!adapter) {
386 pr_err("%s: adapter is NULL\n", __func__); 388 pr_err("%s: adapter is NULL\n", __func__);
387 return; 389 return;
@@ -396,7 +398,16 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
396 dev_dbg(adapter->dev, "info: free cmd buffer\n"); 398 dev_dbg(adapter->dev, "info: free cmd buffer\n");
397 mwifiex_free_cmd_buffer(adapter); 399 mwifiex_free_cmd_buffer(adapter);
398 400
399 dev_dbg(adapter->dev, "info: free scan table\n"); 401 for (idx = 0; idx < adapter->num_mem_types; idx++) {
402 struct memory_type_mapping *entry =
403 &adapter->mem_type_mapping_tbl[idx];
404
405 if (entry->mem_ptr) {
406 vfree(entry->mem_ptr);
407 entry->mem_ptr = NULL;
408 }
409 entry->mem_size = 0;
410 }
400 411
401 if (adapter->sleep_cfm) 412 if (adapter->sleep_cfm)
402 dev_kfree_skb_any(adapter->sleep_cfm); 413 dev_kfree_skb_any(adapter->sleep_cfm);
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 40e4dbd5b89d..31bd34d0f79b 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -879,6 +879,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
879 goto err_kmalloc; 879 goto err_kmalloc;
880 880
881 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 881 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
882 if (adapter->if_ops.iface_work)
883 INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
882 884
883 /* Register the device. Fill up the private data structure with relevant 885 /* Register the device. Fill up the private data structure with relevant
884 information from the card. */ 886 information from the card. */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 1398afa84064..24791e2acf24 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -30,6 +30,7 @@
30#include <linux/etherdevice.h> 30#include <linux/etherdevice.h>
31#include <net/sock.h> 31#include <net/sock.h>
32#include <net/lib80211.h> 32#include <net/lib80211.h>
33#include <linux/vmalloc.h>
33#include <linux/firmware.h> 34#include <linux/firmware.h>
34#include <linux/ctype.h> 35#include <linux/ctype.h>
35#include <linux/of.h> 36#include <linux/of.h>
@@ -410,6 +411,28 @@ struct mwifiex_roc_cfg {
410 struct ieee80211_channel chan; 411 struct ieee80211_channel chan;
411}; 412};
412 413
414#define MWIFIEX_FW_DUMP_IDX 0xff
415#define FW_DUMP_MAX_NAME_LEN 8
416#define FW_DUMP_HOST_READY 0xEE
417#define FW_DUMP_DONE 0xFF
418
419struct memory_type_mapping {
420 u8 mem_name[FW_DUMP_MAX_NAME_LEN];
421 u8 *mem_ptr;
422 u32 mem_size;
423 u8 done_flag;
424};
425
426enum rdwr_status {
427 RDWR_STATUS_SUCCESS = 0,
428 RDWR_STATUS_FAILURE = 1,
429 RDWR_STATUS_DONE = 2
430};
431
432enum mwifiex_iface_work_flags {
433 MWIFIEX_IFACE_WORK_FW_DUMP,
434};
435
413struct mwifiex_adapter; 436struct mwifiex_adapter;
414struct mwifiex_private; 437struct mwifiex_private;
415 438
@@ -674,6 +697,7 @@ struct mwifiex_if_ops {
674 void (*card_reset) (struct mwifiex_adapter *); 697 void (*card_reset) (struct mwifiex_adapter *);
675 void (*fw_dump)(struct mwifiex_adapter *); 698 void (*fw_dump)(struct mwifiex_adapter *);
676 int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); 699 int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
700 void (*iface_work)(struct work_struct *work);
677}; 701};
678 702
679struct mwifiex_adapter { 703struct mwifiex_adapter {
@@ -809,6 +833,11 @@ struct mwifiex_adapter {
809 bool ext_scan; 833 bool ext_scan;
810 u8 fw_api_ver; 834 u8 fw_api_ver;
811 u8 fw_key_api_major_ver, fw_key_api_minor_ver; 835 u8 fw_key_api_major_ver, fw_key_api_minor_ver;
836 struct work_struct iface_work;
837 unsigned long iface_work_flags;
838 struct memory_type_mapping *mem_type_mapping_tbl;
839 u8 num_mem_types;
840 u8 curr_mem_idx;
812}; 841};
813 842
814int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); 843int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 574d4b597468..6ea8e9d314b7 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -37,6 +37,13 @@ static struct mwifiex_if_ops pcie_ops;
37 37
38static struct semaphore add_remove_card_sem; 38static struct semaphore add_remove_card_sem;
39 39
40static struct memory_type_mapping mem_type_mapping_tbl[] = {
41 {"ITCM", NULL, 0, 0xF0},
42 {"DTCM", NULL, 0, 0xF1},
43 {"SQRAM", NULL, 0, 0xF2},
44 {"IRAM", NULL, 0, 0xF3},
45};
46
40static int 47static int
41mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, 48mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
42 size_t size, int flags) 49 size_t size, int flags)
@@ -192,6 +199,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
192 card->pcie.reg = data->reg; 199 card->pcie.reg = data->reg;
193 card->pcie.blksz_fw_dl = data->blksz_fw_dl; 200 card->pcie.blksz_fw_dl = data->blksz_fw_dl;
194 card->pcie.tx_buf_size = data->tx_buf_size; 201 card->pcie.tx_buf_size = data->tx_buf_size;
202 card->pcie.supports_fw_dump = data->supports_fw_dump;
195 } 203 }
196 204
197 if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, 205 if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
@@ -221,6 +229,8 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
221 if (!adapter || !adapter->priv_num) 229 if (!adapter || !adapter->priv_num)
222 return; 230 return;
223 231
232 cancel_work_sync(&adapter->iface_work);
233
224 if (user_rmmod) { 234 if (user_rmmod) {
225#ifdef CONFIG_PM_SLEEP 235#ifdef CONFIG_PM_SLEEP
226 if (adapter->is_suspended) 236 if (adapter->is_suspended)
@@ -307,6 +317,17 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
307 return 0; 317 return 0;
308} 318}
309 319
320/* This function reads u8 data from PCIE card register. */
321static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
322 int reg, u8 *data)
323{
324 struct pcie_service_card *card = adapter->card;
325
326 *data = ioread8(card->pci_mmap1 + reg);
327
328 return 0;
329}
330
310/* 331/*
311 * This function adds delay loop to ensure FW is awake before proceeding. 332 * This function adds delay loop to ensure FW is awake before proceeding.
312 */ 333 */
@@ -2173,6 +2194,174 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
2173 return 0; 2194 return 0;
2174} 2195}
2175 2196
2197/* This function read/write firmware */
2198static enum rdwr_status
2199mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
2200{
2201 int ret, tries;
2202 u8 ctrl_data;
2203 struct pcie_service_card *card = adapter->card;
2204 const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
2205
2206 ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY);
2207 if (ret) {
2208 dev_err(adapter->dev, "PCIE write err\n");
2209 return RDWR_STATUS_FAILURE;
2210 }
2211
2212 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
2213 mwifiex_read_reg_byte(adapter, reg->fw_dump_ctrl, &ctrl_data);
2214 if (ctrl_data == FW_DUMP_DONE)
2215 return RDWR_STATUS_SUCCESS;
2216 if (doneflag && ctrl_data == doneflag)
2217 return RDWR_STATUS_DONE;
2218 if (ctrl_data != FW_DUMP_HOST_READY) {
2219 dev_info(adapter->dev,
2220 "The ctrl reg was changed, re-try again!\n");
2221 mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
2222 FW_DUMP_HOST_READY);
2223 if (ret) {
2224 dev_err(adapter->dev, "PCIE write err\n");
2225 return RDWR_STATUS_FAILURE;
2226 }
2227 }
2228 usleep_range(100, 200);
2229 }
2230
2231 dev_err(adapter->dev, "Fail to pull ctrl_data\n");
2232 return RDWR_STATUS_FAILURE;
2233}
2234
2235/* This function dump firmware memory to file */
2236static void mwifiex_pcie_fw_dump_work(struct mwifiex_adapter *adapter)
2237{
2238 struct pcie_service_card *card = adapter->card;
2239 const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
2240 unsigned int reg, reg_start, reg_end;
2241 struct timeval t;
2242 u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
2243 enum rdwr_status stat;
2244 u32 memory_size;
2245 static char *env[] = { "DRIVER=mwifiex_pcie", "EVENT=fw_dump", NULL };
2246
2247 if (!card->pcie.supports_fw_dump)
2248 return;
2249
2250 for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
2251 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2252
2253 if (entry->mem_ptr) {
2254 vfree(entry->mem_ptr);
2255 entry->mem_ptr = NULL;
2256 }
2257 entry->mem_size = 0;
2258 }
2259
2260 do_gettimeofday(&t);
2261 dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n",
2262 (u32)t.tv_sec, (u32)t.tv_usec);
2263
2264 /* Read the number of the memories which will dump */
2265 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2266 if (stat == RDWR_STATUS_FAILURE)
2267 goto done;
2268
2269 reg = creg->fw_dump_start;
2270 mwifiex_read_reg_byte(adapter, reg, &dump_num);
2271
2272 /* Read the length of every memory which will dump */
2273 for (idx = 0; idx < dump_num; idx++) {
2274 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2275
2276 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2277 if (stat == RDWR_STATUS_FAILURE)
2278 goto done;
2279
2280 memory_size = 0;
2281 reg = creg->fw_dump_start;
2282 for (i = 0; i < 4; i++) {
2283 mwifiex_read_reg_byte(adapter, reg, &read_reg);
2284 memory_size |= (read_reg << (i * 8));
2285 reg++;
2286 }
2287
2288 if (memory_size == 0) {
2289 dev_info(adapter->dev, "Firmware dump Finished!\n");
2290 break;
2291 }
2292
2293 dev_info(adapter->dev,
2294 "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
2295 entry->mem_ptr = vmalloc(memory_size + 1);
2296 entry->mem_size = memory_size;
2297 if (!entry->mem_ptr) {
2298 dev_err(adapter->dev,
2299 "Vmalloc %s failed\n", entry->mem_name);
2300 goto done;
2301 }
2302 dbg_ptr = entry->mem_ptr;
2303 end_ptr = dbg_ptr + memory_size;
2304
2305 doneflag = entry->done_flag;
2306 do_gettimeofday(&t);
2307 dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n",
2308 entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec);
2309
2310 do {
2311 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2312 if (RDWR_STATUS_FAILURE == stat)
2313 goto done;
2314
2315 reg_start = creg->fw_dump_start;
2316 reg_end = creg->fw_dump_end;
2317 for (reg = reg_start; reg <= reg_end; reg++) {
2318 mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
2319 if (dbg_ptr < end_ptr)
2320 dbg_ptr++;
2321 else
2322 dev_err(adapter->dev,
2323 "Allocated buf not enough\n");
2324 }
2325
2326 if (stat != RDWR_STATUS_DONE)
2327 continue;
2328
2329 dev_info(adapter->dev, "%s done: size=0x%tx\n",
2330 entry->mem_name, dbg_ptr - entry->mem_ptr);
2331 break;
2332 } while (true);
2333 }
2334 do_gettimeofday(&t);
2335 dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n",
2336 (u32)t.tv_sec, (u32)t.tv_usec);
2337
2338 kobject_uevent_env(&adapter->wiphy->dev.kobj, KOBJ_CHANGE, env);
2339
2340done:
2341 adapter->curr_mem_idx = 0;
2342}
2343
2344static void mwifiex_pcie_work(struct work_struct *work)
2345{
2346 struct mwifiex_adapter *adapter =
2347 container_of(work, struct mwifiex_adapter, iface_work);
2348
2349 if (test_and_clear_bit(MWIFIEX_IFACE_WORK_FW_DUMP,
2350 &adapter->iface_work_flags))
2351 mwifiex_pcie_fw_dump_work(adapter);
2352}
2353
2354/* This function dumps FW information */
2355static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
2356{
2357 if (test_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags))
2358 return;
2359
2360 set_bit(MWIFIEX_IFACE_WORK_FW_DUMP, &adapter->iface_work_flags);
2361
2362 schedule_work(&adapter->iface_work);
2363}
2364
2176/* 2365/*
2177 * This function initializes the PCI-E host memory space, WCB rings, etc. 2366 * This function initializes the PCI-E host memory space, WCB rings, etc.
2178 * 2367 *
@@ -2342,6 +2531,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
2342 2531
2343 adapter->dev = &pdev->dev; 2532 adapter->dev = &pdev->dev;
2344 adapter->tx_buf_size = card->pcie.tx_buf_size; 2533 adapter->tx_buf_size = card->pcie.tx_buf_size;
2534 adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
2535 adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
2345 strcpy(adapter->fw_name, card->pcie.firmware); 2536 strcpy(adapter->fw_name, card->pcie.firmware);
2346 2537
2347 return 0; 2538 return 0;
@@ -2394,6 +2585,8 @@ static struct mwifiex_if_ops pcie_ops = {
2394 .cleanup_mpa_buf = NULL, 2585 .cleanup_mpa_buf = NULL,
2395 .init_fw_port = mwifiex_pcie_init_fw_port, 2586 .init_fw_port = mwifiex_pcie_init_fw_port,
2396 .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, 2587 .clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
2588 .fw_dump = mwifiex_pcie_fw_dump,
2589 .iface_work = mwifiex_pcie_work,
2397}; 2590};
2398 2591
2399/* 2592/*
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index e8ec561f8a64..ee073f5c9f0d 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -129,6 +129,9 @@ struct mwifiex_pcie_card_reg {
129 u32 ring_tx_start_ptr; 129 u32 ring_tx_start_ptr;
130 u8 pfu_enabled; 130 u8 pfu_enabled;
131 u8 sleep_cookie; 131 u8 sleep_cookie;
132 u16 fw_dump_ctrl;
133 u16 fw_dump_start;
134 u16 fw_dump_end;
132}; 135};
133 136
134static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = { 137static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
@@ -191,6 +194,9 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
191 .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR, 194 .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
192 .pfu_enabled = 1, 195 .pfu_enabled = 1,
193 .sleep_cookie = 0, 196 .sleep_cookie = 0,
197 .fw_dump_ctrl = 0xcf4,
198 .fw_dump_start = 0xcf8,
199 .fw_dump_end = 0xcff
194}; 200};
195 201
196struct mwifiex_pcie_device { 202struct mwifiex_pcie_device {
@@ -198,6 +204,7 @@ struct mwifiex_pcie_device {
198 const struct mwifiex_pcie_card_reg *reg; 204 const struct mwifiex_pcie_card_reg *reg;
199 u16 blksz_fw_dl; 205 u16 blksz_fw_dl;
200 u16 tx_buf_size; 206 u16 tx_buf_size;
207 bool supports_fw_dump;
201}; 208};
202 209
203static const struct mwifiex_pcie_device mwifiex_pcie8766 = { 210static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
@@ -205,6 +212,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
205 .reg = &mwifiex_reg_8766, 212 .reg = &mwifiex_reg_8766,
206 .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, 213 .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
207 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K, 214 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
215 .supports_fw_dump = false,
208}; 216};
209 217
210static const struct mwifiex_pcie_device mwifiex_pcie8897 = { 218static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
@@ -212,6 +220,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
212 .reg = &mwifiex_reg_8897, 220 .reg = &mwifiex_reg_8897,
213 .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD, 221 .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
214 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K, 222 .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
223 .supports_fw_dump = true,
215}; 224};
216 225
217struct mwifiex_evt_buf_desc { 226struct mwifiex_evt_buf_desc {
@@ -322,4 +331,5 @@ mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
322 331
323 return 0; 332 return 0;
324} 333}
334
325#endif /* _MWIFIEX_PCIE_H */ 335#endif /* _MWIFIEX_PCIE_H */