[PATCH V2, 2/2] mtd: nand: brcmnand: Check flash #WP pin status before nand erase/program
Marek Vasut
marek.vasut at gmail.com
Sat Feb 18 07:21:54 PST 2017
On 02/18/2017 09:03 AM, Boris Brezillon wrote:
> On Fri, 17 Feb 2017 22:38:04 +0100
> Marek Vasut <marek.vasut at gmail.com> wrote:
>
>> On 02/16/2017 07:46 PM, Kamal Dasu wrote:
>>> brcmnand controller v6.x and v7.x lets driver to enable disable #WP pin
>>> via NAND_WP bit in CS_SELECT register. Driver implementation assumes that
>>> setting/resetting the bit would assert/de-assert #WP pin instantaneously
>>> from the flash part's perspective, and was proceeding to erase/program
>>> without verifying flash status byte for protection bit. In rigorous
>>> testing this was causing rare data corruptions with erase and/or
>>> subsequent programming. To fix this added verification logic to
>>> brcmandn_wp_set() by reading flash status and verifying protection bit
>>> indicating #WP pin status. The new logic makes sure controller as well
>>> as the flash is ready to accept commands.
>>>
>>> Signed-off-by: Kamal Dasu <kdasu.kdev at gmail.com>
>>> ---
>>> drivers/mtd/nand/brcmnand/brcmnand.c | 53 ++++++++++++++++++++++++++++++++++--
>>> 1 file changed, 51 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
>>> index c7c4efe..2f082a3 100644
>>> --- a/drivers/mtd/nand/brcmnand/brcmnand.c
>>> +++ b/drivers/mtd/nand/brcmnand/brcmnand.c
>>> @@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {
>>> #define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)
>>> #define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024)
>>>
>>> +#define FLASH_RDY (NAND_STATUS_READY)
>>
>> Drop extra parenthesis
>>
>>> +#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY)
>>> +
>>> /* Controller feature flags */
>>> enum {
>>> BRCMNAND_HAS_1K_SECTORS = BIT(0),
>>> @@ -765,12 +768,57 @@ enum {
>>> CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30),
>>> };
>>>
>>> -static int brcmnand_set_wp(struct brcmnand_host *host, int en)
>>> +static void bcmnand_ctrl_busy_poll(struct brcmnand_controller *ctrl, u32 mask)
>>> +{
>>> + unsigned long timeout = jiffies + msecs_to_jiffies(200);
>>> +
>>> + while ((brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) & mask) !=
>>> + mask) {
>>
>> Ewww, make this into something like ...
>>
>> while (true) { / for (;;) {
>> reg = read.....
>> if ((reg & mask) == mask)
>> ...
>> if (time ....)
>> dev_warn...
>> cpu_relax();
>> }
>>
>> But then again, there's the readx_poll_timeout() , which seems like
>> exactly the thing you implemented here .
>
> I agree that using readl_poll_timeout() would be better, but it's not
> so simple (see brcmnand_read_reg() and brcmnand_readl()
> implementations).
I admit I didn't look at how those are implemented.
--
Best regards,
Marek Vasut
More information about the linux-mtd
mailing list