LKML Archive mirror
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@free-electrons.com>
To: David Woodhouse <dwmw2@infradead.org>,
	Brian Norris <computersforpeace@gmail.com>,
	linux-mtd@lists.infradead.org
Cc: Daniel Mack <daniel@zonque.org>,
	Haojian Zhuang <haojian.zhuang@gmail.com>,
	Robert Jarzmik <robert.jarzmik@free.fr>,
	Kukjin Kim <kgene@kernel.org>,
	Krzysztof Kozlowski <k.kozlowski@samsung.com>,
	linux-samsung-soc@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	Ralf Baechle <ralf@linux-mips.org>,
	linux-mips@linux-mips.org, Josh Wu <josh.wu@atmel.com>,
	Ezequiel Garcia <ezequiel.garcia@free-electrons.com>,
	Maxime Ripard <maxime.ripard@free-electrons.com>,
	Chen-Yu Tsai <wens@csie.org>,
	linux-sunxi@googlegroups.com, Stefan Agner <stefan@agner.ch>,
	Kyungmin Park <kyungmin.park@samsung.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org,
	punnaiah choudary kalluri <punnaia@xilinx.com>,
	Priit Laes <plaes@plaes.org>,
	Boris Brezillon <boris.brezillon@free-electrons.com>
Subject: [PATCH v2 19/51] mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition
Date: Thu,  4 Feb 2016 11:06:42 +0100	[thread overview]
Message-ID: <1454580434-32078-20-git-send-email-boris.brezillon@free-electrons.com> (raw)
In-Reply-To: <1454580434-32078-1-git-send-email-boris.brezillon@free-electrons.com>

ECC layout definitions are currently exposed using the nand_ecclayout
struct which embeds oobfree and eccpos arrays with predefined size.
This approach was acceptable when NAND chips were providing relatively
small OOB regions, but MLC and TLC now provide OOB regions of several
hundreds of bytes, which implies a non negligible overhead for everybody
even those who only need to support legacy NANDs.

Create an mtd_ooblayout_ops interface providing the same functionality
(expose the ECC and oobfree layout) without the need for this huge
structure.

The mtd->ecclayout is now deprecated and should be replaced by the
equivalent mtd_ooblayout_ops. In the meantime we provide a wrapper around
the ->ecclayout field to ease migration to this new model.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/mtdchar.c   |   4 +-
 drivers/mtd/mtdconcat.c |   2 +-
 drivers/mtd/mtdcore.c   | 171 +++++++++++++++++++++++++++++++++++-------------
 drivers/mtd/mtdpart.c   |  23 ++++++-
 include/linux/mtd/mtd.h |  32 +++++++--
 5 files changed, 177 insertions(+), 55 deletions(-)

diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index cd64ab7..3fad2c7 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -888,7 +888,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 	{
 		struct nand_oobinfo oi;
 
-		if (!mtd->ecclayout)
+		if (!mtd->ooblayout)
 			return -EOPNOTSUPP;
 
 		ret = get_oobinfo(mtd, &oi);
@@ -982,7 +982,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
 	{
 		struct nand_ecclayout_user *usrlay;
 
-		if (!mtd->ecclayout)
+		if (!mtd->ooblayout)
 			return -EOPNOTSUPP;
 
 		usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 481565e..d573606 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to c
 
 	}
 
-	mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout);
+	mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);
 
 	concat->num_subdev = num_devs;
 	concat->mtd.name = name;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 14e46ca..dccd132 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1016,52 +1016,15 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
 		      struct mtd_oob_region *oobecc)
 {
-	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
-
 	memset(oobecc, 0, sizeof(*oobecc));
 
 	if (!mtd || section < 0)
 		return -EINVAL;
 
-	if (!mtd->ecclayout)
+	if (!mtd->ooblayout || !mtd->ooblayout->ecc)
 		return -ENOTSUPP;
 
-	if (mtd->ecclayout->eccbytes < 1)
-		return -ERANGE;
-
-	/*
-	 * This logic allows us to reuse the ->ecclayout information and
-	 * expose them as ECC regions (as done for the OOB free regions).
-	 *
-	 * TODO: this should be dropped as soon as we get rid of the
-	 * ->ecclayout field.
-	 */
-	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
-		eccpos = mtd->ecclayout->eccpos[eccbyte];
-
-		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
-			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
-
-			if (eccpos + 1 == neccpos) {
-				length++;
-				continue;
-			}
-		}
-
-		if (section == cursection)
-			break;
-
-		length = 0;
-		cursection++;
-	}
-
-	if (cursection != section)
-		return -ERANGE;
-
-	oobecc->length = length + 1;
-	oobecc->offset = eccpos - length;
-
-	return 0;
+	return mtd->ooblayout->ecc(mtd, section, oobecc);
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
 
