18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2014 Cisco Systems, Inc.  All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This program is free software; you may redistribute it and/or modify
58c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
68c2ecf20Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
98c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
118c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
128c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
148c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
158c2ecf20Sopenharmony_ci * SOFTWARE.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/mempool.h>
208c2ecf20Sopenharmony_ci#include <linux/errno.h>
218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "snic_io.h"
248c2ecf20Sopenharmony_ci#include "snic.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * snic_get_trc_buf : Allocates a trace record and returns.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistruct snic_trc_data *
308c2ecf20Sopenharmony_cisnic_get_trc_buf(void)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct snic_trc *trc = &snic_glob->trc;
338c2ecf20Sopenharmony_ci	struct snic_trc_data *td = NULL;
348c2ecf20Sopenharmony_ci	unsigned long flags;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	spin_lock_irqsave(&trc->lock, flags);
378c2ecf20Sopenharmony_ci	td = &trc->buf[trc->wr_idx];
388c2ecf20Sopenharmony_ci	trc->wr_idx++;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (trc->wr_idx == trc->max_idx)
418c2ecf20Sopenharmony_ci		trc->wr_idx = 0;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (trc->wr_idx != trc->rd_idx) {
448c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&trc->lock, flags);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci		goto end;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	trc->rd_idx++;
508c2ecf20Sopenharmony_ci	if (trc->rd_idx == trc->max_idx)
518c2ecf20Sopenharmony_ci		trc->rd_idx = 0;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	td->ts = 0;	/* Marker for checking the record, for complete data*/
548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&trc->lock, flags);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciend:
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return td;
598c2ecf20Sopenharmony_ci} /* end of snic_get_trc_buf */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * snic_fmt_trc_data : Formats trace data for printing.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistatic int
658c2ecf20Sopenharmony_cisnic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	int len = 0;
688c2ecf20Sopenharmony_ci	struct timespec64 tmspec;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	jiffies_to_timespec64(td->ts, &tmspec);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	len += snprintf(buf, buf_sz,
738c2ecf20Sopenharmony_ci			"%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n",
748c2ecf20Sopenharmony_ci			tmspec.tv_sec,
758c2ecf20Sopenharmony_ci			tmspec.tv_nsec,
768c2ecf20Sopenharmony_ci			td->fn,
778c2ecf20Sopenharmony_ci			td->hno,
788c2ecf20Sopenharmony_ci			td->tag,
798c2ecf20Sopenharmony_ci			td->data[0], td->data[1], td->data[2], td->data[3],
808c2ecf20Sopenharmony_ci			td->data[4]);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return len;
838c2ecf20Sopenharmony_ci} /* end of snic_fmt_trc_data */
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/*
868c2ecf20Sopenharmony_ci * snic_get_trc_data : Returns a formatted trace buffer.
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_ciint
898c2ecf20Sopenharmony_cisnic_get_trc_data(char *buf, int buf_sz)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct snic_trc_data *td = NULL;
928c2ecf20Sopenharmony_ci	struct snic_trc *trc = &snic_glob->trc;
938c2ecf20Sopenharmony_ci	unsigned long flags;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	spin_lock_irqsave(&trc->lock, flags);
968c2ecf20Sopenharmony_ci	if (trc->rd_idx == trc->wr_idx) {
978c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&trc->lock, flags);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		return -1;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	td = &trc->buf[trc->rd_idx];
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (td->ts == 0) {
1048c2ecf20Sopenharmony_ci		/* write in progress. */
1058c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&trc->lock, flags);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci		return -1;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	trc->rd_idx++;
1118c2ecf20Sopenharmony_ci	if (trc->rd_idx == trc->max_idx)
1128c2ecf20Sopenharmony_ci		trc->rd_idx = 0;
1138c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&trc->lock, flags);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return snic_fmt_trc_data(td, buf, buf_sz);
1168c2ecf20Sopenharmony_ci} /* end of snic_get_trc_data */
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/*
1198c2ecf20Sopenharmony_ci * snic_trc_init() : Configures Trace Functionality for snic.
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_ciint
1228c2ecf20Sopenharmony_cisnic_trc_init(void)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct snic_trc *trc = &snic_glob->trc;
1258c2ecf20Sopenharmony_ci	void *tbuf = NULL;
1268c2ecf20Sopenharmony_ci	int tbuf_sz = 0, ret;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	tbuf_sz = (snic_trace_max_pages * PAGE_SIZE);
1298c2ecf20Sopenharmony_ci	tbuf = vzalloc(tbuf_sz);
1308c2ecf20Sopenharmony_ci	if (!tbuf) {
1318c2ecf20Sopenharmony_ci		SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz);
1328c2ecf20Sopenharmony_ci		SNIC_ERR("Trace Facility not enabled.\n");
1338c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		return ret;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	trc->buf = (struct snic_trc_data *) tbuf;
1398c2ecf20Sopenharmony_ci	spin_lock_init(&trc->lock);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	snic_trc_debugfs_init();
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ);
1448c2ecf20Sopenharmony_ci	trc->rd_idx = trc->wr_idx = 0;
1458c2ecf20Sopenharmony_ci	trc->enable = true;
1468c2ecf20Sopenharmony_ci	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n",
1478c2ecf20Sopenharmony_ci		  tbuf_sz / PAGE_SIZE);
1488c2ecf20Sopenharmony_ci	ret = 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return ret;
1518c2ecf20Sopenharmony_ci} /* end of snic_trc_init */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * snic_trc_free : Releases the trace buffer and disables the tracing.
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_civoid
1578c2ecf20Sopenharmony_cisnic_trc_free(void)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct snic_trc *trc = &snic_glob->trc;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	trc->enable = false;
1628c2ecf20Sopenharmony_ci	snic_trc_debugfs_term();
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (trc->buf) {
1658c2ecf20Sopenharmony_ci		vfree(trc->buf);
1668c2ecf20Sopenharmony_ci		trc->buf = NULL;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	SNIC_INFO("Trace Facility Disabled.\n");
1708c2ecf20Sopenharmony_ci} /* end of snic_trc_free */
171