diff options
| author | Sachin Ahuja <sahuja@qti.qualcomm.com> | 2016-01-20 19:09:29 +0530 |
|---|---|---|
| committer | Anjaneedevi Kapparapu <akappa@codeaurora.org> | 2016-01-28 13:44:03 +0530 |
| commit | b2487f65f9b080a2109785e83e2d832edbaccc77 (patch) | |
| tree | c2a303e29fa6da3e62680b5f64524e3679db50ac | |
| parent | c640a069aa710f1bb0e671296fbb236a3f86e107 (diff) | |
qcacld-2.0: Add infrastructure for pktstats based on linkedlist
Currently pktstats are stored in static allocated memory. This
pkt stats can be accessed using
1) procEntry function
2) hal_proxy_daemon
If user access it using procEntry then read pointer is moved ahead
in static memory array because of which incomplete data goes when
queried using hal_proxy_daemon.
Fix this by maintaining the pktstats in link list. When the
request comes from hal_proxy_daemon, complete data is sent
to it from this link list.
Change-Id: I09bbd03fe378b296e110ce52cc8cbeb8cf8d723d
CRs-Fixed: 958544
| -rw-r--r-- | CORE/SVC/inc/wlan_logging_sock_svc.h | 5 | ||||
| -rw-r--r-- | CORE/SVC/src/logging/wlan_logging_sock_svc.c | 388 | ||||
| -rw-r--r-- | CORE/UTILS/PKTLOG/include/pktlog_ac.h | 3 | ||||
| -rw-r--r-- | CORE/UTILS/PKTLOG/linux_ac.c | 135 | ||||
| -rw-r--r-- | CORE/UTILS/PKTLOG/pktlog_internal.c | 27 | ||||
| -rw-r--r-- | CORE/VOSS/inc/vos_api.h | 1 | ||||
| -rw-r--r-- | CORE/VOSS/src/vos_api.c | 20 |
7 files changed, 420 insertions, 159 deletions
diff --git a/CORE/SVC/inc/wlan_logging_sock_svc.h b/CORE/SVC/inc/wlan_logging_sock_svc.h index ce009b69ecd8..a76041394c62 100644 --- a/CORE/SVC/inc/wlan_logging_sock_svc.h +++ b/CORE/SVC/inc/wlan_logging_sock_svc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -74,4 +74,7 @@ static inline void wlan_report_log_completion(uint32_t is_fatal, return; } #endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); + #endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/CORE/SVC/src/logging/wlan_logging_sock_svc.c b/CORE/SVC/src/logging/wlan_logging_sock_svc.c index 81ee5a882c61..729ddfd65ca9 100644 --- a/CORE/SVC/src/logging/wlan_logging_sock_svc.c +++ b/CORE/SVC/src/logging/wlan_logging_sock_svc.c @@ -43,6 +43,7 @@ #include <adf_os_time.h> #include "pktlog_ac.h" #include <linux/rtc.h> +#include <vos_diag_core_log.h> #define LOGGING_TRACE(level, args...) \ VOS_TRACE(VOS_MODULE_ID_HDD, level, ## args) @@ -51,11 +52,15 @@ #define ANI_NL_MSG_LOG_TYPE 89 #define ANI_NL_MSG_READY_IND_TYPE 90 #define MAX_LOGMSG_LENGTH 4096 +#define MAX_PKTSTATS_LENGTH 2048 +#define MAX_PKTSTATS_BUFF 16 #define HOST_LOG_DRIVER_MSG 0x001 #define HOST_LOG_PER_PKT_STATS 0x002 #define HOST_LOG_FW_FLUSH_COMPLETE 0x003 +#define DIAG_TYPE_LOGS 1 +#define PTT_MSG_DIAG_CMDS_TYPE 0x5050 struct log_msg { struct list_head node; unsigned int radio; @@ -69,6 +74,32 @@ struct log_msg { char logbuf[MAX_LOGMSG_LENGTH]; }; +/** + * struct packet_dump - This data structure contains the + * Tx/Rx packet stats + * @status: Status + * @type: Type + * @reserved: Reserved + */ + +struct packet_dump { + unsigned char status; + unsigned char type; + unsigned char reserved[6]; +}; + +/** + * struct pkt_stats_msg - This data structure contains the + * pkt stats node for link list + * @node: LinkList node + * @node: Pointer to skb + */ + +struct pkt_stats_msg { + struct list_head node; + struct sk_buff *skb; +}; + struct wlan_logging { /* Log Fatal and ERROR to console */ bool log_fe_to_console; @@ -98,10 +129,18 @@ struct wlan_logging { bool is_active; /* Flush completion check */ bool is_flush_complete; + /* paramaters for pkt stats */ + struct list_head pkt_stat_free_list; + struct list_head pkt_stat_filled_list; + struct pkt_stats_msg *pkt_stats_pcur_node; + unsigned int pkt_stat_drop_cnt; + spinlock_t pkt_stats_lock; + unsigned int pkt_stats_msg_idx; }; static struct wlan_logging gwlan_logging; static struct log_msg *gplog_msg; +static struct pkt_stats_msg *gpkt_stats_buffers; /* PID of the APP to log the message */ static int gapp_pid = INVALID_PID; @@ -369,6 +408,145 @@ int wlan_log_to_user(VOS_TRACE_LEVEL log_level, char *to_be_sent, int length) return 0; } +/** + * pkt_stats_fill_headers() - This function adds headers to skb + * @skb: skb to which headers need to be added + * + * Return: 0 on success or Errno on failure + */ + +static int pkt_stats_fill_headers(struct sk_buff *skb) +{ + struct vos_log_pktlog_info vos_pktlog; + int vos_pkt_size = sizeof(struct vos_log_pktlog_info); + tAniNlHdr msg_header; + int extra_header_len, nl_payload_len; + static int nlmsg_seq; + int diag_type; + + vos_mem_zero(&vos_pktlog, vos_pkt_size); + vos_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C; + vos_pktlog.buf_len = skb->len; + vos_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++; + vos_log_set_code(&vos_pktlog, LOG_WLAN_PKT_LOG_INFO_C); + vos_log_set_length(&vos_pktlog.log_hdr, skb->len + + vos_pkt_size); + + if (unlikely(skb_headroom(skb) < vos_pkt_size)) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(msg_header)); + return -EIO; + } + + vos_mem_copy(skb_push(skb, vos_pkt_size), + &vos_pktlog, vos_pkt_size); + + if (unlikely(skb_headroom(skb) < sizeof(int))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(int)); + return -EIO; + } + + diag_type = DIAG_TYPE_LOGS; + vos_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int)); + + extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr); + nl_payload_len = NLMSG_ALIGN(extra_header_len + skb->len); + + msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC; + msg_header.nlh.nlmsg_len = nl_payload_len; + msg_header.nlh.nlmsg_flags = NLM_F_REQUEST; + msg_header.nlh.nlmsg_pid = 0; + msg_header.nlh.nlmsg_seq = nlmsg_seq++; + msg_header.radio = 0; + msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE; + msg_header.wmsg.length = skb->len; + + if (unlikely(skb_headroom(skb) < sizeof(msg_header))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(msg_header)); + return -EIO; + } + + vos_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header, + sizeof(msg_header)); + + return 0; +} + +/** + * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per + * packet statistics to the user + * + * This function is used to send the per packet statistics to the user + * + * Return: Success if the message is posted to user + */ + +int pktlog_send_per_pkt_stats_to_user(void) +{ + int ret = -1; + struct pkt_stats_msg *pstats_msg; + unsigned long flags; + struct sk_buff *skb_new = NULL; + static int rate_limit; + bool free_old_skb = false; + + while (!list_empty(&gwlan_logging.pkt_stat_filled_list) + && !gwlan_logging.exit) { + skb_new = dev_alloc_skb(MAX_PKTSTATS_LENGTH); + if (skb_new == NULL) { + if (!rate_limit) { + pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n", + __func__, MAX_LOGMSG_LENGTH, + gwlan_logging.drop_count); + } + rate_limit = 1; + ret = -ENOMEM; + break; + } + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + + pstats_msg = (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_filled_list.next); + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + + ret = pkt_stats_fill_headers(pstats_msg->skb); + if (ret < 0) { + pr_err("%s failed to fill headers %d\n", __func__, ret); + free_old_skb = true; + goto err; + } + ret = nl_srv_bcast(pstats_msg->skb); + if (ret < 0) { + pr_info("%s: Send Failed %d drop_count = %u\n", + __func__, ret, + ++gwlan_logging.pkt_stat_drop_cnt); + } else { + ret = 0; + } +err: + /* + * Free old skb in case or error before assigning new skb + * to the free list. + */ + if (free_old_skb) + dev_kfree_skb(pstats_msg->skb); + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + pstats_msg->skb = skb_new; + list_add_tail(&pstats_msg->node, + &gwlan_logging.pkt_stat_free_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + ret = 0; + } + + return ret; + +} + static int send_filled_buffers_to_user(void) { int ret = -1; @@ -640,7 +818,7 @@ static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) { - int i = 0; + int i, j, pkt_stats_size; unsigned long irq_flag; pr_info("%s: Initalizing FEConsoleLog = %d NumBuff = %d\n", @@ -673,6 +851,46 @@ int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) list_del_init(gwlan_logging.free_list.next); spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + /* Initialize the pktStats data structure here */ + pkt_stats_size = sizeof(struct pkt_stats_msg); + gpkt_stats_buffers = vmalloc(MAX_PKTSTATS_BUFF * pkt_stats_size); + if (!gpkt_stats_buffers) { + pr_err("%s: Could not allocate memory for Pkt stats\n", + __func__); + goto err1; + } + vos_mem_zero(gpkt_stats_buffers, + MAX_PKTSTATS_BUFF * pkt_stats_size); + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_msg_idx = 0; + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list); + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + + + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH); + if (gpkt_stats_buffers[i].skb == NULL) { + pr_err("%s: Memory alloc failed for skb", __func__); + /* free previously allocated skb and return */ + for (j = 0; j < i ; j++) { + dev_kfree_skb(gpkt_stats_buffers[j].skb); + } + goto err2; + } + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + list_add(&gpkt_stats_buffers[i].node, + &gwlan_logging.pkt_stat_free_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + } + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_free_list.next); + list_del_init(gwlan_logging.pkt_stat_free_list.next); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + /* Pkt Stats intialization done */ + init_waitqueue_head(&gwlan_logging.wait_queue); gwlan_logging.exit = false; clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); @@ -684,12 +902,7 @@ int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) if (IS_ERR(gwlan_logging.thread)) { pr_err("%s: Could not Create LogMsg Thread Controller", __func__); - spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); - gwlan_logging.pcur_node = NULL; - spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); - vfree(gplog_msg); - gplog_msg = NULL; - return -ENOMEM; + goto err3; } wake_up_process(gwlan_logging.thread); gwlan_logging.is_active = true; @@ -699,12 +912,31 @@ int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) pr_info("%s: Activated wlan_logging svc\n", __func__); return 0; + +err3: + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + if (gpkt_stats_buffers[i].skb) + dev_kfree_skb(gpkt_stats_buffers[i].skb); + } +err2: + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + vfree(gpkt_stats_buffers); + gpkt_stats_buffers = NULL; +err1: + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + gwlan_logging.pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + vfree(gplog_msg); + gplog_msg = NULL; + return -ENOMEM; } int wlan_logging_sock_deactivate_svc(void) { unsigned long irq_flag; - + int i = 0; if (!gplog_msg) return 0; @@ -729,6 +961,18 @@ int wlan_logging_sock_deactivate_svc(void) vfree(gplog_msg); gplog_msg = NULL; + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = NULL; + gwlan_logging.pkt_stats_msg_idx = 0; + gwlan_logging.pkt_stat_drop_cnt = 0; + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + if (gpkt_stats_buffers[i].skb) + dev_kfree_skb(gpkt_stats_buffers[i].skb); + } + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + + vfree(gpkt_stats_buffers); + gpkt_stats_buffers = NULL; pr_info("%s: Deactivate wlan_logging svc\n", __func__); return 0; @@ -737,15 +981,17 @@ int wlan_logging_sock_deactivate_svc(void) int wlan_logging_sock_init_svc(void) { spin_lock_init(&gwlan_logging.spin_lock); + spin_lock_init(&gwlan_logging.pkt_stats_lock); gapp_pid = INVALID_PID; gwlan_logging.pcur_node = NULL; - + gwlan_logging.pkt_stats_pcur_node = NULL; return 0; } int wlan_logging_sock_deinit_svc(void) { gwlan_logging.pcur_node = NULL; + gwlan_logging.pkt_stats_pcur_node = NULL; gapp_pid = INVALID_PID; return 0; @@ -798,4 +1044,128 @@ void wlan_logging_set_fw_flush_complete(void) set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); wake_up_interruptible(&gwlan_logging.wait_queue); } + +/** + * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats + * + * This function is used to get the free node for pkt stats from + * free list/filles list + * + * Return: int + * + */ + +static int wlan_get_pkt_stats_free_node(void) +{ + int ret = 0; + + list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node, + &gwlan_logging.pkt_stat_filled_list); + + if (!list_empty(&gwlan_logging.pkt_stat_free_list)) { + /* Get buffer from free list */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next); + list_del_init(gwlan_logging.pkt_stat_free_list.next); + } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) { + /* Get buffer from filled list. This condition will drop the + * packet from being indicated to app + */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_filled_list.next); + ++gwlan_logging.pkt_stat_drop_cnt; + /* print every 64th drop count */ + if (vos_is_multicast_logging() && + (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) { + pr_err("%s: drop_count = %u\n", + __func__, gwlan_logging.pkt_stat_drop_cnt); + } + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + ret = 1; + } + + /* Reset the current node values */ + gwlan_logging.pkt_stats_pcur_node->skb->len = 0; + return ret; +} + +/** + * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB + * @pl_hdr: Pointer to pl_hdr + * @pkt_dump: Pointer to pkt_dump + * @data: Pointer to data + * + * This function adds the pktstats hdr and data to current + * skb node of free list. + * + * Return: None + */ +void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) +{ + struct ath_pktlog_hdr *pktlog_hdr; + struct packet_dump *pkt_stats_dump; + int total_stats_len = 0; + bool wake_up_thread = false; + unsigned long flags; + struct sk_buff *ptr; + int hdr_size; + + pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr; + + if (pktlog_hdr == NULL) { + pr_err("%s : Invalid pkt_stats_header\n", __func__); + return; + } + + pkt_stats_dump = (struct packet_dump *)pkt_dump; + if (pkt_stats_dump) + total_stats_len = sizeof(struct ath_pktlog_hdr) + + pktlog_hdr->size + + sizeof(struct packet_dump); + else + total_stats_len = sizeof(struct ath_pktlog_hdr) + + pktlog_hdr->size; + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + + if (!gwlan_logging.pkt_stats_pcur_node) { + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + return; + } + + /* Check if we can accomodate more log into current node/buffer */ + hdr_size = sizeof(struct vos_log_pktlog_info) + + sizeof(tAniNlHdr); + if ((total_stats_len + hdr_size) >= + skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) { + wake_up_thread = true; + wlan_get_pkt_stats_free_node(); + } + + ptr = gwlan_logging.pkt_stats_pcur_node->skb; + vos_mem_copy(skb_put(ptr, + sizeof(struct ath_pktlog_hdr)), + pktlog_hdr, + sizeof(struct ath_pktlog_hdr)); + + if (pkt_stats_dump) + vos_mem_copy(skb_put(ptr, + sizeof(struct packet_dump)), + pkt_stats_dump, + sizeof(struct packet_dump)); + + vos_mem_copy(skb_put(ptr, + pktlog_hdr->size), + data, pktlog_hdr->size); + + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + + /* Wakeup logger thread */ + if (true == wake_up_thread) { + set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } +} + #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/CORE/UTILS/PKTLOG/include/pktlog_ac.h b/CORE/UTILS/PKTLOG/include/pktlog_ac.h index 88f5bdfc63c7..4e3d34a2f19a 100644 --- a/CORE/UTILS/PKTLOG/include/pktlog_ac.h +++ b/CORE/UTILS/PKTLOG/include/pktlog_ac.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -65,7 +65,6 @@ extern void pktlog_release_buf(struct ol_softc *scn); ssize_t pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos, struct ath_pktlog_info *pl_info, bool *read_complete); -int pktlog_send_per_pkt_stats_to_user(void); struct ol_pl_arch_dep_funcs { void (*pktlog_init) (struct ol_softc *scn); diff --git a/CORE/UTILS/PKTLOG/linux_ac.c b/CORE/UTILS/PKTLOG/linux_ac.c index 07d6412be356..9ed3f5f85579 100644 --- a/CORE/UTILS/PKTLOG/linux_ac.c +++ b/CORE/UTILS/PKTLOG/linux_ac.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -576,139 +576,6 @@ static int pktlog_release(struct inode *i, struct file *f) #endif /** - * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per - * packet statistics to the user - * - * This function is used to send the per packet statistics to the user - * - * Return: Success if the message is posted to user - * - */ -int pktlog_send_per_pkt_stats_to_user(void) -{ - ssize_t ret_val; - struct vos_log_pktlog_info *pktlog = NULL; - void *vos = vos_get_global_context(VOS_MODULE_ID_HIF, NULL); - ol_txrx_pdev_handle txrx_pdev = - vos_get_context(VOS_MODULE_ID_TXRX, vos); - struct ath_pktlog_info *pl_info; - bool read_complete; - uint32_t num_bytes_read = 0; - - /* - * We do not want to do this packet stats related processing when - * packet log tool is run. i.e., we want this processing to be - * done only when start logging command of packet stats is initiated. - */ - if ((vos_get_ring_log_level(RING_ID_PER_PACKET_STATS) < - WLAN_LOG_LEVEL_ACTIVE)) { - printk(PKTLOG_TAG " %s: Shouldnt happen. Logging not started\n", - __func__); - return -EINVAL; - } - - if (!txrx_pdev) { - printk(PKTLOG_TAG " %s: Invalid TxRx handle\n", __func__); - return -EINVAL; - } - - pl_info = txrx_pdev->pl_dev->pl_info; - - if (!pl_info || !pl_info->buf) { - printk(PKTLOG_TAG " %s: Shouldnt happen. pl_info is invalid\n", - __func__); - return -EINVAL; - } - - if (pl_info->buf->rd_offset == -1) { - printk(PKTLOG_TAG " %s: Shouldnt happen. No write yet!\n", - __func__); - return -EINVAL; - } - - do { - pktlog = (struct vos_log_pktlog_info *) - vos_mem_malloc(sizeof(struct vos_log_pktlog_info) + - VOS_LOG_PKT_LOG_SIZE); - if (!pktlog) { - printk(PKTLOG_TAG " %s: Memory allocation failed\n", - __func__); - return -ENOMEM; - } - - vos_mem_zero(pktlog, VOS_LOG_PKT_LOG_SIZE); - vos_log_set_code(pktlog, LOG_WLAN_PKT_LOG_INFO_C); - - pktlog->buf_len = 0; - pktlog->version = VERSION_LOG_WLAN_PKT_LOG_INFO_C; - - /* - * @ret_val: ret_val gives the actual data read from the buffer. - * When there is no more data to read, this value will be zero - * @offset: offset in the ring buffer. Initially it is zero and - * is incremented during every read based on number of bytes - * read - */ - ret_val = pktlog_read_proc_entry(pktlog->buf, - VOS_LOG_PKT_LOG_SIZE, - &pl_info->buf->offset, - pl_info, &read_complete); - if (ret_val) { - int index = 0; - struct ath_pktlog_hdr *temp; - while (1) { - if ((ret_val - index) < - sizeof(struct ath_pktlog_hdr)) { - /* Partial header */ - pl_info->buf->offset -= - (ret_val - index); - ret_val = index; - break; - } - temp = (struct ath_pktlog_hdr *) - (pktlog->buf + index); - if ((ret_val - index) < (temp->size + - sizeof(struct ath_pktlog_hdr))) { - /* Partial record payload */ - pl_info->buf->offset -= - (ret_val - index); - ret_val = index; - break; - } - index += temp->size + - sizeof(struct ath_pktlog_hdr); - } - } - - /* Data will include message index/seq number and buf length */ - pktlog->buf_len = ret_val; - if (ret_val) { - vos_log_set_length(pktlog, ret_val + - sizeof(struct vos_log_pktlog_info)); - pktlog->seq_no = pl_info->buf->msg_index++; - WLAN_VOS_DIAG_LOG_REPORT(pktlog); - } else { - vos_mem_free(pktlog); - } - num_bytes_read += ret_val; - /* - * If the logger thread is scheduled late and the proc entry - * is having too much data to be read, we might start to starve - * the other threads if we continuously keep reading the proc - * entry. So, having a threshold to break this read from proc - * entry. - */ - if (num_bytes_read > VOS_LOG_PKT_LOG_THRESHOLD) { - read_complete = true; - printk(PKTLOG_TAG " %s: Break read to prevent starve\n", - __func__); - } - } while (read_complete == false); - - return 0; -} - -/** * pktlog_read_proc_entry() - This function is used to read data from the * proc entry into the readers buffer * @buf: Readers buffer diff --git a/CORE/UTILS/PKTLOG/pktlog_internal.c b/CORE/UTILS/PKTLOG/pktlog_internal.c index 8f9042fe2ef0..cd013bfdb0c5 100644 --- a/CORE/UTILS/PKTLOG/pktlog_internal.c +++ b/CORE/UTILS/PKTLOG/pktlog_internal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -170,16 +170,6 @@ pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev, pktlog_getbuf_intsafe(&plarg); PKTLOG_UNLOCK(pl_info); } - - /* - * We do not want to do this packet stats related processing when - * packet log tool is run. i.e., we want this processing to be - * done only when start logging command of packet stats is initiated. - */ - if (vos_get_ring_log_level(RING_ID_PER_PACKET_STATS) == - WLAN_LOG_LEVEL_ACTIVE) - pktlog_check_threshold(pl_info, log_size); - return plarg.buf; } @@ -320,6 +310,10 @@ process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, adf_os_assert(txctl_log.txdesc_hdr_ctl); adf_os_mem_copy(txctl_log.txdesc_hdr_ctl, &txctl_log.priv, sizeof(txctl_log.priv)); + + pl_hdr.size = log_size; + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txctl_log.txdesc_hdr_ctl); /* Add Protocol information and HT specific information */ } @@ -333,6 +327,8 @@ process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, adf_os_mem_copy(txstat_log.ds_status, ((void *)data + sizeof(struct ath_pktlog_hdr)), pl_hdr.size); + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txstat_log.ds_status); } if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) { @@ -422,6 +418,8 @@ process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, sizeof(pl_msdu_info.priv.msdu_id_info)); adf_os_mem_copy(pl_msdu_info.ath_msdu_info, &pl_msdu_info.priv, sizeof(pl_msdu_info.priv)); + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, + pl_msdu_info.ath_msdu_info); } return A_OK; } @@ -471,6 +469,8 @@ process_rx_info_remote(void *pdev, adf_nbuf_t amsdu) adf_os_mem_copy(rxstat_log.rx_desc, (void *)rx_desc + sizeof(struct htt_host_fw_desc_base), pl_hdr.size); + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, + rxstat_log.rx_desc); msdu = adf_nbuf_next(msdu); } return A_OK; @@ -513,7 +513,7 @@ process_rx_info(void *pdev, void *data) adf_os_mem_copy(rxstat_log.rx_desc, (void *)data + sizeof(struct ath_pktlog_hdr), pl_hdr.size); - + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc); return A_OK; } @@ -569,7 +569,7 @@ process_rate_find(void *pdev, void *data) adf_os_mem_copy(rcf_log.rcFind, ((char *)data + sizeof(struct ath_pktlog_hdr)), pl_hdr.size); - + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcf_log.rcFind); return A_OK; } @@ -623,6 +623,7 @@ process_rate_update(void *pdev, void *data) adf_os_mem_copy(rcu_log.txRateCtrl, ((char *)data + sizeof(struct ath_pktlog_hdr)), pl_hdr.size); + vos_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcu_log.txRateCtrl); return A_OK; } #endif /*REMOVE_PKT_LOG*/ diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h index c68ea70f6f39..b151d6a2e74f 100644 --- a/CORE/VOSS/inc/vos_api.h +++ b/CORE/VOSS/inc/vos_api.h @@ -367,4 +367,5 @@ void vos_logging_set_fw_flush_complete(void); void vos_probe_threads(void); bool vos_is_crash_indication_pending(void); void vos_set_crash_indication_pending(bool value); +void vos_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); #endif // if !defined __VOS_API_H diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c index 5c06638c785d..3e0bb5cd1680 100644 --- a/CORE/VOSS/src/vos_api.c +++ b/CORE/VOSS/src/vos_api.c @@ -2813,3 +2813,23 @@ void vos_probe_threads(void) FL("Unable to post SYS_MSG_ID_MC_THR_PROBE message to MC thread")); } } + +/** + * vos_pkt_stats_to_logger_thread() - send pktstats to user + * @pl_hdr: Pointer to pl_hdr + * @pkt_dump: Pointer to pkt_dump data structure. + * @data: Pointer to data + * + * This function is used to send the pkt stats to SVC module. + * + * Return: None + */ +inline void vos_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, + void *data) +{ + if (vos_get_ring_log_level(RING_ID_PER_PACKET_STATS) != + WLAN_LOG_LEVEL_ACTIVE) + return; + + wlan_pkt_stats_to_logger_thread(pl_hdr, pkt_dump, data); +} |
