All of lore.kernel.org
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@collabora.com>
To: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Vignesh Raghavendra <vigneshr@ti.com>,
	Tudor Ambarus <Tudor.Ambarus@microchip.com>,
	Julien Su <juliensu@mxic.com.tw>,
	Richard Weinberger <richard@nod.at>,
	linux-mtd@lists.infradead.org,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	Mason Yang <masonccyang@mxic.com.tw>,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v9 9/9] mtd: rawnand: Move the user input parsing bits to the ECC framework
Date: Tue, 2 Jun 2020 18:18:58 +0200	[thread overview]
Message-ID: <20200602181858.0565ad31@collabora.com> (raw)
In-Reply-To: <20200602143124.29553-10-miquel.raynal@bootlin.com>

On Tue,  2 Jun 2020 16:31:24 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Many helpers are generic to all NAND chips, they should not be
> restricted to be only used by raw NAND controller drivers. They might
> later be used by generic ECC engines and SPI-NAND devices as well so
> move them into a more generic place.
> 
> To avoid moving all the raw NAND core "history" into the generic NAND
> layer, we already moved certain bits into legacy helpers in the raw
> NAND core to ensure backward compatibility.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/ecc.c                       | 138 +++++++++++++++++
>  drivers/mtd/nand/raw/atmel/nand-controller.c |   3 +-
>  drivers/mtd/nand/raw/denali.c                |   3 +
>  drivers/mtd/nand/raw/nand_base.c             | 150 ++-----------------
>  drivers/mtd/nand/raw/sunxi_nand.c            |   3 +-
>  drivers/mtd/nand/raw/tegra_nand.c            |   5 +-
>  include/linux/mtd/nand.h                     |   7 +
>  include/linux/mtd/rawnand.h                  |   1 -
>  8 files changed, 166 insertions(+), 144 deletions(-)
> 
> diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
> index ad08a047dfc5..1ac7aaa6c6c2 100644
> --- a/drivers/mtd/nand/ecc.c
> +++ b/drivers/mtd/nand/ecc.c
> @@ -328,6 +328,144 @@ const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void)
>  }
>  EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout);
>  
> +static enum nand_ecc_engine_type
> +of_get_nand_ecc_engine_type(struct device_node *np)
> +{
> +	return NAND_ECC_ENGINE_TYPE_INVALID;
> +}
> +
> +static const char * const nand_ecc_placement[] = {
> +	[NAND_ECC_PLACEMENT_OOB] = "oob",
> +	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
> +};
> +
> +enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
> +{
> +	enum nand_ecc_placement placement;
> +	const char *pm;
> +	int err;
> +
> +	err = of_property_read_string(np, "nand-ecc-placement", &pm);
> +	if (!err) {
> +		for (placement = NAND_ECC_PLACEMENT_OOB;
> +		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
> +			if (!strcasecmp(pm, nand_ecc_placement[placement]))
> +				return placement;
> +		}
> +	}
> +
> +	return NAND_ECC_PLACEMENT_UNKNOWN;
> +}
> +
> +static const char * const nand_ecc_algos[] = {
> +	[NAND_ECC_ALGO_HAMMING]	= "hamming",
> +	[NAND_ECC_ALGO_BCH]	= "bch",
> +	[NAND_ECC_ALGO_RS]	= "rs",

Can we use spaces instead of tabs, as done for nand_ecc_placement?

> +};
> +
> +static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
> +{
> +	enum nand_ecc_algo ecc_algo;
> +	const char *pm;
> +	int err;
> +
> +	err = of_property_read_string(np, "nand-ecc-algo", &pm);
> +	if (!err) {
> +		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
> +		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
> +		     ecc_algo++) {
> +			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
> +				return ecc_algo;
> +		}
> +	}
> +
> +	return NAND_ECC_ALGO_UNKNOWN;
> +}
> +
> +static int of_get_nand_ecc_step_size(struct device_node *np)
> +{
> +	int ret;
> +	u32 val;
> +
> +	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
> +	return ret ? ret : val;
> +}
> +
> +static int of_get_nand_ecc_strength(struct device_node *np)
> +{
> +	int ret;
> +	u32 val;
> +
> +	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
> +	return ret ? ret : val;
> +}
> +
> +static inline bool of_get_nand_ecc_maximize(struct device_node *np)
> +{
> +	return of_property_read_bool(np, "nand-ecc-maximize");
> +}
> +
> +void nand_ecc_read_user_conf(struct nand_device *nand)
> +{
> +	struct device_node *dn = nanddev_get_of_node(nand);
> +	int strength, size;
> +
> +	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
> +	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
> +	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
> +
> +	strength = of_get_nand_ecc_strength(dn);
> +	if (strength >= 0)
> +		nand->ecc.user_conf.strength = strength;
> +
> +	size = of_get_nand_ecc_step_size(dn);
> +	if (size >= 0)
> +		nand->ecc.user_conf.step_size = size;
> +
> +	if (of_get_nand_ecc_maximize(dn))
> +		nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
> +}
> +EXPORT_SYMBOL(nand_ecc_read_user_conf);
> +
> +/**
> + * nand_ecc_correction_is_enough - Check if the chip configuration meets the
> + *                                 datasheet requirements.
> + *
> + * @nand: Device to check
> + *
> + * If our configuration corrects A bits per B bytes and the minimum
> + * required correction level is X bits per Y bytes, then we must ensure
> + * both of the following are true:
> + *
> + * (1) A / B >= X / Y
> + * (2) A >= X
> + *
> + * Requirement (1) ensures we can correct for the required bitflip density.
> + * Requirement (2) ensures we can correct even when all bitflips are clumped
> + * in the same sector.
> + */
> +bool nand_ecc_correction_is_enough(struct nand_device *nand)

