diff mbox series

[7/8] coresight: etm4x: Add missing single-shot control API to sysfs

Message ID 20190819205720.24457-8-mike.leach@linaro.org (mailing list archive)
State New, archived
Headers show
Series coresight: etm4x: Fixes and updates for sysfs API | expand

Commit Message

Mike Leach Aug. 19, 2019, 8:57 p.m. UTC
An API to control single-shot comparator operation was missing from sysfs.
This adds the parameters to sysfs to allow programming of this feature.

Signed-off-by: Mike Leach <mike.leach@linaro.org>
---
 .../coresight/coresight-etm4x-sysfs.c         | 122 ++++++++++++++++++
 drivers/hwtracing/coresight/coresight-etm4x.c |  26 +++-
 drivers/hwtracing/coresight/coresight-etm4x.h |   3 +
 3 files changed, 150 insertions(+), 1 deletion(-)

Comments

Mathieu Poirier Aug. 27, 2019, 10:27 p.m. UTC | #1
On Mon, Aug 19, 2019 at 09:57:19PM +0100, Mike Leach wrote:
> An API to control single-shot comparator operation was missing from sysfs.
> This adds the parameters to sysfs to allow programming of this feature.
> 
> Signed-off-by: Mike Leach <mike.leach@linaro.org>
> ---
>  .../coresight/coresight-etm4x-sysfs.c         | 122 ++++++++++++++++++
>  drivers/hwtracing/coresight/coresight-etm4x.c |  26 +++-
>  drivers/hwtracing/coresight/coresight-etm4x.h |   3 +
>  3 files changed, 150 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index 483976074779..7c019dda1236 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -239,6 +239,7 @@ static ssize_t reset_store(struct device *dev,
>  	for (i = 0; i < drvdata->nr_resource; i++)
>  		config->res_ctrl[i] = 0x0;
>  
> +	config->ss_idx = 0x0;
>  	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
>  		config->ss_ctrl[i] = 0x0;
>  		config->ss_pe_cmp[i] = 0x0;
> @@ -1713,6 +1714,123 @@ static ssize_t res_ctrl_store(struct device *dev,
>  }
>  static DEVICE_ATTR_RW(res_ctrl);
>  
> +static ssize_t sshot_idx_show(struct device *dev,
> +			      struct device_attribute *attr, char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	val = config->ss_idx;
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_idx_store(struct device *dev,
> +			       struct device_attribute *attr,
> +			       const char *buf, size_t size)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +	if (val >= drvdata->nr_ss_cmp)
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	config->ss_idx = val;
> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_idx);
> +
> +static ssize_t sshot_ctrl_show(struct device *dev,
> +			       struct device_attribute *attr,
> +			       char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_ctrl[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_ctrl_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	u8 idx;
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	idx = config->ss_idx;
> +	config->ss_ctrl[idx] = val & GENMASK(24, 0);
> +	/* must clear bit 31 in related status register on programming */
> +	config->ss_status[idx] &= ~BIT(31);
> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_ctrl);
> +
> +static ssize_t sshot_status_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_status[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +static DEVICE_ATTR_RO(sshot_status);
> +
> +static ssize_t sshot_pe_ctrl_show(struct device *dev,
> +				  struct device_attribute *attr,
> +				  char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_pe_cmp[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_pe_ctrl_store(struct device *dev,
> +				   struct device_attribute *attr,
> +				   const char *buf, size_t size)
> +{
> +	u8 idx;
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	idx = config->ss_idx;
> +	config->ss_ctrl[idx] = val & GENMASK(7, 0);

        config->ss_pe_cmp[idx] = val & GENMASK(7, 0);

> +	/* must clear bit 31 in related status register on programming */
> +	config->ss_status[idx] &= ~BIT(31);
> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_pe_ctrl);
> +
>  static ssize_t ctxid_idx_show(struct device *dev,
>  			      struct device_attribute *attr,
>  			      char *buf)
> @@ -2169,6 +2287,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
>  	&dev_attr_addr_exlevel_s_ns.attr,
>  	&dev_attr_addr_cmp_view.attr,
>  	&dev_attr_vinst_pe_cmp_start_stop.attr,
> +	&dev_attr_sshot_idx.attr,
> +	&dev_attr_sshot_ctrl.attr,
> +	&dev_attr_sshot_pe_ctrl.attr,
> +	&dev_attr_sshot_status.attr,
>  	&dev_attr_seq_idx.attr,
>  	&dev_attr_seq_state.attr,
>  	&dev_attr_seq_event.attr,
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> index d8b078d0cc7f..fb7083218410 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> @@ -149,6 +149,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
>  			       drvdata->base + TRCRSCTLRn(i));
>  
>  	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		/* always clear status bit on restart if using single-shot */
> +		if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> +			config->ss_status[i] &= ~BIT(31);
>  		writel_relaxed(config->ss_ctrl[i],
>  			       drvdata->base + TRCSSCCRn(i));
>  		writel_relaxed(config->ss_status[i],
> @@ -448,6 +451,9 @@ static void etm4_disable_hw(void *info)
>  {
>  	u32 control;
>  	struct etmv4_drvdata *drvdata = info;
> +	struct etmv4_config *config = &drvdata->config;
> +	struct device *etm_dev = &drvdata->csdev->dev;
> +	int i;
>  
>  	CS_UNLOCK(drvdata->base);
>  
> @@ -470,6 +476,18 @@ static void etm4_disable_hw(void *info)
>  	isb();
>  	writel_relaxed(control, drvdata->base + TRCPRGCTLR);
>  
> +	/* wait for TRCSTATR.PMSTABLE to go to '1' */
> +	if (coresight_timeout(drvdata->base, TRCSTATR,
> +			      TRCSTATR_PMSTABLE_BIT, 1))
> +		dev_err(etm_dev,
> +			"timeout while waiting for PM stable Trace Status\n");
> +
> +	/* read the status of the single shot comparators */
> +	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		config->ss_status[i] =
> +			readl_relaxed(drvdata->base + TRCSSCSRn(i));
> +	}
> +
>  	coresight_disclaim_device_unlocked(drvdata->base);
>  
>  	CS_LOCK(drvdata->base);
> @@ -576,6 +594,7 @@ static void etm4_init_arch_data(void *info)
>  	u32 etmidr4;
>  	u32 etmidr5;
>  	struct etmv4_drvdata *drvdata = info;
> +	int i;
>  
>  	/* Make sure all registers are accessible */
>  	etm4_os_unlock(drvdata);
> @@ -699,9 +718,14 @@ static void etm4_init_arch_data(void *info)
>  	drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
>  	/*
>  	 * NUMSSCC, bits[23:20] the number of single-shot
> -	 * comparator control for tracing
> +	 * comparator control for tracing. Read any status regs as these
> +	 * also contain RO capability data.
>  	 */
>  	drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
> +	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		drvdata->config.ss_status[i] =
> +			readl_relaxed(drvdata->base + TRCSSCSRn(i));
> +	}
>  	/* 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 */
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 60bc2fb5159b..be8b32ea1654 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -175,6 +175,7 @@
>  					 ETM_MODE_EXCL_USER)
>  
>  #define TRCSTATR_IDLE_BIT		0
> +#define TRCSTATR_PMSTABLE_BIT		1
>  #define ETM_DEFAULT_ADDR_COMP		0
>  
>  /* PowerDown Control Register bits */
> @@ -226,6 +227,7 @@
>   * @cntr_val:	Sets or returns the value for a counter.
>   * @res_idx:	Resource index selector.
>   * @res_ctrl:	Controls the selection of the resources in the trace unit.
> + * @ss_idx:	Single-shot index selector.
>   * @ss_ctrl:	Controls the corresponding single-shot comparator resource.
>   * @ss_status:	The status of the corresponding single-shot comparator.
>   * @ss_pe_cmp:	Selects the PE comparator inputs for Single-shot control.
> @@ -269,6 +271,7 @@ struct etmv4_config {
>  	u32				cntr_val[ETMv4_MAX_CNTR];
>  	u8				res_idx;
>  	u32				res_ctrl[ETM_MAX_RES_SEL];
> +	u8				ss_idx;
>  	u32				ss_ctrl[ETM_MAX_SS_CMP];
>  	u32				ss_status[ETM_MAX_SS_CMP];
>  	u32				ss_pe_cmp[ETM_MAX_SS_CMP];
> -- 
> 2.17.1
>
Leo Yan Aug. 28, 2019, 5:18 a.m. UTC | #2
On Mon, Aug 19, 2019 at 09:57:19PM +0100, Mike Leach wrote:
> An API to control single-shot comparator operation was missing from sysfs.
> This adds the parameters to sysfs to allow programming of this feature.
> 
> Signed-off-by: Mike Leach <mike.leach@linaro.org>
> ---
>  .../coresight/coresight-etm4x-sysfs.c         | 122 ++++++++++++++++++
>  drivers/hwtracing/coresight/coresight-etm4x.c |  26 +++-
>  drivers/hwtracing/coresight/coresight-etm4x.h |   3 +
>  3 files changed, 150 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index 483976074779..7c019dda1236 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -239,6 +239,7 @@ static ssize_t reset_store(struct device *dev,
>  	for (i = 0; i < drvdata->nr_resource; i++)
>  		config->res_ctrl[i] = 0x0;
>  
> +	config->ss_idx = 0x0;
>  	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
>  		config->ss_ctrl[i] = 0x0;
>  		config->ss_pe_cmp[i] = 0x0;
> @@ -1713,6 +1714,123 @@ static ssize_t res_ctrl_store(struct device *dev,
>  }
>  static DEVICE_ATTR_RW(res_ctrl);
>  
> +static ssize_t sshot_idx_show(struct device *dev,
> +			      struct device_attribute *attr, char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	val = config->ss_idx;
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_idx_store(struct device *dev,
> +			       struct device_attribute *attr,
> +			       const char *buf, size_t size)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +	if (val >= drvdata->nr_ss_cmp)
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	config->ss_idx = val;
> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_idx);
> +
> +static ssize_t sshot_ctrl_show(struct device *dev,
> +			       struct device_attribute *attr,
> +			       char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_ctrl[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_ctrl_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	u8 idx;
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	idx = config->ss_idx;
> +	config->ss_ctrl[idx] = val & GENMASK(24, 0);
> +	/* must clear bit 31 in related status register on programming */
> +	config->ss_status[idx] &= ~BIT(31);

Since function etm4_enable_hw() will clear ss_status's bit 31 when
program TRCSSCSRn, so is here redundant to clear bit 31?

> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_ctrl);
> +
> +static ssize_t sshot_status_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_status[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +static DEVICE_ATTR_RO(sshot_status);
> +
> +static ssize_t sshot_pe_ctrl_show(struct device *dev,
> +				  struct device_attribute *attr,
> +				  char *buf)
> +{
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	spin_lock(&drvdata->spinlock);
> +	val = config->ss_pe_cmp[config->ss_idx];
> +	spin_unlock(&drvdata->spinlock);
> +	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> +}
> +
> +static ssize_t sshot_pe_ctrl_store(struct device *dev,
> +				   struct device_attribute *attr,
> +				   const char *buf, size_t size)
> +{
> +	u8 idx;
> +	unsigned long val;
> +	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	struct etmv4_config *config = &drvdata->config;
> +
> +	if (kstrtoul(buf, 16, &val))
> +		return -EINVAL;
> +
> +	spin_lock(&drvdata->spinlock);
> +	idx = config->ss_idx;
> +	config->ss_ctrl[idx] = val & GENMASK(7, 0);
> +	/* must clear bit 31 in related status register on programming */
> +	config->ss_status[idx] &= ~BIT(31);

Same question for if it's redundant to clear bit 31?

Thanks,
Leo Yan

> +	spin_unlock(&drvdata->spinlock);
> +	return size;
> +}
> +static DEVICE_ATTR_RW(sshot_pe_ctrl);
> +
>  static ssize_t ctxid_idx_show(struct device *dev,
>  			      struct device_attribute *attr,
>  			      char *buf)
> @@ -2169,6 +2287,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
>  	&dev_attr_addr_exlevel_s_ns.attr,
>  	&dev_attr_addr_cmp_view.attr,
>  	&dev_attr_vinst_pe_cmp_start_stop.attr,
> +	&dev_attr_sshot_idx.attr,
> +	&dev_attr_sshot_ctrl.attr,
> +	&dev_attr_sshot_pe_ctrl.attr,
> +	&dev_attr_sshot_status.attr,
>  	&dev_attr_seq_idx.attr,
>  	&dev_attr_seq_state.attr,
>  	&dev_attr_seq_event.attr,
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> index d8b078d0cc7f..fb7083218410 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> @@ -149,6 +149,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
>  			       drvdata->base + TRCRSCTLRn(i));
>  
>  	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		/* always clear status bit on restart if using single-shot */
> +		if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> +			config->ss_status[i] &= ~BIT(31);
>  		writel_relaxed(config->ss_ctrl[i],
>  			       drvdata->base + TRCSSCCRn(i));
>  		writel_relaxed(config->ss_status[i],
> @@ -448,6 +451,9 @@ static void etm4_disable_hw(void *info)
>  {
>  	u32 control;
>  	struct etmv4_drvdata *drvdata = info;
> +	struct etmv4_config *config = &drvdata->config;
> +	struct device *etm_dev = &drvdata->csdev->dev;
> +	int i;
>  
>  	CS_UNLOCK(drvdata->base);
>  
> @@ -470,6 +476,18 @@ static void etm4_disable_hw(void *info)
>  	isb();
>  	writel_relaxed(control, drvdata->base + TRCPRGCTLR);
>  
> +	/* wait for TRCSTATR.PMSTABLE to go to '1' */
> +	if (coresight_timeout(drvdata->base, TRCSTATR,
> +			      TRCSTATR_PMSTABLE_BIT, 1))
> +		dev_err(etm_dev,
> +			"timeout while waiting for PM stable Trace Status\n");
> +
> +	/* read the status of the single shot comparators */
> +	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		config->ss_status[i] =
> +			readl_relaxed(drvdata->base + TRCSSCSRn(i));
> +	}
> +
>  	coresight_disclaim_device_unlocked(drvdata->base);
>  
>  	CS_LOCK(drvdata->base);
> @@ -576,6 +594,7 @@ static void etm4_init_arch_data(void *info)
>  	u32 etmidr4;
>  	u32 etmidr5;
>  	struct etmv4_drvdata *drvdata = info;
> +	int i;
>  
>  	/* Make sure all registers are accessible */
>  	etm4_os_unlock(drvdata);
> @@ -699,9 +718,14 @@ static void etm4_init_arch_data(void *info)
>  	drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
>  	/*
>  	 * NUMSSCC, bits[23:20] the number of single-shot
> -	 * comparator control for tracing
> +	 * comparator control for tracing. Read any status regs as these
> +	 * also contain RO capability data.
>  	 */
>  	drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
> +	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> +		drvdata->config.ss_status[i] =
> +			readl_relaxed(drvdata->base + TRCSSCSRn(i));
> +	}
>  	/* 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 */
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 60bc2fb5159b..be8b32ea1654 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -175,6 +175,7 @@
>  					 ETM_MODE_EXCL_USER)
>  
>  #define TRCSTATR_IDLE_BIT		0
> +#define TRCSTATR_PMSTABLE_BIT		1
>  #define ETM_DEFAULT_ADDR_COMP		0
>  
>  /* PowerDown Control Register bits */
> @@ -226,6 +227,7 @@
>   * @cntr_val:	Sets or returns the value for a counter.
>   * @res_idx:	Resource index selector.
>   * @res_ctrl:	Controls the selection of the resources in the trace unit.
> + * @ss_idx:	Single-shot index selector.
>   * @ss_ctrl:	Controls the corresponding single-shot comparator resource.
>   * @ss_status:	The status of the corresponding single-shot comparator.
>   * @ss_pe_cmp:	Selects the PE comparator inputs for Single-shot control.
> @@ -269,6 +271,7 @@ struct etmv4_config {
>  	u32				cntr_val[ETMv4_MAX_CNTR];
>  	u8				res_idx;
>  	u32				res_ctrl[ETM_MAX_RES_SEL];
> +	u8				ss_idx;
>  	u32				ss_ctrl[ETM_MAX_SS_CMP];
>  	u32				ss_status[ETM_MAX_SS_CMP];
>  	u32				ss_pe_cmp[ETM_MAX_SS_CMP];
> -- 
> 2.17.1
> 
> _______________________________________________
> CoreSight mailing list
> CoreSight@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/coresight
Mike Leach Aug. 28, 2019, 2:15 p.m. UTC | #3
HI Leo,

On Wed, 28 Aug 2019 at 06:18, Leo Yan <leo.yan@linaro.org> wrote:
>
> On Mon, Aug 19, 2019 at 09:57:19PM +0100, Mike Leach wrote:
> > An API to control single-shot comparator operation was missing from sysfs.
> > This adds the parameters to sysfs to allow programming of this feature.
> >
> > Signed-off-by: Mike Leach <mike.leach@linaro.org>
> > ---
> >  .../coresight/coresight-etm4x-sysfs.c         | 122 ++++++++++++++++++
> >  drivers/hwtracing/coresight/coresight-etm4x.c |  26 +++-
> >  drivers/hwtracing/coresight/coresight-etm4x.h |   3 +
> >  3 files changed, 150 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > index 483976074779..7c019dda1236 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > @@ -239,6 +239,7 @@ static ssize_t reset_store(struct device *dev,
> >       for (i = 0; i < drvdata->nr_resource; i++)
> >               config->res_ctrl[i] = 0x0;
> >
> > +     config->ss_idx = 0x0;
> >       for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> >               config->ss_ctrl[i] = 0x0;
> >               config->ss_pe_cmp[i] = 0x0;
> > @@ -1713,6 +1714,123 @@ static ssize_t res_ctrl_store(struct device *dev,
> >  }
> >  static DEVICE_ATTR_RW(res_ctrl);
> >
> > +static ssize_t sshot_idx_show(struct device *dev,
> > +                           struct device_attribute *attr, char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     val = config->ss_idx;
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_idx_store(struct device *dev,
> > +                            struct device_attribute *attr,
> > +                            const char *buf, size_t size)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +     if (val >= drvdata->nr_ss_cmp)
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     config->ss_idx = val;
> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_idx);
> > +
> > +static ssize_t sshot_ctrl_show(struct device *dev,
> > +                            struct device_attribute *attr,
> > +                            char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_ctrl[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_ctrl_store(struct device *dev,
> > +                             struct device_attribute *attr,
> > +                             const char *buf, size_t size)
> > +{
> > +     u8 idx;
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     idx = config->ss_idx;
> > +     config->ss_ctrl[idx] = val & GENMASK(24, 0);
> > +     /* must clear bit 31 in related status register on programming */
> > +     config->ss_status[idx] &= ~BIT(31);
>
> Since function etm4_enable_hw() will clear ss_status's bit 31 when
> program TRCSSCSRn, so is here redundant to clear bit 31?
>
> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_ctrl);
> > +
> > +static ssize_t sshot_status_show(struct device *dev,
> > +                              struct device_attribute *attr, char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_status[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +static DEVICE_ATTR_RO(sshot_status);
> > +
> > +static ssize_t sshot_pe_ctrl_show(struct device *dev,
> > +                               struct device_attribute *attr,
> > +                               char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_pe_cmp[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_pe_ctrl_store(struct device *dev,
> > +                                struct device_attribute *attr,
> > +                                const char *buf, size_t size)
> > +{
> > +     u8 idx;
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     idx = config->ss_idx;
> > +     config->ss_ctrl[idx] = val & GENMASK(7, 0);
> > +     /* must clear bit 31 in related status register on programming */
> > +     config->ss_status[idx] &= ~BIT(31);
>
> Same question for if it's redundant to clear bit 31?
>
> Thanks,
> Leo Yan
>

The sysfs representation is not the current state of these registers,
but the values that will be programmed on enabling the hardware. We do
not write anything to hardware immediately.
So from a sysfs perspective, the bit clear is reflected in the status
register here to recognise that it will be programmed as cleared.

Should the same registers be set from a different path - e.g. perf,
then the status will automatically be cleared each time the hw is
enabled.

Regards

Mike




> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_pe_ctrl);
> > +
> >  static ssize_t ctxid_idx_show(struct device *dev,
> >                             struct device_attribute *attr,
> >                             char *buf)
> > @@ -2169,6 +2287,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
> >       &dev_attr_addr_exlevel_s_ns.attr,
> >       &dev_attr_addr_cmp_view.attr,
> >       &dev_attr_vinst_pe_cmp_start_stop.attr,
> > +     &dev_attr_sshot_idx.attr,
> > +     &dev_attr_sshot_ctrl.attr,
> > +     &dev_attr_sshot_pe_ctrl.attr,
> > +     &dev_attr_sshot_status.attr,
> >       &dev_attr_seq_idx.attr,
> >       &dev_attr_seq_state.attr,
> >       &dev_attr_seq_event.attr,
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> > index d8b078d0cc7f..fb7083218410 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> > @@ -149,6 +149,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> >                              drvdata->base + TRCRSCTLRn(i));
> >
> >       for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             /* always clear status bit on restart if using single-shot */
> > +             if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> > +                     config->ss_status[i] &= ~BIT(31);
> >               writel_relaxed(config->ss_ctrl[i],
> >                              drvdata->base + TRCSSCCRn(i));
> >               writel_relaxed(config->ss_status[i],
> > @@ -448,6 +451,9 @@ static void etm4_disable_hw(void *info)
> >  {
> >       u32 control;
> >       struct etmv4_drvdata *drvdata = info;
> > +     struct etmv4_config *config = &drvdata->config;
> > +     struct device *etm_dev = &drvdata->csdev->dev;
> > +     int i;
> >
> >       CS_UNLOCK(drvdata->base);
> >
> > @@ -470,6 +476,18 @@ static void etm4_disable_hw(void *info)
> >       isb();
> >       writel_relaxed(control, drvdata->base + TRCPRGCTLR);
> >
> > +     /* wait for TRCSTATR.PMSTABLE to go to '1' */
> > +     if (coresight_timeout(drvdata->base, TRCSTATR,
> > +                           TRCSTATR_PMSTABLE_BIT, 1))
> > +             dev_err(etm_dev,
> > +                     "timeout while waiting for PM stable Trace Status\n");
> > +
> > +     /* read the status of the single shot comparators */
> > +     for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             config->ss_status[i] =
> > +                     readl_relaxed(drvdata->base + TRCSSCSRn(i));
> > +     }
> > +
> >       coresight_disclaim_device_unlocked(drvdata->base);
> >
> >       CS_LOCK(drvdata->base);
> > @@ -576,6 +594,7 @@ static void etm4_init_arch_data(void *info)
> >       u32 etmidr4;
> >       u32 etmidr5;
> >       struct etmv4_drvdata *drvdata = info;
> > +     int i;
> >
> >       /* Make sure all registers are accessible */
> >       etm4_os_unlock(drvdata);
> > @@ -699,9 +718,14 @@ static void etm4_init_arch_data(void *info)
> >       drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
> >       /*
> >        * NUMSSCC, bits[23:20] the number of single-shot
> > -      * comparator control for tracing
> > +      * comparator control for tracing. Read any status regs as these
> > +      * also contain RO capability data.
> >        */
> >       drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
> > +     for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             drvdata->config.ss_status[i] =
> > +                     readl_relaxed(drvdata->base + TRCSSCSRn(i));
> > +     }
> >       /* 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 */
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> > index 60bc2fb5159b..be8b32ea1654 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> > @@ -175,6 +175,7 @@
> >                                        ETM_MODE_EXCL_USER)
> >
> >  #define TRCSTATR_IDLE_BIT            0
> > +#define TRCSTATR_PMSTABLE_BIT                1
> >  #define ETM_DEFAULT_ADDR_COMP                0
> >
> >  /* PowerDown Control Register bits */
> > @@ -226,6 +227,7 @@
> >   * @cntr_val:        Sets or returns the value for a counter.
> >   * @res_idx: Resource index selector.
> >   * @res_ctrl:        Controls the selection of the resources in the trace unit.
> > + * @ss_idx:  Single-shot index selector.
> >   * @ss_ctrl: Controls the corresponding single-shot comparator resource.
> >   * @ss_status:       The status of the corresponding single-shot comparator.
> >   * @ss_pe_cmp:       Selects the PE comparator inputs for Single-shot control.
> > @@ -269,6 +271,7 @@ struct etmv4_config {
> >       u32                             cntr_val[ETMv4_MAX_CNTR];
> >       u8                              res_idx;
> >       u32                             res_ctrl[ETM_MAX_RES_SEL];
> > +     u8                              ss_idx;
> >       u32                             ss_ctrl[ETM_MAX_SS_CMP];
> >       u32                             ss_status[ETM_MAX_SS_CMP];
> >       u32                             ss_pe_cmp[ETM_MAX_SS_CMP];
> > --
> > 2.17.1
> >
> > _______________________________________________
> > CoreSight mailing list
> > CoreSight@lists.linaro.org
> > https://lists.linaro.org/mailman/listinfo/coresight
Mike Leach Aug. 28, 2019, 2:15 p.m. UTC | #4
Hi,

On Tue, 27 Aug 2019 at 23:27, Mathieu Poirier
<mathieu.poirier@linaro.org> wrote:
>
> On Mon, Aug 19, 2019 at 09:57:19PM +0100, Mike Leach wrote:
> > An API to control single-shot comparator operation was missing from sysfs.
> > This adds the parameters to sysfs to allow programming of this feature.
> >
> > Signed-off-by: Mike Leach <mike.leach@linaro.org>
> > ---
> >  .../coresight/coresight-etm4x-sysfs.c         | 122 ++++++++++++++++++
> >  drivers/hwtracing/coresight/coresight-etm4x.c |  26 +++-
> >  drivers/hwtracing/coresight/coresight-etm4x.h |   3 +
> >  3 files changed, 150 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > index 483976074779..7c019dda1236 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > @@ -239,6 +239,7 @@ static ssize_t reset_store(struct device *dev,
> >       for (i = 0; i < drvdata->nr_resource; i++)
> >               config->res_ctrl[i] = 0x0;
> >
> > +     config->ss_idx = 0x0;
> >       for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> >               config->ss_ctrl[i] = 0x0;
> >               config->ss_pe_cmp[i] = 0x0;
> > @@ -1713,6 +1714,123 @@ static ssize_t res_ctrl_store(struct device *dev,
> >  }
> >  static DEVICE_ATTR_RW(res_ctrl);
> >
> > +static ssize_t sshot_idx_show(struct device *dev,
> > +                           struct device_attribute *attr, char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     val = config->ss_idx;
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_idx_store(struct device *dev,
> > +                            struct device_attribute *attr,
> > +                            const char *buf, size_t size)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +     if (val >= drvdata->nr_ss_cmp)
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     config->ss_idx = val;
> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_idx);
> > +
> > +static ssize_t sshot_ctrl_show(struct device *dev,
> > +                            struct device_attribute *attr,
> > +                            char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_ctrl[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_ctrl_store(struct device *dev,
> > +                             struct device_attribute *attr,
> > +                             const char *buf, size_t size)
> > +{
> > +     u8 idx;
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     idx = config->ss_idx;
> > +     config->ss_ctrl[idx] = val & GENMASK(24, 0);
> > +     /* must clear bit 31 in related status register on programming */
> > +     config->ss_status[idx] &= ~BIT(31);
> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_ctrl);
> > +
> > +static ssize_t sshot_status_show(struct device *dev,
> > +                              struct device_attribute *attr, char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_status[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +static DEVICE_ATTR_RO(sshot_status);
> > +
> > +static ssize_t sshot_pe_ctrl_show(struct device *dev,
> > +                               struct device_attribute *attr,
> > +                               char *buf)
> > +{
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     val = config->ss_pe_cmp[config->ss_idx];
> > +     spin_unlock(&drvdata->spinlock);
> > +     return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > +}
> > +
> > +static ssize_t sshot_pe_ctrl_store(struct device *dev,
> > +                                struct device_attribute *attr,
> > +                                const char *buf, size_t size)
> > +{
> > +     u8 idx;
> > +     unsigned long val;
> > +     struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > +     struct etmv4_config *config = &drvdata->config;
> > +
> > +     if (kstrtoul(buf, 16, &val))
> > +             return -EINVAL;
> > +
> > +     spin_lock(&drvdata->spinlock);
> > +     idx = config->ss_idx;
> > +     config->ss_ctrl[idx] = val & GENMASK(7, 0);
>
>         config->ss_pe_cmp[idx] = val & GENMASK(7, 0);
>

Good spot, Thanks

Mike


> > +     /* must clear bit 31 in related status register on programming */
> > +     config->ss_status[idx] &= ~BIT(31);
> > +     spin_unlock(&drvdata->spinlock);
> > +     return size;
> > +}
> > +static DEVICE_ATTR_RW(sshot_pe_ctrl);
> > +
> >  static ssize_t ctxid_idx_show(struct device *dev,
> >                             struct device_attribute *attr,
> >                             char *buf)
> > @@ -2169,6 +2287,10 @@ static struct attribute *coresight_etmv4_attrs[] = {
> >       &dev_attr_addr_exlevel_s_ns.attr,
> >       &dev_attr_addr_cmp_view.attr,
> >       &dev_attr_vinst_pe_cmp_start_stop.attr,
> > +     &dev_attr_sshot_idx.attr,
> > +     &dev_attr_sshot_ctrl.attr,
> > +     &dev_attr_sshot_pe_ctrl.attr,
> > +     &dev_attr_sshot_status.attr,
> >       &dev_attr_seq_idx.attr,
> >       &dev_attr_seq_state.attr,
> >       &dev_attr_seq_event.attr,
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
> > index d8b078d0cc7f..fb7083218410 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.c
> > @@ -149,6 +149,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> >                              drvdata->base + TRCRSCTLRn(i));
> >
> >       for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             /* always clear status bit on restart if using single-shot */
> > +             if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> > +                     config->ss_status[i] &= ~BIT(31);
> >               writel_relaxed(config->ss_ctrl[i],
> >                              drvdata->base + TRCSSCCRn(i));
> >               writel_relaxed(config->ss_status[i],
> > @@ -448,6 +451,9 @@ static void etm4_disable_hw(void *info)
> >  {
> >       u32 control;
> >       struct etmv4_drvdata *drvdata = info;
> > +     struct etmv4_config *config = &drvdata->config;
> > +     struct device *etm_dev = &drvdata->csdev->dev;
> > +     int i;
> >
> >       CS_UNLOCK(drvdata->base);
> >
> > @@ -470,6 +476,18 @@ static void etm4_disable_hw(void *info)
> >       isb();
> >       writel_relaxed(control, drvdata->base + TRCPRGCTLR);
> >
> > +     /* wait for TRCSTATR.PMSTABLE to go to '1' */
> > +     if (coresight_timeout(drvdata->base, TRCSTATR,
> > +                           TRCSTATR_PMSTABLE_BIT, 1))
> > +             dev_err(etm_dev,
> > +                     "timeout while waiting for PM stable Trace Status\n");
> > +
> > +     /* read the status of the single shot comparators */
> > +     for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             config->ss_status[i] =
> > +                     readl_relaxed(drvdata->base + TRCSSCSRn(i));
> > +     }
> > +
> >       coresight_disclaim_device_unlocked(drvdata->base);
> >
> >       CS_LOCK(drvdata->base);
> > @@ -576,6 +594,7 @@ static void etm4_init_arch_data(void *info)
> >       u32 etmidr4;
> >       u32 etmidr5;
> >       struct etmv4_drvdata *drvdata = info;
> > +     int i;
> >
> >       /* Make sure all registers are accessible */
> >       etm4_os_unlock(drvdata);
> > @@ -699,9 +718,14 @@ static void etm4_init_arch_data(void *info)
> >       drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
> >       /*
> >        * NUMSSCC, bits[23:20] the number of single-shot
> > -      * comparator control for tracing
> > +      * comparator control for tracing. Read any status regs as these
> > +      * also contain RO capability data.
> >        */
> >       drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
> > +     for (i = 0; i < drvdata->nr_ss_cmp; i++) {
> > +             drvdata->config.ss_status[i] =
> > +                     readl_relaxed(drvdata->base + TRCSSCSRn(i));
> > +     }
> >       /* 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 */
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> > index 60bc2fb5159b..be8b32ea1654 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> > @@ -175,6 +175,7 @@
> >                                        ETM_MODE_EXCL_USER)
> >
> >  #define TRCSTATR_IDLE_BIT            0
> > +#define TRCSTATR_PMSTABLE_BIT                1
> >  #define ETM_DEFAULT_ADDR_COMP                0
> >
> >  /* PowerDown Control Register bits */
> > @@ -226,6 +227,7 @@
> >   * @cntr_val:        Sets or returns the value for a counter.
> >   * @res_idx: Resource index selector.
> >   * @res_ctrl:        Controls the selection of the resources in the trace unit.
> > + * @ss_idx:  Single-shot index selector.
> >   * @ss_ctrl: Controls the corresponding single-shot comparator resource.
> >   * @ss_status:       The status of the corresponding single-shot comparator.
> >   * @ss_pe_cmp:       Selects the PE comparator inputs for Single-shot control.
> > @@ -269,6 +271,7 @@ struct etmv4_config {
> >       u32                             cntr_val[ETMv4_MAX_CNTR];
> >       u8                              res_idx;
> >       u32                             res_ctrl[ETM_MAX_RES_SEL];
> > +     u8                              ss_idx;
> >       u32                             ss_ctrl[ETM_MAX_SS_CMP];
> >       u32                             ss_status[ETM_MAX_SS_CMP];
> >       u32                             ss_pe_cmp[ETM_MAX_SS_CMP];
> > --
> > 2.17.1
> >



--
Mike Leach
Principal Engineer, ARM Ltd.
Manchester Design Centre. UK
diff mbox series

Patch

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 483976074779..7c019dda1236 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -239,6 +239,7 @@  static ssize_t reset_store(struct device *dev,
 	for (i = 0; i < drvdata->nr_resource; i++)
 		config->res_ctrl[i] = 0x0;
 
+	config->ss_idx = 0x0;
 	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
 		config->ss_ctrl[i] = 0x0;
 		config->ss_pe_cmp[i] = 0x0;
@@ -1713,6 +1714,123 @@  static ssize_t res_ctrl_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(res_ctrl);
 
+static ssize_t sshot_idx_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	val = config->ss_idx;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_idx_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t size)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+	if (val >= drvdata->nr_ss_cmp)
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	config->ss_idx = val;
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(sshot_idx);
+
+static ssize_t sshot_ctrl_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	spin_lock(&drvdata->spinlock);
+	val = config->ss_ctrl[config->ss_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_ctrl_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = config->ss_idx;
+	config->ss_ctrl[idx] = val & GENMASK(24, 0);
+	/* must clear bit 31 in related status register on programming */
+	config->ss_status[idx] &= ~BIT(31);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(sshot_ctrl);
+
+static ssize_t sshot_status_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	spin_lock(&drvdata->spinlock);
+	val = config->ss_status[config->ss_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+static DEVICE_ATTR_RO(sshot_status);
+
+static ssize_t sshot_pe_ctrl_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	spin_lock(&drvdata->spinlock);
+	val = config->ss_pe_cmp[config->ss_idx];
+	spin_unlock(&drvdata->spinlock);
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+
+static ssize_t sshot_pe_ctrl_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t size)
+{
+	u8 idx;
+	unsigned long val;
+	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	struct etmv4_config *config = &drvdata->config;
+
+	if (kstrtoul(buf, 16, &val))
+		return -EINVAL;
+
+	spin_lock(&drvdata->spinlock);
+	idx = config->ss_idx;
+	config->ss_ctrl[idx] = val & GENMASK(7, 0);
+	/* must clear bit 31 in related status register on programming */
+	config->ss_status[idx] &= ~BIT(31);
+	spin_unlock(&drvdata->spinlock);
+	return size;
+}
+static DEVICE_ATTR_RW(sshot_pe_ctrl);
+
 static ssize_t ctxid_idx_show(struct device *dev,
 			      struct device_attribute *attr,
 			      char *buf)
@@ -2169,6 +2287,10 @@  static struct attribute *coresight_etmv4_attrs[] = {
 	&dev_attr_addr_exlevel_s_ns.attr,
 	&dev_attr_addr_cmp_view.attr,
 	&dev_attr_vinst_pe_cmp_start_stop.attr,
+	&dev_attr_sshot_idx.attr,
+	&dev_attr_sshot_ctrl.attr,
+	&dev_attr_sshot_pe_ctrl.attr,
+	&dev_attr_sshot_status.attr,
 	&dev_attr_seq_idx.attr,
 	&dev_attr_seq_state.attr,
 	&dev_attr_seq_event.attr,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index d8b078d0cc7f..fb7083218410 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -149,6 +149,9 @@  static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 			       drvdata->base + TRCRSCTLRn(i));
 
 	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		/* always clear status bit on restart if using single-shot */
+		if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
+			config->ss_status[i] &= ~BIT(31);
 		writel_relaxed(config->ss_ctrl[i],
 			       drvdata->base + TRCSSCCRn(i));
 		writel_relaxed(config->ss_status[i],
@@ -448,6 +451,9 @@  static void etm4_disable_hw(void *info)
 {
 	u32 control;
 	struct etmv4_drvdata *drvdata = info;
+	struct etmv4_config *config = &drvdata->config;
+	struct device *etm_dev = &drvdata->csdev->dev;
+	int i;
 
 	CS_UNLOCK(drvdata->base);
 
@@ -470,6 +476,18 @@  static void etm4_disable_hw(void *info)
 	isb();
 	writel_relaxed(control, drvdata->base + TRCPRGCTLR);
 
+	/* wait for TRCSTATR.PMSTABLE to go to '1' */
+	if (coresight_timeout(drvdata->base, TRCSTATR,
+			      TRCSTATR_PMSTABLE_BIT, 1))
+		dev_err(etm_dev,
+			"timeout while waiting for PM stable Trace Status\n");
+
+	/* read the status of the single shot comparators */
+	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		config->ss_status[i] =
+			readl_relaxed(drvdata->base + TRCSSCSRn(i));
+	}
+
 	coresight_disclaim_device_unlocked(drvdata->base);
 
 	CS_LOCK(drvdata->base);
@@ -576,6 +594,7 @@  static void etm4_init_arch_data(void *info)
 	u32 etmidr4;
 	u32 etmidr5;
 	struct etmv4_drvdata *drvdata = info;
+	int i;
 
 	/* Make sure all registers are accessible */
 	etm4_os_unlock(drvdata);
@@ -699,9 +718,14 @@  static void etm4_init_arch_data(void *info)
 	drvdata->nr_resource = BMVAL(etmidr4, 16, 19) + 1;
 	/*
 	 * NUMSSCC, bits[23:20] the number of single-shot
-	 * comparator control for tracing
+	 * comparator control for tracing. Read any status regs as these
+	 * also contain RO capability data.
 	 */
 	drvdata->nr_ss_cmp = BMVAL(etmidr4, 20, 23);
+	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+		drvdata->config.ss_status[i] =
+			readl_relaxed(drvdata->base + TRCSSCSRn(i));
+	}
 	/* 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 */
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 60bc2fb5159b..be8b32ea1654 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -175,6 +175,7 @@ 
 					 ETM_MODE_EXCL_USER)
 
 #define TRCSTATR_IDLE_BIT		0
+#define TRCSTATR_PMSTABLE_BIT		1
 #define ETM_DEFAULT_ADDR_COMP		0
 
 /* PowerDown Control Register bits */
@@ -226,6 +227,7 @@ 
  * @cntr_val:	Sets or returns the value for a counter.
  * @res_idx:	Resource index selector.
  * @res_ctrl:	Controls the selection of the resources in the trace unit.
+ * @ss_idx:	Single-shot index selector.
  * @ss_ctrl:	Controls the corresponding single-shot comparator resource.
  * @ss_status:	The status of the corresponding single-shot comparator.
  * @ss_pe_cmp:	Selects the PE comparator inputs for Single-shot control.
@@ -269,6 +271,7 @@  struct etmv4_config {
 	u32				cntr_val[ETMv4_MAX_CNTR];
 	u8				res_idx;
 	u32				res_ctrl[ETM_MAX_RES_SEL];
+	u8				ss_idx;
 	u32				ss_ctrl[ETM_MAX_SS_CMP];
 	u32				ss_status[ETM_MAX_SS_CMP];
 	u32				ss_pe_cmp[ETM_MAX_SS_CMP];