Merge tag 'lsk-v3.10-android-15.01'

LSK Android 15.01 v3.10

Conflicts:
	arch/arm/Kconfig.debug
	arch/arm64/mm/init.c
	drivers/Makefile
	drivers/cpufreq/cpufreq_interactive.c
This commit is contained in:
Huang, Tao
2015-02-10 16:24:25 +08:00
222 changed files with 12614 additions and 2549 deletions

View File

@@ -0,0 +1,204 @@
* CoreSight Components:
CoreSight components are compliant with the ARM CoreSight architecture
specification and can be connected in various topologies to suit a particular
SoCs tracing needs. These trace components can generally be classified as
sinks, links and sources. Trace data produced by one or more sources flows
through the intermediate links connecting the source to the currently selected
sink. Each CoreSight component device should use these properties to describe
its hardware characteristcs.
* Required properties for all components *except* non-configurable replicators:
* compatible: These have to be supplemented with "arm,primecell" as
drivers are using the AMBA bus interface. Possible values include:
- "arm,coresight-etb10", "arm,primecell";
- "arm,coresight-tpiu", "arm,primecell";
- "arm,coresight-tmc", "arm,primecell";
- "arm,coresight-funnel", "arm,primecell";
- "arm,coresight-etm3x", "arm,primecell";
* reg: physical base address and length of the register
set(s) of the component.
* clocks: the clock associated to this component.
* clock-names: the name of the clock as referenced by the code.
Since we are using the AMBA framework, the name should be
"apb_pclk".
* port or ports: The representation of the component's port
layout using the generic DT graph presentation found in
"bindings/graph.txt".
* Required properties for devices that don't show up on the AMBA bus, such as
non-configurable replicators:
* compatible: Currently supported value is (note the absence of the
AMBA markee):
- "arm,coresight-replicator"
* id: a unique number that will identify this replicator.
* port or ports: same as above.
* Optional properties for ETM/PTMs:
* arm,cp14: must be present if the system accesses ETM/PTM management
registers via co-processor 14.
* cpu: the cpu phandle this ETM/PTM is affined to. When omitted the
source is considered to belong to CPU0.
* Optional property for TMC:
* arm,buffer-size: size of contiguous buffer space for TMC ETR
(embedded trace router)
Example:
1. Sinks
etb@20010000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0 0x20010000 0 0x1000>;
coresight-default-sink;
clocks = <&oscclk6a>;
clock-names = "apb_pclk";
port {
etb_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator_out_port0>;
};
};
};
tpiu@20030000 {
compatible = "arm,coresight-tpiu", "arm,primecell";
reg = <0 0x20030000 0 0x1000>;
clocks = <&oscclk6a>;
clock-names = "apb_pclk";
port {
tpiu_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator_out_port1>;
};
};
};
2. Links
replicator {
/* non-configurable replicators don't show up on the
* AMBA bus. As such no need to add "arm,primecell".
*/
compatible = "arm,coresight-replicator";
/* this will show up in debugfs as "0.replicator" */
id = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator_out_port0: endpoint {
remote-endpoint = <&etb_in_port>;
};
};
port@1 {
reg = <1>;
replicator_out_port1: endpoint {
remote-endpoint = <&tpiu_in_port>;
};
};
/* replicator input port */
port@2 {
reg = <0>;
replicator_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel_out_port0>;
};
};
};
};
funnel@20040000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0x20040000 0 0x1000>;
clocks = <&oscclk6a>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel_out_port0: endpoint {
remote-endpoint =
<&replicator_in_port0>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm0_out_port>;
};
};
port@2 {
reg = <1>;
funnel_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm1_out_port>;
};
};
port@3 {
reg = <2>;
funnel_in_port2: endpoint {
slave-mode;
remote-endpoint = <&etm0_out_port>;
};
};
};
};
3. Sources
ptm@2201c000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0x2201c000 0 0x1000>;
cpu = <&cpu0>;
clocks = <&oscclk6a>;
clock-names = "apb_pclk";
port {
ptm0_out_port: endpoint {
remote-endpoint = <&funnel_in_port0>;
};
};
};
ptm@2201d000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0x2201d000 0 0x1000>;
cpu = <&cpu1>;
clocks = <&oscclk6a>;
clock-names = "apb_pclk";
port {
ptm1_out_port: endpoint {
remote-endpoint = <&funnel_in_port1>;
};
};
};

View File

@@ -14,11 +14,19 @@ survive after a restart.
1. Ramoops concepts
Ramoops uses a predefined memory area to store the dump. The start and size of
the memory area are set using two variables:
Ramoops uses a predefined memory area to store the dump. The start and size
and type of the memory area are set using three variables:
* "mem_address" for the start
* "mem_size" for the size. The memory size will be rounded down to a
power of two.
* "mem_type" to specifiy if the memory type (default is pgprot_writecombine).
Typically the default value of mem_type=0 should be used as that sets the pstore
mapping to pgprot_writecombine. Setting mem_type=1 attempts to use
pgprot_noncached, which only works on some platforms. This is because pstore
depends on atomic operations. At least on ARM, pgprot_noncached causes the
memory to be mapped strongly ordered, and atomic operations on strongly ordered
memory are implementation defined, and won't work on many ARMs such as omaps.
The memory area is divided into "record_size" chunks (also rounded down to
power of two) and each oops/panic writes a "record_size" chunk of
@@ -55,6 +63,7 @@ Setting the ramoops parameters can be done in 2 different manners:
static struct ramoops_platform_data ramoops_data = {
.mem_size = <...>,
.mem_address = <...>,
.mem_type = <...>,
.record_size = <...>,
.dump_oops = <...>,
.ecc = <...>,

View File

@@ -0,0 +1,299 @@
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 systhesis time to cater to specific tracing needs.
Compoments 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 ABP ************************
*****************************************************************
| . ! . ! ! . |
| . * . * * . |
*****************************************************************
******************** 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 ABP 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 "strut 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
----------
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

View File

@@ -783,6 +783,14 @@ M: Hubert Feurstein <hubert.feurstein@contec.at>
S: Maintained
F: arch/arm/mach-ep93xx/micro9.c
ARM/CORESIGHT FRAMEWORK AND DRIVERS
M: Mathieu Poirier <mathieu.poirier@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/coresight/*
F: Documentation/trace/coresight.txt
F: Documentation/devicetree/bindings/arm/coresight.txt
ARM/CORGI MACHINE SUPPORT
M: Richard Purdie <rpurdie@rpsys.net>
S: Maintained

View File

@@ -1,6 +1,6 @@
VERSION = 3
PATCHLEVEL = 10
SUBLEVEL = 62
SUBLEVEL = 65
EXTRAVERSION =
NAME = TOSSUG Baby Fish

View File

@@ -706,14 +706,6 @@ config EARLY_PRINTK_DIRECT
kernel low-level debugging functions and EARLY_PRINTK is
not early enough.
config OC_ETM
bool "On-chip ETM and ETB"
depends on ARM_AMBA
help
Enables the on-chip embedded trace macrocell and embedded trace
buffer driver that will allow you to collect traces of the
kernel code.
config ARM_KPROBES_TEST
tristate "Kprobes test module"
depends on KPROBES && MODULES
@@ -729,4 +721,70 @@ config PID_IN_CONTEXTIDR
additional instructions during context switch. Say Y here only if you
are planning to use hardware trace tools with this kernel.
config DEBUG_SET_MODULE_RONX
bool "Set loadable kernel module data as NX and text as RO"
depends on MODULES
---help---
This option helps catch unintended modifications to loadable
kernel module's text and read-only data. It also prevents execution
of module data. Such protection may interfere with run-time code
patching and dynamic kernel tracing - and they might also protect
against certain classes of kernel exploits.
If in doubt, say "N".
menuconfig CORESIGHT
bool "CoreSight Tracing Support"
select ARM_AMBA
help
This framework provides a kernel interface for the CoreSight debug
and trace drivers to register themselves with. It's intended to build
a topological view of the CoreSight components based on a DT
specification and configure the right serie of components when a
trace source gets enabled.
if CORESIGHT
config CORESIGHT_LINKS_AND_SINKS
bool "CoreSight Link and Sink drivers"
help
This enables support for CoreSight link and sink drivers that are
responsible for transporting and collecting the trace data
respectively. Link and sinks are dynamically aggregated with a trace
entity at run time to form a complete trace path.
config CORESIGHT_LINK_AND_SINK_TMC
bool "Coresight generic TMC driver"
depends on CORESIGHT_LINKS_AND_SINKS
help
This enables support for the Trace Memory Controller driver. Depending
on its configuration the device can act as a link (embedded trace router
- ETR) or sink (embedded trace FIFO). The driver complies with the
generic implementation of the component without special enhancement or
added features.
config CORESIGHT_SINK_TPIU
bool "Coresight generic TPIU driver"
depends on CORESIGHT_LINKS_AND_SINKS
help
This enables support for the Trace Port Interface Unit driver, responsible
for bridging the gap between the on-chip coresight components and a trace
port collection engine, typically connected to an external host for use
case capturing more traces than the on-board coresight memory can handle.
config CORESIGHT_SINK_ETBV10
bool "Coresight ETBv1.0 driver"
depends on CORESIGHT_LINKS_AND_SINKS
help
This enables support for the Embedded Trace Buffer version 1.0 driver
that complies with the generic implementation of the component without
special enhancement or added features.
config CORESIGHT_SOURCE_ETM3X
bool "CoreSight Embedded Trace Macrocell 3.x driver"
select CORESIGHT_LINKS_AND_SINKS
help
This driver provides support for processor ETM3.x and PTM1.x modules,
which allows tracing the instructions that a processor is executing
This is primarily useful for instruction level tracing. Depending
the ETM version data tracing may also be available.
endif
endmenu

View File

@@ -0,0 +1,984 @@
/*
* Hisilicon Ltd. HiP04 SoC
*
* Copyright (C) 2013-2014 Hisilicon Ltd.
* Copyright (C) 2013-2014 Linaro Ltd.
*
* Author: Haojian Zhuang <haojian.zhuang@linaro.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/ {
/* memory bus is 64-bit */
#address-cells = <2>;
#size-cells = <2>;
aliases {
serial0 = &uart0;
};
bootwrapper {
compatible = "hisilicon,hip04-bootwrapper";
boot-method = <0x10c00000 0x10000>, <0xe0000100 0x1000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&CPU0>;
};
core1 {
cpu = <&CPU1>;
};
core2 {
cpu = <&CPU2>;
};
core3 {
cpu = <&CPU3>;
};
};
cluster1 {
core0 {
cpu = <&CPU4>;
};
core1 {
cpu = <&CPU5>;
};
core2 {
cpu = <&CPU6>;
};
core3 {
cpu = <&CPU7>;
};
};
cluster2 {
core0 {
cpu = <&CPU8>;
};
core1 {
cpu = <&CPU9>;
};
core2 {
cpu = <&CPU10>;
};
core3 {
cpu = <&CPU11>;
};
};
cluster3 {
core0 {
cpu = <&CPU12>;
};
core1 {
cpu = <&CPU13>;
};
core2 {
cpu = <&CPU14>;
};
core3 {
cpu = <&CPU15>;
};
};
};
CPU0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0>;
};
CPU1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <1>;
};
CPU2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <2>;
};
CPU3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <3>;
};
CPU4: cpu@100 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x100>;
};
CPU5: cpu@101 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x101>;
};
CPU6: cpu@102 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x102>;
};
CPU7: cpu@103 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x103>;
};
CPU8: cpu@200 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x200>;
};
CPU9: cpu@201 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x201>;
};
CPU10: cpu@202 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x202>;
};
CPU11: cpu@203 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x203>;
};
CPU12: cpu@300 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x300>;
};
CPU13: cpu@301 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x301>;
};
CPU14: cpu@302 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x302>;
};
CPU15: cpu@303 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <0x303>;
};
};
timer {
compatible = "arm,armv7-timer";
interrupt-parent = <&gic>;
interrupts = <1 13 0xf08>,
<1 14 0xf08>,
<1 11 0xf08>,
<1 10 0xf08>;
};
clk_50m: clk_50m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
clk_168m: clk_168m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <168000000>;
};
clk_375m: clk_375m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <375000000>;
};
soc {
/* It's a 32-bit SoC. */
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
interrupt-parent = <&gic>;
ranges = <0 0 0xe0000000 0x10000000>;
gic: interrupt-controller@c01000 {
compatible = "hisilicon,hip04-intc";
#interrupt-cells = <3>;
#address-cells = <0>;
interrupt-controller;
interrupts = <1 9 0xf04>;
reg = <0xc01000 0x1000>, <0xc02000 0x1000>,
<0xc04000 0x2000>, <0xc06000 0x2000>;
};
sysctrl: sysctrl {
compatible = "hisilicon,sysctrl";
reg = <0x3e00000 0x00100000>;
};
fabric: fabric {
compatible = "hisilicon,hip04-fabric";
reg = <0x302a000 0x1000>;
};
dual_timer0: dual_timer@3000000 {
compatible = "arm,sp804", "arm,primecell";
reg = <0x3000000 0x1000>;
interrupts = <0 224 4>;
clocks = <&clk_50m>, <&clk_50m>;
clock-names = "apb_pclk";
};
arm-pmu {
compatible = "arm,cortex-a15-pmu";
interrupts = <0 64 4>,
<0 65 4>,
<0 66 4>,
<0 67 4>,
<0 68 4>,
<0 69 4>,
<0 70 4>,
<0 71 4>,
<0 72 4>,
<0 73 4>,
<0 74 4>,
<0 75 4>,
<0 76 4>,
<0 77 4>,
<0 78 4>,
<0 79 4>;
};
uart0: uart@4007000 {
compatible = "snps,dw-apb-uart";
reg = <0x4007000 0x1000>;
interrupts = <0 381 4>;
clocks = <&clk_168m>;
clock-names = "uartclk";
reg-shift = <2>;
status = "disabled";
};
sata0: sata@a000000 {
compatible = "hisilicon,hisi-ahci";
reg = <0xa000000 0x1000000>;
interrupts = <0 372 4>;
};
};
etb@0,e3c42000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0 0xe3c42000 0 0x1000>;
coresight-default-sink;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
port {
etb0_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator0_out_port0>;
};
};
};
etb@0,e3c82000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0 0xe3c82000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
port {
etb1_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator1_out_port0>;
};
};
};
etb@0,e3cc2000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0 0xe3cc2000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
port {
etb2_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator2_out_port0>;
};
};
};
etb@0,e3d02000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0 0xe3d02000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
port {
etb3_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&replicator3_out_port0>;
};
};
};
tpiu@0,e3c05000 {
compatible = "arm,coresight-tpiu", "arm,primecell";
reg = <0 0xe3c05000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
port {
tpiu_in_port: endpoint@0 {
slave-mode;
remote-endpoint = <&funnel4_out_port0>;
};
};
};
replicator0 {
/* non-configurable replicators don't show up on the
* AMBA bus. As such no need to add "arm,primecell".
*/
compatible = "arm,coresight-replicator";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator0_out_port0: endpoint {
remote-endpoint = <&etb0_in_port>;
};
};
port@1 {
reg = <1>;
replicator0_out_port1: endpoint {
remote-endpoint = <&funnel4_in_port0>;
};
};
/* replicator input port */
port@2 {
reg = <0>;
replicator0_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel0_out_port0>;
};
};
};
};
replicator1 {
/* non-configurable replicators don't show up on the
* AMBA bus. As such no need to add "arm,primecell".
*/
compatible = "arm,coresight-replicator";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator1_out_port0: endpoint {
remote-endpoint = <&etb1_in_port>;
};
};
port@1 {
reg = <1>;
replicator1_out_port1: endpoint {
remote-endpoint = <&funnel4_in_port1>;
};
};
/* replicator input port */
port@2 {
reg = <0>;
replicator1_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel1_out_port0>;
};
};
};
};
replicator2 {
/* non-configurable replicators don't show up on the
* AMBA bus. As such no need to add "arm,primecell".
*/
compatible = "arm,coresight-replicator";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator2_out_port0: endpoint {
remote-endpoint = <&etb2_in_port>;
};
};
port@1 {
reg = <1>;
replicator2_out_port1: endpoint {
remote-endpoint = <&funnel4_in_port2>;
};
};
/* replicator input port */
port@2 {
reg = <0>;
replicator2_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel2_out_port0>;
};
};
};
};
replicator3 {
/* non-configurable replicators don't show up on the
* AMBA bus. As such no need to add "arm,primecell".
*/
compatible = "arm,coresight-replicator";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator3_out_port0: endpoint {
remote-endpoint = <&etb3_in_port>;
};
};
port@1 {
reg = <1>;
replicator3_out_port1: endpoint {
remote-endpoint = <&funnel4_in_port3>;
};
};
/* replicator input port */
port@2 {
reg = <0>;
replicator3_in_port0: endpoint {
slave-mode;
remote-endpoint = <&funnel3_out_port0>;
};
};
};
};
funnel@0,e3c41000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0xe3c41000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel0_out_port0: endpoint {
remote-endpoint =
<&replicator0_in_port0>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel0_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm0_out_port>;
};
};
port@2 {
reg = <1>;
funnel0_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm1_out_port>;
};
};
port@3 {
reg = <2>;
funnel0_in_port2: endpoint {
slave-mode;
remote-endpoint = <&ptm2_out_port>;
};
};
port@4 {
reg = <3>;
funnel0_in_port3: endpoint {
slave-mode;
remote-endpoint = <&ptm3_out_port>;
};
};
};
};
funnel@0,e3c81000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0xe3c81000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel1_out_port0: endpoint {
remote-endpoint =
<&replicator1_in_port0>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel1_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm4_out_port>;
};
};
port@2 {
reg = <1>;
funnel1_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm5_out_port>;
};
};
port@3 {
reg = <2>;
funnel1_in_port2: endpoint {
slave-mode;
remote-endpoint = <&ptm6_out_port>;
};
};
port@4 {
reg = <3>;
funnel1_in_port3: endpoint {
slave-mode;
remote-endpoint = <&ptm7_out_port>;
};
};
};
};
funnel@0,e3cc1000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0xe3cc1000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel2_out_port0: endpoint {
remote-endpoint =
<&replicator2_in_port0>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel2_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm8_out_port>;
};
};
port@2 {
reg = <1>;
funnel2_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm9_out_port>;
};
};
port@3 {
reg = <2>;
funnel2_in_port2: endpoint {
slave-mode;
remote-endpoint = <&ptm10_out_port>;
};
};
port@4 {
reg = <3>;
funnel2_in_port3: endpoint {
slave-mode;
remote-endpoint = <&ptm11_out_port>;
};
};
};
};
funnel@0,e3d01000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0xe3d01000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel3_out_port0: endpoint {
remote-endpoint =
<&replicator3_in_port0>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel3_in_port0: endpoint {
slave-mode;
remote-endpoint = <&ptm12_out_port>;
};
};
port@2 {
reg = <1>;
funnel3_in_port1: endpoint {
slave-mode;
remote-endpoint = <&ptm13_out_port>;
};
};
port@3 {
reg = <2>;
funnel3_in_port2: endpoint {
slave-mode;
remote-endpoint = <&ptm14_out_port>;
};
};
port@4 {
reg = <3>;
funnel3_in_port3: endpoint {
slave-mode;
remote-endpoint = <&ptm15_out_port>;
};
};
};
};
funnel@0,e3c04000 {
compatible = "arm,coresight-funnel", "arm,primecell";
reg = <0 0xe3c04000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel output port */
port@0 {
reg = <0>;
funnel4_out_port0: endpoint {
remote-endpoint = <&tpiu_in_port>;
};
};
/* funnel input ports */
port@1 {
reg = <0>;
funnel4_in_port0: endpoint {
slave-mode;
remote-endpoint =
<&replicator0_out_port1>;
};
};
port@2 {
reg = <1>;
funnel4_in_port1: endpoint {
slave-mode;
remote-endpoint =
<&replicator1_out_port1>;
};
};
port@3 {
reg = <2>;
funnel4_in_port2: endpoint {
slave-mode;
remote-endpoint =
<&replicator2_out_port1>;
};
};
port@4 {
reg = <3>;
funnel4_in_port3: endpoint {
slave-mode;
remote-endpoint =
<&replicator3_out_port1>;
};
};
};
};
ptm@0,e3c7c000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3c7c000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU0>;
port {
ptm0_out_port: endpoint {
remote-endpoint = <&funnel0_in_port0>;
};
};
};
ptm@0,e3c7d000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3c7d000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU1>;
port {
ptm1_out_port: endpoint {
remote-endpoint = <&funnel0_in_port1>;
};
};
};
ptm@0,e3c7e000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3c7e000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU2>;
port {
ptm2_out_port: endpoint {
remote-endpoint = <&funnel0_in_port2>;
};
};
};
ptm@0,e3c7f000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3c7f000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU3>;
port {
ptm3_out_port: endpoint {
remote-endpoint = <&funnel0_in_port3>;
};
};
};
ptm@0,e3cbc000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cbc000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU4>;
port {
ptm4_out_port: endpoint {
remote-endpoint = <&funnel1_in_port0>;
};
};
};
ptm@0,e3cbd000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cbd000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU5>;
port {
ptm5_out_port: endpoint {
remote-endpoint = <&funnel1_in_port1>;
};
};
};
ptm@0,e3cbe000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cbe000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU6>;
port {
ptm6_out_port: endpoint {
remote-endpoint = <&funnel1_in_port2>;
};
};
};
ptm@0,e3cbf000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cbf000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU7>;
port {
ptm7_out_port: endpoint {
remote-endpoint = <&funnel1_in_port3>;
};
};
};
ptm@0,e3cfc000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cfc000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU8>;
port {
ptm8_out_port: endpoint {
remote-endpoint = <&funnel2_in_port0>;
};
};
};
ptm@0,e3cfd000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cfd000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU9>;
port {
ptm9_out_port: endpoint {
remote-endpoint = <&funnel2_in_port1>;
};
};
};
ptm@0,e3cfe000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cfe000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU10>;
port {
ptm10_out_port: endpoint {
remote-endpoint = <&funnel2_in_port2>;
};
};
};
ptm@0,e3cff000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3cff000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU11>;
port {
ptm11_out_port: endpoint {
remote-endpoint = <&funnel2_in_port3>;
};
};
};
ptm@0,e3d3c000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3d3c000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU12>;
port {
ptm12_out_port: endpoint {
remote-endpoint = <&funnel3_in_port0>;
};
};
};
ptm@0,e3d3d000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3d3d000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU13>;
port {
ptm13_out_port: endpoint {
remote-endpoint = <&funnel3_in_port1>;
};
};
};
ptm@0,e3d3e000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3d3e000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU14>;
port {
ptm14_out_port: endpoint {
remote-endpoint = <&funnel3_in_port2>;
};
};
};
ptm@0,e3d3f000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0 0xe3d3f000 0 0x1000>;
clocks = <&clk_375m>;
clock-names = "apb_pclk";
cpu = <&CPU15>;
port {
ptm15_out_port: endpoint {
remote-endpoint = <&funnel3_in_port3>;
};
};
};
};

View File

