xref: /wlan-dirver/qca-wifi-host-cmn/qdf/linux/src/qdf_perf.c (revision 6ecd284e5a94a1c96e26d571dd47419ac305990d)
1 /*
2  * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 /**
29  * DOC: qdf_perf
30  * This file provides OS dependent perf API's.
31  */
32 
33 #include <linux/version.h>
34 #include <linux/kernel.h>
35 #include <linux/uaccess.h>
36 #include <linux/fs.h>
37 #include <linux/proc_fs.h>
38 #include <linux/vmalloc.h>
39 #include <linux/list.h>
40 #include <linux/spinlock.h>
41 
42 #include <qdf_perf.h>
43 #include <qdf_module.h>
44 #ifdef QCA_PERF_PROFILING
45 
46 qdf_perf_entry_t     perf_root = {{0, 0} };
47 
48 /**
49  * qdf_perfmod_init() - Module init
50  *
51  * return: int
52  */
53 int
54 qdf_perfmod_init(void)
55 {
56 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
57 		  "Perf Debug Module Init");
58 	INIT_LIST_HEAD(&perf_root.list);
59 	INIT_LIST_HEAD(&perf_root.child);
60 	perf_root.proc = proc_mkdir(PROCFS_PERF_DIRNAME, 0);
61 	return 0;
62 }
63 qdf_export_symbol(qdf_perfmod_init);
64 
65 /**
66  * qdf_perfmod_exit() - Module exit
67  *
68  * Return: none
69  */
70 void
71 qdf_perfmod_exit(void)
72 {
73 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO,
74 		  "Perf Debug Module Exit");
75 	remove_proc_entry(PROCFS_PERF_DIRNAME, 0);
76 }
77 qdf_export_symbol(qdf_perfmod_exit);
78 
79 /**
80  * __qdf_perf_init() - Create the perf entry
81  * @parent: parent perf id
82  * @id_name: name of perf id
83  * @type: type of perf counter
84  *
85  * return: perf id
86  */
87 qdf_perf_id_t
88 __qdf_perf_init(qdf_perf_id_t parent, uint8_t *id_name,
89 		qdf_perf_cntr_t type)
90 {
91 	qdf_perf_entry_t    *entry  = NULL;
92 	qdf_perf_entry_t    *pentry = PERF_ENTRY(parent);
93 
94 	if (type >= CNTR_LAST) {
95 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
96 			  "%s:%s Invalid perf-type", __FILE__, __func__);
97 		goto done;
98 	}
99 
100 	if (!pentry)
101 		pentry = &perf_root;
102 	entry = kmalloc(sizeof(struct qdf_perf_entry), GFP_ATOMIC);
103 
104 	if (!entry) {
105 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
106 			  " Out of Memory,:%s", __func__);
107 		return NULL;
108 	}
109 
110 	memset(entry, 0, sizeof(struct qdf_perf_entry));
111 
112 	INIT_LIST_HEAD(&entry->list);
113 	INIT_LIST_HEAD(&entry->child);
114 
115 	spin_lock_init(&entry->lock_irq);
116 
117 	list_add_tail(&entry->list, &pentry->child);
118 
119 	entry->name = id_name;
120 	entry->type = type;
121 
122 	if (type == CNTR_GROUP) {
123 		entry->proc = proc_mkdir(id_name, pentry->proc);
124 		goto done;
125 	}
126 
127 	entry->parent   = pentry;
128 	entry->proc     = create_proc_entry(id_name, S_IFREG|S_IRUGO|S_IWUSR,
129 					pentry->proc);
130 	entry->proc->data       = entry;
131 	entry->proc->read_proc  = api_tbl[type].proc_read;
132 	entry->proc->write_proc = api_tbl[type].proc_write;
133 
134 	/*
135 	 * Initialize the Event with default values
136 	 */
137 	api_tbl[type].init(entry, api_tbl[type].def_val);
138 
139 done:
140 	return entry;
141 }
142 qdf_export_symbol(__qdf_perf_init);
143 
144 /**
145  * __qdf_perf_destroy - Destroy the perf entry
146  * @id: pointer to qdf_perf_id_t
147  *
148  * @return: bool
149  */
150 bool __qdf_perf_destroy(qdf_perf_id_t  id)
151 {
152 	qdf_perf_entry_t     *entry  = PERF_ENTRY(id),
153 		*parent = entry->parent;
154 
155 	if (!list_empty(&entry->child)) {
156 		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
157 			  "Child's are alive, Can't delete");
158 		return A_FALSE;
159 	}
160 
161 	remove_proc_entry(entry->name, parent->proc);
162 
163 	list_del(&entry->list);
164 
165 	vfree(entry);
166 
167 	return true;
168 }
169 qdf_export_symbol(__qdf_perf_destroy);
170 
171 /**
172  * __qdf_perf_start - Start the sampling
173  * @id: Instance of qdf_perf_id_t
174  *
175  * Returns: none
176  */
177 void __qdf_perf_start(qdf_perf_id_t id)
178 {
179 	qdf_perf_entry_t *entry = PERF_ENTRY(id);
180 
181 	api_tbl[entry->type].sample(entry, 0);
182 }
183 qdf_export_symbol(__qdf_perf_start);
184 
185 /**
186  * __qdf_perf_end - Stop sampling
187  * @id: Instance of qdf_perf_id_t
188  *
189  * Returns: none
190  */
191 void __qdf_perf_end(qdf_perf_id_t id)
192 {
193 	qdf_perf_entry_t *entry = PERF_ENTRY(id);
194 
195 	api_tbl[entry->type].sample(entry, 1);
196 }
197 qdf_export_symbol(__qdf_perf_end);
198 
199 #endif /* QCA_PERF_PROFILING */
200