aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorAmitkumar Karwar <akarwar@marvell.com>2014-04-17 14:47:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-04-22 15:06:31 -0400
commite050c76fcf49599c5b98e4614392dc87c69123a6 (patch)
tree2ab5ff830cc3aadb0b960077057c47b58aae449f /drivers/net/wireless
parent1c09bf682cbcad8ddeea6ac69decda411f88dd35 (diff)
mwifiex: add firmware dump feature for PCIe
Firmware dump feature is added for PCIe based chipsets. Separate file will be created at /var/log/fw_dump_* for each memory segment. 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>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c3
-rw-r--r--drivers/net/wireless/mwifiex/main.c2
-rw-r--r--drivers/net/wireless/mwifiex/main.h2
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c227
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h27
5 files changed, 261 insertions, 0 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/main.c b/drivers/net/wireless/mwifiex/main.c
index cbabc12fbda3..6bc645a120fa 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -881,6 +881,8 @@ mwifiex_add_card(void *card, struct semaphore *sem,
881 goto err_kmalloc; 881 goto err_kmalloc;
882 882
883 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue); 883 INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
884 if (adapter->if_ops.iface_work)
885 INIT_WORK(&adapter->iface_work, adapter->if_ops.iface_work);
884 886
885 /* Register the device. Fill up the private data structure with relevant 887 /* Register the device. Fill up the private data structure with relevant
886 information from the card. */ 888 information from the card. */
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 34181192a666..d70457b26e26 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -674,6 +674,7 @@ struct mwifiex_if_ops {
674 void (*card_reset) (struct mwifiex_adapter *); 674 void (*card_reset) (struct mwifiex_adapter *);
675 void (*fw_dump)(struct mwifiex_adapter *); 675 void (*fw_dump)(struct mwifiex_adapter *);
676 int (*clean_pcie_ring) (struct mwifiex_adapter *adapter); 676 int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
677 void (*iface_work)(struct work_struct *work);
677}; 678};
678 679
679struct mwifiex_adapter { 680struct mwifiex_adapter {
@@ -809,6 +810,7 @@ struct mwifiex_adapter {
809 bool ext_scan; 810 bool ext_scan;
810 u8 fw_api_ver; 811 u8 fw_api_ver;
811 u8 fw_key_api_major_ver, fw_key_api_minor_ver; 812 u8 fw_key_api_major_ver, fw_key_api_minor_ver;
813 struct work_struct iface_work;
812}; 814};
813 815
814int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); 816int 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 c2cfeec466d8..51989b31137a 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -37,6 +37,9 @@ 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
40/* enum mwifiex_pcie_work_flags bitmap */
41static unsigned long pcie_work_flags;
42
40static int 43static int
41mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb, 44mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
42 size_t size, int flags) 45 size_t size, int flags)
@@ -221,6 +224,8 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
221 if (!adapter || !adapter->priv_num) 224 if (!adapter || !adapter->priv_num)
222 return; 225 return;
223 226
227 cancel_work_sync(&adapter->iface_work);
228
224 if (user_rmmod) { 229 if (user_rmmod) {
225#ifdef CONFIG_PM_SLEEP 230#ifdef CONFIG_PM_SLEEP
226 if (adapter->is_suspended) 231 if (adapter->is_suspended)
@@ -307,6 +312,17 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
307 return 0; 312 return 0;
308} 313}
309 314
315/* This function reads u8 data from PCIE card register. */
316static int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
317 int reg, u8 *data)
318{
319 struct pcie_service_card *card = adapter->card;
320
321 *data = ioread8(card->pci_mmap1 + reg);
322
323 return 0;
324}
325
310/* 326/*
311 * This function adds delay loop to ensure FW is awake before proceeding. 327 * This function adds delay loop to ensure FW is awake before proceeding.
312 */ 328 */
@@ -2172,6 +2188,215 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
2172 return 0; 2188 return 0;
2173} 2189}
2174 2190
2191/* This function read/write firmware */
2192static enum rdwr_status
2193mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
2194{
2195 int ret, tries;
2196 u8 ctrl_data;
2197
2198 ret = mwifiex_write_reg(adapter, DEBUG_DUMP_CTRL_REG, DEBUG_HOST_READY);
2199 if (ret) {
2200 dev_err(adapter->dev, "PCIE write err\n");
2201 return RDWR_STATUS_FAILURE;
2202 }
2203
2204 for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
2205 mwifiex_read_reg_byte(adapter, DEBUG_DUMP_CTRL_REG, &ctrl_data);
2206 if (ctrl_data == DEBUG_FW_DONE)
2207 return RDWR_STATUS_SUCCESS;
2208 if (doneflag && ctrl_data == doneflag)
2209 return RDWR_STATUS_DONE;
2210 if (ctrl_data != DEBUG_HOST_READY) {
2211 dev_info(adapter->dev,
2212 "The ctrl reg was changed, re-try again!\n");
2213 mwifiex_write_reg(adapter, DEBUG_DUMP_CTRL_REG,
2214 DEBUG_HOST_READY);
2215 if (ret) {
2216 dev_err(adapter->dev, "PCIE write err\n");
2217 return RDWR_STATUS_FAILURE;
2218 }
2219 }
2220 usleep_range(100, 200);
2221 }
2222
2223 dev_err(adapter->dev, "Fail to pull ctrl_data\n");
2224 return RDWR_STATUS_FAILURE;
2225}
2226
2227/* This function dump firmware memory to file */
2228static void mwifiex_pcie_fw_dump_work(struct work_struct *work)
2229{
2230 struct mwifiex_adapter *adapter =
2231 container_of(work, struct mwifiex_adapter, iface_work);
2232 unsigned int reg, reg_start, reg_end;
2233 u8 *dbg_ptr;
2234 struct timeval t;
2235 u8 dump_num = 0, idx, i, read_reg, doneflag = 0;
2236 enum rdwr_status stat;
2237 u32 memory_size;
2238 u8 filename[MAX_FULL_NAME_LEN];
2239 mm_segment_t fs;
2240 loff_t pos;
2241 u8 *end_ptr;
2242 u8 *name_prefix = "/var/log/fw_dump_";
2243 struct memory_type_mapping mem_type_mapping_tbl[] = {
2244 {"ITCM", NULL, NULL, 0xF0},
2245 {"DTCM", NULL, NULL, 0xF1},
2246 {"SQRAM", NULL, NULL, 0xF2},
2247 {"IRAM", NULL, NULL, 0xF3},
2248 };
2249
2250 if (!adapter) {
2251 dev_err(adapter->dev, "Could not dump firmwware info\n");
2252 return;
2253 }
2254
2255 do_gettimeofday(&t);
2256 dev_info(adapter->dev, "== mwifiex firmware dump start: %u.%06u ==\n",
2257 (u32)t.tv_sec, (u32)t.tv_usec);
2258
2259 /* Read the number of the memories which will dump */
2260 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2261 if (stat == RDWR_STATUS_FAILURE)
2262 goto done;
2263
2264 reg = DEBUG_DUMP_START_REG;
2265 mwifiex_read_reg_byte(adapter, reg, &dump_num);
2266
2267 /* Read the length of every memory which will dump */
2268 for (idx = 0; idx < dump_num; idx++) {
2269 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2270
2271 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2272 if (stat == RDWR_STATUS_FAILURE)
2273 goto done;
2274
2275 memory_size = 0;
2276 reg = DEBUG_DUMP_START_REG;
2277 for (i = 0; i < 4; i++) {
2278 mwifiex_read_reg_byte(adapter, reg, &read_reg);
2279 memory_size |= (read_reg << (i * 8));
2280 reg++;
2281 }
2282
2283 if (memory_size == 0) {
2284 dev_info(adapter->dev, "Firmware dump Finished!\n");
2285 break;
2286 }
2287
2288 dev_info(adapter->dev,
2289 "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
2290 entry->mem_ptr = vmalloc(memory_size + 1);
2291 if (!entry->mem_ptr) {
2292 dev_err(adapter->dev,
2293 "Vmalloc %s failed\n", entry->mem_name);
2294 goto done;
2295 }
2296 dbg_ptr = entry->mem_ptr;
2297 end_ptr = dbg_ptr + memory_size;
2298
2299 doneflag = entry->done_flag;
2300 do_gettimeofday(&t);
2301 dev_info(adapter->dev, "Start %s output %u.%06u, please wait...\n",
2302 entry->mem_name, (u32)t.tv_sec, (u32)t.tv_usec);
2303
2304 do {
2305 stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
2306 if (RDWR_STATUS_FAILURE == stat)
2307 goto done;
2308
2309 reg_start = DEBUG_DUMP_START_REG;
2310 reg_end = DEBUG_DUMP_END_REG;
2311 for (reg = reg_start; reg <= reg_end; reg++) {
2312 mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
2313 if (dbg_ptr < end_ptr)
2314 dbg_ptr++;
2315 else
2316 dev_err(adapter->dev,
2317 "Allocated buf not enough\n");
2318 }
2319
2320 if (stat != RDWR_STATUS_DONE)
2321 continue;
2322
2323 dev_info(adapter->dev, "%s done: size=0x%lx\n",
2324 entry->mem_name, dbg_ptr - entry->mem_ptr);
2325 memset(filename, 0, sizeof(filename));
2326 memcpy(filename, name_prefix, strlen(name_prefix));
2327 strcat(filename, entry->mem_name);
2328 do_gettimeofday(&t);
2329 entry->file_mem = filp_open(filename, O_CREAT | O_RDWR,
2330 0644);
2331 if (IS_ERR(entry->file_mem)) {
2332 dev_info(adapter->dev,
2333 "Create %s file failed at %s, opening another dir /tmp\n",
2334 entry->mem_name, filename);
2335 memset(filename, 0, sizeof(filename));
2336 sprintf(filename, "%s%s", "/tmp/fw_dump_",
2337 entry->mem_name);
2338 entry->file_mem =
2339 filp_open(filename,
2340 O_CREAT | O_RDWR, 0644);
2341 }
2342 if (!IS_ERR(entry->file_mem)) {
2343 dev_info(adapter->dev,
2344 "Start to save the output : %u.%06u, please wait...\n",
2345 (u32)t.tv_sec, (u32)t.tv_usec);
2346 fs = get_fs();
2347 set_fs(KERNEL_DS);
2348 pos = 0;
2349 vfs_write(entry->file_mem,
2350 (char __user *)entry->mem_ptr,
2351 memory_size, &pos);
2352 filp_close(entry->file_mem, NULL);
2353 set_fs(fs);
2354 dev_info(adapter->dev,
2355 "The output %s have been saved to file successfully!\n",
2356 entry->mem_name);
2357 } else {
2358 dev_err(adapter->dev,
2359 "Failed to create file %s\n", filename);
2360 }
2361 vfree(entry->mem_ptr);
2362 entry->mem_ptr = NULL;
2363 break;
2364 } while (true);
2365 }
2366 do_gettimeofday(&t);
2367 dev_info(adapter->dev, "== mwifiex firmware dump end: %u.%06u ==\n",
2368 (u32)t.tv_sec, (u32)t.tv_usec);
2369
2370done:
2371 for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
2372 struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
2373
2374 if (entry->mem_ptr) {
2375 vfree(entry->mem_ptr);
2376 entry->mem_ptr = NULL;
2377 }
2378 }
2379
2380 return;
2381}
2382
2383static void mwifiex_pcie_work(struct work_struct *work)
2384{
2385 if (test_and_clear_bit(MWIFIEX_PCIE_WORK_FW_DUMP, &pcie_work_flags))
2386 mwifiex_pcie_fw_dump_work(work);
2387}
2388
2389/* This function dumps FW information */
2390static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
2391{
2392 if (test_bit(MWIFIEX_PCIE_WORK_FW_DUMP, &pcie_work_flags))
2393 return;
2394
2395 set_bit(MWIFIEX_PCIE_WORK_FW_DUMP, &pcie_work_flags);
2396
2397 schedule_work(&adapter->iface_work);
2398}
2399
2175/* 2400/*
2176 * This function initializes the PCI-E host memory space, WCB rings, etc. 2401 * This function initializes the PCI-E host memory space, WCB rings, etc.
2177 * 2402 *
@@ -2393,6 +2618,8 @@ static struct mwifiex_if_ops pcie_ops = {
2393 .cleanup_mpa_buf = NULL, 2618 .cleanup_mpa_buf = NULL,
2394 .init_fw_port = mwifiex_pcie_init_fw_port, 2619 .init_fw_port = mwifiex_pcie_init_fw_port,
2395 .clean_pcie_ring = mwifiex_clean_pcie_ring_buf, 2620 .clean_pcie_ring = mwifiex_clean_pcie_ring_buf,
2621 .fw_dump = mwifiex_pcie_fw_dump,
2622 .iface_work = mwifiex_pcie_work,
2396}; 2623};
2397 2624
2398/* 2625/*
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index e8ec561f8a64..3abba32e9448 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -100,6 +100,28 @@
100#define MWIFIEX_DEF_SLEEP_COOKIE 0xBEEFBEEF 100#define MWIFIEX_DEF_SLEEP_COOKIE 0xBEEFBEEF
101#define MWIFIEX_MAX_DELAY_COUNT 5 101#define MWIFIEX_MAX_DELAY_COUNT 5
102 102
103#define DEBUG_DUMP_CTRL_REG 0xCF4
104#define DEBUG_DUMP_START_REG 0xCF8
105#define DEBUG_DUMP_END_REG 0xCFF
106#define DEBUG_HOST_READY 0xEE
107#define DEBUG_FW_DONE 0xFF
108
109#define MAX_NAME_LEN 8
110#define MAX_FULL_NAME_LEN 32
111
112struct memory_type_mapping {
113 u8 mem_name[MAX_NAME_LEN];
114 u8 *mem_ptr;
115 struct file *file_mem;
116 u8 done_flag;
117};
118
119enum rdwr_status {
120 RDWR_STATUS_SUCCESS = 0,
121 RDWR_STATUS_FAILURE = 1,
122 RDWR_STATUS_DONE = 2
123};
124
103struct mwifiex_pcie_card_reg { 125struct mwifiex_pcie_card_reg {
104 u16 cmd_addr_lo; 126 u16 cmd_addr_lo;
105 u16 cmd_addr_hi; 127 u16 cmd_addr_hi;
@@ -322,4 +344,9 @@ mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
322 344
323 return 0; 345 return 0;
324} 346}
347
348enum mwifiex_pcie_work_flags {
349 MWIFIEX_PCIE_WORK_FW_DUMP,
350};
351
325#endif /* _MWIFIEX_PCIE_H */ 352#endif /* _MWIFIEX_PCIE_H */