@@ -1,185 +0,0 @@
/*
* linux/arch/arm/include/asm/hardware/coresight.h
*
* CoreSight components' registers
*
* Copyright (C) 2009 Nokia Corporation.
* Alexander Shishkin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_HARDWARE_CORESIGHT_H
#define __ASM_HARDWARE_CORESIGHT_H
#define TRACER_ACCESSED_BIT 0
#define TRACER_RUNNING_BIT 1
#define TRACER_CYCLE_ACC_BIT 2
#define TRACER_TRACE_DATA_BIT 3
#define TRACER_TIMESTAMP_BIT 4
#define TRACER_BRANCHOUTPUT_BIT 5
#define TRACER_RETURN_STACK_BIT 6
#define TRACER_ACCESSED BIT(TRACER_ACCESSED_BIT)
#define TRACER_RUNNING BIT(TRACER_RUNNING_BIT)
#define TRACER_CYCLE_ACC BIT(TRACER_CYCLE_ACC_BIT)
#define TRACER_TRACE_DATA BIT(TRACER_TRACE_DATA_BIT)
#define TRACER_TIMESTAMP BIT(TRACER_TIMESTAMP_BIT)
#define TRACER_BRANCHOUTPUT BIT(TRACER_BRANCHOUTPUT_BIT)
#define TRACER_RETURN_STACK BIT(TRACER_RETURN_STACK_BIT)
#define TRACER_TIMEOUT 10000
#define etm_writel(t, v, x) \
(writel_relaxed((v), (t)->etm_regs + (x)))
#define etm_readl(t, x) (readl_relaxed((t)->etm_regs + (x)))
/* CoreSight Management Registers */
#define CSMR_LOCKACCESS 0xfb0
#define CSMR_LOCKSTATUS 0xfb4
#define CSMR_AUTHSTATUS 0xfb8
#define CSMR_DEVID 0xfc8
#define CSMR_DEVTYPE 0xfcc
/* CoreSight Component Registers */
#define CSCR_CLASS 0xff4
#define CS_LAR_KEY 0xc5acce55
/* ETM control register, "ETM Architecture", 3.3.1 */
#define ETMR_CTRL 0
#define ETMCTRL_POWERDOWN 1
#define ETMCTRL_PROGRAM (1 << 10)
#define ETMCTRL_PORTSEL (1 << 11)
#define ETMCTRL_CONTEXTIDSIZE(x) (((x) & 3) << 14)
#define ETMCTRL_PORTMASK1 (7 << 4)
#define ETMCTRL_PORTMASK2 (1 << 21)
#define ETMCTRL_PORTMASK (ETMCTRL_PORTMASK1 | ETMCTRL_PORTMASK2)
#define ETMCTRL_PORTSIZE(x) ((((x) & 7) << 4) | (!!((x) & 8)) << 21)
#define ETMCTRL_DO_CPRT (1 << 1)
#define ETMCTRL_DATAMASK (3 << 2)
#define ETMCTRL_DATA_DO_DATA (1 << 2)
#define ETMCTRL_DATA_DO_ADDR (1 << 3)
#define ETMCTRL_DATA_DO_BOTH (ETMCTRL_DATA_DO_DATA | ETMCTRL_DATA_DO_ADDR)
#define ETMCTRL_BRANCH_OUTPUT (1 << 8)
#define ETMCTRL_CYCLEACCURATE (1 << 12)
#define ETMCTRL_TIMESTAMP_EN (1 << 28)
#define ETMCTRL_RETURN_STACK_EN (1 << 29)
/* ETM configuration code register */
#define ETMR_CONFCODE (0x04)
#define ETMCCR_ETMIDR_PRESENT BIT(31)
/* ETM trace start/stop resource control register */
#define ETMR_TRACESSCTRL (0x18)
/* ETM trigger event register */
#define ETMR_TRIGEVT (0x08)
/* address access type register bits, "ETM architecture",
* table 3-27 */
/* - access type */
#define ETMAAT_IFETCH 0
#define ETMAAT_IEXEC 1
#define ETMAAT_IEXECPASS 2
#define ETMAAT_IEXECFAIL 3
#define ETMAAT_DLOADSTORE 4
#define ETMAAT_DLOAD 5
#define ETMAAT_DSTORE 6
/* - comparison access size */
#define ETMAAT_JAVA (0 << 3)
#define ETMAAT_THUMB (1 << 3)
#define ETMAAT_ARM (3 << 3)
/* - data value comparison control */
#define ETMAAT_NOVALCMP (0 << 5)
#define ETMAAT_VALMATCH (1 << 5)
#define ETMAAT_VALNOMATCH (3 << 5)
/* - exact match */
#define ETMAAT_EXACTMATCH (1 << 7)
/* - context id comparator control */
#define ETMAAT_IGNCONTEXTID (0 << 8)
#define ETMAAT_VALUE1 (1 << 8)
#define ETMAAT_VALUE2 (2 << 8)
#define ETMAAT_VALUE3 (3 << 8)
/* - security level control */
#define ETMAAT_IGNSECURITY (0 << 10)
#define ETMAAT_NSONLY (1 << 10)
#define ETMAAT_SONLY (2 << 10)
#define ETMR_COMP_VAL(x) (0x40 + (x) * 4)
#define ETMR_COMP_ACC_TYPE(x) (0x80 + (x) * 4)
/* ETM status register, "ETM Architecture", 3.3.2 */
#define ETMR_STATUS (0x10)
#define ETMST_OVERFLOW BIT(0)
#define ETMST_PROGBIT BIT(1)
#define ETMST_STARTSTOP BIT(2)
#define ETMST_TRIGGER BIT(3)
#define etm_progbit(t) (etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
#define etm_started(t) (etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
#define etm_triggered(t) (etm_readl((t), ETMR_STATUS) & ETMST_TRIGGER)
#define ETMR_TRACEENCTRL2 0x1c
#define ETMR_TRACEENCTRL 0x24
#define ETMTE_INCLEXCL BIT(24)
#define ETMR_TRACEENEVT 0x20
#define ETMR_VIEWDATAEVT 0x30
#define ETMR_VIEWDATACTRL1 0x34
#define ETMR_VIEWDATACTRL2 0x38
#define ETMR_VIEWDATACTRL3 0x3c
#define ETMVDC3_EXCLONLY BIT(16)
#define ETMCTRL_OPTS (ETMCTRL_DO_CPRT)
#define ETMR_ID 0x1e4
#define ETMIDR_VERSION(x) (((x) >> 4) & 0xff)
#define ETMIDR_VERSION_3_1 0x21
#define ETMIDR_VERSION_PFT_1_0 0x30
#define ETMR_CCE 0x1e8
#define ETMCCER_RETURN_STACK_IMPLEMENTED BIT(23)
#define ETMCCER_TIMESTAMPING_IMPLEMENTED BIT(22)
#define ETMR_TRACEIDR 0x200
/* ETM management registers, "ETM Architecture", 3.5.24 */
#define ETMMR_OSLAR 0x300
#define ETMMR_OSLSR 0x304
#define ETMMR_OSSRR 0x308
#define ETMMR_PDSR 0x314
/* ETB registers, "CoreSight Components TRM", 9.3 */
#define ETBR_DEPTH 0x04
#define ETBR_STATUS 0x0c
#define ETBR_READMEM 0x10
#define ETBR_READADDR 0x14
#define ETBR_WRITEADDR 0x18
#define ETBR_TRIGGERCOUNT 0x1c
#define ETBR_CTRL 0x20
#define ETBR_FORMATTERCTRL 0x304
#define ETBFF_ENFTC 1
#define ETBFF_ENFCONT BIT(1)
#define ETBFF_FONFLIN BIT(4)
#define ETBFF_MANUAL_FLUSH BIT(6)
#define ETBFF_TRIGIN BIT(8)
#define ETBFF_TRIGEVT BIT(9)
#define ETBFF_TRIGFL BIT(10)
#define ETBFF_STOPFL BIT(12)
#define etb_writel(t, v, x) \
(writel_relaxed((v), (t)->etb_regs + (x)))
#define etb_readl(t, x) (readl_relaxed((t)->etb_regs + (x)))
#define etm_lock(t, id) \
do { etm_writel((t), (id), 0, CSMR_LOCKACCESS); } while (0)
#define etm_unlock(t, id) \
do { etm_writel((t), (id), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
#define etb_lock(t) do { etb_writel((t), 0, CSMR_LOCKACCESS); } while (0)
#define etb_unlock(t) \
do { etb_writel((t), CS_LAR_KEY, CSMR_LOCKACCESS); } while (0)
#endif /* __ASM_HARDWARE_CORESIGHT_H */

View File

@@ -0,0 +1,542 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __ASM_HARDWARE_CP14_H
#define __ASM_HARDWARE_CP14_H
#include <linux/types.h>
/* Accessors for CP14 registers */
#define dbg_read(reg) RCP14_##reg()
#define dbg_write(val, reg) WCP14_##reg(val)
#define etm_read(reg) RCP14_##reg()
#define etm_write(val, reg) WCP14_##reg(val)
/* MRC14 and MCR14 */
#define MRC14(op1, crn, crm, op2) \
({ \
u32 val; \
asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val)); \
val; \
})
#define MCR14(val, op1, crn, crm, op2) \
({ \
asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
})
/*
* Debug Registers
*
* Available only in DBGv7
* DBGECR, DBGDSCCR, DBGDSMCR, DBGDRCR
*
* Available only in DBGv7.1
* DBGBXVRm, DBGOSDLR, DBGDEVID2, DBGDEVID1
*
* Read only
* DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGPRSR,
* DBGPRSR, DBGDSAR, DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
*
* Write only
* DBGDTRTXint, DBGOSLAR
*/
#define RCP14_DBGDIDR() MRC14(0, c0, c0, 0)
#define RCP14_DBGDSCRint() MRC14(0, c0, c1, 0)
#define RCP14_DBGDTRRXint() MRC14(0, c0, c5, 0)
#define RCP14_DBGWFAR() MRC14(0, c0, c6, 0)
#define RCP14_DBGVCR() MRC14(0, c0, c7, 0)
#define RCP14_DBGECR() MRC14(0, c0, c9, 0)
#define RCP14_DBGDSCCR() MRC14(0, c0, c10, 0)
#define RCP14_DBGDSMCR() MRC14(0, c0, c11, 0)
#define RCP14_DBGDTRRXext() MRC14(0, c0, c0, 2)
#define RCP14_DBGDSCRext() MRC14(0, c0, c2, 2)
#define RCP14_DBGDTRTXext() MRC14(0, c0, c3, 2)
#define RCP14_DBGDRCR() MRC14(0, c0, c4, 2)
#define RCP14_DBGBVR0() MRC14(0, c0, c0, 4)
#define RCP14_DBGBVR1() MRC14(0, c0, c1, 4)
#define RCP14_DBGBVR2() MRC14(0, c0, c2, 4)
#define RCP14_DBGBVR3() MRC14(0, c0, c3, 4)
#define RCP14_DBGBVR4() MRC14(0, c0, c4, 4)
#define RCP14_DBGBVR5() MRC14(0, c0, c5, 4)
#define RCP14_DBGBVR6() MRC14(0, c0, c6, 4)
#define RCP14_DBGBVR7() MRC14(0, c0, c7, 4)
#define RCP14_DBGBVR8() MRC14(0, c0, c8, 4)
#define RCP14_DBGBVR9() MRC14(0, c0, c9, 4)
#define RCP14_DBGBVR10() MRC14(0, c0, c10, 4)
#define RCP14_DBGBVR11() MRC14(0, c0, c11, 4)
#define RCP14_DBGBVR12() MRC14(0, c0, c12, 4)
#define RCP14_DBGBVR13() MRC14(0, c0, c13, 4)
#define RCP14_DBGBVR14() MRC14(0, c0, c14, 4)
#define RCP14_DBGBVR15() MRC14(0, c0, c15, 4)
#define RCP14_DBGBCR0() MRC14(0, c0, c0, 5)
#define RCP14_DBGBCR1() MRC14(0, c0, c1, 5)
#define RCP14_DBGBCR2() MRC14(0, c0, c2, 5)
#define RCP14_DBGBCR3() MRC14(0, c0, c3, 5)
#define RCP14_DBGBCR4() MRC14(0, c0, c4, 5)
#define RCP14_DBGBCR5() MRC14(0, c0, c5, 5)
#define RCP14_DBGBCR6() MRC14(0, c0, c6, 5)
#define RCP14_DBGBCR7() MRC14(0, c0, c7, 5)
#define RCP14_DBGBCR8() MRC14(0, c0, c8, 5)
#define RCP14_DBGBCR9() MRC14(0, c0, c9, 5)
#define RCP14_DBGBCR10() MRC14(0, c0, c10, 5)
#define RCP14_DBGBCR11() MRC14(0, c0, c11, 5)
#define RCP14_DBGBCR12() MRC14(0, c0, c12, 5)
#define RCP14_DBGBCR13() MRC14(0, c0, c13, 5)
#define RCP14_DBGBCR14() MRC14(0, c0, c14, 5)
#define RCP14_DBGBCR15() MRC14(0, c0, c15, 5)
#define RCP14_DBGWVR0() MRC14(0, c0, c0, 6)
#define RCP14_DBGWVR1() MRC14(0, c0, c1, 6)
#define RCP14_DBGWVR2() MRC14(0, c0, c2, 6)
#define RCP14_DBGWVR3() MRC14(0, c0, c3, 6)
#define RCP14_DBGWVR4() MRC14(0, c0, c4, 6)
#define RCP14_DBGWVR5() MRC14(0, c0, c5, 6)
#define RCP14_DBGWVR6() MRC14(0, c0, c6, 6)
#define RCP14_DBGWVR7() MRC14(0, c0, c7, 6)
#define RCP14_DBGWVR8() MRC14(0, c0, c8, 6)
#define RCP14_DBGWVR9() MRC14(0, c0, c9, 6)
#define RCP14_DBGWVR10() MRC14(0, c0, c10, 6)
#define RCP14_DBGWVR11() MRC14(0, c0, c11, 6)
#define RCP14_DBGWVR12() MRC14(0, c0, c12, 6)
#define RCP14_DBGWVR13() MRC14(0, c0, c13, 6)
#define RCP14_DBGWVR14() MRC14(0, c0, c14, 6)
#define RCP14_DBGWVR15() MRC14(0, c0, c15, 6)
#define RCP14_DBGWCR0() MRC14(0, c0, c0, 7)
#define RCP14_DBGWCR1() MRC14(0, c0, c1, 7)
#define RCP14_DBGWCR2() MRC14(0, c0, c2, 7)
#define RCP14_DBGWCR3() MRC14(0, c0, c3, 7)
#define RCP14_DBGWCR4() MRC14(0, c0, c4, 7)
#define RCP14_DBGWCR5() MRC14(0, c0, c5, 7)
#define RCP14_DBGWCR6() MRC14(0, c0, c6, 7)
#define RCP14_DBGWCR7() MRC14(0, c0, c7, 7)
#define RCP14_DBGWCR8() MRC14(0, c0, c8, 7)
#define RCP14_DBGWCR9() MRC14(0, c0, c9, 7)
#define RCP14_DBGWCR10() MRC14(0, c0, c10, 7)
#define RCP14_DBGWCR11() MRC14(0, c0, c11, 7)
#define RCP14_DBGWCR12() MRC14(0, c0, c12, 7)
#define RCP14_DBGWCR13() MRC14(0, c0, c13, 7)
#define RCP14_DBGWCR14() MRC14(0, c0, c14, 7)
#define RCP14_DBGWCR15() MRC14(0, c0, c15, 7)
#define RCP14_DBGDRAR() MRC14(0, c1, c0, 0)
#define RCP14_DBGBXVR0() MRC14(0, c1, c0, 1)
#define RCP14_DBGBXVR1() MRC14(0, c1, c1, 1)
#define RCP14_DBGBXVR2() MRC14(0, c1, c2, 1)
#define RCP14_DBGBXVR3() MRC14(0, c1, c3, 1)
#define RCP14_DBGBXVR4() MRC14(0, c1, c4, 1)
#define RCP14_DBGBXVR5() MRC14(0, c1, c5, 1)
#define RCP14_DBGBXVR6() MRC14(0, c1, c6, 1)
#define RCP14_DBGBXVR7() MRC14(0, c1, c7, 1)
#define RCP14_DBGBXVR8() MRC14(0, c1, c8, 1)
#define RCP14_DBGBXVR9() MRC14(0, c1, c9, 1)
#define RCP14_DBGBXVR10() MRC14(0, c1, c10, 1)
#define RCP14_DBGBXVR11() MRC14(0, c1, c11, 1)
#define RCP14_DBGBXVR12() MRC14(0, c1, c12, 1)
#define RCP14_DBGBXVR13() MRC14(0, c1, c13, 1)
#define RCP14_DBGBXVR14() MRC14(0, c1, c14, 1)
#define RCP14_DBGBXVR15() MRC14(0, c1, c15, 1)
#define RCP14_DBGOSLSR() MRC14(0, c1, c1, 4)
#define RCP14_DBGOSSRR() MRC14(0, c1, c2, 4)
#define RCP14_DBGOSDLR() MRC14(0, c1, c3, 4)
#define RCP14_DBGPRCR() MRC14(0, c1, c4, 4)
#define RCP14_DBGPRSR() MRC14(0, c1, c5, 4)
#define RCP14_DBGDSAR() MRC14(0, c2, c0, 0)
#define RCP14_DBGITCTRL() MRC14(0, c7, c0, 4)
#define RCP14_DBGCLAIMSET() MRC14(0, c7, c8, 6)
#define RCP14_DBGCLAIMCLR() MRC14(0, c7, c9, 6)
#define RCP14_DBGAUTHSTATUS() MRC14(0, c7, c14, 6)
#define RCP14_DBGDEVID2() MRC14(0, c7, c0, 7)
#define RCP14_DBGDEVID1() MRC14(0, c7, c1, 7)
#define RCP14_DBGDEVID() MRC14(0, c7, c2, 7)
#define WCP14_DBGDTRTXint(val) MCR14(val, 0, c0, c5, 0)
#define WCP14_DBGWFAR(val) MCR14(val, 0, c0, c6, 0)
#define WCP14_DBGVCR(val) MCR14(val, 0, c0, c7, 0)
#define WCP14_DBGECR(val) MCR14(val, 0, c0, c9, 0)
#define WCP14_DBGDSCCR(val) MCR14(val, 0, c0, c10, 0)
#define WCP14_DBGDSMCR(val) MCR14(val, 0, c0, c11, 0)
#define WCP14_DBGDTRRXext(val) MCR14(val, 0, c0, c0, 2)
#define WCP14_DBGDSCRext(val) MCR14(val, 0, c0, c2, 2)
#define WCP14_DBGDTRTXext(val) MCR14(val, 0, c0, c3, 2)
#define WCP14_DBGDRCR(val) MCR14(val, 0, c0, c4, 2)
#define WCP14_DBGBVR0(val) MCR14(val, 0, c0, c0, 4)
#define WCP14_DBGBVR1(val) MCR14(val, 0, c0, c1, 4)
#define WCP14_DBGBVR2(val) MCR14(val, 0, c0, c2, 4)
#define WCP14_DBGBVR3(val) MCR14(val, 0, c0, c3, 4)
#define WCP14_DBGBVR4(val) MCR14(val, 0, c0, c4, 4)
#define WCP14_DBGBVR5(val) MCR14(val, 0, c0, c5, 4)
#define WCP14_DBGBVR6(val) MCR14(val, 0, c0, c6, 4)
#define WCP14_DBGBVR7(val) MCR14(val, 0, c0, c7, 4)
#define WCP14_DBGBVR8(val) MCR14(val, 0, c0, c8, 4)
#define WCP14_DBGBVR9(val) MCR14(val, 0, c0, c9, 4)
#define WCP14_DBGBVR10(val) MCR14(val, 0, c0, c10, 4)
#define WCP14_DBGBVR11(val) MCR14(val, 0, c0, c11, 4)
#define WCP14_DBGBVR12(val) MCR14(val, 0, c0, c12, 4)
#define WCP14_DBGBVR13(val) MCR14(val, 0, c0, c13, 4)
#define WCP14_DBGBVR14(val) MCR14(val, 0, c0, c14, 4)
#define WCP14_DBGBVR15(val) MCR14(val, 0, c0, c15, 4)
#define WCP14_DBGBCR0(val) MCR14(val, 0, c0, c0, 5)
#define WCP14_DBGBCR1(val) MCR14(val, 0, c0, c1, 5)
#define WCP14_DBGBCR2(val) MCR14(val, 0, c0, c2, 5)
#define WCP14_DBGBCR3(val) MCR14(val, 0, c0, c3, 5)
#define WCP14_DBGBCR4(val) MCR14(val, 0, c0, c4, 5)
#define WCP14_DBGBCR5(val) MCR14(val, 0, c0, c5, 5)
#define WCP14_DBGBCR6(val) MCR14(val, 0, c0, c6, 5)
#define WCP14_DBGBCR7(val) MCR14(val, 0, c0, c7, 5)
#define WCP14_DBGBCR8(val) MCR14(val, 0, c0, c8, 5)
#define WCP14_DBGBCR9(val) MCR14(val, 0, c0, c9, 5)
#define WCP14_DBGBCR10(val) MCR14(val, 0, c0, c10, 5)
#define WCP14_DBGBCR11(val) MCR14(val, 0, c0, c11, 5)
#define WCP14_DBGBCR12(val) MCR14(val, 0, c0, c12, 5)
#define WCP14_DBGBCR13(val) MCR14(val, 0, c0, c13, 5)
#define WCP14_DBGBCR14(val) MCR14(val, 0, c0, c14, 5)
#define WCP14_DBGBCR15(val) MCR14(val, 0, c0, c15, 5)
#define WCP14_DBGWVR0(val) MCR14(val, 0, c0, c0, 6)
#define WCP14_DBGWVR1(val) MCR14(val, 0, c0, c1, 6)
#define WCP14_DBGWVR2(val) MCR14(val, 0, c0, c2, 6)
#define WCP14_DBGWVR3(val) MCR14(val, 0, c0, c3, 6)
#define WCP14_DBGWVR4(val) MCR14(val, 0, c0, c4, 6)
#define WCP14_DBGWVR5(val) MCR14(val, 0, c0, c5, 6)
#define WCP14_DBGWVR6(val) MCR14(val, 0, c0, c6, 6)
#define WCP14_DBGWVR7(val) MCR14(val, 0, c0, c7, 6)
#define WCP14_DBGWVR8(val) MCR14(val, 0, c0, c8, 6)
#define WCP14_DBGWVR9(val) MCR14(val, 0, c0, c9, 6)
#define WCP14_DBGWVR10(val) MCR14(val, 0, c0, c10, 6)
#define WCP14_DBGWVR11(val) MCR14(val, 0, c0, c11, 6)
#define WCP14_DBGWVR12(val) MCR14(val, 0, c0, c12, 6)
#define WCP14_DBGWVR13(val) MCR14(val, 0, c0, c13, 6)
#define WCP14_DBGWVR14(val) MCR14(val, 0, c0, c14, 6)
#define WCP14_DBGWVR15(val) MCR14(val, 0, c0, c15, 6)
#define WCP14_DBGWCR0(val) MCR14(val, 0, c0, c0, 7)
#define WCP14_DBGWCR1(val) MCR14(val, 0, c0, c1, 7)
#define WCP14_DBGWCR2(val) MCR14(val, 0, c0, c2, 7)
#define WCP14_DBGWCR3(val) MCR14(val, 0, c0, c3, 7)
#define WCP14_DBGWCR4(val) MCR14(val, 0, c0, c4, 7)
#define WCP14_DBGWCR5(val) MCR14(val, 0, c0, c5, 7)
#define WCP14_DBGWCR6(val) MCR14(val, 0, c0, c6, 7)
#define WCP14_DBGWCR7(val) MCR14(val, 0, c0, c7, 7)
#define WCP14_DBGWCR8(val) MCR14(val, 0, c0, c8, 7)
#define WCP14_DBGWCR9(val) MCR14(val, 0, c0, c9, 7)
#define WCP14_DBGWCR10(val) MCR14(val, 0, c0, c10, 7)
#define WCP14_DBGWCR11(val) MCR14(val, 0, c0, c11, 7)
#define WCP14_DBGWCR12(val) MCR14(val, 0, c0, c12, 7)
#define WCP14_DBGWCR13(val) MCR14(val, 0, c0, c13, 7)
#define WCP14_DBGWCR14(val) MCR14(val, 0, c0, c14, 7)
#define WCP14_DBGWCR15(val) MCR14(val, 0, c0, c15, 7)
#define WCP14_DBGBXVR0(val) MCR14(val, 0, c1, c0, 1)
#define WCP14_DBGBXVR1(val) MCR14(val, 0, c1, c1, 1)
#define WCP14_DBGBXVR2(val) MCR14(val, 0, c1, c2, 1)
#define WCP14_DBGBXVR3(val) MCR14(val, 0, c1, c3, 1)
#define WCP14_DBGBXVR4(val) MCR14(val, 0, c1, c4, 1)
#define WCP14_DBGBXVR5(val) MCR14(val, 0, c1, c5, 1)
#define WCP14_DBGBXVR6(val) MCR14(val, 0, c1, c6, 1)
#define WCP14_DBGBXVR7(val) MCR14(val, 0, c1, c7, 1)
#define WCP14_DBGBXVR8(val) MCR14(val, 0, c1, c8, 1)
#define WCP14_DBGBXVR9(val) MCR14(val, 0, c1, c9, 1)
#define WCP14_DBGBXVR10(val) MCR14(val, 0, c1, c10, 1)
#define WCP14_DBGBXVR11(val) MCR14(val, 0, c1, c11, 1)
#define WCP14_DBGBXVR12(val) MCR14(val, 0, c1, c12, 1)
#define WCP14_DBGBXVR13(val) MCR14(val, 0, c1, c13, 1)
#define WCP14_DBGBXVR14(val) MCR14(val, 0, c1, c14, 1)
#define WCP14_DBGBXVR15(val) MCR14(val, 0, c1, c15, 1)
#define WCP14_DBGOSLAR(val) MCR14(val, 0, c1, c0, 4)
#define WCP14_DBGOSSRR(val) MCR14(val, 0, c1, c2, 4)
#define WCP14_DBGOSDLR(val) MCR14(val, 0, c1, c3, 4)
#define WCP14_DBGPRCR(val) MCR14(val, 0, c1, c4, 4)
#define WCP14_DBGITCTRL(val) MCR14(val, 0, c7, c0, 4)
#define WCP14_DBGCLAIMSET(val) MCR14(val, 0, c7, c8, 6)
#define WCP14_DBGCLAIMCLR(val) MCR14(val, 0, c7, c9, 6)
/*
* ETM Registers
*
* Available only in ETMv3.3, 3.4, 3.5
* ETMASICCR, ETMTECR2, ETMFFRR, ETMVDEVR, ETMVDCR1, ETMVDCR2, ETMVDCR3,
* ETMDCVRn, ETMDCMRn
*
* Available only in ETMv3.5 as read only
* ETMIDR2
*
* Available only in ETMv3.5, PFTv1.0, 1.1
* ETMTSEVR, ETMVMIDCVR, ETMPDCR
*
* Read only
* ETMCCR, ETMSCR, ETMIDR, ETMCCER, ETMOSLSR
* ETMLSR, ETMAUTHSTATUS, ETMDEVID, ETMDEVTYPE, ETMPIDR4, ETMPIDR5, ETMPIDR6,
* ETMPIDR7, ETMPIDR0, ETMPIDR1, ETMPIDR2, ETMPIDR2, ETMPIDR3, ETMCIDR0,
* ETMCIDR1, ETMCIDR2, ETMCIDR3
*
* Write only
* ETMOSLAR, ETMLAR
* Note: ETMCCER[11] controls WO nature of certain regs. Refer ETM arch spec.
*/
#define RCP14_ETMCR() MRC14(1, c0, c0, 0)
#define RCP14_ETMCCR() MRC14(1, c0, c1, 0)
#define RCP14_ETMTRIGGER() MRC14(1, c0, c2, 0)
#define RCP14_ETMASICCR() MRC14(1, c0, c3, 0)
#define RCP14_ETMSR() MRC14(1, c0, c4, 0)
#define RCP14_ETMSCR() MRC14(1, c0, c5, 0)
#define RCP14_ETMTSSCR() MRC14(1, c0, c6, 0)
#define RCP14_ETMTECR2() MRC14(1, c0, c7, 0)
#define RCP14_ETMTEEVR() MRC14(1, c0, c8, 0)
#define RCP14_ETMTECR1() MRC14(1, c0, c9, 0)
#define RCP14_ETMFFRR() MRC14(1, c0, c10, 0)
#define RCP14_ETMFFLR() MRC14(1, c0, c11, 0)
#define RCP14_ETMVDEVR() MRC14(1, c0, c12, 0)
#define RCP14_ETMVDCR1() MRC14(1, c0, c13, 0)
#define RCP14_ETMVDCR2() MRC14(1, c0, c14, 0)
#define RCP14_ETMVDCR3() MRC14(1, c0, c15, 0)
#define RCP14_ETMACVR0() MRC14(1, c0, c0, 1)
#define RCP14_ETMACVR1() MRC14(1, c0, c1, 1)
#define RCP14_ETMACVR2() MRC14(1, c0, c2, 1)
#define RCP14_ETMACVR3() MRC14(1, c0, c3, 1)
#define RCP14_ETMACVR4() MRC14(1, c0, c4, 1)
#define RCP14_ETMACVR5() MRC14(1, c0, c5, 1)
#define RCP14_ETMACVR6() MRC14(1, c0, c6, 1)
#define RCP14_ETMACVR7() MRC14(1, c0, c7, 1)
#define RCP14_ETMACVR8() MRC14(1, c0, c8, 1)
#define RCP14_ETMACVR9() MRC14(1, c0, c9, 1)
#define RCP14_ETMACVR10() MRC14(1, c0, c10, 1)
#define RCP14_ETMACVR11() MRC14(1, c0, c11, 1)
#define RCP14_ETMACVR12() MRC14(1, c0, c12, 1)
#define RCP14_ETMACVR13() MRC14(1, c0, c13, 1)
#define RCP14_ETMACVR14() MRC14(1, c0, c14, 1)
#define RCP14_ETMACVR15() MRC14(1, c0, c15, 1)
#define RCP14_ETMACTR0() MRC14(1, c0, c0, 2)
#define RCP14_ETMACTR1() MRC14(1, c0, c1, 2)
#define RCP14_ETMACTR2() MRC14(1, c0, c2, 2)
#define RCP14_ETMACTR3() MRC14(1, c0, c3, 2)
#define RCP14_ETMACTR4() MRC14(1, c0, c4, 2)
#define RCP14_ETMACTR5() MRC14(1, c0, c5, 2)
#define RCP14_ETMACTR6() MRC14(1, c0, c6, 2)
#define RCP14_ETMACTR7() MRC14(1, c0, c7, 2)
#define RCP14_ETMACTR8() MRC14(1, c0, c8, 2)
#define RCP14_ETMACTR9() MRC14(1, c0, c9, 2)
#define RCP14_ETMACTR10() MRC14(1, c0, c10, 2)
#define RCP14_ETMACTR11() MRC14(1, c0, c11, 2)
#define RCP14_ETMACTR12() MRC14(1, c0, c12, 2)
#define RCP14_ETMACTR13() MRC14(1, c0, c13, 2)
#define RCP14_ETMACTR14() MRC14(1, c0, c14, 2)
#define RCP14_ETMACTR15() MRC14(1, c0, c15, 2)
#define RCP14_ETMDCVR0() MRC14(1, c0, c0, 3)
#define RCP14_ETMDCVR2() MRC14(1, c0, c2, 3)
#define RCP14_ETMDCVR4() MRC14(1, c0, c4, 3)
#define RCP14_ETMDCVR6() MRC14(1, c0, c6, 3)
#define RCP14_ETMDCVR8() MRC14(1, c0, c8, 3)
#define RCP14_ETMDCVR10() MRC14(1, c0, c10, 3)
#define RCP14_ETMDCVR12() MRC14(1, c0, c12, 3)
#define RCP14_ETMDCVR14() MRC14(1, c0, c14, 3)
#define RCP14_ETMDCMR0() MRC14(1, c0, c0, 4)
#define RCP14_ETMDCMR2() MRC14(1, c0, c2, 4)
#define RCP14_ETMDCMR4() MRC14(1, c0, c4, 4)
#define RCP14_ETMDCMR6() MRC14(1, c0, c6, 4)
#define RCP14_ETMDCMR8() MRC14(1, c0, c8, 4)
#define RCP14_ETMDCMR10() MRC14(1, c0, c10, 4)
#define RCP14_ETMDCMR12() MRC14(1, c0, c12, 4)
#define RCP14_ETMDCMR14() MRC14(1, c0, c14, 4)
#define RCP14_ETMCNTRLDVR0() MRC14(1, c0, c0, 5)
#define RCP14_ETMCNTRLDVR1() MRC14(1, c0, c1, 5)
#define RCP14_ETMCNTRLDVR2() MRC14(1, c0, c2, 5)
#define RCP14_ETMCNTRLDVR3() MRC14(1, c0, c3, 5)
#define RCP14_ETMCNTENR0() MRC14(1, c0, c4, 5)
#define RCP14_ETMCNTENR1() MRC14(1, c0, c5, 5)
#define RCP14_ETMCNTENR2() MRC14(1, c0, c6, 5)
#define RCP14_ETMCNTENR3() MRC14(1, c0, c7, 5)
#define RCP14_ETMCNTRLDEVR0() MRC14(1, c0, c8, 5)
#define RCP14_ETMCNTRLDEVR1() MRC14(1, c0, c9, 5)
#define RCP14_ETMCNTRLDEVR2() MRC14(1, c0, c10, 5)
#define RCP14_ETMCNTRLDEVR3() MRC14(1, c0, c11, 5)
#define RCP14_ETMCNTVR0() MRC14(1, c0, c12, 5)
#define RCP14_ETMCNTVR1() MRC14(1, c0, c13, 5)
#define RCP14_ETMCNTVR2() MRC14(1, c0, c14, 5)
#define RCP14_ETMCNTVR3() MRC14(1, c0, c15, 5)
#define RCP14_ETMSQ12EVR() MRC14(1, c0, c0, 6)
#define RCP14_ETMSQ21EVR() MRC14(1, c0, c1, 6)
#define RCP14_ETMSQ23EVR() MRC14(1, c0, c2, 6)
#define RCP14_ETMSQ31EVR() MRC14(1, c0, c3, 6)
#define RCP14_ETMSQ32EVR() MRC14(1, c0, c4, 6)
#define RCP14_ETMSQ13EVR() MRC14(1, c0, c5, 6)
#define RCP14_ETMSQR() MRC14(1, c0, c7, 6)
#define RCP14_ETMEXTOUTEVR0() MRC14(1, c0, c8, 6)
#define RCP14_ETMEXTOUTEVR1() MRC14(1, c0, c9, 6)
#define RCP14_ETMEXTOUTEVR2() MRC14(1, c0, c10, 6)
#define RCP14_ETMEXTOUTEVR3() MRC14(1, c0, c11, 6)
#define RCP14_ETMCIDCVR0() MRC14(1, c0, c12, 6)
#define RCP14_ETMCIDCVR1() MRC14(1, c0, c13, 6)
#define RCP14_ETMCIDCVR2() MRC14(1, c0, c14, 6)
#define RCP14_ETMCIDCMR() MRC14(1, c0, c15, 6)
#define RCP14_ETMIMPSPEC0() MRC14(1, c0, c0, 7)
#define RCP14_ETMIMPSPEC1() MRC14(1, c0, c1, 7)
#define RCP14_ETMIMPSPEC2() MRC14(1, c0, c2, 7)
#define RCP14_ETMIMPSPEC3() MRC14(1, c0, c3, 7)
#define RCP14_ETMIMPSPEC4() MRC14(1, c0, c4, 7)
#define RCP14_ETMIMPSPEC5() MRC14(1, c0, c5, 7)
#define RCP14_ETMIMPSPEC6() MRC14(1, c0, c6, 7)
#define RCP14_ETMIMPSPEC7() MRC14(1, c0, c7, 7)
#define RCP14_ETMSYNCFR() MRC14(1, c0, c8, 7)
#define RCP14_ETMIDR() MRC14(1, c0, c9, 7)
#define RCP14_ETMCCER() MRC14(1, c0, c10, 7)
#define RCP14_ETMEXTINSELR() MRC14(1, c0, c11, 7)
#define RCP14_ETMTESSEICR() MRC14(1, c0, c12, 7)
#define RCP14_ETMEIBCR() MRC14(1, c0, c13, 7)
#define RCP14_ETMTSEVR() MRC14(1, c0, c14, 7)
#define RCP14_ETMAUXCR() MRC14(1, c0, c15, 7)
#define RCP14_ETMTRACEIDR() MRC14(1, c1, c0, 0)
#define RCP14_ETMIDR2() MRC14(1, c1, c2, 0)
#define RCP14_ETMVMIDCVR() MRC14(1, c1, c0, 1)
#define RCP14_ETMOSLSR() MRC14(1, c1, c1, 4)
/* Not available in PFTv1.1 */
#define RCP14_ETMOSSRR() MRC14(1, c1, c2, 4)
#define RCP14_ETMPDCR() MRC14(1, c1, c4, 4)
#define RCP14_ETMPDSR() MRC14(1, c1, c5, 4)
#define RCP14_ETMITCTRL() MRC14(1, c7, c0, 4)
#define RCP14_ETMCLAIMSET() MRC14(1, c7, c8, 6)
#define RCP14_ETMCLAIMCLR() MRC14(1, c7, c9, 6)
#define RCP14_ETMLSR() MRC14(1, c7, c13, 6)
#define RCP14_ETMAUTHSTATUS() MRC14(1, c7, c14, 6)
#define RCP14_ETMDEVID() MRC14(1, c7, c2, 7)
#define RCP14_ETMDEVTYPE() MRC14(1, c7, c3, 7)
#define RCP14_ETMPIDR4() MRC14(1, c7, c4, 7)
#define RCP14_ETMPIDR5() MRC14(1, c7, c5, 7)
#define RCP14_ETMPIDR6() MRC14(1, c7, c6, 7)
#define RCP14_ETMPIDR7() MRC14(1, c7, c7, 7)
#define RCP14_ETMPIDR0() MRC14(1, c7, c8, 7)
#define RCP14_ETMPIDR1() MRC14(1, c7, c9, 7)
#define RCP14_ETMPIDR2() MRC14(1, c7, c10, 7)
#define RCP14_ETMPIDR3() MRC14(1, c7, c11, 7)
#define RCP14_ETMCIDR0() MRC14(1, c7, c12, 7)
#define RCP14_ETMCIDR1() MRC14(1, c7, c13, 7)
#define RCP14_ETMCIDR2() MRC14(1, c7, c14, 7)
#define RCP14_ETMCIDR3() MRC14(1, c7, c15, 7)
#define WCP14_ETMCR(val) MCR14(val, 1, c0, c0, 0)
#define WCP14_ETMTRIGGER(val) MCR14(val, 1, c0, c2, 0)
#define WCP14_ETMASICCR(val) MCR14(val, 1, c0, c3, 0)
#define WCP14_ETMSR(val) MCR14(val, 1, c0, c4, 0)
#define WCP14_ETMTSSCR(val) MCR14(val, 1, c0, c6, 0)
#define WCP14_ETMTECR2(val) MCR14(val, 1, c0, c7, 0)
#define WCP14_ETMTEEVR(val) MCR14(val, 1, c0, c8, 0)
#define WCP14_ETMTECR1(val) MCR14(val, 1, c0, c9, 0)
#define WCP14_ETMFFRR(val) MCR14(val, 1, c0, c10, 0)
#define WCP14_ETMFFLR(val) MCR14(val, 1, c0, c11, 0)
#define WCP14_ETMVDEVR(val) MCR14(val, 1, c0, c12, 0)
#define WCP14_ETMVDCR1(val) MCR14(val, 1, c0, c13, 0)
#define WCP14_ETMVDCR2(val) MCR14(val, 1, c0, c14, 0)
#define WCP14_ETMVDCR3(val) MCR14(val, 1, c0, c15, 0)
#define WCP14_ETMACVR0(val) MCR14(val, 1, c0, c0, 1)
#define WCP14_ETMACVR1(val) MCR14(val, 1, c0, c1, 1)
#define WCP14_ETMACVR2(val) MCR14(val, 1, c0, c2, 1)
#define WCP14_ETMACVR3(val) MCR14(val, 1, c0, c3, 1)
#define WCP14_ETMACVR4(val) MCR14(val, 1, c0, c4, 1)
#define WCP14_ETMACVR5(val) MCR14(val, 1, c0, c5, 1)
#define WCP14_ETMACVR6(val) MCR14(val, 1, c0, c6, 1)
#define WCP14_ETMACVR7(val) MCR14(val, 1, c0, c7, 1)
#define WCP14_ETMACVR8(val) MCR14(val, 1, c0, c8, 1)
#define WCP14_ETMACVR9(val) MCR14(val, 1, c0, c9, 1)
#define WCP14_ETMACVR10(val) MCR14(val, 1, c0, c10, 1)
#define WCP14_ETMACVR11(val) MCR14(val, 1, c0, c11, 1)
#define WCP14_ETMACVR12(val) MCR14(val, 1, c0, c12, 1)
#define WCP14_ETMACVR13(val) MCR14(val, 1, c0, c13, 1)
#define WCP14_ETMACVR14(val) MCR14(val, 1, c0, c14, 1)
#define WCP14_ETMACVR15(val) MCR14(val, 1, c0, c15, 1)
#define WCP14_ETMACTR0(val) MCR14(val, 1, c0, c0, 2)
#define WCP14_ETMACTR1(val) MCR14(val, 1, c0, c1, 2)
#define WCP14_ETMACTR2(val) MCR14(val, 1, c0, c2, 2)
#define WCP14_ETMACTR3(val) MCR14(val, 1, c0, c3, 2)
#define WCP14_ETMACTR4(val) MCR14(val, 1, c0, c4, 2)
#define WCP14_ETMACTR5(val) MCR14(val, 1, c0, c5, 2)
#define WCP14_ETMACTR6(val) MCR14(val, 1, c0, c6, 2)
#define WCP14_ETMACTR7(val) MCR14(val, 1, c0, c7, 2)
#define WCP14_ETMACTR8(val) MCR14(val, 1, c0, c8, 2)
#define WCP14_ETMACTR9(val) MCR14(val, 1, c0, c9, 2)
#define WCP14_ETMACTR10(val) MCR14(val, 1, c0, c10, 2)
#define WCP14_ETMACTR11(val) MCR14(val, 1, c0, c11, 2)
#define WCP14_ETMACTR12(val) MCR14(val, 1, c0, c12, 2)
#define WCP14_ETMACTR13(val) MCR14(val, 1, c0, c13, 2)
#define WCP14_ETMACTR14(val) MCR14(val, 1, c0, c14, 2)
#define WCP14_ETMACTR15(val) MCR14(val, 1, c0, c15, 2)
#define WCP14_ETMDCVR0(val) MCR14(val, 1, c0, c0, 3)
#define WCP14_ETMDCVR2(val) MCR14(val, 1, c0, c2, 3)
#define WCP14_ETMDCVR4(val) MCR14(val, 1, c0, c4, 3)
#define WCP14_ETMDCVR6(val) MCR14(val, 1, c0, c6, 3)
#define WCP14_ETMDCVR8(val) MCR14(val, 1, c0, c8, 3)
#define WCP14_ETMDCVR10(val) MCR14(val, 1, c0, c10, 3)
#define WCP14_ETMDCVR12(val) MCR14(val, 1, c0, c12, 3)
#define WCP14_ETMDCVR14(val) MCR14(val, 1, c0, c14, 3)
#define WCP14_ETMDCMR0(val) MCR14(val, 1, c0, c0, 4)
#define WCP14_ETMDCMR2(val) MCR14(val, 1, c0, c2, 4)
#define WCP14_ETMDCMR4(val) MCR14(val, 1, c0, c4, 4)
#define WCP14_ETMDCMR6(val) MCR14(val, 1, c0, c6, 4)
#define WCP14_ETMDCMR8(val) MCR14(val, 1, c0, c8, 4)
#define WCP14_ETMDCMR10(val) MCR14(val, 1, c0, c10, 4)
#define WCP14_ETMDCMR12(val) MCR14(val, 1, c0, c12, 4)
#define WCP14_ETMDCMR14(val) MCR14(val, 1, c0, c14, 4)
#define WCP14_ETMCNTRLDVR0(val) MCR14(val, 1, c0, c0, 5)
#define WCP14_ETMCNTRLDVR1(val) MCR14(val, 1, c0, c1, 5)
#define WCP14_ETMCNTRLDVR2(val) MCR14(val, 1, c0, c2, 5)
#define WCP14_ETMCNTRLDVR3(val) MCR14(val, 1, c0, c3, 5)
#define WCP14_ETMCNTENR0(val) MCR14(val, 1, c0, c4, 5)
#define WCP14_ETMCNTENR1(val) MCR14(val, 1, c0, c5, 5)
#define WCP14_ETMCNTENR2(val) MCR14(val, 1, c0, c6, 5)
#define WCP14_ETMCNTENR3(val) MCR14(val, 1, c0, c7, 5)
#define WCP14_ETMCNTRLDEVR0(val) MCR14(val, 1, c0, c8, 5)
#define WCP14_ETMCNTRLDEVR1(val) MCR14(val, 1, c0, c9, 5)
#define WCP14_ETMCNTRLDEVR2(val) MCR14(val, 1, c0, c10, 5)
#define WCP14_ETMCNTRLDEVR3(val) MCR14(val, 1, c0, c11, 5)
#define WCP14_ETMCNTVR0(val) MCR14(val, 1, c0, c12, 5)
#define WCP14_ETMCNTVR1(val) MCR14(val, 1, c0, c13, 5)
#define WCP14_ETMCNTVR2(val) MCR14(val, 1, c0, c14, 5)
#define WCP14_ETMCNTVR3(val) MCR14(val, 1, c0, c15, 5)
#define WCP14_ETMSQ12EVR(val) MCR14(val, 1, c0, c0, 6)
#define WCP14_ETMSQ21EVR(val) MCR14(val, 1, c0, c1, 6)
#define WCP14_ETMSQ23EVR(val) MCR14(val, 1, c0, c2, 6)
#define WCP14_ETMSQ31EVR(val) MCR14(val, 1, c0, c3, 6)
#define WCP14_ETMSQ32EVR(val) MCR14(val, 1, c0, c4, 6)
#define WCP14_ETMSQ13EVR(val) MCR14(val, 1, c0, c5, 6)
#define WCP14_ETMSQR(val) MCR14(val, 1, c0, c7, 6)
#define WCP14_ETMEXTOUTEVR0(val) MCR14(val, 1, c0, c8, 6)
#define WCP14_ETMEXTOUTEVR1(val) MCR14(val, 1, c0, c9, 6)
#define WCP14_ETMEXTOUTEVR2(val) MCR14(val, 1, c0, c10, 6)
#define WCP14_ETMEXTOUTEVR3(val) MCR14(val, 1, c0, c11, 6)
#define WCP14_ETMCIDCVR0(val) MCR14(val, 1, c0, c12, 6)
#define WCP14_ETMCIDCVR1(val) MCR14(val, 1, c0, c13, 6)
#define WCP14_ETMCIDCVR2(val) MCR14(val, 1, c0, c14, 6)
#define WCP14_ETMCIDCMR(val) MCR14(val, 1, c0, c15, 6)
#define WCP14_ETMIMPSPEC0(val) MCR14(val, 1, c0, c0, 7)
#define WCP14_ETMIMPSPEC1(val) MCR14(val, 1, c0, c1, 7)
#define WCP14_ETMIMPSPEC2(val) MCR14(val, 1, c0, c2, 7)
#define WCP14_ETMIMPSPEC3(val) MCR14(val, 1, c0, c3, 7)
#define WCP14_ETMIMPSPEC4(val) MCR14(val, 1, c0, c4, 7)
#define WCP14_ETMIMPSPEC5(val) MCR14(val, 1, c0, c5, 7)
#define WCP14_ETMIMPSPEC6(val) MCR14(val, 1, c0, c6, 7)
#define WCP14_ETMIMPSPEC7(val) MCR14(val, 1, c0, c7, 7)
/* Can be read only in ETMv3.4, ETMv3.5 */
#define WCP14_ETMSYNCFR(val) MCR14(val, 1, c0, c8, 7)
#define WCP14_ETMEXTINSELR(val) MCR14(val, 1, c0, c11, 7)
#define WCP14_ETMTESSEICR(val) MCR14(val, 1, c0, c12, 7)
#define WCP14_ETMEIBCR(val) MCR14(val, 1, c0, c13, 7)
#define WCP14_ETMTSEVR(val) MCR14(val, 1, c0, c14, 7)
#define WCP14_ETMAUXCR(val) MCR14(val, 1, c0, c15, 7)
#define WCP14_ETMTRACEIDR(val) MCR14(val, 1, c1, c0, 0)
#define WCP14_ETMIDR2(val) MCR14(val, 1, c1, c2, 0)
#define WCP14_ETMVMIDCVR(val) MCR14(val, 1, c1, c0, 1)
#define WCP14_ETMOSLAR(val) MCR14(val, 1, c1, c0, 4)
/* Not available in PFTv1.1 */
#define WCP14_ETMOSSRR(val) MCR14(val, 1, c1, c2, 4)
#define WCP14_ETMPDCR(val) MCR14(val, 1, c1, c4, 4)
#define WCP14_ETMPDSR(val) MCR14(val, 1, c1, c5, 4)
#define WCP14_ETMITCTRL(val) MCR14(val, 1, c7, c0, 4)
#define WCP14_ETMCLAIMSET(val) MCR14(val, 1, c7, c8, 6)
#define WCP14_ETMCLAIMCLR(val) MCR14(val, 1, c7, c9, 6)
/* Writes to this from CP14 interface are ignored */
#define WCP14_ETMLAR(val) MCR14(val, 1, c7, c12, 6)
#endif

