1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright 2014 Cisco Systems, Inc.  All rights reserved.
3
4#include <linux/module.h>
5#include <linux/mempool.h>
6#include <linux/errno.h>
7#include <linux/vmalloc.h>
8
9#include "snic_io.h"
10#include "snic.h"
11
12/*
13 * snic_get_trc_buf : Allocates a trace record and returns.
14 */
15struct snic_trc_data *
16snic_get_trc_buf(void)
17{
18	struct snic_trc *trc = &snic_glob->trc;
19	struct snic_trc_data *td = NULL;
20	unsigned long flags;
21
22	spin_lock_irqsave(&trc->lock, flags);
23	td = &trc->buf[trc->wr_idx];
24	trc->wr_idx++;
25
26	if (trc->wr_idx == trc->max_idx)
27		trc->wr_idx = 0;
28
29	if (trc->wr_idx != trc->rd_idx) {
30		spin_unlock_irqrestore(&trc->lock, flags);
31
32		goto end;
33	}
34
35	trc->rd_idx++;
36	if (trc->rd_idx == trc->max_idx)
37		trc->rd_idx = 0;
38
39	td->ts = 0;	/* Marker for checking the record, for complete data*/
40	spin_unlock_irqrestore(&trc->lock, flags);
41
42end:
43
44	return td;
45} /* end of snic_get_trc_buf */
46
47/*
48 * snic_fmt_trc_data : Formats trace data for printing.
49 */
50static int
51snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz)
52{
53	int len = 0;
54	struct timespec64 tmspec;
55
56	jiffies_to_timespec64(td->ts, &tmspec);
57
58	len += snprintf(buf, buf_sz,
59			"%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n",
60			tmspec.tv_sec,
61			tmspec.tv_nsec,
62			td->fn,
63			td->hno,
64			td->tag,
65			td->data[0], td->data[1], td->data[2], td->data[3],
66			td->data[4]);
67
68	return len;
69} /* end of snic_fmt_trc_data */
70
71/*
72 * snic_get_trc_data : Returns a formatted trace buffer.
73 */
74int
75snic_get_trc_data(char *buf, int buf_sz)
76{
77	struct snic_trc_data *td = NULL;
78	struct snic_trc *trc = &snic_glob->trc;
79	unsigned long flags;
80
81	spin_lock_irqsave(&trc->lock, flags);
82	if (trc->rd_idx == trc->wr_idx) {
83		spin_unlock_irqrestore(&trc->lock, flags);
84
85		return -1;
86	}
87	td = &trc->buf[trc->rd_idx];
88
89	if (td->ts == 0) {
90		/* write in progress. */
91		spin_unlock_irqrestore(&trc->lock, flags);
92
93		return -1;
94	}
95
96	trc->rd_idx++;
97	if (trc->rd_idx == trc->max_idx)
98		trc->rd_idx = 0;
99	spin_unlock_irqrestore(&trc->lock, flags);
100
101	return snic_fmt_trc_data(td, buf, buf_sz);
102} /* end of snic_get_trc_data */
103
104/*
105 * snic_trc_init() : Configures Trace Functionality for snic.
106 */
107int
108snic_trc_init(void)
109{
110	struct snic_trc *trc = &snic_glob->trc;
111	void *tbuf = NULL;
112	int tbuf_sz = 0, ret;
113
114	tbuf_sz = (snic_trace_max_pages * PAGE_SIZE);
115	tbuf = vzalloc(tbuf_sz);
116	if (!tbuf) {
117		SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz);
118		SNIC_ERR("Trace Facility not enabled.\n");
119		ret = -ENOMEM;
120
121		return ret;
122	}
123
124	trc->buf = (struct snic_trc_data *) tbuf;
125	spin_lock_init(&trc->lock);
126
127	snic_trc_debugfs_init();
128
129	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ);
130	trc->rd_idx = trc->wr_idx = 0;
131	trc->enable = true;
132	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n",
133		  tbuf_sz / PAGE_SIZE);
134	ret = 0;
135
136	return ret;
137} /* end of snic_trc_init */
138
139/*
140 * snic_trc_free : Releases the trace buffer and disables the tracing.
141 */
142void
143snic_trc_free(void)
144{
145	struct snic_trc *trc = &snic_glob->trc;
146
147	trc->enable = false;
148	snic_trc_debugfs_term();
149
150	if (trc->buf) {
151		vfree(trc->buf);
152		trc->buf = NULL;
153	}
154
155	SNIC_INFO("Trace Facility Disabled.\n");
156} /* end of snic_trc_free */
157