cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

coresight-cti-core.c (25636B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2018 Linaro Limited, All rights reserved.
      4 * Author: Mike Leach <mike.leach@linaro.org>
      5 */
      6
      7#include <linux/amba/bus.h>
      8#include <linux/atomic.h>
      9#include <linux/bits.h>
     10#include <linux/coresight.h>
     11#include <linux/cpu_pm.h>
     12#include <linux/cpuhotplug.h>
     13#include <linux/device.h>
     14#include <linux/io.h>
     15#include <linux/kernel.h>
     16#include <linux/list.h>
     17#include <linux/mutex.h>
     18#include <linux/pm_runtime.h>
     19#include <linux/property.h>
     20#include <linux/spinlock.h>
     21
     22#include "coresight-priv.h"
     23#include "coresight-cti.h"
     24
     25/**
     26 * CTI devices can be associated with a PE, or be connected to CoreSight
     27 * hardware. We have a list of all CTIs irrespective of CPU bound or
     28 * otherwise.
     29 *
     30 * We assume that the non-CPU CTIs are always powered as we do with sinks etc.
     31 *
     32 * We leave the client to figure out if all the CTIs are interconnected with
     33 * the same CTM, in general this is the case but does not always have to be.
     34 */
     35
     36/* net of CTI devices connected via CTM */
     37static LIST_HEAD(ect_net);
     38
     39/* protect the list */
     40static DEFINE_MUTEX(ect_mutex);
     41
     42#define csdev_to_cti_drvdata(csdev)	\
     43	dev_get_drvdata(csdev->dev.parent)
     44
     45/* power management handling */
     46static int nr_cti_cpu;
     47
     48/* quick lookup list for CPU bound CTIs when power handling */
     49static struct cti_drvdata *cti_cpu_drvdata[NR_CPUS];
     50
     51/*
     52 * CTI naming. CTI bound to cores will have the name cti_cpu<N> where
     53 * N is the CPU ID. System CTIs will have the name cti_sys<I> where I
     54 * is an index allocated by order of discovery.
     55 *
     56 * CTI device name list - for CTI not bound to cores.
     57 */
     58DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys");
     59
     60/* write set of regs to hardware - call with spinlock claimed */
     61void cti_write_all_hw_regs(struct cti_drvdata *drvdata)
     62{
     63	struct cti_config *config = &drvdata->config;
     64	int i;
     65
     66	CS_UNLOCK(drvdata->base);
     67
     68	/* disable CTI before writing registers */
     69	writel_relaxed(0, drvdata->base + CTICONTROL);
     70
     71	/* write the CTI trigger registers */
     72	for (i = 0; i < config->nr_trig_max; i++) {
     73		writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));
     74		writel_relaxed(config->ctiouten[i],
     75			       drvdata->base + CTIOUTEN(i));
     76	}
     77
     78	/* other regs */
     79	writel_relaxed(config->ctigate, drvdata->base + CTIGATE);
     80	writel_relaxed(config->asicctl, drvdata->base + ASICCTL);
     81	writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);
     82
     83	/* re-enable CTI */
     84	writel_relaxed(1, drvdata->base + CTICONTROL);
     85
     86	CS_LOCK(drvdata->base);
     87}
     88
     89/* write regs to hardware and enable */
     90static int cti_enable_hw(struct cti_drvdata *drvdata)
     91{
     92	struct cti_config *config = &drvdata->config;
     93	struct device *dev = &drvdata->csdev->dev;
     94	unsigned long flags;
     95	int rc = 0;
     96
     97	pm_runtime_get_sync(dev->parent);
     98	spin_lock_irqsave(&drvdata->spinlock, flags);
     99
    100	/* no need to do anything if enabled or unpowered*/
    101	if (config->hw_enabled || !config->hw_powered)
    102		goto cti_state_unchanged;
    103
    104	/* claim the device */
    105	rc = coresight_claim_device(drvdata->csdev);
    106	if (rc)
    107		goto cti_err_not_enabled;
    108
    109	cti_write_all_hw_regs(drvdata);
    110
    111	config->hw_enabled = true;
    112	atomic_inc(&drvdata->config.enable_req_count);
    113	spin_unlock_irqrestore(&drvdata->spinlock, flags);
    114	return rc;
    115
    116cti_state_unchanged:
    117	atomic_inc(&drvdata->config.enable_req_count);
    118
    119	/* cannot enable due to error */
    120cti_err_not_enabled:
    121	spin_unlock_irqrestore(&drvdata->spinlock, flags);
    122	pm_runtime_put(dev->parent);
    123	return rc;
    124}
    125
    126/* re-enable CTI on CPU when using CPU hotplug */
    127static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
    128{
    129	struct cti_config *config = &drvdata->config;
    130
    131	spin_lock(&drvdata->spinlock);
    132	config->hw_powered = true;
    133
    134	/* no need to do anything if no enable request */
    135	if (!atomic_read(&drvdata->config.enable_req_count))
    136		goto cti_hp_not_enabled;
    137
    138	/* try to claim the device */
    139	if (coresight_claim_device(drvdata->csdev))
    140		goto cti_hp_not_enabled;
    141
    142	cti_write_all_hw_regs(drvdata);
    143	config->hw_enabled = true;
    144	spin_unlock(&drvdata->spinlock);
    145	return;
    146
    147	/* did not re-enable due to no claim / no request */
    148cti_hp_not_enabled:
    149	spin_unlock(&drvdata->spinlock);
    150}
    151
    152/* disable hardware */
    153static int cti_disable_hw(struct cti_drvdata *drvdata)
    154{
    155	struct cti_config *config = &drvdata->config;
    156	struct device *dev = &drvdata->csdev->dev;
    157	struct coresight_device *csdev = drvdata->csdev;
    158
    159	spin_lock(&drvdata->spinlock);
    160
    161	/* check refcount - disable on 0 */
    162	if (atomic_dec_return(&drvdata->config.enable_req_count) > 0)
    163		goto cti_not_disabled;
    164
    165	/* no need to do anything if disabled or cpu unpowered */
    166	if (!config->hw_enabled || !config->hw_powered)
    167		goto cti_not_disabled;
    168
    169	CS_UNLOCK(drvdata->base);
    170
    171	/* disable CTI */
    172	writel_relaxed(0, drvdata->base + CTICONTROL);
    173	config->hw_enabled = false;
    174
    175	coresight_disclaim_device_unlocked(csdev);
    176	CS_LOCK(drvdata->base);
    177	spin_unlock(&drvdata->spinlock);
    178	pm_runtime_put(dev->parent);
    179	return 0;
    180
    181	/* not disabled this call */
    182cti_not_disabled:
    183	spin_unlock(&drvdata->spinlock);
    184	return 0;
    185}
    186
    187void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value)
    188{
    189	CS_UNLOCK(drvdata->base);
    190	writel_relaxed(value, drvdata->base + offset);
    191	CS_LOCK(drvdata->base);
    192}
    193
    194void cti_write_intack(struct device *dev, u32 ackval)
    195{
    196	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
    197	struct cti_config *config = &drvdata->config;
    198
    199	spin_lock(&drvdata->spinlock);
    200	/* write if enabled */
    201	if (cti_active(config))
    202		cti_write_single_reg(drvdata, CTIINTACK, ackval);
    203	spin_unlock(&drvdata->spinlock);
    204}
    205
    206/*
    207 * Look at the HW DEVID register for some of the HW settings.
    208 * DEVID[15:8] - max number of in / out triggers.
    209 */
    210#define CTI_DEVID_MAXTRIGS(devid_val) ((int) BMVAL(devid_val, 8, 15))
    211
    212/* DEVID[19:16] - number of CTM channels */
    213#define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))
    214
    215static void cti_set_default_config(struct device *dev,
    216				   struct cti_drvdata *drvdata)
    217{
    218	struct cti_config *config = &drvdata->config;
    219	u32 devid;
    220
    221	devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);
    222	config->nr_trig_max = CTI_DEVID_MAXTRIGS(devid);
    223
    224	/*
    225	 * no current hardware should exceed this, but protect the driver
    226	 * in case of fault / out of spec hw
    227	 */
    228	if (config->nr_trig_max > CTIINOUTEN_MAX) {
    229		dev_warn_once(dev,
    230			"Limiting HW MaxTrig value(%d) to driver max(%d)\n",
    231			config->nr_trig_max, CTIINOUTEN_MAX);
    232		config->nr_trig_max = CTIINOUTEN_MAX;
    233	}
    234
    235	config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);
    236
    237	/* Most regs default to 0 as zalloc'ed except...*/
    238	config->trig_filter_enable = true;
    239	config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);
    240	atomic_set(&config->enable_req_count, 0);
    241}
    242
    243/*
    244 * Add a connection entry to the list of connections for this
    245 * CTI device.
    246 */
    247int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
    248			     struct cti_trig_con *tc,
    249			     struct coresight_device *csdev,
    250			     const char *assoc_dev_name)
    251{
    252	struct cti_device *cti_dev = &drvdata->ctidev;
    253
    254	tc->con_dev = csdev;
    255	/*
    256	 * Prefer actual associated CS device dev name to supplied value -
    257	 * which is likely to be node name / other conn name.
    258	 */
    259	if (csdev)
    260		tc->con_dev_name = dev_name(&csdev->dev);
    261	else if (assoc_dev_name != NULL) {
    262		tc->con_dev_name = devm_kstrdup(dev,
    263						assoc_dev_name, GFP_KERNEL);
    264		if (!tc->con_dev_name)
    265			return -ENOMEM;
    266	}
    267	list_add_tail(&tc->node, &cti_dev->trig_cons);
    268	cti_dev->nr_trig_con++;
    269
    270	/* add connection usage bit info to overall info */
    271	drvdata->config.trig_in_use |= tc->con_in->used_mask;
    272	drvdata->config.trig_out_use |= tc->con_out->used_mask;
    273
    274	return 0;
    275}
    276
    277/* create a trigger connection with appropriately sized signal groups */
    278struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
    279					   int out_sigs)
    280{
    281	struct cti_trig_con *tc = NULL;
    282	struct cti_trig_grp *in = NULL, *out = NULL;
    283
    284	tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL);
    285	if (!tc)
    286		return tc;
    287
    288	in = devm_kzalloc(dev,
    289			  offsetof(struct cti_trig_grp, sig_types[in_sigs]),
    290			  GFP_KERNEL);
    291	if (!in)
    292		return NULL;
    293
    294	out = devm_kzalloc(dev,
    295			   offsetof(struct cti_trig_grp, sig_types[out_sigs]),
    296			   GFP_KERNEL);
    297	if (!out)
    298		return NULL;
    299
    300	tc->con_in = in;
    301	tc->con_out = out;
    302	tc->con_in->nr_sigs = in_sigs;
    303	tc->con_out->nr_sigs = out_sigs;
    304	return tc;
    305}
    306
    307/*
    308 * Add a default connection if nothing else is specified.
    309 * single connection based on max in/out info, no assoc device
    310 */
    311int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)
    312{
    313	int ret = 0;
    314	int n_trigs = drvdata->config.nr_trig_max;
    315	u32 n_trig_mask = GENMASK(n_trigs - 1, 0);
    316	struct cti_trig_con *tc = NULL;
    317
    318	/*
    319	 * Assume max trigs for in and out,
    320	 * all used, default sig types allocated
    321	 */
    322	tc = cti_allocate_trig_con(dev, n_trigs, n_trigs);
    323	if (!tc)
    324		return -ENOMEM;
    325
    326	tc->con_in->used_mask = n_trig_mask;
    327	tc->con_out->used_mask = n_trig_mask;
    328	ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");
    329	return ret;
    330}
    331
    332/** cti channel api **/
    333/* attach/detach channel from trigger - write through if enabled. */
    334int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,
    335			enum cti_trig_dir direction, u32 channel_idx,
    336			u32 trigger_idx)
    337{
    338	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
    339	struct cti_config *config = &drvdata->config;
    340	u32 trig_bitmask;
    341	u32 chan_bitmask;
    342	u32 reg_value;
    343	int reg_offset;
    344
    345	/* ensure indexes in range */
    346	if ((channel_idx >= config->nr_ctm_channels) ||
    347	   (trigger_idx >= config->nr_trig_max))
    348		return -EINVAL;
    349
    350	trig_bitmask = BIT(trigger_idx);
    351
    352	/* ensure registered triggers and not out filtered */
    353	if (direction == CTI_TRIG_IN)	{
    354		if (!(trig_bitmask & config->trig_in_use))
    355			return -EINVAL;
    356	} else {
    357		if (!(trig_bitmask & config->trig_out_use))
    358			return -EINVAL;
    359
    360		if ((config->trig_filter_enable) &&
    361		    (config->trig_out_filter & trig_bitmask))
    362			return -EINVAL;
    363	}
    364
    365	/* update the local register values */
    366	chan_bitmask = BIT(channel_idx);
    367	reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :
    368		      CTIOUTEN(trigger_idx));
    369
    370	spin_lock(&drvdata->spinlock);
    371
    372	/* read - modify write - the trigger / channel enable value */
    373	reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :
    374		     config->ctiouten[trigger_idx];
    375	if (op == CTI_CHAN_ATTACH)
    376		reg_value |= chan_bitmask;
    377	else
    378		reg_value &= ~chan_bitmask;
    379
    380	/* write local copy */
    381	if (direction == CTI_TRIG_IN)
    382		config->ctiinen[trigger_idx] = reg_value;
    383	else
    384		config->ctiouten[trigger_idx] = reg_value;
    385
    386	/* write through if enabled */
    387	if (cti_active(config))
    388		cti_write_single_reg(drvdata, reg_offset, reg_value);
    389	spin_unlock(&drvdata->spinlock);
    390	return 0;
    391}
    392
    393int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,
    394			u32 channel_idx)
    395{
    396	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
    397	struct cti_config *config = &drvdata->config;
    398	u32 chan_bitmask;
    399	u32 reg_value;
    400	int err = 0;
    401
    402	if (channel_idx >= config->nr_ctm_channels)
    403		return -EINVAL;
    404
    405	chan_bitmask = BIT(channel_idx);
    406
    407	spin_lock(&drvdata->spinlock);
    408	reg_value = config->ctigate;
    409	switch (op) {
    410	case CTI_GATE_CHAN_ENABLE:
    411		reg_value |= chan_bitmask;
    412		break;
    413
    414	case CTI_GATE_CHAN_DISABLE:
    415		reg_value &= ~chan_bitmask;
    416		break;
    417
    418	default:
    419		err = -EINVAL;
    420		break;
    421	}
    422	if (err == 0) {
    423		config->ctigate = reg_value;
    424		if (cti_active(config))
    425			cti_write_single_reg(drvdata, CTIGATE, reg_value);
    426	}
    427	spin_unlock(&drvdata->spinlock);
    428	return err;
    429}
    430
    431int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,
    432		      u32 channel_idx)
    433{
    434	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
    435	struct cti_config *config = &drvdata->config;
    436	u32 chan_bitmask;
    437	u32 reg_value;
    438	u32 reg_offset;
    439	int err = 0;
    440
    441	if (channel_idx >= config->nr_ctm_channels)
    442		return -EINVAL;
    443
    444	chan_bitmask = BIT(channel_idx);
    445
    446	spin_lock(&drvdata->spinlock);
    447	reg_value = config->ctiappset;
    448	switch (op) {
    449	case CTI_CHAN_SET:
    450		config->ctiappset |= chan_bitmask;
    451		reg_value  = config->ctiappset;
    452		reg_offset = CTIAPPSET;
    453		break;
    454
    455	case CTI_CHAN_CLR:
    456		config->ctiappset &= ~chan_bitmask;
    457		reg_value = chan_bitmask;
    458		reg_offset = CTIAPPCLEAR;
    459		break;
    460
    461	case CTI_CHAN_PULSE:
    462		config->ctiappset &= ~chan_bitmask;
    463		reg_value = chan_bitmask;
    464		reg_offset = CTIAPPPULSE;
    465		break;
    466
    467	default:
    468		err = -EINVAL;
    469		break;
    470	}
    471
    472	if ((err == 0) && cti_active(config))
    473		cti_write_single_reg(drvdata, reg_offset, reg_value);
    474	spin_unlock(&drvdata->spinlock);
    475
    476	return err;
    477}
    478
    479static bool cti_add_sysfs_link(struct cti_drvdata *drvdata,
    480			       struct cti_trig_con *tc)
    481{
    482	struct coresight_sysfs_link link_info;
    483	int link_err = 0;
    484
    485	link_info.orig = drvdata->csdev;
    486	link_info.orig_name = tc->con_dev_name;
    487	link_info.target = tc->con_dev;
    488	link_info.target_name = dev_name(&drvdata->csdev->dev);
    489
    490	link_err = coresight_add_sysfs_link(&link_info);
    491	if (link_err)
    492		dev_warn(&drvdata->csdev->dev,
    493			 "Failed to set CTI sysfs link %s<=>%s\n",
    494			 link_info.orig_name, link_info.target_name);
    495	return !link_err;
    496}
    497
    498static void cti_remove_sysfs_link(struct cti_drvdata *drvdata,
    499				  struct cti_trig_con *tc)
    500{
    501	struct coresight_sysfs_link link_info;
    502
    503	link_info.orig = drvdata->csdev;
    504	link_info.orig_name = tc->con_dev_name;
    505	link_info.target = tc->con_dev;
    506	link_info.target_name = dev_name(&drvdata->csdev->dev);
    507	coresight_remove_sysfs_link(&link_info);
    508}
    509
    510/*
    511 * Look for a matching connection device name in the list of connections.
    512 * If found then swap in the csdev name, set trig con association pointer
    513 * and return found.
    514 */
    515static bool
    516cti_match_fixup_csdev(struct cti_device *ctidev, const char *node_name,
    517		      struct coresight_device *csdev)
    518{
    519	struct cti_trig_con *tc;
    520	struct cti_drvdata *drvdata = container_of(ctidev, struct cti_drvdata,
    521						   ctidev);
    522
    523	list_for_each_entry(tc, &ctidev->trig_cons, node) {
    524		if (tc->con_dev_name) {
    525			if (!strcmp(node_name, tc->con_dev_name)) {
    526				/* match: so swap in csdev name & dev */
    527				tc->con_dev_name = dev_name(&csdev->dev);
    528				tc->con_dev = csdev;
    529				/* try to set sysfs link */
    530				if (cti_add_sysfs_link(drvdata, tc))
    531					return true;
    532				/* link failed - remove CTI reference */
    533				tc->con_dev = NULL;
    534				break;
    535			}
    536		}
    537	}
    538	return false;
    539}
    540
    541/*
    542 * Search the cti list to add an associated CTI into the supplied CS device
    543 * This will set the association if CTI declared before the CS device.
    544 * (called from coresight_register() with coresight_mutex locked).
    545 */
    546static void cti_add_assoc_to_csdev(struct coresight_device *csdev)
    547{
    548	struct cti_drvdata *ect_item;
    549	struct cti_device *ctidev;
    550	const char *node_name = NULL;
    551
    552	/* protect the list */
    553	mutex_lock(&ect_mutex);
    554
    555	/* exit if current is an ECT device.*/
    556	if ((csdev->type == CORESIGHT_DEV_TYPE_ECT) || list_empty(&ect_net))
    557		goto cti_add_done;
    558
    559	/* if we didn't find the csdev previously we used the fwnode name */
    560	node_name = cti_plat_get_node_name(dev_fwnode(csdev->dev.parent));
    561	if (!node_name)
    562		goto cti_add_done;
    563
    564	/* for each CTI in list... */
    565	list_for_each_entry(ect_item, &ect_net, node) {
    566		ctidev = &ect_item->ctidev;
    567		if (cti_match_fixup_csdev(ctidev, node_name, csdev)) {
    568			/*
    569			 * if we found a matching csdev then update the ECT
    570			 * association pointer for the device with this CTI.
    571			 */
    572			csdev->ect_dev = ect_item->csdev;
    573			break;
    574		}
    575	}
    576cti_add_done:
    577	mutex_unlock(&ect_mutex);
    578}
    579
    580/*
    581 * Removing the associated devices is easier.
    582 * A CTI will not have a value for csdev->ect_dev.
    583 */
    584static void cti_remove_assoc_from_csdev(struct coresight_device *csdev)
    585{
    586	struct cti_drvdata *ctidrv;
    587	struct cti_trig_con *tc;
    588	struct cti_device *ctidev;
    589
    590	mutex_lock(&ect_mutex);
    591	if (csdev->ect_dev) {
    592		ctidrv = csdev_to_cti_drvdata(csdev->ect_dev);
    593		ctidev = &ctidrv->ctidev;
    594		list_for_each_entry(tc, &ctidev->trig_cons, node) {
    595			if (tc->con_dev == csdev) {
    596				cti_remove_sysfs_link(ctidrv, tc);
    597				tc->con_dev = NULL;
    598				break;
    599			}
    600		}
    601		csdev->ect_dev = NULL;
    602	}
    603	mutex_unlock(&ect_mutex);
    604}
    605
    606/*
    607 * Operations to add and remove associated CTI.
    608 * Register to coresight core driver as call back function.
    609 */
    610static struct cti_assoc_op cti_assoc_ops = {
    611	.add = cti_add_assoc_to_csdev,
    612	.remove = cti_remove_assoc_from_csdev
    613};
    614
    615/*
    616 * Update the cross references where the associated device was found
    617 * while we were building the connection info. This will occur if the
    618 * assoc device was registered before the CTI.
    619 */
    620static void cti_update_conn_xrefs(struct cti_drvdata *drvdata)
    621{
    622	struct cti_trig_con *tc;
    623	struct cti_device *ctidev = &drvdata->ctidev;
    624
    625	list_for_each_entry(tc, &ctidev->trig_cons, node) {
    626		if (tc->con_dev) {
    627			/* if we can set the sysfs link */
    628			if (cti_add_sysfs_link(drvdata, tc))
    629				/* set the CTI/csdev association */
    630				coresight_set_assoc_ectdev_mutex(tc->con_dev,
    631							 drvdata->csdev);
    632			else
    633				/* otherwise remove reference from CTI */
    634				tc->con_dev = NULL;
    635		}
    636	}
    637}
    638
    639static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata)
    640{
    641	struct cti_trig_con *tc;
    642	struct cti_device *ctidev = &drvdata->ctidev;
    643
    644	list_for_each_entry(tc, &ctidev->trig_cons, node) {
    645		if (tc->con_dev) {
    646			coresight_set_assoc_ectdev_mutex(tc->con_dev,
    647							 NULL);
    648			cti_remove_sysfs_link(drvdata, tc);
    649			tc->con_dev = NULL;
    650		}
    651	}
    652}
    653
    654/** cti PM callbacks **/
    655static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
    656			     void *v)
    657{
    658	struct cti_drvdata *drvdata;
    659	struct coresight_device *csdev;
    660	unsigned int cpu = smp_processor_id();
    661	int notify_res = NOTIFY_OK;
    662
    663	if (!cti_cpu_drvdata[cpu])
    664		return NOTIFY_OK;
    665
    666	drvdata = cti_cpu_drvdata[cpu];
    667	csdev = drvdata->csdev;
    668
    669	if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))
    670		return NOTIFY_BAD;
    671
    672	spin_lock(&drvdata->spinlock);
    673
    674	switch (cmd) {
    675	case CPU_PM_ENTER:
    676		/* CTI regs all static - we have a copy & nothing to save */
    677		drvdata->config.hw_powered = false;
    678		if (drvdata->config.hw_enabled)
    679			coresight_disclaim_device(csdev);
    680		break;
    681
    682	case CPU_PM_ENTER_FAILED:
    683		drvdata->config.hw_powered = true;
    684		if (drvdata->config.hw_enabled) {
    685			if (coresight_claim_device(csdev))
    686				drvdata->config.hw_enabled = false;
    687		}
    688		break;
    689
    690	case CPU_PM_EXIT:
    691		/* write hardware registers to re-enable. */
    692		drvdata->config.hw_powered = true;
    693		drvdata->config.hw_enabled = false;
    694
    695		/* check enable reference count to enable HW */
    696		if (atomic_read(&drvdata->config.enable_req_count)) {
    697			/* check we can claim the device as we re-power */
    698			if (coresight_claim_device(csdev))
    699				goto cti_notify_exit;
    700
    701			drvdata->config.hw_enabled = true;
    702			cti_write_all_hw_regs(drvdata);
    703		}
    704		break;
    705
    706	default:
    707		notify_res = NOTIFY_DONE;
    708		break;
    709	}
    710
    711cti_notify_exit:
    712	spin_unlock(&drvdata->spinlock);
    713	return notify_res;
    714}
    715
    716static struct notifier_block cti_cpu_pm_nb = {
    717	.notifier_call = cti_cpu_pm_notify,
    718};
    719
    720/* CPU HP handlers */
    721static int cti_starting_cpu(unsigned int cpu)
    722{
    723	struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu];
    724
    725	if (!drvdata)
    726		return 0;
    727
    728	cti_cpuhp_enable_hw(drvdata);
    729	return 0;
    730}
    731
    732static int cti_dying_cpu(unsigned int cpu)
    733{
    734	struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu];
    735
    736	if (!drvdata)
    737		return 0;
    738
    739	spin_lock(&drvdata->spinlock);
    740	drvdata->config.hw_powered = false;
    741	if (drvdata->config.hw_enabled)
    742		coresight_disclaim_device(drvdata->csdev);
    743	spin_unlock(&drvdata->spinlock);
    744	return 0;
    745}
    746
    747static int cti_pm_setup(struct cti_drvdata *drvdata)
    748{
    749	int ret;
    750
    751	if (drvdata->ctidev.cpu == -1)
    752		return 0;
    753
    754	if (nr_cti_cpu)
    755		goto done;
    756
    757	cpus_read_lock();
    758	ret = cpuhp_setup_state_nocalls_cpuslocked(
    759			CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,
    760			"arm/coresight_cti:starting",
    761			cti_starting_cpu, cti_dying_cpu);
    762	if (ret) {
    763		cpus_read_unlock();
    764		return ret;
    765	}
    766
    767	ret = cpu_pm_register_notifier(&cti_cpu_pm_nb);
    768	cpus_read_unlock();
    769	if (ret) {
    770		cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING);
    771		return ret;
    772	}
    773
    774done:
    775	nr_cti_cpu++;
    776	cti_cpu_drvdata[drvdata->ctidev.cpu] = drvdata;
    777
    778	return 0;
    779}
    780
    781/* release PM registrations */
    782static void cti_pm_release(struct cti_drvdata *drvdata)
    783{
    784	if (drvdata->ctidev.cpu == -1)
    785		return;
    786
    787	cti_cpu_drvdata[drvdata->ctidev.cpu] = NULL;
    788	if (--nr_cti_cpu == 0) {
    789		cpu_pm_unregister_notifier(&cti_cpu_pm_nb);
    790		cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING);
    791	}
    792}
    793
    794/** cti ect operations **/
    795int cti_enable(struct coresight_device *csdev)
    796{
    797	struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
    798
    799	return cti_enable_hw(drvdata);
    800}
    801
    802int cti_disable(struct coresight_device *csdev)
    803{
    804	struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
    805
    806	return cti_disable_hw(drvdata);
    807}
    808
    809static const struct coresight_ops_ect cti_ops_ect = {
    810	.enable = cti_enable,
    811	.disable = cti_disable,
    812};
    813
    814static const struct coresight_ops cti_ops = {
    815	.ect_ops = &cti_ops_ect,
    816};
    817
    818/*
    819 * Free up CTI specific resources
    820 * called by dev->release, need to call down to underlying csdev release.
    821 */
    822static void cti_device_release(struct device *dev)
    823{
    824	struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
    825	struct cti_drvdata *ect_item, *ect_tmp;
    826
    827	mutex_lock(&ect_mutex);
    828	cti_pm_release(drvdata);
    829
    830	/* remove from the list */
    831	list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) {
    832		if (ect_item == drvdata) {
    833			list_del(&ect_item->node);
    834			break;
    835		}
    836	}
    837	mutex_unlock(&ect_mutex);
    838
    839	if (drvdata->csdev_release)
    840		drvdata->csdev_release(dev);
    841}
    842static void cti_remove(struct amba_device *adev)
    843{
    844	struct cti_drvdata *drvdata = dev_get_drvdata(&adev->dev);
    845
    846	mutex_lock(&ect_mutex);
    847	cti_remove_conn_xrefs(drvdata);
    848	mutex_unlock(&ect_mutex);
    849
    850	coresight_unregister(drvdata->csdev);
    851}
    852
    853static int cti_probe(struct amba_device *adev, const struct amba_id *id)
    854{
    855	int ret = 0;
    856	void __iomem *base;
    857	struct device *dev = &adev->dev;
    858	struct cti_drvdata *drvdata = NULL;
    859	struct coresight_desc cti_desc;
    860	struct coresight_platform_data *pdata = NULL;
    861	struct resource *res = &adev->res;
    862
    863	/* driver data*/
    864	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
    865	if (!drvdata)
    866		return -ENOMEM;
    867
    868	/* Validity for the resource is already checked by the AMBA core */
    869	base = devm_ioremap_resource(dev, res);
    870	if (IS_ERR(base))
    871		return PTR_ERR(base);
    872
    873	drvdata->base = base;
    874	cti_desc.access = CSDEV_ACCESS_IOMEM(base);
    875
    876	dev_set_drvdata(dev, drvdata);
    877
    878	/* default CTI device info  */
    879	drvdata->ctidev.cpu = -1;
    880	drvdata->ctidev.nr_trig_con = 0;
    881	drvdata->ctidev.ctm_id = 0;
    882	INIT_LIST_HEAD(&drvdata->ctidev.trig_cons);
    883
    884	spin_lock_init(&drvdata->spinlock);
    885
    886	/* initialise CTI driver config values */
    887	cti_set_default_config(dev, drvdata);
    888
    889	pdata = coresight_cti_get_platform_data(dev);
    890	if (IS_ERR(pdata)) {
    891		dev_err(dev, "coresight_cti_get_platform_data err\n");
    892		return  PTR_ERR(pdata);
    893	}
    894
    895	/* default to powered - could change on PM notifications */
    896	drvdata->config.hw_powered = true;
    897
    898	/* set up device name - will depend if cpu bound or otherwise */
    899	if (drvdata->ctidev.cpu >= 0)
    900		cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d",
    901					       drvdata->ctidev.cpu);
    902	else
    903		cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev);
    904	if (!cti_desc.name)
    905		return -ENOMEM;
    906
    907	/* setup CPU power management handling for CPU bound CTI devices. */
    908	ret = cti_pm_setup(drvdata);
    909	if (ret)
    910		return ret;
    911
    912	/* create dynamic attributes for connections */
    913	ret = cti_create_cons_sysfs(dev, drvdata);
    914	if (ret) {
    915		dev_err(dev, "%s: create dynamic sysfs entries failed\n",
    916			cti_desc.name);
    917		goto pm_release;
    918	}
    919
    920	/* set up coresight component description */
    921	cti_desc.pdata = pdata;
    922	cti_desc.type = CORESIGHT_DEV_TYPE_ECT;
    923	cti_desc.subtype.ect_subtype = CORESIGHT_DEV_SUBTYPE_ECT_CTI;
    924	cti_desc.ops = &cti_ops;
    925	cti_desc.groups = drvdata->ctidev.con_groups;
    926	cti_desc.dev = dev;
    927	drvdata->csdev = coresight_register(&cti_desc);
    928	if (IS_ERR(drvdata->csdev)) {
    929		ret = PTR_ERR(drvdata->csdev);
    930		goto pm_release;
    931	}
    932
    933	/* add to list of CTI devices */
    934	mutex_lock(&ect_mutex);
    935	list_add(&drvdata->node, &ect_net);
    936	/* set any cross references */
    937	cti_update_conn_xrefs(drvdata);
    938	mutex_unlock(&ect_mutex);
    939
    940	/* set up release chain */
    941	drvdata->csdev_release = drvdata->csdev->dev.release;
    942	drvdata->csdev->dev.release = cti_device_release;
    943
    944	/* all done - dec pm refcount */
    945	pm_runtime_put(&adev->dev);
    946	dev_info(&drvdata->csdev->dev, "CTI initialized\n");
    947	return 0;
    948
    949pm_release:
    950	cti_pm_release(drvdata);
    951	return ret;
    952}
    953
    954static struct amba_cs_uci_id uci_id_cti[] = {
    955	{
    956		/*  CTI UCI data */
    957		.devarch	= 0x47701a14, /* CTI v2 */
    958		.devarch_mask	= 0xfff0ffff,
    959		.devtype	= 0x00000014, /* maj(0x4-debug) min(0x1-ECT) */
    960	}
    961};
    962
    963static const struct amba_id cti_ids[] = {
    964	CS_AMBA_ID(0x000bb906), /* Coresight CTI (SoC 400), C-A72, C-A57 */
    965	CS_AMBA_ID(0x000bb922), /* CTI - C-A8 */
    966	CS_AMBA_ID(0x000bb9a8), /* CTI - C-A53 */
    967	CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */
    968	CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */
    969	CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */
    970	{ 0, 0},
    971};
    972
    973MODULE_DEVICE_TABLE(amba, cti_ids);
    974
    975static struct amba_driver cti_driver = {
    976	.drv = {
    977		.name	= "coresight-cti",
    978		.owner = THIS_MODULE,
    979		.suppress_bind_attrs = true,
    980	},
    981	.probe		= cti_probe,
    982	.remove		= cti_remove,
    983	.id_table	= cti_ids,
    984};
    985
    986static int __init cti_init(void)
    987{
    988	int ret;
    989
    990	ret = amba_driver_register(&cti_driver);
    991	if (ret)
    992		pr_info("Error registering cti driver\n");
    993	coresight_set_cti_ops(&cti_assoc_ops);
    994	return ret;
    995}
    996
    997static void __exit cti_exit(void)
    998{
    999	coresight_remove_cti_ops();
   1000	amba_driver_unregister(&cti_driver);
   1001}
   1002
   1003module_init(cti_init);
   1004module_exit(cti_exit);
   1005
   1006MODULE_AUTHOR("Mike Leach <mike.leach@linaro.org>");
   1007MODULE_DESCRIPTION("Arm CoreSight CTI Driver");
   1008MODULE_LICENSE("GPL v2");