/* * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* * This file was originally distributed by Qualcomm Atheros, Inc. * under proprietary terms before Copyright ownership was assigned * to the Linux Foundation. */ /** * DOC: qdf_perf * This file provides OS dependent perf API's. */ #include #include #include #include #include #include #include #include #include #ifdef QCA_PERF_PROFILING qdf_perf_entry_t perf_root = {{0, 0} }; /** * qdf_perfmod_init() - Module init * * return: int */ int qdf_perfmod_init(void) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "Perf Debug Module Init"); INIT_LIST_HEAD(&perf_root.list); INIT_LIST_HEAD(&perf_root.child); perf_root.proc = proc_mkdir(PROCFS_PERF_DIRNAME, 0); return 0; } EXPORT_SYMBOL(qdf_perfmod_init); /** * qdf_perfmod_exit() - Module exit * * Return: none */ void qdf_perfmod_exit(void) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "Perf Debug Module Exit"); remove_proc_entry(PROCFS_PERF_DIRNAME, 0); } EXPORT_SYMBOL(qdf_perfmod_exit); /** * __qdf_perf_init() - Create the perf entry * @parent: parent perf id * @id_name: name of perf id * @type: type of perf counter * * return: perf id */ qdf_perf_id_t __qdf_perf_init(qdf_perf_id_t parent, uint8_t *id_name, qdf_perf_cntr_t type) { qdf_perf_entry_t *entry = NULL; qdf_perf_entry_t *pentry = PERF_ENTRY(parent); if (type >= CNTR_LAST) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s:%s Invalid perf-type", __FILE__, __func__); goto done; } if (!pentry) pentry = &perf_root; entry = kmalloc(sizeof(struct qdf_perf_entry), GFP_ATOMIC); if (!entry) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, " Out of Memory,:%s", __func__); return NULL; } memset(entry, 0, sizeof(struct qdf_perf_entry)); INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->child); spin_lock_init(&entry->lock_irq); list_add_tail(&entry->list, &pentry->child); entry->name = id_name; entry->type = type; if (type == CNTR_GROUP) { entry->proc = proc_mkdir(id_name, pentry->proc); goto done; } entry->parent = pentry; entry->proc = create_proc_entry(id_name, S_IFREG|S_IRUGO|S_IWUSR, pentry->proc); entry->proc->data = entry; entry->proc->read_proc = api_tbl[type].proc_read; entry->proc->write_proc = api_tbl[type].proc_write; /* * Initialize the Event with default values */ api_tbl[type].init(entry, api_tbl[type].def_val); done: return entry; } EXPORT_SYMBOL(__qdf_perf_init); /** * __qdf_perf_destroy - Destroy the perf entry * @id: pointer to qdf_perf_id_t * * @return: bool */ bool __qdf_perf_destroy(qdf_perf_id_t id) { qdf_perf_entry_t *entry = PERF_ENTRY(id), *parent = entry->parent; if (!list_empty(&entry->child)) { QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "Child's are alive, Can't delete"); return A_FALSE; } remove_proc_entry(entry->name, parent->proc); list_del(&entry->list); vfree(entry); return true; } EXPORT_SYMBOL(__qdf_perf_destroy); /** * __qdf_perf_start - Start the sampling * @id: Instance of qdf_perf_id_t * * Returns: none */ void __qdf_perf_start(qdf_perf_id_t id) { qdf_perf_entry_t *entry = PERF_ENTRY(id); api_tbl[entry->type].sample(entry, 0); } EXPORT_SYMBOL(__qdf_perf_start); /** * __qdf_perf_end - Stop sampling * @id: Instance of qdf_perf_id_t * * Returns: none */ void __qdf_perf_end(qdf_perf_id_t id) { qdf_perf_entry_t *entry = PERF_ENTRY(id); api_tbl[entry->type].sample(entry, 1); } EXPORT_SYMBOL(__qdf_perf_end); #endif /* QCA_PERF_PROFILING */