| // SPDX-License-Identifier: GPL-2.0-only | 
 | // Copyright 2014 Cisco Systems, Inc.  All rights reserved. | 
 |  | 
 | #include <linux/module.h> | 
 | #include <linux/mempool.h> | 
 | #include <linux/errno.h> | 
 | #include <linux/vmalloc.h> | 
 |  | 
 | #include "snic_io.h" | 
 | #include "snic.h" | 
 |  | 
 | /* | 
 |  * snic_get_trc_buf : Allocates a trace record and returns. | 
 |  */ | 
 | struct snic_trc_data * | 
 | snic_get_trc_buf(void) | 
 | { | 
 | 	struct snic_trc *trc = &snic_glob->trc; | 
 | 	struct snic_trc_data *td = NULL; | 
 | 	unsigned long flags; | 
 |  | 
 | 	spin_lock_irqsave(&trc->lock, flags); | 
 | 	td = &trc->buf[trc->wr_idx]; | 
 | 	trc->wr_idx++; | 
 |  | 
 | 	if (trc->wr_idx == trc->max_idx) | 
 | 		trc->wr_idx = 0; | 
 |  | 
 | 	if (trc->wr_idx != trc->rd_idx) { | 
 | 		spin_unlock_irqrestore(&trc->lock, flags); | 
 |  | 
 | 		goto end; | 
 | 	} | 
 |  | 
 | 	trc->rd_idx++; | 
 | 	if (trc->rd_idx == trc->max_idx) | 
 | 		trc->rd_idx = 0; | 
 |  | 
 | 	td->ts = 0;	/* Marker for checking the record, for complete data*/ | 
 | 	spin_unlock_irqrestore(&trc->lock, flags); | 
 |  | 
 | end: | 
 |  | 
 | 	return td; | 
 | } /* end of snic_get_trc_buf */ | 
 |  | 
 | /* | 
 |  * snic_fmt_trc_data : Formats trace data for printing. | 
 |  */ | 
 | static int | 
 | snic_fmt_trc_data(struct snic_trc_data *td, char *buf, int buf_sz) | 
 | { | 
 | 	int len = 0; | 
 | 	struct timespec64 tmspec; | 
 |  | 
 | 	jiffies_to_timespec64(td->ts, &tmspec); | 
 |  | 
 | 	len += snprintf(buf, buf_sz, | 
 | 			"%llu.%09lu %-25s %3d %4x %16llx %16llx %16llx %16llx %16llx\n", | 
 | 			tmspec.tv_sec, | 
 | 			tmspec.tv_nsec, | 
 | 			td->fn, | 
 | 			td->hno, | 
 | 			td->tag, | 
 | 			td->data[0], td->data[1], td->data[2], td->data[3], | 
 | 			td->data[4]); | 
 |  | 
 | 	return len; | 
 | } /* end of snic_fmt_trc_data */ | 
 |  | 
 | /* | 
 |  * snic_get_trc_data : Returns a formatted trace buffer. | 
 |  */ | 
 | int | 
 | snic_get_trc_data(char *buf, int buf_sz) | 
 | { | 
 | 	struct snic_trc_data *td = NULL; | 
 | 	struct snic_trc *trc = &snic_glob->trc; | 
 | 	unsigned long flags; | 
 |  | 
 | 	spin_lock_irqsave(&trc->lock, flags); | 
 | 	if (trc->rd_idx == trc->wr_idx) { | 
 | 		spin_unlock_irqrestore(&trc->lock, flags); | 
 |  | 
 | 		return -1; | 
 | 	} | 
 | 	td = &trc->buf[trc->rd_idx]; | 
 |  | 
 | 	if (td->ts == 0) { | 
 | 		/* write in progress. */ | 
 | 		spin_unlock_irqrestore(&trc->lock, flags); | 
 |  | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	trc->rd_idx++; | 
 | 	if (trc->rd_idx == trc->max_idx) | 
 | 		trc->rd_idx = 0; | 
 | 	spin_unlock_irqrestore(&trc->lock, flags); | 
 |  | 
 | 	return snic_fmt_trc_data(td, buf, buf_sz); | 
 | } /* end of snic_get_trc_data */ | 
 |  | 
 | /* | 
 |  * snic_trc_init() : Configures Trace Functionality for snic. | 
 |  */ | 
 | int | 
 | snic_trc_init(void) | 
 | { | 
 | 	struct snic_trc *trc = &snic_glob->trc; | 
 | 	void *tbuf = NULL; | 
 | 	int tbuf_sz = 0, ret; | 
 |  | 
 | 	tbuf_sz = (snic_trace_max_pages * PAGE_SIZE); | 
 | 	tbuf = vzalloc(tbuf_sz); | 
 | 	if (!tbuf) { | 
 | 		SNIC_ERR("Failed to Allocate Trace Buffer Size. %d\n", tbuf_sz); | 
 | 		SNIC_ERR("Trace Facility not enabled.\n"); | 
 | 		ret = -ENOMEM; | 
 |  | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	trc->buf = (struct snic_trc_data *) tbuf; | 
 | 	spin_lock_init(&trc->lock); | 
 |  | 
 | 	snic_trc_debugfs_init(); | 
 |  | 
 | 	trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ); | 
 | 	trc->rd_idx = trc->wr_idx = 0; | 
 | 	trc->enable = true; | 
 | 	SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n", | 
 | 		  tbuf_sz / PAGE_SIZE); | 
 | 	ret = 0; | 
 |  | 
 | 	return ret; | 
 | } /* end of snic_trc_init */ | 
 |  | 
 | /* | 
 |  * snic_trc_free : Releases the trace buffer and disables the tracing. | 
 |  */ | 
 | void | 
 | snic_trc_free(void) | 
 | { | 
 | 	struct snic_trc *trc = &snic_glob->trc; | 
 |  | 
 | 	trc->enable = false; | 
 | 	snic_trc_debugfs_term(); | 
 |  | 
 | 	if (trc->buf) { | 
 | 		vfree(trc->buf); | 
 | 		trc->buf = NULL; | 
 | 	} | 
 |  | 
 | 	SNIC_INFO("Trace Facility Disabled.\n"); | 
 | } /* end of snic_trc_free */ |