From bdf0f67439baf5dec556eca56607f01cb420dbe0 Mon Sep 17 00:00:00 2001 From: Krishna Kumaar Natarajan Date: Thu, 16 Apr 2015 12:29:20 -0700 Subject: qcacld: Support to send memory dump to user space Add support to send firmware memory dump to user space application for debugging Change-Id: I426be14c701d9d523b30704580700cc9914d4f66 CRs-Fixed: 822917 --- CORE/HDD/inc/wlan_hdd_cfg80211.h | 3 + CORE/HDD/inc/wlan_hdd_main.h | 7 + CORE/HDD/inc/wlan_hdd_memdump.h | 72 ++++++ CORE/HDD/src/wlan_hdd_cfg80211.c | 18 ++ CORE/HDD/src/wlan_hdd_main.c | 6 +- CORE/HDD/src/wlan_hdd_memdump.c | 507 ++++++++++++++++++++++++++++++++++++++ CORE/MAC/inc/sirApi.h | 55 +++++ CORE/MAC/inc/wniApi.h | 1 + CORE/MAC/src/include/sirParams.h | 2 + CORE/SERVICES/WMA/wma.c | 204 +++++++++++++++ CORE/SME/inc/smeInternal.h | 3 + CORE/SME/inc/sme_Api.h | 5 + CORE/SME/src/sme_common/sme_Api.c | 173 +++++++++++++ CORE/WDA/inc/wlan_qct_wda.h | 2 + Kbuild | 10 + Kconfig | 4 + 16 files changed, 1071 insertions(+), 1 deletion(-) create mode 100644 CORE/HDD/inc/wlan_hdd_memdump.h create mode 100644 CORE/HDD/src/wlan_hdd_memdump.c diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h index 571ec6c03852..f55459cc97f6 100644 --- a/CORE/HDD/inc/wlan_hdd_cfg80211.h +++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h @@ -301,6 +301,9 @@ enum qca_nl80211_vendor_subcmds_index { #endif /* OCB events */ QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, +#ifdef WLAN_FEATURE_MEMDUMP + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX, +#endif /* WLAN_FEATURE_MEMDUMP */ }; /* EXT TDLS */ diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h index 061a2d337a5a..01a01a6b4d82 100644 --- a/CORE/HDD/inc/wlan_hdd_main.h +++ b/CORE/HDD/inc/wlan_hdd_main.h @@ -1512,6 +1512,13 @@ struct hdd_context_s struct hdd_ll_stats_context ll_stats_context; #endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef WLAN_FEATURE_MEMDUMP + uint8_t *fw_dump_loc; + uint32_t dump_loc_paddr; + vos_timer_t memdump_cleanup_timer; + struct mutex memdump_lock; + bool memdump_in_progress; +#endif /* WLAN_FEATURE_MEMDUMP */ }; /*--------------------------------------------------------------------------- diff --git a/CORE/HDD/inc/wlan_hdd_memdump.h b/CORE/HDD/inc/wlan_hdd_memdump.h new file mode 100644 index 000000000000..9cf488067830 --- /dev/null +++ b/CORE/HDD/inc/wlan_hdd_memdump.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * All Rights Reserved. + * Qualcomm Atheros Confidential and Proprietary. + * + */ + +/** + * DOC : wlan_hdd_memdump.h + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#if !defined(WLAN_HDD_MEMDUMP_H) +#define WLAN_HDD_MEMDUMP_H + +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_MEMDUMP +/** + * enum qca_wlan_vendor_attr_memory_dump - values for memory dump attributes + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_REQUEST_ID - Indicate request ID + * @QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE - Indicate size of the memory dump + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP sub command. + */ +enum qca_wlan_vendor_attr_memory_dump { + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_REQUEST_ID = 1, + QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE = 2, + + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX = + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - 1, +}; + +/* Size of fw memory dump is estimated to be 327680 bytes */ +#define FW_MEM_DUMP_SIZE 327680 +#define FW_DRAM_LOCATION 0x00400000 +#define FW_MEM_DUMP_REQ_ID 1 +#define FW_MEM_DUMP_NUM_SEG 1 +#define MEMDUMP_COMPLETION_TIME_MS 5000 + +int memdump_init(void); +void memdump_deinit(void); +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#else +static inline int memdump_init(void) +{ + return -ENOTSUPP; +} + +static inline void memdump_deinit(void) +{ +} + +static inline int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} +#endif + +#endif /* if !defined(WLAN_HDD_MEMDUMP_H)*/ diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c index f764deb02b10..3140a4c9f924 100644 --- a/CORE/HDD/src/wlan_hdd_cfg80211.c +++ b/CORE/HDD/src/wlan_hdd_cfg80211.c @@ -109,6 +109,8 @@ #include "wlan_hdd_ocb.h" #include "qwlan_version.h" +#include "wlan_hdd_memdump.h" + #define g_mode_rates_size (12) #define a_mode_rates_size (8) #define FREQ_BASE_80211G (2407) @@ -1223,6 +1225,12 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT }, +#ifdef WLAN_FEATURE_MEMDUMP + [QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP + }, +#endif /* WLAN_FEATURE_MEMDUMP */ }; static int is_driver_dfs_capable(struct wiphy *wiphy, @@ -7342,6 +7350,16 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = .doit = wlan_hdd_cfg80211_get_logger_supp_feature }, +#ifdef WLAN_FEATURE_MEMDUMP + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_fw_mem_dump + }, +#endif /* WLAN_FEATURE_MEMDUMP */ }; diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index 4e30b30eb7a2..c4e50fa14e45 100755 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -110,6 +110,8 @@ #ifdef CONFIG_CNSS #include #endif +#include "wlan_hdd_memdump.h" + extern int hdd_hostapd_stop (struct net_device *dev); void hdd_ch_avoid_cb(void *hdd_context,void *indi_param); #endif /* FEATURE_WLAN_CH_AVOID */ @@ -12282,6 +12284,7 @@ static int hdd_driver_init( void) break; } else { pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); + memdump_init(); return 0; } @@ -12302,7 +12305,7 @@ static int hdd_driver_init( void) #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE wlan_logging_sock_deinit_svc(); #endif - + memdump_deinit(); pr_err("%s: driver load failure\n", WLAN_MODULE_NAME); } else @@ -12408,6 +12411,7 @@ static void hdd_driver_exit(void) } vos_wait_for_work_thread_completion(__func__); + memdump_deinit(); hif_unregister_driver(); diff --git a/CORE/HDD/src/wlan_hdd_memdump.c b/CORE/HDD/src/wlan_hdd_memdump.c new file mode 100644 index 000000000000..399576b5f7ba --- /dev/null +++ b/CORE/HDD/src/wlan_hdd_memdump.c @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * All Rights Reserved. + * Qualcomm Atheros Confidential and Proprietary. + * + */ + +/** + * DOC : wlan_hdd_memdump.c + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#include +#include +#include "wlan_hdd_memdump.h" + +/** + * memdump_cleanup_timer_cb() - Timer callback function for memory dump cleanup. + * + * @data: Callback data (used to stored HDD context) + * + * Callback function registered for memory dump cleanup VOS timer. + * + * Return: none + */ + +static void memdump_cleanup_timer_cb(void *data) +{ + int status; + hdd_context_t *hdd_ctx = data; + adf_os_dma_addr_t paddr; + adf_os_dma_addr_t dma_ctx; + adf_os_device_t adf_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return; + } + + if (!hdd_ctx->fw_dump_loc) { + hddLog(LOG1, FL("Memory dump already freed")); + return; + } + + adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, hdd_ctx->pvosContext); + if (!adf_ctx) { + hddLog(LOGE, FL("ADF context is NULL")); + return; + } + + paddr = hdd_ctx->dump_loc_paddr; + mutex_lock(&hdd_ctx->memdump_lock); + adf_os_mem_free_consistent(adf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + mutex_unlock(&hdd_ctx->memdump_lock); + +} + +/** + * wlan_hdd_cfg80211_fw_mem_dump_cb() - Callback to receive FW memory dump + * @ctx: pointer to HDD context. + * @rsp: pointer to fw dump copy complete response + * + * This is a callback function used to indicate user space about the + * availability for firmware memory dump via vendor event. + * + * Return: None + */ +static void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, + struct fw_dump_rsp *dump_rsp) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + int status; + struct sk_buff *skb = NULL; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return; + } + + if (!dump_rsp->dump_complete) { + hddLog(LOGE, FL("fw dump copy failed status from FW.")); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX, + GFP_KERNEL); + + if (!skb) { + hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed")); + return; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE, + FW_MEM_DUMP_SIZE)) { + hddLog(LOGE, FL("nla put fail")); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + hddLog(LOG1, FL("Memdump event sent successfully to user space")); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int status; + VOS_STATUS sme_status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct fw_dump_req fw_mem_dump_req; + struct fw_dump_seg_req* seg_req; + uint8_t loop; + adf_os_dma_addr_t paddr; + adf_os_dma_addr_t dma_ctx; + adf_os_device_t adf_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is invalid")); + return status; + } + + adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, hdd_ctx->pvosContext); + if (!adf_ctx) { + hddLog(LOGE, FL("ADF context is NULL")); + return -EINVAL; + } + + if (hdd_ctx->memdump_in_progress) { + hddLog(LOGE, FL("Already a memdump req in progress.")); + return -EBUSY; + } + + /* + * Allocate memory for fw memory dump. Memory allocated should be + * contiguous. Physical address of the allocated memory is passed + * to the FW for copy + * + * Reuse the memory if available. + */ + mutex_lock(&hdd_ctx->memdump_lock); + if (!hdd_ctx->fw_dump_loc) { + hdd_ctx->fw_dump_loc = adf_os_mem_alloc_consistent( + adf_ctx, FW_MEM_DUMP_SIZE, &paddr, dma_ctx); + if (!hdd_ctx->fw_dump_loc) { + mutex_unlock(&hdd_ctx->memdump_lock); + hddLog(LOGE, FL("adf_os_mem_alloc_consistent failed")); + return -ENOMEM; + } + hdd_ctx->dump_loc_paddr = paddr; + } + mutex_unlock(&hdd_ctx->memdump_lock); + + /* + * Currently request_id and num_seg is assumed to be default(1) + * It is assumed that firmware dump requested is for DRAM section + * only + */ + + fw_mem_dump_req.request_id = FW_MEM_DUMP_REQ_ID; + fw_mem_dump_req.num_seg = FW_MEM_DUMP_NUM_SEG; + + hddLog(LOG1, FL("request_id:%d num_seg:%d"), + fw_mem_dump_req.request_id, fw_mem_dump_req.num_seg); + seg_req = (struct fw_dump_seg_req *) fw_mem_dump_req.segment; + for (loop = 0; loop < fw_mem_dump_req.num_seg; loop++) { + seg_req->seg_id = 1; + seg_req->seg_start_addr_lo = FW_DRAM_LOCATION; + seg_req->seg_start_addr_hi = 0; + seg_req->seg_length = FW_MEM_DUMP_SIZE; + seg_req->dst_addr_lo = hdd_ctx->dump_loc_paddr; + seg_req->dst_addr_hi = 0; + hddLog(LOG1, FL("seg_number:%d"), loop); + hddLog(LOG1, + FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + seg_req->seg_id, seg_req->seg_start_addr_lo, + seg_req->seg_start_addr_hi); + hddLog(LOG1, + FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + seg_req->seg_length, seg_req->dst_addr_lo, + seg_req->dst_addr_hi); + seg_req++; + } + + /** + * Start the cleanup timer. + * Memory allocated for this request will be freed up + * once the timer expires. Memory dump request is expected to be + * completed by this time. + * + * User space will not be able to access the dump after this time. + * New request should be issued to get the dump again. + */ + vos_timer_start(&hdd_ctx->memdump_cleanup_timer, + MEMDUMP_COMPLETION_TIME_MS); + hdd_ctx->memdump_in_progress = true; + + sme_status = sme_fw_mem_dump(hdd_ctx->hHal, &fw_mem_dump_req); + if (VOS_STATUS_SUCCESS != sme_status) { + hddLog(LOGE, FL("sme_fw_mem_dump Failed")); + mutex_lock(&hdd_ctx->memdump_lock); + adf_os_mem_free_consistent(adf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_ctx->memdump_in_progress = false; + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&hdd_ctx->memdump_cleanup_timer)) { + vos_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + return -EINVAL; + } + + return 0; +} + +#define PROCFS_MEMDUMP_DIR "debug" +#define PROCFS_MEMDUMP_NAME "fwdump" + +static struct proc_dir_entry *proc_file, *proc_dir; + +/** + * memdump_read() - perform read operation in memory dump proc file + * + * @file - handle for the proc file. + * @buf - pointer to user space buffer. + * @count - number of bytes to be read. + * @pos - offset in the from buffer. + * + * This function performs read operation for the memory dump proc file. + * + * Return: number of bytes read on success, error code otherwise. + */ +static ssize_t memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + hdd_context_t *hdd_ctx = (hdd_context_t *)PDE_DATA(file_inode(file)); + adf_os_dma_addr_t paddr; + adf_os_dma_addr_t dma_ctx; + adf_os_device_t adf_ctx; + + hddLog(LOG1, FL("Read req for size:%zu pos:%llu"), count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hddLog(LOGE, FL("HDD context is not valid")); + return -EINVAL; + } + adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, hdd_ctx->pvosContext); + if (!adf_ctx) { + hddLog(LOGE, FL("ADF context is NULL")); + return -EINVAL; + } + + if (!hdd_ctx->memdump_in_progress) { + hddLog(LOGE, FL("Current mem dump request timed out/failed")); + return -EINVAL; + } + + if (*pos < 0) { + hddLog(LOGE, FL("Invalid start offset for memdump read")); + return -EINVAL; + } else if (*pos >= FW_MEM_DUMP_SIZE || !count) { + hddLog(LOGE, FL("No more data to copy")); + return 0; + } else if (count > FW_MEM_DUMP_SIZE - *pos) { + count = FW_MEM_DUMP_SIZE - *pos; + } + + if (!hdd_ctx->fw_dump_loc) { + hddLog(LOGE, FL("Invalid fw mem dump location")); + return -EINVAL; + } + + if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) { + hddLog(LOGE, FL("copy to user space failed")); + return -EFAULT; + } + + /* offset(pos) should be updated here based on the copy done*/ + *pos += count; + + /* Entire FW memory dump copy completed */ + if (*pos >= FW_MEM_DUMP_SIZE) { + paddr = hdd_ctx->dump_loc_paddr; + mutex_lock(&hdd_ctx->memdump_lock); + adf_os_mem_free_consistent(adf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&hdd_ctx->memdump_cleanup_timer)) { + vos_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + mutex_unlock(&hdd_ctx->memdump_lock); + } + + return count; +} + +/** + * struct memdump_fops - file operations for memory dump feature + * @read - read function for memory dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations memdump_fops = { + read: memdump_read +}; + +/** + * memdump_procfs_init() - Initialize procfs for memory dump + * + * @vos_ctx - Global vos context. + * + * This function create file under proc file system to be used later for + * processing firmware memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int memdump_procfs_init(void *vos_ctx) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + proc_dir = proc_mkdir(PROCFS_MEMDUMP_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_MEMDUMP_NAME, + S_IRUSR | S_IWUSR, proc_dir, + &memdump_fops, hdd_ctx); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_NAME); + return -ENOMEM; + } + + pr_debug("/proc/%s/%s created\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + return 0; +} + +/** + * memdump_procfs_remove() - Remove file/dir under procfs for memory dump + * + * This function removes file/dir under proc file system that was + * processing firmware memory dump + * + * Return: None + */ +static void memdump_procfs_remove(void) +{ + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("/proc/%s/%s removed\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("/proc/%s removed\n", PROCFS_MEMDUMP_DIR); +} + +/** + * memdump_init() - Intialization function for memory dump feature + * + * This function creates proc file for memdump feature and registers + * HDD callback function with SME. + * + * Return - 0 on success, error otherwise + */ +int memdump_init(void) +{ + hdd_context_t *hdd_ctx; + void *vos_ctx; + int status = 0; + eHalStatus cb_status; + VOS_STATUS vos_status; + + vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_ctx) { + hddLog(LOGE, FL("Invalid VOS context")); + return -EINVAL; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if (!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return -EINVAL; + } + + cb_status = sme_fw_mem_dump_register_cb(hdd_ctx->hHal, + wlan_hdd_cfg80211_fw_mem_dump_cb); + if (eHAL_STATUS_SUCCESS != cb_status) { + hddLog(LOGE , FL("Failed to register the callback")); + return -EINVAL; + } + + status = memdump_procfs_init(vos_ctx); + if (status) { + hddLog(LOGE , FL("Failed to create proc file")); + return status; + } + + vos_status = vos_timer_init(&hdd_ctx->memdump_cleanup_timer, + VOS_TIMER_TYPE_SW, memdump_cleanup_timer_cb, + (void *)hdd_ctx); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("Failed to init memdump cleanup timer")); + return -EINVAL; + } + + mutex_init(&hdd_ctx->memdump_lock); + + return 0; +} + +/** + * memdump_deinit() - De initialize memdump feature + * + * This function removes proc file created for memdump feature. + * + * Return: None + */ +void memdump_deinit(void) { + hdd_context_t *hdd_ctx; + void *vos_ctx; + adf_os_dma_addr_t paddr; + adf_os_dma_addr_t dma_ctx; + adf_os_device_t adf_ctx; + VOS_STATUS vos_status; + + vos_ctx = vos_get_global_context(VOS_MODULE_ID_SYS, NULL); + if (!vos_ctx) { + hddLog(LOGE, FL("Invalid VOS context")); + return; + } + + hdd_ctx = vos_get_context(VOS_MODULE_ID_HDD, vos_ctx); + if(!hdd_ctx) { + hddLog(LOGE , FL("Invalid HDD context")); + return; + } + + adf_ctx = vos_get_context(VOS_MODULE_ID_ADF, hdd_ctx->pvosContext); + if (!adf_ctx) { + hddLog(LOGE, FL("ADF context is NULL")); + return; + } + + memdump_procfs_remove(); + sme_fw_mem_dump_unregister_cb(hdd_ctx->hHal); + + mutex_lock(&hdd_ctx->memdump_lock); + if (hdd_ctx->fw_dump_loc) { + paddr = hdd_ctx->dump_loc_paddr; + adf_os_mem_free_consistent(adf_ctx, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + } + mutex_unlock(&hdd_ctx->memdump_lock); + + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&hdd_ctx->memdump_cleanup_timer)) { + vos_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + + vos_status = vos_timer_destroy(&hdd_ctx->memdump_cleanup_timer); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + hddLog(LOGE, FL("Failed to deallocate timer")); + } +} diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h index 8e85808b4c03..bd16fe8bbdad 100644 --- a/CORE/MAC/inc/sirApi.h +++ b/CORE/MAC/inc/sirApi.h @@ -6053,4 +6053,59 @@ struct sir_guard_time_request { /* Max number of rates allowed in Supported Rates IE */ #define MAX_NUM_SUPPORTED_RATES (8) +#define MAX_NUM_FW_SEGMENTS 4 + +/** + * struct fw_dump_seg_req - individual segment details + * @seg_id - segment id. + * @seg_start_addr_lo - lower address of the segment. + * @seg_start_addr_hi - higher address of the segment. + * @seg_length - length of the segment. + * @dst_addr_lo - lower address of the destination buffer. + * @dst_addr_hi - higher address of the destination buffer. + * + * This structure carries the information to firmware about the + * individual segments. This structure is part of firmware memory + * dump request. + */ +struct fw_dump_seg_req +{ + uint8_t seg_id; + uint32_t seg_start_addr_lo; + uint32_t seg_start_addr_hi; + uint32_t seg_length; + uint32_t dst_addr_lo; + uint32_t dst_addr_hi; +}; + +/** + * struct fw_dump_req - firmware memory dump request details. + * @request_id - request id. + * @num_seg - requested number of segments. + * @fw_dump_seg_req - individual segment information. + * + * This structure carries information about the firmware + * memory dump request. + */ +struct fw_dump_req +{ + uint32_t request_id; + uint32_t num_seg; + struct fw_dump_seg_req segment[MAX_NUM_FW_SEGMENTS]; +}; + +/** + * struct fw_dump_rsp - firmware dump response details. + * @request_id - request id. + * @dump_complete - copy completion status. + * + * This structure is used to store the firmware dump copy complete + * response from the firmware. + */ +struct fw_dump_rsp +{ + uint32_t request_id; + uint32_t dump_complete; +}; + #endif /* __SIR_API_H */ diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h index 553711dc386b..89896b527d73 100644 --- a/CORE/MAC/inc/wniApi.h +++ b/CORE/MAC/inc/wniApi.h @@ -392,6 +392,7 @@ enum eWniMsgTypes eWNI_SME_DCC_STATS_EVENT, eWNI_SME_TSF_EVENT, + eWNI_SME_FW_DUMP_IND, eWNI_SME_MSG_TYPES_END }; diff --git a/CORE/MAC/src/include/sirParams.h b/CORE/MAC/src/include/sirParams.h index c44f4a052b76..785968b5fb20 100644 --- a/CORE/MAC/src/include/sirParams.h +++ b/CORE/MAC/src/include/sirParams.h @@ -708,6 +708,8 @@ typedef struct sSirMbMsgP2p #define SIR_HAL_DCC_CLEAR_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 325) #define SIR_HAL_DCC_UPDATE_NDL_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 326) +#define SIR_HAL_FW_MEM_DUMP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 327) + #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) // CFG message types diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c index 581cd7eaf785..22c3b5165dca 100644 --- a/CORE/SERVICES/WMA/wma.c +++ b/CORE/SERVICES/WMA/wma.c @@ -2353,6 +2353,50 @@ static void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, } } +#ifdef WLAN_FEATURE_MEMDUMP +/** + * wma_fw_mem_dump_rsp() - send fw mem dump response to SME + * + * @req_id - request id. + * @status - copy status from the firmware. + * + * This function is called by the memory dump response handler to + * indicate SME that firmware dump copy is complete + */ +static VOS_STATUS wma_fw_mem_dump_rsp(uint32_t req_id, uint32_t status) +{ + struct fw_dump_rsp *dump_rsp; + vos_msg_t sme_msg = {0} ; + VOS_STATUS vos_status = VOS_STATUS_SUCCESS; + + dump_rsp = vos_mem_malloc(sizeof(*dump_rsp)); + + if (!dump_rsp) { + WMA_LOGE(FL("Memory allocation failed.")); + vos_status = VOS_STATUS_E_NOMEM; + return vos_status; + } + + WMA_LOGI(FL("FW memory dump copy complete status: %d for request: %d"), + status, req_id); + + dump_rsp->request_id = req_id; + dump_rsp->dump_complete = status; + + sme_msg.type = eWNI_SME_FW_DUMP_IND; + sme_msg.bodyptr = dump_rsp; + sme_msg.bodyval = 0; + + vos_status = vos_mq_post_message(VOS_MODULE_ID_SME, &sme_msg); + if (!VOS_IS_STATUS_SUCCESS(vos_status)) { + WMA_LOGE(FL("Fail to post fw mem dump ind msg")); + vos_mem_free(dump_rsp); + } + + return vos_status; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + static int wma_link_status_rsp(tp_wma_handle wma, u_int8_t *buf) { wmi_vdev_rate_stats_event_fixed_param *event; @@ -4019,6 +4063,49 @@ static int wma_unified_link_radio_stats_event_handler(void *handle, #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +/** + * wma_fw_mem_dump_event_handler() - handles fw memory dump event + * + * handle - pointer to wma handle. + * cmd_param_info - pointer to TLV info received in the event. + * len - length of data in @cmd_param_info + * + * This function is a handler for firmware memory dump event. + */ +#ifdef WLAN_FEATURE_MEMDUMP +static int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *param_buf; + wmi_update_fw_mem_dump_fixed_param *event; + VOS_STATUS status; + + param_buf = + (WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + + status = wma_fw_mem_dump_rsp(event->request_id, + event->fw_mem_dump_complete); + if (VOS_STATUS_SUCCESS != status) { + return -EINVAL; + } + + WMA_LOGI("FW MEM DUMP RSP posted successfully"); + return 0; +} +#else +static int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + return 0; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + u_int8_t *wma_add_p2p_ie(u_int8_t *frm) { u_int8_t wfa_oui[3] = WMA_P2P_WFA_OUI; @@ -6014,6 +6101,12 @@ VOS_STATUS WDA_open(v_VOID_t *vos_context, v_VOID_t *os_ctx, wma_register_ll_stats_event_handler(wma_handle); #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + /* Register event handler to receive firmware mem dump + * copy complete indication + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_FW_MEM_DUMP_EVENTID, + wma_fw_mem_dump_event_handler); /* Firmware debug log */ vos_status = dbglog_init(wma_handle->wmi_handle); @@ -24464,6 +24557,112 @@ VOS_STATUS wma_config_guard_time(tp_wma_handle wma, return ret; } +#ifdef WLAN_FEATURE_MEMDUMP +/* + * wma_process_fw_mem_dump_req() - Function to request fw memory dump from + * firmware + * @wma: Pointer to WMA handle + * @mem_dump_req: Pointer for mem_dump_req + * + * This function sends memory dump request to firmware + * + * Return: VOS_STATUS_SUCCESS for success otherwise failure + * + */ +static VOS_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + struct fw_dump_req* mem_dump_req) +{ + wmi_get_fw_mem_dump_fixed_param *cmd; + wmi_fw_mem_dump *dump_params; + struct fw_dump_seg_req *seg_req; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret, loop; + + if (!mem_dump_req || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return VOS_STATUS_E_FAILURE; + } + + /* + * len = sizeof(fixed param) that includes tlv header + + * tlv header for array of struc + + * sizeof (each struct) + */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += mem_dump_req->num_seg * sizeof(wmi_fw_mem_dump); + buf = wmi_buf_alloc(wma->wmi_handle, len); + + if (!buf) { + WMA_LOGE(FL("Failed allocate wmi buffer")); + return VOS_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + vos_mem_zero(buf_ptr, len); + cmd = (wmi_get_fw_mem_dump_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_get_fw_mem_dump_fixed_param)); + + cmd->request_id = mem_dump_req->request_id; + cmd->num_fw_mem_dump_segs = mem_dump_req->num_seg; + + /* TLV indicating array of structures to follow */ + buf_ptr += sizeof(wmi_get_fw_mem_dump_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_fw_mem_dump) * + cmd->num_fw_mem_dump_segs); + + buf_ptr += WMI_TLV_HDR_SIZE; + dump_params = (wmi_fw_mem_dump *) buf_ptr; + + WMA_LOGI(FL("request_id:%d num_seg:%d"), + mem_dump_req->request_id, mem_dump_req->num_seg); + for (loop = 0; loop < cmd->num_fw_mem_dump_segs; loop++) { + seg_req = (struct fw_dump_seg_req *) + ((uint8_t *)(mem_dump_req->segment) + + loop * sizeof(*seg_req)); + WMITLV_SET_HDR(&dump_params->tlv_header, + WMITLV_TAG_STRUC_wmi_fw_mem_dump_params, + WMITLV_GET_STRUCT_TLVLEN(wmi_fw_mem_dump)); + dump_params->seg_id = seg_req->seg_id; + dump_params->seg_start_addr_lo = seg_req-> seg_start_addr_lo; + dump_params->seg_start_addr_hi = seg_req->seg_start_addr_hi; + dump_params->seg_length = seg_req->seg_length; + dump_params->dest_addr_lo = seg_req->dst_addr_lo; + dump_params->dest_addr_hi = seg_req->dst_addr_hi; + WMA_LOGI(FL("seg_number:%d"), loop); + WMA_LOGI(FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + dump_params->seg_id, dump_params->seg_start_addr_lo, + dump_params->seg_start_addr_hi); + WMA_LOGI(FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + dump_params->seg_length, dump_params->dest_addr_lo, + dump_params->dest_addr_hi); + dump_params++; + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_GET_FW_MEM_DUMP_CMDID); + if (ret) { + WMA_LOGE(FL("Failed to send get firmware mem dump request")); + wmi_buf_free(buf); + return VOS_STATUS_E_FAILURE; + } + + WMA_LOGI(FL("Get firmware mem dump request sent successfully")); + return VOS_STATUS_SUCCESS; +} +#else +static VOS_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + void *mem_dump_req) +{ + return VOS_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + /* * function : wma_mc_process_msg * Description : @@ -25213,6 +25412,11 @@ VOS_STATUS wma_mc_process_msg(v_VOID_t *vos_context, vos_msg_t *msg) (struct sir_guard_time_request *)msg->bodyptr); vos_mem_free(msg->bodyptr); break; + case WDA_FW_MEM_DUMP_REQ: + wma_process_fw_mem_dump_req(wma_handle, + (struct fw_dump_req*)msg->bodyptr); + vos_mem_free(msg->bodyptr); + break; default: WMA_LOGD("unknow msg type %x", msg->type); /* Do Nothing? MSG Body should be freed at here */ diff --git a/CORE/SME/inc/smeInternal.h b/CORE/SME/inc/smeInternal.h index 9e63ec5e89cb..110bfdd8b91a 100644 --- a/CORE/SME/inc/smeInternal.h +++ b/CORE/SME/inc/smeInternal.h @@ -204,6 +204,9 @@ typedef struct tagSmeStruct ocb_callback dcc_update_ndl_callback; void *dcc_stats_event_context; ocb_callback dcc_stats_event_callback; +#ifdef WLAN_FEATURE_MEMDUMP + void (*fw_dump_callback)(void *context, struct fw_dump_rsp *rsp); +#endif } tSmeStruct, *tpSmeStruct; diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h index 1e887fe6cc67..ae37014faaa0 100644 --- a/CORE/SME/inc/sme_Api.h +++ b/CORE/SME/inc/sme_Api.h @@ -4026,6 +4026,11 @@ eHalStatus sme_SetLinkLayerStatsIndCB #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +eHalStatus sme_fw_mem_dump(tHalHandle hHal, void *recvd_req); +eHalStatus sme_fw_mem_dump_register_cb(tHalHandle hHal, + void (*callback_routine)(void *cb_context, struct fw_dump_rsp *rsp)); +eHalStatus sme_fw_mem_dump_unregister_cb(tHalHandle hHal); + #ifdef WLAN_FEATURE_ROAM_OFFLOAD /*-------------------------------------------------------------------------- \brief sme_UpdateRoamOffloadEnabled() - enable/disable roam offload feature diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c index 87384683d409..199640b03e8b 100644 --- a/CORE/SME/src/sme_common/sme_Api.c +++ b/CORE/SME/src/sme_common/sme_Api.c @@ -2363,6 +2363,31 @@ eHalStatus sme_SetEseBeaconRequest(tHalHandle hHal, const tANI_U8 sessionId, #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */ +/** + * sme_process_fw_mem_dump_rsp - process fw memory dump response from WMA + * + * @pMac - pointer to MAC handle. + * @pMsg - pointer to received SME msg. + * + * This function process the received SME message and calls the corresponding + * callback which was already registered with SME. + */ +#ifdef WLAN_FEATURE_MEMDUMP +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal pMac, vos_msg_t* pMsg) +{ + if (pMsg->bodyptr) { + if (pMac->sme.fw_dump_callback) + pMac->sme.fw_dump_callback(pMac->hHdd, + (struct fw_dump_rsp*) pMsg->bodyptr); + vos_mem_free(pMsg->bodyptr); + } +} +#else +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal pMac, vos_msg_t* pMsg) +{ +} +#endif + /*-------------------------------------------------------------------------- \brief sme_ProcessMsg() - The main message processor for SME. @@ -3016,6 +3041,9 @@ eHalStatus sme_ProcessMsg(tHalHandle hHal, vos_msg_t* pMsg) } vos_mem_free(pMsg->bodyptr); break; + case eWNI_SME_FW_DUMP_IND: + sme_process_fw_mem_dump_rsp(pMac, pMsg); + break; default: if ( ( pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN ) @@ -15327,6 +15355,78 @@ eHalStatus sme_SetLinkLayerStatsIndCB } #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * sme_fw_mem_dump_register_cb() - Register fw memory dump callback + * + * @hHal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: eHalStatus + */ +#ifdef WLAN_FEATURE_MEMDUMP +eHalStatus sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_AcquireGlobalLock(&pmac->sme); + if (eHAL_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = callback_routine; + sme_ReleaseGlobalLock(&pmac->sme); + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("sme_AcquireGlobalLock error")); + } + + return status; +} +#else +eHalStatus sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + return eHAL_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/** + * sme_fw_mem_dump_unregister_cb() - Unregister fw memory dump callback + * + * @hHal - MAC global handle + * + * This API is invoked by HDD to unregister its callback in SME + * + * Return: eHalStatus + */ +#ifdef WLAN_FEATURE_MEMDUMP +eHalStatus sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + eHalStatus status; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_AcquireGlobalLock(&pmac->sme); + if (eHAL_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = NULL; + sme_ReleaseGlobalLock(&pmac->sme); + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("sme_AcquireGlobalLock error")); + } + + return status; +} +#else +eHalStatus sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + return eHAL_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + #ifdef WLAN_FEATURE_ROAM_OFFLOAD /*-------------------------------------------------------------------------- \brief sme_UpdateRoamOffloadEnabled() - enable/disable roam offload feature @@ -15859,7 +15959,80 @@ VOS_STATUS sme_apfind_set_cmd(struct sme_ap_find_request_req *input) return VOS_STATUS_SUCCESS; } #endif /* WLAN_FEATURE_APFIND */ +/** + * sme_fw_mem_dump() - Get FW memory dump + * + * This API is invoked by HDD to indicate FW to start + * dumping firmware memory. + * + * Return: eHalStatus + */ +#ifdef WLAN_FEATURE_MEMDUMP +eHalStatus sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + eHalStatus status = eHAL_STATUS_SUCCESS; + VOS_STATUS vos_status = VOS_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + vos_msg_t msg; + struct fw_dump_req* send_req; + struct fw_dump_seg_req seg_req; + int loop; + + send_req = vos_mem_malloc(sizeof(*send_req)); + if(!send_req) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Memory allocation failed for WDA_FW_MEM_DUMP")); + return eHAL_STATUS_FAILURE; + } + vos_mem_copy(send_req, recvd_req, sizeof(*send_req)); + + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("request_id:%d num_seg:%d"), + send_req->request_id, send_req->num_seg); + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("Segment Information")); + for (loop = 0; loop < send_req->num_seg; loop++) { + seg_req = send_req->segment[loop]; + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("seg_number:%d"), loop); + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + seg_req.seg_id, seg_req.seg_start_addr_lo, + seg_req.seg_start_addr_hi); + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO, + FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + seg_req.seg_length, seg_req.dst_addr_lo, + seg_req.dst_addr_hi); + } + + if (eHAL_STATUS_SUCCESS == sme_AcquireGlobalLock(&pMac->sme)) { + msg.bodyptr = send_req; + msg.type = WDA_FW_MEM_DUMP_REQ; + msg.reserved = 0; + + vos_status = vos_mq_post_message(VOS_MODULE_ID_WDA, &msg); + if (VOS_STATUS_SUCCESS != vos_status) { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Not able to post WDA_FW_MEM_DUMP")); + vos_mem_free(send_req); + status = eHAL_STATUS_FAILURE; + } + sme_ReleaseGlobalLock(&pMac->sme); + } else { + VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, + FL("Failed to acquire SME Global Lock")); + vos_mem_free(send_req); + status = eHAL_STATUS_FAILURE; + } + return status; +} +#else +eHalStatus sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + return eHAL_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH /* * sme_validate_sap_channel_switch() - validate target channel switch w.r.t diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h index 37bedfe4dd85..50e1ac485ef9 100644 --- a/CORE/WDA/inc/wlan_qct_wda.h +++ b/CORE/WDA/inc/wlan_qct_wda.h @@ -1033,6 +1033,8 @@ tSirRetStatus uMacPostCtrlMsg(void* pSirGlobal, tSirMbMsg* pMb); #define WDA_UPDATE_Q2Q_IE_IND SIR_HAL_UPDATE_Q2Q_IE_IND #endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define WDA_FW_MEM_DUMP_REQ SIR_HAL_FW_MEM_DUMP_REQ + tSirRetStatus wdaPostCtrlMsg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); #define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 // Bit 6 will be used to control BD rate for Management frames diff --git a/Kbuild b/Kbuild index 9d897fa04de4..c06a2db1908a 100644 --- a/Kbuild +++ b/Kbuild @@ -97,6 +97,8 @@ ifeq ($(KERNEL_BUILD), 0) ifeq ($(CONFIG_ROME_IF),usb) CONFIG_LINUX_QCMBR :=y endif + #Flag to enable memdump feature + CONFIG_FEATURE_MEMDUMP := y endif ifdef CPTCFG_QCA_CLD_WLAN @@ -385,6 +387,10 @@ ifeq ($(CONFIG_WLAN_SYNC_TSF),y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tsf.o endif +ifeq ($(CONFIG_FEATURE_MEMDUMP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_memdump.o +endif + ############ EPPING ############ EPPING_DIR := CORE/EPPING EPPING_INC_DIR := $(EPPING_DIR)/inc @@ -1371,6 +1377,10 @@ ifeq ($(CONFIG_STATICALLY_ADD_11P_CHANNELS),y) CDEFINES += -DFEATURE_STATICALLY_ADD_11P_CHANNELS endif +ifeq ($(CONFIG_FEATURE_MEMDUMP),y) +CDEFINES += -DWLAN_FEATURE_MEMDUMP +endif + KBUILD_CPPFLAGS += $(CDEFINES) # Currently, for versions of gcc which support it, the kernel Makefile diff --git a/Kconfig b/Kconfig index 31a48a0c90cc..d917ada85892 100644 --- a/Kconfig +++ b/Kconfig @@ -49,4 +49,8 @@ config CONFIG_WLAN_SYNC_TSF bool "Enable QCOM sync multi devices tsf feature" default n +config CONFIG_FEATURE_MEMDUMP + bool "Enable MEMDUMP feature" + default n + endif # QCA_CLD_WLAN -- cgit v1.2.3 From 3c7365651b1cc2df334d2adbf167f3dcf69bd867 Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Wed, 22 Apr 2015 15:59:10 +0800 Subject: qcacld: Add parameter for iwpriv command In order to set GPIO number when set LED GPIO parameters, add parameter "gpio_num" for iwpriv command "gpio_control". CRs-Fixed: 826952 Change-Id: I2a30f4c22d5f463a4efa7dec225675e3d92b5b0d --- CORE/HDD/src/wlan_hdd_wext.c | 8 ++++---- CORE/MAC/inc/sirApi.h | 1 + CORE/SERVICES/WMA/wma.c | 1 + CORE/SME/inc/sme_Api.h | 3 ++- CORE/SME/src/sme_common/sme_Api.c | 4 +++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c index 54009f03545c..741e70a2c529 100644 --- a/CORE/HDD/src/wlan_hdd_wext.c +++ b/CORE/HDD/src/wlan_hdd_wext.c @@ -7679,9 +7679,9 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, case WE_LED_FLASHING_PARAM: { int i; - if (num_args != 4) { + if (num_args != 5) { hddLog(LOGE, - FL("gpio_control: 4 parameters are required")); + FL("gpio_control: 5 parameters are required")); return -EINVAL; } @@ -7693,9 +7693,9 @@ static int __iw_set_var_ints_getnone(struct net_device *dev, } } sme_SetLedFlashing(WLAN_HDD_GET_HAL_CTX(pAdapter), - 0, apps_args[0], apps_args[1]); + 0, apps_args[0], apps_args[1], apps_args[4]); sme_SetLedFlashing(WLAN_HDD_GET_HAL_CTX(pAdapter), - 1, apps_args[2], apps_args[3]); + 1, apps_args[2], apps_args[3], apps_args[4]); } break; #endif diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h index bd16fe8bbdad..11daad2e2bdd 100644 --- a/CORE/MAC/inc/sirApi.h +++ b/CORE/MAC/inc/sirApi.h @@ -5740,6 +5740,7 @@ typedef struct tANI_U32 pattern_id; /* pattern identifier. 0: disconnected 1: connected*/ tANI_U32 led_x0; /* led flashing parameter0 */ tANI_U32 led_x1; /* led flashing parameter1 */ + tANI_U32 gpio_num; /* GPIO number */ } tSirLedFlashingReq, *tpSirLedFlashingReq; #endif diff --git a/CORE/SERVICES/WMA/wma.c b/CORE/SERVICES/WMA/wma.c index 22c3b5165dca..6be4593bc86c 100644 --- a/CORE/SERVICES/WMA/wma.c +++ b/CORE/SERVICES/WMA/wma.c @@ -24106,6 +24106,7 @@ VOS_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, cmd->pattern_id = flashing->pattern_id; cmd->led_x0 = flashing->led_x0; cmd->led_x1 = flashing->led_x1; + cmd->gpio_num = flashing->gpio_num; status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, WMI_PDEV_SET_LED_FLASHING_CMDID); diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h index ae37014faaa0..5370b1a979c6 100644 --- a/CORE/SME/inc/sme_Api.h +++ b/CORE/SME/inc/sme_Api.h @@ -4145,10 +4145,11 @@ eHalStatus sme_setDhcpSrvOffload(tHalHandle hHal, \brief API to set the LED flashing feature. \param hHal - The handle returned by macOpen. \param x0, x1 - led flashing parameters + \param gpio_num - GPIO number \return eHalStatus ---------------------------------------------------------------------------*/ eHalStatus sme_SetLedFlashing (tHalHandle hHal, tANI_U8 type, - tANI_U32 x0, tANI_U32 x1); + tANI_U32 x0, tANI_U32 x1, tANI_U32 gpio_num); #endif /* --------------------------------------------------------------------------- \fn sme_handle_dfS_chan_scan diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c index 199640b03e8b..61c511f88510 100644 --- a/CORE/SME/src/sme_common/sme_Api.c +++ b/CORE/SME/src/sme_common/sme_Api.c @@ -15634,10 +15634,11 @@ eHalStatus sme_setDhcpSrvOffload(tHalHandle hHal, \brief API to set the Led flashing parameters. \param hHal - The handle returned by macOpen. \param x0, x1 - led flashing parameters + \param gpio_num - GPIO number \return eHalStatus ---------------------------------------------------------------------------*/ eHalStatus sme_SetLedFlashing (tHalHandle hHal, tANI_U8 type, - tANI_U32 x0, tANI_U32 x1) + tANI_U32 x0, tANI_U32 x1, tANI_U32 gpio_num) { eHalStatus status = eHAL_STATUS_SUCCESS; VOS_STATUS vosStatus = VOS_STATUS_SUCCESS; @@ -15655,6 +15656,7 @@ eHalStatus sme_SetLedFlashing (tHalHandle hHal, tANI_U8 type, ledflashing->pattern_id = type; ledflashing->led_x0 = x0; ledflashing->led_x1 = x1; + ledflashing->gpio_num = gpio_num; if (eHAL_STATUS_SUCCESS == (status = sme_AcquireGlobalLock(&pMac->sme))) { /* Serialize the req through MC thread */ -- cgit v1.2.3 From 8f58fb74fedbf135dc87c114d28808d5919c41b7 Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Wed, 8 Apr 2015 20:30:06 -0700 Subject: QCACLD: Kconfig: Correct NAN feature config Kconfig has wrong config flag for NAN feature, correct it. Also rename the NAN config to be in line with other configs and remove couple of varilables which are not used in Kbuild. Change-Id: I798b581b2fef9ad57b4e99b15795129df79759ef CRs-fixed: 827374 --- Kbuild | 8 +++----- Kconfig | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Kbuild b/Kbuild index c06a2db1908a..610692f14f48 100644 --- a/Kbuild +++ b/Kbuild @@ -25,8 +25,6 @@ ifeq ($(KERNEL_BUILD),1) MODNAME := wlan WLAN_ROOT := drivers/staging/qcacld-2.0 WLAN_OPEN_SOURCE := 1 - CONFIG_QCA_WIFI_2_0 := 1 - CONFIG_QCA_WIFI_ISOC := 0 endif ifeq ($(KERNEL_BUILD), 0) @@ -90,7 +88,7 @@ ifeq ($(KERNEL_BUILD), 0) ifneq ($(CONFIG_MOBILE_ROUTER), y) #Flag to enable NAN - CONFIG_FEATURE_NAN := y + CONFIG_WLAN_FEATURE_NAN := y endif #Flag to enable Linux QCMBR feature as default feature @@ -573,7 +571,7 @@ SME_P2P_OBJS = $(SME_SRC_DIR)/p2p/p2p_Api.o SME_RRM_OBJS := $(SME_SRC_DIR)/rrm/sme_rrm.o -ifeq ($(CONFIG_FEATURE_NAN),y) +ifeq ($(CONFIG_WLAN_FEATURE_NAN),y) SME_NAN_OBJS = $(SME_SRC_DIR)/nan/nan_Api.o endif @@ -1098,7 +1096,7 @@ ifeq ($(CONFIG_FEATURE_STATS_EXT), 1) CDEFINES += -DWLAN_FEATURE_STATS_EXT endif -ifeq ($(CONFIG_FEATURE_NAN),y) +ifeq ($(CONFIG_WLAN_FEATURE_NAN),y) CDEFINES += -DWLAN_FEATURE_NAN endif diff --git a/Kconfig b/Kconfig index d917ada85892..ad8eca198a49 100644 --- a/Kconfig +++ b/Kconfig @@ -33,7 +33,7 @@ config QCOM_VOWIFI_11R bool "Enable Fast Transition (11r) feature" default n -config CONFIG_FEATURE_NAN +config WLAN_FEATURE_NAN bool "Enable NAN feature" default n -- cgit v1.2.3 From 10db26b07f61afbbb5b71e97e7d88a55cca7c430 Mon Sep 17 00:00:00 2001 From: Prashanth Bhatta Date: Wed, 22 Apr 2015 16:01:24 -0700 Subject: qcacld: hdd: Stop bus BW compute timer during SSR Some times while SSR is in progress, bus bandwidth compute timer can fire and request for IPA UC stats. Because SSR is going on or just completed, NULL pointer dereference was noticed in HTC layer while trying to send the command down to firmware. Fix the issue by stopping the bus BW compute timer during shutting down and also have a HDD context validation in the timer handler. Change-Id: I7ce7bd9315ae07b7248a3adb7d1a67960c194633 CRs-fixed: 827317 --- CORE/HDD/src/wlan_hdd_early_suspend.c | 8 ++++++++ CORE/HDD/src/wlan_hdd_main.c | 15 ++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CORE/HDD/src/wlan_hdd_early_suspend.c b/CORE/HDD/src/wlan_hdd_early_suspend.c index 10d9dd6f9f65..d9f605bcbb4f 100644 --- a/CORE/HDD/src/wlan_hdd_early_suspend.c +++ b/CORE/HDD/src/wlan_hdd_early_suspend.c @@ -1794,6 +1794,14 @@ VOS_STATUS hdd_wlan_shutdown(void) vos_clear_concurrent_session_count(); +#ifdef MSM_PLATFORM + if (VOS_TIMER_STATE_RUNNING == + vos_timer_getCurrentState(&pHddCtx->bus_bw_timer)) + { + vos_timer_stop(&pHddCtx->bus_bw_timer); + } +#endif + hdd_stop_auto_suspend_attempt(pHddCtx); hdd_reset_all_adapters(pHddCtx); diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index c4e50fa14e45..8dd3bc3e7d25 100755 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -11116,6 +11116,9 @@ static void hdd_bus_bw_compute_cbk(void *priv) hdd_adapter_t *pValidAdapter = NULL; #endif /* IPA_UC_OFFLOAD */ + if (wlan_hdd_validate_context(pHddCtx)) + return; + for (status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); NULL != pAdapterNode && VOS_STATUS_SUCCESS == status; status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pAdapterNode)) @@ -11154,17 +11157,19 @@ static void hdd_bus_bw_compute_cbk(void *priv) spin_unlock_bh(&pHddCtx->bus_bw_lock); connected = TRUE; } -#ifdef IPA_UC_OFFLOAD - hdd_ipa_uc_stat_query(pHddCtx, &ipa_tx_packets, &ipa_rx_packets); - tx_packets += (uint64_t)ipa_tx_packets; - rx_packets += (uint64_t)ipa_rx_packets; -#endif /* IPA_UC_OFFLOAD */ + if (!connected) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "bus bandwidth timer running in disconnected state"); return; } +#ifdef IPA_UC_OFFLOAD + hdd_ipa_uc_stat_query(pHddCtx, &ipa_tx_packets, &ipa_rx_packets); + tx_packets += (uint64_t)ipa_tx_packets; + rx_packets += (uint64_t)ipa_rx_packets; +#endif /* IPA_UC_OFFLOAD */ + hdd_cnss_request_bus_bandwidth(pHddCtx, tx_packets, rx_packets); #ifdef IPA_OFFLOAD -- cgit v1.2.3 From f6c964363c4ccda83160a63aaf320b36d792013c Mon Sep 17 00:00:00 2001 From: AnjaneeDevi Kapparapu Date: Fri, 24 Apr 2015 16:08:48 +0530 Subject: Cafstaging Release 4.0.10.84 Cafstaging Release 4.0.10.84 Change-Id: I209b7b8878de924ab9025728764b8a67bb51b905 CRs-Fixed: 688141 --- CORE/MAC/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CORE/MAC/inc/qwlan_version.h b/CORE/MAC/inc/qwlan_version.h index 782d6bc13054..53ff774adc01 100644 --- a/CORE/MAC/inc/qwlan_version.h +++ b/CORE/MAC/inc/qwlan_version.h @@ -42,9 +42,9 @@ BRIEF DESCRIPTION: #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 10 #define QWLAN_VERSION_EXTRA "" -#define QWLAN_VERSION_BUILD 83 +#define QWLAN_VERSION_BUILD 84 -#define QWLAN_VERSIONSTR "4.0.10.83" +#define QWLAN_VERSIONSTR "4.0.10.84" #define AR6320_REV1_VERSION 0x5000000 -- cgit v1.2.3