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