nand_ecc_is_strong_enough() ?

> +{
> +	const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand);
> +	const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand);
> +	struct mtd_info *mtd = nanddev_to_mtd(nand);
> +	int corr, ds_corr;
> +
> +	if (conf->step_size == 0 || reqs->step_size == 0)
> +		/* Not enough information */
> +		return true;
> +
> +	/*
> +	 * We get the number of corrected bits per page to compare
> +	 * the correction density.
> +	 */
> +	corr = (mtd->writesize * conf->strength) / conf->step_size;
> +	ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
> +
> +	return corr >= ds_corr && conf->strength >= reqs->strength;
> +}
> +EXPORT_SYMBOL(nand_ecc_correction_is_enough);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
>  MODULE_DESCRIPTION("Generic ECC engine");
> diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
> index 08df7f23b859..39d8fe15b8ab 100644
> --- a/drivers/mtd/nand/raw/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
> @@ -1046,6 +1046,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
>  	const struct nand_ecc_props *requirements =
>  		nanddev_get_ecc_requirements(&chip->base);
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct atmel_nand *nand = to_atmel_nand(chip);
>  	struct atmel_nand_controller *nc;
>  	struct atmel_pmecc_user_req req;
> @@ -1070,7 +1071,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
>  			chip->ecc.size = val;
>  	}
>  
> -	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
> +	if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
>  		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;

I'd prefer to have that done in 2 steps:

1/ move/duplicate definitions found in rawnand.h
2/ patch rawnand code to finally use the nanddev->ecc.user_conf object
   for the ECC config.

