This patch set is to explore Coresight trace data for postmortem debugging. When kernel panic happens, the Coresight panic kdump can help save on-chip trace data and tracer metadata into DRAM, later relies on kdump and crash/perf for "offline" analysis.
The documentation is important to understand the purpose of Coresight panic kdump, the implementation and usage. Patches 0001/0002 are used to relocate and add related documenation.
Patch 0003 introduces the simple panic kdump framework which can be easily used by Coresight devices.
Patches 0004/0005 support panic kdump for ETB; Patch 0006 supports the dump for ETMv4. As Mathieu suggested, patch 0006 distinguish two different tracer enabling mode: sysFS interface and perf mode.
This patch set have been verified on 96boards Hikey with tracer enabling by sysFS interface.
Changes from v2: * Add the two patches for documentation. * Following Mathieu suggestion, reworked the panic kdump framework, removed the useless flag "PRE_PANIC". * According to comment, changed to add and delete kdump node operations in sink enable/disable functions; * According to Mathieu suggestion, handle kdump node addition/deletion/updating separately for sysFS interface and perf method.
Changes from v1: * Add support to dump ETMv4 meta data. * Wrote 'crash' extension csdump.so so rely on it to generate 'perf' format compatible file. * Refactored panic dump driver to support pre & post panic dump.
Changes from RFC: * Follow Mathieu's suggestion, use general framework to support dump functionality. * Changed to use perf to analyse trace data.
Leo Yan (6): doc: Add Coresight documentation directory doc: Add documentation for Coresight panic kdump coresight: Support panic kdump functionality coresight: tmc: Hook callback for panic kdump coresight: Add and delete sink callback for panic kdump list coresight: etm4x: Support panic kdump
Documentation/trace/coresight-cpu-debug.txt | 187 ------------ Documentation/trace/coresight.txt | 332 --------------------- .../trace/coresight/coresight-cpu-debug.txt | 187 ++++++++++++ .../trace/coresight/coresight-panic-kdump.txt | 91 ++++++ Documentation/trace/coresight/coresight.txt | 332 +++++++++++++++++++++ MAINTAINERS | 5 +- drivers/hwtracing/coresight/Kconfig | 9 + drivers/hwtracing/coresight/Makefile | 1 + drivers/hwtracing/coresight/coresight-etm-perf.c | 12 +- drivers/hwtracing/coresight/coresight-etm4x.c | 23 ++ drivers/hwtracing/coresight/coresight-etm4x.h | 15 + .../hwtracing/coresight/coresight-panic-kdump.c | 154 ++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 13 + drivers/hwtracing/coresight/coresight-tmc-etf.c | 29 ++ drivers/hwtracing/coresight/coresight.c | 12 + include/linux/coresight.h | 7 + 16 files changed, 887 insertions(+), 522 deletions(-) delete mode 100644 Documentation/trace/coresight-cpu-debug.txt delete mode 100644 Documentation/trace/coresight.txt create mode 100644 Documentation/trace/coresight/coresight-cpu-debug.txt create mode 100644 Documentation/trace/coresight/coresight-panic-kdump.txt create mode 100644 Documentation/trace/coresight/coresight.txt create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c
For easily management and friendly adding more Coresight related documentations, this commit creates one dedicated directory: Documentation/trace/coresight. It moves Coresight related docs into this new directory and updates MAINTAINERS file to reflect docs movement.
Signed-off-by: Leo Yan leo.yan@linaro.org --- Documentation/trace/coresight-cpu-debug.txt | 187 ------------ Documentation/trace/coresight.txt | 332 --------------------- .../trace/coresight/coresight-cpu-debug.txt | 187 ++++++++++++ Documentation/trace/coresight/coresight.txt | 332 +++++++++++++++++++++ MAINTAINERS | 4 +- 5 files changed, 521 insertions(+), 521 deletions(-) delete mode 100644 Documentation/trace/coresight-cpu-debug.txt delete mode 100644 Documentation/trace/coresight.txt create mode 100644 Documentation/trace/coresight/coresight-cpu-debug.txt create mode 100644 Documentation/trace/coresight/coresight.txt
diff --git a/Documentation/trace/coresight-cpu-debug.txt b/Documentation/trace/coresight-cpu-debug.txt deleted file mode 100644 index 2b9b51c..0000000 --- a/Documentation/trace/coresight-cpu-debug.txt +++ /dev/null @@ -1,187 +0,0 @@ - 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) diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt deleted file mode 100644 index a33c88c..0000000 --- a/Documentation/trace/coresight.txt +++ /dev/null @@ -1,332 +0,0 @@ - Coresight - HW Assisted Tracing on ARM - ====================================== - - Author: Mathieu Poirier mathieu.poirier@linaro.org - Date: September 11th, 2014 - -Introduction ------------- - -Coresight is an umbrella of technologies allowing for the debugging of ARM -based SoC. It includes solutions for JTAG and HW assisted tracing. This -document is concerned with the latter. - -HW assisted tracing is becoming increasingly useful when dealing with systems -that have many SoCs and other components like GPU and DMA engines. ARM has -developed a HW assisted tracing solution by means of different components, each -being added to a design at synthesis time to cater to specific tracing needs. -Components are generally categorised as source, link and sinks and are -(usually) discovered using the AMBA bus. - -"Sources" generate a compressed stream representing the processor instruction -path based on tracing scenarios as configured by users. From there the stream -flows through the coresight system (via ATB bus) using links that are connecting -the emanating source to a sink(s). Sinks serve as endpoints to the coresight -implementation, either storing the compressed stream in a memory buffer or -creating an interface to the outside world where data can be transferred to a -host without fear of filling up the onboard coresight memory buffer. - -At typical coresight system would look like this: - - ***************************************************************** - **************************** AMBA AXI ****************************===|| - ***************************************************************** || - ^ ^ | || - | | * ** - 0000000 ::::: 0000000 ::::: ::::: @@@@@@@ |||||||||||| - 0 CPU 0<-->: C : 0 CPU 0<-->: C : : C : @ STM @ || System || - |->0000000 : T : |->0000000 : T : : T :<--->@@@@@ || Memory || - | #######<-->: I : | #######<-->: I : : I : @@@<-| |||||||||||| - | # ETM # ::::: | # PTM # ::::: ::::: @ | - | ##### ^ ^ | ##### ^ ! ^ ! . | ||||||||| - | |->### | ! | |->### | ! | ! . | || DAP || - | | # | ! | | # | ! | ! . | ||||||||| - | | . | ! | | . | ! | ! . | | | - | | . | ! | | . | ! | ! . | | * - | | . | ! | | . | ! | ! . | | SWD/ - | | . | ! | | . | ! | ! . | | JTAG - *****************************************************************<-| - *************************** AMBA Debug APB ************************ - ***************************************************************** - | . ! . ! ! . | - | . * . * * . | - ***************************************************************** - ******************** Cross Trigger Matrix (CTM) ******************* - ***************************************************************** - | . ^ . . | - | * ! * * | - ***************************************************************** - ****************** AMBA Advanced Trace Bus (ATB) ****************** - ***************************************************************** - | ! =============== | - | * ===== F =====<---------| - | ::::::::: ==== U ==== - |-->:: CTI ::<!! === N === - | ::::::::: ! == N == - | ^ * == E == - | ! &&&&&&&&& IIIIIII == L == - |------>&& ETB &&<......II I ======= - | ! &&&&&&&&& II I . - | ! I I . - | ! I REP I<.......... - | ! I I - | !!>&&&&&&&&& II I *Source: ARM ltd. - |------>& TPIU &<......II I DAP = Debug Access Port - &&&&&&&&& IIIIIII ETM = Embedded Trace Macrocell - ; PTM = Program Trace Macrocell - ; CTI = Cross Trigger Interface - * ETB = Embedded Trace Buffer - To trace port TPIU= Trace Port Interface Unit - SWD = Serial Wire Debug - -While on target configuration of the components is done via the APB bus, -all trace data are carried out-of-band on the ATB bus. The CTM provides -a way to aggregate and distribute signals between CoreSight components. - -The coresight framework provides a central point to represent, configure and -manage coresight devices on a platform. This first implementation centers on -the basic tracing functionality, enabling components such ETM/PTM, funnel, -replicator, TMC, TPIU and ETB. Future work will enable more -intricate IP blocks such as STM and CTI. - - -Acronyms and Classification ---------------------------- - -Acronyms: - -PTM: Program Trace Macrocell -ETM: Embedded Trace Macrocell -STM: System trace Macrocell -ETB: Embedded Trace Buffer -ITM: Instrumentation Trace Macrocell -TPIU: Trace Port Interface Unit -TMC-ETR: Trace Memory Controller, configured as Embedded Trace Router -TMC-ETF: Trace Memory Controller, configured as Embedded Trace FIFO -CTI: Cross Trigger Interface - -Classification: - -Source: - ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM -Link: - Funnel, replicator (intelligent or not), TMC-ETR -Sinks: - ETBv1.0, ETB1.1, TPIU, TMC-ETF -Misc: - CTI - - -Device Tree Bindings ----------------------- - -See Documentation/devicetree/bindings/arm/coresight.txt for details. - -As of this writing drivers for ITM, STMs and CTIs are not provided but are -expected to be added as the solution matures. - - -Framework and implementation ----------------------------- - -The coresight framework provides a central point to represent, configure and -manage coresight devices on a platform. Any coresight compliant device can -register with the framework for as long as they use the right APIs: - -struct coresight_device *coresight_register(struct coresight_desc *desc); -void coresight_unregister(struct coresight_device *csdev); - -The registering function is taking a "struct coresight_device *csdev" and -register the device with the core framework. The unregister function takes -a reference to a "struct coresight_device", obtained at registration time. - -If everything goes well during the registration process the new devices will -show up under /sys/bus/coresight/devices, as showns here for a TC2 platform: - -root:~# ls /sys/bus/coresight/devices/ -replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm -20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm -root:~# - -The functions take a "struct coresight_device", which looks like this: - -struct coresight_desc { - enum coresight_dev_type type; - struct coresight_dev_subtype subtype; - const struct coresight_ops *ops; - struct coresight_platform_data *pdata; - struct device *dev; - const struct attribute_group **groups; -}; - - -The "coresight_dev_type" identifies what the device is, i.e, source link or -sink while the "coresight_dev_subtype" will characterise that type further. - -The "struct coresight_ops" is mandatory and will tell the framework how to -perform base operations related to the components, each component having -a different set of requirement. For that "struct coresight_ops_sink", -"struct coresight_ops_link" and "struct coresight_ops_source" have been -provided. - -The next field, "struct coresight_platform_data *pdata" is acquired by calling -"of_get_coresight_platform_data()", as part of the driver's _probe routine and -"struct device *dev" gets the device reference embedded in the "amba_device": - -static int etm_probe(struct amba_device *adev, const struct amba_id *id) -{ - ... - ... - drvdata->dev = &adev->dev; - ... -} - -Specific class of device (source, link, or sink) have generic operations -that can be performed on them (see "struct coresight_ops"). The -"**groups" is a list of sysfs entries pertaining to operations -specific to that component only. "Implementation defined" customisations are -expected to be accessed and controlled using those entries. - -Last but not least, "struct module *owner" is expected to be set to reflect -the information carried in "THIS_MODULE". - -How to use the tracer modules ------------------------------ - -Before trace collection can start, a coresight sink needs to be identify. -There is no limit on the amount of sinks (nor sources) that can be enabled at -any given moment. As a generic operation, all device pertaining to the sink -class will have an "active" entry in sysfs: - -root:/sys/bus/coresight/devices# ls -replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm -20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm -root:/sys/bus/coresight/devices# ls 20010000.etb -enable_sink status trigger_cntr -root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink -root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink -1 -root:/sys/bus/coresight/devices# - -At boot time the current etm3x driver will configure the first address -comparator with "_stext" and "_etext", essentially tracing any instruction -that falls within that range. As such "enabling" a source will immediately -trigger a trace capture: - -root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source -root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source -1 -root:/sys/bus/coresight/devices# cat 20010000.etb/status -Depth: 0x2000 -Status: 0x1 -RAM read ptr: 0x0 -RAM wrt ptr: 0x19d3 <----- The write pointer is moving -Trigger cnt: 0x0 -Control: 0x1 -Flush status: 0x0 -Flush ctrl: 0x2001 -root:/sys/bus/coresight/devices# - -Trace collection is stopped the same way: - -root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source -root:/sys/bus/coresight/devices# - -The content of the ETB buffer can be harvested directly from /dev: - -root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \ -of=~/cstrace.bin - -64+0 records in -64+0 records out -32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s -root:/sys/bus/coresight/devices# - -The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32. - -Following is a DS-5 output of an experimental loop that increments a variable up -to a certain value. The example is simple and yet provides a glimpse of the -wealth of possibilities that coresight provides. - -Info Tracing enabled -Instruction 106378866 0x8026B53C E52DE004 false PUSH {lr} -Instruction 0 0x8026B540 E24DD00C false SUB sp,sp,#0xc -Instruction 0 0x8026B544 E3A03000 false MOV r3,#0 -Instruction 0 0x8026B548 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Timestamp Timestamp: 17106715833 -Instruction 319 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 9 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 10 0x8026B54C E59D3004 false LDR r3,[sp,#4] -Instruction 0 0x8026B550 E3530004 false CMP r3,#4 -Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 -Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] -Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c -Instruction 6 0x8026B560 EE1D3F30 false MRC p15,#0x0,r3,c13,c0,#1 -Instruction 0 0x8026B564 E1A0100D false MOV r1,sp -Instruction 0 0x8026B568 E3C12D7F false BIC r2,r1,#0x1fc0 -Instruction 0 0x8026B56C E3C2203F false BIC r2,r2,#0x3f -Instruction 0 0x8026B570 E59D1004 false LDR r1,[sp,#4] -Instruction 0 0x8026B574 E59F0010 false LDR r0,[pc,#16] ; [0x8026B58C] = 0x80550368 -Instruction 0 0x8026B578 E592200C false LDR r2,[r2,#0xc] -Instruction 0 0x8026B57C E59221D0 false LDR r2,[r2,#0x1d0] -Instruction 0 0x8026B580 EB07A4CF true BL {pc}+0x1e9344 ; 0x804548c4 -Info Tracing enabled -Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc -Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} -Timestamp Timestamp: 17107041535 - -How to use the STM module -------------------------- - -Using the System Trace Macrocell module is the same as the tracers - the only -difference is that clients are driving the trace capture rather -than the program flow through the code. - -As with any other CoreSight component, specifics about the STM tracer can be -found in sysfs with more information on each entry being found in [1]: - -root@genericarmv8:~# ls /sys/bus/coresight/devices/20100000.stm -enable_source hwevent_select port_enable subsystem uevent -hwevent_enable mgmt port_select traceid -root@genericarmv8:~# - -Like any other source a sink needs to be identified and the STM enabled before -being used: - -root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20010000.etf/enable_sink -root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20100000.stm/enable_source - -From there user space applications can request and use channels using the devfs -interface provided for that purpose by the generic STM API: - -root@genericarmv8:~# ls -l /dev/20100000.stm -crw------- 1 root root 10, 61 Jan 3 18:11 /dev/20100000.stm -root@genericarmv8:~# - -Details on how to use the generic STM API can be found here [2]. - -[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm -[2]. Documentation/trace/stm.txt diff --git a/Documentation/trace/coresight/coresight-cpu-debug.txt b/Documentation/trace/coresight/coresight-cpu-debug.txt new file mode 100644 index 0000000..2b9b51c --- /dev/null +++ b/Documentation/trace/coresight/coresight-cpu-debug.txt @@ -0,0 +1,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) diff --git a/Documentation/trace/coresight/coresight.txt b/Documentation/trace/coresight/coresight.txt new file mode 100644 index 0000000..a33c88c --- /dev/null +++ b/Documentation/trace/coresight/coresight.txt @@ -0,0 +1,332 @@ + Coresight - HW Assisted Tracing on ARM + ====================================== + + Author: Mathieu Poirier mathieu.poirier@linaro.org + Date: September 11th, 2014 + +Introduction +------------ + +Coresight is an umbrella of technologies allowing for the debugging of ARM +based SoC. It includes solutions for JTAG and HW assisted tracing. This +document is concerned with the latter. + +HW assisted tracing is becoming increasingly useful when dealing with systems +that have many SoCs and other components like GPU and DMA engines. ARM has +developed a HW assisted tracing solution by means of different components, each +being added to a design at synthesis time to cater to specific tracing needs. +Components are generally categorised as source, link and sinks and are +(usually) discovered using the AMBA bus. + +"Sources" generate a compressed stream representing the processor instruction +path based on tracing scenarios as configured by users. From there the stream +flows through the coresight system (via ATB bus) using links that are connecting +the emanating source to a sink(s). Sinks serve as endpoints to the coresight +implementation, either storing the compressed stream in a memory buffer or +creating an interface to the outside world where data can be transferred to a +host without fear of filling up the onboard coresight memory buffer. + +At typical coresight system would look like this: + + ***************************************************************** + **************************** AMBA AXI ****************************===|| + ***************************************************************** || + ^ ^ | || + | | * ** + 0000000 ::::: 0000000 ::::: ::::: @@@@@@@ |||||||||||| + 0 CPU 0<-->: C : 0 CPU 0<-->: C : : C : @ STM @ || System || + |->0000000 : T : |->0000000 : T : : T :<--->@@@@@ || Memory || + | #######<-->: I : | #######<-->: I : : I : @@@<-| |||||||||||| + | # ETM # ::::: | # PTM # ::::: ::::: @ | + | ##### ^ ^ | ##### ^ ! ^ ! . | ||||||||| + | |->### | ! | |->### | ! | ! . | || DAP || + | | # | ! | | # | ! | ! . | ||||||||| + | | . | ! | | . | ! | ! . | | | + | | . | ! | | . | ! | ! . | | * + | | . | ! | | . | ! | ! . | | SWD/ + | | . | ! | | . | ! | ! . | | JTAG + *****************************************************************<-| + *************************** AMBA Debug APB ************************ + ***************************************************************** + | . ! . ! ! . | + | . * . * * . | + ***************************************************************** + ******************** Cross Trigger Matrix (CTM) ******************* + ***************************************************************** + | . ^ . . | + | * ! * * | + ***************************************************************** + ****************** AMBA Advanced Trace Bus (ATB) ****************** + ***************************************************************** + | ! =============== | + | * ===== F =====<---------| + | ::::::::: ==== U ==== + |-->:: CTI ::<!! === N === + | ::::::::: ! == N == + | ^ * == E == + | ! &&&&&&&&& IIIIIII == L == + |------>&& ETB &&<......II I ======= + | ! &&&&&&&&& II I . + | ! I I . + | ! I REP I<.......... + | ! I I + | !!>&&&&&&&&& II I *Source: ARM ltd. + |------>& TPIU &<......II I DAP = Debug Access Port + &&&&&&&&& IIIIIII ETM = Embedded Trace Macrocell + ; PTM = Program Trace Macrocell + ; CTI = Cross Trigger Interface + * ETB = Embedded Trace Buffer + To trace port TPIU= Trace Port Interface Unit + SWD = Serial Wire Debug + +While on target configuration of the components is done via the APB bus, +all trace data are carried out-of-band on the ATB bus. The CTM provides +a way to aggregate and distribute signals between CoreSight components. + +The coresight framework provides a central point to represent, configure and +manage coresight devices on a platform. This first implementation centers on +the basic tracing functionality, enabling components such ETM/PTM, funnel, +replicator, TMC, TPIU and ETB. Future work will enable more +intricate IP blocks such as STM and CTI. + + +Acronyms and Classification +--------------------------- + +Acronyms: + +PTM: Program Trace Macrocell +ETM: Embedded Trace Macrocell +STM: System trace Macrocell +ETB: Embedded Trace Buffer +ITM: Instrumentation Trace Macrocell +TPIU: Trace Port Interface Unit +TMC-ETR: Trace Memory Controller, configured as Embedded Trace Router +TMC-ETF: Trace Memory Controller, configured as Embedded Trace FIFO +CTI: Cross Trigger Interface + +Classification: + +Source: + ETMv3.x ETMv4, PTMv1.0, PTMv1.1, STM, STM500, ITM +Link: + Funnel, replicator (intelligent or not), TMC-ETR +Sinks: + ETBv1.0, ETB1.1, TPIU, TMC-ETF +Misc: + CTI + + +Device Tree Bindings +---------------------- + +See Documentation/devicetree/bindings/arm/coresight.txt for details. + +As of this writing drivers for ITM, STMs and CTIs are not provided but are +expected to be added as the solution matures. + + +Framework and implementation +---------------------------- + +The coresight framework provides a central point to represent, configure and +manage coresight devices on a platform. Any coresight compliant device can +register with the framework for as long as they use the right APIs: + +struct coresight_device *coresight_register(struct coresight_desc *desc); +void coresight_unregister(struct coresight_device *csdev); + +The registering function is taking a "struct coresight_device *csdev" and +register the device with the core framework. The unregister function takes +a reference to a "struct coresight_device", obtained at registration time. + +If everything goes well during the registration process the new devices will +show up under /sys/bus/coresight/devices, as showns here for a TC2 platform: + +root:~# ls /sys/bus/coresight/devices/ +replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm +20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm +root:~# + +The functions take a "struct coresight_device", which looks like this: + +struct coresight_desc { + enum coresight_dev_type type; + struct coresight_dev_subtype subtype; + const struct coresight_ops *ops; + struct coresight_platform_data *pdata; + struct device *dev; + const struct attribute_group **groups; +}; + + +The "coresight_dev_type" identifies what the device is, i.e, source link or +sink while the "coresight_dev_subtype" will characterise that type further. + +The "struct coresight_ops" is mandatory and will tell the framework how to +perform base operations related to the components, each component having +a different set of requirement. For that "struct coresight_ops_sink", +"struct coresight_ops_link" and "struct coresight_ops_source" have been +provided. + +The next field, "struct coresight_platform_data *pdata" is acquired by calling +"of_get_coresight_platform_data()", as part of the driver's _probe routine and +"struct device *dev" gets the device reference embedded in the "amba_device": + +static int etm_probe(struct amba_device *adev, const struct amba_id *id) +{ + ... + ... + drvdata->dev = &adev->dev; + ... +} + +Specific class of device (source, link, or sink) have generic operations +that can be performed on them (see "struct coresight_ops"). The +"**groups" is a list of sysfs entries pertaining to operations +specific to that component only. "Implementation defined" customisations are +expected to be accessed and controlled using those entries. + +Last but not least, "struct module *owner" is expected to be set to reflect +the information carried in "THIS_MODULE". + +How to use the tracer modules +----------------------------- + +Before trace collection can start, a coresight sink needs to be identify. +There is no limit on the amount of sinks (nor sources) that can be enabled at +any given moment. As a generic operation, all device pertaining to the sink +class will have an "active" entry in sysfs: + +root:/sys/bus/coresight/devices# ls +replicator 20030000.tpiu 2201c000.ptm 2203c000.etm 2203e000.etm +20010000.etb 20040000.funnel 2201d000.ptm 2203d000.etm +root:/sys/bus/coresight/devices# ls 20010000.etb +enable_sink status trigger_cntr +root:/sys/bus/coresight/devices# echo 1 > 20010000.etb/enable_sink +root:/sys/bus/coresight/devices# cat 20010000.etb/enable_sink +1 +root:/sys/bus/coresight/devices# + +At boot time the current etm3x driver will configure the first address +comparator with "_stext" and "_etext", essentially tracing any instruction +that falls within that range. As such "enabling" a source will immediately +trigger a trace capture: + +root:/sys/bus/coresight/devices# echo 1 > 2201c000.ptm/enable_source +root:/sys/bus/coresight/devices# cat 2201c000.ptm/enable_source +1 +root:/sys/bus/coresight/devices# cat 20010000.etb/status +Depth: 0x2000 +Status: 0x1 +RAM read ptr: 0x0 +RAM wrt ptr: 0x19d3 <----- The write pointer is moving +Trigger cnt: 0x0 +Control: 0x1 +Flush status: 0x0 +Flush ctrl: 0x2001 +root:/sys/bus/coresight/devices# + +Trace collection is stopped the same way: + +root:/sys/bus/coresight/devices# echo 0 > 2201c000.ptm/enable_source +root:/sys/bus/coresight/devices# + +The content of the ETB buffer can be harvested directly from /dev: + +root:/sys/bus/coresight/devices# dd if=/dev/20010000.etb \ +of=~/cstrace.bin + +64+0 records in +64+0 records out +32768 bytes (33 kB) copied, 0.00125258 s, 26.2 MB/s +root:/sys/bus/coresight/devices# + +The file cstrace.bin can be decompressed using "ptm2human", DS-5 or Trace32. + +Following is a DS-5 output of an experimental loop that increments a variable up +to a certain value. The example is simple and yet provides a glimpse of the +wealth of possibilities that coresight provides. + +Info Tracing enabled +Instruction 106378866 0x8026B53C E52DE004 false PUSH {lr} +Instruction 0 0x8026B540 E24DD00C false SUB sp,sp,#0xc +Instruction 0 0x8026B544 E3A03000 false MOV r3,#0 +Instruction 0 0x8026B548 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Timestamp Timestamp: 17106715833 +Instruction 319 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 9 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 7 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 10 0x8026B54C E59D3004 false LDR r3,[sp,#4] +Instruction 0 0x8026B550 E3530004 false CMP r3,#4 +Instruction 0 0x8026B554 E2833001 false ADD r3,r3,#1 +Instruction 0 0x8026B558 E58D3004 false STR r3,[sp,#4] +Instruction 0 0x8026B55C DAFFFFFA true BLE {pc}-0x10 ; 0x8026b54c +Instruction 6 0x8026B560 EE1D3F30 false MRC p15,#0x0,r3,c13,c0,#1 +Instruction 0 0x8026B564 E1A0100D false MOV r1,sp +Instruction 0 0x8026B568 E3C12D7F false BIC r2,r1,#0x1fc0 +Instruction 0 0x8026B56C E3C2203F false BIC r2,r2,#0x3f +Instruction 0 0x8026B570 E59D1004 false LDR r1,[sp,#4] +Instruction 0 0x8026B574 E59F0010 false LDR r0,[pc,#16] ; [0x8026B58C] = 0x80550368 +Instruction 0 0x8026B578 E592200C false LDR r2,[r2,#0xc] +Instruction 0 0x8026B57C E59221D0 false LDR r2,[r2,#0x1d0] +Instruction 0 0x8026B580 EB07A4CF true BL {pc}+0x1e9344 ; 0x804548c4 +Info Tracing enabled +Instruction 13570831 0x8026B584 E28DD00C false ADD sp,sp,#0xc +Instruction 0 0x8026B588 E8BD8000 true LDM sp!,{pc} +Timestamp Timestamp: 17107041535 + +How to use the STM module +------------------------- + +Using the System Trace Macrocell module is the same as the tracers - the only +difference is that clients are driving the trace capture rather +than the program flow through the code. + +As with any other CoreSight component, specifics about the STM tracer can be +found in sysfs with more information on each entry being found in [1]: + +root@genericarmv8:~# ls /sys/bus/coresight/devices/20100000.stm +enable_source hwevent_select port_enable subsystem uevent +hwevent_enable mgmt port_select traceid +root@genericarmv8:~# + +Like any other source a sink needs to be identified and the STM enabled before +being used: + +root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20010000.etf/enable_sink +root@genericarmv8:~# echo 1 > /sys/bus/coresight/devices/20100000.stm/enable_source + +From there user space applications can request and use channels using the devfs +interface provided for that purpose by the generic STM API: + +root@genericarmv8:~# ls -l /dev/20100000.stm +crw------- 1 root root 10, 61 Jan 3 18:11 /dev/20100000.stm +root@genericarmv8:~# + +Details on how to use the generic STM API can be found here [2]. + +[1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm +[2]. Documentation/trace/stm.txt diff --git a/MAINTAINERS b/MAINTAINERS index 4641719..d7a6fc7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1307,8 +1307,8 @@ M: Mathieu Poirier mathieu.poirier@linaro.org L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: drivers/hwtracing/coresight/* -F: Documentation/trace/coresight.txt -F: Documentation/trace/coresight-cpu-debug.txt +F: Documentation/trace/coresight/coresight.txt +F: Documentation/trace/coresight/coresight-cpu-debug.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
Add detailed documentation for Coresight panic kdump, which contains the idea for why need this and introduce the framework implementation and usage.
Signed-off-by: Leo Yan leo.yan@linaro.org --- .../trace/coresight/coresight-panic-kdump.txt | 91 ++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 92 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-panic-kdump.txt
diff --git a/Documentation/trace/coresight/coresight-panic-kdump.txt b/Documentation/trace/coresight/coresight-panic-kdump.txt new file mode 100644 index 0000000..6bf9cac --- /dev/null +++ b/Documentation/trace/coresight/coresight-panic-kdump.txt @@ -0,0 +1,91 @@ + Coresight Panic Kdump + ===================== + + Author: Leo Yan leo.yan@linaro.org + Date: Dec 21th, 2017 + +Introduction +------------ + +Coresight has different sinks for trace data, the trace data is quite useful +for postmortem debugging. Embedded Trace Buffer (ETB) is one type sink which +provides on-chip storage of trace data, usually uses SRAM as buffer with +several KBs size; if the SoC designs to support 'Local ETF' (ARM DDI 0461B, +chapter 1.2.7), every CPU has one local ETB buffer so the per CPU trace data +can avoid to be overwritted by other CPUs. Trace Memory Controller (TMC) is +another kind sink designed as a successor to the CoreSight ETB to capture trace +into DRAM. + +After Linux kernel trigger panic, the trace data keeps the last execution flow +before issues happen. We could consider the trace data is quite useful for +postmortem debugging, especially when we can record trace data into DRAM and rely +on kdump to save them into vmcore file; at the end we can retrieve trace data +from vmcore file and "offline" to analyze the execution flow. + + +Implementation +-------------- + +Coresight panic kdump is a simple framework to support dump functionality, +it maintains dump list with every node recording the dump buffer base address +and buffer size. Coresight panic kdump provides the general APIs +{coresight_kdump_add|coresight_kdump_del} as helper functions so any coresight +device can add itself into dump list or delete as needed. + +Generally coresight device set its 'panic_cb' in the ops structure, the panic +notifier iterates dump list and invokes callback function to dump device specific +info. + +For easily used by offline analysis, we also record tracer metadata so can +retrieve tracer IDs and configuration, in this case the node records CPU number so +can create connection between the metadata and specific CPU. The tracer +driver uses helper function coresight_kdump_update() to update the dump +buffer base address and buffer size; so the tracer can save metadata at runtime +and these info can be prepared well pre panic happening. + + +Usage +----- + +Build Linux kernel with enabling 'CONFIG_CORESIGHT_PANIC_KDUMP' configuration. + +After system booting up, we need firstly prepare dump-capture kernel, this can +refer doc [1] chapter 'Load the Dump-capture Kernel' for detailed steps. Then +we need enable the coresight tracer, this can use either perf framework method +or sysFS interface, please refer doc [2] chapter 'How to use the tracer modules' +for detailed steps. + +When kernel panic happens, the panic kdump records trace data and launches +dump-capture kernel, we can utilize the dump-capture kernel to save kernel dump +file, this can refer doc [1] chapter 'Write Out the Dump File'. + +After get kernel dump file, we can use 'crash' tool + csdump.so extension to +extract trace data and generate 'perf.data' file: + + ./crash vmcore vmlinux + crash> extend csdump.so + crash> csdump output_dir + + We can see in the 'output_dir' there will generate out three files: + output_dir/ + ├── cstrace.bin -> trace raw data + ├── metadata.bin -> meta data + └── perf.data -> 'perf' format compatible file + +Finally use 'perf' tool for offline analysis: + + ./perf script -v -F cpu,event,ip,sym,symoff -i perf.data -k vmlinux --kallsyms /proc/kallsyms + [001] instructions: ffff000008559ad0 pl011_console_write+0x90 + [001] instructions: ffff000008559230 pl011_read+0x0 + [001] instructions: ffff00000855924c pl011_read+0x1c + [001] instructions: ffff000008559ae0 pl011_console_write+0xa0 + [001] instructions: ffff000008559ad0 pl011_console_write+0x90 + [001] instructions: ffff000008559230 pl011_read+0x0 + [001] instructions: ffff00000855924c pl011_read+0x1c + [001] instructions: ffff000008559ae0 pl011_console_write+0xa0 + [001] instructions: ffff000008559ad0 pl011_console_write+0x90 + [001] instructions: ffff000008559230 pl011_read+0x0 + [001] instructions: ffff00000855924c pl011_read+0x1c + +[1] Documentation/kdump/kdump.txt +[2] Documentation/trace/coresight/coresight.txt diff --git a/MAINTAINERS b/MAINTAINERS index d7a6fc7..26276e0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1309,6 +1309,7 @@ S: Maintained F: drivers/hwtracing/coresight/* F: Documentation/trace/coresight/coresight.txt F: Documentation/trace/coresight/coresight-cpu-debug.txt +F: Documentation/trace/coresight/coresight-panic-kdump.txt F: Documentation/devicetree/bindings/arm/coresight.txt F: Documentation/devicetree/bindings/arm/coresight-cpu-debug.txt F: Documentation/ABI/testing/sysfs-bus-coresight-devices-*
After kernel panic happens, coresight has many useful info can be used for analysis. For example, the trace info from ETB RAM can be used to check the CPU execution flows before crash. So we can save the tracing data from sink devices, and rely on kdump to save DDR content and uses "crash" tool to extract coresight dumping from vmcore file.
This patch is to add a simple framework to support panic dump functionality; it registers panic notifier, and provide the general APIs {coresight_kdump_add|coresight_kdump_del} as helper functions so any coresight device can add itself into dump list or delete as needed.
This driver provides helper function coresight_kdump_update() to update the dump buffer base address and buffer size. This function can be used by coresight driver, e.g. it can be used to save ETM meta data info at runtime and these info can be prepared pre panic happening.
When kernel panic happens, the notifier iterates dump list and calls callback function to dump device specific info. The panic dump is mainly used to dump trace data so we can get to know the execution flow before the panic happens.
Signed-off-by: Leo Yan leo.yan@linaro.org --- drivers/hwtracing/coresight/Kconfig | 9 ++ drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-panic-kdump.c | 154 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 13 ++ include/linux/coresight.h | 7 + 5 files changed, 184 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ef9cb3c..4812529 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -103,4 +103,13 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage.
+config CORESIGHT_PANIC_KDUMP + bool "CoreSight Panic Kdump driver" + depends on ARM || ARM64 + help + This driver provides panic kdump functionality for CoreSight + devices. When a kernel panic happen a device supplied callback function + is used to save trace data to memory. From there we rely on kdump to extract + the trace data from kernel dump file. + endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 61db9dd..946fe19 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o +obj-$(CONFIG_CORESIGHT_PANIC_KDUMP) += coresight-panic-kdump.o diff --git a/drivers/hwtracing/coresight/coresight-panic-kdump.c b/drivers/hwtracing/coresight/coresight-panic-kdump.c new file mode 100644 index 0000000..c21d20b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-panic-kdump.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Linaro Limited. +#include <linux/coresight.h> +#include <linux/coresight-pmu.h> +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/perf_event.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "coresight-priv.h" + +typedef void (*coresight_cb_t)(void *data); + +/** + * struct coresight_kdump_node - Node information for dump + * @cpu: The cpu this node is affined to. + * @csdev: Handler for coresight device. + * @buf: Pointer for dump buffer. + * @buf_size: Length of dump buffer. + * @list: Hook to the list. + */ +struct coresight_kdump_node { + int cpu; + struct coresight_device *csdev; + char *buf; + unsigned int buf_size; + struct list_head list; +}; + +static DEFINE_SPINLOCK(coresight_kdump_lock); +static LIST_HEAD(coresight_kdump_list); +static struct notifier_block coresight_kdump_nb; + +int coresight_kdump_update(struct coresight_device *csdev, char *buf, + unsigned int buf_size) +{ + struct coresight_kdump_node *node = csdev->dump_node; + + if (!node) { + dev_err(&csdev->dev, "Failed to update dump node.\n"); + return -EINVAL; + } + + node->buf = buf; + node->buf_size = buf_size; + return 0; +} + +int coresight_kdump_add(struct coresight_device *csdev, int cpu) +{ + struct coresight_kdump_node *node; + unsigned long flags; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + csdev->dump_node = (void *)node; + node->cpu = cpu; + node->csdev = csdev; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + list_add_tail(&node->list, &coresight_kdump_list); + spin_unlock_irqrestore(&coresight_kdump_lock, flags); + return 0; +} + +void coresight_kdump_del(struct coresight_device *csdev) +{ + struct coresight_kdump_node *node, *next; + unsigned long flags; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + list_for_each_entry_safe(node, next, &coresight_kdump_list, list) { + if (node->csdev == csdev) { + list_del(&node->list); + kfree(node); + break; + } + } + spin_unlock_irqrestore(&coresight_kdump_lock, flags); +} + +static coresight_cb_t +coresight_kdump_get_cb(struct coresight_device *csdev) +{ + coresight_cb_t cb = NULL; + + switch (csdev->type) { + case CORESIGHT_DEV_TYPE_SINK: + case CORESIGHT_DEV_TYPE_LINKSINK: + cb = sink_ops(csdev)->panic_cb; + break; + case CORESIGHT_DEV_TYPE_SOURCE: + cb = source_ops(csdev)->panic_cb; + break; + case CORESIGHT_DEV_TYPE_LINK: + cb = link_ops(csdev)->panic_cb; + break; + default: + dev_info(&csdev->dev, "Unsupport panic dump\n"); + break; + } + + return cb; +} + +/** + * coresight_kdump_notify - Invoke panic dump callbacks, this is + * the main function to fulfill the panic dump. It distinguishs + * to two types: one is pre panic dump which the callback function + * handler is NULL and coresight drivers can use function + * coresight_kdump_update() to directly update dump buffer base + * address and buffer size, for this case this function does nothing + * and directly bail out; another case is for post panic dump so + * invoke callback on alive CPU. + * + * Returns: 0 on success. + */ +static int coresight_kdump_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + struct coresight_kdump_node *node; + struct coresight_device *csdev; + coresight_cb_t cb; + unsigned long flags; + + spin_lock_irqsave(&coresight_kdump_lock, flags); + + list_for_each_entry(node, &coresight_kdump_list, list) { + csdev = node->csdev; + cb = coresight_kdump_get_cb(csdev); + if (cb) + cb(csdev); + } + + spin_unlock_irqrestore(&coresight_kdump_lock, flags); + return 0; +} + +static int __init coresight_kdump_init(void) +{ + int ret; + + coresight_kdump_nb.notifier_call = coresight_kdump_notify; + ret = atomic_notifier_chain_register(&panic_notifier_list, + &coresight_kdump_nb); + return ret; +} +late_initcall(coresight_kdump_init); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d..937750e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -151,4 +151,17 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif
+#ifdef CONFIG_CORESIGHT_PANIC_KDUMP +extern int coresight_kdump_add(struct coresight_device *csdev, int cpu); +extern void coresight_kdump_del(struct coresight_device *csdev); +extern int coresight_kdump_update(struct coresight_device *csdev, + char *buf, unsigned int buf_size); +#else +static inline int +coresight_kdump_add(struct coresight_device *csdev, int cpu) { return 0; } +static inline void coresight_kdump_del(struct coresight_device *csdev) {} +static inline int coresight_kdump_update(struct coresight_device *csdev, + char *buf, unsigned int buf_size) { return 0; } +#endif + #endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad..43e40fa 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -171,6 +171,7 @@ struct coresight_device { bool orphan; bool enable; /* true only if configured as part of a path */ bool activated; /* true only if a sink is part of a path */ + void *dump_node; };
#define to_coresight_device(d) container_of(d, struct coresight_device, dev) @@ -189,6 +190,7 @@ struct coresight_device { * @set_buffer: initialises buffer mechanic before a trace session. * @reset_buffer: finalises buffer mechanic after a trace session. * @update_buffer: update buffer pointers after a trace session. + * @panic_cb: hook function for panic notifier. */ struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); @@ -205,6 +207,7 @@ struct coresight_ops_sink { void (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); + void (*panic_cb)(void *data); };
/** @@ -212,10 +215,12 @@ struct coresight_ops_sink { * Operations available for links. * @enable: enables flow between iport and oport. * @disable: disables flow between iport and oport. + * @panic_cb: hook function for panic notifier. */ struct coresight_ops_link { int (*enable)(struct coresight_device *csdev, int iport, int oport); void (*disable)(struct coresight_device *csdev, int iport, int oport); + void (*panic_cb)(void *data); };
/** @@ -227,6 +232,7 @@ struct coresight_ops_link { * to the HW. * @enable: enables tracing for a source. * @disable: disables tracing for a source. + * @panic_cb: hook function for panic notifier. */ struct coresight_ops_source { int (*cpu_id)(struct coresight_device *csdev); @@ -235,6 +241,7 @@ struct coresight_ops_source { struct perf_event *event, u32 mode); void (*disable)(struct coresight_device *csdev, struct perf_event *event); + void (*panic_cb)(void *data); };
struct coresight_ops {
On Thu, Dec 21, 2017 at 04:20:12PM +0800, Leo Yan wrote:
After kernel panic happens, coresight has many useful info can be used for analysis. For example, the trace info from ETB RAM can be used to check the CPU execution flows before crash. So we can save the tracing data from sink devices, and rely on kdump to save DDR content and uses "crash" tool to extract coresight dumping from vmcore file.
This patch is to add a simple framework to support panic dump functionality; it registers panic notifier, and provide the general APIs {coresight_kdump_add|coresight_kdump_del} as helper functions so any coresight device can add itself into dump list or delete as needed.
This driver provides helper function coresight_kdump_update() to update the dump buffer base address and buffer size. This function can be used by coresight driver, e.g. it can be used to save ETM meta data info at runtime and these info can be prepared pre panic happening.
When kernel panic happens, the notifier iterates dump list and calls callback function to dump device specific info. The panic dump is mainly used to dump trace data so we can get to know the execution flow before the panic happens.
Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/Kconfig | 9 ++ drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-panic-kdump.c | 154 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 13 ++ include/linux/coresight.h | 7 + 5 files changed, 184 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ef9cb3c..4812529 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -103,4 +103,13 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage. +config CORESIGHT_PANIC_KDUMP
- bool "CoreSight Panic Kdump driver"
- depends on ARM || ARM64
At this time only ETMv4 supports the feature, so it is only ARM64.
- help
This driver provides panic kdump functionality for CoreSight
devices. When a kernel panic happen a device supplied callback function
is used to save trace data to memory. From there we rely on kdump to extract
the trace data from kernel dump file.
endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 61db9dd..946fe19 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o +obj-$(CONFIG_CORESIGHT_PANIC_KDUMP) += coresight-panic-kdump.o diff --git a/drivers/hwtracing/coresight/coresight-panic-kdump.c b/drivers/hwtracing/coresight/coresight-panic-kdump.c new file mode 100644 index 0000000..c21d20b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-panic-kdump.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Linaro Limited. +#include <linux/coresight.h> +#include <linux/coresight-pmu.h> +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/perf_event.h> +#include <linux/slab.h> +#include <linux/types.h>
+#include "coresight-priv.h"
+typedef void (*coresight_cb_t)(void *data);
+/**
- struct coresight_kdump_node - Node information for dump
- @cpu: The cpu this node is affined to.
- @csdev: Handler for coresight device.
- @buf: Pointer for dump buffer.
- @buf_size: Length of dump buffer.
- @list: Hook to the list.
- */
+struct coresight_kdump_node {
- int cpu;
- struct coresight_device *csdev;
- char *buf;
- unsigned int buf_size;
- struct list_head list;
+};
+static DEFINE_SPINLOCK(coresight_kdump_lock); +static LIST_HEAD(coresight_kdump_list); +static struct notifier_block coresight_kdump_nb;
+int coresight_kdump_update(struct coresight_device *csdev, char *buf,
unsigned int buf_size)
+{
- struct coresight_kdump_node *node = csdev->dump_node;
- if (!node) {
dev_err(&csdev->dev, "Failed to update dump node.\n");
return -EINVAL;
- }
- node->buf = buf;
- node->buf_size = buf_size;
- return 0;
+}
+int coresight_kdump_add(struct coresight_device *csdev, int cpu) +{
- struct coresight_kdump_node *node;
- unsigned long flags;
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node)
return -ENOMEM;
- csdev->dump_node = (void *)node;
- node->cpu = cpu;
- node->csdev = csdev;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_add_tail(&node->list, &coresight_kdump_list);
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+void coresight_kdump_del(struct coresight_device *csdev) +{
- struct coresight_kdump_node *node, *next;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry_safe(node, next, &coresight_kdump_list, list) {
if (node->csdev == csdev) {
list_del(&node->list);
kfree(node);
break;
}
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
+}
+static coresight_cb_t +coresight_kdump_get_cb(struct coresight_device *csdev) +{
- coresight_cb_t cb = NULL;
- switch (csdev->type) {
- case CORESIGHT_DEV_TYPE_SINK:
- case CORESIGHT_DEV_TYPE_LINKSINK:
cb = sink_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_SOURCE:
cb = source_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_LINK:
cb = link_ops(csdev)->panic_cb;
break;
I don't see why we need a callback for link devices - didn't I raised that question before?
And I've been thinking further about this. The way we call the panic callbacks won't work. When a panic is triggered there might be trace data in the CS network that hasn't made it to the sink yet and calling the panic callbacks for sinks will lead to a loss of data.
That is why, when accessing from both sysFS and perf, the current implementation takes great care to stop the tracers first and then deal with the sink. To fix this I suggest to call the panic callbacks only for sources. What happens there will depend on what interface is used (sysFS or perf) - look at what is currently done to get a better understanding.
- default:
dev_info(&csdev->dev, "Unsupport panic dump\n");
I would not bother with the dev_info()...
break;
- }
- return cb;
+}
+/**
- coresight_kdump_notify - Invoke panic dump callbacks, this is
- the main function to fulfill the panic dump. It distinguishs
- to two types: one is pre panic dump which the callback function
- handler is NULL and coresight drivers can use function
- coresight_kdump_update() to directly update dump buffer base
- address and buffer size, for this case this function does nothing
- and directly bail out; another case is for post panic dump so
- invoke callback on alive CPU.
Now that pre and post processing are gone the description above doesn't match what the function is doing.
- Returns: 0 on success.
- */
+static int coresight_kdump_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
+{
- struct coresight_kdump_node *node;
- struct coresight_device *csdev;
- coresight_cb_t cb;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry(node, &coresight_kdump_list, list) {
csdev = node->csdev;
cb = coresight_kdump_get_cb(csdev);
if (cb)
cb(csdev);
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+static int __init coresight_kdump_init(void) +{
- int ret;
- coresight_kdump_nb.notifier_call = coresight_kdump_notify;
- ret = atomic_notifier_chain_register(&panic_notifier_list,
&coresight_kdump_nb);
- return ret;
+} +late_initcall(coresight_kdump_init); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d..937750e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -151,4 +151,17 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_PANIC_KDUMP +extern int coresight_kdump_add(struct coresight_device *csdev, int cpu); +extern void coresight_kdump_del(struct coresight_device *csdev); +extern int coresight_kdump_update(struct coresight_device *csdev,
char *buf, unsigned int buf_size);
+#else +static inline int +coresight_kdump_add(struct coresight_device *csdev, int cpu) { return 0; } +static inline void coresight_kdump_del(struct coresight_device *csdev) {} +static inline int coresight_kdump_update(struct coresight_device *csdev,
- char *buf, unsigned int buf_size) { return 0; }
static inline int coresight_kdump_update(struct coresight_device *csdev, char *buf, unsigned int buf_size) { return 0; }
+#endif
#endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad..43e40fa 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -171,6 +171,7 @@ struct coresight_device { bool orphan; bool enable; /* true only if configured as part of a path */ bool activated; /* true only if a sink is part of a path */
- void *dump_node;
Please add a description for this entry.
}; #define to_coresight_device(d) container_of(d, struct coresight_device, dev) @@ -189,6 +190,7 @@ struct coresight_device {
- @set_buffer: initialises buffer mechanic before a trace session.
- @reset_buffer: finalises buffer mechanic after a trace session.
- @update_buffer: update buffer pointers after a trace session.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); @@ -205,6 +207,7 @@ struct coresight_ops_sink { void (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config);
- void (*panic_cb)(void *data);
}; /** @@ -212,10 +215,12 @@ struct coresight_ops_sink {
- Operations available for links.
- @enable: enables flow between iport and oport.
- @disable: disables flow between iport and oport.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_link { int (*enable)(struct coresight_device *csdev, int iport, int oport); void (*disable)(struct coresight_device *csdev, int iport, int oport);
- void (*panic_cb)(void *data);
}; /** @@ -227,6 +232,7 @@ struct coresight_ops_link {
to the HW.
- @enable: enables tracing for a source.
- @disable: disables tracing for a source.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_source { int (*cpu_id)(struct coresight_device *csdev); @@ -235,6 +241,7 @@ struct coresight_ops_source { struct perf_event *event, u32 mode); void (*disable)(struct coresight_device *csdev, struct perf_event *event);
- void (*panic_cb)(void *data);
}; struct coresight_ops { -- 2.7.4
On Tue, Jan 09, 2018 at 11:41:26AM -0700, Mathieu Poirier wrote:
On Thu, Dec 21, 2017 at 04:20:12PM +0800, Leo Yan wrote:
After kernel panic happens, coresight has many useful info can be used for analysis. For example, the trace info from ETB RAM can be used to check the CPU execution flows before crash. So we can save the tracing data from sink devices, and rely on kdump to save DDR content and uses "crash" tool to extract coresight dumping from vmcore file.
This patch is to add a simple framework to support panic dump functionality; it registers panic notifier, and provide the general APIs {coresight_kdump_add|coresight_kdump_del} as helper functions so any coresight device can add itself into dump list or delete as needed.
This driver provides helper function coresight_kdump_update() to update the dump buffer base address and buffer size. This function can be used by coresight driver, e.g. it can be used to save ETM meta data info at runtime and these info can be prepared pre panic happening.
When kernel panic happens, the notifier iterates dump list and calls callback function to dump device specific info. The panic dump is mainly used to dump trace data so we can get to know the execution flow before the panic happens.
Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/Kconfig | 9 ++ drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-panic-kdump.c | 154 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 13 ++ include/linux/coresight.h | 7 + 5 files changed, 184 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ef9cb3c..4812529 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -103,4 +103,13 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage. +config CORESIGHT_PANIC_KDUMP
- bool "CoreSight Panic Kdump driver"
- depends on ARM || ARM64
At this time only ETMv4 supports the feature, so it is only ARM64.
Thanks for reviewing, Mathieu.
Will change to only for ARM64.
- help
This driver provides panic kdump functionality for CoreSight
devices. When a kernel panic happen a device supplied callback function
is used to save trace data to memory. From there we rely on kdump to extract
the trace data from kernel dump file.
endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 61db9dd..946fe19 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o +obj-$(CONFIG_CORESIGHT_PANIC_KDUMP) += coresight-panic-kdump.o diff --git a/drivers/hwtracing/coresight/coresight-panic-kdump.c b/drivers/hwtracing/coresight/coresight-panic-kdump.c new file mode 100644 index 0000000..c21d20b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-panic-kdump.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Linaro Limited. +#include <linux/coresight.h> +#include <linux/coresight-pmu.h> +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/perf_event.h> +#include <linux/slab.h> +#include <linux/types.h>
+#include "coresight-priv.h"
+typedef void (*coresight_cb_t)(void *data);
+/**
- struct coresight_kdump_node - Node information for dump
- @cpu: The cpu this node is affined to.
- @csdev: Handler for coresight device.
- @buf: Pointer for dump buffer.
- @buf_size: Length of dump buffer.
- @list: Hook to the list.
- */
+struct coresight_kdump_node {
- int cpu;
- struct coresight_device *csdev;
- char *buf;
- unsigned int buf_size;
- struct list_head list;
+};
+static DEFINE_SPINLOCK(coresight_kdump_lock); +static LIST_HEAD(coresight_kdump_list); +static struct notifier_block coresight_kdump_nb;
+int coresight_kdump_update(struct coresight_device *csdev, char *buf,
unsigned int buf_size)
+{
- struct coresight_kdump_node *node = csdev->dump_node;
- if (!node) {
dev_err(&csdev->dev, "Failed to update dump node.\n");
return -EINVAL;
- }
- node->buf = buf;
- node->buf_size = buf_size;
- return 0;
+}
+int coresight_kdump_add(struct coresight_device *csdev, int cpu) +{
- struct coresight_kdump_node *node;
- unsigned long flags;
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node)
return -ENOMEM;
- csdev->dump_node = (void *)node;
- node->cpu = cpu;
- node->csdev = csdev;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_add_tail(&node->list, &coresight_kdump_list);
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+void coresight_kdump_del(struct coresight_device *csdev) +{
- struct coresight_kdump_node *node, *next;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry_safe(node, next, &coresight_kdump_list, list) {
if (node->csdev == csdev) {
list_del(&node->list);
kfree(node);
break;
}
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
+}
+static coresight_cb_t +coresight_kdump_get_cb(struct coresight_device *csdev) +{
- coresight_cb_t cb = NULL;
- switch (csdev->type) {
- case CORESIGHT_DEV_TYPE_SINK:
- case CORESIGHT_DEV_TYPE_LINKSINK:
cb = sink_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_SOURCE:
cb = source_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_LINK:
cb = link_ops(csdev)->panic_cb;
break;
I don't see why we need a callback for link devices - didn't I raised that question before?
Yes, sorry I have not deleted for link devices completely. Will remove it.
And I've been thinking further about this. The way we call the panic callbacks won't work. When a panic is triggered there might be trace data in the CS network that hasn't made it to the sink yet and calling the panic callbacks for sinks will lead to a loss of data.
That is why, when accessing from both sysFS and perf, the current implementation takes great care to stop the tracers first and then deal with the sink. To fix this I suggest to call the panic callbacks only for sources. What happens there will depend on what interface is used (sysFS or perf) - look at what is currently done to get a better understanding.
Will look into this.
If I understand correctly, we need firstly stop tracers and save trace data from sink, right? If so we need use single callback function to disable path and dump data for sink, will study current case and check what's the clean method for kdump.
- default:
dev_info(&csdev->dev, "Unsupport panic dump\n");
I would not bother with the dev_info()...
Will remove it.
break;
- }
- return cb;
+}
+/**
- coresight_kdump_notify - Invoke panic dump callbacks, this is
- the main function to fulfill the panic dump. It distinguishs
- to two types: one is pre panic dump which the callback function
- handler is NULL and coresight drivers can use function
- coresight_kdump_update() to directly update dump buffer base
- address and buffer size, for this case this function does nothing
- and directly bail out; another case is for post panic dump so
- invoke callback on alive CPU.
Now that pre and post processing are gone the description above doesn't match what the function is doing.
Yeah, will remove 'pre' and 'post' to avoid confusion.
- Returns: 0 on success.
- */
+static int coresight_kdump_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
+{
- struct coresight_kdump_node *node;
- struct coresight_device *csdev;
- coresight_cb_t cb;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry(node, &coresight_kdump_list, list) {
csdev = node->csdev;
cb = coresight_kdump_get_cb(csdev);
if (cb)
cb(csdev);
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+static int __init coresight_kdump_init(void) +{
- int ret;
- coresight_kdump_nb.notifier_call = coresight_kdump_notify;
- ret = atomic_notifier_chain_register(&panic_notifier_list,
&coresight_kdump_nb);
- return ret;
+} +late_initcall(coresight_kdump_init); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d..937750e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -151,4 +151,17 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif +#ifdef CONFIG_CORESIGHT_PANIC_KDUMP +extern int coresight_kdump_add(struct coresight_device *csdev, int cpu); +extern void coresight_kdump_del(struct coresight_device *csdev); +extern int coresight_kdump_update(struct coresight_device *csdev,
char *buf, unsigned int buf_size);
+#else +static inline int +coresight_kdump_add(struct coresight_device *csdev, int cpu) { return 0; } +static inline void coresight_kdump_del(struct coresight_device *csdev) {} +static inline int coresight_kdump_update(struct coresight_device *csdev,
- char *buf, unsigned int buf_size) { return 0; }
static inline int coresight_kdump_update(struct coresight_device *csdev, char *buf, unsigned int buf_size) { return 0; }
Will fix.
+#endif
#endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad..43e40fa 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -171,6 +171,7 @@ struct coresight_device { bool orphan; bool enable; /* true only if configured as part of a path */ bool activated; /* true only if a sink is part of a path */
- void *dump_node;
Please add a description for this entry.
Will do.
Thanks, Leo Yan
}; #define to_coresight_device(d) container_of(d, struct coresight_device, dev) @@ -189,6 +190,7 @@ struct coresight_device {
- @set_buffer: initialises buffer mechanic before a trace session.
- @reset_buffer: finalises buffer mechanic after a trace session.
- @update_buffer: update buffer pointers after a trace session.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); @@ -205,6 +207,7 @@ struct coresight_ops_sink { void (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config);
- void (*panic_cb)(void *data);
}; /** @@ -212,10 +215,12 @@ struct coresight_ops_sink {
- Operations available for links.
- @enable: enables flow between iport and oport.
- @disable: disables flow between iport and oport.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_link { int (*enable)(struct coresight_device *csdev, int iport, int oport); void (*disable)(struct coresight_device *csdev, int iport, int oport);
- void (*panic_cb)(void *data);
}; /** @@ -227,6 +232,7 @@ struct coresight_ops_link {
to the HW.
- @enable: enables tracing for a source.
- @disable: disables tracing for a source.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_source { int (*cpu_id)(struct coresight_device *csdev); @@ -235,6 +241,7 @@ struct coresight_ops_source { struct perf_event *event, u32 mode); void (*disable)(struct coresight_device *csdev, struct perf_event *event);
- void (*panic_cb)(void *data);
}; struct coresight_ops { -- 2.7.4
On 9 January 2018 at 22:19, Leo Yan leo.yan@linaro.org wrote:
On Tue, Jan 09, 2018 at 11:41:26AM -0700, Mathieu Poirier wrote:
On Thu, Dec 21, 2017 at 04:20:12PM +0800, Leo Yan wrote:
After kernel panic happens, coresight has many useful info can be used for analysis. For example, the trace info from ETB RAM can be used to check the CPU execution flows before crash. So we can save the tracing data from sink devices, and rely on kdump to save DDR content and uses "crash" tool to extract coresight dumping from vmcore file.
This patch is to add a simple framework to support panic dump functionality; it registers panic notifier, and provide the general APIs {coresight_kdump_add|coresight_kdump_del} as helper functions so any coresight device can add itself into dump list or delete as needed.
This driver provides helper function coresight_kdump_update() to update the dump buffer base address and buffer size. This function can be used by coresight driver, e.g. it can be used to save ETM meta data info at runtime and these info can be prepared pre panic happening.
When kernel panic happens, the notifier iterates dump list and calls callback function to dump device specific info. The panic dump is mainly used to dump trace data so we can get to know the execution flow before the panic happens.
Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/Kconfig | 9 ++ drivers/hwtracing/coresight/Makefile | 1 + .../hwtracing/coresight/coresight-panic-kdump.c | 154 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-priv.h | 13 ++ include/linux/coresight.h | 7 + 5 files changed, 184 insertions(+) create mode 100644 drivers/hwtracing/coresight/coresight-panic-kdump.c
diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index ef9cb3c..4812529 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -103,4 +103,13 @@ config CORESIGHT_CPU_DEBUG properly, please refer Documentation/trace/coresight-cpu-debug.txt for detailed description and the example for usage.
+config CORESIGHT_PANIC_KDUMP
- bool "CoreSight Panic Kdump driver"
- depends on ARM || ARM64
At this time only ETMv4 supports the feature, so it is only ARM64.
Thanks for reviewing, Mathieu.
Will change to only for ARM64.
- help
This driver provides panic kdump functionality for CoreSight
devices. When a kernel panic happen a device supplied callback function
is used to save trace data to memory. From there we rely on kdump to extract
the trace data from kernel dump file.
endif diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 61db9dd..946fe19 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o +obj-$(CONFIG_CORESIGHT_PANIC_KDUMP) += coresight-panic-kdump.o diff --git a/drivers/hwtracing/coresight/coresight-panic-kdump.c b/drivers/hwtracing/coresight/coresight-panic-kdump.c new file mode 100644 index 0000000..c21d20b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-panic-kdump.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Linaro Limited. +#include <linux/coresight.h> +#include <linux/coresight-pmu.h> +#include <linux/cpumask.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mm.h> +#include <linux/perf_event.h> +#include <linux/slab.h> +#include <linux/types.h>
+#include "coresight-priv.h"
+typedef void (*coresight_cb_t)(void *data);
+/**
- struct coresight_kdump_node - Node information for dump
- @cpu: The cpu this node is affined to.
- @csdev: Handler for coresight device.
- @buf: Pointer for dump buffer.
- @buf_size: Length of dump buffer.
- @list: Hook to the list.
- */
+struct coresight_kdump_node {
- int cpu;
- struct coresight_device *csdev;
- char *buf;
- unsigned int buf_size;
- struct list_head list;
+};
+static DEFINE_SPINLOCK(coresight_kdump_lock); +static LIST_HEAD(coresight_kdump_list); +static struct notifier_block coresight_kdump_nb;
+int coresight_kdump_update(struct coresight_device *csdev, char *buf,
unsigned int buf_size)
+{
- struct coresight_kdump_node *node = csdev->dump_node;
- if (!node) {
dev_err(&csdev->dev, "Failed to update dump node.\n");
return -EINVAL;
- }
- node->buf = buf;
- node->buf_size = buf_size;
- return 0;
+}
+int coresight_kdump_add(struct coresight_device *csdev, int cpu) +{
- struct coresight_kdump_node *node;
- unsigned long flags;
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node)
return -ENOMEM;
- csdev->dump_node = (void *)node;
- node->cpu = cpu;
- node->csdev = csdev;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_add_tail(&node->list, &coresight_kdump_list);
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+void coresight_kdump_del(struct coresight_device *csdev) +{
- struct coresight_kdump_node *node, *next;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry_safe(node, next, &coresight_kdump_list, list) {
if (node->csdev == csdev) {
list_del(&node->list);
kfree(node);
break;
}
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
+}
+static coresight_cb_t +coresight_kdump_get_cb(struct coresight_device *csdev) +{
- coresight_cb_t cb = NULL;
- switch (csdev->type) {
- case CORESIGHT_DEV_TYPE_SINK:
- case CORESIGHT_DEV_TYPE_LINKSINK:
cb = sink_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_SOURCE:
cb = source_ops(csdev)->panic_cb;
break;
- case CORESIGHT_DEV_TYPE_LINK:
cb = link_ops(csdev)->panic_cb;
break;
I don't see why we need a callback for link devices - didn't I raised that question before?
Yes, sorry I have not deleted for link devices completely. Will remove it.
And I've been thinking further about this. The way we call the panic callbacks won't work. When a panic is triggered there might be trace data in the CS network that hasn't made it to the sink yet and calling the panic callbacks for sinks will lead to a loss of data.
That is why, when accessing from both sysFS and perf, the current implementation takes great care to stop the tracers first and then deal with the sink. To fix this I suggest to call the panic callbacks only for sources. What happens there will depend on what interface is used (sysFS or perf) - look at what is currently done to get a better understanding.
Will look into this.
If I understand correctly, we need firstly stop tracers and save trace data from sink, right? If so we need use single callback function to disable path and dump data for sink, will study current case and check what's the clean method for kdump.
You are correct - only the callback for sources should be used. In that callback processing is different whether trace collection was started from sysFS or perf. The code already exists, it's just a matter of doing the right thing.
- default:
dev_info(&csdev->dev, "Unsupport panic dump\n");
I would not bother with the dev_info()...
Will remove it.
break;
- }
- return cb;
+}
+/**
- coresight_kdump_notify - Invoke panic dump callbacks, this is
- the main function to fulfill the panic dump. It distinguishs
- to two types: one is pre panic dump which the callback function
- handler is NULL and coresight drivers can use function
- coresight_kdump_update() to directly update dump buffer base
- address and buffer size, for this case this function does nothing
- and directly bail out; another case is for post panic dump so
- invoke callback on alive CPU.
Now that pre and post processing are gone the description above doesn't match what the function is doing.
Yeah, will remove 'pre' and 'post' to avoid confusion.
- Returns: 0 on success.
- */
+static int coresight_kdump_notify(struct notifier_block *nb,
unsigned long mode, void *_unused)
+{
- struct coresight_kdump_node *node;
- struct coresight_device *csdev;
- coresight_cb_t cb;
- unsigned long flags;
- spin_lock_irqsave(&coresight_kdump_lock, flags);
- list_for_each_entry(node, &coresight_kdump_list, list) {
csdev = node->csdev;
cb = coresight_kdump_get_cb(csdev);
if (cb)
cb(csdev);
- }
- spin_unlock_irqrestore(&coresight_kdump_lock, flags);
- return 0;
+}
+static int __init coresight_kdump_init(void) +{
- int ret;
- coresight_kdump_nb.notifier_call = coresight_kdump_notify;
- ret = atomic_notifier_chain_register(&panic_notifier_list,
&coresight_kdump_nb);
- return ret;
+} +late_initcall(coresight_kdump_init); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index f1d0e21d..937750e 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -151,4 +151,17 @@ static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; } static inline int etm_writel_cp14(u32 off, u32 val) { return 0; } #endif
+#ifdef CONFIG_CORESIGHT_PANIC_KDUMP +extern int coresight_kdump_add(struct coresight_device *csdev, int cpu); +extern void coresight_kdump_del(struct coresight_device *csdev); +extern int coresight_kdump_update(struct coresight_device *csdev,
char *buf, unsigned int buf_size);
+#else +static inline int +coresight_kdump_add(struct coresight_device *csdev, int cpu) { return 0; } +static inline void coresight_kdump_del(struct coresight_device *csdev) {} +static inline int coresight_kdump_update(struct coresight_device *csdev,
- char *buf, unsigned int buf_size) { return 0; }
static inline int coresight_kdump_update(struct coresight_device *csdev, char *buf, unsigned int buf_size) { return 0; }
Will fix.
+#endif
#endif diff --git a/include/linux/coresight.h b/include/linux/coresight.h index d950dad..43e40fa 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -171,6 +171,7 @@ struct coresight_device { bool orphan; bool enable; /* true only if configured as part of a path */ bool activated; /* true only if a sink is part of a path */
- void *dump_node;
Please add a description for this entry.
Will do.
Thanks, Leo Yan
};
#define to_coresight_device(d) container_of(d, struct coresight_device, dev) @@ -189,6 +190,7 @@ struct coresight_device {
- @set_buffer: initialises buffer mechanic before a trace session.
- @reset_buffer: finalises buffer mechanic after a trace session.
- @update_buffer: update buffer pointers after a trace session.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, u32 mode); @@ -205,6 +207,7 @@ struct coresight_ops_sink { void (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config);
- void (*panic_cb)(void *data);
};
/** @@ -212,10 +215,12 @@ struct coresight_ops_sink {
- Operations available for links.
- @enable: enables flow between iport and oport.
- @disable: disables flow between iport and oport.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_link { int (*enable)(struct coresight_device *csdev, int iport, int oport); void (*disable)(struct coresight_device *csdev, int iport, int oport);
- void (*panic_cb)(void *data);
};
/** @@ -227,6 +232,7 @@ struct coresight_ops_link {
to the HW.
- @enable: enables tracing for a source.
- @disable: disables tracing for a source.
*/
- @panic_cb: hook function for panic notifier.
struct coresight_ops_source { int (*cpu_id)(struct coresight_device *csdev); @@ -235,6 +241,7 @@ struct coresight_ops_source { struct perf_event *event, u32 mode); void (*disable)(struct coresight_device *csdev, struct perf_event *event);
- void (*panic_cb)(void *data);
};
struct coresight_ops {
2.7.4
Since the panic kdump functionality has been ready, this patch is to hook panic callback function for ETB/ETF. Since the driver data structure has allocated buffer when the session started, so simply save ETB/ETF trace data into the buffer when panic happens and update related info into dump node.
Signed-off-by: Leo Yan leo.yan@linaro.org --- drivers/hwtracing/coresight/coresight-tmc-etf.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index e2513b7..f823464 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -504,6 +504,34 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, CS_LOCK(drvdata->base); }
+static void tmc_panic_cb(void *data) +{ + struct coresight_device *csdev = (struct coresight_device *)data; + struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + unsigned long flags; + + if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETB && + drvdata->config_type != TMC_CONFIG_TYPE_ETF)) + return; + + if (drvdata->mode == CS_MODE_DISABLED) + return; + + spin_lock_irqsave(&drvdata->spinlock, flags); + + CS_UNLOCK(drvdata->base); + + tmc_flush_and_stop(drvdata); + tmc_etb_dump_hw(drvdata); + + CS_LOCK(drvdata->base); + + /* Update buffer info for panic dump */ + coresight_kdump_update(csdev, drvdata->buf, drvdata->len); + + spin_unlock_irqrestore(&drvdata->spinlock, flags); +} + static const struct coresight_ops_sink tmc_etf_sink_ops = { .enable = tmc_enable_etf_sink, .disable = tmc_disable_etf_sink, @@ -512,6 +540,7 @@ static const struct coresight_ops_sink tmc_etf_sink_ops = { .set_buffer = tmc_set_etf_buffer, .reset_buffer = tmc_reset_etf_buffer, .update_buffer = tmc_update_etf_buffer, + .panic_cb = tmc_panic_cb, };
static const struct coresight_ops_link tmc_etf_link_ops = {
If the sink device has panic kdump callback, this means the sink device wants to save tracing data for panic happening.
This commit adds node into panic kdump list when the sink device is enabled, and delete node when the sink device is disabled.
Signed-off-by: Leo Yan leo.yan@linaro.org --- drivers/hwtracing/coresight/coresight.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 389c4ba..56798b1 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -146,6 +146,14 @@ static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) if (ret) return ret; } + + /* Add into panic kdump list */ + if (sink_ops(csdev)->panic_cb) { + ret = coresight_kdump_add(csdev, 0); + if (ret) + return ret; + } + csdev->enable = true; }
@@ -157,6 +165,10 @@ static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) static void coresight_disable_sink(struct coresight_device *csdev) { if (atomic_dec_return(csdev->refcnt) == 0) { + /* Delete from panic kdump list */ + if (sink_ops(csdev)->panic_cb) + coresight_kdump_del(csdev); + if (sink_ops(csdev)->disable) { sink_ops(csdev)->disable(csdev); csdev->enable = false;
ETMv4 hardware information and configuration needs to be saved as metadata; these metadata should be compatible with tool 'perf' and can be used for tracing data analysis. ETMv4 usually works as tracer per CPU, we cannot wait to gather ETM info after the CPU has been panic and cannot execute dump operations for itself; so should gather metadata when the corresponding CPU is alive.
Since values in TRCIDR{0, 1, 2, 8} and TRCAUTHSTATUS are read-only and won't change at the runtime. Those registers value are filled when tracers are instantiated.
The configuration and control registers TRCCONFIGR and TRCTRACEIDR are dynamically configured, we record their value when enabling coresight path. When operating from sysFS tracer these two registers are recorded in etm4_enable_sysfs() and add kdump node into list, and remove the kdump node in etm4_disable_sysfs(). When operating from perf, etm_setup_aux() adds all tracers to the dump list and etm4_enable_perf() is used to record configuration registers and update dump buffer info, this can avoid unnecessary list addition and deletion operations. Removal of the tracers from the dump list is done in function free_event_data().
Suggested-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Leo Yan leo.yan@linaro.org --- drivers/hwtracing/coresight/coresight-etm-perf.c | 12 +++++++++++- drivers/hwtracing/coresight/coresight-etm4x.c | 23 +++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x.h | 15 +++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 8a0ad77..fec779b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -137,6 +137,12 @@ static void free_event_data(struct work_struct *work) }
for_each_cpu(cpu, mask) { + struct coresight_device *csdev; + + csdev = per_cpu(csdev_src, cpu); + if (csdev) + coresight_kdump_del(csdev); + if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) coresight_release_path(event_data->path[cpu]); } @@ -195,7 +201,7 @@ static void etm_free_aux(void *data) static void *etm_setup_aux(int event_cpu, void **pages, int nr_pages, bool overwrite) { - int cpu; + int cpu, ret; cpumask_t *mask; struct coresight_device *sink; struct etm_event_data *event_data = NULL; @@ -238,6 +244,10 @@ static void *etm_setup_aux(int event_cpu, void **pages, event_data->path[cpu] = coresight_build_path(csdev, sink); if (IS_ERR(event_data->path[cpu])) goto err; + + ret = coresight_kdump_add(csdev, cpu); + if (ret) + goto err; }
if (!sink_ops(sink)->alloc_buffer) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index cf364a5..cbde398 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -258,10 +258,19 @@ static int etm4_enable_perf(struct coresight_device *csdev, static int etm4_enable_sysfs(struct coresight_device *csdev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct etmv4_config *config = &drvdata->config; + struct etmv4_metadata *metadata = &drvdata->metadata; int ret;
spin_lock(&drvdata->spinlock);
+ /* Update meta data and add into kdump list */ + metadata->trcconfigr = config->cfg; + metadata->trctraceidr = drvdata->trcid; + + coresight_kdump_add(csdev, drvdata->cpu); + coresight_kdump_update(csdev, (char *)metadata, sizeof(*metadata)); + /* * Executing etm4_enable_hw on the cpu whose ETM is being enabled * ensures that register writes occur when cpu is powered. @@ -384,6 +393,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) */ smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
+ /* Delete from kdump list */ + coresight_kdump_del(csdev); + spin_unlock(&drvdata->spinlock); cpus_read_unlock();
@@ -438,6 +450,7 @@ static void etm4_init_arch_data(void *info) u32 etmidr4; u32 etmidr5; struct etmv4_drvdata *drvdata = info; + struct etmv4_metadata *metadata = &drvdata->metadata;
/* Make sure all registers are accessible */ etm4_os_unlock(drvdata); @@ -590,6 +603,16 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = BMVAL(etmidr5, 28, 30); + + /* Update metadata */ + metadata->magic = ETM4_METADATA_MAGIC; + metadata->cpu = drvdata->cpu; + metadata->trcidr0 = readl_relaxed(drvdata->base + TRCIDR0); + metadata->trcidr1 = readl_relaxed(drvdata->base + TRCIDR1); + metadata->trcidr2 = readl_relaxed(drvdata->base + TRCIDR2); + metadata->trcidr8 = readl_relaxed(drvdata->base + TRCIDR8); + metadata->trcauthstatus = readl_relaxed(drvdata->base + TRCAUTHSTATUS); + CS_LOCK(drvdata->base); }
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index b3b5ea7..08dc8b7 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -198,6 +198,20 @@ #define ETM_EXLEVEL_NS_HYP BIT(14) #define ETM_EXLEVEL_NS_NA BIT(15)
+#define ETM4_METADATA_MAGIC 0x4040404040404040ULL + +struct etmv4_metadata { + u64 magic; + u64 cpu; + u64 trcconfigr; + u64 trctraceidr; + u64 trcidr0; + u64 trcidr1; + u64 trcidr2; + u64 trcidr8; + u64 trcauthstatus; +}; + /** * struct etmv4_config - configuration information related to an ETMv4 * @mode: Controls various modes supported by this ETM. @@ -393,6 +407,7 @@ struct etmv4_drvdata { bool atbtrig; bool lpoverride; struct etmv4_config config; + struct etmv4_metadata metadata; };
/* Address comparator access types */
On Thu, Dec 21, 2017 at 04:20:15PM +0800, Leo Yan wrote:
ETMv4 hardware information and configuration needs to be saved as metadata; these metadata should be compatible with tool 'perf' and can be used for tracing data analysis. ETMv4 usually works as tracer per CPU, we cannot wait to gather ETM info after the CPU has been panic and cannot execute dump operations for itself; so should gather metadata when the corresponding CPU is alive.
Since values in TRCIDR{0, 1, 2, 8} and TRCAUTHSTATUS are read-only and won't change at the runtime. Those registers value are filled when tracers are instantiated.
The configuration and control registers TRCCONFIGR and TRCTRACEIDR are dynamically configured, we record their value when enabling coresight path. When operating from sysFS tracer these two registers are recorded in etm4_enable_sysfs() and add kdump node into list, and remove the kdump node in etm4_disable_sysfs(). When operating from perf, etm_setup_aux() adds all tracers to the dump list and etm4_enable_perf() is used to record configuration registers and update dump buffer info, this can avoid unnecessary list addition and deletion operations. Removal of the tracers from the dump list is done in function free_event_data().
Suggested-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/coresight-etm-perf.c | 12 +++++++++++- drivers/hwtracing/coresight/coresight-etm4x.c | 23 +++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x.h | 15 +++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 8a0ad77..fec779b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -137,6 +137,12 @@ static void free_event_data(struct work_struct *work) } for_each_cpu(cpu, mask) {
struct coresight_device *csdev;
csdev = per_cpu(csdev_src, cpu);
if (csdev)
coresight_kdump_del(csdev);
- if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) coresight_release_path(event_data->path[cpu]); }
@@ -195,7 +201,7 @@ static void etm_free_aux(void *data) static void *etm_setup_aux(int event_cpu, void **pages, int nr_pages, bool overwrite) {
- int cpu;
- int cpu, ret; cpumask_t *mask; struct coresight_device *sink; struct etm_event_data *event_data = NULL;
@@ -238,6 +244,10 @@ static void *etm_setup_aux(int event_cpu, void **pages, event_data->path[cpu] = coresight_build_path(csdev, sink); if (IS_ERR(event_data->path[cpu])) goto err;
ret = coresight_kdump_add(csdev, cpu);
Aren't you missing the configuration for trcconfigr and trctraceidr?
if (ret)
}goto err;
if (!sink_ops(sink)->alloc_buffer) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index cf364a5..cbde398 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -258,10 +258,19 @@ static int etm4_enable_perf(struct coresight_device *csdev, static int etm4_enable_sysfs(struct coresight_device *csdev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- struct etmv4_config *config = &drvdata->config;
- struct etmv4_metadata *metadata = &drvdata->metadata; int ret;
spin_lock(&drvdata->spinlock);
- /* Update meta data and add into kdump list */
- metadata->trcconfigr = config->cfg;
- metadata->trctraceidr = drvdata->trcid;
- coresight_kdump_add(csdev, drvdata->cpu);
- coresight_kdump_update(csdev, (char *)metadata, sizeof(*metadata));
- /*
- Executing etm4_enable_hw on the cpu whose ETM is being enabled
- ensures that register writes occur when cpu is powered.
@@ -384,6 +393,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) */ smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
- /* Delete from kdump list */
- coresight_kdump_del(csdev);
- spin_unlock(&drvdata->spinlock); cpus_read_unlock();
@@ -438,6 +450,7 @@ static void etm4_init_arch_data(void *info) u32 etmidr4; u32 etmidr5; struct etmv4_drvdata *drvdata = info;
- struct etmv4_metadata *metadata = &drvdata->metadata;
/* Make sure all registers are accessible */ etm4_os_unlock(drvdata); @@ -590,6 +603,16 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
- /* Update metadata */
- metadata->magic = ETM4_METADATA_MAGIC;
- metadata->cpu = drvdata->cpu;
- metadata->trcidr0 = readl_relaxed(drvdata->base + TRCIDR0);
- metadata->trcidr1 = readl_relaxed(drvdata->base + TRCIDR1);
- metadata->trcidr2 = readl_relaxed(drvdata->base + TRCIDR2);
- metadata->trcidr8 = readl_relaxed(drvdata->base + TRCIDR8);
- metadata->trcauthstatus = readl_relaxed(drvdata->base + TRCAUTHSTATUS);
- CS_LOCK(drvdata->base);
} diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index b3b5ea7..08dc8b7 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -198,6 +198,20 @@ #define ETM_EXLEVEL_NS_HYP BIT(14) #define ETM_EXLEVEL_NS_NA BIT(15) +#define ETM4_METADATA_MAGIC 0x4040404040404040ULL
This is a duplicate of the magic value found in cs-etm.h but I'm not sure of what we'll do about that. It is probably time to come up with a shared file between the kernel and the perf tools, just like coresight-pmu.h. You can have a stab at it or concentrate on my previous comments for now - it's entirely up to you.
+struct etmv4_metadata {
- u64 magic;
- u64 cpu;
- u64 trcconfigr;
- u64 trctraceidr;
- u64 trcidr0;
- u64 trcidr1;
- u64 trcidr2;
- u64 trcidr8;
- u64 trcauthstatus;
+};
Same here... This is a duplicate of struct etmv4_drvdata. Again not sure about the best way to handle this. I'll think about it.
/**
- struct etmv4_config - configuration information related to an ETMv4
- @mode: Controls various modes supported by this ETM.
@@ -393,6 +407,7 @@ struct etmv4_drvdata { bool atbtrig; bool lpoverride; struct etmv4_config config;
- struct etmv4_metadata metadata;
}; /* Address comparator access types */ -- 2.7.4
On Tue, Jan 09, 2018 at 01:21:28PM -0700, Mathieu Poirier wrote:
On Thu, Dec 21, 2017 at 04:20:15PM +0800, Leo Yan wrote:
ETMv4 hardware information and configuration needs to be saved as metadata; these metadata should be compatible with tool 'perf' and can be used for tracing data analysis. ETMv4 usually works as tracer per CPU, we cannot wait to gather ETM info after the CPU has been panic and cannot execute dump operations for itself; so should gather metadata when the corresponding CPU is alive.
Since values in TRCIDR{0, 1, 2, 8} and TRCAUTHSTATUS are read-only and won't change at the runtime. Those registers value are filled when tracers are instantiated.
The configuration and control registers TRCCONFIGR and TRCTRACEIDR are dynamically configured, we record their value when enabling coresight path. When operating from sysFS tracer these two registers are recorded in etm4_enable_sysfs() and add kdump node into list, and remove the kdump node in etm4_disable_sysfs(). When operating from perf, etm_setup_aux() adds all tracers to the dump list and etm4_enable_perf() is used to record configuration registers and update dump buffer info, this can avoid unnecessary list addition and deletion operations. Removal of the tracers from the dump list is done in function free_event_data().
Suggested-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/coresight-etm-perf.c | 12 +++++++++++- drivers/hwtracing/coresight/coresight-etm4x.c | 23 +++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x.h | 15 +++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 8a0ad77..fec779b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -137,6 +137,12 @@ static void free_event_data(struct work_struct *work) } for_each_cpu(cpu, mask) {
struct coresight_device *csdev;
csdev = per_cpu(csdev_src, cpu);
if (csdev)
coresight_kdump_del(csdev);
- if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) coresight_release_path(event_data->path[cpu]); }
@@ -195,7 +201,7 @@ static void etm_free_aux(void *data) static void *etm_setup_aux(int event_cpu, void **pages, int nr_pages, bool overwrite) {
- int cpu;
- int cpu, ret; cpumask_t *mask; struct coresight_device *sink; struct etm_event_data *event_data = NULL;
@@ -238,6 +244,10 @@ static void *etm_setup_aux(int event_cpu, void **pages, event_data->path[cpu] = coresight_build_path(csdev, sink); if (IS_ERR(event_data->path[cpu])) goto err;
ret = coresight_kdump_add(csdev, cpu);
Aren't you missing the configuration for trcconfigr and trctraceidr?
Ah, should update these two configurations in function etm4_enable_perf()?
if (ret)
}goto err;
if (!sink_ops(sink)->alloc_buffer) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index cf364a5..cbde398 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -258,10 +258,19 @@ static int etm4_enable_perf(struct coresight_device *csdev, static int etm4_enable_sysfs(struct coresight_device *csdev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- struct etmv4_config *config = &drvdata->config;
- struct etmv4_metadata *metadata = &drvdata->metadata; int ret;
spin_lock(&drvdata->spinlock);
- /* Update meta data and add into kdump list */
- metadata->trcconfigr = config->cfg;
- metadata->trctraceidr = drvdata->trcid;
- coresight_kdump_add(csdev, drvdata->cpu);
- coresight_kdump_update(csdev, (char *)metadata, sizeof(*metadata));
- /*
- Executing etm4_enable_hw on the cpu whose ETM is being enabled
- ensures that register writes occur when cpu is powered.
@@ -384,6 +393,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) */ smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
- /* Delete from kdump list */
- coresight_kdump_del(csdev);
- spin_unlock(&drvdata->spinlock); cpus_read_unlock();
@@ -438,6 +450,7 @@ static void etm4_init_arch_data(void *info) u32 etmidr4; u32 etmidr5; struct etmv4_drvdata *drvdata = info;
- struct etmv4_metadata *metadata = &drvdata->metadata;
/* Make sure all registers are accessible */ etm4_os_unlock(drvdata); @@ -590,6 +603,16 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
- /* Update metadata */
- metadata->magic = ETM4_METADATA_MAGIC;
- metadata->cpu = drvdata->cpu;
- metadata->trcidr0 = readl_relaxed(drvdata->base + TRCIDR0);
- metadata->trcidr1 = readl_relaxed(drvdata->base + TRCIDR1);
- metadata->trcidr2 = readl_relaxed(drvdata->base + TRCIDR2);
- metadata->trcidr8 = readl_relaxed(drvdata->base + TRCIDR8);
- metadata->trcauthstatus = readl_relaxed(drvdata->base + TRCAUTHSTATUS);
- CS_LOCK(drvdata->base);
} diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index b3b5ea7..08dc8b7 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -198,6 +198,20 @@ #define ETM_EXLEVEL_NS_HYP BIT(14) #define ETM_EXLEVEL_NS_NA BIT(15) +#define ETM4_METADATA_MAGIC 0x4040404040404040ULL
This is a duplicate of the magic value found in cs-etm.h but I'm not sure of what we'll do about that. It is probably time to come up with a shared file between the kernel and the perf tools, just like coresight-pmu.h. You can have a stab at it or concentrate on my previous comments for now - it's entirely up to you.
I will do some try for this for changing to use one shared single header, if I have no confidence for this I will go back to keep this code for new version patch.
+struct etmv4_metadata {
- u64 magic;
- u64 cpu;
- u64 trcconfigr;
- u64 trctraceidr;
- u64 trcidr0;
- u64 trcidr1;
- u64 trcidr2;
- u64 trcidr8;
- u64 trcauthstatus;
+};
Same here... This is a duplicate of struct etmv4_drvdata. Again not sure about the best way to handle this. I'll think about it.
Sure, I might check with you when I spin patches for this.
Thanks, Leo Yan
/**
- struct etmv4_config - configuration information related to an ETMv4
- @mode: Controls various modes supported by this ETM.
@@ -393,6 +407,7 @@ struct etmv4_drvdata { bool atbtrig; bool lpoverride; struct etmv4_config config;
- struct etmv4_metadata metadata;
}; /* Address comparator access types */ -- 2.7.4
On 9 January 2018 at 22:33, Leo Yan leo.yan@linaro.org wrote:
On Tue, Jan 09, 2018 at 01:21:28PM -0700, Mathieu Poirier wrote:
On Thu, Dec 21, 2017 at 04:20:15PM +0800, Leo Yan wrote:
ETMv4 hardware information and configuration needs to be saved as metadata; these metadata should be compatible with tool 'perf' and can be used for tracing data analysis. ETMv4 usually works as tracer per CPU, we cannot wait to gather ETM info after the CPU has been panic and cannot execute dump operations for itself; so should gather metadata when the corresponding CPU is alive.
Since values in TRCIDR{0, 1, 2, 8} and TRCAUTHSTATUS are read-only and won't change at the runtime. Those registers value are filled when tracers are instantiated.
The configuration and control registers TRCCONFIGR and TRCTRACEIDR are dynamically configured, we record their value when enabling coresight path. When operating from sysFS tracer these two registers are recorded in etm4_enable_sysfs() and add kdump node into list, and remove the kdump node in etm4_disable_sysfs(). When operating from perf, etm_setup_aux() adds all tracers to the dump list and etm4_enable_perf() is used to record configuration registers and update dump buffer info, this can avoid unnecessary list addition and deletion operations. Removal of the tracers from the dump list is done in function free_event_data().
Suggested-by: Mathieu Poirier mathieu.poirier@linaro.org Signed-off-by: Leo Yan leo.yan@linaro.org
drivers/hwtracing/coresight/coresight-etm-perf.c | 12 +++++++++++- drivers/hwtracing/coresight/coresight-etm4x.c | 23 +++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x.h | 15 +++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 8a0ad77..fec779b 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -137,6 +137,12 @@ static void free_event_data(struct work_struct *work) }
for_each_cpu(cpu, mask) {
struct coresight_device *csdev;
csdev = per_cpu(csdev_src, cpu);
if (csdev)
coresight_kdump_del(csdev);
}if (!(IS_ERR_OR_NULL(event_data->path[cpu]))) coresight_release_path(event_data->path[cpu]);
@@ -195,7 +201,7 @@ static void etm_free_aux(void *data) static void *etm_setup_aux(int event_cpu, void **pages, int nr_pages, bool overwrite) {
- int cpu;
- int cpu, ret; cpumask_t *mask; struct coresight_device *sink; struct etm_event_data *event_data = NULL;
@@ -238,6 +244,10 @@ static void *etm_setup_aux(int event_cpu, void **pages, event_data->path[cpu] = coresight_build_path(csdev, sink); if (IS_ERR(event_data->path[cpu])) goto err;
ret = coresight_kdump_add(csdev, cpu);
Aren't you missing the configuration for trcconfigr and trctraceidr?
Ah, should update these two configurations in function etm4_enable_perf()?
Looking at what you've done for etm4_enable_sysfs() that is probably a better choice.
if (ret)
goto err;
}
if (!sink_ops(sink)->alloc_buffer)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index cf364a5..cbde398 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -258,10 +258,19 @@ static int etm4_enable_perf(struct coresight_device *csdev, static int etm4_enable_sysfs(struct coresight_device *csdev) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etmv4_config *config = &drvdata->config;
struct etmv4_metadata *metadata = &drvdata->metadata; int ret;
spin_lock(&drvdata->spinlock);
/* Update meta data and add into kdump list */
metadata->trcconfigr = config->cfg;
metadata->trctraceidr = drvdata->trcid;
coresight_kdump_add(csdev, drvdata->cpu);
coresight_kdump_update(csdev, (char *)metadata, sizeof(*metadata));
/*
- Executing etm4_enable_hw on the cpu whose ETM is being enabled
- ensures that register writes occur when cpu is powered.
@@ -384,6 +393,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) */ smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
- /* Delete from kdump list */
- coresight_kdump_del(csdev);
- spin_unlock(&drvdata->spinlock); cpus_read_unlock();
@@ -438,6 +450,7 @@ static void etm4_init_arch_data(void *info) u32 etmidr4; u32 etmidr5; struct etmv4_drvdata *drvdata = info;
struct etmv4_metadata *metadata = &drvdata->metadata;
/* Make sure all registers are accessible */ etm4_os_unlock(drvdata);
@@ -590,6 +603,16 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
- /* Update metadata */
- metadata->magic = ETM4_METADATA_MAGIC;
- metadata->cpu = drvdata->cpu;
- metadata->trcidr0 = readl_relaxed(drvdata->base + TRCIDR0);
- metadata->trcidr1 = readl_relaxed(drvdata->base + TRCIDR1);
- metadata->trcidr2 = readl_relaxed(drvdata->base + TRCIDR2);
- metadata->trcidr8 = readl_relaxed(drvdata->base + TRCIDR8);
- metadata->trcauthstatus = readl_relaxed(drvdata->base + TRCAUTHSTATUS);
- CS_LOCK(drvdata->base);
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index b3b5ea7..08dc8b7 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -198,6 +198,20 @@ #define ETM_EXLEVEL_NS_HYP BIT(14) #define ETM_EXLEVEL_NS_NA BIT(15)
+#define ETM4_METADATA_MAGIC 0x4040404040404040ULL
This is a duplicate of the magic value found in cs-etm.h but I'm not sure of what we'll do about that. It is probably time to come up with a shared file between the kernel and the perf tools, just like coresight-pmu.h. You can have a stab at it or concentrate on my previous comments for now - it's entirely up to you.
I will do some try for this for changing to use one shared single header, if I have no confidence for this I will go back to keep this code for new version patch.
Deal.
+struct etmv4_metadata {
- u64 magic;
- u64 cpu;
- u64 trcconfigr;
- u64 trctraceidr;
- u64 trcidr0;
- u64 trcidr1;
- u64 trcidr2;
- u64 trcidr8;
- u64 trcauthstatus;
+};
Same here... This is a duplicate of struct etmv4_drvdata. Again not sure about the best way to handle this. I'll think about it.
Sure, I might check with you when I spin patches for this.
Thanks, Leo Yan
/**
- struct etmv4_config - configuration information related to an ETMv4
- @mode: Controls various modes supported by this ETM.
@@ -393,6 +407,7 @@ struct etmv4_drvdata { bool atbtrig; bool lpoverride; struct etmv4_config config;
- struct etmv4_metadata metadata;
};
/* Address comparator access types */
2.7.4