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