/* ----------------------------------------------------------------------------- * Copyright (c) 2011 Ozmo Inc * Released under the GNU General Public License Version 2 (GPLv2). * ----------------------------------------------------------------------------- */ #include "ozconfig.h" #ifdef WANT_EVENT_TRACE #include #include #include "oztrace.h" #include "ozevent.h" /*------------------------------------------------------------------------------ */ unsigned long g_evt_mask = 0xffffffff; /*------------------------------------------------------------------------------ */ #define OZ_MAX_EVTS 2048 /* Must be power of 2 */ DEFINE_SPINLOCK(g_eventlock); static int g_evt_in; static int g_evt_out; static int g_missed_events; static struct oz_event g_events[OZ_MAX_EVTS]; /*------------------------------------------------------------------------------ * Context: process */ void oz_event_init(void) { oz_trace("Event tracing initialized\n"); g_evt_in = g_evt_out = 0; g_missed_events = 0; } /*------------------------------------------------------------------------------ * Context: process */ void oz_event_term(void) { oz_trace("Event tracing terminated\n"); } /*------------------------------------------------------------------------------ * Context: any */ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4) { unsigned long irqstate; int ix; spin_lock_irqsave(&g_eventlock, irqstate); ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1); if (ix != g_evt_out) { struct oz_event *e = &g_events[g_evt_in]; e->jiffies = jiffies; e->evt = evt; e->ctx1 = ctx1; e->ctx2 = ctx2; e->ctx3 = ctx3; e->ctx4 = ctx4; g_evt_in = ix; } else { g_missed_events++; } spin_unlock_irqrestore(&g_eventlock, irqstate); } /*------------------------------------------------------------------------------ * Context: process */ int oz_events_copy(struct oz_evtlist __user *lst) { int first; int ix; struct hdr { int count; int missed; } hdr; ix = g_evt_out; hdr.count = g_evt_in - ix; if (hdr.count < 0) hdr.count += OZ_MAX_EVTS; if (hdr.count > OZ_EVT_LIST_SZ) hdr.count = OZ_EVT_LIST_SZ; hdr.missed = g_missed_events; g_missed_events = 0; if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr))) return -EFAULT; first = OZ_MAX_EVTS - ix; if (first > hdr.count) first = hdr.count; if (first) { int sz = first*sizeof(struct oz_event); void __user *p = (void __user *)lst->evts; if (copy_to_user(p, &g_events[ix], sz)) return -EFAULT; if (hdr.count > first) { p = (void __user *)&lst->evts[first]; sz = (hdr.count-first)*sizeof(struct oz_event); if (copy_to_user(p, g_events, sz)) return -EFAULT; } } ix += hdr.count; if (ix >= OZ_MAX_EVTS) ix -= OZ_MAX_EVTS; g_evt_out = ix; return 0; } /*------------------------------------------------------------------------------ * Context: process */ void oz_events_clear(void) { unsigned long irqstate; spin_lock_irqsave(&g_eventlock, irqstate); g_evt_in = g_evt_out = 0; g_missed_events = 0; spin_unlock_irqrestore(&g_eventlock, irqstate); } #endif /* WANT_EVENT_TRACE */