linux-old/arch/cris/kernel/debug.c
<<
>>
Prefs
   1/*
   2 * arch/cris/kernel/debug.c
   3 * Various debug routines:
   4 * o Logging of interrupt enabling/disabling. /proc/debug_interrupt
   5 *   gives result and enables logging when read.
   6 *
   7 * Copyright (C) 2003 Axis Communications AB
   8 */
   9
  10#include <linux/config.h>
  11#include <asm/system.h>
  12#include <linux/init.h>
  13#include <linux/proc_fs.h>
  14#include <asm/svinto.h>
  15
  16#ifdef CONFIG_ETRAX_DEBUG_INTERRUPT
  17#define LOG_INT_SIZE 8192
  18#define DEBUG_INT_PROC_FILE "debug_interrupt"
  19#define LOG_INT_SHOW_MIN_USEC 45000
  20
  21/* These are global and can be used to trig certain events. */
  22int log_int_pos = 0;
  23int log_int_size = LOG_INT_SIZE;
  24int log_int_trig0_pos = 0;
  25int log_int_trig1_pos = 0;
  26
  27int log_int_enable = 0; /* Enabled every read of /proc/debug_interrupt */
  28
  29struct log_int_struct 
  30{
  31  unsigned long pc;
  32  unsigned long ev_timer_data;
  33};
  34
  35static struct log_int_struct log_ints[LOG_INT_SIZE];
  36
  37//static unsigned long prev_log_int_t = 0;
  38static unsigned long prev_logged_ccr = 0;
  39static unsigned long prev_ei_timer_data = 0;
  40static unsigned long prev_di_timer_data = 0;
  41
  42#define CCR_EI_BIT 5
  43enum {
  44        INT_OLD_MASK = 0x01, INT_OLD_BIT = 0,
  45        INT_NEW_MASK = 0x02, INT_NEW_BIT = 1,
  46        INT_EI_CHANGE_MASK = 0x04, INT_EI_CHANGE_BIT = 2,
  47        INT_ACTION_RESTORE = 0x08, INT_ACTION_RESTORE_BIT = 3,
  48        INT_ACTION_MISSED = 0x10, INT_ACTION_MISSED_BIT = 4,
  49        INT_ACTION_LONG = 0x20,  INT_ACTION_LONG_BIT = 5,
  50
  51        INT_OLD_EI = INT_OLD_MASK, INT_OLD_EI_BIT = INT_OLD_BIT,
  52        INT_NEW_EI = INT_NEW_MASK, INT_NEW_EI_BIT = INT_NEW_BIT,
  53        INT_EV_DI = INT_OLD_EI | INT_EI_CHANGE_MASK,
  54        INT_EV_NOP_DI = 0,
  55        INT_EV_EI = INT_NEW_EI | INT_EI_CHANGE_MASK,
  56        INT_EV_NOP_EI = INT_OLD_EI | INT_NEW_EI, 
  57        INT_EV_RESTORE_DI= INT_EV_DI | INT_EI_CHANGE_MASK | INT_ACTION_RESTORE,
  58        INT_EV_RESTORE_EI= INT_EV_EI | INT_EI_CHANGE_MASK | INT_ACTION_RESTORE,
  59        INT_EV_RESTORE_NOP_DI = INT_EV_NOP_DI | INT_ACTION_RESTORE,
  60        INT_EV_RESTORE_NOP_EI = INT_EV_NOP_EI | INT_ACTION_RESTORE,
  61};
  62
  63void log_int(unsigned long pc, unsigned long curr_ccr, unsigned long next_ccr)
  64{
  65        unsigned long t;
  66        int ev;
  67        static int no_change_cnt = 0;
  68        
  69        /* Just disable interrupts without logging here,
  70         * the caller will either do ei, di or restore
  71         */
  72        __asm__ __volatile__ ("di" : : :"memory");
  73        t = *R_TIMER_DATA;
  74
  75        if (curr_ccr & CCR_EI_MASK) {
  76                prev_ei_timer_data = t;         
  77                ev = INT_OLD_EI;
  78        } else {
  79                prev_di_timer_data = t;
  80                if ( (((prev_ei_timer_data >> 8) & 0x000000FF) -
  81                      ((prev_di_timer_data >> 8) & 0x000000FF)) & ~0x03)
  82                                            ev = INT_ACTION_LONG;
  83                else
  84                        ev = 0;
  85        }
  86        if ((curr_ccr ^ prev_logged_ccr) & CCR_EI_MASK)
  87                ev |= INT_ACTION_MISSED;
  88        if (next_ccr & CCR_EI_MASK)
  89                ev |= INT_NEW_EI;
  90        if ((curr_ccr ^ next_ccr) & CCR_EI_MASK) {
  91                ev |= INT_EI_CHANGE_MASK;
  92                no_change_cnt = 0;
  93        } else
  94                no_change_cnt++;
  95
  96        prev_logged_ccr = next_ccr;
  97        
  98        if (log_int_enable &&
  99            ((ev & (INT_EI_CHANGE_MASK | INT_ACTION_MISSED | INT_ACTION_LONG))
 100             || (no_change_cnt < 40)) &&
 101            log_int_pos < LOG_INT_SIZE) {
 102                int i;
 103                i = log_int_pos;
 104                log_int_pos++;
 105                log_ints[i].pc = pc;
 106                log_ints[i].ev_timer_data = (t & 0x00FFFFFF) |
 107                        ((ev & 0xFF) << 24);
 108
 109        }
 110//      __asm__ __volatile__ ("move %0,$ccr" : : "rm" (curr_ccr) : "memory");
 111}
 112void log_int_di(void)
 113{
 114  unsigned long pc;
 115  unsigned long flags;
 116  __asm__ __volatile__ ("move $srp,%0" : "=rm" (pc) : : "memory");
 117  __asm__ __volatile__ ("move $ccr,%0" : "=rm" (flags) : : "memory");
 118  log_int(pc, flags, 0);
 119}
 120
 121void log_int_ei(void)
 122{
 123  unsigned long pc;
 124  unsigned long flags;
 125  __asm__ __volatile__ ("move $srp,%0" : "=rm" (pc) : : "memory");
 126  __asm__ __volatile__ ("move $ccr,%0" : "=rm" (flags) : : "memory");
 127  log_int(pc, flags, CCR_EI_MASK);
 128}
 129
 130
 131static int log_int_read_proc(char *page, char **start, off_t off, int count,
 132                             int *eof, void *data)
 133{
 134        int i, len = 0;
 135        off_t   begin = 0;      
 136        int j, t0, t1, t, thigh, tlow, tdi0;
 137        int di0, ei1;
 138        len += sprintf(page + len, "trig0: %i trig1: %i\n", log_int_trig0_pos, log_int_trig1_pos);
 139        for (i = 0; i < log_int_pos-1; i++) {
 140
 141                if (((log_ints[i].ev_timer_data >> 24) & INT_NEW_EI)) {
 142                        di0 = i;
 143                        while (di0 < log_int_pos-1 && (((log_ints[di0].ev_timer_data >> 24) & INT_NEW_EI)))
 144                                di0++;
 145                        ei1 = di0+1;
 146                        while (ei1 < log_int_pos-1 && (((log_ints[ei1].ev_timer_data >> 24) & INT_NEW_EI) == 0))
 147                                ei1++;
 148                        thigh = timer_data_to_ns(log_ints[ei1].ev_timer_data);
 149                        tlow = timer_data_to_ns(log_ints[di0].ev_timer_data);
 150                        tdi0 = timer_data_to_ns(log_ints[di0].ev_timer_data);
 151                        
 152                        t = thigh-tlow;
 153                        j = di0-1;              
 154                        if ((t > LOG_INT_SHOW_MIN_USEC) || (log_int_trig0_pos-30 < j && j < log_int_trig1_pos+30)) {
 155
 156                        for (; j <= ei1; j++) {
 157                                t0 = ((log_ints[j+1].ev_timer_data & 0xFF) -
 158                                      (log_ints[j].ev_timer_data & 0xFF));
 159                                t1 = (((log_ints[j+1].ev_timer_data >> 8) & 0xFF) -
 160                                      ((log_ints[j].ev_timer_data >> 8) & 0xFF));
 161                                if (t1 == 0 || t1 == 1) {
 162                                        if (t0 < 0)
 163                                                t0 += 256;
 164                                } else {
 165                                        if (t1 < 0)
 166                                                t1 += 256;
 167                                }
 168                                thigh = timer_data_to_ns(log_ints[j+1].ev_timer_data);
 169                                tlow = timer_data_to_ns(log_ints[j].ev_timer_data);
 170                                t = thigh-tlow;
 171                                len += sprintf(page + len, "%4i PC %08lX-%08lX %08lX-%08lX %s high %i in %-6i ns %-7i to %-7i = %-5i ns, from first di %i ns %s\n",
 172                                               j, log_ints[j].pc, log_ints[j+1].pc,
 173                                               log_ints[j].ev_timer_data, log_ints[j+1].ev_timer_data,
 174                                               ((log_ints[j].ev_timer_data >> 24) & INT_NEW_EI)!= 0?"ei":"di", t1, t,
 175                                               tlow, thigh, thigh-tlow, thigh-tdi0,
 176                                               j==log_int_trig0_pos?"TRIG0":(j==log_int_trig1_pos?"TRIG1":""));
 177                                if (len+begin > off+count)
 178                                        goto done;
 179                                if (len+begin < off) {
 180                                        begin += len;
 181                                        len = 0;
 182                                }
 183                        }
 184                        
 185                        len += sprintf(page + len,"\n");
 186                        i = ei1-2;
 187                        }
 188                        
 189                }
 190        
 191        }
 192        log_int_enable = 1;
 193        log_int_pos = 0;
 194        log_int_trig0_pos = 0;
 195        log_int_trig1_pos = 0;
 196        *eof = 1;
 197done:
 198        if (off >= len+begin)
 199                return 0;
 200        *start = page + (off-begin);
 201        return ((count < begin+len-off) ? count : begin+len-off);       
 202}
 203
 204static int __init
 205log_int_init(void)
 206{
 207        create_proc_read_entry (DEBUG_INT_PROC_FILE, 0, 0, log_int_read_proc, NULL);
 208        printk(KERN_INFO "/proc/" DEBUG_INT_PROC_FILE " size %i.\r\n",
 209               LOG_INT_SIZE);
 210        return 0;
 211}
 212module_init(log_int_init);
 213#endif /* CONFIG_ETRAX_DEBUG_INTERRUPT */
 214
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.