aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
diff options
context:
space:
mode:
authorChuanhong Guo <gch981213@gmail.com>2022-04-07 10:05:25 +0800
committerChuanhong Guo <gch981213@gmail.com>2022-04-28 18:06:00 +0800
commit861efe158ac56da2e00637aed704a77994bec54c (patch)
tree539836b2d4f7ec33792b2dda0b6ab7f45455c35f /target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
parent3e5925225ec27519f1eccc1605fe9a76303d539b (diff)
downloadupstream-861efe158ac56da2e00637aed704a77994bec54c.tar.gz
upstream-861efe158ac56da2e00637aed704a77994bec54c.tar.bz2
upstream-861efe158ac56da2e00637aed704a77994bec54c.zip
mediatek: v5.15: backport spi-mem ecc support
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
Diffstat (limited to 'target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch')
-rw-r--r--target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch224
1 files changed, 224 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch b/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
new file mode 100644
index 0000000000..b6b069d234
--- /dev/null
+++ b/target/linux/mediatek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
@@ -0,0 +1,224 @@
+From ad4944aa0b02cb043afe20bc2a018c161e65c992 Mon Sep 17 00:00:00 2001
+From: Miquel Raynal <miquel.raynal@bootlin.com>
+Date: Thu, 16 Dec 2021 12:16:38 +0100
+Subject: [PATCH 01/15] mtd: nand: ecc: Add infrastructure to support hardware
+ engines
+
+Add the necessary helpers to register/unregister hardware ECC engines
+that will be called from ECC engine drivers.
+
+Also add helpers to get the right engine from the user
+perspective. Keep a reference of the in use ECC engine in order to
+prevent modules to be unloaded. Put the reference when the engine gets
+retired.
+
+A static list of hardware (only) ECC engines is setup to keep track of
+the registered engines.
+
+Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
+Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-13-miquel.raynal@bootlin.com
+(cherry picked from commit 96489c1c0b53131b0e1ec33e2060538379ad6152)
+---
+ drivers/mtd/nand/core.c | 10 +++--
+ drivers/mtd/nand/ecc.c | 88 ++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/nand.h | 28 +++++++++++++
+ 3 files changed, 123 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
+index 5e13a03d2b32..b228b4d13b7a 100644
+--- a/drivers/mtd/nand/core.c
++++ b/drivers/mtd/nand/core.c
+@@ -232,7 +232,9 @@ static int nanddev_get_ecc_engine(struct nand_device *nand)
+ nand->ecc.engine = nand_ecc_get_on_die_hw_engine(nand);
+ break;
+ case NAND_ECC_ENGINE_TYPE_ON_HOST:
+- pr_err("On-host hardware ECC engines not supported yet\n");
++ nand->ecc.engine = nand_ecc_get_on_host_hw_engine(nand);
++ if (PTR_ERR(nand->ecc.engine) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
+ break;
+ default:
+ pr_err("Missing ECC engine type\n");
+@@ -252,7 +254,7 @@ static int nanddev_put_ecc_engine(struct nand_device *nand)
+ {
+ switch (nand->ecc.ctx.conf.engine_type) {
+ case NAND_ECC_ENGINE_TYPE_ON_HOST:
+- pr_err("On-host hardware ECC engines not supported yet\n");
++ nand_ecc_put_on_host_hw_engine(nand);
+ break;
+ case NAND_ECC_ENGINE_TYPE_NONE:
+ case NAND_ECC_ENGINE_TYPE_SOFT:
+@@ -297,7 +299,9 @@ int nanddev_ecc_engine_init(struct nand_device *nand)
+ /* Look for the ECC engine to use */
+ ret = nanddev_get_ecc_engine(nand);
+ if (ret) {
+- pr_err("No ECC engine found\n");
++ if (ret != -EPROBE_DEFER)
++ pr_err("No ECC engine found\n");
++
+ return ret;
+ }
+
+diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c
+index 6c43dfda01d4..078f5ec38de3 100644
+--- a/drivers/mtd/nand/ecc.c
++++ b/drivers/mtd/nand/ecc.c
+@@ -96,6 +96,12 @@
+ #include <linux/module.h>
+ #include <linux/mtd/nand.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_platform.h>
++
++static LIST_HEAD(on_host_hw_engines);
++static DEFINE_MUTEX(on_host_hw_engines_mutex);
+
+ /**
+ * nand_ecc_init_ctx - Init the ECC engine context
+@@ -611,6 +617,88 @@ struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand)
+ }
+ EXPORT_SYMBOL(nand_ecc_get_on_die_hw_engine);
+
++int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine)
++{
++ struct nand_ecc_engine *item;
++
++ if (!engine)
++ return -EINVAL;
++
++ /* Prevent multiple registrations of one engine */
++ list_for_each_entry(item, &on_host_hw_engines, node)
++ if (item == engine)
++ return 0;
++
++ mutex_lock(&on_host_hw_engines_mutex);
++ list_add_tail(&engine->node, &on_host_hw_engines);
++ mutex_unlock(&on_host_hw_engines_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(nand_ecc_register_on_host_hw_engine);
++
++int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine)
++{
++ if (!engine)
++ return -EINVAL;
++
++ mutex_lock(&on_host_hw_engines_mutex);
++ list_del(&engine->node);
++ mutex_unlock(&on_host_hw_engines_mutex);
++
++ return 0;
++}
++EXPORT_SYMBOL(nand_ecc_unregister_on_host_hw_engine);
++
++static struct nand_ecc_engine *nand_ecc_match_on_host_hw_engine(struct device *dev)
++{
++ struct nand_ecc_engine *item;
++
++ list_for_each_entry(item, &on_host_hw_engines, node)
++ if (item->dev == dev)
++ return item;
++
++ return NULL;
++}
++
++struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand)
++{
++ struct nand_ecc_engine *engine = NULL;
++ struct device *dev = &nand->mtd.dev;
++ struct platform_device *pdev;
++ struct device_node *np;
++
++ if (list_empty(&on_host_hw_engines))
++ return NULL;
++
++ /* Check for an explicit nand-ecc-engine property */
++ np = of_parse_phandle(dev->of_node, "nand-ecc-engine", 0);
++ if (np) {
++ pdev = of_find_device_by_node(np);
++ if (!pdev)
++ return ERR_PTR(-EPROBE_DEFER);
++
++ engine = nand_ecc_match_on_host_hw_engine(&pdev->dev);
++ platform_device_put(pdev);
++ of_node_put(np);
++
++ if (!engine)
++ return ERR_PTR(-EPROBE_DEFER);
++ }
++
++ if (engine)
++ get_device(engine->dev);
++
++ return engine;
++}
++EXPORT_SYMBOL(nand_ecc_get_on_host_hw_engine);
++
++void nand_ecc_put_on_host_hw_engine(struct nand_device *nand)
++{
++ put_device(nand->ecc.engine->dev);
++}
++EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine);
++
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
+ MODULE_DESCRIPTION("Generic ECC engine");
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 32fc7edf65b3..4ddd20fe9c9e 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -263,12 +263,36 @@ struct nand_ecc_engine_ops {
+ struct nand_page_io_req *req);
+ };
+
++/**
++ * enum nand_ecc_engine_integration - How the NAND ECC engine is integrated
++ * @NAND_ECC_ENGINE_INTEGRATION_INVALID: Invalid value
++ * @NAND_ECC_ENGINE_INTEGRATION_PIPELINED: Pipelined engine, performs on-the-fly
++ * correction, does not need to copy
++ * data around
++ * @NAND_ECC_ENGINE_INTEGRATION_EXTERNAL: External engine, needs to bring the
++ * data into its own area before use
++ */
++enum nand_ecc_engine_integration {
++ NAND_ECC_ENGINE_INTEGRATION_INVALID,
++ NAND_ECC_ENGINE_INTEGRATION_PIPELINED,
++ NAND_ECC_ENGINE_INTEGRATION_EXTERNAL,
++};
++
+ /**
+ * struct nand_ecc_engine - ECC engine abstraction for NAND devices
++ * @dev: Host device
++ * @node: Private field for registration time
+ * @ops: ECC engine operations
++ * @integration: How the engine is integrated with the host
++ * (only relevant on %NAND_ECC_ENGINE_TYPE_ON_HOST engines)
++ * @priv: Private data
+ */
+ struct nand_ecc_engine {
++ struct device *dev;
++ struct list_head node;
+ struct nand_ecc_engine_ops *ops;
++ enum nand_ecc_engine_integration integration;
++ void *priv;
+ };
+
+ void of_get_nand_ecc_user_config(struct nand_device *nand);
+@@ -279,8 +303,12 @@ int nand_ecc_prepare_io_req(struct nand_device *nand,
+ int nand_ecc_finish_io_req(struct nand_device *nand,
+ struct nand_page_io_req *req);
+ bool nand_ecc_is_strong_enough(struct nand_device *nand);
++int nand_ecc_register_on_host_hw_engine(struct nand_ecc_engine *engine);
++int nand_ecc_unregister_on_host_hw_engine(struct nand_ecc_engine *engine);
+ struct nand_ecc_engine *nand_ecc_get_sw_engine(struct nand_device *nand);
+ struct nand_ecc_engine *nand_ecc_get_on_die_hw_engine(struct nand_device *nand);
++struct nand_ecc_engine *nand_ecc_get_on_host_hw_engine(struct nand_device *nand);
++void nand_ecc_put_on_host_hw_engine(struct nand_device *nand);
+
+ #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
+ struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void);
+--
+2.35.1
+