>  	else if (chip->ecc.strength)
>  		req.ecc.strength = chip->ecc.strength;
> diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
> index a6a6464974ec..51bc014ebc0a 100644
> --- a/drivers/mtd/nand/raw/denali.c
> +++ b/drivers/mtd/nand/raw/denali.c
> @@ -1181,6 +1181,7 @@ int denali_chip_init(struct denali_controller *denali,
>  {
>  	struct nand_chip *chip = &dchip->chip;
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct denali_chip *dchip2;
>  	int i, j, ret;
>  
> @@ -1248,6 +1249,8 @@ int denali_chip_init(struct denali_controller *denali,
>  
>  	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
>  
> +	nanddev->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
> +

Is that correct? I don't find the 

	chip->ecc.options |= NAND_ECC_MAXIMIZE;

removal that this line is replacing.

>  	ret = nand_scan(chip, dchip->nsels);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index afc3506468ba..036e88cb52a1 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -4854,17 +4854,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
>  	return ret;
>  }
>  
> -static const char * const nand_ecc_placement[] = {
> -	[NAND_ECC_PLACEMENT_OOB] = "oob",
> -	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
> -};
> -
> -static enum nand_ecc_engine_type
> -of_get_nand_ecc_engine_type(struct device_node *np)
> -{
> -	return NAND_ECC_ENGINE_TYPE_INVALID;
> -}
> -
>  static enum nand_ecc_engine_type
>  of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
>  {
> @@ -4916,24 +4905,6 @@ of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
>  	return NAND_ECC_ENGINE_TYPE_INVALID;
>  }
>  
> -enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
> -{
> -	enum nand_ecc_placement placement;
> -	const char *pm;
> -	int err;
> -
> -	err = of_property_read_string(np, "nand-ecc-placement", &pm);
> -	if (!err) {
> -		for (placement = NAND_ECC_PLACEMENT_OOB;
> -		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
> -			if (!strcasecmp(pm, nand_ecc_placement[placement]))
> -				return placement;
> -		}
> -	}
> -
> -	return NAND_ECC_PLACEMENT_UNKNOWN;
> -}
> -
>  enum nand_ecc_placement
>  of_get_rawnand_ecc_placement_legacy(struct device_node *np)
>  {
> @@ -4949,31 +4920,6 @@ of_get_rawnand_ecc_placement_legacy(struct device_node *np)
>  	return NAND_ECC_PLACEMENT_UNKNOWN;
>  }
>  
> -static const char * const nand_ecc_algos[] = {
> -	[NAND_ECC_ALGO_HAMMING]	= "hamming",
> -	[NAND_ECC_ALGO_BCH]	= "bch",
> -	[NAND_ECC_ALGO_RS]	= "rs",
> -};
> -
> -static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
> -{
> -	enum nand_ecc_algo ecc_algo;
> -	const char *pm;
> -	int err;
> -
> -	err = of_property_read_string(np, "nand-ecc-algo", &pm);
> -	if (!err) {
> -		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
> -		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
> -		     ecc_algo++) {
> -			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
> -				return ecc_algo;
> -		}
> -	}
> -
> -	return NAND_ECC_ALGO_UNKNOWN;
> -}
> -
>  static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
>  {
>  	const char *pm;
> @@ -4990,48 +4936,10 @@ static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
>  	return NAND_ECC_ALGO_UNKNOWN;
>  }
>  
> -static int of_get_nand_ecc_step_size(struct device_node *np)
> -{
> -	int ret;
> -	u32 val;
> -
> -	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
> -	return ret ? ret : val;
> -}
> -
> -static int of_get_nand_ecc_strength(struct device_node *np)
> -{
> -	int ret;
> -	u32 val;
> -
> -	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
> -	return ret ? ret : val;
> -}
> -
> -static void nand_ecc_read_user_conf(struct nand_chip *chip)
> -{
> -	struct device_node *dn = nand_get_flash_node(chip);
> -	struct nand_device *nand = &chip->base;
> -	int strength, size;
> -
> -	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
> -	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
> -	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
> -
> -	strength = of_get_nand_ecc_strength(dn);
> -	if (strength >= 0)
> -		nand->ecc.user_conf.strength = strength;
> -
> -	size = of_get_nand_ecc_step_size(dn);
> -	if (size >= 0)
> -		nand->ecc.user_conf.step_size = size;
> -}
> -
>  static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip)
>  {
>  	struct device_node *dn = nand_get_flash_node(chip);
> -	struct nand_device *nand = &chip->base;
> -	struct nand_ecc_props *user_conf = &nand->ecc.user_conf;
> +	struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf;
>  
>  	if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
>  		user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);
> @@ -5081,10 +4989,7 @@ static int rawnand_dt_init(struct nand_chip *chip)
>  	if (of_get_nand_on_flash_bbt(dn))
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
>  
> -	if (of_property_read_bool(dn, "nand-ecc-maximize"))
> -		chip->ecc.options |= NAND_ECC_MAXIMIZE;
> -
> -	nand_ecc_read_user_conf(chip);
> +	nand_ecc_read_user_conf(nand);
>  	rawnand_ecc_read_legacy_user_conf(chip);
>  
>  	/*
> @@ -5214,6 +5119,7 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
>  static int nand_set_ecc_soft_ops(struct nand_chip *chip)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct nand_ecc_ctrl *ecc = &chip->ecc;
>  
>  	if (WARN_ON(ecc->engine_type != NAND_ECC_ENGINE_TYPE_SOFT))
> @@ -5289,7 +5195,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
>  		 * used.
>  		 */
>  		if (mtd->ooblayout == nand_get_large_page_ooblayout() &&
> -		    ecc->options & NAND_ECC_MAXIMIZE) {
> +		    nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) {
>  			int steps, bytes;
>  
>  			/* Always prefer 1k blocks over 512bytes ones */
> @@ -5529,11 +5435,12 @@ nand_maximize_ecc(struct nand_chip *chip,
>   * @caps: ECC engine caps info structure
>   * @oobavail: OOB size that the ECC engine can use
>   *
> - * Choose the ECC configuration according to following logic
> + * Choose the ECC configuration according to following logic.
>   *
>   * 1. If both ECC step size and ECC strength are already set (usually by DT)
>   *    then check if it is supported by this controller.
> - * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 2. If the user provided the nand-ecc-maximize property, then select maximum
> + *    ECC strength.
>   * 3. Otherwise, try to match the ECC step size and ECC strength closest
>   *    to the chip's requirement. If available OOB size can't fit the chip
>   *    requirement then fallback to the maximum ECC step size and ECC strength.
> @@ -5544,6 +5451,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  			 const struct nand_ecc_caps *caps, int oobavail)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  
>  	if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
>  		return -EINVAL;
> @@ -5551,7 +5459,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  	if (chip->ecc.size && chip->ecc.strength)
>  		return nand_check_ecc_caps(chip, caps, oobavail);
>  
> -	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
> +	if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
>  		return nand_maximize_ecc(chip, caps, oobavail);
>  
>  	if (!nand_match_ecc_req(chip, caps, oobavail))
> @@ -5561,43 +5469,6 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
>  
> -/*
> - * Check if the chip configuration meet the datasheet requirements.
> -
> - * If our configuration corrects A bits per B bytes and the minimum
> - * required correction level is X bits per Y bytes, then we must ensure
> - * both of the following are true:
> - *
> - * (1) A / B >= X / Y
> - * (2) A >= X
> - *
> - * Requirement (1) ensures we can correct for the required bitflip density.
> - * Requirement (2) ensures we can correct even when all bitflips are clumped
> - * in the same sector.
> - */
> -static bool nand_ecc_strength_good(struct nand_chip *chip)
> -{
> -	struct mtd_info *mtd = nand_to_mtd(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	const struct nand_ecc_props *requirements =
> -		nanddev_get_ecc_requirements(&chip->base);
> -	int corr, ds_corr;
> -
> -	if (ecc->size == 0 || requirements->step_size == 0)
> -		/* Not enough information */
> -		return true;
> -
> -	/*
> -	 * We get the number of corrected bits per page to compare
> -	 * the correction density.
> -	 */
> -	corr = (mtd->writesize * ecc->strength) / ecc->size;
> -	ds_corr = (mtd->writesize * requirements->strength) /
> -		  requirements->step_size;
> -
> -	return corr >= ds_corr && ecc->strength >= requirements->strength;
> -}
> -
>  static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
>  {
>  	struct nand_chip *chip = container_of(nand, struct nand_chip,
> @@ -5653,6 +5524,7 @@ static const struct nand_ops rawnand_ops = {
>  static int nand_scan_tail(struct nand_chip *chip)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct nand_ecc_ctrl *ecc = &chip->ecc;
>  	int ret, i;
>  
> @@ -5880,7 +5752,7 @@ static int nand_scan_tail(struct nand_chip *chip)
>  	mtd->oobavail = ret;
>  
>  	/* ECC sanity check: warn if it's too weak */
> -	if (!nand_ecc_strength_good(chip))
> +	if (!nand_ecc_correction_is_enough(nanddev))

Can we do this rename separately?

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

WARNING: multiple messages have this Message-ID (diff)
From: Boris Brezillon <boris.brezillon@collabora.com>
To: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Vignesh Raghavendra <vigneshr@ti.com>,
	Tudor Ambarus <Tudor.Ambarus@microchip.com>,
	Julien Su <juliensu@mxic.com.tw>,
	Richard Weinberger <richard@nod.at>,
	linux-mtd@lists.infradead.org,
	Thomas Petazzoni <thomas.petazzoni@bootlin.com>,
	Mason Yang <masonccyang@mxic.com.tw>,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v9 9/9] mtd: rawnand: Move the user input parsing bits to the ECC framework
Date: Tue, 2 Jun 2020 18:18:58 +0200	[thread overview]
Message-ID: <20200602181858.0565ad31@collabora.com> (raw)
In-Reply-To: <20200602143124.29553-10-miquel.raynal@bootlin.com>

On Tue,  2 Jun 2020 16:31:24 +0200
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Many helpers are generic to all NAND chips, they should not be
> restricted to be only used by raw NAND controller drivers. They might
> later be used by generic ECC engines and SPI-NAND devices as well so
> move them into a more generic place.
> 
> To avoid moving all the raw NAND core "history" into the generic NAND
> layer, we already moved certain bits into legacy helpers in the raw
> NAND core to ensure backward compatibility.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/ecc.c                       | 138 +++++++++++++++++
>  drivers/mtd/nand/raw/atmel/nand-controller.c |   3 +-
>  drivers/mtd/nand/raw/denali.c                |   3 +
>  drivers/mtd/nand/raw/nand_base.c             | 150 ++-----------------
>  drivers/mtd/nand/raw/sunxi_nand.c            |   3 +-
>  drivers/mtd/nand/raw/tegra_nand.c            |   5 +-
>  include/linux/mtd/nand.h                     |   7 +
>  include/linux/mtd/rawnand.h                  |   1 -
>  8 files changed, 166 insertions(+), 144 deletions(-)
> 
> diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
> index ad08a047dfc5..1ac7aaa6c6c2 100644
> --- a/drivers/mtd/nand/ecc.c
> +++ b/drivers/mtd/nand/ecc.c
> @@ -328,6 +328,144 @@ const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void)
>  }
>  EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout);
>  
> +static enum nand_ecc_engine_type
> +of_get_nand_ecc_engine_type(struct device_node *np)
> +{
> +	return NAND_ECC_ENGINE_TYPE_INVALID;
> +}
> +
> +static const char * const nand_ecc_placement[] = {
> +	[NAND_ECC_PLACEMENT_OOB] = "oob",
> +	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
> +};
> +
> +enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
> +{
> +	enum nand_ecc_placement placement;
> +	const char *pm;
> +	int err;
> +
> +	err = of_property_read_string(np, "nand-ecc-placement", &pm);
> +	if (!err) {
> +		for (placement = NAND_ECC_PLACEMENT_OOB;
> +		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
> +			if (!strcasecmp(pm, nand_ecc_placement[placement]))
> +				return placement;
> +		}
> +	}
> +
> +	return NAND_ECC_PLACEMENT_UNKNOWN;
> +}
> +
> +static const char * const nand_ecc_algos[] = {
> +	[NAND_ECC_ALGO_HAMMING]	= "hamming",
> +	[NAND_ECC_ALGO_BCH]	= "bch",
> +	[NAND_ECC_ALGO_RS]	= "rs",

Can we use spaces instead of tabs, as done for nand_ecc_placement?

> +};
> +
> +static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
> +{
> +	enum nand_ecc_algo ecc_algo;
> +	const char *pm;
> +	int err;
> +
> +	err = of_property_read_string(np, "nand-ecc-algo", &pm);
> +	if (!err) {
> +		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
> +		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
> +		     ecc_algo++) {
> +			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
> +				return ecc_algo;
> +		}
> +	}
> +
> +	return NAND_ECC_ALGO_UNKNOWN;
> +}
> +
> +static int of_get_nand_ecc_step_size(struct device_node *np)
> +{
> +	int ret;
> +	u32 val;
> +
> +	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
> +	return ret ? ret : val;
> +}
> +
> +static int of_get_nand_ecc_strength(struct device_node *np)
> +{
> +	int ret;
> +	u32 val;
> +
> +	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
> +	return ret ? ret : val;
> +}
> +
> +static inline bool of_get_nand_ecc_maximize(struct device_node *np)
> +{
> +	return of_property_read_bool(np, "nand-ecc-maximize");
> +}
> +
> +void nand_ecc_read_user_conf(struct nand_device *nand)
> +{
> +	struct device_node *dn = nanddev_get_of_node(nand);
> +	int strength, size;
> +
> +	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
> +	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
> +	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
> +
> +	strength = of_get_nand_ecc_strength(dn);
> +	if (strength >= 0)
> +		nand->ecc.user_conf.strength = strength;
> +
> +	size = of_get_nand_ecc_step_size(dn);
> +	if (size >= 0)
> +		nand->ecc.user_conf.step_size = size;
> +
> +	if (of_get_nand_ecc_maximize(dn))
> +		nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
> +}
> +EXPORT_SYMBOL(nand_ecc_read_user_conf);
> +
> +/**
> + * nand_ecc_correction_is_enough - Check if the chip configuration meets the
> + *                                 datasheet requirements.
> + *
> + * @nand: Device to check
> + *
> + * If our configuration corrects A bits per B bytes and the minimum
> + * required correction level is X bits per Y bytes, then we must ensure
> + * both of the following are true:
> + *
> + * (1) A / B >= X / Y
> + * (2) A >= X
> + *
> + * Requirement (1) ensures we can correct for the required bitflip density.
> + * Requirement (2) ensures we can correct even when all bitflips are clumped
> + * in the same sector.
> + */
> +bool nand_ecc_correction_is_enough(struct nand_device *nand)

