[RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

From: Jaswinder Singh Rajput
Date: Sat Jun 13 2009 - 12:38:18 EST


By adding these patches, cpu_debug will support :

1. Standard Registers
2. Control Registers
3. Debug Registers
4. Descriptor Tables
5. APIC Registers
6. Model specific Register (MSRs)
7. PCI configuration registers (for AMD)
8. Basic cpuinfo
9. CPUID Functions

Please let me know how we can improve it and add more features so it
becomes more useful.

For example on AMD 64 Laptop :

1. Standard Registers
---------------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/tss/state
RAX : ffffffff81789fe8
RBX : 000000000007e000
RCX : ffffffff8179437f
RDX : 0000000000000000
RSI : 0000000000000000
RDI : 81798e0000104136
RBP : 000000000000001f
ESP : 0000000000000000
R08 : 00000000000932d0
R09 : 0000000000000000
R10 : ffffffff8179429a
R11 : ffffffff81789fa8
R12 : 00000000afc723ac
R13 : 00000000018e4f80
R14 : ffffffff817cee80
R15 : ffffffff81789f88
CS : 0010
DS : 0018
SS : 0000
ES : 0018
FS : 0000
GS : 0000
EFLAGS : 0000000000000000
EIP : 0000000000000000

2. Control Registers
--------------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/cr/state
cr0 : 000000008005003b
cr2 : 0000000000429040
cr3 : 0000000001001000
cr4 : 00000000000006b0
cr8 : 0000000000000000

3. Debug Registers
------------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/debug/state
dr0 : 0000000000000000
dr1 : 0000000000000000
dr2 : 0000000000000000
dr3 : 0000000000000000
dr6 : 00000000ffff0ff0
dr7 : 0000000000000400

MSR :
000001d9: 00000000_00000000

4. Descriptor Tables
--------------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/dt/state
IDT : ffffffff81820fff
GDT : ffff88002802607f
LDT : ffffffff810b0000
TR : 0000000000000040

5. APIC Registers
-----------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/apic/state
LAPIC :
ID : 00000000
LVR : 80050010
TASKPRI : 00000000
ARBPRI : 00000000
PROCPRI : 00000000
LDR : 01000000
DFR : ffffffff
SPIV : 000001ff
ISR : 00000000
ESR : 00000004
ICR : 000208fd
ICR2 : 02000000
LVTT : 000300ef
LVTTHMR : 00010000
LVTPC : 00000400
LVT0 : 00010700
LVT1 : 00000400
LVTERR : 000000fe
TMICT : ffffffff
TMCCT : 8d52660d
TDCR : 00000003
EFEAT : 00040007
ECTRL : 00000000
EILVT0 : 00010000
EILVT1 : 00010000
EILVT2 : 00010000
EILVT3 : 00010000

MSR :
0000001b: 00000000_fee00900

b. access individual APIC register :

# cat /sys/kernel/debug/x86/cpu/cpu0/apic/APIC_EFEAT/value
0x40007

# cat /sys/kernel/debug/x86/cpu/cpu0/apic/MSR_1b/value
0xfee00900

6. Model specific Register (MSRs)
---------------------------------

a. access complete state, say performance monitor counter (pmc)

# cat /sys/kernel/debug/x86/cpu/cpu0/pmc/state
MSR :
c0010000: 00000000_00430076
c0010001: 00000000_3d179f6b
c0010002: 00000000_7993feae
c0010003: 00000000_f69637fe
c0010004: 0000000f_4c47618a
c0010005: 0000f0db_ffc3e9c3
c0010006: 0000834f_15f5610e
c0010007: 00006ade_595d2c95

b. access individual MSR :

# cat /sys/kernel/debug/x86/cpu/cpu0/pmc/MSR_c0010006/value
0x834f15f5610e

c. write individual MSR :
# echo 2 > /sys/kernel/debug/x86/cpu/cpu0/pmc/MSR_c0010006/value

# cat /sys/kernel/debug/x86/cpu/cpu0/pmc/MSR_c0010006/value
0x2

7. PCI configuration registers (for AMD)
----------------------------------------

a. access complete state

PCI configuration regsiters :
function : 0
000 : 13001022
004 : 00100000
008 : 06000040
00c : 00800000
034 : 00000080
040 : 00000000
044 : 00000000
048 : 00000000
04c : 00000000
050 : 00000000
054 : 00000000
058 : 00000000
05c : 00000000
060 : 00000000
064 : 00000000
068 : 012e4820
06c : 00000030
080 : 21010008
084 : 11112020
088 : 1ff50a60
08c : 00000003
090 : 001005b6
094 : 00000000
098 : 00000007
0a0 : 00000000
0a4 : 00000000
0a8 : 00000000
0ac : 00000000
0b0 : 00000000
0b4 : 00000000
0b8 : 00000000
0c0 : 00000000
0c4 : 00000000
0c8 : 00000000
0cc : 00000000
0d0 : 00000000
0d4 : 00000000
0d8 : 00000000
0e0 : 00000000
0e4 : 00000000
0e8 : 00000000
0ec : 00000000
0f0 : 00000000
0f4 : 00000000
0f8 : 00000000
110 : 00000000
114 : 00000000
118 : 00000000
11c : 00000000
120 : 00000000
124 : 00000000
128 : 00000000
12c : 00000000
130 : 000000c1
134 : 00000000
138 : 00000000
13c : 00000000
140 : 00000000
144 : 00000000
148 : 00000000
14c : 00000000
150 : 00070000
164 : 00000000
168 : 00000000
16c : 0074e026
170 : 07c00109
174 : 00000000
178 : 00000000
17c : 00000000
180 : 00000000
184 : 00000000
188 : 00000000
18c : 00000000
1a0 : 00000000
1a4 : 00002824
1d0 : 00000400
1d4 : 00000051

function : 1
000 : 13011022
004 : 00000000
008 : 06000000
00c : 00800000
034 : 00000000
040 : 00000003
044 : 013f0000
048 : 00000000
04c : 00000000
050 : 00000000
054 : 00000000
058 : 00000000
05c : 00000000
060 : 00000000
064 : 00000000
068 : 00000000
06c : 00000000
070 : 00000000
074 : 00000000
078 : 00000000
07c : 00000000
080 : 00000000
084 : 00000000
088 : 00000a03
08c : 00000b00
090 : 00c00003
094 : 00cfff80
098 : 00d00003
09c : 00d21f00
0a0 : 00d22003
0a4 : 00d22f80
0a8 : 00d23003
0ac : 00dfff00
0b0 : 00e00003
0b4 : 00e3ff80
0b8 : 00e40003
0bc : 00ffff00
0c0 : 00000013
0c4 : 00fff000
0c8 : 00000000
0cc : 00000000
0d0 : 00000000
0d4 : 00000000
0d8 : 00000000
0dc : 00000000
0e0 : 00000000
0e4 : 00000000
0e8 : 00000000
0ec : 00000000
0f0 : c0004001
0f4 : 00000000
110 : 00000000
114 : 00000000
120 : 00000000
124 : 00000000
140 : 00000000
144 : 00000000
148 : 00000000
14c : 00000000
150 : 00000000
154 : 00000000
158 : 00000000
15c : 00000000
160 : 00000000
164 : 00000000
168 : 00000000
16c : 00000000
170 : 00000000
174 : 00000000
178 : 00000000
17c : 00000000
180 : e0000011
184 : 00000000

function : 2
000 : 13021022
004 : 00000000
008 : 06000000
00c : 00800000
034 : 00000000
040 : 00000001
044 : 00000101
048 : 00000000
04c : 00000000
050 : 00000000
054 : 00000000
058 : 00000000
05c : 00000000
060 : 00783ee0
064 : 00000000
068 : 00000000
06c : 00000000
070 : 00000000
074 : 00000000
078 : 00000036
07c : 00000000
080 : 00000005
084 : 00000000
088 : 7d7dfb35
08c : 0022173f
090 : 00600020
094 : 7e51806b
098 : 80000013
09c : 0000003a
0a0 : 000000a8
0a4 : 00000000
10c : 00000000
110 : 00000584
114 : 00000000
118 : 1441b4a4
11c : 00402064
140 : 00000001
144 : 00000101
148 : 00000000
14c : 00000000
150 : 00000000
154 : 00000000
158 : 00000000
15c : 00000000
160 : 00783ee0
164 : 00000000
168 : 00000000
16c : 00000000
178 : 00000036
17c : 00000000
180 : 00000005
184 : 00000000
188 : 4d7dfb35
18c : 0022173f
190 : 00600020
194 : 7e51806b
198 : 80000013
19c : 0000003c
1a0 : 00000008
1b0 : 00000000

function : 3
000 : 13031022
004 : 00100000
008 : 06000000
00c : 00800000
034 : 000000f0
040 : 00000100
044 : 0a100040
048 : 00000000
04c : 00000000
050 : 00000000
054 : 00000000
058 : 00000000
05c : 00000000
060 : 00000000
064 : 1a600000
068 : 100000c0
06c : 08000808
070 : 00000000
074 : 30000876
078 : 00000000
07c : 85001101
080 : ff00f300
084 : 80e600ee
088 : 00000000
08c : 00000000
090 : 00000000
094 : 00000000
098 : 00000000
09c : 00000000
0a0 : 800402bc
0a4 : 3b201800
0b0 : 00000000
0d4 : 0005024d
0d8 : 03000025
0dc : 00034240
0e4 : 00000520
0e8 : 00001f81
0f0 : 0010000f
0f4 : 00000000
0f8 : 00000000
0fc : 00200f31
140 : 00000000
144 : 00000000
148 : 00000000
14c : 00000000
150 : 00000000
154 : 00000000
158 : 00000000
15c : 00000000
160 : 00000000
164 : 00000000
168 : 00000000
16c : 00000000
170 : 00000000
174 : 00000000
178 : 00000000
17c : 00000000
180 : 00400002
188 : 1b000438
190 : 00000000
1a0 : 00000000
1cc : 00000000
1e4 : 80000000
1e8 : 00000000
1ec : 00000000
1f0 : 000f0500
1fc : 00000000

function : 4
000 : 13041022
004 : 00000000
008 : 06000000
00c : 00800000
034 : 00000000
080 : 00000000
084 : 00000000
088 : 00000000
08c : 00000000
090 : 00000000
094 : 00000000
098 : 00000000
09c : 00000000
0a0 : 00000000
0a4 : 00000000
0a8 : 00000000
0ac : 00000000
0b0 : 00000000
0b4 : 00000000
0b8 : 00000000
0bc : 00000000
0c0 : 00000000
0c4 : 00000000
0c8 : 00000000
0cc : 00000000
0d0 : 00000000
0d4 : 00000000
0d8 : 00000000
0dc : 00000000
0e0 : 00000000
0e4 : 00000000
0e8 : 00000000
0ec : 00000000
0f0 : 00000000
0f4 : 00000000
0f8 : 00000000
170 : 00000006
174 : 0a3cdfe6
180 : 800000c4
184 : 00006400
188 : 00000000
18c : 00000000
190 : 00000000
194 : 00000000
198 : 00000000
19c : 00000000
1c4 : 00000000
1e0 : 00000000
1e4 : 00000000
1e8 : 00000000
1ec : 00000000
1f0 : 00000000

b. access individual PCI configuration :

# cat /sys/kernel/debug/x86/cpu/cpu0/pci/PCI0_000/value
0x13001022

# cat /sys/kernel/debug/x86/cpu/cpu0/therm/PCI3_0a4/value
0x3c001800

8. Basic cpuinfo
----------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/cpuinfo/state
CPUINFO :
processor : 0
family : 17
vendor : 2
model : 3
mask : 1
TLB size : 1024 4K pages
virtual bits : 48
physical bits : 40
extended cpuid level : 8000001a (8000001a)
cpuid level : 1
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt rdtscp lm 3dnowext 3dnow constant_tsc rep_good nonstop_tsc pni cx16 lahf_lm cmp_legacy svm extapic cr8_legacy 3dnowprefetch osvw skinit
vendor id : AuthenticAMD
model id : AMD Turion(tm) X2 Ultra Dual-Core Mobile ZM-80
cache size : 1024 KB
cache alignment : 64
power management : ts ttp tm stc 100mhzsteps hwpstate
loops per jiffy : 2098811
bogomips : 4197.62
max cores : 2
apic id : 0
intial apic id : 0
clflush size : 64
cpu cores : 2
physical id : 0
core id : 0
cpu index : 0
hyper vendor : 0

9. CPUID Functions
------------------

a. access complete state

# cat /sys/kernel/debug/x86/cpu/cpu0/cpuid/state
CPUID :
eax ebx ecx edx
00000000 00000001 68747541 444d4163 69746e65
00000001 00200f31 00020800 00002001 178bfbff
80000000 8000001a 68747541 444d4163 69746e65
80000001 00200f31 20000500 0000131f ebd3fbff
80000002 20444d41 69727554 74286e6f 5820296d
80000003 6c552032 20617274 6c617544 726f432d
80000004 6f4d2065 656c6962 2d4d5a20 00003038
80000005 ff08ff08 ff20ff20 40020140 40020140
80000006 00000000 42004200 04008140 00000000
80000007 00000000 00000000 00000000 000001f9
80000008 00003028 00000000 00001001 00000000
80000009 00000000 00000000 00000000 00000000
8000000a 00000001 00000040 00000000 0000000e
8000000b 00000000 00000000 00000000 00000000
8000000c 00000000 00000000 00000000 00000000
8000000d 00000000 00000000 00000000 00000000
8000000e 00000000 00000000 00000000 00000000
8000000f 00000000 00000000 00000000 00000000
80000010 00000000 00000000 00000000 00000000
80000011 00000000 00000000 00000000 00000000
80000012 00000000 00000000 00000000 00000000
80000013 00000000 00000000 00000000 00000000
80000014 00000000 00000000 00000000 00000000
80000015 00000000 00000000 00000000 00000000
80000016 00000000 00000000 00000000 00000000
80000017 00000000 00000000 00000000 00000000
80000018 00000000 00000000 00000000 00000000
80000019 00000000 00000000 00000000 00000000
8000001a 00000000 00000000 00000000 00000000

The following changes since commit 50149b2db7be15514079089d0c4efa4c7a2676bb:
Ingo Molnar (1):
Merge branch 'linus'

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/jaswinder/linux-2.6-tip.git master

Jaswinder Singh Rajput (10):
x86: cpu_debug update Kconfig entry
x86: cpu_debug.c remove some not required header files
x86: cpu_debug.c use a WARN_ONCE() instead of a pr_err()
x86: cpu_debug make room to support more categories
x86: cpu_debug update MSR list to support new architectures
x86: cpu_debug make room for more cpu registers
x86: cpu_debug support APIC_register_name with directory structure
x86: cpu_debug display PCI configuration registers for AMD
x86: cpu_debug display cpuid functions
x86: cpu_debug display basic cpuinfo

arch/x86/Kconfig | 12 +-
arch/x86/include/asm/cpu_debug.h | 125 ++++----
arch/x86/kernel/cpu/cpu_debug.c | 681 +++++++++++++++++++++++++++++++++-----
3 files changed, 666 insertions(+), 152 deletions(-)

Complete diff :

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0c2321d..e5e26b3 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -994,9 +994,19 @@ config X86_CPUID

config X86_CPU_DEBUG
tristate "/sys/kernel/debug/x86/cpu/* - CPU Debug support"
+ select DEBUG_FS
---help---
If you select this option, this will provide various x86 CPUs
- information through debugfs.
+ information through debugfs. Any user can read these file but writing
+ needs root privilege.
+
+ Note: 1. If you compile cpu_debug as a module, it will _not_ be loaded
+ automatically (like usual drivers). You will need to load it manually
+ (or add it to list of modules loaded during boot).
+
+ 2. You need debugfs, if you want to mount debugfs automatically
+ append this line in /etc/fstab:
+ debugfs /sys/kernel/debug debugfs defaults 0 0

choice
prompt "High Memory Support"
diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index d96c1ee..b75758e 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -10,91 +10,80 @@
/* Register flags */
enum cpu_debug_bit {
/* Model Specific Registers (MSRs) */
- CPU_MC_BIT, /* Machine Check */
- CPU_MONITOR_BIT, /* Monitor */
- CPU_TIME_BIT, /* Time */
- CPU_PMC_BIT, /* Performance Monitor */
- CPU_PLATFORM_BIT, /* Platform */
- CPU_APIC_BIT, /* APIC */
- CPU_POWERON_BIT, /* Power-on */
- CPU_CONTROL_BIT, /* Control */
- CPU_FEATURES_BIT, /* Features control */
- CPU_LBRANCH_BIT, /* Last Branch */
- CPU_BIOS_BIT, /* BIOS */
- CPU_FREQ_BIT, /* Frequency */
- CPU_MTTR_BIT, /* MTRR */
- CPU_PERF_BIT, /* Performance */
- CPU_CACHE_BIT, /* Cache */
- CPU_SYSENTER_BIT, /* Sysenter */
- CPU_THERM_BIT, /* Thermal */
- CPU_MISC_BIT, /* Miscellaneous */
- CPU_DEBUG_BIT, /* Debug */
- CPU_PAT_BIT, /* PAT */
- CPU_VMX_BIT, /* VMX */
- CPU_CALL_BIT, /* System Call */
- CPU_BASE_BIT, /* BASE Address */
- CPU_VER_BIT, /* Version ID */
- CPU_CONF_BIT, /* Configuration */
- CPU_SMM_BIT, /* System mgmt mode */
- CPU_SVM_BIT, /*Secure Virtual Machine*/
- CPU_OSVM_BIT, /* OS-Visible Workaround*/
+ CPU_MC, /* Machine Check */
+ CPU_MONITOR, /* Monitor */
+ CPU_TIME, /* Time */
+ CPU_PMC, /* Performance Monitor */
+ CPU_PLATFORM, /* Platform */
+ CPU_APIC, /* APIC */
+ CPU_POWERON, /* Power-on */
+ CPU_CONTROL, /* Control */
+ CPU_FEATURES, /* Features control */
+ CPU_LBRANCH, /* Last Branch */
+ CPU_BIOS, /* BIOS */
+ CPU_FREQ, /* Frequency */
+ CPU_MTRR, /* MTRR */
+ CPU_PERF, /* Performance */
+ CPU_CACHE, /* Cache */
+ CPU_SYSENTER, /* Sysenter */
+ CPU_THERM, /* Thermal */
+ CPU_MISC, /* Miscellaneous */
+ CPU_DEBUG, /* Debug */
+ CPU_PAT, /* PAT */
+ CPU_VMX, /* VMX */
+ CPU_CALL, /* System Call */
+ CPU_BASE, /* BASE Address */
+ CPU_VER, /* Version ID */
+ CPU_CONF, /* Configuration */
+ CPU_SMM, /* System mgmt mode */
+ CPU_POWER, /* Power mgmt */
+ CPU_PNAME, /* Processor name */
+ CPU_IBS, /* IBS */
+ CPU_SVM, /*Secure Virtual Machine*/
+ CPU_OSVM, /* OS-Visible Workaround*/
+ CPU_NB, /* North Bridge */
+ CPU_DRAM, /* DRAM */
+ CPU_MMIO, /* Memory based IO */
+ CPU_DISPLAY, /* Display/VGA */
+ CPU_LINK, /* HyperTransport */
/* Standard Registers */
- CPU_TSS_BIT, /* Task Stack Segment */
- CPU_CR_BIT, /* Control Registers */
- CPU_DT_BIT, /* Descriptor Table */
+ CPU_TSS, /* Task Stack Segment */
+ CPU_CR, /* Control Registers */
+ CPU_DT, /* Descriptor Table */
+ CPU_CPUID, /* CPUID */
+ CPU_CPUINFO, /* struct cpuinfo_x86 */
+ CPU_PCI, /* PCI configuration */
/* End of Registers flags */
- CPU_REG_ALL_BIT, /* Select all Registers */
+ CPU_REG_MAX, /* Max Registers flags */
};

#define CPU_REG_ALL (~0) /* Select all Registers */

-#define CPU_MC (1 << CPU_MC_BIT)
-#define CPU_MONITOR (1 << CPU_MONITOR_BIT)
-#define CPU_TIME (1 << CPU_TIME_BIT)
-#define CPU_PMC (1 << CPU_PMC_BIT)
-#define CPU_PLATFORM (1 << CPU_PLATFORM_BIT)
-#define CPU_APIC (1 << CPU_APIC_BIT)
-#define CPU_POWERON (1 << CPU_POWERON_BIT)
-#define CPU_CONTROL (1 << CPU_CONTROL_BIT)
-#define CPU_FEATURES (1 << CPU_FEATURES_BIT)
-#define CPU_LBRANCH (1 << CPU_LBRANCH_BIT)
-#define CPU_BIOS (1 << CPU_BIOS_BIT)
-#define CPU_FREQ (1 << CPU_FREQ_BIT)
-#define CPU_MTRR (1 << CPU_MTTR_BIT)
-#define CPU_PERF (1 << CPU_PERF_BIT)
-#define CPU_CACHE (1 << CPU_CACHE_BIT)
-#define CPU_SYSENTER (1 << CPU_SYSENTER_BIT)
-#define CPU_THERM (1 << CPU_THERM_BIT)
-#define CPU_MISC (1 << CPU_MISC_BIT)
-#define CPU_DEBUG (1 << CPU_DEBUG_BIT)
-#define CPU_PAT (1 << CPU_PAT_BIT)
-#define CPU_VMX (1 << CPU_VMX_BIT)
-#define CPU_CALL (1 << CPU_CALL_BIT)
-#define CPU_BASE (1 << CPU_BASE_BIT)
-#define CPU_VER (1 << CPU_VER_BIT)
-#define CPU_CONF (1 << CPU_CONF_BIT)
-#define CPU_SMM (1 << CPU_SMM_BIT)
-#define CPU_SVM (1 << CPU_SVM_BIT)
-#define CPU_OSVM (1 << CPU_OSVM_BIT)
-#define CPU_TSS (1 << CPU_TSS_BIT)
-#define CPU_CR (1 << CPU_CR_BIT)
-#define CPU_DT (1 << CPU_DT_BIT)
-
/* Register file flags */
enum cpu_file_bit {
- CPU_INDEX_BIT, /* index */
- CPU_VALUE_BIT, /* value */
+ CPU_INDEX, /* index */
+ CPU_VALUE, /* value */
+};
+
+/* Register category flags */
+enum cpu_cat_bit {
+ CPU_REG_STD, /* Standard registers */
+ CPU_REG_MSR, /* MSRs */
+ CPU_REG_APIC, /* APIC registers */
+ CPU_REG_PCI, /* PCI conf registers */
};

-#define CPU_FILE_VALUE (1 << CPU_VALUE_BIT)
+#define MAX_CPU_FILES 768 /* Max CPU debug files */
+#define MAX_CPU_PCI 5 /* AMD supports func 0-4*/

-#define MAX_CPU_FILES 512
+#define CPUID_MASK 0xffff0000

struct cpu_private {
unsigned cpu;
unsigned type;
unsigned reg;
unsigned file;
+ unsigned cat;
};

struct cpu_debug_base {
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index 6b2a52d..993a5bc 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -6,32 +6,34 @@
* For licencing details see kernel-base/COPYING
*/

-#include <linux/interrupt.h>
-#include <linux/compiler.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
-#include <linux/kprobes.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/percpu.h>
-#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/pci.h>
#include <linux/smp.h>

#include <asm/cpu_debug.h>
#include <asm/paravirt.h>
#include <asm/system.h>
-#include <asm/traps.h>
#include <asm/apic.h>
#include <asm/desc.h>

-static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]);
+#ifdef MODULE
+#include "capflags.c"
+#include "powerflags.c"
+#endif
+
+static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_MAX]);
static DEFINE_PER_CPU(struct cpu_private *, priv_arr[MAX_CPU_FILES]);
+static DEFINE_PER_CPU(struct pci_dev *, pci_arr[MAX_CPU_PCI]);
static DEFINE_PER_CPU(int, cpu_priv_count);

