summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSachin Ahuja <sahuja@qti.qualcomm.com>2016-01-20 19:09:29 +0530
committerAnjaneedevi Kapparapu <akappa@codeaurora.org>2016-01-28 13:44:03 +0530
commitb2487f65f9b080a2109785e83e2d832edbaccc77 (patch)
treec2a303e29fa6da3e62680b5f64524e3679db50ac
parentc640a069aa710f1bb0e671296fbb236a3f86e107 (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.h5
-rw-r--r--CORE/SVC/src/logging/wlan_logging_sock_svc.c388
-rw-r--r--CORE/UTILS/PKTLOG/include/pktlog_ac.h3
-rw-r--r--CORE/UTILS/PKTLOG/linux_ac.c135
-rw-r--r--CORE/UTILS/PKTLOG/pktlog_internal.c27
-rw-r--r--CORE/VOSS/inc/vos_api.h1
-rw-r--r--CORE/VOSS/src/vos_api.c20
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);
+}