[PATCH] mtd: rawnand: brcmnand: Initial exec_op implementation
dregan at mail.com
dregan at mail.com
Fri Sep 29 12:47:22 PDT 2023
Thank you Miquel, comments below:
> Sent: Friday, September 22, 2023 at 7:24 AM
> From: "Miquel Raynal" <miquel.raynal at bootlin.com>
> To: dregan at mail.com
> Cc: bcm-kernel-feedback-list at broadcom.com, linux-mtd at lists.infradead.org, f.fainelli at gmail.com, rafal at milecki.pl, joel.peshkin at broadcom.com, computersforpeace at gmail.com, dan.beygelman at broadcom.com, william.zhang at broadcom.com, frieder.schrempf at kontron.de, linux-kernel at vger.kernel.org, vigneshr at ti.com, richard at nod.at, bbrezillon at kernel.org, kdasu.kdev at gmail.com
> Subject: Re: [PATCH] mtd: rawnand: brcmnand: Initial exec_op implementation
>
> Hello,
>
> dregan at mail.com wrote on Wed, 13 Sep 2023 04:24:41 +0200:
>
> > Initial exec_op implementation for Broadcom STB, Broadband and iProc SoC
> > This adds exec_op and removes the legacy interface.
>
> Thanks a lot for the conversion, a few comments below.
>
...
> > +static void brcmnand_exec_instr(struct brcmnand_host *host,
> > + const struct nand_op_instr *instr,
> > + bool last_op)
> > +{
> > + struct brcmnand_controller *ctrl = host->ctrl;
> > + unsigned int i;
> > + const u8 *out;
> > + u8 *in;
> > +
> > + bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
> > +
> > + switch (instr->type) {
> > + case NAND_OP_CMD_INSTR:
> > + brcmnand_low_level_op(host, LL_OP_CMD,
> > + instr->ctx.cmd.opcode, last_op);
> > + break;
> > +
> > + case NAND_OP_ADDR_INSTR:
> > + for (i = 0; i < instr->ctx.addr.naddrs; i++)
> > + brcmnand_low_level_op(host, LL_OP_ADDR,
> > + instr->ctx.addr.addrs[i],
> > + last_op);
> > + break;
> > +
> > + case NAND_OP_DATA_IN_INSTR:
> > + in = instr->ctx.data.buf.in;
> > + for (i = 0; i < instr->ctx.data.len; i++) {
> > + brcmnand_low_level_op(host, LL_OP_RD, 0, last_op);
> > + in[i] = brcmnand_read_reg(host->ctrl,
> > + BRCMNAND_LL_RDATA);
> > + }
> > + break;
> > +
> > + case NAND_OP_DATA_OUT_INSTR:
> > + out = instr->ctx.data.buf.out;
> > + for (i = 0; i < instr->ctx.data.len; i++)
> > + brcmnand_low_level_op(host, LL_OP_WR, out[i], last_op);
> > + break;
> > +
> > + default:
>
> Should probably return an error.
>
Will do.
> > + break;
> > + }
> > +}
> > +
> > +static int brcmnand_parser_exec_matched_op(struct nand_chip *chip,
> > + const struct nand_subop *subop)
> > +{
> > + struct brcmnand_host *host = nand_get_controller_data(chip);
> > + struct mtd_info *mtd = nand_to_mtd(chip);
> > + const struct nand_op_instr *instr = &subop->instrs[0];
> > + unsigned int i;
> > + int ret = 0;
> > +
> > + static int erase; /* will initialize to zero */
> > + static int status; /* will initialize to zero */
>
> Looks really suspicious, I believe you should rework your
> implementation to avoid static variables here.
>
Will move these flags into our local structure.
> > +
> > + for (i = 0; i < subop->ninstrs; i++) {
> > + instr = &subop->instrs[i];
> > +
> > + if ((instr->type == NAND_OP_CMD_INSTR) &&
> > + (instr->ctx.cmd.opcode == NAND_CMD_STATUS))
> > + status = 1;
> > + else if (status && (instr->type == NAND_OP_DATA_IN_INSTR)) {
> > + /*
> > + * need to fake the nand device write protect because nand_base does a
> > + * nand_check_wp which calls nand_status_op NAND_CMD_STATUS which checks
> > + * that the nand is not write protected before an operation starts.
> > + * The problem with this is it's done outside exec_op so the nand is
> > + * write protected and this check will fail until the write or erase
> > + * or write back operation actually happens where we turn off wp.
> > + */
>
> If there is a problem with the core it needs to be handled in the core,
> not workarounded here. The whole logic with the status property seems
> really wrong.
>
I'm trying to change our current code functionality as little as
possible by having this function in the same way as it always has
and I do not want to make changes too much outside the scope
of this exec_op change.
> > + u8 *in;
> > +
> > + status = 0;
> > +
> > + instr = &subop->instrs[i];
> > + in = instr->ctx.data.buf.in;
> > + in[0] = brcmnand_status(host) | NAND_STATUS_WP; /* hide WP status */
> > + } else { /* otherwise pass to low level implementation */
> > + if ((instr->type == NAND_OP_CMD_INSTR) &&
> > + (instr->ctx.cmd.opcode == NAND_CMD_RESET)) {
> > + erase = 0;
> > + status = 0;
> > + }
> > +
> > + if (erase) {
> > + erase = 0;
> > + brcmnand_wp(mtd, 1);
> > + }
> > +
> > + if ((instr->type == NAND_OP_CMD_INSTR) &&
> > + (instr->ctx.cmd.opcode == NAND_CMD_ERASE1))
> > + brcmnand_wp(mtd, 0);
> > +
> > + if ((instr->type == NAND_OP_CMD_INSTR) &&
> > + (instr->ctx.cmd.opcode == NAND_CMD_ERASE2))
> > + erase = 1;
> > +
> > + brcmnand_exec_instr(host, instr, i == (subop->ninstrs - 1));
> > + }
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static const struct nand_op_parser brcmnand_op_parser = NAND_OP_PARSER(
> > + /* false means the element MUST match,
> > + * true means it does not have to match, catch all patterns
> > + */
>
> I believe the comment is not really useful here?
>
Will remove.
...
>
> Thanks,
> Miquèl
>
Thanks!
-Dave
More information about the linux-mtd
mailing list