summaryrefslogtreecommitdiff
path: root/Documentation/trace/coresight-cpu-debug.txt
blob: 2b9b51cd501e68aff9d65d5a5de3d5514dc416a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
		Coresight CPU Debug Module
		==========================

   Author:   Leo Yan <leo.yan@linaro.org>
   Date:     April 5th, 2017

Introduction
------------

Coresight CPU debug module is defined in ARMv8-a architecture reference manual
(ARM DDI 0487A.k) Chapter 'Part H: External debug', the CPU can integrate
debug module and it is mainly used for two modes: self-hosted debug and
external debug. Usually the external debug mode is well known as the external
debugger connects with SoC from JTAG port; on the other hand the program can
explore debugging method which rely on self-hosted debug mode, this document
is to focus on this part.

The debug module provides sample-based profiling extension, which can be used
to sample CPU program counter, secure state and exception level, etc; usually
every CPU has one dedicated debug module to be connected. Based on self-hosted
debug mechanism, Linux kernel can access these related registers from mmio
region when the kernel panic happens. The callback notifier for kernel panic
will dump related registers for every CPU; finally this is good for assistant
analysis for panic.


Implementation
--------------

- During driver registration, it uses EDDEVID and EDDEVID1 - two device ID
  registers to decide if sample-based profiling is implemented or not. On some
  platforms this hardware feature is fully or partially implemented; and if
  this feature is not supported then registration will fail.

- At the time this documentation was written, the debug driver mainly relies on
  information gathered by the kernel panic callback notifier from three
  sampling registers: EDPCSR, EDVIDSR and EDCIDSR: from EDPCSR we can get
  program counter; EDVIDSR has information for secure state, exception level,
  bit width, etc; EDCIDSR is context ID value which contains the sampled value
  of CONTEXTIDR_EL1.

- The driver supports a CPU running in either AArch64 or AArch32 mode. The
  registers naming convention is a bit different between them, AArch64 uses
  'ED' for register prefix (ARM DDI 0487A.k, chapter H9.1) and AArch32 uses
  'DBG' as prefix (ARM DDI 0487A.k, chapter G5.1). The driver is unified to
  use AArch64 naming convention.

- ARMv8-a (ARM DDI 0487A.k) and ARMv7-a (ARM DDI 0406C.b) have different
  register bits definition. So the driver consolidates two difference:

  If PCSROffset=0b0000, on ARMv8-a the feature of EDPCSR is not implemented;
  but ARMv7-a defines "PCSR samples are offset by a value that depends on the
  instruction set state". For ARMv7-a, the driver checks furthermore if CPU
  runs with ARM or thumb instruction set and calibrate PCSR value, the
  detailed description for offset is in ARMv7-a ARM (ARM DDI 0406C.b) chapter
  C11.11.34 "DBGPCSR, Program Counter Sampling Register".

  If PCSROffset=0b0010, ARMv8-a defines "EDPCSR implemented, and samples have
  no offset applied and do not sample the instruction set state in AArch32
  state". So on ARMv8 if EDDEVID1.PCSROffset is 0b0010 and the CPU operates
  in AArch32 state, EDPCSR is not sampled; when the CPU operates in AArch64
  state EDPCSR is sampled and no offset are applied.


Clock and power domain
----------------------

Before accessing debug registers, we should ensure the clock and power domain
have been enabled properly. In ARMv8-a ARM (ARM DDI 0487A.k) chapter 'H9.1
Debug registers', the debug registers are spread into two domains: the debug
domain and the CPU domain.

                                +---------------+
                                |               |
                                |               |
                     +----------+--+            |
        dbg_clock -->|          |**|            |<-- cpu_clock
                     |    Debug |**|   CPU      |
 dbg_power_domain -->|          |**|            |<-- cpu_power_domain
                     +----------+--+            |
                                |               |
                                |               |
                                +---------------+

For debug domain, the user uses DT binding "clocks" and "power-domains" to
specify the corresponding clock source and power supply for the debug logic.
The driver calls the pm_runtime_{put|get} operations as needed to handle the
debug power domain.

For CPU domain, the different SoC designs have different power management
schemes and finally this heavily impacts external debug module. So we can
divide into below cases:

- On systems with a sane power controller which can behave correctly with
  respect to CPU power domain, the CPU power domain can be controlled by
  register EDPRCR in driver. The driver firstly writes bit EDPRCR.COREPURQ
  to power up the CPU, and then writes bit EDPRCR.CORENPDRQ for emulation
  of CPU power down. As result, this can ensure the CPU power domain is
  powered on properly during the period when access debug related registers;

- Some designs will power down an entire cluster if all CPUs on the cluster
  are powered down - including the parts of the debug registers that should
  remain powered in the debug power domain. The bits in EDPRCR are not
  respected in these cases, so these designs do not support debug over
  power down in the way that the CoreSight / Debug designers anticipated.
  This means that even checking EDPRSR has the potential to cause a bus hang
  if the target register is unpowered.

  In this case, accessing to the debug registers while they are not powered
  is a recipe for disaster; so we need preventing CPU low power states at boot
  time or when user enable module at the run time. Please see chapter
  "How to use the module" for detailed usage info for this.


Device Tree Bindings
--------------------

See Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt for details.


How to use the module
---------------------

If you want to enable debugging functionality at boot time, you can add
"coresight_cpu_debug.enable=1" to the kernel command line parameter.

The driver also can work as module, so can enable the debugging when insmod
module:
# insmod coresight_cpu_debug.ko debug=1

When boot time or insmod module you have not enabled the debugging, the driver
uses the debugfs file system to provide a knob to dynamically enable or disable
debugging:

To enable it, write a '1' into /sys/kernel/debug/coresight_cpu_debug/enable:
# echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable

To disable it, write a '0' into /sys/kernel/debug/coresight_cpu_debug/enable:
# echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable

As explained in chapter "Clock and power domain", if you are working on one
platform which has idle states to power off debug logic and the power
controller cannot work well for the request from EDPRCR, then you should
firstly constraint CPU idle states before enable CPU debugging feature; so can
ensure the accessing to debug logic.

If you want to limit idle states at boot time, you can use "nohlt" or
"cpuidle.off=1" in the kernel command line.

At the runtime you can disable idle states with below methods:

It is possible to disable CPU idle states by way of the PM QoS
subsystem, more specifically by using the "/dev/cpu_dma_latency"
interface (see Documentation/power/pm_qos_interface.txt for more
details).  As specified in the PM QoS documentation the requested
parameter will stay in effect until the file descriptor is released.
For example:

# exec 3<> /dev/cpu_dma_latency; echo 0 >&3
...
Do some work...
...
# exec 3<>-

The same can also be done from an application program.

Disable specific CPU's specific idle state from cpuidle sysfs (see
Documentation/cpuidle/sysfs.txt):
# echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable


Output format
-------------

Here is an example of the debugging output format:

ARM external debug module:
coresight-cpu-debug 850000.debug: CPU[0]:
coresight-cpu-debug 850000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 850000.debug:  EDPCSR:  [<ffff00000808e9bc>] handle_IPI+0x174/0x1d8
coresight-cpu-debug 850000.debug:  EDCIDSR: 00000000
coresight-cpu-debug 850000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
coresight-cpu-debug 852000.debug: CPU[1]:
coresight-cpu-debug 852000.debug:  EDPRSR:  00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 852000.debug:  EDPCSR:  [<ffff0000087fab34>] debug_notifier_call+0x23c/0x358
coresight-cpu-debug 852000.debug:  EDCIDSR: 00000000
coresight-cpu-debug 852000.debug:  EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)