All of lore.kernel.org
 help / color / mirror / Atom feed
From: Serge Semin <Sergey.Semin@baikalelectronics.ru>
To: Michal Simek <michal.simek@xilinx.com>,
	Borislav Petkov <bp@alien8.de>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Tony Luck <tony.luck@intel.com>,
	James Morse <james.morse@arm.com>,
	Robert Richter <rric@kernel.org>
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>,
	Serge Semin <fancer.lancer@gmail.com>,
	Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>,
	Michail Ivanov <Michail.Ivanov@baikalelectronics.ru>,
	Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>,
	Punnaiah Choudary Kalluri <punnaiah.choudary.kalluri@xilinx.com>,
	Manish Narani <manish.narani@xilinx.com>,
	Dinh Nguyen <dinguyen@kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-edac@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [PATCH RESEND v3 03/18] EDAC/synopsys: Extend memtypes supported by controller
Date: Fri, 30 Sep 2022 02:35:15 +0300	[thread overview]
Message-ID: <20220929233530.13016-4-Sergey.Semin@baikalelectronics.ru> (raw)
In-Reply-To: <20220929233530.13016-1-Sergey.Semin@baikalelectronics.ru>

In accordance with [1] the DW uMCTL2 DDR controllers can support the next
DDR protocols: LPDDR, (LP)DDR(2|3|4). If the controller is configured to
support several of these memory chip types only one of these modes will be
able to be enabled at runtime [2]. Taking all of that into account in
order to have a generic DW uMCTL2 DDR controller support in the driver we
need to update the snps_get_mtype() procedure so one would be able to
detect all the currently supported memory types in accordance with the
table defined in [2]. Note alas it's not possible do determine which MEMC
DDR configs were enabled at the IP-core synthesize. Thus we have no choice
but to initialize the mci->mtype_cap field with all the types claimed to
be supported by the reference manual.

While at it convert the MEM_TYPE_* macros to have a unified within the
driver name - attach DDR_MSTR prefix indicating the CSR macro is defined
for.

[1] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2)
Databook, Version 3.91a, October 2020, p.501
[2] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2)
Databook, Version 3.91a, October 2020, p.501

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/edac/synopsys_edac.c | 59 +++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
index b2a2f938045c..5adf6598465a 100644
--- a/drivers/edac/synopsys_edac.c
+++ b/drivers/edac/synopsys_edac.c
@@ -97,6 +97,14 @@
 #define DDRCTL_EWDTH_16			2
 #define DDRCTL_EWDTH_32			1
 #define DDRCTL_EWDTH_64			0
+#define DDR_MSTR_MEM_MASK		GENMASK(5, 0)
+#define DDR_MSTR_MEM_DDR2		0
+#define DDR_MSTR_MEM_DDR3		BIT(0)
+#define DDR_MSTR_MEM_LPDDR		BIT(1)
+#define DDR_MSTR_MEM_LPDDR2		BIT(2)
+#define DDR_MSTR_MEM_LPDDR3		BIT(3)
+#define DDR_MSTR_MEM_DDR4		BIT(4)
+#define DDR_MSTR_MEM_LPDDR4		BIT(5)
 
 /* ECC CFG0 register definitions */
 #define ECC_CFG0_MODE_MASK		GENMASK(2, 0)
@@ -141,13 +149,6 @@
 #define ECC_POISON1_BANK_MASK		GENMASK(26, 24)
 #define ECC_POISON1_ROW_MASK		GENMASK(17, 0)
 
-/* DDR Memory type defines */
-#define MEM_TYPE_DDR3			BIT(0)
-#define MEM_TYPE_DDR2			BIT(2)
-#define MEM_TYPE_LPDDR3			BIT(3)
-#define MEM_TYPE_DDR4			BIT(4)
-#define MEM_TYPE_LPDDR4			BIT(5)
-
 /* DDRC ECC CE & UE poison mask */
 #define ECC_CEPOISON_MASK		GENMASK(1, 0)
 #define ECC_UEPOISON_MASK		BIT(0)
@@ -473,7 +474,7 @@ static enum dev_type snps_get_dtype(const void __iomem *base)
 	u32 regval;
 
 	regval = readl(base + DDR_MSTR_OFST);
-	if (!(regval & MEM_TYPE_DDR4))
+	if (!(regval & DDR_MSTR_MEM_DDR4))
 		return DEV_UNKNOWN;
 
 	regval = FIELD_GET(DDR_MSTR_DEV_CFG_MASK, regval);
