All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@free-electrons.com>
To: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: linux-mtd@lists.infradead.org, Enrico Jorns <ejo@pengutronix.de>,
	Artem Bityutskiy <artem.bityutskiy@linux.intel.com>,
	Dinh Nguyen <dinguyen@kernel.org>,
	Marek Vasut <marek.vasut@gmail.com>,
	Graham Moore <grmoore@opensource.altera.com>,
	David Woodhouse <dwmw2@infradead.org>,
	Masami Hiramatsu <mhiramat@kernel.org>,
	Chuanxiao Dong <chuanxiao.dong@intel.com>,
	Jassi Brar <jaswinder.singh@linaro.org>,
	devicetree@vger.kernel.org,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	Brian Norris <computersforpeace@gmail.com>,
	Richard Weinberger <richard@nod.at>,
	Cyrille Pitchen <cyrille.pitchen@atmel.com>,
	Rob Herring <robh+dt@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>
Subject: Re: [PATCH v3 14/37] mtd: nand: denali: support "nand-ecc-strength" DT property
Date: Sun, 9 Apr 2017 18:33:01 +0200	[thread overview]
Message-ID: <20170409183301.037d3f95@bbrezillon> (raw)
In-Reply-To: <CAK7LNAToTmirpkhNmPCLhcTXG_SFqS762mEGK3mjyqLKXuWa1Q@mail.gmail.com>

On Mon, 3 Apr 2017 12:16:34 +0900
Masahiro Yamada <yamada.masahiro@socionext.com> wrote:

> Hi Boris,
> 
> 
> 
> 2017-03-31 18:46 GMT+09:00 Boris Brezillon <boris.brezillon@free-electrons.com>:
> 
> > You can try something like that when no explicit ecc.strength and
> > ecc.size has been set in the DT and when ECC_MAXIMIZE was not passed.
> >
> > static int
> > denali_get_closest_ecc_strength(struct denali_nand_info *denali,
> >                                 int strength)
> > {
> >         /*
> >          * Whatever you need to select a strength that is greater than
> >          * or equal to strength.
> >          */
> >
> >         return X;
> > }  
> 
> 
> Is here anything specific to Denali?

Well, only the denali driver knows what the hardware supports, though
having a generic function that takes a table of supported strengths
would work.

> 
> 
> > static int denali_try_to_match_ecc_req(struct denali_nand_info *denali)
> > {
> >         struct nand_chip *chip = &denali->nand;
> >         struct mtd_info *mtd = nand_to_mtd(chip);
> >         int max_ecc_bytes = mtd->oobsize - denali->bbtskipbytes;
> >         int ecc_steps, ecc_strength, ecc_bytes;
> >         int ecc_size = chip->ecc_step_ds;
> >         int ecc_strength = chip->ecc_strength_ds;
> >
> >         /*
> >          * No information provided by the NAND chip, let the core
> >          * maximize the strength.
> >          */
> >         if (!ecc_size || !ecc_strength)
> >                 return -ENOTSUPP;
> >
> >         if (ecc_size > 512)
> >                 ecc_size = 1024;
> >         else
> >                 ecc_size = 512;
> >
> >         /* Adjust ECC step size based on hardware support. */
> >         if (ecc_size == 1024 &&
> >             !(denali->caps & DENALI_CAP_ECC_SIZE_1024))
> >                 ecc_size = 512;
> >         else if(ecc_size == 512 &&
> >                 !(denali->caps & DENALI_CAP_ECC_SIZE_512))
> >                 ecc_size = 1024;
> >
> >         if (ecc_size < chip->ecc_size_ds) {
> >                 /*
> >                  * When the selected size if smaller than the expected
> >                  * one we try to use the same strength but on 512 blocks
> >                  * so that we can still fix the same number of errors
> >                  * even if they are concentrated in the first 512bytes
> >                  * of a 1024bytes portion.
> >                  */
> >                 ecc_strength = chip->ecc_strength_ds;
> >                 ecc_strength = denali_get_closest_ecc_strength(denali,
> >                                                                ecc_strength);
> >         } else {
> >                 /* Always prefer 1024bytes ECC blocks when possible. */
> >                 if (ecc_size != 1024 &&
> >                     (denali->caps & DENALI_CAP_ECC_SIZE_1024) &&
> >                     mtd->writesize > 1024)
> >                         ecc_size = 1024;
> >
> >                 /*
> >                  * Adjust the strength based on the selected ECC step
> >                  * size.
> >                  */
> >                 ecc_strength = DIV_ROUND_UP(ecc_size,
> >                                             chip->ecc_step_ds) *
> >                                chip->ecc_strength_ds;
> >         }
> >
> >         ecc_bytes = denali_calc_ecc_bytes(ecc_size,
> >                                           ecc_strength);
> >         ecc_bytes *= mtd->writesize / ecc_size;
> >
> >         /*
> >          * If we don't have enough space, let the core maximize
> >          * the strength.
> >          */
> >         if (ecc_bytes > max_ecc_bytes)
> >                 return -ENOTSUPP;
> >
> >         chip->ecc.strength = ecc_strength;
> >         chip->ecc.size = ecc_size;
> >
> >         return 0;
> > }  
> 
> 
> As a whole, this does not seem to driver-specific.

