forked from openwrt/openwrt
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mediatek: v5.15: backport spi-mem ecc support
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
- Loading branch information
Showing
10 changed files
with
928 additions
and
0 deletions.
There are no files selected for viewing
224 changes: 224 additions & 0 deletions
224
...atek/patches-5.15/120-01-v5.18-mtd-nand-ecc-Add-infrastructure-to-support-hardware-.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
36 changes: 36 additions & 0 deletions
36
...atek/patches-5.15/120-02-v5.18-mtd-nand-Add-a-new-helper-to-retrieve-the-ECC-contex.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
From 840b2f8dd2d0579e517140e1f9bbc482eaf4ed07 Mon Sep 17 00:00:00 2001 | ||
From: Miquel Raynal <miquel.raynal@bootlin.com> | ||
Date: Thu, 16 Dec 2021 12:16:39 +0100 | ||
Subject: [PATCH 02/15] mtd: nand: Add a new helper to retrieve the ECC context | ||
|
||
Introduce nand_to_ecc_ctx() which will allow to easily jump to the | ||
private pointer of an ECC context given a NAND device. This is very | ||
handy, from the prepare or finish ECC hook, to get the internal context | ||
out of the NAND device object. | ||
|
||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> | ||
Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-14-miquel.raynal@bootlin.com | ||
(cherry picked from commit cda32a618debd3fad8e42757b198719ae180f8f4) | ||
--- | ||
include/linux/mtd/nand.h | 5 +++++ | ||
1 file changed, 5 insertions(+) | ||
|
||
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h | ||
index 4ddd20fe9c9e..b617efa0a881 100644 | ||
--- a/include/linux/mtd/nand.h | ||
+++ b/include/linux/mtd/nand.h | ||
@@ -990,6 +990,11 @@ int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos); | ||
int nanddev_ecc_engine_init(struct nand_device *nand); | ||
void nanddev_ecc_engine_cleanup(struct nand_device *nand); | ||
|
||
+static inline void *nand_to_ecc_ctx(struct nand_device *nand) | ||
+{ | ||
+ return nand->ecc.ctx.priv; | ||
+} | ||
+ | ||
/* BBT related functions */ | ||
enum nand_bbt_block_status { | ||
NAND_BBT_BLOCK_STATUS_UNKNOWN, | ||
-- | ||
2.35.1 | ||
|
80 changes: 80 additions & 0 deletions
80
...atek/patches-5.15/120-03-v5.18-mtd-nand-ecc-Provide-a-helper-to-retrieve-a-pileline.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
From 784866bc4f9f25e0494b77750f95af2a2619e498 Mon Sep 17 00:00:00 2001 | ||
From: Miquel Raynal <miquel.raynal@bootlin.com> | ||
Date: Thu, 16 Dec 2021 12:16:41 +0100 | ||
Subject: [PATCH 03/15] mtd: nand: ecc: Provide a helper to retrieve a | ||
pilelined engine device | ||
|
||
In a pipelined engine situation, we might either have the host which | ||
internally has support for error correction, or have it using an | ||
external hardware block for this purpose. In the former case, the host | ||
is also the ECC engine. In the latter case, it is not. In order to get | ||
the right pointers on the right devices (for example: in order to devm_* | ||
allocate variables), let's introduce this helper which can safely be | ||
called by pipelined ECC engines in order to retrieve the right device | ||
structure. | ||
|
||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> | ||
Link: https://lore.kernel.org/linux-mtd/20211216111654.238086-16-miquel.raynal@bootlin.com | ||
(cherry picked from commit 5145abeb0649acf810a32e63bd762e617a9b3309) | ||
--- | ||
drivers/mtd/nand/ecc.c | 31 +++++++++++++++++++++++++++++++ | ||
include/linux/mtd/nand.h | 1 + | ||
2 files changed, 32 insertions(+) | ||
|
||
diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c | ||
index 078f5ec38de3..5250764cedee 100644 | ||
--- a/drivers/mtd/nand/ecc.c | ||
+++ b/drivers/mtd/nand/ecc.c | ||
@@ -699,6 +699,37 @@ void nand_ecc_put_on_host_hw_engine(struct nand_device *nand) | ||
} | ||
EXPORT_SYMBOL(nand_ecc_put_on_host_hw_engine); | ||
|
||
+/* | ||
+ * In the case of a pipelined engine, the device registering the ECC | ||
+ * engine is not necessarily the ECC engine itself but may be a host controller. | ||
+ * It is then useful to provide a helper to retrieve the right device object | ||
+ * which actually represents the ECC engine. | ||
+ */ | ||
+struct device *nand_ecc_get_engine_dev(struct device *host) | ||
+{ | ||
+ struct platform_device *ecc_pdev; | ||
+ struct device_node *np; | ||
+ | ||
+ /* | ||
+ * If the device node contains this property, it means we need to follow | ||
+ * it in order to get the right ECC engine device we are looking for. | ||
+ */ | ||
+ np = of_parse_phandle(host->of_node, "nand-ecc-engine", 0); | ||
+ if (!np) | ||
+ return host; | ||
+ | ||
+ ecc_pdev = of_find_device_by_node(np); | ||
+ if (!ecc_pdev) { | ||
+ of_node_put(np); | ||
+ return NULL; | ||
+ } | ||
+ | ||
+ platform_device_put(ecc_pdev); | ||
+ of_node_put(np); | ||
+ | ||
+ return &ecc_pdev->dev; | ||
+} | ||
+ | ||
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 b617efa0a881..615b3e3a3920 100644 | ||
--- a/include/linux/mtd/nand.h | ||
+++ b/include/linux/mtd/nand.h | ||
@@ -309,6 +309,7 @@ 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); | ||
+struct device *nand_ecc_get_engine_dev(struct device *host); | ||
|
||
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING) | ||
struct nand_ecc_engine *nand_ecc_sw_hamming_get_engine(void); | ||
-- | ||
2.35.1 | ||
|
Oops, something went wrong.