View File

@@ -24,7 +24,6 @@ obj-$(CONFIG_ATAGS) += atags_parse.o
obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
obj-$(CONFIG_OC_ETM) += etm.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_FIQ) += fiq.o fiqasm.o

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,7 @@
#include <linux/hw_breakpoint.h>
#include <linux/smp.h>
#include <linux/cpu_pm.h>
#include <linux/coresight.h>
#include <asm/cacheflush.h>
#include <asm/cputype.h>
@@ -36,7 +37,6 @@
#include <asm/hw_breakpoint.h>
#include <asm/kdebug.h>
#include <asm/traps.h>
#include <asm/hardware/coresight.h>
/* Breakpoint currently in use for each BRP. */
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -975,7 +975,7 @@ static void reset_ctrl_regs(void *unused)
* Unconditionally clear the OS lock by writing a value
* other than CS_LAR_KEY to the access register.
*/
ARM_DBG_WRITE(c1, c0, 4, ~CS_LAR_KEY);
ARM_DBG_WRITE(c1, c0, 4, ~CORESIGHT_UNLOCK);
isb();
/*

View File

@@ -51,10 +51,11 @@ static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
return (cyc * mult) >> shift;
}
static unsigned long long notrace cyc_to_sched_clock(u32 cyc, u32 mask)
static unsigned long long notrace sched_clock_32(void)
{
u64 epoch_ns;
u32 epoch_cyc;
u32 cyc;
if (cd.suspended)
return cd.epoch_ns;
@@ -73,7 +74,9 @@ static unsigned long long notrace cyc_to_sched_clock(u32 cyc, u32 mask)
smp_rmb();
} while (epoch_cyc != cd.epoch_cyc_copy);
return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
cyc = read_sched_clock();
cyc = (cyc - epoch_cyc) & sched_clock_mask;
return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
}
/*
@@ -165,12 +168,6 @@ void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
pr_debug("Registered %pF as sched_clock source\n", read);
}
static unsigned long long notrace sched_clock_32(void)
{
u32 cyc = read_sched_clock();
return cyc_to_sched_clock(cyc, sched_clock_mask);
}
unsigned long long __read_mostly (*sched_clock_func)(void) = sched_clock_32;
unsigned long long notrace sched_clock(void)

View File

@@ -141,6 +141,29 @@ int __init coherency_init(void)
{
struct device_node *np;
/*
* The coherency fabric is needed:
* - For coherency between processors on Armada XP, so only
* when SMP is enabled.
* - For coherency between the processor and I/O devices, but
* this coherency requires many pre-requisites (write
* allocate cache policy, shareable pages, SMP bit set) that
* are only meant in SMP situations.
*
* Note that this means that on Armada 370, there is currently
* no way to use hardware I/O coherency, because even when
* CONFIG_SMP is enabled, is_smp() returns false due to the
* Armada 370 being a single-core processor. To lift this
* limitation, we would have to find a way to make the cache
* policy set to write-allocate (on all Armada SoCs), and to
* set the shareable attribute in page tables (on all Armada
* SoCs except the Armada 370). Unfortunately, such decisions
* are taken very early in the kernel boot process, at a point
* where we don't know yet on which SoC we are running.
*/
if (!is_smp())
return 0;
np = of_find_matching_node(NULL, of_coherency_table);
if (np) {
pr_info("Initializing Coherency fabric\n");

View File

@@ -394,14 +394,6 @@ config MACH_OMAP4_PANDA
select OMAP_PACKAGE_CBS
select REGULATOR_FIXED_VOLTAGE if REGULATOR
config OMAP3_EMU
bool "OMAP3 debugging peripherals"
depends on ARCH_OMAP3
select ARM_AMBA
select OC_ETM
help
Say Y here to enable debugging hardware of omap3
config OMAP3_SDRC_AC_TIMING
bool "Enable SDRC AC timing register changes"
depends on ARCH_OMAP3

View File

@@ -200,7 +200,6 @@ obj-$(CONFIG_SOC_AM33XX) += omap_hwmod_33xx_data.o
obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o
# EMU peripherals
obj-$(CONFIG_OMAP3_EMU) += emu.o
obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o

View File

@@ -1,50 +0,0 @@
/*
* emu.c
*
* ETM and ETB CoreSight components' resources as found in OMAP3xxx.
*
* Copyright (C) 2009 Nokia Corporation.
* Alexander Shishkin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include "soc.h"
#include "iomap.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shishkin");
/* Cortex CoreSight components within omap3xxx EMU */
#define ETM_BASE (L4_EMU_34XX_PHYS + 0x10000)
#define DBG_BASE (L4_EMU_34XX_PHYS + 0x11000)
#define ETB_BASE (L4_EMU_34XX_PHYS + 0x1b000)
#define DAPCTL (L4_EMU_34XX_PHYS + 0x1d000)
static AMBA_APB_DEVICE(omap3_etb, "etb", 0x000bb907, ETB_BASE, { }, NULL);
static AMBA_APB_DEVICE(omap3_etm, "etm", 0x102bb921, ETM_BASE, { }, NULL);
static int __init emu_init(void)
{
if (!cpu_is_omap34xx())
return -ENODEV;
amba_device_register(&omap3_etb_device, &iomem_resource);
amba_device_register(&omap3_etm_device, &iomem_resource);
return 0;
}
omap_subsys_initcall(emu_init);

View File

@@ -268,37 +268,19 @@ static void *
__dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
const void *caller)
{
struct vm_struct *area;
unsigned long addr;
/*
* DMA allocation can be mapped to user space, so lets
* set VM_USERMAP flags too.
*/
area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
caller);
if (!area)
return NULL;
addr = (unsigned long)area->addr;
area->phys_addr = __pfn_to_phys(page_to_pfn(page));
if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
vunmap((void *)addr);
return NULL;
}
return (void *)addr;
return dma_common_contiguous_remap(page, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP,
prot, caller);
}
static void __dma_free_remap(void *cpu_addr, size_t size)
{
unsigned int flags = VM_ARM_DMA_CONSISTENT | VM_USERMAP;
struct vm_struct *area = find_vm_area(cpu_addr);
if (!area || (area->flags & flags) != flags) {
WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
return;
}
unmap_kernel_range((unsigned long)cpu_addr, size);
vunmap(cpu_addr);
dma_common_free_remap(cpu_addr, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP);
}
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
@@ -1223,29 +1205,8 @@ static void *
__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
const void *caller)
{
unsigned int i, nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
struct vm_struct *area;
unsigned long p;
area = get_vm_area_caller(size, VM_ARM_DMA_CONSISTENT | VM_USERMAP,
caller);
if (!area)
return NULL;
area->pages = pages;
area->nr_pages = nr_pages;
p = (unsigned long)area->addr;
for (i = 0; i < nr_pages; i++) {
phys_addr_t phys = __pfn_to_phys(page_to_pfn(pages[i]));
if (ioremap_page_range(p, p + PAGE_SIZE, phys, prot))
goto err;
p += PAGE_SIZE;
}
return area->addr;
err:
unmap_kernel_range((unsigned long)area->addr, size);
vunmap(area->addr);
return dma_common_pages_remap(pages, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP, prot, caller);
return NULL;
}
@@ -1442,8 +1403,8 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
}
if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) {
unmap_kernel_range((unsigned long)cpu_addr, size);
vunmap(cpu_addr);
dma_common_free_remap(cpu_addr, size,
VM_ARM_DMA_CONSISTENT | VM_USERMAP);
}
__iommu_remove_mapping(dev, handle, size);

View File

@@ -1,6 +1,7 @@
config ARM64
def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_OPP
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_HAS_OPP
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
@@ -18,6 +19,7 @@ config ARM64
select COMMON_CLK
select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS
select GENERIC_ALLOCATOR
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_CPU_AUTOPROBE
@@ -36,6 +38,7 @@ config ARM64
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT
select HAVE_CC_STACKPROTECTOR
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG

View File

@@ -44,4 +44,15 @@ config PID_IN_CONTEXTIDR
instructions during context switch. Say Y here only if you are
planning to use hardware trace tools with this kernel.
config DEBUG_SET_MODULE_RONX
bool "Set loadable kernel module data as NX and text as RO"
depends on MODULES
help
This option helps catch unintended modifications to loadable
kernel module's text and read-only data. It also prevents execution
of module data. Such protection may interfere with run-time code
patching and dynamic kernel tracing - and they might also protect
against certain classes of kernel exploits.
If in doubt, say "N".
endmenu

View File

@@ -39,7 +39,11 @@ CHECKFLAGS += -D__aarch64__
head-y := arch/arm64/kernel/head.o
# The byte offset of the kernel image in RAM from the start of RAM.
ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
else
TEXT_OFFSET := 0x00080000
endif
export TEXT_OFFSET GZFLAGS

View File

@@ -148,4 +148,8 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
{
}
int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages);
int set_memory_x(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
#endif

View File

@@ -28,6 +28,8 @@ struct device_node;
* enable-method property.
* @cpu_init: Reads any data necessary for a specific enable-method from the
* devicetree, for a given cpu node and proposed logical id.
* @cpu_init_idle: Reads any data necessary to initialize CPU idle states from
* devicetree, for a given cpu node and proposed logical id.
* @cpu_prepare: Early one-time preparation step for a cpu. If there is a
* mechanism for doing so, tests whether it is possible to boot
* the given CPU.
@@ -39,6 +41,7 @@ struct device_node;
* from the cpu to be killed.
* @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the
* cpu being killed.
* @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu.
* @cpu_suspend: Suspends a cpu and saves the required context. May fail owing
* to wrong parameters or error conditions. Called from the
* CPU being suspended. Must be called with IRQs disabled.
@@ -46,12 +49,14 @@ struct device_node;
struct cpu_operations {
const char *name;
int (*cpu_init)(struct device_node *, unsigned int);
int (*cpu_init_idle)(struct device_node *, unsigned int);
int (*cpu_prepare)(unsigned int);
int (*cpu_boot)(unsigned int);
void (*cpu_postboot)(void);
#ifdef CONFIG_HOTPLUG_CPU
int (*cpu_disable)(unsigned int cpu);
void (*cpu_die)(unsigned int cpu);
int (*cpu_kill)(unsigned int cpu);
#endif
#ifdef CONFIG_ARM64_CPU_SUSPEND
int (*cpu_suspend)(unsigned long);

View File

@@ -0,0 +1,13 @@
#ifndef __ASM_CPUIDLE_H
#define __ASM_CPUIDLE_H
#ifdef CONFIG_CPU_IDLE
extern int cpu_init_idle(unsigned int cpu);
#else
static inline int cpu_init_idle(unsigned int cpu)
{
return -EOPNOTSUPP;
}
#endif
#endif

View File

@@ -36,15 +36,34 @@
__val; \
})
#define MIDR_REVISION_MASK 0xf
#define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK)
#define MIDR_PARTNUM_SHIFT 4
#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
#define MIDR_PARTNUM(midr) \
(((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT)
#define MIDR_ARCHITECTURE_SHIFT 16
#define MIDR_ARCHITECTURE_MASK (0xf << MIDR_ARCHITECTURE_SHIFT)
#define MIDR_ARCHITECTURE(midr) \
(((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT)
#define MIDR_VARIANT_SHIFT 20
#define MIDR_VARIANT_MASK (0xf << MIDR_VARIANT_SHIFT)
#define MIDR_VARIANT(midr) \
(((midr) & MIDR_VARIANT_MASK) >> MIDR_VARIANT_SHIFT)
#define MIDR_IMPLEMENTOR_SHIFT 24
#define MIDR_IMPLEMENTOR_MASK (0xff << MIDR_IMPLEMENTOR_SHIFT)
#define MIDR_IMPLEMENTOR(midr) \
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
#define ARM_CPU_IMP_ARM 0x41
#define ARM_CPU_IMP_APM 0x50
#define ARM_CPU_PART_AEM_V8 0xD0F0
#define ARM_CPU_PART_FOUNDATION 0xD000
#define ARM_CPU_PART_CORTEX_A53 0xD030
#define ARM_CPU_PART_CORTEX_A57 0xD070
#define ARM_CPU_PART_AEM_V8 0xD0F
#define ARM_CPU_PART_FOUNDATION 0xD00
#define ARM_CPU_PART_CORTEX_A57 0xD07
#define ARM_CPU_PART_CORTEX_A53 0xD03
#define APM_CPU_PART_POTENZA 0x0000
#define APM_CPU_PART_POTENZA 0x000
#ifndef __ASSEMBLY__
@@ -65,12 +84,12 @@ static inline u64 __attribute_const__ read_cpuid_mpidr(void)
static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
{
return (read_cpuid_id() & 0xFF000000) >> 24;
return MIDR_IMPLEMENTOR(read_cpuid_id());
}
static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
{
return (read_cpuid_id() & 0xFFF0);
return MIDR_PARTNUM(read_cpuid_id());
}
static inline u32 __attribute_const__ read_cpuid_cachetype(void)

View File

@@ -23,8 +23,6 @@
#include <asm-generic/dma-coherent.h>
#define ARCH_HAS_DMA_GET_REQUIRED_MASK
#define DMA_ERROR_CODE (~(dma_addr_t)0)
extern struct dma_map_ops *dma_ops;
extern struct dma_map_ops coherent_swiotlb_dma_ops;

View File

@@ -33,11 +33,11 @@
/*
* The idmap and swapper page tables need some space reserved in the kernel
* image. The idmap only requires a pgd and a next level table to (section) map
* the kernel, while the swapper also maps the FDT and requires an additional
* table to map an early UART. See __create_page_tables for more information.
* image. Both require a pgd and a next level table to (section) map the
* kernel. The the swapper also maps the FDT (see __create_page_tables for
* more information).
*/
#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE)
#define SWAPPER_DIR_SIZE (2 * PAGE_SIZE)
#define IDMAP_DIR_SIZE (2 * PAGE_SIZE)
#ifndef __ASSEMBLY__

View File

@@ -26,13 +26,13 @@ static inline void set_my_cpu_offset(unsigned long off)
static inline unsigned long __my_cpu_offset(void)
{
unsigned long off;
register unsigned long *sp asm ("sp");
/*
* We want to allow caching the value, so avoid using volatile and
* instead use a fake stack read to hazard against barrier().
*/
asm("mrs %0, tpidr_el1" : "=r" (off) : "Q" (*sp));
asm("mrs %0, tpidr_el1" : "=r" (off) :
"Q" (*(const unsigned long *)current_stack_pointer));
return off;
}

View File

@@ -141,46 +141,51 @@ extern struct page *empty_zero_page;
#define pte_valid_not_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) &= ~pgprot_val(prot);
return pte;
}
static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) |= pgprot_val(prot);
return pte;
}
static inline pte_t pte_wrprotect(pte_t pte)
{
pte_val(pte) &= ~PTE_WRITE;
return pte;
return clear_pte_bit(pte, __pgprot(PTE_WRITE));
}
static inline pte_t pte_mkwrite(pte_t pte)
{
pte_val(pte) |= PTE_WRITE;
return pte;
return set_pte_bit(pte, __pgprot(PTE_WRITE));
}
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~PTE_DIRTY;
return pte;
return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
}
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_val(pte) |= PTE_DIRTY;
return pte;
return set_pte_bit(pte, __pgprot(PTE_DIRTY));
}
static inline pte_t pte_mkold(pte_t pte)
{
pte_val(pte) &= ~PTE_AF;
return pte;
return clear_pte_bit(pte, __pgprot(PTE_AF));
}
static inline pte_t pte_mkyoung(pte_t pte)
{
pte_val(pte) |= PTE_AF;
return pte;
return set_pte_bit(pte, __pgprot(PTE_AF));
}
static inline pte_t pte_mkspecial(pte_t pte)
{
pte_val(pte) |= PTE_SPECIAL;
return pte;
return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
}
static inline void set_pte(pte_t *ptep, pte_t pte)
@@ -257,7 +262,7 @@ static inline pmd_t pte_pmd(pte_t pte)
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK))
#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
#define __HAVE_ARCH_PMD_WRITE
#define pmd_write(pmd) pte_write(pmd_pte(pmd))

View File

@@ -34,6 +34,8 @@ extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
void cpu_soft_restart(phys_addr_t cpu_reset,
unsigned long addr) __attribute__((noreturn));
#include <asm/memory.h>

View File

@@ -14,10 +14,6 @@
#ifndef __ASM_PSCI_H
#define __ASM_PSCI_H
struct cpuidle_driver;
void psci_init(void);
int __init psci_dt_register_idle_states(struct cpuidle_driver *,
struct device_node *[]);
int psci_init(void);
#endif /* __ASM_PSCI_H */

View File

@@ -17,7 +17,7 @@
#define __ASM_SPARSEMEM_H
#ifdef CONFIG_SPARSEMEM
#define MAX_PHYSMEM_BITS 40
#define MAX_PHYSMEM_BITS 48
#define SECTION_SIZE_BITS 30
#endif

View File

@@ -0,0 +1,38 @@
/*
* GCC stack protector support.
*
* Stack protector works by putting predefined pattern at the start of
* the stack frame and verifying that it hasn't been overwritten when
* returning from the function. The pattern is called stack canary
* and gcc expects it to be defined by a global variable called
* "__stack_chk_guard" on ARM. This unfortunately means that on SMP
* we cannot have a different canary value per task.
*/
#ifndef __ASM_STACKPROTECTOR_H
#define __ASM_STACKPROTECTOR_H
#include <linux/random.h>
#include <linux/version.h>
extern unsigned long __stack_chk_guard;
/*
* Initialize the stackprotector canary value.
*
* NOTE: this must only be called from functions that never return,
* and it must always be inlined.
*/
static __always_inline void boot_init_stack_canary(void)
{
unsigned long canary;
/* Try to get a semi random initial value. */
get_random_bytes(&canary, sizeof(canary));
canary ^= LINUX_VERSION_CODE;
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
}
#endif /* _ASM_STACKPROTECTOR_H */

View File

@@ -22,6 +22,18 @@ extern char *strrchr(const char *, int c);
#define __HAVE_ARCH_STRCHR
extern char *strchr(const char *, int c);
#define __HAVE_ARCH_STRCMP
extern int strcmp(const char *, const char *);
#define __HAVE_ARCH_STRNCMP
extern int strncmp(const char *, const char *, __kernel_size_t);
#define __HAVE_ARCH_STRLEN
extern __kernel_size_t strlen(const char *);
#define __HAVE_ARCH_STRNLEN
extern __kernel_size_t strnlen(const char *, __kernel_size_t);
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *, const void *, __kernel_size_t);
@@ -34,4 +46,7 @@ extern void *memchr(const void *, int, __kernel_size_t);
#define __HAVE_ARCH_MEMSET
extern void *memset(void *, int, __kernel_size_t);
#define __HAVE_ARCH_MEMCMP
extern int memcmp(const void *, const void *, size_t);
#endif

View File

@@ -68,6 +68,11 @@ struct thread_info {
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
/*
* how to get the current stack pointer from C
*/
register unsigned long current_stack_pointer asm ("sp");
/*
* how to get the thread information struct from C
*/
@@ -75,8 +80,8 @@ static inline struct thread_info *current_thread_info(void) __attribute_const__;
static inline struct thread_info *current_thread_info(void)
{
register unsigned long sp asm ("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
return (struct thread_info *)
(current_stack_pointer & ~(THREAD_SIZE - 1));
}
#define thread_saved_pc(tsk) \

View File

@@ -98,8 +98,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
dsb(ish);
}
static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
static inline void __flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
unsigned long addr;
@@ -112,7 +112,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
dsb(ish);
}
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
unsigned long addr;
start >>= 12;
@@ -125,6 +125,29 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
isb();
}
/*
* This is meant to avoid soft lock-ups on large TLB flushing ranges and not
* necessarily a performance improvement.
*/
#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT)
static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
if ((end - start) <= MAX_TLB_RANGE)
__flush_tlb_range(vma, start, end);
else
flush_tlb_mm(vma->vm_mm);
}
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
if ((end - start) <= MAX_TLB_RANGE)
__flush_tlb_kernel_range(start, end);
else
flush_tlb_all();
}
/*
* On AArch64, the cache coherency is handled via the set_pte_at() function.
*/

View File

@@ -31,6 +31,7 @@ arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o

View File

@@ -44,10 +44,15 @@ EXPORT_SYMBOL(memstart_addr);
/* string / mem functions */
EXPORT_SYMBOL(strchr);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strcmp);
EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcmp);
/* atomic bitops */
EXPORT_SYMBOL(set_bit);

View File

@@ -30,8 +30,8 @@ const struct cpu_operations *cpu_ops[NR_CPUS];
static const struct cpu_operations *supported_cpu_ops[] __initconst = {
#ifdef CONFIG_SMP
&smp_spin_table_ops,
&cpu_psci_ops,
#endif
&cpu_psci_ops,
NULL,
};

View File

@@ -0,0 +1,31 @@
/*
* ARM64 CPU idle arch support
*
* Copyright (C) 2014 ARM Ltd.
* Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of.h>
#include <linux/of_device.h>
#include <asm/cpuidle.h>
#include <asm/cpu_ops.h>
int cpu_init_idle(unsigned int cpu)
{
int ret = -EOPNOTSUPP;
struct device_node *cpu_node = of_cpu_device_node_get(cpu);
if (!cpu_node)
return -ENODEV;
if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_init_idle)
ret = cpu_ops[cpu]->cpu_init_idle(cpu_node, cpu);
of_node_put(cpu_node);
return ret;
}

View File

@@ -303,20 +303,20 @@ static int brk_handler(unsigned long addr, unsigned int esr,
{
siginfo_t info;
if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED)
return 0;
if (user_mode(regs)) {
info = (siginfo_t) {
.si_signo = SIGTRAP,
.si_errno = 0,
.si_code = TRAP_BRKPT,
.si_addr = (void __user *)instruction_pointer(regs),
};
if (!user_mode(regs))
force_sig_info(SIGTRAP, &info, current);
} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
pr_warning("Unexpected kernel BRK exception at EL1\n");
return -EFAULT;
}
info = (siginfo_t) {
.si_signo = SIGTRAP,
.si_errno = 0,
.si_code = TRAP_BRKPT,
.si_addr = (void __user *)instruction_pointer(regs),
};
force_sig_info(SIGTRAP, &info, current);
return 0;
}

View File

@@ -38,8 +38,12 @@
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
#error KERNEL_RAM_VADDR must start at 0xXXX80000
#if (TEXT_OFFSET & 0xfff) != 0
#error TEXT_OFFSET must be at least 4KB aligned
#elif (PAGE_OFFSET & 0x1fffff) != 0
#error PAGE_OFFSET must be at least 2MB aligned
#elif TEXT_OFFSET > 0x1fffff
#error TEXT_OFFSET must be less than 2MB
#endif
.macro pgtbl, ttb0, ttb1, virt_to_phys
@@ -349,6 +353,8 @@ ENTRY(set_cpu_boot_mode_flag)
b.ne 1f
add x1, x1, #4
1: str w20, [x1] // This CPU has booted in EL1
dmb sy
dc ivac, x1 // Invalidate potentially stale cache line
ret
ENDPROC(set_cpu_boot_mode_flag)
@@ -366,10 +372,6 @@ ENTRY(__boot_cpu_mode)
.long 0
.popsection
.align 3
2: .quad .
.quad PAGE_OFFSET
#ifdef CONFIG_SMP
.align 3
1: .quad .
@@ -594,13 +596,6 @@ __create_page_tables:
sub x6, x6, #1 // inclusive range
create_block_map x0, x7, x3, x5, x6
1:
/*
* Create the pgd entry for the fixed mappings.
*/
ldr x5, =FIXADDR_TOP // Fixed mapping virtual address
add x0, x26, #2 * PAGE_SIZE // section table address
create_pgd_entry x26, x0, x5, x6, x7
/*
* Since the page tables have been populated with non-cacheable
* accesses (MMU disabled), invalidate the idmap and swapper page

View File

@@ -105,7 +105,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
c = irq_data_get_irq_chip(d);
if (!c->irq_set_affinity)
pr_debug("IRQ%u: unable to set affinity\n", d->irq);
else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret)
else if (c->irq_set_affinity(d, affinity, false) == IRQ_SET_MASK_OK && ret)
cpumask_copy(d->affinity, affinity);
return ret;

View File

@@ -52,36 +52,16 @@
#include <asm/processor.h>
#include <asm/stacktrace.h>
static void setup_restart(void)
{
/*
* Tell the mm system that we are going to reboot -
* we may need it to insert some 1:1 mappings so that
* soft boot works.
*/
setup_mm_for_reboot();
/* Clean and invalidate caches */
flush_cache_all();
/* Turn D-cache off */
cpu_cache_off();
/* Push out any further dirty data, and ensure cache is empty */
flush_cache_all();
}
#ifdef CONFIG_CC_STACKPROTECTOR
#include <linux/stackprotector.h>
unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
void soft_restart(unsigned long addr)
{
typedef void (*phys_reset_t)(unsigned long);
phys_reset_t phys_reset;
setup_restart();
/* Switch to the identity mapping */
phys_reset = (phys_reset_t)virt_to_phys(cpu_reset);
phys_reset(addr);
setup_mm_for_reboot();
cpu_soft_restart(virt_to_phys(cpu_reset), addr);
/* Should never get here */
BUG();
}