nand_ecc_is_strong_enough() ?

> +{
> +	const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand);
> +	const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand);
> +	struct mtd_info *mtd = nanddev_to_mtd(nand);
> +	int corr, ds_corr;
> +
> +	if (conf->step_size == 0 || reqs->step_size == 0)
> +		/* Not enough information */
> +		return true;
> +
> +	/*
> +	 * We get the number of corrected bits per page to compare
> +	 * the correction density.
> +	 */
> +	corr = (mtd->writesize * conf->strength) / conf->step_size;
> +	ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size;
> +
> +	return corr >= ds_corr && conf->strength >= reqs->strength;
> +}
> +EXPORT_SYMBOL(nand_ecc_correction_is_enough);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
>  MODULE_DESCRIPTION("Generic ECC engine");
> diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c
> index 08df7f23b859..39d8fe15b8ab 100644
> --- a/drivers/mtd/nand/raw/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c
> @@ -1046,6 +1046,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
>  	const struct nand_ecc_props *requirements =
>  		nanddev_get_ecc_requirements(&chip->base);
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct atmel_nand *nand = to_atmel_nand(chip);
>  	struct atmel_nand_controller *nc;
>  	struct atmel_pmecc_user_req req;
> @@ -1070,7 +1071,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip)
>  			chip->ecc.size = val;
>  	}
>  
> -	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
> +	if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
>  		req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH;

