1 /* -----------------------------------------------------------------------------
2  * Copyright (c) 2011 Ozmo Inc
3  * Released under the GNU General Public License Version 2 (GPLv2).
4  * -----------------------------------------------------------------------------
5  */
6 #include "ozconfig.h"
7 #ifdef WANT_EVENT_TRACE
8 #include <linux/jiffies.h>
9 #include <linux/uaccess.h>
10 #include "oztrace.h"
11 #include "ozevent.h"
12 /*------------------------------------------------------------------------------
13  */
14 unsigned long g_evt_mask = 0xffffffff;
15 /*------------------------------------------------------------------------------
16  */
17 #define OZ_MAX_EVTS	2048	/* Must be power of 2 */
18 DEFINE_SPINLOCK(g_eventlock);
19 static int g_evt_in;
20 static int g_evt_out;
21 static int g_missed_events;
22 static struct oz_event g_events[OZ_MAX_EVTS];
23 /*------------------------------------------------------------------------------
24  * Context: process
25  */
oz_event_init(void)26 void oz_event_init(void)
27 {
28 	oz_trace("Event tracing initialized\n");
29 	g_evt_in = g_evt_out = 0;
30 	g_missed_events = 0;
31 }
32 /*------------------------------------------------------------------------------
33  * Context: process
34  */
oz_event_term(void)35 void oz_event_term(void)
36 {
37 	oz_trace("Event tracing terminated\n");
38 }
39 /*------------------------------------------------------------------------------
40  * Context: any
41  */
oz_event_log2(u8 evt,u8 ctx1,u16 ctx2,void * ctx3,unsigned ctx4)42 void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
43 {
44 	unsigned long irqstate;
45 	int ix;
46 	spin_lock_irqsave(&g_eventlock, irqstate);
47 	ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
48 	if (ix != g_evt_out) {
49 		struct oz_event *e = &g_events[g_evt_in];
50 		e->jiffies = jiffies;
51 		e->evt = evt;
52 		e->ctx1 = ctx1;
53 		e->ctx2 = ctx2;
54 		e->ctx3 = ctx3;
55 		e->ctx4 = ctx4;
56 		g_evt_in = ix;
57 	} else {
58 		g_missed_events++;
59 	}
60 	spin_unlock_irqrestore(&g_eventlock, irqstate);
61 }
62 /*------------------------------------------------------------------------------
63  * Context: process
64  */
oz_events_copy(struct oz_evtlist __user * lst)65 int oz_events_copy(struct oz_evtlist __user *lst)
66 {
67 	int first;
68 	int ix;
69 	struct hdr {
70 		int count;
71 		int missed;
72 	} hdr;
73 	ix = g_evt_out;
74 	hdr.count = g_evt_in - ix;
75 	if (hdr.count < 0)
76 		hdr.count += OZ_MAX_EVTS;
77 	if (hdr.count > OZ_EVT_LIST_SZ)
78 		hdr.count = OZ_EVT_LIST_SZ;
79 	hdr.missed = g_missed_events;
80 	g_missed_events = 0;
81 	if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
82 		return -EFAULT;
83 	first = OZ_MAX_EVTS - ix;
84 	if (first > hdr.count)
85 		first = hdr.count;
86 	if (first) {
87 		int sz = first*sizeof(struct oz_event);
88 		void __user *p = (void __user *)lst->evts;
89 		if (copy_to_user(p, &g_events[ix], sz))
90 			return -EFAULT;
91 		if (hdr.count > first) {
92 			p = (void __user *)&lst->evts[first];
93 			sz = (hdr.count-first)*sizeof(struct oz_event);
94 			if (copy_to_user(p, g_events, sz))
95 				return -EFAULT;
96 		}
97 	}
98 	ix += hdr.count;
99 	if (ix >= OZ_MAX_EVTS)
100 		ix -= OZ_MAX_EVTS;
101 	g_evt_out = ix;
102 	return 0;
103 }
104 /*------------------------------------------------------------------------------
105  * Context: process
106  */
oz_events_clear(void)107 void oz_events_clear(void)
108 {
109 	unsigned long irqstate;
110 	spin_lock_irqsave(&g_eventlock, irqstate);
111 	g_evt_in = g_evt_out = 0;
112 	g_missed_events = 0;
113 	spin_unlock_irqrestore(&g_eventlock, irqstate);
114 }
115 #endif /* WANT_EVENT_TRACE */
116 
117