diff options
| author | Ryan Hsu <ryanhsu@qca.qualcomm.com> | 2016-03-24 16:43:30 -0700 |
|---|---|---|
| committer | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-04-22 10:23:11 +0530 |
| commit | 6e6deb97a9a0bd2a39c5fd1bf97fef72206ce4e7 (patch) | |
| tree | 94b78c0eed7f677595906091e9b889deac75c969 | |
| parent | 36cd27ee15883dca8886f1b5d2fe318be973ed45 (diff) | |
qcacld-2.0: Add support for cnss logger module
CONFIG_CNSS_LOGGER is introduced to move the logging feature from
CLD driver to kernel module.
This change will mainly benefit for two things for CLD driver.
- To support for dual wifi driver instances and also
future plan of moving out the logging thread and buffer
management to the kernel module.
- While debugging the critical feature that triggers the
autoshutdown and SSR, the log buffer in the CLD driver will
be lost after the driver restart or unload.
The CLD driver will register itself to the cnss logging module and
get the radio index as the indentification for rest of the operation.
Also the message sent from CLD driver to usespace need to be packed with
struct tAniNlHdr; and the hddctx.radio_index need to be filled along with
the message, so that usespace can differentiate the message.
Change-Id: I7ea6cdefac0916b9d4dd76da175607bf7169a8fa
CRs-fixed: 995073
| -rw-r--r-- | CORE/HDD/inc/wlan_hdd_main.h | 42 | ||||
| -rw-r--r-- | CORE/HDD/src/wlan_hdd_main.c | 7 | ||||
| -rw-r--r-- | CORE/SVC/inc/wlan_nlink_srv.h | 15 | ||||
| -rw-r--r-- | CORE/SVC/src/logging/wlan_logging_sock_svc.c | 24 | ||||
| -rw-r--r-- | CORE/SVC/src/nlink/wlan_nlink_srv.c | 215 | ||||
| -rw-r--r-- | CORE/UTILS/FWLOG/dbglog_host.c | 47 | ||||
| -rw-r--r-- | CORE/VOSS/inc/vos_api.h | 2 | ||||
| -rw-r--r-- | CORE/VOSS/src/vos_api.c | 27 |
8 files changed, 343 insertions, 36 deletions
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h index 587da017ae14..069588c9b598 100644 --- a/CORE/HDD/inc/wlan_hdd_main.h +++ b/CORE/HDD/inc/wlan_hdd_main.h @@ -1762,6 +1762,9 @@ struct hdd_context_s * at runtime and intersecting it with target capab before updating. */ uint32_t fine_time_meas_cap_target; + + int radio_index; + #ifdef WLAN_FEATURE_NAN_DATAPATH bool nan_datapath_enabled; #endif @@ -2089,4 +2092,43 @@ int hdd_enable_disable_ca_event(hdd_context_t *hddctx, void wlan_hdd_undo_acs(hdd_adapter_t *adapter); void hdd_decide_dynamic_chain_mask(hdd_context_t *hdd_ctx, enum antenna_mode forced); +#ifdef CONFIG_CNSS_LOGGER +/** + * wlan_hdd_nl_init() - wrapper function to CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * The nl_srv_init() will call to cnss_logger_device_register() and + * expect to get a radio_index from cnss_logger module and assign to + * hdd_ctx->radio_index, then to maintain the consistency to original + * design, adding the radio_index check here, then return the error + * code if radio_index is not assigned correctly, which means the nl_init + * from cnss_logger is failed. + * + * Return: 0 if successfully, otherwise error code + */ +static inline int wlan_hdd_nl_init(hdd_context_t *hdd_ctx) +{ + hdd_ctx->radio_index = nl_srv_init(hdd_ctx->wiphy); + + /* radio_index is assigned from 0, so only >=0 will be valid index */ + if (hdd_ctx->radio_index >= 0) + return 0; + else + return -EINVAL; +} +#else +/** + * wlan_hdd_nl_init() - wrapper function to non CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * In case of non CNSS_LOGGER case, the nl_srv_init() will initialize + * the netlink socket and return the success or not. + * + * Return: the return value from nl_srv_init() + */ +static inline int wlan_hdd_nl_init(hdd_context_t *hdd_ctx) +{ + return nl_srv_init(hdd_ctx->wiphy); +} +#endif #endif // end #if !defined( WLAN_HDD_MAIN_H ) diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index 550262f0bad2..6da01e808e0d 100644 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -14903,10 +14903,9 @@ int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc) reg_netdev_notifier_done = TRUE; #endif - //Initialize the nlink service - if(nl_srv_init() != 0) - { - hddLog(VOS_TRACE_LEVEL_FATAL,"%s: nl_srv_init failed", __func__); + /* Initialize the nlink service */ + if (wlan_hdd_nl_init(pHddCtx) != 0) { + hddLog(LOGP, FL("nl_srv_init failed")); goto err_reg_netdev; } diff --git a/CORE/SVC/inc/wlan_nlink_srv.h b/CORE/SVC/inc/wlan_nlink_srv.h index df7214421be8..cd49ee0d0662 100644 --- a/CORE/SVC/inc/wlan_nlink_srv.h +++ b/CORE/SVC/inc/wlan_nlink_srv.h @@ -56,18 +56,21 @@ typedef int (* nl_srv_msg_callback)(struct sk_buff * skb); * and the diagnotics netlink socket will not be available since this * diagnostics netlink socket can only be exposed by one instance of the driver. */ -#ifndef MULTI_IF_NAME -int nl_srv_init(void); +#if defined(CONFIG_CNSS_LOGGER) || !defined(MULTI_IF_NAME) + +int nl_srv_init(void *wiphy); void nl_srv_exit(void); -int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler); -int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler); +int nl_srv_register(tWlanNlModTypes msg_type, + nl_srv_msg_callback msg_handler); +int nl_srv_unregister(tWlanNlModTypes msg_type, + nl_srv_msg_callback msg_handler); int nl_srv_ucast(struct sk_buff * skb, int dst_pid, int flag); int nl_srv_bcast(struct sk_buff * skb); int nl_srv_is_initialized(void); #else -static inline int nl_srv_init(void) { return 0; } +static inline int nl_srv_init(void *wiphy) { return 0; } static inline void nl_srv_exit(void) {} static inline int nl_srv_register(tWlanNlModTypes msg_type, @@ -99,5 +102,5 @@ static inline int nl_srv_is_initialized() return -EPERM; } -#endif /* MULTI_IF_NAME */ +#endif /* defined(CONFIG_CNSS_LOGGER) || !defined(MULTI_IF_NAME) */ #endif diff --git a/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/CORE/SVC/src/logging/wlan_logging_sock_svc.c index 2d91826ff799..08ef067eef73 100644 --- a/CORE/SVC/src/logging/wlan_logging_sock_svc.c +++ b/CORE/SVC/src/logging/wlan_logging_sock_svc.c @@ -347,9 +347,12 @@ int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length) struct timeval tv; struct rtc_time tm; unsigned long local_time; + int radio; + + radio = vos_get_radio_index(); - if ((!vos_is_multicast_logging()) || - (!gwlan_logging.is_active)) { + if ((!vos_is_multicast_logging()) || (!gwlan_logging.is_active) || + (radio == -EINVAL)) { /* * This is to make sure that we print the logs to kmsg console * when no logger app is running. This is also needed to @@ -358,18 +361,25 @@ int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length) * register with driver immediately and start logging all the * messages. */ - pr_info("%s\n", to_be_sent); + /* + * R%d: if the radio index is invalid, just post the message + * to console. + * Also the radio index shouldn't happen to be EINVAL, but if + * that happen just print it, so that the logging would be + * aware the cnss_logger is somehow failed. + */ + pr_info("R%d: %s\n", radio, to_be_sent); } else { - /* Format the Log time [hr:min:sec.microsec] */ + /* Format the Log time R#: [hr:min:sec.microsec] */ do_gettimeofday(&tv); /* Convert rtc to local time */ local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); rtc_time_to_tm(local_time, &tm); tlen = snprintf(tbuf, sizeof(tbuf), - "[%s][%02d:%02d:%02d.%06lu] ", - current->comm, tm.tm_hour, tm.tm_min, tm.tm_sec, - tv.tv_usec); + "R%d: [%s][%02d:%02d:%02d.%06lu] ", + radio, current->comm, tm.tm_hour, + tm.tm_min, tm.tm_sec, tv.tv_usec); /* 1+1 indicate '\n'+'\0' */ total_log_len = length + tlen + 1 + 1; diff --git a/CORE/SVC/src/nlink/wlan_nlink_srv.c b/CORE/SVC/src/nlink/wlan_nlink_srv.c index 275e70715d1b..61d5e096e1c5 100644 --- a/CORE/SVC/src/nlink/wlan_nlink_srv.c +++ b/CORE/SVC/src/nlink/wlan_nlink_srv.c @@ -32,15 +32,6 @@ * ******************************************************************************/ -/* - * If MULTI_IF_NAME is not defined, then this is the primary instance of the - * driver and the diagnostics netlink socket will be available. If - * MULTI_IF_NAME is defined then this is not the primary instance of the driver - * and the diagnotics netlink socket will not be available since this - * diagnostics netlink socket can only be exposed by one instance of the driver. - */ -#ifndef MULTI_IF_NAME - #include <linux/version.h> #include <linux/kernel.h> #include <linux/module.h> @@ -52,6 +43,208 @@ #include <wlan_nlink_srv.h> #include <vos_trace.h> +#if defined(CONFIG_CNSS_LOGGER) + +#include <net/cnss_logger.h> + +static int radio_idx = -EINVAL; +static void *wiphy_ptr; +static bool logger_initialized; + +/** + * nl_srv_init() - wrapper function to register to cnss_logger + * @wiphy: the pointer to the wiphy structure + * + * The netlink socket is no longer initialized in the driver itself, instead + * will be initialized in the cnss_logger module, the driver should register + * itself to cnss_logger module to get the radio_index for all the netlink + * operation. (cfg80211 vendor command is using different netlink socket). + * + * The cnss_logger_device_register() use to register the driver with the + * wiphy structure and the module name (debug purpose) and then return the + * radio_index depending on the availibility. + * + * Return: radio index for success and -EINVAL for failure + */ +int nl_srv_init(void *wiphy) +{ + if (logger_initialized) + goto initialized; + + wiphy_ptr = wiphy; + radio_idx = cnss_logger_device_register(wiphy, THIS_MODULE->name); + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "%s: radio_index: %d, wiphy_ptr: %p", + __func__, radio_idx, wiphy_ptr); + + if (radio_idx >= 0) + logger_initialized = true; + +initialized: + return radio_idx; +} + +/** + * nl_srv_exit() - wrapper function to unregister from cnss_logger + * + * The cnss_logger_device_unregister() use to unregister the driver with + * the radio_index assigned and wiphy structure from cnss_logger. + * + * Return: None + */ +void nl_srv_exit(void) +{ + if (logger_initialized) { + cnss_logger_device_unregister(radio_idx, wiphy_ptr); + radio_idx = -EINVAL; + wiphy_ptr = NULL; + logger_initialized = false; + } +} + +/** + * nl_srv_ucast() - wrapper function to do unicast tx through cnss_logger + * @skb: the socket buffer to send + * @dst_pid: the port id + * @flag: the blocking or nonblocking flag + * + * The nl_srv_is_initialized() is used to do sanity check if the netlink + * service is ready, e.g if the radio_index is assigned properly, if not + * the driver should take the responsibility to free the skb. + * + * The cnss_logger_nl_ucast() use the same parameters to send the socket + * buffers. + * + * Return: the error of the transmission status + */ +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) +{ + int err = -EINVAL; + + /* sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; +#else + NETLINK_CB(skb).portid = 0; +#endif + /* not multicast */ + NETLINK_CB(skb).dst_group = 0; + + if (nl_srv_is_initialized() == 0) + err = cnss_logger_nl_ucast(skb, dst_pid, flag); + else + dev_kfree_skb(skb); + return err; +} + +/** + * nl_srv_bcast() - wrapper function to do broadcast tx through cnss_logger + * @skb: the socket buffer to send + * + * The cnss_logger_nl_bcast() is used to transmit the socket buffer. + * + * Return: status of transmission + */ +int nl_srv_bcast(struct sk_buff *skb) +{ + int err = -EINVAL; + int flags = GFP_KERNEL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + /* sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; +#else + NETLINK_CB(skb).portid = 0; +#endif + /* destination group */ + NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; + + if (nl_srv_is_initialized() == 0) + err = cnss_logger_nl_bcast(skb, WLAN_NLINK_MCAST_GRP_ID, flags); + else + dev_kfree_skb(skb); + return err; +} + +/** + * nl_srv_unregister() - wrapper function to unregister event to cnss_logger + * @msg_type: the message to unregister + * @msg_handler: the message handler + * + * The cnss_logger_event_unregister() is used to unregister the message and + * message handler. + * + * Return: 0 if successfully unregister, otherwise proper error code + */ +int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int ret = -EINVAL; + + if (nl_srv_is_initialized() != 0) + return ret; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + ret = cnss_logger_event_unregister(radio_idx, msg_type, + msg_handler); + } else { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "NLINK: nl_srv_unregister failed for msg_type %d", + msg_type); + ret = -EINVAL; + } + + return ret; +} + +/** + * nl_srv_register() - wrapper function to register event to cnss_logger + * @msg_type: the message to register + * @msg_handler: the message handler + * + * The cnss_logger_event_register() is used to register the message and + * message handler. + * + * Return: 0 if successfully register, otherwise proper error code + */ +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int ret = -EINVAL; + + if (nl_srv_is_initialized() != 0) + return ret; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + ret = cnss_logger_event_register(radio_idx, msg_type, + msg_handler); + } else { + VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, + "NLINK: nl_srv_register failed for msg_type %d", + msg_type); + ret = -EINVAL; + } + + return ret; +} + +/** + * nl_srv_is_initialized() - check if netlink service is initialized + * + * Return: 0 if it is initialized, otherwise error code + */ +inline int nl_srv_is_initialized(void) +{ + if (logger_initialized) + return 0; + else + return -EPERM; +} + +#elif !defined(MULTI_IF_NAME) /* Global variables */ static DEFINE_MUTEX(nl_srv_sem); static struct sock *nl_srv_sock; @@ -66,7 +259,7 @@ static void nl_srv_rcv_msg (struct sk_buff *skb, struct nlmsghdr *nlh); * Initialize the netlink service. * Netlink service is usable after this. */ -int nl_srv_init(void) +int nl_srv_init(void *wiphy) { int retcode = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)) @@ -217,7 +410,7 @@ int nl_srv_bcast(struct sk_buff *skb) * all the netlink messages in that skb, before moving * to the next skb. */ -static void nl_srv_rcv (struct sk_buff *sk) +static void nl_srv_rcv(struct sk_buff *sk) { mutex_lock(&nl_srv_sem); nl_srv_rcv_skb(sk); diff --git a/CORE/UTILS/FWLOG/dbglog_host.c b/CORE/UTILS/FWLOG/dbglog_host.c index ff73b3ca040c..e1b8fe10e833 100644 --- a/CORE/UTILS/FWLOG/dbglog_host.c +++ b/CORE/UTILS/FWLOG/dbglog_host.c @@ -1645,6 +1645,8 @@ send_fw_diag_nl_data(const u_int8_t *buffer, struct sk_buff *skb_out; struct nlmsghdr *nlh; int res = 0; + tAniNlHdr *wnl; + int radio; if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) return -ENODEV; @@ -1652,6 +1654,10 @@ send_fw_diag_nl_data(const u_int8_t *buffer, if (nl_srv_is_initialized() != 0) return -EIO; + radio = vos_get_radio_index(); + if (radio == -EINVAL) + return -EIO; + if (vos_is_multicast_logging()) { skb_out = nlmsg_new(len, 0); @@ -1661,7 +1667,11 @@ send_fw_diag_nl_data(const u_int8_t *buffer, return -1; } nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, len, 0); - memcpy(nlmsg_data(nlh), buffer, len); + wnl = (tAniNlHdr *)nlh; + wnl->radio = radio; + + /* data buffer should offset after the nlmsg_hdr + sizeof(int) radio */ + memcpy(nlmsg_data(nlh) + sizeof(radio), buffer, len); res = nl_srv_bcast(skb_out); if (res < 0) @@ -1675,20 +1685,25 @@ send_fw_diag_nl_data(const u_int8_t *buffer, } static int -send_diag_netlink_data(const u_int8_t *buffer, - A_UINT32 len, A_UINT32 cmd) +send_diag_netlink_data(const u_int8_t *buffer, A_UINT32 len, A_UINT32 cmd) { struct sk_buff *skb_out; struct nlmsghdr *nlh; int res = 0; struct dbglog_slot *slot; size_t slot_len; + tAniNlHdr *wnl; + int radio; if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) return -ENODEV; if (nl_srv_is_initialized() != 0) - return -EIO; + return -EIO; + + radio = vos_get_radio_index(); + if (radio == -EINVAL) + return -EIO; if (vos_is_multicast_logging()) { slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; @@ -1701,7 +1716,12 @@ send_diag_netlink_data(const u_int8_t *buffer, } nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, slot_len, 0); - slot = (struct dbglog_slot *) nlmsg_data(nlh); + wnl = (tAniNlHdr *)nlh; + + wnl->radio = radio; + + /* data buffer should offset after the nlmsg_hdr + sizeof(int) radio */ + slot = (struct dbglog_slot *) (nlmsg_data(nlh) + sizeof(radio)); slot->diag_type = cmd; slot->timestamp = cpu_to_le32(jiffies); slot->length = cpu_to_le32(len); @@ -1722,19 +1742,25 @@ send_diag_netlink_data(const u_int8_t *buffer, int dbglog_process_netlink_data(wmi_unified_t wmi_handle, const u_int8_t *buffer, - A_UINT32 len, A_UINT32 dropped) + A_UINT32 len, A_UINT32 dropped) { struct sk_buff *skb_out; struct nlmsghdr *nlh; int res = 0; struct dbglog_slot *slot; size_t slot_len; + tAniNlHdr *wnl; + int radio; if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) return -ENODEV; if (nl_srv_is_initialized() != 0) - return -EIO; + return -EIO; + + radio = vos_get_radio_index(); + if (radio == -EINVAL) + return -EIO; if (vos_is_multicast_logging()) { @@ -1748,7 +1774,12 @@ dbglog_process_netlink_data(wmi_unified_t wmi_handle, const u_int8_t *buffer, } nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, slot_len, 0); - slot = (struct dbglog_slot *) nlmsg_data(nlh); + wnl = (tAniNlHdr *)nlh; + + wnl->radio = radio; + + /* data buffer should offset after the nlmsg_hdr + sizeof(int) radio */ + slot = (struct dbglog_slot *) (nlmsg_data(nlh) + sizeof(radio)); slot->diag_type = (A_UINT32)DIAG_TYPE_FW_DEBUG_MSG; slot->timestamp = cpu_to_le32(jiffies); slot->length = cpu_to_le32(len); diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h index dce0a458e29b..89ba9da1eb89 100644 --- a/CORE/VOSS/inc/vos_api.h +++ b/CORE/VOSS/inc/vos_api.h @@ -374,4 +374,6 @@ void vos_logging_set_fw_flush_complete(void); void vos_probe_threads(void); void vos_set_fatal_event(bool value); void vos_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); +int vos_get_radio_index(void); + #endif // if !defined __VOS_API_H diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c index 398bb69d0828..620368fe11a6 100644 --- a/CORE/VOSS/src/vos_api.c +++ b/CORE/VOSS/src/vos_api.c @@ -2964,3 +2964,30 @@ inline void vos_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, wlan_pkt_stats_to_logger_thread(pl_hdr, pkt_dump, data); } + +/** + * + * vos_get_radio_index() - get radio index + * + * Return: radio index otherwise, -EINVAL + */ +int vos_get_radio_index(void) +{ + hdd_context_t *hdd_ctx = NULL; + + if (gpVosContext == NULL) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, + FL("global voss context is NULL")); + return -EINVAL; + } + hdd_ctx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, + gpVosContext); + + if (!hdd_ctx) { + VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, + FL("HDD context is Null")); + return -EINVAL; + } + return hdd_ctx->radio_index; +} + |