static DEFINE_MUTEX(cpu_debug_lock);
@@ -65,21 +67,63 @@ static struct cpu_debug_base cpu_base[] = {
{ "ver", CPU_VER, 0 },
{ "conf", CPU_CONF, 0 },
{ "smm", CPU_SMM, 0 },
+ { "power", CPU_POWER, 0 },
+ { "pname", CPU_PNAME, 0 },
+ { "ibs", CPU_IBS, 0 },
{ "svm", CPU_SVM, 0 },
{ "osvm", CPU_OSVM, 0 },
+ { "nbridge", CPU_NB, 0 },
+ { "dram", CPU_DRAM, 0 },
+ { "mmio", CPU_MMIO, 0 },
+ { "display", CPU_DISPLAY, 0 },
+ { "link", CPU_LINK, 0 },
{ "tss", CPU_TSS, 0 },
{ "cr", CPU_CR, 0 },
{ "dt", CPU_DT, 0 },
+ { "cpuid", CPU_CPUID, 0 },
+ { "cpuinfo", CPU_CPUINFO, 0 },
+ { "pci", CPU_PCI, 0 },
{ "registers", CPU_REG_ALL, 0 },
};

+#ifdef CONFIG_X86_LOCAL_APIC
+static struct cpu_debug_base cpu_apic[] = {
+ { "ID", APIC_ID, 0 },
+ { "LVR", APIC_LVR, 0 },
+ { "TASKPRI", APIC_TASKPRI, 0 },
+ { "ARBPRI", APIC_ARBPRI, 0 },
+ { "PROCPRI", APIC_PROCPRI, 0 },
+ { "LDR", APIC_LDR, 0 },
+ { "DFR", APIC_DFR, 0 },
+ { "SPIV", APIC_SPIV, 0 },
+ { "ISR", APIC_ISR, 0 },
+ { "ESR", APIC_ESR, 0 },
+ { "ICR", APIC_ICR, 0 },
+ { "ICR2", APIC_ICR2, 0 },
+ { "LVTT", APIC_LVTT, 0 },
+ { "LVTTHMR", APIC_LVTTHMR, 0 },
+ { "LVTPC", APIC_LVTPC, 0 },
+ { "LVT0", APIC_LVT0, 0 },
+ { "LVT1", APIC_LVT1, 0 },
+ { "LVTERR", APIC_LVTERR, 0 },
+ { "TMICT", APIC_TMICT, 0 },
+ { "TMCCT", APIC_TMCCT, 0 },
+ { "TDCR", APIC_TDCR, 0 },
+};
+
+static struct cpu_debug_base cpu_xapic[] = {
+ { "EFEAT", APIC_EFEAT, 0 },
+ { "ECTRL", APIC_ECTRL, 0 },
+};
+#endif
+
static struct cpu_file_base cpu_file[] = {
- { "index", CPU_REG_ALL, 0 },
+ { "state", CPU_REG_ALL, 0 },
{ "value", CPU_REG_ALL, 1 },
};