I'd prefer to have that done in 2 steps:

1/ move/duplicate definitions found in rawnand.h
2/ patch rawnand code to finally use the nanddev->ecc.user_conf object
   for the ECC config.

>  	else if (chip->ecc.strength)
>  		req.ecc.strength = chip->ecc.strength;
> diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
> index a6a6464974ec..51bc014ebc0a 100644
> --- a/drivers/mtd/nand/raw/denali.c
> +++ b/drivers/mtd/nand/raw/denali.c
> @@ -1181,6 +1181,7 @@ int denali_chip_init(struct denali_controller *denali,
>  {
>  	struct nand_chip *chip = &dchip->chip;
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct denali_chip *dchip2;
>  	int i, j, ret;
>  
> @@ -1248,6 +1249,8 @@ int denali_chip_init(struct denali_controller *denali,
>  
>  	mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
>  
> +	nanddev->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE;
> +

Is that correct? I don't find the 

	chip->ecc.options |= NAND_ECC_MAXIMIZE;

removal that this line is replacing.

>  	ret = nand_scan(chip, dchip->nsels);
>  	if (ret)
>  		return ret;
> diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
> index afc3506468ba..036e88cb52a1 100644
> --- a/drivers/mtd/nand/raw/nand_base.c
> +++ b/drivers/mtd/nand/raw/nand_base.c
> @@ -4854,17 +4854,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
>  	return ret;
>  }
>  
> -static const char * const nand_ecc_placement[] = {
> -	[NAND_ECC_PLACEMENT_OOB] = "oob",
> -	[NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved",
> -};
> -
> -static enum nand_ecc_engine_type
> -of_get_nand_ecc_engine_type(struct device_node *np)
> -{
> -	return NAND_ECC_ENGINE_TYPE_INVALID;
> -}
> -
>  static enum nand_ecc_engine_type
>  of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
>  {
> @@ -4916,24 +4905,6 @@ of_get_rawnand_ecc_engine_type_legacy(struct device_node *np)
>  	return NAND_ECC_ENGINE_TYPE_INVALID;
>  }
>  
> -enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np)
> -{
> -	enum nand_ecc_placement placement;
> -	const char *pm;
> -	int err;
> -
> -	err = of_property_read_string(np, "nand-ecc-placement", &pm);
> -	if (!err) {
> -		for (placement = NAND_ECC_PLACEMENT_OOB;
> -		     placement < ARRAY_SIZE(nand_ecc_placement); placement++) {
> -			if (!strcasecmp(pm, nand_ecc_placement[placement]))
> -				return placement;
> -		}
> -	}
> -
> -	return NAND_ECC_PLACEMENT_UNKNOWN;
> -}
> -
>  enum nand_ecc_placement
>  of_get_rawnand_ecc_placement_legacy(struct device_node *np)
>  {
> @@ -4949,31 +4920,6 @@ of_get_rawnand_ecc_placement_legacy(struct device_node *np)
>  	return NAND_ECC_PLACEMENT_UNKNOWN;
>  }
>  
> -static const char * const nand_ecc_algos[] = {
> -	[NAND_ECC_ALGO_HAMMING]	= "hamming",
> -	[NAND_ECC_ALGO_BCH]	= "bch",
> -	[NAND_ECC_ALGO_RS]	= "rs",
> -};
> -
> -static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np)
> -{
> -	enum nand_ecc_algo ecc_algo;
> -	const char *pm;
> -	int err;
> -
> -	err = of_property_read_string(np, "nand-ecc-algo", &pm);
> -	if (!err) {
> -		for (ecc_algo = NAND_ECC_ALGO_HAMMING;
> -		     ecc_algo < ARRAY_SIZE(nand_ecc_algos);
> -		     ecc_algo++) {
> -			if (!strcasecmp(pm, nand_ecc_algos[ecc_algo]))
> -				return ecc_algo;
> -		}
> -	}
> -
> -	return NAND_ECC_ALGO_UNKNOWN;
> -}
> -
>  static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
>  {
>  	const char *pm;
> @@ -4990,48 +4936,10 @@ static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np)
>  	return NAND_ECC_ALGO_UNKNOWN;
>  }
>  
> -static int of_get_nand_ecc_step_size(struct device_node *np)
> -{
> -	int ret;
> -	u32 val;
> -
> -	ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
> -	return ret ? ret : val;
> -}
> -
> -static int of_get_nand_ecc_strength(struct device_node *np)
> -{
> -	int ret;
> -	u32 val;
> -
> -	ret = of_property_read_u32(np, "nand-ecc-strength", &val);
> -	return ret ? ret : val;
> -}
> -
> -static void nand_ecc_read_user_conf(struct nand_chip *chip)
> -{
> -	struct device_node *dn = nand_get_flash_node(chip);
> -	struct nand_device *nand = &chip->base;
> -	int strength, size;
> -
> -	nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn);
> -	nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn);
> -	nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn);
> -
> -	strength = of_get_nand_ecc_strength(dn);
> -	if (strength >= 0)
> -		nand->ecc.user_conf.strength = strength;
> -
> -	size = of_get_nand_ecc_step_size(dn);
> -	if (size >= 0)
> -		nand->ecc.user_conf.step_size = size;
> -}
> -
>  static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip)
>  {
>  	struct device_node *dn = nand_get_flash_node(chip);
> -	struct nand_device *nand = &chip->base;
> -	struct nand_ecc_props *user_conf = &nand->ecc.user_conf;
> +	struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf;
>  
>  	if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID)
>  		user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn);
> @@ -5081,10 +4989,7 @@ static int rawnand_dt_init(struct nand_chip *chip)
>  	if (of_get_nand_on_flash_bbt(dn))
>  		chip->bbt_options |= NAND_BBT_USE_FLASH;
>  
> -	if (of_property_read_bool(dn, "nand-ecc-maximize"))
> -		chip->ecc.options |= NAND_ECC_MAXIMIZE;
> -
> -	nand_ecc_read_user_conf(chip);
> +	nand_ecc_read_user_conf(nand);
>  	rawnand_ecc_read_legacy_user_conf(chip);
>  
>  	/*
> @@ -5214,6 +5119,7 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
>  static int nand_set_ecc_soft_ops(struct nand_chip *chip)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct nand_ecc_ctrl *ecc = &chip->ecc;
>  
>  	if (WARN_ON(ecc->engine_type != NAND_ECC_ENGINE_TYPE_SOFT))
> @@ -5289,7 +5195,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
>  		 * used.
>  		 */
>  		if (mtd->ooblayout == nand_get_large_page_ooblayout() &&
> -		    ecc->options & NAND_ECC_MAXIMIZE) {
> +		    nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) {
>  			int steps, bytes;
>  
>  			/* Always prefer 1k blocks over 512bytes ones */
> @@ -5529,11 +5435,12 @@ nand_maximize_ecc(struct nand_chip *chip,
>   * @caps: ECC engine caps info structure
>   * @oobavail: OOB size that the ECC engine can use
>   *
> - * Choose the ECC configuration according to following logic
> + * Choose the ECC configuration according to following logic.
>   *
>   * 1. If both ECC step size and ECC strength are already set (usually by DT)
>   *    then check if it is supported by this controller.
> - * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength.
> + * 2. If the user provided the nand-ecc-maximize property, then select maximum
> + *    ECC strength.
>   * 3. Otherwise, try to match the ECC step size and ECC strength closest
>   *    to the chip's requirement. If available OOB size can't fit the chip
>   *    requirement then fallback to the maximum ECC step size and ECC strength.
> @@ -5544,6 +5451,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  			 const struct nand_ecc_caps *caps, int oobavail)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  
>  	if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize))
>  		return -EINVAL;
> @@ -5551,7 +5459,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  	if (chip->ecc.size && chip->ecc.strength)
>  		return nand_check_ecc_caps(chip, caps, oobavail);
>  
> -	if (chip->ecc.options & NAND_ECC_MAXIMIZE)
> +	if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE)
>  		return nand_maximize_ecc(chip, caps, oobavail);
>  
>  	if (!nand_match_ecc_req(chip, caps, oobavail))
> @@ -5561,43 +5469,6 @@ int nand_ecc_choose_conf(struct nand_chip *chip,
>  }
>  EXPORT_SYMBOL_GPL(nand_ecc_choose_conf);
>  
> -/*
> - * Check if the chip configuration meet the datasheet requirements.
> -
> - * If our configuration corrects A bits per B bytes and the minimum
> - * required correction level is X bits per Y bytes, then we must ensure
> - * both of the following are true:
> - *
> - * (1) A / B >= X / Y
> - * (2) A >= X
> - *
> - * Requirement (1) ensures we can correct for the required bitflip density.
> - * Requirement (2) ensures we can correct even when all bitflips are clumped
> - * in the same sector.
> - */
> -static bool nand_ecc_strength_good(struct nand_chip *chip)
> -{
> -	struct mtd_info *mtd = nand_to_mtd(chip);
> -	struct nand_ecc_ctrl *ecc = &chip->ecc;
> -	const struct nand_ecc_props *requirements =
> -		nanddev_get_ecc_requirements(&chip->base);
> -	int corr, ds_corr;
> -
> -	if (ecc->size == 0 || requirements->step_size == 0)
> -		/* Not enough information */
> -		return true;
> -
> -	/*
> -	 * We get the number of corrected bits per page to compare
> -	 * the correction density.
> -	 */
> -	corr = (mtd->writesize * ecc->strength) / ecc->size;
> -	ds_corr = (mtd->writesize * requirements->strength) /
> -		  requirements->step_size;
> -
> -	return corr >= ds_corr && ecc->strength >= requirements->strength;
> -}
> -
>  static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos)
>  {
>  	struct nand_chip *chip = container_of(nand, struct nand_chip,
> @@ -5653,6 +5524,7 @@ static const struct nand_ops rawnand_ops = {
>  static int nand_scan_tail(struct nand_chip *chip)
>  {
>  	struct mtd_info *mtd = nand_to_mtd(chip);
> +	struct nand_device *nanddev = mtd_to_nanddev(mtd);
>  	struct nand_ecc_ctrl *ecc = &chip->ecc;
>  	int ret, i;
>  
> @@ -5880,7 +5752,7 @@ static int nand_scan_tail(struct nand_chip *chip)
>  	mtd->oobavail = ret;
>  
>  	/* ECC sanity check: warn if it's too weak */
> -	if (!nand_ecc_strength_good(chip))
> +	if (!nand_ecc_correction_is_enough(nanddev))

Can we do this rename separately?

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

  reply	other threads:[~2020-06-02 16:20 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-02 14:31 [PATCH v9 0/9] Preparation to the generic ECC engine abstraction Miquel Raynal
2020-06-02 14:31 ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 1/9] mtd: nand: Create a helper to extract the ECC configuration Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 15:51   ` Boris Brezillon
2020-06-02 15:51     ` Boris Brezillon
2020-06-02 14:31 ` [PATCH v9 2/9] mtd: spinand: Use nanddev_get_ecc_conf() when relevant Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 3/9] mtd: nand: Create a helper to extract the ECC requirements Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 4/9] mtd: rawnand: Use nanddev_get_ecc_requirements() when relevant Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 16:00   ` Boris Brezillon
2020-06-02 16:00     ` Boris Brezillon
2020-06-03 10:30     ` Miquel Raynal
2020-06-03 10:30       ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 5/9] mtd: nand: Convert generic NAND bits to use the ECC framework Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 16:03   ` Boris Brezillon
2020-06-02 16:03     ` Boris Brezillon
2020-06-03 10:29     ` Miquel Raynal
2020-06-03 10:29       ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 6/9] mtd: rawnand: Hide the generic OOB layout objects behind helpers Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 16:05   ` Boris Brezillon
2020-06-02 16:05     ` Boris Brezillon
2020-06-02 14:31 ` [PATCH v9 7/9] mtd: rawnand: Write a compatibility layer Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 8/9] mtd: rawnand: Move generic OOB layouts to the ECC framework Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 14:31 ` [PATCH v9 9/9] mtd: rawnand: Move the user input parsing bits " Miquel Raynal
2020-06-02 14:31   ` Miquel Raynal
2020-06-02 16:18   ` Boris Brezillon [this message]
2020-06-02 16:18     ` Boris Brezillon
2020-06-02 16:21   ` Boris Brezillon
2020-06-02 16:21     ` Boris Brezillon
2020-06-03 12:58     ` Miquel Raynal
2020-06-03 12:58       ` Miquel Raynal
2020-06-03 13:05       ` Boris Brezillon
2020-06-03 13:05         ` Boris Brezillon
2020-06-02 16:23   ` Boris Brezillon
2020-06-02 16:23     ` Boris Brezillon
2020-06-02 16:33 ` [PATCH v9 0/9] Preparation to the generic ECC engine abstraction Boris Brezillon
2020-06-02 16:33   ` 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=20200602181858.0565ad31@collabora.com \
    --to=boris.brezillon@collabora.com \
    --cc=Tudor.Ambarus@microchip.com \
    --cc=juliensu@mxic.com.tw \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=masonccyang@mxic.com.tw \
    --cc=miquel.raynal@bootlin.com \
    --cc=richard@nod.at \
    --cc=thomas.petazzoni@bootlin.com \
    --cc=vigneshr@ti.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.