It's almost controller-agnostic, except for the denali_calc_ecc_bytes()
function, but I guess we could ask drivers to implement a hook that is
passed the ECC step size and strength and returns the associated
number of ECC bytes.

> 
> 
> [1] A driver provides some pairs of (ecc_strength, ecc_size)
>     it can support.
> 
> [2] The core framework knows the chip's requirement
>     (ecc_strength_ds, ecc_size_ds).
> 
> 
> Then, the core framework provides a function
> to return a most recommended (ecc_strength, ecc_size).
> 
> 
> 
> struct nand_ecc_spec {
>        int ecc_strength;
>        int ecc_size;
> };
> 
> /*
>  * This function choose the most recommented (ecc_str, ecc_size)
>  * "recommended" means: minimum ecc stregth that meets
>  * the chip's requirment.
>  *
>  *
>  * @chip   - nand_chip
>  * @controller_ecc_spec - Array of (ecc_str, ecc_size) supported by the
>                           controller. (terminated by NULL as sentinel)
>  */
> struct nand_ecc_spec * nand_try_to_match_ecc_req(struct nand_chip *chip,
>                                                  struct nand_ecc_spec
> *controller_ecc_spec)
> {
>       /*
>        * Return the pointer to the most recommended
>        * struct nand_ecc_spec.
>        * If nothing suitable found, return NULL.
>        */
> }
>

I like the idea, except I would do this slightly differently to avoid
declaring all combinations of stepsize and strengths

struct nand_ecc_stepsize_info {
	int stepsize;
	int nstrengths;
	int *strengths;
};

struct nand_ecc_engine_caps {
	int nstepsizes;
	struct nand_ecc_stepsize_info *stepsizes;
	int (*calc_ecc_bytes)(int stepsize, int strength);
};

int nand_try_to_match_ecc_req(struct nand_chip *chip,
			      const struct nand_ecc_engine_caps *caps,
			      struct nand_ecc_spec *spec)
{
	/*
	 * Find the most appropriate setting based on the ECC engine
	 * caps and fill the spec object accordingly.
	 * Returns 0 in case of success and a negative error code
	 * otherwise.
	 */
}

Note that nand_try_to_match_ecc_req() has to be more generic than
denali_try_to_match_ecc_req() WRT step sizes, which will probably
complexify the logic.

WARNING: multiple messages have this Message-ID (diff)
From: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
To: Masahiro Yamada
	<yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org>
Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Enrico Jorns <ejo-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
	Artem Bityutskiy
	<artem.bityutskiy-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	Dinh Nguyen <dinguyen-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	Marek Vasut <marek.vasut-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	Graham Moore
	<grmoore-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>,
	David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>,
	Masami Hiramatsu
	<mhiramat-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	Chuanxiao Dong
	<chuanxiao.dong-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
	Jassi Brar
	<jaswinder.singh-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Linux Kernel Mailing List
	<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	Brian Norris
	<computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	Richard Weinberger <richard-/L3Ra7n9ekc@public.gmane.org>,
	Cyrille Pitchen
	<cyrille.pitchen-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>,
	Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Subject: Re: [PATCH v3 14/37] mtd: nand: denali: support "nand-ecc-strength" DT property
