blob: 80951ccd12130344aebd8ecb698089b5b5c557c2 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Anurag Chouhanfb54ab02016-02-18 18:00:46 +05302 * Copyright (c) 2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC : wlan_hdd_memdump.c
30 *
31 * WLAN Host Device Driver file for dumping firmware memory
32 *
33 */
34
35#include <sme_api.h>
36#include <wlan_hdd_includes.h>
37#include "wlan_hdd_memdump.h"
38#include <linux/module.h>
39#include <linux/kernel.h>
40#include <linux/version.h>
41#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
42#include <linux/uaccess.h> /* for copy_to_user */
43
44/**
45 * hdd_fw_dump_context - hdd firmware memory dump context
46 *
47 * @request_id: userspace assigned firmware memory dump request ID
48 * @response_event: firmware memory dump request wait event
49 */
50struct hdd_fw_dump_context {
51 uint32_t request_id;
52 struct completion response_event;
53};
54static struct hdd_fw_dump_context fw_dump_context;
55
56/**
57 * memdump_cleanup_timer_cb() - Timer callback function for memory dump cleanup.
58 *
59 * @data: Callback data (used to stored HDD context)
60 *
61 * Callback function registered for memory dump cleanup VOS timer.
62 *
63 * Return: none
64 */
65
66static void memdump_cleanup_timer_cb(void *data)
67{
68 int status;
69 hdd_context_t *hdd_ctx = data;
70 cdf_dma_addr_t paddr;
71 cdf_dma_addr_t dma_ctx = 0;
72 cdf_device_t cdf_ctx;
73
74 status = wlan_hdd_validate_context(hdd_ctx);
75 if (0 != status) {
76 hddLog(LOGE, FL("HDD context is not valid"));
77 return;
78 }
79
80 if (!hdd_ctx->fw_dump_loc) {
81 hddLog(LOG1, FL("Memory dump already freed"));
82 return;
83 }
84
85 cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE);
86 if (!cdf_ctx) {
87 hddLog(LOGE, FL("CDF context is NULL"));
88 return;
89 }
90
91 paddr = hdd_ctx->dump_loc_paddr;
92 mutex_lock(&hdd_ctx->memdump_lock);
93 cdf_os_mem_free_consistent(cdf_ctx,
94 FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx);
95 hdd_ctx->fw_dump_loc = NULL;
96 hdd_ctx->memdump_in_progress = false;
97 mutex_unlock(&hdd_ctx->memdump_lock);
98
99}
100
101/**
102 * wlan_hdd_cfg80211_fw_mem_dump_cb() - Callback to receive FW memory dump
103 * @ctx: pointer to HDD context.
104 * @rsp: pointer to fw dump copy complete response
105 *
106 * This is a callback function used to indicate user space about the
107 * availability for firmware memory dump via vendor event.
108 *
109 * Return: None
110 */
111static void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx,
112 struct fw_dump_rsp *dump_rsp)
113{
114 hdd_context_t *hdd_ctx = ctx;
115 struct hdd_fw_dump_context *context;
116 int status;
117
118 status = wlan_hdd_validate_context(hdd_ctx);
119 if (0 != status) {
120 hddLog(LOGE, FL("HDD context is not valid"));
121 return;
122 }
123
124 spin_lock(&hdd_context_lock);
125 context = &fw_dump_context;
126 /* validate the response received */
127 if (!dump_rsp->dump_complete ||
128 context->request_id != dump_rsp->request_id) {
129 spin_unlock(&hdd_context_lock);
130 hddLog(LOGE,
131 FL("Error @ request_id: %d response_id: %d status: %d"),
132 context->request_id, dump_rsp->request_id,
133 dump_rsp->dump_complete);
134 return;
135 } else {
136 complete(&context->response_event);
137 }
138 spin_unlock(&hdd_context_lock);
139
140 return;
141}
142
143/**
144 * wlan_hdd_send_memdump_rsp - send memory dump response to user space
145 * @hdd_ctx: Pointer to hdd context
146 *
147 * Return: 0 for success; non-zero for failure
148 */
149static int wlan_hdd_send_memdump_rsp(hdd_context_t *hdd_ctx)
150{
151 struct sk_buff *skb;
152 int status;
153
154 status = wlan_hdd_validate_context(hdd_ctx);
155 if (0 != status) {
156 hddLog(LOGE, FL("HDD context is not valid"));
157 return status;
158 }
159
160 skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
161 NLMSG_HDRLEN + NLA_HDRLEN + sizeof(uint32_t));
162
163 if (!skb) {
164 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
165 return -ENOMEM;
166 }
167
168 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE,
169 FW_MEM_DUMP_SIZE)) {
170 hddLog(LOGE, FL("nla put fail"));
171 goto nla_put_failure;
172 }
173
174 cfg80211_vendor_cmd_reply(skb);
175 hddLog(LOG1, FL("Memdump event sent successfully to user space"));
176 return 0;
177
178nla_put_failure:
179 kfree_skb(skb);
180 return -EINVAL;
181}
182
183/**
184 * __wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump
185 * @wiphy: pointer to wireless wiphy structure.
186 * @wdev: pointer to wireless_dev structure.
187 * @data: Pointer to the NL data.
188 * @data_len:Length of @data
189 *
190 * This is called when wlan driver needs to get the firmware memory dump
191 * via vendor specific command.
192 *
193 * Return: 0 on success, error number otherwise.
194 */
195static int __wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy,
196 struct wireless_dev *wdev,
197 const void *data, int data_len)
198{
199 int status;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530200 QDF_STATUS sme_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800201 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
202 struct fw_dump_req fw_mem_dump_req;
203 struct fw_dump_seg_req *seg_req;
204 uint8_t loop;
205 cdf_dma_addr_t paddr;
206 cdf_dma_addr_t dma_ctx = 0;
207 cdf_device_t cdf_ctx;
208 unsigned long rc;
209 struct hdd_fw_dump_context *context;
210
211 status = wlan_hdd_validate_context(hdd_ctx);
212 if (0 != status) {
213 hddLog(LOGE, FL("HDD context is invalid"));
214 return status;
215 }
216
217 cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE);
218 if (!cdf_ctx) {
219 hddLog(LOGE, FL("CDF context is NULL"));
220 return -EINVAL;
221 }
222
223 if (hdd_ctx->memdump_in_progress) {
224 hddLog(LOGE, FL("Already a memdump req in progress."));
225 return -EBUSY;
226 }
227
228 /*
229 * Allocate memory for fw memory dump. Memory allocated should be
230 * contiguous. Physical address of the allocated memory is passed
231 * to the FW for copy
232 *
233 * Reuse the memory if available.
234 */
235 mutex_lock(&hdd_ctx->memdump_lock);
236 if (!hdd_ctx->fw_dump_loc) {
237 hdd_ctx->fw_dump_loc = cdf_os_mem_alloc_consistent(
238 cdf_ctx, FW_MEM_DUMP_SIZE, &paddr, dma_ctx);
239 if (!hdd_ctx->fw_dump_loc) {
240 mutex_unlock(&hdd_ctx->memdump_lock);
241 hddLog(LOGE, FL("cdf_os_mem_alloc_consistent failed"));
242 return -ENOMEM;
243 }
244 hdd_ctx->dump_loc_paddr = paddr;
245 }
246 mutex_unlock(&hdd_ctx->memdump_lock);
247
248 /*
249 * Currently request_id and num_seg is assumed to be default(1)
250 * It is assumed that firmware dump requested is for DRAM section
251 * only
252 */
253
254 fw_mem_dump_req.request_id = FW_MEM_DUMP_REQ_ID;
255 fw_mem_dump_req.num_seg = FW_MEM_DUMP_NUM_SEG;
256
257 hddLog(LOG1, FL("request_id:%d num_seg:%d"),
258 fw_mem_dump_req.request_id, fw_mem_dump_req.num_seg);
259 seg_req = (struct fw_dump_seg_req *) fw_mem_dump_req.segment;
260 for (loop = 0; loop < fw_mem_dump_req.num_seg; loop++) {
261 seg_req->seg_id = 1;
262 seg_req->seg_start_addr_lo = FW_DRAM_LOCATION;
263 seg_req->seg_start_addr_hi = 0;
264 seg_req->seg_length = FW_MEM_DUMP_SIZE;
265 seg_req->dst_addr_lo = hdd_ctx->dump_loc_paddr;
266 seg_req->dst_addr_hi = 0;
267 hddLog(LOG1, FL("seg_number:%d"), loop);
268 hddLog(LOG1,
269 FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"),
270 seg_req->seg_id, seg_req->seg_start_addr_lo,
271 seg_req->seg_start_addr_hi);
272 hddLog(LOG1,
273 FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"),
274 seg_req->seg_length, seg_req->dst_addr_lo,
275 seg_req->dst_addr_hi);
276 seg_req++;
277 }
278
279 /**
280 * Start the cleanup timer.
281 * Memory allocated for this request will be freed up
282 * once the timer expires. Memory dump request is expected to be
283 * completed by this time.
284 *
285 * User space will not be able to access the dump after this time.
286 * New request should be issued to get the dump again.
287 */
288 cdf_mc_timer_start(&hdd_ctx->memdump_cleanup_timer,
289 MEMDUMP_COMPLETION_TIME_MS);
290 hdd_ctx->memdump_in_progress = true;
291
292 spin_lock(&hdd_context_lock);
293 context = &fw_dump_context;
294 context->request_id = fw_mem_dump_req.request_id;
295 INIT_COMPLETION(context->response_event);
296 spin_unlock(&hdd_context_lock);
297
298 sme_status = sme_fw_mem_dump(hdd_ctx->hHal, &fw_mem_dump_req);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530299 if (QDF_STATUS_SUCCESS != sme_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800300 hddLog(LOGE, FL("sme_fw_mem_dump Failed"));
301 mutex_lock(&hdd_ctx->memdump_lock);
302 cdf_os_mem_free_consistent(cdf_ctx,
303 FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx);
304 hdd_ctx->fw_dump_loc = NULL;
305 mutex_unlock(&hdd_ctx->memdump_lock);
306 hdd_ctx->memdump_in_progress = false;
307 if (CDF_TIMER_STATE_RUNNING ==
308 cdf_mc_timer_get_current_state(
309 &hdd_ctx->memdump_cleanup_timer)) {
310 cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer);
311 }
312 return -EINVAL;
313 }
314
315 rc = wait_for_completion_timeout(&context->response_event,
316 msecs_to_jiffies(MEMDUMP_COMPLETION_TIME_MS));
317 if (!rc) {
318 hddLog(LOGE, FL("Target response timed out for request_id: %d"),
319 context->request_id);
320 return -ETIMEDOUT;
321 }
322
323 status = wlan_hdd_send_memdump_rsp(hdd_ctx);
324 if (status)
325 hddLog(LOGE,
326 FL("Failed to send FW memory dump rsp to user space"));
327
328 return status;
329}
330
331/**
332 * wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump
333 * @wiphy: pointer to wireless wiphy structure.
334 * @wdev: pointer to wireless_dev structure.
335 * @data: Pointer to the NL data.
336 * @data_len:Length of @data
337 *
338 * This is called when wlan driver needs to get the firmware memory dump
339 * via vendor specific command.
340 *
341 * Return: 0 on success, error number otherwise.
342 */
343int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy,
344 struct wireless_dev *wdev,
345 const void *data, int data_len)
346{
347 int ret;
348
349 cds_ssr_protect(__func__);
350 ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data, data_len);
351 cds_ssr_unprotect(__func__);
352
353 return ret;
354}
355
356#define PROCFS_MEMDUMP_DIR "debug"
357#define PROCFS_MEMDUMP_NAME "fwdump"
358#define PROCFS_MEMDUMP_PERM 0444
359
360static struct proc_dir_entry *proc_file, *proc_dir;
361
362/** memdump_get_file_data() - get data available in proc file
363 *
364 * @file - handle for the proc file.
365 *
366 * This function is used to retrieve the data passed while
367 * creating proc file entry.
368 *
369 * Return: void pointer to hdd_context
370 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800371static void *memdump_get_file_data(struct file *file)
372{
373 void *hdd_ctx;
374
375 hdd_ctx = PDE_DATA(file_inode(file));
376 return hdd_ctx;
377}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800378
379/**
380 * memdump_read() - perform read operation in memory dump proc file
381 *
382 * @file - handle for the proc file.
383 * @buf - pointer to user space buffer.
384 * @count - number of bytes to be read.
385 * @pos - offset in the from buffer.
386 *
387 * This function performs read operation for the memory dump proc file.
388 *
389 * Return: number of bytes read on success, error code otherwise.
390 */
391static ssize_t memdump_read(struct file *file, char __user *buf,
392 size_t count, loff_t *pos)
393{
394 int status;
395 hdd_context_t *hdd_ctx;
396 cdf_dma_addr_t paddr;
397 cdf_dma_addr_t dma_ctx = 0;
398 cdf_device_t cdf_ctx;
399
400 hdd_ctx = memdump_get_file_data(file);
401
402 hddLog(LOG1, FL("Read req for size:%zu pos:%llu"), count, *pos);
403 status = wlan_hdd_validate_context(hdd_ctx);
404 if (0 != status) {
405 hddLog(LOGE, FL("HDD context is not valid"));
406 return -EINVAL;
407 }
408 cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE);
409 if (!cdf_ctx) {
410 hddLog(LOGE, FL("CDF context is NULL"));
411 return -EINVAL;
412 }
413
414 if (!hdd_ctx->memdump_in_progress) {
415 hddLog(LOGE, FL("Current mem dump request timed out/failed"));
416 return -EINVAL;
417 }
418
419 if (*pos < 0) {
420 hddLog(LOGE, FL("Invalid start offset for memdump read"));
421 return -EINVAL;
422 } else if (*pos >= FW_MEM_DUMP_SIZE || !count) {
423 hddLog(LOGE, FL("No more data to copy"));
424 return 0;
425 } else if (count > FW_MEM_DUMP_SIZE - *pos) {
426 count = FW_MEM_DUMP_SIZE - *pos;
427 }
428
429 if (!hdd_ctx->fw_dump_loc) {
430 hddLog(LOGE, FL("Invalid fw mem dump location"));
431 return -EINVAL;
432 }
433
434 if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) {
435 hddLog(LOGE, FL("copy to user space failed"));
436 return -EFAULT;
437 }
438
439 /* offset(pos) should be updated here based on the copy done*/
440 *pos += count;
441
442 /* Entire FW memory dump copy completed */
443 if (*pos >= FW_MEM_DUMP_SIZE) {
444 paddr = hdd_ctx->dump_loc_paddr;
445 mutex_lock(&hdd_ctx->memdump_lock);
446 cdf_os_mem_free_consistent(cdf_ctx,
447 FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx);
448 hdd_ctx->fw_dump_loc = NULL;
449 hdd_ctx->memdump_in_progress = false;
450 if (CDF_TIMER_STATE_RUNNING ==
451 cdf_mc_timer_get_current_state(
452 &hdd_ctx->memdump_cleanup_timer)) {
453 cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer);
454 }
455 mutex_unlock(&hdd_ctx->memdump_lock);
456 }
457
458 return count;
459}
460
461/**
462 * struct memdump_fops - file operations for memory dump feature
463 * @read - read function for memory dump operation.
464 *
465 * This structure initialize the file operation handle for memory
466 * dump feature
467 */
468static const struct file_operations memdump_fops = {
469 read: memdump_read
470};
471
472/**
473 * memdump_procfs_init() - Initialize procfs for memory dump
474 *
475 * This function create file under proc file system to be used later for
476 * processing firmware memory dump
477 *
478 * Return: 0 on success, error code otherwise.
479 */
480static int memdump_procfs_init(void)
481{
482 hdd_context_t *hdd_ctx;
483
484 hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
485 if (!hdd_ctx) {
486 hddLog(LOGE , FL("Invalid HDD context"));
487 return -EINVAL;
488 }
489
490 proc_dir = proc_mkdir(PROCFS_MEMDUMP_DIR, NULL);
491 if (proc_dir == NULL) {
492 remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL);
493 pr_debug("Error: Could not initialize /proc/%s\n",
494 PROCFS_MEMDUMP_DIR);
495 return -ENOMEM;
496 }
497
498 proc_file = proc_create_data(PROCFS_MEMDUMP_NAME,
499 PROCFS_MEMDUMP_PERM, proc_dir,
500 &memdump_fops, hdd_ctx);
501 if (proc_file == NULL) {
502 remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir);
503 pr_debug("Error: Could not initialize /proc/%s\n",
504 PROCFS_MEMDUMP_NAME);
505 return -ENOMEM;
506 }
507
508 pr_debug("/proc/%s/%s created\n", PROCFS_MEMDUMP_DIR,
509 PROCFS_MEMDUMP_NAME);
510 return 0;
511}
512
513/**
514 * memdump_procfs_remove() - Remove file/dir under procfs for memory dump
515 *
516 * This function removes file/dir under proc file system that was
517 * processing firmware memory dump
518 *
519 * Return: None
520 */
521static void memdump_procfs_remove(void)
522{
523 remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir);
524 pr_debug("/proc/%s/%s removed\n", PROCFS_MEMDUMP_DIR,
525 PROCFS_MEMDUMP_NAME);
526 remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL);
527 pr_debug("/proc/%s removed\n", PROCFS_MEMDUMP_DIR);
528}
529
530/**
531 * memdump_init() - Intialization function for memory dump feature
532 *
533 * This function creates proc file for memdump feature and registers
534 * HDD callback function with SME.
535 *
536 * Return - 0 on success, error otherwise
537 */
538int memdump_init(void)
539{
540 hdd_context_t *hdd_ctx;
541 int status = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530542 QDF_STATUS cb_status;
543 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800544
545 hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
546 if (!hdd_ctx) {
547 hddLog(LOGE , FL("Invalid HDD context"));
548 return -EINVAL;
549 }
550
Peng Xuf5d60c82015-10-02 17:17:03 -0700551 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800552 hddLog(LOGE, FL("Not initializing memdump in FTM mode"));
553 return -EINVAL;
554 }
555
556 cb_status = sme_fw_mem_dump_register_cb(hdd_ctx->hHal,
557 wlan_hdd_cfg80211_fw_mem_dump_cb);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530558 if (QDF_STATUS_SUCCESS != cb_status) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800559 hddLog(LOGE , FL("Failed to register the callback"));
560 return -EINVAL;
561 }
562
563 status = memdump_procfs_init();
564 if (status) {
565 hddLog(LOGE , FL("Failed to create proc file"));
566 return status;
567 }
568
569 init_completion(&fw_dump_context.response_event);
570
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530571 qdf_status = cdf_mc_timer_init(&hdd_ctx->memdump_cleanup_timer,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800572 CDF_TIMER_TYPE_SW, memdump_cleanup_timer_cb,
573 (void *)hdd_ctx);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530574 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800575 hddLog(LOGE, FL("Failed to init memdump cleanup timer"));
576 return -EINVAL;
577 }
578
579 mutex_init(&hdd_ctx->memdump_lock);
580
581 return 0;
582}
583
584/**
585 * memdump_deinit() - De initialize memdump feature
586 *
587 * This function removes proc file created for memdump feature.
588 *
589 * Return: None
590 */
591void memdump_deinit(void)
592{
593 hdd_context_t *hdd_ctx;
594 cdf_dma_addr_t paddr;
595 cdf_dma_addr_t dma_ctx = 0;
596 cdf_device_t cdf_ctx;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530597 QDF_STATUS qdf_status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800598
599 hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
600 if (!hdd_ctx) {
601 hddLog(LOGE , FL("Invalid HDD context"));
602 return;
603 }
604
Peng Xuf5d60c82015-10-02 17:17:03 -0700605 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800606 hddLog(LOGE, FL("Not deinitializing memdump in FTM mode"));
607 return;
608 }
609
610 cdf_ctx = cds_get_context(CDF_MODULE_ID_CDF_DEVICE);
611 if (!cdf_ctx) {
612 hddLog(LOGE, FL("CDF context is NULL"));
613 return;
614 }
615
616 memdump_procfs_remove();
617 sme_fw_mem_dump_unregister_cb(hdd_ctx->hHal);
618
619 mutex_lock(&hdd_ctx->memdump_lock);
620 if (hdd_ctx->fw_dump_loc) {
621 paddr = hdd_ctx->dump_loc_paddr;
622 cdf_os_mem_free_consistent(cdf_ctx,
623 FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx);
624 hdd_ctx->fw_dump_loc = NULL;
625 hdd_ctx->memdump_in_progress = false;
626 }
627 mutex_unlock(&hdd_ctx->memdump_lock);
628
629 if (CDF_TIMER_STATE_RUNNING ==
630 cdf_mc_timer_get_current_state(&hdd_ctx->memdump_cleanup_timer)) {
631 cdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer);
632 }
633
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530634 qdf_status = cdf_mc_timer_destroy(&hdd_ctx->memdump_cleanup_timer);
635 if (!QDF_IS_STATUS_SUCCESS(qdf_status))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800636 hddLog(LOGE, FL("Failed to deallocate timer"));
637}