@@ -534,21 +535,29 @@ static u32 snps_get_memsize(void)
  */
 static enum mem_type snps_get_mtype(const void __iomem *base)
 {
-	enum mem_type mt;
-	u32 memtype;
+	u32 regval;
 
-	memtype = readl(base + DDR_MSTR_OFST);
+	regval = readl(base + DDR_MSTR_OFST);
+	regval = FIELD_GET(DDR_MSTR_MEM_MASK, regval);
 
-	if ((memtype & MEM_TYPE_DDR3) || (memtype & MEM_TYPE_LPDDR3))
-		mt = MEM_DDR3;
-	else if (memtype & MEM_TYPE_DDR2)
-		mt = MEM_RDDR2;
-	else if ((memtype & MEM_TYPE_LPDDR4) || (memtype & MEM_TYPE_DDR4))
-		mt = MEM_DDR4;
-	else
-		mt = MEM_EMPTY;
+	switch (regval) {
+	case DDR_MSTR_MEM_DDR2:
+		return MEM_DDR2;
+	case DDR_MSTR_MEM_DDR3:
+		return MEM_DDR3;
+	case DDR_MSTR_MEM_LPDDR:
+		return MEM_LPDDR;
+	case DDR_MSTR_MEM_LPDDR2:
+		return MEM_LPDDR2;
+	case DDR_MSTR_MEM_LPDDR3:
+		return MEM_LPDDR3;
+	case DDR_MSTR_MEM_DDR4:
+		return MEM_DDR4;
+	case DDR_MSTR_MEM_LPDDR4:
+		return MEM_LPDDR4;
+	}
 
-	return mt;
+	return MEM_RESERVED;
 }
 
 /**
@@ -596,7 +605,9 @@ static void snps_mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
 	platform_set_drvdata(pdev, mci);
 
 	/* Initialize controller capabilities and configuration */
-	mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
+	mci->mtype_cap = MEM_FLAG_LPDDR | MEM_FLAG_DDR2 | MEM_FLAG_LPDDR2 |
+			 MEM_FLAG_DDR3 | MEM_FLAG_LPDDR3 |
+			 MEM_FLAG_DDR4 | MEM_FLAG_LPDDR4;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
 	mci->scrub_mode = SCRUB_NONE;
