All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mathieu Poirier <mathieu.poirier@linaro.org>
To: Mike Leach <mike.leach@linaro.org>
Cc: coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org,
	suzuki.poulose@arm.com, leo.yan@linaro.org
Subject: Re: [RFC PATCH 6/8] coresight: etm4x: syscfg: Add resource management to etm4x.
Date: Fri, 28 May 2021 10:17:04 -0600	[thread overview]
Message-ID: <20210528161704.GA1355502@xps15> (raw)
In-Reply-To: <20210512211752.4103-7-mike.leach@linaro.org>

On Wed, May 12, 2021 at 10:17:50PM +0100, Mike Leach wrote:
> Adds resource management to configuration and feature handling for ETM4
> using the system configuration resource management API.
> 
> Allows specification of ETM4 resources when creating configurations
> and features.
> 
> Adds in checking and validation of resources used by features to
> prevent over allocation when multiple features used in a configuration.
> 
> Signed-off-by: Mike Leach <mike.leach@linaro.org>
> ---
>  .../hwtracing/coresight/coresight-etm4x-cfg.c | 533 ++++++++++++++++++
>  .../hwtracing/coresight/coresight-etm4x-cfg.h | 196 ++++++-
>  include/linux/coresight.h                     |   2 +
>  3 files changed, 724 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index d2ea903231b2..ba6d20b58a9a 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -28,6 +28,11 @@
>  		} \
>  	}
>  
> +/* check for a match to ts rate */
> +static bool etm4_cfg_feat_is_ts_rate(const struct cscfg_feature_desc *feat_desc);
> +
> +#define TS_RATE_REG_VAL_IDX 0
> +
>  /**
>   * etm4_cfg_map_reg_offset - validate and map the register offset into a
>   *			     location in the driver config struct.
> @@ -128,6 +133,66 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
>  	return err;
>  }
>  
> +static void etm4_cfg_dump_res_mask(const char *name, struct etm4_cfg_resources *res)
> +{
> +	pr_debug("Mask %s\n", name);
> +	pr_debug("selectors %08x; addr_cmp %04x\n", res->selectors, res->addr_cmp);
> +	pr_debug("cid_cmp %02x; vmid_cmp %02x; counters %02x\n",  res->cid_cmp,
> +		 res->vmid_cmp, res->counters);
> +	pr_debug("misc bits %08x\n", res->misc);
> +}
> +
> +/*
> + * generate an address offset from a resource type and index
> + * Bit selected resources will return a ETM4_RES_OFFSET_SKIP value
> + * as these require special handling on enable / disable.
> + */
> +static u32 etm4_cfg_get_res_offset(u16 res_type, u32 res_idx)
> +{
> +	u32 offset = ETM4_RES_OFFSET_ERR;
> +
> +	switch (res_type & ETM4_CFG_RES_MASK) {
> +	case ETM4_CFG_RES_CTR:
> +		if (res_type & ETM4_CTR_VAL)
> +			offset = TRCCNTVRn(res_idx);
> +		else if (res_type & ETM4_CTR_RLD)
> +			offset = TRCCNTRLDVRn(res_idx);
> +		else if (res_type & ETM4_CTR_CTRL)
> +			offset = TRCCNTCTLRn(res_idx);
> +		break;
> +	case ETM4_CFG_RES_CMP:
> +		if (res_type & ETM4_CMP_VAL)
> +			offset = TRCACVRn(res_idx);
> +		else if (res_type & ETM4_CMP_CTL)
> +			offset = TRCACATRn(res_idx);
> +		break;
> +	case ETM4_CFG_RES_SEL:
> +		offset = TRCRSCTLRn(res_idx);
> +		break;
> +
> +	case ETM4_CFG_RES_SEQ:
> +		if (res_type & ETM4_SEQ_STATE_R)
> +			offset = TRCSEQEVRn(res_idx);
> +		else if (res_type & ETM4_SEQ_RESET_R)
> +			offset = TRCSEQRSTEVR;
> +		break;
> +	case ETM4_CFG_RES_CID_CMP:
> +		offset = TRCCIDCVRn(res_idx);
> +		break;
> +
> +	case ETM4_CFG_RES_VID_CMP:
> +		offset = TRCVMIDCVRn(res_idx);
> +		break;
> +
> +		/* these two have dedicated enable functions, no address needed */
> +	case ETM4_CFG_RES_BITCTRL:

        fallthrough;

> +	case ETM4_CFG_RES_TS:
> +		offset = ETM4_RES_OFFSET_SKIP;
> +		break;
> +	}
> +	return offset;
> +}
> +
>  /**
>   * etm4_cfg_load_feature - load a feature into a device instance.
>   *
> @@ -163,11 +228,349 @@ static int etm4_cfg_load_feature(struct coresight_device *csdev,
>  	/* process the register descriptions */
>  	for (i = 0; i < feat_csdev->nr_regs && !err; i++) {
>  		offset = feat_desc->regs_desc[i].offset;
> +
> +		/* resource needs conversion to a register access value */
> +		if (feat_desc->regs_desc[i].type & CS_CFG_REG_TYPE_RESOURCE) {
> +			offset = etm4_cfg_get_res_offset(feat_desc->regs_desc[i].hw_info,
> +							 offset);
> +			if (offset == ETM4_RES_OFFSET_ERR) {
> +				err = -ENODEV;
> +				break;
> +			} else if (offset == ETM4_RES_OFFSET_SKIP)
> +				continue;
> +		}
>  		err = etm4_cfg_map_reg_offset(drvdata, &feat_csdev->regs_csdev[i], offset);
>  	}
>  	return err;
>  }
>  
> +/*
> + * ts rate - set a counter to emit timestamp requests at a set interval.
> + *	if we have sufficient resources then we use a counter and resource
> + *	selector to achieve this.
> + *
> + *	However, if not then do the best possible - which prevents the perf
> + *	event timestamp request from failing if any configuration selection
> + *	is using resources. e.g. when profiling, timestamps do not really matter.

To me it seems like we are adding too much intelligence, but we can have this
conversation at a later time.

> + */
> +void etm4_cfg_set_ts_rate(struct coresight_device *csdev, u32 ts_rate_val)
> +{
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	struct etmv4_config *drvcfg = &drvdata->config;
> +	struct cscfg_res_impl_used *res_impl_used;
> +	int counter_idx, res_sel_idx;
> +	u32 tsctlr_val = 0;
> +
> +	res_impl_used = (struct cscfg_res_impl_used *)csdev->cscfg_res_mask;
> +
> +	/* look for resources */
> +	counter_idx = etm4_res_find_counter(res_impl_used);
> +	res_sel_idx = etm4_res_find_selector(res_impl_used);
> +	if (counter_idx >= 0 && res_sel_idx >= 0) {
> +		/* counter and selector - can set up ts rate normally */
> +		/*
> +		 * counter @ 1 and reload @ rate supplied -
> +		 * immediate timestamp then every rate
> +		 */
> +		drvcfg->cntr_val[counter_idx] = 1;
> +		drvcfg->cntrldvr[counter_idx] = ts_rate_val;
> +		/*
> +		 * counter ctrl - bit 16: 1 for reload self,
> +		 * bit 7: 0 single event,
> +		 * bit 6:0 res sel 1 - true
> +		 */
> +		drvcfg->cntr_ctrl[counter_idx] = 0x1 << 16 | 0x1;
> +
> +		/*
> +		 * set up resource selector for the counter.
> +		 * bits 19:16 - group 0b0010 counter
> +		 * bits 15:0 - bit select for counter idx
> +		 */
> +		drvcfg->res_ctrl[res_sel_idx] = (0x2 << 16) | (0x1 << counter_idx);
> +
> +		/* single selector bit 7 == 0, bit 6:0 - selector index */
> +		tsctlr_val = res_sel_idx;
> +
> +	} else if (ts_rate_val == 1) {
> +		/*
> +		 * perf always tries to use a min value -
> +		 * emulate by setting the ts event to true
> +		 */
> +		/* single selector bit 7 == 0, bit 6:0 - selector 1 - always true */
> +		tsctlr_val = 0x1;
> +	}
> +
> +	/* set the configr reg to enable TS, and the ts control reg */
> +	drvcfg->ts_ctrl = tsctlr_val;
> +	drvcfg->cfg |= BIT(11);
> +}
> +
> +/*
> + * on enable a feature - called after generic routine has programmed other registers.
> + * handle bit selects and custom elements
> + */
> +static int etm4_cfg_on_enable_feat(struct cscfg_feature_csdev *feat_csdev)
> +{
> +	int err = 0;
> +	struct etm4_cfg_resources *res_feat;
> +	struct device *dev = feat_csdev->csdev->dev.parent;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
> +	struct etmv4_config *drvcfg = &drvdata->config;
> +	u32 ts_rate_val;
> +
> +	/*
> +	 * look for the bit selected resources in this feature and set driver
> +	 * values to be programmed when enabling hardware.
> +	 */
> +	res_feat = (struct etm4_cfg_resources *)feat_csdev->res_used;
> +
> +	/* if none of the bit selected resources in use, exit early */
> +	if (!res_feat->misc)
> +		return 0;
> +
> +	/* otherwise check each and set as required */
> +	if (res_feat->ctxt_id)
> +		drvcfg->cfg |= BIT(6);
> +
> +	if (res_feat->vm_id)
> +		drvcfg->cfg |= BIT(7);
> +
> +	/* return stack is bit 12 in config register */
> +	if (res_feat->return_stack)
> +		drvcfg->cfg |= BIT(12);
> +
> +	/* branch broadcast - feature using this must program the bbctlr */
> +	if (res_feat->branch_broadcast)
> +		drvcfg->cfg |= BIT(3);
> +
> +	/* cycle count */
> +	if (res_feat->cycle_cnt) {
> +		drvcfg->cfg |= BIT(4);
> +		/* TRM: Must program this for cycacc to work - ensure mun permitted */
> +		if (drvcfg->ccctlr < drvdata->ccitmin)
> +			drvcfg->ccctlr = drvdata->ccitmin;
> +	}
> +
> +	/*
> +	 * timestamps - if not ts-rate just set to on, otherwise
> +	 * set using reload counter according to requested rate
> +	 */
> +	if (res_feat->timestamp) {
> +		/* the current feature is the ts-rate feature */
> +		if (res_feat->ts_rate) {
> +			ts_rate_val = feat_csdev->regs_csdev[TS_RATE_REG_VAL_IDX].reg_desc.val32;
> +			etm4_cfg_set_ts_rate(feat_csdev->csdev, ts_rate_val);

I would like to see a better way to do this.  Setting the timestamp rate
should be treated like any other feature.  If the current framework doesn't
allow for it then it should be extended.  

> +		} else
> +			drvcfg->cfg |= BIT(11);
> +	}
> +	return err;
> +}
> +
> +/* set the overall available resource masks for the device */
> +static int etm4_cfg_set_res_mask(struct coresight_device *csdev)
> +{
> +	struct device *dev = csdev->dev.parent;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
> +	struct etm4_cfg_resources *res;
> +	struct cscfg_res_impl_used *res_impl_used;
> +
> +	res_impl_used = devm_kzalloc(dev, sizeof(*res_impl_used), GFP_KERNEL);
> +	if (!res_impl_used)
> +		return -ENOMEM;
> +	res = &res_impl_used->impl;
> +
> +	/* selectors */
> +	if (drvdata->nr_resource)
> +		res->selectors = GENMASK((drvdata->nr_resource * 2) - 1, 0);
> +
> +	/* comparators */
> +	if (drvdata->nr_addr_cmp)
> +		res->addr_cmp = GENMASK(drvdata->nr_addr_cmp - 1, 0);
> +
> +	if (drvdata->numvmidc)
> +		res->vmid_cmp = GENMASK(drvdata->numvmidc - 1, 0);
> +
> +	if (drvdata->numcidc)
> +		res->cid_cmp = GENMASK(drvdata->numcidc - 1, 0);
> +
> +	/* misc resources */
> +	if (drvdata->nr_cntr)
> +		res->counters = GENMASK(drvdata->nr_cntr - 1, 0);
> +
> +	if (drvdata->trccci)
> +		res->cycle_cnt = 1;
> +
> +	if (drvdata->trcbb)
> +		res->branch_broadcast = 1;
> +
> +	if (drvdata->ctxid_size)
> +		res->ctxt_id = 1;
> +
> +	if (drvdata->vmid_size)
> +		res->vm_id = 1;
> +
> +	if (drvdata->nrseqstate)
> +		res->sequencer = 1;
> +
> +	if (drvdata->retstack)
> +		res->return_stack = 1;
> +
> +	if (drvdata->ts_size) {
> +		res->timestamp = 1;
> +		if (drvdata->nr_cntr && drvdata->nr_resource)
> +			res->ts_rate = 1;
> +	}
> +	etm4_cfg_dump_res_mask("device impl resources", &res_impl_used->impl);
> +	csdev->cscfg_res_mask = res_impl_used;
> +	return 0;
> +}
> +
> +/*
> + *  reads a descriptor and updates the resource mask structure
> + *  checks resource indexes are valid.
> + */
> +static int etm4_cfg_update_res_from_desc(const struct cscfg_feature_desc *feat_desc,
> +					 struct etm4_cfg_resources *res)
> +{
> +	struct cscfg_regval_desc *regs_desc = &feat_desc->regs_desc[0];
> +	u32 res_idx, hw_info;
> +	int i;
> +
> +	for (i = 0; i < feat_desc->nr_regs; i++) {
> +		if (regs_desc[i].type & CS_CFG_REG_TYPE_RESOURCE) {
> +			res_idx = regs_desc[i].offset;
> +			hw_info = regs_desc[i].hw_info;
> +			switch (hw_info & ETM4_CFG_RES_MASK) {
> +			case ETM4_CFG_RES_CTR:
> +				if (res_idx >= ETMv4_MAX_CNTR)
> +					goto invalid_resource_err;
> +				res->counters |= BIT(res_idx);
> +				break;
> +
> +			case ETM4_CFG_RES_CMP:
> +				if (res_idx >= ETM_MAX_SINGLE_ADDR_CMP)
> +					goto invalid_resource_err;
> +				res->addr_cmp |= BIT(res_idx);
> +				break;
> +
> +			case ETM4_CFG_RES_SEL:
> +				if (res_idx >= ETM_MAX_RES_SEL)
> +					goto invalid_resource_err;
> +				res->selectors |= BIT(res_idx);
> +				break;
> +
> +			case ETM4_CFG_RES_SEQ:
> +				res->sequencer = 1;
> +				break;
> +
> +			case ETM4_CFG_RES_TS:
> +				res->timestamp = 1;
> +				if (etm4_cfg_feat_is_ts_rate(feat_desc))
> +					res->ts_rate = 1;
> +				break;
> +
> +			case ETM4_CFG_RES_BITCTRL:
> +				if (hw_info & ETM4_BITCTRL_BRANCH_BROADCAST)
> +					res->branch_broadcast = 1;
> +				if (hw_info & ETM4_BITCTRL_CYCLE_COUNT)
> +					res->cycle_cnt = 1;
> +				if (hw_info & ETM4_BITCTRL_CTXTID)
> +					res->ctxt_id = 1;
> +				if (hw_info & ETM4_BITCTRL_VMID)
> +					res->vm_id = 1;
> +				if (hw_info & ETM4_BITCTRL_RETSTACK)
> +					res->return_stack = 1;
> +				break;
> +
> +			case ETM4_CFG_RES_CID_CMP:
> +				if (res_idx >= ETMv4_MAX_CTXID_CMP)
> +					goto invalid_resource_err;
> +				res->cid_cmp |= BIT(res_idx);
> +				break;
> +
> +			case ETM4_CFG_RES_VID_CMP:
> +				if (res_idx >= ETM_MAX_VMID_CMP)
> +					goto invalid_resource_err;
> +				res->vmid_cmp |= BIT(res_idx);
> +				break;
> +			}
> +		}
> +	}
> +	return 0;
> +
> +invalid_resource_err:
> +	pr_err("Error: Invalid resource values in feature %s\n", feat_desc->name);
> +	return -EINVAL;
> +}
> +/*
> + * Check that the device contains the minimum resources required to support the
> + * described @feat_desc. Return -ENODEV if missing required resources.
> + */
> +static int etm4_cfg_check_feat_res(struct coresight_device *csdev,
> +				   struct cscfg_feature_desc *feat_desc)
> +{
> +	struct etm4_cfg_resources req_res;
> +	struct cscfg_res_impl_used *dev_res;
> +	int err;
> +
> +	/* create a resource mask from descriptor and validate */
> +	memset(&req_res, 0, sizeof(req_res));
> +	err = etm4_cfg_update_res_from_desc(feat_desc, &req_res);
> +	etm4_cfg_dump_res_mask("check_feat_res", &req_res);
> +	if (!err) {
> +		dev_res = (struct cscfg_res_impl_used *)csdev->cscfg_res_mask;
> +		if (!etm4_cfg_check_impl(&dev_res->impl, &req_res))
> +			return -ENODEV;
> +	}
> +	return err;
> +}
> +
> +/*
> + * Allocate resource requirements for the feature before
> + * it is programmed into the system. Ensures that two or more features in a
> + * configuration do not try to use the same resources on the device.
> + *
> + * At this point we use the absolute programmed resources - we do not attempt
> + * to find alternate available resources. (e.g. if 2 features use selector 3,
> + * fail the 2nd feature - do not look for an alternative free selector).
> + */
> +static int etm4_cfg_alloc_feat_res(struct cscfg_feature_csdev *feat_csdev)
> +{
> +	struct coresight_device *csdev = feat_csdev->csdev;
> +	struct device *dev = csdev->dev.parent;
> +	struct etm4_cfg_resources *res_feat, *res_inuse;
> +	int err = 0;
> +
> +	/* one off initialisation of resources required for this feature */
> +	if (!feat_csdev->res_used) {
> +		res_feat = devm_kzalloc(dev, sizeof(*res_feat), GFP_KERNEL);
> +		if (!res_feat)
> +			return -ENOMEM;
> +		err = etm4_cfg_update_res_from_desc(feat_csdev->feat_desc, res_feat);
> +		if (err)
> +			return err;
> +		feat_csdev->res_used = res_feat;
> +	} else
> +		res_feat = (struct etm4_cfg_resources *)feat_csdev->res_used;
> +
> +	/* check that the device resources reqiured are not in use */
> +	res_inuse = &((struct cscfg_res_impl_used *)csdev->cscfg_res_mask)->used;
> +	if (!etm4_cfg_check_set_inuse(res_inuse, res_feat))
> +		err = -ENOSPC;
> +
> +	return err;
> +}
> +
> +static void etm4_cfg_clear_feat_res(struct cscfg_feature_csdev *feat_csdev)
> +{
> +	struct coresight_device *csdev = feat_csdev->csdev;
> +	struct etm4_cfg_resources *res_feat, *res_inuse;
> +
> +	res_feat = (struct etm4_cfg_resources *)feat_csdev->res_used;
> +	res_inuse = &((struct cscfg_res_impl_used *)csdev->cscfg_res_mask)->used;
> +	etm4_cfg_clear_inuse(res_inuse, res_feat);
> +}
> +
>  /* match information when loading configurations */
>  #define CS_CFG_ETM4_MATCH_FLAGS	(CS_CFG_MATCH_CLASS_SRC_ALL | \
>  				 CS_CFG_MATCH_CLASS_SRC_ETM4)
> @@ -175,8 +578,138 @@ static int etm4_cfg_load_feature(struct coresight_device *csdev,
>  int etm4_cscfg_register(struct coresight_device *csdev)
>  {
>  	struct cscfg_csdev_feat_ops ops;
> +	int err = 0;
> +
> +	err = etm4_cfg_set_res_mask(csdev);
> +	if (err)
> +		return err;
>  
>  	ops.load_feat = &etm4_cfg_load_feature;
> +	ops.check_feat_res = &etm4_cfg_check_feat_res;
> +	ops.alloc_feat_res = &etm4_cfg_alloc_feat_res;
> +	ops.clear_feat_res = &etm4_cfg_clear_feat_res;
> +	ops.set_on_enable = &etm4_cfg_on_enable_feat;
> +	ops.clear_on_disable = 0;
>  
>  	return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops);
>  }
> +
> +/*
> + * find first available bit in implemented mask @impl, that is not set in @used mask.
> + * set bit in @used and return. Return -ENOSPC if no available bits.
> + */
> +int etm4_cfg_find_unused_idx(unsigned long *impl, unsigned long *used, int size)
> +{
> +	unsigned long end_idx, unused_idx;
> +
> +	end_idx = find_first_zero_bit(impl, size);
> +	unused_idx = find_first_zero_bit(used, size);
> +	if (unused_idx < end_idx) {
> +		*used |= BIT(unused_idx);
> +		return (int)unused_idx;
> +	}
> +	return -ENOSPC;
> +}
> +
> +/*
> + * find first available pair of bits in implemented mask @impl, that are not set in
> + * @used mask. First bit of pair will always be an even index.
> + * Set bits in @used and return. Return -ENOSPC if no available bits.
> + */
> +int etm4_cfg_find_unused_idx_pair(unsigned long *impl, unsigned long *used, int size)
> +{
> +	unsigned long end_idx, first_unused_idx, next_unused_idx;
> +
> +	end_idx = find_first_zero_bit(impl, size);
> +	first_unused_idx = find_first_zero_bit(used, size);
> +
> +	/*
> +	 * even indexes are the 1st in a pair, look through the comparators
> +	 * till a pair found or we are at the end of the list.
> +	 */
> +	while (first_unused_idx < end_idx) {
> +		/* first is an even number, if the next is free we have a pair */
> +		if (!(first_unused_idx % 2)) {
> +			next_unused_idx = find_next_zero_bit(used, size, first_unused_idx);
> +			if (next_unused_idx == (first_unused_idx + 1)) {
> +				*used |= BIT(first_unused_idx);
> +				*used |= BIT(next_unused_idx);
> +				return (int)first_unused_idx;
> +			}
> +			first_unused_idx = next_unused_idx;
> +		} else
> +			first_unused_idx = find_next_zero_bit(used, size, first_unused_idx);
> +	}
> +	return -ENOSPC;
> +}
> +
> +
> +/* built in timestamp rate for etm4x */
> +static struct cscfg_parameter_desc ts_rate_param[] = {
> +	{
> +		.name = "ts_rate_cycles",
> +		.value = 100.
> +	},
> +};
> +
> +static struct cscfg_regval_desc ts_rate_regs[] = {
> +	{
> +		.type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM,
> +		.offset = 0,
> +		.hw_info = ETM4_CFG_RES_TS,
> +		.param_idx = 0,
> +	},
> +};
> +
> +static struct cscfg_feature_desc ts_rate_etm4x = {
> +	.name = "timestamp-rate",
> +	.description = "Enable timestamps and set rate they appear in the trace.\n"
> +	"Rate value is number of cycles between timestamp requests. Min value 1.\n",
> +	.match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4,
> +	.nr_params = ARRAY_SIZE(ts_rate_param),
> +	.params_desc = ts_rate_param,
> +	.nr_regs = ARRAY_SIZE(ts_rate_regs),
> +	.regs_desc = ts_rate_regs,
> +};