Date: Sun, 9 Apr 2017 18:33:01 +0200	[thread overview]
Message-ID: <20170409183301.037d3f95@bbrezillon> (raw)
In-Reply-To: <CAK7LNAToTmirpkhNmPCLhcTXG_SFqS762mEGK3mjyqLKXuWa1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Mon, 3 Apr 2017 12:16:34 +0900
Masahiro Yamada <yamada.masahiro-uWyLwvC0a2jby3iVrkZq2A@public.gmane.org> wrote:

> Hi Boris,
> 
> 
> 
> 2017-03-31 18:46 GMT+09:00 Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>:
> 
> > You can try something like that when no explicit ecc.strength and
> > ecc.size has been set in the DT and when ECC_MAXIMIZE was not passed.
> >
> > static int
> > denali_get_closest_ecc_strength(struct denali_nand_info *denali,
> >                                 int strength)
> > {
> >         /*
> >          * Whatever you need to select a strength that is greater than
> >          * or equal to strength.
> >          */
> >
> >         return X;
> > }  
> 
> 
> Is here anything specific to Denali?

Well, only the denali driver knows what the hardware supports, though
having a generic function that takes a table of supported strengths
would work.

> 
> 
> > static int denali_try_to_match_ecc_req(struct denali_nand_info *denali)
> > {
> >         struct nand_chip *chip = &denali->nand;
> >         struct mtd_info *mtd = nand_to_mtd(chip);
> >         int max_ecc_bytes = mtd->oobsize - denali->bbtskipbytes;
> >         int ecc_steps, ecc_strength, ecc_bytes;
> >         int ecc_size = chip->ecc_step_ds;
> >         int ecc_strength = chip->ecc_strength_ds;
> >
> >         /*
> >          * No information provided by the NAND chip, let the core
> >          * maximize the strength.
> >          */
> >         if (!ecc_size || !ecc_strength)
> >                 return -ENOTSUPP;
> >
> >         if (ecc_size > 512)
> >                 ecc_size = 1024;
> >         else
> >                 ecc_size = 512;
> >
> >         /* Adjust ECC step size based on hardware support. */
> >         if (ecc_size == 1024 &&
> >             !(denali->caps & DENALI_CAP_ECC_SIZE_1024))
> >                 ecc_size = 512;
> >         else if(ecc_size == 512 &&
> >                 !(denali->caps & DENALI_CAP_ECC_SIZE_512))
> >                 ecc_size = 1024;
> >
> >         if (ecc_size < chip->ecc_size_ds) {
> >                 /*
> >                  * When the selected size if smaller than the expected
> >                  * one we try to use the same strength but on 512 blocks
> >                  * so that we can still fix the same number of errors
> >                  * even if they are concentrated in the first 512bytes
> >                  * of a 1024bytes portion.
> >                  */
> >                 ecc_strength = chip->ecc_strength_ds;
> >                 ecc_strength = denali_get_closest_ecc_strength(denali,
> >                                                                ecc_strength);
> >         } else {
> >                 /* Always prefer 1024bytes ECC blocks when possible. */
> >                 if (ecc_size != 1024 &&
> >                     (denali->caps & DENALI_CAP_ECC_SIZE_1024) &&
> >                     mtd->writesize > 1024)
> >                         ecc_size = 1024;
> >
> >                 /*
> >                  * Adjust the strength based on the selected ECC step
> >                  * size.
> >                  */
> >                 ecc_strength = DIV_ROUND_UP(ecc_size,
> >                                             chip->ecc_step_ds) *
> >                                chip->ecc_strength_ds;
> >         }
> >
> >         ecc_bytes = denali_calc_ecc_bytes(ecc_size,
> >                                           ecc_strength);
> >         ecc_bytes *= mtd->writesize / ecc_size;
> >
> >         /*
> >          * If we don't have enough space, let the core maximize
> >          * the strength.
> >          */
> >         if (ecc_bytes > max_ecc_bytes)
> >                 return -ENOTSUPP;
> >
> >         chip->ecc.strength = ecc_strength;
> >         chip->ecc.size = ecc_size;
> >
> >         return 0;
> > }  
> 
> 
> As a whole, this does not seem to driver-specific.