/* CPU Registers Range */
-static struct cpu_debug_range cpu_reg_range[] = {
+static struct cpu_debug_range cpu_msr_range[] = {
{ 0x00000000, 0x00000001, CPU_MC, },
{ 0x00000006, 0x00000007, CPU_MONITOR, },
{ 0x00000010, 0x00000010, CPU_TIME, },
@@ -95,6 +139,7 @@ static struct cpu_debug_range cpu_reg_range[] = {
{ 0x00000088, 0x0000008A, CPU_CACHE, },
{ 0x0000008B, 0x0000008B, CPU_BIOS, },
{ 0x0000009B, 0x0000009B, CPU_MONITOR, },
+ { 0x000000A0, 0x000000A1, CPU_SMM, },
{ 0x000000C1, 0x000000C4, CPU_PMC, },
{ 0x000000CD, 0x000000CD, CPU_FREQ, },
{ 0x000000E7, 0x000000E8, CPU_PERF, },
@@ -103,40 +148,49 @@ static struct cpu_debug_range cpu_reg_range[] = {
{ 0x00000116, 0x0000011E, CPU_CACHE, },
{ 0x00000174, 0x00000176, CPU_SYSENTER, },
{ 0x00000179, 0x0000017B, CPU_MC, },
+ { 0x00000180, 0x00000185, CPU_MC, },
{ 0x00000186, 0x00000189, CPU_PMC, },
{ 0x00000198, 0x00000199, CPU_PERF, },
{ 0x0000019A, 0x0000019A, CPU_TIME, },
{ 0x0000019B, 0x0000019D, CPU_THERM, },
{ 0x000001A0, 0x000001A0, CPU_MISC, },
- { 0x000001C9, 0x000001C9, CPU_LBRANCH, },
+ { 0x000001A1, 0x000001A1, CPU_PLATFORM, },
+ { 0x000001A2, 0x000001A2, CPU_THERM, },
+ { 0x000001A6, 0x000001A6, CPU_PMC, },
+ { 0x000001AD, 0x000001AD, CPU_FREQ, },
+ { 0x000001C8, 0x000001C9, CPU_LBRANCH, },
{ 0x000001D7, 0x000001D8, CPU_LBRANCH, },
{ 0x000001D9, 0x000001D9, CPU_DEBUG, },
{ 0x000001DA, 0x000001E0, CPU_LBRANCH, },
+ { 0x000001F2, 0x000001F3, CPU_SMM, },

{ 0x00000200, 0x0000020F, CPU_MTRR, },
{ 0x00000250, 0x00000250, CPU_MTRR, },
{ 0x00000258, 0x00000259, CPU_MTRR, },
{ 0x00000268, 0x0000026F, CPU_MTRR, },
{ 0x00000277, 0x00000277, CPU_PAT, },
+ { 0x00000280, 0x00000288, CPU_MC, },
{ 0x000002FF, 0x000002FF, CPU_MTRR, },

{ 0x00000300, 0x00000311, CPU_PMC, },
{ 0x00000345, 0x00000345, CPU_PMC, },
{ 0x00000360, 0x00000371, CPU_PMC, },
- { 0x0000038D, 0x00000390, CPU_PMC, },
+ { 0x0000038D, 0x00000396, CPU_PMC, },
{ 0x000003A0, 0x000003BE, CPU_PMC, },
{ 0x000003C0, 0x000003CD, CPU_PMC, },
{ 0x000003E0, 0x000003E1, CPU_PMC, },
- { 0x000003F0, 0x000003F2, CPU_PMC, },
+ { 0x000003F0, 0x000003FD, CPU_PMC, },

- { 0x00000400, 0x00000417, CPU_MC, },
+ { 0x00000400, 0x00000421, CPU_MC, },
{ 0x00000480, 0x0000048B, CPU_VMX, },

{ 0x00000600, 0x00000600, CPU_DEBUG, },
{ 0x00000680, 0x0000068F, CPU_LBRANCH, },
{ 0x000006C0, 0x000006CF, CPU_LBRANCH, },

- { 0x000107CC, 0x000107D3, CPU_PMC, },
+ { 0x00000800, 0x0000083F, CPU_APIC, },
+
+ { 0x000107CC, 0x000107D8, CPU_PMC, },

{ 0xC0000080, 0xC0000080, CPU_FEATURES, },
{ 0xC0000081, 0xC0000084, CPU_CALL, },
@@ -149,20 +203,120 @@ static struct cpu_debug_range cpu_reg_range[] = {
{ 0xC0010016, 0xC001001A, CPU_MTRR, },
{ 0xC001001D, 0xC001001D, CPU_MTRR, },
{ 0xC001001F, 0xC001001F, CPU_CONF, },
- { 0xC0010030, 0xC0010035, CPU_BIOS, },
- { 0xC0010044, 0xC0010048, CPU_MC, },
+ { 0xC0010022, 0xC0010022, CPU_MC, },
+ { 0xC0010030, 0xC0010035, CPU_PNAME, },
+ { 0xC0010044, 0xC0010049, CPU_MC, },
{ 0xC0010050, 0xC0010056, CPU_SMM, },
{ 0xC0010058, 0xC0010058, CPU_CONF, },
{ 0xC0010060, 0xC0010060, CPU_CACHE, },
- { 0xC0010061, 0xC0010068, CPU_SMM, },
- { 0xC0010069, 0xC001006B, CPU_SMM, },
+ { 0xC0010061, 0xC001006B, CPU_POWER, },
{ 0xC0010070, 0xC0010071, CPU_SMM, },
+ { 0xC0010074, 0xC0010074, CPU_TIME, },
{ 0xC0010111, 0xC0010113, CPU_SMM, },
{ 0xC0010114, 0xC0010118, CPU_SVM, },
{ 0xC0010140, 0xC0010141, CPU_OSVM, },
+
+ { 0xC0011004, 0xC0011005, CPU_FEATURES, },
{ 0xC0011022, 0xC0011023, CPU_CONF, },
+ { 0xC001102A, 0xC001102A, CPU_CONF, },
+ { 0xC0011030, 0xC001103A, CPU_IBS, },
+};
+
+/* PCI-defined configurations registers */
+
+/* Function 0 Link Configuration Registers */
+static struct cpu_debug_range cpu_amd_pci0[] = {
+ { 0x000, 0x00C, CPU_PCI },
+ { 0x034, 0x034, CPU_PCI },
+ { 0x040, 0x06C, CPU_LINK },
+ { 0x080, 0x098, CPU_LINK },
+ { 0x0A0, 0x0B8, CPU_LINK },
+ { 0x0C0, 0x0D8, CPU_LINK },
+ { 0x0E0, 0x0F8, CPU_LINK },
+ { 0x110, 0x150, CPU_LINK },
+ { 0x164, 0x18C, CPU_LINK },
+ { 0x1A0, 0x1A0, CPU_LINK },
+ { 0x1A4, 0x1A4, CPU_DISPLAY },
+ { 0x1D0, 0x1D4, CPU_DISPLAY },
+};
+
+/* Function 1 Address Map Registers */
+static struct cpu_debug_range cpu_amd_pci1[] = {
+ { 0x000, 0x00C, CPU_PCI },
+ { 0x034, 0x034, CPU_PCI },
+ { 0x040, 0x07C, CPU_DRAM },
+ { 0x080, 0x0BC, CPU_MMIO },
+ { 0x0C0, 0x0DC, CPU_PCI },
+ { 0x0E0, 0x0EC, CPU_CONF },
+ { 0x0F0, 0x0F0, CPU_DRAM },
+ { 0x0F4, 0x0F4, CPU_DISPLAY },
+ { 0x110, 0x114, CPU_MMIO },
+ { 0x120, 0x124, CPU_DRAM },
+ { 0x140, 0x17C, CPU_DRAM },
+ { 0x180, 0x184, CPU_NB },
+};
+
+/* Function 2 DRAM Controller Registers */
+static struct cpu_debug_range cpu_amd_pci2[] = {
+ { 0x000, 0x00C, CPU_PCI },
+ { 0x034, 0x034, CPU_PCI },
+ { 0x040, 0x0A4, CPU_DRAM },
+ { 0x10C, 0x11C, CPU_DRAM },
+ { 0x140, 0x16C, CPU_DRAM },
+ { 0x178, 0x1A0, CPU_DRAM },
+ { 0x1B0, 0x1B0, CPU_DRAM },
+};
+
+/* Function 3 Misc. Configuration Registers */
+static struct cpu_debug_range cpu_amd_pci3[] = {
+ { 0x000, 0x00C, CPU_PCI },
+ { 0x034, 0x034, CPU_PCI },
+ { 0x040, 0x054, CPU_NB },
+ { 0x058, 0x060, CPU_DRAM },
+ { 0x064, 0x068, CPU_THERM },
+ { 0x06C, 0x06C, CPU_POWER },
+ { 0x070, 0x07C, CPU_DISPLAY },
+ { 0x080, 0x084, CPU_POWER },
+ { 0x088, 0x08C, CPU_NB },
+ { 0x090, 0x09C, CPU_DISPLAY },
+ { 0x0A0, 0x0A0, CPU_POWER },
+ { 0x0A4, 0x0A4, CPU_THERM },
+ { 0x0B0, 0x0B0, CPU_DISPLAY },
+ { 0x0D4, 0x0DC, CPU_POWER },
+ { 0x0E4, 0x0E4, CPU_THERM },
+ { 0x0E8, 0x0E8, CPU_NB },
+ { 0x0F0, 0x0F0, CPU_PCI },
+ { 0x0F4, 0x0F8, CPU_PCI },
+ { 0x0FC, 0x0FC, CPU_CPUID },
+ { 0x140, 0x180, CPU_NB },
+ { 0x188, 0x188, CPU_NB },
+ { 0x190, 0x190, CPU_CONTROL },
+ { 0x1A0, 0x1A0, CPU_CACHE },
+ { 0x1CC, 0x1CC, CPU_IBS },
+ { 0x1E4, 0x1EC, CPU_THERM },
+ { 0x1F0, 0x1F0, CPU_CPUID },
+ { 0x1FC, 0x1FC, CPU_NB },
};

+/* Function 4 Link Configuration Registers */
+static struct cpu_debug_range cpu_amd_pci4[] = {
+ { 0x000, 0x00C, CPU_PCI },
+ { 0x034, 0x034, CPU_PCI },
+ { 0x080, 0x0F8, CPU_LINK },
+ { 0x170, 0x174, CPU_POWER },
+ { 0x180, 0x19C, CPU_LINK },
+ { 0x1C4, 0x1C4, CPU_POWER },
+ { 0x1E0, 0x1F0, CPU_POWER },
+};
+
+/* Extended CPUID base address */
+static u32 cpu_ext_cpuid[] = {
+ 0x80000000, /* Intel, AMD */
+ 0x80860000, /* Transmeta */
+ 0xC0000000, /* Centaur */
+};
+
+/* Check validity of cpu debug flag */
static int is_typeflag_valid(unsigned cpu, unsigned flag)
{
int i;
@@ -171,8 +325,9 @@ static int is_typeflag_valid(unsigned cpu, unsigned flag)
if (flag >= CPU_TSS)
return 1;

- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
- if (cpu_reg_range[i].flag == flag)
+ /* check MSR range */
+ for (i = 0; i < ARRAY_SIZE(cpu_msr_range); i++) {
+ if (cpu_msr_range[i].flag == flag)
return 1;
}

@@ -180,12 +335,13 @@ static int is_typeflag_valid(unsigned cpu, unsigned flag)
return 0;
}

-static unsigned get_cpu_range(unsigned cpu, unsigned *min, unsigned *max,
+/* get MSR range */
+static unsigned get_msr_range(unsigned cpu, unsigned *min, unsigned *max,
int index, unsigned flag)
{
- if (cpu_reg_range[index].flag == flag) {
- *min = cpu_reg_range[index].min;
- *max = cpu_reg_range[index].max;
+ if (cpu_msr_range[index].flag == flag) {
+ *min = cpu_msr_range[index].min;
+ *max = cpu_msr_range[index].max;
} else
*max = 0;

@@ -226,11 +382,12 @@ static void print_msr(struct seq_file *seq, unsigned cpu, unsigned flag)
&low, &high))
print_cpu_data(seq, priv->reg, low, high);
return;
- }
+ } else
+ seq_printf(seq, " MSR\t:\n");
}

- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
- if (!get_cpu_range(cpu, &msr_min, &msr_max, i, flag))
+ for (i = 0; i < ARRAY_SIZE(cpu_msr_range); i++) {
+ if (!get_msr_range(cpu, &msr_min, &msr_max, i, flag))
continue;

for (msr = msr_min; msr <= msr_max; msr++) {
@@ -339,7 +496,7 @@ static void print_dr(void *arg)
seq_printf(seq, " dr%d\t: %016lx\n", i, dr);
}

- seq_printf(seq, "\n MSR\t:\n");
+ seq_printf(seq, "\n");
}

static void print_apic(void *arg)
@@ -347,43 +504,251 @@ static void print_apic(void *arg)
struct seq_file *seq = arg;

#ifdef CONFIG_X86_LOCAL_APIC
+ unsigned int i;
+
seq_printf(seq, " LAPIC\t:\n");
- seq_printf(seq, " ID\t\t: %08x\n", apic_read(APIC_ID) >> 24);
- seq_printf(seq, " LVR\t\t: %08x\n", apic_read(APIC_LVR));
- seq_printf(seq, " TASKPRI\t: %08x\n", apic_read(APIC_TASKPRI));
- seq_printf(seq, " ARBPRI\t\t: %08x\n", apic_read(APIC_ARBPRI));
- seq_printf(seq, " PROCPRI\t: %08x\n", apic_read(APIC_PROCPRI));
- seq_printf(seq, " LDR\t\t: %08x\n", apic_read(APIC_LDR));
- seq_printf(seq, " DFR\t\t: %08x\n", apic_read(APIC_DFR));
- seq_printf(seq, " SPIV\t\t: %08x\n", apic_read(APIC_SPIV));
- seq_printf(seq, " ISR\t\t: %08x\n", apic_read(APIC_ISR));
- seq_printf(seq, " ESR\t\t: %08x\n", apic_read(APIC_ESR));
- seq_printf(seq, " ICR\t\t: %08x\n", apic_read(APIC_ICR));
- seq_printf(seq, " ICR2\t\t: %08x\n", apic_read(APIC_ICR2));
- seq_printf(seq, " LVTT\t\t: %08x\n", apic_read(APIC_LVTT));
- seq_printf(seq, " LVTTHMR\t: %08x\n", apic_read(APIC_LVTTHMR));
- seq_printf(seq, " LVTPC\t\t: %08x\n", apic_read(APIC_LVTPC));
- seq_printf(seq, " LVT0\t\t: %08x\n", apic_read(APIC_LVT0));
- seq_printf(seq, " LVT1\t\t: %08x\n", apic_read(APIC_LVT1));
- seq_printf(seq, " LVTERR\t\t: %08x\n", apic_read(APIC_LVTERR));
- seq_printf(seq, " TMICT\t\t: %08x\n", apic_read(APIC_TMICT));
- seq_printf(seq, " TMCCT\t\t: %08x\n", apic_read(APIC_TMCCT));
- seq_printf(seq, " TDCR\t\t: %08x\n", apic_read(APIC_TDCR));
+ for (i = 0; i < ARRAY_SIZE(cpu_apic); i++) {
+ if (strlen(cpu_apic[i].name) < 7)
+ seq_printf(seq, " %s\t\t: %08x\n", cpu_apic[i].name,
+ apic_read(cpu_apic[i].flag));
+ else
+ seq_printf(seq, " %s\t: %08x\n", cpu_apic[i].name,
+ apic_read(cpu_apic[i].flag));
+ }
if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
- unsigned int i, v, maxeilvt;
+ unsigned int maxeilvt;

- v = apic_read(APIC_EFEAT);
- maxeilvt = (v >> 16) & 0xff;
- seq_printf(seq, " EFEAT\t\t: %08x\n", v);
- seq_printf(seq, " ECTRL\t\t: %08x\n", apic_read(APIC_ECTRL));
+ for (i = 0; i < ARRAY_SIZE(cpu_xapic); i++)
+ seq_printf(seq, " %s\t\t: %08x\n", cpu_xapic[i].name,
+ apic_read(cpu_xapic[i].flag));

- for (i = 0; i < maxeilvt; i++) {
- v = apic_read(APIC_EILVTn(i));
- seq_printf(seq, " EILVT%d\t\t: %08x\n", i, v);
+ maxeilvt = (apic_read(APIC_EFEAT) >> 16) & 0xff;
+ for (i = 0; i < maxeilvt; i++)
+ seq_printf(seq, " EILVT%d\t\t: %08x\n",
+ i, apic_read(APIC_EILVTn(i)));
+ }
+ seq_printf(seq, "\n");
+#endif
+}
+
+/* Get extended CPUID level */
+static u32 get_extended_cpuid(void)
+{
+ u32 i, level;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_ext_cpuid); i++) {
+ level = cpuid_eax(cpu_ext_cpuid[i]);
+ if ((level & CPUID_MASK) == cpu_ext_cpuid[i])
+ return level;
+ }
+
+ return 0; /* Not found */
+}
+
+static void print_cpuidabcd(struct seq_file *seq, u32 min, u32 max)
+{
+ u32 i, eax, ebx, ecx, edx;
+
+ for (i = min; i <= max; i++) {
+ cpuid(i, &eax, &ebx, &ecx, &edx);
+ seq_printf(seq, " %08x %08x %08x %08x %08x\n",
+ i, eax, ebx, ecx, edx);
+ }
+}
+
+static void print_cpuid(void *arg)
+{
+ struct seq_file *seq = arg;
+ u32 level;
+
+ seq_printf(seq, " CPUID\t:\n");
+ seq_printf(seq, " eax ebx ecx edx\n");
+
+ /* Standard CPUID functions */
+ level = cpuid_eax(0);
+ print_cpuidabcd(seq, 0, level);
+
+ /* Extended CPUID functions */
+ level = get_extended_cpuid();
+ if (level)
+ print_cpuidabcd(seq, (level & CPUID_MASK), level);
+}
+
+/* dump struct cpuinfo_x86 */
+static void print_cpuinfo(void *arg)
+{
+ struct seq_file *seq = arg;
+ struct cpu_private *priv = seq->private;
+ struct cpuinfo_x86 *cpui;
+ unsigned int i;
+
+ cpui = &cpu_data(priv->cpu);
+ seq_printf(seq, " CPUINFO\t:\n");
+ seq_printf(seq, " processor\t\t: %u\n", priv->cpu);
+
+ seq_printf(seq, " family\t\t\t: %u\n", cpui->x86);
+ seq_printf(seq, " vendor\t\t\t: %u\n", cpui->x86_vendor);
+ seq_printf(seq, " model\t\t\t: %u\n", cpui->x86_model);
+ seq_printf(seq, " mask\t\t\t: %u\n", cpui->x86_mask);
+#ifdef CONFIG_X86_32
+ seq_printf(seq, " wp_works_ok\t\t: %u\n", cpui->wp_works_ok);
+ seq_printf(seq, " halt_works_ok\t\t: %u\n", cpui->hlt_works_ok);
+ seq_printf(seq, " hard_math\t\t: %u\n", cpui->hard_math);
+ seq_printf(seq, " rfu\t\t\t: %u\n", cpui->rfu);
+ seq_printf(seq, " fdiv_bug\t\t: %u\n", cpui->fdiv_bug);
+ seq_printf(seq, " f00f_bug\t\t: %u\n", cpui->f00f_bug);
+ seq_printf(seq, " coma_bug\t\t: %u\n", cpui->coma_bug);
+#else
+ seq_printf(seq, " TLB size\t\t: %d 4K pages\n", cpui->x86_tlbsize);
+#endif
+ seq_printf(seq, " virtual bits\t\t: %u\n", cpui->x86_virt_bits);
+ seq_printf(seq, " physical bits\t\t: %u\n", cpui->x86_phys_bits);
+
+ seq_printf(seq, " extended cpuid level\t: %08x (%08x)\n",
+ cpui->extended_cpuid_level, get_extended_cpuid());
+ seq_printf(seq, " cpuid level\t\t: %d\n", cpui->cpuid_level);
+
+ seq_printf(seq, " flags\t\t\t:");
+ for (i = 0; i < 32 * NCAPINTS; i++)
+ if (cpu_has(cpui, i) && x86_cap_flags[i] != NULL)
+ seq_printf(seq, " %s", x86_cap_flags[i]);
+
+ seq_printf(seq, "\n vendor id\t\t: %s\n",
+ cpui->x86_vendor_id[0] ? cpui->x86_vendor_id : "unknown");
+ seq_printf(seq, " model id\t\t: %s\n",
+ cpui->x86_model_id[0] ? cpui->x86_model_id : "unknown");
+
+ seq_printf(seq, " cache size\t\t: %d KB\n", cpui->x86_cache_size);
+ seq_printf(seq, " cache alignment\t: %d\n", cpui->x86_cache_alignment);
+
+ seq_printf(seq, " power management\t:");
+ for (i = 0; i < 32; i++) {
+ if (cpui->x86_power & (1 << i)) {
+ if (i < ARRAY_SIZE(x86_power_flags) &&
+ x86_power_flags[i])
+ seq_printf(seq, "%s%s",
+ x86_power_flags[i][0] ? " " : "",
+ x86_power_flags[i]);
+ else
+ seq_printf(seq, " [%d]", i);
}
}
-#endif /* CONFIG_X86_LOCAL_APIC */
- seq_printf(seq, "\n MSR\t:\n");
+
+ seq_printf(seq, "\n loops per jiffy\t: %lu\n", cpui->loops_per_jiffy);
+ seq_printf(seq, " bogomips\t\t: %lu.%02lu\n",
+ cpui->loops_per_jiffy/(500000/HZ),
+ (cpui->loops_per_jiffy/(5000/HZ)) % 100);
+
+ seq_printf(seq, " max cores\t\t: %d\n", cpui->x86_max_cores);
+ seq_printf(seq, " apic id\t\t: %d\n", cpui->apicid);
+ seq_printf(seq, " intial apic id\t\t: %d\n", cpui->initial_apicid);
+ seq_printf(seq, " clflush size\t\t: %u\n", cpui->x86_clflush_size);
+
+#ifdef CONFIG_SMP
+ seq_printf(seq, " cpu cores\t\t: %d\n", cpui->booted_cores);
+ seq_printf(seq, " physical id\t\t: %d\n", cpui->phys_proc_id);
+ seq_printf(seq, " core id\t\t: %d\n", cpui->cpu_core_id);
+ seq_printf(seq, " cpu index\t\t: %d\n", cpui->cpu_index);
+#endif
+
+ seq_printf(seq, " hyper vendor\t\t: %d\n", cpui->x86_hyper_vendor);
+}
+
+static void print_apicval(void *arg)
+{
+ struct seq_file *seq = arg;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+ struct cpu_private *priv = seq->private;
+
+ seq_printf(seq, "0x%x\n", apic_read(priv->reg));
+#endif
+}
+
+static void print_pcival(void *arg)
+{
+ struct seq_file *seq = arg;
+ struct cpu_private *priv = seq->private;
+ struct pci_dev *dev;
+ u32 data = (priv->reg & 0xf0000) >> 16;
+
+ if (data >= MAX_CPU_PCI)
+ return;
+
+ dev = per_cpu(pci_arr[data], priv->cpu);
+ if (!pci_read_config_dword(dev, priv->reg & 0x0fff, &data))
+ seq_printf(seq, "0x%x\n", data);
+}
+
+#define PRINT_AMD_PCI(func) \
+static void print_amd_pci##func(struct seq_file *seq, struct pci_dev *dev) \
+{ \
+ unsigned int reg, i; \
+ u32 data; \
+ \
+ for (i = 0; i < ARRAY_SIZE(cpu_amd_pci##func); i++) { \
+ for (reg = cpu_amd_pci##func[i].min; \
+ reg <= cpu_amd_pci##func[i].max; reg++) { \
+ if (!pci_read_config_dword(dev, reg, &data)) { \
+ seq_printf(seq, " %03x\t: %08x\n", \
+ reg, data); \
+ } \
+ } \
+ } \
+ seq_printf(seq, "\n"); \
+}
+
+PRINT_AMD_PCI(0)
+PRINT_AMD_PCI(1)
+PRINT_AMD_PCI(2)
+PRINT_AMD_PCI(3)
+PRINT_AMD_PCI(4)
+
+static void print_amd_pci(struct seq_file *seq)
+{
+ struct cpu_private *priv = seq->private;
+ struct pci_dev *dev;
+ unsigned int func;
+
+ for (func = 0; func < MAX_CPU_PCI; func++) {
+ dev = per_cpu(pci_arr[func], priv->cpu);
+ if (dev == NULL)
+ continue;
+
+ seq_printf(seq, " function : %d\n", func);
+
+ switch (func) {
+ case 0:
+ print_amd_pci0(seq, dev);
+ break;
+ case 1:
+ print_amd_pci1(seq, dev);
+ break;
+ case 2:
+ print_amd_pci2(seq, dev);
+ break;
+ case 3:
+ print_amd_pci3(seq, dev);
+ break;
+ case 4:
+ print_amd_pci4(seq, dev);
+ break;
+ }
+ }
+}
+
+static void print_pci(void *arg)
+{
+ struct seq_file *seq = arg;
+
+ seq_printf(seq, " PCI configuration regsiters :\n");
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ print_amd_pci(seq);
+ break;
+ default:
+ return;
+ }
}

