18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify 58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 158c2ecf20Sopenharmony_ci * SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/mempool.h> 208c2ecf20Sopenharmony_ci#include <linux/errno.h> 218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "snic_io.h" 248c2ecf20Sopenharmony_ci#include "snic.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * snic_get_trc_buf : Allocates a trace record and returns. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistruct snic_trc_data * 308c2ecf20Sopenharmony_cisnic_get_trc_buf(void) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct snic_trc *trc = &snic_glob->trc; 338c2ecf20Sopenharmony_ci struct snic_trc_data *td = NULL; 348c2ecf20Sopenharmony_ci unsigned long flags; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci spin_lock_irqsave(&trc->lock, flags); 378c2ecf20Sopenharmony_ci td = &trc->buf[trc->wr_idx]; 388c2ecf20Sopenharmony_ci trc->wr_idx++; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (trc->wr_idx == trc->max_idx) 418c2ecf20Sopenharmony_ci trc->wr_idx = 0; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (trc->wr_idx != trc->rd_idx) { 448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&trc->lock, flags); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci goto end; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci trc->rd_idx++; 508c2ecf20Sopenharmony_ci if (trc->rd_idx == trc->max_idx) 518c2ecf20Sopenharmony_ci trc->rd_idx = 0; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci td->ts = 0; /* Marker for checking the record, for complete data*/ 548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&trc->lock, flags); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciend: 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return td; 598c2ecf20Sopenharmony_ci} /* end of snic_get_trc_buf */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * snic_fmt_trc_data : Formats trace data for printing. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic int 658c2ecf20Sopenharmony_cisnic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int len = 0; 688c2ecf20Sopenharmony_ci struct timespec64 tmspec; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci jiffies_to_timespec64(td->ts, &tmspec); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci len += snprintf(buf, buf_sz, 738c2ecf20Sopenharmony_ci "%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", 748c2ecf20Sopenharmony_ci tmspec.tv_sec, 758c2ecf20Sopenharmony_ci tmspec.tv_nsec, 768c2ecf20Sopenharmony_ci td->fn, 778c2ecf20Sopenharmony_ci td->hno, 788c2ecf20Sopenharmony_ci td->tag, 798c2ecf20Sopenharmony_ci td->data[0], td->data[1], td->data[2], td->data[3], 808c2ecf20Sopenharmony_ci td->data[4]); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return len; 838c2ecf20Sopenharmony_ci} /* end of snic_fmt_trc_data */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * snic_get_trc_data : Returns a formatted trace buffer. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ciint 898c2ecf20Sopenharmony_cisnic_get_trc_data(char *buf, int buf_sz) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct snic_trc_data *td = NULL; 928c2ecf20Sopenharmony_ci struct snic_trc *trc = &snic_glob->trc; 938c2ecf20Sopenharmony_ci unsigned long flags; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci spin_lock_irqsave(&trc->lock, flags); 968c2ecf20Sopenharmony_ci if (trc->rd_idx == trc->wr_idx) { 978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&trc->lock, flags); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return -1; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci td = &trc->buf[trc->rd_idx]; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (td->ts == 0) { 1048c2ecf20Sopenharmony_ci /* write in progress. */ 1058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&trc->lock, flags); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return -1; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci trc->rd_idx++; 1118c2ecf20Sopenharmony_ci if (trc->rd_idx == trc->max_idx) 1128c2ecf20Sopenharmony_ci trc->rd_idx = 0; 1138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&trc->lock, flags); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return snic_fmt_trc_data(td, buf, buf_sz); 1168c2ecf20Sopenharmony_ci} /* end of snic_get_trc_data */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * snic_trc_init() : Configures Trace Functionality for snic. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ciint 1228c2ecf20Sopenharmony_cisnic_trc_init(void) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct snic_trc *trc = &snic_glob->trc; 1258c2ecf20Sopenharmony_ci void *tbuf = NULL; 1268c2ecf20Sopenharmony_ci int tbuf_sz = 0, ret; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci tbuf_sz = (snic_trace_max_pages * PAGE_SIZE); 1298c2ecf20Sopenharmony_ci tbuf = vzalloc(tbuf_sz); 1308c2ecf20Sopenharmony_ci if (!tbuf) { 1318c2ecf20Sopenharmony_ci SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz); 1328c2ecf20Sopenharmony_ci SNIC_ERR("Trace Facility not enabled.\n"); 1338c2ecf20Sopenharmony_ci ret = -ENOMEM; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return ret; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci trc->buf = (struct snic_trc_data *) tbuf; 1398c2ecf20Sopenharmony_ci spin_lock_init(&trc->lock); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci snic_trc_debugfs_init(); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ); 1448c2ecf20Sopenharmony_ci trc->rd_idx = trc->wr_idx = 0; 1458c2ecf20Sopenharmony_ci trc->enable = true; 1468c2ecf20Sopenharmony_ci SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n", 1478c2ecf20Sopenharmony_ci tbuf_sz / PAGE_SIZE); 1488c2ecf20Sopenharmony_ci ret = 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci} /* end of snic_trc_init */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * snic_trc_free : Releases the trace buffer and disables the tracing. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_civoid 1578c2ecf20Sopenharmony_cisnic_trc_free(void) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct snic_trc *trc = &snic_glob->trc; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci trc->enable = false; 1628c2ecf20Sopenharmony_ci snic_trc_debugfs_term(); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (trc->buf) { 1658c2ecf20Sopenharmony_ci vfree(trc->buf); 1668c2ecf20Sopenharmony_ci trc->buf = NULL; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci SNIC_INFO("Trace Facility Disabled.\n"); 1708c2ecf20Sopenharmony_ci} /* end of snic_trc_free */ 171