@@ -802,7 +813,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 			COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 24) &
 					COL_MAX_VAL_MASK) + COL_B9_BASE);
 	if (width == DDRCTL_EWDTH_64) {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = ((addrmap[4] &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				((addrmap[4] & COL_MAX_VAL_MASK) +
@@ -822,7 +833,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 				 COL_B11_BASE);
 		}
 	} else if (width == DDRCTL_EWDTH_32) {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = (((addrmap[3] >> 24) &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				(((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
@@ -842,7 +853,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 				 COL_B10_BASE);
 		}
 	} else {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = (((addrmap[3] >> 16) &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				(((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
-- 
2.37.3



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

WARNING: multiple messages have this Message-ID (diff)
From: Serge Semin <Sergey.Semin@baikalelectronics.ru>
To: Michal Simek <michal.simek@xilinx.com>,
	Borislav Petkov <bp@alien8.de>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Tony Luck <tony.luck@intel.com>,
	James Morse <james.morse@arm.com>,
	Robert Richter <rric@kernel.org>
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>,
	Serge Semin <fancer.lancer@gmail.com>,
	Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>,
	Michail Ivanov <Michail.Ivanov@baikalelectronics.ru>,
	Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>,
	Punnaiah Choudary Kalluri  <punnaiah.choudary.kalluri@xilinx.com>,
	Manish Narani <manish.narani@xilinx.com>,
	Dinh Nguyen <dinguyen@kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-edac@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [PATCH RESEND v3 03/18] EDAC/synopsys: Extend memtypes supported by controller
Date: Fri, 30 Sep 2022 02:35:15 +0300	[thread overview]
Message-ID: <20220929233530.13016-4-Sergey.Semin@baikalelectronics.ru> (raw)
In-Reply-To: <20220929233530.13016-1-Sergey.Semin@baikalelectronics.ru>

In accordance with [1] the DW uMCTL2 DDR controllers can support the next
DDR protocols: LPDDR, (LP)DDR(2|3|4). If the controller is configured to
support several of these memory chip types only one of these modes will be
able to be enabled at runtime [2]. Taking all of that into account in
order to have a generic DW uMCTL2 DDR controller support in the driver we
need to update the snps_get_mtype() procedure so one would be able to
detect all the currently supported memory types in accordance with the
table defined in [2]. Note alas it's not possible do determine which MEMC
DDR configs were enabled at the IP-core synthesize. Thus we have no choice
but to initialize the mci->mtype_cap field with all the types claimed to
be supported by the reference manual.

While at it convert the MEM_TYPE_* macros to have a unified within the
driver name - attach DDR_MSTR prefix indicating the CSR macro is defined
for.

[1] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2)
Databook, Version 3.91a, October 2020, p.501
[2] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2)
Databook, Version 3.91a, October 2020, p.501

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/edac/synopsys_edac.c | 59 +++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
index b2a2f938045c..5adf6598465a 100644
--- a/drivers/edac/synopsys_edac.c
+++ b/drivers/edac/synopsys_edac.c
@@ -97,6 +97,14 @@
 #define DDRCTL_EWDTH_16			2
 #define DDRCTL_EWDTH_32			1
 #define DDRCTL_EWDTH_64			0
+#define DDR_MSTR_MEM_MASK		GENMASK(5, 0)
+#define DDR_MSTR_MEM_DDR2		0
+#define DDR_MSTR_MEM_DDR3		BIT(0)
+#define DDR_MSTR_MEM_LPDDR		BIT(1)
+#define DDR_MSTR_MEM_LPDDR2		BIT(2)
+#define DDR_MSTR_MEM_LPDDR3		BIT(3)
+#define DDR_MSTR_MEM_DDR4		BIT(4)
+#define DDR_MSTR_MEM_LPDDR4		BIT(5)
 
 /* ECC CFG0 register definitions */
 #define ECC_CFG0_MODE_MASK		GENMASK(2, 0)
@@ -141,13 +149,6 @@
 #define ECC_POISON1_BANK_MASK		GENMASK(26, 24)
 #define ECC_POISON1_ROW_MASK		GENMASK(17, 0)
 
-/* DDR Memory type defines */
-#define MEM_TYPE_DDR3			BIT(0)
-#define MEM_TYPE_DDR2			BIT(2)
-#define MEM_TYPE_LPDDR3			BIT(3)
-#define MEM_TYPE_DDR4			BIT(4)
-#define MEM_TYPE_LPDDR4			BIT(5)
-
 /* DDRC ECC CE & UE poison mask */
 #define ECC_CEPOISON_MASK		GENMASK(1, 0)
 #define ECC_UEPOISON_MASK		BIT(0)
@@ -473,7 +474,7 @@ static enum dev_type snps_get_dtype(const void __iomem *base)
 	u32 regval;
 
 	regval = readl(base + DDR_MSTR_OFST);
-	if (!(regval & MEM_TYPE_DDR4))
+	if (!(regval & DDR_MSTR_MEM_DDR4))
 		return DEV_UNKNOWN;
 
 	regval = FIELD_GET(DDR_MSTR_DEV_CFG_MASK, regval);
@@ -534,21 +535,29 @@ static u32 snps_get_memsize(void)
  */
 static enum mem_type snps_get_mtype(const void __iomem *base)
 {
-	enum mem_type mt;
-	u32 memtype;
+	u32 regval;
 
-	memtype = readl(base + DDR_MSTR_OFST);
+	regval = readl(base + DDR_MSTR_OFST);
+	regval = FIELD_GET(DDR_MSTR_MEM_MASK, regval);
 
-	if ((memtype & MEM_TYPE_DDR3) || (memtype & MEM_TYPE_LPDDR3))
-		mt = MEM_DDR3;
-	else if (memtype & MEM_TYPE_DDR2)
-		mt = MEM_RDDR2;
-	else if ((memtype & MEM_TYPE_LPDDR4) || (memtype & MEM_TYPE_DDR4))
-		mt = MEM_DDR4;
-	else
-		mt = MEM_EMPTY;
+	switch (regval) {
+	case DDR_MSTR_MEM_DDR2:
+		return MEM_DDR2;
+	case DDR_MSTR_MEM_DDR3:
+		return MEM_DDR3;
+	case DDR_MSTR_MEM_LPDDR:
+		return MEM_LPDDR;
+	case DDR_MSTR_MEM_LPDDR2:
+		return MEM_LPDDR2;
+	case DDR_MSTR_MEM_LPDDR3:
+		return MEM_LPDDR3;
+	case DDR_MSTR_MEM_DDR4:
+		return MEM_DDR4;
+	case DDR_MSTR_MEM_LPDDR4:
+		return MEM_LPDDR4;
+	}
 
-	return mt;
+	return MEM_RESERVED;
 }
 
 /**
@@ -596,7 +605,9 @@ static void snps_mc_init(struct mem_ctl_info *mci, struct platform_device *pdev)
 	platform_set_drvdata(pdev, mci);
 
 	/* Initialize controller capabilities and configuration */
-	mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
+	mci->mtype_cap = MEM_FLAG_LPDDR | MEM_FLAG_DDR2 | MEM_FLAG_LPDDR2 |
+			 MEM_FLAG_DDR3 | MEM_FLAG_LPDDR3 |
+			 MEM_FLAG_DDR4 | MEM_FLAG_LPDDR4;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
 	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
 	mci->scrub_mode = SCRUB_NONE;
@@ -802,7 +813,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 			COL_MAX_VAL_MASK) ? 0 : (((addrmap[3] >> 24) &
 					COL_MAX_VAL_MASK) + COL_B9_BASE);
 	if (width == DDRCTL_EWDTH_64) {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = ((addrmap[4] &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				((addrmap[4] & COL_MAX_VAL_MASK) +
@@ -822,7 +833,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 				 COL_B11_BASE);
 		}
 	} else if (width == DDRCTL_EWDTH_32) {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = (((addrmap[3] >> 24) &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				(((addrmap[3] >> 24) & COL_MAX_VAL_MASK) +
@@ -842,7 +853,7 @@ static void snps_setup_column_address_map(struct snps_edac_priv *priv, u32 *addr
 				 COL_B10_BASE);
 		}
 	} else {
-		if (memtype & MEM_TYPE_LPDDR3) {
+		if (memtype & DDR_MSTR_MEM_LPDDR3) {
 			priv->col_shift[10] = (((addrmap[3] >> 16) &
 				COL_MAX_VAL_MASK) == COL_MAX_VAL_MASK) ? 0 :
 				(((addrmap[3] >> 16) & COL_MAX_VAL_MASK) +
-- 
2.37.3



  parent reply	other threads:[~2022-09-29 23:41 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-29 23:35 [PATCH RESEND v3 00/18] EDAC/synopsys: Add generic DDRC info and address mapping Serge Semin
2022-09-29 23:35 ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 01/18] EDAC/synopsys: Convert sysfs nodes to debugfs ones Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 02/18] EDAC/mc: Extend memtypes with LPDDR(mDDR) and LPDDR2 Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` Serge Semin [this message]
2022-09-29 23:35   ` [PATCH RESEND v3 03/18] EDAC/synopsys: Extend memtypes supported by controller Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 04/18] EDAC/synopsys: Detach private data from mci instance Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 05/18] EDAC/synopsys: Add DDRC basic parameters infrastructure Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 06/18] EDAC/synopsys: Convert plat-data to plat-init function Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 07/18] EDAC/synopsys: Parse ADDRMAP[7-8] CSRs for (LP)DDR4 only Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 08/18] EDAC/synopsys: Parse ADDRMAP[0] CSR for multi-ranks case only Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 09/18] EDAC/synopsys: Set actual DIMM ECC errors grain Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 10/18] EDAC/synopsys: Get corrected bit position Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 11/18] EDAC/synopsys: Read full data pattern on errors Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 12/18] EDAC/synopsys: Read data syndrome " Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 13/18] EDAC/synopsys: Introduce System/SDRAM address translation interface Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 14/18] EDAC/synopsys: Simplify HIF/SDRAM column mapping get procedure Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 15/18] EDAC/synopsys: Add HIF/SDRAM mapping debugfs node Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 16/18] EDAC/synopsys: Add erroneous page-frame/offset reporting Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 17/18] EDAC/synopsys: Add system address regions support Serge Semin
2022-09-29 23:35   ` Serge Semin
2022-09-29 23:35 ` [PATCH RESEND v3 18/18] EDAC/synopsys: Add mapping-based memory size calculation Serge Semin
2022-09-29 23:35   ` Serge Semin

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=20220929233530.13016-4-Sergey.Semin@baikalelectronics.ru \
    --to=sergey.semin@baikalelectronics.ru \
    --cc=Alexey.Malahov@baikalelectronics.ru \
    --cc=Michail.Ivanov@baikalelectronics.ru \
    --cc=Pavel.Parkhomenko@baikalelectronics.ru \
    --cc=bp@alien8.de \
    --cc=dinguyen@kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=james.morse@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=manish.narani@xilinx.com \
    --cc=mchehab@kernel.org \
    --cc=michal.simek@xilinx.com \
    --cc=punnaiah.choudary.kalluri@xilinx.com \
    --cc=rric@kernel.org \
    --cc=tony.luck@intel.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.