static int cpu_seq_show(struct seq_file *seq, void *v)
@@ -403,19 +768,46 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
case CPU_DT:
smp_call_function_single(priv->cpu, print_dt, seq, 1);
break;
+ case CPU_CPUID:
+ if (priv->file == CPU_INDEX)
+ smp_call_function_single(priv->cpu, print_cpuid,
+ seq, 1);
+ else
+ smp_call_function_single(priv->cpu, print_pcival,
+ seq, 1);
+ break;
+ case CPU_CPUINFO:
+ smp_call_function_single(priv->cpu, print_cpuinfo, seq, 1);
+ break;
+ case CPU_PCI:
+ if (priv->file == CPU_INDEX)
+ smp_call_function_single(priv->cpu, print_pci, seq, 1);
+ else
+ smp_call_function_single(priv->cpu, print_pcival,
+ seq, 1);
+ break;
case CPU_DEBUG:
- if (priv->file == CPU_INDEX_BIT)
+ if (priv->file == CPU_INDEX)
smp_call_function_single(priv->cpu, print_dr, seq, 1);
- print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+ if (priv->cat == CPU_REG_MSR)
+ print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
break;
case CPU_APIC:
- if (priv->file == CPU_INDEX_BIT)
+ if (priv->file == CPU_INDEX)
smp_call_function_single(priv->cpu, print_apic, seq, 1);
- print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+ if (priv->cat == CPU_REG_MSR)
+ print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+ else if (priv->cat == CPU_REG_APIC)
+ smp_call_function_single(priv->cpu, print_apicval,
+ seq, 1);
break;