@@ -1090,16 +1053,10 @@ int mtd_ooblayout_free(struct mtd_info *mtd, int section,
 	if (!mtd || section < 0)
 		return -EINVAL;
 
-	if (!mtd->ecclayout)
+	if (!mtd->ooblayout || !mtd->ooblayout->free)
 		return -ENOTSUPP;
 
-	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
-		return -ERANGE;
-
-	oobfree->offset = mtd->ecclayout->oobfree[section].offset;
-	oobfree->length = mtd->ecclayout->oobfree[section].length;
-
-	return 0;
+	return mtd->ooblayout->free(mtd, section, oobfree);
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
 
@@ -1398,6 +1355,126 @@ int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd)
 }
 EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
 
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation
+ * @mtd: MTD device structure
+ * @section: ECC section. Depending on the layout you may have all the ECC
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobecc: OOB region struct filled with the appropriate ECC position
+ *	    information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->eccpos information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section,
+			     struct mtd_oob_region *oobecc)
+{
+	int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
+
+	if (!mtd->ecclayout)
+		return -ENOTSUPP;
+
+	if (mtd->ecclayout->eccbytes < 1)
+		return -ERANGE;
+
+	/*
+	 * This logic allows us to reuse the ->ecclayout information and
+	 * expose them as ECC regions (as done for the OOB free regions).
+	 *
+	 * TODO: this should be dropped as soon as we get rid of the
+	 * ->ecclayout field.
+	 */
+	for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
+		eccpos = mtd->ecclayout->eccpos[eccbyte];
+
+		if (eccbyte < mtd->ecclayout->eccbytes - 1) {
+			int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
+
+			if (eccpos + 1 == neccpos) {
+				length++;
+				continue;
+			}
+		}
+
+		if (section == cursection)
+			break;
+
+		length = 0;
+		cursection++;
+	}
+
+	if (cursection != section)
+		return -ERANGE;
+
+	oobecc->length = length + 1;
+	oobecc->offset = eccpos - length;
+
+	return 0;
+}
+
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation
+ * @mtd: MTD device structure
+ * @section: Free section. Depending on the layout you may have all the free
+ *	     bytes stored in a single contiguous section, or one section
+ *	     per ECC chunk (and sometime several sections for a single ECC
+ *	     ECC chunk)
+ * @oobfree: OOB region struct filled with the appropriate free position
+ *	     information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->oobfree information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_free(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobfree)
+{
+	struct nand_ecclayout *layout = mtd->ecclayout;
+
+	if (!layout)
+		return -ENOTSUPP;
+
+	if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE ||
+	    !layout->oobfree[section].length)
+		return -ERANGE;
+
+	oobfree->offset = layout->oobfree[section].offset;
+	oobfree->length = layout->oobfree[section].length;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = {
+	.ecc = mtd_ecclayout_ecc,
+	.free = mtd_ecclayout_free,
+};
+
+/**
+ * mtd_set_ecclayout - Attach an ecclayout to an MTD device
+ * @mtd: MTD device structure
+ * @ecclayout: The ecclayout to attach to the device
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
+{
+	if (!mtd || !ecclayout)
+		return;
+
+	mtd->ecclayout = ecclayout;
+	mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops);
+}
+EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
+
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index f53d9d7..1f13e32 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -317,6 +317,27 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	return res;
 }
 
+static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
+			      struct mtd_oob_region *oobregion)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	return mtd_ooblayout_ecc(part->master, section, oobregion);
+}
+
+static int part_ooblayout_free(struct mtd_info *mtd, int section,
+			       struct mtd_oob_region *oobregion)
+{
+	struct mtd_part *part = mtd_to_part(mtd);
+
+	return mtd_ooblayout_free(part->master, section, oobregion);
+}
+
+static const struct mtd_ooblayout_ops part_ooblayout_ops = {
+	.ecc = part_ooblayout_ecc,
+	.free = part_ooblayout_free,
+};
+
 static inline void free_partition(struct mtd_part *p)
 {
 	kfree(p->mtd.name);
@@ -533,7 +554,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
 			part->name);
 	}
 
-	mtd_set_ecclayout(&slave->mtd, master->ecclayout);
+	mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
 	slave->mtd.ecc_step_size = master->ecc_step_size;
 	slave->mtd.ecc_strength = master->ecc_strength;
 	slave->mtd.bitflip_threshold = master->bitflip_threshold;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 6250dd8..a38fe9a 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -101,6 +101,9 @@ struct mtd_oob_ops {
  * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
  * for export to user-space via the ECCGETLAYOUT ioctl.
  * nand_ecclayout should be expandable in the future simply by the above macros.
+ *
+ * This structure is now deprecated, you should use struct nand_ecclayout_ops
+ * to describe your OOB layout.
  */
 struct nand_ecclayout {
 	__u32 eccbytes;
@@ -123,6 +126,22 @@ struct mtd_oob_region {
 	u32 length;
 };
 
+/*
+ * struct mtd_ooblayout_ops - NAND OOB layout operations
+ * @ecc: function returning an ECC region in the OOB area.
+ *	 Should return -ERANGE if %section exceeds the total number of
+ *	 ECC sections.
+ * @free: function returning a free region in the OOB area.
+ *	  Should return -ERANGE if %section exceeds the total number of
+ *	  free sections.
+ */
+struct mtd_ooblayout_ops {
+	int (*ecc)(struct mtd_info *mtd, int section,
+		   struct mtd_oob_region *oobecc);
+	int (*free)(struct mtd_info *mtd, int section,
+		    struct mtd_oob_region *oobfree);
+};
+
 struct module;	/* only needed for owner field in mtd_info */
 
 struct mtd_info {
@@ -181,9 +200,12 @@ struct mtd_info {
 	const char *name;
 	int index;
 
-	/* ECC layout structure pointer - read only! */
+	/* [Deprecated] ECC layout structure pointer - read only! */
 	struct nand_ecclayout *ecclayout;
 
+	/* OOB layout description */
+	const struct mtd_ooblayout_ops *ooblayout;
+
 	/* the ecc step size. */
 	unsigned int ecc_step_size;
 
@@ -286,10 +308,12 @@ int mtd_ooblayout_set_databytes(struct mtd_info *mtd, const u8 *databuf,
 int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
 int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
 
-static inline void mtd_set_ecclayout(struct mtd_info *mtd,
-				     struct nand_ecclayout *ecclayout)
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
+
+static inline void mtd_set_ooblayout(struct mtd_info *mtd,
+				     const struct mtd_ooblayout_ops *ooblayout)
 {
-	mtd->ecclayout = ecclayout;
+	mtd->ooblayout = ooblayout;
 }
 
 static inline void mtd_set_of_node(struct mtd_info *mtd,
-- 
2.1.4

  parent reply	other threads:[~2016-02-04 10:23 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-04 10:06 [PATCH v2 00/51] mtd: rework ECC layout definition Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 01/51] mtd: kill the ecclayout->oobavail field Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 02/51] mtd: create an mtd_oobavail() helper and make use of it Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 03/51] mtd: mtdswap: remove useless if (!mtd->ecclayout) test Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 04/51] mtd: nand: simplify nand_bch_init() usage Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 05/51] mtd: add mtd_ooblayout_xxx() helper functions Boris Brezillon
2016-02-05  7:35   ` Boris Brezillon
2016-02-05  9:27   ` Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 06/51] mtd: use mtd_ooblayout_xxx() helpers where appropriate Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 07/51] mtd: nand: core: " Boris Brezillon
2016-02-05  9:31   ` Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 08/51] mtd: nand: atmel: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 09/51] mtd: nand: fsl_ifc: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 10/51] mtd: nand: gpmi: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 11/51] mtd: nand: lpc32xx: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 12/51] mtd: nand: omap2: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 13/51] mtd: onenand: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 14/51] mtd: add mtd_set_ecclayout() helper function Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 15/51] mtd: use mtd_set_ecclayout() where appropriate Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 16/51] mtd: nand: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 17/51] mtd: onenand: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 18/51] mtd: docg3: " Boris Brezillon
2016-02-06 21:55   ` Robert Jarzmik
2016-02-04 10:06 ` Boris Brezillon [this message]
2016-02-04 10:06 ` [PATCH v2 20/51] mtd: docg3: switch to mtd_ooblayout_ops Boris Brezillon
2016-02-06 21:57   ` Robert Jarzmik
2016-02-04 10:06 ` [PATCH v2 21/51] mtd: nand: implement the default mtd_ooblayout_ops Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 22/51] mtd: nand: bch: switch to mtd_ooblayout_ops Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 23/51] mtd: nand: sharpsl: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 24/51] mtd: nand: jz4740: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 25/51] mtd: nand: atmel: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 26/51] mtd: nand: bf5xx: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 27/51] mtd: nand: brcm: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 28/51] mtd: nand: cafe: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 29/51] mtd: nand: davinci: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 30/51] mtd: nand: denali: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 31/51] mtd: nand: diskonchip: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 32/51] mtd: nand: docg4: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 33/51] mtd: nand: fsl_elbc: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 34/51] mtd: nand: fsl_ifc: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 35/51] mtd: nand: fsmc: " Boris Brezillon
2016-02-04 10:06 ` [PATCH v2 36/51] mtd: nand: gpmi: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 37/51] mtd: nand: hisi504: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 38/51] mtd: nand: jz4780: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 39/51] mtd: nand: lpc32xx: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 40/51] mtd: nand: mxc: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 41/51] mtd: nand: omap2: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 42/51] mtd: nand: pxa3xx: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 43/51] mtd: nand: s3c2410: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 44/51] mtd: nand: sh_flctl: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 45/51] mtd: nand: sm_common: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 46/51] mtd: nand: sunxi: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 47/51] mtd: nand: vf610: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 48/51] mtd: onenand: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 49/51] staging: mt29f_spinand: " Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 50/51] mtd: nand: kill the ecc->layout field Boris Brezillon
2016-02-04 10:07 ` [PATCH v2 51/51] mtd: kill the nand_ecclayout struct Boris Brezillon

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=1454580434-32078-20-git-send-email-boris.brezillon@free-electrons.com \
    --to=boris.brezillon@free-electrons.com \
    --cc=computersforpeace@gmail.com \
    --cc=daniel@zonque.org \
    --cc=devel@driverdev.osuosl.org \
    --cc=dwmw2@infradead.org \
    --cc=ezequiel.garcia@free-electrons.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=haojian.zhuang@gmail.com \
    --cc=josh.wu@atmel.com \
    --cc=k.kozlowski@samsung.com \
    --cc=kgene@kernel.org \
    --cc=kyungmin.park@samsung.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux-sunxi@googlegroups.com \
    --cc=maxime.ripard@free-electrons.com \
    --cc=plaes@plaes.org \
    --cc=punnaia@xilinx.com \
    --cc=ralf@linux-mips.org \
    --cc=robert.jarzmik@free.fr \
    --cc=stefan@agner.ch \
    --cc=wens@csie.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).