View File

@@ -20,6 +20,10 @@
#include <linux/of.h>
#include <linux/smp.h>
#include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <uapi/linux/psci.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
@@ -27,6 +31,7 @@
#include <asm/psci.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/system_misc.h>
#define PSCI_POWER_STATE_TYPE_STANDBY 0
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
@@ -43,17 +48,23 @@ struct psci_operations {
int (*cpu_off)(struct psci_power_state state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
int (*migrate)(unsigned long cpuid);
int (*affinity_info)(unsigned long target_affinity,
unsigned long lowest_affinity_level);
int (*migrate_info_type)(void);
};
static struct psci_operations psci_ops;
static int (*invoke_psci_fn)(u64, u64, u64, u64);
typedef int (*psci_initcall_t)(const struct device_node *);
enum psci_function {
PSCI_FN_CPU_SUSPEND,
PSCI_FN_CPU_ON,
PSCI_FN_CPU_OFF,
PSCI_FN_MIGRATE,
PSCI_FN_AFFINITY_INFO,
PSCI_FN_MIGRATE_INFO_TYPE,
PSCI_FN_MAX,
};
@@ -61,53 +72,41 @@ static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
static u32 psci_function_id[PSCI_FN_MAX];
#define PSCI_RET_SUCCESS 0
#define PSCI_RET_EOPNOTSUPP -1
#define PSCI_RET_EINVAL -2
#define PSCI_RET_EPERM -3
static int psci_to_linux_errno(int errno)
{
switch (errno) {
case PSCI_RET_SUCCESS:
return 0;
case PSCI_RET_EOPNOTSUPP:
case PSCI_RET_NOT_SUPPORTED:
return -EOPNOTSUPP;
case PSCI_RET_EINVAL:
case PSCI_RET_INVALID_PARAMS:
return -EINVAL;
case PSCI_RET_EPERM:
case PSCI_RET_DENIED:
return -EPERM;
};
return -EINVAL;
}
#define PSCI_POWER_STATE_ID_MASK 0xffff
#define PSCI_POWER_STATE_ID_SHIFT 0
#define PSCI_POWER_STATE_TYPE_MASK 0x1
#define PSCI_POWER_STATE_TYPE_SHIFT 16
#define PSCI_POWER_STATE_AFFL_MASK 0x3
#define PSCI_POWER_STATE_AFFL_SHIFT 24
static u32 psci_power_state_pack(struct psci_power_state state)
{
return ((state.id & PSCI_POWER_STATE_ID_MASK)
<< PSCI_POWER_STATE_ID_SHIFT) |
((state.type & PSCI_POWER_STATE_TYPE_MASK)
<< PSCI_POWER_STATE_TYPE_SHIFT) |
((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK)
<< PSCI_POWER_STATE_AFFL_SHIFT);
return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT)
& PSCI_0_2_POWER_STATE_ID_MASK) |
((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
& PSCI_0_2_POWER_STATE_TYPE_MASK) |
((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
& PSCI_0_2_POWER_STATE_AFFL_MASK);
}
static void psci_power_state_unpack(u32 power_state,
struct psci_power_state *state)
{
state->id = (power_state >> PSCI_POWER_STATE_ID_SHIFT)
& PSCI_POWER_STATE_ID_MASK;
state->type = (power_state >> PSCI_POWER_STATE_TYPE_SHIFT)
& PSCI_POWER_STATE_TYPE_MASK;
state->affinity_level = (power_state >> PSCI_POWER_STATE_AFFL_SHIFT)
& PSCI_POWER_STATE_AFFL_MASK;
state->id = (power_state >> PSCI_0_2_POWER_STATE_ID_SHIFT)
& PSCI_0_2_POWER_STATE_ID_MASK;
state->type = (power_state >> PSCI_0_2_POWER_STATE_TYPE_SHIFT)
& PSCI_0_2_POWER_STATE_TYPE_MASK;
state->affinity_level = (power_state >> PSCI_0_2_POWER_STATE_AFFL_SHIFT)
& PSCI_0_2_POWER_STATE_AFFL_MASK;
}
/*
@@ -144,6 +143,14 @@ static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
return function_id;
}
static int psci_get_version(void)
{
int err;
err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
return err;
}
static int psci_cpu_suspend(struct psci_power_state state,
unsigned long entry_point)
{
@@ -187,97 +194,36 @@ static int psci_migrate(unsigned long cpuid)
return psci_to_linux_errno(err);
}
static const struct of_device_id psci_of_match[] __initconst = {
{ .compatible = "arm,psci", },
{},
};
int __init psci_dt_register_idle_states(struct cpuidle_driver *drv,
struct device_node *state_nodes[])
static int psci_affinity_info(unsigned long target_affinity,
unsigned long lowest_affinity_level)
{
int cpu, i;
struct psci_power_state *psci_states;
const struct cpu_operations *cpu_ops_ptr;
int err;
u32 fn;
if (!state_nodes)
return -EINVAL;
/*
* This is belt-and-braces: make sure that if the idle
* specified protocol is psci, the cpu_ops have been
* initialized to psci operations. Anything else is
* a recipe for mayhem.
*/
for_each_cpu(cpu, drv->cpumask) {
cpu_ops_ptr = cpu_ops[cpu];
if (WARN_ON(!cpu_ops_ptr || strcmp(cpu_ops_ptr->name, "psci")))
return -EOPNOTSUPP;
}
psci_states = kcalloc(drv->state_count, sizeof(*psci_states),
GFP_KERNEL);
if (!psci_states) {
pr_warn("psci idle state allocation failed\n");
return -ENOMEM;
}
for_each_cpu(cpu, drv->cpumask) {
if (per_cpu(psci_power_state, cpu)) {
pr_warn("idle states already initialized on cpu %u\n",
cpu);
continue;
}
per_cpu(psci_power_state, cpu) = psci_states;
}
for (i = 0; i < drv->state_count; i++) {
u32 psci_power_state;
if (!state_nodes[i]) {
/*
* An index with a missing node pointer falls back to
* simple STANDBYWFI
*/
psci_states[i].type = PSCI_POWER_STATE_TYPE_STANDBY;
continue;
}
if (of_property_read_u32(state_nodes[i], "entry-method-param",
&psci_power_state)) {
pr_warn(" * %s missing entry-method-param property\n",
state_nodes[i]->full_name);
/*
* If entry-method-param property is missing, fall
* back to STANDBYWFI state
*/
psci_states[i].type = PSCI_POWER_STATE_TYPE_STANDBY;
continue;
}
pr_debug("psci-power-state %#x index %u\n",
psci_power_state, i);
psci_power_state_unpack(psci_power_state, &psci_states[i]);
}
return 0;
fn = psci_function_id[PSCI_FN_AFFINITY_INFO];
err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0);
return err;
}
void __init psci_init(void)
static int psci_migrate_info_type(void)
{
int err;
u32 fn;
fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE];
err = invoke_psci_fn(fn, 0, 0, 0);
return err;
}
static int get_set_conduit_method(struct device_node *np)
{
struct device_node *np;
const char *method;
u32 id;
np = of_find_matching_node(NULL, psci_of_match);
if (!np)
return;
pr_info("probing function IDs from device-tree\n");
pr_info("probing for conduit method from DT.\n");
if (of_property_read_string(np, "method", &method)) {
pr_warning("missing \"method\" property\n");
goto out_put_node;
pr_warn("missing \"method\" property\n");
return -ENXIO;
}
if (!strcmp("hvc", method)) {
@@ -285,9 +231,98 @@ void __init psci_init(void)
} else if (!strcmp("smc", method)) {
invoke_psci_fn = __invoke_psci_fn_smc;
} else {
pr_warning("invalid \"method\" property: %s\n", method);
goto out_put_node;
pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL;
}
return 0;
}
static void psci_sys_reset(char str, const char *cmd)
{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
}
static void psci_sys_poweroff(void)
{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
/*
* PSCI Function IDs for v0.2+ are well defined so use
* standard values.
*/
static int __init psci_0_2_init(struct device_node *np)
{
int err, ver;
err = get_set_conduit_method(np);
if (err)
goto out_put_node;
ver = psci_get_version();
if (ver == PSCI_RET_NOT_SUPPORTED) {
/* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */
pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
err = -EOPNOTSUPP;
goto out_put_node;
} else {
pr_info("PSCIv%d.%d detected in firmware.\n",
PSCI_VERSION_MAJOR(ver),
PSCI_VERSION_MINOR(ver));
if (PSCI_VERSION_MAJOR(ver) == 0 &&
PSCI_VERSION_MINOR(ver) < 2) {
err = -EINVAL;
pr_err("Conflicting PSCI version detected.\n");
goto out_put_node;
}
}
pr_info("Using standard PSCI v0.2 function IDs\n");
psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
psci_ops.cpu_suspend = psci_cpu_suspend;
psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
psci_ops.cpu_off = psci_cpu_off;
psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
psci_ops.cpu_on = psci_cpu_on;
psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
psci_ops.migrate = psci_migrate;
psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
psci_ops.affinity_info = psci_affinity_info;
psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
PSCI_0_2_FN_MIGRATE_INFO_TYPE;
psci_ops.migrate_info_type = psci_migrate_info_type;
arm_pm_restart = psci_sys_reset;
pm_power_off = psci_sys_poweroff;
out_put_node:
of_node_put(np);
return err;
}
/*
* PSCI < v0.2 get PSCI Function IDs via DT.
*/
static int __init psci_0_1_init(struct device_node *np)
{
u32 id;
int err;
err = get_set_conduit_method(np);
if (err)
goto out_put_node;
pr_info("Using PSCI v0.1 Function IDs from DT\n");
if (!of_property_read_u32(np, "cpu_suspend", &id)) {
psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
@@ -311,7 +346,28 @@ void __init psci_init(void)
out_put_node:
of_node_put(np);
return;
return err;
}
static const struct of_device_id psci_of_match[] __initconst = {
{ .compatible = "arm,psci", .data = psci_0_1_init},
{ .compatible = "arm,psci-0.2", .data = psci_0_2_init},
{},
};
int __init psci_init(void)
{
struct device_node *np;
const struct of_device_id *matched_np;
psci_initcall_t init_fn;
np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
if (!np)
return -ENODEV;
init_fn = (psci_initcall_t)matched_np->data;
return init_fn(np);
}
#ifdef CONFIG_SMP
@@ -364,6 +420,36 @@ static void cpu_psci_cpu_die(unsigned int cpu)
pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
}
static int cpu_psci_cpu_kill(unsigned int cpu)
{
int err, i;
if (!psci_ops.affinity_info)
return 1;
/*
* cpu_kill could race with cpu_die and we can
* potentially end up declaring this cpu undead
* while it is dying. So, try again a few times.
*/
for (i = 0; i < 10; i++) {
err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
pr_info("CPU%d killed.\n", cpu);
return 1;
}
msleep(10);
pr_info("Retrying again to check for CPU kill\n");
}
pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
cpu, err);
/* Make op_cpu_kill() fail. */
return 0;
}
#endif
#endif
#ifdef CONFIG_ARM64_CPU_SUSPEND
@@ -380,16 +466,18 @@ static int cpu_psci_cpu_suspend(unsigned long index)
const struct cpu_operations cpu_psci_ops = {
.name = "psci",
#ifdef CONFIG_SMP
.cpu_init = cpu_psci_cpu_init,
.cpu_prepare = cpu_psci_cpu_prepare,
.cpu_boot = cpu_psci_cpu_boot,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_disable = cpu_psci_cpu_disable,
.cpu_die = cpu_psci_cpu_die,
.cpu_kill = cpu_psci_cpu_kill,
#endif
#endif
#ifdef CONFIG_ARM64_CPU_SUSPEND
.cpu_suspend = cpu_psci_cpu_suspend,
#endif
};
#endif

View File

@@ -659,11 +659,18 @@ static int compat_gpr_get(struct task_struct *target,
reg = task_pt_regs(target)->regs[idx];
}
ret = copy_to_user(ubuf, &reg, sizeof(reg));
if (ret)
break;
if (kbuf) {
memcpy(kbuf, &reg, sizeof(reg));
kbuf += sizeof(reg);
} else {
ret = copy_to_user(ubuf, &reg, sizeof(reg));
if (ret) {
ret = -EFAULT;
break;
}
ubuf += sizeof(reg);
ubuf += sizeof(reg);
}
}
return ret;
@@ -693,11 +700,18 @@ static int compat_gpr_set(struct task_struct *target,
unsigned int idx = start + i;
compat_ulong_t reg;
ret = copy_from_user(&reg, ubuf, sizeof(reg));
if (ret)
return ret;
if (kbuf) {
memcpy(&reg, kbuf, sizeof(reg));
kbuf += sizeof(reg);
} else {
ret = copy_from_user(&reg, ubuf, sizeof(reg));
if (ret) {
ret = -EFAULT;
break;
}
ubuf += sizeof(reg);
ubuf += sizeof(reg);
}
switch (idx) {
case 15:

View File

@@ -231,6 +231,19 @@ int __cpu_disable(void)
return 0;
}
static int op_cpu_kill(unsigned int cpu)
{
/*
* If we have no means of synchronising with the dying CPU, then assume
* that it is really dead. We can only wait for an arbitrary length of
* time and hope that it's dead, so let's skip the wait and just hope.
*/
if (!cpu_ops[cpu]->cpu_kill)
return 1;
return cpu_ops[cpu]->cpu_kill(cpu);
}
static DECLARE_COMPLETION(cpu_died);
/*
@@ -244,6 +257,15 @@ void __cpu_die(unsigned int cpu)
return;
}
pr_notice("CPU%u: shutdown\n", cpu);
/*
* Now that the dying CPU is beyond the point of no return w.r.t.
* in-kernel synchronisation, try to get the firwmare to help us to
* verify that it has really left the kernel before we consider
* clobbering anything it might still be using.
*/
if (!op_cpu_kill(cpu))
pr_warn("CPU%d may not have shut down cleanly\n", cpu);
}
/*

View File

@@ -111,10 +111,9 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
frame.sp = thread_saved_sp(tsk);
frame.pc = thread_saved_pc(tsk);
} else {
register unsigned long current_sp asm("sp");
data.no_sched_functions = 0;
frame.fp = (unsigned long)__builtin_frame_address(0);
frame.sp = current_sp;
frame.sp = current_stack_pointer;
frame.pc = (unsigned long)save_stack_trace_tsk;
}

View File

@@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clockchips.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
@@ -74,6 +75,8 @@ void __init time_init(void)
clocksource_of_init();
tick_setup_hrtimer_broadcast();
arch_timer_rate = arch_timer_get_rate();
if (!arch_timer_rate)
panic("Unable to initialise architected timer.\n");

View File

@@ -133,7 +133,6 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
struct stackframe frame;
const register unsigned long current_sp asm ("sp");
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
@@ -146,7 +145,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.pc = regs->pc;
} else if (tsk == current) {
frame.fp = (unsigned long)__builtin_frame_address(0);
frame.sp = current_sp;
frame.sp = current_stack_pointer;
frame.pc = (unsigned long)dump_backtrace;
} else {
/*
@@ -157,7 +156,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.pc = thread_saved_pc(tsk);
}
printk("Call trace:\n");
pr_emerg("Call trace:\n");
while (1) {
unsigned long where = frame.pc;
int ret;
@@ -372,17 +371,17 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
void __pte_error(const char *file, int line, unsigned long val)
{
printk("%s:%d: bad pte %016lx.\n", file, line, val);
pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
}
void __pmd_error(const char *file, int line, unsigned long val)
{
printk("%s:%d: bad pmd %016lx.\n", file, line, val);
pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
}
void __pgd_error(const char *file, int line, unsigned long val)
{
printk("%s:%d: bad pgd %016lx.\n", file, line, val);
pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
}
void __init trap_init(void)

View File

@@ -43,7 +43,7 @@ $(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
$(call if_changed,vdsosym)
# Assembly rules for the .S files
$(obj-vdso): %.o: %.S
$(obj-vdso): %.o: %.S FORCE
$(call if_changed_dep,vdsoas)
# Actual build commands

View File

@@ -13,7 +13,7 @@
#define ARM_EXIT_DISCARD(x) x
OUTPUT_ARCH(aarch64)
ENTRY(stext)
ENTRY(_text)
jiffies = jiffies_64;

View File

@@ -1,4 +1,5 @@
lib-y := bitops.o clear_user.o delay.o copy_from_user.o \
copy_to_user.o copy_in_user.o copy_page.o \
clear_page.o memchr.o memcpy.o memmove.o memset.o \
memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \
strchr.o strrchr.o

258
arch/arm64/lib/memcmp.S Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* compare memory areas(when two memory areas' offset are different,
* alignment handled by the hardware)
*
* Parameters:
* x0 - const memory area 1 pointer
* x1 - const memory area 2 pointer
* x2 - the maximal compare byte length
* Returns:
* x0 - a compare result, maybe less than, equal to, or greater than ZERO
*/
/* Parameters and result. */
src1 .req x0
src2 .req x1
limit .req x2
result .req x0
/* Internal variables. */
data1 .req x3
data1w .req w3
data2 .req x4
data2w .req w4
has_nul .req x5
diff .req x6
endloop .req x7
tmp1 .req x8
tmp2 .req x9
tmp3 .req x10
pos .req x11
limit_wd .req x12
mask .req x13
ENTRY(memcmp)
cbz limit, .Lret0
eor tmp1, src1, src2
tst tmp1, #7
b.ne .Lmisaligned8
ands tmp1, src1, #7
b.ne .Lmutual_align
sub limit_wd, limit, #1 /* limit != 0, so no underflow. */
lsr limit_wd, limit_wd, #3 /* Convert to Dwords. */
/*
* The input source addresses are at alignment boundary.
* Directly compare eight bytes each time.
*/
.Lloop_aligned:
ldr data1, [src1], #8
ldr data2, [src2], #8
.Lstart_realigned:
subs limit_wd, limit_wd, #1
eor diff, data1, data2 /* Non-zero if differences found. */
csinv endloop, diff, xzr, cs /* Last Dword or differences. */
cbz endloop, .Lloop_aligned
/* Not reached the limit, must have found a diff. */
tbz limit_wd, #63, .Lnot_limit
/* Limit % 8 == 0 => the diff is in the last 8 bytes. */
ands limit, limit, #7
b.eq .Lnot_limit
/*
* The remained bytes less than 8. It is needed to extract valid data
* from last eight bytes of the intended memory range.
*/
lsl limit, limit, #3 /* bytes-> bits. */
mov mask, #~0
CPU_BE( lsr mask, mask, limit )
CPU_LE( lsl mask, mask, limit )
bic data1, data1, mask
bic data2, data2, mask
orr diff, diff, mask
b .Lnot_limit
.Lmutual_align:
/*
* Sources are mutually aligned, but are not currently at an
* alignment boundary. Round down the addresses and then mask off
* the bytes that precede the start point.
*/
bic src1, src1, #7
bic src2, src2, #7
ldr data1, [src1], #8
ldr data2, [src2], #8
/*
* We can not add limit with alignment offset(tmp1) here. Since the
* addition probably make the limit overflown.
*/
sub limit_wd, limit, #1/*limit != 0, so no underflow.*/
and tmp3, limit_wd, #7
lsr limit_wd, limit_wd, #3
add tmp3, tmp3, tmp1
add limit_wd, limit_wd, tmp3, lsr #3
add limit, limit, tmp1/* Adjust the limit for the extra. */
lsl tmp1, tmp1, #3/* Bytes beyond alignment -> bits.*/
neg tmp1, tmp1/* Bits to alignment -64. */
mov tmp2, #~0
/*mask off the non-intended bytes before the start address.*/
CPU_BE( lsl tmp2, tmp2, tmp1 )/*Big-endian.Early bytes are at MSB*/
/* Little-endian. Early bytes are at LSB. */
CPU_LE( lsr tmp2, tmp2, tmp1 )
orr data1, data1, tmp2
orr data2, data2, tmp2
b .Lstart_realigned
/*src1 and src2 have different alignment offset.*/
.Lmisaligned8:
cmp limit, #8
b.lo .Ltiny8proc /*limit < 8: compare byte by byte*/
and tmp1, src1, #7
neg tmp1, tmp1
add tmp1, tmp1, #8/*valid length in the first 8 bytes of src1*/
and tmp2, src2, #7
neg tmp2, tmp2
add tmp2, tmp2, #8/*valid length in the first 8 bytes of src2*/
subs tmp3, tmp1, tmp2
csel pos, tmp1, tmp2, hi /*Choose the maximum.*/
sub limit, limit, pos
/*compare the proceeding bytes in the first 8 byte segment.*/
.Ltinycmp:
ldrb data1w, [src1], #1
ldrb data2w, [src2], #1
subs pos, pos, #1
ccmp data1w, data2w, #0, ne /* NZCV = 0b0000. */
b.eq .Ltinycmp
cbnz pos, 1f /*diff occurred before the last byte.*/
cmp data1w, data2w
b.eq .Lstart_align
1:
sub result, data1, data2
ret
.Lstart_align:
lsr limit_wd, limit, #3
cbz limit_wd, .Lremain8
ands xzr, src1, #7
b.eq .Lrecal_offset
/*process more leading bytes to make src1 aligned...*/
add src1, src1, tmp3 /*backwards src1 to alignment boundary*/
add src2, src2, tmp3
sub limit, limit, tmp3
lsr limit_wd, limit, #3
cbz limit_wd, .Lremain8
/*load 8 bytes from aligned SRC1..*/
ldr data1, [src1], #8
ldr data2, [src2], #8
subs limit_wd, limit_wd, #1
eor diff, data1, data2 /*Non-zero if differences found.*/
csinv endloop, diff, xzr, ne
cbnz endloop, .Lunequal_proc
/*How far is the current SRC2 from the alignment boundary...*/
and tmp3, tmp3, #7
.Lrecal_offset:/*src1 is aligned now..*/
neg pos, tmp3
.Lloopcmp_proc:
/*
* Divide the eight bytes into two parts. First,backwards the src2
* to an alignment boundary,load eight bytes and compare from
* the SRC2 alignment boundary. If all 8 bytes are equal,then start
* the second part's comparison. Otherwise finish the comparison.
* This special handle can garantee all the accesses are in the
* thread/task space in avoid to overrange access.
*/
ldr data1, [src1,pos]
ldr data2, [src2,pos]
eor diff, data1, data2 /* Non-zero if differences found. */
cbnz diff, .Lnot_limit
/*The second part process*/
ldr data1, [src1], #8
ldr data2, [src2], #8
eor diff, data1, data2 /* Non-zero if differences found. */
subs limit_wd, limit_wd, #1
csinv endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
cbz endloop, .Lloopcmp_proc
.Lunequal_proc:
cbz diff, .Lremain8
/*There is differnence occured in the latest comparison.*/
.Lnot_limit:
/*
* For little endian,reverse the low significant equal bits into MSB,then
* following CLZ can find how many equal bits exist.
*/
CPU_LE( rev diff, diff )
CPU_LE( rev data1, data1 )
CPU_LE( rev data2, data2 )
/*
* The MS-non-zero bit of DIFF marks either the first bit
* that is different, or the end of the significant data.
* Shifting left now will bring the critical information into the
* top bits.
*/
clz pos, diff
lsl data1, data1, pos
lsl data2, data2, pos
/*
* We need to zero-extend (char is unsigned) the value and then
* perform a signed subtraction.
*/
lsr data1, data1, #56
sub result, data1, data2, lsr #56
ret
.Lremain8:
/* Limit % 8 == 0 =>. all data are equal.*/
ands limit, limit, #7
b.eq .Lret0
.Ltiny8proc:
ldrb data1w, [src1], #1
ldrb data2w, [src2], #1
subs limit, limit, #1
ccmp data1w, data2w, #0, ne /* NZCV = 0b0000. */
b.eq .Ltiny8proc
sub result, data1, data2
ret
.Lret0:
mov result, #0
ret
ENDPROC(memcmp)

View File

@@ -1,5 +1,13 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/cache.h>
/*
* Copy a buffer from src to dest (alignment handled by the hardware)
@@ -27,27 +36,166 @@
* Returns:
* x0 - dest
*/
dstin .req x0
src .req x1
count .req x2
tmp1 .req x3
tmp1w .req w3
tmp2 .req x4
tmp2w .req w4
tmp3 .req x5
tmp3w .req w5
dst .req x6
A_l .req x7
A_h .req x8
B_l .req x9
B_h .req x10
C_l .req x11
C_h .req x12
D_l .req x13
D_h .req x14
ENTRY(memcpy)
mov x4, x0
subs x2, x2, #8
b.mi 2f
1: ldr x3, [x1], #8
subs x2, x2, #8
str x3, [x4], #8
b.pl 1b
2: adds x2, x2, #4
b.mi 3f
ldr w3, [x1], #4
sub x2, x2, #4
str w3, [x4], #4
3: adds x2, x2, #2
b.mi 4f
ldrh w3, [x1], #2
sub x2, x2, #2
strh w3, [x4], #2
4: adds x2, x2, #1
b.mi 5f
ldrb w3, [x1]
strb w3, [x4]
5: ret
mov dst, dstin
cmp count, #16
/*When memory length is less than 16, the accessed are not aligned.*/
b.lo .Ltiny15
neg tmp2, src
ands tmp2, tmp2, #15/* Bytes to reach alignment. */
b.eq .LSrcAligned
sub count, count, tmp2
/*
* Copy the leading memory data from src to dst in an increasing
* address order.By this way,the risk of overwritting the source
* memory data is eliminated when the distance between src and
* dst is less than 16. The memory accesses here are alignment.
*/
tbz tmp2, #0, 1f
ldrb tmp1w, [src], #1
strb tmp1w, [dst], #1
1:
tbz tmp2, #1, 2f
ldrh tmp1w, [src], #2
strh tmp1w, [dst], #2
2:
tbz tmp2, #2, 3f
ldr tmp1w, [src], #4
str tmp1w, [dst], #4
3:
tbz tmp2, #3, .LSrcAligned
ldr tmp1, [src],#8
str tmp1, [dst],#8
.LSrcAligned:
cmp count, #64
b.ge .Lcpy_over64
/*
* Deal with small copies quickly by dropping straight into the
* exit block.
*/
.Ltail63:
/*
* Copy up to 48 bytes of data. At this point we only need the
* bottom 6 bits of count to be accurate.
*/
ands tmp1, count, #0x30
b.eq .Ltiny15
cmp tmp1w, #0x20
b.eq 1f
b.lt 2f
ldp A_l, A_h, [src], #16
stp A_l, A_h, [dst], #16
1:
ldp A_l, A_h, [src], #16
stp A_l, A_h, [dst], #16
2:
ldp A_l, A_h, [src], #16
stp A_l, A_h, [dst], #16
.Ltiny15:
/*
* Prefer to break one ldp/stp into several load/store to access
* memory in an increasing address order,rather than to load/store 16
* bytes from (src-16) to (dst-16) and to backward the src to aligned
* address,which way is used in original cortex memcpy. If keeping
* the original memcpy process here, memmove need to satisfy the
* precondition that src address is at least 16 bytes bigger than dst
* address,otherwise some source data will be overwritten when memove
* call memcpy directly. To make memmove simpler and decouple the
* memcpy's dependency on memmove, withdrew the original process.
*/
tbz count, #3, 1f
ldr tmp1, [src], #8
str tmp1, [dst], #8
1:
tbz count, #2, 2f
ldr tmp1w, [src], #4
str tmp1w, [dst], #4
2:
tbz count, #1, 3f
ldrh tmp1w, [src], #2
strh tmp1w, [dst], #2
3:
tbz count, #0, .Lexitfunc
ldrb tmp1w, [src]
strb tmp1w, [dst]
.Lexitfunc:
ret
.Lcpy_over64:
subs count, count, #128
b.ge .Lcpy_body_large
/*
* Less than 128 bytes to copy, so handle 64 here and then jump
* to the tail.
*/
ldp A_l, A_h, [src],#16
stp A_l, A_h, [dst],#16
ldp B_l, B_h, [src],#16
ldp C_l, C_h, [src],#16
stp B_l, B_h, [dst],#16
stp C_l, C_h, [dst],#16
ldp D_l, D_h, [src],#16
stp D_l, D_h, [dst],#16
tst count, #0x3f
b.ne .Ltail63
ret
/*
* Critical loop. Start at a new cache line boundary. Assuming
* 64 bytes per line this ensures the entire loop is in one line.
*/
.p2align L1_CACHE_SHIFT
.Lcpy_body_large:
/* pre-get 64 bytes data. */
ldp A_l, A_h, [src],#16
ldp B_l, B_h, [src],#16
ldp C_l, C_h, [src],#16
ldp D_l, D_h, [src],#16
1:
/*
* interlace the load of next 64 bytes data block with store of the last
* loaded 64 bytes data.
*/
stp A_l, A_h, [dst],#16
ldp A_l, A_h, [src],#16
stp B_l, B_h, [dst],#16
ldp B_l, B_h, [src],#16
stp C_l, C_h, [dst],#16
ldp C_l, C_h, [src],#16
stp D_l, D_h, [dst],#16
ldp D_l, D_h, [src],#16
subs count, count, #64
b.ge 1b
stp A_l, A_h, [dst],#16
stp B_l, B_h, [dst],#16
stp C_l, C_h, [dst],#16
stp D_l, D_h, [dst],#16
tst count, #0x3f
b.ne .Ltail63
ret
ENDPROC(memcpy)

View File