default:
- print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+ if (priv->cat == CPU_REG_MSR)
+ print_msr(seq, priv->cpu, cpu_base[priv->type].flag);
+ else if (priv->cat == CPU_REG_PCI)
+ smp_call_function_single(priv->cpu, print_pcival,
+ seq, 1);
break;
}
seq_printf(seq, "\n");
@@ -487,7 +879,7 @@ static int write_cpu_register(struct cpu_private *priv, const char *buf)
return ret;

/* Supporting only MSRs */
- if (priv->type < CPU_TSS_BIT)
+ if (priv->type < CPU_TSS)
return write_msr(priv, val);

return ret;
@@ -525,12 +917,12 @@ static const struct file_operations cpu_fops = {
};

static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
- unsigned file, struct dentry *dentry)
+ unsigned file, unsigned cat, struct dentry *dentry)
{
struct cpu_private *priv = NULL;

/* Already intialized */
- if (file == CPU_INDEX_BIT)
+ if (file == CPU_INDEX)
if (per_cpu(cpu_arr[type].init, cpu))
return 0;

@@ -542,6 +934,7 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
priv->type = type;
priv->reg = reg;
priv->file = file;
+ priv->cat = cat;
mutex_lock(&cpu_debug_lock);
per_cpu(priv_arr[type], cpu) = priv;
per_cpu(cpu_priv_count, cpu)++;
@@ -551,7 +944,7 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
debugfs_create_file(cpu_file[file].name, S_IRUGO,
dentry, (void *)priv, &cpu_fops);
else {
- debugfs_create_file(cpu_base[type].name, S_IRUGO,
+ debugfs_create_file(cpu_file[file].name, S_IRUGO,
per_cpu(cpu_arr[type].dentry, cpu),
(void *)priv, &cpu_fops);
mutex_lock(&cpu_debug_lock);
@@ -563,13 +956,13 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
}

static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg,
- struct dentry *dentry)
+ unsigned cat, struct dentry *dentry)
{
unsigned file;
int err = 0;

- for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
- err = cpu_create_file(cpu, type, reg, file, dentry);
+ for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
+ err = cpu_create_file(cpu, type, reg, file, cat, dentry);
if (err)
return err;
}
@@ -585,8 +978,8 @@ static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry)
char reg_dir[12];
u32 low, high;

- for (i = 0; i < ARRAY_SIZE(cpu_reg_range); i++) {
- if (!get_cpu_range(cpu, &reg_min, &reg_max, i,
+ for (i = 0; i < ARRAY_SIZE(cpu_msr_range); i++) {
+ if (!get_msr_range(cpu, &reg_min, &reg_max, i,
cpu_base[type].flag))
continue;

@@ -594,9 +987,10 @@ static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry)
if (rdmsr_safe_on_cpu(cpu, reg, &low, &high))
continue;

- sprintf(reg_dir, "0x%x", reg);
+ sprintf(reg_dir, "MSR_%x", reg);
cpu_dentry = debugfs_create_dir(reg_dir, dentry);
- err = cpu_init_regfiles(cpu, type, reg, cpu_dentry);
+ err = cpu_init_regfiles(cpu, type, reg, CPU_REG_MSR,
+ cpu_dentry);
if (err)
return err;
}
@@ -605,23 +999,144 @@ static int cpu_init_msr(unsigned cpu, unsigned type, struct dentry *dentry)
return err;
}

+static void cpu_init_apic(unsigned cpu, struct dentry *dentry)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ struct dentry *cpu_dentry;
+ char reg_dir[16];
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_apic); i++) {
+ sprintf(reg_dir, "APIC_%s", cpu_apic[i].name);
+ cpu_dentry = debugfs_create_dir(reg_dir, dentry);
+ cpu_create_file(cpu, CPU_APIC, cpu_apic[i].flag, CPU_VALUE,
+ CPU_REG_APIC, cpu_dentry);
+ }
+
+ if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
+ unsigned int maxeilvt;
+
+ for (i = 0; i < ARRAY_SIZE(cpu_xapic); i++) {
+ sprintf(reg_dir, "APIC_%s", cpu_xapic[i].name);
+ cpu_dentry = debugfs_create_dir(reg_dir, dentry);
+ cpu_create_file(cpu, CPU_APIC, cpu_xapic[i].flag,
+ CPU_VALUE, CPU_REG_APIC, cpu_dentry);
+ }
+
+ maxeilvt = (apic_read(APIC_EFEAT) >> 16) & 0xff;
+ for (i = 0; i < maxeilvt; i++) {
+ sprintf(reg_dir, "APIC_EILVT%d", i);
+ cpu_dentry = debugfs_create_dir(reg_dir, dentry);
+ cpu_create_file(cpu, CPU_APIC, APIC_EILVTn(i),
+ CPU_VALUE, CPU_REG_APIC, cpu_dentry);
+ }
+ }
+#endif
+}
+
+#define INIT_AMD_PCI(func) \
+static void init_amd_pci##func(unsigned cpu, struct dentry *dentry, \
+ struct pci_dev *dev) \
+{ \
+ struct dentry *cdentry; \
+ unsigned int reg, i, id; \
+ char reg_dir[10]; \
+ u32 data; \
+ \
+ for (i = 0; i < ARRAY_SIZE(cpu_amd_pci##func); i++) { \
+ for (reg = cpu_amd_pci##func[i].min; \
+ reg <= cpu_amd_pci##func[i].max; reg++) { \
+ if (!pci_read_config_dword(dev, reg, &data)) { \
+ sprintf(reg_dir, "PCI%d_%03x", \
+ func, reg); \
+ id = cpu_amd_pci##func[i].flag; \
+ cdentry = debugfs_create_dir(reg_dir, \
+ per_cpu(cpu_arr[id].dentry, cpu)); \
+ cpu_create_file(cpu, \
+ cpu_amd_pci##func[i].flag, \
+ (func << 16) | reg, \
+ CPU_VALUE, CPU_REG_PCI, \
+ cdentry); \
+ } \
+ } \
+ } \
+}
+
+/* AMD supports five functions, 0 through 4 */
+INIT_AMD_PCI(0)
+INIT_AMD_PCI(1)
+INIT_AMD_PCI(2)
+INIT_AMD_PCI(3)
+INIT_AMD_PCI(4)
+
+static void init_amd_pci(unsigned cpu, struct dentry *dentry)
+{
+ struct pci_dev *dev = NULL;
+ unsigned int func;
+
+ while ((dev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_ANY_ID, dev))
+ != NULL) {
+ if ((dev->device >= 0x1100) && (dev->device < 0x2000)) {
+ func = dev->device & 0xff;
+ if (func >= MAX_CPU_PCI)
+ continue;
+
+ per_cpu(pci_arr[func], cpu) = dev;
+ switch (func) {
+ case 0:
+ init_amd_pci0(cpu, dentry, dev);
+ break;
+ case 1:
+ init_amd_pci1(cpu, dentry, dev);
+ break;
+ case 2:
+ init_amd_pci2(cpu, dentry, dev);
+ break;
+ case 3:
+ init_amd_pci3(cpu, dentry, dev);
+ break;
+ case 4:
+ init_amd_pci4(cpu, dentry, dev);
+ break;
+ }
+ }
+ }
+}
+
+static void cpu_init_pci(unsigned cpu, struct dentry *dentry)
+{
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ init_amd_pci(cpu, dentry);
+ break;
+ default:
+ return;
+ }
+}
+
static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
{
struct dentry *cpu_dentry = NULL;
unsigned type;
int err = 0;

- for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) {
- if (!is_typeflag_valid(cpu, cpu_base[type].flag))
- continue;
+ for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) {
cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry);
per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry;

