2018-05-09 21:06:04 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2014 , The Linux Foundation . All rights reserved .
2015-05-13 19:34:09 +03:00
*/
# include <linux/kernel.h>
# include <linux/moduleparam.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/slab.h>
# include <linux/delay.h>
# include <linux/smp.h>
# include <linux/sysfs.h>
# include <linux/stat.h>
# include <linux/clk.h>
# include <linux/cpu.h>
# include <linux/coresight.h>
2016-04-05 20:53:45 +03:00
# include <linux/coresight-pmu.h>
2015-05-13 19:34:09 +03:00
# include <linux/pm_wakeup.h>
# include <linux/amba/bus.h>
# include <linux/seq_file.h>
# include <linux/uaccess.h>
2016-04-05 20:53:49 +03:00
# include <linux/perf_event.h>
2015-05-13 19:34:09 +03:00
# include <linux/pm_runtime.h>
# include <asm/sections.h>
2016-04-05 20:53:47 +03:00
# include <asm/local.h>
2018-09-20 22:18:00 +03:00
# include <asm/virt.h>
2015-05-13 19:34:09 +03:00
# include "coresight-etm4x.h"
2016-04-05 20:53:49 +03:00
# include "coresight-etm-perf.h"
2015-05-13 19:34:09 +03:00
static int boot_enable ;
module_param_named ( boot_enable , boot_enable , int , S_IRUGO ) ;
/* The number of ETMv4 currently registered */
static int etm4_count ;
static struct etmv4_drvdata * etmdrvdata [ NR_CPUS ] ;
2016-08-26 00:19:17 +03:00
static void etm4_set_default_config ( struct etmv4_config * config ) ;
static int etm4_set_event_filters ( struct etmv4_drvdata * drvdata ,
struct perf_event * event ) ;
2015-05-13 19:34:09 +03:00
2016-07-13 20:16:55 +03:00
static enum cpuhp_state hp_online ;
2016-04-05 20:53:46 +03:00
static void etm4_os_unlock ( struct etmv4_drvdata * drvdata )
2015-05-13 19:34:09 +03:00
{
/* Writing any value to ETMOSLAR unlocks the trace registers */
writel_relaxed ( 0x0 , drvdata - > base + TRCOSLAR ) ;
2016-04-05 20:53:46 +03:00
drvdata - > os_unlock = true ;
2015-05-13 19:34:09 +03:00
isb ( ) ;
}
static bool etm4_arch_supported ( u8 arch )
{
switch ( arch ) {
case ETM_ARCH_V4 :
break ;
default :
return false ;
}
return true ;
}
2016-02-03 00:14:01 +03:00
static int etm4_cpu_id ( struct coresight_device * csdev )
{
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
return drvdata - > cpu ;
}
2015-05-13 19:34:09 +03:00
static int etm4_trace_id ( struct coresight_device * csdev )
{
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
2016-08-26 00:18:53 +03:00
return drvdata - > trcid ;
2015-05-13 19:34:09 +03:00
}
2018-09-20 22:18:07 +03:00
struct etm4_enable_arg {
struct etmv4_drvdata * drvdata ;
int rc ;
} ;
static int etm4_enable_hw ( struct etmv4_drvdata * drvdata )
2015-05-13 19:34:09 +03:00
{
2018-09-20 22:18:12 +03:00
int i , rc ;
2016-04-05 20:53:44 +03:00
struct etmv4_config * config = & drvdata - > config ;
2015-05-13 19:34:09 +03:00
CS_UNLOCK ( drvdata - > base ) ;
etm4_os_unlock ( drvdata ) ;
2018-09-20 22:18:12 +03:00
rc = coresight_claim_device_unlocked ( drvdata - > base ) ;
if ( rc )
goto done ;
2015-05-13 19:34:09 +03:00
/* Disable the trace unit before programming trace registers */
writel_relaxed ( 0 , drvdata - > base + TRCPRGCTLR ) ;
/* wait for TRCSTATR.IDLE to go up */
if ( coresight_timeout ( drvdata - > base , TRCSTATR , TRCSTATR_IDLE_BIT , 1 ) )
dev_err ( drvdata - > dev ,
2016-08-26 00:19:00 +03:00
" timeout while waiting for Idle Trace Status \n " ) ;
2015-05-13 19:34:09 +03:00
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > pe_sel , drvdata - > base + TRCPROCSELR ) ;
writel_relaxed ( config - > cfg , drvdata - > base + TRCCONFIGR ) ;
2015-05-13 19:34:09 +03:00
/* nothing specific implemented */
writel_relaxed ( 0x0 , drvdata - > base + TRCAUXCTLR ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > eventctrl0 , drvdata - > base + TRCEVENTCTL0R ) ;
writel_relaxed ( config - > eventctrl1 , drvdata - > base + TRCEVENTCTL1R ) ;
writel_relaxed ( config - > stall_ctrl , drvdata - > base + TRCSTALLCTLR ) ;
writel_relaxed ( config - > ts_ctrl , drvdata - > base + TRCTSCTLR ) ;
writel_relaxed ( config - > syncfreq , drvdata - > base + TRCSYNCPR ) ;
writel_relaxed ( config - > ccctlr , drvdata - > base + TRCCCCTLR ) ;
writel_relaxed ( config - > bb_ctrl , drvdata - > base + TRCBBCTLR ) ;
2015-05-13 19:34:09 +03:00
writel_relaxed ( drvdata - > trcid , drvdata - > base + TRCTRACEIDR ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > vinst_ctrl , drvdata - > base + TRCVICTLR ) ;
writel_relaxed ( config - > viiectlr , drvdata - > base + TRCVIIECTLR ) ;
writel_relaxed ( config - > vissctlr ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCVISSCTLR ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > vipcssctlr ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCVIPCSSCTLR ) ;
for ( i = 0 ; i < drvdata - > nrseqstate - 1 ; i + + )
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > seq_ctrl [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCSEQEVRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > seq_rst , drvdata - > base + TRCSEQRSTEVR ) ;
writel_relaxed ( config - > seq_state , drvdata - > base + TRCSEQSTR ) ;
writel_relaxed ( config - > ext_inp , drvdata - > base + TRCEXTINSELR ) ;
2015-05-13 19:34:09 +03:00
for ( i = 0 ; i < drvdata - > nr_cntr ; i + + ) {
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > cntrldvr [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCCNTRLDVRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > cntr_ctrl [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCCNTCTLRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > cntr_val [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCCNTVRn ( i ) ) ;
}
2015-10-07 18:26:38 +03:00
/* Resource selector pair 0 is always implemented and reserved */
2016-04-05 20:53:44 +03:00
for ( i = 0 ; i < drvdata - > nr_resource * 2 ; i + + )
writel_relaxed ( config - > res_ctrl [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCRSCTLRn ( i ) ) ;
for ( i = 0 ; i < drvdata - > nr_ss_cmp ; i + + ) {
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > ss_ctrl [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCSSCCRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > ss_status [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCSSCSRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > ss_pe_cmp [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCSSPCICRn ( i ) ) ;
}
for ( i = 0 ; i < drvdata - > nr_addr_cmp ; i + + ) {
2016-04-05 20:53:44 +03:00
writeq_relaxed ( config - > addr_val [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCACVRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writeq_relaxed ( config - > addr_acc [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCACATRn ( i ) ) ;
}
for ( i = 0 ; i < drvdata - > numcidc ; i + + )
2016-04-05 20:53:44 +03:00
writeq_relaxed ( config - > ctxid_pid [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCCIDCVRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > ctxid_mask0 , drvdata - > base + TRCCIDCCTLR0 ) ;
writel_relaxed ( config - > ctxid_mask1 , drvdata - > base + TRCCIDCCTLR1 ) ;
2015-05-13 19:34:09 +03:00
for ( i = 0 ; i < drvdata - > numvmidc ; i + + )
2016-04-05 20:53:44 +03:00
writeq_relaxed ( config - > vmid_val [ i ] ,
2015-05-13 19:34:09 +03:00
drvdata - > base + TRCVMIDCVRn ( i ) ) ;
2016-04-05 20:53:44 +03:00
writel_relaxed ( config - > vmid_mask0 , drvdata - > base + TRCVMIDCCTLR0 ) ;
writel_relaxed ( config - > vmid_mask1 , drvdata - > base + TRCVMIDCCTLR1 ) ;
2015-05-13 19:34:09 +03:00
2016-08-26 00:19:08 +03:00
/*
* Request to keep the trace unit powered and also
* emulation of powerdown
*/
writel_relaxed ( readl_relaxed ( drvdata - > base + TRCPDCR ) | TRCPDCR_PU ,
drvdata - > base + TRCPDCR ) ;
2015-05-13 19:34:09 +03:00
/* Enable the trace unit */
writel_relaxed ( 1 , drvdata - > base + TRCPRGCTLR ) ;
/* wait for TRCSTATR.IDLE to go back down to '0' */
if ( coresight_timeout ( drvdata - > base , TRCSTATR , TRCSTATR_IDLE_BIT , 0 ) )
dev_err ( drvdata - > dev ,
2016-08-26 00:19:00 +03:00
" timeout while waiting for Idle Trace Status \n " ) ;
2015-05-13 19:34:09 +03:00
2018-09-20 22:18:12 +03:00
done :
2015-05-13 19:34:09 +03:00
CS_LOCK ( drvdata - > base ) ;
2018-09-20 22:18:12 +03:00
dev_dbg ( drvdata - > dev , " cpu: %d enable smp call done: %d \n " ,
drvdata - > cpu , rc ) ;
return rc ;
2018-09-20 22:18:07 +03:00
}
static void etm4_enable_hw_smp_call ( void * info )
{
struct etm4_enable_arg * arg = info ;
if ( WARN_ON ( ! arg ) )
return ;
arg - > rc = etm4_enable_hw ( arg - > drvdata ) ;
2015-05-13 19:34:09 +03:00
}
2016-04-05 20:53:49 +03:00
static int etm4_parse_event_config ( struct etmv4_drvdata * drvdata ,
2016-08-26 00:19:10 +03:00
struct perf_event * event )
2016-04-05 20:53:49 +03:00
{
2016-08-26 00:19:17 +03:00
int ret = 0 ;
2016-04-05 20:53:49 +03:00
struct etmv4_config * config = & drvdata - > config ;
2016-08-26 00:19:10 +03:00
struct perf_event_attr * attr = & event - > attr ;
2016-04-05 20:53:49 +03:00
2016-08-26 00:19:17 +03:00
if ( ! attr ) {
ret = - EINVAL ;
goto out ;
}
2016-04-05 20:53:49 +03:00
/* Clear configuration from previous run */
memset ( config , 0 , sizeof ( struct etmv4_config ) ) ;
if ( attr - > exclude_kernel )
config - > mode = ETM_MODE_EXCL_KERN ;
if ( attr - > exclude_user )
config - > mode = ETM_MODE_EXCL_USER ;
/* Always start from the default config */
2016-08-26 00:19:17 +03:00
etm4_set_default_config ( config ) ;
/* Configure filters specified on the perf cmd line, if any. */
ret = etm4_set_event_filters ( drvdata , event ) ;
if ( ret )
goto out ;
2016-04-05 20:53:49 +03:00
/* Go from generic option to ETMv4 specifics */
2017-01-23 20:41:23 +03:00
if ( attr - > config & BIT ( ETM_OPT_CYCACC ) ) {
config - > cfg | = BIT ( 4 ) ;
/* TRM: Must program this for cycacc to work */
config - > ccctlr = ETM_CYC_THRESHOLD_DEFAULT ;
}
2016-04-05 20:53:49 +03:00
if ( attr - > config & BIT ( ETM_OPT_TS ) )
2017-01-23 20:41:24 +03:00
/* bit[11], Global timestamp tracing bit */
config - > cfg | = BIT ( 11 ) ;
2017-08-02 19:22:03 +03:00
/* return stack - enable if selected and supported */
if ( ( attr - > config & BIT ( ETM_OPT_RETSTK ) ) & & drvdata - > retstack )
/* bit[12], Return stack enable bit */
config - > cfg | = BIT ( 12 ) ;
2016-04-05 20:53:49 +03:00
2016-08-26 00:19:17 +03:00
out :
return ret ;
2016-04-05 20:53:49 +03:00
}
static int etm4_enable_perf ( struct coresight_device * csdev ,
2016-08-26 00:19:10 +03:00
struct perf_event * event )
2016-04-05 20:53:49 +03:00
{
2016-08-26 00:19:17 +03:00
int ret = 0 ;
2016-04-05 20:53:49 +03:00
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
2016-08-26 00:19:17 +03:00
if ( WARN_ON_ONCE ( drvdata - > cpu ! = smp_processor_id ( ) ) ) {
ret = - EINVAL ;
goto out ;
}
2016-04-05 20:53:49 +03:00
/* Configure the tracer based on the session's specifics */
2016-08-26 00:19:17 +03:00
ret = etm4_parse_event_config ( drvdata , event ) ;
if ( ret )
goto out ;
2016-04-05 20:53:49 +03:00
/* And enable it */
2018-09-20 22:18:07 +03:00
ret = etm4_enable_hw ( drvdata ) ;
2016-04-05 20:53:49 +03:00
2016-08-26 00:19:17 +03:00
out :
return ret ;
2016-04-05 20:53:49 +03:00
}
2016-04-05 20:53:47 +03:00
static int etm4_enable_sysfs ( struct coresight_device * csdev )
2015-05-13 19:34:09 +03:00
{
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
2018-09-20 22:18:07 +03:00
struct etm4_enable_arg arg = { 0 } ;
2015-05-13 19:34:09 +03:00
int ret ;
spin_lock ( & drvdata - > spinlock ) ;
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered .
*/
2018-09-20 22:18:07 +03:00
arg . drvdata = drvdata ;
2015-05-13 19:34:09 +03:00
ret = smp_call_function_single ( drvdata - > cpu ,
2018-09-20 22:18:07 +03:00
etm4_enable_hw_smp_call , & arg , 1 ) ;
if ( ! ret )
ret = arg . rc ;
if ( ! ret )
drvdata - > sticky_enable = true ;
2015-05-13 19:34:09 +03:00
spin_unlock ( & drvdata - > spinlock ) ;
2018-09-20 22:18:07 +03:00
if ( ! ret )
dev_dbg ( drvdata - > dev , " ETM tracing enabled \n " ) ;
2015-05-13 19:34:09 +03:00
return ret ;
}
2016-04-05 20:53:47 +03:00
static int etm4_enable ( struct coresight_device * csdev ,
2016-08-26 00:19:10 +03:00
struct perf_event * event , u32 mode )
2016-04-05 20:53:47 +03:00
{
int ret ;
u32 val ;
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
val = local_cmpxchg ( & drvdata - > mode , CS_MODE_DISABLED , mode ) ;
/* Someone is already using the tracer */
if ( val )
return - EBUSY ;
switch ( mode ) {
case CS_MODE_SYSFS :
ret = etm4_enable_sysfs ( csdev ) ;
break ;
2016-04-05 20:53:49 +03:00
case CS_MODE_PERF :
2016-08-26 00:19:10 +03:00
ret = etm4_enable_perf ( csdev , event ) ;
2016-04-05 20:53:49 +03:00
break ;
2016-04-05 20:53:47 +03:00
default :
ret = - EINVAL ;
}
/* The tracer didn't start */
if ( ret )
local_set ( & drvdata - > mode , CS_MODE_DISABLED ) ;
return ret ;
}
2015-05-13 19:34:09 +03:00
static void etm4_disable_hw ( void * info )
{
u32 control ;
struct etmv4_drvdata * drvdata = info ;
CS_UNLOCK ( drvdata - > base ) ;
2016-08-26 00:19:08 +03:00
/* power can be removed from the trace unit now */
control = readl_relaxed ( drvdata - > base + TRCPDCR ) ;
control & = ~ TRCPDCR_PU ;
writel_relaxed ( control , drvdata - > base + TRCPDCR ) ;
2015-05-13 19:34:09 +03:00
control = readl_relaxed ( drvdata - > base + TRCPRGCTLR ) ;
/* EN, bit[0] Trace unit enable bit */
control & = ~ 0x1 ;
/* make sure everything completes before disabling */
mb ( ) ;
isb ( ) ;
writel_relaxed ( control , drvdata - > base + TRCPRGCTLR ) ;
2018-09-20 22:18:12 +03:00
coresight_disclaim_device_unlocked ( drvdata - > base ) ;
2015-05-13 19:34:09 +03:00
CS_LOCK ( drvdata - > base ) ;
dev_dbg ( drvdata - > dev , " cpu: %d disable smp call done \n " , drvdata - > cpu ) ;
}
2016-08-26 00:19:10 +03:00
static int etm4_disable_perf ( struct coresight_device * csdev ,
struct perf_event * event )
2016-04-05 20:53:49 +03:00
{
2016-08-26 00:19:18 +03:00
u32 control ;
struct etm_filters * filters = event - > hw . addr_filters ;
2016-04-05 20:53:49 +03:00
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
if ( WARN_ON_ONCE ( drvdata - > cpu ! = smp_processor_id ( ) ) )
return - EINVAL ;
etm4_disable_hw ( drvdata ) ;
2016-08-26 00:19:18 +03:00
/*
* Check if the start / stop logic was active when the unit was stopped .
* That way we can re - enable the start / stop logic when the process is
* scheduled again . Configuration of the start / stop logic happens in
* function etm4_set_event_filters ( ) .
*/
control = readl_relaxed ( drvdata - > base + TRCVICTLR ) ;
/* TRCVICTLR::SSSTATUS, bit[9] */
filters - > ssstatus = ( control & BIT ( 9 ) ) ;
2016-04-05 20:53:49 +03:00
return 0 ;
}
2016-04-05 20:53:47 +03:00
static void etm4_disable_sysfs ( struct coresight_device * csdev )
2015-05-13 19:34:09 +03:00
{
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
/*
* Taking hotplug lock here protects from clocks getting disabled
* with tracing being left on ( crash scenario ) if user disable occurs
* after cpu online mask indicates the cpu is offline but before the
* DYING hotplug callback is serviced by the ETM driver .
*/
2017-05-24 11:15:23 +03:00
cpus_read_lock ( ) ;
2015-05-13 19:34:09 +03:00
spin_lock ( & drvdata - > spinlock ) ;
/*
* Executing etm4_disable_hw on the cpu whose ETM is being disabled
* ensures that register writes occur when cpu is powered .
*/
smp_call_function_single ( drvdata - > cpu , etm4_disable_hw , drvdata , 1 ) ;
spin_unlock ( & drvdata - > spinlock ) ;
2017-05-24 11:15:23 +03:00
cpus_read_unlock ( ) ;
2015-05-13 19:34:09 +03:00
2018-09-20 22:17:53 +03:00
dev_dbg ( drvdata - > dev , " ETM tracing disabled \n " ) ;
2015-05-13 19:34:09 +03:00
}
2016-08-26 00:19:10 +03:00
static void etm4_disable ( struct coresight_device * csdev ,
struct perf_event * event )
2016-04-05 20:53:47 +03:00
{
u32 mode ;
struct etmv4_drvdata * drvdata = dev_get_drvdata ( csdev - > dev . parent ) ;
/*
* For as long as the tracer isn ' t disabled another entity can ' t
* change its status . As such we can read the status here without
* fearing it will change under us .
*/
mode = local_read ( & drvdata - > mode ) ;
switch ( mode ) {
case CS_MODE_DISABLED :
break ;
case CS_MODE_SYSFS :
etm4_disable_sysfs ( csdev ) ;
break ;
2016-04-05 20:53:49 +03:00
case CS_MODE_PERF :
2016-08-26 00:19:10 +03:00
etm4_disable_perf ( csdev , event ) ;
2016-04-05 20:53:49 +03:00
break ;
2016-04-05 20:53:47 +03:00
}
if ( mode )
local_set ( & drvdata - > mode , CS_MODE_DISABLED ) ;
}
2015-05-13 19:34:09 +03:00
static const struct coresight_ops_source etm4_source_ops = {
2016-02-03 00:14:01 +03:00
. cpu_id = etm4_cpu_id ,
2015-05-13 19:34:09 +03:00
. trace_id = etm4_trace_id ,
. enable = etm4_enable ,
. disable = etm4_disable ,
} ;
static const struct coresight_ops etm4_cs_ops = {
. source_ops = & etm4_source_ops ,
} ;
static void etm4_init_arch_data ( void * info )
{
u32 etmidr0 ;
u32 etmidr1 ;
u32 etmidr2 ;
u32 etmidr3 ;
u32 etmidr4 ;
u32 etmidr5 ;
struct etmv4_drvdata * drvdata = info ;
2016-04-05 20:53:46 +03:00
/* Make sure all registers are accessible */
etm4_os_unlock ( drvdata ) ;
2015-05-13 19:34:09 +03:00
CS_UNLOCK ( drvdata - > base ) ;
/* find all capabilities of the tracing unit */
etmidr0 = readl_relaxed ( drvdata - > base + TRCIDR0 ) ;
/* INSTP0, bits[2:1] P0 tracing support field */
if ( BMVAL ( etmidr0 , 1 , 1 ) & & BMVAL ( etmidr0 , 2 , 2 ) )
drvdata - > instrp0 = true ;
else
drvdata - > instrp0 = false ;
/* TRCBB, bit[5] Branch broadcast tracing support bit */
if ( BMVAL ( etmidr0 , 5 , 5 ) )
drvdata - > trcbb = true ;
else
drvdata - > trcbb = false ;
/* TRCCOND, bit[6] Conditional instruction tracing support bit */
if ( BMVAL ( etmidr0 , 6 , 6 ) )
drvdata - > trccond = true ;
else
drvdata - > trccond = false ;
/* TRCCCI, bit[7] Cycle counting instruction bit */
if ( BMVAL ( etmidr0 , 7 , 7 ) )
drvdata - > trccci = true ;
else
drvdata - > trccci = false ;
/* RETSTACK, bit[9] Return stack bit */
if ( BMVAL ( etmidr0 , 9 , 9 ) )
drvdata - > retstack = true ;
else
drvdata - > retstack = false ;
/* NUMEVENT, bits[11:10] Number of events field */
drvdata - > nr_event = BMVAL ( etmidr0 , 10 , 11 ) ;
/* QSUPP, bits[16:15] Q element support field */
drvdata - > q_support = BMVAL ( etmidr0 , 15 , 16 ) ;
/* TSSIZE, bits[28:24] Global timestamp size field */
drvdata - > ts_size = BMVAL ( etmidr0 , 24 , 28 ) ;
/* base architecture of trace unit */
etmidr1 = readl_relaxed ( drvdata - > base + TRCIDR1 ) ;
/*
* TRCARCHMIN , bits [ 7 : 4 ] architecture the minor version number
* TRCARCHMAJ , bits [ 11 : 8 ] architecture major versin number
*/
drvdata - > arch = BMVAL ( etmidr1 , 4 , 11 ) ;
/* maximum size of resources */
etmidr2 = readl_relaxed ( drvdata - > base + TRCIDR2 ) ;
/* CIDSIZE, bits[9:5] Indicates the Context ID size */
drvdata - > ctxid_size = BMVAL ( etmidr2 , 5 , 9 ) ;
/* VMIDSIZE, bits[14:10] Indicates the VMID size */
drvdata - > vmid_size = BMVAL ( etmidr2 , 10 , 14 ) ;
/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
drvdata - > ccsize = BMVAL ( etmidr2 , 25 , 28 ) ;
etmidr3 = readl_relaxed ( drvdata - > base + TRCIDR3 ) ;
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
drvdata - > ccitmin = BMVAL ( etmidr3 , 0 , 11 ) ;
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
drvdata - > s_ex_level = BMVAL ( etmidr3 , 16 , 19 ) ;
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
drvdata - > ns_ex_level = BMVAL ( etmidr3 , 20 , 23 ) ;
/*
* TRCERR , bit [ 24 ] whether a trace unit can trace a
* system error exception .
*/
if ( BMVAL ( etmidr3 , 24 , 24 ) )
drvdata - > trc_error = true ;
else
drvdata - > trc_error = false ;
/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
if ( BMVAL ( etmidr3 , 25 , 25 ) )
drvdata - > syncpr = true ;
else
drvdata - > syncpr = false ;
/* STALLCTL, bit[26] is stall control implemented? */
if ( BMVAL ( etmidr3 , 26 , 26 ) )
drvdata - > stallctl = true ;
else
drvdata - > stallctl = false ;
/* SYSSTALL, bit[27] implementation can support stall control? */
if ( BMVAL ( etmidr3 , 27 , 27 ) )
drvdata - > sysstall = true ;
else
drvdata - > sysstall = false ;
/* NUMPROC, bits[30:28] the number of PEs available for tracing */
drvdata - > nr_pe = BMVAL ( etmidr3 , 28 , 30 ) ;
/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
if ( BMVAL ( etmidr3 , 31 , 31 ) )
drvdata - > nooverflow = true ;
else
drvdata - > nooverflow = false ;
/* number of resources trace unit supports */
etmidr4 = readl_relaxed ( drvdata - > base + TRCIDR4 ) ;
/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
drvdata - > nr_addr_cmp = BMVAL ( etmidr4 , 0 , 3 ) ;
/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
drvdata - > nr_pe_cmp = BMVAL ( etmidr4 , 12 , 15 ) ;
2015-10-07 18:26:38 +03:00
/*
* NUMRSPAIR , bits [ 19 : 16 ]
* The number of resource pairs conveyed by the HW starts at 0 , i . e a
* value of 0x0 indicate 1 resource pair , 0x1 indicate two and so on .
* As such add 1 to the value of NUMRSPAIR for a better representation .
*/
drvdata - > nr_resource = BMVAL ( etmidr4 , 16 , 19 ) + 1 ;
2015-05-13 19:34:09 +03:00
/*
* NUMSSCC , bits [ 23 : 20 ] the number of single - shot
* comparator control for tracing
*/
drvdata - > nr_ss_cmp = BMVAL ( etmidr4 , 20 , 23 ) ;
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
drvdata - > numcidc = BMVAL ( etmidr4 , 24 , 27 ) ;
/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
drvdata - > numvmidc = BMVAL ( etmidr4 , 28 , 31 ) ;
etmidr5 = readl_relaxed ( drvdata - > base + TRCIDR5 ) ;
/* NUMEXTIN, bits[8:0] number of external inputs implemented */
drvdata - > nr_ext_inp = BMVAL ( etmidr5 , 0 , 8 ) ;
/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
drvdata - > trcid_size = BMVAL ( etmidr5 , 16 , 21 ) ;
/* ATBTRIG, bit[22] implementation can support ATB triggers? */
if ( BMVAL ( etmidr5 , 22 , 22 ) )
drvdata - > atbtrig = true ;
else
drvdata - > atbtrig = false ;
/*
* LPOVERRIDE , bit [ 23 ] implementation supports
* low - power state override
*/
if ( BMVAL ( etmidr5 , 23 , 23 ) )
drvdata - > lpoverride = true ;
else
drvdata - > lpoverride = false ;
/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
drvdata - > nrseqstate = BMVAL ( etmidr5 , 25 , 27 ) ;
/* NUMCNTR, bits[30:28] number of counters available for tracing */
drvdata - > nr_cntr = BMVAL ( etmidr5 , 28 , 30 ) ;
CS_LOCK ( drvdata - > base ) ;
}
2016-08-26 00:19:13 +03:00
static void etm4_set_default_config ( struct etmv4_config * config )
2015-05-13 19:34:09 +03:00
{
/* disable all events tracing */
2016-04-05 20:53:44 +03:00
config - > eventctrl0 = 0x0 ;
config - > eventctrl1 = 0x0 ;
2015-05-13 19:34:09 +03:00
/* disable stalling */
2016-04-05 20:53:44 +03:00
config - > stall_ctrl = 0x0 ;
2015-05-13 19:34:09 +03:00
2016-04-05 20:53:45 +03:00
/* enable trace synchronization every 4096 bytes, if available */
config - > syncfreq = 0xC ;
2015-05-13 19:34:09 +03:00
/* disable timestamp event */
2016-04-05 20:53:44 +03:00
config - > ts_ctrl = 0x0 ;
2015-05-13 19:34:09 +03:00
2016-04-05 20:53:45 +03:00
/* TRCVICTLR::EVENT = 0x01, select the always on logic */
config - > vinst_ctrl | = BIT ( 0 ) ;
2016-08-26 00:19:13 +03:00
}
2015-05-13 19:34:09 +03:00
2018-09-20 22:18:00 +03:00
static u64 etm4_get_ns_access_type ( struct etmv4_config * config )
2016-08-26 00:19:13 +03:00
{
2016-08-26 00:19:15 +03:00
u64 access_type = 0 ;
2015-07-31 18:37:28 +03:00
2016-08-26 00:19:16 +03:00
/*
* EXLEVEL_NS , bits [ 15 : 12 ]
* The Exception levels are :
* Bit [ 12 ] Exception level 0 - Application
* Bit [ 13 ] Exception level 1 - OS
* Bit [ 14 ] Exception level 2 - Hypervisor
* Bit [ 15 ] Never implemented
*/
2018-09-20 22:18:00 +03:00
if ( ! is_kernel_in_hyp_mode ( ) ) {
/* Stay away from hypervisor mode for non-VHE */
access_type = ETM_EXLEVEL_NS_HYP ;
if ( config - > mode & ETM_MODE_EXCL_KERN )
access_type | = ETM_EXLEVEL_NS_OS ;
} else if ( config - > mode & ETM_MODE_EXCL_KERN ) {
access_type = ETM_EXLEVEL_NS_HYP ;
}
2016-08-26 00:19:16 +03:00
if ( config - > mode & ETM_MODE_EXCL_USER )
access_type | = ETM_EXLEVEL_NS_APP ;
2018-09-20 22:18:00 +03:00
return access_type ;
}
static u64 etm4_get_access_type ( struct etmv4_config * config )
{
u64 access_type = etm4_get_ns_access_type ( config ) ;
2016-04-05 20:53:45 +03:00
/*
2016-08-26 00:19:14 +03:00
* EXLEVEL_S , bits [ 11 : 8 ] , don ' t trace anything happening
* in secure state .
*/
access_type | = ( ETM_EXLEVEL_S_APP |
ETM_EXLEVEL_S_OS |
ETM_EXLEVEL_S_HYP ) ;
2016-08-26 00:19:16 +03:00
return access_type ;
}
static void etm4_set_comparator_filter ( struct etmv4_config * config ,
u64 start , u64 stop , int comparator )
{
u64 access_type = etm4_get_access_type ( config ) ;
2016-08-26 00:19:14 +03:00
/* First half of default address comparator */
2016-08-26 00:19:15 +03:00
config - > addr_val [ comparator ] = start ;
config - > addr_acc [ comparator ] = access_type ;
config - > addr_type [ comparator ] = ETM_ADDR_TYPE_RANGE ;
2016-08-26 00:19:14 +03:00
/* Second half of default address comparator */
2016-08-26 00:19:15 +03:00
config - > addr_val [ comparator + 1 ] = stop ;
config - > addr_acc [ comparator + 1 ] = access_type ;
config - > addr_type [ comparator + 1 ] = ETM_ADDR_TYPE_RANGE ;
/*
* Configure the ViewInst function to include this address range
* comparator .
*
* @ comparator is divided by two since it is the index in the
* etmv4_config : : addr_val array but register TRCVIIECTLR deals with
* address range comparator _pairs_ .
*
* Therefore :
* index 0 - > compatator pair 0
* index 2 - > comparator pair 1
* index 4 - > comparator pair 2
* . . .
* index 14 - > comparator pair 7
*/
config - > viiectlr | = BIT ( comparator / 2 ) ;
}
2016-08-26 00:19:18 +03:00
static void etm4_set_start_stop_filter ( struct etmv4_config * config ,
u64 address , int comparator ,
enum etm_addr_type type )
{
int shift ;
u64 access_type = etm4_get_access_type ( config ) ;
/* Configure the comparator */
config - > addr_val [ comparator ] = address ;
config - > addr_acc [ comparator ] = access_type ;
config - > addr_type [ comparator ] = type ;
/*
* Configure ViewInst Start - Stop control register .
* Addresses configured to start tracing go from bit 0 to n - 1 ,
* while those configured to stop tracing from 16 to 16 + n - 1.
*/
shift = ( type = = ETM_ADDR_TYPE_START ? 0 : 16 ) ;
config - > vissctlr | = BIT ( shift + comparator ) ;
}
2016-08-26 00:19:15 +03:00
static void etm4_set_default_filter ( struct etmv4_config * config )
{
u64 start , stop ;
2015-05-13 19:34:09 +03:00
/*
2016-08-26 00:19:15 +03:00
* Configure address range comparator ' 0 ' to encompass all
* possible addresses .
2015-05-13 19:34:09 +03:00
*/
2016-08-26 00:19:15 +03:00
start = 0x0 ;
stop = ~ 0x0 ;
etm4_set_comparator_filter ( config , start , stop ,
ETM_DEFAULT_ADDR_COMP ) ;
2016-04-05 20:53:45 +03:00
2016-08-26 00:19:14 +03:00
/*
* TRCVICTLR : : SSSTATUS = = 1 , the start - stop logic is
* in the started state
*/
config - > vinst_ctrl | = BIT ( 9 ) ;
/* No start-stop filtering for ViewInst */
2016-04-05 20:53:45 +03:00
config - > vissctlr = 0x0 ;
2015-05-13 19:34:09 +03:00
}
2016-08-26 00:19:13 +03:00
static void etm4_set_default ( struct etmv4_config * config )
{
if ( WARN_ON_ONCE ( ! config ) )
return ;
/*
* Make default initialisation trace everything
*
* Select the " always true " resource selector on the
* " Enablign Event " line and configure address range comparator
* ' 0 ' to trace all the possible address range . From there
* configure the " include/exclude " engine to include address
* range comparator ' 0 ' .
*/
etm4_set_default_config ( config ) ;
etm4_set_default_filter ( config ) ;
}
2016-08-26 00:19:17 +03:00
static int etm4_get_next_comparator ( struct etmv4_drvdata * drvdata , u32 type )
{
int nr_comparator , index = 0 ;
struct etmv4_config * config = & drvdata - > config ;
/*
* nr_addr_cmp holds the number of comparator _pair_ , so time 2
* for the total number of comparators .
*/
nr_comparator = drvdata - > nr_addr_cmp * 2 ;
/* Go through the tally of comparators looking for a free one. */
while ( index < nr_comparator ) {
switch ( type ) {
case ETM_ADDR_TYPE_RANGE :
if ( config - > addr_type [ index ] = = ETM_ADDR_TYPE_NONE & &
config - > addr_type [ index + 1 ] = = ETM_ADDR_TYPE_NONE )
return index ;
/* Address range comparators go in pairs */
index + = 2 ;
break ;
2016-08-26 00:19:18 +03:00
case ETM_ADDR_TYPE_START :
case ETM_ADDR_TYPE_STOP :
if ( config - > addr_type [ index ] = = ETM_ADDR_TYPE_NONE )
return index ;
/* Start/stop address can have odd indexes */
index + = 1 ;
break ;
2016-08-26 00:19:17 +03:00
default :
return - EINVAL ;
}
}
/* If we are here all the comparators have been used. */
return - ENOSPC ;
}
static int etm4_set_event_filters ( struct etmv4_drvdata * drvdata ,
struct perf_event * event )
{
int i , comparator , ret = 0 ;
2016-08-26 00:19:18 +03:00
u64 address ;
2016-08-26 00:19:17 +03:00
struct etmv4_config * config = & drvdata - > config ;
struct etm_filters * filters = event - > hw . addr_filters ;
if ( ! filters )
goto default_filter ;
/* Sync events with what Perf got */
perf_event_addr_filters_sync ( event ) ;
/*
* If there are no filters to deal with simply go ahead with
* the default filter , i . e the entire address range .
*/
if ( ! filters - > nr_filters )
goto default_filter ;
for ( i = 0 ; i < filters - > nr_filters ; i + + ) {
struct etm_filter * filter = & filters - > etm_filter [ i ] ;
enum etm_addr_type type = filter - > type ;
/* See if a comparator is free. */
comparator = etm4_get_next_comparator ( drvdata , type ) ;
if ( comparator < 0 ) {
ret = comparator ;
goto out ;
}
switch ( type ) {
case ETM_ADDR_TYPE_RANGE :
etm4_set_comparator_filter ( config ,
filter - > start_addr ,
filter - > stop_addr ,
comparator ) ;
/*
* TRCVICTLR : : SSSTATUS = = 1 , the start - stop logic is
* in the started state
*/
config - > vinst_ctrl | = BIT ( 9 ) ;
/* No start-stop filtering for ViewInst */
config - > vissctlr = 0x0 ;
break ;
2016-08-26 00:19:18 +03:00
case ETM_ADDR_TYPE_START :
case ETM_ADDR_TYPE_STOP :
/* Get the right start or stop address */
address = ( type = = ETM_ADDR_TYPE_START ?
filter - > start_addr :
filter - > stop_addr ) ;
/* Configure comparator */
etm4_set_start_stop_filter ( config , address ,
comparator , type ) ;
/*
* If filters : : ssstatus = = 1 , trace acquisition was
* started but the process was yanked away before the
* the stop address was hit . As such the start / stop
* logic needs to be re - started so that tracing can
* resume where it left .
*
* The start / stop logic status when a process is
* scheduled out is checked in function
* etm4_disable_perf ( ) .
*/
if ( filters - > ssstatus )
config - > vinst_ctrl | = BIT ( 9 ) ;
/* No include/exclude filtering for ViewInst */
config - > viiectlr = 0x0 ;
break ;
2016-08-26 00:19:17 +03:00
default :
ret = - EINVAL ;
goto out ;
}
}
goto out ;
default_filter :
etm4_set_default_filter ( config ) ;
out :
return ret ;
}
2016-04-05 20:53:48 +03:00
void etm4_config_trace_mode ( struct etmv4_config * config )
{
u32 addr_acc , mode ;
mode = config - > mode ;
mode & = ( ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER ) ;
/* excluding kernel AND user space doesn't make sense */
WARN_ON_ONCE ( mode = = ( ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER ) ) ;
/* nothing to do if neither flags are set */
if ( ! ( mode & ETM_MODE_EXCL_KERN ) & & ! ( mode & ETM_MODE_EXCL_USER ) )
return ;
addr_acc = config - > addr_acc [ ETM_DEFAULT_ADDR_COMP ] ;
/* clear default config */
2018-09-20 22:18:00 +03:00
addr_acc & = ~ ( ETM_EXLEVEL_NS_APP | ETM_EXLEVEL_NS_OS |
ETM_EXLEVEL_NS_HYP ) ;
2016-04-05 20:53:48 +03:00
2018-09-20 22:18:00 +03:00
addr_acc | = etm4_get_ns_access_type ( config ) ;
2016-04-05 20:53:48 +03:00
config - > addr_acc [ ETM_DEFAULT_ADDR_COMP ] = addr_acc ;
config - > addr_acc [ ETM_DEFAULT_ADDR_COMP + 1 ] = addr_acc ;
}
2016-07-13 20:16:55 +03:00
static int etm4_online_cpu ( unsigned int cpu )
2015-05-13 19:34:09 +03:00
{
if ( ! etmdrvdata [ cpu ] )
2016-07-13 20:16:55 +03:00
return 0 ;
2015-05-13 19:34:09 +03:00
2016-07-13 20:16:55 +03:00
if ( etmdrvdata [ cpu ] - > boot_enable & & ! etmdrvdata [ cpu ] - > sticky_enable )
coresight_enable ( etmdrvdata [ cpu ] - > csdev ) ;
return 0 ;
}
2015-05-13 19:34:09 +03:00
2016-07-13 20:16:55 +03:00
static int etm4_starting_cpu ( unsigned int cpu )
{
if ( ! etmdrvdata [ cpu ] )
return 0 ;
spin_lock ( & etmdrvdata [ cpu ] - > spinlock ) ;
if ( ! etmdrvdata [ cpu ] - > os_unlock ) {
etm4_os_unlock ( etmdrvdata [ cpu ] ) ;
etmdrvdata [ cpu ] - > os_unlock = true ;
2015-05-13 19:34:09 +03:00
}
2016-07-13 20:16:55 +03:00
if ( local_read ( & etmdrvdata [ cpu ] - > mode ) )
etm4_enable_hw ( etmdrvdata [ cpu ] ) ;
spin_unlock ( & etmdrvdata [ cpu ] - > spinlock ) ;
return 0 ;
2015-05-13 19:34:09 +03:00
}
2016-07-13 20:16:55 +03:00
static int etm4_dying_cpu ( unsigned int cpu )
{
if ( ! etmdrvdata [ cpu ] )
return 0 ;
spin_lock ( & etmdrvdata [ cpu ] - > spinlock ) ;
if ( local_read ( & etmdrvdata [ cpu ] - > mode ) )
etm4_disable_hw ( etmdrvdata [ cpu ] ) ;
spin_unlock ( & etmdrvdata [ cpu ] - > spinlock ) ;
return 0 ;
}
2015-05-13 19:34:09 +03:00
2016-04-05 20:53:45 +03:00
static void etm4_init_trace_id ( struct etmv4_drvdata * drvdata )
{
drvdata - > trcid = coresight_get_trace_id ( drvdata - > cpu ) ;
}
2015-05-13 19:34:09 +03:00
static int etm4_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 etmv4_drvdata * drvdata ;
struct resource * res = & adev - > res ;
2016-08-26 00:19:05 +03:00
struct coresight_desc desc = { 0 } ;
2015-05-13 19:34:09 +03:00
struct device_node * np = adev - > dev . of_node ;
drvdata = devm_kzalloc ( dev , sizeof ( * drvdata ) , GFP_KERNEL ) ;
if ( ! drvdata )
return - ENOMEM ;
if ( np ) {
pdata = of_get_coresight_platform_data ( dev , np ) ;
if ( IS_ERR ( pdata ) )
return PTR_ERR ( pdata ) ;
adev - > dev . platform_data = pdata ;
}
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 - > cpu = pdata ? pdata - > cpu : 0 ;
2017-05-24 11:15:23 +03:00
cpus_read_lock ( ) ;
2015-05-13 19:34:09 +03:00
etmdrvdata [ drvdata - > cpu ] = drvdata ;
if ( smp_call_function_single ( drvdata - > cpu ,
etm4_init_arch_data , drvdata , 1 ) )
dev_err ( dev , " ETM arch init failed \n " ) ;
2016-07-13 20:16:55 +03:00
if ( ! etm4_count + + ) {
2017-05-24 11:15:23 +03:00
cpuhp_setup_state_nocalls_cpuslocked ( CPUHP_AP_ARM_CORESIGHT_STARTING ,
" arm/coresight4:starting " ,
etm4_starting_cpu , etm4_dying_cpu ) ;
ret = cpuhp_setup_state_nocalls_cpuslocked ( CPUHP_AP_ONLINE_DYN ,
" arm/coresight4:online " ,
etm4_online_cpu , NULL ) ;
2016-07-13 20:16:55 +03:00
if ( ret < 0 )
goto err_arch_supported ;
hp_online = ret ;
}
2015-05-13 19:34:09 +03:00
2017-05-24 11:15:23 +03:00
cpus_read_unlock ( ) ;
2015-05-13 19:34:09 +03:00
if ( etm4_arch_supported ( drvdata - > arch ) = = false ) {
ret = - EINVAL ;
goto err_arch_supported ;
}
2016-04-05 20:53:45 +03:00
etm4_init_trace_id ( drvdata ) ;
etm4_set_default ( & drvdata - > config ) ;
2015-05-13 19:34:09 +03:00
2016-08-26 00:19:05 +03:00
desc . type = CORESIGHT_DEV_TYPE_SOURCE ;
desc . subtype . source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC ;
desc . ops = & etm4_cs_ops ;
desc . pdata = pdata ;
desc . dev = dev ;
desc . groups = coresight_etmv4_groups ;
drvdata - > csdev = coresight_register ( & desc ) ;
2015-05-13 19:34:09 +03:00
if ( IS_ERR ( drvdata - > csdev ) ) {
ret = PTR_ERR ( drvdata - > csdev ) ;
2016-04-05 20:53:49 +03:00
goto err_arch_supported ;
2015-05-13 19:34:09 +03:00
}
2016-04-05 20:53:49 +03:00
ret = etm_perf_symlink ( drvdata - > csdev , true ) ;
if ( ret ) {
coresight_unregister ( drvdata - > csdev ) ;
goto err_arch_supported ;
}
pm_runtime_put ( & adev - > dev ) ;
2018-07-11 22:40:14 +03:00
dev_info ( dev , " CPU%d: ETM v%d.%d initialized \n " ,
drvdata - > cpu , drvdata - > arch > > 4 , drvdata - > arch & 0xf ) ;
2015-05-13 19:34:09 +03:00
if ( boot_enable ) {
coresight_enable ( drvdata - > csdev ) ;
drvdata - > boot_enable = true ;
}
return 0 ;
err_arch_supported :
2016-07-13 20:16:55 +03:00
if ( - - etm4_count = = 0 ) {
2016-12-21 22:19:55 +03:00
cpuhp_remove_state_nocalls ( CPUHP_AP_ARM_CORESIGHT_STARTING ) ;
2016-07-13 20:16:55 +03:00
if ( hp_online )
cpuhp_remove_state_nocalls ( hp_online ) ;
}
2015-05-13 19:34:09 +03:00
return ret ;
}
2018-07-11 22:40:14 +03:00
# define ETM4x_AMBA_ID(pid) \
{ \
. id = pid , \
. mask = 0x000fffff , \
}
2017-08-24 19:36:00 +03:00
static const struct amba_id etm4_ids [ ] = {
2018-07-11 22:40:14 +03:00
ETM4x_AMBA_ID ( 0x000bb95d ) , /* Cortex-A53 */
ETM4x_AMBA_ID ( 0x000bb95e ) , /* Cortex-A57 */
ETM4x_AMBA_ID ( 0x000bb95a ) , /* Cortex-A72 */
ETM4x_AMBA_ID ( 0x000bb959 ) , /* Cortex-A73 */
ETM4x_AMBA_ID ( 0x000bb9da ) , /* Cortex-A35 */
{ } ,
2015-05-13 19:34:09 +03:00
} ;
static struct amba_driver etm4x_driver = {
. drv = {
. name = " coresight-etm4x " ,
2016-02-03 00:14:00 +03:00
. suppress_bind_attrs = true ,
2015-05-13 19:34:09 +03:00
} ,
. probe = etm4_probe ,
. id_table = etm4_ids ,
} ;
2016-02-18 03:52:03 +03:00
builtin_amba_driver ( etm4x_driver ) ;