diff -urbBwP linux-pmac-stable/Documentation/Configure.help stable-intlat/Documentation/Configure.help --- linux-pmac-stable/Documentation/Configure.help Sun Jun 25 23:57:39 2000 +++ stable-intlat/Documentation/Configure.help Wed Jul 5 13:26:55 2000 @@ -12372,6 +12372,11 @@ This will use DMA if possible to reduce CPU usage. If in doubt, say Y here. +Interupt Latency Measurement +CONFIG_IRQ_LATENCY + This will install Jun Sun's IRQ latency measurement code into the kernel and + modules. Not many people are likely to use it... If in doubt answer N. + # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -urbBwP linux-pmac-stable/Makefile stable-intlat/Makefile --- linux-pmac-stable/Makefile Sun Jun 25 23:51:14 2000 +++ stable-intlat/Makefile Wed Jul 5 13:02:01 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 17 -EXTRAVERSION = pre7 +EXTRAVERSION = p7int ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) Only in linux-pmac-stable/arch/ppc/boot: ramdisk.image.gz Only in linux-pmac-stable/arch/ppc/chrpboot: ramdisk.image.gz diff -urbBwP linux-pmac-stable/arch/ppc/config.in stable-intlat/arch/ppc/config.in --- linux-pmac-stable/arch/ppc/config.in Fri Jun 9 12:54:50 2000 +++ stable-intlat/arch/ppc/config.in Wed Jul 5 13:02:27 2000 @@ -63,6 +63,9 @@ bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC bool 'Networking support' CONFIG_NET bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then +bool 'IRQ Latency Profiling' CONFIG_IRQ_LATENCY +fi bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT diff -urbBwP linux-pmac-stable/arch/ppc/kernel/Makefile stable-intlat/arch/ppc/kernel/Makefile --- linux-pmac-stable/arch/ppc/kernel/Makefile Sat Jun 17 01:12:30 2000 +++ stable-intlat/arch/ppc/kernel/Makefile Wed Jul 5 13:19:27 2000 @@ -16,11 +16,16 @@ #endif O_TARGET := kernel.o -OX_OBJS := ppc_ksyms.o setup.o +OX_OBJS := ppc_ksyms.o setup.o O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \ bitops.o ptrace.o align.o ppc_htab.o + +ifeq ($(CONFIG_IRQ_LATENCY),y) +O_OBJS += intr_blocking.o +endif + ifdef CONFIG_PCI O_OBJS += pci.o endif diff -urbBwP linux-pmac-stable/arch/ppc/kernel/head.S stable-intlat/arch/ppc/kernel/head.S --- linux-pmac-stable/arch/ppc/kernel/head.S Sat May 27 21:41:39 2000 +++ stable-intlat/arch/ppc/kernel/head.S Tue Jul 4 19:50:23 2000 @@ -312,7 +312,7 @@ mtspr IBAT2L,r18 mtspr IBAT2U,r21 #endif /* ndef CONFIG_GEMINI */ -#endif +#endif /* CONFIG_APUS */ mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 diff -urbBwP linux-pmac-stable/arch/ppc/kernel/intr_blocking.c stable-intlat/arch/ppc/kernel/intr_blocking.c --- linux-pmac-stable/arch/ppc/kernel/intr_blocking.c Thu Jan 1 01:00:00 1970 +++ stable-intlat/arch/ppc/kernel/intr_blocking.c Tue Jul 4 09:16:57 2000 @@ -0,0 +1,328 @@ +#include + + +/**** platform ****/ +#define readclock(low) \ + __asm__ __volatile__ ("mftb %0" : "=r" (low) :) + +#define __intr_save_flags(x) __save_flags(x) + +/**** configure ****/ +#define NUM_LOG_ENTRY 8 +#define INTR_IENABLE MSR_EE + +/**** data structure ****/ +struct IntrData { + /* count interrupt and iret */ + int breakCount; + + /* the test name */ + const char * testName; + + /* flag to control logging */ + unsigned logFlag; /* 0 - no logging; 1 - logging */ + + /* panic flag - set to 1 if something is realy wrong */ + unsigned panicFlag; + + /* for synchro between start and end */ + unsigned syncFlag; + + /* we only log interrupts within certain range */ + unsigned rangeLow; + unsigned rangeHigh; + + /* count the total number interrupts and intrs in range*/ + unsigned numIntrs; + unsigned numInRangeIntrs; + + + /* error accounting */ + unsigned skipSti; + unsigned skipCli; + unsigned syncStiError; + unsigned syncCliError; + unsigned stiBreakError; + unsigned restoreSti; + unsigned restoreCli; + + struct { + /* worst blocking time */ + unsigned blockingTime; + + const char * startFileName; + unsigned startFileLine; + unsigned startCount; + + const char *endFileName; + unsigned endFileLine; + unsigned endCount; + } count[NUM_LOG_ENTRY]; +}; + +struct IntrData intrData = { + 0, + "interrupt latency test for PPC (8 distinctive entries)", + 0, + 0, + 0, + + 1, + 0xffffffff, + + 0, + 0, + + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + + +/**** functions ****/ +#if 0 +void intr_check_int(int x) +{ + + unsigned flag; + __intr_save_flags(flag); + + if ((flag & INTR_IENABLE) != 0) { + switch(x) { + case 0 : + intrData.count[0].blockingTime ++; + break; + case 1 : + intrData.count[0].startFileLine ++; + break; + case 2 : + intrData.count[0].startCount ++; + break; + case 3 : + intrData.count[0].endFileLine ++; + break; + case 4 : + intrData.count[0].endCount ++; + break; + default : + intrData.count[0].startFileName = "Wrong check number"; + break; + } + } else { + switch(x) { + case 0 : + intrData.count[1].blockingTime ++; + break; + case 1 : + intrData.count[1].startFileLine ++; + break; + case 2 : + intrData.count[1].startCount ++; + break; + case 3 : + intrData.count[1].endFileLine ++; + break; + case 4 : + intrData.count[1].endCount ++; + break; + default : + intrData.count[1].startFileName = "Wrong check number"; + break; + } + } +} + +#endif + + +static inline void intr_SetPanic(unsigned x, const char *fname, unsigned l) +{ + if (intrData.panicFlag != 0) { + /* double error; impossible */ + intrData.panicFlag = 99; + return; + } + intrData.panicFlag = x; + intrData.count[0].startFileName = fname; + intrData.count[0].startFileLine = l; +} + +static const char *intrStartFileName; +static unsigned intrStartFileLine; +static unsigned intrStartCount; + +/* strategy : + * if it is true "cli", i.e., clearing the IF, we remember + * everything, and clear breakCount. + */ +int intr_cli(const char *fname, unsigned lineno) +{ + unsigned flag; + int retValue; + + __intr_save_flags(flag); + + retValue = __intr_cli(); + + /* if we are not logging or we have an error, do nothing */ + if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) { + return retValue; + } + + /* do nothing we had IF cleared before we call this function */ + if ((flag & INTR_IENABLE) == 0) { + intrData.skipCli ++; + return retValue; + } + + /* debug */ + if (intrData.syncFlag == 1) { + intrData.syncCliError ++; + } + intrData.syncFlag = 1; + + intrData.breakCount = 0; + + /* Read the Time Stamp Counter */ + intrStartFileName = fname; + intrStartFileLine = lineno; + readclock(intrStartCount); + + return retValue; +} + + +/* strategy: + * we do a count only if + * 1. syncFlag is 1 (a valid cli() was called) + * 2. breakCount is 0 (no iret is called between cli() and this sti() + */ +void intr_sti(const char *fname, unsigned lineno) +{ + unsigned flag; + unsigned endCount; + unsigned diff; + int i; + + __intr_save_flags(flag); + + /* if we are not logging or we have an error, do nothing */ + if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) { + __intr_sti(); + return; + } + + + /* check if this is a real sti() */ + if ((flag & INTR_IENABLE) != 0) { + intrData.skipSti ++; + __intr_sti(); + return; + } + + /* check 1*/ + if (intrData.syncFlag != 1) { + intrData.syncStiError ++; + __intr_sti(); + return; + } + + /* check 2 */ + if (intrData.breakCount != 0) { + intrData.stiBreakError ++; + __intr_sti(); + return; + } + + /* read count again */ + readclock(endCount); + + intrData.syncFlag = 0; + + diff = endCount - intrStartCount; + + if ((diff >= intrData.rangeLow) && (diff <= intrData.rangeHigh)) { + unsigned lowest=0xffffffff; + unsigned lowestIndex; + unsigned sameIndex = 0xffffffff; + + intrData.numInRangeIntrs++; + + /* check if we need to log this event */ + for (i=0; i< NUM_LOG_ENTRY; i++) { + + if (lowest > intrData.count[i].blockingTime) { + lowest = intrData.count[i].blockingTime; + lowestIndex = i; + } + + if ( (lineno == intrData.count[i].endFileLine) && + (intrStartFileLine == intrData.count[i].startFileLine) && + (fname[0] == intrData.count[i].endFileName[0]) && + (intrStartFileName[0] == intrData.count[i].startFileName[0]) ) { + /* if the line numbers are same, the first chars in + * both file names are same, we consider it is the same + * entry. */ + sameIndex = i; + } + } + + if (sameIndex == 0xffffffff) { + i = lowestIndex; + } else { + i = sameIndex; + } + + if (diff > intrData.count[i].blockingTime) { + intrData.count[i].blockingTime = diff; + intrData.count[i].endFileName = fname; + intrData.count[i].endFileLine = lineno; + intrData.count[i].endCount = endCount; + intrData.count[i].startFileName = intrStartFileName; + intrData.count[i].startFileLine = intrStartFileLine; + intrData.count[i].startCount = intrStartCount; + } + } + + intrData.numIntrs++; + __intr_sti(); +} + + +void intr_restore_flags(const char *fname, unsigned lineno, unsigned x) +{ + unsigned flag; + + /* if we are not logging or we have an error, do nothing */ + if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) { + __intr_restore_flags(x); + return; + } + + __intr_save_flags(flag); + + if (((flag & INTR_IENABLE) == 0) && + ((x & INTR_IENABLE) != 0) ) { + intrData.restoreSti ++; + intr_sti(fname, lineno); + } + + if ( ((flag & INTR_IENABLE) != 0) && + ((x & INTR_IENABLE) == 0) ) { + intrData.restoreCli ++; + intr_cli(fname, lineno); + } + + __intr_restore_flags(x); +} + +#include + +asmlinkage int sys_get_intrData(void ** ptr) +{ + return put_user(&intrData, ptr); +} diff -urbBwP linux-pmac-stable/arch/ppc/kernel/misc.S stable-intlat/arch/ppc/kernel/misc.S --- linux-pmac-stable/arch/ppc/kernel/misc.S Tue Mar 28 05:08:46 2000 +++ stable-intlat/arch/ppc/kernel/misc.S Tue Jul 4 20:03:19 2000 @@ -52,9 +52,15 @@ * Disable interrupts * rc = _disable_interrupts() */ +#ifdef CONFIG_IRQ_LATENCY +_GLOBAL(_intr_disable_interrupts) +_GLOBAL(__intr_cli) +_GLOBAL(_intr_hard_cli) +#else _GLOBAL(_disable_interrupts) _GLOBAL(__cli) _GLOBAL(_hard_cli) +#endif mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ li r4,0 /* Need [unsigned] value of MSR_EE */ @@ -72,8 +78,13 @@ _GLOBAL(_enable_interrupts) cmpi 0,r3,0 /* turning them on? */ beqlr /* nothing to do if state == 0 */ +#ifdef CONFIG_IRQ_LATENCY +_GLOBAL(__intr_sti) +_GLOBAL(_intr_hard_sti) +#else _GLOBAL(__sti) _GLOBAL(_hard_sti) +#endif lis r4,ppc_n_lost_interrupts@ha lwz r4,ppc_n_lost_interrupts@l(r4) mfmsr r3 /* Get current state */ @@ -493,7 +504,6 @@ mtspr ICTC,r3 blr - /* L2CR functions Copyright © 1997-1998 by PowerLogix R & D, Inc. @@ -961,4 +971,8 @@ .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork +#ifdef CONFIG_IRQ_LATENCY + .long sys_get_intrData /* 190 */ + .long sys_get_intrData /* 191 */ +#endif .space (NR_syscalls-183)*4 diff -urbBwP linux-pmac-stable/arch/ppc/kernel/ppc_ksyms.c stable-intlat/arch/ppc/kernel/ppc_ksyms.c --- linux-pmac-stable/arch/ppc/kernel/ppc_ksyms.c Sat Jun 24 03:06:00 2000 +++ stable-intlat/arch/ppc/kernel/ppc_ksyms.c Tue Jul 4 22:53:51 2000 @@ -160,11 +160,19 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(init_mm); +#ifdef CONFIG_IRQ_LATENCY +EXPORT_SYMBOL(intr_cli); +EXPORT_SYMBOL(intr_restore_flags); +EXPORT_SYMBOL(intr_sti) ; +#else EXPORT_SYMBOL(__cli); EXPORT_SYMBOL(__sti); +#endif /*EXPORT_SYMBOL(__restore_flags);*/ +#ifndef CONFIG_IRQ_LATENCY EXPORT_SYMBOL(_disable_interrupts); EXPORT_SYMBOL(_enable_interrupts); +#endif EXPORT_SYMBOL(flush_instruction_cache); EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); diff -urbBwP linux-pmac-stable/include/asm-ppc/system.h stable-intlat/include/asm-ppc/system.h --- linux-pmac-stable/include/asm-ppc/system.h Sat Jun 24 02:49:58 2000 +++ stable-intlat/include/asm-ppc/system.h Wed Jul 5 13:45:14 2000 @@ -39,7 +39,11 @@ asm("dcbf %0,%1; sync" : : "r" (line), "r" (0)); } +#ifdef CONFIG_IRQ_LATENCY +extern __inline__ void __intr_restore_flags(unsigned long flags) +#else extern __inline__ void __restore_flags(unsigned long flags) +#endif { extern atomic_t ppc_n_lost_interrupts; extern void do_lost_interrupts(unsigned long); @@ -52,11 +56,30 @@ } } - +#ifdef CONFIG_IRQ_LATENCY +/* jsun's IRQ latency measurement stuff */ +extern void __intr_sti(void); +extern int __intr_cli(void); +#else extern void __sti(void); extern void __cli(void); +#endif + +#ifdef CONFIG_IRQ_LATENCY +extern int intr_cli(const char*, unsigned); +extern void intr_sti(const char *, unsigned); +extern void intr_restore_flags(const char *, unsigned, unsigned); +#define __cli() intr_cli(__FILE__, __LINE__) +#define __sti() intr_sti(__FILE__, __LINE__) +#define __restore_flags(x) intr_restore_flags(__FILE__, __LINE__, x) +#define _disable_interrupts() __cli() +#define _enable_interrupts(x) { if (x != 0) __sti(); } +#else +extern void _sti(void); +extern void _cli(void); extern int _disable_interrupts(void); extern void _enable_interrupts(int); +#endif extern void print_backtrace(unsigned long *); extern void show_regs(struct pt_regs * regs);