--- zzzz-none-000/linux-2.6.13.1/arch/mips/mips-boards/generic/time.c 2005-09-10 02:42:58.000000000 +0000 +++ ohio-7170-487/linux-2.6.13.1/arch/mips/mips-boards/generic/time.c 2007-10-26 16:53:33.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,10 +39,25 @@ #include #include +#if defined(CONFIG_MIPS_OHIO) +#include +#include +#include +#elif defined(CONFIG_MIPS_AR7) +#include +#include +#include +#elif defined(CONFIG_MIPS_UR8) +#include +#include +#include +#else +#error unknown CONFIG_MIPS_... +#endif /*--- #if defined(CONFIG_MIPS_UR8) ---*/ unsigned long cpu_khz; -#if defined(CONFIG_MIPS_SEAD) +#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_UR8) #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5) #else #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) @@ -56,6 +72,15 @@ #if defined(CONFIG_MIPS_SEAD) static char display_string[] = " LINUX ON SEAD "; #endif +#if defined(CONFIG_MIPS_OHIO) +static char display_string[] = " LINUX ON OHIO "; +#endif +#if defined(CONFIG_MIPS_AR7) +static char display_string[] = " LINUX ON AR7 "; +#endif +#if defined(CONFIG_MIPS_UR8) +static char display_string[] = " LINUX ON UR8 "; +#endif static unsigned int display_count = 0; #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) @@ -63,15 +88,261 @@ static unsigned int timer_tick_count=0; +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +#if defined(CONFIG_AVM_SIMPLE_PROFILING) +#include +#include + +#define PROFILE_BUFFER_LEN (CONFIG_AVM_PROFILING_TRACE_MODE * 1024) + +struct _simple_profiling { + struct _avm_profile_data data[PROFILE_BUFFER_LEN]; + atomic_t pos; + unsigned int len; + unsigned int enabled; + unsigned long start_time; + unsigned long end_time; +} simple_profiling; +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +/*--- #define REALTIME_LOG ---*/ +#if defined(REALTIME_LOG) +#define TIME_DIFF(act, old) ((old) > (act)) ? ((0xFFFFFFFFUL - (old)) + (act)) : ((act) - (old)) +#define CLK_TO_USEC(a) ((a) / 211 / 2) /*--- 212 MHz CPU-Takt ---*/ + +/*--------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------*/ +static void real_timelog(unsigned int time, enum _avm_profile_data_type type, unsigned int addr, unsigned int id) { + static struct _actvalue { + unsigned int peak; + unsigned int id; + unsigned int time; + unsigned int addr; + } actlist[avm_profile_data_type_unknown]; + unsigned int timediff; + + switch(type) { + case avm_profile_data_type_hw_irq_begin: + case avm_profile_data_type_timer_begin: + case avm_profile_data_type_tasklet_begin: + case avm_profile_data_type_hi_tasklet_begin: + case avm_profile_data_type_sw_irq_begin: + case avm_profile_data_type_func_begin: + actlist[type].addr = addr; + actlist[type].id = id; + actlist[type].time = time; + break; + case avm_profile_data_type_hw_irq_end: + case avm_profile_data_type_sw_irq_end: + case avm_profile_data_type_timer_end: + case avm_profile_data_type_tasklet_end: + case avm_profile_data_type_hi_tasklet_end: + case avm_profile_data_type_func_end: + type--; + if(actlist[type].addr == addr) { + timediff = TIME_DIFF(time, actlist[type].time); + if((timediff > actlist[type].peak) || (CLK_TO_USEC(timediff) > 2000)) { + actlist[type].peak = timediff; + printk("PEAK: %s addr=%08x id=%08x(%08x) %d usec\n", + type == avm_profile_data_type_hw_irq_begin ? "hw_irq" : + type == avm_profile_data_type_timer_begin ? "timer" : + type == avm_profile_data_type_tasklet_begin ? "tasklet" : + type == avm_profile_data_type_hi_tasklet_begin ? "hi_tasklet" : + type == avm_profile_data_type_sw_irq_begin ? "sw_irq" : + type == avm_profile_data_type_func_begin ? "func" : "?", + addr, id, actlist[type].id, CLK_TO_USEC(timediff)); + } + } + break; + default: + break; + } +} +#endif/*--- #if defined(REALTIME_LOG) ---*/ +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +unsigned int avm_simple_profiling(struct pt_regs *regs, unsigned int irq_num) { + unsigned int pos, epc, time; + if(simple_profiling.enabled == 0) return 0; +#if defined(CONFIG_ARM) + epc = regs->ARM_pc; +#endif /*--- #if defined(CONFIG_ARM) ---*/ +#if defined(CONFIG_MIPS) + epc = regs->cp0_epc; +#endif /*--- #if defined(CONFIG_MIPS) ---*/ + + time = avm_profile_counter(); + pos = atomic_inc_return(&(simple_profiling.pos)) - 1; + if(pos >= simple_profiling.len - 1) { + simple_profiling.enabled = 0; + simple_profiling.end_time = jiffies | 1; + printk("[simple_profiling] buffer full: %u entries recorded\n", simple_profiling.len); + } + simple_profiling.data[pos].type = avm_profile_data_type_code_address_info; + simple_profiling.data[pos].curr = current; + simple_profiling.data[pos].id = irq_num; + simple_profiling.data[pos].addr = epc; + simple_profiling.data[pos].time = time; + simple_profiling.data[pos].total_access = avm_profile_sdramacess(); + simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); + return time; +} +EXPORT_SYMBOL(avm_simple_profiling); + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +void avm_simple_profiling_log(enum _avm_profile_data_type type, unsigned int addr, unsigned int id) { + unsigned int pos, time; + struct sk_buff *skb; +#if defined(REALTIME_LOG) + real_timelog(avm_profile_counter(), type, addr, id); +#endif/*--- #if defined(REALTIME_LOG) ---*/ + if(simple_profiling.enabled == 0) return; + + time = avm_profile_counter(); + pos = atomic_inc_return(&(simple_profiling.pos)) - 1; + if(pos >= simple_profiling.len - 1) { + simple_profiling.enabled = 0; + simple_profiling.end_time = jiffies | 1; + printk("[simple_profiling] buffer full: %u entries recorded\n", simple_profiling.len); + } + switch(type) { + default: + case avm_profile_data_type_free: + case avm_profile_data_type_unknown: + break; + + case avm_profile_data_type_text: + case avm_profile_data_type_code_address_info: + case avm_profile_data_type_data_address_info: + simple_profiling.data[pos].type = type; + simple_profiling.data[pos].addr = addr; + simple_profiling.data[pos].time = time; + simple_profiling.data[pos].total_access = avm_profile_sdramacess(); + simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); + break; + + case avm_profile_data_type_trace_skb: + skb = (struct sk_buff *)addr; + simple_profiling.data[pos].type = type; + simple_profiling.data[pos].id = id; + simple_profiling.data[pos].addr = skb->uniq_id; + simple_profiling.data[pos].time = time; + simple_profiling.data[pos].total_access = avm_profile_sdramacess(); + simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); + break; + + case avm_profile_data_type_hw_irq_begin: + case avm_profile_data_type_hw_irq_end: + case avm_profile_data_type_sw_irq_begin: + case avm_profile_data_type_sw_irq_end: + case avm_profile_data_type_timer_begin: + case avm_profile_data_type_timer_end: + case avm_profile_data_type_tasklet_begin: + case avm_profile_data_type_tasklet_end: + case avm_profile_data_type_hi_tasklet_begin: + case avm_profile_data_type_hi_tasklet_end: + case avm_profile_data_type_workitem_begin: + case avm_profile_data_type_workitem_end: + case avm_profile_data_type_cpphytx_begin: + case avm_profile_data_type_cpphytx_end: + case avm_profile_data_type_cpphyrx_begin: + case avm_profile_data_type_cpphyrx_end: + case avm_profile_data_type_func_begin: + case avm_profile_data_type_func_end: + simple_profiling.data[pos].type = type; + simple_profiling.data[pos].id = id; + simple_profiling.data[pos].addr = addr; + simple_profiling.data[pos].time = time; + simple_profiling.data[pos].total_access = avm_profile_sdramacess(); + simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); + break; + } +} +EXPORT_SYMBOL(avm_simple_profiling_log); + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +void avm_simple_profiling_text(const char *text) { + unsigned int pos; + if(simple_profiling.enabled == 0) return; + pos = atomic_inc_return(&(simple_profiling.pos)) - 1; + if(pos >= simple_profiling.len - 1) { + simple_profiling.enabled = 0; + simple_profiling.end_time = jiffies | 1; + printk("[simple_profiling] buffer full: %u entries recorded\n", simple_profiling.len); + } + simple_profiling.data[pos].type = avm_profile_data_type_text; + simple_profiling.data[pos].time = avm_profile_counter(); + simple_profiling.data[pos].addr = (unsigned int)text; + simple_profiling.data[pos].total_access = avm_profile_sdramacess(); + simple_profiling.data[pos].total_activate = avm_profile_sdramactivate(); + return; +} +EXPORT_SYMBOL(avm_simple_profiling_text); + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +struct _avm_profile_data *avm_simple_profiling_enable(unsigned int on, unsigned int *count, unsigned long *timediff) { + if(on) { + simple_profiling.enabled = 1; + simple_profiling.start_time = jiffies; + simple_profiling.end_time = 0; + atomic_set(&(simple_profiling.pos), 0); + if(count) *count = 0; + if(timediff)*timediff = 0; + return NULL; + } + simple_profiling.enabled = 0; + if(simple_profiling.end_time == 0) simple_profiling.end_time = jiffies; + if(count) *count = simple_profiling.pos.counter; + printk("[simple_profiling] off: %u entries\n", simple_profiling.pos.counter); + if(timediff) { + if(time_after(simple_profiling.start_time, simple_profiling.end_time)) { + *timediff = simple_profiling.end_time + 0xFFFFFFFF - simple_profiling.start_time; + } else { + *timediff = simple_profiling.end_time - simple_profiling.start_time; + } + } + return simple_profiling.data; +} + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +int avm_simple_profiling_init(void) { + simple_profiling.len = PROFILE_BUFFER_LEN; + simple_profiling.enabled = 0; + atomic_set(&(simple_profiling.pos), 0); + printk("[simple_profiling] %u entries %u min\n", simple_profiling.len, CONFIG_AVM_PROFILING_TRACE_MODE); + return 0; +} + +module_init(avm_simple_profiling_init); +#endif /*--- #if defined(CONFIG_AVM_SIMPLE_PROFILING) ---*/ + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ void mips_timer_interrupt(struct pt_regs *regs) { + extern void r4k_wait_end(void); + r4k_wait_end(); +#if defined(CONFIG_MIPS_OHIO) + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ohio_timer_interrupt(); +#elif defined(CONFIG_MIPS_AR7) + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ar7_timer_interrupt(); +#elif defined(CONFIG_MIPS_UR8) /*--- #if defined(CONFIG_MIPS_OHIO) ---*/ + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ur8_timer_interrupt(); +#endif /*--- #elif ---*/ /*--- #if defined(CONFIG_MIPS_OHIO) ---*/ if ((timer_tick_count++ % HZ) == 0) { mips_display_message(&display_string[display_count++]); if (display_count == MAX_DISPLAY_COUNT) display_count = 0; } - ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs); } @@ -80,10 +351,10 @@ */ static unsigned int __init estimate_cpu_frequency(void) { - unsigned int prid = read_c0_prid() & 0xffff00; unsigned int count; #ifdef CONFIG_MIPS_SEAD + unsigned int prid = read_c0_prid() & 0xffff00; /* * The SEAD board doesn't have a real time clock, so we can't * really calculate the timer frequency @@ -117,23 +388,50 @@ /* restore interrupts */ local_irq_restore(flags); #endif +#if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_UR8) +#if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) + { + static unsigned int mips_time_cpu_frequenz_change(enum _avm_clock_id, unsigned int); + count = avm_get_clock_notify(avm_clock_id_cpu, mips_time_cpu_frequenz_change); + } +#else /*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ + count = avm_get_clock(avm_clock_id_cpu); +#endif /*--- #else ---*//*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ + mips_hpt_frequency = count / 2; +#endif - mips_hpt_frequency = count; +#if !defined(CONFIG_MIPS_OHIO) && !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) count *= 2; + mips_hpt_frequency = count; +#endif /*--- #if !defined(CONFIG_MIPS_OHIO) && !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) ---*/ + count += 5000; /* round */ count -= count%10000; return count; } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +#if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) +static unsigned int mips_time_cpu_frequenz_change(enum _avm_clock_id clock_id, unsigned int new_clk) { + printk("[mips_time_cpu_frequenz_change] change to %u Hz\n", new_clk); + return 0; +} +#endif /*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) ---*/ + +#if defined(CONFIG_MIPS_RTC) unsigned long __init mips_rtc_get_time(void) { return mc146818_get_cmos_time(); } +#endif /*--- #if defined(CONFIG_MIPS_RTC) ---*/ +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ void __init mips_time_init(void) { unsigned int est_freq, flags; @@ -147,21 +445,27 @@ est_freq = estimate_cpu_frequency (); - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, (est_freq%1000000)*100/1000000); cpu_khz = est_freq / 1000; local_irq_restore(flags); } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ void __init mips_timer_setup(struct irqaction *irq) { + /*--- printk("[mips_timer_setup] 1\n"); ---*/ /* we are using the cpu counter for timer interrupts */ irq->handler = no_action; /* we use our own handler */ + /*--- printk("[mips_timer_setup] 2\n"); ---*/ setup_irq(MIPS_CPU_TIMER_IRQ, irq); + /*--- printk("[mips_timer_setup] 3\n"); ---*/ /* to generate the first timer interrupt */ write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); + /*--- printk("[mips_timer_setup] 4\n"); ---*/ set_c0_status(ALLINTS); + /*--- printk("[mips_timer_setup] 5\n"); ---*/ }