All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mike Leach <mike.leach@arm.com>
To: Yeoreum Yun <yeoreum.yun@arm.com>,
	James Clark <james.clark@linaro.org>, Leo Yan <leo.yan@arm.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Mathieu Poirier <mathieu.poirier@linaro.org>,
	coresight@lists.linaro.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-rt-devel@lists.linux.dev
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
	Clark Williams <clrkwllms@kernel.org>,
	Steven Rostedt <rostedt@goodmis.org>
Subject: Re: [PATCH v11 9/9] coresight: etm3x: introduce struct etm_caps
Date: Fri, 18 Sep 2026 15:57:32 +0100	[thread overview]
Message-ID: <3f91ecea-05ad-4b95-9352-37ae2203807b@arm.com> (raw)
In-Reply-To: <20260915-separate_etm_cfg_v2-v11-9-d2b258d51747@arm.com>

Reviewed-by: Mike Leach <mike.leach@arm.com>

On 9/15/26 12:34, Yeoreum Yun wrote:
> Introduce struct etm_caps to describe ETMv3 capabilities
> and move capabilities information into it.
> 
> Since drvdata->etmccr and drvdata->etmccer are used to check
> whether it supports fifofull logic and timestamping,
> remove etmccr and etmccer field from drvdata and add relevant fields
> in etm_caps structure.
> 
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>   drivers/hwtracing/coresight/coresight-etm.h        | 42 +++++++++++++---------
>   drivers/hwtracing/coresight/coresight-etm3x-core.c | 42 +++++++++++++---------
>   .../hwtracing/coresight/coresight-etm3x-sysfs.c    | 24 ++++++++-----
>   3 files changed, 66 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
> index f3796162168d4..cb5f18dcdd974 100644
> --- a/drivers/hwtracing/coresight/coresight-etm.h
> +++ b/drivers/hwtracing/coresight/coresight-etm.h
> @@ -140,6 +140,30 @@
>   				 ETM_ADD_COMP_0		|	\
>   				 ETM_EVENT_NOT_A)
>   
> +/**
> + * struct etm_caps - specifics ETM capabilities
> + * @port_size:	port size as reported by ETMCR bit 4-6 and 21.
> + * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
> + * @nr_cntr:	Number of counters as found in ETMCCR bit 13-15.
> + * @nr_ext_inp:	Number of external input as found in ETMCCR bit 17-19.
> + * @nr_ext_out:	Number of external output as found in ETMCCR bit 20-22.
> + * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
> + * @fifofull:	FIFOFULL logic is present.
> + * @timestamp:	Timestamping is implemented.
> + * @retstack:	Return stack is implemented.
> + */
> +struct etm_caps {
> +	int	port_size;
> +	u8	nr_addr_cmp;
> +	u8	nr_cntr;
> +	u8	nr_ext_inp;
> +	u8	nr_ext_out;
> +	u8	nr_ctxid_cmp;
> +	bool	fifofull : 1;
> +	bool	timestamp : 1;
> +	bool	retstack : 1;
> +};
> +
>   /**
>    * struct etm_config - configuration information related to an ETM
>    * @mode:	controls various modes supported by this ETM/PTM.
> @@ -212,19 +236,12 @@ struct etm_config {
>    * @csdev:	component vitals needed by the framework.
>    * @spinlock:	only one at a time pls.
>    * @cpu:	the cpu this component is affined to.
> - * @port_size:	port size as reported by ETMCR bit 4-6 and 21.
>    * @arch:	ETM/PTM version number.
> + * @caps:	ETM capabilities.
>    * @use_cpu14:	true if management registers need to be accessed via CP14.
>    * @sticky_enable: true if ETM base configuration has been done.
>    * @boot_enable:true if we should start tracing at boot time.
>    * @os_unlock:	true if access to management registers is allowed.
> - * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
> - * @nr_cntr:	Number of counters as found in ETMCCR bit 13-15.
> - * @nr_ext_inp:	Number of external input as found in ETMCCR bit 17-19.
> - * @nr_ext_out:	Number of external output as found in ETMCCR bit 20-22.
> - * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
> - * @etmccr:	value of register ETMCCR.
> - * @etmccer:	value of register ETMCCER.
>    * @traceid:	value of the current ID for this component.
>    * @active_config:	structure holding current running configuration.
>    * @config:	structure holding sysfs mode configuration.
> @@ -235,19 +252,12 @@ struct etm_drvdata {
>   	struct coresight_device		*csdev;
>   	spinlock_t			spinlock;
>   	int				cpu;
> -	int				port_size;
>   	u8				arch;
> +	struct etm_caps			caps;
>   	bool				use_cp14;
>   	bool				sticky_enable;
>   	bool				boot_enable;
>   	bool				os_unlock;
> -	u8				nr_addr_cmp;
> -	u8				nr_cntr;
> -	u8				nr_ext_inp;
> -	u8				nr_ext_out;
> -	u8				nr_ctxid_cmp;
> -	u32				etmccr;
> -	u32				etmccer;
>   	u32				traceid;
>   	struct etm_config		active_config;
>   	struct etm_config		config;
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> index 12bb38dc596e7..79c7cbe2084de 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
> @@ -308,6 +308,7 @@ void etm_config_trace_mode(struct etm_config *config)
>   static int etm_parse_event_config(struct etm_drvdata *drvdata,
>   				  struct perf_event *event)
>   {
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->active_config;
>   	struct perf_event_attr *attr = &event->attr;
>   	u8 ts_level;
> @@ -356,8 +357,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
>   	 * has ret stack) on the same SoC. So only enable when it can be honored
>   	 * - trace will still continue normally otherwise.
>   	 */
> -	if (ATTR_CFG_GET_FLD(attr, retstack) &&
> -	    (drvdata->etmccer & ETMCCER_RETSTACK))
> +	if (ATTR_CFG_GET_FLD(attr, retstack) && (caps->retstack))
>   		config->ctrl |= ETMCR_RETURN_STACK;
>   
>   	return 0;
> @@ -367,6 +367,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
>   {
>   	int i, rc;
>   	u32 etmcr;
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->active_config;
>   	struct coresight_device *csdev = drvdata->csdev;
>   
> @@ -388,7 +389,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
>   	etmcr = etm_readl(drvdata, ETMCR);
>   	/* Clear setting from a previous run if need be */
>   	etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
> -	etmcr |= drvdata->port_size;
> +	etmcr |= caps->port_size;
>   	etmcr |= ETMCR_ETM_EN;
>   	etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
>   	etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
> @@ -396,11 +397,11 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
>   	etm_writel(drvdata, config->enable_event, ETMTEEVR);
>   	etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
>   	etm_writel(drvdata, config->fifofull_level, ETMFFLR);
> -	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
> +	for (i = 0; i < caps->nr_addr_cmp; i++) {
>   		etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
>   		etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
>   	}
> -	for (i = 0; i < drvdata->nr_cntr; i++) {
> +	for (i = 0; i < caps->nr_cntr; i++) {
>   		etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
>   		etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
>   		etm_writel(drvdata, config->cntr_rld_event[i],
> @@ -414,9 +415,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
>   	etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
>   	etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
>   	etm_writel(drvdata, config->seq_curr_state, ETMSQR);
> -	for (i = 0; i < drvdata->nr_ext_out; i++)
> +	for (i = 0; i < caps->nr_ext_out; i++)
>   		etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
> -	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
> +	for (i = 0; i < caps->nr_ctxid_cmp; i++)
>   		etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
>   	etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
>   	etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
> @@ -562,6 +563,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
>   static void etm_disable_hw(struct etm_drvdata *drvdata)
>   {
>   	int i;
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->active_config;
>   	struct coresight_device *csdev = drvdata->csdev;
>   
> @@ -571,7 +573,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
>   	/* Read back sequencer and counters for post trace analysis */
>   	config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
>   
> -	for (i = 0; i < drvdata->nr_cntr; i++)
> +	for (i = 0; i < caps->nr_cntr; i++)
>   		config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
>   
>   	etm_set_pwrdwn(drvdata);
> @@ -626,6 +628,7 @@ static void etm_disable_perf(struct coresight_device *csdev)
>   static void etm_disable_sysfs(struct coresight_device *csdev)
>   {
>   	struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->config;
>   	const struct etm_config *active_config = &drvdata->active_config;
>   	int i;
> @@ -641,7 +644,7 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
>   	 * Userspace may read seq_curr_state and cntr_val through sysfs
>   	 * after the sysfs-session has been disabled.
>   	 */
> -	for (i = 0; i < drvdata->nr_cntr; i++)
> +	for (i = 0; i < caps->nr_cntr; i++)
>   		config->cntr_val[i] = active_config->cntr_val[i];
>   
>   	config->seq_curr_state = active_config->seq_curr_state;
> @@ -726,7 +729,9 @@ static void etm_init_arch_data(void *info)
>   {
>   	u32 etmidr;
>   	u32 etmccr;
> +	u32 etmccer;
>   	struct etm_drvdata *drvdata = info;
> +	struct etm_caps *caps = &drvdata->caps;
>   
>   	/* Make sure all registers are accessible */
>   	etm_os_unlock(drvdata);
> @@ -751,16 +756,19 @@ static void etm_init_arch_data(void *info)
>   	/* Find all capabilities */
>   	etmidr = etm_readl(drvdata, ETMIDR);
>   	drvdata->arch = BMVAL(etmidr, 4, 11);
> -	drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
> +	caps->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
> +
> +	etmccer = etm_readl(drvdata, ETMCCER);
> +	caps->timestamp = !!(etmccer & ETMCCER_TIMESTAMP);
> +	caps->retstack = !!(etmccer & ETMCCER_RETSTACK);
>   
> -	drvdata->etmccer = etm_readl(drvdata, ETMCCER);
>   	etmccr = etm_readl(drvdata, ETMCCR);
> -	drvdata->etmccr = etmccr;
> -	drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
> -	drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
> -	drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
> -	drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
> -	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
> +	caps->fifofull = !!(etmccr & ETMCCR_FIFOFULL);
> +	caps->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
> +	caps->nr_cntr = BMVAL(etmccr, 13, 15);
> +	caps->nr_ext_inp = BMVAL(etmccr, 17, 19);
> +	caps->nr_ext_out = BMVAL(etmccr, 20, 22);
> +	caps->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
>   
>   	coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
>   	etm_set_pwrdwn(drvdata);
> diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> index 2c8c129228589..36d4673537930 100644
> --- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
> @@ -53,8 +53,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
>   {
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   
> -	val = drvdata->nr_addr_cmp;
> +	val = caps->nr_addr_cmp;
>   	return sprintf(buf, "%#lx\n", val);
>   }
>   static DEVICE_ATTR_RO(nr_addr_cmp);
> @@ -63,8 +64,9 @@ static ssize_t nr_cntr_show(struct device *dev,
>   			    struct device_attribute *attr, char *buf)
>   {	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   
> -	val = drvdata->nr_cntr;
> +	val = caps->nr_cntr;
>   	return sprintf(buf, "%#lx\n", val);
>   }
>   static DEVICE_ATTR_RO(nr_cntr);
> @@ -75,7 +77,7 @@ static ssize_t nr_ctxid_cmp_show(struct device *dev,
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
>   
> -	val = drvdata->nr_ctxid_cmp;
> +	val = drvdata->caps.nr_ctxid_cmp;
>   	return sprintf(buf, "%#lx\n", val);
>   }
>   static DEVICE_ATTR_RO(nr_ctxid_cmp);
> @@ -115,7 +117,7 @@ static ssize_t reset_store(struct device *dev,
>   		memset(config, 0, sizeof(struct etm_config));
>   		config->mode = ETM_MODE_EXCLUDE;
>   		config->trigger_event = ETM_DEFAULT_EVENT_VAL;
> -		for (i = 0; i < drvdata->nr_addr_cmp; i++) {
> +		for (i = 0; i < drvdata->caps.nr_addr_cmp; i++) {
>   			config->addr_type[i] = ETM_ADDR_TYPE_NONE;
>   		}
>   
> @@ -146,6 +148,7 @@ static ssize_t mode_store(struct device *dev,
>   	int ret;
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->config;
>   
>   	ret = kstrtoul(buf, 16, &val);
> @@ -166,7 +169,7 @@ static ssize_t mode_store(struct device *dev,
>   		config->ctrl &= ~ETMCR_CYC_ACC;
>   
>   	if (config->mode & ETM_MODE_STALL) {
> -		if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
> +		if (!caps->fifofull) {
>   			dev_warn(dev, "stall mode not supported\n");
>   			ret = -EINVAL;
>   			goto err_unlock;
> @@ -176,7 +179,7 @@ static ssize_t mode_store(struct device *dev,
>   		config->ctrl &= ~ETMCR_STALL_MODE;
>   
>   	if (config->mode & ETM_MODE_TIMESTAMP) {
> -		if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
> +		if (!caps->timestamp) {
>   			dev_warn(dev, "timestamp not supported\n");
>   			ret = -EINVAL;
>   			goto err_unlock;
> @@ -321,13 +324,14 @@ static ssize_t addr_idx_store(struct device *dev,
>   	int ret;
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->config;
>   
>   	ret = kstrtoul(buf, 16, &val);
>   	if (ret)
>   		return ret;
>   
> -	if (val >= drvdata->nr_addr_cmp)
> +	if (val >= caps->nr_addr_cmp)
>   		return -EINVAL;
>   
>   	/*
> @@ -624,13 +628,14 @@ static ssize_t cntr_idx_store(struct device *dev,
>   	int ret;
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->config;
>   
>   	ret = kstrtoul(buf, 16, &val);
>   	if (ret)
>   		return ret;
>   
> -	if (val >= drvdata->nr_cntr)
> +	if (val >= caps->nr_cntr)
>   		return -EINVAL;
>   	/*
>   	 * Use spinlock to ensure index doesn't change while it gets
> @@ -1030,13 +1035,14 @@ static ssize_t ctxid_idx_store(struct device *dev,
>   	int ret;
>   	unsigned long val;
>   	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
> +	const struct etm_caps *caps = &drvdata->caps;
>   	struct etm_config *config = &drvdata->config;
>   
>   	ret = kstrtoul(buf, 16, &val);
>   	if (ret)
>   		return ret;
>   
> -	if (val >= drvdata->nr_ctxid_cmp)
> +	if (val >= caps->nr_ctxid_cmp)
>   		return -EINVAL;
>   
>   	/*
> 



  reply	other threads:[~2026-09-18 14:58 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-15 11:34 [PATCH v11 0/9] fix several inconsistencies with sysfs configuration in etmX Yeoreum Yun
2026-09-15 11:34 ` [PATCH v11 1/9] coresight: etm4x: prohibit modifying ss_status and cntr_val while session is enabled Yeoreum Yun
2026-09-15 11:51   ` sashiko-bot
2026-09-15 13:26     ` Yeoreum Yun
2026-09-18 11:14   ` Mike Leach
2026-09-18 17:08     ` Yeoreum Yun
2026-09-15 11:34 ` [PATCH v11 2/9] coresight: etm3x: prohibit modifying cntr_val and reset " Yeoreum Yun
2026-09-15 11:48   ` sashiko-bot
2026-09-15 13:30     ` Yeoreum Yun
2026-09-15 13:55       ` Yeoreum Yun
2026-09-18 11:15   ` Mike Leach
2026-09-15 11:34 ` [PATCH v11 3/9] coresight: etm4x: fix inconsistencies with sysfs configuration Yeoreum Yun
2026-09-15 11:53   ` sashiko-bot
2026-09-15 12:36     ` Yeoreum Yun
2026-09-18 13:49   ` Mike Leach
2026-09-18 17:00     ` Yeoreum Yun
2026-09-15 11:34 ` [PATCH v11 4/9] coresight: etm3x: " Yeoreum Yun
2026-09-15 11:47   ` sashiko-bot
2026-09-15 13:42     ` Yeoreum Yun
2026-09-18 13:57   ` Mike Leach
2026-09-18 17:09     ` Yeoreum Yun
2026-09-15 11:34 ` [PATCH v11 5/9] coresight: etm3x: remove redundant cpu online check on etm_enable_sysfs() Yeoreum Yun
2026-09-18 13:58   ` Mike Leach
2026-09-15 11:34 ` [PATCH v11 6/9] coresight: etm4x: introduce struct etm4_caps Yeoreum Yun
2026-09-18 14:01   ` Mike Leach
2026-09-15 11:34 ` [PATCH v11 7/9] coresight: etm4x: exclude ss_status from drvdata->config Yeoreum Yun
2026-09-15 11:49   ` sashiko-bot
2026-09-15 13:35     ` Yeoreum Yun
2026-09-18 14:04   ` Mike Leach
2026-09-18 17:13     ` Yeoreum Yun
2026-09-15 11:34 ` [PATCH v11 8/9] coresight: etm4x: remove s_ex_level from config Yeoreum Yun
2026-09-18 14:05   ` Mike Leach
2026-09-15 11:34 ` [PATCH v11 9/9] coresight: etm3x: introduce struct etm_caps Yeoreum Yun
2026-09-18 14:57   ` Mike Leach [this message]
2026-09-24 15:25 ` [PATCH v11 0/9] fix several inconsistencies with sysfs configuration in etmX Leo Yan
2026-09-24 17:28   ` Yeoreum Yun

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=3f91ecea-05ad-4b95-9352-37ae2203807b@arm.com \
    --to=mike.leach@arm.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=bigeasy@linutronix.de \
    --cc=clrkwllms@kernel.org \
    --cc=coresight@lists.linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=james.clark@linaro.org \
    --cc=leo.yan@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=mathieu.poirier@linaro.org \
    --cc=rostedt@goodmis.org \
    --cc=suzuki.poulose@arm.com \
    --cc=yeoreum.yun@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.