I vote for leaving the timestamp rate feature out of this set.  It is
introducing a fair amount of complexity to a patchset that is already complex.
When we move forward with it, it should be in its own file like we did for
autoFDO.

I am out of time for this set and as such will stop here.  We can tackle the
rest in future revisions.

Thanks,
Mathieu

> +
> +static struct cscfg_feature_desc *etm4x_feats[] = {
> +	&ts_rate_etm4x,
> +	NULL,
> +};
> +
> +static struct cscfg_config_desc *etm4x_cfgs[] = {
> +	NULL,
> +};
> +
> +static struct cscfg_load_owner_info etm4x_mod_owner = {
> +	.type = CSCFG_OWNER_MODULE,
> +	.owner_handle = THIS_MODULE,
> +};
> +
> +/*
> + * check if incoming feature is ts-rate
> + */
> +static bool etm4_cfg_feat_is_ts_rate(const struct cscfg_feature_desc *feat_desc)
> +{
> +	if (!strcmp(feat_desc->name, ts_rate_etm4x.name))
> +		return true;
> +	return false;
> +}
> +
> +/* load the etm4 builtin ts_rate feature into the system */
> +int etm4_cscfg_load_builtin_cfg(void)
> +{
> +	int err;
> +
> +	err = cscfg_load_config_sets(etm4x_cfgs, etm4x_feats, &etm4x_mod_owner);
> +
> +	/* if currently loaded matching devs ts_rate, still allow to load */
> +	if (err == -ENODEV)
> +		err = 0;
> +	return err;
> +}
> +
> +void etm4_cscfg_unload_builtin_cfg(void)
> +{
> +	cscfg_unload_config_sets(&etm4x_mod_owner);
> +}
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h
> index 32dab34c1dac..dd69a8ef522d 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h
> @@ -13,18 +13,200 @@
>  
>  /* resource IDs */
>  
> +/*
> + * 12 bit resource ID:
> + * 3:0 = resource type in use.
> + * 11:4 = additional resource specific information.
> + */
>  #define ETM4_CFG_RES_CTR	0x001
>  #define ETM4_CFG_RES_CMP	0x002
> -#define ETM4_CFG_RES_CMP_PAIR0	0x003
> -#define ETM4_CFG_RES_CMP_PAIR1	0x004
> -#define ETM4_CFG_RES_SEL	0x005
> -#define ETM4_CFG_RES_SEL_PAIR0	0x006
> -#define ETM4_CFG_RES_SEL_PAIR1	0x007
> -#define ETM4_CFG_RES_SEQ	0x008
> -#define ETM4_CFG_RES_TS		0x009
> +#define ETM4_CFG_RES_SEL	0x003
> +#define ETM4_CFG_RES_SEQ	0x004
> +#define ETM4_CFG_RES_TS		0x005
> +#define ETM4_CFG_RES_BITCTRL	0x006
> +#define ETM4_CFG_RES_CID_CMP	0x007
> +#define ETM4_CFG_RES_VID_CMP	0x008
>  #define ETM4_CFG_RES_MASK	0x00F
>  
> +/* additional bits to supplement _CFG_RES_CTR */
> +#define ETM4_CTR_VAL	0x010
> +#define ETM4_CTR_RLD	0x020
> +#define ETM4_CTR_CTRL	0x040
> +
> +/* additional bits for address comparators _CFG_RES_CMP */
> +#define ETM4_CMP_PAIR0	0x010
> +#define ETM4_CMP_PAIR1	0x020
> +#define ETM4_CMP_VAL	0x040
> +#define ETM4_CMP_CTL	0x080
> +
> +/* additional bits for resource selectors _CFG_RES_SEL */
> +#define ETM4_SEL_PAIR0	0x010
> +#define ETM4_SEL_PAIR1	0x020
> +
> +/* addtional bits for sequencer _CFG_RES_SEQ */
> +#define ETM4_SEQ_STATE_R	0x010
> +#define ETM4_SEQ_RESET_R        0x020
> +
> +/* additional bits to supplement _CFG_RES_BITCTRL */
> +#define ETM4_BITCTRL_BRANCH_BROADCAST	0x010
> +#define ETM4_BITCTRL_CYCLE_COUNT	0x020
> +#define ETM4_BITCTRL_CTXTID		0x040
> +#define ETM4_BITCTRL_VMID		0x080
> +#define ETM4_BITCTRL_RETSTACK		0x100
> +
> +/* error value when calculating resource register offset (max offset = 0xFFC) */
> +#define ETM4_RES_OFFSET_ERR	0xFFF
> +
> +/* skip value if a bit control that is resolved later */
> +#define ETM4_RES_OFFSET_SKIP	0xFFE
> +
> +/**
> + * Masks to indicate resource usage.
> + * @selectors: The resource selector regs - max 32 off
> + * @comparators: Comparators - address (16 max), context ID (8 max), VMID (8 max).
> + * @misc:-  bitselected features, sequencer etc.
> + */
> +struct etm4_cfg_resources {
> +	u32 selectors;
> +	u16 addr_cmp;
> +	u8 cid_cmp;
> +	u8 vmid_cmp;
> +	u8 counters;
> +	union {
> +		u32 misc;
> +		struct {
> +			u32 cycle_cnt:1;
> +			u32 branch_broadcast:1;
> +			u32 ctxt_id:1;
> +			u32 vm_id:1;
> +			u32 sequencer:1;
> +			u32 return_stack:1;
> +			u32 timestamp:1;
> +			u32 ts_rate:1;
> +		};
> +	};
> +};
> +
> +/* structure to hold implemented & used resources for the coresight device */
> +struct cscfg_res_impl_used {
> +	struct etm4_cfg_resources impl;
> +	struct etm4_cfg_resources used;
> +};
> +
> +/* resource mask tests */
> +/* check implmented - ensure that all bits in @req exist in @impl */
> +static inline bool etm4_cfg_check_impl(struct etm4_cfg_resources *impl,
> +				       struct etm4_cfg_resources *req)
> +{
> +	/* invert impl then and req - anything set is outside impl mask */
> +	if ((~impl->selectors & req->selectors) ||
> +	    (~impl->addr_cmp & req->addr_cmp) ||
> +	    (~impl->cid_cmp & req->cid_cmp) ||
> +	    (~impl->vmid_cmp & req->vmid_cmp) ||
> +	    (~impl->counters & req->counters) ||
> +	    (~impl->misc & req->misc))
> +		return false;
> +	return true;
> +}
> +
> +/* check @req not @inuse, & set @inuse if free (assumes @req passed the impl check) */
> +static inline bool etm4_cfg_check_set_inuse(struct etm4_cfg_resources *inuse,
> +					    struct etm4_cfg_resources *req)
> +{
> +	/* first check for hits between inuse and requested bits */
> +	if ((inuse->selectors & req->selectors) ||
> +	    (inuse->addr_cmp & req->addr_cmp) ||
> +	    (inuse->cid_cmp & req->cid_cmp) ||
> +	    (inuse->vmid_cmp & req->vmid_cmp) ||
> +	    (inuse->counters & req->counters) ||
> +	    (inuse->misc & req->misc))
> +		return false;
> +
> +	/* set all requested bits as inuse */
> +	inuse->selectors |= req->selectors;
> +	inuse->addr_cmp |= req->addr_cmp;
> +	inuse->cid_cmp |= req->cid_cmp;
> +	inuse->vmid_cmp |= req->vmid_cmp;
> +	inuse->counters |= req->counters;
> +	inuse->misc |= req->misc;
> +	return true;
> +}
> +
> +static inline void etm4_cfg_clear_inuse(struct etm4_cfg_resources *inuse,
> +					struct etm4_cfg_resources *req)
> +{
> +	/* clear requested bits from inuse */
> +	inuse->selectors &= ~req->selectors;
> +	inuse->addr_cmp &= ~req->addr_cmp;
> +	inuse->cid_cmp &= ~req->cid_cmp;
> +	inuse->vmid_cmp &= ~req->vmid_cmp;
> +	inuse->counters &= ~req->counters;
> +	inuse->misc &= ~req->misc;
> +}
> +
>  /* ETMv4 specific config functions */
>  int etm4_cscfg_register(struct coresight_device *csdev);
> +int etm4_cfg_find_unused_idx(unsigned long *impl, unsigned long *used, int size);
> +int etm4_cfg_find_unused_idx_pair(unsigned long *impl, unsigned long *used, int size);
> +void etm4_cfg_set_ts_rate(struct coresight_device *csdev, u32 ts_rate_val);
> +
> +/* register etm4x builtins with cscfg on module load */
> +int etm4_cscfg_load_builtin_cfg(void);
> +void etm4_cscfg_unload_builtin_cfg(void);
> +
> +/*
> + * Set of functions to find an available resource from @res->impl, not already marked as used
> + * in @res->used.
> + * return index and mark as used in @res->used. return -ENOSPC if nothing available.
> + */
> +
> +static inline int etm4_res_find_selector(struct cscfg_res_impl_used *res)
> +{
> +	unsigned long *impl, *used;
> +
> +	if (!res->impl.selectors)
> +		return -ENOSPC;
> +
> +	impl = (unsigned long *)&res->impl.selectors;
> +	used = (unsigned long *)&res->used.selectors;
> +	return etm4_cfg_find_unused_idx(impl, used, ETM_MAX_RES_SEL);
> +}
> +
> +static inline int etm4_res_find_counter(struct cscfg_res_impl_used *res)
> +{
> +	unsigned long *impl, *used;
> +
> +	if (!res->impl.counters)
> +		return -ENOSPC;
> +
> +	impl = (unsigned long *)&res->impl.counters;
> +	used = (unsigned long *)&res->used.counters;
> +	return etm4_cfg_find_unused_idx(impl, used, ETMv4_MAX_CNTR);
> +}
> +
> +static inline int etm4_res_find_addr_comparator(struct cscfg_res_impl_used *res)
> +{
> +	unsigned long *impl, *used;
> +
> +	if (!res->impl.addr_cmp)
> +		return -ENOSPC;
> +
> +	impl = (unsigned long *)&res->impl.addr_cmp;
> +	used = (unsigned long *)&res->used.addr_cmp;
> +	return etm4_cfg_find_unused_idx(impl, used, ETM_MAX_SINGLE_ADDR_CMP);
> +}
> +
> +
> +static inline int etm4_res_find_addr_comp_pair(struct cscfg_res_impl_used *res)
> +{
> +	unsigned long *impl, *used;
> +
> +	if (!res->impl.addr_cmp)
> +		return -ENOSPC;
> +
> +	impl = (unsigned long *)&res->impl.addr_cmp;
> +	used = (unsigned long *)&res->used.addr_cmp;
> +	return etm4_cfg_find_unused_idx_pair(impl, used, ETM_MAX_SINGLE_ADDR_CMP);
> +}
>  
>  #endif /* CORESIGHT_ETM4X_CFG_H */
> diff --git a/include/linux/coresight.h b/include/linux/coresight.h
> index a348049ee08b..b513964b9305 100644
> --- a/include/linux/coresight.h
> +++ b/include/linux/coresight.h
> @@ -223,6 +223,7 @@ struct coresight_sysfs_link {
>   * @feature_csdev_list: List of complex feature programming added to the device.
>   * @config_csdev_list:  List of system configurations added to the device.
>   * @active_cscfg_ctxt:  Context information for current active system configuration.
> + * @cscfg_res_mask:	Available device specific resources usable in features.
>   */
>  struct coresight_device {
>  	struct coresight_platform_data *pdata;
> @@ -248,6 +249,7 @@ struct coresight_device {
>  	struct list_head feature_csdev_list;
>  	struct list_head config_csdev_list;
>  	void *active_cscfg_ctxt;
> +	void *cscfg_res_mask;
>  };
>  
>  /*
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2021-05-28 16:18 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-12 21:17 [RFC PATCH 0/8] coresight: syscfg: dynamic load, resource management Mike Leach
2021-05-12 21:17 ` [RFC PATCH 1/8] coresight: syscfg: Update API to allow dynamic load and unload Mike Leach
2021-05-17 17:15   ` Mathieu Poirier
2021-05-17 17:27     ` Mathieu Poirier
2021-05-19 13:28       ` Mike Leach
2021-05-12 21:17 ` [RFC PATCH 2/8] coresight: syscfg: Update load API for config loadable modules Mike Leach
2021-05-17 17:38   ` Mathieu Poirier
2021-05-12 21:17 ` [RFC PATCH 3/8] coresight: syscfg: Example CoreSight configuration loadable module Mike Leach
2021-05-18 15:52   ` Mathieu Poirier
2021-05-18 16:38     ` Mike Leach
2021-05-18 21:15       ` Mathieu Poirier
2021-05-12 21:17 ` [RFC PATCH 4/8] coresight: configfs: Allow configfs to activate configuration Mike Leach
2021-05-18 19:36   ` Mathieu Poirier
2021-05-19  9:47     ` Mike Leach
2021-05-12 21:17 ` [RFC PATCH 5/8] coresight: syscfg: Add API to check and validate device resources Mike Leach
2021-05-21 17:56   ` Mathieu Poirier
2021-07-08 16:30     ` Mike Leach
2021-05-12 21:17 ` [RFC PATCH 6/8] coresight: etm4x: syscfg: Add resource management to etm4x Mike Leach
2021-05-26 17:51   ` Mathieu Poirier
2021-05-27 17:41   ` Mathieu Poirier
2021-05-28 16:17   ` Mathieu Poirier [this message]
2021-07-09  9:32     ` Mike Leach
2021-05-12 21:17 ` [RFC PATCH 7/8] coresight: etm4x: Update perf event resource handling Mike Leach
2021-05-12 21:17 ` [RFC PATCH 8/8] coresight: etm4x: Update configuration example Mike Leach
2021-05-13 15:56 ` [RFC PATCH 0/8] coresight: syscfg: dynamic load, resource management Mathieu Poirier
2021-05-13 16:53   ` Mike Leach
2021-05-14  1:35     ` Leo Yan
2021-05-18 18:31 ` Suzuki K Poulose
2021-05-19  9:43   ` Mike Leach
2021-05-19 15:37     ` Mathieu Poirier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210528161704.GA1355502@xps15 \
    --to=mathieu.poirier@linaro.org \
    --cc=coresight@lists.linaro.org \
    --cc=leo.yan@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=mike.leach@linaro.org \
    --cc=suzuki.poulose@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.