- if (type < CPU_TSS_BIT)
+ /* check before preparing "state" file */
+ if (!is_typeflag_valid(cpu, cpu_base[type].flag))
+ continue;
+
+ if (type == CPU_APIC)
+ cpu_init_apic(cpu, cpu_dentry);
+ if (type == CPU_PCI)
+ cpu_init_pci(cpu, cpu_dentry);
+ if (type < CPU_TSS)
err = cpu_init_msr(cpu, type, cpu_dentry);
else
- err = cpu_create_file(cpu, type, 0, CPU_INDEX_BIT,
- cpu_dentry);
+ err = cpu_create_file(cpu, type, 0, CPU_INDEX,
+ CPU_REG_STD, cpu_dentry);
if (err)
return err;
}
@@ -649,8 +1164,8 @@ static int cpu_init_cpu(void)
pr_info("cpu%d(%d) debug files %d\n",
cpu, nr_cpu_ids, per_cpu(cpu_priv_count, cpu));
if (per_cpu(cpu_priv_count, cpu) > MAX_CPU_FILES) {
- pr_err("Register files count %d exceeds limit %d\n",
- per_cpu(cpu_priv_count, cpu), MAX_CPU_FILES);
+ WARN_ONCE(1, "debug files count %d exceeds limit %d\n",
+ per_cpu(cpu_priv_count, cpu), MAX_CPU_FILES);
per_cpu(cpu_priv_count, cpu) = MAX_CPU_FILES;
err = -ENFILE;
}
@@ -683,6 +1198,6 @@ static void __exit cpu_debug_exit(void)
module_init(cpu_debug_init);
module_exit(cpu_debug_exit);

-MODULE_AUTHOR("Jaswinder Singh Rajput");
+MODULE_AUTHOR("Jaswinder Singh Rajput <jaswinder@xxxxxxxxxx>");
MODULE_DESCRIPTION("CPU Debug module");
MODULE_LICENSE("GPL");


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/