FSL ELBC kernel driver bug-fixed

Fsl elbc driver causes corruption with bus monitor timeouts while simultaneously access on nand device
The issue is caused by statements such as the following

if (elbc_fcm_ctrl->status) != LTESR_CC)
{
… error …
}

in the driver linux/drivers/mtd/nand/fsl_elbc_nand.c.
The variable status of elbc_fcm_ctrl structure instance is updated in the interrupt handler named fsl_lbc_ctrl_irq (implemented in the file linux/arch/powerpc/sysdev/fsl_lbc.c)
When the handler is executed, status is set with LTESR register content.

If a NAND operation is completed while simultaneously bus monitor timeout occurs, status will be set with LTESR_BM (0x80000000) + NAND related bit fields, and then the nand driver is notified for NAND related event.
The corruption occurs when status is finally compared with LTESR_CC. The test fails because of the simultaneous presence of BM bit with other NAND operation related bits.
The driver should ignore BM event, so the solution of the issue is simply to mask the status value with ~LTESR_BM, before comparing with LTESR_CC.

if ((elbc_fcm_ctrl->status & (~LTESR_BM)) != LTESR_CC)
{
… error …
}

For kernel version 2.6.38, the fixing could be made by using the following patch

--- linux-2.6.38.or/drivers/mtd/nand/fsl_elbc_nand.c    2011-05-22 00:13:59.000000000 +0200
+++ linux-2.6.38/drivers/mtd/nand/fsl_elbc_nand.c       2013-12-12 16:03:29.118872000 +0100
@@ -236,7 +236,8 @@
 
        elbc_fcm_ctrl->use_mdr = 0;
 
-       if (elbc_fcm_ctrl->status != LTESR_CC) {
+   /* check status, ignoring bus timeout event */
+       if ((elbc_fcm_ctrl->status & (~LTESR_BM)) != LTESR_CC) {
                dev_info(priv->dev,
                         "command failed: fir %x fcr %x status %x mdr %x\n",
                         in_be32(&lbc->fir), in_be32(&lbc->fcr),
@@ -629,7 +630,7 @@
                        break;
 
        elbc_fcm_ctrl->index += len;
-       return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
+       return i == len && ((elbc_fcm_ctrl->status & (~LTESR_BM)) == LTESR_CC) ? 0 : -EIO;
 }
 
 /* This function is called after Program and Erase Operations to
@@ -640,7 +641,7 @@
        struct fsl_elbc_mtd *priv = chip->priv;
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;

-       if (elbc_fcm_ctrl->status != LTESR_CC)
+       if ((elbc_fcm_ctrl->status & (~LTESR_BM)) != LTESR_CC)
                return NAND_STATUS_FAIL;

 
        /* The chip always seems to report that it is

Comments