@@ -1,5 +1,13 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/cache.h>
/*
* Move a buffer from src to test (alignment handled by the hardware).
@@ -28,30 +37,161 @@
* Returns:
* x0 - dest
*/
dstin .req x0
src .req x1
count .req x2
tmp1 .req x3
tmp1w .req w3
tmp2 .req x4
tmp2w .req w4
tmp3 .req x5
tmp3w .req w5
dst .req x6
A_l .req x7
A_h .req x8
B_l .req x9
B_h .req x10
C_l .req x11
C_h .req x12
D_l .req x13
D_h .req x14
ENTRY(memmove)
cmp x0, x1
b.ls memcpy
add x4, x0, x2
add x1, x1, x2
subs x2, x2, #8
b.mi 2f
1: ldr x3, [x1, #-8]!
subs x2, x2, #8
str x3, [x4, #-8]!
b.pl 1b
2: adds x2, x2, #4
b.mi 3f
ldr w3, [x1, #-4]!
sub x2, x2, #4
str w3, [x4, #-4]!
3: adds x2, x2, #2
b.mi 4f
ldrh w3, [x1, #-2]!
sub x2, x2, #2
strh w3, [x4, #-2]!
4: adds x2, x2, #1
b.mi 5f
ldrb w3, [x1, #-1]
strb w3, [x4, #-1]
5: ret
cmp dstin, src
b.lo memcpy
add tmp1, src, count
cmp dstin, tmp1
b.hs memcpy /* No overlap. */
add dst, dstin, count
add src, src, count
cmp count, #16
b.lo .Ltail15 /*probably non-alignment accesses.*/
ands tmp2, src, #15 /* Bytes to reach alignment. */
b.eq .LSrcAligned
sub count, count, tmp2
/*
* process the aligned offset length to make the src aligned firstly.
* those extra instructions' cost is acceptable. It also make the
* coming accesses are based on aligned address.
*/
tbz tmp2, #0, 1f
ldrb tmp1w, [src, #-1]!
strb tmp1w, [dst, #-1]!
1:
tbz tmp2, #1, 2f
ldrh tmp1w, [src, #-2]!
strh tmp1w, [dst, #-2]!
2:
tbz tmp2, #2, 3f
ldr tmp1w, [src, #-4]!
str tmp1w, [dst, #-4]!
3:
tbz tmp2, #3, .LSrcAligned
ldr tmp1, [src, #-8]!
str tmp1, [dst, #-8]!
.LSrcAligned:
cmp count, #64
b.ge .Lcpy_over64
/*
* Deal with small copies quickly by dropping straight into the
* exit block.
*/
.Ltail63:
/*
* Copy up to 48 bytes of data. At this point we only need the
* bottom 6 bits of count to be accurate.
*/
ands tmp1, count, #0x30
b.eq .Ltail15
cmp tmp1w, #0x20
b.eq 1f
b.lt 2f
ldp A_l, A_h, [src, #-16]!
stp A_l, A_h, [dst, #-16]!
1:
ldp A_l, A_h, [src, #-16]!
stp A_l, A_h, [dst, #-16]!
2:
ldp A_l, A_h, [src, #-16]!
stp A_l, A_h, [dst, #-16]!
.Ltail15:
tbz count, #3, 1f
ldr tmp1, [src, #-8]!
str tmp1, [dst, #-8]!
1:
tbz count, #2, 2f
ldr tmp1w, [src, #-4]!
str tmp1w, [dst, #-4]!
2:
tbz count, #1, 3f
ldrh tmp1w, [src, #-2]!
strh tmp1w, [dst, #-2]!
3:
tbz count, #0, .Lexitfunc
ldrb tmp1w, [src, #-1]
strb tmp1w, [dst, #-1]
.Lexitfunc:
ret
.Lcpy_over64:
subs count, count, #128
b.ge .Lcpy_body_large
/*
* Less than 128 bytes to copy, so handle 64 bytes here and then jump
* to the tail.
*/
ldp A_l, A_h, [src, #-16]
stp A_l, A_h, [dst, #-16]
ldp B_l, B_h, [src, #-32]
ldp C_l, C_h, [src, #-48]
stp B_l, B_h, [dst, #-32]
stp C_l, C_h, [dst, #-48]
ldp D_l, D_h, [src, #-64]!
stp D_l, D_h, [dst, #-64]!
tst count, #0x3f
b.ne .Ltail63
ret
/*
* Critical loop. Start at a new cache line boundary. Assuming
* 64 bytes per line this ensures the entire loop is in one line.
*/
.p2align L1_CACHE_SHIFT
.Lcpy_body_large:
/* pre-load 64 bytes data. */
ldp A_l, A_h, [src, #-16]
ldp B_l, B_h, [src, #-32]
ldp C_l, C_h, [src, #-48]
ldp D_l, D_h, [src, #-64]!
1:
/*
* interlace the load of next 64 bytes data block with store of the last
* loaded 64 bytes data.
*/
stp A_l, A_h, [dst, #-16]
ldp A_l, A_h, [src, #-16]
stp B_l, B_h, [dst, #-32]
ldp B_l, B_h, [src, #-32]
stp C_l, C_h, [dst, #-48]
ldp C_l, C_h, [src, #-48]
stp D_l, D_h, [dst, #-64]!
ldp D_l, D_h, [src, #-64]!
subs count, count, #64
b.ge 1b
stp A_l, A_h, [dst, #-16]
stp B_l, B_h, [dst, #-32]
stp C_l, C_h, [dst, #-48]
stp D_l, D_h, [dst, #-64]!
tst count, #0x3f
b.ne .Ltail63
ret
ENDPROC(memmove)

View File

@@ -1,5 +1,13 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/cache.h>
/*
* Fill in the buffer with character c (alignment handled by the hardware)
@@ -27,27 +36,181 @@
* Returns:
* x0 - buf
*/
dstin .req x0
val .req w1
count .req x2
tmp1 .req x3
tmp1w .req w3
tmp2 .req x4
tmp2w .req w4
zva_len_x .req x5
zva_len .req w5
zva_bits_x .req x6
A_l .req x7
A_lw .req w7
dst .req x8
tmp3w .req w9
tmp3 .req x9
ENTRY(memset)
mov x4, x0
and w1, w1, #0xff
orr w1, w1, w1, lsl #8
orr w1, w1, w1, lsl #16
orr x1, x1, x1, lsl #32
subs x2, x2, #8
b.mi 2f
1: str x1, [x4], #8
subs x2, x2, #8
b.pl 1b
2: adds x2, x2, #4
b.mi 3f
sub x2, x2, #4
str w1, [x4], #4
3: adds x2, x2, #2
b.mi 4f
sub x2, x2, #2
strh w1, [x4], #2
4: adds x2, x2, #1
b.mi 5f
strb w1, [x4]
5: ret
mov dst, dstin /* Preserve return value. */
and A_lw, val, #255
orr A_lw, A_lw, A_lw, lsl #8
orr A_lw, A_lw, A_lw, lsl #16
orr A_l, A_l, A_l, lsl #32
cmp count, #15
b.hi .Lover16_proc
/*All store maybe are non-aligned..*/
tbz count, #3, 1f
str A_l, [dst], #8
1:
tbz count, #2, 2f
str A_lw, [dst], #4
2:
tbz count, #1, 3f
strh A_lw, [dst], #2
3:
tbz count, #0, 4f
strb A_lw, [dst]
4:
ret
.Lover16_proc:
/*Whether the start address is aligned with 16.*/
neg tmp2, dst
ands tmp2, tmp2, #15
b.eq .Laligned
/*
* The count is not less than 16, we can use stp to store the start 16 bytes,
* then adjust the dst aligned with 16.This process will make the current
* memory address at alignment boundary.
*/
stp A_l, A_l, [dst] /*non-aligned store..*/
/*make the dst aligned..*/
sub count, count, tmp2
add dst, dst, tmp2
.Laligned:
cbz A_l, .Lzero_mem
.Ltail_maybe_long:
cmp count, #64
b.ge .Lnot_short
.Ltail63:
ands tmp1, count, #0x30
b.eq 3f
cmp tmp1w, #0x20
b.eq 1f
b.lt 2f
stp A_l, A_l, [dst], #16
1:
stp A_l, A_l, [dst], #16
2:
stp A_l, A_l, [dst], #16
/*
* The last store length is less than 16,use stp to write last 16 bytes.
* It will lead some bytes written twice and the access is non-aligned.
*/
3:
ands count, count, #15
cbz count, 4f
add dst, dst, count
stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */
4:
ret
/*
* Critical loop. Start at a new cache line boundary. Assuming
* 64 bytes per line, this ensures the entire loop is in one line.
*/
.p2align L1_CACHE_SHIFT
.Lnot_short:
sub dst, dst, #16/* Pre-bias. */
sub count, count, #64
1:
stp A_l, A_l, [dst, #16]
stp A_l, A_l, [dst, #32]
stp A_l, A_l, [dst, #48]
stp A_l, A_l, [dst, #64]!
subs count, count, #64
b.ge 1b
tst count, #0x3f
add dst, dst, #16
b.ne .Ltail63
.Lexitfunc:
ret
/*
* For zeroing memory, check to see if we can use the ZVA feature to
* zero entire 'cache' lines.
*/
.Lzero_mem:
cmp count, #63
b.le .Ltail63
/*
* For zeroing small amounts of memory, it's not worth setting up
* the line-clear code.
*/
cmp count, #128
b.lt .Lnot_short /*count is at least 128 bytes*/
mrs tmp1, dczid_el0
tbnz tmp1, #4, .Lnot_short
mov tmp3w, #4
and zva_len, tmp1w, #15 /* Safety: other bits reserved. */
lsl zva_len, tmp3w, zva_len
ands tmp3w, zva_len, #63
/*
* ensure the zva_len is not less than 64.
* It is not meaningful to use ZVA if the block size is less than 64.
*/
b.ne .Lnot_short
.Lzero_by_line:
/*
* Compute how far we need to go to become suitably aligned. We're
* already at quad-word alignment.
*/
cmp count, zva_len_x
b.lt .Lnot_short /* Not enough to reach alignment. */
sub zva_bits_x, zva_len_x, #1
neg tmp2, dst
ands tmp2, tmp2, zva_bits_x
b.eq 2f /* Already aligned. */
/* Not aligned, check that there's enough to copy after alignment.*/
sub tmp1, count, tmp2
/*
* grantee the remain length to be ZVA is bigger than 64,
* avoid to make the 2f's process over mem range.*/
cmp tmp1, #64
ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */
b.lt .Lnot_short
/*
* We know that there's at least 64 bytes to zero and that it's safe
* to overrun by 64 bytes.
*/
mov count, tmp1
1:
stp A_l, A_l, [dst]
stp A_l, A_l, [dst, #16]
stp A_l, A_l, [dst, #32]
subs tmp2, tmp2, #64
stp A_l, A_l, [dst, #48]
add dst, dst, #64
b.ge 1b
/* We've overrun a bit, so adjust dst downwards.*/
add dst, dst, tmp2
2:
sub count, count, zva_len_x
3:
dc zva, dst
add dst, dst, zva_len_x
subs count, count, zva_len_x
b.ge 3b
ands count, count, zva_bits_x
b.ne .Ltail_maybe_long
ret
ENDPROC(memset)

234
arch/arm64/lib/strcmp.S Normal file
View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* compare two strings
*
* Parameters:
* x0 - const string 1 pointer
* x1 - const string 2 pointer
* Returns:
* x0 - an integer less than, equal to, or greater than zero
* if s1 is found, respectively, to be less than, to match,
* or be greater than s2.
*/
#define REP8_01 0x0101010101010101
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
/* Parameters and result. */
src1 .req x0
src2 .req x1
result .req x0
/* Internal variables. */
data1 .req x2
data1w .req w2
data2 .req x3
data2w .req w3
has_nul .req x4
diff .req x5
syndrome .req x6
tmp1 .req x7
tmp2 .req x8
tmp3 .req x9
zeroones .req x10
pos .req x11
ENTRY(strcmp)
eor tmp1, src1, src2
mov zeroones, #REP8_01
tst tmp1, #7
b.ne .Lmisaligned8
ands tmp1, src1, #7
b.ne .Lmutual_align
/*
* NUL detection works on the principle that (X - 1) & (~X) & 0x80
* (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
* can be done in parallel across the entire word.
*/
.Lloop_aligned:
ldr data1, [src1], #8
ldr data2, [src2], #8
.Lstart_realigned:
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
eor diff, data1, data2 /* Non-zero if differences found. */
bic has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */
orr syndrome, diff, has_nul
cbz syndrome, .Lloop_aligned
b .Lcal_cmpresult
.Lmutual_align:
/*
* Sources are mutually aligned, but are not currently at an
* alignment boundary. Round down the addresses and then mask off
* the bytes that preceed the start point.
*/
bic src1, src1, #7
bic src2, src2, #7
lsl tmp1, tmp1, #3 /* Bytes beyond alignment -> bits. */
ldr data1, [src1], #8
neg tmp1, tmp1 /* Bits to alignment -64. */
ldr data2, [src2], #8
mov tmp2, #~0
/* Big-endian. Early bytes are at MSB. */
CPU_BE( lsl tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */
/* Little-endian. Early bytes are at LSB. */
CPU_LE( lsr tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */
orr data1, data1, tmp2
orr data2, data2, tmp2
b .Lstart_realigned
.Lmisaligned8:
/*
* Get the align offset length to compare per byte first.
* After this process, one string's address will be aligned.
*/
and tmp1, src1, #7
neg tmp1, tmp1
add tmp1, tmp1, #8
and tmp2, src2, #7
neg tmp2, tmp2
add tmp2, tmp2, #8
subs tmp3, tmp1, tmp2
csel pos, tmp1, tmp2, hi /*Choose the maximum. */
.Ltinycmp:
ldrb data1w, [src1], #1
ldrb data2w, [src2], #1
subs pos, pos, #1
ccmp data1w, #1, #0, ne /* NZCV = 0b0000. */
ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */
b.eq .Ltinycmp
cbnz pos, 1f /*find the null or unequal...*/
cmp data1w, #1
ccmp data1w, data2w, #0, cs
b.eq .Lstart_align /*the last bytes are equal....*/
1:
sub result, data1, data2
ret
.Lstart_align:
ands xzr, src1, #7
b.eq .Lrecal_offset
/*process more leading bytes to make str1 aligned...*/
add src1, src1, tmp3
add src2, src2, tmp3
/*load 8 bytes from aligned str1 and non-aligned str2..*/
ldr data1, [src1], #8
ldr data2, [src2], #8
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
bic has_nul, tmp1, tmp2
eor diff, data1, data2 /* Non-zero if differences found. */
orr syndrome, diff, has_nul
cbnz syndrome, .Lcal_cmpresult
/*How far is the current str2 from the alignment boundary...*/
and tmp3, tmp3, #7
.Lrecal_offset:
neg pos, tmp3
.Lloopcmp_proc:
/*
* Divide the eight bytes into two parts. First,backwards the src2
* to an alignment boundary,load eight bytes from the SRC2 alignment
* boundary,then compare with the relative bytes from SRC1.
* If all 8 bytes are equal,then start the second part's comparison.
* Otherwise finish the comparison.
* This special handle can garantee all the accesses are in the
* thread/task space in avoid to overrange access.
*/
ldr data1, [src1,pos]
ldr data2, [src2,pos]
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
bic has_nul, tmp1, tmp2
eor diff, data1, data2 /* Non-zero if differences found. */
orr syndrome, diff, has_nul
cbnz syndrome, .Lcal_cmpresult
/*The second part process*/
ldr data1, [src1], #8
ldr data2, [src2], #8
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
bic has_nul, tmp1, tmp2
eor diff, data1, data2 /* Non-zero if differences found. */
orr syndrome, diff, has_nul
cbz syndrome, .Lloopcmp_proc
.Lcal_cmpresult:
/*
* reversed the byte-order as big-endian,then CLZ can find the most
* significant zero bits.
*/
CPU_LE( rev syndrome, syndrome )
CPU_LE( rev data1, data1 )
CPU_LE( rev data2, data2 )
/*
* For big-endian we cannot use the trick with the syndrome value
* as carry-propagation can corrupt the upper bits if the trailing
* bytes in the string contain 0x01.
* However, if there is no NUL byte in the dword, we can generate
* the result directly. We ca not just subtract the bytes as the
* MSB might be significant.
*/
CPU_BE( cbnz has_nul, 1f )
CPU_BE( cmp data1, data2 )
CPU_BE( cset result, ne )
CPU_BE( cneg result, result, lo )
CPU_BE( ret )
CPU_BE( 1: )
/*Re-compute the NUL-byte detection, using a byte-reversed value. */
CPU_BE( rev tmp3, data1 )
CPU_BE( sub tmp1, tmp3, zeroones )
CPU_BE( orr tmp2, tmp3, #REP8_7f )
CPU_BE( bic has_nul, tmp1, tmp2 )
CPU_BE( rev has_nul, has_nul )
CPU_BE( orr syndrome, diff, has_nul )
clz pos, syndrome
/*
* The MS-non-zero bit of the syndrome marks either the first bit
* that is different, or the top bit of the first zero byte.
* Shifting left now will bring the critical information into the
* top bits.
*/
lsl data1, data1, pos
lsl data2, data2, pos
/*
* But we need to zero-extend (char is unsigned) the value and then
* perform a signed 32-bit subtraction.
*/
lsr data1, data1, #56
sub result, data1, data2, lsr #56
ret
ENDPROC(strcmp)

126
arch/arm64/lib/strlen.S Normal file
View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* calculate the length of a string
*
* Parameters:
* x0 - const string pointer
* Returns:
* x0 - the return length of specific string
*/
/* Arguments and results. */
srcin .req x0
len .req x0
/* Locals and temporaries. */
src .req x1
data1 .req x2
data2 .req x3
data2a .req x4
has_nul1 .req x5
has_nul2 .req x6
tmp1 .req x7
tmp2 .req x8
tmp3 .req x9
tmp4 .req x10
zeroones .req x11
pos .req x12
#define REP8_01 0x0101010101010101
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
ENTRY(strlen)
mov zeroones, #REP8_01
bic src, srcin, #15
ands tmp1, srcin, #15
b.ne .Lmisaligned
/*
* NUL detection works on the principle that (X - 1) & (~X) & 0x80
* (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
* can be done in parallel across the entire word.
*/
/*
* The inner loop deals with two Dwords at a time. This has a
* slightly higher start-up cost, but we should win quite quickly,
* especially on cores with a high number of issue slots per
* cycle, as we get much better parallelism out of the operations.
*/
.Lloop:
ldp data1, data2, [src], #16
.Lrealigned:
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
sub tmp3, data2, zeroones
orr tmp4, data2, #REP8_7f
bic has_nul1, tmp1, tmp2
bics has_nul2, tmp3, tmp4
ccmp has_nul1, #0, #0, eq /* NZCV = 0000 */
b.eq .Lloop
sub len, src, srcin
cbz has_nul1, .Lnul_in_data2
CPU_BE( mov data2, data1 ) /*prepare data to re-calculate the syndrome*/
sub len, len, #8
mov has_nul2, has_nul1
.Lnul_in_data2:
/*
* For big-endian, carry propagation (if the final byte in the
* string is 0x01) means we cannot use has_nul directly. The
* easiest way to get the correct byte is to byte-swap the data
* and calculate the syndrome a second time.
*/
CPU_BE( rev data2, data2 )
CPU_BE( sub tmp1, data2, zeroones )
CPU_BE( orr tmp2, data2, #REP8_7f )
CPU_BE( bic has_nul2, tmp1, tmp2 )
sub len, len, #8
rev has_nul2, has_nul2
clz pos, has_nul2
add len, len, pos, lsr #3 /* Bits to bytes. */
ret
.Lmisaligned:
cmp tmp1, #8
neg tmp1, tmp1
ldp data1, data2, [src], #16
lsl tmp1, tmp1, #3 /* Bytes beyond alignment -> bits. */
mov tmp2, #~0
/* Big-endian. Early bytes are at MSB. */
CPU_BE( lsl tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */
/* Little-endian. Early bytes are at LSB. */
CPU_LE( lsr tmp2, tmp2, tmp1 ) /* Shift (tmp1 & 63). */
orr data1, data1, tmp2
orr data2a, data2, tmp2
csinv data1, data1, xzr, le
csel data2, data2, data2a, le
b .Lrealigned
ENDPROC(strlen)

310
arch/arm64/lib/strncmp.S Normal file
View File

@@ -0,0 +1,310 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* compare two strings
*
* Parameters:
* x0 - const string 1 pointer
* x1 - const string 2 pointer
* x2 - the maximal length to be compared
* Returns:
* x0 - an integer less than, equal to, or greater than zero if s1 is found,
* respectively, to be less than, to match, or be greater than s2.
*/
#define REP8_01 0x0101010101010101
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
/* Parameters and result. */
src1 .req x0
src2 .req x1
limit .req x2
result .req x0
/* Internal variables. */
data1 .req x3
data1w .req w3
data2 .req x4
data2w .req w4
has_nul .req x5
diff .req x6
syndrome .req x7
tmp1 .req x8
tmp2 .req x9
tmp3 .req x10
zeroones .req x11
pos .req x12
limit_wd .req x13
mask .req x14
endloop .req x15
ENTRY(strncmp)
cbz limit, .Lret0
eor tmp1, src1, src2
mov zeroones, #REP8_01
tst tmp1, #7
b.ne .Lmisaligned8
ands tmp1, src1, #7
b.ne .Lmutual_align
/* Calculate the number of full and partial words -1. */
/*
* when limit is mulitply of 8, if not sub 1,
* the judgement of last dword will wrong.
*/
sub limit_wd, limit, #1 /* limit != 0, so no underflow. */
lsr limit_wd, limit_wd, #3 /* Convert to Dwords. */
/*
* NUL detection works on the principle that (X - 1) & (~X) & 0x80
* (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
* can be done in parallel across the entire word.
*/
.Lloop_aligned:
ldr data1, [src1], #8
ldr data2, [src2], #8
.Lstart_realigned:
subs limit_wd, limit_wd, #1
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
eor diff, data1, data2 /* Non-zero if differences found. */
csinv endloop, diff, xzr, pl /* Last Dword or differences.*/
bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */
ccmp endloop, #0, #0, eq
b.eq .Lloop_aligned
/*Not reached the limit, must have found the end or a diff. */
tbz limit_wd, #63, .Lnot_limit
/* Limit % 8 == 0 => all bytes significant. */
ands limit, limit, #7
b.eq .Lnot_limit
lsl limit, limit, #3 /* Bits -> bytes. */
mov mask, #~0
CPU_BE( lsr mask, mask, limit )
CPU_LE( lsl mask, mask, limit )
bic data1, data1, mask
bic data2, data2, mask
/* Make sure that the NUL byte is marked in the syndrome. */
orr has_nul, has_nul, mask
.Lnot_limit:
orr syndrome, diff, has_nul
b .Lcal_cmpresult
.Lmutual_align:
/*
* Sources are mutually aligned, but are not currently at an
* alignment boundary. Round down the addresses and then mask off
* the bytes that precede the start point.
* We also need to adjust the limit calculations, but without
* overflowing if the limit is near ULONG_MAX.
*/
bic src1, src1, #7
bic src2, src2, #7
ldr data1, [src1], #8
neg tmp3, tmp1, lsl #3 /* 64 - bits(bytes beyond align). */
ldr data2, [src2], #8
mov tmp2, #~0
sub limit_wd, limit, #1 /* limit != 0, so no underflow. */
/* Big-endian. Early bytes are at MSB. */
CPU_BE( lsl tmp2, tmp2, tmp3 ) /* Shift (tmp1 & 63). */
/* Little-endian. Early bytes are at LSB. */
CPU_LE( lsr tmp2, tmp2, tmp3 ) /* Shift (tmp1 & 63). */
and tmp3, limit_wd, #7
lsr limit_wd, limit_wd, #3
/* Adjust the limit. Only low 3 bits used, so overflow irrelevant.*/
add limit, limit, tmp1
add tmp3, tmp3, tmp1
orr data1, data1, tmp2
orr data2, data2, tmp2
add limit_wd, limit_wd, tmp3, lsr #3
b .Lstart_realigned
/*when src1 offset is not equal to src2 offset...*/
.Lmisaligned8:
cmp limit, #8
b.lo .Ltiny8proc /*limit < 8... */
/*
* Get the align offset length to compare per byte first.
* After this process, one string's address will be aligned.*/
and tmp1, src1, #7
neg tmp1, tmp1
add tmp1, tmp1, #8
and tmp2, src2, #7
neg tmp2, tmp2
add tmp2, tmp2, #8
subs tmp3, tmp1, tmp2
csel pos, tmp1, tmp2, hi /*Choose the maximum. */
/*
* Here, limit is not less than 8, so directly run .Ltinycmp
* without checking the limit.*/
sub limit, limit, pos
.Ltinycmp:
ldrb data1w, [src1], #1
ldrb data2w, [src2], #1
subs pos, pos, #1
ccmp data1w, #1, #0, ne /* NZCV = 0b0000. */
ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */
b.eq .Ltinycmp
cbnz pos, 1f /*find the null or unequal...*/
cmp data1w, #1
ccmp data1w, data2w, #0, cs
b.eq .Lstart_align /*the last bytes are equal....*/
1:
sub result, data1, data2
ret
.Lstart_align:
lsr limit_wd, limit, #3
cbz limit_wd, .Lremain8
/*process more leading bytes to make str1 aligned...*/
ands xzr, src1, #7
b.eq .Lrecal_offset
add src1, src1, tmp3 /*tmp3 is positive in this branch.*/
add src2, src2, tmp3
ldr data1, [src1], #8
ldr data2, [src2], #8
sub limit, limit, tmp3
lsr limit_wd, limit, #3
subs limit_wd, limit_wd, #1
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
eor diff, data1, data2 /* Non-zero if differences found. */
csinv endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
bics has_nul, tmp1, tmp2
ccmp endloop, #0, #0, eq /*has_null is ZERO: no null byte*/
b.ne .Lunequal_proc
/*How far is the current str2 from the alignment boundary...*/
and tmp3, tmp3, #7
.Lrecal_offset:
neg pos, tmp3
.Lloopcmp_proc:
/*
* Divide the eight bytes into two parts. First,backwards the src2
* to an alignment boundary,load eight bytes from the SRC2 alignment
* boundary,then compare with the relative bytes from SRC1.
* If all 8 bytes are equal,then start the second part's comparison.
* Otherwise finish the comparison.
* This special handle can garantee all the accesses are in the
* thread/task space in avoid to overrange access.
*/
ldr data1, [src1,pos]
ldr data2, [src2,pos]
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */
eor diff, data1, data2 /* Non-zero if differences found. */
csinv endloop, diff, xzr, eq
cbnz endloop, .Lunequal_proc
/*The second part process*/
ldr data1, [src1], #8
ldr data2, [src2], #8
subs limit_wd, limit_wd, #1
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
eor diff, data1, data2 /* Non-zero if differences found. */
csinv endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/
bics has_nul, tmp1, tmp2
ccmp endloop, #0, #0, eq /*has_null is ZERO: no null byte*/
b.eq .Lloopcmp_proc
.Lunequal_proc:
orr syndrome, diff, has_nul
cbz syndrome, .Lremain8
.Lcal_cmpresult:
/*
* reversed the byte-order as big-endian,then CLZ can find the most
* significant zero bits.
*/
CPU_LE( rev syndrome, syndrome )
CPU_LE( rev data1, data1 )
CPU_LE( rev data2, data2 )
/*
* For big-endian we cannot use the trick with the syndrome value
* as carry-propagation can corrupt the upper bits if the trailing
* bytes in the string contain 0x01.
* However, if there is no NUL byte in the dword, we can generate
* the result directly. We can't just subtract the bytes as the
* MSB might be significant.
*/
CPU_BE( cbnz has_nul, 1f )
CPU_BE( cmp data1, data2 )
CPU_BE( cset result, ne )
CPU_BE( cneg result, result, lo )
CPU_BE( ret )
CPU_BE( 1: )
/* Re-compute the NUL-byte detection, using a byte-reversed value.*/
CPU_BE( rev tmp3, data1 )
CPU_BE( sub tmp1, tmp3, zeroones )
CPU_BE( orr tmp2, tmp3, #REP8_7f )
CPU_BE( bic has_nul, tmp1, tmp2 )
CPU_BE( rev has_nul, has_nul )
CPU_BE( orr syndrome, diff, has_nul )
/*
* The MS-non-zero bit of the syndrome marks either the first bit
* that is different, or the top bit of the first zero byte.
* Shifting left now will bring the critical information into the
* top bits.
*/
clz pos, syndrome
lsl data1, data1, pos
lsl data2, data2, pos
/*
* But we need to zero-extend (char is unsigned) the value and then
* perform a signed 32-bit subtraction.
*/
lsr data1, data1, #56
sub result, data1, data2, lsr #56
ret
.Lremain8:
/* Limit % 8 == 0 => all bytes significant. */
ands limit, limit, #7
b.eq .Lret0
.Ltiny8proc:
ldrb data1w, [src1], #1
ldrb data2w, [src2], #1
subs limit, limit, #1
ccmp data1w, #1, #0, ne /* NZCV = 0b0000. */
ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */
b.eq .Ltiny8proc
sub result, data1, data2
ret
.Lret0:
mov result, #0
ret
ENDPROC(strncmp)

171
arch/arm64/lib/strnlen.S Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2013 ARM Ltd.
* Copyright (C) 2013 Linaro.
*
* This code is based on glibc cortex strings work originally authored by Linaro
* and re-licensed under GPLv2 for the Linux kernel. The original code can
* be found @
*
* http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
* files/head:/src/aarch64/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
/*
* determine the length of a fixed-size string
*
* Parameters:
* x0 - const string pointer
* x1 - maximal string length
* Returns:
* x0 - the return length of specific string
*/
/* Arguments and results. */
srcin .req x0
len .req x0
limit .req x1
/* Locals and temporaries. */
src .req x2
data1 .req x3
data2 .req x4
data2a .req x5
has_nul1 .req x6
has_nul2 .req x7
tmp1 .req x8
tmp2 .req x9
tmp3 .req x10
tmp4 .req x11
zeroones .req x12
pos .req x13
limit_wd .req x14
#define REP8_01 0x0101010101010101
#define REP8_7f 0x7f7f7f7f7f7f7f7f
#define REP8_80 0x8080808080808080
ENTRY(strnlen)
cbz limit, .Lhit_limit
mov zeroones, #REP8_01
bic src, srcin, #15
ands tmp1, srcin, #15
b.ne .Lmisaligned
/* Calculate the number of full and partial words -1. */
sub limit_wd, limit, #1 /* Limit != 0, so no underflow. */
lsr limit_wd, limit_wd, #4 /* Convert to Qwords. */
/*
* NUL detection works on the principle that (X - 1) & (~X) & 0x80
* (=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
* can be done in parallel across the entire word.
*/
/*
* The inner loop deals with two Dwords at a time. This has a
* slightly higher start-up cost, but we should win quite quickly,
* especially on cores with a high number of issue slots per
* cycle, as we get much better parallelism out of the operations.
*/
.Lloop:
ldp data1, data2, [src], #16
.Lrealigned:
sub tmp1, data1, zeroones
orr tmp2, data1, #REP8_7f
sub tmp3, data2, zeroones
orr tmp4, data2, #REP8_7f
bic has_nul1, tmp1, tmp2
bic has_nul2, tmp3, tmp4
subs limit_wd, limit_wd, #1
orr tmp1, has_nul1, has_nul2
ccmp tmp1, #0, #0, pl /* NZCV = 0000 */
b.eq .Lloop
cbz tmp1, .Lhit_limit /* No null in final Qword. */
/*
* We know there's a null in the final Qword. The easiest thing
* to do now is work out the length of the string and return
* MIN (len, limit).
*/
sub len, src, srcin
cbz has_nul1, .Lnul_in_data2
CPU_BE( mov data2, data1 ) /*perpare data to re-calculate the syndrome*/
sub len, len, #8
mov has_nul2, has_nul1
.Lnul_in_data2:
/*
* For big-endian, carry propagation (if the final byte in the
* string is 0x01) means we cannot use has_nul directly. The
* easiest way to get the correct byte is to byte-swap the data
* and calculate the syndrome a second time.
*/
CPU_BE( rev data2, data2 )
CPU_BE( sub tmp1, data2, zeroones )
CPU_BE( orr tmp2, data2, #REP8_7f )
CPU_BE( bic has_nul2, tmp1, tmp2 )
sub len, len, #8
rev has_nul2, has_nul2
clz pos, has_nul2
add len, len, pos, lsr #3 /* Bits to bytes. */
cmp len, limit
csel len, len, limit, ls /* Return the lower value. */
ret
.Lmisaligned:
/*
* Deal with a partial first word.
* We're doing two things in parallel here;
* 1) Calculate the number of words (but avoiding overflow if
* limit is near ULONG_MAX) - to do this we need to work out
* limit + tmp1 - 1 as a 65-bit value before shifting it;
* 2) Load and mask the initial data words - we force the bytes
* before the ones we are interested in to 0xff - this ensures
* early bytes will not hit any zero detection.
*/
ldp data1, data2, [src], #16
sub limit_wd, limit, #1
and tmp3, limit_wd, #15
lsr limit_wd, limit_wd, #4
add tmp3, tmp3, tmp1
add limit_wd, limit_wd, tmp3, lsr #4
neg tmp4, tmp1
lsl tmp4, tmp4, #3 /* Bytes beyond alignment -> bits. */
mov tmp2, #~0
/* Big-endian. Early bytes are at MSB. */
CPU_BE( lsl tmp2, tmp2, tmp4 ) /* Shift (tmp1 & 63). */
/* Little-endian. Early bytes are at LSB. */
CPU_LE( lsr tmp2, tmp2, tmp4 ) /* Shift (tmp1 & 63). */
cmp tmp1, #8
orr data1, data1, tmp2
orr data2a, data2, tmp2
csinv data1, data1, xzr, le
csel data2, data2, data2a, le
b .Lrealigned
.Lhit_limit:
mov len, limit
ret
ENDPROC(strnlen)

View File

@@ -1,5 +1,5 @@
obj-y := dma-mapping.o extable.o fault.o init.o \
cache.o copypage.o flush.o \
ioremap.o mmap.o pgd.o mmu.o \
context.o proc.o
context.o proc.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o

View File

@@ -31,7 +31,7 @@
* Corrupted registers: x0-x7, x9-x11
*/
__flush_dcache_all:
dsb sy // ensure ordering with previous memory accesses
dmb sy // ensure ordering with previous memory accesses
mrs x0, clidr_el1 // read clidr
and x3, x0, #0x7000000 // extract loc from clidr
lsr x3, x3, #23 // left align loc bit field
@@ -128,7 +128,7 @@ USER(9f, dc cvau, x4 ) // clean D line to PoU
add x4, x4, x2
cmp x4, x1
b.lo 1b
dsb sy
dsb ish
icache_line_size x2, x3
sub x3, x2, #1
@@ -139,7 +139,7 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU
cmp x4, x1
b.lo 1b
9: // ignore any faulting cache operation
dsb sy
dsb ish
isb
ret
ENDPROC(flush_icache_range)

View File

@@ -20,6 +20,7 @@
#include <linux/gfp.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h>
#include <linux/of.h>
@@ -43,6 +44,54 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
return prot;
}
static struct gen_pool *atomic_pool;
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
static int __init early_coherent_pool(char *p)
{
atomic_pool_size = memparse(p, &p);
return 0;
}
early_param("coherent_pool", early_coherent_pool);
static void *__alloc_from_pool(size_t size, struct page **ret_page)
{
unsigned long val;
void *ptr = NULL;
if (!atomic_pool) {
WARN(1, "coherent pool not initialised!\n");
return NULL;
}
val = gen_pool_alloc(atomic_pool, size);
if (val) {
phys_addr_t phys = gen_pool_virt_to_phys(atomic_pool, val);
*ret_page = phys_to_page(phys);
ptr = (void *)val;
}
return ptr;
}
static bool __in_atomic_pool(void *start, size_t size)
{
return addr_in_gen_pool(atomic_pool, (unsigned long)start, size);
}
static int __free_from_pool(void *start, size_t size)
{
if (!__in_atomic_pool(start, size))
return 0;
gen_pool_free(atomic_pool, (unsigned long)start, size);
return 1;
}
static void *__dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
struct dma_attrs *attrs)
@@ -50,7 +99,7 @@ static void *__dma_alloc_coherent(struct device *dev, size_t size,
if (IS_ENABLED(CONFIG_ZONE_DMA) &&
dev->coherent_dma_mask <= DMA_BIT_MASK(32))
flags |= GFP_DMA;
if (IS_ENABLED(CONFIG_DMA_CMA)) {
if (IS_ENABLED(CONFIG_DMA_CMA) && (flags & __GFP_WAIT)) {
struct page *page;
size = PAGE_ALIGN(size);
@@ -70,50 +119,54 @@ static void __dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
struct dma_attrs *attrs)
{
bool freed;
phys_addr_t paddr = dma_to_phys(dev, dma_handle);
if (dev == NULL) {
WARN_ONCE(1, "Use an actual device structure for DMA allocation\n");
return;
}
if (IS_ENABLED(CONFIG_DMA_CMA)) {
phys_addr_t paddr = dma_to_phys(dev, dma_handle);
dma_release_from_contiguous(dev,
freed = dma_release_from_contiguous(dev,
phys_to_page(paddr),
size >> PAGE_SHIFT);
} else {
if (!freed)
swiotlb_free_coherent(dev, size, vaddr, dma_handle);
}
}
static void *__dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flags,
struct dma_attrs *attrs)
{
struct page *page, **map;
struct page *page;
void *ptr, *coherent_ptr;
int order, i;
size = PAGE_ALIGN(size);
order = get_order(size);
if (!(flags & __GFP_WAIT)) {
struct page *page = NULL;
void *addr = __alloc_from_pool(size, &page);
if (addr)
*dma_handle = phys_to_dma(dev, page_to_phys(page));
return addr;
}
ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs);
if (!ptr)
goto no_mem;
map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA);
if (!map)
goto no_map;
/* remove any dirty cache lines on the kernel alias */
__dma_flush_range(ptr, ptr + size);
/* create a coherent mapping */
page = virt_to_page(ptr);
for (i = 0; i < (size >> PAGE_SHIFT); i++)
map[i] = page + i;
coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
__get_dma_pgprot(attrs, __pgprot(PROT_NORMAL_NC), false));
kfree(map);
coherent_ptr = dma_common_contiguous_remap(page, size, VM_USERMAP,
__get_dma_pgprot(attrs,
__pgprot(PROT_NORMAL_NC), false),
NULL);
if (!coherent_ptr)
goto no_map;
@@ -132,6 +185,8 @@ static void __dma_free_noncoherent(struct device *dev, size_t size,
{
void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle));
if (__free_from_pool(vaddr, size))
return;
vunmap(vaddr);
__dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs);
}
@@ -329,6 +384,67 @@ static struct notifier_block amba_bus_nb = {
extern int swiotlb_late_init_with_default_size(size_t default_size);
static int __init atomic_pool_init(void)
{
pgprot_t prot = __pgprot(PROT_NORMAL_NC);
unsigned long nr_pages = atomic_pool_size >> PAGE_SHIFT;
struct page *page;
void *addr;
unsigned int pool_size_order = get_order(atomic_pool_size);
if (dev_get_cma_area(NULL))
page = dma_alloc_from_contiguous(NULL, nr_pages,
pool_size_order);
else
page = alloc_pages(GFP_DMA, pool_size_order);
if (page) {
int ret;
void *page_addr = page_address(page);
memset(page_addr, 0, atomic_pool_size);
__dma_flush_range(page_addr, page_addr + atomic_pool_size);
atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
if (!atomic_pool)
goto free_page;
addr = dma_common_contiguous_remap(page, atomic_pool_size,
VM_USERMAP, prot, atomic_pool_init);
if (!addr)
goto destroy_genpool;
ret = gen_pool_add_virt(atomic_pool, (unsigned long)addr,
page_to_phys(page),
atomic_pool_size, -1);
if (ret)
goto remove_mapping;
gen_pool_set_algo(atomic_pool,
gen_pool_first_fit_order_align,
(void *)PAGE_SHIFT);
pr_info("DMA: preallocated %zu KiB pool for atomic allocations\n",
atomic_pool_size / 1024);
return 0;
}
goto out;
remove_mapping:
dma_common_free_remap(addr, atomic_pool_size, VM_USERMAP);
destroy_genpool:
gen_pool_destroy(atomic_pool);
atomic_pool = NULL;
free_page:
if (!dma_release_from_contiguous(NULL, page, nr_pages))
__free_pages(page, pool_size_order);
out:
pr_err("DMA: failed to allocate %zu KiB pool for atomic coherent allocation\n",
atomic_pool_size / 1024);
return -ENOMEM;
}
static int __init swiotlb_late_init(void)
{
size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT);
@@ -343,7 +459,17 @@ static int __init swiotlb_late_init(void)
return swiotlb_late_init_with_default_size(swiotlb_size);
}
arch_initcall(swiotlb_late_init);
static int __init arm64_dma_init(void)
{
int ret = 0;
ret |= swiotlb_late_init();
ret |= atomic_pool_init();
return ret;
}
arch_initcall(arm64_dma_init);
#define PREALLOC_DMA_DEBUG_ENTRIES 4096

View File

@@ -51,7 +51,11 @@ int pmd_huge(pmd_t pmd)
int pud_huge(pud_t pud)
{
#ifndef __PAGETABLE_PMD_FOLDED
return !(pud_val(pud) & PUD_TABLE_BIT);
#else
return 0;
#endif
}
static __init int setup_hugepagesz(char *opt)

View File

@@ -68,6 +68,17 @@ static int __init early_initrd(char *p)
}
early_param("initrd", early_initrd);
/*
* Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It
* currently assumes that for memory starting above 4G, 32-bit devices will
* use a DMA offset.
*/
static phys_addr_t max_zone_dma_phys(void)
{
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
return min(offset + (1ULL << 32), memblock_end_of_DRAM());
}
static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
struct memblock_region *reg;
@@ -78,9 +89,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
/* 4GB maximum for 32-bit only capable devices */
if (IS_ENABLED(CONFIG_ZONE_DMA)) {
unsigned long max_dma_phys =
(unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1);
max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT));
max_dma = PFN_DOWN(max_zone_dma_phys());
zone_size[ZONE_DMA] = max_dma - min;
}
zone_size[ZONE_NORMAL] = max - max_dma;
@@ -153,6 +162,7 @@ void __init rockchip_ion_reserve_bit64(void)
void __init arm64_memblock_init(void)
{
u64 *reserve_map, base, size;
phys_addr_t dma_phys_limit = 0;
/*
* Register the kernel text, kernel data, initrd, and initial
@@ -192,7 +202,11 @@ void __init arm64_memblock_init(void)
#ifdef CONFIG_ARCH_ROCKCHIP
rockchip_ion_reserve_bit64();
#endif
dma_contiguous_reserve(0);
/* 4GB maximum for 32-bit only capable devices */
if (IS_ENABLED(CONFIG_ZONE_DMA))
dma_phys_limit = max_zone_dma_phys();
dma_contiguous_reserve(dma_phys_limit);
memblock_allow_resize();
memblock_dump_all();

View File

@@ -98,19 +98,25 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
}
EXPORT_SYMBOL(ioremap_cache);
#ifndef CONFIG_ARM64_64K_PAGES
static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
#ifndef CONFIG_ARM64_64K_PAGES
static pte_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
#endif
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
static inline pud_t * __init early_ioremap_pud(unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
pgd = pgd_offset_k(addr);
BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
pud = pud_offset(pgd, addr);
return pud_offset(pgd, addr);
}
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
{
pud_t *pud = early_ioremap_pud(addr);
BUG_ON(pud_none(*pud) || pud_bad(*pud));
return pmd_offset(pud, addr);
@@ -127,13 +133,17 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
void __init early_ioremap_init(void)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
unsigned long addr = fix_to_virt(FIX_BTMAP_BEGIN);
pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
#ifndef CONFIG_ARM64_64K_PAGES
/* need to populate pmd for 4k pagesize only */
pgd = pgd_offset_k(addr);
pud = pud_offset(pgd, addr);
pud_populate(&init_mm, pud, bm_pmd);
pmd = pmd_offset(pud, addr);
pmd_populate_kernel(&init_mm, pmd, bm_pte);
#endif
/*
* The boot-ioremap range spans multiple pmds, for which
* we are not prepared:

96
arch/arm64/mm/pageattr.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
struct page_change_data {
pgprot_t set_mask;
pgprot_t clear_mask;
};
static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
void *data)
{
struct page_change_data *cdata = data;
pte_t pte = *ptep;
pte = clear_pte_bit(pte, cdata->clear_mask);
pte = set_pte_bit(pte, cdata->set_mask);
set_pte(ptep, pte);
return 0;
}
static int change_memory_common(unsigned long addr, int numpages,
pgprot_t set_mask, pgprot_t clear_mask)
{
unsigned long start = addr;
unsigned long size = PAGE_SIZE*numpages;
unsigned long end = start + size;
int ret;
struct page_change_data data;
if (!IS_ALIGNED(addr, PAGE_SIZE)) {
addr &= PAGE_MASK;
WARN_ON_ONCE(1);
}
if (!is_module_address(start) || !is_module_address(end - 1))
return -EINVAL;
data.set_mask = set_mask;
data.clear_mask = clear_mask;
ret = apply_to_page_range(&init_mm, start, size, change_page_range,
&data);
flush_tlb_kernel_range(start, end);
return ret;
}
int set_memory_ro(unsigned long addr, int numpages)
{
return change_memory_common(addr, numpages,
__pgprot(PTE_RDONLY),
__pgprot(PTE_WRITE));
}
EXPORT_SYMBOL_GPL(set_memory_ro);
int set_memory_rw(unsigned long addr, int numpages)
{
return change_memory_common(addr, numpages,
__pgprot(PTE_WRITE),
__pgprot(PTE_RDONLY));
}
EXPORT_SYMBOL_GPL(set_memory_rw);
int set_memory_nx(unsigned long addr, int numpages)
{
return change_memory_common(addr, numpages,
__pgprot(PTE_PXN),
__pgprot(0));
}
EXPORT_SYMBOL_GPL(set_memory_nx);
int set_memory_x(unsigned long addr, int numpages)
{
return change_memory_common(addr, numpages,
__pgprot(0),
__pgprot(PTE_PXN));
}
EXPORT_SYMBOL_GPL(set_memory_x);

View File

@@ -69,6 +69,21 @@ ENTRY(cpu_reset)
ret x0
ENDPROC(cpu_reset)
ENTRY(cpu_soft_restart)
/* Save address of cpu_reset() and reset address */
mov x19, x0
mov x20, x1
/* Turn D-cache off */
bl cpu_cache_off
/* Push out all dirty data, and ensure cache is empty */
bl flush_cache_all
mov x0, x20
ret x19
ENDPROC(cpu_soft_restart)
/*
* cpu_do_idle()
*
@@ -175,7 +190,7 @@ ENDPROC(cpu_do_switch_mm)
ENTRY(__cpu_setup)
ic iallu // I+BTB cache invalidate
tlbi vmalle1is // invalidate I + D TLBs
dsb sy
dsb ish
mov x0, #3 << 20
msr cpacr_el1, x0 // Enable FP/ASIMD

View File

@@ -30,8 +30,8 @@
V_FUNCTION_BEGIN(__kernel_getcpu)
.cfi_startproc
mfspr r5,SPRN_USPRG3
cmpdi cr0,r3,0
cmpdi cr1,r4,0
cmpwi cr0,r3,0
cmpwi cr1,r4,0
clrlwi r6,r5,16
rlwinm r7,r5,16,31-15,31-0
beq cr0,1f

View File

@@ -248,7 +248,7 @@ asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
struct group_info *group_info;
int retval;
if (!capable(CAP_SETGID))
if (!may_setgroups())
return -EPERM;
if ((unsigned)gidsetsize > NGROUPS_MAX)
return -EINVAL;

View File

@@ -34,7 +34,7 @@ static inline unsigned int __getcpu(void)
native_read_tscp(&p);
} else {
/* Load per CPU data from GDT */
asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
asm volatile ("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
}
return p;

View File

@@ -28,6 +28,13 @@ struct user_desc {
unsigned int seg_not_present:1;
unsigned int useable:1;
#ifdef __x86_64__
/*
* Because this bit is not present in 32-bit user code, user
* programs can pass uninitialized values here. Therefore, in
* any context in which a user_desc comes from a 32-bit program,
* the kernel must act as though lm == 0, regardless of the
* actual value.
*/
unsigned int lm:1;
#endif
};

View File

@@ -65,6 +65,7 @@
#define EXIT_REASON_EOI_INDUCED 45
#define EXIT_REASON_EPT_VIOLATION 48
#define EXIT_REASON_EPT_MISCONFIG 49
#define EXIT_REASON_INVEPT 50
#define EXIT_REASON_PREEMPTION_TIMER 52
#define EXIT_REASON_WBINVD 54
#define EXIT_REASON_XSETBV 55

View File

@@ -2657,6 +2657,17 @@ static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
}
/*
* Using uncore_pmu_event_init pmu event_init callback
* as a detection point for uncore events.
*/
static int uncore_pmu_event_init(struct perf_event *event);
static bool is_uncore_event(struct perf_event *event)
{
return event->pmu->event_init == uncore_pmu_event_init;
}
static int
uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, bool dogrp)
{
@@ -2671,13 +2682,18 @@ uncore_collect_events(struct intel_uncore_box *box, struct perf_event *leader, b
return -EINVAL;
n = box->n_events;
box->event_list[n] = leader;
n++;
if (is_uncore_event(leader)) {
box->event_list[n] = leader;
n++;
}
if (!dogrp)
return n;
list_for_each_entry(event, &leader->sibling_list, group_entry) {
if (event->state <= PERF_EVENT_STATE_OFF)
if (!is_uncore_event(event) ||
event->state <= PERF_EVENT_STATE_OFF)
continue;
if (n >= max_count)

View File

@@ -279,7 +279,14 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
static void __init paravirt_ops_setup(void)
{
pv_info.name = "KVM";
pv_info.paravirt_enabled = 1;
/*
* KVM isn't paravirt in the sense of paravirt_enabled. A KVM
* guest kernel works like a bare metal kernel with additional
* features, and paravirt_enabled is about features that are
* missing.
*/
pv_info.paravirt_enabled = 0;
if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY))
pv_cpu_ops.io_delay = kvm_io_delay;

View File

@@ -265,7 +265,6 @@ void __init kvmclock_init(void)
#endif
kvm_get_preset_lpj();
clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
pv_info.paravirt_enabled = 1;
pv_info.name = "KVM";
if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))

View File

@@ -279,24 +279,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
fpu = switch_fpu_prepare(prev_p, next_p, cpu);
/*
* Reload esp0, LDT and the page table pointer:
*/
/* Reload esp0 and ss1. */
load_sp0(tss, next);
/*
* Switch DS and ES.
* This won't pick up thread selector changes, but I guess that is ok.
*/
savesegment(es, prev->es);
if (unlikely(next->es | prev->es))
loadsegment(es, next->es);
savesegment(ds, prev->ds);
if (unlikely(next->ds | prev->ds))
loadsegment(ds, next->ds);
/* We must save %fs and %gs before load_TLS() because
* %fs and %gs may be cleared by load_TLS().
*
@@ -305,41 +290,101 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
savesegment(fs, fsindex);
savesegment(gs, gsindex);
/*
* Load TLS before restoring any segments so that segment loads
* reference the correct GDT entries.
*/
load_TLS(next, cpu);
/*
* Leave lazy mode, flushing any hypercalls made here.
* This must be done before restoring TLS segments so
* the GDT and LDT are properly updated, and must be
* done before math_state_restore, so the TS bit is up
* to date.
* Leave lazy mode, flushing any hypercalls made here. This
* must be done after loading TLS entries in the GDT but before
* loading segments that might reference them, and and it must
* be done before math_state_restore, so the TS bit is up to
* date.
*/
arch_end_context_switch(next_p);
/* Switch DS and ES.
*
* Reading them only returns the selectors, but writing them (if
* nonzero) loads the full descriptor from the GDT or LDT. The
* LDT for next is loaded in switch_mm, and the GDT is loaded
* above.
*
* We therefore need to write new values to the segment
* registers on every context switch unless both the new and old
* values are zero.
*
* Note that we don't need to do anything for CS and SS, as
* those are saved and restored as part of pt_regs.
*/
savesegment(es, prev->es);
if (unlikely(next->es | prev->es))
loadsegment(es, next->es);
savesegment(ds, prev->ds);
if (unlikely(next->ds | prev->ds))
loadsegment(ds, next->ds);
/*
* Switch FS and GS.
*
* Segment register != 0 always requires a reload. Also
* reload when it has changed. When prev process used 64bit
* base always reload to avoid an information leak.
* These are even more complicated than FS and GS: they have
* 64-bit bases are that controlled by arch_prctl. Those bases
* only differ from the values in the GDT or LDT if the selector
* is 0.
*
* Loading the segment register resets the hidden base part of
* the register to 0 or the value from the GDT / LDT. If the
* next base address zero, writing 0 to the segment register is
* much faster than using wrmsr to explicitly zero the base.
*
* The thread_struct.fs and thread_struct.gs values are 0
* if the fs and gs bases respectively are not overridden
* from the values implied by fsindex and gsindex. They
* are nonzero, and store the nonzero base addresses, if
* the bases are overridden.
*
* (fs != 0 && fsindex != 0) || (gs != 0 && gsindex != 0) should
* be impossible.
*
* Therefore we need to reload the segment registers if either
* the old or new selector is nonzero, and we need to override
* the base address if next thread expects it to be overridden.
*
* This code is unnecessarily slow in the case where the old and
* new indexes are zero and the new base is nonzero -- it will
* unnecessarily write 0 to the selector before writing the new
* base address.
*
* Note: This all depends on arch_prctl being the only way that
* user code can override the segment base. Once wrfsbase and
* wrgsbase are enabled, most of this code will need to change.
*/
if (unlikely(fsindex | next->fsindex | prev->fs)) {
loadsegment(fs, next->fsindex);
/*
* Check if the user used a selector != 0; if yes
* clear 64bit base, since overloaded base is always
* mapped to the Null selector
* If user code wrote a nonzero value to FS, then it also
* cleared the overridden base address.
*
* XXX: if user code wrote 0 to FS and cleared the base
* address itself, we won't notice and we'll incorrectly
* restore the prior base address next time we reschdule
* the process.
*/
if (fsindex)
prev->fs = 0;
}
/* when next process has a 64bit base use it */
if (next->fs)
wrmsrl(MSR_FS_BASE, next->fs);
prev->fsindex = fsindex;
if (unlikely(gsindex | next->gsindex | prev->gs)) {
load_gs_index(next->gsindex);
/* This works (and fails) the same way as fsindex above. */
if (gsindex)
prev->gs = 0;
}

View File

@@ -36,7 +36,7 @@ void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
static const struct desc_ptr no_idt = {};
static int reboot_mode;
static enum reboot_mode reboot_mode;
enum reboot_type reboot_type = BOOT_ACPI;
int reboot_force;
@@ -88,11 +88,11 @@ static int __init reboot_setup(char *str)
switch (*str) {
case 'w':
reboot_mode = 0x1234;
reboot_mode = REBOOT_WARM;
break;
case 'c':
reboot_mode = 0;
reboot_mode = REBOOT_COLD;
break;
#ifdef CONFIG_SMP
@@ -552,6 +552,7 @@ static void native_machine_emergency_restart(void)
int i;
int attempt = 0;
int orig_reboot_type = reboot_type;
unsigned short mode;
if (reboot_emergency)
emergency_vmx_disable_all();
@@ -559,7 +560,8 @@ static void native_machine_emergency_restart(void)
tboot_shutdown(TB_SHUTDOWN_REBOOT);
/* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode;
mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0;
*((unsigned short *)__va(0x472)) = mode;
for (;;) {
/* Could also try the reset bit in the Hammer NB */
@@ -601,7 +603,7 @@ static void native_machine_emergency_restart(void)
case BOOT_EFI:
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi.reset_system(reboot_mode ?
efi.reset_system(reboot_mode == REBOOT_WARM ?
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL);

View File

@@ -27,6 +27,37 @@ static int get_free_idx(void)
return -ESRCH;
}
static bool tls_desc_okay(const struct user_desc *info)
{
if (LDT_empty(info))
return true;
/*
* espfix is required for 16-bit data segments, but espfix
* only works for LDT segments.
*/
if (!info->seg_32bit)
return false;
/* Only allow data segments in the TLS array. */
if (info->contents > 1)
return false;
/*
* Non-present segments with DPL 3 present an interesting attack
* surface. The kernel should handle such segments correctly,
* but TLS is very difficult to protect in a sandbox, so prevent
* such segments from being created.
*
* If userspace needs to remove a TLS entry, it can still delete
* it outright.
*/
if (info->seg_not_present)
return false;
return true;
}
static void set_tls_desc(struct task_struct *p, int idx,
const struct user_desc *info, int n)
{
@@ -66,6 +97,9 @@ int do_set_thread_area(struct task_struct *p, int idx,
if (copy_from_user(&info, u_info, sizeof(info)))
return -EFAULT;
if (!tls_desc_okay(&info))
return -EINVAL;
if (idx == -1)
idx = info.entry_number;
@@ -192,6 +226,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset,
{
struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
const struct user_desc *info;
int i;
if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
(pos % sizeof(struct user_desc)) != 0 ||
@@ -205,6 +240,10 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset,
else
info = infobuf;
for (i = 0; i < count / sizeof(struct user_desc); i++)
if (!tls_desc_okay(info + i))
return -EINVAL;
set_tls_desc(target,
GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)),
info, count / sizeof(struct user_desc));

View File

@@ -6242,6 +6242,12 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
return 1;
}
static int handle_invept(struct kvm_vcpu *vcpu)
{
kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
}
/*
* The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs
@@ -6286,6 +6292,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_PAUSE_INSTRUCTION] = handle_pause,
[EXIT_REASON_MWAIT_INSTRUCTION] = handle_invalid_op,
[EXIT_REASON_MONITOR_INSTRUCTION] = handle_invalid_op,
[EXIT_REASON_INVEPT] = handle_invept,
};
static const int kvm_vmx_max_exit_handlers =
@@ -6512,6 +6519,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD:
case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE:
case EXIT_REASON_VMOFF: case EXIT_REASON_VMON:
case EXIT_REASON_INVEPT:
/*
* VMX instructions trap unconditionally. This allows L1 to
* emulate them for its L2 guest, i.e., allows 3-level nesting!

View File

@@ -117,30 +117,45 @@ subsys_initcall(init_vdso);
struct linux_binprm;
/* Put the vdso above the (randomized) stack with another randomized offset.
This way there is no hole in the middle of address space.
To save memory make sure it is still in the same PTE as the stack top.
This doesn't give that many random bits */
/*
* Put the vdso above the (randomized) stack with another randomized
* offset. This way there is no hole in the middle of address space.
* To save memory make sure it is still in the same PTE as the stack
* top. This doesn't give that many random bits.
*
* Note that this algorithm is imperfect: the distribution of the vdso
* start address within a PMD is biased toward the end.
*
* Only used for the 64-bit and x32 vdsos.
*/
static unsigned long vdso_addr(unsigned long start, unsigned len)
{
unsigned long addr, end;
unsigned offset;
end = (start + PMD_SIZE - 1) & PMD_MASK;
/*
* Round up the start address. It can start out unaligned as a result
* of stack start randomization.
*/
start = PAGE_ALIGN(start);
/* Round the lowest possible end address up to a PMD boundary. */
end = (start + len + PMD_SIZE - 1) & PMD_MASK;
if (end >= TASK_SIZE_MAX)
end = TASK_SIZE_MAX;
end -= len;
/* This loses some more bits than a modulo, but is cheaper */
offset = get_random_int() & (PTRS_PER_PTE - 1);
addr = start + (offset << PAGE_SHIFT);
if (addr >= end)
addr = end;
if (end > start) {
offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
addr = start + (offset << PAGE_SHIFT);
} else {
addr = start;
}
/*
* page-align it here so that get_unmapped_area doesn't
* align it wrongfully again to the next page. addr can come in 4K
* unaligned here as a result of stack start randomization.
* Forcibly align the final address in case we have a hardware
* issue that requires alignment for performance reasons.
*/
addr = PAGE_ALIGN(addr);
addr = align_vdso_addr(addr);
return addr;

View File

@@ -1070,9 +1070,16 @@ int disk_expand_part_tbl(struct gendisk *disk, int partno)
struct disk_part_tbl *old_ptbl = disk->part_tbl;
struct disk_part_tbl *new_ptbl;
int len = old_ptbl ? old_ptbl->len : 0;
int target = partno + 1;
int i, target;
size_t size;
int i;
/*
* check for int overflow, since we can get here from blkpg_ioctl()
* with a user passed 'partno'.
*/
target = partno + 1;
if (target < 0)
return -EINVAL;
/* disk_max_parts() is zero during initialization, ignore if so */
if (disk_max_parts(disk) && target > disk_max_parts(disk))

View File

@@ -449,6 +449,9 @@ void af_alg_complete(struct crypto_async_request *req, int err)
{
struct af_alg_completion *completion = req->data;
if (err == -EINPROGRESS)
return;
completion->err = err;
complete(&completion->completion);
}

View File

@@ -157,4 +157,5 @@ obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_GATOR) += gator/
obj-y += headset_observe/
obj-y += headset_observe/
obj-$(CONFIG_CORESIGHT) += coresight/

View File

@@ -508,7 +508,7 @@ int amba_device_add(struct amba_device *dev, struct resource *parent)
// amba_put_disable_pclk(dev);
if (cid == AMBA_CID)
if (cid == AMBA_CID || cid == CORESIGHT_CID)
dev->periphid = pid;
if (!dev->periphid)

View File

@@ -320,6 +320,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
@@ -491,6 +494,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
* enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731
*/
{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
{ PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
/* Enmotus */
{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },

View File

@@ -1501,7 +1501,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
host_priv->csr_base = csr_base;
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (irq < 0) {
if (!irq) {
dev_err(&ofdev->dev, "invalid irq from platform\n");
goto error_exit_with_cleanup;
}

View File

@@ -242,13 +242,15 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
const char *buf, size_t count)
{
struct device *dev;
int err = -EINVAL;
dev = bus_find_device_by_name(bus, NULL, buf);
if (!dev)
return -ENODEV;
if (bus_rescan_devices_helper(dev, NULL) != 0)
return -EINVAL;
return count;
if (bus_rescan_devices_helper(dev, NULL) == 0)
err = count;
put_device(dev);
return err;
}
static struct device *next_device(struct klist_iter *i)

View File

@@ -10,6 +10,8 @@
#include <linux/dma-mapping.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm-generic/dma-coherent.h>
/*
@@ -267,3 +269,73 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
return ret;
}
EXPORT_SYMBOL(dma_common_mmap);
#ifdef CONFIG_MMU
/*
* remaps an array of PAGE_SIZE pages into another vm_area
* Cannot be used in non-sleeping contexts
*/
void *dma_common_pages_remap(struct page **pages, size_t size,
unsigned long vm_flags, pgprot_t prot,
const void *caller)
{
struct vm_struct *area;
area = get_vm_area_caller(size, vm_flags, caller);
if (!area)
return NULL;
area->pages = pages;
if (map_vm_area(area, prot, &pages)) {
vunmap(area->addr);
return NULL;
}
return area->addr;
}
/*
* remaps an allocated contiguous region into another vm_area.
* Cannot be used in non-sleeping contexts
*/
void *dma_common_contiguous_remap(struct page *page, size_t size,
unsigned long vm_flags,
pgprot_t prot, const void *caller)
{
int i;
struct page **pages;
void *ptr;
unsigned long pfn;
pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL);
if (!pages)
return NULL;
for (i = 0, pfn = page_to_pfn(page); i < (size >> PAGE_SHIFT); i++)
pages[i] = pfn_to_page(pfn + i);
ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller);
kfree(pages);
return ptr;
}
/*
* unmaps a range previously mapped by dma_common_*_remap
*/
void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
{
struct vm_struct *area = find_vm_area(cpu_addr);
if (!area || (area->flags & vm_flags) != vm_flags) {
WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
return;
}
unmap_kernel_range((unsigned long)cpu_addr, size);
vunmap(cpu_addr);
}
#endif

View File

@@ -0,0 +1,11 @@
#
# Makefile for CoreSight drivers.
#
obj-$(CONFIG_CORESIGHT) += coresight.o
obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o
obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o

View File

@@ -0,0 +1,537 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/seq_file.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include "coresight-priv.h"
#define ETB_RAM_DEPTH_REG 0x004
#define ETB_STATUS_REG 0x00c
#define ETB_RAM_READ_DATA_REG 0x010
#define ETB_RAM_READ_POINTER 0x014
#define ETB_RAM_WRITE_POINTER 0x018
#define ETB_TRG 0x01c
#define ETB_CTL_REG 0x020
#define ETB_RWD_REG 0x024
#define ETB_FFSR 0x300
#define ETB_FFCR 0x304
#define ETB_ITMISCOP0 0xee0
#define ETB_ITTRFLINACK 0xee4
#define ETB_ITTRFLIN 0xee8
#define ETB_ITATBDATA0 0xeeC
#define ETB_ITATBCTR2 0xef0
#define ETB_ITATBCTR1 0xef4
#define ETB_ITATBCTR0 0xef8
/* register description */
/* STS - 0x00C */
#define ETB_STATUS_RAM_FULL BIT(0)
/* CTL - 0x020 */
#define ETB_CTL_CAPT_EN BIT(0)
/* FFCR - 0x304 */
#define ETB_FFCR_EN_FTC BIT(0)
#define ETB_FFCR_FON_MAN BIT(6)
#define ETB_FFCR_STOP_FI BIT(12)
#define ETB_FFCR_STOP_TRIGGER BIT(13)
#define ETB_FFCR_BIT 6
#define ETB_FFSR_BIT 1
#define ETB_FRAME_SIZE_WORDS 4
/**
* struct etb_drvdata - specifics associated to an ETB component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.etb" entry.
* @clk: the clock this component is associated to.
* @spinlock: only one at a time pls.
* @in_use: synchronise user space access to etb buffer.
* @buf: area of memory where ETB buffer content gets sent.
* @buffer_depth: size of @buf.
* @enable: this ETB is being used.
* @trigger_cntr: amount of words to store after a trigger.
*/
struct etb_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
struct clk *clk;
spinlock_t spinlock;
atomic_t in_use;
u8 *buf;
u32 buffer_depth;
bool enable;
u32 trigger_cntr;
};
static unsigned int etb_get_buffer_depth(struct etb_drvdata *drvdata)
{
int ret;
u32 depth = 0;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
/* RO registers don't need locking */
depth = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG);
clk_disable_unprepare(drvdata->clk);
return depth;
}
static void etb_enable_hw(struct etb_drvdata *drvdata)
{
int i;
u32 depth;
CS_UNLOCK(drvdata->base);
depth = drvdata->buffer_depth;
/* reset write RAM pointer address */
writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
/* clear entire RAM buffer */
for (i = 0; i < depth; i++)
writel_relaxed(0x0, drvdata->base + ETB_RWD_REG);
/* reset write RAM pointer address */
writel_relaxed(0x0, drvdata->base + ETB_RAM_WRITE_POINTER);
/* reset read RAM pointer address */
writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
writel_relaxed(drvdata->trigger_cntr, drvdata->base + ETB_TRG);
writel_relaxed(ETB_FFCR_EN_FTC | ETB_FFCR_STOP_TRIGGER,
drvdata->base + ETB_FFCR);
/* ETB trace capture enable */
writel_relaxed(ETB_CTL_CAPT_EN, drvdata->base + ETB_CTL_REG);
CS_LOCK(drvdata->base);
}
static int etb_enable(struct coresight_device *csdev)
{
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
unsigned long flags;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
spin_lock_irqsave(&drvdata->spinlock, flags);
etb_enable_hw(drvdata);
drvdata->enable = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "ETB enabled\n");
return 0;
}
static void etb_disable_hw(struct etb_drvdata *drvdata)
{
u32 ffcr;
CS_UNLOCK(drvdata->base);
ffcr = readl_relaxed(drvdata->base + ETB_FFCR);
/* stop formatter when a stop has completed */
ffcr |= ETB_FFCR_STOP_FI;
writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
/* manually generate a flush of the system */
ffcr |= ETB_FFCR_FON_MAN;
writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
ETB_FFCR);
}
/* disable trace capture */
writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
ETB_FFCR);
}
CS_LOCK(drvdata->base);
}
static void etb_dump_hw(struct etb_drvdata *drvdata)
{
int i;
u8 *buf_ptr;
u32 read_data, depth;
u32 read_ptr, write_ptr;
u32 frame_off, frame_endoff;
CS_UNLOCK(drvdata->base);
read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
write_ptr = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
frame_off = write_ptr % ETB_FRAME_SIZE_WORDS;
frame_endoff = ETB_FRAME_SIZE_WORDS - frame_off;
if (frame_off) {
dev_err(drvdata->dev,
"write_ptr: %lu not aligned to formatter frame size\n",
(unsigned long)write_ptr);
dev_err(drvdata->dev, "frameoff: %lu, frame_endoff: %lu\n",
(unsigned long)frame_off, (unsigned long)frame_endoff);
write_ptr += frame_endoff;
}
if ((readl_relaxed(drvdata->base + ETB_STATUS_REG)
& ETB_STATUS_RAM_FULL) == 0)
writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER);
else
writel_relaxed(write_ptr, drvdata->base + ETB_RAM_READ_POINTER);
depth = drvdata->buffer_depth;
buf_ptr = drvdata->buf;
for (i = 0; i < depth; i++) {
read_data = readl_relaxed(drvdata->base +
ETB_RAM_READ_DATA_REG);
*buf_ptr++ = read_data >> 0;
*buf_ptr++ = read_data >> 8;
*buf_ptr++ = read_data >> 16;
*buf_ptr++ = read_data >> 24;
}
if (frame_off) {
buf_ptr -= (frame_endoff * 4);
for (i = 0; i < frame_endoff; i++) {
*buf_ptr++ = 0x0;
*buf_ptr++ = 0x0;
*buf_ptr++ = 0x0;
*buf_ptr++ = 0x0;
}
}
writel_relaxed(read_ptr, drvdata->base + ETB_RAM_READ_POINTER);
CS_LOCK(drvdata->base);
}
static void etb_disable(struct coresight_device *csdev)
{
struct etb_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
drvdata->enable = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
clk_disable_unprepare(drvdata->clk);
dev_info(drvdata->dev, "ETB disabled\n");
}
static const struct coresight_ops_sink etb_sink_ops = {
.enable = etb_enable,
.disable = etb_disable,
};
static const struct coresight_ops etb_cs_ops = {
.sink_ops = &etb_sink_ops,
};
static void etb_dump(struct etb_drvdata *drvdata)
{
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->enable) {
etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
etb_enable_hw(drvdata);
}
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "ETB dumped\n");
}
static int etb_open(struct inode *inode, struct file *file)
{
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
if (atomic_cmpxchg(&drvdata->in_use, 0, 1))
return -EBUSY;
dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
return 0;
}
static ssize_t etb_read(struct file *file, char __user *data,
size_t len, loff_t *ppos)
{
u32 depth;
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
etb_dump(drvdata);
depth = drvdata->buffer_depth;
if (*ppos + len > depth * 4)
len = depth * 4 - *ppos;
if (copy_to_user(data, drvdata->buf + *ppos, len)) {
dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
return -EFAULT;
}
*ppos += len;
dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
__func__, len, (int) (depth * 4 - *ppos));
return len;
}
static int etb_release(struct inode *inode, struct file *file)
{
struct etb_drvdata *drvdata = container_of(file->private_data,
struct etb_drvdata, miscdev);
atomic_set(&drvdata->in_use, 0);
dev_dbg(drvdata->dev, "%s: released\n", __func__);
return 0;
}
static const struct file_operations etb_fops = {
.owner = THIS_MODULE,
.open = etb_open,
.read = etb_read,
.release = etb_release,
.llseek = no_llseek,
};
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
unsigned long flags;
u32 etb_rdr, etb_sr, etb_rrp, etb_rwp;
u32 etb_trg, etb_cr, etb_ffsr, etb_ffcr;
struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = clk_prepare_enable(drvdata->clk);
if (ret)
goto out;
spin_lock_irqsave(&drvdata->spinlock, flags);
CS_UNLOCK(drvdata->base);
etb_rdr = readl_relaxed(drvdata->base + ETB_RAM_DEPTH_REG);
etb_sr = readl_relaxed(drvdata->base + ETB_STATUS_REG);
etb_rrp = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER);
etb_rwp = readl_relaxed(drvdata->base + ETB_RAM_WRITE_POINTER);
etb_trg = readl_relaxed(drvdata->base + ETB_TRG);
etb_cr = readl_relaxed(drvdata->base + ETB_CTL_REG);
etb_ffsr = readl_relaxed(drvdata->base + ETB_FFSR);
etb_ffcr = readl_relaxed(drvdata->base + ETB_FFCR);
CS_LOCK(drvdata->base);
spin_unlock_irqrestore(&drvdata->spinlock, flags);
clk_disable_unprepare(drvdata->clk);
return sprintf(buf,
"Depth:\t\t0x%x\n"
"Status:\t\t0x%x\n"
"RAM read ptr:\t0x%x\n"
"RAM wrt ptr:\t0x%x\n"
"Trigger cnt:\t0x%x\n"
"Control:\t0x%x\n"
"Flush status:\t0x%x\n"
"Flush ctrl:\t0x%x\n",
etb_rdr, etb_sr, etb_rrp, etb_rwp,
etb_trg, etb_cr, etb_ffsr, etb_ffcr);
out:
return -EINVAL;
}
static DEVICE_ATTR_RO(status);
static ssize_t trigger_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->trigger_cntr;
return sprintf(buf, "%#lx\n", val);
}
static ssize_t trigger_cntr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret;
unsigned long val;
struct etb_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
drvdata->trigger_cntr = val;
return size;
}
static DEVICE_ATTR_RW(trigger_cntr);
static struct attribute *coresight_etb_attrs[] = {
&dev_attr_trigger_cntr.attr,
&dev_attr_status.attr,
NULL,
};
ATTRIBUTE_GROUPS(coresight_etb);
static int etb_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
void __iomem *base;
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
struct etb_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct device_node *np = adev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
adev->dev.platform_data = pdata;
}
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
drvdata->base = base;
spin_lock_init(&drvdata->spinlock);
drvdata->clk = adev->pclk;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
clk_disable_unprepare(drvdata->clk);
if (drvdata->buffer_depth < 0)
return -EINVAL;
drvdata->buf = devm_kzalloc(dev,
drvdata->buffer_depth * 4, GFP_KERNEL);
if (!drvdata->buf)
return -ENOMEM;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc->ops = &etb_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_etb_groups;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
drvdata->miscdev.name = pdata->name;
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
drvdata->miscdev.fops = &etb_fops;
ret = misc_register(&drvdata->miscdev);
if (ret)
goto err_misc_register;
dev_info(dev, "ETB initialized\n");
return 0;
err_misc_register:
coresight_unregister(drvdata->csdev);
return ret;
}
static int etb_remove(struct amba_device *adev)
{
struct etb_drvdata *drvdata = amba_get_drvdata(adev);
misc_deregister(&drvdata->miscdev);
coresight_unregister(drvdata->csdev);
return 0;
}
static struct amba_id etb_ids[] = {
{
.id = 0x0003b907,
.mask = 0x0003ffff,
},
{ 0, 0},
};
static struct amba_driver etb_driver = {
.drv = {
.name = "coresight-etb10",
.owner = THIS_MODULE,
},
.probe = etb_probe,
.remove = etb_remove,
.id_table = etb_ids,
};
static int __init etb_init(void)
{
return amba_driver_register(&etb_driver);
}
module_init(etb_init);
static void __exit etb_exit(void)
{
amba_driver_unregister(&etb_driver);
}
module_exit(etb_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");

View File

@@ -0,0 +1,591 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bug.h>
#include <asm/hardware/cp14.h>
#include "coresight-etm.h"
int etm_readl_cp14(u32 reg, unsigned int *val)
{
switch (reg) {
case ETMCR:
*val = etm_read(ETMCR);
return 0;
case ETMCCR:
*val = etm_read(ETMCCR);
return 0;
case ETMTRIGGER:
*val = etm_read(ETMTRIGGER);
return 0;
case ETMSR:
*val = etm_read(ETMSR);
return 0;
case ETMSCR:
*val = etm_read(ETMSCR);
return 0;
case ETMTSSCR:
*val = etm_read(ETMTSSCR);
return 0;
case ETMTEEVR:
*val = etm_read(ETMTEEVR);
return 0;
case ETMTECR1:
*val = etm_read(ETMTECR1);
return 0;
case ETMFFLR:
*val = etm_read(ETMFFLR);
return 0;
case ETMACVRn(0):
*val = etm_read(ETMACVR0);
return 0;
case ETMACVRn(1):
*val = etm_read(ETMACVR1);
return 0;
case ETMACVRn(2):
*val = etm_read(ETMACVR2);
return 0;
case ETMACVRn(3):
*val = etm_read(ETMACVR3);
return 0;
case ETMACVRn(4):
*val = etm_read(ETMACVR4);
return 0;
case ETMACVRn(5):
*val = etm_read(ETMACVR5);
return 0;
case ETMACVRn(6):
*val = etm_read(ETMACVR6);
return 0;
case ETMACVRn(7):
*val = etm_read(ETMACVR7);
return 0;
case ETMACVRn(8):
*val = etm_read(ETMACVR8);
return 0;
case ETMACVRn(9):
*val = etm_read(ETMACVR9);
return 0;
case ETMACVRn(10):
*val = etm_read(ETMACVR10);
return 0;
case ETMACVRn(11):
*val = etm_read(ETMACVR11);
return 0;
case ETMACVRn(12):
*val = etm_read(ETMACVR12);
return 0;
case ETMACVRn(13):
*val = etm_read(ETMACVR13);
return 0;
case ETMACVRn(14):
*val = etm_read(ETMACVR14);
return 0;
case ETMACVRn(15):
*val = etm_read(ETMACVR15);
return 0;
case ETMACTRn(0):
*val = etm_read(ETMACTR0);
return 0;
case ETMACTRn(1):
*val = etm_read(ETMACTR1);
return 0;
case ETMACTRn(2):
*val = etm_read(ETMACTR2);
return 0;
case ETMACTRn(3):
*val = etm_read(ETMACTR3);
return 0;
case ETMACTRn(4):
*val = etm_read(ETMACTR4);
return 0;
case ETMACTRn(5):
*val = etm_read(ETMACTR5);
return 0;
case ETMACTRn(6):
*val = etm_read(ETMACTR6);
return 0;
case ETMACTRn(7):
*val = etm_read(ETMACTR7);
return 0;
case ETMACTRn(8):
*val = etm_read(ETMACTR8);
return 0;
case ETMACTRn(9):
*val = etm_read(ETMACTR9);
return 0;
case ETMACTRn(10):
*val = etm_read(ETMACTR10);
return 0;
case ETMACTRn(11):
*val = etm_read(ETMACTR11);
return 0;
case ETMACTRn(12):
*val = etm_read(ETMACTR12);
return 0;
case ETMACTRn(13):
*val = etm_read(ETMACTR13);
return 0;
case ETMACTRn(14):
*val = etm_read(ETMACTR14);
return 0;
case ETMACTRn(15):
*val = etm_read(ETMACTR15);
return 0;
case ETMCNTRLDVRn(0):
*val = etm_read(ETMCNTRLDVR0);
return 0;
case ETMCNTRLDVRn(1):
*val = etm_read(ETMCNTRLDVR1);
return 0;
case ETMCNTRLDVRn(2):
*val = etm_read(ETMCNTRLDVR2);
return 0;
case ETMCNTRLDVRn(3):
*val = etm_read(ETMCNTRLDVR3);
return 0;
case ETMCNTENRn(0):
*val = etm_read(ETMCNTENR0);
return 0;
case ETMCNTENRn(1):
*val = etm_read(ETMCNTENR1);
return 0;
case ETMCNTENRn(2):
*val = etm_read(ETMCNTENR2);
return 0;
case ETMCNTENRn(3):
*val = etm_read(ETMCNTENR3);
return 0;
case ETMCNTRLDEVRn(0):
*val = etm_read(ETMCNTRLDEVR0);
return 0;
case ETMCNTRLDEVRn(1):
*val = etm_read(ETMCNTRLDEVR1);
return 0;
case ETMCNTRLDEVRn(2):
*val = etm_read(ETMCNTRLDEVR2);
return 0;
case ETMCNTRLDEVRn(3):
*val = etm_read(ETMCNTRLDEVR3);
return 0;
case ETMCNTVRn(0):
*val = etm_read(ETMCNTVR0);
return 0;
case ETMCNTVRn(1):
*val = etm_read(ETMCNTVR1);
return 0;
case ETMCNTVRn(2):
*val = etm_read(ETMCNTVR2);
return 0;
case ETMCNTVRn(3):
*val = etm_read(ETMCNTVR3);
return 0;
case ETMSQ12EVR:
*val = etm_read(ETMSQ12EVR);
return 0;
case ETMSQ21EVR:
*val = etm_read(ETMSQ21EVR);
return 0;
case ETMSQ23EVR:
*val = etm_read(ETMSQ23EVR);
return 0;
case ETMSQ31EVR:
*val = etm_read(ETMSQ31EVR);
return 0;
case ETMSQ32EVR:
*val = etm_read(ETMSQ32EVR);
return 0;
case ETMSQ13EVR:
*val = etm_read(ETMSQ13EVR);
return 0;
case ETMSQR:
*val = etm_read(ETMSQR);
return 0;
case ETMEXTOUTEVRn(0):
*val = etm_read(ETMEXTOUTEVR0);
return 0;
case ETMEXTOUTEVRn(1):
*val = etm_read(ETMEXTOUTEVR1);
return 0;
case ETMEXTOUTEVRn(2):
*val = etm_read(ETMEXTOUTEVR2);
return 0;
case ETMEXTOUTEVRn(3):
*val = etm_read(ETMEXTOUTEVR3);
return 0;
case ETMCIDCVRn(0):
*val = etm_read(ETMCIDCVR0);
return 0;
case ETMCIDCVRn(1):
*val = etm_read(ETMCIDCVR1);
return 0;
case ETMCIDCVRn(2):
*val = etm_read(ETMCIDCVR2);
return 0;
case ETMCIDCMR:
*val = etm_read(ETMCIDCMR);
return 0;
case ETMIMPSPEC0:
*val = etm_read(ETMIMPSPEC0);
return 0;
case ETMIMPSPEC1:
*val = etm_read(ETMIMPSPEC1);
return 0;
case ETMIMPSPEC2:
*val = etm_read(ETMIMPSPEC2);
return 0;
case ETMIMPSPEC3:
*val = etm_read(ETMIMPSPEC3);
return 0;
case ETMIMPSPEC4:
*val = etm_read(ETMIMPSPEC4);
return 0;
case ETMIMPSPEC5:
*val = etm_read(ETMIMPSPEC5);
return 0;
case ETMIMPSPEC6:
*val = etm_read(ETMIMPSPEC6);
return 0;
case ETMIMPSPEC7:
*val = etm_read(ETMIMPSPEC7);
return 0;
case ETMSYNCFR:
*val = etm_read(ETMSYNCFR);
return 0;
case ETMIDR:
*val = etm_read(ETMIDR);
return 0;
case ETMCCER:
*val = etm_read(ETMCCER);
return 0;
case ETMEXTINSELR:
*val = etm_read(ETMEXTINSELR);
return 0;
case ETMTESSEICR:
*val = etm_read(ETMTESSEICR);
return 0;
case ETMEIBCR:
*val = etm_read(ETMEIBCR);
return 0;
case ETMTSEVR:
*val = etm_read(ETMTSEVR);
return 0;
case ETMAUXCR:
*val = etm_read(ETMAUXCR);
return 0;
case ETMTRACEIDR:
*val = etm_read(ETMTRACEIDR);
return 0;
case ETMVMIDCVR:
*val = etm_read(ETMVMIDCVR);
return 0;
case ETMOSLSR:
*val = etm_read(ETMOSLSR);
return 0;
case ETMOSSRR:
*val = etm_read(ETMOSSRR);
return 0;
case ETMPDCR:
*val = etm_read(ETMPDCR);
return 0;
case ETMPDSR:
*val = etm_read(ETMPDSR);
return 0;
default:
*val = 0;
return -EINVAL;
}
}
int etm_writel_cp14(u32 reg, u32 val)
{
switch (reg) {
case ETMCR:
etm_write(val, ETMCR);
break;
case ETMTRIGGER:
etm_write(val, ETMTRIGGER);
break;
case ETMSR:
etm_write(val, ETMSR);
break;
case ETMTSSCR:
etm_write(val, ETMTSSCR);
break;
case ETMTEEVR:
etm_write(val, ETMTEEVR);
break;
case ETMTECR1:
etm_write(val, ETMTECR1);
break;
case ETMFFLR:
etm_write(val, ETMFFLR);
break;
case ETMACVRn(0):
etm_write(val, ETMACVR0);
break;
case ETMACVRn(1):
etm_write(val, ETMACVR1);
break;
case ETMACVRn(2):
etm_write(val, ETMACVR2);
break;
case ETMACVRn(3):
etm_write(val, ETMACVR3);
break;
case ETMACVRn(4):
etm_write(val, ETMACVR4);
break;
case ETMACVRn(5):
etm_write(val, ETMACVR5);
break;
case ETMACVRn(6):
etm_write(val, ETMACVR6);
break;
case ETMACVRn(7):
etm_write(val, ETMACVR7);
break;
case ETMACVRn(8):
etm_write(val, ETMACVR8);
break;
case ETMACVRn(9):
etm_write(val, ETMACVR9);
break;
case ETMACVRn(10):
etm_write(val, ETMACVR10);
break;
case ETMACVRn(11):
etm_write(val, ETMACVR11);
break;
case ETMACVRn(12):
etm_write(val, ETMACVR12);
break;
case ETMACVRn(13):
etm_write(val, ETMACVR13);
break;
case ETMACVRn(14):
etm_write(val, ETMACVR14);
break;
case ETMACVRn(15):
etm_write(val, ETMACVR15);
break;
case ETMACTRn(0):
etm_write(val, ETMACTR0);
break;
case ETMACTRn(1):
etm_write(val, ETMACTR1);
break;
case ETMACTRn(2):
etm_write(val, ETMACTR2);
break;
case ETMACTRn(3):
etm_write(val, ETMACTR3);
break;
case ETMACTRn(4):
etm_write(val, ETMACTR4);
break;
case ETMACTRn(5):
etm_write(val, ETMACTR5);
break;
case ETMACTRn(6):
etm_write(val, ETMACTR6);
break;
case ETMACTRn(7):
etm_write(val, ETMACTR7);
break;
case ETMACTRn(8):
etm_write(val, ETMACTR8);
break;
case ETMACTRn(9):
etm_write(val, ETMACTR9);
break;
case ETMACTRn(10):
etm_write(val, ETMACTR10);
break;
case ETMACTRn(11):
etm_write(val, ETMACTR11);
break;
case ETMACTRn(12):
etm_write(val, ETMACTR12);
break;
case ETMACTRn(13):
etm_write(val, ETMACTR13);
break;
case ETMACTRn(14):
etm_write(val, ETMACTR14);
break;
case ETMACTRn(15):
etm_write(val, ETMACTR15);
break;
case ETMCNTRLDVRn(0):
etm_write(val, ETMCNTRLDVR0);
break;
case ETMCNTRLDVRn(1):
etm_write(val, ETMCNTRLDVR1);
break;
case ETMCNTRLDVRn(2):
etm_write(val, ETMCNTRLDVR2);
break;
case ETMCNTRLDVRn(3):
etm_write(val, ETMCNTRLDVR3);
break;
case ETMCNTENRn(0):
etm_write(val, ETMCNTENR0);
break;
case ETMCNTENRn(1):
etm_write(val, ETMCNTENR1);
break;
case ETMCNTENRn(2):
etm_write(val, ETMCNTENR2);
break;
case ETMCNTENRn(3):
etm_write(val, ETMCNTENR3);
break;
case ETMCNTRLDEVRn(0):
etm_write(val, ETMCNTRLDEVR0);
break;
case ETMCNTRLDEVRn(1):
etm_write(val, ETMCNTRLDEVR1);
break;
case ETMCNTRLDEVRn(2):
etm_write(val, ETMCNTRLDEVR2);
break;
case ETMCNTRLDEVRn(3):
etm_write(val, ETMCNTRLDEVR3);
break;
case ETMCNTVRn(0):
etm_write(val, ETMCNTVR0);
break;
case ETMCNTVRn(1):
etm_write(val, ETMCNTVR1);
break;
case ETMCNTVRn(2):
etm_write(val, ETMCNTVR2);
break;
case ETMCNTVRn(3):
etm_write(val, ETMCNTVR3);
break;
case ETMSQ12EVR:
etm_write(val, ETMSQ12EVR);
break;
case ETMSQ21EVR:
etm_write(val, ETMSQ21EVR);
break;
case ETMSQ23EVR:
etm_write(val, ETMSQ23EVR);
break;
case ETMSQ31EVR:
etm_write(val, ETMSQ31EVR);
break;
case ETMSQ32EVR:
etm_write(val, ETMSQ32EVR);
break;
case ETMSQ13EVR:
etm_write(val, ETMSQ13EVR);
break;
case ETMSQR:
etm_write(val, ETMSQR);
break;
case ETMEXTOUTEVRn(0):
etm_write(val, ETMEXTOUTEVR0);
break;
case ETMEXTOUTEVRn(1):
etm_write(val, ETMEXTOUTEVR1);
break;
case ETMEXTOUTEVRn(2):
etm_write(val, ETMEXTOUTEVR2);
break;
case ETMEXTOUTEVRn(3):
etm_write(val, ETMEXTOUTEVR3);
break;
case ETMCIDCVRn(0):
etm_write(val, ETMCIDCVR0);
break;
case ETMCIDCVRn(1):
etm_write(val, ETMCIDCVR1);
break;
case ETMCIDCVRn(2):
etm_write(val, ETMCIDCVR2);
break;
case ETMCIDCMR:
etm_write(val, ETMCIDCMR);
break;
case ETMIMPSPEC0:
etm_write(val, ETMIMPSPEC0);
break;
case ETMIMPSPEC1:
etm_write(val, ETMIMPSPEC1);
break;
case ETMIMPSPEC2:
etm_write(val, ETMIMPSPEC2);
break;
case ETMIMPSPEC3:
etm_write(val, ETMIMPSPEC3);
break;
case ETMIMPSPEC4:
etm_write(val, ETMIMPSPEC4);
break;
case ETMIMPSPEC5:
etm_write(val, ETMIMPSPEC5);
break;
case ETMIMPSPEC6:
etm_write(val, ETMIMPSPEC6);
break;
case ETMIMPSPEC7:
etm_write(val, ETMIMPSPEC7);
break;
case ETMSYNCFR:
etm_write(val, ETMSYNCFR);
break;
case ETMEXTINSELR:
etm_write(val, ETMEXTINSELR);
break;
case ETMTESSEICR:
etm_write(val, ETMTESSEICR);
break;
case ETMEIBCR:
etm_write(val, ETMEIBCR);
break;
case ETMTSEVR:
etm_write(val, ETMTSEVR);
break;
case ETMAUXCR:
etm_write(val, ETMAUXCR);
break;
case ETMTRACEIDR:
etm_write(val, ETMTRACEIDR);
break;
case ETMVMIDCVR:
etm_write(val, ETMVMIDCVR);
break;
case ETMOSLAR:
etm_write(val, ETMOSLAR);
break;
case ETMOSSRR:
etm_write(val, ETMOSSRR);
break;
case ETMPDCR:
etm_write(val, ETMPDCR);
break;
case ETMPDSR:
etm_write(val, ETMPDSR);
break;
default:
return -EINVAL;
}
return 0;
}

View File

@@ -0,0 +1,251 @@
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CORESIGHT_CORESIGHT_ETM_H
#define _CORESIGHT_CORESIGHT_ETM_H
#include <linux/spinlock.h>
#include "coresight-priv.h"
/*
* Device registers:
* 0x000 - 0x2FC: Trace registers
* 0x300 - 0x314: Management registers
* 0x318 - 0xEFC: Trace registers
*
* Coresight registers
* 0xF00 - 0xF9C: Management registers
* 0xFA0 - 0xFA4: Management registers in PFTv1.0
* Trace registers in PFTv1.1
* 0xFA8 - 0xFFC: Management registers
*/
/* Trace registers (0x000-0x2FC) */
#define ETMCR 0x000
#define ETMCCR 0x004
#define ETMTRIGGER 0x008
#define ETMSR 0x010
#define ETMSCR 0x014
#define ETMTSSCR 0x018
#define ETMTECR2 0x01c
#define ETMTEEVR 0x020
#define ETMTECR1 0x024
#define ETMFFLR 0x02c
#define ETMACVRn(n) (0x040 + (n * 4))
#define ETMACTRn(n) (0x080 + (n * 4))
#define ETMCNTRLDVRn(n) (0x140 + (n * 4))
#define ETMCNTENRn(n) (0x150 + (n * 4))
#define ETMCNTRLDEVRn(n) (0x160 + (n * 4))
#define ETMCNTVRn(n) (0x170 + (n * 4))
#define ETMSQ12EVR 0x180
#define ETMSQ21EVR 0x184
#define ETMSQ23EVR 0x188
#define ETMSQ31EVR 0x18c
#define ETMSQ32EVR 0x190
#define ETMSQ13EVR 0x194
#define ETMSQR 0x19c
#define ETMEXTOUTEVRn(n) (0x1a0 + (n * 4))
#define ETMCIDCVRn(n) (0x1b0 + (n * 4))
#define ETMCIDCMR 0x1bc
#define ETMIMPSPEC0 0x1c0
#define ETMIMPSPEC1 0x1c4
#define ETMIMPSPEC2 0x1c8
#define ETMIMPSPEC3 0x1cc
#define ETMIMPSPEC4 0x1d0
#define ETMIMPSPEC5 0x1d4
#define ETMIMPSPEC6 0x1d8
#define ETMIMPSPEC7 0x1dc
#define ETMSYNCFR 0x1e0
#define ETMIDR 0x1e4
#define ETMCCER 0x1e8
#define ETMEXTINSELR 0x1ec
#define ETMTESSEICR 0x1f0
#define ETMEIBCR 0x1f4
#define ETMTSEVR 0x1f8
#define ETMAUXCR 0x1fc
#define ETMTRACEIDR 0x200
#define ETMVMIDCVR 0x240
/* Management registers (0x300-0x314) */
#define ETMOSLAR 0x300
#define ETMOSLSR 0x304
#define ETMOSSRR 0x308
#define ETMPDCR 0x310
#define ETMPDSR 0x314
#define ETM_MAX_ADDR_CMP 16
#define ETM_MAX_CNTR 4
#define ETM_MAX_CTXID_CMP 3
/* Register definition */
/* ETMCR - 0x00 */
#define ETMCR_PWD_DWN BIT(0)
#define ETMCR_STALL_MODE BIT(7)
#define ETMCR_ETM_PRG BIT(10)
#define ETMCR_ETM_EN BIT(11)
#define ETMCR_CYC_ACC BIT(12)
#define ETMCR_CTXID_SIZE (BIT(14)|BIT(15))
#define ETMCR_TIMESTAMP_EN BIT(28)
/* ETMCCR - 0x04 */
#define ETMCCR_FIFOFULL BIT(23)
/* ETMPDCR - 0x310 */
#define ETMPDCR_PWD_UP BIT(3)
/* ETMTECR1 - 0x024 */
#define ETMTECR1_ADDR_COMP_1 BIT(0)
#define ETMTECR1_INC_EXC BIT(24)
#define ETMTECR1_START_STOP BIT(25)
/* ETMCCER - 0x1E8 */
#define ETMCCER_TIMESTAMP BIT(22)
#define ETM_MODE_EXCLUDE BIT(0)
#define ETM_MODE_CYCACC BIT(1)
#define ETM_MODE_STALL BIT(2)
#define ETM_MODE_TIMESTAMP BIT(3)
#define ETM_MODE_CTXID BIT(4)
#define ETM_MODE_ALL 0x1f
#define ETM_SQR_MASK 0x3
#define ETM_TRACEID_MASK 0x3f
#define ETM_EVENT_MASK 0x1ffff
#define ETM_SYNC_MASK 0xfff
#define ETM_ALL_MASK 0xffffffff
#define ETMSR_PROG_BIT 1
#define ETM_SEQ_STATE_MAX_VAL (0x2)
#define PORT_SIZE_MASK (GENMASK(21, 21) | GENMASK(6, 4))
#define ETM_HARD_WIRE_RES_A /* Hard wired, always true */ \
((0x0f << 0) | \
/* Resource index A */ \
(0x06 << 4))
#define ETM_ADD_COMP_0 /* Single addr comparator 1 */ \
((0x00 << 7) | \
/* Resource index B */ \
(0x00 << 11))
#define ETM_EVENT_NOT_A BIT(14) /* NOT(A) */
#define ETM_DEFAULT_EVENT_VAL (ETM_HARD_WIRE_RES_A | \
ETM_ADD_COMP_0 | \
ETM_EVENT_NOT_A)
/**
* struct etm_drvdata - specifics associated to an ETM component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @clk: the clock this component is associated to.
* @spinlock: only one at a time pls.
* @cpu: the cpu this component is affined to.
* @port_size: port size as reported by ETMCR bit 4-6 and 21.
* @arch: ETM/PTM version number.
* @use_cpu14: true if management registers need to be accessed via CP14.
* @enable: is this ETM/PTM currently tracing.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
* @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
* @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
* @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
* @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
* @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
* @etmccr: value of register ETMCCR.
* @etmccer: value of register ETMCCER.
* @traceid: value of the current ID for this component.
* @mode: controls various modes supported by this ETM/PTM.
* @ctrl: used in conjunction with @mode.
* @trigger_event: setting for register ETMTRIGGER.
* @startstop_ctrl: setting for register ETMTSSCR.
* @enable_event: setting for register ETMTEEVR.
* @enable_ctrl1: setting for register ETMTECR1.
* @fifofull_level: setting for register ETMFFLR.
* @addr_idx: index for the address comparator selection.
* @addr_val: value for address comparator register.
* @addr_acctype: access type for address comparator register.
* @addr_type: current status of the comparator register.
* @cntr_idx: index for the counter register selection.
* @cntr_rld_val: reload value of a counter register.
* @cntr_event: control for counter enable register.
* @cntr_rld_event: value for counter reload event register.
* @cntr_val: counter value register.
* @seq_12_event: event causing the transition from 1 to 2.
* @seq_21_event: event causing the transition from 2 to 1.
* @seq_23_event: event causing the transition from 2 to 3.
* @seq_31_event: event causing the transition from 3 to 1.
* @seq_32_event: event causing the transition from 3 to 2.
* @seq_13_event: event causing the transition from 1 to 3.
* @seq_curr_state: current value of the sequencer register.
* @ctxid_idx: index for the context ID registers.
* @ctxid_val: value for the context ID to trigger on.
* @ctxid_mask: mask applicable to all the context IDs.
* @sync_freq: Synchronisation frequency.
* @timestamp_event: Defines an event that requests the insertion
of a timestamp into the trace stream.
*/
struct etm_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct clk *clk;
spinlock_t spinlock;
int cpu;
int port_size;
u8 arch;
bool use_cp14;
bool enable;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
u8 nr_addr_cmp;
u8 nr_cntr;
u8 nr_ext_inp;
u8 nr_ext_out;
u8 nr_ctxid_cmp;
u32 etmccr;
u32 etmccer;
u32 traceid;
u32 mode;
u32 ctrl;
u32 trigger_event;
u32 startstop_ctrl;
u32 enable_event;
u32 enable_ctrl1;
u32 fifofull_level;
u8 addr_idx;
u32 addr_val[ETM_MAX_ADDR_CMP];
u32 addr_acctype[ETM_MAX_ADDR_CMP];
u32 addr_type[ETM_MAX_ADDR_CMP];
u8 cntr_idx;
u32 cntr_rld_val[ETM_MAX_CNTR];
u32 cntr_event[ETM_MAX_CNTR];
u32 cntr_rld_event[ETM_MAX_CNTR];
u32 cntr_val[ETM_MAX_CNTR];
u32 seq_12_event;
u32 seq_21_event;
u32 seq_23_event;
u32 seq_31_event;
u32 seq_32_event;
u32 seq_13_event;
u32 seq_curr_state;
u8 ctxid_idx;
u32 ctxid_val[ETM_MAX_CTXID_CMP];
u32 ctxid_mask;
u32 sync_freq;
u32 timestamp_event;
};
enum etm_addr_type {
ETM_ADDR_TYPE_NONE,
ETM_ADDR_TYPE_SINGLE,
ETM_ADDR_TYPE_RANGE,
ETM_ADDR_TYPE_START,
ETM_ADDR_TYPE_STOP,
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,268 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include "coresight-priv.h"
#define FUNNEL_FUNCTL 0x000
#define FUNNEL_PRICTL 0x004
#define FUNNEL_HOLDTIME_MASK 0xf00
#define FUNNEL_HOLDTIME_SHFT 0x8
#define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT)
/**
* struct funnel_drvdata - specifics associated to a funnel component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @clk: the clock this component is associated to.
* @priority: port selection order.
*/
struct funnel_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct clk *clk;
unsigned long priority;
};
static void funnel_enable_hw(struct funnel_drvdata *drvdata, int port)
{
u32 functl;
CS_UNLOCK(drvdata->base);
functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
functl &= ~FUNNEL_HOLDTIME_MASK;
functl |= FUNNEL_HOLDTIME;
functl |= (1 << port);
writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
writel_relaxed(drvdata->priority, drvdata->base + FUNNEL_PRICTL);
CS_LOCK(drvdata->base);
}
static int funnel_enable(struct coresight_device *csdev, int inport,
int outport)
{
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
funnel_enable_hw(drvdata, inport);
dev_info(drvdata->dev, "FUNNEL inport %d enabled\n", inport);
return 0;
}
static void funnel_disable_hw(struct funnel_drvdata *drvdata, int inport)
{
u32 functl;
CS_UNLOCK(drvdata->base);
functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
functl &= ~(1 << inport);
writel_relaxed(functl, drvdata->base + FUNNEL_FUNCTL);
CS_LOCK(drvdata->base);
}
static void funnel_disable(struct coresight_device *csdev, int inport,
int outport)
{
struct funnel_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
funnel_disable_hw(drvdata, inport);
clk_disable_unprepare(drvdata->clk);
dev_info(drvdata->dev, "FUNNEL inport %d disabled\n", inport);
}
static const struct coresight_ops_link funnel_link_ops = {
.enable = funnel_enable,
.disable = funnel_disable,
};
static const struct coresight_ops funnel_cs_ops = {
.link_ops = &funnel_link_ops,
};
static ssize_t priority_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->priority;
return sprintf(buf, "%#lx\n", val);
}
static ssize_t priority_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret;
unsigned long val;
struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
drvdata->priority = val;
return size;
}
static DEVICE_ATTR_RW(priority);
static u32 get_funnel_ctrl_hw(struct funnel_drvdata *drvdata)
{
u32 functl;
CS_UNLOCK(drvdata->base);
functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL);
CS_LOCK(drvdata->base);
return functl;
}
static ssize_t funnel_ctrl_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret;
u32 val;
struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
val = get_funnel_ctrl_hw(drvdata);
clk_disable_unprepare(drvdata->clk);
return sprintf(buf, "%#x\n", val);
}
static DEVICE_ATTR_RO(funnel_ctrl);
static struct attribute *coresight_funnel_attrs[] = {
&dev_attr_funnel_ctrl.attr,
&dev_attr_priority.attr,
NULL,
};
ATTRIBUTE_GROUPS(coresight_funnel);
static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
{
void __iomem *base;
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
struct funnel_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct device_node *np = adev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
adev->dev.platform_data = pdata;
}
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
drvdata->base = base;
drvdata->clk = adev->pclk;
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc->ops = &funnel_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
desc->groups = coresight_funnel_groups;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
dev_info(dev, "FUNNEL initialized\n");
return 0;
}
static int funnel_remove(struct amba_device *adev)
{
struct funnel_drvdata *drvdata = amba_get_drvdata(adev);
coresight_unregister(drvdata->csdev);
return 0;
}
static struct amba_id funnel_ids[] = {
{
.id = 0x0003b908,
.mask = 0x0003ffff,
},
{ 0, 0},
};
static struct amba_driver funnel_driver = {
.drv = {
.name = "coresight-funnel",
.owner = THIS_MODULE,
},
.probe = funnel_probe,
.remove = funnel_remove,
.id_table = funnel_ids,
};
static int __init funnel_init(void)
{
return amba_driver_register(&funnel_driver);
}
module_init(funnel_init);
static void __exit funnel_exit(void)
{
amba_driver_unregister(&funnel_driver);
}
module_exit(funnel_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Funnel driver");

View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CORESIGHT_PRIV_H
#define _CORESIGHT_PRIV_H
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/coresight.h>
/*
* Coresight management registers (0xf00-0xfcc)
* 0xfa0 - 0xfa4: Management registers in PFTv1.0
* Trace registers in PFTv1.1
*/
#define CORESIGHT_ITCTRL 0xf00
#define CORESIGHT_CLAIMSET 0xfa0
#define CORESIGHT_CLAIMCLR 0xfa4
#define CORESIGHT_LAR 0xfb0
#define CORESIGHT_LSR 0xfb4
#define CORESIGHT_AUTHSTATUS 0xfb8
#define CORESIGHT_DEVID 0xfc8
#define CORESIGHT_DEVTYPE 0xfcc
#define TIMEOUT_US 100
#define BMVAL(val, lsb, msb) ((val & GENMASK(msb, lsb)) >> lsb)
static inline void CS_LOCK(void __iomem *addr)
{
do {
/* Wait for things to settle */
mb();
writel_relaxed(0x0, addr + CORESIGHT_LAR);
} while (0);
}
static inline void CS_UNLOCK(void __iomem *addr)
{
do {
writel_relaxed(CORESIGHT_UNLOCK, addr + CORESIGHT_LAR);
/* Make sure everyone has seen this */
mb();
} while (0);
}
#ifdef CONFIG_CORESIGHT_SOURCE_ETM3X
extern int etm_readl_cp14(u32 off, unsigned int *val);
extern int etm_writel_cp14(u32 off, u32 val);
#else
static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
static inline int etm_writel_cp14(u32 val, u32 off) { return 0; }
#endif
#endif

View File

@@ -0,0 +1,137 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/coresight.h>
#include "coresight-priv.h"
/**
* struct replicator_drvdata - specifics associated to a replicator component
* @dev: the device entity associated with this component
* @csdev: component vitals needed by the framework
*/
struct replicator_drvdata {
struct device *dev;
struct coresight_device *csdev;
};
static int replicator_enable(struct coresight_device *csdev, int inport,
int outport)
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
dev_info(drvdata->dev, "REPLICATOR enabled\n");
return 0;
}
static void replicator_disable(struct coresight_device *csdev, int inport,
int outport)
{
struct replicator_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
dev_info(drvdata->dev, "REPLICATOR disabled\n");
}
static const struct coresight_ops_link replicator_link_ops = {
.enable = replicator_enable,
.disable = replicator_disable,
};
static const struct coresight_ops replicator_cs_ops = {
.link_ops = &replicator_link_ops,
};
static int replicator_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct coresight_platform_data *pdata = NULL;
struct replicator_drvdata *drvdata;
struct coresight_desc *desc;
struct device_node *np = pdev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
pdev->dev.platform_data = pdata;
}
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &pdev->dev;
platform_set_drvdata(pdev, drvdata);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc->ops = &replicator_cs_ops;
desc->pdata = pdev->dev.platform_data;
desc->dev = &pdev->dev;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
dev_info(dev, "REPLICATOR initialized\n");
return 0;
}
static int replicator_remove(struct platform_device *pdev)
{
struct replicator_drvdata *drvdata = platform_get_drvdata(pdev);
coresight_unregister(drvdata->csdev);
return 0;
}
static struct of_device_id replicator_match[] = {
{.compatible = "arm,coresight-replicator"},
{}
};
static struct platform_driver replicator_driver = {
.probe = replicator_probe,
.remove = replicator_remove,
.driver = {
.name = "coresight-replicator",
.of_match_table = replicator_match,
},
};
static int __init replicator_init(void)
{
return platform_driver_register(&replicator_driver);
}
module_init(replicator_init);
static void __exit replicator_exit(void)
{
platform_driver_unregister(&replicator_driver);
}
module_exit(replicator_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Replicator driver");

View File

@@ -0,0 +1,776 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include "coresight-priv.h"
#define TMC_RSZ 0x004
#define TMC_STS 0x00c
#define TMC_RRD 0x010
#define TMC_RRP 0x014
#define TMC_RWP 0x018
#define TMC_TRG 0x01c
#define TMC_CTL 0x020
#define TMC_RWD 0x024
#define TMC_MODE 0x028
#define TMC_LBUFLEVEL 0x02c
#define TMC_CBUFLEVEL 0x030
#define TMC_BUFWM 0x034
#define TMC_RRPHI 0x038
#define TMC_RWPHI 0x03c
#define TMC_AXICTL 0x110
#define TMC_DBALO 0x118
#define TMC_DBAHI 0x11c
#define TMC_FFSR 0x300
#define TMC_FFCR 0x304
#define TMC_PSCR 0x308
#define TMC_ITMISCOP0 0xee0
#define TMC_ITTRFLIN 0xee8
#define TMC_ITATBDATA0 0xeec
#define TMC_ITATBCTR2 0xef0
#define TMC_ITATBCTR1 0xef4
#define TMC_ITATBCTR0 0xef8
/* register description */
/* TMC_CTL - 0x020 */
#define TMC_CTL_CAPT_EN BIT(0)
/* TMC_STS - 0x00C */
#define TMC_STS_TRIGGERED BIT(1)
/* TMC_AXICTL - 0x110 */
#define TMC_AXICTL_PROT_CTL_B0 BIT(0)
#define TMC_AXICTL_PROT_CTL_B1 BIT(1)
#define TMC_AXICTL_SCT_GAT_MODE BIT(7)
#define TMC_AXICTL_WR_BURST_LEN 0xF00
/* TMC_FFCR - 0x304 */
#define TMC_FFCR_EN_FMT BIT(0)
#define TMC_FFCR_EN_TI BIT(1)
#define TMC_FFCR_FON_FLIN BIT(4)
#define TMC_FFCR_FON_TRIG_EVT BIT(5)
#define TMC_FFCR_FLUSHMAN BIT(6)
#define TMC_FFCR_TRIGON_TRIGIN BIT(8)
#define TMC_FFCR_STOP_ON_FLUSH BIT(12)
#define TMC_STS_TRIGGERED_BIT 2
#define TMC_FFCR_FLUSHMAN_BIT 6
enum tmc_config_type {
TMC_CONFIG_TYPE_ETB,
TMC_CONFIG_TYPE_ETR,
TMC_CONFIG_TYPE_ETF,
};
enum tmc_mode {
TMC_MODE_CIRCULAR_BUFFER,
TMC_MODE_SOFTWARE_FIFO,
TMC_MODE_HARDWARE_FIFO,
};
enum tmc_mem_intf_width {
TMC_MEM_INTF_WIDTH_32BITS = 0x2,
TMC_MEM_INTF_WIDTH_64BITS = 0x3,
TMC_MEM_INTF_WIDTH_128BITS = 0x4,
TMC_MEM_INTF_WIDTH_256BITS = 0x5,
};
/**
* struct tmc_drvdata - specifics associated to an TMC component
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @miscdev: specifics to handle "/dev/xyz.tmc" entry.
* @clk: the clock this component is associated to.
* @spinlock: only one at a time pls.
* @read_count: manages preparation of buffer for reading.
* @buf: area of memory where trace data get sent.
* @paddr: DMA start location in RAM.
* @vaddr: virtual representation of @paddr.
* @size: @buf size.
* @enable: this TMC is being used.
* @config_type: TMC variant, must be of type @tmc_config_type.
* @trigger_cntr: amount of words to store after a trigger.
*/
struct tmc_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct miscdevice miscdev;
struct clk *clk;
spinlock_t spinlock;
int read_count;
bool reading;
char *buf;
dma_addr_t paddr;
void __iomem *vaddr;
u32 size;
bool enable;
enum tmc_config_type config_type;
u32 trigger_cntr;
};
static void tmc_wait_for_ready(struct tmc_drvdata *drvdata)
{
/* Ensure formatter, unformatter and hardware fifo are empty */
if (coresight_timeout(drvdata->base,
TMC_STS, TMC_STS_TRIGGERED_BIT, 1)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
TMC_STS);
}
}
static void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
{
u32 ffcr;
ffcr = readl_relaxed(drvdata->base + TMC_FFCR);
ffcr |= TMC_FFCR_STOP_ON_FLUSH;
writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
ffcr |= TMC_FFCR_FLUSHMAN;
writel_relaxed(ffcr, drvdata->base + TMC_FFCR);
/* Ensure flush completes */
if (coresight_timeout(drvdata->base,
TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
dev_err(drvdata->dev,
"timeout observed when probing at offset %#x\n",
TMC_FFCR);
}
tmc_wait_for_ready(drvdata);
}
static void tmc_enable_hw(struct tmc_drvdata *drvdata)
{
writel_relaxed(TMC_CTL_CAPT_EN, drvdata->base + TMC_CTL);
}
static void tmc_disable_hw(struct tmc_drvdata *drvdata)
{
writel_relaxed(0x0, drvdata->base + TMC_CTL);
}
static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
{
/* Zero out the memory to help with debug */
memset(drvdata->buf, 0, drvdata->size);
CS_UNLOCK(drvdata->base);
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
TMC_FFCR_TRIGON_TRIGIN,
drvdata->base + TMC_FFCR);
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
{
u32 axictl;
/* Zero out the memory to help with debug */
memset(drvdata->vaddr, 0, drvdata->size);
CS_UNLOCK(drvdata->base);
writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ);
writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE);
axictl = readl_relaxed(drvdata->base + TMC_AXICTL);
axictl |= TMC_AXICTL_WR_BURST_LEN;
writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
axictl &= ~TMC_AXICTL_SCT_GAT_MODE;
writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
axictl = (axictl &
~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) |
TMC_AXICTL_PROT_CTL_B1;
writel_relaxed(axictl, drvdata->base + TMC_AXICTL);
writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO);
writel_relaxed(0x0, drvdata->base + TMC_DBAHI);
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI |
TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT |
TMC_FFCR_TRIGON_TRIGIN,
drvdata->base + TMC_FFCR);
writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG);
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static void tmc_etf_enable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
writel_relaxed(TMC_MODE_HARDWARE_FIFO, drvdata->base + TMC_MODE);
writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI,
drvdata->base + TMC_FFCR);
writel_relaxed(0x0, drvdata->base + TMC_BUFWM);
tmc_enable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static int tmc_enable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
{
int ret;
unsigned long flags;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
clk_disable_unprepare(drvdata->clk);
return -EBUSY;
}
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
tmc_etb_enable_hw(drvdata);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
tmc_etr_enable_hw(drvdata);
} else {
if (mode == TMC_MODE_CIRCULAR_BUFFER)
tmc_etb_enable_hw(drvdata);
else
tmc_etf_enable_hw(drvdata);
}
drvdata->enable = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC enabled\n");
return 0;
}
static int tmc_enable_sink(struct coresight_device *csdev)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
return tmc_enable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
}
static int tmc_enable_link(struct coresight_device *csdev, int inport,
int outport)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
return tmc_enable(drvdata, TMC_MODE_HARDWARE_FIFO);
}
static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
{
enum tmc_mem_intf_width memwidth;
u8 memwords;
char *bufp;
u32 read_data;
int i;
memwidth = BMVAL(readl_relaxed(drvdata->base + CORESIGHT_DEVID), 8, 10);
if (memwidth == TMC_MEM_INTF_WIDTH_32BITS)
memwords = 1;
else if (memwidth == TMC_MEM_INTF_WIDTH_64BITS)
memwords = 2;
else if (memwidth == TMC_MEM_INTF_WIDTH_128BITS)
memwords = 4;
else
memwords = 8;
bufp = drvdata->buf;
while (1) {
for (i = 0; i < memwords; i++) {
read_data = readl_relaxed(drvdata->base + TMC_RRD);
if (read_data == 0xFFFFFFFF)
return;
memcpy(bufp, &read_data, 4);
bufp += 4;
}
}
}
static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
tmc_etb_dump_hw(drvdata);
tmc_disable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
{
u32 rwp, val;
rwp = readl_relaxed(drvdata->base + TMC_RWP);
val = readl_relaxed(drvdata->base + TMC_STS);
/* How much memory do we still have */
if (val & BIT(0))
drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
else
drvdata->buf = drvdata->vaddr;
}
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
tmc_etr_dump_hw(drvdata);
tmc_disable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static void tmc_etf_disable_hw(struct tmc_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
tmc_flush_and_stop(drvdata);
tmc_disable_hw(drvdata);
CS_LOCK(drvdata->base);
}
static void tmc_disable(struct tmc_drvdata *drvdata, enum tmc_mode mode)
{
unsigned long flags;
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->reading)
goto out;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
tmc_etb_disable_hw(drvdata);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
tmc_etr_disable_hw(drvdata);
} else {
if (mode == TMC_MODE_CIRCULAR_BUFFER)
tmc_etb_disable_hw(drvdata);
else
tmc_etf_disable_hw(drvdata);
}
out:
drvdata->enable = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
clk_disable_unprepare(drvdata->clk);
dev_info(drvdata->dev, "TMC disabled\n");
}
static void tmc_disable_sink(struct coresight_device *csdev)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
tmc_disable(drvdata, TMC_MODE_CIRCULAR_BUFFER);
}
static void tmc_disable_link(struct coresight_device *csdev, int inport,
int outport)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
tmc_disable(drvdata, TMC_MODE_HARDWARE_FIFO);
}
static const struct coresight_ops_sink tmc_sink_ops = {
.enable = tmc_enable_sink,
.disable = tmc_disable_sink,
};
static const struct coresight_ops_link tmc_link_ops = {
.enable = tmc_enable_link,
.disable = tmc_disable_link,
};
static const struct coresight_ops tmc_etb_cs_ops = {
.sink_ops = &tmc_sink_ops,
};
static const struct coresight_ops tmc_etr_cs_ops = {
.sink_ops = &tmc_sink_ops,
};
static const struct coresight_ops tmc_etf_cs_ops = {
.sink_ops = &tmc_sink_ops,
.link_ops = &tmc_link_ops,
};
static int tmc_read_prepare(struct tmc_drvdata *drvdata)
{
int ret;
unsigned long flags;
enum tmc_mode mode;
spin_lock_irqsave(&drvdata->spinlock, flags);
if (!drvdata->enable)
goto out;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
tmc_etb_disable_hw(drvdata);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
tmc_etr_disable_hw(drvdata);
} else {
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode == TMC_MODE_CIRCULAR_BUFFER) {
tmc_etb_disable_hw(drvdata);
} else {
ret = -ENODEV;
goto err;
}
}
out:
drvdata->reading = true;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC read start\n");
return 0;
err:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return ret;
}
static void tmc_read_unprepare(struct tmc_drvdata *drvdata)
{
unsigned long flags;
enum tmc_mode mode;
spin_lock_irqsave(&drvdata->spinlock, flags);
if (!drvdata->enable)
goto out;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
tmc_etb_enable_hw(drvdata);
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
tmc_etr_enable_hw(drvdata);
} else {
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode == TMC_MODE_CIRCULAR_BUFFER)
tmc_etb_enable_hw(drvdata);
}
out:
drvdata->reading = false;
spin_unlock_irqrestore(&drvdata->spinlock, flags);
dev_info(drvdata->dev, "TMC read end\n");
}
static int tmc_open(struct inode *inode, struct file *file)
{
struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev);
int ret = 0;
if (drvdata->read_count++)
goto out;
ret = tmc_read_prepare(drvdata);
if (ret)
return ret;
out:
nonseekable_open(inode, file);
dev_dbg(drvdata->dev, "%s: successfully opened\n", __func__);
return 0;
}
static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
loff_t *ppos)
{
struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev);
char *bufp = drvdata->buf + *ppos;
if (*ppos + len > drvdata->size)
len = drvdata->size - *ppos;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
if (bufp == (char *)(drvdata->vaddr + drvdata->size))
bufp = drvdata->vaddr;
else if (bufp > (char *)(drvdata->vaddr + drvdata->size))
bufp -= drvdata->size;
if ((bufp + len) > (char *)(drvdata->vaddr + drvdata->size))
len = (char *)(drvdata->vaddr + drvdata->size) - bufp;
}
if (copy_to_user(data, bufp, len)) {
dev_dbg(drvdata->dev, "%s: copy_to_user failed\n", __func__);
return -EFAULT;
}
*ppos += len;
dev_dbg(drvdata->dev, "%s: %d bytes copied, %d bytes left\n",
__func__, len, (int) (drvdata->size - *ppos));
return len;
}
static int tmc_release(struct inode *inode, struct file *file)
{
struct tmc_drvdata *drvdata = container_of(file->private_data,
struct tmc_drvdata, miscdev);
if (--drvdata->read_count) {
if (drvdata->read_count < 0) {
dev_err(drvdata->dev, "mismatched close\n");
drvdata->read_count = 0;
}
goto out;
}
tmc_read_unprepare(drvdata);
out:
dev_dbg(drvdata->dev, "%s: released\n", __func__);
return 0;
}
static const struct file_operations tmc_fops = {
.owner = THIS_MODULE,
.open = tmc_open,
.read = tmc_read,
.release = tmc_release,
.llseek = no_llseek,
};
static ssize_t trigger_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
unsigned long val = drvdata->trigger_cntr;
return sprintf(buf, "%#lx\n", val);
}
static ssize_t trigger_cntr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret;
unsigned long val;
struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
drvdata->trigger_cntr = val;
return size;
}
static DEVICE_ATTR_RW(trigger_cntr);
static struct attribute *coresight_etb_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
};
ATTRIBUTE_GROUPS(coresight_etb);
static struct attribute *coresight_etr_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
};
ATTRIBUTE_GROUPS(coresight_etr);
static struct attribute *coresight_etf_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
};
ATTRIBUTE_GROUPS(coresight_etf);
static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
u32 devid;
void __iomem *base;
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
struct tmc_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct device_node *np = adev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
adev->dev.platform_data = pdata;
}
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
drvdata->base = base;
spin_lock_init(&drvdata->spinlock);
drvdata->clk = adev->pclk;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
drvdata->config_type = BMVAL(devid, 6, 7);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
if (np)
ret = of_property_read_u32(np,
"arm,buffer-size",
&drvdata->size);
if (ret)
drvdata->size = SZ_1M;
} else {
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
}
clk_disable_unprepare(drvdata->clk);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
drvdata->vaddr = dma_alloc_coherent(dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
if (!drvdata->vaddr)
return -ENOMEM;
memset(drvdata->vaddr, 0, drvdata->size);
drvdata->buf = drvdata->vaddr;
} else {
drvdata->buf = devm_kzalloc(dev, drvdata->size, GFP_KERNEL);
if (!drvdata->buf)
return -ENOMEM;
}
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto err_devm_kzalloc;
}
desc->pdata = pdata;
desc->dev = dev;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->ops = &tmc_etb_cs_ops;
desc->groups = coresight_etb_groups;
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->ops = &tmc_etr_cs_ops;
desc->groups = coresight_etr_groups;
} else {
desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
desc->ops = &tmc_etf_cs_ops;
desc->groups = coresight_etf_groups;
}
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
ret = PTR_ERR(drvdata->csdev);
goto err_devm_kzalloc;
}
drvdata->miscdev.name = pdata->name;
drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
drvdata->miscdev.fops = &tmc_fops;
ret = misc_register(&drvdata->miscdev);
if (ret)
goto err_misc_register;
dev_info(dev, "TMC initialized\n");
return 0;
err_misc_register:
coresight_unregister(drvdata->csdev);
err_devm_kzalloc:
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
return ret;
}
static int tmc_remove(struct amba_device *adev)
{
struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
misc_deregister(&drvdata->miscdev);
coresight_unregister(drvdata->csdev);
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
dma_free_coherent(drvdata->dev, drvdata->size,
&drvdata->paddr, GFP_KERNEL);
return 0;
}
static struct amba_id tmc_ids[] = {
{
.id = 0x0003b961,
.mask = 0x0003ffff,
},
{ 0, 0},
};
static struct amba_driver tmc_driver = {
.drv = {
.name = "coresight-tmc",
.owner = THIS_MODULE,
},
.probe = tmc_probe,
.remove = tmc_remove,
.id_table = tmc_ids,
};
static int __init tmc_init(void)
{
return amba_driver_register(&tmc_driver);
}
module_init(tmc_init);
static void __exit tmc_exit(void)
{
amba_driver_unregister(&tmc_driver);
}
module_exit(tmc_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");

View File

@@ -0,0 +1,217 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/coresight.h>
#include <linux/amba/bus.h>
#include "coresight-priv.h"
#define TPIU_SUPP_PORTSZ 0x000
#define TPIU_CURR_PORTSZ 0x004
#define TPIU_SUPP_TRIGMODES 0x100
#define TPIU_TRIG_CNTRVAL 0x104
#define TPIU_TRIG_MULT 0x108
#define TPIU_SUPP_TESTPATM 0x200
#define TPIU_CURR_TESTPATM 0x204
#define TPIU_TEST_PATREPCNTR 0x208
#define TPIU_FFSR 0x300
#define TPIU_FFCR 0x304
#define TPIU_FSYNC_CNTR 0x308
#define TPIU_EXTCTL_INPORT 0x400
#define TPIU_EXTCTL_OUTPORT 0x404
#define TPIU_ITTRFLINACK 0xee4
#define TPIU_ITTRFLIN 0xee8
#define TPIU_ITATBDATA0 0xeec
#define TPIU_ITATBCTR2 0xef0
#define TPIU_ITATBCTR1 0xef4
#define TPIU_ITATBCTR0 0xef8
/** register definition **/
/* FFCR - 0x304 */
#define FFCR_FON_MAN BIT(6)
/**
* @base: memory mapped base address for this component.
* @dev: the device entity associated to this component.
* @csdev: component vitals needed by the framework.
* @clk: the clock this component is associated to.
*/
struct tpiu_drvdata {
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
struct clk *clk;
};
static void tpiu_enable_hw(struct tpiu_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
/* TODO: fill this up */
CS_LOCK(drvdata->base);
}
static int tpiu_enable(struct coresight_device *csdev)
{
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
tpiu_enable_hw(drvdata);
dev_info(drvdata->dev, "TPIU enabled\n");
return 0;
}
static void tpiu_disable_hw(struct tpiu_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
/* Clear formatter controle reg. */
writel_relaxed(0x0, drvdata->base + TPIU_FFCR);
/* Generate manual flush */
writel_relaxed(FFCR_FON_MAN, drvdata->base + TPIU_FFCR);
CS_LOCK(drvdata->base);
}
static void tpiu_disable(struct coresight_device *csdev)
{
struct tpiu_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
tpiu_disable_hw(drvdata);
clk_disable_unprepare(drvdata->clk);
dev_info(drvdata->dev, "TPIU disabled\n");
}
static const struct coresight_ops_sink tpiu_sink_ops = {
.enable = tpiu_enable,
.disable = tpiu_disable,
};
static const struct coresight_ops tpiu_cs_ops = {
.sink_ops = &tpiu_sink_ops,
};
static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
void __iomem *base;
struct device *dev = &adev->dev;
struct coresight_platform_data *pdata = NULL;
struct tpiu_drvdata *drvdata;
struct resource *res = &adev->res;
struct coresight_desc *desc;
struct device_node *np = adev->dev.of_node;
if (np) {
pdata = of_get_coresight_platform_data(dev, np);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
adev->dev.platform_data = pdata;
}
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->dev = &adev->dev;
dev_set_drvdata(dev, drvdata);
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
drvdata->base = base;
drvdata->clk = adev->pclk;
ret = clk_prepare_enable(drvdata->clk);
if (ret)
return ret;
/* Disable tpiu to support older devices */
tpiu_disable_hw(drvdata);
clk_disable_unprepare(drvdata->clk);
desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_SINK;
desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
desc->ops = &tpiu_cs_ops;
desc->pdata = pdata;
desc->dev = dev;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
return PTR_ERR(drvdata->csdev);
dev_info(dev, "TPIU initialized\n");
return 0;
}
static int tpiu_remove(struct amba_device *adev)
{
struct tpiu_drvdata *drvdata = amba_get_drvdata(adev);
coresight_unregister(drvdata->csdev);
return 0;
}
static struct amba_id tpiu_ids[] = {
{
.id = 0x0003b912,
.mask = 0x0003ffff,
},
{ 0, 0},
};
static struct amba_driver tpiu_driver = {
.drv = {
.name = "coresight-tpiu",
.owner = THIS_MODULE,
},
.probe = tpiu_probe,
.remove = tpiu_remove,
.id_table = tpiu_ids,
};
static int __init tpiu_init(void)
{
return amba_driver_register(&tpiu_driver);
}
module_init(tpiu_init);
static void __exit tpiu_exit(void)
{
amba_driver_unregister(&tpiu_driver);
}
module_exit(tpiu_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");

Some files were not shown because too many files have changed in this diff Show More