From: johann Date: Fri, 20 Jul 2007 08:54:08 +0000 (+0000) Subject: Branch b1_6 X-Git-Tag: v1_8_0_110~1438 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=c4bc58c20842ff6dd4065064363005ac8c533c1c;p=fs%2Flustre-release.git Branch b1_6 b=11039 i=nathan i=scjody (get approval by email on rmg@) Remove obsolete kernel patches. --- diff --git a/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch b/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch deleted file mode 100644 index f3067fa..0000000 --- a/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch +++ /dev/null @@ -1,6371 +0,0 @@ - - -This kgdb will get called and will trap almost any kernel -fault WITHOUT BEING ARMED. - -It is entered at boot time via "kgdb" in the boot string, -not "gdb". This entry occurs when the first setup on the -boot string is called, not sometime later. You will not -find a "waiting for gdb" on your console, as the console has -not yet been enabled at this time. (Note, this early stuff -is a bit fragile as the full trap table has yet to be -loaded, something I might address, sometime... So don't try -to look at memory that can not be reached, for example. -Once the full trap table is loaded this restriction goes -away.) - -If you hard code it, you can put a breakpoint() as the FIRST -LINE OF C CODE. - -It does NOT use the serial driver, but if the serial driver -is loaded, it tells it to release the port to avoid -conflict. - -The threads stuff is not configurable, does not require -redirection of schedule() calls and does back track to the -first non schedule() caller on the info threads command. If -you switch to the thread, however, it will show it in the -switch code (as it should). - -It is MUCH more aggressive and paranoid about grabbing the -other cpus on entry. It issues a "send_nmi_all_but_self()" -rather than depending on them to interrupt or hit an NMI -sometime in the distant future. If a cpu does not come to -the party, it will continue without it so all is not lost. - -It does not have anything to do with IOCTL calls, but does -do the control-C thing. - -There is a LOT of info in the patch which ends up in -.../Documentation/i386/kgdb/* - -There is a nifty little thing call kgdb_ts() (kgdb time -stamp) which is a function you can code calls to which puts -some useful stuff in a circular buffer which can be examined -with the supplied gdb macros. - -It also allows you do to do "p foobar(...)" i.e. to call a -function from gdb, just like gdb allows in program -debugging. - -In an SMP system, you can choose to "hold" any given set of -cpus. It also defaults to holding other cpus on single step -(this can be overridden). - -This said, you can imagine my consternation when I found it -"lost it" on continues on 2.5. I found and fixed this this -early pm, a hold cpu on exit goof on my part. - -Oh, and a final point, the configure options are more -extensive (the serial port is set up here, for example, (can -not wait for a command line to do this)). There is one to -do system call exit tests. This is VERY new and causes the -kernel to hit a hard "int 3" if a system call attempts to -exit with preempt count other than zero. This is a fault, -of course, but the current 2.5 is full of them so I don't -recommend turning this on. - - -DESC -kgdbL warning fix -EDESC -From: Ingo Molnar - -this patch fixes a deprecated use of asm input operands. (and shuts up a -gcc 3.3 warning.) - -DESC -kgdb buffer overflow fix -EDESC -From: George Anzinger - - -DESC -kgdbL warning fix -EDESC -From: Ingo Molnar - -this patch fixes a deprecated use of asm input operands. (and shuts up a -gcc 3.3 warning.) - -DESC -kgdb: CONFIG_DEBUG_INFO fix -EDESC -From: Thomas Schlichter - -that patch sets DEBUG_INFO to y by default, even if whether DEBUG_KERNEL nor -KGDB is enabled. The attached patch changes this to enable DEBUG_INFO by -default only if KGDB is enabled. - -DESC -x86_64 fixes -EDESC -From Andi Kleen - -Fix x86_64 for kgdb. We forget why. -DESC -correct kgdb.txt Documentation link (against 2.6.1-rc1-mm2) -EDESC -From: Jesper Juhl - -The help text for "config KGDB" in arch/i386/Kconfig refers to -Documentation/i386/kgdb.txt - the actual location is -Documentation/i386/kgdb/kgdb.txt - patch below to fix that. - -DESC -kgdb: fix for recent gcc -EDESC - -arch/i386/kernel/traps.c:97: error: conflicting types for 'int3' -arch/i386/kernel/traps.c:77: error: previous declaration of 'int3' was here -arch/i386/kernel/traps.c:97: error: conflicting types for 'int3' -arch/i386/kernel/traps.c:77: error: previous declaration of 'int3' was here -arch/i386/kernel/traps.c:99: error: conflicting types for 'debug' -arch/i386/kernel/traps.c:75: error: previous declaration of 'debug' was here -arch/i386/kernel/traps.c:99: error: conflicting types for 'debug' -arch/i386/kernel/traps.c:75: error: previous declaration of 'debug' was here - -DESC -kgdb warning fixes -EDESC - -arch/i386/kernel/kgdb_stub.c:1306: warning: 'time' might be used uninitialized in this function -arch/i386/kernel/kgdb_stub.c:1306: warning: 'dum' might be used uninitialized in this function -DESC -THREAD_SIZE fixes for kgdb -EDESC -From: Matt Mackall - -Noticed the THREAD_SIZE clean-ups are in -mm now. Here are the missing -bits for kgdb, tested in -tiny with 4k stacks. -DESC -Fix stack overflow test for non-8k stacks -EDESC -From: Matt Mackall - -This is needed to work properly with 4k and 16k stacks. -DESC -kgdb-ga.patch fix for i386 single-step into sysenter -EDESC -From: Roland McGrath - -Using kgdb-ga.patch from -mm, if userland single-steps (PTRACE_SINGLESTEP) -into the `sysenter' instruction, kgdb reports a bogus trap: - - Program received signal SIGTRAP, Trace/breakpoint trap. - sysenter_past_esp () at arch/i386/kernel/entry.S:249 - 1: x/i $pc 0xc0106023 : sti - (gdb) - -The hackery in the "FIX_STACK" macro in entry.S changes the saved PC for a -the spurious kernel-mode debug trap when TF was set on user-mode execution -of `sysenter', so sysenter_past_esp is where it actually lies in this case. - The following patch removes the kgdb hiccup when userland -PTRACE_SINGLESTEP's into sysenter. -DESC -fix TRAP_BAD_SYSCALL_EXITS on i386 -EDESC -From: Andy Whitcroft - -We are not using the right offset name, nor the right address when checking -for a non-zero preempt count. Move to TI_preempt_count(%ebp). - -Signed-off-by: Andy Whitcroft -DESC -add TRAP_BAD_SYSCALL_EXITS config for i386 -EDESC -From: Andy Whitcroft - -There seems to be code recently added to -bk and thereby -mm which supports -extra debug for preempt on system call exit. Oddly there doesn't seem to -be configuration options to enable them. Below is a possible patch to -allow enabling this on i386. Sadly the most obvious menu to add this to is -the Kernel Hacking menu, but that is defined in architecture specific -configuration. If this makes sense I could patch the other arches? - -Add a configuration option to allow enabling TRAP_BAD_SYSCALL_EXITS to the -Kernel Hacking menu. - -Signed-off-by: Andy Whitcroft -Signed-off-by: Andrew Morton ---- - - 25-akpm/Documentation/i386/kgdb/andthen | 100 + - 25-akpm/Documentation/i386/kgdb/debug-nmi.txt | 37 - 25-akpm/Documentation/i386/kgdb/gdb-globals.txt | 71 - 25-akpm/Documentation/i386/kgdb/gdbinit | 14 - 25-akpm/Documentation/i386/kgdb/gdbinit-modules | 146 + - 25-akpm/Documentation/i386/kgdb/gdbinit.hw | 117 + - 25-akpm/Documentation/i386/kgdb/kgdb.txt | 775 +++++++ - 25-akpm/Documentation/i386/kgdb/loadmodule.sh | 78 - 25-akpm/MAINTAINERS | 6 - 25-akpm/arch/i386/Kconfig | 8 - 25-akpm/arch/i386/Kconfig.debug | 2 - 25-akpm/arch/i386/Kconfig.kgdb | 175 + - 25-akpm/arch/i386/Makefile | 3 - 25-akpm/arch/i386/kernel/Makefile | 1 - 25-akpm/arch/i386/kernel/entry.S | 29 - 25-akpm/arch/i386/kernel/kgdb_stub.c | 2330 ++++++++++++++++++++++++ - 25-akpm/arch/i386/kernel/nmi.c | 25 - 25-akpm/arch/i386/kernel/smp.c | 12 - 25-akpm/arch/i386/kernel/traps.c | 77 - 25-akpm/arch/i386/lib/Makefile | 1 - 25-akpm/arch/i386/lib/kgdb_serial.c | 485 ++++ - 25-akpm/arch/i386/mm/fault.c | 6 - 25-akpm/arch/x86_64/boot/compressed/head.S | 1 - 25-akpm/arch/x86_64/boot/compressed/misc.c | 1 - 25-akpm/drivers/char/keyboard.c | 3 - 25-akpm/drivers/char/sysrq.c | 23 - 25-akpm/drivers/serial/8250.c | 40 - 25-akpm/drivers/serial/serial_core.c | 5 - 25-akpm/include/asm-i386/bugs.h | 21 - 25-akpm/include/asm-i386/kgdb.h | 59 - 25-akpm/include/asm-i386/kgdb_local.h | 102 + - 25-akpm/include/linux/config.h | 3 - 25-akpm/include/linux/dwarf2-lang.h | 132 + - 25-akpm/include/linux/dwarf2.h | 738 +++++++ - 25-akpm/include/linux/serial_core.h | 4 - 25-akpm/include/linux/spinlock.h | 12 - 25-akpm/kernel/pid.c | 6 - 25-akpm/kernel/sched.c | 7 - 38 files changed, 5645 insertions(+), 10 deletions(-) - -diff -puN arch/i386/Kconfig~kgdb-ga arch/i386/Kconfig ---- 25/arch/i386/Kconfig~kgdb-ga 2004-10-21 14:54:15.256604136 -0700 -+++ 25-akpm/arch/i386/Kconfig 2004-10-21 14:54:15.295598208 -0700 -@@ -1184,6 +1184,14 @@ menu "Executable file formats" - - source "fs/Kconfig.binfmt" - -+config TRAP_BAD_SYSCALL_EXITS -+ bool "Debug bad system call exits" -+ depends on KGDB -+ help -+ If you say Y here the kernel will check for system calls which -+ return without clearing preempt. -+ default n -+ - endmenu - - source "drivers/Kconfig" -diff -puN arch/i386/kernel/entry.S~kgdb-ga arch/i386/kernel/entry.S ---- 25/arch/i386/kernel/entry.S~kgdb-ga 2004-10-21 14:54:15.257603984 -0700 -+++ 25-akpm/arch/i386/kernel/entry.S 2004-10-21 14:54:15.296598056 -0700 -@@ -48,6 +48,18 @@ - #include - #include - #include "irq_vectors.h" -+ /* We do not recover from a stack overflow, but at least -+ * we know it happened and should be able to track it down. -+ */ -+#ifdef CONFIG_STACK_OVERFLOW_TEST -+#define STACK_OVERFLOW_TEST \ -+ testl $(THREAD_SIZE - 512),%esp; \ -+ jnz 10f; \ -+ call stack_overflow; \ -+10: -+#else -+#define STACK_OVERFLOW_TEST -+#endif - - #define nr_syscalls ((syscall_table_size)/4) - -@@ -94,7 +106,8 @@ VM_MASK = 0x00020000 - pushl %ebx; \ - movl $(__USER_DS), %edx; \ - movl %edx, %ds; \ -- movl %edx, %es; -+ movl %edx, %es; \ -+ STACK_OVERFLOW_TEST - - #define RESTORE_INT_REGS \ - popl %ebx; \ -@@ -198,6 +211,7 @@ need_resched: - # sysenter call handler stub - ENTRY(sysenter_entry) - movl TSS_sysenter_esp0(%esp),%esp -+ .globl sysenter_past_esp - sysenter_past_esp: - sti - pushl $(__USER_DS) -@@ -260,6 +274,19 @@ syscall_exit: - testw $_TIF_ALLWORK_MASK, %cx # current->work - jne syscall_exit_work - restore_all: -+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS -+ movl EFLAGS(%esp), %eax # mix EFLAGS and CS -+ movb CS(%esp), %al -+ testl $(VM_MASK | 3), %eax -+ jz resume_kernelX # returning to kernel or vm86-space -+ -+ cmpl $0,TI_preempt_count(%ebp) # non-zero preempt_count ? -+ jz resume_kernelX -+ -+ int $3 -+ -+resume_kernelX: -+#endif - RESTORE_ALL - - # perform work that needs to be done immediately before resumption -diff -puN /dev/null arch/i386/kernel/kgdb_stub.c ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/arch/i386/kernel/kgdb_stub.c 2004-10-21 14:54:15.307596384 -0700 -@@ -0,0 +1,2330 @@ -+/* -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2, or (at your option) any -+ * later version. -+ * -+ * This program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ */ -+ -+/* -+ * Copyright (c) 2000 VERITAS Software Corporation. -+ * -+ */ -+/**************************************************************************** -+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ -+ * -+ * Module name: remcom.c $ -+ * Revision: 1.34 $ -+ * Date: 91/03/09 12:29:49 $ -+ * Contributor: Lake Stevens Instrument Division$ -+ * -+ * Description: low level support for gdb debugger. $ -+ * -+ * Considerations: only works on target hardware $ -+ * -+ * Written by: Glenn Engel $ -+ * Updated by: David Grothe -+ * ModuleState: Experimental $ -+ * -+ * NOTES: See Below $ -+ * -+ * Modified for 386 by Jim Kingdon, Cygnus Support. -+ * Compatibility with 2.1.xx kernel by David Grothe -+ * -+ * Changes to allow auto initilization. All that is needed is that it -+ * be linked with the kernel and a break point (int 3) be executed. -+ * The header file defines BREAKPOINT to allow one to do -+ * this. It should also be possible, once the interrupt system is up, to -+ * call putDebugChar("+"). Once this is done, the remote debugger should -+ * get our attention by sending a ^C in a packet. George Anzinger -+ * -+ * Integrated into 2.2.5 kernel by Tigran Aivazian -+ * Added thread support, support for multiple processors, -+ * support for ia-32(x86) hardware debugging. -+ * Amit S. Kale ( akale@veritas.com ) -+ * -+ * -+ * To enable debugger support, two things need to happen. One, a -+ * call to set_debug_traps() is necessary in order to allow any breakpoints -+ * or error conditions to be properly intercepted and reported to gdb. -+ * Two, a breakpoint needs to be generated to begin communication. This -+ * is most easily accomplished by a call to breakpoint(). Breakpoint() -+ * simulates a breakpoint by executing an int 3. -+ * -+ ************* -+ * -+ * The following gdb commands are supported: -+ * -+ * command function Return value -+ * -+ * g return the value of the CPU registers hex data or ENN -+ * G set the value of the CPU registers OK or ENN -+ * -+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN -+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN -+ * -+ * c Resume at current address SNN ( signal NN) -+ * cAA..AA Continue at address AA..AA SNN -+ * -+ * s Step one instruction SNN -+ * sAA..AA Step one instruction from AA..AA SNN -+ * -+ * k kill -+ * -+ * ? What was the last sigval ? SNN (signal NN) -+ * -+ * All commands and responses are sent with a packet which includes a -+ * checksum. A packet consists of -+ * -+ * $#. -+ * -+ * where -+ * :: -+ * :: < two hex digits computed as modulo 256 sum of > -+ * -+ * When a packet is received, it is first acknowledged with either '+' or '-'. -+ * '+' indicates a successful transfer. '-' indicates a failed transfer. -+ * -+ * Example: -+ * -+ * Host: Reply: -+ * $m0,10#2a +$00010203040506070809101112131415#42 -+ * -+ ****************************************************************************/ -+#define KGDB_VERSION "<20030915.1651.33>" -+#include -+#include -+#include /* for strcpy */ -+#include -+#include -+#include -+#include -+#include /* for linux pt_regs struct */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/************************************************************************ -+ * -+ * external low-level support routines -+ */ -+typedef void (*Function) (void); /* pointer to a function */ -+ -+/* Thread reference */ -+typedef unsigned char threadref[8]; -+ -+extern void putDebugChar(int); /* write a single character */ -+extern int getDebugChar(void); /* read and return a single char */ -+ -+/************************************************************************/ -+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/ -+/* at least NUMREGBYTES*2 are needed for register packets */ -+/* Longer buffer is needed to list all threads */ -+#define BUFMAX 400 -+ -+char *kgdb_version = KGDB_VERSION; -+ -+/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ -+int debug_regs = 0; /* set to non-zero to print registers */ -+ -+/* filled in by an external module */ -+char *gdb_module_offsets; -+ -+static const char hexchars[] = "0123456789abcdef"; -+ -+/* Number of bytes of registers. */ -+#define NUMREGBYTES 64 -+/* -+ * Note that this register image is in a different order than -+ * the register image that Linux produces at interrupt time. -+ * -+ * Linux's register image is defined by struct pt_regs in ptrace.h. -+ * Just why GDB uses a different order is a historical mystery. -+ */ -+enum regnames { _EAX, /* 0 */ -+ _ECX, /* 1 */ -+ _EDX, /* 2 */ -+ _EBX, /* 3 */ -+ _ESP, /* 4 */ -+ _EBP, /* 5 */ -+ _ESI, /* 6 */ -+ _EDI, /* 7 */ -+ _PC /* 8 also known as eip */ , -+ _PS /* 9 also known as eflags */ , -+ _CS, /* 10 */ -+ _SS, /* 11 */ -+ _DS, /* 12 */ -+ _ES, /* 13 */ -+ _FS, /* 14 */ -+ _GS /* 15 */ -+}; -+ -+/*************************** ASSEMBLY CODE MACROS *************************/ -+/* -+ * Put the error code here just in case the user cares. -+ * Likewise, the vector number here (since GDB only gets the signal -+ * number through the usual means, and that's not very specific). -+ * The called_from is the return address so he can tell how we entered kgdb. -+ * This will allow him to seperate out the various possible entries. -+ */ -+#define REMOTE_DEBUG 0 /* set != to turn on printing (also available in info) */ -+ -+#define PID_MAX PID_MAX_DEFAULT -+ -+#ifdef CONFIG_SMP -+void smp_send_nmi_allbutself(void); -+#define IF_SMP(x) x -+#undef MAX_NO_CPUS -+#ifndef CONFIG_NO_KGDB_CPUS -+#define CONFIG_NO_KGDB_CPUS 2 -+#endif -+#if CONFIG_NO_KGDB_CPUS > NR_CPUS -+#define MAX_NO_CPUS NR_CPUS -+#else -+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS -+#endif -+#define hold_init hold_on_sstep: 1, -+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL) -+#define NUM_CPUS num_online_cpus() -+#else -+#define IF_SMP(x) -+#define hold_init -+#undef MAX_NO_CPUS -+#define MAX_NO_CPUS 1 -+#define NUM_CPUS 1 -+#endif -+#define NOCPU (struct task_struct *)0xbad1fbad -+/* *INDENT-OFF* */ -+struct kgdb_info { -+ int used_malloc; -+ void *called_from; -+ long long entry_tsc; -+ int errcode; -+ int vector; -+ int print_debug_info; -+#ifdef CONFIG_SMP -+ int hold_on_sstep; -+ struct { -+ volatile struct task_struct *task; -+ int pid; -+ int hold; -+ struct pt_regs *regs; -+ } cpus_waiting[MAX_NO_CPUS]; -+#endif -+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1}; -+ -+/* *INDENT-ON* */ -+ -+#define used_m kgdb_info.used_malloc -+/* -+ * This is little area we set aside to contain the stack we -+ * need to build to allow gdb to call functions. We use one -+ * per cpu to avoid locking issues. We will do all this work -+ * with interrupts off so that should take care of the protection -+ * issues. -+ */ -+#define LOOKASIDE_SIZE 200 /* should be more than enough */ -+#define MALLOC_MAX 200 /* Max malloc size */ -+struct { -+ unsigned int esp; -+ int array[LOOKASIDE_SIZE]; -+} fn_call_lookaside[MAX_NO_CPUS]; -+ -+static int trap_cpu; -+static unsigned int OLD_esp; -+ -+#define END_OF_LOOKASIDE &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE] -+#define IF_BIT 0x200 -+#define TF_BIT 0x100 -+ -+#define MALLOC_ROUND 8-1 -+ -+static char malloc_array[MALLOC_MAX]; -+IF_SMP(static void to_gdb(const char *mess)); -+void * -+malloc(int size) -+{ -+ -+ if (size <= (MALLOC_MAX - used_m)) { -+ int old_used = used_m; -+ used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND)); -+ return &malloc_array[old_used]; -+ } else { -+ return NULL; -+ } -+} -+ -+/* -+ * Gdb calls functions by pushing agruments, including a return address -+ * on the stack and the adjusting EIP to point to the function. The -+ * whole assumption in GDB is that we are on a different stack than the -+ * one the "user" i.e. code that hit the break point, is on. This, of -+ * course is not true in the kernel. Thus various dodges are needed to -+ * do the call without directly messing with EIP (which we can not change -+ * as it is just a location and not a register. To adjust it would then -+ * require that we move every thing below EIP up or down as needed. This -+ * will not work as we may well have stack relative pointer on the stack -+ * (such as the pointer to regs, for example). -+ -+ * So here is what we do: -+ * We detect gdb attempting to store into the stack area and instead, store -+ * into the fn_call_lookaside.array at the same relative location as if it -+ * were the area ESP pointed at. We also trap ESP modifications -+ * and uses these to adjust fn_call_lookaside.esp. On entry -+ * fn_call_lookaside.esp will be set to point at the last entry in -+ * fn_call_lookaside.array. This allows us to check if it has changed, and -+ * if so, on exit, we add the registers we will use to do the move and a -+ * trap/ interrupt return exit sequence. We then adjust the eflags in the -+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to -+ * kill the interrupt bit, AND we change EIP to point at our set up stub. -+ * As part of the register set up we preset the registers to point at the -+ * begining and end of the fn_call_lookaside.array, so all the stub needs to -+ * do is move words from the array to the stack until ESP= the desired value -+ * then do the rti. This will then transfer to the desired function with -+ * all the correct registers. Nifty huh? -+ */ -+extern asmlinkage void fn_call_stub(void); -+extern asmlinkage void fn_rtn_stub(void); -+/* *INDENT-OFF* */ -+__asm__("fn_rtn_stub:\n\t" -+ "movl %eax,%esp\n\t" -+ "fn_call_stub:\n\t" -+ "1:\n\t" -+ "addl $-4,%ebx\n\t" -+ "movl (%ebx), %eax\n\t" -+ "pushl %eax\n\t" -+ "cmpl %esp,%ecx\n\t" -+ "jne 1b\n\t" -+ "popl %eax\n\t" -+ "popl %ebx\n\t" -+ "popl %ecx\n\t" -+ "iret \n\t"); -+/* *INDENT-ON* */ -+#define gdb_i386vector kgdb_info.vector -+#define gdb_i386errcode kgdb_info.errcode -+#define waiting_cpus kgdb_info.cpus_waiting -+#define remote_debug kgdb_info.print_debug_info -+#define hold_cpu(cpu) kgdb_info.cpus_waiting[cpu].hold -+/* gdb locks */ -+ -+#ifdef CONFIG_SMP -+static int in_kgdb_called; -+static spinlock_t waitlocks[MAX_NO_CPUS] = -+ {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED }; -+/* -+ * The following array has the thread pointer of each of the "other" -+ * cpus. We make it global so it can be seen by gdb. -+ */ -+volatile int in_kgdb_entry_log[MAX_NO_CPUS]; -+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS]; -+/* -+static spinlock_t continuelocks[MAX_NO_CPUS]; -+*/ -+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED; -+/* waiters on our spinlock plus us */ -+static atomic_t spinlock_waiters = ATOMIC_INIT(1); -+static int spinlock_count = 0; -+static int spinlock_cpu = 0; -+/* -+ * Note we use nested spin locks to account for the case where a break -+ * point is encountered when calling a function by user direction from -+ * kgdb. Also there is the memory exception recursion to account for. -+ * Well, yes, but this lets other cpus thru too. Lets add a -+ * cpu id to the lock. -+ */ -+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \ -+ spinlock_cpu != smp_processor_id()){\ -+ atomic_inc(&spinlock_waiters); \ -+ while (! spin_trylock(x)) {\ -+ in_kgdb(®s);\ -+ }\ -+ atomic_dec(&spinlock_waiters); \ -+ spinlock_count = 1; \ -+ spinlock_cpu = smp_processor_id(); \ -+ }else{ \ -+ spinlock_count++; \ -+ } -+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x) -+#else -+unsigned kgdb_spinlock = 0; -+#define KGDB_SPIN_LOCK(x) --*x -+#define KGDB_SPIN_UNLOCK(x) ++*x -+#endif -+ -+int -+hex(char ch) -+{ -+ if ((ch >= 'a') && (ch <= 'f')) -+ return (ch - 'a' + 10); -+ if ((ch >= '0') && (ch <= '9')) -+ return (ch - '0'); -+ if ((ch >= 'A') && (ch <= 'F')) -+ return (ch - 'A' + 10); -+ return (-1); -+} -+ -+/* scan for the sequence $# */ -+void -+getpacket(char *buffer) -+{ -+ unsigned char checksum; -+ unsigned char xmitcsum; -+ int i; -+ int count; -+ char ch; -+ -+ do { -+ /* wait around for the start character, ignore all other characters */ -+ while ((ch = (getDebugChar() & 0x7f)) != '$') ; -+ checksum = 0; -+ xmitcsum = -1; -+ -+ count = 0; -+ -+ /* now, read until a # or end of buffer is found */ -+ while (count < BUFMAX) { -+ ch = getDebugChar() & 0x7f; -+ if (ch == '#') -+ break; -+ checksum = checksum + ch; -+ buffer[count] = ch; -+ count = count + 1; -+ } -+ buffer[count] = 0; -+ -+ if (ch == '#') { -+ xmitcsum = hex(getDebugChar() & 0x7f) << 4; -+ xmitcsum += hex(getDebugChar() & 0x7f); -+ if ((remote_debug) && (checksum != xmitcsum)) { -+ printk -+ ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", -+ checksum, xmitcsum, buffer); -+ } -+ -+ if (checksum != xmitcsum) -+ putDebugChar('-'); /* failed checksum */ -+ else { -+ putDebugChar('+'); /* successful transfer */ -+ /* if a sequence char is present, reply the sequence ID */ -+ if (buffer[2] == ':') { -+ putDebugChar(buffer[0]); -+ putDebugChar(buffer[1]); -+ /* remove sequence chars from buffer */ -+ count = strlen(buffer); -+ for (i = 3; i <= count; i++) -+ buffer[i - 3] = buffer[i]; -+ } -+ } -+ } -+ } while (checksum != xmitcsum); -+ -+ if (remote_debug) -+ printk("R:%s\n", buffer); -+} -+ -+/* send the packet in buffer. */ -+ -+void -+putpacket(char *buffer) -+{ -+ unsigned char checksum; -+ int count; -+ char ch; -+ -+ /* $#. */ -+ do { -+ if (remote_debug) -+ printk("T:%s\n", buffer); -+ putDebugChar('$'); -+ checksum = 0; -+ count = 0; -+ -+ while ((ch = buffer[count])) { -+ putDebugChar(ch); -+ checksum += ch; -+ count += 1; -+ } -+ -+ putDebugChar('#'); -+ putDebugChar(hexchars[checksum >> 4]); -+ putDebugChar(hexchars[checksum % 16]); -+ -+ } while ((getDebugChar() & 0x7f) != '+'); -+ -+} -+ -+static char remcomInBuffer[BUFMAX]; -+static char remcomOutBuffer[BUFMAX]; -+static short error; -+ -+void -+debug_error(char *format, char *parm) -+{ -+ if (remote_debug) -+ printk(format, parm); -+} -+ -+static void -+print_regs(struct pt_regs *regs) -+{ -+ printk("EAX=%08lx ", regs->eax); -+ printk("EBX=%08lx ", regs->ebx); -+ printk("ECX=%08lx ", regs->ecx); -+ printk("EDX=%08lx ", regs->edx); -+ printk("\n"); -+ printk("ESI=%08lx ", regs->esi); -+ printk("EDI=%08lx ", regs->edi); -+ printk("EBP=%08lx ", regs->ebp); -+ printk("ESP=%08lx ", (long) ®s->esp); -+ printk("\n"); -+ printk(" DS=%08x ", regs->xds); -+ printk(" ES=%08x ", regs->xes); -+ printk(" SS=%08x ", __KERNEL_DS); -+ printk(" FL=%08lx ", regs->eflags); -+ printk("\n"); -+ printk(" CS=%08x ", regs->xcs); -+ printk(" IP=%08lx ", regs->eip); -+#if 0 -+ printk(" FS=%08x ", regs->fs); -+ printk(" GS=%08x ", regs->gs); -+#endif -+ printk("\n"); -+ -+} /* print_regs */ -+ -+#define NEW_esp fn_call_lookaside[trap_cpu].esp -+ -+static void -+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs) -+{ -+ gdb_regs[_EAX] = regs->eax; -+ gdb_regs[_EBX] = regs->ebx; -+ gdb_regs[_ECX] = regs->ecx; -+ gdb_regs[_EDX] = regs->edx; -+ gdb_regs[_ESI] = regs->esi; -+ gdb_regs[_EDI] = regs->edi; -+ gdb_regs[_EBP] = regs->ebp; -+ gdb_regs[_DS] = regs->xds; -+ gdb_regs[_ES] = regs->xes; -+ gdb_regs[_PS] = regs->eflags; -+ gdb_regs[_CS] = regs->xcs; -+ gdb_regs[_PC] = regs->eip; -+ /* Note, as we are a debugging the kernel, we will always -+ * trap in kernel code, this means no priviledge change, -+ * and so the pt_regs structure is not completely valid. In a non -+ * privilege change trap, only EFLAGS, CS and EIP are put on the stack, -+ * SS and ESP are not stacked, this means that the last 2 elements of -+ * pt_regs is not valid (they would normally refer to the user stack) -+ * also, using regs+1 is no good because you end up will a value that is -+ * 2 longs (8) too high. This used to cause stepping over functions -+ * to fail, so my fix is to use the address of regs->esp, which -+ * should point at the end of the stack frame. Note I have ignored -+ * completely exceptions that cause an error code to be stacked, such -+ * as double fault. Stuart Hughes, Zentropix. -+ * original code: gdb_regs[_ESP] = (int) (regs + 1) ; -+ -+ * this is now done on entry and moved to OLD_esp (as well as NEW_esp). -+ */ -+ gdb_regs[_ESP] = NEW_esp; -+ gdb_regs[_SS] = __KERNEL_DS; -+ gdb_regs[_FS] = 0xFFFF; -+ gdb_regs[_GS] = 0xFFFF; -+} /* regs_to_gdb_regs */ -+ -+static void -+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs) -+{ -+ regs->eax = gdb_regs[_EAX]; -+ regs->ebx = gdb_regs[_EBX]; -+ regs->ecx = gdb_regs[_ECX]; -+ regs->edx = gdb_regs[_EDX]; -+ regs->esi = gdb_regs[_ESI]; -+ regs->edi = gdb_regs[_EDI]; -+ regs->ebp = gdb_regs[_EBP]; -+ regs->xds = gdb_regs[_DS]; -+ regs->xes = gdb_regs[_ES]; -+ regs->eflags = gdb_regs[_PS]; -+ regs->xcs = gdb_regs[_CS]; -+ regs->eip = gdb_regs[_PC]; -+ NEW_esp = gdb_regs[_ESP]; /* keep the value */ -+#if 0 /* can't change these */ -+ regs->esp = gdb_regs[_ESP]; -+ regs->xss = gdb_regs[_SS]; -+ regs->fs = gdb_regs[_FS]; -+ regs->gs = gdb_regs[_GS]; -+#endif -+ -+} /* gdb_regs_to_regs */ -+ -+int thread_list = 0; -+ -+void -+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs) -+{ -+ unsigned long stack_page; -+ int count = 0; -+ IF_SMP(int i); -+ if (!p || p == current) { -+ regs_to_gdb_regs(gdb_regs, regs); -+ return; -+ } -+#ifdef CONFIG_SMP -+ for (i = 0; i < MAX_NO_CPUS; i++) { -+ if (p == kgdb_info.cpus_waiting[i].task) { -+ regs_to_gdb_regs(gdb_regs, -+ kgdb_info.cpus_waiting[i].regs); -+ gdb_regs[_ESP] = -+ (int) &kgdb_info.cpus_waiting[i].regs->esp; -+ -+ return; -+ } -+ } -+#endif -+ memset(gdb_regs, 0, NUMREGBYTES); -+ gdb_regs[_ESP] = p->thread.esp; -+ gdb_regs[_PC] = p->thread.eip; -+ gdb_regs[_EBP] = *(int *) gdb_regs[_ESP]; -+ gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4); -+ gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8); -+ -+/* -+ * This code is to give a more informative notion of where a process -+ * is waiting. It is used only when the user asks for a thread info -+ * list. If he then switches to the thread, s/he will find the task -+ * is in schedule, but a back trace should show the same info we come -+ * up with. This code was shamelessly purloined from process.c. It was -+ * then enhanced to provide more registers than simply the program -+ * counter. -+ */ -+ -+ if (!thread_list) { -+ return; -+ } -+ -+ if (p->state == TASK_RUNNING) -+ return; -+ stack_page = (unsigned long) p->thread_info; -+ if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] > -+ THREAD_SIZE - sizeof(long) + stack_page) -+ return; -+ /* include/asm-i386/system.h:switch_to() pushes ebp last. */ -+ do { -+ if (gdb_regs[_EBP] < stack_page || -+ gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page) -+ return; -+ gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4); -+ gdb_regs[_ESP] = gdb_regs[_EBP] + 8; -+ gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP]; -+ if (!in_sched_functions(gdb_regs[_PC])) -+ return; -+ } while (count++ < 16); -+ return; -+} -+ -+/* Indicate to caller of mem2hex or hex2mem that there has been an -+ error. */ -+static volatile int mem_err = 0; -+static volatile int mem_err_expected = 0; -+static volatile int mem_err_cnt = 0; -+static int garbage_loc = -1; -+ -+int -+get_char(char *addr) -+{ -+ return *addr; -+} -+ -+void -+set_char(char *addr, int val, int may_fault) -+{ -+ /* -+ * This code traps references to the area mapped to the kernel -+ * stack as given by the regs and, instead, stores to the -+ * fn_call_lookaside[cpu].array -+ */ -+ if (may_fault && -+ (unsigned int) addr < OLD_esp && -+ ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) { -+ addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr); -+ } -+ *addr = val; -+} -+ -+/* convert the memory pointed to by mem into hex, placing result in buf */ -+/* return a pointer to the last char put in buf (null) */ -+/* If MAY_FAULT is non-zero, then we should set mem_err in response to -+ a fault; if zero treat a fault like any other fault in the stub. */ -+char * -+mem2hex(char *mem, char *buf, int count, int may_fault) -+{ -+ int i; -+ unsigned char ch; -+ -+ if (may_fault) { -+ mem_err_expected = 1; -+ mem_err = 0; -+ } -+ for (i = 0; i < count; i++) { -+ /* printk("%lx = ", mem) ; */ -+ -+ ch = get_char(mem++); -+ -+ /* printk("%02x\n", ch & 0xFF) ; */ -+ if (may_fault && mem_err) { -+ if (remote_debug) -+ printk("Mem fault fetching from addr %lx\n", -+ (long) (mem - 1)); -+ *buf = 0; /* truncate buffer */ -+ return (buf); -+ } -+ *buf++ = hexchars[ch >> 4]; -+ *buf++ = hexchars[ch % 16]; -+ } -+ *buf = 0; -+ if (may_fault) -+ mem_err_expected = 0; -+ return (buf); -+} -+ -+/* convert the hex array pointed to by buf into binary to be placed in mem */ -+/* return a pointer to the character AFTER the last byte written */ -+/* NOTE: We use the may fault flag to also indicate if the write is to -+ * the registers (0) or "other" memory (!=0) -+ */ -+char * -+hex2mem(char *buf, char *mem, int count, int may_fault) -+{ -+ int i; -+ unsigned char ch; -+ -+ if (may_fault) { -+ mem_err_expected = 1; -+ mem_err = 0; -+ } -+ for (i = 0; i < count; i++) { -+ ch = hex(*buf++) << 4; -+ ch = ch + hex(*buf++); -+ set_char(mem++, ch, may_fault); -+ -+ if (may_fault && mem_err) { -+ if (remote_debug) -+ printk("Mem fault storing to addr %lx\n", -+ (long) (mem - 1)); -+ return (mem); -+ } -+ } -+ if (may_fault) -+ mem_err_expected = 0; -+ return (mem); -+} -+ -+/**********************************************/ -+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ -+/* RETURN NUMBER OF CHARS PROCESSED */ -+/**********************************************/ -+int -+hexToInt(char **ptr, int *intValue) -+{ -+ int numChars = 0; -+ int hexValue; -+ -+ *intValue = 0; -+ -+ while (**ptr) { -+ hexValue = hex(**ptr); -+ if (hexValue >= 0) { -+ *intValue = (*intValue << 4) | hexValue; -+ numChars++; -+ } else -+ break; -+ -+ (*ptr)++; -+ } -+ -+ return (numChars); -+} -+ -+#define stubhex(h) hex(h) -+#ifdef old_thread_list -+ -+static int -+stub_unpack_int(char *buff, int fieldlength) -+{ -+ int nibble; -+ int retval = 0; -+ -+ while (fieldlength) { -+ nibble = stubhex(*buff++); -+ retval |= nibble; -+ fieldlength--; -+ if (fieldlength) -+ retval = retval << 4; -+ } -+ return retval; -+} -+#endif -+static char * -+pack_hex_byte(char *pkt, int byte) -+{ -+ *pkt++ = hexchars[(byte >> 4) & 0xf]; -+ *pkt++ = hexchars[(byte & 0xf)]; -+ return pkt; -+} -+ -+#define BUF_THREAD_ID_SIZE 16 -+ -+static char * -+pack_threadid(char *pkt, threadref * id) -+{ -+ char *limit; -+ unsigned char *altid; -+ -+ altid = (unsigned char *) id; -+ limit = pkt + BUF_THREAD_ID_SIZE; -+ while (pkt < limit) -+ pkt = pack_hex_byte(pkt, *altid++); -+ return pkt; -+} -+ -+#ifdef old_thread_list -+static char * -+unpack_byte(char *buf, int *value) -+{ -+ *value = stub_unpack_int(buf, 2); -+ return buf + 2; -+} -+ -+static char * -+unpack_threadid(char *inbuf, threadref * id) -+{ -+ char *altref; -+ char *limit = inbuf + BUF_THREAD_ID_SIZE; -+ int x, y; -+ -+ altref = (char *) id; -+ -+ while (inbuf < limit) { -+ x = stubhex(*inbuf++); -+ y = stubhex(*inbuf++); -+ *altref++ = (x << 4) | y; -+ } -+ return inbuf; -+} -+#endif -+void -+int_to_threadref(threadref * id, int value) -+{ -+ unsigned char *scan; -+ -+ scan = (unsigned char *) id; -+ { -+ int i = 4; -+ while (i--) -+ *scan++ = 0; -+ } -+ *scan++ = (value >> 24) & 0xff; -+ *scan++ = (value >> 16) & 0xff; -+ *scan++ = (value >> 8) & 0xff; -+ *scan++ = (value & 0xff); -+} -+int -+int_to_hex_v(unsigned char * id, int value) -+{ -+ unsigned char *start = id; -+ int shift; -+ int ch; -+ -+ for (shift = 28; shift >= 0; shift -= 4) { -+ if ((ch = (value >> shift) & 0xf) || (id != start)) { -+ *id = hexchars[ch]; -+ id++; -+ } -+ } -+ if (id == start) -+ *id++ = '0'; -+ return id - start; -+} -+#ifdef old_thread_list -+ -+static int -+threadref_to_int(threadref * ref) -+{ -+ int i, value = 0; -+ unsigned char *scan; -+ -+ scan = (char *) ref; -+ scan += 4; -+ i = 4; -+ while (i-- > 0) -+ value = (value << 8) | ((*scan++) & 0xff); -+ return value; -+} -+#endif -+static int -+cmp_str(char *s1, char *s2, int count) -+{ -+ while (count--) { -+ if (*s1++ != *s2++) -+ return 0; -+ } -+ return 1; -+} -+ -+#if 1 /* this is a hold over from 2.4 where O(1) was "sometimes" */ -+extern struct task_struct *kgdb_get_idle(int cpu); -+#define idle_task(cpu) kgdb_get_idle(cpu) -+#else -+#define idle_task(cpu) init_tasks[cpu] -+#endif -+ -+extern int kgdb_pid_init_done; -+ -+struct task_struct * -+getthread(int pid) -+{ -+ struct task_struct *thread; -+ if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) { -+ -+ return idle_task(pid - PID_MAX); -+ } else { -+ /* -+ * find_task_by_pid is relatively safe all the time -+ * Other pid functions require lock downs which imply -+ * that we may be interrupting them (as we get here -+ * in the middle of most any lock down). -+ * Still we don't want to call until the table exists! -+ */ -+ if (kgdb_pid_init_done){ -+ thread = find_task_by_pid(pid); -+ if (thread) { -+ return thread; -+ } -+ } -+ } -+ return NULL; -+} -+/* *INDENT-OFF* */ -+struct hw_breakpoint { -+ unsigned enabled; -+ unsigned type; -+ unsigned len; -+ unsigned addr; -+} breakinfo[4] = { {enabled:0}, -+ {enabled:0}, -+ {enabled:0}, -+ {enabled:0}}; -+/* *INDENT-ON* */ -+unsigned hw_breakpoint_status; -+void -+correct_hw_break(void) -+{ -+ int breakno; -+ int correctit; -+ int breakbit; -+ unsigned dr7; -+ -+ asm volatile ("movl %%db7, %0\n":"=r" (dr7) -+ :); -+ /* *INDENT-OFF* */ -+ do { -+ unsigned addr0, addr1, addr2, addr3; -+ asm volatile ("movl %%db0, %0\n" -+ "movl %%db1, %1\n" -+ "movl %%db2, %2\n" -+ "movl %%db3, %3\n" -+ :"=r" (addr0), "=r"(addr1), -+ "=r"(addr2), "=r"(addr3) -+ :); -+ } while (0); -+ /* *INDENT-ON* */ -+ correctit = 0; -+ for (breakno = 0; breakno < 3; breakno++) { -+ breakbit = 2 << (breakno << 1); -+ if (!(dr7 & breakbit) && breakinfo[breakno].enabled) { -+ correctit = 1; -+ dr7 |= breakbit; -+ dr7 &= ~(0xf0000 << (breakno << 2)); -+ dr7 |= (((breakinfo[breakno].len << 2) | -+ breakinfo[breakno].type) << 16) << -+ (breakno << 2); -+ switch (breakno) { -+ case 0: -+ asm volatile ("movl %0, %%dr0\n"::"r" -+ (breakinfo[breakno].addr)); -+ break; -+ -+ case 1: -+ asm volatile ("movl %0, %%dr1\n"::"r" -+ (breakinfo[breakno].addr)); -+ break; -+ -+ case 2: -+ asm volatile ("movl %0, %%dr2\n"::"r" -+ (breakinfo[breakno].addr)); -+ break; -+ -+ case 3: -+ asm volatile ("movl %0, %%dr3\n"::"r" -+ (breakinfo[breakno].addr)); -+ break; -+ } -+ } else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) { -+ correctit = 1; -+ dr7 &= ~breakbit; -+ dr7 &= ~(0xf0000 << (breakno << 2)); -+ } -+ } -+ if (correctit) { -+ asm volatile ("movl %0, %%db7\n"::"r" (dr7)); -+ } -+} -+ -+int -+remove_hw_break(unsigned breakno) -+{ -+ if (!breakinfo[breakno].enabled) { -+ return -1; -+ } -+ breakinfo[breakno].enabled = 0; -+ return 0; -+} -+ -+int -+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr) -+{ -+ if (breakinfo[breakno].enabled) { -+ return -1; -+ } -+ breakinfo[breakno].enabled = 1; -+ breakinfo[breakno].type = type; -+ breakinfo[breakno].len = len; -+ breakinfo[breakno].addr = addr; -+ return 0; -+} -+ -+#ifdef CONFIG_SMP -+static int in_kgdb_console = 0; -+ -+int -+in_kgdb(struct pt_regs *regs) -+{ -+ unsigned flags; -+ int cpu = smp_processor_id(); -+ in_kgdb_called = 1; -+ if (!spin_is_locked(&kgdb_spinlock)) { -+ if (in_kgdb_here_log[cpu] || /* we are holding this cpu */ -+ in_kgdb_console) { /* or we are doing slow i/o */ -+ return 1; -+ } -+ return 0; -+ } -+ -+ /* As I see it the only reason not to let all cpus spin on -+ * the same spin_lock is to allow selected ones to proceed. -+ * This would be a good thing, so we leave it this way. -+ * Maybe someday.... Done ! -+ -+ * in_kgdb() is called from an NMI so we don't pretend -+ * to have any resources, like printk() for example. -+ */ -+ -+ kgdb_local_irq_save(flags); /* only local here, to avoid hanging */ -+ /* -+ * log arival of this cpu -+ * The NMI keeps on ticking. Protect against recurring more -+ * than once, and ignor the cpu that has the kgdb lock -+ */ -+ in_kgdb_entry_log[cpu]++; -+ in_kgdb_here_log[cpu] = regs; -+ if (cpu == spinlock_cpu || waiting_cpus[cpu].task) { -+ goto exit_in_kgdb; -+ } -+ /* -+ * For protection of the initilization of the spin locks by kgdb -+ * it locks the kgdb spinlock before it gets the wait locks set -+ * up. We wait here for the wait lock to be taken. If the -+ * kgdb lock goes away first?? Well, it could be a slow exit -+ * sequence where the wait lock is removed prior to the kgdb lock -+ * so if kgdb gets unlocked, we just exit. -+ */ -+ while (spin_is_locked(&kgdb_spinlock) && -+ !spin_is_locked(waitlocks + cpu)) ; -+ if (!spin_is_locked(&kgdb_spinlock)) { -+ goto exit_in_kgdb; -+ } -+ waiting_cpus[cpu].task = current; -+ waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu); -+ waiting_cpus[cpu].regs = regs; -+ -+ spin_unlock_wait(waitlocks + cpu); -+ /* -+ * log departure of this cpu -+ */ -+ waiting_cpus[cpu].task = 0; -+ waiting_cpus[cpu].pid = 0; -+ waiting_cpus[cpu].regs = 0; -+ correct_hw_break(); -+ exit_in_kgdb: -+ in_kgdb_here_log[cpu] = 0; -+ kgdb_local_irq_restore(flags); -+ return 1; -+ /* -+ spin_unlock(continuelocks + smp_processor_id()); -+ */ -+} -+ -+void -+smp__in_kgdb(struct pt_regs regs) -+{ -+ ack_APIC_irq(); -+ in_kgdb(®s); -+} -+#else -+int -+in_kgdb(struct pt_regs *regs) -+{ -+ return (kgdb_spinlock); -+} -+#endif -+ -+void -+printexceptioninfo(int exceptionNo, int errorcode, char *buffer) -+{ -+ unsigned dr6; -+ int i; -+ switch (exceptionNo) { -+ case 1: /* debug exception */ -+ break; -+ case 3: /* breakpoint */ -+ sprintf(buffer, "Software breakpoint"); -+ return; -+ default: -+ sprintf(buffer, "Details not available"); -+ return; -+ } -+ asm volatile ("movl %%db6, %0\n":"=r" (dr6) -+ :); -+ if (dr6 & 0x4000) { -+ sprintf(buffer, "Single step"); -+ return; -+ } -+ for (i = 0; i < 4; ++i) { -+ if (dr6 & (1 << i)) { -+ sprintf(buffer, "Hardware breakpoint %d", i); -+ return; -+ } -+ } -+ sprintf(buffer, "Unknown trap"); -+ return; -+} -+ -+/* -+ * This function does all command procesing for interfacing to gdb. -+ * -+ * NOTE: The INT nn instruction leaves the state of the interrupt -+ * enable flag UNCHANGED. That means that when this routine -+ * is entered via a breakpoint (INT 3) instruction from code -+ * that has interrupts enabled, then interrupts will STILL BE -+ * enabled when this routine is entered. The first thing that -+ * we do here is disable interrupts so as to prevent recursive -+ * entries and bothersome serial interrupts while we are -+ * trying to run the serial port in polled mode. -+ * -+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so -+ * it is always necessary to do a restore_flags before returning -+ * so as to let go of that lock. -+ */ -+int -+kgdb_handle_exception(int exceptionVector, -+ int signo, int err_code, struct pt_regs *linux_regs) -+{ -+ struct task_struct *usethread = NULL; -+ struct task_struct *thread_list_start = 0, *thread = NULL; -+ int addr, length; -+ int breakno, breaktype; -+ char *ptr; -+ int newPC; -+ threadref thref; -+ int threadid; -+ int thread_min = PID_MAX + MAX_NO_CPUS; -+#ifdef old_thread_list -+ int maxthreads; -+#endif -+ int nothreads; -+ unsigned long flags; -+ int gdb_regs[NUMREGBYTES / 4]; -+ int dr6; -+ IF_SMP(int entry_state = 0); /* 0, ok, 1, no nmi, 2 sync failed */ -+#define NO_NMI 1 -+#define NO_SYNC 2 -+#define regs (*linux_regs) -+#define NUMREGS NUMREGBYTES/4 -+ /* -+ * If the entry is not from the kernel then return to the Linux -+ * trap handler and let it process the interrupt normally. -+ */ -+ if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) { -+ printk("ignoring non-kernel exception\n"); -+ print_regs(®s); -+ return (0); -+ } -+ -+ kgdb_local_irq_save(flags); -+ -+ /* Get kgdb spinlock */ -+ -+ KGDB_SPIN_LOCK(&kgdb_spinlock); -+ rdtscll(kgdb_info.entry_tsc); -+ /* -+ * We depend on this spinlock and the NMI watch dog to control the -+ * other cpus. They will arrive at "in_kgdb()" as a result of the -+ * NMI and will wait there for the following spin locks to be -+ * released. -+ */ -+#ifdef CONFIG_SMP -+ -+#if 0 -+ if (cpu_callout_map & ~MAX_CPU_MASK) { -+ printk("kgdb : too many cpus, possibly not mapped" -+ " in contiguous space, change MAX_NO_CPUS" -+ " in kgdb_stub and make new kernel.\n" -+ " cpu_callout_map is %lx\n", cpu_callout_map); -+ goto exit_just_unlock; -+ } -+#endif -+ if (spinlock_count == 1) { -+ int time = 0, end_time, dum = 0; -+ int i; -+ int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0) -+ }; -+ if (remote_debug) { -+ printk("kgdb : cpu %d entry, syncing others\n", -+ smp_processor_id()); -+ } -+ for (i = 0; i < MAX_NO_CPUS; i++) { -+ /* -+ * Use trylock as we may already hold the lock if -+ * we are holding the cpu. Net result is all -+ * locked. -+ */ -+ spin_trylock(&waitlocks[i]); -+ } -+ for (i = 0; i < MAX_NO_CPUS; i++) -+ cpu_logged_in[i] = 0; -+ /* -+ * Wait for their arrival. We know the watch dog is active if -+ * in_kgdb() has ever been called, as it is always called on a -+ * watchdog tick. -+ */ -+ rdtsc(dum, time); -+ end_time = time + 2; /* Note: we use the High order bits! */ -+ i = 1; -+ if (num_online_cpus() > 1) { -+ int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()]; -+ smp_send_nmi_allbutself(); -+ while (i < num_online_cpus() && time != end_time) { -+ int j; -+ for (j = 0; j < MAX_NO_CPUS; j++) { -+ if (waiting_cpus[j].task && -+ !cpu_logged_in[j]) { -+ i++; -+ cpu_logged_in[j] = 1; -+ if (remote_debug) { -+ printk -+ ("kgdb : cpu %d arrived at kgdb\n", -+ j); -+ } -+ break; -+ } else if (!waiting_cpus[j].task && -+ !cpu_online(j)) { -+ waiting_cpus[j].task = NOCPU; -+ cpu_logged_in[j] = 1; -+ waiting_cpus[j].hold = 1; -+ break; -+ } -+ if (!waiting_cpus[j].task && -+ in_kgdb_here_log[j]) { -+ -+ int wait = 100000; -+ while (wait--) ; -+ if (!waiting_cpus[j].task && -+ in_kgdb_here_log[j]) { -+ printk -+ ("kgdb : cpu %d stall" -+ " in in_kgdb\n", -+ j); -+ i++; -+ cpu_logged_in[j] = 1; -+ waiting_cpus[j].task = -+ (struct task_struct -+ *) 1; -+ } -+ } -+ } -+ -+ if (in_kgdb_entry_log[smp_processor_id()] > -+ (me_in_kgdb + 10)) { -+ break; -+ } -+ -+ rdtsc(dum, time); -+ } -+ if (i < num_online_cpus()) { -+ printk -+ ("kgdb : time out, proceeding without sync\n"); -+#if 0 -+ printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n", -+ waiting_cpus[0].task != 0, -+ waiting_cpus[1].task != 0); -+ printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n", -+ cpu_logged_in[0], cpu_logged_in[1]); -+ printk -+ ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n", -+ in_kgdb_here_log[0] != 0, -+ in_kgdb_here_log[1] != 0); -+#endif -+ entry_state = NO_SYNC; -+ } else { -+#if 0 -+ int ent = -+ in_kgdb_entry_log[smp_processor_id()] - -+ me_in_kgdb; -+ printk("kgdb : sync after %d entries\n", ent); -+#endif -+ } -+ } else { -+ if (remote_debug) { -+ printk -+ ("kgdb : %d cpus, but watchdog not active\n" -+ "proceeding without locking down other cpus\n", -+ num_online_cpus()); -+ entry_state = NO_NMI; -+ } -+ } -+ } -+#endif -+ -+ if (remote_debug) { -+ unsigned long *lp = (unsigned long *) &linux_regs; -+ -+ printk("handle_exception(exceptionVector=%d, " -+ "signo=%d, err_code=%d, linux_regs=%p)\n", -+ exceptionVector, signo, err_code, linux_regs); -+ if (debug_regs) { -+ print_regs(®s); -+ printk("Stk: %8lx %8lx %8lx %8lx" -+ " %8lx %8lx %8lx %8lx\n", -+ lp[0], lp[1], lp[2], lp[3], -+ lp[4], lp[5], lp[6], lp[7]); -+ printk(" %8lx %8lx %8lx %8lx" -+ " %8lx %8lx %8lx %8lx\n", -+ lp[8], lp[9], lp[10], lp[11], -+ lp[12], lp[13], lp[14], lp[15]); -+ printk(" %8lx %8lx %8lx %8lx " -+ "%8lx %8lx %8lx %8lx\n", -+ lp[16], lp[17], lp[18], lp[19], -+ lp[20], lp[21], lp[22], lp[23]); -+ printk(" %8lx %8lx %8lx %8lx " -+ "%8lx %8lx %8lx %8lx\n", -+ lp[24], lp[25], lp[26], lp[27], -+ lp[28], lp[29], lp[30], lp[31]); -+ } -+ } -+ -+ /* Disable hardware debugging while we are in kgdb */ -+ /* Get the debug register status register */ -+/* *INDENT-OFF* */ -+ __asm__("movl %0,%%db7" -+ : /* no output */ -+ :"r"(0)); -+ -+ asm volatile ("movl %%db6, %0\n" -+ :"=r" (hw_breakpoint_status) -+ :); -+ -+/* *INDENT-ON* */ -+ switch (exceptionVector) { -+ case 0: /* divide error */ -+ case 1: /* debug exception */ -+ case 2: /* NMI */ -+ case 3: /* breakpoint */ -+ case 4: /* overflow */ -+ case 5: /* bounds check */ -+ case 6: /* invalid opcode */ -+ case 7: /* device not available */ -+ case 8: /* double fault (errcode) */ -+ case 10: /* invalid TSS (errcode) */ -+ case 12: /* stack fault (errcode) */ -+ case 16: /* floating point error */ -+ case 17: /* alignment check (errcode) */ -+ default: /* any undocumented */ -+ break; -+ case 11: /* segment not present (errcode) */ -+ case 13: /* general protection (errcode) */ -+ case 14: /* page fault (special errcode) */ -+ case 19: /* cache flush denied */ -+ if (mem_err_expected) { -+ /* -+ * This fault occured because of the -+ * get_char or set_char routines. These -+ * two routines use either eax of edx to -+ * indirectly reference the location in -+ * memory that they are working with. -+ * For a page fault, when we return the -+ * instruction will be retried, so we -+ * have to make sure that these -+ * registers point to valid memory. -+ */ -+ mem_err = 1; /* set mem error flag */ -+ mem_err_expected = 0; -+ mem_err_cnt++; /* helps in debugging */ -+ /* make valid address */ -+ regs.eax = (long) &garbage_loc; -+ /* make valid address */ -+ regs.edx = (long) &garbage_loc; -+ if (remote_debug) -+ printk("Return after memory error: " -+ "mem_err_cnt=%d\n", mem_err_cnt); -+ if (debug_regs) -+ print_regs(®s); -+ goto exit_kgdb; -+ } -+ break; -+ } -+ if (remote_debug) -+ printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id()); -+ -+ gdb_i386vector = exceptionVector; -+ gdb_i386errcode = err_code; -+ kgdb_info.called_from = __builtin_return_address(0); -+#ifdef CONFIG_SMP -+ /* -+ * OK, we can now communicate, lets tell gdb about the sync. -+ * but only if we had a problem. -+ */ -+ switch (entry_state) { -+ case NO_NMI: -+ to_gdb("NMI not active, other cpus not stopped\n"); -+ break; -+ case NO_SYNC: -+ to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n"); -+ default:; -+ } -+ -+#endif -+/* -+ * Set up the gdb function call area. -+ */ -+ trap_cpu = smp_processor_id(); -+ OLD_esp = NEW_esp = (int) (&linux_regs->esp); -+ -+ IF_SMP(once_again:) -+ /* reply to host that an exception has occurred */ -+ remcomOutBuffer[0] = 'S'; -+ remcomOutBuffer[1] = hexchars[signo >> 4]; -+ remcomOutBuffer[2] = hexchars[signo % 16]; -+ remcomOutBuffer[3] = 0; -+ -+ putpacket(remcomOutBuffer); -+ -+ while (1 == 1) { -+ error = 0; -+ remcomOutBuffer[0] = 0; -+ getpacket(remcomInBuffer); -+ switch (remcomInBuffer[0]) { -+ case '?': -+ remcomOutBuffer[0] = 'S'; -+ remcomOutBuffer[1] = hexchars[signo >> 4]; -+ remcomOutBuffer[2] = hexchars[signo % 16]; -+ remcomOutBuffer[3] = 0; -+ break; -+ case 'd': -+ remote_debug = !(remote_debug); /* toggle debug flag */ -+ printk("Remote debug %s\n", -+ remote_debug ? "on" : "off"); -+ break; -+ case 'g': /* return the value of the CPU registers */ -+ get_gdb_regs(usethread, ®s, gdb_regs); -+ mem2hex((char *) gdb_regs, -+ remcomOutBuffer, NUMREGBYTES, 0); -+ break; -+ case 'G': /* set the value of the CPU registers - return OK */ -+ hex2mem(&remcomInBuffer[1], -+ (char *) gdb_regs, NUMREGBYTES, 0); -+ if (!usethread || usethread == current) { -+ gdb_regs_to_regs(gdb_regs, ®s); -+ strcpy(remcomOutBuffer, "OK"); -+ } else { -+ strcpy(remcomOutBuffer, "E00"); -+ } -+ break; -+ -+ case 'P':{ /* set the value of a single CPU register - -+ return OK */ -+ /* -+ * For some reason, gdb wants to talk about psudo -+ * registers (greater than 15). These may have -+ * meaning for ptrace, but for us it is safe to -+ * ignor them. We do this by dumping them into -+ * _GS which we also ignor, but do have memory for. -+ */ -+ int regno; -+ -+ ptr = &remcomInBuffer[1]; -+ regs_to_gdb_regs(gdb_regs, ®s); -+ if ((!usethread || usethread == current) && -+ hexToInt(&ptr, ®no) && -+ *ptr++ == '=' && (regno >= 0)) { -+ regno = -+ (regno >= NUMREGS ? _GS : regno); -+ hex2mem(ptr, (char *) &gdb_regs[regno], -+ 4, 0); -+ gdb_regs_to_regs(gdb_regs, ®s); -+ strcpy(remcomOutBuffer, "OK"); -+ break; -+ } -+ strcpy(remcomOutBuffer, "E01"); -+ break; -+ } -+ -+ /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ -+ case 'm': -+ /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ -+ ptr = &remcomInBuffer[1]; -+ if (hexToInt(&ptr, &addr) && -+ (*(ptr++) == ',') && (hexToInt(&ptr, &length))) { -+ ptr = 0; -+ /* -+ * hex doubles the byte count -+ */ -+ if (length > (BUFMAX / 2)) -+ length = BUFMAX / 2; -+ mem2hex((char *) addr, -+ remcomOutBuffer, length, 1); -+ if (mem_err) { -+ strcpy(remcomOutBuffer, "E03"); -+ debug_error("memory fault\n", NULL); -+ } -+ } -+ -+ if (ptr) { -+ strcpy(remcomOutBuffer, "E01"); -+ debug_error -+ ("malformed read memory command: %s\n", -+ remcomInBuffer); -+ } -+ break; -+ -+ /* MAA..AA,LLLL: -+ Write LLLL bytes at address AA.AA return OK */ -+ case 'M': -+ /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ -+ ptr = &remcomInBuffer[1]; -+ if (hexToInt(&ptr, &addr) && -+ (*(ptr++) == ',') && -+ (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) { -+ hex2mem(ptr, (char *) addr, length, 1); -+ -+ if (mem_err) { -+ strcpy(remcomOutBuffer, "E03"); -+ debug_error("memory fault\n", NULL); -+ } else { -+ strcpy(remcomOutBuffer, "OK"); -+ } -+ -+ ptr = 0; -+ } -+ if (ptr) { -+ strcpy(remcomOutBuffer, "E02"); -+ debug_error -+ ("malformed write memory command: %s\n", -+ remcomInBuffer); -+ } -+ break; -+ case 'S': -+ remcomInBuffer[0] = 's'; -+ case 'C': -+ /* Csig;AA..AA where ;AA..AA is optional -+ * continue with signal -+ * Since signals are meaning less to us, delete that -+ * part and then fall into the 'c' code. -+ */ -+ ptr = &remcomInBuffer[1]; -+ length = 2; -+ while (*ptr && *ptr != ';') { -+ length++; -+ ptr++; -+ } -+ if (*ptr) { -+ do { -+ ptr++; -+ *(ptr - length++) = *ptr; -+ } while (*ptr); -+ } else { -+ remcomInBuffer[1] = 0; -+ } -+ -+ /* cAA..AA Continue at address AA..AA(optional) */ -+ /* sAA..AA Step one instruction from AA..AA(optional) */ -+ /* D detach, reply OK and then continue */ -+ case 'c': -+ case 's': -+ case 'D': -+ -+ /* try to read optional parameter, -+ pc unchanged if no parm */ -+ ptr = &remcomInBuffer[1]; -+ if (hexToInt(&ptr, &addr)) { -+ if (remote_debug) -+ printk("Changing EIP to 0x%x\n", addr); -+ -+ regs.eip = addr; -+ } -+ -+ newPC = regs.eip; -+ -+ /* clear the trace bit */ -+ regs.eflags &= 0xfffffeff; -+ -+ /* set the trace bit if we're stepping */ -+ if (remcomInBuffer[0] == 's') -+ regs.eflags |= 0x100; -+ -+ /* detach is a friendly version of continue. Note that -+ debugging is still enabled (e.g hit control C) -+ */ -+ if (remcomInBuffer[0] == 'D') { -+ strcpy(remcomOutBuffer, "OK"); -+ putpacket(remcomOutBuffer); -+ } -+ -+ if (remote_debug) { -+ printk("Resuming execution\n"); -+ print_regs(®s); -+ } -+ asm volatile ("movl %%db6, %0\n":"=r" (dr6) -+ :); -+ if (!(dr6 & 0x4000)) { -+ for (breakno = 0; breakno < 4; ++breakno) { -+ if (dr6 & (1 << breakno) && -+ (breakinfo[breakno].type == 0)) { -+ /* Set restore flag */ -+ regs.eflags |= 0x10000; -+ break; -+ } -+ } -+ } -+ correct_hw_break(); -+ asm volatile ("movl %0, %%db6\n"::"r" (0)); -+ goto exit_kgdb; -+ -+ /* kill the program */ -+ case 'k': /* do nothing */ -+ break; -+ -+ /* query */ -+ case 'q': -+ nothreads = 0; -+ switch (remcomInBuffer[1]) { -+ case 'f': -+ threadid = 1; -+ thread_list = 2; -+ thread_list_start = (usethread ? : current); -+ case 's': -+ if (!cmp_str(&remcomInBuffer[2], -+ "ThreadInfo", 10)) -+ break; -+ -+ remcomOutBuffer[nothreads++] = 'm'; -+ for (; threadid < PID_MAX + MAX_NO_CPUS; -+ threadid++) { -+ thread = getthread(threadid); -+ if (thread) { -+ nothreads += int_to_hex_v( -+ &remcomOutBuffer[ -+ nothreads], -+ threadid); -+ if (thread_min > threadid) -+ thread_min = threadid; -+ remcomOutBuffer[ -+ nothreads] = ','; -+ nothreads++; -+ if (nothreads > BUFMAX - 10) -+ break; -+ } -+ } -+ if (remcomOutBuffer[nothreads - 1] == 'm') { -+ remcomOutBuffer[nothreads - 1] = 'l'; -+ } else { -+ nothreads--; -+ } -+ remcomOutBuffer[nothreads] = 0; -+ break; -+ -+#ifdef old_thread_list /* Old thread info request */ -+ case 'L': -+ /* List threads */ -+ thread_list = 2; -+ thread_list_start = (usethread ? : current); -+ unpack_byte(remcomInBuffer + 3, &maxthreads); -+ unpack_threadid(remcomInBuffer + 5, &thref); -+ do { -+ int buf_thread_limit = -+ (BUFMAX - 22) / BUF_THREAD_ID_SIZE; -+ if (maxthreads > buf_thread_limit) { -+ maxthreads = buf_thread_limit; -+ } -+ } while (0); -+ remcomOutBuffer[0] = 'q'; -+ remcomOutBuffer[1] = 'M'; -+ remcomOutBuffer[4] = '0'; -+ pack_threadid(remcomOutBuffer + 5, &thref); -+ -+ threadid = threadref_to_int(&thref); -+ for (nothreads = 0; -+ nothreads < maxthreads && -+ threadid < PID_MAX + MAX_NO_CPUS; -+ threadid++) { -+ thread = getthread(threadid); -+ if (thread) { -+ int_to_threadref(&thref, -+ threadid); -+ pack_threadid(remcomOutBuffer + -+ 21 + -+ nothreads * 16, -+ &thref); -+ nothreads++; -+ if (thread_min > threadid) -+ thread_min = threadid; -+ } -+ } -+ -+ if (threadid == PID_MAX + MAX_NO_CPUS) { -+ remcomOutBuffer[4] = '1'; -+ } -+ pack_hex_byte(remcomOutBuffer + 2, nothreads); -+ remcomOutBuffer[21 + nothreads * 16] = '\0'; -+ break; -+#endif -+ case 'C': -+ /* Current thread id */ -+ remcomOutBuffer[0] = 'Q'; -+ remcomOutBuffer[1] = 'C'; -+ threadid = current->pid; -+ if (!threadid) { -+ /* -+ * idle thread -+ */ -+ for (threadid = PID_MAX; -+ threadid < PID_MAX + MAX_NO_CPUS; -+ threadid++) { -+ if (current == -+ idle_task(threadid - -+ PID_MAX)) -+ break; -+ } -+ } -+ int_to_threadref(&thref, threadid); -+ pack_threadid(remcomOutBuffer + 2, &thref); -+ remcomOutBuffer[18] = '\0'; -+ break; -+ -+ case 'E': -+ /* Print exception info */ -+ printexceptioninfo(exceptionVector, -+ err_code, remcomOutBuffer); -+ break; -+ case 'T':{ -+ char * nptr; -+ /* Thread extra info */ -+ if (!cmp_str(&remcomInBuffer[2], -+ "hreadExtraInfo,", 15)) { -+ break; -+ } -+ ptr = &remcomInBuffer[17]; -+ hexToInt(&ptr, &threadid); -+ thread = getthread(threadid); -+ nptr = &thread->comm[0]; -+ length = 0; -+ ptr = &remcomOutBuffer[0]; -+ do { -+ length++; -+ ptr = pack_hex_byte(ptr, *nptr++); -+ } while (*nptr && length < 16); -+ /* -+ * would like that 16 to be the size of -+ * task_struct.comm but don't know the -+ * syntax.. -+ */ -+ *ptr = 0; -+ } -+ } -+ break; -+ -+ /* task related */ -+ case 'H': -+ switch (remcomInBuffer[1]) { -+ case 'g': -+ ptr = &remcomInBuffer[2]; -+ hexToInt(&ptr, &threadid); -+ thread = getthread(threadid); -+ if (!thread) { -+ remcomOutBuffer[0] = 'E'; -+ remcomOutBuffer[1] = '\0'; -+ break; -+ } -+ /* -+ * Just in case I forget what this is all about, -+ * the "thread info" command to gdb causes it -+ * to ask for a thread list. It then switches -+ * to each thread and asks for the registers. -+ * For this (and only this) usage, we want to -+ * fudge the registers of tasks not on the run -+ * list (i.e. waiting) to show the routine that -+ * called schedule. Also, gdb, is a minimalist -+ * in that if the current thread is the last -+ * it will not re-read the info when done. -+ * This means that in this case we must show -+ * the real registers. So here is how we do it: -+ * Each entry we keep track of the min -+ * thread in the list (the last that gdb will) -+ * get info for. We also keep track of the -+ * starting thread. -+ * "thread_list" is cleared when switching back -+ * to the min thread if it is was current, or -+ * if it was not current, thread_list is set -+ * to 1. When the switch to current comes, -+ * if thread_list is 1, clear it, else do -+ * nothing. -+ */ -+ usethread = thread; -+ if ((thread_list == 1) && -+ (thread == thread_list_start)) { -+ thread_list = 0; -+ } -+ if (thread_list && (threadid == thread_min)) { -+ if (thread == thread_list_start) { -+ thread_list = 0; -+ } else { -+ thread_list = 1; -+ } -+ } -+ /* follow through */ -+ case 'c': -+ remcomOutBuffer[0] = 'O'; -+ remcomOutBuffer[1] = 'K'; -+ remcomOutBuffer[2] = '\0'; -+ break; -+ } -+ break; -+ -+ /* Query thread status */ -+ case 'T': -+ ptr = &remcomInBuffer[1]; -+ hexToInt(&ptr, &threadid); -+ thread = getthread(threadid); -+ if (thread) { -+ remcomOutBuffer[0] = 'O'; -+ remcomOutBuffer[1] = 'K'; -+ remcomOutBuffer[2] = '\0'; -+ if (thread_min > threadid) -+ thread_min = threadid; -+ } else { -+ remcomOutBuffer[0] = 'E'; -+ remcomOutBuffer[1] = '\0'; -+ } -+ break; -+ -+ case 'Y': /* set up a hardware breakpoint */ -+ ptr = &remcomInBuffer[1]; -+ hexToInt(&ptr, &breakno); -+ ptr++; -+ hexToInt(&ptr, &breaktype); -+ ptr++; -+ hexToInt(&ptr, &length); -+ ptr++; -+ hexToInt(&ptr, &addr); -+ if (set_hw_break(breakno & 0x3, -+ breaktype & 0x3, -+ length & 0x3, addr) == 0) { -+ strcpy(remcomOutBuffer, "OK"); -+ } else { -+ strcpy(remcomOutBuffer, "ERROR"); -+ } -+ break; -+ -+ /* Remove hardware breakpoint */ -+ case 'y': -+ ptr = &remcomInBuffer[1]; -+ hexToInt(&ptr, &breakno); -+ if (remove_hw_break(breakno & 0x3) == 0) { -+ strcpy(remcomOutBuffer, "OK"); -+ } else { -+ strcpy(remcomOutBuffer, "ERROR"); -+ } -+ break; -+ -+ case 'r': /* reboot */ -+ strcpy(remcomOutBuffer, "OK"); -+ putpacket(remcomOutBuffer); -+ /*to_gdb("Rebooting\n"); */ -+ /* triplefault no return from here */ -+ { -+ static long no_idt[2]; -+ __asm__ __volatile__("lidt %0"::"m"(no_idt[0])); -+ BREAKPOINT; -+ } -+ -+ } /* switch */ -+ -+ /* reply to the request */ -+ putpacket(remcomOutBuffer); -+ } /* while(1==1) */ -+ /* -+ * reached by goto only. -+ */ -+ exit_kgdb: -+ /* -+ * Here is where we set up to trap a gdb function call. NEW_esp -+ * will be changed if we are trying to do this. We handle both -+ * adding and subtracting, thus allowing gdb to put grung on -+ * the stack which it removes later. -+ */ -+ if (NEW_esp != OLD_esp) { -+ int *ptr = END_OF_LOOKASIDE; -+ if (NEW_esp < OLD_esp) -+ ptr -= (OLD_esp - NEW_esp) / sizeof (int); -+ *--ptr = linux_regs->eflags; -+ *--ptr = linux_regs->xcs; -+ *--ptr = linux_regs->eip; -+ *--ptr = linux_regs->ecx; -+ *--ptr = linux_regs->ebx; -+ *--ptr = linux_regs->eax; -+ linux_regs->ecx = NEW_esp - (sizeof (int) * 6); -+ linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE; -+ if (NEW_esp < OLD_esp) { -+ linux_regs->eip = (unsigned int) fn_call_stub; -+ } else { -+ linux_regs->eip = (unsigned int) fn_rtn_stub; -+ linux_regs->eax = NEW_esp; -+ } -+ linux_regs->eflags &= ~(IF_BIT | TF_BIT); -+ } -+#ifdef CONFIG_SMP -+ /* -+ * Release gdb wait locks -+ * Sanity check time. Must have at least one cpu to run. Also single -+ * step must not be done if the current cpu is on hold. -+ */ -+ if (spinlock_count == 1) { -+ int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep; -+ int cpu_avail = 0; -+ int i; -+ -+ for (i = 0; i < MAX_NO_CPUS; i++) { -+ if (!cpu_online(i)) -+ break; -+ if (!hold_cpu(i)) { -+ cpu_avail = 1; -+ } -+ } -+ /* -+ * Early in the bring up there will be NO cpus on line... -+ */ -+ if (!cpu_avail && !cpus_empty(cpu_online_map)) { -+ to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n"); -+ goto once_again; -+ } -+ if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) { -+ to_gdb -+ ("Current cpu must be unblocked to single step\n"); -+ goto once_again; -+ } -+ if (!(ss_hold)) { -+ int i; -+ for (i = 0; i < MAX_NO_CPUS; i++) { -+ if (!hold_cpu(i)) { -+ spin_unlock(&waitlocks[i]); -+ } -+ } -+ } else { -+ spin_unlock(&waitlocks[smp_processor_id()]); -+ } -+ /* Release kgdb spinlock */ -+ KGDB_SPIN_UNLOCK(&kgdb_spinlock); -+ /* -+ * If this cpu is on hold, this is where we -+ * do it. Note, the NMI will pull us out of here, -+ * but will return as the above lock is not held. -+ * We will stay here till another cpu releases the lock for us. -+ */ -+ spin_unlock_wait(waitlocks + smp_processor_id()); -+ kgdb_local_irq_restore(flags); -+ return (0); -+ } -+#if 0 -+exit_just_unlock: -+#endif -+#endif -+ /* Release kgdb spinlock */ -+ KGDB_SPIN_UNLOCK(&kgdb_spinlock); -+ kgdb_local_irq_restore(flags); -+ return (0); -+} -+ -+/* this function is used to set up exception handlers for tracing and -+ * breakpoints. -+ * This function is not needed as the above line does all that is needed. -+ * We leave it for backward compatitability... -+ */ -+void -+set_debug_traps(void) -+{ -+ /* -+ * linux_debug_hook is defined in traps.c. We store a pointer -+ * to our own exception handler into it. -+ -+ * But really folks, every hear of labeled common, an old Fortran -+ * concept. Lots of folks can reference it and it is define if -+ * anyone does. Only one can initialize it at link time. We do -+ * this with the hook. See the statement above. No need for any -+ * executable code and it is ready as soon as the kernel is -+ * loaded. Very desirable in kernel debugging. -+ -+ linux_debug_hook = handle_exception ; -+ */ -+ -+ /* In case GDB is started before us, ack any packets (presumably -+ "$?#xx") sitting there. -+ putDebugChar ('+'); -+ -+ initialized = 1; -+ */ -+} -+ -+/* This function will generate a breakpoint exception. It is used at the -+ beginning of a program to sync up with a debugger and can be used -+ otherwise as a quick means to stop program execution and "break" into -+ the debugger. */ -+/* But really, just use the BREAKPOINT macro. We will handle the int stuff -+ */ -+ -+#ifdef later -+/* -+ * possibly we should not go thru the traps.c code at all? Someday. -+ */ -+void -+do_kgdb_int3(struct pt_regs *regs, long error_code) -+{ -+ kgdb_handle_exception(3, 5, error_code, regs); -+ return; -+} -+#endif -+#undef regs -+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS -+asmlinkage void -+bad_sys_call_exit(int stuff) -+{ -+ struct pt_regs *regs = (struct pt_regs *) &stuff; -+ printk("Sys call %d return with %x preempt_count\n", -+ (int) regs->orig_eax, preempt_count()); -+} -+#endif -+#ifdef CONFIG_STACK_OVERFLOW_TEST -+#include -+asmlinkage void -+stack_overflow(void) -+{ -+#ifdef BREAKPOINT -+ BREAKPOINT; -+#else -+ printk("Kernel stack overflow, looping forever\n"); -+#endif -+ while (1) { -+ } -+} -+#endif -+ -+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE) -+char gdbconbuf[BUFMAX]; -+ -+static void -+kgdb_gdb_message(const char *s, unsigned count) -+{ -+ int i; -+ int wcount; -+ char *bufptr; -+ /* -+ * This takes care of NMI while spining out chars to gdb -+ */ -+ IF_SMP(in_kgdb_console = 1); -+ gdbconbuf[0] = 'O'; -+ bufptr = gdbconbuf + 1; -+ while (count > 0) { -+ if ((count << 1) > (BUFMAX - 2)) { -+ wcount = (BUFMAX - 2) >> 1; -+ } else { -+ wcount = count; -+ } -+ count -= wcount; -+ for (i = 0; i < wcount; i++) { -+ bufptr = pack_hex_byte(bufptr, s[i]); -+ } -+ *bufptr = '\0'; -+ s += wcount; -+ -+ putpacket(gdbconbuf); -+ -+ } -+ IF_SMP(in_kgdb_console = 0); -+} -+#endif -+#ifdef CONFIG_SMP -+static void -+to_gdb(const char *s) -+{ -+ int count = 0; -+ while (s[count] && (count++ < BUFMAX)) ; -+ kgdb_gdb_message(s, count); -+} -+#endif -+#ifdef CONFIG_KGDB_CONSOLE -+#include -+#include -+#include -+#include -+#include -+ -+void -+kgdb_console_write(struct console *co, const char *s, unsigned count) -+{ -+ -+ if (gdb_i386vector == -1) { -+ /* -+ * We have not yet talked to gdb. What to do... -+ * lets break, on continue we can do the write. -+ * But first tell him whats up. Uh, well no can do, -+ * as this IS the console. Oh well... -+ * We do need to wait or the messages will be lost. -+ * Other option would be to tell the above code to -+ * ignore this breakpoint and do an auto return, -+ * but that might confuse gdb. Also this happens -+ * early enough in boot up that we don't have the traps -+ * set up yet, so... -+ */ -+ breakpoint(); -+ } -+ kgdb_gdb_message(s, count); -+} -+ -+/* -+ * ------------------------------------------------------------ -+ * Serial KGDB driver -+ * ------------------------------------------------------------ -+ */ -+ -+static struct console kgdbcons = { -+ name:"kgdb", -+ write:kgdb_console_write, -+#ifdef CONFIG_KGDB_USER_CONSOLE -+ device:kgdb_console_device, -+#endif -+ flags:CON_PRINTBUFFER | CON_ENABLED, -+ index:-1, -+}; -+ -+/* -+ * The trick here is that this file gets linked before printk.o -+ * That means we get to peer at the console info in the command -+ * line before it does. If we are up, we register, otherwise, -+ * do nothing. By returning 0, we allow printk to look also. -+ */ -+static int kgdb_console_enabled; -+ -+int __init -+kgdb_console_init(char *str) -+{ -+ if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) { -+ register_console(&kgdbcons); -+ kgdb_console_enabled = 1; -+ } -+ return 0; /* let others look at the string */ -+} -+ -+__setup("console=", kgdb_console_init); -+ -+#ifdef CONFIG_KGDB_USER_CONSOLE -+static kdev_t kgdb_console_device(struct console *c); -+/* This stuff sort of works, but it knocks out telnet devices -+ * we are leaving it here in case we (or you) find time to figure it out -+ * better.. -+ */ -+ -+/* -+ * We need a real char device as well for when the console is opened for user -+ * space activities. -+ */ -+ -+static int -+kgdb_consdev_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static ssize_t -+kgdb_consdev_write(struct file *file, const char *buf, -+ size_t count, loff_t * ppos) -+{ -+ int size, ret = 0; -+ static char kbuf[128]; -+ static DECLARE_MUTEX(sem); -+ -+ /* We are not reentrant... */ -+ if (down_interruptible(&sem)) -+ return -ERESTARTSYS; -+ -+ while (count > 0) { -+ /* need to copy the data from user space */ -+ size = count; -+ if (size > sizeof (kbuf)) -+ size = sizeof (kbuf); -+ if (copy_from_user(kbuf, buf, size)) { -+ ret = -EFAULT; -+ break;; -+ } -+ kgdb_console_write(&kgdbcons, kbuf, size); -+ count -= size; -+ ret += size; -+ buf += size; -+ } -+ -+ up(&sem); -+ -+ return ret; -+} -+ -+struct file_operations kgdb_consdev_fops = { -+ open:kgdb_consdev_open, -+ write:kgdb_consdev_write -+}; -+static kdev_t -+kgdb_console_device(struct console *c) -+{ -+ return MKDEV(TTYAUX_MAJOR, 1); -+} -+ -+/* -+ * This routine gets called from the serial stub in the i386/lib -+ * This is so it is done late in bring up (just before the console open). -+ */ -+void -+kgdb_console_finit(void) -+{ -+ if (kgdb_console_enabled) { -+ char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1)); -+ char *cp = cptr; -+ while (*cptr && *cptr != '(') -+ cptr++; -+ *cptr = 0; -+ unregister_chrdev(TTYAUX_MAJOR, cp); -+ register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops); -+ } -+} -+#endif -+#endif -+#ifdef CONFIG_KGDB_TS -+#include /* time stamp code */ -+#include /* in_interrupt */ -+#ifdef CONFIG_KGDB_TS_64 -+#define DATA_POINTS 64 -+#endif -+#ifdef CONFIG_KGDB_TS_128 -+#define DATA_POINTS 128 -+#endif -+#ifdef CONFIG_KGDB_TS_256 -+#define DATA_POINTS 256 -+#endif -+#ifdef CONFIG_KGDB_TS_512 -+#define DATA_POINTS 512 -+#endif -+#ifdef CONFIG_KGDB_TS_1024 -+#define DATA_POINTS 1024 -+#endif -+#ifndef DATA_POINTS -+#define DATA_POINTS 128 /* must be a power of two */ -+#endif -+#define INDEX_MASK (DATA_POINTS - 1) -+#if (INDEX_MASK & DATA_POINTS) -+#error "CONFIG_KGDB_TS_COUNT must be a power of 2" -+#endif -+struct kgdb_and_then_struct { -+#ifdef CONFIG_SMP -+ int on_cpu; -+#endif -+ struct task_struct *task; -+ long long at_time; -+ int from_ln; -+ char *in_src; -+ void *from; -+ int *with_shpf; -+ int data0; -+ int data1; -+}; -+struct kgdb_and_then_struct2 { -+#ifdef CONFIG_SMP -+ int on_cpu; -+#endif -+ struct task_struct *task; -+ long long at_time; -+ int from_ln; -+ char *in_src; -+ void *from; -+ int *with_shpf; -+ struct task_struct *t1; -+ struct task_struct *t2; -+}; -+struct kgdb_and_then_struct kgdb_data[DATA_POINTS]; -+ -+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0]; -+int kgdb_and_then_count; -+ -+void -+kgdb_tstamp(int line, char *source, int data0, int data1) -+{ -+ static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED; -+ int flags; -+ kgdb_local_irq_save(flags); -+ spin_lock(&ts_spin); -+ rdtscll(kgdb_and_then->at_time); -+#ifdef CONFIG_SMP -+ kgdb_and_then->on_cpu = smp_processor_id(); -+#endif -+ kgdb_and_then->task = current; -+ kgdb_and_then->from_ln = line; -+ kgdb_and_then->in_src = source; -+ kgdb_and_then->from = __builtin_return_address(0); -+ kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) | -+ (preempt_count() << 8)); -+ kgdb_and_then->data0 = data0; -+ kgdb_and_then->data1 = data1; -+ kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK]; -+ spin_unlock(&ts_spin); -+ kgdb_local_irq_restore(flags); -+#ifdef CONFIG_PREEMPT -+ -+#endif -+ return; -+} -+#endif -+typedef int gdb_debug_hook(int exceptionVector, -+ int signo, int err_code, struct pt_regs *linux_regs); -+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception; /* histerical reasons... */ -diff -puN arch/i386/kernel/Makefile~kgdb-ga arch/i386/kernel/Makefile ---- 25/arch/i386/kernel/Makefile~kgdb-ga 2004-10-21 14:54:15.259603680 -0700 -+++ 25-akpm/arch/i386/kernel/Makefile 2004-10-21 14:54:15.308596232 -0700 -@@ -14,6 +14,7 @@ obj-y += timers/ - obj-$(CONFIG_ACPI_BOOT) += acpi/ - obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o - obj-$(CONFIG_MCA) += mca.o -+obj-$(CONFIG_KGDB) += kgdb_stub.o - obj-$(CONFIG_X86_MSR) += msr.o - obj-$(CONFIG_X86_CPUID) += cpuid.o - obj-$(CONFIG_MICROCODE) += microcode.o -diff -puN arch/i386/kernel/nmi.c~kgdb-ga arch/i386/kernel/nmi.c ---- 25/arch/i386/kernel/nmi.c~kgdb-ga 2004-10-21 14:54:15.261603376 -0700 -+++ 25-akpm/arch/i386/kernel/nmi.c 2004-10-21 14:54:15.308596232 -0700 -@@ -34,7 +34,17 @@ - - #include "mach_traps.h" - -+#ifdef CONFIG_KGDB -+#include -+#ifdef CONFIG_SMP -+unsigned int nmi_watchdog = NMI_IO_APIC; -+#else -+unsigned int nmi_watchdog = NMI_LOCAL_APIC; -+#endif -+#else - unsigned int nmi_watchdog = NMI_NONE; -+#endif -+ - extern int unknown_nmi_panic; - static unsigned int nmi_hz = HZ; - static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ -@@ -466,6 +476,9 @@ void touch_nmi_watchdog (void) - for (i = 0; i < NR_CPUS; i++) - alert_counter[i] = 0; - } -+#ifdef CONFIG_KGDB -+int tune_watchdog = 5*HZ; -+#endif - - extern void die_nmi(struct pt_regs *, const char *msg); - -@@ -481,12 +494,24 @@ void nmi_watchdog_tick (struct pt_regs * - */ - sum = irq_stat[cpu].apic_timer_irqs; - -+#ifdef CONFIG_KGDB -+ if (!in_kgdb(regs) && last_irq_sums[cpu] == sum) { -+ -+#else - if (last_irq_sums[cpu] == sum) { -+#endif - /* - * Ayiee, looks like this CPU is stuck ... - * wait a few IRQs (5 seconds) before doing the oops ... - */ - alert_counter[cpu]++; -+#ifdef CONFIG_KGDB -+ if (alert_counter[cpu] == tune_watchdog) { -+ kgdb_handle_exception(2, SIGPWR, 0, regs); -+ last_irq_sums[cpu] = sum; -+ alert_counter[cpu] = 0; -+ } -+#endif - if (alert_counter[cpu] == 30*nmi_hz) - die_nmi(regs, "NMI Watchdog detected LOCKUP"); - } else { -diff -puN arch/i386/kernel/smp.c~kgdb-ga arch/i386/kernel/smp.c ---- 25/arch/i386/kernel/smp.c~kgdb-ga 2004-10-21 14:54:15.262603224 -0700 -+++ 25-akpm/arch/i386/kernel/smp.c 2004-10-21 14:54:15.309596080 -0700 -@@ -466,7 +466,17 @@ void flush_tlb_all(void) - { - on_each_cpu(do_flush_tlb_all, NULL, 1, 1); - } -- -+#ifdef CONFIG_KGDB -+/* -+ * By using the NMI code instead of a vector we just sneak thru the -+ * word generator coming out with just what we want. AND it does -+ * not matter if clustered_apic_mode is set or not. -+ */ -+void smp_send_nmi_allbutself(void) -+{ -+ send_IPI_allbutself(APIC_DM_NMI); -+} -+#endif - /* - * this function sends a 'reschedule' IPI to another CPU. - * it goes straight through and wastes no time serializing -diff -puN arch/i386/kernel/traps.c~kgdb-ga arch/i386/kernel/traps.c ---- 25/arch/i386/kernel/traps.c~kgdb-ga 2004-10-21 14:54:15.264602920 -0700 -+++ 25-akpm/arch/i386/kernel/traps.c 2004-10-21 14:54:15.311595776 -0700 -@@ -105,6 +105,39 @@ int register_die_notifier(struct notifie - return err; - } - -+#ifdef CONFIG_KGDB -+extern void sysenter_past_esp(void); -+#include -+#include -+void set_intr_gate(unsigned int n, void *addr); -+static void set_intr_usr_gate(unsigned int n, void *addr); -+/* -+ * Should be able to call this breakpoint() very early in -+ * bring up. Just hard code the call where needed. -+ * The breakpoint() code is here because set_?_gate() functions -+ * are local (static) to trap.c. They need be done only once, -+ * but it does not hurt to do them over. -+ */ -+void breakpoint(void) -+{ -+ set_intr_usr_gate(3,&int3); /* disable ints on trap */ -+ set_intr_gate(1,&debug); -+ set_intr_gate(14,&page_fault); -+ -+ BREAKPOINT; -+} -+#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) \ -+ { \ -+ if (!user_mode(regs) ) \ -+ { \ -+ kgdb_handle_exception(trapnr, signr, error_code, regs); \ -+ after; \ -+ } else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \ -+ } -+#else -+#define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after) -+#endif -+ - static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) - { - return p > (void *)tinfo && -@@ -332,6 +365,15 @@ void die(const char * str, struct pt_reg - #endif - if (nl) - printk("\n"); -+#ifdef CONFIG_KGDB -+ /* This is about the only place we want to go to kgdb even if in -+ * user mode. But we must go in via a trap so within kgdb we will -+ * always be in kernel mode. -+ */ -+ if (user_mode(regs)) -+ BREAKPOINT; -+#endif -+ CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,) - notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); - show_registers(regs); - } else -@@ -406,6 +448,7 @@ static inline void do_trap(int trapnr, i - #define DO_ERROR(trapnr, signr, str, name) \ - asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ - { \ -+ CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,) \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ - == NOTIFY_STOP) \ - return; \ -@@ -429,6 +472,7 @@ asmlinkage void do_##name(struct pt_regs - #define DO_VM86_ERROR(trapnr, signr, str, name) \ - asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ - { \ -+ CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return) \ - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ - == NOTIFY_STOP) \ - return; \ -@@ -512,7 +556,8 @@ gp_in_vm86: - - gp_in_kernel: - if (!fixup_exception(regs)) { - die: -+ CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,) - if (notify_die(DIE_GPF, "general protection fault", regs, - error_code, 13, SIGSEGV) == NOTIFY_STOP) - return; -@@ -721,8 +766,18 @@ asmlinkage void do_debug(struct pt_regs - * allowing programs to debug themselves without the ptrace() - * interface. - */ -+#ifdef CONFIG_KGDB -+ /* -+ * I think this is the only "real" case of a TF in the kernel -+ * that really belongs to user space. Others are -+ * "Ours all ours!" -+ */ -+ if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_past_esp)) -+ goto clear_TF_reenable; -+#else - if ((regs->xcs & 3) == 0) - goto clear_TF_reenable; -+#endif - if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE) - goto clear_TF; - } -@@ -734,6 +789,17 @@ asmlinkage void do_debug(struct pt_regs - info.si_errno = 0; - info.si_code = TRAP_BRKPT; - -+#ifdef CONFIG_KGDB -+ /* -+ * If this is a kernel mode trap, we need to reset db7 to allow us -+ * to continue sanely ALSO skip the signal delivery -+ */ -+ if ((regs->xcs & 3) == 0) -+ goto clear_dr7; -+ -+ /* if not kernel, allow ints but only if they were on */ -+ if ( regs->eflags & 0x200) local_irq_enable(); -+#endif - /* If this is a kernel mode trap, save the user PC on entry to - * the kernel, that's what the debugger can make sense of. - */ -@@ -748,6 +814,7 @@ clear_dr7: - __asm__("movl %0,%%db7" - : /* no output */ - : "r" (0)); -+ CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,) - return; - - debug_vm86: -@@ -1004,6 +1071,12 @@ static void __init set_task_gate(unsigne - { - _set_gate(idt_table+n,5,0,0,(gdt_entry<<3)); - } -+#ifdef CONFIG_KGDB -+void set_intr_usr_gate(unsigned int n, void *addr) -+{ -+ _set_gate(idt_table+n,14,3,addr,__KERNEL_CS); -+} -+#endif - - - void __init trap_init(void) -@@ -1021,7 +1094,11 @@ void __init trap_init(void) - set_trap_gate(0,÷_error); - set_intr_gate(1,&debug); - set_intr_gate(2,&nmi); -+#ifndef CONFIG_KGDB - set_system_intr_gate(3, &int3); /* int3-5 can be called from all */ -+#else -+ set_intr_usr_gate(3,&int3); /* int3-5 can be called from all */ -+#endif - set_system_gate(4,&overflow); - set_system_gate(5,&bounds); - set_trap_gate(6,&invalid_op); -diff -puN /dev/null arch/i386/lib/kgdb_serial.c ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/arch/i386/lib/kgdb_serial.c 2004-10-21 14:54:15.313595472 -0700 -@@ -0,0 +1,485 @@ -+/* -+ * Serial interface GDB stub -+ * -+ * Written (hacked together) by David Grothe (dave@gcom.com) -+ * Modified to allow invokation early in boot see also -+ * kgdb.h for instructions by George Anzinger(george@mvista.com) -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef CONFIG_KGDB_USER_CONSOLE -+extern void kgdb_console_finit(void); -+#endif -+#define PRNT_off -+#define TEST_EXISTANCE -+#ifdef PRNT -+#define dbprintk(s) printk s -+#else -+#define dbprintk(s) -+#endif -+#define TEST_INTERRUPT_off -+#ifdef TEST_INTERRUPT -+#define intprintk(s) printk s -+#else -+#define intprintk(s) -+#endif -+ -+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) -+ -+#define GDB_BUF_SIZE 512 /* power of 2, please */ -+ -+static char gdb_buf[GDB_BUF_SIZE]; -+static int gdb_buf_in_inx; -+static atomic_t gdb_buf_in_cnt; -+static int gdb_buf_out_inx; -+ -+struct async_struct *gdb_async_info; -+static int gdb_async_irq; -+ -+#define outb_px(a,b) outb_p(b,a) -+ -+static void program_uart(struct async_struct *info); -+static void write_char(struct async_struct *info, int chr); -+/* -+ * Get a byte from the hardware data buffer and return it -+ */ -+static int -+read_data_bfr(struct async_struct *info) -+{ -+ char it = inb_p(info->port + UART_LSR); -+ -+ if (it & UART_LSR_DR) -+ return (inb_p(info->port + UART_RX)); -+ /* -+ * If we have a framing error assume somebody messed with -+ * our uart. Reprogram it and send '-' both ways... -+ */ -+ if (it & 0xc) { -+ program_uart(info); -+ write_char(info, '-'); -+ return ('-'); -+ } -+ return (-1); -+ -+} /* read_data_bfr */ -+ -+/* -+ * Get a char if available, return -1 if nothing available. -+ * Empty the receive buffer first, then look at the interface hardware. -+ -+ * Locking here is a bit of a problem. We MUST not lock out communication -+ * if we are trying to talk to gdb about a kgdb entry. ON the other hand -+ * we can loose chars in the console pass thru if we don't lock. It is also -+ * possible that we could hold the lock or be waiting for it when kgdb -+ * NEEDS to talk. Since kgdb locks down the world, it does not need locks. -+ * We do, of course have possible issues with interrupting a uart operation, -+ * but we will just depend on the uart status to help keep that straight. -+ -+ */ -+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED; -+#ifdef CONFIG_SMP -+extern spinlock_t kgdb_spinlock; -+#endif -+ -+static int -+read_char(struct async_struct *info) -+{ -+ int chr; -+ unsigned long flags; -+ local_irq_save(flags); -+#ifdef CONFIG_SMP -+ if (!spin_is_locked(&kgdb_spinlock)) { -+ spin_lock(&uart_interrupt_lock); -+ } -+#endif -+ if (atomic_read(&gdb_buf_in_cnt) != 0) { /* intr routine has q'd chars */ -+ chr = gdb_buf[gdb_buf_out_inx++]; -+ gdb_buf_out_inx &= (GDB_BUF_SIZE - 1); -+ atomic_dec(&gdb_buf_in_cnt); -+ } else { -+ chr = read_data_bfr(info); -+ } -+#ifdef CONFIG_SMP -+ if (!spin_is_locked(&kgdb_spinlock)) { -+ spin_unlock(&uart_interrupt_lock); -+ } -+#endif -+ local_irq_restore(flags); -+ return (chr); -+} -+ -+/* -+ * Wait until the interface can accept a char, then write it. -+ */ -+static void -+write_char(struct async_struct *info, int chr) -+{ -+ while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ; -+ -+ outb_p(chr, info->port + UART_TX); -+ -+} /* write_char */ -+ -+/* -+ * Mostly we don't need a spinlock, but since the console goes -+ * thru here with interrutps on, well, we need to catch those -+ * chars. -+ */ -+/* -+ * This is the receiver interrupt routine for the GDB stub. -+ * It will receive a limited number of characters of input -+ * from the gdb host machine and save them up in a buffer. -+ * -+ * When the gdb stub routine getDebugChar() is called it -+ * draws characters out of the buffer until it is empty and -+ * then reads directly from the serial port. -+ * -+ * We do not attempt to write chars from the interrupt routine -+ * since the stubs do all of that via putDebugChar() which -+ * writes one byte after waiting for the interface to become -+ * ready. -+ * -+ * The debug stubs like to run with interrupts disabled since, -+ * after all, they run as a consequence of a breakpoint in -+ * the kernel. -+ * -+ * Perhaps someone who knows more about the tty driver than I -+ * care to learn can make this work for any low level serial -+ * driver. -+ */ -+static irqreturn_t -+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct async_struct *info; -+ unsigned long flags; -+ -+ info = gdb_async_info; -+ if (!info || !info->tty || irq != gdb_async_irq) -+ return IRQ_NONE; -+ -+ local_irq_save(flags); -+ spin_lock(&uart_interrupt_lock); -+ do { -+ int chr = read_data_bfr(info); -+ intprintk(("Debug char on int: %x hex\n", chr)); -+ if (chr < 0) -+ continue; -+ -+ if (chr == 3) { /* Ctrl-C means remote interrupt */ -+ BREAKPOINT; -+ continue; -+ } -+ -+ if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) { -+ /* buffer overflow tosses early char */ -+ read_char(info); -+ } -+ gdb_buf[gdb_buf_in_inx++] = chr; -+ gdb_buf_in_inx &= (GDB_BUF_SIZE - 1); -+ } while (inb_p(info->port + UART_IIR) & UART_IIR_RDI); -+ spin_unlock(&uart_interrupt_lock); -+ local_irq_restore(flags); -+ return IRQ_HANDLED; -+} /* gdb_interrupt */ -+ -+/* -+ * Just a NULL routine for testing. -+ */ -+void -+gdb_null(void) -+{ -+} /* gdb_null */ -+ -+/* These structure are filled in with values defined in asm/kgdb_local.h -+ */ -+static struct serial_state state = SB_STATE; -+static struct async_struct local_info = SB_INFO; -+static int ok_to_enable_ints = 0; -+static void kgdb_enable_ints_now(void); -+ -+extern char *kgdb_version; -+/* -+ * Hook an IRQ for KGDB. -+ * -+ * This routine is called from putDebugChar, below. -+ */ -+static int ints_disabled = 1; -+int -+gdb_hook_interrupt(struct async_struct *info, int verb) -+{ -+ struct serial_state *state = info->state; -+ unsigned long flags; -+ int port; -+#ifdef TEST_EXISTANCE -+ int scratch, scratch2; -+#endif -+ -+ /* The above fails if memory managment is not set up yet. -+ * Rather than fail the set up, just keep track of the fact -+ * and pick up the interrupt thing later. -+ */ -+ gdb_async_info = info; -+ port = gdb_async_info->port; -+ gdb_async_irq = state->irq; -+ if (verb) { -+ printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n", -+ kgdb_version, -+ port, -+ gdb_async_irq, gdb_async_info->state->custom_divisor); -+ } -+ local_irq_save(flags); -+#ifdef TEST_EXISTANCE -+ /* Existance test */ -+ /* Should not need all this, but just in case.... */ -+ -+ scratch = inb_p(port + UART_IER); -+ outb_px(port + UART_IER, 0); -+ outb_px(0xff, 0x080); -+ scratch2 = inb_p(port + UART_IER); -+ outb_px(port + UART_IER, scratch); -+ if (scratch2) { -+ printk -+ ("gdb_hook_interrupt: Could not clear IER, not a UART!\n"); -+ local_irq_restore(flags); -+ return 1; /* We failed; there's nothing here */ -+ } -+ scratch2 = inb_p(port + UART_LCR); -+ outb_px(port + UART_LCR, 0xBF); /* set up for StarTech test */ -+ outb_px(port + UART_EFR, 0); /* EFR is the same as FCR */ -+ outb_px(port + UART_LCR, 0); -+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO); -+ scratch = inb_p(port + UART_IIR) >> 6; -+ if (scratch == 1) { -+ printk("gdb_hook_interrupt: Undefined UART type!" -+ " Not a UART! \n"); -+ local_irq_restore(flags); -+ return 1; -+ } else { -+ dbprintk(("gdb_hook_interrupt: UART type " -+ "is %d where 0=16450, 2=16550 3=16550A\n", scratch)); -+ } -+ scratch = inb_p(port + UART_MCR); -+ outb_px(port + UART_MCR, UART_MCR_LOOP | scratch); -+ outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A); -+ scratch2 = inb_p(port + UART_MSR) & 0xF0; -+ outb_px(port + UART_MCR, scratch); -+ if (scratch2 != 0x90) { -+ printk("gdb_hook_interrupt: " -+ "Loop back test failed! Not a UART!\n"); -+ local_irq_restore(flags); -+ return scratch2 + 1000; /* force 0 to fail */ -+ } -+#endif /* test existance */ -+ program_uart(info); -+ local_irq_restore(flags); -+ -+ return (0); -+ -+} /* gdb_hook_interrupt */ -+ -+static void -+program_uart(struct async_struct *info) -+{ -+ int port = info->port; -+ -+ (void) inb_p(port + UART_RX); -+ outb_px(port + UART_IER, 0); -+ -+ (void) inb_p(port + UART_RX); /* serial driver comments say */ -+ (void) inb_p(port + UART_IIR); /* this clears the interrupt regs */ -+ (void) inb_p(port + UART_MSR); -+ outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); -+ outb_px(port + UART_DLL, info->state->custom_divisor & 0xff); /* LS */ -+ outb_px(port + UART_DLM, info->state->custom_divisor >> 8); /* MS */ -+ outb_px(port + UART_MCR, info->MCR); -+ -+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR); /* set fcr */ -+ outb_px(port + UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ -+ outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1); /* set fcr */ -+ if (!ints_disabled) { -+ intprintk(("KGDB: Sending %d to port %x offset %d\n", -+ gdb_async_info->IER, -+ (int) gdb_async_info->port, UART_IER)); -+ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); -+ } -+ return; -+} -+ -+/* -+ * getDebugChar -+ * -+ * This is a GDB stub routine. It waits for a character from the -+ * serial interface and then returns it. If there is no serial -+ * interface connection then it returns a bogus value which will -+ * almost certainly cause the system to hang. In the -+ */ -+int kgdb_in_isr = 0; -+int kgdb_in_lsr = 0; -+extern spinlock_t kgdb_spinlock; -+ -+/* Caller takes needed protections */ -+ -+int -+getDebugChar(void) -+{ -+ volatile int chr, dum, time, end_time; -+ -+ dbprintk(("getDebugChar(port %x): ", gdb_async_info->port)); -+ -+ if (gdb_async_info == NULL) { -+ gdb_hook_interrupt(&local_info, 0); -+ } -+ /* -+ * This trick says if we wait a very long time and get -+ * no char, return the -1 and let the upper level deal -+ * with it. -+ */ -+ rdtsc(dum, time); -+ end_time = time + 2; -+ while (((chr = read_char(gdb_async_info)) == -1) && -+ (end_time - time) > 0) { -+ rdtsc(dum, time); -+ }; -+ /* -+ * This covers our butts if some other code messes with -+ * our uart, hay, it happens :o) -+ */ -+ if (chr == -1) -+ program_uart(gdb_async_info); -+ -+ dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ')); -+ return (chr); -+ -+} /* getDebugChar */ -+ -+static int count = 3; -+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED; -+ -+static int __init -+kgdb_enable_ints(void) -+{ -+ if (gdb_async_info == NULL) { -+ gdb_hook_interrupt(&local_info, 1); -+ } -+ ok_to_enable_ints = 1; -+ kgdb_enable_ints_now(); -+#ifdef CONFIG_KGDB_USER_CONSOLE -+ kgdb_console_finit(); -+#endif -+ return 0; -+} -+ -+#ifdef CONFIG_SERIAL_8250 -+void shutdown_for_kgdb(struct async_struct *gdb_async_info); -+#endif -+ -+#ifdef CONFIG_DISCONTIGMEM -+static inline int kgdb_mem_init_done(void) -+{ -+ return highmem_start_page != NULL; -+} -+#else -+static inline int kgdb_mem_init_done(void) -+{ -+ return max_mapnr != 0; -+} -+#endif -+ -+static void -+kgdb_enable_ints_now(void) -+{ -+ if (!spin_trylock(&one_at_atime)) -+ return; -+ if (!ints_disabled) -+ goto exit; -+ if (kgdb_mem_init_done() && -+ ints_disabled) { /* don't try till mem init */ -+#ifdef CONFIG_SERIAL_8250 -+ /* -+ * The ifdef here allows the system to be configured -+ * without the serial driver. -+ * Don't make it a module, however, it will steal the port -+ */ -+ shutdown_for_kgdb(gdb_async_info); -+#endif -+ ints_disabled = request_irq(gdb_async_info->state->irq, -+ gdb_interrupt, -+ IRQ_T(gdb_async_info), -+ "KGDB-stub", NULL); -+ intprintk(("KGDB: request_irq returned %d\n", ints_disabled)); -+ } -+ if (!ints_disabled) { -+ intprintk(("KGDB: Sending %d to port %x offset %d\n", -+ gdb_async_info->IER, -+ (int) gdb_async_info->port, UART_IER)); -+ outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER); -+ } -+ exit: -+ spin_unlock(&one_at_atime); -+} -+ -+/* -+ * putDebugChar -+ * -+ * This is a GDB stub routine. It waits until the interface is ready -+ * to transmit a char and then sends it. If there is no serial -+ * interface connection then it simply returns to its caller, having -+ * pretended to send the char. Caller takes needed protections. -+ */ -+void -+putDebugChar(int chr) -+{ -+ dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n", -+ gdb_async_info->port, -+ chr, -+ chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1)); -+ -+ if (gdb_async_info == NULL) { -+ gdb_hook_interrupt(&local_info, 0); -+ } -+ -+ write_char(gdb_async_info, chr); /* this routine will wait */ -+ count = (chr == '#') ? 0 : count + 1; -+ if ((count == 2)) { /* try to enable after */ -+ if (ints_disabled & ok_to_enable_ints) -+ kgdb_enable_ints_now(); /* try to enable after */ -+ -+ /* We do this a lot because, well we really want to get these -+ * interrupts. The serial driver will clear these bits when it -+ * initializes the chip. Every thing else it does is ok, -+ * but this. -+ */ -+ if (!ints_disabled) { -+ outb_px(gdb_async_info->port + UART_IER, -+ gdb_async_info->IER); -+ } -+ } -+ -+} /* putDebugChar */ -+ -+module_init(kgdb_enable_ints); -diff -puN arch/i386/lib/Makefile~kgdb-ga arch/i386/lib/Makefile ---- 25/arch/i386/lib/Makefile~kgdb-ga 2004-10-21 14:54:15.265602768 -0700 -+++ 25-akpm/arch/i386/lib/Makefile 2004-10-21 14:54:15.313595472 -0700 -@@ -8,3 +8,4 @@ lib-y = checksum.o delay.o usercopy.o ge - - lib-$(CONFIG_X86_USE_3DNOW) += mmx.o - lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o -+lib-$(CONFIG_KGDB) += kgdb_serial.o -diff -puN arch/i386/Makefile~kgdb-ga arch/i386/Makefile ---- 25/arch/i386/Makefile~kgdb-ga 2004-10-21 14:54:15.266602616 -0700 -+++ 25-akpm/arch/i386/Makefile 2004-10-21 14:54:15.314595320 -0700 -@@ -99,6 +99,9 @@ core-$(CONFIG_X86_ES7000) := arch/i386/m - # default subarch .h files - mflags-y += -Iinclude/asm-i386/mach-default - -+mflags-$(CONFIG_KGDB) += -gdwarf-2 -+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g') -+ - head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o - - libs-y += arch/i386/lib/ -diff -puN arch/i386/mm/fault.c~kgdb-ga arch/i386/mm/fault.c ---- 25/arch/i386/mm/fault.c~kgdb-ga 2004-10-21 14:54:15.268602312 -0700 -+++ 25-akpm/arch/i386/mm/fault.c 2004-10-21 14:54:15.314595320 -0700 -@@ -430,6 +430,12 @@ no_context: - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ -+#ifdef CONFIG_KGDB -+ if (!user_mode(regs)){ -+ kgdb_handle_exception(14,SIGBUS, error_code, regs); -+ return; -+ } -+#endif - - bust_spinlocks(1); - -diff -puN arch/x86_64/boot/compressed/head.S~kgdb-ga arch/x86_64/boot/compressed/head.S ---- 25/arch/x86_64/boot/compressed/head.S~kgdb-ga 2004-10-21 14:54:15.269602160 -0700 -+++ 25-akpm/arch/x86_64/boot/compressed/head.S 2004-10-21 14:54:15.315595168 -0700 -@@ -26,6 +26,7 @@ - .code32 - .text - -+#define IN_BOOTLOADER - #include - #include - -diff -puN arch/x86_64/boot/compressed/misc.c~kgdb-ga arch/x86_64/boot/compressed/misc.c ---- 25/arch/x86_64/boot/compressed/misc.c~kgdb-ga 2004-10-21 14:54:15.270602008 -0700 -+++ 25-akpm/arch/x86_64/boot/compressed/misc.c 2004-10-21 14:54:15.315595168 -0700 -@@ -9,6 +9,7 @@ - * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 - */ - -+#define IN_BOOTLOADER - #include "miscsetup.h" - #include - -diff -puN /dev/null Documentation/i386/kgdb/andthen ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/andthen 2004-10-21 14:54:15.316595016 -0700 -@@ -0,0 +1,100 @@ -+ -+define set_andthen -+ set var $thp=0 -+ set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0] -+ set var $at_size = (sizeof kgdb_data)/(sizeof *$thp) -+ set var $at_oc=kgdb_and_then_count -+ set var $at_cc=$at_oc -+end -+ -+define andthen_next -+ set var $at_cc=$arg0 -+end -+ -+define andthen -+ andthen_set_edge -+ if ($at_cc >= $at_oc) -+ printf "Outside window. Window size is %d\n",($at_oc-$at_low) -+ else -+ printf "%d: ",$at_cc -+ output *($thp+($at_cc++ % $at_size )) -+ printf "\n" -+ end -+end -+define andthen_set_edge -+ set var $at_oc=kgdb_and_then_count -+ set var $at_low = $at_oc - $at_size -+ if ($at_low < 0 ) -+ set var $at_low = 0 -+ end -+ if (( $at_cc > $at_oc) || ($at_cc < $at_low)) -+ printf "Count outside of window, setting count to " -+ if ($at_cc >= $at_oc) -+ set var $at_cc = $at_oc -+ else -+ set var $at_cc = $at_low -+ end -+ printf "%d\n",$at_cc -+ end -+end -+ -+define beforethat -+ andthen_set_edge -+ if ($at_cc <= $at_low) -+ printf "Outside window. Window size is %d\n",($at_oc-$at_low) -+ else -+ printf "%d: ",$at_cc-1 -+ output *($thp+(--$at_cc % $at_size )) -+ printf "\n" -+ end -+end -+ -+document andthen_next -+ andthen_next -+ . sets the number of the event to display next. If this event -+ . is not in the event pool, either andthen or beforethat will -+ . correct it to the nearest event pool edge. The event pool -+ . ends at the last event recorded and begins -+ . prior to that. If beforethat is used next, it will display -+ . event -1. -+. -+ andthen commands are: set_andthen, andthen_next, andthen and beforethat -+end -+ -+ -+document andthen -+ andthen -+. displays the next event in the list. sets up to display -+. the oldest saved event first. -+. (optional) count of the event to display. -+. note the number of events saved is specified at configure time. -+. if events are saved between calls to andthen the index will change -+. but the displayed event will be the next one (unless the event buffer -+. is overrun). -+. -+. andthen commands are: set_andthen, andthen_next, andthen and beforethat -+end -+ -+document set_andthen -+ set_andthen -+. sets up to use the and commands. -+. if you have defined your own struct, use the above and -+. then enter the following: -+. p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0] -+. where is the name of your structure. -+. -+. andthen commands are: set_andthen, andthen_next, andthen and beforethat -+end -+ -+document beforethat -+ beforethat -+. displays the next prior event in the list. sets up to -+. display the last occuring event first. -+. -+. note the number of events saved is specified at configure time. -+. if events are saved between calls to beforethat the index will change -+. but the displayed event will be the next one (unless the event buffer -+. is overrun). -+. -+. andthen commands are: set_andthen, andthen_next, andthen and beforethat -+end -diff -puN /dev/null Documentation/i386/kgdb/debug-nmi.txt ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/debug-nmi.txt 2004-10-21 14:54:15.316595016 -0700 -@@ -0,0 +1,37 @@ -+Subject: Debugging with NMI -+Date: Mon, 12 Jul 1999 11:28:31 -0500 -+From: David Grothe -+Organization: Gcom, Inc -+To: David Grothe -+ -+Kernel hackers: -+ -+Maybe this is old hat, but it is new to me -- -+ -+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA -+slot you will generate an NMI to the CPU. This interrupts even a -+machine that is hung in a loop with interrupts disabled. Used in -+conjunction with kgdb < -+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can -+gain debugger control of a machine that is hung in the kernel! Even -+without kgdb the kernel will print a stack trace so you can find out -+where it was hung. -+ -+The A1/B1 pins are directly opposite one another and the farthest pins -+towards the bracket end of the ISA bus socket. You can stick a paper -+clip or multi-meter probe between them to short them out. -+ -+I had a spare ISA bus to PC104 bus adapter around. The PC104 end of the -+board consists of two rows of wire wrap pins. So I wired a push button -+between the A1/B1 pins and now have an ISA board that I can stick into -+any ISA bus slot for debugger entry. -+ -+Microsoft has a circuit diagram of a PCI card at -+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM. If you want to -+build one you will have to mail them and ask for the PAL equations. -+Nobody makes one comercially. -+ -+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER. It works for me, but if -+your machine catches fire, it is your problem, not mine.] -+ -+-- Dave (the kgdb guy) -diff -puN /dev/null Documentation/i386/kgdb/gdb-globals.txt ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/gdb-globals.txt 2004-10-21 14:54:15.317594864 -0700 -@@ -0,0 +1,71 @@ -+Sender: akale@veritas.com -+Date: Fri, 23 Jun 2000 19:26:35 +0530 -+From: "Amit S. Kale" -+Organization: Veritas Software (India) -+To: Dave Grothe , linux-kernel@vger.rutgers.edu -+CC: David Milburn , -+ "Edouard G. Parmelan" , -+ ezannoni@cygnus.com, Keith Owens -+Subject: Re: Module debugging using kgdb -+ -+Dave Grothe wrote: -+> -+> Amit: -+> -+> There is a 2.4.0 version of kgdb on our ftp site: -+> ftp://ftp.gcom.com/pub/linux/src/kgdb. I mirrored your version of gdb -+> and loadmodule.sh there. -+> -+> Have a look at the README file and see if I go it right. If not, send -+> me some corrections and I will update it. -+> -+> Does your version of gdb solve the global variable problem? -+ -+Yes. -+Thanks to Elena Zanoni, gdb (developement version) can now calculate -+correctly addresses of dynamically loaded object files. I have not been -+following gdb developement for sometime and am not sure when symbol -+address calculation fix is going to appear in a gdb stable version. -+ -+Elena, any idea when the fix will make it to a prebuilt gdb from a -+redhat release? -+ -+For the time being I have built a gdb developement version. It can be -+used for module debugging with loadmodule.sh script. -+ -+The problem with calculating of module addresses with previous versions -+of gdb was as follows: -+gdb did not use base address of a section while calculating address of -+a symbol in the section in an object file loaded via 'add-symbol-file'. -+It used address of .text segment instead. Due to this addresses of -+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly. -+ -+Above mentioned fix allow gdb to use base address of a segment while -+calculating address of a symbol in it. It adds a parameter '-s' to -+'add-symbol-file' command for specifying base address of a segment. -+ -+loadmodule.sh script works as follows. -+ -+1. Copy a module file to target machine. -+2. Load the module on the target machine using insmod with -m parameter. -+insmod produces a module load map which contains base addresses of all -+sections in the module and addresses of symbols in the module file. -+3. Find all sections and their base addresses in the module from -+the module map. -+4. Generate a script that loads the module file. The script uses -+'add-symbol-file' and specifies address of text segment followed by -+addresses of all segments in the module. -+ -+Here is an example gdb script produced by loadmodule.sh script. -+ -+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5 -+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38 -+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838 -+ -+With this command gdb can calculate addresses of symbols in ANY segment -+in a module file. -+ -+Regards. -+-- -+Amit Kale -+Veritas Software ( http://www.veritas.com ) -diff -puN /dev/null Documentation/i386/kgdb/gdbinit ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/gdbinit 2004-10-21 14:54:15.317594864 -0700 -@@ -0,0 +1,14 @@ -+shell echo -e "\003" >/dev/ttyS0 -+set remotebaud 38400 -+target remote /dev/ttyS0 -+define si -+stepi -+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx -+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp -+x/i $eip -+end -+define ni -+nexti -+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx -+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp -+x/i $eip -diff -puN /dev/null Documentation/i386/kgdb/gdbinit.hw ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/gdbinit.hw 2004-10-21 14:54:15.318594712 -0700 -@@ -0,0 +1,117 @@ -+ -+#Using ia-32 hardware breakpoints. -+# -+#4 hardware breakpoints are available in ia-32 processors. These breakpoints -+#do not need code modification. They are set using debug registers. -+# -+#Each hardware breakpoint can be of one of the -+#three types: execution, write, access. -+#1. An Execution breakpoint is triggered when code at the breakpoint address is -+#executed. -+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location -+#at the breakpoint address is written. -+#3. An access breakpoint is triggered when memory location at the breakpoint -+#address is either read or written. -+# -+#As hardware breakpoints are available in limited number, use software -+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints. -+# -+#Length of an access or a write breakpoint defines length of the datatype to -+#be watched. Length is 1 for char, 2 short , 3 int. -+# -+#For placing execution, write and access breakpoints, use commands -+#hwebrk, hwwbrk, hwabrk -+#To remove a breakpoint use hwrmbrk command. -+# -+#These commands take following types of arguments. For arguments associated -+#with each command, use help command. -+#1. breakpointno: 0 to 3 -+#2. length: 1 to 3 -+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc -+# -+#Use the command exinfo to find which hardware breakpoint occured. -+ -+#hwebrk breakpointno address -+define hwebrk -+ maintenance packet Y$arg0,0,0,$arg1 -+end -+document hwebrk -+ hwebrk
-+ Places a hardware execution breakpoint -+ = 0 - 3 -+
= Hex digits without leading "0x". -+end -+ -+#hwwbrk breakpointno length address -+define hwwbrk -+ maintenance packet Y$arg0,1,$arg1,$arg2 -+end -+document hwwbrk -+ hwwbrk
-+ Places a hardware write breakpoint -+ = 0 - 3 -+ = 1 (1 byte), 2 (2 byte), 3 (4 byte) -+
= Hex digits without leading "0x". -+end -+ -+#hwabrk breakpointno length address -+define hwabrk -+ maintenance packet Y$arg0,1,$arg1,$arg2 -+end -+document hwabrk -+ hwabrk
-+ Places a hardware access breakpoint -+ = 0 - 3 -+ = 1 (1 byte), 2 (2 byte), 3 (4 byte) -+
= Hex digits without leading "0x". -+end -+ -+#hwrmbrk breakpointno -+define hwrmbrk -+ maintenance packet y$arg0 -+end -+document hwrmbrk -+ hwrmbrk -+ = 0 - 3 -+ Removes a hardware breakpoint -+end -+ -+define reboot -+ maintenance packet r -+end -+#exinfo -+define exinfo -+ maintenance packet qE -+end -+document exinfo -+ exinfo -+ Gives information about a breakpoint. -+end -+define get_th -+ p $th=(struct thread_info *)((int)$esp & ~8191) -+end -+document get_th -+ get_tu -+ Gets and prints the current thread_info pointer, Defines th to be it. -+end -+define get_cu -+ p $cu=((struct thread_info *)((int)$esp & ~8191))->task -+end -+document get_cu -+ get_cu -+ Gets and print the "current" value. Defines $cu to be it. -+end -+define int_off -+ set var $flags=$eflags -+ set $eflags=$eflags&~0x200 -+ end -+define int_on -+ set var $eflags|=$flags&0x200 -+ end -+document int_off -+ saves the current interrupt state and clears the processor interrupt -+ flag. Use int_on to restore the saved flag. -+end -+document int_on -+ Restores the interrupt flag saved by int_off. -+end -diff -puN /dev/null Documentation/i386/kgdb/gdbinit-modules ---- /dev/null Thu Apr 11 07:25:15 2002 -+++ 25-akpm/Documentation/i386/kgdb/gdbinit-modules Fri Jan 13 17:54:25 2006 -@@ -0,0 +1,149 @@ -+# -+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub. -+# -+# This don't work for Linux-2.0 or older. -+# -+# Author Edouard G. Parmelan -+# -+# -+# Fri Apr 30 20:33:29 CEST 1999 -+# First public release. -+# -+# Major cleanup after experiment Linux-2.0 kernel without success. -+# Symbols of a module are not in the correct order, I can't explain -+# why :( -+# -+# Fri Mar 19 15:41:40 CET 1999 -+# Initial version. -+# -+# Thu Jan 6 16:29:03 CST 2000 -+# A little fixing by Dave Grothe -+# -+# Mon Jun 19 09:33:13 CDT 2000 -+# Alignment changes from Edouard Parmelan -+# -+# The basic idea is to find where insmod load the module and inform -+# GDB to load the symbol table of the module with the GDB command -+# ``add-symbol-file
''. -+# -+# The Linux kernel holds the list of all loaded modules in module_list, -+# this list end with &kernel_module (exactly with module->next == NULL, -+# but the last module is not a real module). -+# -+# Insmod allocates the struct module before the object file. Since -+# Linux-2.1, this structure contain his size. The real address of -+# the object file is then (char*)module + module->size_of_struct. -+# -+# You can use three user functions ``mod-list'', ``mod-print-symbols'' -+# and ``add-module-symbols''. -+# -+# mod-list list all loaded modules with the format: -+# -+# -+# As soon as you have found the address of your module, you can -+# print its exported symbols (mod-print-symbols) or inform GDB to add -+# symbols from your module file (mod-add-symbols). -+# -+# The argument that you give to mod-print-symbols or mod-add-symbols -+# is the from the mod-list command. -+# -+# When using the mod-add-symbols command you must also give the full -+# pathname of the modules object code file. -+# -+# The command mod-add-lis is an example of how to make this easier. -+# You can edit this macro to contain the path name of your own -+# favorite module and then use it as a shorthand to load it. You -+# still need the module-address, however. -+# -+# The internal function ``mod-validate'' set the GDB variable $mod -+# as a ``struct module*'' if the kernel known the module otherwise -+# $mod is set to NULL. This ensure to not add symbols for a wrong -+# address. -+# -+# -+# Sat Feb 12 20:05:47 CET 2005 -+# -+# Adapted to the 2.6.* module data structure. -+# (Getting miffed at gdb for not having "offsetof" in the process :-/ ) -+# -+# Autogenerate add-symbol-file statements from the module list instead -+# of relying on a no-longer-working loadmodule.sh program. -+# -+# Matthias Urlichs -+# -+# -+# Have a nice hacking day ! -+# -+# -+define mod-list -+ set $lmod = modules->next -+ # This is a circular data structure -+ while $lmod != &modules -+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list))) -+ printf "%p\t%s\n", $mod, $mod->name -+ set $lmod = $lmod->next -+ end -+end -+document mod-list -+mod-list -+List all modules in the form: -+Use the as the argument for the other -+mod-commands: mod-print-symbols, mod-add-symbols. -+end -+ -+define mod-list-syms -+ set $lmod = modules->next -+ # This is a circular data structure -+ while $lmod != &modules -+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list))) -+ printf "add-symbol-file %s.ko %p\n", $mod->name, $mod->module_core -+ set $lmod = $lmod->next -+ end -+end -+document mod-list-syms -+mod-list-syms -+List all modules in the form: add-symbol-file -+for adding modules' symbol tables without loadmodule.sh. -+end -+ -+define mod-validate -+ set $lmod = modules->next -+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list))) -+ while ($lmod != &modules) && ($mod != $arg0) -+ set $lmod = $lmod->next -+ set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list))) -+ end -+ if $lmod == &modules -+ set $mod = 0 -+ printf "%p is not a module\n", $arg0 -+ end -+end -+document mod-validate -+mod-validate -+Internal user-command used to validate the module parameter. -+If is a real loaded module, set $mod to it, otherwise set $mod -+to 0. -+end -+ -+define mod-print-symbols -+ mod-validate $arg0 -+ if $mod != 0 -+ set $i = 0 -+ while $i < $mod->num_syms -+ set $sym = $mod->syms[$i] -+ printf "%p\t%s\n", $sym->value, $sym->name -+ set $i = $i + 1 -+ end -+ set $i = 0 -+ while $i < $mod->num_gpl_syms -+ set $sym = $mod->gpl_syms[$i] -+ printf "%p\t%s\n", $sym->value, $sym->name -+ set $i = $i + 1 -+ end -+ end -+end -+document mod-print-symbols -+mod-print-symbols -+Print all exported symbols of the module. See mod-list -+end -+ -diff -puN /dev/null Documentation/i386/kgdb/kgdb.txt ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/kgdb.txt 2004-10-21 14:54:15.324593800 -0700 -@@ -0,0 +1,775 @@ -+Last edit: <20030806.1637.12> -+This file has information specific to the i386 kgdb option. Other -+platforms with the kgdb option may behave in a similar fashion. -+ -+New features: -+============ -+20030806.1557.37 -+This version was made against the 2.6.0-test2 kernel. We have made the -+following changes: -+ -+- The getthread() code in the stub calls find_task_by_pid(). It fails -+ if we are early in the bring up such that the pid arrays have yet to -+ be allocated. We have added a line to kernel/pid.c to make -+ "kgdb_pid_init_done" true once the arrays are allocated. This way the -+ getthread() code knows not to call. This is only used by the thread -+ debugging stuff and threads will not yet exist at this point in the -+ boot. -+ -+- For some reason, gdb was not asking for a new thread list when the -+ "info thread" command was given. We changed to the newer version of -+ the thread info command and gdb now seems to ask when needed. Result, -+ we now get all threads in the thread list. -+ -+- We now respond to the ThreadExtraInfo request from gdb with the thread -+ name from task_struct .comm. This then appears in the thread list. -+ Thoughts on additional options for this are welcome. Things such as -+ "has BKL" and "Preempted" come to mind. I think we could have a flag -+ word that could enable different bits of info here. -+ -+- We now honor, sort of, the C and S commands. These are continue and -+ single set after delivering a signal. We ignore the signal and do the -+ requested action. This only happens when we told gdb that a signal -+ was the reason for entry, which is only done on memory faults. The -+ result is that you can now continue into the Oops. -+ -+- We changed the -g to -gdwarf-2. This seems to be the same as -ggdb, -+ but it is more exact on what language to use. -+ -+- We added two dwarf2 include files and a bit of code at the end of -+ entry.S. This does not yet work, so it is disabled. Still we want to -+ keep track of the code and "maybe" someone out there can fix it. -+ -+- Randy Dunlap sent some fix ups for this file which are now merged. -+ -+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a -+ compiler warning if CONFIG_KGDB is off (now who would do that :). -+ -+- Andrew Morton sent a fix for the serial driver which is now merged. -+ -+- Andrew also sent a change to the stub around the cpu managment code -+ which is also merged. -+ -+- Andrew also sent a patch to make "f" as well as "g" work as SysRq -+ commands to enter kgdb, merged. -+ -+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a -+ "who" field to the spinlock data struct. This is filled with -+ "current" when ever the spinlock suceeds. Useful if you want to know -+ who has the lock. -+ -+_ And last, but not least, we fixed the "get_cu" macro to properly get -+ the current value of "current". -+ -+New features: -+============ -+20030505.1827.27 -+We are starting to align with the sourceforge version, at least in -+commands. To this end, the boot command string to start kgdb at -+boot time has been changed from "kgdb" to "gdb". -+ -+Andrew Morton sent a couple of patches which are now included as follows: -+1.) We now return a flag to the interrupt handler. -+2.) We no longer use smp_num_cpus (a conflict with the lock meter). -+3.) And from William Lee Irwin III code to make -+ sure high-mem is set up before we attempt to register our interrupt -+ handler. -+We now include asm/kgdb.h from config.h so you will most likely never -+have to include it. It also 'NULLS' the kgdb macros you might have in -+your code when CONFIG_KGDB is not defined. This allows you to just -+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such. -+This include is conditioned on the machine being an x86 so as to not -+mess with other archs. -+ -+20020801.1129.03 -+This is currently the version for the 2.4.18 (and beyond?) kernel. -+ -+We have several new "features" beginning with this version: -+ -+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI. No more -+ waiting and it will pull that guy out of an IRQ off spin lock :) -+ -+2.) We doctored up the code that tells where a task is waiting and -+ included it so that the "info thread" command will show a bit more -+ than "schedule()". Try it... -+ -+3.) Added the ability to call a function from gdb. All the standard gdb -+ issues apply, i.e. if you hit a breakpoint in the function, you are -+ not allowed to call another (gdb limitation, not kgdb). To help -+ this capability we added a memory allocation function. Gdb does not -+ return this memory (it is used for strings that you pass to that function -+ you are calling from gdb) so we fixed up a way to allow you to -+ manually return the memory (see below). -+ -+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the -+ interrupt flag to now also include the preemption count and the -+ "in_interrupt" info. The flag is now called "with_pif" to indicate -+ the order, preempt_count, in_interrupt, flag. The preempt_count is -+ shifted left by 4 bits so you can read the count in hex by dropping -+ the low order digit. In_interrupt is in bit 1, and the flag is in -+ bit 0. -+ -+5.) The command: "p kgdb_info" is now expanded and prints something -+ like: -+(gdb) p kgdb_info -+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259, -+ errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1, -+ cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0, -+ regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}} -+ -+ Things to note here: a.) used_malloc is the amount of memory that -+ has been malloc'ed to do calls from gdb. You can reclaim this -+ memory like this: "p kgdb_info.used_malloc=0" Cool, huh? b.) -+ cpus_waiting is now "sized" by the number of CPUs you enter at -+ configure time in the kgdb configure section. This is NOT used -+ anywhere else in the system, but it is "nice" here. c.) The task's -+ "pid" is now in the structure. This is the pid you will need to use -+ to decode to the thread id to get gdb to look at that thread. -+ Remember that the "info thread" command prints a list of threads -+ wherein it numbers each thread with its reference number followed -+ by the thread's pid. Note that the per-CPU idle threads actually -+ have pids of 0 (yes, there is more than one pid 0 in an SMP system). -+ To avoid confusion, kgdb numbers these threads with numbers beyond -+ the MAX_PID. That is why you see 32768 and above. -+ -+6.) A subtle change, we now provide the complete register set for tasks -+ that are active on the other CPUs. This allows better trace back on -+ those tasks. -+ -+ And, let's mention what we could not fix. Back-trace from all but the -+ thread that we trapped will, most likely, have a bogus entry in it. -+ The problem is that gdb does not recognize the entry code for -+ functions that use "current" near (at all?) the entry. The compiler -+ is putting the "current" decode as the first two instructions of the -+ function where gdb expects to find %ebp changing code. Back trace -+ also has trouble with interrupt frames. I am talking with Daniel -+ Jacobowitz about some way to fix this, but don't hold your breath. -+ -+20011220.0050.35 -+Major enhancement with this version is the ability to hold one or more -+CPUs in an SMP system while allowing the others to continue. Also, by -+default only the current CPU is enabled on single-step commands (please -+note that gdb issues single-step commands at times other than when you -+use the si command). -+ -+Another change is to collect some useful information in -+a global structure called "kgdb_info". You should be able to just: -+ -+p kgdb_info -+ -+although I have seen cases where the first time this is done gdb just -+prints the first member but prints the whole structure if you then enter -+CR (carriage return or enter). This also works: -+ -+p *&kgdb_info -+ -+Here is a sample: -+(gdb) p kgdb_info -+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0, -+ vector = 3, print_debug_info = 0} -+ -+"Called_from" is the return address from the current entry into kgdb. -+Sometimes it is useful to know why you are in kgdb, for example, was -+it an NMI or a real breakpoint? The simple way to interrogate this -+return address is: -+ -+l *0xc010732c -+ -+which will print the surrounding few lines of source code. -+ -+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the -+kgdb_ts entries). -+ -+"errcode" and "vector" are other entry parameters which may be helpful on -+some traps. -+ -+"print_debug_info" is the internal debugging kgdb print enable flag. Yes, -+you can modify it. -+ -+In SMP systems kgdb_info also includes the "cpus_waiting" structure and -+"hold_on_step": -+ -+(gdb) p kgdb_info -+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0, -+ vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{ -+ task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0, -+ regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, -+ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, -+ hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0, -+ hold = 0, regs = 0x0}}} -+ -+"Cpus_waiting" has an entry for each CPU other than the current one that -+has been stopped. Each entry contains the task_struct address for that -+CPU, the address of the regs for that task and a hold flag. All these -+have the proper typing so that, for example: -+ -+p *kgdb_info.cpus_waiting[1].regs -+ -+will print the registers for CPU 1. -+ -+"Hold_on_sstep" is a new feature with this version and comes up set or -+true. What this means is that whenever kgdb is asked to single-step all -+other CPUs are held (i.e. not allowed to execute). The flag applies to -+all but the current CPU and, again, can be changed: -+ -+p kgdb_info.hold_on_sstep=0 -+ -+restores the old behavior of letting all CPUs run during single-stepping. -+ -+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out -+of execution. Note that this has some risk in cases where the CPUs need -+to communicate with each other. If kgdb finds no CPU available on exit, -+it will push a message thru gdb and stay in kgdb. Note that it is legal -+to hold the current CPU as long as at least one CPU can execute. -+ -+20010621.1117.09 -+This version implements an event queue. Events are signaled by calling -+a function in the kgdb stub and may be examined from gdb. See EVENTS -+below for details. This version also tightens up the interrupt and SMP -+handling to not allow interrupts on the way to kgdb from a breakpoint -+trap. It is fine to allow these interrupts for user code, but not -+system debugging. -+ -+Version -+======= -+ -+This version of the kgdb package was developed and tested on -+kernel version 2.4.16. It will not install on any earlier kernels. -+It is possible that it will continue to work on later versions -+of 2.4 and then versions of 2.5 (I hope). -+ -+ -+Debugging Setup -+=============== -+ -+Designate one machine as the "development" machine. This is the -+machine on which you run your compiles and which has your source -+code for the kernel. Designate a second machine as the "target" -+machine. This is the machine that will run your experimental -+kernel. -+ -+The two machines will be connected together via a serial line out -+one or the other of the COM ports of the PC. You will need the -+appropriate modem eliminator (null modem) cable(s) for this. -+ -+Decide on which tty port you want the machines to communicate, then -+connect them up back-to-back using the null modem cable. COM1 is -+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection -+with the two machines prior to trying to debug a kernel. Once you -+have it working, on the TARGET machine, enter: -+ -+setserial /dev/ttyS0 (or what ever tty you are using) -+ -+and record the port address and the IRQ number. -+ -+On the DEVELOPMENT machine you need to apply the patch for the kgdb -+hooks. You have probably already done that if you are reading this -+file. -+ -+On your DEVELOPMENT machine, go to your kernel source directory and do -+"make Xconfig" where X is one of "x", "menu", or "". If you are -+configuring in the standard serial driver, it must not be a module. -+Either yes or no is ok, but making the serial driver a module means it -+will initialize after kgdb has set up the UART interrupt code and may -+cause a failure of the control-C option discussed below. The configure -+question for the serial driver is under the "Character devices" heading -+and is: -+ -+"Standard/generic (8250/16550 and compatible UARTs) serial support" -+ -+Go down to the kernel debugging menu item and open it up. Enable the -+kernel kgdb stub code by selecting that item. You can also choose to -+turn on the "-ggdb -O1" compile options. The -ggdb causes the compiler -+to put more debug info (like local symbols) in the object file. On the -+i386 -g and -ggdb are the same so this option just reduces to "O1". The -+-O1 reduces the optimization level. This may be helpful in some cases, -+be aware, however, that this may also mask the problem you are looking -+for. -+ -+The baud rate. Default is 115200. What ever you choose be sure that -+the host machine is set to the same speed. I recommend the default. -+ -+The port. This is the I/O address of the serial UART that you should -+have gotten using setserial as described above. The standard COM1 port -+(3f8) using IRQ 4 is default. COM2 is 2f8 which by convention uses IRQ -+3. -+ -+The port IRQ (see above). -+ -+Stack overflow test. This option makes a minor change in the trap, -+system call and interrupt code to detect stack overflow and transfer -+control to kgdb if it happens. (Some platforms have this in the -+baseline code, but the i386 does not.) -+ -+You can also configure the system to recognize the boot option -+"console=kgdb" which if given will cause all console output during -+booting to be put thru gdb as well as other consoles. This option -+requires that gdb and kgdb be connected prior to sending console output -+so, if they are not, a breakpoint is executed to force the connection. -+This will happen before any kernel output (it is going thru gdb, right), -+and will stall the boot until the connection is made. -+ -+You can also configure in a patch to SysRq to enable the kGdb SysRq. -+This request generates a breakpoint. Since the serial port IRQ line is -+set up after any serial drivers, it is possible that this command will -+work when the control-C will not. -+ -+Save and exit the Xconfig program. Then do "make clean" , "make dep" -+and "make bzImage" (or whatever target you want to make). This gets the -+kernel compiled with the "-g" option set -- necessary for debugging. -+ -+You have just built the kernel on your DEVELOPMENT machine that you -+intend to run on your TARGET machine. -+ -+To install this new kernel, use the following installation procedure. -+Remember, you are on the DEVELOPMENT machine patching the kernel source -+for the kernel that you intend to run on the TARGET machine. -+ -+Copy this kernel to your target machine using your usual procedures. I -+usually arrange to copy development: -+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine -+via a LAN based NFS access. That is, I run the cp command on the target -+and copy from the development machine via the LAN. Run Lilo (see "man -+lilo" for details on how to set this up) on the new kernel on the target -+machine so that it will boot! Then boot the kernel on the target -+machine. -+ -+On the DEVELOPMENT machine, create a file called .gdbinit in the -+directory /usr/src/linux. An example .gdbinit file looks like this: -+ -+shell echo -e "\003" >/dev/ttyS0 -+set remotebaud 38400 (or what ever speed you have chosen) -+target remote /dev/ttyS0 -+ -+ -+Change the "echo" and "target" definition so that it specifies the tty -+port that you intend to use. Change the "remotebaud" definition to -+match the data rate that you are going to use for the com line. -+ -+You are now ready to try it out. -+ -+Boot your target machine with "kgdb" in the boot command i.e. something -+like: -+ -+lilo> test kgdb -+ -+or if you also want console output thru gdb: -+ -+lilo> test kgdb console=kgdb -+ -+You should see the lilo message saying it has loaded the kernel and then -+all output stops. The kgdb stub is trying to connect with gdb. Start -+gdb something like this: -+ -+ -+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux". -+When gdb gets the symbols loaded it will read your .gdbinit file and, if -+everything is working correctly, you should see gdb print out a few -+lines indicating that a breakpoint has been taken. It will actually -+show a line of code in the target kernel inside the kgdb activation -+code. -+ -+The gdb interaction should look something like this: -+ -+ linux-dev:/usr/src/linux# gdb vmlinux -+ GDB is free software and you are welcome to distribute copies of it -+ under certain conditions; type "show copying" to see the conditions. -+ There is absolutely no warranty for GDB; type "show warranty" for details. -+ GDB 4.15.1 (i486-slackware-linux), -+ Copyright 1995 Free Software Foundation, Inc... -+ breakpoint () at i386-stub.c:750 -+ 750 } -+ (gdb) -+ -+You can now use whatever gdb commands you like to set breakpoints. -+Enter "continue" to start your target machine executing again. At this -+point the target system will run at full speed until it encounters -+your breakpoint or gets a segment violation in the kernel, or whatever. -+ -+If you have the kgdb console enabled when you continue, gdb will print -+out all the console messages. -+ -+The above example caused a breakpoint relatively early in the boot -+process. For the i386 kgdb it is possible to code a break instruction -+as the first C-language point in init/main.c, i.e. as the first instruction -+in start_kernel(). This could be done as follows: -+ -+#include -+ breakpoint(); -+ -+This breakpoint() is really a function that sets up the breakpoint and -+single-step hardware trap cells and then executes a breakpoint. Any -+early hard coded breakpoint will need to use this function. Once the -+trap cells are set up they need not be set again, but doing it again -+does not hurt anything, so you don't need to be concerned about which -+breakpoint is hit first. Once the trap cells are set up (and the kernel -+sets them up in due course even if breakpoint() is never called) the -+macro: -+ -+BREAKPOINT; -+ -+will generate an inline breakpoint. This may be more useful as it stops -+the processor at the instruction instead of in a function a step removed -+from the location of interest. In either case must be -+included to define both breakpoint() and BREAKPOINT. -+ -+Triggering kgdbstub at other times -+================================== -+ -+Often you don't need to enter the debugger until much later in the boot -+or even after the machine has been running for some time. Once the -+kernel is booted and interrupts are on, you can force the system to -+enter the debugger by sending a control-C to the debug port. This is -+what the first line of the recommended .gdbinit file does. This allows -+you to start gdb any time after the system is up as well as when the -+system is already at a breakpoint. (In the case where the system is -+already at a breakpoint the control-C is not needed, however, it will -+be ignored by the target so no harm is done. Also note the the echo -+command assumes that the port speed is already set. This will be true -+once gdb has connected, but it is best to set the port speed before you -+run gdb.) -+ -+Another simple way to do this is to put the following file in you ~/bin -+directory: -+ -+#!/bin/bash -+echo -e "\003" > /dev/ttyS0 -+ -+Here, the ttyS0 should be replaced with what ever port you are using. -+The "\003" is control-C. Once you are connected with gdb, you can enter -+control-C at the command prompt. -+ -+An alternative way to get control to the debugger is to enable the kGdb -+SysRq command. Then you would enter Alt-SysRq-g (all three keys at the -+same time, but push them down in the order given). To refresh your -+memory of the available SysRq commands try Alt-SysRq-=. Actually any -+undefined command could replace the "=", but I like to KNOW that what I -+am pushing will never be defined. -+ -+Debugging hints -+=============== -+ -+You can break into the target machine at any time from the development -+machine by typing ^C (see above paragraph). If the target machine has -+interrupts enabled this will stop it in the kernel and enter the -+debugger. -+ -+There is unfortunately no way of breaking into the kernel if it is -+in a loop with interrupts disabled, so if this happens to you then -+you need to place exploratory breakpoints or printk's into the kernel -+to find out where it is looping. The exploratory breakpoints can be -+entered either thru gdb or hard coded into the source. This is very -+handy if you do something like: -+ -+if () BREAKPOINT; -+ -+ -+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory -+(debug-nmi.txt) which describes how to create an NMI on an ISA bus -+machine using a paper clip. I have a sophisticated version of this made -+by wiring a push button switch into a PC104/ISA bus adapter card. The -+adapter card nicely furnishes wire wrap pins for all the ISA bus -+signals. -+ -+When you are done debugging the kernel on the target machine it is a -+good idea to leave it in a running state. This makes reboots faster, -+bypassing the fsck. So do a gdb "continue" as the last gdb command if -+this is possible. To terminate gdb itself on the development machine -+and leave the target machine running, first clear all breakpoints and -+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or -+something similar. -+ -+If gdbstub Does Not Work -+======================== -+ -+If it doesn't work, you will have to troubleshoot it. Do the easy -+things first like double checking your cabling and data rates. You -+might try some non-kernel based programs to see if the back-to-back -+connection works properly. Just something simple like cat /etc/hosts -+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you -+if you can send data from one machine to the other. Make sure it works -+in both directions. There is no point in tearing out your hair in the -+kernel if the line doesn't work. -+ -+All of the real action takes place in the file -+/usr/src/linux/arch/i386/kernel/kgdb_stub.c. That is the code on the target -+machine that interacts with gdb on the development machine. In gdb you can -+turn on a debug switch with the following command: -+ -+ set remotedebug -+ -+This will print out the protocol messages that gdb is exchanging with -+the target machine. -+ -+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is -+the code that talks to the serial port on the target side. There might -+be a problem there. In particular there is a section of this code that -+tests the UART which will tell you what UART you have if you define -+"PRNT" (just remove "_off" from the #define PRNT_off). To view this -+report you will need to boot the system without any beakpoints. This -+allows the kernel to run to the point where it calls kgdb to set up -+interrupts. At this time kgdb will test the UART and print out the type -+it finds. (You need to wait so that the printks are actually being -+printed. Early in the boot they are cached, waiting for the console to -+be enabled. Also, if kgdb is entered thru a breakpoint it is possible -+to cause a dead lock by calling printk when the console is locked. The -+stub thus avoids doing printks from breakpoints, especially in the -+serial code.) At this time, if the UART fails to do the expected thing, -+kgdb will print out (using printk) information on what failed. (These -+messages will be buried in all the other boot up messages. Look for -+lines that start with "gdb_hook_interrupt:". You may want to use dmesg -+once the system is up to view the log. If this fails or if you still -+don't connect, review your answers for the port address. Use: -+ -+setserial /dev/ttyS0 -+ -+to get the current port and IRQ information. This command will also -+tell you what the system found for the UART type. The stub recognizes -+the following UART types: -+ -+16450, 16550, and 16550A -+ -+If you are really desperate you can use printk debugging in the -+kgdbstub code in the target kernel until you get it working. In particular, -+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c -+named "remote_debug". Compile your kernel with this set to 1, rather -+than 0 and the debug stub will print out lots of stuff as it does -+what it does. Likewise there are debug printks in the kgdb_serial.c -+code that can be turned on with simple changes in the macro defines. -+ -+ -+Debugging Loadable Modules -+========================== -+ -+This technique comes courtesy of Edouard Parmelan -+ -+ -+When you run gdb, enter the command -+ -+source gdbinit-modules -+ -+This will read in a file of gdb macros that was installed in your -+kernel source directory when kgdb was installed. This file implements -+the following commands: -+ -+mod-list -+ Lists the loaded modules in the form -+ -+mod-print-symbols -+ Prints all the symbols in the indicated module. -+ -+mod-add-symbols -+ Loads the symbols from the object file and associates them -+ with the indicated module. -+ -+After you have loaded the module that you want to debug, use the command -+mod-list to find the of your module. Then use that -+address in the mod-add-symbols command to load your module's symbols. -+From that point onward you can debug your module as if it were a part -+of the kernel. -+ -+The file gdbinit-modules also contains a command named mod-add-lis as -+an example of how to construct a command of your own to load your -+favorite module. The idea is to "can" the pathname of the module -+in the command so you don't have to type so much. -+ -+Threads -+======= -+ -+Each process in a target machine is seen as a gdb thread. gdb thread -+related commands (info threads, thread n) can be used. -+ -+ia-32 hardware breakpoints -+========================== -+ -+kgdb stub contains support for hardware breakpoints using debugging features -+of ia-32(x86) processors. These breakpoints do not need code modification. -+They use debugging registers. 4 hardware breakpoints are available in ia-32 -+processors. -+ -+Each hardware breakpoint can be of one of the following three types. -+ -+1. Execution breakpoint - An Execution breakpoint is triggered when code -+ at the breakpoint address is executed. -+ -+ As limited number of hardware breakpoints are available, it is -+ advisable to use software breakpoints ( break command ) instead -+ of execution hardware breakpoints, unless modification of code -+ is to be avoided. -+ -+2. Write breakpoint - A write breakpoint is triggered when memory -+ location at the breakpoint address is written. -+ -+ A write or can be placed for data of variable length. Length of -+ a write breakpoint indicates length of the datatype to be -+ watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for -+ 4 byte data. -+ -+3. Access breakpoint - An access breakpoint is triggered when memory -+ location at the breakpoint address is either read or written. -+ -+ Access breakpoints also have lengths similar to write breakpoints. -+ -+IO breakpoints in ia-32 are not supported. -+ -+Since gdb stub at present does not use the protocol used by gdb for hardware -+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros -+for hardware breakpoints are described below. -+ -+hwebrk - Places an execution breakpoint -+ hwebrk breakpointno address -+hwwbrk - Places a write breakpoint -+ hwwbrk breakpointno length address -+hwabrk - Places an access breakpoint -+ hwabrk breakpointno length address -+hwrmbrk - Removes a breakpoint -+ hwrmbrk breakpointno -+exinfo - Tells whether a software or hardware breakpoint has occurred. -+ Prints number of the hardware breakpoint if a hardware breakpoint has -+ occurred. -+ -+Arguments required by these commands are as follows -+breakpointno - 0 to 3 -+length - 1 to 3 -+address - Memory location in hex digits ( without 0x ) e.g c015e9bc -+ -+SMP support -+========== -+ -+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb -+client, all the processors are forced to enter the debugger. Current -+thread corresponds to the thread running on the processor where -+breakpoint occurred. Threads running on other processor(s) appear -+similar to other non-running threads in the 'info threads' output. -+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb -+records the values of "current" and "regs" for each CPU other than the -+one that hit the breakpoint. "current" is a pointer to the task -+structure for the task that CPU is running, while "regs" points to the -+saved registers for the task. This structure can be examined with the -+gdb "p" command. -+ -+ia-32 hardware debugging registers on all processors are set to same -+values. Hence any hardware breakpoints may occur on any processor. -+ -+gdb troubleshooting -+=================== -+ -+1. gdb hangs -+Kill it. restart gdb. Connect to target machine. -+ -+2. gdb cannot connect to target machine (after killing a gdb and -+restarting another) If the target machine was not inside debugger when -+you killed gdb, gdb cannot connect because the target machine won't -+respond. In this case echo "Ctrl+C"(ASCII 3) to the serial line. -+e.g. echo -e "\003" > /dev/ttyS1 -+This forces that target machine into the debugger, after which you -+can connect. -+ -+3. gdb cannot connect even after echoing Ctrl+C into serial line -+Try changing serial line settings min to 1 and time to 0 -+e.g. stty min 1 time 0 < /dev/ttyS1 -+Try echoing again -+ -+Check serial line speed and set it to correct value if required -+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1 -+ -+EVENTS -+====== -+ -+Ever want to know the order of things happening? Which CPU did what and -+when? How did the spinlock get the way it is? Then events are for -+you. Events are defined by calls to an event collection interface and -+saved for later examination. In this case, kgdb events are saved by a -+very fast bit of code in kgdb which is fully SMP and interrupt protected -+and they are examined by using gdb to display them. Kgdb keeps only -+the last N events, where N must be a power of two and is defined at -+configure time. -+ -+ -+Events are signaled to kgdb by calling: -+ -+kgdb_ts(data0,data1) -+ -+For each call kgdb records each call in an array along with other info. -+Here is the array definition: -+ -+struct kgdb_and_then_struct { -+#ifdef CONFIG_SMP -+ int on_cpu; -+#endif -+ long long at_time; -+ int from_ln; -+ char * in_src; -+ void *from; -+ int with_if; -+ int data0; -+ int data1; -+}; -+ -+For SMP machines the CPU is recorded, for all machines the TSC is -+recorded (gets a time stamp) as well as the line number and source file -+the call was made from. The address of the (from), the "if" (interrupt -+flag) and the two data items are also recorded. The macro kgdb_ts casts -+the types to int, so you can put any 32-bit values here. There is a -+configure option to select the number of events you want to keep. A -+nice number might be 128, but you can keep up to 1024 if you want. The -+number must be a power of two. An "andthen" macro library is provided -+for gdb to help you look at these events. It is also possible to define -+a different structure for the event storage and cast the data to this -+structure. For example the following structure is defined in kgdb: -+ -+struct kgdb_and_then_struct2 { -+#ifdef CONFIG_SMP -+ int on_cpu; -+#endif -+ long long at_time; -+ int from_ln; -+ char * in_src; -+ void *from; -+ int with_if; -+ struct task_struct *t1; -+ struct task_struct *t2; -+}; -+ -+If you use this for display, the data elements will be displayed as -+pointers to task_struct entries. You may want to define your own -+structure to use in casting. You should only change the last two items -+and you must keep the structure size the same. Kgdb will handle these -+as 32-bit ints, but within that constraint you can define a structure to -+cast to any 32-bit quantity. This need only be available to gdb and is -+only used for casting in the display code. -+ -+Final Items -+=========== -+ -+I picked up this code from Amit S. Kale and enhanced it. -+ -+If you make some really cool modification to this stuff, or if you -+fix a bug, please let me know. -+ -+George Anzinger -+ -+ -+Amit S. Kale -+ -+ -+(First kgdb by David Grothe ) -+ -+(modified by Tigran Aivazian ) -+ Putting gdbstub into the kernel config menu. -+ -+(modified by Scott Foehner ) -+ Hooks for entering gdbstub at boot time. -+ -+(modified by Amit S. Kale ) -+ Threads, ia-32 hw debugging, mp support, console support, -+ nmi watchdog handling. -+ -+(modified by George Anzinger ) -+ Extended threads to include the idle threads. -+ Enhancements to allow breakpoint() at first C code. -+ Use of module_init() and __setup() to automate the configure. -+ Enhanced the cpu "collection" code to work in early bring-up. -+ Added ability to call functions from gdb -+ Print info thread stuff without going back to schedule() -+ Now collect the "other" cpus with an IPI/ NMI. -diff -puN /dev/null Documentation/i386/kgdb/loadmodule.sh ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/Documentation/i386/kgdb/loadmodule.sh 2004-10-21 14:54:15.325593648 -0700 -@@ -0,0 +1,78 @@ -+#/bin/sh -+# This script loads a module on a target machine and generates a gdb script. -+# source generated gdb script to load the module file at appropriate addresses -+# in gdb. -+# -+# Usage: -+# Loading the module on target machine and generating gdb script) -+# [foo]$ loadmodule.sh -+# -+# Loading the module file into gdb -+# (gdb) source -+# -+# Modify following variables according to your setup. -+# TESTMACHINE - Name of the target machine -+# GDBSCRIPTS - The directory where a gdb script will be generated -+# -+# Author: Amit S. Kale (akale@veritas.com). -+# -+# If you run into problems, please check files pointed to by following -+# variables. -+# ERRFILE - /tmp/.errs contains stderr output of insmod -+# MAPFILE - /tmp/.map contains stdout output of insmod -+# GDBSCRIPT - $GDBSCRIPTS/load gdb script. -+ -+TESTMACHINE=foo -+GDBSCRIPTS=/home/bar -+ -+if [ $# -lt 1 ] ; then { -+ echo Usage: $0 modulefile -+ exit -+} ; fi -+ -+MODULEFILE=$1 -+MODULEFILEBASENAME=`basename $1` -+ -+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then { -+ MODULEFILE=`pwd`/$MODULEFILE -+} fi -+ -+ERRFILE=/tmp/$MODULEFILEBASENAME.errs -+MAPFILE=/tmp/$MODULEFILEBASENAME.map -+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME -+ -+function findaddr() { -+ local ADDR=0x$(echo "$SEGMENTS" | \ -+ grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \ -+ sed 's/[ ]*[^ ]*$//') -+ echo $ADDR -+} -+ -+function checkerrs() { -+ if [ "`cat $ERRFILE`" != "" ] ; then { -+ cat $ERRFILE -+ exit -+ } fi -+} -+ -+#load the module -+echo Copying $MODULEFILE to $TESTMACHINE -+rcp $MODULEFILE root@${TESTMACHINE}: -+ -+echo Loading module $MODULEFILE -+rsh -l root $TESTMACHINE /sbin/insmod -m ./`basename $MODULEFILE` \ -+ > $MAPFILE 2> $ERRFILE -+checkerrs -+ -+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10` -+TEXTADDR=$(findaddr "\\.text[^.]") -+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR" -+SEGADDRS=`echo "$SEGMENTS" | awk '//{ -+ if ($1 != ".text" && $1 != ".this" && -+ $1 != ".kstrtab" && $1 != ".kmodtab") { -+ print " -s " $1 " 0x" $3 " " -+ } -+}'` -+LOADSTRING="$LOADSTRING $SEGADDRS" -+echo Generating script $GDBSCRIPT -+echo $LOADSTRING > $GDBSCRIPT -diff -puN drivers/char/keyboard.c~kgdb-ga drivers/char/keyboard.c ---- 25/drivers/char/keyboard.c~kgdb-ga 2004-10-21 14:54:15.273601552 -0700 -+++ 25-akpm/drivers/char/keyboard.c 2004-10-21 14:54:15.326593496 -0700 -@@ -1081,6 +1081,9 @@ void kbd_keycode(unsigned int keycode, i - } - if (sysrq_down && down && !rep) { - handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty); -+#ifdef CONFIG_KGDB_SYSRQ -+ sysrq_down = 0; /* in case we miss the "up" event */ -+#endif - return; - } - #endif -diff -puN drivers/char/sysrq.c~kgdb-ga drivers/char/sysrq.c ---- 25/drivers/char/sysrq.c~kgdb-ga 2004-10-21 14:54:15.275601248 -0700 -+++ 25-akpm/drivers/char/sysrq.c 2004-10-21 14:54:15.326593496 -0700 -@@ -35,6 +35,25 @@ - #include - - #include -+#ifdef CONFIG_KGDB_SYSRQ -+ -+#define GDB_OP &kgdb_op -+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty) -+{ -+ printk("kgdb sysrq\n"); -+ breakpoint(); -+} -+ -+static struct sysrq_key_op kgdb_op = { -+ .handler = kgdb_sysrq, -+ .help_msg = "kGdb|Fgdb", -+ .action_msg = "Debug breakpoint\n", -+}; -+ -+#else -+#define GDB_OP NULL -+#endif -+ - - extern void reset_vc(unsigned int); - -@@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta - /* c */ NULL, - /* d */ NULL, - /* e */ &sysrq_term_op, --/* f */ NULL, --/* g */ NULL, -+/* f */ GDB_OP, -+/* g */ GDB_OP, - /* h */ NULL, - /* i */ &sysrq_kill_op, - /* j */ NULL, -diff -puN drivers/serial/8250.c~kgdb-ga drivers/serial/8250.c ---- 25/drivers/serial/8250.c~kgdb-ga 2004-10-21 14:54:15.276601096 -0700 -+++ 25-akpm/drivers/serial/8250.c 2004-10-21 14:54:15.328593192 -0700 -@@ -983,7 +983,7 @@ receive_chars(struct uart_8250_port *up, - if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { - tty->flip.work.func((void *)tty); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) -- return; // if TTY_DONT_FLIP is set -+ return; /* if TTY_DONT_FLIP is set */ - } - ch = serial_inp(up, UART_RX); - *tty->flip.char_buf_ptr = ch; -@@ -1348,12 +1348,21 @@ static void serial8250_break_ctl(struct - spin_unlock_irqrestore(&up->port.lock, flags); - } - -+#ifdef CONFIG_KGDB -+static int kgdb_irq = -1; -+#endif -+ - static int serial8250_startup(struct uart_port *port) - { - struct uart_8250_port *up = (struct uart_8250_port *)port; - unsigned long flags; - int retval; - -+#ifdef CONFIG_KGDB -+ if (up->port.irq == kgdb_irq) -+ return -EBUSY; -+#endif -+ - up->capabilities = uart_config[up->port.type].flags; - up->mcr = 0; - -@@ -1990,6 +1999,10 @@ serial8250_register_ports(struct uart_dr - for (i = 0; i < UART_NR; i++) { - struct uart_8250_port *up = &serial8250_ports[i]; - -+#ifdef CONFIG_KGDB -+ if (up->port.irq == kgdb_irq) -+ up->port.kgdb = 1; -+#endif - up->port.line = i; - up->port.ops = &serial8250_pops; - up->port.dev = dev; -@@ -2376,6 +2389,31 @@ void serial8250_unregister_port(int line - } - EXPORT_SYMBOL(serial8250_unregister_port); - -+#ifdef CONFIG_KGDB -+/* -+ * Find all the ports using the given irq and shut them down. -+ * Result should be that the irq will be released. -+ */ -+void shutdown_for_kgdb(struct async_struct * info) -+{ -+ int irq = info->state->irq; -+ struct uart_8250_port *up; -+ int ttyS; -+ -+ kgdb_irq = irq; /* save for later init */ -+ for (ttyS = 0; ttyS < UART_NR; ttyS++){ -+ up = &serial8250_ports[ttyS]; -+ if (up->port.irq == irq && (irq_lists + irq)->head) { -+#ifdef CONFIG_DEBUG_SPINLOCK /* ugly business... */ -+ if(up->port.lock.magic != SPINLOCK_MAGIC) -+ spin_lock_init(&up->port.lock); -+#endif -+ serial8250_shutdown(&up->port); -+ } -+ } -+} -+#endif /* CONFIG_KGDB */ -+ - static int __init serial8250_init(void) - { - int ret, i; -diff -puN drivers/serial/serial_core.c~kgdb-ga drivers/serial/serial_core.c ---- 25/drivers/serial/serial_core.c~kgdb-ga 2004-10-21 14:54:15.278600792 -0700 -+++ 25-akpm/drivers/serial/serial_core.c 2004-10-21 14:54:15.330592888 -0700 -@@ -1976,6 +1976,11 @@ uart_configure_port(struct uart_driver * - { - unsigned int flags; - -+#ifdef CONFIG_KGDB -+ if (port->kgdb) -+ return; -+#endif -+ - /* - * If there isn't a port here, don't do anything further. - */ -diff -puN include/asm-i386/bugs.h~kgdb-ga include/asm-i386/bugs.h ---- 25/include/asm-i386/bugs.h~kgdb-ga 2004-10-21 14:54:15.279600640 -0700 -+++ 25-akpm/include/asm-i386/bugs.h 2004-10-21 14:54:15.331592736 -0700 -@@ -1,11 +1,11 @@ - /* - * include/asm-i386/bugs.h - * -- * Copyright (C) 1994 Linus Torvalds -+ * Copyright (C) 1994 Linus Torvalds - * - * Cyrix stuff, June 1998 by: - * - Rafael R. Reilova (moved everything from head.S), -- * -+ * - * - Channing Corn (tests & fixes), - * - Andrew D. Balsa (code cleanup). - * -@@ -25,7 +25,20 @@ - #include - #include - #include -- -+#ifdef CONFIG_KGDB -+/* -+ * Provied the command line "gdb" initial break -+ */ -+int __init kgdb_initial_break(char * str) -+{ -+ if (*str == '\0'){ -+ breakpoint(); -+ return 1; -+ } -+ return 0; -+} -+__setup("gdb",kgdb_initial_break); -+#endif - static int __init no_halt(char *s) - { - boot_cpu_data.hlt_works_ok = 0; -@@ -140,7 +153,7 @@ static void __init check_popad(void) - : "ecx", "edi" ); - /* If this fails, it means that any user program may lock the CPU hard. Too bad. */ - if (res != 12345678) printk( "Buggy.\n" ); -- else printk( "OK.\n" ); -+ else printk( "OK.\n" ); - #endif - } - -diff -puN /dev/null include/asm-i386/kgdb.h ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/include/asm-i386/kgdb.h 2004-10-21 14:54:15.331592736 -0700 -@@ -0,0 +1,59 @@ -+#ifndef __KGDB -+#define __KGDB -+ -+/* -+ * This file should not include ANY others. This makes it usable -+ * most anywhere without the fear of include order or inclusion. -+ * Make it so! -+ * -+ * This file may be included all the time. It is only active if -+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros -+ * and entry points. -+ */ -+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__) -+ -+extern void breakpoint(void); -+#define INIT_KGDB_INTS kgdb_enable_ints() -+ -+#ifndef BREAKPOINT -+#define BREAKPOINT asm(" int $3") -+#endif -+/* -+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook' -+ * pointer to its routine and it will be entered as the first thing -+ * when a trap occurs. -+ * -+ * Return values are, at present, undefined. -+ * -+ * The debug hook routine does not necessarily return to its caller. -+ * It has the register image and thus may choose to resume execution -+ * anywhere it pleases. -+ */ -+struct pt_regs; -+ -+extern int kgdb_handle_exception(int trapno, -+ int signo, int err_code, struct pt_regs *regs); -+extern int in_kgdb(struct pt_regs *regs); -+ -+#ifdef CONFIG_KGDB_TS -+void kgdb_tstamp(int line, char *source, int data0, int data1); -+/* -+ * This is the time stamp function. The macro adds the source info and -+ * does a cast on the data to allow most any 32-bit value. -+ */ -+ -+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1) -+#else -+#define kgdb_ts(data0,data1) -+#endif -+#else /* CONFIG_KGDB && ! __ASSEMBLY__ ,stubs follow... */ -+#ifndef BREAKPOINT -+#define BREAKPOINT -+#endif -+#define kgdb_ts(data0,data1) -+#define in_kgdb -+#define kgdb_handle_exception -+#define breakpoint -+#define INIT_KGDB_INTS -+#endif -+#endif /* __KGDB */ -diff -puN /dev/null include/asm-i386/kgdb_local.h ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/include/asm-i386/kgdb_local.h 2004-10-21 14:54:15.332592584 -0700 -@@ -0,0 +1,102 @@ -+#ifndef __KGDB_LOCAL -+#define ___KGDB_LOCAL -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define PORT 0x3f8 -+#ifdef CONFIG_KGDB_PORT -+#undef PORT -+#define PORT CONFIG_KGDB_PORT -+#endif -+#define IRQ 4 -+#ifdef CONFIG_KGDB_IRQ -+#undef IRQ -+#define IRQ CONFIG_KGDB_IRQ -+#endif -+#define SB_CLOCK 1843200 -+#define SB_BASE (SB_CLOCK/16) -+#define SB_BAUD9600 SB_BASE/9600 -+#define SB_BAUD192 SB_BASE/19200 -+#define SB_BAUD384 SB_BASE/38400 -+#define SB_BAUD576 SB_BASE/57600 -+#define SB_BAUD1152 SB_BASE/115200 -+#ifdef CONFIG_KGDB_9600BAUD -+#define SB_BAUD SB_BAUD9600 -+#endif -+#ifdef CONFIG_KGDB_19200BAUD -+#define SB_BAUD SB_BAUD192 -+#endif -+#ifdef CONFIG_KGDB_38400BAUD -+#define SB_BAUD SB_BAUD384 -+#endif -+#ifdef CONFIG_KGDB_57600BAUD -+#define SB_BAUD SB_BAUD576 -+#endif -+#ifdef CONFIG_KGDB_115200BAUD -+#define SB_BAUD SB_BAUD1152 -+#endif -+#ifndef SB_BAUD -+#define SB_BAUD SB_BAUD1152 /* Start with this if not given */ -+#endif -+ -+#ifndef CONFIG_X86_TSC -+#undef rdtsc -+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;} -+#undef rdtscll -+#define rdtscll(s) s++ -+#endif -+ -+#ifdef _raw_read_unlock /* must use a name that is "define"ed, not an inline */ -+#undef spin_lock -+#undef spin_trylock -+#undef spin_unlock -+#define spin_lock _raw_spin_lock -+#define spin_trylock _raw_spin_trylock -+#define spin_unlock _raw_spin_unlock -+#else -+#endif -+#undef spin_unlock_wait -+#define spin_unlock_wait(x) do { cpu_relax(); barrier();} \ -+ while(spin_is_locked(x)) -+ -+#define SB_IER 1 -+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS -+ -+#define FLAGS 0 -+#define SB_STATE { \ -+ magic: SSTATE_MAGIC, \ -+ baud_base: SB_BASE, \ -+ port: PORT, \ -+ irq: IRQ, \ -+ flags: FLAGS, \ -+ custom_divisor:SB_BAUD} -+#define SB_INFO { \ -+ magic: SERIAL_MAGIC, \ -+ port: PORT,0,FLAGS, \ -+ state: &state, \ -+ tty: (struct tty_struct *)&state, \ -+ IER: SB_IER, \ -+ MCR: SB_MCR} -+extern void putDebugChar(int); -+/* RTAI support needs us to really stop/start interrupts */ -+ -+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory") -+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory") -+#define kgdb_local_save_flags(x) __asm__ __volatile__(\ -+ "pushfl ; popl %0":"=g" (x): /* no input */) -+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\ -+ "pushl %0 ; popfl": \ -+ /* no output */ :"g" (x):"memory", "cc") -+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli() -+ -+#ifdef CONFIG_SERIAL -+extern void shutdown_for_kgdb(struct async_struct *info); -+#endif -+#define INIT_KDEBUG putDebugChar("+"); -+#endif /* __KGDB_LOCAL */ -diff -puN include/linux/config.h~kgdb-ga include/linux/config.h ---- 25/include/linux/config.h~kgdb-ga 2004-10-21 14:54:15.281600336 -0700 -+++ 25-akpm/include/linux/config.h 2004-10-21 14:54:15.332592584 -0700 -@@ -2,6 +2,9 @@ - #define _LINUX_CONFIG_H - - #include -+#if defined(__i386__) && !defined(IN_BOOTLOADER) -+#include -+#endif - #if !defined (__KERNEL__) && !defined(__KERNGLUE__) - #error including kernel header in userspace; use the glibc headers instead! - #endif -diff -puN /dev/null include/linux/dwarf2.h ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/include/linux/dwarf2.h 2004-10-21 14:54:15.336591976 -0700 -@@ -0,0 +1,738 @@ -+/* Declarations and definitions of codes relating to the DWARF2 symbolic -+ debugging information format. -+ Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002 -+ Free Software Foundation, Inc. -+ -+ Written by Gary Funck (gary@intrepid.com) The Ada Joint Program -+ Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. -+ provided support for this effort -- June 21, 1995. -+ -+ Derived from the DWARF 1 implementation written by Ron Guilmette -+ (rfg@netcom.com), November 1990. -+ -+ This file is part of GCC. -+ -+ GCC is free software; you can redistribute it and/or modify it under -+ the terms of the GNU General Public License as published by the Free -+ Software Foundation; either version 2, or (at your option) any later -+ version. -+ -+ GCC is distributed in the hope that it will be useful, but WITHOUT -+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -+ License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with GCC; see the file COPYING. If not, write to the Free -+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA -+ 02111-1307, USA. */ -+ -+/* This file is derived from the DWARF specification (a public document) -+ Revision 2.0.0 (July 27, 1993) developed by the UNIX International -+ Programming Languages Special Interest Group (UI/PLSIG) and distributed -+ by UNIX International. Copies of this specification are available from -+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. -+ -+ This file also now contains definitions from the DWARF 3 specification. */ -+ -+/* This file is shared between GCC and GDB, and should not contain -+ prototypes. */ -+ -+#ifndef _ELF_DWARF2_H -+#define _ELF_DWARF2_H -+ -+/* Structure found in the .debug_line section. */ -+#ifndef __ASSEMBLY__ -+typedef struct -+{ -+ unsigned char li_length [4]; -+ unsigned char li_version [2]; -+ unsigned char li_prologue_length [4]; -+ unsigned char li_min_insn_length [1]; -+ unsigned char li_default_is_stmt [1]; -+ unsigned char li_line_base [1]; -+ unsigned char li_line_range [1]; -+ unsigned char li_opcode_base [1]; -+} -+DWARF2_External_LineInfo; -+ -+typedef struct -+{ -+ unsigned long li_length; -+ unsigned short li_version; -+ unsigned int li_prologue_length; -+ unsigned char li_min_insn_length; -+ unsigned char li_default_is_stmt; -+ int li_line_base; -+ unsigned char li_line_range; -+ unsigned char li_opcode_base; -+} -+DWARF2_Internal_LineInfo; -+ -+/* Structure found in .debug_pubnames section. */ -+typedef struct -+{ -+ unsigned char pn_length [4]; -+ unsigned char pn_version [2]; -+ unsigned char pn_offset [4]; -+ unsigned char pn_size [4]; -+} -+DWARF2_External_PubNames; -+ -+typedef struct -+{ -+ unsigned long pn_length; -+ unsigned short pn_version; -+ unsigned long pn_offset; -+ unsigned long pn_size; -+} -+DWARF2_Internal_PubNames; -+ -+/* Structure found in .debug_info section. */ -+typedef struct -+{ -+ unsigned char cu_length [4]; -+ unsigned char cu_version [2]; -+ unsigned char cu_abbrev_offset [4]; -+ unsigned char cu_pointer_size [1]; -+} -+DWARF2_External_CompUnit; -+ -+typedef struct -+{ -+ unsigned long cu_length; -+ unsigned short cu_version; -+ unsigned long cu_abbrev_offset; -+ unsigned char cu_pointer_size; -+} -+DWARF2_Internal_CompUnit; -+ -+typedef struct -+{ -+ unsigned char ar_length [4]; -+ unsigned char ar_version [2]; -+ unsigned char ar_info_offset [4]; -+ unsigned char ar_pointer_size [1]; -+ unsigned char ar_segment_size [1]; -+} -+DWARF2_External_ARange; -+ -+typedef struct -+{ -+ unsigned long ar_length; -+ unsigned short ar_version; -+ unsigned long ar_info_offset; -+ unsigned char ar_pointer_size; -+ unsigned char ar_segment_size; -+} -+DWARF2_Internal_ARange; -+ -+#define ENUM(name) enum name { -+#define IF_NOT_ASM(a) a -+#define COMMA , -+#else -+#define ENUM(name) -+#define IF_NOT_ASM(a) -+#define COMMA -+ -+#endif -+ -+/* Tag names and codes. */ -+ENUM(dwarf_tag) -+ -+ DW_TAG_padding = 0x00 COMMA -+ DW_TAG_array_type = 0x01 COMMA -+ DW_TAG_class_type = 0x02 COMMA -+ DW_TAG_entry_point = 0x03 COMMA -+ DW_TAG_enumeration_type = 0x04 COMMA -+ DW_TAG_formal_parameter = 0x05 COMMA -+ DW_TAG_imported_declaration = 0x08 COMMA -+ DW_TAG_label = 0x0a COMMA -+ DW_TAG_lexical_block = 0x0b COMMA -+ DW_TAG_member = 0x0d COMMA -+ DW_TAG_pointer_type = 0x0f COMMA -+ DW_TAG_reference_type = 0x10 COMMA -+ DW_TAG_compile_unit = 0x11 COMMA -+ DW_TAG_string_type = 0x12 COMMA -+ DW_TAG_structure_type = 0x13 COMMA -+ DW_TAG_subroutine_type = 0x15 COMMA -+ DW_TAG_typedef = 0x16 COMMA -+ DW_TAG_union_type = 0x17 COMMA -+ DW_TAG_unspecified_parameters = 0x18 COMMA -+ DW_TAG_variant = 0x19 COMMA -+ DW_TAG_common_block = 0x1a COMMA -+ DW_TAG_common_inclusion = 0x1b COMMA -+ DW_TAG_inheritance = 0x1c COMMA -+ DW_TAG_inlined_subroutine = 0x1d COMMA -+ DW_TAG_module = 0x1e COMMA -+ DW_TAG_ptr_to_member_type = 0x1f COMMA -+ DW_TAG_set_type = 0x20 COMMA -+ DW_TAG_subrange_type = 0x21 COMMA -+ DW_TAG_with_stmt = 0x22 COMMA -+ DW_TAG_access_declaration = 0x23 COMMA -+ DW_TAG_base_type = 0x24 COMMA -+ DW_TAG_catch_block = 0x25 COMMA -+ DW_TAG_const_type = 0x26 COMMA -+ DW_TAG_constant = 0x27 COMMA -+ DW_TAG_enumerator = 0x28 COMMA -+ DW_TAG_file_type = 0x29 COMMA -+ DW_TAG_friend = 0x2a COMMA -+ DW_TAG_namelist = 0x2b COMMA -+ DW_TAG_namelist_item = 0x2c COMMA -+ DW_TAG_packed_type = 0x2d COMMA -+ DW_TAG_subprogram = 0x2e COMMA -+ DW_TAG_template_type_param = 0x2f COMMA -+ DW_TAG_template_value_param = 0x30 COMMA -+ DW_TAG_thrown_type = 0x31 COMMA -+ DW_TAG_try_block = 0x32 COMMA -+ DW_TAG_variant_part = 0x33 COMMA -+ DW_TAG_variable = 0x34 COMMA -+ DW_TAG_volatile_type = 0x35 COMMA -+ /* DWARF 3. */ -+ DW_TAG_dwarf_procedure = 0x36 COMMA -+ DW_TAG_restrict_type = 0x37 COMMA -+ DW_TAG_interface_type = 0x38 COMMA -+ DW_TAG_namespace = 0x39 COMMA -+ DW_TAG_imported_module = 0x3a COMMA -+ DW_TAG_unspecified_type = 0x3b COMMA -+ DW_TAG_partial_unit = 0x3c COMMA -+ DW_TAG_imported_unit = 0x3d COMMA -+ /* SGI/MIPS Extensions. */ -+ DW_TAG_MIPS_loop = 0x4081 COMMA -+ /* GNU extensions. */ -+ DW_TAG_format_label = 0x4101 COMMA /* For FORTRAN 77 and Fortran 90. */ -+ DW_TAG_function_template = 0x4102 COMMA /* For C++. */ -+ DW_TAG_class_template = 0x4103 COMMA /* For C++. */ -+ DW_TAG_GNU_BINCL = 0x4104 COMMA -+ DW_TAG_GNU_EINCL = 0x4105 COMMA -+ /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ -+ DW_TAG_upc_shared_type = 0x8765 COMMA -+ DW_TAG_upc_strict_type = 0x8766 COMMA -+ DW_TAG_upc_relaxed_type = 0x8767 -+IF_NOT_ASM(};) -+ -+#define DW_TAG_lo_user 0x4080 -+#define DW_TAG_hi_user 0xffff -+ -+/* Flag that tells whether entry has a child or not. */ -+#define DW_children_no 0 -+#define DW_children_yes 1 -+ -+/* Form names and codes. */ -+ENUM(dwarf_form) -+ -+ DW_FORM_addr = 0x01 COMMA -+ DW_FORM_block2 = 0x03 COMMA -+ DW_FORM_block4 = 0x04 COMMA -+ DW_FORM_data2 = 0x05 COMMA -+ DW_FORM_data4 = 0x06 COMMA -+ DW_FORM_data8 = 0x07 COMMA -+ DW_FORM_string = 0x08 COMMA -+ DW_FORM_block = 0x09 COMMA -+ DW_FORM_block1 = 0x0a COMMA -+ DW_FORM_data1 = 0x0b COMMA -+ DW_FORM_flag = 0x0c COMMA -+ DW_FORM_sdata = 0x0d COMMA -+ DW_FORM_strp = 0x0e COMMA -+ DW_FORM_udata = 0x0f COMMA -+ DW_FORM_ref_addr = 0x10 COMMA -+ DW_FORM_ref1 = 0x11 COMMA -+ DW_FORM_ref2 = 0x12 COMMA -+ DW_FORM_ref4 = 0x13 COMMA -+ DW_FORM_ref8 = 0x14 COMMA -+ DW_FORM_ref_udata = 0x15 COMMA -+ DW_FORM_indirect = 0x16 -+IF_NOT_ASM(};) -+ -+/* Attribute names and codes. */ -+ -+ENUM(dwarf_attribute) -+ -+ DW_AT_sibling = 0x01 COMMA -+ DW_AT_location = 0x02 COMMA -+ DW_AT_name = 0x03 COMMA -+ DW_AT_ordering = 0x09 COMMA -+ DW_AT_subscr_data = 0x0a COMMA -+ DW_AT_byte_size = 0x0b COMMA -+ DW_AT_bit_offset = 0x0c COMMA -+ DW_AT_bit_size = 0x0d COMMA -+ DW_AT_element_list = 0x0f COMMA -+ DW_AT_stmt_list = 0x10 COMMA -+ DW_AT_low_pc = 0x11 COMMA -+ DW_AT_high_pc = 0x12 COMMA -+ DW_AT_language = 0x13 COMMA -+ DW_AT_member = 0x14 COMMA -+ DW_AT_discr = 0x15 COMMA -+ DW_AT_discr_value = 0x16 COMMA -+ DW_AT_visibility = 0x17 COMMA -+ DW_AT_import = 0x18 COMMA -+ DW_AT_string_length = 0x19 COMMA -+ DW_AT_common_reference = 0x1a COMMA -+ DW_AT_comp_dir = 0x1b COMMA -+ DW_AT_const_value = 0x1c COMMA -+ DW_AT_containing_type = 0x1d COMMA -+ DW_AT_default_value = 0x1e COMMA -+ DW_AT_inline = 0x20 COMMA -+ DW_AT_is_optional = 0x21 COMMA -+ DW_AT_lower_bound = 0x22 COMMA -+ DW_AT_producer = 0x25 COMMA -+ DW_AT_prototyped = 0x27 COMMA -+ DW_AT_return_addr = 0x2a COMMA -+ DW_AT_start_scope = 0x2c COMMA -+ DW_AT_stride_size = 0x2e COMMA -+ DW_AT_upper_bound = 0x2f COMMA -+ DW_AT_abstract_origin = 0x31 COMMA -+ DW_AT_accessibility = 0x32 COMMA -+ DW_AT_address_class = 0x33 COMMA -+ DW_AT_artificial = 0x34 COMMA -+ DW_AT_base_types = 0x35 COMMA -+ DW_AT_calling_convention = 0x36 COMMA -+ DW_AT_count = 0x37 COMMA -+ DW_AT_data_member_location = 0x38 COMMA -+ DW_AT_decl_column = 0x39 COMMA -+ DW_AT_decl_file = 0x3a COMMA -+ DW_AT_decl_line = 0x3b COMMA -+ DW_AT_declaration = 0x3c COMMA -+ DW_AT_discr_list = 0x3d COMMA -+ DW_AT_encoding = 0x3e COMMA -+ DW_AT_external = 0x3f COMMA -+ DW_AT_frame_base = 0x40 COMMA -+ DW_AT_friend = 0x41 COMMA -+ DW_AT_identifier_case = 0x42 COMMA -+ DW_AT_macro_info = 0x43 COMMA -+ DW_AT_namelist_items = 0x44 COMMA -+ DW_AT_priority = 0x45 COMMA -+ DW_AT_segment = 0x46 COMMA -+ DW_AT_specification = 0x47 COMMA -+ DW_AT_static_link = 0x48 COMMA -+ DW_AT_type = 0x49 COMMA -+ DW_AT_use_location = 0x4a COMMA -+ DW_AT_variable_parameter = 0x4b COMMA -+ DW_AT_virtuality = 0x4c COMMA -+ DW_AT_vtable_elem_location = 0x4d COMMA -+ /* DWARF 3 values. */ -+ DW_AT_allocated = 0x4e COMMA -+ DW_AT_associated = 0x4f COMMA -+ DW_AT_data_location = 0x50 COMMA -+ DW_AT_stride = 0x51 COMMA -+ DW_AT_entry_pc = 0x52 COMMA -+ DW_AT_use_UTF8 = 0x53 COMMA -+ DW_AT_extension = 0x54 COMMA -+ DW_AT_ranges = 0x55 COMMA -+ DW_AT_trampoline = 0x56 COMMA -+ DW_AT_call_column = 0x57 COMMA -+ DW_AT_call_file = 0x58 COMMA -+ DW_AT_call_line = 0x59 COMMA -+ /* SGI/MIPS extensions. */ -+ DW_AT_MIPS_fde = 0x2001 COMMA -+ DW_AT_MIPS_loop_begin = 0x2002 COMMA -+ DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA -+ DW_AT_MIPS_epilog_begin = 0x2004 COMMA -+ DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA -+ DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA -+ DW_AT_MIPS_linkage_name = 0x2007 COMMA -+ DW_AT_MIPS_stride = 0x2008 COMMA -+ DW_AT_MIPS_abstract_name = 0x2009 COMMA -+ DW_AT_MIPS_clone_origin = 0x200a COMMA -+ DW_AT_MIPS_has_inlines = 0x200b COMMA -+ /* GNU extensions. */ -+ DW_AT_sf_names = 0x2101 COMMA -+ DW_AT_src_info = 0x2102 COMMA -+ DW_AT_mac_info = 0x2103 COMMA -+ DW_AT_src_coords = 0x2104 COMMA -+ DW_AT_body_begin = 0x2105 COMMA -+ DW_AT_body_end = 0x2106 COMMA -+ DW_AT_GNU_vector = 0x2107 COMMA -+ /* VMS extensions. */ -+ DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA -+ /* UPC extension. */ -+ DW_AT_upc_threads_scaled = 0x3210 -+IF_NOT_ASM(};) -+ -+#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ -+#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ -+ -+/* Location atom names and codes. */ -+ENUM(dwarf_location_atom) -+ -+ DW_OP_addr = 0x03 COMMA -+ DW_OP_deref = 0x06 COMMA -+ DW_OP_const1u = 0x08 COMMA -+ DW_OP_const1s = 0x09 COMMA -+ DW_OP_const2u = 0x0a COMMA -+ DW_OP_const2s = 0x0b COMMA -+ DW_OP_const4u = 0x0c COMMA -+ DW_OP_const4s = 0x0d COMMA -+ DW_OP_const8u = 0x0e COMMA -+ DW_OP_const8s = 0x0f COMMA -+ DW_OP_constu = 0x10 COMMA -+ DW_OP_consts = 0x11 COMMA -+ DW_OP_dup = 0x12 COMMA -+ DW_OP_drop = 0x13 COMMA -+ DW_OP_over = 0x14 COMMA -+ DW_OP_pick = 0x15 COMMA -+ DW_OP_swap = 0x16 COMMA -+ DW_OP_rot = 0x17 COMMA -+ DW_OP_xderef = 0x18 COMMA -+ DW_OP_abs = 0x19 COMMA -+ DW_OP_and = 0x1a COMMA -+ DW_OP_div = 0x1b COMMA -+ DW_OP_minus = 0x1c COMMA -+ DW_OP_mod = 0x1d COMMA -+ DW_OP_mul = 0x1e COMMA -+ DW_OP_neg = 0x1f COMMA -+ DW_OP_not = 0x20 COMMA -+ DW_OP_or = 0x21 COMMA -+ DW_OP_plus = 0x22 COMMA -+ DW_OP_plus_uconst = 0x23 COMMA -+ DW_OP_shl = 0x24 COMMA -+ DW_OP_shr = 0x25 COMMA -+ DW_OP_shra = 0x26 COMMA -+ DW_OP_xor = 0x27 COMMA -+ DW_OP_bra = 0x28 COMMA -+ DW_OP_eq = 0x29 COMMA -+ DW_OP_ge = 0x2a COMMA -+ DW_OP_gt = 0x2b COMMA -+ DW_OP_le = 0x2c COMMA -+ DW_OP_lt = 0x2d COMMA -+ DW_OP_ne = 0x2e COMMA -+ DW_OP_skip = 0x2f COMMA -+ DW_OP_lit0 = 0x30 COMMA -+ DW_OP_lit1 = 0x31 COMMA -+ DW_OP_lit2 = 0x32 COMMA -+ DW_OP_lit3 = 0x33 COMMA -+ DW_OP_lit4 = 0x34 COMMA -+ DW_OP_lit5 = 0x35 COMMA -+ DW_OP_lit6 = 0x36 COMMA -+ DW_OP_lit7 = 0x37 COMMA -+ DW_OP_lit8 = 0x38 COMMA -+ DW_OP_lit9 = 0x39 COMMA -+ DW_OP_lit10 = 0x3a COMMA -+ DW_OP_lit11 = 0x3b COMMA -+ DW_OP_lit12 = 0x3c COMMA -+ DW_OP_lit13 = 0x3d COMMA -+ DW_OP_lit14 = 0x3e COMMA -+ DW_OP_lit15 = 0x3f COMMA -+ DW_OP_lit16 = 0x40 COMMA -+ DW_OP_lit17 = 0x41 COMMA -+ DW_OP_lit18 = 0x42 COMMA -+ DW_OP_lit19 = 0x43 COMMA -+ DW_OP_lit20 = 0x44 COMMA -+ DW_OP_lit21 = 0x45 COMMA -+ DW_OP_lit22 = 0x46 COMMA -+ DW_OP_lit23 = 0x47 COMMA -+ DW_OP_lit24 = 0x48 COMMA -+ DW_OP_lit25 = 0x49 COMMA -+ DW_OP_lit26 = 0x4a COMMA -+ DW_OP_lit27 = 0x4b COMMA -+ DW_OP_lit28 = 0x4c COMMA -+ DW_OP_lit29 = 0x4d COMMA -+ DW_OP_lit30 = 0x4e COMMA -+ DW_OP_lit31 = 0x4f COMMA -+ DW_OP_reg0 = 0x50 COMMA -+ DW_OP_reg1 = 0x51 COMMA -+ DW_OP_reg2 = 0x52 COMMA -+ DW_OP_reg3 = 0x53 COMMA -+ DW_OP_reg4 = 0x54 COMMA -+ DW_OP_reg5 = 0x55 COMMA -+ DW_OP_reg6 = 0x56 COMMA -+ DW_OP_reg7 = 0x57 COMMA -+ DW_OP_reg8 = 0x58 COMMA -+ DW_OP_reg9 = 0x59 COMMA -+ DW_OP_reg10 = 0x5a COMMA -+ DW_OP_reg11 = 0x5b COMMA -+ DW_OP_reg12 = 0x5c COMMA -+ DW_OP_reg13 = 0x5d COMMA -+ DW_OP_reg14 = 0x5e COMMA -+ DW_OP_reg15 = 0x5f COMMA -+ DW_OP_reg16 = 0x60 COMMA -+ DW_OP_reg17 = 0x61 COMMA -+ DW_OP_reg18 = 0x62 COMMA -+ DW_OP_reg19 = 0x63 COMMA -+ DW_OP_reg20 = 0x64 COMMA -+ DW_OP_reg21 = 0x65 COMMA -+ DW_OP_reg22 = 0x66 COMMA -+ DW_OP_reg23 = 0x67 COMMA -+ DW_OP_reg24 = 0x68 COMMA -+ DW_OP_reg25 = 0x69 COMMA -+ DW_OP_reg26 = 0x6a COMMA -+ DW_OP_reg27 = 0x6b COMMA -+ DW_OP_reg28 = 0x6c COMMA -+ DW_OP_reg29 = 0x6d COMMA -+ DW_OP_reg30 = 0x6e COMMA -+ DW_OP_reg31 = 0x6f COMMA -+ DW_OP_breg0 = 0x70 COMMA -+ DW_OP_breg1 = 0x71 COMMA -+ DW_OP_breg2 = 0x72 COMMA -+ DW_OP_breg3 = 0x73 COMMA -+ DW_OP_breg4 = 0x74 COMMA -+ DW_OP_breg5 = 0x75 COMMA -+ DW_OP_breg6 = 0x76 COMMA -+ DW_OP_breg7 = 0x77 COMMA -+ DW_OP_breg8 = 0x78 COMMA -+ DW_OP_breg9 = 0x79 COMMA -+ DW_OP_breg10 = 0x7a COMMA -+ DW_OP_breg11 = 0x7b COMMA -+ DW_OP_breg12 = 0x7c COMMA -+ DW_OP_breg13 = 0x7d COMMA -+ DW_OP_breg14 = 0x7e COMMA -+ DW_OP_breg15 = 0x7f COMMA -+ DW_OP_breg16 = 0x80 COMMA -+ DW_OP_breg17 = 0x81 COMMA -+ DW_OP_breg18 = 0x82 COMMA -+ DW_OP_breg19 = 0x83 COMMA -+ DW_OP_breg20 = 0x84 COMMA -+ DW_OP_breg21 = 0x85 COMMA -+ DW_OP_breg22 = 0x86 COMMA -+ DW_OP_breg23 = 0x87 COMMA -+ DW_OP_breg24 = 0x88 COMMA -+ DW_OP_breg25 = 0x89 COMMA -+ DW_OP_breg26 = 0x8a COMMA -+ DW_OP_breg27 = 0x8b COMMA -+ DW_OP_breg28 = 0x8c COMMA -+ DW_OP_breg29 = 0x8d COMMA -+ DW_OP_breg30 = 0x8e COMMA -+ DW_OP_breg31 = 0x8f COMMA -+ DW_OP_regx = 0x90 COMMA -+ DW_OP_fbreg = 0x91 COMMA -+ DW_OP_bregx = 0x92 COMMA -+ DW_OP_piece = 0x93 COMMA -+ DW_OP_deref_size = 0x94 COMMA -+ DW_OP_xderef_size = 0x95 COMMA -+ DW_OP_nop = 0x96 COMMA -+ /* DWARF 3 extensions. */ -+ DW_OP_push_object_address = 0x97 COMMA -+ DW_OP_call2 = 0x98 COMMA -+ DW_OP_call4 = 0x99 COMMA -+ DW_OP_call_ref = 0x9a COMMA -+ /* GNU extensions. */ -+ DW_OP_GNU_push_tls_address = 0xe0 -+IF_NOT_ASM(};) -+ -+#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ -+#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ -+ -+/* Type encodings. */ -+ENUM(dwarf_type) -+ -+ DW_ATE_void = 0x0 COMMA -+ DW_ATE_address = 0x1 COMMA -+ DW_ATE_boolean = 0x2 COMMA -+ DW_ATE_complex_float = 0x3 COMMA -+ DW_ATE_float = 0x4 COMMA -+ DW_ATE_signed = 0x5 COMMA -+ DW_ATE_signed_char = 0x6 COMMA -+ DW_ATE_unsigned = 0x7 COMMA -+ DW_ATE_unsigned_char = 0x8 COMMA -+ /* DWARF 3. */ -+ DW_ATE_imaginary_float = 0x9 -+IF_NOT_ASM(};) -+ -+#define DW_ATE_lo_user 0x80 -+#define DW_ATE_hi_user 0xff -+ -+/* Array ordering names and codes. */ -+ENUM(dwarf_array_dim_ordering) -+ -+ DW_ORD_row_major = 0 COMMA -+ DW_ORD_col_major = 1 -+IF_NOT_ASM(};) -+ -+/* Access attribute. */ -+ENUM(dwarf_access_attribute) -+ -+ DW_ACCESS_public = 1 COMMA -+ DW_ACCESS_protected = 2 COMMA -+ DW_ACCESS_private = 3 -+IF_NOT_ASM(};) -+ -+/* Visibility. */ -+ENUM(dwarf_visibility_attribute) -+ -+ DW_VIS_local = 1 COMMA -+ DW_VIS_exported = 2 COMMA -+ DW_VIS_qualified = 3 -+IF_NOT_ASM(};) -+ -+/* Virtuality. */ -+ENUM(dwarf_virtuality_attribute) -+ -+ DW_VIRTUALITY_none = 0 COMMA -+ DW_VIRTUALITY_virtual = 1 COMMA -+ DW_VIRTUALITY_pure_virtual = 2 -+IF_NOT_ASM(};) -+ -+/* Case sensitivity. */ -+ENUM(dwarf_id_case) -+ -+ DW_ID_case_sensitive = 0 COMMA -+ DW_ID_up_case = 1 COMMA -+ DW_ID_down_case = 2 COMMA -+ DW_ID_case_insensitive = 3 -+IF_NOT_ASM(};) -+ -+/* Calling convention. */ -+ENUM(dwarf_calling_convention) -+ -+ DW_CC_normal = 0x1 COMMA -+ DW_CC_program = 0x2 COMMA -+ DW_CC_nocall = 0x3 -+IF_NOT_ASM(};) -+ -+#define DW_CC_lo_user 0x40 -+#define DW_CC_hi_user 0xff -+ -+/* Inline attribute. */ -+ENUM(dwarf_inline_attribute) -+ -+ DW_INL_not_inlined = 0 COMMA -+ DW_INL_inlined = 1 COMMA -+ DW_INL_declared_not_inlined = 2 COMMA -+ DW_INL_declared_inlined = 3 -+IF_NOT_ASM(};) -+ -+/* Discriminant lists. */ -+ENUM(dwarf_discrim_list) -+ -+ DW_DSC_label = 0 COMMA -+ DW_DSC_range = 1 -+IF_NOT_ASM(};) -+ -+/* Line number opcodes. */ -+ENUM(dwarf_line_number_ops) -+ -+ DW_LNS_extended_op = 0 COMMA -+ DW_LNS_copy = 1 COMMA -+ DW_LNS_advance_pc = 2 COMMA -+ DW_LNS_advance_line = 3 COMMA -+ DW_LNS_set_file = 4 COMMA -+ DW_LNS_set_column = 5 COMMA -+ DW_LNS_negate_stmt = 6 COMMA -+ DW_LNS_set_basic_block = 7 COMMA -+ DW_LNS_const_add_pc = 8 COMMA -+ DW_LNS_fixed_advance_pc = 9 COMMA -+ /* DWARF 3. */ -+ DW_LNS_set_prologue_end = 10 COMMA -+ DW_LNS_set_epilogue_begin = 11 COMMA -+ DW_LNS_set_isa = 12 -+IF_NOT_ASM(};) -+ -+/* Line number extended opcodes. */ -+ENUM(dwarf_line_number_x_ops) -+ -+ DW_LNE_end_sequence = 1 COMMA -+ DW_LNE_set_address = 2 COMMA -+ DW_LNE_define_file = 3 -+IF_NOT_ASM(};) -+ -+/* Call frame information. */ -+ENUM(dwarf_call_frame_info) -+ -+ DW_CFA_advance_loc = 0x40 COMMA -+ DW_CFA_offset = 0x80 COMMA -+ DW_CFA_restore = 0xc0 COMMA -+ DW_CFA_nop = 0x00 COMMA -+ DW_CFA_set_loc = 0x01 COMMA -+ DW_CFA_advance_loc1 = 0x02 COMMA -+ DW_CFA_advance_loc2 = 0x03 COMMA -+ DW_CFA_advance_loc4 = 0x04 COMMA -+ DW_CFA_offset_extended = 0x05 COMMA -+ DW_CFA_restore_extended = 0x06 COMMA -+ DW_CFA_undefined = 0x07 COMMA -+ DW_CFA_same_value = 0x08 COMMA -+ DW_CFA_register = 0x09 COMMA -+ DW_CFA_remember_state = 0x0a COMMA -+ DW_CFA_restore_state = 0x0b COMMA -+ DW_CFA_def_cfa = 0x0c COMMA -+ DW_CFA_def_cfa_register = 0x0d COMMA -+ DW_CFA_def_cfa_offset = 0x0e COMMA -+ -+ /* DWARF 3. */ -+ DW_CFA_def_cfa_expression = 0x0f COMMA -+ DW_CFA_expression = 0x10 COMMA -+ DW_CFA_offset_extended_sf = 0x11 COMMA -+ DW_CFA_def_cfa_sf = 0x12 COMMA -+ DW_CFA_def_cfa_offset_sf = 0x13 COMMA -+ -+ /* SGI/MIPS specific. */ -+ DW_CFA_MIPS_advance_loc8 = 0x1d COMMA -+ -+ /* GNU extensions. */ -+ DW_CFA_GNU_window_save = 0x2d COMMA -+ DW_CFA_GNU_args_size = 0x2e COMMA -+ DW_CFA_GNU_negative_offset_extended = 0x2f -+IF_NOT_ASM(};) -+ -+#define DW_CIE_ID 0xffffffff -+#define DW_CIE_VERSION 1 -+ -+#define DW_CFA_extended 0 -+#define DW_CFA_lo_user 0x1c -+#define DW_CFA_hi_user 0x3f -+ -+#define DW_CHILDREN_no 0x00 -+#define DW_CHILDREN_yes 0x01 -+ -+#define DW_ADDR_none 0 -+ -+/* Source language names and codes. */ -+ENUM(dwarf_source_language) -+ -+ DW_LANG_C89 = 0x0001 COMMA -+ DW_LANG_C = 0x0002 COMMA -+ DW_LANG_Ada83 = 0x0003 COMMA -+ DW_LANG_C_plus_plus = 0x0004 COMMA -+ DW_LANG_Cobol74 = 0x0005 COMMA -+ DW_LANG_Cobol85 = 0x0006 COMMA -+ DW_LANG_Fortran77 = 0x0007 COMMA -+ DW_LANG_Fortran90 = 0x0008 COMMA -+ DW_LANG_Pascal83 = 0x0009 COMMA -+ DW_LANG_Modula2 = 0x000a COMMA -+ DW_LANG_Java = 0x000b COMMA -+ /* DWARF 3. */ -+ DW_LANG_C99 = 0x000c COMMA -+ DW_LANG_Ada95 = 0x000d COMMA -+ DW_LANG_Fortran95 = 0x000e COMMA -+ /* MIPS. */ -+ DW_LANG_Mips_Assembler = 0x8001 COMMA -+ /* UPC. */ -+ DW_LANG_Upc = 0x8765 -+IF_NOT_ASM(};) -+ -+#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ -+#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ -+ -+/* Names and codes for macro information. */ -+ENUM(dwarf_macinfo_record_type) -+ -+ DW_MACINFO_define = 1 COMMA -+ DW_MACINFO_undef = 2 COMMA -+ DW_MACINFO_start_file = 3 COMMA -+ DW_MACINFO_end_file = 4 COMMA -+ DW_MACINFO_vendor_ext = 255 -+IF_NOT_ASM(};) -+ -+/* @@@ For use with GNU frame unwind information. */ -+ -+#define DW_EH_PE_absptr 0x00 -+#define DW_EH_PE_omit 0xff -+ -+#define DW_EH_PE_uleb128 0x01 -+#define DW_EH_PE_udata2 0x02 -+#define DW_EH_PE_udata4 0x03 -+#define DW_EH_PE_udata8 0x04 -+#define DW_EH_PE_sleb128 0x09 -+#define DW_EH_PE_sdata2 0x0A -+#define DW_EH_PE_sdata4 0x0B -+#define DW_EH_PE_sdata8 0x0C -+#define DW_EH_PE_signed 0x08 -+ -+#define DW_EH_PE_pcrel 0x10 -+#define DW_EH_PE_textrel 0x20 -+#define DW_EH_PE_datarel 0x30 -+#define DW_EH_PE_funcrel 0x40 -+#define DW_EH_PE_aligned 0x50 -+ -+#define DW_EH_PE_indirect 0x80 -+ -+#endif /* _ELF_DWARF2_H */ -diff -puN /dev/null include/linux/dwarf2-lang.h ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/include/linux/dwarf2-lang.h 2004-10-21 14:54:15.337591824 -0700 -@@ -0,0 +1,132 @@ -+#ifndef DWARF2_LANG -+#define DWARF2_LANG -+#include -+ -+/* -+ * This is free software; you can redistribute it and/or modify it under -+ * the terms of the GNU General Public License as published by the Free -+ * Software Foundation; either version 2, or (at your option) any later -+ * version. -+ */ -+/* -+ * This file defines macros that allow generation of DWARF debug records -+ * for asm files. This file is platform independent. Register numbers -+ * (which are about the only thing that is platform dependent) are to be -+ * supplied by a platform defined file. -+ */ -+#define DWARF_preamble() .section .debug_frame,"",@progbits -+/* -+ * This macro starts a debug frame section. The debug_frame describes -+ * where to find the registers that the enclosing function saved on -+ * entry. -+ * -+ * ORD is use by the label generator and should be the same as what is -+ * passed to CFI_postamble. -+ * -+ * pc, pc register gdb ordinal. -+ * -+ * code_align this is the factor used to define locations or regions -+ * where the given definitions apply. If you use labels to define these -+ * this should be 1. -+ * -+ * data_align this is the factor used to define register offsets. If -+ * you use struct offset, this should be the size of the register in -+ * bytes or the negative of that. This is how it is used: you will -+ * define a register as the reference register, say the stack pointer, -+ * then you will say where a register is located relative to this -+ * reference registers value, say 40 for register 3 (the gdb register -+ * number). The <40> will be multiplied by to define the -+ * byte offset of the given register (3, in this example). So if your -+ * <40> is the byte offset and the reference register points at the -+ * begining, you would want 1 for the data_offset. If <40> was the 40th -+ * 4-byte element in that structure you would want 4. And if your -+ * reference register points at the end of the structure you would want -+ * a negative data_align value(and you would have to do other math as -+ * well). -+ */ -+ -+#define CFI_preamble(ORD, pc, code_align, data_align) \ -+.section .debug_frame,"",@progbits ; \ -+frame/**/_/**/ORD: \ -+ .long end/**/_/**/ORD-start/**/_/**/ORD; \ -+start/**/_/**/ORD: \ -+ .long DW_CIE_ID; \ -+ .byte DW_CIE_VERSION; \ -+ .byte 0 ; \ -+ .uleb128 code_align; \ -+ .sleb128 data_align; \ -+ .byte pc; -+ -+/* -+ * After the above macro and prior to the CFI_postamble, you need to -+ * define the initial state. This starts with defining the reference -+ * register and, usually the pc. Here are some helper macros: -+ */ -+ -+#define CFA_define_reference(reg, offset) \ -+ .byte DW_CFA_def_cfa; \ -+ .uleb128 reg; \ -+ .uleb128 (offset); -+ -+#define CFA_define_offset(reg, offset) \ -+ .byte (DW_CFA_offset + reg); \ -+ .uleb128 (offset); -+ -+#define CFI_postamble(ORD) \ -+ .align 4; \ -+end/**/_/**/ORD: -+/* -+ * So now your code pushs stuff on the stack, you need a new location -+ * and the rules for what to do. This starts a running description of -+ * the call frame. You need to describe what changes with respect to -+ * the call registers as the location of the pc moves through the code. -+ * The following builds an FDE (fram descriptor entry?). Like the -+ * above, it has a preamble and a postamble. It also is tied to the CFI -+ * above. -+ * The first entry after the preamble must be the location in the code -+ * that the call frame is being described for. -+ */ -+#define FDE_preamble(ORD, fde_no, initial_address, length) \ -+ .long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no; \ -+FDE_start/**/_/**/fde_no: \ -+ .long frame/**/_/**/ORD; \ -+ .long initial_address; \ -+ .long length; -+ -+#define FDE_postamble(fde_no) \ -+ .align 4; \ -+FDE_end/**/_/**/fde_no: -+/* -+ * That done, you can now add registers, subtract registers, move the -+ * reference and even change the reference. You can also define a new -+ * area of code the info applies to. For discontinuous bits you should -+ * start a new FDE. You may have as many as you like. -+ */ -+ -+/* -+ * To advance the address by -+ */ -+ -+#define FDE_advance(bytes) \ -+ .byte DW_CFA_advance_loc4 \ -+ .long bytes -+ -+ -+ -+/* -+ * With the above you can define all the register locations. But -+ * suppose the reference register moves... Takes the new offset NOT an -+ * increment. This is how esp is tracked if it is not saved. -+ */ -+ -+#define CFA_define_cfa_offset(offset) \ -+ .byte $DW_CFA_def_cfa_offset; \ -+ .uleb128 (offset); -+/* -+ * Or suppose you want to use a different reference register... -+ */ -+#define CFA_define_cfa_register(reg) \ -+ .byte DW_CFA_def_cfa_register; \ -+ .uleb128 reg; -+ -+#endif -diff -puN include/linux/serial_core.h~kgdb-ga include/linux/serial_core.h ---- 25/include/linux/serial_core.h~kgdb-ga 2004-10-21 14:54:15.282600184 -0700 -+++ 25-akpm/include/linux/serial_core.h 2004-10-21 14:54:15.338591672 -0700 -@@ -172,7 +172,9 @@ struct uart_port { - unsigned char x_char; /* xon/xoff char */ - unsigned char regshift; /* reg offset shift */ - unsigned char iotype; /* io access style */ -- -+#ifdef CONFIG_KGDB -+ int kgdb; /* in use by kgdb */ -+#endif - #define UPIO_PORT (0) - #define UPIO_HUB6 (1) - #define UPIO_MEM (2) -diff -puN include/linux/spinlock.h~kgdb-ga include/linux/spinlock.h ---- 25/include/linux/spinlock.h~kgdb-ga 2004-10-21 14:54:15.284599880 -0700 -+++ 25-akpm/include/linux/spinlock.h 2004-10-21 14:54:15.338591672 -0700 -@@ -15,6 +15,12 @@ - - #include /* for cpu relax */ - #include -+#ifdef CONFIG_KGDB -+#include -+#define SET_WHO(x, him) (x)->who = him; -+#else -+#define SET_WHO(x, him) -+#endif - - /* - * Must define these before including other files, inline functions need them -@@ -88,6 +94,9 @@ typedef struct { - const char *module; - char *owner; - int oline; -+#ifdef CONFIG_KGDB -+ struct task_struct *who; -+#endif - } spinlock_t; - #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0} - -@@ -99,6 +108,7 @@ typedef struct { - (x)->module = __FILE__; \ - (x)->owner = NULL; \ - (x)->oline = 0; \ -+ SET_WHO(x, NULL) \ - } while (0) - - #define CHECK_LOCK(x) \ -@@ -121,6 +131,7 @@ typedef struct { - (x)->lock = 1; \ - (x)->owner = __FILE__; \ - (x)->oline = __LINE__; \ -+ SET_WHO(x, current) \ - } while (0) - - /* without debugging, spin_is_locked on UP always says -@@ -151,6 +162,7 @@ typedef struct { - (x)->lock = 1; \ - (x)->owner = __FILE__; \ - (x)->oline = __LINE__; \ -+ SET_WHO(x, current) \ - 1; \ - }) - -diff -puN kernel/pid.c~kgdb-ga kernel/pid.c ---- 25/kernel/pid.c~kgdb-ga 2004-10-21 14:54:15.285599728 -0700 -+++ 25-akpm/kernel/pid.c 2004-10-21 14:54:15.339591520 -0700 -@@ -252,6 +252,9 @@ void switch_exec_pids(task_t *leader, ta - * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or - * more. - */ -+#ifdef CONFIG_KGDB -+int kgdb_pid_init_done; /* so we don't call prior to... */ -+#endif - void __init pidhash_init(void) - { - int i, j, pidhash_size; -@@ -273,6 +276,9 @@ void __init pidhash_init(void) - for (j = 0; j < pidhash_size; j++) - INIT_HLIST_HEAD(&pid_hash[i][j]); - } -+#ifdef CONFIG_KGDB -+ kgdb_pid_init_done++; -+#endif - } - - void __init pidmap_init(void) -diff -puN kernel/sched.c~kgdb-ga kernel/sched.c ---- 25/kernel/sched.c~kgdb-ga 2004-10-21 14:54:15.287599424 -0700 -+++ 25-akpm/kernel/sched.c 2004-10-21 14:54:15.342591064 -0700 -@@ -2931,6 +2931,13 @@ out_unlock: - - EXPORT_SYMBOL(set_user_nice); - -+#ifdef CONFIG_KGDB -+struct task_struct *kgdb_get_idle(int this_cpu) -+{ -+ return cpu_rq(this_cpu)->idle; -+} -+#endif -+ - #ifdef __ARCH_WANT_SYS_NICE - - /* -diff -puN MAINTAINERS~kgdb-ga MAINTAINERS ---- 25/MAINTAINERS~kgdb-ga 2004-10-21 14:54:15.288599272 -0700 -+++ 25-akpm/MAINTAINERS 2004-10-21 14:54:15.344590760 -0700 -@@ -1242,6 +1242,12 @@ W: http://sf.net/projects/kernel-janitor - W: http://developer.osdl.org/rddunlap/kj-patches/ - S: Maintained - -+KGDB FOR I386 PLATFORM -+P: George Anzinger -+M: george@mvista.com -+L: linux-net@vger.kernel.org -+S: Supported -+ - KERNEL NFSD - P: Neil Brown - M: neilb@cse.unsw.edu.au -diff -puN arch/i386/Kconfig.debug~kgdb-ga arch/i386/Kconfig.debug ---- 25/arch/i386/Kconfig.debug~kgdb-ga 2004-10-21 14:54:15.290598968 -0700 -+++ 25-akpm/arch/i386/Kconfig.debug 2004-10-21 14:54:15.344590760 -0700 -@@ -65,4 +65,6 @@ config X86_MPPARSE - depends on X86_LOCAL_APIC && !X86_VISWS - default y - -+source "arch/i386/Kconfig.kgdb" -+ - endmenu -diff -puN /dev/null arch/i386/Kconfig.kgdb ---- /dev/null 2003-09-15 06:40:47.000000000 -0700 -+++ 25-akpm/arch/i386/Kconfig.kgdb 2004-10-21 14:54:15.345590608 -0700 -@@ -0,0 +1,175 @@ -+config KGDB -+ bool "Include kgdb kernel debugger" -+ depends on DEBUG_KERNEL -+ help -+ If you say Y here, the system will be compiled with the debug -+ option (-g) and a debugging stub will be included in the -+ kernel. This stub communicates with gdb on another (host) -+ computer via a serial port. The host computer should have -+ access to the kernel binary file (vmlinux) and a serial port -+ that is connected to the target machine. Gdb can be made to -+ configure the serial port or you can use stty and setserial to -+ do this. See the 'target' command in gdb. This option also -+ configures in the ability to request a breakpoint early in the -+ boot process. To request the breakpoint just include 'kgdb' -+ as a boot option when booting the target machine. The system -+ will then break as soon as it looks at the boot options. This -+ option also installs a breakpoint in panic and sends any -+ kernel faults to the debugger. For more information see the -+ Documentation/i386/kgdb/kgdb.txt file. -+ -+choice -+ depends on KGDB -+ prompt "Debug serial port BAUD" -+ default KGDB_115200BAUD -+ help -+ Gdb and the kernel stub need to agree on the baud rate to be -+ used. Some systems (x86 family at this writing) allow this to -+ be configured. -+ -+config KGDB_9600BAUD -+ bool "9600" -+ -+config KGDB_19200BAUD -+ bool "19200" -+ -+config KGDB_38400BAUD -+ bool "38400" -+ -+config KGDB_57600BAUD -+ bool "57600" -+ -+config KGDB_115200BAUD -+ bool "115200" -+endchoice -+ -+config KGDB_PORT -+ hex "hex I/O port address of the debug serial port" -+ depends on KGDB -+ default 3f8 -+ help -+ Some systems (x86 family at this writing) allow the port -+ address to be configured. The number entered is assumed to be -+ hex, don't put 0x in front of it. The standard address are: -+ COM1 3f8 , irq 4 and COM2 2f8 irq 3. Setserial /dev/ttySx -+ will tell you what you have. It is good to test the serial -+ connection with a live system before trying to debug. -+ -+config KGDB_IRQ -+ int "IRQ of the debug serial port" -+ depends on KGDB -+ default 4 -+ help -+ This is the irq for the debug port. If everything is working -+ correctly and the kernel has interrupts on a control C to the -+ port should cause a break into the kernel debug stub. -+ -+config DEBUG_INFO -+ bool -+ depends on KGDB -+ default y -+ -+config KGDB_MORE -+ bool "Add any additional compile options" -+ depends on KGDB -+ default n -+ help -+ Saying yes here turns on the ability to enter additional -+ compile options. -+ -+ -+config KGDB_OPTIONS -+ depends on KGDB_MORE -+ string "Additional compile arguments" -+ default "-O1" -+ help -+ This option allows you enter additional compile options for -+ the whole kernel compile. Each platform will have a default -+ that seems right for it. For example on PPC "-ggdb -O1", and -+ for i386 "-O1". Note that by configuring KGDB "-g" is already -+ turned on. In addition, on i386 platforms -+ "-fomit-frame-pointer" is deleted from the standard compile -+ options. -+ -+config NO_KGDB_CPUS -+ int "Number of CPUs" -+ depends on KGDB && SMP -+ default NR_CPUS -+ help -+ -+ This option sets the number of cpus for kgdb ONLY. It is used -+ to prune some internal structures so they look "nice" when -+ displayed with gdb. This is to overcome possibly larger -+ numbers that may have been entered above. Enter the real -+ number to get nice clean kgdb_info displays. -+ -+config KGDB_TS -+ bool "Enable kgdb time stamp macros?" -+ depends on KGDB -+ default n -+ help -+ Kgdb event macros allow you to instrument your code with calls -+ to the kgdb event recording function. The event log may be -+ examined with gdb at a break point. Turning on this -+ capability also allows you to choose how many events to -+ keep. Kgdb always keeps the lastest events. -+ -+choice -+ depends on KGDB_TS -+ prompt "Max number of time stamps to save?" -+ default KGDB_TS_128 -+ -+config KGDB_TS_64 -+ bool "64" -+ -+config KGDB_TS_128 -+ bool "128" -+ -+config KGDB_TS_256 -+ bool "256" -+ -+config KGDB_TS_512 -+ bool "512" -+ -+config KGDB_TS_1024 -+ bool "1024" -+ -+endchoice -+ -+config STACK_OVERFLOW_TEST -+ bool "Turn on kernel stack overflow testing?" -+ depends on KGDB -+ default n -+ help -+ This option enables code in the front line interrupt handlers -+ to check for kernel stack overflow on interrupts and system -+ calls. This is part of the kgdb code on x86 systems. -+ -+config KGDB_CONSOLE -+ bool "Enable serial console thru kgdb port" -+ depends on KGDB -+ default n -+ help -+ This option enables the command line "console=kgdb" option. -+ When the system is booted with this option in the command line -+ all kernel printk output is sent to gdb (as well as to other -+ consoles). For this to work gdb must be connected. For this -+ reason, this command line option will generate a breakpoint if -+ gdb has not yet connected. After the gdb continue command is -+ given all pent up console output will be printed by gdb on the -+ host machine. Neither this option, nor KGDB require the -+ serial driver to be configured. -+ -+config KGDB_SYSRQ -+ bool "Turn on SysRq 'G' command to do a break?" -+ depends on KGDB -+ default y -+ help -+ This option includes an option in the SysRq code that allows -+ you to enter SysRq G which generates a breakpoint to the KGDB -+ stub. This will work if the keyboard is alive and can -+ interrupt the system. Because of constraints on when the -+ serial port interrupt can be enabled, this code may allow you -+ to interrupt the system before the serial port control C is -+ available. Just say yes here. -+ -_ diff --git a/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch b/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch deleted file mode 100644 index 36fea12..0000000 --- a/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: linux-2.6.9-5.0.3.EL/include/asm-i386/thread_info.h -=================================================================== ---- linux-2.6.9-5.0.3.EL.orig/include/asm-i386/thread_info.h 2005-02-25 10:25:33.000000000 +0200 -+++ linux-2.6.9-5.0.3.EL/include/asm-i386/thread_info.h 2005-02-25 20:19:11.676139032 +0200 -@@ -54,7 +54,7 @@ - #endif - - #define PREEMPT_ACTIVE 0x4000000 --#define THREAD_SIZE (4096) -+#define THREAD_SIZE (8192) - - #define STACK_WARN (THREAD_SIZE/8) - /* diff --git a/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch deleted file mode 100644 index a6501a4..0000000 --- a/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch +++ /dev/null @@ -1,5485 +0,0 @@ -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Kconfig 2004-11-11 10:28:08.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig 2004-12-17 12:45:23.000000000 -0500 -@@ -6,6 +6,8 @@ - - source "drivers/mtd/Kconfig" - -+source "drivers/bluesmoke/Kconfig" -+ - source "drivers/parport/Kconfig" - - source "drivers/pnp/Kconfig" -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Makefile 2004-11-11 10:28:16.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile 2004-12-17 12:45:23.000000000 -0500 -@@ -29,6 +29,7 @@ - obj-$(CONFIG_IEEE1394) += ieee1394/ - obj-y += cdrom/ video/ - obj-$(CONFIG_MTD) += mtd/ -+obj-$(CONFIG_BLUESMOKE) += bluesmoke/ - obj-$(CONFIG_PCMCIA) += pcmcia/ - obj-$(CONFIG_DIO) += dio/ - obj-$(CONFIG_SBUS) += sbus/ -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Kconfig 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,72 @@ -+# -+# Bluesmoke Kconfig -+# Copyright (c) 2003 Linux Networx -+# Licensed and distributed under the GPL -+# -+# $Id: Kconfig,v 1.4 2004/11/10 01:12:35 thayne Exp $ -+# -+ -+menu 'Bluesmoke - error detection and reporting (RAS)' -+ -+config BLUESMOKE -+ tristate "Bluesmoke core system error reporting" -+ help -+ Bluesmoke is designed to report errors in the core system. -+ These are low-level errors that are reported in the CPU or -+ supporting chipset: memory errors, cache errors, PCI errors, -+ thermal throttling, etc.. If unsure, select 'Y'. -+ -+ -+comment "Reporting subsystems" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_DEBUG -+ bool "Debugging" -+ depends on BLUESMOKE -+ help -+ This turns on debugging information for the entire Bluesmoke -+ sub-system. Usually you should select 'N'. -+ -+config BULESMOKE_DEBUG_VERBOSE -+ int "Debugging verbosity (0=quiet, 3=noisy)" -+ depends on BLUESMOKE_DEBUG -+ default "0" -+ help -+ Verbosity level of Bluesmoke debug messages. -+ -+config BLUESMOKE_MM_EDAC -+ tristate "Bluesmoke Main Memory EDAC (Error Detection And Correction) reporting" -+ depends on BLUESMOKE -+ help -+ Some systems are able to detect and correct errors in main -+ memory. Bluesmoke can report statistics on memory error -+ detection and correction (EDAC - or commonly referred to ECC -+ errors). Bluesmoke will also try to decode where these errors -+ occurred so that a particular failing memory module can be -+ replaced. If unsure, select 'Y'. -+ -+ -+comment "Bluesmoke system controller/chipset support" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_AMD76X -+ tristate "AMD 76x (760, 762, 768)" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_E7XXX -+ tristate "Intel e7xxx (e7205, e7500, e7501, e7505)" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_E752X -+ tristate "Intel e752x (e7520)" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_I82875P -+ tristate "Intel 82875p" -+ depends on BLUESMOKE -+ -+config BLUESMOKE_K8 -+ tristate "AMD K8 (Athlon FX, Athlon 64, Opteron)" -+ depends on BLUESMOKE -+ -+endmenu -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Makefile 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,26 @@ -+# -+# Makefile for the Linux kernel bluesmoke drivers. -+# -+# Copyright 02 Jul 2003, Linux Networx (http://lnxi.com) -+# This file may be distributed under the terms of the -+# GNU General Public License. -+# -+# $Id: Makefile,v 1.4 2004/11/10 01:12:35 thayne Exp $ -+ -+ -+obj-$(CONFIG_BLUESMOKE_MM_EDAC) += bluesmoke_mc.o -+obj-$(CONFIG_BLUESMOKE_AMD76X) += bluesmoke_amd76x.o -+obj-$(CONFIG_BLUESMOKE_E7XXX) += bluesmoke_e7xxx.o -+obj-$(CONFIG_BLUESMOKE_E752X) += bluesmoke_e752x.o -+obj-$(CONFIG_BLUESMOKE_I82875P) += bluesmoke_i82875p.o -+obj-$(CONFIG_BLUESMOKE_K8) += bluesmoke_k8.o -+ -+ifeq ($(PATCHLEVEL),4) -+ -+export-objs := bluesmoke_mc.o -+ -+O_TARGET := bluesmokelink.o -+ -+include $(TOPDIR)/Rules.make -+ -+endif -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_amd76x.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,323 @@ -+/* -+ * AMD 76x Memory Controller kernel module -+ * (C) 2003 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * Written by Thayne Harbaugh -+ * Based on work by Dan Hollis and others. -+ * http://www.anime.net/~goemon/linux-ecc/ -+ * -+ * $Id: bluesmoke_amd76x.c,v 1.4 2004/11/10 01:12:35 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#define AMD76X_NR_CSROWS 8 -+#define AMD76X_NR_CHANS 1 -+#define AMD76X_NR_DIMMS 4 -+ -+ -+/* AMD 76x register addresses - device 0 function 0 - PCI bridge */ -+#define AMD76X_ECC_MODE_STATUS 0x48 /* Mode and status of ECC (32b) -+ * -+ * 31:16 reserved -+ * 15:14 SERR enabled: x1=ue 1x=ce -+ * 13 reserved -+ * 12 diag: disabled, enabled -+ * 11:10 mode: dis, EC, ECC, ECC+scrub -+ * 9:8 status: x1=ue 1x=ce -+ * 7:4 UE cs row -+ * 3:0 CE cs row -+ */ -+#define AMD76X_DRAM_MODE_STATUS 0x58 /* DRAM Mode and status (32b) -+ * -+ * 31:26 clock disable 5 - 0 -+ * 25 SDRAM init -+ * 24 reserved -+ * 23 mode register service -+ * 22:21 suspend to RAM -+ * 20 burst refresh enable -+ * 19 refresh disable -+ * 18 reserved -+ * 17:16 cycles-per-refresh -+ * 15:8 reserved -+ * 7:0 x4 mode enable 7 - 0 -+ */ -+#define AMD76X_MEM_BASE_ADDR 0xC0 /* Memory base address (8 x 32b) -+ * -+ * 31:23 chip-select base -+ * 22:16 reserved -+ * 15:7 chip-select mask -+ * 6:3 reserved -+ * 2:1 address mode -+ * 0 chip-select enable -+ */ -+ -+ -+enum amd76x_chips { -+ AMD761 = 0, -+ AMD762 -+}; -+ -+ -+struct amd76x_dev_info { -+ const char *ctl_name; -+}; -+ -+ -+static const struct amd76x_dev_info amd76x_devs[] = { -+ [AMD761] = { -+ .ctl_name = "AMD761" -+ }, -+ [AMD762] = { -+ .ctl_name = "AMD762" -+ }, -+}; -+ -+ -+static void amd76x_check(struct mem_ctl_info *mci) -+{ -+ u32 ems; -+ -+ debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ ); -+ -+ pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, &ems); -+ -+ if ( ems & BIT(8) ) { /* UE? */ -+ u32 ems_ue_row = (ems >> 4) & 0xf; -+ -+ pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS, -+ (u32)BIT(8), (u32)BIT(8) ); -+ -+ bluesmoke_mc_handle_ue( mci, mci->csrows[ems_ue_row].first_page, -+ 0, ems_ue_row, mci->ctl_name ); -+ } -+ -+ if ( ems & BIT(9) ) { /* CE? */ -+ u32 ems_ce_row = ems & 0xf; -+ -+ pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS, -+ (u32)BIT(9), (u32)BIT(9) ); -+ -+ bluesmoke_mc_handle_ce( mci, mci->csrows[ems_ce_row].first_page, -+ 0, 0, ems_ce_row, 0, mci->ctl_name ); -+ } -+ return; -+} -+ -+ -+static int amd76x_probe1( struct pci_dev *pdev, int dev_idx ) -+{ -+ int rc = -ENODEV; -+ int index; -+ struct mem_ctl_info *mci = NULL; -+ enum edac_type ems_modes[] = { EDAC_NONE, -+ EDAC_EC, -+ EDAC_SECDED, -+ EDAC_SECDED }; -+ u32 ems; -+ u32 ems_mode; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); -+ ems_mode = ( ems >> 10 ) & 0x3; -+ -+ mci = bluesmoke_mc_init_structs(0, -+ AMD76X_NR_CSROWS, -+ AMD76X_NR_CHANS); -+ -+ if ( ! mci ) { -+ rc = -ENOMEM; -+ goto FAIL_FINISHED; -+ } -+ -+ debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci ); -+ -+ mci->pdev = pdev; -+ mci->mtype_cap = MEM_FLAG_RDDR; -+ -+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; -+ if ( ems_mode ) { -+ mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED; -+ } else { -+ mci->edac_cap = EDAC_FLAG_NONE; -+ } -+ -+ mci->mod_name = BS_MOD_STR; -+ mci->mod_ver = "$Revision: 1.4 $"; -+ mci->ctl_name = amd76x_devs[dev_idx].ctl_name; -+ mci->edac_check = amd76x_check; -+ mci->clear_err = NULL; -+ mci->ctl_page_to_phys = NULL; -+ -+ for ( index = 0; index < mci->nr_csrows; index++ ) { -+ struct csrow_info *csrow = &mci->csrows[ index ]; -+ u32 mba; -+ u32 mba_base; -+ u32 mba_mask; -+ u32 dms; -+ -+ /* find the DRAM Chip Select Base address and mask */ -+ pci_read_config_dword( mci->pdev, -+ AMD76X_MEM_BASE_ADDR + (index*4), -+ &mba ); -+ -+ if ( ! (mba & BIT(0)) ) { -+ continue; -+ } -+ -+ mba_base = mba & 0xff800000UL; -+ mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; -+ -+ pci_read_config_dword( mci->pdev, -+ AMD76X_DRAM_MODE_STATUS, -+ &dms ); -+ -+ csrow->first_page = mba_base >> PAGE_SHIFT; -+ csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; -+ csrow->last_page = csrow->first_page + csrow->nr_pages - 1; -+ csrow->page_mask = mba_mask >> PAGE_SHIFT; -+ csrow->grain = csrow->nr_pages << PAGE_SHIFT; -+ csrow->mtype = MEM_RDDR; -+ csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; -+ csrow->edac_mode = ems_modes[ ems_mode ]; -+ } -+ -+ /* clear counters */ -+ pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS, -+ (u32)(0x3 << 8), (u32)(0x3 << 8) ); -+ -+ if ( 0 != bluesmoke_mc_add_mc( mci ) ) { -+ debugf3( "MC: " __FILE__ -+ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* get this far and it's successful */ -+ debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ ); -+ rc = 0; -+ goto FINISHED; -+ -+ FAIL_FINISHED: -+ if ( mci ) { -+ kfree( mci ); -+ } -+ -+ FINISHED: -+ return( rc ); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int amd76x_suspend (struct pci_dev *pdev, u32 state) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+ -+static int amd76x_resume (struct pci_dev *pdev) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* returns count (>= 0), or negative on error */ -+static int __devinit amd76x_init_one( struct pci_dev *pdev, -+ const struct pci_device_id *ent ) -+{ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* don't need to call pci_device_enable() */ -+ return amd76x_probe1( pdev, ent->driver_data ); -+} -+ -+ -+static void __devexit amd76x_remove_one( struct pci_dev *pdev ) -+{ -+ struct mem_ctl_info *mci; -+ -+ debugf0( __FILE__ ": %s()\n", __func__); -+ -+ if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) { -+ goto FINISHED; -+ } -+ -+ if ( 0 != bluesmoke_mc_del_mc( mci ) ) { -+ goto FINISHED; -+ } -+ -+ kfree( mci ); -+ -+ FINISHED: -+ return; -+} -+ -+ -+static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { -+ { PCI_VEND_DEV( AMD, FE_GATE_700C ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD762 }, -+ { PCI_VEND_DEV( AMD, FE_GATE_700E ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD761 }, -+ {0,} /* 0 terminated list. */ -+}; -+ -+MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); -+ -+ -+static struct pci_driver amd76x_driver = { -+ .name = BS_MOD_STR, -+ .probe = amd76x_init_one, -+ .remove = __devexit_p(amd76x_remove_one), -+ .id_table = amd76x_pci_tbl, -+#ifdef CONFIG_PM -+ .suspend = amd76x_suspend, -+ .resume = amd76x_resume, -+#endif /* CONFIG_PM */ -+}; -+ -+ -+int __init amd76x_init(void) -+{ -+ int pci_rc; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_rc = pci_module_init( &amd76x_driver ); -+ if ( pci_rc < 0 ) return pci_rc; -+ -+ return 0; -+} -+ -+ -+static void __exit amd76x_exit(void) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_unregister_driver( &amd76x_driver ); -+} -+ -+ -+module_init(amd76x_init); -+module_exit(amd76x_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); -+MODULE_DESCRIPTION("MC support for AMD 76x memory controllers"); -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e752x.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,1027 @@ -+/* -+ * Intel e752x Memory Controller kernel module -+ * (C) 2004 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * See "enum e752x_chips" below for supported chipsets -+ * -+ * Written by Tom Zimmerman -+ * -+ * Contributors: -+ * Thayne Harbaugh (Linux Networx) -+ * -+ * $Id: bluesmoke_e752x.c,v 1.5 2004/11/18 22:19:46 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7520_0 -+#define PCI_DEVICE_ID_INTEL_7520_0 0x3590 -+#endif /* PCI_DEVICE_ID_INTEL_7520_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR -+#define PCI_DEVICE_ID_INTEL_7520_1_ERR 0x3591 -+#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR */ -+ -+ -+#define E752X_NR_CSROWS 8 /* number of csrows */ -+ -+ -+/* E752X register addresses - device 0 function 0 */ -+#define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ -+#define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ -+ /* -+ * 31:30 Device width row 7 -+ * 01=x8 10=x4 11=x8 DDR2 -+ * 27:26 Device width row 6 -+ * 23:22 Device width row 5 -+ * 19:20 Device width row 4 -+ * 15:14 Device width row 3 -+ * 11:10 Device width row 2 -+ * 7:6 Device width row 1 -+ * 3:2 Device width row 0 -+ */ -+#define E752X_DRC 0x7C /* DRAM controller mode reg (32b) */ -+ /* -+ * 22 Number channels 0=1,1=2 -+ * 19:18 DRB Granularity 32/64MB -+ */ -+#define E752X_DRM 0x80 /* Dimm mapping register */ -+#define E752X_DDRCSR 0x9A /* DDR control and status reg (16b) */ -+ /* -+ * 14:12 1 single A, 2 single B, 3 dual -+ */ -+#define E752X_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ -+#define E752X_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ -+#define E752X_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ -+#define E752X_REMAPOFFSET 0xCA /* DRAM remap limit offset reg (16b) */ -+ -+/* E752X register addresses - device 0 function 1 */ -+#define E752X_FERR_GLOBAL 0x40 /* Global first error register (32b)*/ -+#define E752X_NERR_GLOBAL 0x44 /* Global next error register (32b) */ -+#define E752X_HI_FERR 0x50 /* Hub interface first error reg (8b)*/ -+#define E752X_HI_NERR 0x52 /* Hub interface next error reg (8b)*/ -+#define E752X_HI_ERRMASK 0x54 /* Hub interface error mask reg (8b)*/ -+#define E752X_HI_SMICMD 0x5A /* Hub interface SMI command reg (8b)*/ -+#define E752X_SYSBUS_FERR 0x60 /* System buss first error reg (16b)*/ -+#define E752X_SYSBUS_NERR 0x62 /* System buss next error reg (16b)*/ -+#define E752X_SYSBUS_ERRMASK 0x64 /* System buss error mask reg (16b) */ -+#define E752X_SYSBUS_SMICMD 0x6A /* System buss SMI command reg (16b) */ -+#define E752X_BUF_FERR 0x70 /* Memory buffer first error reg (8b)*/ -+#define E752X_BUF_NERR 0x72 /* Memory buffer next error reg (8b)*/ -+#define E752X_BUF_ERRMASK 0x74 /* Memory buffer error mask reg (8b)*/ -+#define E752X_BUF_SMICMD 0x7A /* Memory buffer SMI command reg (8b)*/ -+#define E752X_DRAM_FERR 0x80 /* DRAM first error register (16b) */ -+#define E752X_DRAM_NERR 0x82 /* DRAM next error register (16b) */ -+#define E752X_DRAM_ERRMASK 0x84 /* DRAM error mask register (8b) */ -+#define E752X_DRAM_SMICMD 0x8A /* DRAM SMI command register (8b) */ -+#define E752X_DRAM_RETRY_ADD 0xAC /* DRAM Retry address register (32b) */ -+#define E752X_DRAM_CELOG1_ADD 0xA0 /* DRAM first correctable memory */ -+ /* error address register (32b) */ -+ /* -+ * 31 Reserved -+ * 30:2 CE address (64 byte block 34:6) -+ * 1 Reserved -+ * 0 HiLoCS -+ */ -+#define E752X_DRAM_CELOG2_ADD 0xC8 /* DRAM first correctable memory */ -+ /* error address register (32b) */ -+ /* -+ * 31 Reserved -+ * 30:2 CE address (64 byte block 34:6) -+ * 1 Reserved -+ * 0 HiLoCS -+ */ -+#define E752X_DRAM_UELOG_ADD 0xA4 /* DRAM first uncorrectable memory */ -+ /* error address register (32b) */ -+ /* -+ * 31 Reserved -+ * 30:2 CE address (64 byte block 34:6) -+ * 1 Reserved -+ * 0 HiLoCS -+ */ -+#define E752X_DRAM_UELOGS_ADD 0xA8 /* DRAM first uncorrectable scrub memory */ -+ /* error address register (32b) */ -+ /* -+ * 31 Reserved -+ * 30:2 CE address (64 byte block 34:6) -+ * 1 Reserved -+ * 0 HiLoCS -+ */ -+#define E752X_DRAM_CELOG1_SYNDROME 0xC4 /* DRAM first correctable memory */ -+ /* error syndrome register (16b) */ -+#define E752X_DRAM_CELOG2_SYNDROME 0xC6 /* DRAM second correctable memory */ -+ /* error syndrome register (16b) */ -+#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ -+ -+/* ICH5R register addresses - device 30 function 0 */ -+#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ -+#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ -+#define ICH5R_PCI_BRIDGE_CTL 0x3E /* PCI bridge control register (16b) */ -+ -+enum e752x_chips { -+ E7520 = 0, -+}; -+ -+ -+struct e752x_pvt { -+ struct pci_dev *bridge_ck; -+ struct pci_dev *dev_d0f0; -+ struct pci_dev *dev_d0f1; -+ u32 tolm; -+ u32 remapbase; -+ u32 remaplimit; -+ int mc_symmetric; -+ u8 map[8]; -+ int map_type; -+ const struct e752x_dev_info *dev_info; -+}; -+ -+ -+struct e752x_dev_info { -+ u16 err_dev; -+ const char *ctl_name; -+}; -+ -+ -+static const struct e752x_dev_info e752x_devs[] = { -+ [E7520] = { -+ .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, -+ .ctl_name = "E7520" -+ }, -+}; -+ -+ -+/* FIXME - is this valid for both SECDED and S4ECD4ED? */ -+static inline int e752x_find_channel(u16 syndrome) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if((syndrome & 0xff00)==0) -+ return(0); -+ if((syndrome & 0x00ff)==0) -+ return(1); -+ if((syndrome & 0xf000)==0) -+ return(0); -+ if((syndrome & 0x0f00)==0) -+ return(0); -+ return(1); -+} -+ -+ -+static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, -+ unsigned long page) -+{ -+ u32 remap; -+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if(page < pvt->tolm) -+ return(page); -+ if((page >= 0x100000)&&(page < pvt->remapbase)) -+ return(page); -+ remap = (page - pvt->tolm) + pvt->remapbase; -+ if(remap < pvt->remaplimit) -+ return(remap); -+ printk(KERN_ERR "Invalid page %lx - out of range\n", page); -+ return(pvt->tolm-1); -+} -+ -+ -+static void process_ce(struct mem_ctl_info *mci, u16 error_one, -+ u32 celog1_add, u16 celog1_syndrome) -+{ -+ u32 error_1b, page; -+ u16 syndrome; -+ int row; -+ int channel; -+ int i; -+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if(error_one&0x0101) { -+ /* read the error address */ -+// pci_read_config_dword(pvt->bridge_ck,E752X_DRAM_CELOG1_ADD, -+// &error_1b); -+ error_1b = celog1_add; -+ page = error_1b >> (PAGE_SHIFT-4); /* convert the addr to 4k page */ -+ /* read the syndrome */ -+// pci_read_config_word(pvt->bridge_ck,E752X_DRAM_CELOG1_SYNDROME, -+// &syndrome); -+ syndrome = celog1_syndrome; -+ /* FIXME - check for -1 */ -+ if (pvt->mc_symmetric) { -+ row = ((page >>1)&3); /* chip select are bits 14 & 13 */ -+ printk( KERN_WARNING -+ "Test row %d Table %d %d %d %d %d %d %d %d\n", -+ row,pvt->map[0],pvt->map[1],pvt->map[2],pvt->map[3],pvt->map[4], -+ pvt->map[5],pvt->map[6],pvt->map[7]); -+ -+ /* test for channel remapping */ -+ for(i=0;i<8;i++) { -+ if(pvt->map[i] == row) -+ break; -+ } -+ printk( KERN_WARNING -+ "Test computed row %d\n",i); -+ if(i<8) { -+ row = i; -+ } -+ else { -+ printk( KERN_WARNING -+ "MC%d: row %d not found in remap table\n", -+ mci->mc_idx,row); -+ } -+ -+ -+ } else { -+ row = bluesmoke_mc_find_csrow_by_page( mci, page ); -+ } -+ if(error_one&1) -+ channel = 0; /* 0 = channel A */ -+ else -+ channel = 1; /* 1 = channel B */ -+ -+ if(!pvt->map_type) -+ row = 7 - row; -+ bluesmoke_mc_handle_ce( mci, page, 0, syndrome, -+ row, channel, "e752x CE" ); -+ } -+} -+ -+ -+static void process_ue(struct mem_ctl_info *mci, u16 error_one, -+ u32 uelog_add, u32 uelogs_add) -+{ -+ u32 error_2b, block_page; -+ int row; -+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if(error_one & 0x0202) { -+ error_2b = uelog_add; -+ /* convert to 4k address */ -+ block_page = error_2b >> (PAGE_SHIFT - 4); -+ if (pvt->mc_symmetric) { -+ /* chip select are bits 14 & 13 */ -+ row = ((block_page >>1)&3); -+ } -+ else { -+ row = bluesmoke_mc_find_csrow_by_page(mci, block_page); -+ } -+ bluesmoke_mc_handle_ue( mci, block_page, 0, row, -+ "e752x UE from Read" ); -+ } -+ if(error_one & 0x0404) { -+ error_2b = uelogs_add; -+ /* convert to 4k address */ -+ block_page = error_2b >> (PAGE_SHIFT - 4); -+ if (pvt->mc_symmetric) { -+ /* chip select are bits 14 & 13 */ -+ row = ((block_page >>1)&3); -+ } -+ else { -+ row = bluesmoke_mc_find_csrow_by_page(mci, block_page); -+ } -+ bluesmoke_mc_handle_ue( mci, block_page, 0, row, -+ "e752x UE from Scruber" ); -+ } -+} -+ -+#if 0 -+static void process_ue_no_info(struct mem_ctl_info *mci) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log register overflow" ); -+} -+#endif -+ -+static void process_ue_no_info_wr(struct mem_ctl_info *mci) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log memory write" ); -+} -+ -+static void process_ded_retry(struct mem_ctl_info *mci,u16 error,u32 retry_add) -+{ -+ u32 error_1b, page; -+ int row; -+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info; -+ -+ error_1b = retry_add; -+ page = error_1b >> (PAGE_SHIFT-4); /* convert the addr to 4k page */ -+ if (pvt->mc_symmetric) { -+ row = ((page >>1)&3); /* chip select are bits 14 & 13 */ -+ } else { -+ row = bluesmoke_mc_find_csrow_by_page( mci, page ); -+ } -+ printk( KERN_WARNING -+ "MC%d: CE page 0x%lx, row %d : Memory read retry\n", -+ mci->mc_idx,(long unsigned int)page,row); -+} -+ -+static void process_threshold_ce(struct mem_ctl_info *mci,u16 error) -+{ -+ printk( KERN_WARNING -+ "MC%d: Memory threshold CE\n",mci->mc_idx); -+} -+ -+char *global_message[11]= {"PCI Express C1","PCI Express C","PCI Express B1", -+ "PCI Express B","PCI Express A1","PCI Express A", -+ "DMA Controler","HUB Interface","System Bus", -+ "DRAM Controler","Internal Buffer"}; -+char *fatal_message[2]={"Non-Fatal ","Fatal "}; -+ -+static void global_error(int fatal, u32 errors) -+{ -+ int i; -+ -+ for(i=0;i<11;i++) { -+ if(errors & (1<pvt_info; -+ struct pci_dev *pres_dev; -+ struct pci_dev *dev; -+ -+ /* clear snapshot */ -+ hi_ferr=hi_nerr=buf_ferr=buf_nerr=0; -+ sysbus_ferr=sysbus_nerr=dram_ferr=dram_nerr=0; -+ celog1_syndrome=celog2_syndrome=retry_add=0; -+ celog1_add=celog2_add=uelog_add=uelogs_add=0; -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if (pvt->dev_d0f1 != NULL) { -+ dev = pvt->dev_d0f1; -+ pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32); -+ if(stat32) { /* Error, so process */ -+#if 1 -+ /* dump d0f0 and d0f1 */ -+ printk("\nDevice 0 Function 0"); -+ for(i=0;i<0x100;i++) { -+ pci_read_config_byte(mci->pdev,i,&stat8); -+ if((i%16)==0) { -+ printk("\n%2.2x ",i); -+ } -+ printk("%2.2x ",stat8); -+ } -+ printk("\n"); -+ /* dump d0f0 and d0f1 */ -+ printk("\nDevice 0 Function 1"); -+ for(i=0;i<0x100;i++) { -+ pci_read_config_byte(dev,i,&stat8); -+ if((i%16)==0) { -+ printk("\n%2.2x ",i); -+ } -+ printk("%2.2x ",stat8); -+ } -+ printk("\n\n"); -+#endif -+ /* take a snap shot of first errors */ -+ pci_read_config_byte(dev,E752X_HI_FERR,&hi_ferr); -+ pci_read_config_word(dev,E752X_SYSBUS_FERR,&sysbus_ferr); -+ pci_read_config_byte(dev,E752X_BUF_FERR,&buf_ferr); -+ pci_read_config_word(dev,E752X_DRAM_FERR,&dram_ferr); -+ pci_read_config_dword(dev,E752X_DRAM_CELOG1_ADD, -+ &celog1_add); -+ pci_read_config_word(dev,E752X_DRAM_CELOG1_SYNDROME, -+ &celog1_syndrome); -+ pci_read_config_dword(dev,E752X_DRAM_UELOG_ADD, -+ &uelog_add); -+ pci_read_config_dword(dev,E752X_DRAM_UELOGS_ADD, -+ &uelogs_add); -+ pci_read_config_dword(dev,E752X_DRAM_RETRY_ADD, -+ &retry_add); -+ -+ pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32); -+ error32=(stat32>>18)&0x3ff; -+ stat32=(stat32>>4)&0x7ff; -+ if(error32) -+ global_error(1,error32); -+ if(stat32) -+ global_error(0,stat32); -+ } -+ -+ pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32); -+ if(stat32) { /* Error, so process */ -+ /* take a snap shot of second errors */ -+ pci_read_config_byte(dev,E752X_HI_NERR,&hi_nerr); -+ pci_read_config_word(dev,E752X_SYSBUS_NERR,&sysbus_nerr); -+ pci_read_config_byte(dev,E752X_BUF_NERR,&buf_nerr); -+ pci_read_config_word(dev,E752X_DRAM_NERR,&dram_nerr); -+ pci_read_config_dword(dev,E752X_DRAM_CELOG2_ADD, -+ &celog2_add); -+ pci_read_config_word(dev,E752X_DRAM_CELOG2_SYNDROME, -+ &celog2_syndrome); -+ -+ pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32); -+ error32=(stat32>>18)&0x3ff; -+ stat32=(stat32>>4)&0x7ff; -+ if(error32) -+ global_error(1,error32); -+ if(stat32) -+ global_error(0,stat32); -+ } -+ -+// pci_read_config_byte(dev,E752X_HI_FERR,&stat8); -+ stat8=hi_ferr; -+ if(stat8&0x7f) { /* Error, so process */ -+ pci_write_config_dword(dev,E752X_HI_FERR,stat8); -+ stat8 &= 0x7f; -+ if(stat8&0x2b) -+ hub_error(1,(stat8&0x2b)); -+ if(stat8 & 0x54) -+ hub_error(0,(stat8&0x54)); -+ } -+// pci_read_config_byte(dev,E752X_HI_NERR,&stat8); -+ stat8=hi_nerr; -+ if(stat8&0x7f) { /* Error, so process */ -+ pci_write_config_dword(dev,E752X_HI_NERR,stat8); -+ stat8 &= 0x7f; -+ if(stat8&0x2b) -+ hub_error(1,(stat8&0x2b)); -+ if(stat8 & 0x54) -+ hub_error(0,(stat8&0x54)); -+ } -+// pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32); -+ stat32 = sysbus_ferr + (sysbus_nerr <<16); -+ if(stat32) { /* Error, so process */ -+ pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32); -+ error32=(stat32>>16)&0x3ff; -+ stat32=stat32&0x3ff; -+ if(stat32 & 0x083) -+ sysbus_error(1,(stat32&0x083)); -+ if(stat32 & 0x37c) -+ sysbus_error(0,(stat32&0x37c)); -+ if(error32 & 0x083) -+ sysbus_error(1,(error32&0x083)); -+ if(error32 & 0x37c) -+ sysbus_error(0,(error32&0x37c)); -+ } -+// pci_read_config_byte(dev,E752X_BUF_FERR,&stat8); -+ stat8 = buf_ferr; -+ if(stat8&0x0f) { /* Error, so process */ -+ pci_write_config_dword(dev,E752X_BUF_FERR,stat8); -+ stat8 &= 0x0f; -+ membuf_error(stat8); -+ } -+// pci_read_config_byte(dev,E752X_BUF_NERR,&stat8); -+ stat8 = buf_nerr; -+ if(stat8&0x0f) { /* Error, so process */ -+ pci_write_config_dword(dev,E752X_BUF_NERR,stat8); -+ stat8 &= 0x0f; -+ membuf_error(stat8); -+ } -+ -+ -+ -+ -+// pci_read_config_word(pvt->bridge_ck,E752X_DRAM_FERR,&error_one); -+// pci_read_config_word(pvt->bridge_ck,E752X_DRAM_NERR,&error_next); -+ error_one = dram_ferr; -+ error_next = dram_nerr; -+ /* clear any error bits */ -+ if(error_one) { -+ pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, -+ error_one,error_one); -+ } -+ if(error_next) { -+ pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, -+ error_next, error_next); -+ } -+ -+ /* decode and report errors */ -+ if(error_one & 0x0101) { /* check first error correctable */ -+ process_ce(mci,error_one,celog1_add,celog1_syndrome); -+ } -+ if(error_next & 0x0101) { /* check next error correctable */ -+ process_ce(mci,error_next,celog2_add,celog2_syndrome); -+ } -+ if(error_one & 0x4040) { -+ process_ue_no_info_wr(mci); -+ } -+ if(error_next & 0x4040) { -+ process_ue_no_info_wr(mci); -+ } -+ if(error_one & 0x2020) { -+ process_ded_retry(mci,error_one,retry_add); -+ } -+ if(error_next & 0x2020) { -+ process_ded_retry(mci,error_next,retry_add); -+ } -+ if(error_one & 0x0808) { -+ process_threshold_ce(mci,error_one); -+ } -+ if(error_next & 0x0808) { -+ process_threshold_ce(mci,error_next); -+ } -+ if(error_one & 0x0606) { -+ process_ue(mci,error_one,uelog_add,uelogs_add); -+ } -+ if(error_next & 0x0606) { -+ process_ue(mci,error_next,uelog_add,uelogs_add); -+ } -+ -+ -+ } -+ /* Test for PCI Parity errors in the southbridge */ -+ if (pvt->dev_d0f0 != NULL) { -+ dev = pvt->dev_d0f0; -+ for(pres_dev = dev; -+ ((struct pci_dev*)pres_dev->global_list.next != dev); -+ pres_dev = (struct pci_dev*)pres_dev->global_list.next) { -+ pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32); -+ stat = (u16)(stat32 >>16); -+ /* test for error any error bits */ -+ if(stat32 & ((1<<6)+(1<<8))) { /* error reporting dev */ -+ if(stat & ((1<<15)+(1<<14)+(1<<8))) { -+ pci_write_config_word(pres_dev,6,stat); -+ if(stat & (1<<14)) { -+ printk( KERN_WARNING -+ "System Error on %s %s\n", -+ pres_dev->slot_name, -+ pci_pretty_name(pres_dev)); -+ } -+ if(stat & ((1<<15)+(1<<8))) { -+ printk( KERN_WARNING -+ "Parity Error on %s %s\n", -+ pres_dev->slot_name, -+ pci_pretty_name(pres_dev)); -+ } -+ } -+ } -+ } -+ } -+} -+ -+ -+static int e752x_probe1( struct pci_dev *pdev, int dev_idx ) -+{ -+ int rc = -ENODEV; -+ int index; -+ u16 pci_data, stat; -+ u32 stat32; -+ u16 stat16; -+ u8 stat8; -+ struct mem_ctl_info *mci = NULL; -+ struct e752x_pvt *pvt = NULL; -+ u16 ddrcsr; -+ u32 drc; -+ int drc_chan; /* Number of channels 0=1chan,1=2chan */ -+ int drc_drbg; /* DRB granularity 0=32mb,1=64mb */ -+ int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ -+ u32 dra; -+ unsigned long last_cumul_size; -+ struct pci_dev *pres_dev; -+ struct pci_dev *dev; -+ -+ debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ ); -+ printk( KERN_ERR "Starting Probe1\n" ); -+ -+ /* enable device 0 function 1 */ -+ pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8); -+ stat8 |= (1<<5); -+ pci_write_config_byte(pdev, E752X_DEVPRES1, stat8); -+ -+ /* need to find out the number of channels */ -+ pci_read_config_dword(pdev, E752X_DRC, &drc); -+ pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr); -+ if(((ddrcsr>>12)&3)==3) -+ drc_chan = 1; /* Dual channel */ -+ else -+ drc_chan = 0; /* Single channel */ -+ drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ -+ drc_ddim = ( drc >> 20 ) & 0x3; -+ -+ mci = bluesmoke_mc_init_structs(sizeof(*pvt), -+ E752X_NR_CSROWS, -+ drc_chan + 1); -+ -+ if ( ! mci ) { -+ rc = -ENOMEM; -+ goto FAIL_FINISHED; -+ } -+ -+ debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ ); -+ -+ mci->mtype_cap = MEM_FLAG_RDDR; -+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED; -+ /* FIXME - what if different memory types are in different csrows? */ -+ mci->mod_name = BS_MOD_STR; -+ mci->mod_ver = "$Revision: 1.5 $"; -+ mci->pdev = pdev; -+ -+ debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ ); -+ pvt = (struct e752x_pvt *)mci->pvt_info; -+ pvt->dev_info = &e752x_devs[dev_idx]; -+ pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL, -+ pvt->dev_info->err_dev, -+ pvt->bridge_ck ); -+ if ( ! pvt->bridge_ck ) { -+ pvt->bridge_ck = pci_scan_single_device(pdev->bus, PCI_DEVFN(0,1)); -+ } -+ if ( ! pvt->bridge_ck ) { -+ printk( KERN_ERR -+ "MC: error reporting device not found:" -+ "vendor %x device 0x%x (broken BIOS?)\n", -+ PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev ); -+ goto FAIL_FINISHED; -+ } -+ if(ddrcsr & 0x10) { -+ pvt->mc_symmetric = 1; -+ } else { -+ pvt->mc_symmetric =0; -+ } -+ -+ debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ ); -+ mci->ctl_name = pvt->dev_info->ctl_name; -+ -+ mci->edac_check = e752x_check; -+ /* FIXME - why isn't clear_err set to something? */ -+ mci->clear_err = NULL; -+ mci->ctl_page_to_phys = ctl_page_to_phys; -+ -+ /* find out the device types */ -+ pci_read_config_dword(pdev, E752X_DRA, &dra); -+ -+ /* -+ * The dram row boundary (DRB) reg values are boundary address -+ * for each DRAM row with a granularity of 64 or 128MB (single/dual -+ * channel operation). DRB regs are cumulative; therefore DRB7 will -+ * contain the total memory contained in all eight rows. -+ */ -+ for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) { -+ u8 value; -+ u32 cumul_size; -+ /* mem_dev 0=x8, 1=x4 */ -+ int mem_dev = ( dra >> ( index * 4 + 2 ) ) & 0x3; -+ struct csrow_info *csrow = &mci->csrows[ index ]; -+ -+ if(mem_dev == 2) -+ mem_dev = 1; -+ else -+ mem_dev = 0; -+ pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); -+ /* convert a 128 or 64 MiB DRB to a page size. */ -+ cumul_size = value << (25 + drc_drbg - PAGE_SHIFT ); -+ debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", -+ __func__, index, cumul_size ); -+ if ( cumul_size == last_cumul_size ) { -+ continue; /* not populated */ -+ } -+ -+ csrow->first_page = last_cumul_size; -+ csrow->last_page = cumul_size - 1; -+ csrow->nr_pages = cumul_size - last_cumul_size; -+ last_cumul_size = cumul_size; -+ csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ -+ csrow->mtype = MEM_RDDR; /* only one type supported */ -+ csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; -+ -+ /* -+ * if single channel or x8 devices then SECDED -+ * if dual channel and x4 then S4ECD4ED -+ */ -+ if ( drc_ddim ) { -+ if ( drc_chan && mem_dev ) { -+ csrow->edac_mode = EDAC_S4ECD4ED; -+ mci->edac_cap |= EDAC_FLAG_S4ECD4ED; -+ } else { -+ csrow->edac_mode = EDAC_SECDED; -+ mci->edac_cap |= EDAC_FLAG_SECDED; -+ } -+ } else { -+ csrow->edac_mode = EDAC_NONE; -+ } -+ } -+ -+ /* Fill in the memory map table */ -+ { -+ u8 value; -+ u8 last=0; -+ u8 row=0; -+ for(index=0;index<8;index+=2) { -+ -+ pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); -+ /* test if there is a dimm in this slot */ -+ if(value == last) { -+ /* no dimm in the slot, so flag it as empty */ -+ pvt->map[index]=0xff; -+ pvt->map[index+1]=0xff; -+ } -+ else { /* there is a dimm in the slot */ -+ pvt->map[index]=row; -+ row++; -+ last = value; -+ /* test the next value to see if the dimm is double sided */ -+ pci_read_config_byte(mci->pdev, E752X_DRB + index + 1, &value); -+ if(value == last) { -+ /* the dimm is single sided, so flag as empty */ -+ pvt->map[index+1]=0xff; -+ row++; -+ } -+ else { -+ /* this is a double sided dimm to save the next row # */ -+ pvt->map[index+1]=row; -+ row++; -+ } -+ last = value; -+ } -+ } -+ } -+ -+ /* set the map type. 1 = normal, 0 = reversed */ -+ pci_read_config_byte(mci->pdev, E752X_DRM, &stat8); -+ if((stat8&0x0f) > ((stat8>>4)&0x0f)) { -+ /* map type is normal */ -+ pvt->map_type = 1; -+ } -+ else { -+ /* map type is reversed */ -+ pvt->map_type = 0; -+ } -+ -+ mci->edac_cap |= EDAC_FLAG_NONE; -+ -+ debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ ); -+ /* load the top of low memory, remap base, and remap limit vars */ -+ pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data); -+ pvt->tolm = ((u32)pci_data) << 4; -+ pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data); -+ pvt->remapbase = ((u32)pci_data) << 14; -+ pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data); -+ pvt->remaplimit = ((u32)pci_data) << 14; -+ printk( "tolm = %x, remapbase = %x, remaplimit = %x\n", -+ pvt->tolm, pvt->remapbase, pvt->remaplimit); -+ -+ if ( 0 != bluesmoke_mc_add_mc( mci ) ) { -+ debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* Walk through the PCI table and clear errors */ -+ dev = pci_find_device( PCI_VENDOR_ID_INTEL, -+ PCI_DEVICE_ID_INTEL_7520_0, NULL ); -+ pvt->dev_d0f0 = dev; -+ for(pres_dev = dev; -+ ((struct pci_dev*)pres_dev->global_list.next != dev); -+ pres_dev = (struct pci_dev*)pres_dev->global_list.next) { -+ pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32); -+ stat = (u16)(stat32 >>16); -+ /* clear any error bits */ -+ if(stat32 & ((1<<6)+(1<<8))) { -+ pci_write_config_word(pres_dev,PCI_STATUS,stat); -+ } -+ } -+ /* find the error reporting device and clear errors */ -+ dev = pvt->dev_d0f1 = pvt->bridge_ck; -+ /* Turn off error disable & SMI in case the BIOS turned it on */ -+ pci_write_config_byte(dev,E752X_HI_ERRMASK,0x00); -+ pci_write_config_byte(dev,E752X_HI_SMICMD,0x00); -+ pci_write_config_word(dev,E752X_SYSBUS_ERRMASK,0x00); -+ pci_write_config_word(dev,E752X_SYSBUS_SMICMD,0x00); -+ pci_write_config_byte(dev,E752X_BUF_ERRMASK,0x00); -+ pci_write_config_byte(dev,E752X_BUF_SMICMD,0x00); -+ pci_write_config_byte(dev,E752X_DRAM_ERRMASK,0x00); -+ pci_write_config_byte(dev,E752X_DRAM_SMICMD,0x00); -+ /* clear other MCH errors */ -+ pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32); -+ pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32); -+ pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32); -+ pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32); -+ pci_read_config_byte(dev,E752X_HI_FERR,&stat8); -+ pci_write_config_byte(dev,E752X_HI_FERR,stat8); -+ pci_read_config_byte(dev,E752X_HI_NERR,&stat8); -+ pci_write_config_byte(dev,E752X_HI_NERR,stat8); -+ pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32); -+ pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32); -+ pci_read_config_byte(dev,E752X_BUF_FERR,&stat8); -+ pci_write_config_byte(dev,E752X_BUF_FERR,stat8); -+ pci_read_config_byte(dev,E752X_BUF_NERR,&stat8); -+ pci_write_config_byte(dev,E752X_BUF_NERR,stat8); -+ pci_read_config_word(dev, E752X_DRAM_FERR, &stat16); -+ pci_write_config_word(dev, E752X_DRAM_FERR, stat16); -+ pci_read_config_word(dev, E752X_DRAM_NERR, &stat16); -+ pci_write_config_word(dev, E752X_DRAM_NERR, stat16); -+ -+ /* get this far and it's successful */ -+ debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ ); -+ rc = 0; -+ goto FINISHED; -+ -+ FAIL_FINISHED: -+ if ( mci ) { -+ kfree( mci ); -+ } -+ FINISHED: -+ return( rc ); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int e752x_suspend (struct pci_dev *pdev, u32 state) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+ -+static int e752x_resume (struct pci_dev *pdev) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* returns count (>= 0), or negative on error */ -+static int __devinit e752x_init_one( struct pci_dev *pdev, -+ const struct pci_device_id *ent ) -+{ -+ int rc; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* wake up and enable device */ -+ if (pci_enable_device (pdev)) { -+ rc = -EIO; -+ } else { -+ rc = e752x_probe1( pdev, ent->driver_data ); -+ } -+ return rc; -+} -+ -+ -+static void __devexit e752x_remove_one( struct pci_dev *pdev ) -+{ -+ struct mem_ctl_info *mci; -+ -+ debugf0( __FILE__ ": %s()\n", __func__); -+ -+ if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) { -+ goto FINISHED; -+ } -+ -+ if ( 0 != bluesmoke_mc_del_mc( mci ) ) { -+ goto FINISHED; -+ } -+ -+ kfree( mci ); -+ -+ FINISHED: -+ return; -+} -+ -+ -+static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { -+ { PCI_VEND_DEV( INTEL, 7520_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7520 }, -+ {0,} /* 0 terminated list. */ -+}; -+ -+MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); -+ -+ -+static struct pci_driver e752x_driver = { -+ name: BS_MOD_STR, -+ probe: e752x_init_one, -+ remove: __devexit_p(e752x_remove_one), -+ id_table: e752x_pci_tbl, -+#ifdef CONFIG_PM -+ suspend: e752x_suspend, -+ resume: e752x_resume, -+#endif /* CONFIG_PM */ -+}; -+ -+ -+int __init e752x_init(void) -+{ -+ int pci_rc; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_rc = pci_module_init( &e752x_driver ); -+ if ( pci_rc < 0 ) return pci_rc; -+ -+ return 0; -+} -+ -+ -+static void __exit e752x_exit(void) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_unregister_driver( &e752x_driver ); -+} -+ -+ -+module_init(e752x_init); -+module_exit(e752x_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); -+MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e7xxx.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,552 @@ -+/* -+ * Intel e7xxx Memory Controller kernel module -+ * (C) 2003 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * See "enum e7xxx_chips" below for supported chipsets -+ * -+ * Written by Thayne Harbaugh -+ * Based on work by Dan Hollis and others. -+ * http://www.anime.net/~goemon/linux-ecc/ -+ * -+ * Contributors: -+ * Eric Biederman (Linux Networx) -+ * Tom Zimmerman (Linux Networx) -+ * Jim Garlic (Lawrence Livermore National Labs) -+ * Dave Peterson (Lawrence Livermore National Labs) -+ * That One Guy (Some other place) -+ * -+ * $Id: bluesmoke_e7xxx.c,v 1.5 2004/11/18 22:19:46 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7205_0 -+#define PCI_DEVICE_ID_INTEL_7205_0 0x255d -+#endif /* PCI_DEVICE_ID_INTEL_7205_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR -+#define PCI_DEVICE_ID_INTEL_7205_1_ERR 0x2551 -+#endif /* PCI_DEVICE_ID_INTEL_7205_1_ERR */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7500_0 -+#define PCI_DEVICE_ID_INTEL_7500_0 0x2540 -+#endif /* PCI_DEVICE_ID_INTEL_7500_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR -+#define PCI_DEVICE_ID_INTEL_7500_1_ERR 0x2541 -+#endif /* PCI_DEVICE_ID_INTEL_7500_1_ERR */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7501_0 -+#define PCI_DEVICE_ID_INTEL_7501_0 0x254c -+#endif /* PCI_DEVICE_ID_INTEL_7501_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR -+#define PCI_DEVICE_ID_INTEL_7501_1_ERR 0x2541 -+#endif /* PCI_DEVICE_ID_INTEL_7501_1_ERR */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7505_0 -+#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 -+#endif /* PCI_DEVICE_ID_INTEL_7505_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR -+#define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551 -+#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ -+ -+ -+#define E7XXX_NR_CSROWS 8 /* number of csrows */ -+#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ -+ -+ -+/* E7XXX register addresses - device 0 function 0 */ -+#define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ -+#define E7XXX_DRA 0x70 /* DRAM row attribute register (8b) */ -+ /* -+ * 31 Device width row 7 0=x8 1=x4 -+ * 27 Device width row 6 -+ * 23 Device width row 5 -+ * 19 Device width row 4 -+ * 15 Device width row 3 -+ * 11 Device width row 2 -+ * 7 Device width row 1 -+ * 3 Device width row 0 -+ */ -+#define E7XXX_DRC 0x7C /* DRAM controller mode reg (32b) */ -+ /* -+ * 22 Number channels 0=1,1=2 -+ * 19:18 DRB Granularity 32/64MB -+ */ -+#define E7XXX_TOLM 0xC4 /* DRAM top of low memory reg (16b) */ -+#define E7XXX_REMAPBASE 0xC6 /* DRAM remap base address reg (16b) */ -+#define E7XXX_REMAPLIMIT 0xC8 /* DRAM remap limit address reg (16b) */ -+ -+/* E7XXX register addresses - device 0 function 1 */ -+#define E7XXX_DRAM_FERR 0x80 /* DRAM first error register (8b) */ -+#define E7XXX_DRAM_NERR 0x82 /* DRAM next error register (8b) */ -+#define E7XXX_DRAM_CELOG_ADD 0xA0 /* DRAM first correctable memory */ -+ /* error address register (32b) */ -+ /* -+ * 31:28 Reserved -+ * 27:6 CE address (4k block 33:12) -+ * 5:0 Reserved -+ */ -+#define E7XXX_DRAM_UELOG_ADD 0xB0 /* DRAM first uncorrectable memory */ -+ /* error address register (32b) */ -+ /* -+ * 31:28 Reserved -+ * 27:6 CE address (4k block 33:12) -+ * 5:0 Reserved -+ */ -+#define E7XXX_DRAM_CELOG_SYNDROME 0xD0 /* DRAM first correctable memory */ -+ /* error syndrome register (16b) */ -+ -+enum e7xxx_chips { -+ E7500 = 0, -+ E7501, -+ E7505, -+ E7205, -+}; -+ -+ -+struct e7xxx_pvt { -+ struct pci_dev *bridge_ck; -+ u32 tolm; -+ u32 remapbase; -+ u32 remaplimit; -+ const struct e7xxx_dev_info *dev_info; -+}; -+ -+ -+struct e7xxx_dev_info { -+ u16 err_dev; -+ const char *ctl_name; -+}; -+ -+ -+static const struct e7xxx_dev_info e7xxx_devs[] = { -+ [E7500] = { -+ .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, -+ .ctl_name = "E7500" -+ }, -+ [E7501] = { -+ .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, -+ .ctl_name = "E7501" -+ }, -+ [E7505] = { -+ .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, -+ .ctl_name = "E7505" -+ }, -+ [E7205] = { -+ .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, -+ .ctl_name = "E7205" -+ }, -+}; -+ -+ -+/* FIXME - is this valid for both SECDED and S4ECD4ED? */ -+static inline int e7xxx_find_channel(u16 syndrome) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if((syndrome & 0xff00)==0) -+ return(0); -+ if((syndrome & 0x00ff)==0) -+ return(1); -+ if((syndrome & 0xf000)==0) -+ return(0); -+ if((syndrome & 0x0f00)==0) -+ return(0); -+ return(1); -+} -+ -+ -+static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, -+ unsigned long page) -+{ -+ u32 remap; -+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if(page < pvt->tolm) -+ return(page); -+ if((page >= 0x100000)&&(page < pvt->remapbase)) -+ return(page); -+ remap = (page - pvt->tolm) + pvt->remapbase; -+ if(remap < pvt->remaplimit) -+ return(remap); -+ printk(KERN_ERR "Invalid page %lx - out of range\n", page); -+ return(pvt->tolm-1); -+} -+ -+ -+static void process_ce(struct mem_ctl_info *mci) -+{ -+ u32 error_1b, page; -+ u16 syndrome; -+ int row; -+ int channel; -+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* read the error address */ -+ pci_read_config_dword(pvt->bridge_ck,E7XXX_DRAM_CELOG_ADD, -+ &error_1b); -+ /* FIXME - should use PAGE_SHIFT */ -+ page = error_1b >>6; /* convert the address to 4k page */ -+ /* read the syndrome */ -+ pci_read_config_word(pvt->bridge_ck,E7XXX_DRAM_CELOG_SYNDROME, -+ &syndrome); -+ /* FIXME - check for -1 */ -+ row = bluesmoke_mc_find_csrow_by_page( mci, page ); -+ channel = e7xxx_find_channel(syndrome); /* convert syndrome to channel */ -+ bluesmoke_mc_handle_ce( mci, page, 0, syndrome, -+ row, channel, "e7xxx CE" ); -+} -+ -+ -+static void process_ce_no_info(struct mem_ctl_info *mci) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ bluesmoke_mc_handle_ce_no_info( mci, "e7xxx CE log register overflow" ); -+} -+ -+ -+static void process_ue(struct mem_ctl_info *mci) -+{ -+ u32 error_2b, block_page; -+ int row; -+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* read the error address */ -+ pci_read_config_dword( pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD, -+ &error_2b ); -+ /* FIXME - should use PAGE_SHIFT */ -+ block_page = error_2b >>6; /* convert to 4k address */ -+ row = bluesmoke_mc_find_csrow_by_page( mci, block_page ); -+ bluesmoke_mc_handle_ue( mci, block_page, 0, row, "e7xxx UE" ); -+} -+ -+ -+static void process_ue_no_info(struct mem_ctl_info *mci) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ bluesmoke_mc_handle_ue_no_info( mci, "e7xxx UE log register overflow" ); -+} -+ -+ -+static void e7xxx_check(struct mem_ctl_info *mci) -+{ -+ u8 error_one, error_next; -+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_FERR,&error_one); -+ pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_NERR,&error_next); -+ -+ /* clear any error bits */ -+ if(error_one & 3) { -+ pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03); -+ } -+ if(error_next & 3) { -+ pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); -+ } -+ -+ /* decode and report errors */ -+ if(error_one & 1) { /* check first error correctable */ -+ process_ce(mci); -+ if(error_next & 1) { /* check next error correctable */ -+ process_ce_no_info(mci); -+ } -+ if(error_next & 2) { /* check next error uncorrectable */ -+ process_ue(mci); -+ } -+ } else if(error_one & 2) { /* check first error uncorrectable */ -+ process_ue(mci); -+ if(error_next & 1) { /* check next error correctable */ -+ process_ce(mci); -+ } -+ if(error_next & 2) { /* check next error uncorrectable */ -+ process_ue_no_info(mci); -+ } -+ } -+} -+ -+ -+static int e7xxx_probe1( struct pci_dev *pdev, int dev_idx ) -+{ -+ int rc = -ENODEV; -+ int index; -+ u16 pci_data; -+ struct mem_ctl_info *mci = NULL; -+ struct e7xxx_pvt *pvt = NULL; -+ u32 drc; -+ int drc_chan; /* Number of channels 0=1chan,1=2chan */ -+ int drc_drbg; /* DRB granularity 0=32mb,1=64mb */ -+ int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ -+ u32 dra; -+ unsigned long last_cumul_size; -+ -+ -+ debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ ); -+ -+ /* need to find out the number of channels */ -+ pci_read_config_dword(pdev, E7XXX_DRC, &drc); -+ drc_chan = ( ( drc >> 22 ) & 0x1 ); -+ drc_drbg = ( drc >> 18 ) & 0x3; -+ drc_ddim = ( drc >> 20 ) & 0x3; -+ -+ mci = bluesmoke_mc_init_structs(sizeof(*pvt), -+ E7XXX_NR_CSROWS, -+ drc_chan + 1); -+ -+ if ( ! mci ) { -+ rc = -ENOMEM; -+ goto FAIL_FINISHED; -+ } -+ -+ debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ ); -+ -+ mci->mtype_cap = MEM_FLAG_RDDR; -+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED; -+ /* FIXME - what if different memory types are in different csrows? */ -+ mci->mod_name = BS_MOD_STR; -+ mci->mod_ver = "$Revision: 1.5 $"; -+ mci->pdev = pdev; -+ -+ debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ ); -+ pvt = (struct e7xxx_pvt *)mci->pvt_info; -+ pvt->dev_info = &e7xxx_devs[dev_idx]; -+ pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL, -+ pvt->dev_info->err_dev, -+ pvt->bridge_ck ); -+ if ( ! pvt->bridge_ck ) { -+ printk( KERN_ERR -+ "MC: error reporting device not found:" -+ "vendor %x device 0x%x (broken BIOS?)\n", -+ PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev ); -+ goto FAIL_FINISHED; -+ } -+ -+ debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ ); -+ mci->ctl_name = pvt->dev_info->ctl_name; -+ -+ mci->edac_check = e7xxx_check; -+ /* FIXME - why isn't clear_err set to something? */ -+ mci->clear_err = NULL; -+ mci->ctl_page_to_phys = ctl_page_to_phys; -+ -+ /* find out the device types */ -+ pci_read_config_dword(pdev, E7XXX_DRA, &dra); -+ -+ /* -+ * The dram row boundary (DRB) reg values are boundary address -+ * for each DRAM row with a granularity of 32 or 64MB (single/dual -+ * channel operation). DRB regs are cumulative; therefore DRB7 will -+ * contain the total memory contained in all eight rows. -+ */ -+ for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) { -+ u8 value; -+ u32 cumul_size; -+ /* mem_dev 0=x8, 1=x4 */ -+ int mem_dev = ( dra >> ( index * 4 + 3 ) ) & 0x1; -+ struct csrow_info *csrow = &mci->csrows[ index ]; -+ -+ pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value); -+ /* convert a 64 or 32 MiB DRB to a page size. */ -+ cumul_size = value << (25 + drc_drbg - PAGE_SHIFT ); -+ debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", -+ __func__, index, cumul_size ); -+ if ( cumul_size == last_cumul_size ) { -+ continue; /* not populated */ -+ } -+ -+ csrow->first_page = last_cumul_size; -+ csrow->last_page = cumul_size - 1; -+ csrow->nr_pages = cumul_size - last_cumul_size; -+ last_cumul_size = cumul_size; -+ csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ -+ csrow->mtype = MEM_RDDR; /* only one type supported */ -+ csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; -+ -+ /* -+ * if single channel or x8 devices then SECDED -+ * if dual channel and x4 then S4ECD4ED -+ */ -+ if ( drc_ddim ) { -+ if ( drc_chan && mem_dev ) { -+ csrow->edac_mode = EDAC_S4ECD4ED; -+ mci->edac_cap |= EDAC_FLAG_S4ECD4ED; -+ } else { -+ csrow->edac_mode = EDAC_SECDED; -+ mci->edac_cap |= EDAC_FLAG_SECDED; -+ } -+ } else { -+ csrow->edac_mode = EDAC_NONE; -+ } -+ } -+ -+ mci->edac_cap |= EDAC_FLAG_NONE; -+ -+ debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ ); -+ /* load the top of low memory, remap base, and remap limit vars */ -+ pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data); -+ pvt->tolm = ((u32)pci_data) << 4; -+ pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data); -+ pvt->remapbase = ((u32)pci_data) << 14; -+ pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data); -+ pvt->remaplimit = ((u32)pci_data) << 14; -+ printk( "tolm = %x, remapbase = %x, remaplimit = %x\n", -+ pvt->tolm, pvt->remapbase, pvt->remaplimit); -+ -+ /* clear any pending errors, or initial state bits */ -+ pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03); -+ pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); -+ -+ if ( 0 != bluesmoke_mc_add_mc( mci ) ) { -+ debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* get this far and it's successful */ -+ debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ ); -+ rc = 0; -+ goto FINISHED; -+ -+ FAIL_FINISHED: -+ if ( mci ) { -+ kfree( mci ); -+ } -+ FINISHED: -+ return( rc ); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int e7xxx_suspend (struct pci_dev *pdev, u32 state) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+ -+static int e7xxx_resume (struct pci_dev *pdev) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* returns count (>= 0), or negative on error */ -+static int __devinit e7xxx_init_one( struct pci_dev *pdev, -+ const struct pci_device_id *ent ) -+{ -+ int rc; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* wake up and enable device */ -+ if (pci_enable_device (pdev)) { -+ rc = -EIO; -+ } else { -+ rc = e7xxx_probe1( pdev, ent->driver_data ); -+ } -+ return rc; -+} -+ -+ -+static void __devexit e7xxx_remove_one( struct pci_dev *pdev ) -+{ -+ struct mem_ctl_info *mci; -+ -+ debugf0( __FILE__ ": %s()\n", __func__); -+ -+ if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) { -+ goto FINISHED; -+ } -+ -+ if ( 0 != bluesmoke_mc_del_mc( mci ) ) { -+ goto FINISHED; -+ } -+ -+ kfree( mci ); -+ -+ FINISHED: -+ return; -+} -+ -+ -+static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { -+ { PCI_VEND_DEV( INTEL, 7205_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7205 }, -+ { PCI_VEND_DEV( INTEL, 7500_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7500 }, -+ { PCI_VEND_DEV( INTEL, 7501_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7501 }, -+ { PCI_VEND_DEV( INTEL, 7505_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7505 }, -+ {0,} /* 0 terminated list. */ -+}; -+ -+MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); -+ -+ -+static struct pci_driver e7xxx_driver = { -+ .name = BS_MOD_STR, -+ .probe = e7xxx_init_one, -+ .remove = __devexit_p(e7xxx_remove_one), -+ .id_table = e7xxx_pci_tbl, -+#ifdef CONFIG_PM -+ .suspend = e7xxx_suspend, -+ .resume = e7xxx_resume, -+#endif /* CONFIG_PM */ -+}; -+ -+ -+int __init e7xxx_init(void) -+{ -+ int pci_rc; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_rc = pci_module_init( &e7xxx_driver ); -+ if ( pci_rc < 0 ) return pci_rc; -+ -+ return 0; -+} -+ -+ -+static void __exit e7xxx_exit(void) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_unregister_driver( &e7xxx_driver ); -+} -+ -+ -+module_init(e7xxx_init); -+module_exit(e7xxx_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" -+ "Based on.work by Dan Hollis et al"); -+MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_i82875p.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,510 @@ -+/* -+ * AMD 76x Memory Controller kernel module -+ * (C) 2003 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * Written by Thayne Harbaugh -+ * -+ * $Id: bluesmoke_i82875p.c,v 1.5 2004/11/18 22:19:46 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#ifndef PCI_DEVICE_ID_INTEL_82875_0 -+#define PCI_DEVICE_ID_INTEL_82875_0 0x2578 -+#endif /* PCI_DEVICE_ID_INTEL_82875_0 */ -+ -+#ifndef PCI_DEVICE_ID_INTEL_82875_6 -+#define PCI_DEVICE_ID_INTEL_82875_6 0x257e -+#endif /* PCI_DEVICE_ID_INTEL_82875_6 */ -+ -+ -+/* four csrows in dual channel, eight in single channel */ -+#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans)) -+ -+ -+/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */ -+#define I82875P_EAP 0x58 /* Error Address Pointer (32b) -+ * -+ * 31:12 block address -+ * 11:0 reserved -+ */ -+ -+#define I82875P_DERRSYN 0x5c /* DRAM Error Syndrome (8b) -+ * -+ * 7:0 DRAM ECC Syndrome -+ */ -+ -+#define I82875P_DES 0x5d /* DRAM Error Status (8b) -+ * -+ * 7:1 reserved -+ * 0 Error channel 0/1 -+ */ -+ -+#define I82875P_ERRSTS 0xc8 /* Error Status Register (16b) -+ * -+ * 15:10 reserved -+ * 9 non-DRAM lock error (ndlock) -+ * 8 Sftwr Generated SMI -+ * 7 ECC UE -+ * 6 reserved -+ * 5 MCH detects unimplemented cycle -+ * 4 AGP access outside GA -+ * 3 Invalid AGP access -+ * 2 Invalid GA translation table -+ * 1 Unsupported AGP command -+ * 0 ECC CE -+ */ -+ -+#define I82875P_ERRCMD 0xca /* Error Command (16b) -+ * -+ * 15:10 reserved -+ * 9 SERR on non-DRAM lock -+ * 8 SERR on ECC UE -+ * 7 SERR on ECC CE -+ * 6 target abort on high exception -+ * 5 detect unimplemented cyc -+ * 4 AGP access outside of GA -+ * 3 SERR on invalid AGP access -+ * 2 invalid translation table -+ * 1 SERR on unsupported AGP command -+ * 0 reserved -+ */ -+ -+ -+/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */ -+#define I82875P_PCICMD6 0x04 /* PCI Command Register (16b) -+ * -+ * 15:10 reserved -+ * 9 fast back-to-back - ro 0 -+ * 8 SERR enable - ro 0 -+ * 7 addr/data stepping - ro 0 -+ * 6 parity err enable - ro 0 -+ * 5 VGA palette snoop - ro 0 -+ * 4 mem wr & invalidate - ro 0 -+ * 3 special cycle - ro 0 -+ * 2 bus master - ro 0 -+ * 1 mem access dev6 - 0(dis),1(en) -+ * 0 IO access dev3 - 0(dis),1(en) -+ */ -+ -+#define I82875P_BAR6 0x10 /* Mem Delays Base ADDR Reg (32b) -+ * -+ * 31:12 mem base addr [31:12] -+ * 11:4 address mask - ro 0 -+ * 3 prefetchable - ro 0(non),1(pre) -+ * 2:1 mem type - ro 0 -+ * 0 mem space - ro 0 -+ */ -+ -+/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */ -+ -+#define I82875P_DRB_SHIFT 26 /* 64MiB grain */ -+#define I82875P_DRB 0x00 /* DRAM Row Boundary (8b x 8) -+ * -+ * 7 reserved -+ * 6:0 64MiB row boundary addr -+ */ -+ -+#define I82875P_DRA 0x10 /* DRAM Row Attribute (4b x 8) -+ * -+ * 7 reserved -+ * 6:4 row attr row 1 -+ * 3 reserved -+ * 2:0 row attr row 0 -+ * -+ * 000 = 4KiB -+ * 001 = 8KiB -+ * 010 = 16KiB -+ * 011 = 32KiB -+ */ -+ -+#define I82875P_DRC 0x68 /* DRAM Controller Mode (32b) -+ * -+ * 31:30 reserved -+ * 29 init complete -+ * 28:23 reserved -+ * 22:21 nr chan 00=1,01=2 -+ * 20 reserved -+ * 19:18 Data Integ Mode 00=none,01=ecc -+ * 17:11 reserved -+ * 10:8 refresh mode -+ * 7 reserved -+ * 6:4 mode select -+ * 3:2 reserved -+ * 1:0 DRAM type 01=DDR -+ */ -+ -+ -+enum i82875p_chips { -+ I82875P = 0, -+}; -+ -+ -+struct i82875p_pvt { -+ struct pci_dev *ovrfl_pdev; -+ void *ovrfl_window; -+}; -+ -+ -+struct i82875p_dev_info { -+ const char *ctl_name; -+}; -+ -+ -+static const struct i82875p_dev_info i82875p_devs[] = { -+ [I82875P] = { -+ .ctl_name = "i828875p" -+ }, -+}; -+ -+ -+static void i82875p_check(struct mem_ctl_info *mci) -+{ -+ u8 des; -+ u8 derrsyn; -+ u16 errsts, errsts2; -+ u32 eap; -+ int row; -+ int multi_chan = mci->csrows[0].nr_channels - 1; -+ -+ debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ ); -+ -+ /* -+ * This is a mess because there is no atomic way to read all -+ * the registers at once and the registers can transition -+ * from CE being overwritten by UE. -+ */ -+ pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts ); -+ pci_read_config_dword( mci->pdev, I82875P_EAP, &eap ); -+ pci_read_config_byte( mci->pdev, I82875P_DES, &des ); -+ pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn ); -+ pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts2 ); -+ -+ pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 ); -+ -+ /* -+ * If the error is the same then we can for both reads then -+ * the first set of reads is valid. If there is a change then -+ * there is a CE no info and the second set of reads is valid -+ * and should be UE info. -+ */ -+ if (! (errsts2 & 0x0081) ) return; -+ if ( (errsts ^ errsts2) & 0x0081 ) { -+ bluesmoke_mc_handle_ce_no_info( mci, "UE overwrote CE" ); -+ errsts = errsts2; -+ pci_read_config_dword( mci->pdev, I82875P_EAP, &eap ); -+ pci_read_config_byte( mci->pdev, I82875P_DES, &des ); -+ pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn ); -+ } -+ -+ eap >>= PAGE_SHIFT; -+ row = bluesmoke_mc_find_csrow_by_page( mci, eap ); -+ -+ if ( errsts & 0x0080 ) { -+ bluesmoke_mc_handle_ue( mci, eap, 0, row, "i82875p UE" ); -+ } else { -+ bluesmoke_mc_handle_ce( mci, eap, 0, derrsyn, row, -+ multi_chan ? (des & 0x1) : 0, -+ "i82875p UE" ); -+ } -+ -+ return; -+} -+ -+ -+static int i82875p_probe1( struct pci_dev *pdev, int dev_idx ) -+{ -+ int rc = -ENODEV; -+ int index; -+ struct mem_ctl_info *mci = NULL; -+ struct i82875p_pvt *pvt = NULL; -+ unsigned long last_cumul_size; -+ struct pci_dev *ovrfl_pdev; -+ void *ovrfl_window = NULL; -+ -+ u32 drc; -+ u32 drc_chan; /* Number of channels 0=1chan,1=2chan */ -+ u32 nr_chans; -+ u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ ovrfl_pdev = pci_find_device( PCI_VEND_DEV( INTEL, 82875_6 ), NULL ); -+ -+ if ( ! ovrfl_pdev ) { -+ /* -+ * Intel tells BIOS developers to hide device 6 which -+ * configures the overflow device access containing -+ * the DRBs - this is where we expose device 6. -+ * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm -+ */ -+ pci_write_bits8( pdev, 0xf4, 0x2, 0x2 ); -+ ovrfl_pdev = pci_scan_single_device( pdev->bus, PCI_DEVFN( 6, 0 ) ); -+ if ( ! ovrfl_pdev ) { -+ goto FAIL_FINISHED; -+ } -+ } -+ -+#ifdef CONFIG_PROC_FS -+ if ( !ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) { -+ printk( KERN_ERR "MC: " __FILE__ -+ ": %s(): Failed to attach overflow device\n", -+ __func__ ); -+ goto FAIL_FINISHED; -+ } -+#endif /* CONFIG_PROC_FS */ -+ if (pci_enable_device(ovrfl_pdev)) { -+ printk( KERN_ERR "MC: " __FILE__ -+ ": %s(): Failed to enable overflow device\n", -+ __func__ ); -+ goto FAIL_FINISHED; -+ } -+ if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) { -+ printk( KERN_ERR "MC: " __FILE__ -+ ": %s(): Failed to reserve regions - broken BIOS?\n", -+ __func__ ); -+#ifdef CORRECT_BIOS -+ goto FAIL_FINISHED; -+#endif /* CORRECT_BIOS */ -+ } -+ -+ /* cache is irrelevant for PCI bus reads/writes */ -+ ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0), -+ pci_resource_len(ovrfl_pdev, 0)); -+ -+ if (!ovrfl_window) { -+ printk( KERN_ERR "MC: " __FILE__ -+ ": %s(): Failed to ioremap bar6\n", -+ __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* need to find out the number of channels */ -+ drc = readl(ovrfl_window + I82875P_DRC); -+ drc_chan = ( ( drc >> 21 ) & 0x1 ); -+ nr_chans = drc_chan + 1; -+ drc_ddim = ( drc >> 18 ) & 0x1; -+ -+ mci = bluesmoke_mc_init_structs(sizeof(*pvt), -+ I82875P_NR_CSROWS(nr_chans), -+ nr_chans ); -+ -+ if ( ! mci ) { -+ rc = -ENOMEM; -+ goto FAIL_FINISHED; -+ } -+ -+ debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ ); -+ -+ mci->pdev = pdev; -+ mci->mtype_cap = MEM_FLAG_RDDR; -+ -+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; -+ mci->edac_cap = EDAC_FLAG_UNKNOWN; -+ /* adjust FLAGS */ -+ -+ mci->mod_name = BS_MOD_STR; -+ mci->mod_ver = "$Revision: 1.5 $"; -+ mci->ctl_name = i82875p_devs[dev_idx].ctl_name; -+ mci->edac_check = i82875p_check; -+ mci->clear_err = NULL; -+ mci->ctl_page_to_phys = NULL; -+ -+ debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ ); -+ -+ pvt = (struct i82875p_pvt *)mci->pvt_info; -+ pvt->ovrfl_pdev = ovrfl_pdev; -+ pvt->ovrfl_window = ovrfl_window; -+ -+ /* -+ * The dram row boundary (DRB) reg values are boundary address -+ * for each DRAM row with a granularity of 32 or 64MB (single/dual -+ * channel operation). DRB regs are cumulative; therefore DRB7 will -+ * contain the total memory contained in all eight rows. -+ */ -+ for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) { -+ u8 value; -+ u32 cumul_size; -+ struct csrow_info *csrow = &mci->csrows[ index ]; -+ -+ value = readb(ovrfl_window + I82875P_DRB + index); -+ cumul_size = value << ( I82875P_DRB_SHIFT - PAGE_SHIFT ); -+ debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", -+ __func__, index, cumul_size ); -+ if ( cumul_size == last_cumul_size ) { -+ continue; /* not populated */ -+ } -+ -+ csrow->first_page = last_cumul_size; -+ csrow->last_page = cumul_size - 1; -+ csrow->nr_pages = cumul_size - last_cumul_size; -+ last_cumul_size = cumul_size; -+ csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ -+ csrow->mtype = MEM_DDR; -+ csrow->dtype = DEV_UNKNOWN; -+ csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; -+ } -+ -+ /* clear counters */ -+ pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 ); -+ -+ if ( 0 != bluesmoke_mc_add_mc( mci ) ) { -+ debugf3( "MC: " __FILE__ -+ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* get this far and it's successful */ -+ debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ ); -+ rc = 0; -+ goto FINISHED; -+ -+ FAIL_FINISHED: -+ if ( mci ) { -+ kfree( mci ); -+ } -+ -+ if (ovrfl_window) { -+ iounmap(ovrfl_window); -+ } -+ -+ if (ovrfl_pdev) { -+ pci_release_regions( ovrfl_pdev ); -+ pci_disable_device( ovrfl_pdev ); -+ } -+ -+ FINISHED: -+ /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ -+ return( rc ); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int i82875p_suspend (struct pci_dev *pdev, u32 state) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+ -+static int i82875p_resume (struct pci_dev *pdev) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* returns count (>= 0), or negative on error */ -+static int __devinit i82875p_init_one( struct pci_dev *pdev, -+ const struct pci_device_id *ent ) -+{ -+ int rc; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ if (pci_enable_device (pdev)) { -+ rc = -EIO; -+ } else { -+ rc = i82875p_probe1( pdev, ent->driver_data ); -+ } -+ return rc; -+} -+ -+ -+static void __devexit i82875p_remove_one( struct pci_dev *pdev ) -+{ -+ struct mem_ctl_info *mci; -+ struct i82875p_pvt *pvt = NULL; -+ -+ debugf0( __FILE__ ": %s()\n", __func__); -+ -+ if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) { -+ goto FINISHED; -+ } -+ -+ pvt = (struct i82875p_pvt *)mci->pvt_info; -+ if (pvt->ovrfl_window) { -+ iounmap(pvt->ovrfl_window); -+ } -+ -+ if (pvt->ovrfl_pdev) { -+ pci_release_regions( pvt->ovrfl_pdev ); -+ pci_disable_device( pvt->ovrfl_pdev ); -+ } -+ -+ if ( 0 != bluesmoke_mc_del_mc( mci ) ) { -+ goto FINISHED; -+ } -+ -+ kfree( mci ); -+ -+ FINISHED: -+ return; -+} -+ -+ -+static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { -+ { PCI_VEND_DEV( INTEL, 82875_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, I82875P }, -+ {0,} /* 0 terminated list. */ -+}; -+ -+MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); -+ -+ -+static struct pci_driver i82875p_driver = { -+ .name = BS_MOD_STR, -+ .probe = i82875p_init_one, -+ .remove = __devexit_p(i82875p_remove_one), -+ .id_table = i82875p_pci_tbl, -+#ifdef CONFIG_PM -+ .suspend = i82875p_suspend, -+ .resume = i82875p_resume, -+#endif /* CONFIG_PM */ -+}; -+ -+ -+int __init i82875p_init(void) -+{ -+ int pci_rc; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_rc = pci_module_init( &i82875p_driver ); -+ if ( pci_rc < 0 ) return pci_rc; -+ -+ return 0; -+} -+ -+ -+static void __exit i82875p_exit(void) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_unregister_driver( &i82875p_driver ); -+} -+ -+ -+module_init(i82875p_init); -+module_exit(i82875p_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); -+MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_k8.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,1252 @@ -+/* -+ * AMD K8 class Memory Controller kernel module -+ * (C) 2003 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * Written by Thayne Harbaugh -+ * -+ * $Id: bluesmoke_k8.c,v 1.6 2004/11/23 01:34:25 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#ifndef PCI_DEVICE_ID_AMD_OPT_0_HT -+#define PCI_DEVICE_ID_AMD_OPT_0_HT 0x1100 -+#endif /* PCI_DEVICE_ID_AMD_OPT_0_HT */ -+ -+#ifndef PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP -+#define PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP 0x1101 -+#endif /* PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP */ -+ -+#ifndef PCI_DEVICE_ID_AMD_OPT_2_MEMCTL -+#define PCI_DEVICE_ID_AMD_OPT_2_MEMCTL 0x1102 -+#endif /* PCI_DEVICE_ID_AMD_OPT_2_MEMCTL */ -+ -+#ifndef PCI_DEVICE_ID_AMD_OPT_3_MISCCTL -+#define PCI_DEVICE_ID_AMD_OPT_3_MISCCTL 0x1103 -+#endif /* PCI_DEVICE_ID_AMD_OPT_3_MISCCTL */ -+ -+ -+#define K8_NR_CSROWS 8 -+ -+ -+/* K8 register addresses - device 0 function 1 - Address Map */ -+#define K8_DBR 0x40 /* DRAM Base Register (8 x 32b -+ * interlaced with K8_DLR) -+ * -+ * 31:16 DRAM Base addr 39:24 -+ * 15:11 reserved -+ * 10:8 interleave enable -+ * 7:2 reserved -+ * 1 write enable -+ * 0 read enable -+ */ -+#define K8_DLR 0x44 /* DRAM Limit Register (8 x 32b -+ * interlaced with K8_DBR) -+ * -+ * 31:16 DRAM Limit addr 32:24 -+ * 15:11 reserved -+ * 10:8 interleave select -+ * 7:3 reserved -+ * 2:0 destination node ID -+ */ -+ -+ -+/* K8 register addresses - device 0 function 2 - DRAM controller */ -+#define K8_DCSB 0x40 /* DRAM Chip-Select Base (8 x 32b) -+ * -+ * 31:21 Base addr high 35:25 -+ * 20:16 reserved -+ * 15:9 Base addr low 19:13 (interlvd) -+ * 8:1 reserved -+ * 0 chip-select bank enable -+ */ -+#define K8_DCSM 0x60 /* DRAM Chip-Select Mask (8 x 32b) -+ * -+ * 31:30 reserved -+ * 29:21 addr mask high 33:25 -+ * 20:16 reserved -+ * 15:9 addr mask low 19:13 -+ * 8:0 reserved -+ */ -+ -+#define K8_DBAM 0x80 /* DRAM Base Addr Mapping (32b) */ -+#define K8_DCL 0x90 /* DRAM configuration low reg (32b) -+ * -+ * 31:28 reserved -+ * 27:25 Bypass Max: 000b=respect -+ * 24 Dissable receivers - no sockets -+ * 23:20 x4 DIMMS -+ * 19 32byte chunks -+ * 18 Unbuffered -+ * 17 ECC enabled -+ * 16 128/64 bit (dual/single chan) -+ * 15:14 R/W Queue bypass count -+ * 13 Self refresh -+ * 12 exit self refresh -+ * 11 mem clear status -+ * 10 DRAM enable -+ * 9 reserved -+ * 8 DRAM init -+ * 7:4 reserved -+ * 3 dis DQS hysteresis -+ * 2 QFC enabled -+ * 1 DRAM drive strength -+ * 0 Digital Locked Loop disable -+ */ -+ -+ -+/* K8 register addresses - device 0 function 3 - Misc Control */ -+#define K8_NBCTL 0x40 /* MCA NB Control (32b) -+ * -+ * 1 MCA UE Reporting -+ * 0 MCA CE Reporting -+ */ -+#define K8_NBCFG 0x44 /* MCA NB Config (32b) -+ * -+ * 23 Chip-kill x4 ECC enable -+ * 22 ECC enable -+ * 1 CPU ECC enable -+ */ -+#define K8_NBSL 0x48 /* MCA NB Status Low (32b) -+ * -+ * 31:24 Syndrome 15:8 chip-kill x4 -+ * 23:20 reserved -+ * 19:16 Extended err code -+ * 15:0 Err code -+ */ -+#define K8_NBSH 0x4C /* MCA NB Status High (32b) -+ * -+ * 31 Err valid -+ * 30 Err overflow -+ * 29 Uncorrected err -+ * 28 Err enable -+ * 27 Misc err reg valid -+ * 26 Err addr valid -+ * 25 proc context corrupt -+ * 24:23 reserved -+ * 22:15 Syndrome 7:0 -+ * 14 CE -+ * 13 UE -+ * 12:9 reserved -+ * 8 err found by scrubber -+ * 7 reserved -+ * 6:4 Hyper-transport link number -+ * 3:2 reserved -+ * 1 Err CPU 1 -+ * 0 Err CPU 0 -+ */ -+#define K8_NBEAL 0x50 /* MCA NB err addr low (32b) -+ * -+ * 31:3 Err addr low 31:3 -+ * 2:0 reserved -+ */ -+#define K8_NBEAH 0x54 /* MCA NB err addr high (32b) -+ * -+ * 31:8 reserved -+ * 7:0 Err addr high 39:32 -+ */ -+#define K8_NBCAP 0xE8 /* MCA NB capabilities (32b) -+ * -+ * 31:9 reserved -+ * 4 S4ECD4ED capable -+ * 3 SECDED capable -+ */ -+ -+ -+ /* MSR's */ -+ /* -+ * K8_MSR_MCxCTL (64b) -+ * (0x400,404,408,40C,410) -+ * 63 Enable reporting source 63 -+ * . -+ * . -+ * . -+ * 2 Enable error source 2 -+ * 1 Enable error source 1 -+ * 0 Enable error source 0 -+ */ -+ /* -+ * K8_MSR_MCxSTAT (64b) -+ * (0x401,405,409,40D,411) -+ * 63 Error valid -+ * 62 Status overflow -+ * 61 UE -+ * 60 Enabled error condition -+ * 59 Misc register valid (not used) -+ * 58 Err addr register valid -+ * 57 Processor context corrupt -+ * 56:32 Other information -+ * 31:16 Model specific error code -+ * 15:0 MCA err code -+ */ -+ /* -+ * K8_MSR_MCxADDR (64b) -+ * (0x402,406,40A,40E,412) -+ * 63:48 reserved -+ * 47:0 Address -+ */ -+ /* -+ * K8_MSR_MCxMISC (64b) -+ * (0x403,407,40B,40F,413) -+ * Unused on Athlon64 and K8 -+ */ -+ -+#define K8_MSR_MCGCTL 0x017b /* Machine Chk Global report ctl (64b) -+ * -+ * 31:5 reserved -+ * 4 North Bridge -+ * 3 Load/Store -+ * 2 Bus Unit -+ * 1 Instruction Cache -+ * 0 Data Cache -+ */ -+#define K8_MSR_MC4CTL 0x0410 /* North Bridge Check report ctl (64b) */ -+#define K8_MSR_MC4STAT 0x0411 /* North Bridge status (64b) */ -+#define K8_MSR_MC4ADDR 0x0412 /* North Bridge Address (64b) */ -+ -+ -+#define MCI2NID(mci) (PCI_SLOT(mci->pdev->devfn) - 0x18) -+ -+ -+enum k8_chips { -+ OPTERON = 0, -+}; -+ -+ -+struct k8_pvt { -+ struct pci_dev *addr_map; -+ struct pci_dev *misc_ctl; -+}; -+ -+ -+struct k8_dev_info { -+ const char *ctl_name; -+ u16 addr_map; -+ u16 misc_ctl; -+}; -+ -+ -+static const struct k8_dev_info k8_devs[] = { -+ [OPTERON] = { -+ .ctl_name = "Athlon64/Opteron", -+ .addr_map = PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP, -+ .misc_ctl = PCI_DEVICE_ID_AMD_OPT_3_MISCCTL -+ }, -+}; -+ -+ -+static inline void pci_find_related_function( unsigned int vendor, -+ unsigned int device, -+ struct pci_dev **from, -+ struct pci_dev *related ) -+{ -+ do { -+ *from = pci_find_device( vendor, device, *from ); -+ if ( ! *from ) return; -+ -+ if ( ((*from)->bus->number == related->bus->number) -+ && (PCI_SLOT((*from)->devfn) -+ == PCI_SLOT(related->devfn)) ) { -+ return; -+ } -+ } while ( 1 ); -+} -+ -+ -+/* FIXME - stolen from msr.c - the calls in msr.c could be exported */ -+#ifdef CONFIG_SMP -+ -+struct msr_command { -+ int cpu; -+ int err; -+ u32 reg; -+ u32 data[2]; -+}; -+ -+ -+static void msr_smp_wrmsr(void *cmd_block) -+{ -+ struct msr_command *cmd = (struct msr_command *) cmd_block; -+ -+ debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n", -+ __func__, cmd->cpu, smp_processor_id() ); -+ -+ if ( cmd->cpu == smp_processor_id() ) { -+ debugf1( "MC: " __FILE__ ": %s(): Matched %d\n", -+ __func__, cmd->cpu ); -+ wrmsr(cmd->reg, cmd->data[0], cmd->data[1]); -+ } -+} -+ -+ -+static void msr_smp_rdmsr(void *cmd_block) -+{ -+ struct msr_command *cmd = (struct msr_command *) cmd_block; -+ -+ debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n", -+ __func__, cmd->cpu, smp_processor_id() ); -+ -+ if ( cmd->cpu == smp_processor_id() ) { -+ debugf1( "MC: " __FILE__ ": %s(): Matched %d\n", -+ __func__, cmd->cpu ); -+ rdmsr(cmd->reg, cmd->data[0], cmd->data[1]); -+ } -+} -+ -+ -+static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -+{ -+ struct msr_command cmd; -+ -+ debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu ); -+ -+ if ( cpu == smp_processor_id() ) { -+ wrmsr(reg, eax, edx); -+ } else { -+ cmd.cpu = cpu; -+ cmd.reg = reg; -+ cmd.data[0] = eax; -+ cmd.data[1] = edx; -+ -+ smp_call_function(msr_smp_wrmsr, &cmd, 1, 1); -+ } -+} -+ -+ -+static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) -+{ -+ struct msr_command cmd; -+ -+ debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu ); -+ -+ if ( cpu == smp_processor_id() ) { -+ rdmsr(reg, eax, edx); -+ } else { -+ cmd.cpu = cpu; -+ cmd.reg = reg; -+ -+ smp_call_function(msr_smp_rdmsr, &cmd, 1, 1); -+ -+ *eax = cmd.data[0]; -+ *edx = cmd.data[1]; -+ } -+} -+ -+#else /* ! CONFIG_SMP */ -+ -+static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) -+{ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ wrmsr(reg, eax, edx); -+} -+ -+ -+static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) -+{ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ rdmsr(reg, eax, edx); -+} -+ -+#endif /* ! CONFIG_SMP */ -+ -+ -+/* -+ * FIXME - This is a large chunk of memory to suck up just to decode the -+ * syndrome. It would be nice to discover a patter in the syndromes that -+ * could be used to quickly identify the channel. The big problems with -+ * this table is memory usage, lookup speed (could sort and binary search), -+ * correctness (there could be a transcription error). A zero in any nibble -+ * for a syndrom is always channel 0, but that only decodes some of the -+ * syndromes. Can anyone find any other patterns? -+ */ -+/* -+ * The comment in the left column is the nibble that is in error. The least -+ * significant nibble of the syndrome is the mask for the bits that are -+ * in error (need to be toggled) for the particular nibble. -+ */ -+#define SYNDROME_TABLE_SIZE 270 -+static const unsigned long syndromes_chan0[SYNDROME_TABLE_SIZE] = { -+ /*0*/ 0xe821, 0x7c32, 0x9413, 0xbb44, 0x5365, 0xc776, 0x2f57, 0xdd88, 0x35a9, 0xa1ba, 0x499b, 0x66cc, 0x8eed, 0x1afe, 0xf2df, -+ /*1*/ 0x5d31, 0xa612, 0xfb23, 0x9584, 0xc8b5, 0x3396, 0x6ea7, 0xeac8, 0xb7f9, 0x4cda, 0x11eb, 0x7f4c, 0x227d, 0xd95e, 0x846f, -+ /*2*/ 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, -+ /*3*/ 0x2021, 0x3032, 0x1013, 0x4044, 0x6065, 0x7076, 0x5057, 0x8088, 0xa0a9, 0xb0ba, 0x909b, 0xc0cc, 0xe0ed, 0xf0fe, 0xd0df, -+ /*4*/ 0x5041, 0xa082, 0xf0c3, 0x9054, 0xc015, 0x30d6, 0x6097, 0xe0a8, 0xb0e9, 0x402a, 0x106b, 0x70fc, 0x20bd, 0xd07e, 0x803f, -+ /*5*/ 0xbe21, 0xd732, 0x6913, 0x2144, 0x9f65, 0xf676, 0x4857, 0x3288, 0x8ca9, 0xe5ba, 0x5b9b, 0x13cc, 0xaded, 0xc4fe, 0x7adf, -+ /*6*/ 0x4951, 0x8ea2, 0xc7f3, 0x5394, 0x1ac5, 0xdd36, 0x9467, 0xa1e8, 0xe8b9, 0x2f4a, 0x661b, 0xf27c, 0xbb2d, 0x7cde, 0x358f, -+ /*7*/ 0x74e1, 0x9872, 0xec93, 0xd6b4, 0xa255, 0x4ec6, 0x3a27, 0x6bd8, 0x1f39, 0xf3aa, 0x874b, 0xbd6c, 0xc98d, 0x251e, 0x51ff, -+ /*8*/ 0x15c1, 0x2a42, 0x3f83, 0xcef4, 0xdb35, 0xe4b6, 0xf177, 0x4758, 0x5299, 0x6d1a, 0x78db, 0x89ac, 0x9c6d, 0xa3ee, 0xb62f, -+ /*9*/ 0x3d01, 0x1602, 0x2b03, 0x8504, 0xb805, 0x9306, 0xae07, 0xca08, 0xf709, 0xdc0a, 0xe10b, 0x4f0c, 0x720d, 0x590e, 0x640f, -+ /*a*/ 0x9801, 0xec02, 0x7403, 0x6b04, 0xf305, 0x8706, 0x1f07, 0xbd08, 0x2509, 0x510a, 0xc90b, 0xd60c, 0x4e0d, 0x3a0e, 0xa20f, -+ /*b*/ 0xd131, 0x6212, 0xb323, 0x3884, 0xe9b5, 0x5a96, 0x8ba7, 0x1cc8, 0xcdf9, 0x7eda, 0xafeb, 0x244c, 0xf57d, 0x465e, 0x976f, -+ /*c*/ 0xe1d1, 0x7262, 0x93b3, 0xb834, 0x59e5, 0xca56, 0x2b87, 0xdc18, 0x3dc9, 0xae7a, 0x4fab, 0x542c, 0x85fd, 0x164e, 0xf79f, -+ /*d*/ 0x6051, 0xb0a2, 0xd0f3, 0x1094, 0x70c5, 0xa036, 0xc067, 0x20e8, 0x40b9, 0x904a, 0x601b, 0x307c, 0x502d, 0x80de, 0xe08f, -+ /*e*/ 0xa4c1, 0xf842, 0x5c83, 0xe6f4, 0x4235, 0x1eb6, 0xba77, 0x7b58, 0xdf99, 0x831a, 0x27db, 0x9dac, 0x396d, 0x65ee, 0xc12f, -+ /*f*/ 0x11c1, 0x2242, 0x3383, 0xc8f4, 0xd935, 0xeab6, 0xfb77, 0x4c58, 0x5d99, 0x6e1a, 0x7fdb, 0x84ac, 0x9562, 0xa6ee, 0xb72f, -+ -+ /*20*/ 0xbe01, 0xd702, 0x6903, 0x2104, 0x9f05, 0xf606, 0x4807, 0x3208, 0x8c09, 0xe50a, 0x5b0b, 0x130c, 0xad0d, 0xc40e, 0x7a0f, -+ /*21*/ 0x4101, 0x8202, 0xc303, 0x5804, 0x1905, 0xda06, 0x9b07, 0xac08, 0xed09, 0x2e0a, 0x6f0b, 0x640c, 0xb50d, 0x760e, 0x370f -+}; -+ -+static const unsigned long syndromes_chan1[SYNDROME_TABLE_SIZE] = { -+ /*10*/ 0x45d1, 0x8a62, 0xcfb3, 0x5e34, 0x1be5, 0xd456, 0x9187, 0xa718, 0xe2c9, 0x2d7a, 0x68ab, 0xf92c, 0xbcfd, 0x734e, 0x369f, -+ /*11*/ 0x63e1, 0xb172, 0xd293, 0x14b4, 0x7755, 0xa5c6, 0xc627, 0x28d8, 0x4b39, 0x99aa, 0xfa4b, 0x3c6c, 0x5f8d, 0x8d1e, 0xeeff, -+ /*12*/ 0xb741, 0xd982, 0x6ec3, 0x2254, 0x9515, 0xfbd6, 0x4c97, 0x33a8, 0x84e9, 0xea2a, 0x5d6b, 0x11fc, 0xa6bd, 0xc87e, 0x7f3f, -+ /*13*/ 0xdd41, 0x6682, 0xbbc3, 0x3554, 0xe815, 0x53d6, 0xce97, 0x1aa8, 0xc7e9, 0x7c2a, 0xa1fb, 0x2ffc, 0xf2bd, 0x497e, 0x943f, -+ /*14*/ 0x2bd1, 0x3d62, 0x16b3, 0x4f34, 0x64e5, 0x7256, 0x5987, 0x8518, 0xaec9, 0xb87a, 0x93ab, 0xca2c, 0xe1fd, 0xf74e, 0xdc9f, -+ /*15*/ 0x83c1, 0xc142, 0x4283, 0xa4f4, 0x2735, 0x65b6, 0xe677, 0xf858, 0x7b99, 0x391a, 0xbadb, 0x5cac, 0xdf6d, 0x9dee, 0x1e2f, -+ /*16*/ 0x8fd1, 0xc562, 0x4ab3, 0xa934, 0x26e5, 0x6c56, 0xe387, 0xfe18, 0x71c9, 0x3b7a, 0xb4ab, 0x572c, 0xd8fd, 0x924e, 0x1d9f, -+ /*17*/ 0x4791, 0x89e2, 0xce73, 0x5264, 0x15f5, 0xdb86, 0x9c17, 0xa3b8, 0xe429, 0x2a5a, 0x6dcb, 0xf1dc, 0xb64d, 0x783e, 0x3faf, -+ /*18*/ 0x5781, 0xa9c2, 0xfe43, 0x92a4, 0xc525, 0x3b66, 0x6ce7, 0xe3f8, 0xb479, 0x4a3a, 0x1dbb, 0x715c, 0x26dd, 0xd89e, 0x8f1f, -+ /*19*/ 0xbf41, 0xd582, 0x6ac3, 0x2954, 0x9615, 0xfcd6, 0x4397, 0x3ea8, 0x81e9, 0xeb2a, 0x546b, 0x17fc, 0xa8bd, 0xc27e, 0x7d3f, -+ /*1a*/ 0x9891, 0xe1e2, 0x7273, 0x6464, 0xf7f5, 0x8586, 0x1617, 0xb8b8, 0x2b29, 0x595a, 0xcacb, 0xdcdc, 0x4f4d, 0x3d3e, 0xaeaf, -+ /*1b*/ 0xcce1, 0x4472, 0x8893, 0xfdb4, 0x3f55, 0xb9c6, 0x7527, 0x56d8, 0x9a39, 0x12aa, 0xde4b, 0xab6c, 0x678d, 0xef1e, 0x23ff, -+ /*1c*/ 0xa761, 0xf9b2, 0x5ed3, 0xe214, 0x4575, 0x1ba6, 0xbcc7, 0x7328, 0xd449, 0x8a9a, 0x2dfb, 0x913c, 0x365d, 0x688e, 0xcfef, -+ /*1d*/ 0xff61, 0x55b2, 0xaad3, 0x7914, 0x8675, 0x2ca6, 0xd3c7, 0x9e28, 0x6149, 0xcb9a, 0x34fb, 0xe73c, 0x185d, 0xb28e, 0x4def, -+ /*1e*/ 0x5451, 0xa8a2, 0xfcf3, 0x9694, 0xc2c5, 0x3e36, 0x6a67, 0xebe8, 0xbfb9, 0x434a, 0x171b, 0x7d7c, 0x292d, 0xd5de, 0x818f, -+ /*1f*/ 0x6fc1, 0xb542, 0xda83, 0x19f4, 0x7635, 0xacb6, 0xc377, 0x2e58, 0x4199, 0x9b1a, 0xf4db, 0x37ac, 0x586d, 0x82ee, 0xed2f, -+ -+ /*22*/ 0xc441, 0x4882, 0x8cc3, 0xf654, 0x3215, 0xbed6, 0x7a97, 0x5ba8, 0x9fe9, 0x132a, 0xd76b, 0xadfc, 0x69bd, 0xe57e, 0x213f, -+ /*23*/ 0x7621, 0x9b32, 0xed13, 0xda44, 0xac65, 0x4176, 0x3757, 0x6f88, 0x19a9, 0xf4ba, 0x829b, 0xb5cc, 0xc3ed, 0x2efe, 0x58df -+}; -+ -+ -+/* -+ * FIXME - either the above table is borken or something is incorrect with -+ * the way the syndrome is read out of the NB. -+ */ -+static int chan_from_syndrome( unsigned long syndrome ) -+{ -+ int i; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ for ( i = 0; i < SYNDROME_TABLE_SIZE; i++ ) { -+ if ( syndromes_chan0[i] == syndrome ) return 0; -+ if ( syndromes_chan1[i] == syndrome ) return 1; -+ } -+ -+ debugf0( "MC: " __FILE__ ": %s(): syndrome(%lx) not found\n", -+ __func__, syndrome ); -+ return -1; -+} -+ -+ -+static const char *tt_msgs[] = { /* transaction type */ -+ "inst", -+ "data", -+ "generic", -+ "reserved" -+}; -+ -+ -+static const char *ll_msgs[] = { /* cache level */ -+ "0", -+ "1", -+ "2", -+ "generic" -+}; -+ -+ -+static const char *memtt_msgs[] = { -+ "generic", -+ "generic read", -+ "generic write", -+ "data read", -+ "data write", -+ "inst fetch", -+ "prefetch", -+ "evict", -+ "snoop", -+ "unknown error 9", -+ "unknown error 10", -+ "unknown error 11", -+ "unknown error 12", -+ "unknown error 13", -+ "unknown error 14", -+ "unknown error 15" -+}; -+ -+ -+static const char *pp_msgs[] = { /* participating processor */ -+ "local node origin", -+ "local node response", -+ "local node observed", -+ "generic" -+}; -+ -+ -+static const char *to_msgs[] = { -+ "no timeout", -+ "timed out" -+}; -+ -+ -+static const char *ii_msgs[] = { /* memory or i/o */ -+ "mem access", -+ "reserved", -+ "i/o access", -+ "generic" -+}; -+ -+ -+static const char *ext_msgs[] = { /* extended error */ -+ "ECC error", -+ "CRC error", -+ "sync error", -+ "mst abort", -+ "tgt abort", -+ "GART error", -+ "RMW error", -+ "watchdog error", -+ "ECC chipkill x4 error", -+ "unknown error 9", -+ "unknown error 10", -+ "unknown error 11", -+ "unknown error 12", -+ "unknown error 13", -+ "unknown error 14", -+ "unknown error 15" -+}; -+ -+ -+static const char *htlink_msgs[] = { -+ "none", -+ "1", -+ "2", -+ "1 2", -+ "3", -+ "1 3", -+ "2 3", -+ "1 2 3" -+}; -+ -+ -+static inline void decode_gart_tlb_error( struct mem_ctl_info *mci, -+ u32 nbeah, u32 nbeal, -+ u32 nbsh, u32 nbsl, -+ u32 nbcfg ) -+{ -+ u32 err_code; -+ u32 ec_tt; /* error code transaction type (2b) */ -+ u32 ec_ll; /* error code cache level (2b) */ -+ -+ debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ ); -+ -+ err_code = nbsl & 0xffffUL; -+ ec_tt = ( err_code >> 2 ) & 0x03UL; -+ ec_ll = ( err_code >> 0 ) & 0x03UL; -+ -+ printk( "BS%d: GART TLB errorr:" -+ " transaction type(%s)," -+ " cache level(%s)\n", -+ mci->mc_idx, -+ tt_msgs[ec_tt], -+ ll_msgs[ec_ll] ); -+} -+ -+ -+static inline void decode_cache_error( struct mem_ctl_info *mci, -+ u32 nbeah, u32 nbeal, -+ u32 nbsh, u32 nbsl, -+ u32 nbcfg ) -+{ -+ u32 err_code; -+ u32 ec_rrrr; /* error code memory transaction (4b) */ -+ u32 ec_tt; /* error code transaction type (2b) */ -+ u32 ec_ll; /* error code cache level (2b) */ -+ -+ debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ ); -+ -+ err_code = nbsl & 0xffffUL; -+ ec_rrrr = ( err_code >> 4 ) & 0x0fUL; -+ ec_tt = ( err_code >> 2 ) & 0x03UL; -+ ec_ll = ( err_code >> 0 ) & 0x03UL; -+ -+ printk( "BS%d: cache heirarchy error:" -+ " memory transaction type(%s)," -+ " transaction type(%s)," -+ " cache level(%s)\n", -+ mci->mc_idx, -+ memtt_msgs[ ec_rrrr ], -+ tt_msgs[ ec_tt ], -+ ll_msgs[ ec_ll ] ); -+} -+ -+ -+static inline void decode_bus_error( struct mem_ctl_info *mci, -+ u32 nbeah, u32 nbeal, -+ u32 nbsh, u32 nbsl, -+ u32 nbcfg ) -+{ -+ u32 page, offset; -+ u32 err_code, ext_ec; -+ int row = 0; -+ u32 ec_pp; /* error code participating processor (2p) */ -+ u32 ec_to; /* error code timed out (1b) */ -+ u32 ec_rrrr; /* error code memory transaction (4b) */ -+ u32 ec_ii; /* error code memory or I/O (2b) */ -+ u32 ec_ll; /* error code cache level (2b) */ -+ char msg[1024] = ""; -+ u32 msg_idx = 0; -+ -+ debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ ); -+ -+ msg_idx = snprintf( msg, 1024, "%s", BS_MOD_STR ); -+ -+ err_code = nbsl & 0xffffUL; -+ ec_pp = ( err_code >> 9 ) & 0x03UL; -+ ec_to = ( err_code >> 8 ) & 0x01UL; -+ ec_rrrr = ( err_code >> 4 ) & 0x0fUL; -+ ec_ii = ( err_code >> 2 ) & 0x03UL; -+ ec_ll = ( err_code >> 0 ) & 0x03UL; -+ -+ ext_ec = ( nbsl >> 16 ) & 0xfUL; -+ -+ /* FIXME - these should report through bluesmoke channels */ -+ -+ printk( "BS%d: general bus error:" -+ " participating processor(%s)," -+ " time-out(%s)," -+ " memory transaction type(%s)," -+ " mem or i/o(%s)," -+ " cache level(%s)\n", -+ mci->mc_idx, -+ pp_msgs[ ec_pp ], -+ to_msgs[ ec_to ], -+ memtt_msgs[ ec_rrrr ], -+ ii_msgs[ ec_ii ], -+ ll_msgs[ ec_ll ] ); -+ -+ /* FIXME - other errors should have other error handling mechanisms. */ -+ if ( ( 0 != ext_ec ) && ( 0x8 != ext_ec ) ) { -+ printk( "BS%d: no special error handling for this error\n", -+ mci->mc_idx ); -+ return; -+ } -+ -+ if ( ec_pp & 0x02 ) { -+ /* We aren't the node involved */ -+ return; -+ } -+ -+ offset = nbeal & ~PAGE_MASK & ~0x7UL; -+ page = ( ( nbeah & 0xff ) << ( 40 - PAGE_SHIFT ) ) -+ | ( ( nbeal & PAGE_MASK ) >> PAGE_SHIFT ); -+ -+ /* process any errors */ -+ if ( nbsh & BIT(14) ) { /* CE */ -+ unsigned long syndrome; -+ int chan = 0; -+ -+ syndrome = ( nbsh >> 15 ) & 0x00ffUL; /* bits 7:0 */ -+ if ( nbcfg & BIT(23) ) { -+ syndrome |= ( nbsl >> 16 ) & 0xff00UL; /* bits 15:8 */ -+ chan = chan_from_syndrome( syndrome ); -+ } -+ -+ if ( 0 > chan ) { -+ /* -+ * If the syndrome couldn't be found then -+ * the race condition for error reporting -+ * registers likely occurred. There's alot -+ * more in doubt than just the channel. -+ * Might as well just log the error without -+ * any info. -+ */ -+ msg_idx += snprintf( &msg[ msg_idx ], 1024 - msg_idx, -+ " unknown syndrome 0x%lx - " -+ " possible error reporting race", -+ syndrome ); -+ bluesmoke_mc_handle_ce_no_info( mci, msg ); -+ } else if ( nbsh & BIT(26) ) { /* valid address? */ -+ row = bluesmoke_mc_find_csrow_by_page( mci, page ); -+ if ( -1 == row ) { -+ bluesmoke_mc_handle_ce_no_info( mci, msg ); -+ } else { -+ bluesmoke_mc_handle_ce( mci, page, offset, -+ syndrome, row, chan, -+ msg ); -+ } -+ } else { -+ bluesmoke_mc_handle_ce_no_info( mci, msg ); -+ } -+ } else if ( nbsh & BIT(13) ) { /* UE */ -+ if ( nbsh & BIT(26) ) { /* valid address? */ -+ row = bluesmoke_mc_find_csrow_by_page( mci, page ); -+ if ( -1 == row ) { -+ bluesmoke_mc_handle_ue_no_info( mci, msg ); -+ } else { -+ bluesmoke_mc_handle_ue( mci, page, offset, -+ row, msg ); -+ } -+ } else { -+ bluesmoke_mc_handle_ue_no_info( mci, msg ); -+ } -+ } -+ -+ if ( nbsh & BIT(30) ) { -+ /* -+ * If main error is CE then overflow must be CE. -+ * If main error is UE then overflow is unknown. -+ * We'll call the overflow a CE - if panic_on_ue -+ * is set then we're already panic'ed and won't -+ * arrive here. If panic_on_ue is not set then -+ * apparently someone doesn't think that -+ * UE's are catastrophic. -+ */ -+ bluesmoke_mc_handle_ce_no_info( mci, BS_MOD_STR ); -+ } -+} -+ -+ -+static void k8_check(struct mem_ctl_info *mci) -+{ -+ struct k8_pvt *pvt = (struct k8_pvt *)mci->pvt_info; -+ u32 nbsl1, nbsh1, nbeal1, nbeah1, nbcfg1; -+ u32 nbsl2, nbsh2, nbeal2, nbeah2, nbcfg2; -+ u32 err_code; -+ u32 ext_ec; -+ -+ debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ ); -+ -+ /* check for an error */ -+ pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh1); -+ if ( ! (nbsh1 & BIT(31) ) ) { /* err valid? */ -+ return; -+ } -+ -+ /* might as well slurp in everything at once */ -+ pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl1); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal1); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah1); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg1); -+ debugf1( KERN_WARNING -+ "NorthBridge ERROR: mci(0x%p) node(%d) nbeah(0x%.8x)" -+ " nbeal(0x%.8x) nbsh(0x%.8x) nbsl(0x%.8x): ", -+ mci, MCI2NID(mci), nbeah1, nbeal1, nbsh1, nbsl1 ); -+ -+ /* -+ * Here's the problem with the K8's EDAC reporting: -+ * There are four registers which report pieces of error -+ * information. These four registers are shared between -+ * CEs and UEs. Furthermore, contrary to what is stated in -+ * the OBKG, the overflow bit is never used! Every error -+ * always updates the reporting registers. -+ * -+ * Can you see the race condition? All four error reporting -+ * registers must be read before a new error updates them! -+ * There is no way to read all four registers atomically. The -+ * best than can be done is to detect that a race has occured -+ * and then report the error without any kind of precision. -+ * -+ * What is still positive is that errors are -+ * still reported and thus problems can still be detected - -+ * just not localized because the syndrome and address are -+ * spread out across registers. -+ * -+ * Grrrrr!!!!! Here's hoping that AMD fixes this in some -+ * future K8 rev. UEs and CEs should have separate -+ * register sets with proper overflow bits that are used! -+ * At very least the problem can be fixed by honoring the -+ * ErrValid bit in nbsh and not updating registers - just -+ * set the overflow bit - unless the current error is CE -+ * and the new error is UE which would be the only situation -+ * for overwriting the current values. -+ */ -+ pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh2); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl2); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal2); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah2); -+ pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg2); -+ debugf1( KERN_WARNING -+ "NorthBridge ERROR2: mci(0x%p) node(%d) nbeah2(0x%.8x)" -+ " nbeal2(0x%.8x) nbsh2(0x%.8x) nbsl2(0x%.8x): ", -+ mci, MCI2NID(mci), nbeah2, nbeal2, nbsh2, nbsl2 ); -+ -+ /* clear the error */ -+ pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) ); -+ -+ if ( ( nbsh1 != nbsh2 ) -+ || ( nbsl1 != nbsl2 ) -+ || ( nbeah1 != nbeah2 ) -+ || ( nbeal1 != nbeal2 ) ) { -+ printk( KERN_WARNING "MC%d: race condition detected!\n", -+ mci->mc_idx ); -+ } -+ -+ err_code = nbsl2 & 0xffffUL; -+ ext_ec = (nbsl2 >> 16) & 0x0fUL; -+ -+ /* Use info from the second read - most current */ -+ if ( 0x0010UL == ( err_code & 0xfff0UL ) ) { -+ debugf1( "GART TLB error\n" ); -+ decode_gart_tlb_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 ); -+ } else if ( 0x0100UL == ( err_code & 0xff00UL ) ) { -+ debugf1( "Cache error\n" ); -+ decode_cache_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 ); -+ } else if ( 0x0800UL == ( err_code & 0xf800UL ) ) { -+ debugf1( "Bus error\n" ); -+ decode_bus_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 ); -+ } else { -+ /* shouldn't reach here! */ -+ printk( KERN_WARNING "MC%d: " __FILE__ -+ ": %s(): unknown MCE error 0x%x\n", -+ mci->mc_idx, __func__, err_code ); -+ } -+ -+ printk( "BS%d: extended error code: %s\n", -+ mci->mc_idx, -+ ext_msgs[ ext_ec ] ); -+ -+ if ( ((ext_ec >=1 && ext_ec <= 4) || (ext_ec == 6)) -+ && ((nbsh2 >> 4) & 0x03UL) ) { -+ /* need to decode which hypertransport link had the error */ -+ u32 htln = (nbsh2 >> 4) & 0x03UL; -+ printk( "BS%d: Error on hypertransport link: %s\n", -+ mci->mc_idx, htlink_msgs[ htln ] ); -+ } -+ -+ /* -+ * If the processor context is corrupt or the error is -+ * uncorrectable then panic - why would you want to continue -+ * with something seriosly broken? -+ */ -+ if ( nbsh2 & ( BIT(29) | BIT(25) ) ) { -+ if ( nbsh2 & BIT(29) ) -+ printk( "BS%d: uncorrected error\n", mci->mc_idx ); -+ -+ if ( nbsh2 & BIT(25) ) -+ printk( "BS%d: processor context corrupt\n", -+ mci->mc_idx ); -+ -+ panic( "BS%d: cannot recover\n", mci->mc_idx ); -+ }; -+} -+ -+ -+static int k8_probe1( struct pci_dev *pdev, int dev_idx ) -+{ -+ int rc = -ENODEV; -+ int index; -+ struct mem_ctl_info *mci = NULL; -+ struct k8_pvt *pvt = NULL; -+ int nid; -+ u32 dram_pg_base = 0; -+ u32 dram_pg_limit = 0; -+ u32 dcl; -+ u32 dcl_chans; -+ u32 dcl_unbuf; -+ u32 dcl_x4; -+ u32 dcl_eccen; -+ u32 dbam; -+ u32 nbcfg; -+ u32 nbcfg_ckx4en; -+ u32 nbcfg_eccen; -+ u32 nbcap; -+ u32 nbcap_ckx4; -+ u32 nbcap_ecc; -+ u32 csrows_loaded = 0; -+ u32 mcgctl_l, mcgctl_h; -+ u32 mc4ctl_l, mc4ctl_h; -+ const struct k8_dev_info *k8_dev = &k8_devs[dev_idx]; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ pci_read_config_dword(pdev, K8_DCL, &dcl); -+ dcl_chans = ( dcl >> 16 ) & 0x1; -+ dcl_unbuf = ( dcl >> 18 ) & 0x1; -+ dcl_x4 = ( dcl >> 20 ) & 0xf; -+ dcl_eccen = ( dcl >> 17 ) & 0x1; -+ pci_read_config_dword(pdev, K8_DBAM, &dbam); -+ -+ mci = bluesmoke_mc_init_structs(sizeof(*pvt), -+ K8_NR_CSROWS, -+ dcl_chans + 1); -+ -+ if ( ! mci ) { -+ rc = -ENOMEM; -+ goto FAIL_FINISHED; -+ } -+ -+ debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci ); -+ -+ pvt = (struct k8_pvt *)mci->pvt_info; -+ -+ mci->pdev = pdev; -+ nid = MCI2NID(mci); -+ -+ /* setup private structure */ -+ /* -+ * The address mapping device provides a table that indicates -+ * which physical address ranges are owned by which node. -+ * Each node's memory controller has memory controller addresses -+ * that begin at 0x0. Locally, the memory controller address -+ * must be added to the mapping device address to convert to -+ * physical address. -+ */ -+ pci_find_related_function( PCI_VENDOR_ID_AMD, -+ k8_dev->addr_map, -+ &pvt->addr_map, -+ mci->pdev ); -+ -+ if ( ! pvt->addr_map ) { -+ printk( KERN_ERR -+ "MC: error address map device not found:" -+ "vendor %x device 0x%x (broken BIOS?)\n", -+ PCI_VENDOR_ID_AMD, -+ k8_dev->addr_map ); -+ goto FAIL_FINISHED; -+ } -+ -+ debugf1( "Addr Map device PCI Bus ID:\t%s\n", pvt->addr_map->name ); -+ -+ /* -+ * Sift through address mapper DRAM table - the documentation isn't -+ * explicit, but it is believed to be an error if there are multiple -+ * entries for the same node. -+ */ -+ for ( index = 0; index < 8; index++ ) { -+ u32 dbr; -+ u32 dbr_base = 0; -+ u32 dbr_inten; -+ u32 dbr_wen; -+ u32 dbr_ren; -+ u32 dlr; -+ u32 dlr_limit = 0; -+ u32 dlr_intsel; -+ u32 dlr_nid; -+ -+ pci_read_config_dword( pvt->addr_map, -+ K8_DLR + (8 * index), -+ &dlr ); -+ -+ dlr_nid = dlr & 0x7; -+ -+ if ( dlr_nid != nid ) continue; -+ -+ /* -+ * dlr_limit has all the low-order bits 1 while dbr_base -+ * has all the low-order bits 0. Here we do some bit -+ * jockeying to set all the low-order bits of dlr_limit. -+ */ -+ dlr_limit = ((((dlr >> 16) & 0xffff) + 1) -+ << (24 - PAGE_SHIFT)) - 1; -+ dlr_intsel = (dlr >> 8) & 0x1f; -+ -+ pci_read_config_dword( pvt->addr_map, -+ K8_DBR + (8 * index), -+ &dbr ); -+ -+ dbr_base = ((dbr >> 16) & 0xffff) << (24 - PAGE_SHIFT); -+ dbr_inten = (dbr >> 8) & 0x7; -+ dbr_wen = (dbr >> 1) & 0x1; -+ dbr_ren = dbr & 0x1; -+ -+ debugf1( "\tAddr Map: %d:0x%x - 0x%x\n", -+ dlr_nid, dbr_base, dlr_limit ); -+ -+ if ( dram_pg_limit ) { -+ printk( KERN_ERR -+ "MC: multiple entries for node %d found" -+ " in Address Mapping device %s:" -+ " PROBE FAILED!\n", -+ nid, pci_name(pvt->misc_ctl) ); -+ goto FAIL_FINISHED; -+ } -+ -+ dram_pg_limit = dlr_limit; -+ dram_pg_base = dbr_base; -+ } -+ -+ if (! dram_pg_limit) { -+ printk( KERN_ERR -+ "MC: no DRAM entry found for node %d in Address" -+ " Mapping device: %s: POBE FAILED!\n", -+ nid, pci_name(pvt->misc_ctl) ); -+ goto FAIL_FINISHED; -+ } -+ -+ pci_find_related_function( PCI_VENDOR_ID_AMD, -+ k8_dev->misc_ctl, -+ &pvt->misc_ctl, -+ mci->pdev ); -+ -+ if ( ! pvt->misc_ctl ) { -+ printk( KERN_ERR -+ "MC: error miscellaneous device not found:" -+ "vendor %x device 0x%x (broken BIOS?)\n", -+ PCI_VENDOR_ID_AMD, -+ k8_dev->misc_ctl ); -+ goto FAIL_FINISHED; -+ } -+ -+ debugf1( "Misc device PCI Bus ID:\t\t%.2x:%.2x.%.1x\n", -+ pvt->misc_ctl->name ); -+ -+ pci_read_config_dword( pvt->misc_ctl, K8_NBCFG, &nbcfg ); -+ nbcfg_ckx4en = nbcfg & BIT(23); -+ nbcfg_eccen = nbcfg & BIT(22); -+ -+ mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR; -+ -+ pci_read_config_dword( pvt->misc_ctl, K8_NBCAP, &nbcap ); -+ nbcap_ckx4 = ( nbcap >> 4 ) & 0x1; -+ nbcap_ecc = ( nbcap >> 3 ) & 0x1; -+ mci->edac_ctl_cap = EDAC_FLAG_NONE; -+ if ( nbcap_ecc ) mci->edac_ctl_cap |= EDAC_FLAG_SECDED; -+ if ( nbcap_ckx4 ) mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; -+ -+ mci->edac_cap = EDAC_FLAG_NONE; -+ if ( dcl_eccen ) { -+ mci->edac_cap |= EDAC_FLAG_SECDED; -+ if ( dcl_chans ) { -+ mci->edac_cap |= EDAC_FLAG_S4ECD4ED; -+ } -+ } -+ -+ mci->mod_name = BS_MOD_STR; -+ mci->mod_ver = "$Revision: 1.6 $"; -+ mci->ctl_name = k8_devs[dev_idx].ctl_name; -+ mci->edac_check = k8_check; -+ mci->clear_err = NULL; -+ mci->ctl_page_to_phys = NULL; -+ -+ for ( index = 0; index < mci->nr_csrows; index++ ) { -+ struct csrow_info *csrow = &mci->csrows[ index ]; -+ u32 dcsb; -+ u32 dcsb_bah; -+ u32 dcsb_bal; -+ u32 dcsm; -+ u32 dcsm_amh; -+ u32 dcsm_aml; -+ u32 aml; -+ u32 device_shift = 0; -+ u32 intlv_shift = 0; -+ int i; -+ -+ /* find the DRAM Chip Select Base address for this row */ -+ pci_read_config_dword(mci->pdev, K8_DCSB + (index*4), &dcsb); -+ if ( ! (dcsb & 0x1) ) { -+ continue; /* empty */ -+ } -+ csrows_loaded++; -+ dcsb_bal = ((dcsb >> 9) & 0x7fUL) << (13 - PAGE_SHIFT); -+ dcsb_bah = ((dcsb >> 21) & 0x7ffUL) << (25 - PAGE_SHIFT); -+ -+ pci_read_config_dword(mci->pdev, K8_DCSM + (index*4), &dcsm); -+ dcsm_aml = ((~dcsm >> 9) & 0x7fUL) << (13 - PAGE_SHIFT); -+ dcsm_amh = ((dcsm >> 21) & 0x1ffUL) << (25 - PAGE_SHIFT); -+ -+ debugf2( "\t%d: dcsb(%x) dcsm(%x)\n", index, dcsb, dcsm ); -+ -+ /* 25 is 32MiB minimum DIMM size */ -+ csrow->first_page = (dcsb_bah | dcsb_bal) + dram_pg_base; -+ csrow->nr_pages = 1 << ((( dbam >> ((index / 2)*4) ) & 0x7) -+ + 25 - PAGE_SHIFT + dcl_chans); -+ if ( dcsm_aml ) { -+ aml = dcsm_aml; -+ i = 0; -+ while ( ! (aml & 0x1UL) ) { -+ i++; -+ aml >>= 1; -+ } -+ device_shift = i; -+ -+ i = 0; -+ while ( aml & 0x1UL ) { -+ i++; -+ aml >>= 1; -+ } -+ intlv_shift = i; -+ -+ csrow->last_page = csrow->first_page -+ + ( csrow->nr_pages << intlv_shift ) -+ - ( (1 << device_shift) | 0x1UL ); -+ } else { -+ csrow->last_page = csrow->first_page -+ + csrow->nr_pages - 1; -+ } -+ -+ csrow->page_mask = dcsm_aml; -+ csrow->grain = 8; /* 8 bytes of resolution */ -+ csrow->mtype = dcl_unbuf ? MEM_DDR : MEM_RDDR; -+ if ( ( dcl_x4 >> (index / 2 ) ) & 0x1 ) { -+ csrow->dtype = DEV_X4; -+ } else { -+ csrow->dtype = DEV_UNKNOWN; -+ } -+ -+ if ( nbcfg_eccen ) { -+ if ( nbcfg_ckx4en ) { -+ csrow->edac_mode = EDAC_S4ECD4ED; -+ } else { -+ csrow->edac_mode = EDAC_SECDED; -+ } -+ } else { -+ csrow->edac_mode = EDAC_NONE; -+ } -+ } -+ -+ /* clear any pending errors, or initial state bits */ -+ /* FIXME - should log what is already there */ -+ pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) ); -+ -+ if ( ! csrows_loaded ) { -+ mci->edac_cap = EDAC_FLAG_NONE; -+ } else { -+ /* turn on error reporting */ -+ pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL ); -+ -+ pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL ); -+ -+ do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h ); -+ mc4ctl_l |= BIT(0) | BIT(1); -+ do_wrmsr( nid, K8_MSR_MC4CTL, mc4ctl_l, mc4ctl_h ); -+ do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h ); -+ -+ do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h ); -+ mcgctl_l |= BIT(4); -+ do_wrmsr( nid, K8_MSR_MCGCTL, mcgctl_l, mcgctl_h ); -+ do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h ); -+ } -+ -+ if ( 0 != bluesmoke_mc_add_mc( mci ) ) { -+ debugf3( "MC: " __FILE__ -+ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ ); -+ goto FAIL_FINISHED; -+ } -+ -+ /* get this far and it's successful */ -+ debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ ); -+ rc = 0; -+ goto FINISHED; -+ -+ FAIL_FINISHED: -+ if ( mci ) { -+ kfree( mci ); -+ } -+ -+ FINISHED: -+ return( rc ); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int k8_suspend (struct pci_dev *pdev, u32 state) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+ -+static int k8_resume (struct pci_dev *pdev) -+{ -+ debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ ); -+ -+ return -ENOSYS; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/* returns count (>= 0), or negative on error */ -+static int __devinit k8_init_one( struct pci_dev *pdev, -+ const struct pci_device_id *ent ) -+{ -+ int rc; -+ -+ debugf0( "MC: " __FILE__ ": %s()\n", __func__ ); -+ -+ /* wake up and enable device */ -+ if (pci_enable_device (pdev)) { -+ rc = -EIO; -+ } else { -+ rc = k8_probe1( pdev, ent->driver_data ); -+ } -+ return rc; -+} -+ -+ -+static void __devexit k8_remove_one( struct pci_dev *pdev ) -+{ -+ struct mem_ctl_info *mci; -+ -+ debugf0( __FILE__ ": %s()\n", __func__); -+ -+ if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) { -+ goto FINISHED; -+ } -+ -+ if ( 0 != bluesmoke_mc_del_mc( mci ) ) { -+ goto FINISHED; -+ } -+ -+ kfree( mci ); -+ -+ FINISHED: -+ return; -+} -+ -+ -+static const struct pci_device_id k8_pci_tbl[] __devinitdata = { -+ { PCI_VEND_DEV( AMD, OPT_2_MEMCTL ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, OPTERON }, -+ {0,} /* 0 terminated list. */ -+}; -+ -+MODULE_DEVICE_TABLE(pci, k8_pci_tbl); -+ -+ -+static struct pci_driver k8_driver = { -+ .name = BS_MOD_STR, -+ .probe = k8_init_one, -+ .remove = __devexit_p(k8_remove_one), -+ .id_table = k8_pci_tbl, -+#ifdef CONFIG_PM -+ .suspend = k8_suspend, -+ .resume = k8_resume, -+#endif /* CONFIG_PM */ -+}; -+ -+ -+int __init k8_init(void) -+{ -+ int pci_rc; -+ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_rc = pci_module_init( &k8_driver ); -+ if ( pci_rc < 0 ) return pci_rc; -+ -+ return 0; -+} -+ -+ -+static void __exit k8_exit(void) -+{ -+ debugf3( "MC: " __FILE__ ": %s()\n", __func__ ); -+ pci_unregister_driver( &k8_driver ); -+} -+ -+ -+module_init(k8_init); -+module_exit(k8_exit); -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); -+MODULE_DESCRIPTION("MC support for AMD K8 memory controllers"); -Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c -=================================================================== ---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_mc.c 1969-12-31 19:00:00.000000000 -0500 -+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c 2004-12-17 12:46:23.000000000 -0500 -@@ -0,0 +1,1112 @@ -+/* -+ * bluesmoke_mc kernel module -+ * (C) 2003 Linux Networx (http://lnxi.com) -+ * This file may be distributed under the terms of the -+ * GNU General Public License. -+ * -+ * Written by Thayne Harbaugh -+ * Based on work by Dan Hollis and others. -+ * http://www.anime.net/~goemon/linux-ecc/ -+ * -+ * $Id: bluesmoke_mc.c,v 1.9 2004/12/13 22:19:40 thayne Exp $ -+ * -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "bluesmoke_mc.h" -+ -+ -+#ifndef pfn_to_page -+#define pfn_to_page(pfn) (mem_map + (pfn)) -+#endif /* pfn_to_page */ -+ -+#define MC_PROC_DIR "mc" -+ -+/* /proc/mc dir */ -+static struct proc_dir_entry *proc_mc; -+ -+/* Setable by module parameter and sysctl */ -+#if SCRUB -+/* FIXME - do something with scrubbing */ -+static int mc_scrub = -1; -+#endif /* SCRUB */ -+static int panic_on_ue = 1; -+static int log_ue = 1; -+static int log_ce = 1; -+static int poll_msec = 1000; -+static struct timer_list timer; -+ -+static DECLARE_MUTEX(mem_ctls_mutex); -+ -+/* FIXME - use list.h */ -+/* FIXME - should be dynamic */ -+static struct mem_ctl_info *mcis[MAX_MC_DEVICES]; -+ -+ -+#ifdef CONFIG_SYSCTL -+static void dimm_labels( char *buf, void *data ) -+{ -+ int mcidx, ridx, chidx; -+ char *mcstr, *rstr, *chstr, *lstr, *p; -+ -+ lstr = buf; -+ -+ mcstr = strsep( &lstr, "." ); -+ if (! lstr) -+ return; -+ mcidx = simple_strtol( mcstr, &p, 0 ); -+ if ( *p ) -+ return; -+ if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] ) -+ return; -+ -+ rstr = strsep( &lstr, "." ); -+ if (! lstr) -+ return; -+ ridx = simple_strtol( rstr, &p, 0 ); -+ if ( *p ) -+ return; -+ if ( ridx >= mcis[mcidx]->nr_csrows -+ || ! mcis[mcidx]->csrows ) -+ return; -+ -+ chstr = strsep( &lstr, ":" ); -+ if (! lstr) -+ return; -+ chidx = simple_strtol( chstr, &p, 0 ); -+ if ( *p ) -+ return; -+ if ( chidx >= mcis[mcidx]->csrows[ridx].nr_channels -+ || ! mcis[mcidx]->csrows[ridx].channels ) -+ return; -+ -+ debugf1( "%d:%d.%d:%s\n", -+ mcidx, ridx, chidx, lstr ); -+ -+ strncpy(mcis[mcidx]->csrows[ridx].channels[chidx].label, -+ lstr, BLUESMOKE_MC_LABEL_LEN + 1); -+ /* -+ * no need to NUL terminate label since -+ * get_user_tok() NUL terminates. -+ */ -+} -+ -+ -+static void counter_reset( char *buf, void *data ) -+{ -+ char *p = buf; -+ int mcidx, row, chan; -+ struct mem_ctl_info *mci; -+ -+ mcidx = simple_strtol( buf, &p, 0 ); -+ if ( *p ) -+ return; -+ if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] ) -+ return; -+ -+ mci = mcis[mcidx]; -+ mci->ue_noinfo_count = 0; -+ mci->ce_noinfo_count = 0; -+ mci->ue_count = 0; -+ mci->ce_count = 0; -+ for ( row = 0; row < mci->nr_csrows; row++ ) { -+ struct csrow_info *ri = &mci->csrows[row]; -+ -+ ri->ue_count = 0; -+ ri->ce_count = 0; -+ for ( chan = 0; chan < ri->nr_channels; chan++ ) { -+ ri->channels[chan].ce_count = 0; -+ } -+ } -+ do_gettimeofday( &mci->tv ); -+} -+ -+ -+struct actionvec_info { -+ void (*action)(char *str, void *data); -+ char separator; -+ char *usage; -+ void *data; -+}; -+ -+ -+static struct actionvec_info dimm_labels_avi = { -+ .action = dimm_labels, -+ .separator = ',', -+ .usage = "..: