2009-06-13 16:38:14

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

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 <[email protected]>");
MODULE_DESCRIPTION("CPU Debug module");
MODULE_LICENSE("GPL");


2009-06-13 16:38:30

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 1/10 -tip] x86: cpu_debug update Kconfig entry


cpu_debug needs DEBUG_FS.

Explain basic info to use cpu_debug.

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/Kconfig | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)

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"
--
1.6.0.6


2009-06-13 16:38:45

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 2/10 -tip] x86: cpu_debug.c remove some not required header files

remove some not required header files

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/kernel/cpu/cpu_debug.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index 6b2a52d..f7b42d2 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -6,16 +6,12 @@
* 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>
@@ -26,7 +22,6 @@
#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>

--
1.6.0.6


2009-06-13 16:39:02

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 3/10 -tip] x86: cpu_debug.c use a WARN_ONCE() instead of a pr_err()


Use a WARN_ONCE() instead of a pr_err(). Hitting this is a
bug we want to fix.

Also added email address.

Reported-by: Ingo Molnar <[email protected]>
Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/kernel/cpu/cpu_debug.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index f7b42d2..3aa3596 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -644,8 +644,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;
}
@@ -678,6 +678,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 <[email protected]>");
MODULE_DESCRIPTION("CPU Debug module");
MODULE_LICENSE("GPL");
--
1.6.0.6


2009-06-13 16:39:26

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 4/10 -tip] x86: cpu_debug make room to support more categories


Earlier cpu_debug categories was stored in bitwise fashion and
we reached the limit of 0-31.

So now storing the categories based on count so that we can add more.

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 102 +++++++++++++-------------------------
arch/x86/kernel/cpu/cpu_debug.c | 14 +++---
2 files changed, 41 insertions(+), 75 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index d96c1ee..da5c221 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -10,84 +10,50 @@
/* 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_SVM, /*Secure Virtual Machine*/
+ CPU_OSVM, /* OS-Visible Workaround*/
/* 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 */
/* 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 */
};

-#define CPU_FILE_VALUE (1 << CPU_VALUE_BIT)
-
#define MAX_CPU_FILES 512

struct cpu_private {
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index 3aa3596..5c45c52 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -25,7 +25,7 @@
#include <asm/apic.h>
#include <asm/desc.h>

-static DEFINE_PER_CPU(struct cpu_cpuX_base, cpu_arr[CPU_REG_ALL_BIT]);
+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(int, cpu_priv_count);

@@ -399,12 +399,12 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
smp_call_function_single(priv->cpu, print_dt, 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);
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);
break;
@@ -482,7 +482,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,7 +525,7 @@ static int cpu_create_file(unsigned cpu, unsigned type, unsigned reg,
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;

@@ -612,10 +612,10 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry);
per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry;

- if (type < CPU_TSS_BIT)
+ if (type < CPU_TSS)
err = cpu_init_msr(cpu, type, cpu_dentry);
else
- err = cpu_create_file(cpu, type, 0, CPU_INDEX_BIT,
+ err = cpu_create_file(cpu, type, 0, CPU_INDEX,
cpu_dentry);
if (err)
return err;
--
1.6.0.6


2009-06-13 16:39:42

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 5/10 -tip] x86: cpu_debug update MSR list to support new architectures


Added support for Intel Xeon MP 7400 series :

Intel Xeon MP 7400 series falls in Intel Core microarchitecture.
Intel Xeon MP 7400 series supports additional:
0x419, 0x107CC-0x107D3 and 0x107D8

Added support for Intel Core i7, Xeon Processor 5500 series (Nehalem)

Added some extra registers for AMD Family 10h Processor

Also fixed some minor range issues.

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 3 +++
arch/x86/kernel/cpu/cpu_debug.c | 36 +++++++++++++++++++++++++++---------
2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index da5c221..f2adad3 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -36,6 +36,9 @@ enum cpu_debug_bit {
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*/
/* Standard Registers */
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index 5c45c52..9435da4 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -60,6 +60,9 @@ 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 },
{ "tss", CPU_TSS, 0 },
@@ -90,6 +93,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, },
@@ -98,40 +102,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, },
@@ -144,18 +157,23 @@ 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, },
};

static int is_typeflag_valid(unsigned cpu, unsigned flag)
--
1.6.0.6


2009-06-13 16:39:57

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 6/10 -tip] x86: cpu_debug make room for more cpu registers


Added Register category flags and define MSR_ for MSRs so that
we can add more cpu registers and distguish between them.

using name "state" do describe the state

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 7 ++++
arch/x86/kernel/cpu/cpu_debug.c | 59 ++++++++++++++++++++++----------------
2 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index f2adad3..79710f2 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -57,6 +57,12 @@ enum cpu_file_bit {
CPU_VALUE, /* value */
};

+/* Register category flags */
+enum cpu_cat_bit {
+ CPU_REG_STD, /* Standard registers */
+ CPU_REG_MSR, /* MSRs */
+};
+
#define MAX_CPU_FILES 512

struct cpu_private {
@@ -64,6 +70,7 @@ struct cpu_private {
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 9435da4..b03245e 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -72,12 +72,12 @@ static struct cpu_debug_base cpu_base[] = {
};

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, },
@@ -176,6 +176,7 @@ static struct cpu_debug_range cpu_reg_range[] = {
{ 0xC0011030, 0xC001103A, CPU_IBS, },
};

+/* Check validity of cpu debug flag */
static int is_typeflag_valid(unsigned cpu, unsigned flag)
{
int i;
@@ -184,8 +185,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;
}

@@ -193,12 +195,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;

@@ -239,11 +242,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++) {
@@ -352,7 +356,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)
@@ -395,8 +399,8 @@ static void print_apic(void *arg)
seq_printf(seq, " EILVT%d\t\t: %08x\n", i, v);
}
}
+ seq_printf(seq, "\n");
#endif /* CONFIG_X86_LOCAL_APIC */
- seq_printf(seq, "\n MSR\t:\n");
}

static int cpu_seq_show(struct seq_file *seq, void *v)
@@ -419,16 +423,19 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
case CPU_DEBUG:
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)
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);
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);
break;
}
seq_printf(seq, "\n");
@@ -538,7 +545,7 @@ 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;

@@ -555,6 +562,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)++;
@@ -564,7 +572,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);
@@ -576,13 +584,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);
+ err = cpu_create_file(cpu, type, reg, file, cat, dentry);
if (err)
return err;
}
@@ -598,8 +606,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;

@@ -607,9 +615,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;
}
@@ -634,7 +643,7 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
err = cpu_init_msr(cpu, type, cpu_dentry);
else
err = cpu_create_file(cpu, type, 0, CPU_INDEX,
- cpu_dentry);
+ CPU_REG_STD, cpu_dentry);
if (err)
return err;
}
--
1.6.0.6


2009-06-13 16:40:22

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 7/10 -tip] x86: cpu_debug support APIC_register_name with directory structure


Added Register category flags and define APIC_ for APIC registers
so that we can distguish between them.

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 1 +
arch/x86/kernel/cpu/cpu_debug.c | 132 +++++++++++++++++++++++++++++---------
2 files changed, 102 insertions(+), 31 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index 79710f2..fd20da7 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -61,6 +61,7 @@ enum cpu_file_bit {
enum cpu_cat_bit {
CPU_REG_STD, /* Standard registers */
CPU_REG_MSR, /* MSRs */
+ CPU_REG_APIC, /* APIC registers */
};

#define MAX_CPU_FILES 512
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index b03245e..fcfd22f 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -71,6 +71,37 @@ static struct cpu_debug_base cpu_base[] = {
{ "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[] = {
{ "state", CPU_REG_ALL, 0 },
{ "value", CPU_REG_ALL, 1 },
@@ -364,43 +395,42 @@ 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 /* CONFIG_X86_LOCAL_APIC */
+#endif
+}
+
+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 int cpu_seq_show(struct seq_file *seq, void *v)
@@ -431,6 +461,9 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
smp_call_function_single(priv->cpu, print_apic, seq, 1);
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:
@@ -627,6 +660,41 @@ 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
+}
+
static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
{
struct dentry *cpu_dentry = NULL;
@@ -639,6 +707,8 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
cpu_dentry = debugfs_create_dir(cpu_base[type].name, dentry);
per_cpu(cpu_arr[type].dentry, cpu) = cpu_dentry;

+ if (type == CPU_APIC)
+ cpu_init_apic(cpu, cpu_dentry);
if (type < CPU_TSS)
err = cpu_init_msr(cpu, type, cpu_dentry);
else
--
1.6.0.6


2009-06-13 16:40:47

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 8/10 -tip] x86: cpu_debug display PCI configuration registers for AMD


PCI-defined configuration space PCIX_YYY:

X specifies the function number
YYY specifies the byte address of the configuration register in hex

e.g., PCI3_040 specifies the register at function 3, address 0x40.

AMD processor supports five functions, 0 through 4.

Also updated MAX_CPU_FILES to 768 to handle pci files.

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 11 ++-
arch/x86/kernel/cpu/cpu_debug.c | 280 +++++++++++++++++++++++++++++++++++++-
2 files changed, 288 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index fd20da7..dc24338 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -41,10 +41,17 @@ enum cpu_debug_bit {
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 */
+ CPU_CPUID, /* CPUID */
/* Standard Registers */
CPU_TSS, /* Task Stack Segment */
CPU_CR, /* Control Registers */
CPU_DT, /* Descriptor Table */
+ CPU_PCI, /* PCI configuration */
/* End of Registers flags */
CPU_REG_MAX, /* Max Registers flags */
};
@@ -62,9 +69,11 @@ 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 MAX_CPU_FILES 512
+#define MAX_CPU_FILES 768 /* Max CPU debug files */
+#define MAX_CPU_PCI 5 /* AMD supports func 0-4*/

struct cpu_private {
unsigned cpu;
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index fcfd22f..b4dfddd 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -17,6 +17,7 @@
#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>
@@ -27,6 +28,7 @@

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,9 +67,16 @@ static struct cpu_debug_base cpu_base[] = {
{ "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 },
+ { "cpuid", CPU_CPUID, 0 },
{ "tss", CPU_TSS, 0 },
{ "cr", CPU_CR, 0 },
{ "dt", CPU_DT, 0 },
+ { "pci", CPU_PCI, 0 },
{ "registers", CPU_REG_ALL, 0 },
};

@@ -207,6 +216,93 @@ static struct cpu_debug_range cpu_msr_range[] = {
{ 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 },
+};
+
/* Check validity of cpu debug flag */
static int is_typeflag_valid(unsigned cpu, unsigned flag)
{
@@ -433,6 +529,92 @@ static void print_apicval(void *arg)
#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)
{
struct cpu_private *priv = seq->private;
@@ -450,6 +632,13 @@ 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_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)
smp_call_function_single(priv->cpu, print_dr, seq, 1);
@@ -469,6 +658,9 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
default:
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");
@@ -695,6 +887,86 @@ static void cpu_init_apic(unsigned cpu, struct dentry *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;
@@ -702,13 +974,17 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
int err = 0;

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

+ /* 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
--
1.6.0.6


2009-06-13 16:41:01

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 9/10 -tip] x86: cpu_debug display cpuid functions


Add support for cpuid standard and extended functions

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 4 ++-
arch/x86/kernel/cpu/cpu_debug.c | 64 ++++++++++++++++++++++++++++++++++++--
2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index dc24338..377f658 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -46,11 +46,11 @@ enum cpu_debug_bit {
CPU_MMIO, /* Memory based IO */
CPU_DISPLAY, /* Display/VGA */
CPU_LINK, /* HyperTransport */
- CPU_CPUID, /* CPUID */
/* Standard Registers */
CPU_TSS, /* Task Stack Segment */
CPU_CR, /* Control Registers */
CPU_DT, /* Descriptor Table */
+ CPU_CPUID, /* CPUID */
CPU_PCI, /* PCI configuration */
/* End of Registers flags */
CPU_REG_MAX, /* Max Registers flags */
@@ -75,6 +75,8 @@ enum cpu_cat_bit {
#define MAX_CPU_FILES 768 /* Max CPU debug files */
#define MAX_CPU_PCI 5 /* AMD supports func 0-4*/

+#define CPUID_MASK 0xffff0000
+
struct cpu_private {
unsigned cpu;
unsigned type;
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index b4dfddd..f7f702e 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -72,10 +72,10 @@ static struct cpu_debug_base cpu_base[] = {
{ "mmio", CPU_MMIO, 0 },
{ "display", CPU_DISPLAY, 0 },
{ "link", CPU_LINK, 0 },
- { "cpuid", CPU_CPUID, 0 },
{ "tss", CPU_TSS, 0 },
{ "cr", CPU_CR, 0 },
{ "dt", CPU_DT, 0 },
+ { "cpuid", CPU_CPUID, 0 },
{ "pci", CPU_PCI, 0 },
{ "registers", CPU_REG_ALL, 0 },
};
@@ -303,6 +303,13 @@ static struct cpu_debug_range cpu_amd_pci4[] = {
{ 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)
{
@@ -518,6 +525,49 @@ static void print_apic(void *arg)
#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);
+}
+
static void print_apicval(void *arg)
{
struct seq_file *seq = arg;
@@ -632,6 +682,14 @@ 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_PCI:
if (priv->file == CPU_INDEX)
smp_call_function_single(priv->cpu, print_pci, seq, 1);
@@ -814,7 +872,7 @@ static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg,
unsigned file;
int err = 0;

- for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
+ for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
err = cpu_create_file(cpu, type, reg, file, cat, dentry);
if (err)
return err;
@@ -973,7 +1031,7 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
unsigned type;
int err = 0;

- for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) {
+ 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;

--
1.6.0.6


2009-06-13 16:41:26

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: [RFC][PATCH 10/10 -tip] x86: cpu_debug display basic cpuinfo


Add support for display struct cpuinfo_x86

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 1 +
arch/x86/kernel/cpu/cpu_debug.c | 89 ++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index 377f658..b75758e 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -51,6 +51,7 @@ enum cpu_debug_bit {
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_MAX, /* Max Registers flags */
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index f7f702e..993a5bc 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -26,6 +26,11 @@
#include <asm/apic.h>
#include <asm/desc.h>

+#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]);
@@ -76,6 +81,7 @@ static struct cpu_debug_base cpu_base[] = {
{ "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 },
};
@@ -568,6 +574,86 @@ static void print_cpuid(void *arg)
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);
+ }
+ }
+
+ 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;
@@ -690,6 +776,9 @@ static int cpu_seq_show(struct seq_file *seq, void *v)
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);
--
1.6.0.6


2009-06-13 17:54:18

by Michael S. Zick

[permalink] [raw]
Subject: Re: [RFC][PATCH 9/10 -tip] x86: cpu_debug display cpuid functions

On Sat June 13 2009, Jaswinder Singh Rajput wrote:
>
> Add support for cpuid standard and extended functions
>
> Signed-off-by: Jaswinder Singh Rajput <[email protected]>
> ---
> arch/x86/include/asm/cpu_debug.h | 4 ++-
> arch/x86/kernel/cpu/cpu_debug.c | 64 ++++++++++++++++++++++++++++++++++++--
> 2 files changed, 64 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
> index dc24338..377f658 100644
> --- a/arch/x86/include/asm/cpu_debug.h
> +++ b/arch/x86/include/asm/cpu_debug.h
> @@ -46,11 +46,11 @@ enum cpu_debug_bit {
> CPU_MMIO, /* Memory based IO */
> CPU_DISPLAY, /* Display/VGA */
> CPU_LINK, /* HyperTransport */
> - CPU_CPUID, /* CPUID */
> /* Standard Registers */
> CPU_TSS, /* Task Stack Segment */
> CPU_CR, /* Control Registers */
> CPU_DT, /* Descriptor Table */
> + CPU_CPUID, /* CPUID */
> CPU_PCI, /* PCI configuration */
> /* End of Registers flags */
> CPU_REG_MAX, /* Max Registers flags */
> @@ -75,6 +75,8 @@ enum cpu_cat_bit {
> #define MAX_CPU_FILES 768 /* Max CPU debug files */
> #define MAX_CPU_PCI 5 /* AMD supports func 0-4*/
>
> +#define CPUID_MASK 0xffff0000
> +
> struct cpu_private {
> unsigned cpu;
> unsigned type;
> diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
> index b4dfddd..f7f702e 100644
> --- a/arch/x86/kernel/cpu/cpu_debug.c
> +++ b/arch/x86/kernel/cpu/cpu_debug.c
> @@ -72,10 +72,10 @@ static struct cpu_debug_base cpu_base[] = {
> { "mmio", CPU_MMIO, 0 },
> { "display", CPU_DISPLAY, 0 },
> { "link", CPU_LINK, 0 },
> - { "cpuid", CPU_CPUID, 0 },
> { "tss", CPU_TSS, 0 },
> { "cr", CPU_CR, 0 },
> { "dt", CPU_DT, 0 },
> + { "cpuid", CPU_CPUID, 0 },
> { "pci", CPU_PCI, 0 },
> { "registers", CPU_REG_ALL, 0 },
> };
> @@ -303,6 +303,13 @@ static struct cpu_debug_range cpu_amd_pci4[] = {
> { 0x1E0, 0x1F0, CPU_POWER },
> };
>
> +/* Extended CPUID base address */
> +static u32 cpu_ext_cpuid[] = {
> + 0x80000000, /* Intel, AMD */
> + 0x80860000, /* Transmeta */
> + 0xC0000000, /* Centaur */
>

VIA/Centaur has both 0xC0000000 and 0x8000000

Mike
> +};
> +
> /* Check validity of cpu debug flag */
> static int is_typeflag_valid(unsigned cpu, unsigned flag)
> {
> @@ -518,6 +525,49 @@ static void print_apic(void *arg)
> #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);
> +}
> +
> static void print_apicval(void *arg)
> {
> struct seq_file *seq = arg;
> @@ -632,6 +682,14 @@ 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_PCI:
> if (priv->file == CPU_INDEX)
> smp_call_function_single(priv->cpu, print_pci, seq, 1);
> @@ -814,7 +872,7 @@ static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg,
> unsigned file;
> int err = 0;
>
> - for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
> + for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
> err = cpu_create_file(cpu, type, reg, file, cat, dentry);
> if (err)
> return err;
> @@ -973,7 +1031,7 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
> unsigned type;
> int err = 0;
>
> - for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) {
> + 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;
>

2009-06-13 18:26:55

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [RFC][PATCH 9/10 -tip] x86: cpu_debug display cpuid functions

On Sat, 2009-06-13 at 12:53 -0500, Michael S. Zick wrote:
> On Sat June 13 2009, Jaswinder Singh Rajput wrote:
> >
> > Add support for cpuid standard and extended functions
> >
> > Signed-off-by: Jaswinder Singh Rajput <[email protected]>
> > ---
> > arch/x86/include/asm/cpu_debug.h | 4 ++-
> > arch/x86/kernel/cpu/cpu_debug.c | 64 ++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 64 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
> > index dc24338..377f658 100644
> > --- a/arch/x86/include/asm/cpu_debug.h
> > +++ b/arch/x86/include/asm/cpu_debug.h
> > @@ -46,11 +46,11 @@ enum cpu_debug_bit {
> > CPU_MMIO, /* Memory based IO */
> > CPU_DISPLAY, /* Display/VGA */
> > CPU_LINK, /* HyperTransport */
> > - CPU_CPUID, /* CPUID */
> > /* Standard Registers */
> > CPU_TSS, /* Task Stack Segment */
> > CPU_CR, /* Control Registers */
> > CPU_DT, /* Descriptor Table */
> > + CPU_CPUID, /* CPUID */
> > CPU_PCI, /* PCI configuration */
> > /* End of Registers flags */
> > CPU_REG_MAX, /* Max Registers flags */
> > @@ -75,6 +75,8 @@ enum cpu_cat_bit {
> > #define MAX_CPU_FILES 768 /* Max CPU debug files */
> > #define MAX_CPU_PCI 5 /* AMD supports func 0-4*/
> >
> > +#define CPUID_MASK 0xffff0000
> > +
> > struct cpu_private {
> > unsigned cpu;
> > unsigned type;
> > diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
> > index b4dfddd..f7f702e 100644
> > --- a/arch/x86/kernel/cpu/cpu_debug.c
> > +++ b/arch/x86/kernel/cpu/cpu_debug.c
> > @@ -72,10 +72,10 @@ static struct cpu_debug_base cpu_base[] = {
> > { "mmio", CPU_MMIO, 0 },
> > { "display", CPU_DISPLAY, 0 },
> > { "link", CPU_LINK, 0 },
> > - { "cpuid", CPU_CPUID, 0 },
> > { "tss", CPU_TSS, 0 },
> > { "cr", CPU_CR, 0 },
> > { "dt", CPU_DT, 0 },
> > + { "cpuid", CPU_CPUID, 0 },
> > { "pci", CPU_PCI, 0 },
> > { "registers", CPU_REG_ALL, 0 },
> > };
> > @@ -303,6 +303,13 @@ static struct cpu_debug_range cpu_amd_pci4[] = {
> > { 0x1E0, 0x1F0, CPU_POWER },
> > };
> >
> > +/* Extended CPUID base address */
> > +static u32 cpu_ext_cpuid[] = {
> > + 0x80000000, /* Intel, AMD */
> > + 0x80860000, /* Transmeta */
> > + 0xC0000000, /* Centaur */
> >
>
> VIA/Centaur has both 0xC0000000 and 0x8000000
>

hmm, then this patch will work for multiple extended cpuid levels :

[PATCH 9/10 -tip] x86: cpu_debug display cpuid functions

Add support for cpuid standard and extended functions

Signed-off-by: Jaswinder Singh Rajput <[email protected]>
---
arch/x86/include/asm/cpu_debug.h | 4 ++-
arch/x86/kernel/cpu/cpu_debug.c | 52 +++++++++++++++++++++++++++++++++++--
2 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/cpu_debug.h b/arch/x86/include/asm/cpu_debug.h
index dc24338..377f658 100644
--- a/arch/x86/include/asm/cpu_debug.h
+++ b/arch/x86/include/asm/cpu_debug.h
@@ -46,11 +46,11 @@ enum cpu_debug_bit {
CPU_MMIO, /* Memory based IO */
CPU_DISPLAY, /* Display/VGA */
CPU_LINK, /* HyperTransport */
- CPU_CPUID, /* CPUID */
/* Standard Registers */
CPU_TSS, /* Task Stack Segment */
CPU_CR, /* Control Registers */
CPU_DT, /* Descriptor Table */
+ CPU_CPUID, /* CPUID */
CPU_PCI, /* PCI configuration */
/* End of Registers flags */
CPU_REG_MAX, /* Max Registers flags */
@@ -75,6 +75,8 @@ enum cpu_cat_bit {
#define MAX_CPU_FILES 768 /* Max CPU debug files */
#define MAX_CPU_PCI 5 /* AMD supports func 0-4*/

+#define CPUID_MASK 0xffff0000
+
struct cpu_private {
unsigned cpu;
unsigned type;
diff --git a/arch/x86/kernel/cpu/cpu_debug.c b/arch/x86/kernel/cpu/cpu_debug.c
index b4dfddd..4d881a3 100644
--- a/arch/x86/kernel/cpu/cpu_debug.c
+++ b/arch/x86/kernel/cpu/cpu_debug.c
@@ -72,10 +72,10 @@ static struct cpu_debug_base cpu_base[] = {
{ "mmio", CPU_MMIO, 0 },
{ "display", CPU_DISPLAY, 0 },
{ "link", CPU_LINK, 0 },
- { "cpuid", CPU_CPUID, 0 },
{ "tss", CPU_TSS, 0 },
{ "cr", CPU_CR, 0 },
{ "dt", CPU_DT, 0 },
+ { "cpuid", CPU_CPUID, 0 },
{ "pci", CPU_PCI, 0 },
{ "registers", CPU_REG_ALL, 0 },
};
@@ -303,6 +303,13 @@ static struct cpu_debug_range cpu_amd_pci4[] = {
{ 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)
{
@@ -518,6 +525,37 @@ static void print_apic(void *arg)
#endif
}

+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 i, 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 */
+ 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])
+ print_cpuidabcd(seq, cpu_ext_cpuid[i], level);
+ }
+}
+
static void print_apicval(void *arg)
{
struct seq_file *seq = arg;
@@ -632,6 +670,14 @@ 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_PCI:
if (priv->file == CPU_INDEX)
smp_call_function_single(priv->cpu, print_pci, seq, 1);
@@ -814,7 +860,7 @@ static int cpu_init_regfiles(unsigned cpu, unsigned int type, unsigned reg,
unsigned file;
int err = 0;

- for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
+ for (file = 0; file < ARRAY_SIZE(cpu_file); file++) {
err = cpu_create_file(cpu, type, reg, file, cat, dentry);
if (err)
return err;
@@ -973,7 +1019,7 @@ static int cpu_init_allreg(unsigned cpu, struct dentry *dentry)
unsigned type;
int err = 0;

- for (type = 0; type < ARRAY_SIZE(cpu_base) - 1; type++) {
+ 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;

--
1.6.0.6


2009-06-13 22:34:45

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

On Sat, 13 Jun 2009, Jaswinder Singh Rajput wrote:

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

I really have to ask, why this is useful at all.

> 1. Standard Registers

What's the point of printing task_pt_regs(current) ?

We dump info of "cat debug/.../tss". Where is the value of this ? Just
because we can ?

> 2. Control Registers

I can see some value in dumping CR0 and CR4, but the rest is pretty useless

CR2 is the pagefault address, which is uninteresting as there is no
context

CR3 is the pagedir, which is pretty uninteresting as well. If we
read it on the current CPU we read the pagedir of "cat ..../cr3" and
if we read it on some other CPU its completely out of context. We
see a pagedir entry and have no information about the context.

CR8 is unused in Linux and always 0

> 3. Debug Registers

Again, where is the point? These registers are only interesting when
we know about the context. This interface just provides the access to
random information.

We already have debuggers which use that and they know the context
they are operating in.

> 4. Descriptor Tables

What's the value of pointers to IDT, GDT tables ? The interesting
information is in the tables, where IDT is static and uninteresting
though GDT table contents can change

Again, LDT and TR are task context dependent values. Where is the
information at which context we are looking ?

> 5. APIC Registers

Dunno, what we gain from that information.

> 6. Model specific Register (MSRs)

Where is the difference of poking in

/sys/kernel/debug/x86/cpu/cpu0/msr/MSR_c0010006/value

and

rdmsr,wrmsr poking on the same MSR ?

There is no difference at all. The information difference is
_ZERO_. The only difference is memory consumption in the kernel and a
even more horrible user interface than we have with mrs-tools.

7. PCI configuration registers (for AMD)

What's the value add over lspci ?

> 8. Basic cpuinfo

Why do we need another incarnation of /proc/cpuinfo ?

Also cpuid provides more useful decoded information than this.

> 9. CPUID Functions

Again, cpuid can do this already w/o a single line of kernel code.


Can we please get some coherent explanation why we need this in the
kernel?

Granted there are about 4 interesting registers where we have no
interface yet and where user space tools can not look into, but 99% of
the information exposed by this module is either useless or redundant
or both.

The worst stuff is the reinvention of exising and _useful_ userspace
tools. Just one example:

AMD specific PCI registers

Current solution:

Ask user to run lscpi -vvv and lspci -xxx[x] and provide the
output, which is for -vvv very well decoded and for -xxxx the same
raw data as we get from cpu_debug (except for the line count)

Single point of failure: lspci is not installed, which is unlikely,
but easy to solve and users/bugreporters usually know how to do
that. Worst case you have to tell him how to do it.

cpu_debug solution:

Ask user to compile the module, load the module, mount debugfs and
provide the output of debug/..... The output is a HEX dump of the
PCI configuration space and has no more information than the lscpi
-xxxx dump, indeed it has less:

lspci -xxxx tells me at which device it is looking in clear text
with a useful description while this tells me:

PCI configuration regsiters :
function : 0
000 : 13001022

So i need to look at the code to see at which pci config space this
is looking and what "function 0" is all about. How useful.

Multiple points of failure:
user can not compile the module
user fails to load the module
user fails to mount debugfs

Same applies for cpuid and msr access. This cpu_debug stuff is harder
to use and provides the same of mostly less information. What's the
gain ?


I'm a full supporter of _useful_ debug interfaces, but this is
definitely not what I call useful and useable.

The reinvention of useful tools like lspci, cpuid, rdmsr, wrmsr inside
of the kernel with a worse user interface and less information
provided is just a waste of time and resources.

Dumping random information out of any context is not helping us to
debug problems. There is no value to look at debug registers, context
registers and tss->regs without the context of the task we look at.

Can we please stop adding more random features to this?

This needs to be done the other way round. First we need to remove all
redundant and useless interfaces from cpu_debug and then think
carefully about in which way we want to expose the few really missing
interesting things either by extending existing user space tools or by
providing context aware and debug relevant interfaces in the kernel.

Thanks,

tglx

2009-06-14 05:43:01

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

On Sun, 2009-06-14 at 00:27 +0200, Thomas Gleixner wrote:
> On Sat, 13 Jun 2009, Jaswinder Singh Rajput wrote:
>
> > Please let me know how we can improve it and add more features so it
> > becomes more useful.
>
> I really have to ask, why this is useful at all.
>

Currently for X86 I can do :

1. read complete state (dump all registers like for MTRR, APIC)
2. read individual register
3. write to individual register
4. read/write these registers/info with shell through debugfs
5. read these registers/info before getting shell

And I did this for complete X86 CPU registers and info:
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

This will be really useful for :
1. developer who is porting/developing the kernel or drivers.
2. User who is reading hardware manual and want to see these value on
its CPU

Of course you need a Hardware manual to check address and detail
information. I do not want to keep detail for each register.

In X86 many tools are available which can read many registers but not
available for many architectures (I CCed some architecture maintainers
so that they can also specify issues they face when supporting new
CPU/architecture), they can also take advantage of it if we move
cpu_debug architecture independent portion outside X86.

I am not against of any tool but some issues about tools are :
1. Not supported for all architectures
2. Do not support latest or upcoming hardware
3. You need to mount filesystem and execute some shell to give commands
4. you need different tools to access different registers

So I want to know how can we can make cpu_debug more useful.


> The reinvention of useful tools like lspci, cpuid, rdmsr, wrmsr inside
> of the kernel with a worse user interface and less information
> provided is just a waste of time and resources.
>

what user interface and information you want ?

Thanks,
--
JSR

2009-06-14 11:20:18

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

Jaswinder,

[ I sanitized the cc list to restrict the annoyance to those who have
to deal with that. Please stop adding people who are not affected by
this. ]

On Sun, 14 Jun 2009, Jaswinder Singh Rajput wrote:

> On Sun, 2009-06-14 at 00:27 +0200, Thomas Gleixner wrote:
> > On Sat, 13 Jun 2009, Jaswinder Singh Rajput wrote:
> >
> > > Please let me know how we can improve it and add more features so it
> > > becomes more useful.
> >
> > I really have to ask, why this is useful at all.
> >
>
> Currently for X86 I can do :
>
> 1. read complete state (dump all registers like for MTRR, APIC)
> 2. read individual register
> 3. write to individual register
> 4. read/write these registers/info with shell through debugfs
> 5. read these registers/info before getting shell
>
> And I did this for complete X86 CPU registers and info:
> 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

I did not ask what it can do. I did ask what's the usefulness of
it. Your answer is the same list on which I commented on already in
technical detail, but you ignored those comments.

> This will be really useful for :
> 1. developer who is porting/developing the kernel or drivers.

We can access all this information already with existing tools.

> 2. User who is reading hardware manual and want to see these value on
> its CPU

Same here.

> Of course you need a Hardware manual to check address and detail
> information. I do not want to keep detail for each register.

That's why anyone with common sense will use lspci, cpuid to get the
information in both raw and decoded format.

> In X86 many tools are available which can read many registers but not
> available for many architectures (I CCed some architecture maintainers
> so that they can also specify issues they face when supporting new
> CPU/architecture), they can also take advantage of it if we move

I have ported Linux to a couple of new platforms and the problem you
face is that the kernel does not boot at all in the early stage of the
boot process.

How does cpu_debug help in that situation ? It does not help at all.

> cpu_debug architecture independent portion outside X86.

There is nothing x86 independent in cpu_debug.

> I am not against of any tool but some issues about tools are :
> 1. Not supported for all architectures

Again cpu_debug can not made generic as it is poking in architecture
specific hardware.

> 2. Do not support latest or upcoming hardware

All these tools show the raw values, which also covers latest hardware.

> 3. You need to mount filesystem and execute some shell to give commands

Are you saying that the access to your debugfs based cpu_debug
information does neither require a mounted file system nor a shell nor
commands? It provides the information by telepathy, right?

> 4. you need different tools to access different registers

Write a wrapper script if that annoys you.

> So I want to know how can we can make cpu_debug more useful.

I have not yet seen a single technical argument for what it is useful
at all.

So please stop hand waving about what it might do as long as you can
not provide a single technical reason why cpu_debug should be in the
kernel at all.

Go through the kernel.org bugzilla and show me _one_ single bug which
I debugged with the bug reporter, which could have been resolved
faster by using cpu_debug. And think careful about it before you
provide me that information.

> > The reinvention of useful tools like lspci, cpuid, rdmsr, wrmsr inside
> > of the kernel with a worse user interface and less information
> > provided is just a waste of time and resources.
> >
>
> what user interface and information you want ?

I'm happy to use the existing tools and their user interface. There is
no value of having inferior reimplementations of those tools in the
kernel.

Thanks,

tglx

2009-06-14 13:19:21

by Jaswinder Singh Rajput

[permalink] [raw]
Subject: Re: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

On Sun, 2009-06-14 at 13:19 +0200, Thomas Gleixner wrote:
> Jaswinder,
>
> [ I sanitized the cc list to restrict the annoyance to those who have
> to deal with that. Please stop adding people who are not affected by
> this. ]
>

I wrote cpu_debug because of past issues I faced working with Hitachi
and ARM processor. I just start working on X86 from last few months, I
wrote cpu_debug for X86 because currently I have only X86 machine, I am
planning to divide cpu_debug into architecture dependent and
non-dependent code so that other architectures can also benefit from it.

That's why I CCed other architecture's maintainers.


> > This will be really useful for :
> > 1. developer who is porting/developing the kernel or drivers.
>
> We can access all this information already with existing tools.
>

Why you are thinking about X86 ?

I worked on embedded processors more than 10 year, I never found any
tools, and sometimes we get the first lot of the boards.

Only tool which I used is printk.

Even though the code I used in cpu_debug I wrote that code to support :
1. Performance counters for AMD
2. Support Temperature sensor for AMD 11H

>
> > Of course you need a Hardware manual to check address and detail
> > information. I do not want to keep detail for each register.
>
> That's why anyone with common sense will use lspci, cpuid to get the
> information in both raw and decoded format.


These does not make sense if the kernel is not booting and filesystem is
not available.
To use the tools I need to build the tools, build filesystem for my
processor and load on filesystem.

>
> > In X86 many tools are available which can read many registers but not
> > available for many architectures (I CCed some architecture maintainers
> > so that they can also specify issues they face when supporting new
> > CPU/architecture), they can also take advantage of it if we move
>
> I have ported Linux to a couple of new platforms and the problem you
> face is that the kernel does not boot at all in the early stage of the
> boot process.
>
> How does cpu_debug help in that situation ? It does not help at all.
>

I supported functions if you pass seq = NULL then it will print on
screen, then you do need any filesystem or debugfs.

> > cpu_debug architecture independent portion outside X86.
>
> There is nothing x86 independent in cpu_debug.
>

There is, I will show you.

> > I am not against of any tool but some issues about tools are :
> > 1. Not supported for all architectures
>
> Again cpu_debug can not made generic as it is poking in architecture
> specific hardware.
>

Ok I will show you.

> > 2. Do not support latest or upcoming hardware
>
> All these tools show the raw values, which also covers latest hardware.
>

But when I used them they said processor not supported.

> > 3. You need to mount filesystem and execute some shell to give commands
>
> Are you saying that the access to your debugfs based cpu_debug
> information does neither require a mounted file system nor a shell nor
> commands? It provides the information by telepathy, right?
>

you can call the function, and pass seq as NULL, it will use printk and
dump state on screen. I just did this for MSR, I can also support for
other registers.

> > 4. you need different tools to access different registers
>
> Write a wrapper script if that annoys you.
>

when tools, filesystem and shell is not available where you will run
your script ?

> > So I want to know how can we can make cpu_debug more useful.
>
> I have not yet seen a single technical argument for what it is useful
> at all.
>

Because your eyes are closed, please open it.

Thanks,
--
JSR

2009-06-14 14:34:14

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC][GIT PULL][PATCH 0/10 -tip] cpu_debug patches 20090613

Jaswinder,

On Sun, 14 Jun 2009, Jaswinder Singh Rajput wrote:
> On Sun, 2009-06-14 at 13:19 +0200, Thomas Gleixner wrote:
> > > This will be really useful for :
> > > 1. developer who is porting/developing the kernel or drivers.
> >
> > We can access all this information already with existing tools.
> >
>
> Why you are thinking about X86 ?

Because I work on it and that code is in the area which I'm
responsible for. And I want useful code in that area, not something
which causes a lot of churn for no value at all.

> I worked on embedded processors more than 10 year, I never found any
> tools, and sometimes we get the first lot of the boards.

I have worked on ARM, MIPS, SH, PPC often enough and I never needed
such a tool.

> Only tool which I used is printk.

Which is perfectly fine to do low level debugging.

> Even though the code I used in cpu_debug I wrote that code to support :
> 1. Performance counters for AMD
> 2. Support Temperature sensor for AMD 11H

And you needed cpu_debug to do this ?

Sorry, I really do not understand that. Ingo and I wrote the inital
code of performance counters (both the generic parts and Intel
support) in a couple of days w/o feeling the need of cpu_debug even
once.

If you need cpu_debug for doing your work, fine. Maintain it somewhere
and figure out how many people come along and find it useful. But do
not impose this on the x86 code base.

> > > In X86 many tools are available which can read many registers but not
> > > available for many architectures (I CCed some architecture maintainers
> > > so that they can also specify issues they face when supporting new
> > > CPU/architecture), they can also take advantage of it if we move
> >
> > I have ported Linux to a couple of new platforms and the problem you
> > face is that the kernel does not boot at all in the early stage of the
> > boot process.
> >
> > How does cpu_debug help in that situation ? It does not help at all.
> >
> I supported functions if you pass seq = NULL then it will print on
> screen, then you do need any filesystem or debugfs.

Fine. And what is triggering the printout of a particular register ?

You need to hack the kernel to call the print functions in cpu_debug,
right ?

So where is the value of this? It is ad hoc debugging and there is no
gain to replace a printk(THE INFO I NEED) with a call to
cpu_debug().

Actually its worse. If I need the information of an APIC register,
then I print excaclty this register and not the whole lot of registers,
which then will scroll the screen with the important information
away.

Also I need information of a register in context with the content of
some variables of the code I'm debugging. printk() allows me to add
sensible and useful information in a compact format. cpu_debug does
not.

> > > 2. Do not support latest or upcoming hardware
> >
> > All these tools show the raw values, which also covers latest hardware.
> >
>
> But when I used them they said processor not supported.

And why didn't you get the source and fix it? Instead of improving an
existing tool you impose a ridicolous amount of useless code on x86.

> > > 3. You need to mount filesystem and execute some shell to give commands
> >
> > Are you saying that the access to your debugfs based cpu_debug
> > information does neither require a mounted file system nor a shell nor
> > commands? It provides the information by telepathy, right?
> >
>
> you can call the function, and pass seq as NULL, it will use printk and
> dump state on screen. I just did this for MSR, I can also support for
> other registers.

As I said above. There is no gain in doing so. Ad hoc debugging is the
same with printk and cpu_debug except that cpu_debug is inferior.

> > > So I want to know how can we can make cpu_debug more useful.
> >
> > I have not yet seen a single technical argument for what it is useful
> > at all.
> >
>
> Because your eyes are closed, please open it.

I have my eyes open and I looked at the existing code and the proposed
patches in detail. I also looked at your arguments which can be boiled
down to:

1) Jaswinder prefers to have cpu_debug_print_whatever() instead of
printk(THE INFO I NEED) for ad hoc debugging.

2) Jaswinder cannot work without cpu_debug.

Both are not really convincing technical arguments. cpu_debug has
_ZERO_ gain over printk() based debugging and it adds _ZERO_ value
with its debugfs based interface.

Thanks,

tglx

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

On Sun, Jun 14, 2009 at 12:27:42AM +0200, Thomas Gleixner wrote:
> On Sat, 13 Jun 2009, Jaswinder Singh Rajput wrote:
>
> > Please let me know how we can improve it and add more features so it
> > becomes more useful.

I second almost all of Thomas points. (The more I am wondering why
cpu_debug was merged at all.)

IMHO removing the cpuid, msr etc. stuff is the right thing to do.

But hey, I even can provide a "use case" for cpu_debug.

Recently I wanted to check some APIC registers. Instead of rebooting
the machine with apic=debug I loaded the module, mounted debugfs and
looked at the cpu_debug stuff to experience that ...

The registers that I was interested in were not provided.

So I had to add some code to print some of the regs in the extended
APIC register with apic=debug code. When submitting the patch
upstream I added the same regs to cpu_debug code. This really good
shows another weak point of cpu_debug:

If the kernel has already code for debugging output cpu_debug just
reinvents the wheel and does not even try to reuse existing code.

So in the end cpu_debug wasn't useful for me at all.

<snip>

> Dumping random information out of any context is not helping us to
> debug problems. There is no value to look at debug registers, context
> registers and tss->regs without the context of the task we look at.
>
> Can we please stop adding more random features to this?
>
> This needs to be done the other way round. First we need to remove all
> redundant and useless interfaces from cpu_debug and then think
> carefully about in which way we want to expose the few really missing
> interesting things either by extending existing user space tools or by
> providing context aware and debug relevant interfaces in the kernel.

IMHO the cpu_debug feature should be renamed to platform_debug and
then already existing kernel debug code could be modified such that it
can also be called from this new platform_debug facility. This would
allow to check certain things not only when booting Linux with certain
debug parameters but also on the fly when mounting the debugfs ...

The registers that come into my mind that would make some kind
of sense to provide with that interface are
- APIC stuff
- HPET stuff

Neither MSR, CPUID, CPU regs nor PCI config space stuff should be
added. Other facilities/tools exist for those (e.g. x86info,
msr-tools, pciutils or Magic SysRq).

... just my two cents.


Regards,

Andreas