It's almost controller-agnostic, except for the denali_calc_ecc_bytes()
function, but I guess we could ask drivers to implement a hook that is
passed the ECC step size and strength and returns the associated
number of ECC bytes.

> 
> 
> [1] A driver provides some pairs of (ecc_strength, ecc_size)
>     it can support.
> 
> [2] The core framework knows the chip's requirement
>     (ecc_strength_ds, ecc_size_ds).
> 
> 
> Then, the core framework provides a function
> to return a most recommended (ecc_strength, ecc_size).
> 
> 
> 
> struct nand_ecc_spec {
>        int ecc_strength;
>        int ecc_size;
> };
> 
> /*
>  * This function choose the most recommented (ecc_str, ecc_size)
>  * "recommended" means: minimum ecc stregth that meets
>  * the chip's requirment.
>  *
>  *
>  * @chip   - nand_chip
>  * @controller_ecc_spec - Array of (ecc_str, ecc_size) supported by the
>                           controller. (terminated by NULL as sentinel)
>  */
> struct nand_ecc_spec * nand_try_to_match_ecc_req(struct nand_chip *chip,
>                                                  struct nand_ecc_spec
> *controller_ecc_spec)
> {
>       /*
>        * Return the pointer to the most recommended
>        * struct nand_ecc_spec.
>        * If nothing suitable found, return NULL.
>        */
> }
>

I like the idea, except I would do this slightly differently to avoid
declaring all combinations of stepsize and strengths

struct nand_ecc_stepsize_info {
	int stepsize;
	int nstrengths;
	int *strengths;
};

struct nand_ecc_engine_caps {
	int nstepsizes;
	struct nand_ecc_stepsize_info *stepsizes;
	int (*calc_ecc_bytes)(int stepsize, int strength);
};

int nand_try_to_match_ecc_req(struct nand_chip *chip,
			      const struct nand_ecc_engine_caps *caps,
			      struct nand_ecc_spec *spec)
{
	/*
	 * Find the most appropriate setting based on the ECC engine
	 * caps and fill the spec object accordingly.
	 * Returns 0 in case of success and a negative error code
	 * otherwise.
	 */
}

