| /* | |
| * Copyright 2014 Cisco Systems, Inc. All rights reserved. | |
| * | |
| * This program is free software; you may redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation; version 2 of the License. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| * SOFTWARE. | |
| */ | |
| #include <linux/module.h> | |
| #include <linux/mempool.h> | |
| #include <linux/errno.h> | |
| #include <linux/vmalloc.h> | |
| #include "snic_io.h" | |
| #include "snic.h" | |
| /* | |
| * snic_get_trc_buf : Allocates a trace record and returns. | |
| */ | |
| struct snic_trc_data * | |
| snic_get_trc_buf(void) | |
| { | |
| struct snic_trc *trc = &snic_glob->trc; | |
| struct snic_trc_data *td = NULL; | |
| unsigned long flags; | |
| spin_lock_irqsave(&trc->lock, flags); | |
| td = &trc->buf[trc->wr_idx]; | |
| trc->wr_idx++; | |
| if (trc->wr_idx == trc->max_idx) | |
| trc->wr_idx = 0; | |
| if (trc->wr_idx != trc->rd_idx) { | |
| spin_unlock_irqrestore(&trc->lock, flags); | |
| goto end; | |
| } | |
| trc->rd_idx++; | |
| if (trc->rd_idx == trc->max_idx) | |
| trc->rd_idx = 0; | |
| td->ts = 0; /* Marker for checking the record, for complete data*/ | |
| spin_unlock_irqrestore(&trc->lock, flags); | |
| end: | |
| return td; | |
| } /* end of snic_get_trc_buf */ | |
| /* | |
| * snic_fmt_trc_data : Formats trace data for printing. | |
| */ | |
| static int | |
| snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz) | |
| { | |
| int len = 0; | |
| struct timespec tmspec; | |
| jiffies_to_timespec(td->ts, &tmspec); | |
| len += snprintf(buf, buf_sz, | |
| "%lu.%10lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", | |
| tmspec.tv_sec, | |
| tmspec.tv_nsec, | |
| td->fn, | |
| td->hno, | |
| td->tag, | |
| td->data[0], td->data[1], td->data[2], td->data[3], | |
| td->data[4]); | |
| return len; | |
| } /* end of snic_fmt_trc_data */ | |
| /* | |
| * snic_get_trc_data : Returns a formatted trace buffer. | |
| */ | |
| int | |
| snic_get_trc_data(char *buf, int buf_sz) | |
| { | |
| struct snic_trc_data *td = NULL; | |
| struct snic_trc *trc = &snic_glob->trc; | |
| unsigned long flags; | |
| spin_lock_irqsave(&trc->lock, flags); | |
| if (trc->rd_idx == trc->wr_idx) { | |
| spin_unlock_irqrestore(&trc->lock, flags); | |
| return -1; | |
| } | |
| td = &trc->buf[trc->rd_idx]; | |
| if (td->ts == 0) { | |
| /* write in progress. */ | |
| spin_unlock_irqrestore(&trc->lock, flags); | |
| return -1; | |
| } | |
| trc->rd_idx++; | |
| if (trc->rd_idx == trc->max_idx) | |
| trc->rd_idx = 0; | |
| spin_unlock_irqrestore(&trc->lock, flags); | |
| return snic_fmt_trc_data(td, buf, buf_sz); | |
| } /* end of snic_get_trc_data */ | |
| /* | |
| * snic_trc_init() : Configures Trace Functionality for snic. | |
| */ | |
| int | |
| snic_trc_init(void) | |
| { | |
| struct snic_trc *trc = &snic_glob->trc; | |
| void *tbuf = NULL; | |
| int tbuf_sz = 0, ret; | |
| tbuf_sz = (snic_trace_max_pages * PAGE_SIZE); | |
| tbuf = vmalloc(tbuf_sz); | |
| if (!tbuf) { | |
| SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz); | |
| SNIC_ERR("Trace Facility not enabled.\n"); | |
| ret = -ENOMEM; | |
| return ret; | |
| } | |
| memset(tbuf, 0, tbuf_sz); | |
| trc->buf = (struct snic_trc_data *) tbuf; | |
| spin_lock_init(&trc->lock); | |
| ret = snic_trc_debugfs_init(); | |
| if (ret) { | |
| SNIC_ERR("Failed to create Debugfs Files.\n"); | |
| goto error; | |
| } | |
| trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ); | |
| trc->rd_idx = trc->wr_idx = 0; | |
| trc->enable = true; | |
| SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n", | |
| tbuf_sz / PAGE_SIZE); | |
| ret = 0; | |
| return ret; | |
| error: | |
| snic_trc_free(); | |
| return ret; | |
| } /* end of snic_trc_init */ | |
| /* | |
| * snic_trc_free : Releases the trace buffer and disables the tracing. | |
| */ | |
| void | |
| snic_trc_free(void) | |
| { | |
| struct snic_trc *trc = &snic_glob->trc; | |
| trc->enable = false; | |
| snic_trc_debugfs_term(); | |
| if (trc->buf) { | |
| vfree(trc->buf); | |
| trc->buf = NULL; | |
| } | |
| SNIC_INFO("Trace Facility Disabled.\n"); | |
| } /* end of snic_trc_free */ |