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  */
29 struct snic_trc_data *
snic_get_trc_buf(void)30 snic_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 
56 end:
57 
58 	return td;
59 } /* end of snic_get_trc_buf */
60 
61 /*
62  * snic_fmt_trc_data : Formats trace data for printing.
63  */
64 static int
snic_fmt_trc_data(struct snic_trc_data * td,char * buf,int buf_sz)65 snic_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  */
88 int
snic_get_trc_data(char * buf,int buf_sz)89 snic_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  */
121 int
snic_trc_init(void)122 snic_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 = vmalloc(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 	memset(tbuf, 0, tbuf_sz);
139 	trc->buf = (struct snic_trc_data *) tbuf;
140 	spin_lock_init(&trc->lock);
141 
142 	ret = snic_trc_debugfs_init();
143 	if (ret) {
144 		SNIC_ERR("Failed to create Debugfs Files.\n");
145 
146 		goto error;
147 	}
148 
149 	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ);
150 	trc->rd_idx = trc->wr_idx = 0;
151 	trc->enable = true;
152 	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n",
153 		  tbuf_sz / PAGE_SIZE);
154 	ret = 0;
155 
156 	return ret;
157 
158 error:
159 	snic_trc_free();
160 
161 	return ret;
162 } /* end of snic_trc_init */
163 
164 /*
165  * snic_trc_free : Releases the trace buffer and disables the tracing.
166  */
167 void
snic_trc_free(void)168 snic_trc_free(void)
169 {
170 	struct snic_trc *trc = &snic_glob->trc;
171 
172 	trc->enable = false;
173 	snic_trc_debugfs_term();
174 
175 	if (trc->buf) {
176 		vfree(trc->buf);
177 		trc->buf = NULL;
178 	}
179 
180 	SNIC_INFO("Trace Facility Disabled.\n");
181 } /* end of snic_trc_free */
182