Note that nand_try_to_match_ecc_req() has to be more generic than
denali_try_to_match_ecc_req() WRT step sizes, which will probably
complexify the logic.


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2017-04-09 16:33 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-03-30  6:45 [PATCH v3 00/37] mtd: nand: denali: 2nd round of Denali NAND IP patch bomb Masahiro Yamada
2017-03-30  6:45 ` Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 01/37] mtd: nand: relax ecc.read_page() return value for uncorrectable ECC Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 02/37] mtd: nand: denali: allow to override mtd->name from label DT property Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 03/37] mtd: nand: denali: remove meaningless pipeline read-ahead operation Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 04/37] mtd: nand: denali: fix bitflips calculation in handle_ecc() Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 05/37] mtd: nand: denali: fix erased page checking Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 06/37] mtd: nand: denali: support HW_ECC_FIXUP capability Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 07/37] mtd: nand: denali_dt: enable HW_ECC_FIXUP for Altera SOCFPGA variant Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 08/37] mtd: nand: denali: support 64bit capable DMA engine Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 09/37] mtd: nand: denali_dt: remove dma-mask DT property Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 10/37] mtd: nand: denali_dt: use pdev instead of ofdev for platform_device Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 11/37] mtd: nand: denali: allow to override revision number Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 12/37] mtd: nand: denali: support 1024 byte ECC step size Masahiro Yamada
2017-03-30  6:45   ` Masahiro Yamada
2017-04-01  8:43   ` Masahiro Yamada
2017-04-01  8:43     ` Masahiro Yamada
2017-03-30  6:45 ` [PATCH v3 13/37] mtd: nand: denali: avoid hard-coding ecc.strength and ecc.bytes Masahiro Yamada
2017-03-31  9:09   ` Boris Brezillon
2017-03-30  6:46 ` [PATCH v3 14/37] mtd: nand: denali: support "nand-ecc-strength" DT property Masahiro Yamada
2017-03-30  6:46   ` Masahiro Yamada
2017-03-30 14:02   ` Boris Brezillon
2017-03-30 14:02     ` Boris Brezillon
2017-03-31  5:06     ` Masahiro Yamada
2017-03-31  9:46       ` Boris Brezillon
2017-04-03  3:16         ` Masahiro Yamada
2017-04-03  3:16           ` Masahiro Yamada
2017-04-09 16:33           ` Boris Brezillon [this message]
2017-04-09 16:33             ` Boris Brezillon
2017-04-11  6:19             ` Masahiro Yamada
2017-04-11  6:19               ` Masahiro Yamada
2017-04-11  7:56               ` Boris Brezillon
2017-04-11  7:56                 ` Boris Brezillon
2017-04-14  7:57                 ` Masahiro Yamada
2017-04-14  8:19                   ` Boris Brezillon
2017-04-14  8:19                     ` Boris Brezillon
2017-04-22 15:00                     ` Masahiro Yamada
2017-04-22 15:00                       ` Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 15/37] mtd: nand: denali: remove Toshiba and Hynix specific fixup code Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 16/37] mtd: nand: denali_dt: add compatible strings for UniPhier SoC variants Masahiro Yamada
2017-04-03 15:46   ` Rob Herring
2017-04-03 15:46     ` Rob Herring
2017-03-30  6:46 ` [PATCH v3 17/37] mtd: nand: denali: set NAND_ECC_CUSTOM_PAGE_ACCESS Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 18/37] mtd: nand: denali: do not propagate NAND_STATUS_FAIL to waitfunc() Masahiro Yamada
2017-03-30 15:17   ` Boris Brezillon
2017-03-30  6:46 ` [PATCH v3 19/37] mtd: nand: denali: use BIT() and GENMASK() for register macros Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 20/37] mtd: nand: denali: remove unneeded find_valid_banks() Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 21/37] mtd: nand: denali: handle timing parameters by setup_data_interface() Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 22/37] mtd: nand: denali: rework interrupt handling Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 23/37] mtd: nand: denali: fix NAND_CMD_STATUS handling Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 24/37] mtd: nand: denali: fix NAND_CMD_PARAM handling Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 25/37] mtd: nand: denali: switch over to cmd_ctrl instead of cmdfunc Masahiro Yamada
2017-03-30 15:55   ` Boris Brezillon
2017-03-30  6:46 ` [PATCH v3 26/37] mtd: nand: denali: fix bank reset function Masahiro Yamada
2017-03-30 16:16   ` Boris Brezillon
2017-04-03  7:05     ` Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 27/37] mtd: nand: denali: use interrupt instead of polling for bank reset Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 28/37] mtd: nand: denali: propagate page to helpers via function argument Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 29/37] mtd: nand: denali: merge struct nand_buf into struct denali_nand_info Masahiro Yamada
2017-03-30  6:46 ` [PATCH v3 30/37] mtd: nand: denali: use flag instead of register macro for direction Masahiro Yamada
2017-03-30 16:38 ` [PATCH v3 00/37] mtd: nand: denali: 2nd round of Denali NAND IP patch bomb Boris Brezillon
2017-03-30 16:38   ` Boris Brezillon
2017-03-31  4:05   ` Masahiro Yamada
2017-03-31  8:27     ` 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=20170409183301.037d3f95@bbrezillon \
    --to=boris.brezillon@free-electrons.com \
    --cc=artem.bityutskiy@linux.intel.com \
    --cc=chuanxiao.dong@intel.com \
    --cc=computersforpeace@gmail.com \
    --cc=cyrille.pitchen@atmel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dinguyen@kernel.org \
    --cc=dwmw2@infradead.org \
    --cc=ejo@pengutronix.de \
    --cc=grmoore@opensource.altera.com \
    --cc=jaswinder.singh@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=marek.vasut@gmail.com \
    --cc=mark.rutland@arm.com \
    --cc=mhiramat@kernel.org \
    --cc=richard@nod.at \
    --cc=robh+dt@kernel.org \
    --cc=yamada.masahiro@socionext.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.