Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdsp5/evlog.h b/arch/arm/mach-msm/qdsp5/evlog.h
new file mode 100644
index 0000000..1f0f16b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp5/evlog.h
@@ -0,0 +1,125 @@
+/* arch/arm/mach-msm/qdsp5/evlog.h
+ *
+ * simple event log debugging facility
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/hrtimer.h>
+#include <linux/debugfs.h>
+
+#define EV_LOG_ENTRY_NAME(n) n##_entry
+
+#define DECLARE_LOG(_name, _size, _str) \
+static struct ev_entry EV_LOG_ENTRY_NAME(_name)[_size]; \
+static struct ev_log _name = { \
+	.name = #_name, \
+	.strings = _str, \
+	.num_strings = ARRAY_SIZE(_str), \
+	.entry = EV_LOG_ENTRY_NAME(_name), \
+	.max = ARRAY_SIZE(EV_LOG_ENTRY_NAME(_name)), \
+}
+
+struct ev_entry {
+	struct timespec when;
+	uint32_t id;
+	uint32_t arg;
+};
+	
+struct ev_log {
+	struct ev_entry *entry;
+	unsigned max;
+	unsigned next;
+	unsigned fault;
+	const char **strings;
+	unsigned num_strings;
+	const char *name;
+};
+
+static char ev_buf[4096];
+
+static ssize_t ev_log_read(struct file *file, char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct ev_log *log = file->private_data;
+	struct ev_entry *entry;
+	unsigned long flags;
+	int size = 0;
+	unsigned n, id, max;
+	struct timespec now, t;
+	
+	max = log->max;
+	getnstimeofday(&now);
+	local_irq_save(flags);
+	n = (log->next - 1) & (max - 1);
+	entry = log->entry;
+	while (n != log->next) {
+		t = timespec_sub(now, entry[n].when);
+		id = entry[n].id;
+		if (id) {
+			const char *str;
+			if (id < log->num_strings)
+				str = log->strings[id];
+			else
+				str = "UNKNOWN";
+			size += scnprintf(ev_buf + size, 4096 - size,
+					  "%lu.%03lu %08x %s\n",
+					  t.tv_sec, t.tv_nsec / 1000000,
+					  entry[n].arg, str);
+		}
+		n = (n - 1) & (max - 1);
+	}
+	log->fault = 0;
+	local_irq_restore(flags);
+	return simple_read_from_buffer(buf, count, ppos, ev_buf, size);
+}
+
+static void ev_log_write(struct ev_log *log, unsigned id, unsigned arg)
+{
+	struct ev_entry *entry;
+	unsigned long flags;
+	local_irq_save(flags);
+
+	if (log->fault) {
+		if (log->fault == 1)
+			goto done;
+		log->fault--;
+	}
+
+	entry = log->entry + log->next;
+	getnstimeofday(&entry->when);
+	entry->id = id;
+	entry->arg = arg;
+	log->next = (log->next + 1) & (log->max - 1);
+done:
+	local_irq_restore(flags);
+}
+
+static int ev_log_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations ev_log_ops = {
+	.read = ev_log_read,
+	.open = ev_log_open,
+};
+
+static int ev_log_init(struct ev_log *log)
+{
+	debugfs_create_file(log->name, 0444, 0, log, &ev_log_ops);
+	return 0;
+}
+