1/*
2 * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
3 *
4 * This program is free software; you may redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15 * SOFTWARE.
16 */
17
18#include <linux/module.h>
19#include <linux/mempool.h>
20#include <linux/errno.h>
21#include <linux/vmalloc.h>
22
23#include "snic_io.h"
24#include "snic.h"
25
26/*
27 * snic_get_trc_buf : Allocates a trace record and returns.
28 */
29struct snic_trc_data *
30snic_get_trc_buf(void)
31{
32	struct snic_trc *trc = &snic_glob->trc;
33	struct snic_trc_data *td = NULL;
34	unsigned long flags;
35
36	spin_lock_irqsave(&trc->lock, flags);
37	td = &trc->buf[trc->wr_idx];
38	trc->wr_idx++;
39
40	if (trc->wr_idx == trc->max_idx)
41		trc->wr_idx = 0;
42
43	if (trc->wr_idx != trc->rd_idx) {
44		spin_unlock_irqrestore(&trc->lock, flags);
45
46		goto end;
47	}
48
49	trc->rd_idx++;
50	if (trc->rd_idx == trc->max_idx)
51		trc->rd_idx = 0;
52
53	td->ts = 0;	/* Marker for checking the record, for complete data*/
54	spin_unlock_irqrestore(&trc->lock, flags);
55
56end:
57
58	return td;
59} /* end of snic_get_trc_buf */
60
61/*
62 * snic_fmt_trc_data : Formats trace data for printing.
63 */
64static int
65snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz)
66{
67	int len = 0;
68	struct timespec64 tmspec;
69
70	jiffies_to_timespec64(td->ts, &tmspec);
71
72	len += snprintf(buf, buf_sz,
73			"%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n",
74			tmspec.tv_sec,
75			tmspec.tv_nsec,
76			td->fn,
77			td->hno,
78			td->tag,
79			td->data[0], td->data[1], td->data[2], td->data[3],
80			td->data[4]);
81
82	return len;
83} /* end of snic_fmt_trc_data */
84
85/*
86 * snic_get_trc_data : Returns a formatted trace buffer.
87 */
88int
89snic_get_trc_data(char *buf, int buf_sz)
90{
91	struct snic_trc_data *td = NULL;
92	struct snic_trc *trc = &snic_glob->trc;
93	unsigned long flags;
94
95	spin_lock_irqsave(&trc->lock, flags);
96	if (trc->rd_idx == trc->wr_idx) {
97		spin_unlock_irqrestore(&trc->lock, flags);
98
99		return -1;
100	}
101	td = &trc->buf[trc->rd_idx];
102
103	if (td->ts == 0) {
104		/* write in progress. */
105		spin_unlock_irqrestore(&trc->lock, flags);
106
107		return -1;
108	}
109
110	trc->rd_idx++;
111	if (trc->rd_idx == trc->max_idx)
112		trc->rd_idx = 0;
113	spin_unlock_irqrestore(&trc->lock, flags);
114
115	return snic_fmt_trc_data(td, buf, buf_sz);
116} /* end of snic_get_trc_data */
117
118/*
119 * snic_trc_init() : Configures Trace Functionality for snic.
120 */
121int
122snic_trc_init(void)
123{
124	struct snic_trc *trc = &snic_glob->trc;
125	void *tbuf = NULL;
126	int tbuf_sz = 0, ret;
127
128	tbuf_sz = (snic_trace_max_pages * PAGE_SIZE);
129	tbuf = vzalloc(tbuf_sz);
130	if (!tbuf) {
131		SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz);
132		SNIC_ERR("Trace Facility not enabled.\n");
133		ret = -ENOMEM;
134
135		return ret;
136	}
137
138	trc->buf = (struct snic_trc_data *) tbuf;
139	spin_lock_init(&trc->lock);
140
141	snic_trc_debugfs_init();
142
143	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ);
144	trc->rd_idx = trc->wr_idx = 0;
145	trc->enable = true;
146	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n",
147		  tbuf_sz / PAGE_SIZE);
148	ret = 0;
149
150	return ret;
151} /* end of snic_trc_init */
152
153/*
154 * snic_trc_free : Releases the trace buffer and disables the tracing.
155 */
156void
157snic_trc_free(void)
158{
159	struct snic_trc *trc = &snic_glob->trc;
160
161	trc->enable = false;
162	snic_trc_debugfs_term();
163
164	if (trc->buf) {
165		vfree(trc->buf);
166		trc->buf = NULL;
167	}
168
169	SNIC_INFO("Trace Facility Disabled.\n");
170} /* end of snic_trc_free */
171