From: Stefan Agner <stefan@agner.ch>
To: bbrezillon@kernel.org, miquel.raynal@bootlin.com
Cc: richard@nod.at, dwmw2@infradead.org, computersforpeace@gmail.com,
marek.vasut@gmail.com, linux-mtd@lists.infradead.org,
linux-kernel@vger.kernel.org, Stefan Agner <stefan@agner.ch>,
Sascha Hauer <s.hauer@pengutronix.de>,
Boris Brezillon <boris.brezillon@collabora.com>
Subject: [PATCH] mtd: rawnand: use longest matching pattern
Date: Fri, 19 Apr 2019 09:47:17 +0200 [thread overview]
Message-ID: <20190419074717.22576-1-stefan@agner.ch> (raw)
Sometimes the exec_op parser does not choose the optimal pattern if
multiple patterns with optional elements are available. Since the stack
automatically splits operations in multiple exec_op calls, a non-optimal
pattern gets broken up into multiple calls. E.g. an OOB read using the
vf610 driver:
nand: executing subop:
nand: ->CMD [0x00]
nand: ->ADDR [5 cyc: 00 08 ea 94 02]
nand: ->CMD [0x30]
nand: ->WAITRDY [max 200000 ms]
nand: DATA_IN [64 B]
nand: executing subop:
nand: CMD [0x00]
nand: ADDR [5 cyc: 00 08 ea 94 02]
nand: CMD [0x30]
nand: WAITRDY [max 200000 ms]
nand: ->DATA_IN [64 B]
However, the vf610 driver has a pattern which can execute the complete
command in a single go...
This patch makes sure that the longest matching pattern is chosen
instead of the first (potentially only partial) match. With this
change the vf610 reads the OOB in a single exec_op call:
nand: executing subop:
nand: ->CMD [0x00]
nand: ->ADDR [5 cyc: 00 08 c0 1d 00]
nand: ->CMD [0x30]
nand: ->WAITRDY [max 200000 ms]
nand: ->DATA_IN [64 B]
Reported-by: Sascha Hauer <s.hauer@pengutronix.de>
Suggested-by: Boris Brezillon <boris.brezillon@collabora.com>
Tested-by: Stefan Agner <stefan@agner.ch>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
drivers/mtd/nand/raw/nand_base.c | 50 +++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 13 deletions(-)
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index ddd396e93e32..ebf219c05853 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -2131,6 +2131,22 @@ static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
}
#endif
+static int nand_op_parser_cmp_ctx(const struct nand_op_parser_ctx *a,
+ const struct nand_op_parser_ctx *b)
+{
+ if (a->subop.ninstrs < b->subop.ninstrs)
+ return -1;
+ else if (a->subop.ninstrs > b->subop.ninstrs)
+ return 1;
+
+ if (a->subop.last_instr_end_off < b->subop.last_instr_end_off)
+ return -1;
+ else if (a->subop.last_instr_end_off > b->subop.last_instr_end_off)
+ return 1;
+
+ return 0;
+}
+
/**
* nand_op_parser_exec_op - exec_op parser
* @chip: the NAND chip
@@ -2165,32 +2181,40 @@ int nand_op_parser_exec_op(struct nand_chip *chip,
unsigned int i;
while (ctx.subop.instrs < op->instrs + op->ninstrs) {
- int ret;
+ const struct nand_op_parser_pattern *pattern;
+ struct nand_op_parser_ctx best_ctx;
+ int ret, best_pattern = -1;
for (i = 0; i < parser->npatterns; i++) {
- const struct nand_op_parser_pattern *pattern;
+ struct nand_op_parser_ctx test_ctx = ctx;
pattern = &parser->patterns[i];
- if (!nand_op_parser_match_pat(pattern, &ctx))
+ if (!nand_op_parser_match_pat(pattern, &test_ctx))
continue;
- nand_op_parser_trace(&ctx);
-
- if (check_only)
- break;
-
- ret = pattern->exec(chip, &ctx.subop);
- if (ret)
- return ret;
+ if (best_pattern >= 0 &&
+ nand_op_parser_cmp_ctx(&test_ctx, &best_ctx) <= 0)
+ continue;
- break;
+ best_pattern = i;
+ best_ctx = test_ctx;
}
- if (i == parser->npatterns) {
+ if (best_pattern < 0) {
pr_debug("->exec_op() parser: pattern not found!\n");
return -ENOTSUPP;
}
+ ctx = best_ctx;
+ nand_op_parser_trace(&ctx);
+
+ if (!check_only) {
+ pattern = &parser->patterns[best_pattern];
+ ret = pattern->exec(chip, &ctx.subop);
+ if (ret)
+ return ret;
+ }
+
/*
* Update the context structure by pointing to the start of the
* next subop.
--
2.21.0
next reply other threads:[~2019-04-19 18:24 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-19 7:47 Stefan Agner [this message]
2019-05-20 14:31 ` Miquel Raynal
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=20190419074717.22576-1-stefan@agner.ch \
--to=stefan@agner.ch \
--cc=bbrezillon@kernel.org \
--cc=boris.brezillon@collabora.com \
--cc=computersforpeace@gmail.com \
--cc=dwmw2@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=marek.vasut@gmail.com \
--cc=miquel.raynal@bootlin.com \
--cc=richard@nod.at \
--cc=s.hauer@pengutronix.de \
/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
all inboxes | Powered by JetHome®