From christian.riesch at omicron.at Mon Sep 1 01:00:45 2014 From: christian.riesch at omicron.at (Christian Riesch) Date: Mon, 1 Sep 2014 10:00:45 +0200 Subject: [PATCH 1/1] mtd: cfi_cmdset_0002:add fixup for Micron M29EW after erase operation In-Reply-To: References: Message-ID: Hi, On Mon, Sep 1, 2014 at 4:20 AM, bpqw wrote: > For Micron M29EW,20ms delay is needed after erase operation. Is there a datasheet/application note/technical note from Micron describing this issue? Like the TN-13-07 for the other M29EW fixes? Are all M29EW types affected? Thanks, Christian > > Signed-off-by: BeanHuo > --- > drivers/mtd/chips/cfi_cmdset_0002.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > > diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c > index 5a4bfe3..9b0de91 100644 > --- a/drivers/mtd/chips/cfi_cmdset_0002.c > +++ b/drivers/mtd/chips/cfi_cmdset_0002.c > @@ -509,6 +509,16 @@ static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) > cfi_udelay(500); > } > > +static void cfi_fixup_m29ew_delay_after_erase(struct cfi_private *cfi) > +{ > + /* > + * Resolving the Delay After ERASE Issue @low temperature. > + * 20ms delay is needed after erase operation. > + */ > + if (is_m29ew(cfi)) > + cfi_udelay(20000); > +} > + > struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { > struct cfi_private *cfi = map->fldrv_priv; @@ -2397,6 +2407,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, > ret = -EIO; > } > > + cfi_fixup_m29ew_delay_after_erase(cfi); > chip->state = FL_READY; > DISABLE_VPP(map); > put_chip(map, chip, adr); > -- > 1.7.9.5 > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ From christian.riesch at omicron.at Mon Sep 1 01:04:03 2014 From: christian.riesch at omicron.at (Christian Riesch) Date: Mon, 1 Sep 2014 10:04:03 +0200 Subject: [PATCH 1/1] mtd: cfi_cmdset_0002:add fixup for Micron M29EW after erase operation In-Reply-To: References: Message-ID: On Mon, Sep 1, 2014 at 4:20 AM, bpqw wrote: > For Micron M29EW,20ms delay is needed after erase operation. > > Signed-off-by: BeanHuo > --- > drivers/mtd/chips/cfi_cmdset_0002.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > > diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c > index 5a4bfe3..9b0de91 100644 > --- a/drivers/mtd/chips/cfi_cmdset_0002.c > +++ b/drivers/mtd/chips/cfi_cmdset_0002.c > @@ -509,6 +509,16 @@ static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) > cfi_udelay(500); > } > > +static void cfi_fixup_m29ew_delay_after_erase(struct cfi_private *cfi) > +{ > + /* > + * Resolving the Delay After ERASE Issue @low temperature. > + * 20ms delay is needed after erase operation. > + */ > + if (is_m29ew(cfi)) > + cfi_udelay(20000); > +} > + > struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { > struct cfi_private *cfi = map->fldrv_priv; @@ -2397,6 +2407,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, > ret = -EIO; > } > > + cfi_fixup_m29ew_delay_after_erase(cfi); > chip->state = FL_READY; > DISABLE_VPP(map); > put_chip(map, chip, adr); > -- > 1.7.9.5 > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ From christian.riesch at omicron.at Mon Sep 1 01:05:15 2014 From: christian.riesch at omicron.at (Christian Riesch) Date: Mon, 1 Sep 2014 10:05:15 +0200 Subject: [PATCH 1/1] mtd: cfi_cmdset_0002:add fixup for Micron M29EW after erase operation In-Reply-To: References: Message-ID: On Mon, Sep 1, 2014 at 4:20 AM, bpqw wrote: > For Micron M29EW,20ms delay is needed after erase operation. > > Signed-off-by: BeanHuo > --- > drivers/mtd/chips/cfi_cmdset_0002.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > > diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c > index 5a4bfe3..9b0de91 100644 > --- a/drivers/mtd/chips/cfi_cmdset_0002.c > +++ b/drivers/mtd/chips/cfi_cmdset_0002.c > @@ -509,6 +509,16 @@ static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi) > cfi_udelay(500); > } > > +static void cfi_fixup_m29ew_delay_after_erase(struct cfi_private *cfi) > +{ > + /* > + * Resolving the Delay After ERASE Issue @low temperature. > + * 20ms delay is needed after erase operation. > + */ > + if (is_m29ew(cfi)) > + cfi_udelay(20000); > +} > + > struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { > struct cfi_private *cfi = map->fldrv_priv; @@ -2397,6 +2407,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, Missing line break? The patch does not apply. Christian > ret = -EIO; > } > > + cfi_fixup_m29ew_delay_after_erase(cfi); > chip->state = FL_READY; > DISABLE_VPP(map); > put_chip(map, chip, adr); > -- > 1.7.9.5 > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ From matteo.fortini at gmail.com Mon Sep 1 02:43:54 2014 From: matteo.fortini at gmail.com (Matteo Fortini) Date: Mon, 01 Sep 2014 11:43:54 +0200 Subject: [RFC] MTD m25p80 3-byte addressing and boot problem Message-ID: <54043FDA.4050707@gmail.com> If a Linux/Barebox system is using an SPI flash of size >= 16 MB, the driver is switching to 3-byte addressing to be able to use linear access to the whole memory. This leads to the impossibility to boot a board after a warm reset, because all bootloaders use the standard 2-byte addressing (if the board doesn't physically reset the flash or do something similar). Some documentation in the following links: http://www.at91.com/discussions/viewtopic.php/f,30/t,22849.html https://community.freescale.com/docs/DOC-93632 The solution proposed on freescale forums is not final: it involves switching back to 2-byte addressing after every access, which still leaves a small window in which a warm reset would be fatal. One solution would be to use the bank command in the flash, using each 16MB bank linearly, and changing bank depending on the address. This would be messy for accesses which are crossing the boundary, but it is doable. I'm asking here for comments before I start patching the code. Right now I resorted to stick to 2-byte addressing and leave half of my NOR (32MB) unused. TIA, M From geert at linux-m68k.org Mon Sep 1 03:13:34 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Mon, 1 Sep 2014 12:13:34 +0200 Subject: [RFC] MTD m25p80 3-byte addressing and boot problem In-Reply-To: <54043FDA.4050707@gmail.com> References: <54043FDA.4050707@gmail.com> Message-ID: Hi Matteo, On Mon, Sep 1, 2014 at 11:43 AM, Matteo Fortini wrote: > If a Linux/Barebox system is using an SPI flash of size >= 16 MB, the driver > is switching to 3-byte addressing to be able to use linear access to the > whole memory. > > This leads to the impossibility to boot a board after a warm reset, because > all bootloaders use the standard 2-byte addressing (if the board doesn't > physically reset the flash or do something similar). > The solution proposed on freescale forums is not final: it involves > switching back to 2-byte addressing after every access, which still leaves a > small window in which a warm reset would be fatal. Indeed. So the board won't boot anymore if that happens. > One solution would be to use the bank command in the flash, using each 16MB > bank linearly, and changing bank depending on the address. This would be > messy for accesses which are crossing the boundary, but it is doable. IMHO this is even more dangerous: what if the board is warm-resetted while a non-first bank is in use? The board may not boot anymore, but worse, if the boot loader would write to the FLASH, it would write to the wrong bank, overwriting innocent data. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From markmarshall14 at gmail.com Mon Sep 1 04:48:25 2014 From: markmarshall14 at gmail.com (Mark Marshall) Date: Mon, 1 Sep 2014 13:48:25 +0200 Subject: [RFC] MTD m25p80 3-byte addressing and boot problem In-Reply-To: <54043FDA.4050707@gmail.com> References: <54043FDA.4050707@gmail.com> Message-ID: Hi. We had the same problem here, but luckily our Flash also supported a different read command that took the larger address. I made a (small) modification to the m25p80 driver to use this command when the flash supported it. I've attached the two patches that come from my tree that are relevant. The first one (42) just changes to the page size used to access the flash, and is only needed so that you don;t get conflicts wit the second. The second patch (45) is the one of interest. These patches are against v3.2.52-rt73 from the real-time tree, and there are (obviously) other patches either side of them, but they should show what I have done. At some point (!) I'll try to push these up-stream, but as ou can see, we are well behind the curve at the moment, which makes this harder. Regards, Mark Marshall. PS. On our original prototype hardware we had no reset line connected to the flash, so even a hard reset wouldn't get things back to how they should be when Linux was changing the bank register! I think that the longer commands should be used if the flash chip supports them in preference to either bank switching or "converting" the small commands to longer ones. On 1 September 2014 11:43, Matteo Fortini wrote: > If a Linux/Barebox system is using an SPI flash of size >= 16 MB, the driver > is switching to 3-byte addressing to be able to use linear access to the > whole memory. > > This leads to the impossibility to boot a board after a warm reset, because > all bootloaders use the standard 2-byte addressing (if the board doesn't > physically reset the flash or do something similar). > > Some documentation in the following links: > http://www.at91.com/discussions/viewtopic.php/f,30/t,22849.html > https://community.freescale.com/docs/DOC-93632 > > The solution proposed on freescale forums is not final: it involves > switching back to 2-byte addressing after every access, which still leaves a > small window in which a warm reset would be fatal. > > One solution would be to use the bank command in the flash, using each 16MB > bank linearly, and changing bank depending on the address. This would be > messy for accesses which are crossing the boundary, but it is doable. > > I'm asking here for comments before I start patching the code. Right now I > resorted to stick to 2-byte addressing and leave half of my NOR (32MB) > unused. > > TIA, > M > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ -------------- next part -------------- A non-text attachment was scrubbed... Name: 0042-m25p80-Use-a-512-byte-page-size-for-Spansion-flash-s.patch Type: text/x-patch Size: 1941 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0045-m25p80-Use-the-4-byte-address-read-command.patch Type: text/x-patch Size: 4285 bytes Desc: not available URL: From richard at nod.at Mon Sep 1 14:51:11 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 01 Sep 2014 23:51:11 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: References: Message-ID: <5404EA4F.1040508@nod.at> Am 29.08.2014 14:26, schrieb jean-philippe francois: > I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct > offset in error case) should be added to 3.10.y stable branch. > > It solves an ubifs corruption problem on my board. Edited bootlog for > each case are attached. > > ubifs corruption can be easily reproduced on this board : > 1) format nand partition and flash rootfs > 2) record h264 stream on nand > 3) scp a file from host pc to rootfs while 2 is ongoing > 4) unplug power Hmm, I think this is a good point to bite the bullet and backport all UBI fastmap related fixes to -stable. Thanks, //richard From greg at kroah.com Mon Sep 1 15:02:58 2014 From: greg at kroah.com (Greg KH) Date: Mon, 1 Sep 2014 15:02:58 -0700 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <5404EA4F.1040508@nod.at> References: <5404EA4F.1040508@nod.at> Message-ID: <20140901220258.GA28791@kroah.com> On Mon, Sep 01, 2014 at 11:51:11PM +0200, Richard Weinberger wrote: > Am 29.08.2014 14:26, schrieb jean-philippe francois: > > I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct > > offset in error case) should be added to 3.10.y stable branch. > > > > It solves an ubifs corruption problem on my board. Edited bootlog for > > each case are attached. > > > > ubifs corruption can be easily reproduced on this board : > > 1) format nand partition and flash rootfs > > 2) record h264 stream on nand > > 3) scp a file from host pc to rootfs while 2 is ongoing > > 4) unplug power > > Hmm, I think this is a good point to bite the bullet and backport all > UBI fastmap related fixes to -stable. And what exactly would those commits be? thanks, greg k-h From nicolas.ferre at atmel.com Tue Sep 2 01:36:59 2014 From: nicolas.ferre at atmel.com (Nicolas Ferre) Date: Tue, 2 Sep 2014 10:36:59 +0200 Subject: [PATCH v2 06/12] ARM: at91: add MTD_SPI_NOR (new dependency for M25P80) In-Reply-To: <1398925607-7482-7-git-send-email-computersforpeace@gmail.com> References: <1398925607-7482-1-git-send-email-computersforpeace@gmail.com> <1398925607-7482-7-git-send-email-computersforpeace@gmail.com> Message-ID: <540581AB.6020101@atmel.com> On 01/05/2014 08:26, Brian Norris : > This defconfig contains the CONFIG_M25P80 symbol, which is now > dependent on the MTD_SPI_NOR symbol. Add CONFIG_MTD_SPI_NOR to satisfy > the new dependency. > > At the same time, drop the now-nonexistent CONFIG_MTD_CHAR symbol. > > Signed-off-by: Brian Norris > Cc: Andrew Victor > Cc: Nicolas Ferre Okay, now taken in at91-3.18-defconfig, thanks: Acked-by: Nicolas Ferre > Cc: Jean-Christophe Plagniol-Villard > Cc: linux-arm-kernel at lists.infradead.org > Cc: linux-kernel at vger.kernel.org > --- > arch/arm/configs/sama5_defconfig | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig > index dc3881e07630..8282ebab6e52 100644 > --- a/arch/arm/configs/sama5_defconfig > +++ b/arch/arm/configs/sama5_defconfig > @@ -65,12 +65,12 @@ CONFIG_DEVTMPFS_MOUNT=y > # CONFIG_PREVENT_FIRMWARE_BUILD is not set > CONFIG_MTD=y > CONFIG_MTD_CMDLINE_PARTS=y > -CONFIG_MTD_CHAR=y > CONFIG_MTD_BLOCK=y > CONFIG_MTD_CFI=y > CONFIG_MTD_M25P80=y > CONFIG_MTD_NAND=y > CONFIG_MTD_NAND_ATMEL=y > +CONFIG_MTD_SPI_NOR=y > CONFIG_MTD_UBI=y > CONFIG_MTD_UBI_GLUEBI=y > CONFIG_PROC_DEVICETREE=y > -- Nicolas Ferre From pekon at pek-sem.com Tue Sep 2 12:02:17 2014 From: pekon at pek-sem.com (pekon) Date: Wed, 03 Sep 2014 00:32:17 +0530 Subject: [PATCH 3/6] ARM: dts: am437x-gp-evm: Don't use read/write wait monitoring In-Reply-To: <1409666227-20622-4-git-send-email-rogerq@ti.com> References: <1409666227-20622-1-git-send-email-rogerq@ti.com> <1409666227-20622-4-git-send-email-rogerq@ti.com> Message-ID: <54061439.1030909@pek-sem.com> Hi Roger, On Tuesday 02 September 2014 07:27 PM, Roger Quadros wrote: > NAND uses wait pin only to indicate device readiness after > a block/page operation. It is not use to extend individual > read/write cycle and so read/write wait pin monitoring must > be disabled for NAND. > I think this is incorrect assumption. NAND framework allows wait-pin monitoring at end of each read/write cycle. Please refer following code in drivers/mtd/nand/nand_base.c @@ void nand_wait_ready(...) - nand_wait_ready() calls controller-driver specific call-back for chip->dev_ready(). - chip->dev_ready in-case of OMAP NAND drivers is set in drivers/mtd/nand/omap2.c during probe. if (pdata->dev_ready) { nand_chip->dev_ready = omap_dev_ready; nand_chip->chip_delay = 0; } Problem is we don't set pdata->dev_ready correctly as part of platform-data dring GPMC initialization. This was what my earlier patch for wait-pin monitoring about. But it was a quick fix for NAND devices. So, I suggest to fix wait-pin monitoring instead of de-scoping it from DTS as wait-pin monitoring should boast the NAND performance significantly. (please see if you can find an old mail thread which had some good feedbacks from Ezequiel and Javier about wait-pin monitoring). [...] > This patch also gets rid of the below warning when NAND is > accessed for the first time. > > omap_l3_noc 44000000.ocp: L3 application error: target 13 mod:1 (unclearable) > Can you debug this further. This warning probably comes when driver tries to access some "reserved" addresses. Or violate read/write bits. with regards, pekon ------------------------ Powered by BigRock.com From rogerq at ti.com Wed Sep 3 01:32:19 2014 From: rogerq at ti.com (Roger Quadros) Date: Wed, 3 Sep 2014 11:32:19 +0300 Subject: [PATCH 3/6] ARM: dts: am437x-gp-evm: Don't use read/write wait monitoring In-Reply-To: <54061439.1030909@pek-sem.com> References: <1409666227-20622-1-git-send-email-rogerq@ti.com> <1409666227-20622-4-git-send-email-rogerq@ti.com> <54061439.1030909@pek-sem.com> Message-ID: <5406D213.6020603@ti.com> Hi Pekon, On 09/02/2014 10:02 PM, pekon wrote: > Hi Roger, > > > On Tuesday 02 September 2014 07:27 PM, Roger Quadros wrote: >> NAND uses wait pin only to indicate device readiness after >> a block/page operation. It is not use to extend individual >> read/write cycle and so read/write wait pin monitoring must >> be disabled for NAND. >> > I think this is incorrect assumption. NAND framework allows > wait-pin monitoring at end of each read/write cycle. Please > refer following code in drivers/mtd/nand/nand_base.c > @@ void nand_wait_ready(...) > > - nand_wait_ready() calls controller-driver specific call-back > for chip->dev_ready(). It is important to note that this NAND device ready mechanism is different from GPMC inter cycle wait state mechanism controlled by the read/write monitoring bits. The same WAIT pin is used in both the cases. For more details about NAND use case refer to AM437x TRM: Section: 9.1.3.3.12.2 NAND Device-Ready Pin below excerpt from there "To avoid a time-out caused by a block/page opening delay in NAND flash, disable the wait pin monitoring for read and write accesses (that is, set the GPMC_CONFIG1_i[[21] WAITWRITEMONITORING and GPMC_CONFIG1_i[[22] WAITREADMONITORING bits to 0): > > - chip->dev_ready in-case of OMAP NAND drivers is set in > drivers/mtd/nand/omap2.c during probe. > if (pdata->dev_ready) { > nand_chip->dev_ready = omap_dev_ready; > nand_chip->chip_delay = 0; > } > > Problem is we don't set pdata->dev_ready correctly as part > of platform-data dring GPMC initialization. This was what my > earlier patch for wait-pin monitoring about. But it was a > quick fix for NAND devices. > > So, I suggest to fix wait-pin monitoring instead of de-scoping > it from DTS as wait-pin monitoring should boast the NAND > performance significantly. > (please see if you can find an old mail thread which had some > good feedbacks from Ezequiel and Javier about wait-pin monitoring). This is to get the device ready mechanism work and has nothing to do with GPMC wait monitoring. Instead the WAIT pin is used to generate the GPMC interrupt based on the WAIT pin polarity. To monitor NAND device ready status from TRM "-Use software to poll the WAITnSTS bit (n = 0 to 1) of the GPMC_STS register. OR -Configure an interrupt that is generated on the WAIT signal change (through the GPMC_IRQEN [11-8] bits)" > > [...] > >> This patch also gets rid of the below warning when NAND is >> accessed for the first time. >> >> omap_l3_noc 44000000.ocp: L3 application error: target 13 mod:1 (unclearable) >> > Can you debug this further. > This warning probably comes when driver tries to access some > "reserved" addresses. Or violate read/write bits. It is caused because of incorrectly enabled the GPMC wait monitoring. Disabling the wait monitoring gets rid of this error. I don't understand what else I should debug and why. cheers, -roger From pekon at pek-sem.com Wed Sep 3 10:29:30 2014 From: pekon at pek-sem.com (pekon) Date: Wed, 03 Sep 2014 22:59:30 +0530 Subject: [PATCH 3/6] ARM: dts: am437x-gp-evm: Don't use read/write wait monitoring In-Reply-To: <5406D213.6020603@ti.com> References: <1409666227-20622-1-git-send-email-rogerq@ti.com> <1409666227-20622-4-git-send-email-rogerq@ti.com> <54061439.1030909@pek-sem.com> <5406D213.6020603@ti.com> Message-ID: <54074FFA.2020406@pek-sem.com> Hi Roger, On Wednesday 03 September 2014 02:02 PM, Roger Quadros wrote: > Hi Pekon, > > On 09/02/2014 10:02 PM, pekon wrote: >> Hi Roger, >> >> >> On Tuesday 02 September 2014 07:27 PM, Roger Quadros wrote: >>> NAND uses wait pin only to indicate device readiness after >>> a block/page operation. It is not use to extend individual >>> read/write cycle and so read/write wait pin monitoring must >>> be disabled for NAND. >>> >> I think this is incorrect assumption. NAND framework allows >> wait-pin monitoring at end of each read/write cycle. Please >> refer following code in drivers/mtd/nand/nand_base.c >> @@ void nand_wait_ready(...) >> >> - nand_wait_ready() calls controller-driver specific call-back >> for chip->dev_ready(). > > It is important to note that this NAND device ready mechanism is different from > GPMC inter cycle wait state mechanism controlled by the read/write monitoring > bits. The same WAIT pin is used in both the cases. > > For more details about NAND use case refer to > > AM437x TRM: > Section: 9.1.3.3.12.2 NAND Device-Ready Pin > > below excerpt from there > "To avoid a time-out caused by a block/page opening delay in NAND flash, disable the wait pin monitoring > for read and write accesses (that is, set the GPMC_CONFIG1_i[[21] WAITWRITEMONITORING and > GPMC_CONFIG1_i[[22] WAITREADMONITORING bits to 0): > I re-read the AM437x TRM, and the section you mentioned above. ----------------- *9.1.3.3.12.2 NAND Device-Ready Pin* The NAND memory device provides a ready pin to indicate data availability after a block/page opening and to indicate that data programming is complete. The ready pin can be connected to one of the WAIT GPMC input pins; data read accesses must not be tried when the ready pin is sampled inactive (device is not ready) even if the associated chip-select WAITREADMONITORING bit field is set. The duration of the NAND device busy state after the block/page opening is so long (up to 50 ?s) that accesses occurring when the ready pin is sampled inactive can stall GPMC access and eventually cause a system time-out. If a read access to a NAND flash is done using the wait monitoring mode, the device is blocked during a page opening, and so is the GPMC. If the correct settings are used, other chip-selects can be used while the memory processes the page opening command. ... ----------------- It's clearly written that wait-pin monitoring is used for read/write (programs) access, and GPMC is blocked till wait signal is asserted during reads. Also, on NAND there can be no read/write access except at page-level so wait-pin monitoring is implicitly related to read/write accesses. However, whether you use it or not is purely user's choice, but it has performance impact. You are probably seeing timeout condition when enabling wait-pin monitoring, and this can be due to multiple reasons like; (1) incorrect pin-mux configuration (like directions, pull-up etc) (2) incorrect board-level pull-up (3) incorrect driver setting, like though wait-pin is enabled but wrong wait-pin is being monitored. I request you to fix this instead of disabling it completely, as you should see significant NAND throughput increase once this feature works correctly. >> >> - chip->dev_ready in-case of OMAP NAND drivers is set in >> drivers/mtd/nand/omap2.c during probe. >> if (pdata->dev_ready) { >> nand_chip->dev_ready = omap_dev_ready; >> nand_chip->chip_delay = 0; >> } >> >> Problem is we don't set pdata->dev_ready correctly as part >> of platform-data dring GPMC initialization. This was what my >> earlier patch for wait-pin monitoring about. But it was a >> quick fix for NAND devices. >> >> So, I suggest to fix wait-pin monitoring instead of de-scoping >> it from DTS as wait-pin monitoring should boast the NAND >> performance significantly. >> (please see if you can find an old mail thread which had some >> good feedbacks from Ezequiel and Javier about wait-pin monitoring). > > This is to get the device ready mechanism work and has nothing to do with > GPMC wait monitoring. Instead the WAIT pin is used to generate the GPMC > interrupt based on the WAIT pin polarity. > > To monitor NAND device ready status > from TRM > "-Use software to poll the WAITnSTS bit (n = 0 to 1) of the GPMC_STS register. > OR > -Configure an interrupt that is generated on the WAIT signal change (through the GPMC_IRQEN [11-8] bits)" > >> >> [...] >> >>> This patch also gets rid of the below warning when NAND is >>> accessed for the first time. >>> >>> omap_l3_noc 44000000.ocp: L3 application error: target 13 mod:1 (unclearable) >>> >> Can you debug this further. >> This warning probably comes when driver tries to access some >> "reserved" addresses. Or violate read/write bits. > > It is caused because of incorrectly enabled the GPMC wait monitoring. Disabling the > wait monitoring gets rid of this error. I don't understand what else I should debug I'm not sure how a NAND or GPMC feature can cause omap_l3_noc: L3 application error ? But now as I re-read the text, its probably the L3 interconnect timeout error due to no response from GPMC. There is a timer in L3 which monitors if the L3 interconnect is stalled/blocked waiting for response from a target. I think it's that timer which is getting timeout. (but just my guess). > and why. > As there were number of users on linux-mtd list wanted to use NAND wait-pin monitoring on OMAP devices, so I have just looped them if they see any concerns. Otherwise, no further concerns from me. with regards, pekon ------------------------ Powered by BigRock.com From richard at nod.at Wed Sep 3 15:08:11 2014 From: richard at nod.at (Richard Weinberger) Date: Thu, 04 Sep 2014 00:08:11 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <20140901220258.GA28791@kroah.com> References: <5404EA4F.1040508@nod.at> <20140901220258.GA28791@kroah.com> Message-ID: <5407914B.302@nod.at> Am 02.09.2014 00:02, schrieb Greg KH: > On Mon, Sep 01, 2014 at 11:51:11PM +0200, Richard Weinberger wrote: >> Am 29.08.2014 14:26, schrieb jean-philippe francois: >>> I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct >>> offset in error case) should be added to 3.10.y stable branch. >>> >>> It solves an ubifs corruption problem on my board. Edited bootlog for >>> each case are attached. >>> >>> ubifs corruption can be easily reproduced on this board : >>> 1) format nand partition and flash rootfs >>> 2) record h264 stream on nand >>> 3) scp a file from host pc to rootfs while 2 is ongoing >>> 4) unplug power >> >> Hmm, I think this is a good point to bite the bullet and backport all >> UBI fastmap related fixes to -stable. Actually I meant, I need to sit down and go through the changelog and locate them all. :) > And what exactly would those commits be? There you go: e8c235b UBI: init_volumes: Ignore volumes with no LEBs 44305eb UBI: fastmap: do not miss bit-flips 604b592 UBI: fix rb_tree node comparison in add_map 5547fec UBI: fix some use after free bugs fe24c6e UBI: Fix memory leak in ubi_attach_fastmap() error path c22301a UBI: fastmap: fix backward compatibility with image_seq 4b3e0a2 UBI: Call scan_all() with correct offset in error case f240dca UBI: Fix error path in scan_pool() fb10e4d UBI: fix refill_wl_user_pool() 8930fa5 UBI: Fix invalidate_fastmap() Thanks, //richard From ben at decadent.org.uk Wed Sep 3 19:11:29 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Thu, 04 Sep 2014 03:11:29 +0100 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: <1409673299.14324.43.camel@dagon.hellion.org.uk> References: <1409673299.14324.43.camel@dagon.hellion.org.uk> Message-ID: <1409796689.27524.34.camel@decadent.org.uk> On Tue, 2014-09-02 at 16:54 +0100, Ian Campbell wrote: > Hello, > > I recently tried to switch to using the DT based kirkwood stuff with > v3.16.1 on a QNAP TS-419 for the Debian kernel. Most things seemed ok > except that the flash driver was not autoloaded -- as well as spi-nor.ko > I had to manually modprobe m25p80.ko. Once I loaded both the flash was > detected. > > I noticed that many platforms declare the flash chip as compatible = > "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried > changing that and it didn't help. In any case without spi-nor.ko being > autoloaded I don't support m25p80.ko ever would be. m25p80.c has: static struct spi_driver m25p80_driver = { ... .id_table = spi_nor_ids, ... }; while spi_nor_ids is defined in spi-nor.c. Since they end up as two separate modules, modpost can't read the ID table and add the device ID aliases to m25p80.ko. It looks like m25p80 has been split up in order that the new fsl-qspi driver can share its code (bypassing the SPI core and its device model!). Why doesn't fsl-qspi implement an SPI controller device? I think it is totally unacceptable to regress m25p80 in this way for the sake of a new driver. > I could set these things to =m for the Debian kirkwood flavour, but > since this is supposed to be a distro-style kernel. > > I'm not entirely sure how module loading of this SPI stuff is supposed > to fit together -- anyone got any hints? Same as for any bus driver. Ben. -- Ben Hutchings Experience is directly proportional to the value of equipment destroyed. - Carolyn Scheppner -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Wed Sep 3 19:21:58 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Thu, 04 Sep 2014 03:21:58 +0100 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: <1409673299.14324.43.camel@dagon.hellion.org.uk> References: <1409673299.14324.43.camel@dagon.hellion.org.uk> Message-ID: <1409797318.27524.37.camel@decadent.org.uk> [Re-sending with more recent address for Huang Shijie.] On Tue, 2014-09-02 at 16:54 +0100, Ian Campbell wrote: > Hello, > > I recently tried to switch to using the DT based kirkwood stuff with > v3.16.1 on a QNAP TS-419 for the Debian kernel. Most things seemed ok > except that the flash driver was not autoloaded -- as well as spi-nor.ko > I had to manually modprobe m25p80.ko. Once I loaded both the flash was > detected. > > I noticed that many platforms declare the flash chip as compatible = > "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried > changing that and it didn't help. In any case without spi-nor.ko being > autoloaded I don't support m25p80.ko ever would be. m25p80.c has: static struct spi_driver m25p80_driver = { ... .id_table = spi_nor_ids, ... }; while spi_nor_ids is defined in spi-nor.c. Since they end up as two separate modules, modpost can't read the ID table and add the device ID aliases to m25p80.ko. It looks like m25p80 has been split up in order that the new fsl-qspi driver can share its code (bypassing the SPI core and its device model!). Why doesn't fsl-qspi implement an SPI controller device? I think it is totally unacceptable to regress m25p80 in this way for the sake of a new driver. > I could set these things to =m for the Debian kirkwood flavour, but > since this is supposed to be a distro-style kernel. > > I'm not entirely sure how module loading of this SPI stuff is supposed > to fit together -- anyone got any hints? Same as for any bus driver. Ben. -- Ben Hutchings Experience is directly proportional to the value of equipment destroyed. - Carolyn Scheppner -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From geert at linux-m68k.org Thu Sep 4 00:02:04 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Thu, 4 Sep 2014 09:02:04 +0200 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: <1409796689.27524.34.camel@decadent.org.uk> References: <1409673299.14324.43.camel@dagon.hellion.org.uk> <1409796689.27524.34.camel@decadent.org.uk> Message-ID: Hi Ben, On Thu, Sep 4, 2014 at 4:11 AM, Ben Hutchings wrote: >> I noticed that many platforms declare the flash chip as compatible = >> "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried >> changing that and it didn't help. In any case without spi-nor.ko being >> autoloaded I don't support m25p80.ko ever would be. > > m25p80.c has: > > static struct spi_driver m25p80_driver = { > ... > .id_table = spi_nor_ids, > ... > }; > > while spi_nor_ids is defined in spi-nor.c. Since they end up as two > separate modules, modpost can't read the ID table and add the device ID > aliases to m25p80.ko. Woops. This indeed doesn't work. Note that the MODULE_DEVICE_TABLE() is also gone from m25p80.c So m25p80.c needs to contain the IDs, while spi-nor.c also needs the IDs because it's a framework/library. A quick solution would be to move the ID table to a header file, and include that by both, and re-add the lost MODULE_DEVICE_TABLE() to m25p80.c. That duplicates the data, though. Hmm, for the built-in case, we can avoid the duplication by letting m25p80.c refer to the table in spi-nor.c if !MODULE. Does anyone see a better solution? > It looks like m25p80 has been split up in order that the new fsl-qspi > driver can share its code (bypassing the SPI core and its device > model!). Why doesn't fsl-qspi implement an SPI controller device? I > think it is totally unacceptable to regress m25p80 in this way for the > sake of a new driver. Fsl-qspi is not a generic SPI driver, but a dedicated SPI NOR driver. It's programmed using high-level SPI NOR commands, instead of low-level SPI commands. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From rogerq at ti.com Thu Sep 4 02:46:33 2014 From: rogerq at ti.com (Roger Quadros) Date: Thu, 4 Sep 2014 12:46:33 +0300 Subject: [PATCH 3/6] ARM: dts: am437x-gp-evm: Don't use read/write wait monitoring In-Reply-To: <54074FFA.2020406@pek-sem.com> References: <1409666227-20622-1-git-send-email-rogerq@ti.com> <1409666227-20622-4-git-send-email-rogerq@ti.com> <54061439.1030909@pek-sem.com> <5406D213.6020603@ti.com> <54074FFA.2020406@pek-sem.com> Message-ID: <540834F9.8080902@ti.com> + Sekhar. Hi Pekon, On 09/03/2014 08:29 PM, pekon wrote: > Hi Roger, > > On Wednesday 03 September 2014 02:02 PM, Roger Quadros wrote: >> Hi Pekon, >> >> On 09/02/2014 10:02 PM, pekon wrote: >>> Hi Roger, >>> >>> >>> On Tuesday 02 September 2014 07:27 PM, Roger Quadros wrote: >>>> NAND uses wait pin only to indicate device readiness after >>>> a block/page operation. It is not use to extend individual >>>> read/write cycle and so read/write wait pin monitoring must >>>> be disabled for NAND. >>>> >>> I think this is incorrect assumption. NAND framework allows >>> wait-pin monitoring at end of each read/write cycle. Please >>> refer following code in drivers/mtd/nand/nand_base.c >>> @@ void nand_wait_ready(...) >>> >>> - nand_wait_ready() calls controller-driver specific call-back >>> for chip->dev_ready(). >> >> It is important to note that this NAND device ready mechanism is different from >> GPMC inter cycle wait state mechanism controlled by the read/write monitoring >> bits. The same WAIT pin is used in both the cases. >> >> For more details about NAND use case refer to >> >> AM437x TRM: >> Section: 9.1.3.3.12.2 NAND Device-Ready Pin >> >> below excerpt from there >> "To avoid a time-out caused by a block/page opening delay in NAND flash, disable the wait pin monitoring >> for read and write accesses (that is, set the GPMC_CONFIG1_i[[21] WAITWRITEMONITORING and >> GPMC_CONFIG1_i[[22] WAITREADMONITORING bits to 0): >> > > I re-read the AM437x TRM, and the section you mentioned above. > > ----------------- > *9.1.3.3.12.2 NAND Device-Ready Pin* > The NAND memory device provides a ready pin to indicate data availability after a block/page opening and to indicate that data programming is complete. The ready pin can be connected to one of the WAIT GPMC input pins; data read accesses must not be tried when the ready pin is sampled inactive (device is not ready) even if the associated chip-select WAITREADMONITORING bit field is set. The duration of the NAND device busy state after the block/page opening is so long (up to 50 ?s) that accesses occurring when the ready pin is sampled inactive can stall GPMC access and eventually cause a system time-out. > If a read access to a NAND flash is done using the wait monitoring mode, the device is blocked during a page opening, and so is the GPMC. If the correct settings are used, other chip-selects can be used while > the memory processes the page opening command. > ... > ----------------- > > It's clearly written that wait-pin monitoring is used for read/write (programs) access, and GPMC is blocked till wait signal is asserted during reads. And you cut out the most important part where it says keep read/write wait monitoring disabled for NAND. pasting again here. "To avoid a time-out caused by a block/page opening delay in NAND flash, disable the wait pin monitoring for read and write accesses (that is, set the GPMC_CONFIG1_i[[21] WAITWRITEMONITORING and GPMC_CONFIG1_i[[22] WAITREADMONITORING bits to 0 and use one of the following methods instead: ?Use software to poll the WAITnSTS bit (n = 0 to 1) of the GPMC_STS register. ?Configure an interrupt that is generated on the WAIT signal change (through the GPMC_IRQEN [11-8] bits). Even if the READWAITMONITORING bit is not set, the external memory nR/B pinstatus is captured in the programmed WAIT bit in the GPMC_STS register. The READWAITMONITORING bit method must be used for other memories than NAND flash, if they require the use of a WAIT signal." > Also, on NAND there can be no read/write access except at page-level And how are command/address inputs sent? ;) > so wait-pin monitoring is implicitly related to read/write accesses. > However, whether you use it or not is purely user's choice, but it > has performance impact. I don't know what you are talking about. I have tried to explain many times but you fail to understand. Nand device ready pin is not same as the wait pin used on other memories where it is used to extend each read/write cycle (by inserting wait state). It is only used to indicate that the NAND device is busy during a block/page operation, so that new commands won't be sent to it by the host processor. This is different from TI GPMC wait monitoring. You have to monitor this device ready pin out of band like polling the status bit or using GPMC interrupt on wait pin transition. Looks like you are getting confused because the same WAIT pin on the SoC is used to get this device ready pin status into the SoC. > > You are probably seeing timeout condition when enabling wait-pin > monitoring, and this can be due to multiple reasons like; > (1) incorrect pin-mux configuration (like directions, pull-up etc) > (2) incorrect board-level pull-up > (3) incorrect driver setting, like though wait-pin is enabled but > wrong wait-pin is being monitored. No for all the 3. > > I request you to fix this instead of disabling it completely, > as you should see significant NAND throughput increase once this > feature works correctly. > >>> >>> - chip->dev_ready in-case of OMAP NAND drivers is set in >>> drivers/mtd/nand/omap2.c during probe. >>> if (pdata->dev_ready) { >>> nand_chip->dev_ready = omap_dev_ready; >>> nand_chip->chip_delay = 0; >>> } >>> >>> Problem is we don't set pdata->dev_ready correctly as part >>> of platform-data dring GPMC initialization. This was what my >>> earlier patch for wait-pin monitoring about. But it was a >>> quick fix for NAND devices. >>> >>> So, I suggest to fix wait-pin monitoring instead of de-scoping >>> it from DTS as wait-pin monitoring should boast the NAND >>> performance significantly. >>> (please see if you can find an old mail thread which had some >>> good feedbacks from Ezequiel and Javier about wait-pin monitoring). This patch is for the 3.17 bug fix cycle. Implementing NAND device ready mechanism is a new feature (for DT case) and I will work on it for future versions. Also I'm not de-scoping wait-pin (or more correctly device ready) mechanism for NAND. The dts file still contains "wait-pin = <0>" property. This will be used to monitor the NAND device ready status via GPMC status or GPMC interrupt. But this is not for 3.17 bug fix cycle. see omap_dev_ready() http://lxr.free-electrons.com/source/drivers/mtd/nand/omap2.c#L1025 >> >> This is to get the device ready mechanism work and has nothing to do with >> GPMC wait monitoring. Instead the WAIT pin is used to generate the GPMC >> interrupt based on the WAIT pin polarity. >> >> To monitor NAND device ready status >> from TRM >> "-Use software to poll the WAITnSTS bit (n = 0 to 1) of the GPMC_STS register. >> OR >> -Configure an interrupt that is generated on the WAIT signal change (through the GPMC_IRQEN [11-8] bits)" >> >>> >>> [...] >>> >>>> This patch also gets rid of the below warning when NAND is >>>> accessed for the first time. >>>> >>>> omap_l3_noc 44000000.ocp: L3 application error: target 13 mod:1 (unclearable) >>>> >>> Can you debug this further. >>> This warning probably comes when driver tries to access some >>> "reserved" addresses. Or violate read/write bits. >> >> It is caused because of incorrectly enabled the GPMC wait monitoring. Disabling the >> wait monitoring gets rid of this error. I don't understand what else I should debug > > I'm not sure how a NAND or GPMC feature can cause omap_l3_noc: L3 application error ? > But now as I re-read the text, its probably the L3 interconnect timeout > error due to no response from GPMC. There is a timer in L3 which monitors if the L3 interconnect is stalled/blocked waiting for response > from a target. I think it's that timer which is getting timeout. (but just my guess). Yes that indeed is the case. > > >> and why. >> > As there were number of users on linux-mtd list wanted to use > NAND wait-pin monitoring on OMAP devices, so I have just looped > them if they see any concerns. It is called NAND device ready mechanism (not wait-pin monitoring). It never worked till now with DT so it is a new feature. > Otherwise, no further concerns from me. Thanks. cheers, -roger From kevint324 at gmail.com Thu Sep 4 05:17:16 2014 From: kevint324 at gmail.com (t kevin) Date: Thu, 4 Sep 2014 20:17:16 +0800 Subject: Question about ubiformat and how to better use UBIFS Message-ID: Hi , Currently I'm trying to create ubifs for rootfs on my device which has a Nand flash on board. Right now I know two approaches to do that. 1. On host,mkfs.ubifs+ubinize to generate one ubi.img. On target board, ubiformat -f ubi.img on the MTD device, ubiattach then mount and it's done. or 2. On host, just tar -cz rootfs to generate root.tgz. On target board, (for the first time)ubiformat the mtd device, ubiattach,ubimkvol, then mount ubifs. Then untar the root.tgz to the mounted ubi volume. Eventually the mountpoint should contain same files. So here are my questions. 1. (Generally speaking) Which one is better? I know ubiformat is going to erase every PEB so right now I prefer the second approach since I don't have to do ubiformat everytime. It sounds like the erase counter grows slower. 2. I'm working on an embedded device which has limited CPU power so I'd like to use compressed_method=none. It can be done by passing -x none to mkfs.ubifs. But I don't see similar option in ubiformat or ubimkvol. So when I go to the 2nd approach the mounted rootfs is always compressed. http://www.linux-mtd.infradead.org/faq/ubifs.html#L_comproff This method is not helping much. I want to disable compression on the entire fs, just like mkfs.ubifs -x none did. Thank you for your time Kevin From pekon at pek-sem.com Thu Sep 4 11:57:45 2014 From: pekon at pek-sem.com (pekon) Date: Fri, 05 Sep 2014 00:27:45 +0530 Subject: [PATCH 3/6] ARM: dts: am437x-gp-evm: Don't use read/write wait monitoring In-Reply-To: <540834F9.8080902@ti.com> References: <1409666227-20622-1-git-send-email-rogerq@ti.com> <1409666227-20622-4-git-send-email-rogerq@ti.com> <54061439.1030909@pek-sem.com> <5406D213.6020603@ti.com> <54074FFA.2020406@pek-sem.com> <540834F9.8080902@ti.com> Message-ID: <5408B629.4030404@pek-sem.com> On Thursday 04 September 2014 03:16 PM, Roger Quadros wrote: [...] > > This patch is for the 3.17 bug fix cycle. Implementing NAND device ready mechanism > is a new feature (for DT case) and I will work on it for future versions. > > Also I'm not de-scoping wait-pin (or more correctly device ready) mechanism for NAND. > The dts file still contains "wait-pin = <0>" property. This will be used to > monitor the NAND device ready status via GPMC status or GPMC interrupt. > But this is not for 3.17 bug fix cycle. > Ok Thanks, that good to know. So for this whole series Reviewed-by: Pekon Gupta with regards, pekon ------------------------ Powered by BigRock.com From ezequiel.garcia at free-electrons.com Fri Sep 5 08:41:40 2014 From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia) Date: Fri, 5 Sep 2014 12:41:40 -0300 Subject: [PATCH] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC In-Reply-To: <1409898233-9273-1-git-send-email-klightspeed@killerwolves.net> References: <1409898233-9273-1-git-send-email-klightspeed@killerwolves.net> Message-ID: <20140905154140.GA1377@arch.hh.imgtec.org> (Fixing Cc list: dropping devicetree guys, and adding Brian and MTD instead) On 05 Sep 04:23 PM, klightspeed at killerwolves.net wrote: > The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC > (strength = 4), while the pxa3xx NAND driver by default uses > Hamming ECC (strength = 1). > Hm, I guess the device (Hynix H27U1G8F2BTR) does not support ONFI, and the kernel is just taking the legacy ECC. The flash specs makes no mention to ONFI, so probably no ONFI here. > This patch changes the ECC mode on these machines to match that > of the bootloader and of the stock firmware, so that for example > updating the kernel is possible without requiring a serial > connection. > > This patch depends on commit 5b3e507 (mtd: nand: pxa3xx: Use ECC > strength and step size devicetree binding) > > Signed-off-by: Ben Peddell Looks good to me, since Arnaud reports this is the correct ECC scheme: http://natisbad.org/NAS2/index.html#hw-nand Acked-by: Ezequiel Garcia Thanks for the fix, -- Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com From arno at natisbad.org Fri Sep 5 13:49:58 2014 From: arno at natisbad.org (Arnaud Ebalard) Date: Fri, 05 Sep 2014 22:49:58 +0200 Subject: [PATCH] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC References: <1409898233-9273-1-git-send-email-klightspeed@killerwolves.net> <20140905154140.GA1377@arch.hh.imgtec.org> Message-ID: <87ha0l23nt.fsf@natisbad.org> Hi, Ezequiel Garcia writes: > (Fixing Cc list: dropping devicetree guys, and adding Brian and MTD instead) > > On 05 Sep 04:23 PM, klightspeed at killerwolves.net wrote: >> The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC >> (strength = 4), while the pxa3xx NAND driver by default uses >> Hamming ECC (strength = 1). >> > > Hm, I guess the device (Hynix H27U1G8F2BTR) does not support ONFI, > and the kernel is just taking the legacy ECC. The flash specs makes no > mention to ONFI, so probably no ONFI here. > >> This patch changes the ECC mode on these machines to match that >> of the bootloader and of the stock firmware, so that for example >> updating the kernel is possible without requiring a serial >> connection. >> >> This patch depends on commit 5b3e507 (mtd: nand: pxa3xx: Use ECC >> strength and step size devicetree binding) >> >> Signed-off-by: Ben Peddell > > Looks good to me, since Arnaud reports this is the correct ECC scheme: > http://natisbad.org/NAS2/index.html#hw-nand > > Acked-by: Ezequiel Garcia > > Thanks for the fix, w/o the patch, you can write data to the flash using userland tools from mtd-utils package (flash_erase and nandwrite); data can then be read again using userland tools (say using dd). But - as reported by Ben - if you nandwrite an uImage from userland, here is what you indeed get from u-boot when you try and boot that image: root at humble:~# flash_erase /dev/mtd2 0 0 Erasing 128 Kibyte @ 5e0000 -- 100 % complete root at humble:~# nandwrite -p /dev/mtd2 /tmp/uImage-3.16.1.rn102 Writing data to block 0 at offset 0x0 Writing data to block 1 at offset 0x20000 Writing data to block 2 at offset 0x40000 Writing data to block 3 at offset 0x60000 Writing data to block 4 at offset 0x80000 ... reboot ... Marvell>> nand read 0x1200000 0x200000 0x600000 NAND read: device 0 offset 0x200000, size 0x600000 6291456 bytes read: OK Marvell>> bootm 0x1200000 ## Booting kernel from Legacy Image at 01200000 ... Image Name: Linux-3.16.1.rn102 Created: 2014-08-14 13:33:46 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4423998 Bytes = 4.2 MB Load Address: 00008000 Entry Point: 00008000 Verifying Checksum ... Bad Data CRC ERROR: can't get kernel image! Now, w/ the patch submitted by Ben, here is what you get: With the patch applied, this indeed works has ## Booting kernel from Legacy Image at 01200000 ... Image Name: Linux-3.16.1.rn102 Created: 2014-09-05 20:25:34 UTC Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4424067 Bytes = 4.2 MB Load Address: 00008000 Entry Point: 00008000 Verifying Checksum ... OK Loading Kernel Image ... OK OK Starting kernel ... i.e. it works. So, thanks for reporting this, Ben. I must confess I got used to update my kernels from u-boot and did not take enough attention to that aspect when I updated the .dts to add access to NAND after Ezequiel wrote the NAND driver. I will take a look at RN104 and RN2120 to check if something similar is needed for those two. FWIW, you can add my: Tested-by: Arnaud Ebalard Additionally, Ezequiel, would anything prevent pushing the patch to stable team (nand entry in .dts was added in 3.14): Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") Cheers, a+ From computersforpeace at gmail.com Fri Sep 5 16:52:01 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 5 Sep 2014 16:52:01 -0700 Subject: [GIT PULL] MTD fixes for 3.17-rc4 Message-ID: <20140905235201.GG18411@ld-irv-0074> Hi Linus, The following changes since commit 2a500afe1e0e84c7a126df693dbd01353756dcfa: mtd: gpmi: make blockmark swapping optional (2014-07-27 22:06:31 -0700) are available in the git repository at: git://git.infradead.org/linux-mtd.git tags/for-linus-20140905 for you to fetch changes up to b25046b1e5e3f1423434da77ccc859f2f779d1ce: mtd: nand: fix DocBook warnings on nand_sdr_timings doc (2014-08-19 11:55:38 -0700) ---------------------------------------------------------------- Two trivial MTD updates for 3.17-rc4: * A tiny comment tweak, to kill a bunch of DocBook warnings added during the merge window * A small fixup to the OTP routines' error handling ---------------------------------------------------------------- Boris BREZILLON (1): mtd: nand: fix DocBook warnings on nand_sdr_timings doc Brian Norris (1): mtd: cfi_cmdset_0002: check return code for get_chip() drivers/mtd/chips/cfi_cmdset_0002.c | 4 ++++ include/linux/mtd/nand.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) From klightspeed at killerwolves.net Fri Sep 5 19:18:49 2014 From: klightspeed at killerwolves.net (Ben Peddell) Date: Sat, 06 Sep 2014 12:18:49 +1000 Subject: [PATCH] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC In-Reply-To: <87ha0l23nt.fsf@natisbad.org> References: <1409898233-9273-1-git-send-email-klightspeed@killerwolves.net> <20140905154140.GA1377@arch.hh.imgtec.org> <87ha0l23nt.fsf@natisbad.org> Message-ID: <540A6F09.9000605@killerwolves.net> On 06 Sep 2014 at 06:49, Arnaud Ebalard wrote: > FWIW, you can add my: > > Tested-by: Arnaud Ebalard > > Additionally, Ezequiel, would anything prevent pushing the patch to > stable team (nand entry in .dts was added in 3.14): > > Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") Depends-on: 5b3e507820c6 ("mtd: nand: pxa3xx: Use ECC strength and step size devicetree binding") The devicetree binding is not currently in linux-stable/linux-3.14.y From ezequiel at vanguardiasur.com.ar Sat Sep 6 12:56:26 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 16:56:26 -0300 Subject: [PATCH 0/3] nand: omap2: Two and a half improvements Message-ID: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> Hi Brian, Roger: Pekon's attempt to add flash BBT support for this driver made me realise the addition made sense and there were good reasons for it. The first patch adds support for enabling a flash BBT either from legacy board files or from devicetree. While testing this, I noticed how the driver relied on a whole bunch of horrible #ifdefs, which prevented me from loading the driver as a module. The second patch attempts to fix that. The third patch is just a dummy cleanup replacing pr_errs with dev_errs. This driver is abusing from user messages, but I'm not sure fixing them worths the trouble. Roger, do you think you can test patches 1 and 2 with different ECCs and configurations? It's an invasive patch and I don't want to see more regressions with this driver. And speaking of modules, the driver loads as "modprobe omap2". And it's not the only one with a clumsy name: "modprobe elm". I guess we cannot fix it now, but it would be great to be more careful with driver naming in the future. Ezequiel Garcia (3): nand: omap2: Add support for a flash-based bad block table nand: omap2: Refactor the code to remove horrible ifdefs nand: omap2: Replace pr_err with dev_err arch/arm/mach-omap2/gpmc.c | 2 + drivers/mtd/nand/omap2.c | 166 +++++++++++++++------------ include/linux/platform_data/elm.h | 14 +++ include/linux/platform_data/mtd-nand-omap2.h | 1 + 4 files changed, 108 insertions(+), 75 deletions(-) -- 2.0.1 From ezequiel at vanguardiasur.com.ar Sat Sep 6 12:56:27 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 16:56:27 -0300 Subject: [PATCH 1/3] nand: omap2: Add support for a flash-based bad block table In-Reply-To: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410033389-32357-2-git-send-email-ezequiel@vanguardiasur.com.ar> This commit adds a new platform-data boolean property that enables use of a flash-based bad block table. This can also be enabled by setting the 'nand-on-flash-bbt' devicetree property. If the flash BBT is not enabled, the driver falls back to use OOB bad block markers only, as before. If the flash BBT is enabled the kernel will keep track of bad blocks using a BBT, in addition to the OOB markers. As explained by Brian Norris the reasons for using a BBT are: "" The primary reason would be that NAND datasheets specify it these days. A better argument is that nobody guarantees that you can write a bad block marker to a worn out block; you may just get program failures. This has been acknowledged by several developers over the last several years. Additionally, you get a boot-time performance improvement if you only have to read a few pages, instead of a page or two from every block on the flash. "" Signed-off-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 2 ++ drivers/mtd/nand/omap2.c | 6 +++++- include/linux/platform_data/mtd-nand-omap2.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8bc1338..bafe190 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1438,6 +1438,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f0ed92e..1170389 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) mtd->owner = THIS_MODULE; nand_chip = &info->nand; nand_chip->ecc.priv = NULL; - nand_chip->options |= NAND_SKIP_BBTSCAN; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 50; } + if (pdata->flash_bbt) + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + else + nand_chip->options |= NAND_SKIP_BBTSCAN; + /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 660c029..781e9e6 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -62,6 +62,7 @@ struct omap_nand_platform_data { struct mtd_partition *parts; int nr_parts; bool dev_ready; + bool flash_bbt; enum nand_io xfer_type; int devsize; enum omap_ecc ecc_opt; -- 2.0.1 From ezequiel at vanguardiasur.com.ar Sat Sep 6 12:56:28 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 16:56:28 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> The current code abuses ifdefs to determine if the selected ECC scheme is supported by the running kernel. As a result the code is hard to read, and it also fails to load as a module. This commit removes all the ifdefs and instead introduces a function omap2_nand_ecc_check() to check if the ECC is supported by using IS_ENABLED(CONFIG_xxx). Since IS_ENABLED() is true when a config is =y or =m, this change fixes the module so it can be loaded with no issues. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 134 +++++++++++++++++++++----------------- include/linux/platform_data/elm.h | 14 ++++ 2 files changed, 87 insertions(+), 61 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 1170389..987dd94 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -136,7 +136,6 @@ #define BADBLOCK_MARKER_LENGTH 2 -#ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -#endif /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, /** * is_elm_present - checks for presence of ELM module by scanning DT nodes * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static bool is_elm_present(struct omap_nand_info *info, + struct device_node *elm_node) { struct platform_device *pdev; - struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int err; + /* check whether elm-id is passed via DT */ if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); + return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { - pr_err("nand: error: ELM device not found\n"); - return -ENODEV; + dev_err(&info->pdev->dev, "ELM device not found\n"); + return false; } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - err = elm_config(info->elm_dev, bch_type, - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + return true; +} - return err; +static bool omap2_nand_ecc_check(struct omap_nand_info *info, + struct omap_nand_platform_data *pdata) +{ + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; + + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + ecc_needs_omap_bch = false; + ecc_needs_bch = true; + ecc_needs_elm = false; + break; + case OMAP_ECC_BCH4_CODE_HW: + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + ecc_needs_omap_bch = true; + ecc_needs_bch = false; + ecc_needs_elm = true; + break; + default: + ecc_needs_omap_bch = false; + ecc_needs_bch = false; + ecc_needs_elm = false; + break; + } + + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + return false; + } + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + return false; + } + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { + dev_err(&info->pdev->dev, "ELM not available\n"); + return false; + } + + return true; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ static int omap_nand_probe(struct platform_device *pdev) { @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } + if (!omap2_nand_ecc_check(info, pdata)) { + err = -EINVAL; + goto return_error; + } + /* populate MTD interface based on ECC scheme */ nand_chip->ecc.layout = &omap_oobinfo; ecclayout = &omap_oobinfo; @@ -1826,7 +1866,6 @@ static int omap_nand_probe(struct platform_device *pdev) break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1858,14 +1897,8 @@ static int omap_nand_probe(struct platform_device *pdev) err = -EINVAL; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1887,21 +1920,15 @@ static int omap_nand_probe(struct platform_device *pdev) /* reserved marker already included in ecclayout->eccbytes */ ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; + + err = elm_config(info->elm_dev, BCH4_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1934,14 +1961,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1953,12 +1974,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); + + err = elm_config(info->elm_dev, BCH8_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1970,14 +1992,8 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1988,12 +2004,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); - if (err < 0) { - pr_err("ELM is required for this ECC scheme\n"); + + err = elm_config(info->elm_dev, BCH16_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -2005,11 +2022,6 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 780d1e9..25d1bca 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,8 +42,22 @@ struct elm_errorvec { int error_loc[16]; }; +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size); +#else +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ +} + +int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_MTD_NAND_ECC_BCH */ + #endif /* __ELM_H */ -- 2.0.1 From ezequiel at vanguardiasur.com.ar Sat Sep 6 12:56:29 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 16:56:29 -0300 Subject: [PATCH 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410033389-32357-4-git-send-email-ezequiel@vanguardiasur.com.ar> Usage of pr_err is frowned upon, so replace it with dev_err. Aditionally, the message on nand_bch_init() error is redundant, since proper error is showed if the function fails. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 987dd94..8521f0d 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, erased_ecc_vec = bch16_vector; break; default: - pr_err("invalid driver configuration\n"); + dev_err(&info->pdev->dev, "invalid driver configuration\n"); return -EINVAL; } @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, err = 0; for (i = 0; i < eccsteps; i++) { if (err_vec[i].error_uncorrectable) { - pr_err("nand: uncorrectable bit-flips found\n"); + dev_err(&info->pdev->dev, + "uncorrectable bit-flips found\n"); err = -EBADMSG; } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, 1 << bit_pos; } } else { - pr_err("invalid bit-flip @ %d:%d\n", - byte_pos, bit_pos); + dev_err(&info->pdev->dev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); err = -EBADMSG; } } @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); err = -ENXIO; goto return_error; } /* check for small page devices */ if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); + dev_err(&info->pdev->dev, "small page devices are not supported\n"); err = -EINVAL; goto return_error; } @@ -1892,10 +1894,8 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.size, nand_chip->ecc.bytes, &nand_chip->ecc.layout); - if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + if (!nand_chip->ecc.priv) err = -EINVAL; - } break; case OMAP_ECC_BCH4_CODE_HW: @@ -1956,7 +1956,6 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &nand_chip->ecc.layout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); err = -EINVAL; goto return_error; } @@ -2023,7 +2022,7 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); err = -EINVAL; goto return_error; } @@ -2032,8 +2031,9 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); + dev_err(&info->pdev->dev, + "not enough OOB bytes required = %d, available=%d\n", + ecclayout->eccbytes, mtd->oobsize); err = -EINVAL; goto return_error; } -- 2.0.1 From arno at natisbad.org Sat Sep 6 13:48:44 2014 From: arno at natisbad.org (Arnaud Ebalard) Date: Sat, 06 Sep 2014 22:48:44 +0200 Subject: [PATCH 0/2] ARM: mvebu: Use Hardware BCH ECC for RN104 and RN2120 Message-ID: Hi, Following Ben's report and fix for RN102, I did some tests on RN104 and RN2120 (they have the same Hynix H27U1G8F2BTR flash and setup) and came up w/ the exact same fixes for their respective .dts files. With those patches, it is now possible to update kernel from userland and u-boot will happily load and boot it on those devices. Both patches should be candidates for stable, I guess. Cheers, a+ Arnaud Ebalard (2): ARM: mvebu: Netgear RN104: Use Hardware BCH ECC ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC arch/arm/boot/dts/armada-370-netgear-rn104.dts | 4 ++++ arch/arm/boot/dts/armada-xp-netgear-rn2120.dts | 4 ++++ 2 files changed, 8 insertions(+) -- 2.1.0 From arno at natisbad.org Sat Sep 6 13:49:25 2014 From: arno at natisbad.org (Arnaud Ebalard) Date: Sat, 06 Sep 2014 22:49:25 +0200 Subject: [PATCH 1/2] ARM: mvebu: Netgear RN104: Use Hardware BCH ECC In-Reply-To: References: Message-ID: <920c7e7169dc6aaaa3eb4bced2336d38e77b8864.1410035142.git.arno@natisbad.org> The bootloader on the Netgear ReadyNAS RN104 uses Hardware BCH ECC (strength = 4), while the pxa3xx NAND driver by default uses Hamming ECC (strength = 1). This patch changes the ECC mode on these machines to match that of the bootloader and of the stock firmware. That way, it is now possible to update the kernel from userland (e.g. using standard tools from mtd-utils package); u-boot will happily load and boot it. The issue was initially reported and fixed by Ben Pedell for RN102. The RN104 shares the same Hynix H27U1G8F2BTR NAND flash and setup. This patch is based on Ben's fix for RN102. Fixes: 0373a558bd79 ("ARM: mvebu: Enable NAND controller in ReadyNAS 104 .dts file") Depends-on: 5b3e507820c6 ("mtd: nand: pxa3xx: Use ECC strength and step size devicetree binding") Signed-off-by: Arnaud Ebalard --- arch/arm/boot/dts/armada-370-netgear-rn104.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts index f7eb110f43d4..d49e8f24a1c9 100644 --- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts +++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts @@ -165,6 +165,10 @@ marvell,nand-enable-arbiter; nand-on-flash-bbt; + /* Use Hardware BCH ECC */ + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + partition at 0 { label = "u-boot"; reg = <0x0000000 0x180000>; /* 1.5MB */ -- 2.1.0 From arno at natisbad.org Sat Sep 6 13:49:38 2014 From: arno at natisbad.org (Arnaud Ebalard) Date: Sat, 06 Sep 2014 22:49:38 +0200 Subject: [PATCH 2/2] ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC In-Reply-To: References: Message-ID: <61f6a1b7ad0adc57a0e201b9680bc2e5f214a317.1410035142.git.arno@natisbad.org> The bootloader on the Netgear ReadyNAS RN2120 uses Hardware BCH ECC (strength = 4), while the pxa3xx NAND driver by default uses Hamming ECC (strength = 1). This patch changes the ECC mode on these machines to match that of the bootloader and of the stock firmware. That way, it is now possible to update the kernel from userland (e.g. using standard tools from mtd-utils package); u-boot will happily load and boot it. The issue was initially reported and fixed by Ben Pedell for RN102. The RN2120 shares the same Hynix H27U1G8F2BTR NAND flash and setup. This patch is based on Ben's fix for RN102. Fixes: ad51eddd95ad ("ARM: mvebu: Enable NAND controller in ReadyNAS 2120 .dts file") Depends-on: 5b3e507820c6 ("mtd: nand: pxa3xx: Use ECC strength and step size devicetree binding") Signed-off-by: Arnaud Ebalard --- arch/arm/boot/dts/armada-xp-netgear-rn2120.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts index 0cf999abc4ed..c5ed85a70ed9 100644 --- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts +++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts @@ -223,6 +223,10 @@ marvell,nand-enable-arbiter; nand-on-flash-bbt; + /* Use Hardware BCH ECC */ + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + partition at 0 { label = "u-boot"; reg = <0x0000000 0x180000>; /* 1.5MB */ -- 2.1.0 From pekon at pek-sem.com Sat Sep 6 14:10:52 2014 From: pekon at pek-sem.com (pekon) Date: Sun, 07 Sep 2014 02:40:52 +0530 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <540B785C.3070400@pek-sem.com> + linux-omap, as this patch touches arch/arm/mach-omap2/gpmc.c Hi Ezequiel, On Sunday 07 September 2014 01:26 AM, Ezequiel Garcia wrote: > The current code abuses ifdefs to determine if the selected ECC scheme > is supported by the running kernel. As a result the code is hard to read, > and it also fails to load as a module. > > This commit removes all the ifdefs and instead introduces a function > omap2_nand_ecc_check() to check if the ECC is supported by using > IS_ENABLED(CONFIG_xxx). > Yup, true. Thanks for cleaning up OMAP2 NAND driver, but few feedbacks. Just for record, current version of omap2.c NAND driver has so many #ifdef because: (1) Many ECC schemes like HAM1 and BCH4_xx, BCH8_SW are supported only for compatibility with old platforms like OMAP3. And these legacy schemes have significant amount of code and data foot-print (as compared to whole driver), so it does not make sense to keep driver bulky for all new platforms which do not use legacy ECC schemes. (2) Specifically, BCH4_SW and BCH8_SW ECC schemes used software library /lib/bch.c "directly". Due to which if BCH4_SW or BCH8_SW was include in code, /lib/bch.c was included implicitly. Later from following following commit nand_bch.c wrapper was used which took care to exclude /lib/bch.c when CONFIG_MTD_NAND_ECC_BCH was not defined, but #ifdef continued :-( (My bad, I accept ..) commit 32d42a855a6f1445373f3d680e9125344aca294c mtd: nand: omap: use drivers/mtd/nand/nand_bch.c wrapper for BCH ECC instead of lib/bch.c > Since IS_ENABLED() is true when a config is =y or =m, this change fixes the > module so it can be loaded with no issues. > > Signed-off-by: Ezequiel Garcia > --- > drivers/mtd/nand/omap2.c | 134 +++++++++++++++++++++----------------- > include/linux/platform_data/elm.h | 14 ++++ > 2 files changed, 87 insertions(+), 61 deletions(-) [...] > @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, > /** > * is_elm_present - checks for presence of ELM module by scanning DT nodes > * @omap_nand_info: NAND device structure containing platform data > - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 > */ > -static int is_elm_present(struct omap_nand_info *info, > - struct device_node *elm_node, enum bch_ecc bch_type) > +static bool is_elm_present(struct omap_nand_info *info, > + struct device_node *elm_node) > { > struct platform_device *pdev; > - struct nand_ecc_ctrl *ecc = &info->nand.ecc; > - int err; > + > /* check whether elm-id is passed via DT */ > if (!elm_node) { > - pr_err("nand: error: ELM DT node not found\n"); > - return -ENODEV; > + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); > + return false; > } > pdev = of_find_device_by_node(elm_node); > /* check whether ELM device is registered */ > if (!pdev) { > - pr_err("nand: error: ELM device not found\n"); > - return -ENODEV; > + dev_err(&info->pdev->dev, "ELM device not found\n"); > + return false; > } Thanks, for this clean-up of replacing pr_err() to dev_err(). Just that if you can resend this as separate patch then I'll surely Ack it. [...] > +static bool omap2_nand_ecc_check(struct omap_nand_info *info, > + struct omap_nand_platform_data *pdata) > +{ > + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; > + > + switch (info->ecc_opt) { > + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: > + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: > + ecc_needs_omap_bch = false; > + ecc_needs_bch = true; > + ecc_needs_elm = false; > + break; > + case OMAP_ECC_BCH4_CODE_HW: > + case OMAP_ECC_BCH8_CODE_HW: > + case OMAP_ECC_BCH16_CODE_HW: > + ecc_needs_omap_bch = true; > + ecc_needs_bch = false; > + ecc_needs_elm = true; > + break; > + default: > + ecc_needs_omap_bch = false; > + ecc_needs_bch = false; > + ecc_needs_elm = false; > + break; > + } > + > + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { > + dev_err(&info->pdev->dev, > + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); > + return false; > + } > + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { > + dev_err(&info->pdev->dev, > + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > + return false; > + } > + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { > + dev_err(&info->pdev->dev, "ELM not available\n"); > + return false; > + } > + > + return true; > } Actually this new function is not required. We already have this check in GPMC driver when we select the ecc-scheme. Plz refer: File: /arch/arm/mach-omap2/gpmc.c @@ static int gpmc_probe_nand_child(...) ... /* select ecc-scheme for NAND */ is_elm_enabled() is a misnomer here. It actually does not check for ELM DTS node, because that check is already done in GPMC driver. It rather checks if ELM device is correctly binded and driver "initialized" before NAND driver is probed. Though ELM is not required during NAND probe because there is no error checking/correction required during NAND probe, but this again comes from the history of maintaining back-ward compatibility with board-file (non DTS) approach. Once we move to all DTS approach may be this can be removed (but on case-by case basis). [...] > diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h > index 780d1e9..25d1bca 100644 > --- a/include/linux/platform_data/elm.h > +++ b/include/linux/platform_data/elm.h > @@ -42,8 +42,22 @@ struct elm_errorvec { > int error_loc[16]; > }; > > +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) > void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > struct elm_errorvec *err_vec); > int elm_config(struct device *dev, enum bch_ecc bch_type, > int ecc_steps, int ecc_step_size, int ecc_syndrome_size); > +#else > +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > + struct elm_errorvec *err_vec) > +{ > +} > + > +int elm_config(struct device *dev, enum bch_ecc bch_type, > + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) > +{ > + return -ENOSYS; > +} > +#endif /* CONFIG_MTD_NAND_ECC_BCH */ > + > #endif /* __ELM_H */ > If I'm not wrong, this is all you need in this patch empty functions for CONFIG_MTD_NAND_ECC_BCH exposed symbols are already handled in /include/linux/mtd/nand_bch.h So, after this change, you can most of #ifdefs and IS_ENABLED() and this patch should be simplified. with regards, pekon ------------------------ Powered by BigRock.com From ezequiel at vanguardiasur.com.ar Sat Sep 6 14:47:11 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 18:47:11 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540B785C.3070400@pek-sem.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540B785C.3070400@pek-sem.com> Message-ID: <20140906214711.GB20943@arch.cereza> On 07 Sep 02:40 AM, pekon wrote: > + linux-omap, as this patch touches arch/arm/mach-omap2/gpmc.c > > Hi Ezequiel, > > On Sunday 07 September 2014 01:26 AM, Ezequiel Garcia wrote: > >The current code abuses ifdefs to determine if the selected ECC scheme > >is supported by the running kernel. As a result the code is hard to read, > >and it also fails to load as a module. > > > >This commit removes all the ifdefs and instead introduces a function > >omap2_nand_ecc_check() to check if the ECC is supported by using > >IS_ENABLED(CONFIG_xxx). > > > Yup, true. > Thanks for cleaning up OMAP2 NAND driver, but few feedbacks. > First of all, this is no cleaning. The driver fails to load as a module over here. Unless I'm missed something, ifdef seemed false when CONFIG_xxx=m. > Just for record, current version of omap2.c NAND driver has so > many #ifdef because: > [..] I can't think of any valid excuses for cluttering the code with ifdefs like this. There are several ways of doing things cleaner, by grouping code differently. [..] > >+ } > >+ if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { > >+ dev_err(&info->pdev->dev, "ELM not available\n"); > >+ return false; > >+ } > >+ > >+ return true; > > } > > Actually this new function is not required. [snip] > If I'm not wrong, this is all you need in this patch > empty functions for CONFIG_MTD_NAND_ECC_BCH exposed symbols are already > handled in /include/linux/mtd/nand_bch.h > > So, after this change, you can most of #ifdefs and IS_ENABLED() > and this patch should be simplified. > OK, I'll take a look. Thanks for the suggestion, -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Sat Sep 6 16:17:28 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 6 Sep 2014 20:17:28 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540B785C.3070400@pek-sem.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540B785C.3070400@pek-sem.com> Message-ID: <20140906231728.GA4663@arch.cereza> On 07 Sep 02:40 AM, pekon wrote: [..] > >+static bool omap2_nand_ecc_check(struct omap_nand_info *info, > >+ struct omap_nand_platform_data *pdata) > >+{ > >+ bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; > >+ > >+ switch (info->ecc_opt) { > >+ case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: > >+ case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: > >+ ecc_needs_omap_bch = false; > >+ ecc_needs_bch = true; > >+ ecc_needs_elm = false; > >+ break; > >+ case OMAP_ECC_BCH4_CODE_HW: > >+ case OMAP_ECC_BCH8_CODE_HW: > >+ case OMAP_ECC_BCH16_CODE_HW: > >+ ecc_needs_omap_bch = true; > >+ ecc_needs_bch = false; > >+ ecc_needs_elm = true; > >+ break; > >+ default: > >+ ecc_needs_omap_bch = false; > >+ ecc_needs_bch = false; > >+ ecc_needs_elm = false; > >+ break; > >+ } > >+ > >+ if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { > >+ dev_err(&info->pdev->dev, > >+ "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); > >+ return false; > >+ } > >+ if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { > >+ dev_err(&info->pdev->dev, > >+ "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > >+ return false; > >+ } > >+ if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { > >+ dev_err(&info->pdev->dev, "ELM not available\n"); > >+ return false; > >+ } > >+ > >+ return true; > > } > > Actually this new function is not required. > We already have this check in GPMC driver when we select the ecc-scheme. > Plz refer: File: /arch/arm/mach-omap2/gpmc.c > @@ static int gpmc_probe_nand_child(...) > ... > /* select ecc-scheme for NAND */ > > is_elm_enabled() is a misnomer here. It actually does not check > for ELM DTS node, because that check is already done in GPMC driver. > It rather checks if ELM device is correctly binded and driver > "initialized" before NAND driver is probed. > > Though ELM is not required during NAND probe because there is no error > checking/correction required during NAND probe, but this again comes > from the history of maintaining back-ward compatibility with board-file > (non DTS) approach. Once we move to all DTS approach may be this can be > removed (but on case-by case basis). > > [...] > > >diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h > >index 780d1e9..25d1bca 100644 > >--- a/include/linux/platform_data/elm.h > >+++ b/include/linux/platform_data/elm.h > >@@ -42,8 +42,22 @@ struct elm_errorvec { > > int error_loc[16]; > > }; > > > >+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) > > void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > > struct elm_errorvec *err_vec); > > int elm_config(struct device *dev, enum bch_ecc bch_type, > > int ecc_steps, int ecc_step_size, int ecc_syndrome_size); > >+#else > >+void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > >+ struct elm_errorvec *err_vec) > >+{ > >+} > >+ > >+int elm_config(struct device *dev, enum bch_ecc bch_type, > >+ int ecc_steps, int ecc_step_size, int ecc_syndrome_size) > >+{ > >+ return -ENOSYS; > >+} > >+#endif /* CONFIG_MTD_NAND_ECC_BCH */ > >+ > > #endif /* __ELM_H */ > > > If I'm not wrong, this is all you need in this patch > empty functions for CONFIG_MTD_NAND_ECC_BCH exposed symbols are already > handled in /include/linux/mtd/nand_bch.h > > So, after this change, you can most of #ifdefs and IS_ENABLED() > and this patch should be simplified. > If I understand your proposal correctly you are suggesting to drop the checks for CONFIG_MTD_NAND_ECC_BCH, CONFIG_MTD_NAND_OMAP_BCH, and the ELM devicetree node. However, I'd say that change is even more invasive than this one. This commit merely replaces the current #ifdefs check with IS_ENABLED and tries to do so in a cleaner way. This is done on purpose, to keep the current behavior as much as possible. In addition, if we don't check for the configs explicitly at probe time, we would only defer the error until some later point, for instance in the call to nand_chip->ecc.correct(). I don't think that's user-friendly. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From thomas.petazzoni at free-electrons.com Sun Sep 7 00:38:51 2014 From: thomas.petazzoni at free-electrons.com (Thomas Petazzoni) Date: Sun, 7 Sep 2014 09:38:51 +0200 Subject: [PATCH 1/2] ARM: mvebu: Netgear RN104: Use Hardware BCH ECC In-Reply-To: <920c7e7169dc6aaaa3eb4bced2336d38e77b8864.1410035142.git.arno@natisbad.org> References: <920c7e7169dc6aaaa3eb4bced2336d38e77b8864.1410035142.git.arno@natisbad.org> Message-ID: <20140907093851.377ddd29@free-electrons.com> Dear Arnaud Ebalard, On Sat, 06 Sep 2014 22:49:25 +0200, Arnaud Ebalard wrote: > Fixes: 0373a558bd79 ("ARM: mvebu: Enable NAND controller in ReadyNAS 104 .dts file") > Depends-on: 5b3e507820c6 ("mtd: nand: pxa3xx: Use ECC strength and step size devicetree binding") Maybe it's worth noting that it's not a build dependency: your commit changing the Device Tree files can perfectly be applied without the NAND ECC strength and step size bindings. Of course, it will have no effect on an older kernel that doesn't support those bindings, but it will not cause a build failure. Thanks! Thomas -- Thomas Petazzoni, CTO, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com From arno at natisbad.org Sun Sep 7 02:19:19 2014 From: arno at natisbad.org (Arnaud Ebalard) Date: Sun, 07 Sep 2014 11:19:19 +0200 Subject: [PATCH 1/2] ARM: mvebu: Netgear RN104: Use Hardware BCH ECC In-Reply-To: <20140907093851.377ddd29@free-electrons.com> (Thomas Petazzoni's message of "Sun, 7 Sep 2014 09:38:51 +0200") References: <920c7e7169dc6aaaa3eb4bced2336d38e77b8864.1410035142.git.arno@natisbad.org> <20140907093851.377ddd29@free-electrons.com> Message-ID: <87oaurg548.fsf@natisbad.org> Hi Thomas, Thomas Petazzoni writes: > On Sat, 06 Sep 2014 22:49:25 +0200, Arnaud Ebalard wrote: > >> Fixes: 0373a558bd79 ("ARM: mvebu: Enable NAND controller in ReadyNAS 104 .dts file") >> Depends-on: 5b3e507820c6 ("mtd: nand: pxa3xx: Use ECC strength and step size devicetree binding") > > Maybe it's worth noting that it's not a build dependency: your commit > changing the Device Tree files can perfectly be applied without the > NAND ECC strength and step size bindings. Of course, it will have no > effect on an older kernel that doesn't support those bindings, but it > will not cause a build failure. Yes. To be more explicit, if the patches are candidates for stable, I think they are only useful for 3.16.y (3.16 is the first kernel with 5b3e507820c6). As you point, backporting down to 3.14 would not hurt but would only be decorative. Cheers, a+ From pekon at pek-sem.com Sun Sep 7 02:35:51 2014 From: pekon at pek-sem.com (pekon) Date: Sun, 07 Sep 2014 15:05:51 +0530 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <20140906231728.GA4663@arch.cereza> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540B785C.3070400@pek-sem.com> <20140906231728.GA4663@arch.cereza> Message-ID: <540C26F7.7020005@pek-sem.com> Hi Ezequiel, On Sunday 07 September 2014 04:47 AM, Ezequiel Garcia wrote: > On 07 Sep 02:40 AM, pekon wrote: >> [...] >> >>> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h >>> index 780d1e9..25d1bca 100644 >>> --- a/include/linux/platform_data/elm.h >>> +++ b/include/linux/platform_data/elm.h >>> @@ -42,8 +42,22 @@ struct elm_errorvec { >>> int error_loc[16]; >>> }; >>> >>> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) >>> void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >>> struct elm_errorvec *err_vec); >>> int elm_config(struct device *dev, enum bch_ecc bch_type, >>> int ecc_steps, int ecc_step_size, int ecc_syndrome_size); >>> +#else >>> +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >>> + struct elm_errorvec *err_vec) >>> +{ >>> +} >>> + >>> +int elm_config(struct device *dev, enum bch_ecc bch_type, >>> + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) >>> +{ >>> + return -ENOSYS; >>> +} >>> +#endif /* CONFIG_MTD_NAND_ECC_BCH */ >>> + >>> #endif /* __ELM_H */ >>> >> If I'm not wrong, this is all you need in this patch >> empty functions for CONFIG_MTD_NAND_ECC_BCH exposed symbols are already >> handled in /include/linux/mtd/nand_bch.h >> >> So, after this change, you can most of #ifdefs and IS_ENABLED() >> and this patch should be simplified. >> > > If I understand your proposal correctly you are suggesting to drop the > checks for CONFIG_MTD_NAND_ECC_BCH, CONFIG_MTD_NAND_OMAP_BCH, and the ELM > devicetree node. > Absolutely .. (1) Just the change marked above handles whether CONFIG_MTD_NAND_OMAP_BCH is defined or not. (2) Same way nand_bch.c takes care whether CONFIG_MTD_NAND_ECC_BCH is defined or not. (3) And gpmc.c @@gpmc_probe_nand_child(...) already checks for ELM DTS node. > However, I'd say that change is even more invasive than this one. This commit > merely replaces the current #ifdefs check with IS_ENABLED and tries to do so > in a cleaner way. > I would say you can get rid of most of #ifdefs and IS_ENABLED() in this patch itself. And testing it that should be easy, you just need to compile with CONFIG_MTD_NAND_xxx_BCH enabled one at a time. > This is done on purpose, to keep the current behavior as much as possible. > > In addition, if we don't check for the configs explicitly at probe time, > we would only defer the error until some later point, for instance in the call to > nand_chip->ecc.correct(). I don't think that's user-friendly. > As ECC-scheme is selected in GPMC driver based on DTS settings, so any mis-match is easily handled there. Moreover, error will occur when we change ECC-scheme on-the-fly, which is still not supported by framework, and require many other updates if we plan to support that in near future. So considering ECC-scheme as static configuration is a safe assumption. But surely you can drop new check in omap2_nand_ecc_check(), which is already covered in @@gpmc_probe_nand_child(...) However, I leave it to you and rogerq at ti.com (as he currently maintains OMAP NAND driver from TI side) to decide how to go about it. with regards, pekon ------------------------ Powered by BigRock.com From dcb314 at hotmail.com Sun Sep 7 07:58:26 2014 From: dcb314 at hotmail.com (David Binderman) Date: Sun, 7 Sep 2014 14:58:26 +0000 Subject: mtd-utils-1.5.1 bug report Message-ID: Hello there, ubi-utils/ubiformat.c:636:28: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] ??????????????? if (!args.subpage_size != mtd->min_io_size) ??????????????????? normsg("may be sub-page size is " ?????????????????????????? "incorrect?"); Something boolean compared to a size. Looks a possible problem to me. Removal of the double negative might also help. Regards David Binderman From ezequiel at vanguardiasur.com.ar Sun Sep 7 08:16:56 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sun, 7 Sep 2014 12:16:56 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540C26F7.7020005@pek-sem.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540B785C.3070400@pek-sem.com> <20140906231728.GA4663@arch.cereza> <540C26F7.7020005@pek-sem.com> Message-ID: <20140907151656.GA1048@arch.cereza> On 07 Sep 03:05 PM, pekon wrote: [..] > As ECC-scheme is selected in GPMC driver based on DTS settings, so > any mis-match is easily handled there. > Moreover, error will occur when we change ECC-scheme on-the-fly, > which is still not supported by framework, and require many other > updates if we plan to support that in near future. > So considering ECC-scheme as static configuration is a safe assumption. > > But surely you can drop new check in omap2_nand_ecc_check(), which > is already covered in @@gpmc_probe_nand_child(...) > > However, I leave it to you and rogerq at ti.com (as he currently > maintains OMAP NAND driver from TI side) to decide how to go about it. > As far as I can see, your proposal only cover the devicetree-probed case and it won't work for legacy boards. Given it seems we still support legacy, I'd say your proposal would break things. Not to mention that I still prefer to fail at probe time if the driver cannot deal with the selected ECC, and that's exactly what omap2_nand_ecc_check() does. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From yamada.m at jp.panasonic.com Mon Sep 8 01:10:10 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:10 +0900 Subject: [PATCH 4/7] mtd: denali: change the type of iterators to int In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-5-git-send-email-yamada.m@jp.panasonic.com> We should rathar use "int" type for loop iterators. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index dcd6771..259ca0ba 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -178,7 +178,7 @@ static void reset_bank(struct denali_nand_info *denali) /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { - uint32_t i; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); @@ -499,7 +499,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) { uint16_t status = PASS; uint32_t id_bytes[8], addr; - uint8_t i, maf_id, device_id; + uint8_t maf_id, device_id; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", @@ -830,7 +831,8 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * verify that the len is a multiple of 4. @@ -850,7 +852,8 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * we assume that len will be a multiple of 4, if not it would be nice -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:07 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:07 +0900 Subject: [PATCH 1/7] mtd: denali: fix the format of comment blocks In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-2-git-send-email-yamada.m@jp.panasonic.com> We should use /* * Blah Blah ... * ... */ for multi-line comment blocks. In addition, refactor some comments where it seems reasonable and remove some comments where the code is clear enough such as: /* clear interrupts */ clear_interrupts(denali); Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 311 ++++++++++++++++++++++++++++------------------ 1 file changed, 188 insertions(+), 123 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index da0fcc2..44a5f159 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -29,7 +29,8 @@ MODULE_LICENSE("GPL"); -/* We define a module parameter that allows the user to override +/* + * We define a module parameter that allows the user to override * the hardware and decide what timing mode should be used. */ #define NAND_DEFAULT_TIMINGS -1 @@ -41,8 +42,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define DENALI_NAND_NAME "denali-nand" -/* We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. */ +/* + * We define a macro here that combines all interrupts this driver uses into + * a single constant value, for convenience. + */ #define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ INTR_STATUS__ECC_TRANSACTION_DONE | \ INTR_STATUS__ECC_ERR | \ @@ -54,23 +57,30 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." INTR_STATUS__RST_COMP | \ INTR_STATUS__ERASE_COMP) -/* indicates whether or not the internal value for the flash bank is - * valid or not */ +/* + * indicates whether or not the internal value for the flash bank is + * valid or not + */ #define CHIP_SELECT_INVALID -1 #define SUPPORT_8BITECC 1 -/* This macro divides two integers and rounds fractional values up - * to the nearest integer value. */ +/* + * This macro divides two integers and rounds fractional values up + * to the nearest integer value. + */ #define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) -/* this macro allows us to convert from an MTD structure to our own +/* + * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ #define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) -/* These constants are defined by the driver to enable common driver - * configuration options. */ +/* + * These constants are defined by the driver to enable common driver + * configuration options. + */ #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 @@ -84,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define ADDR_CYCLE 1 #define STATUS_CYCLE 2 -/* this is a helper macro that allows us to - * format the bank into the proper bits for the controller */ +/* + * this is a helper macro that allows us to + * format the bank into the proper bits for the controller + */ #define BANK(x) ((x) << 24) /* forward declarations */ @@ -96,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali, uint32_t int_mask); static uint32_t read_interrupt_status(struct denali_nand_info *denali); -/* Certain operations for the denali NAND controller use - * an indexed mode to read/write data. The operation is - * performed by writing the address value of the command - * to the device memory followed by the data. This function +/* + * Certain operations for the denali NAND controller use an indexed mode to + * read/write data. The operation is performed by writing the address value + * of the command to the device memory followed by the data. This function * abstracts this common operation. -*/ + */ static void index_addr(struct denali_nand_info *denali, uint32_t address, uint32_t data) { @@ -117,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali, *pdata = ioread32(denali->flash_mem + 0x10); } -/* We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. */ +/* + * We need to buffer some data for some of the NAND core routines. + * The operations manage buffering that data. + */ static void reset_buf(struct denali_nand_info *denali) { denali->buf.head = denali->buf.tail = 0; @@ -192,7 +206,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) return PASS; } -/* this routine calculates the ONFI timing values for a given mode and +/* + * this routine calculates the ONFI timing values for a given mode and * programs the clocking register accordingly. The mode is determined by * the get_onfi_nand_para routine. */ @@ -298,9 +313,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) { int i; - /* we needn't to do a reset here because driver has already + + /* + * we needn't to do a reset here because driver has already * reset all the banks before - * */ + */ if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & ONFI_TIMING_MODE__VALUE)) return FAIL; @@ -313,8 +330,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) nand_onfi_timing_set(denali, i); - /* By now, all the ONFI devices we know support the page cache */ - /* rw feature. So here we enable the pipeline_rw_ahead feature */ + /* + * By now, all the ONFI devices we know support the page cache + * rw feature. So here we enable the pipeline_rw_ahead feature + */ /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ @@ -340,8 +359,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) { uint32_t tmp; - /* Workaround to fix a controller bug which reports a wrong */ - /* spare area size for some kind of Toshiba NAND device */ + /* + * Workaround to fix a controller bug which reports a wrong + * spare area size for some kind of Toshiba NAND device + */ if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); @@ -391,7 +412,8 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, } } -/* determines how many NAND chips are connected to the controller. Note for +/* + * determines how many NAND chips are connected to the controller. Note for * Intel CE4100 devices we don't support more than one device. */ static void find_valid_banks(struct denali_nand_info *denali) @@ -421,7 +443,8 @@ static void find_valid_banks(struct denali_nand_info *denali) } if (denali->platform == INTEL_CE4100) { - /* Platform limitations of the CE4100 device limit + /* + * Platform limitations of the CE4100 device limit * users to a single chip solution for NAND. * Multichip support is not enabled. */ @@ -449,12 +472,13 @@ static void detect_max_banks(struct denali_nand_info *denali) static void detect_partition_feature(struct denali_nand_info *denali) { - /* For MRST platform, denali->fwblks represent the + /* + * For MRST platform, denali->fwblks represent the * number of blocks firmware is taken, * FW is in protect partition and MTD driver has no * permission to access it. So let driver know how many * blocks it can't touch. - * */ + */ if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { @@ -481,11 +505,11 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - /* Use read id method to get device ID and other - * params. For some NAND chips, controller can't - * report the correct device ID by reading from - * DEVICE_ID register - * */ + /* + * Use read id method to get device ID and other params. + * For some NAND chips, controller can't report the correct + * device ID by reading from DEVICE_ID register + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -524,7 +548,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) detect_partition_feature(denali); - /* If the user specified to override the default timings + /* + * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. */ if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) @@ -545,7 +570,8 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); } -/* validation function to verify that the controlling software is making +/* + * validation function to verify that the controlling software is making * a valid request */ static inline bool is_flash_bank_valid(int flash_bank) @@ -585,7 +611,8 @@ static void denali_irq_enable(struct denali_nand_info *denali, iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); } -/* This function only returns when an interrupt that this driver cares about +/* + * This function only returns when an interrupt that this driver cares about * occurs. This is to reduce the overhead of servicing interrupts */ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) @@ -625,9 +652,9 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) return ioread32(denali->flash_reg + intr_status_reg); } -/* This is the interrupt service routine. It handles all interrupts - * sent to this device. Note that on CE4100, this is a shared - * interrupt. +/* + * This is the interrupt service routine. It handles all interrupts + * sent to this device. Note that on CE4100, this is a shared interrupt. */ static irqreturn_t denali_isr(int irq, void *dev_id) { @@ -637,19 +664,21 @@ static irqreturn_t denali_isr(int irq, void *dev_id) spin_lock(&denali->irq_lock); - /* check to see if a valid NAND chip has - * been selected. - */ + /* check to see if a valid NAND chip has been selected. */ if (is_flash_bank_valid(denali->flash_bank)) { - /* check to see if controller generated - * the interrupt, since this is a shared interrupt */ + /* + * check to see if controller generated the interrupt, + * since this is a shared interrupt + */ irq_status = denali_irq_detected(denali); if (irq_status != 0) { /* handle interrupt */ /* first acknowledge it */ clear_interrupt(denali, irq_status); - /* store the status in the device context for someone - to read */ + /* + * store the status in the device context for someone + * to read + */ denali->irq_status |= irq_status; /* notify anyone who cares that it happened */ complete(&denali->complete); @@ -681,8 +710,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) /* our interrupt was detected */ break; } else { - /* these are not the interrupts you are looking for - - * need to wait again */ + /* + * these are not the interrupts you are looking for - + * need to wait again + */ spin_unlock_irq(&denali->irq_lock); retry = true; } @@ -698,8 +729,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) return intr_status; } -/* This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. */ +/* + * This helper function setups the registers for ECC and whether or not + * the spare area will be transferred. + */ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { @@ -715,7 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, denali->flash_reg + TRANSFER_SPARE_REG); } -/* sends a pipeline command operation to the controller. See the Denali NAND +/* + * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, @@ -737,7 +771,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - /* clear interrupts */ clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; @@ -757,9 +790,10 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); - /* page 33 of the NAND controller spec indicates we should not - use the pipeline commands in Spare area only mode. So we - don't. + /* + * page 33 of the NAND controller spec indicates we should not + * use the pipeline commands in Spare area only mode. + * So we don't. */ if (access_type == SPARE_ACCESS) { cmd = MODE_01 | addr; @@ -768,10 +802,11 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, index_addr(denali, (uint32_t)cmd, PIPELINE_ACCESS | op | page_count); - /* wait for command to be accepted + /* + * wait for command to be accepted * can always use status0 bit as the - * mask is identical for each - * bank. */ + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { @@ -796,8 +831,10 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* verify that the len is a multiple of 4. see comment in - * read_data_from_flash_mem() */ + /* + * verify that the len is a multiple of 4. + * see comment in read_data_from_flash_mem() + */ BUG_ON((len % 4) != 0); /* write the data to the flash memory */ @@ -814,14 +851,12 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* we assume that len will be a multiple of 4, if not - * it would be nice to know about it ASAP rather than - * have random failures... - * This assumption is based on the fact that this - * function is designed to be used to read flash pages, - * which are typically multiples of 4... + /* + * we assume that len will be a multiple of 4, if not it would be nice + * to know about it ASAP rather than have random failures... + * This assumption is based on the fact that this function is designed + * to be used to read flash pages, which are typically multiples of 4. */ - BUG_ON((len % 4) != 0); /* transfer the data from the flash */ @@ -873,16 +908,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) DENALI_READ) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); - /* wait for command to be accepted - * can always use status0 bit as the mask is identical for each - * bank. */ + /* + * wait for command to be accepted + * can always use status0 bit as the + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) dev_err(denali->dev, "page on OOB timeout %d\n", denali->page); - /* We set the device back to MAIN_ACCESS here as I observed + /* + * We set the device back to MAIN_ACCESS here as I observed * instability with the controller if you do a block erase * and the last transaction was a SPARE_ACCESS. Block erase * is reliable (according to the MTD test infrastructure) @@ -894,7 +932,8 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) } } -/* this function examines buffers to see if they contain data that +/* + * this function examines buffers to see if they contain data that * indicate that the buffer is part of an erased region of flash. */ static bool is_erased(uint8_t *buf, int len) @@ -940,13 +979,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_device = ECC_ERR_DEVICE(err_correction_info); if (ECC_ERROR_CORRECTABLE(err_correction_info)) { - /* If err_byte is larger than ECC_SECTOR_SIZE, + /* + * If err_byte is larger than ECC_SECTOR_SIZE, * means error happened in OOB, so we ignore * it. It's no need for us to correct it * err_device is represented the NAND error * bits are happened in if there are more * than one NAND connected. - * */ + */ if (err_byte < ECC_SECTOR_SIZE) { int offset; offset = (err_sector * @@ -960,17 +1000,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, bitflips++; } } else { - /* if the error is not correctable, need to + /* + * if the error is not correctable, need to * look at the page to see if it is an erased * page. if so, then it's not a real ECC error - * */ + */ check_erased_page = true; } } while (!ECC_LAST_ERR(err_correction_info)); - /* Once handle all ecc errors, controller will triger + /* + * Once handle all ecc errors, controller will triger * a ECC_TRANSACTION_DONE interrupt, so here just wait * for a while for this interrupt - * */ + */ while (!(read_interrupt_status(denali) & INTR_STATUS__ECC_TRANSACTION_DONE)) cpu_relax(); @@ -1013,12 +1055,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) /* 3. set memory low address bits 23:8 */ index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); - /* 4. interrupt when complete, burst len = 64 bytes*/ + /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); } -/* writes a page. user specifies type, and this function handles the - * configuration details. */ +/* + * writes a page. user specifies type, and this function handles the + * configuration details. + */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { @@ -1031,8 +1075,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; - /* if it is a raw xfer, we want to disable ecc, and send - * the spare area. + /* + * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc * raw_xfer - transfer spare */ @@ -1075,27 +1119,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, /* NAND core entry points */ -/* this is the callback that the NAND core calls to write a page. Since +/* + * this is the callback that the NAND core calls to write a page. Since * writing a page with ECC or without is similar, all the work is done * by write_page above. - * */ + */ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for regular page writes, we let HW handle all the ECC - * data written to the device. */ + /* + * for regular page writes, we let HW handle all the ECC + * data written to the device. + */ return write_page(mtd, chip, buf, false); } -/* This is the callback that the NAND core calls to write a page without ECC. +/* + * This is the callback that the NAND core calls to write a page without ECC. * raw access is similar to ECC page writes, so all the work is done in the * write_page() function above. */ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for raw page writes, we want to disable ECC and simply write - whatever data is in the buffer. */ + /* + * for raw page writes, we want to disable ECC and simply write + * whatever data is in the buffer. + */ return write_page(mtd, chip, buf, true); } @@ -1240,7 +1290,6 @@ static int denali_erase(struct mtd_info *mtd, int page) uint32_t cmd = 0x0, irq_status = 0; - /* clear interrupts */ clear_interrupts(denali); /* setup page read request for access type */ @@ -1270,10 +1319,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, case NAND_CMD_READID: case NAND_CMD_PARAM: reset_buf(denali); - /*sometimes ManufactureId read from register is not right + /* + * sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand - * */ + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -1333,11 +1383,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) { - /* tell driver how many bit controller will skip before + /* + * tell driver how many bit controller will skip before * writing ECC code in OOB, this register may be already * set by firmware. So we read this value out. * if this value is 0, just let it be. - * */ + */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); @@ -1355,10 +1406,11 @@ static void denali_hw_init(struct denali_nand_info *denali) denali_irq_init(denali); } -/* Althogh controller spec said SLC ECC is forceb to be 4bit, +/* + * Althogh controller spec said SLC ECC is forceb to be 4bit, * but denali controller in MRST only support 15bit and 8bit ECC * correction - * */ + */ #define ECC_8BITS 14 static struct nand_ecclayout nand_8bit_oob = { .eccbytes = 14, @@ -1398,13 +1450,16 @@ static void denali_drv_init(struct denali_nand_info *denali) denali->idx = 0; /* setup interrupt handler */ - /* the completion object will be used to notify - * the callee that the interrupt is done */ + /* + * the completion object will be used to notify + * the callee that the interrupt is done + */ init_completion(&denali->complete); - /* the spinlock will be used to synchronize the ISR - * with any element that might be access shared - * data (interrupt status) */ + /* + * the spinlock will be used to synchronize the ISR with any + * element that might be access shared data (interrupt status) + */ spin_lock_init(&denali->irq_lock); /* indicate that MTD has not selected a valid bank yet */ @@ -1419,7 +1474,8 @@ int denali_init(struct denali_nand_info *denali) int ret; if (denali->platform == INTEL_CE4100) { - /* Due to a silicon limitation, we can only support + /* + * Due to a silicon limitation, we can only support * ONFI timing mode 1 and below. */ if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { @@ -1438,8 +1494,10 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); - /* denali_isr register is done after all the hardware - * initilization is finished*/ + /* + * denali_isr register is done after all the hardware + * initilization is finished + */ if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { pr_err("Spectra: Unable to allocate IRQ\n"); @@ -1458,9 +1516,11 @@ int denali_init(struct denali_nand_info *denali) denali->nand.read_byte = denali_read_byte; denali->nand.waitfunc = denali_waitfunc; - /* scan for NAND devices attached to the controller + /* + * scan for NAND devices attached to the controller * this is the first stage in a two step process to register - * with the nand subsystem */ + * with the nand subsystem + */ if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { ret = -ENXIO; goto failed_req_irq; @@ -1492,10 +1552,10 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* support for multi nand - * MTD known nothing about multi nand, - * so we should tell it the real pagesize - * and anything necessery + /* + * support for multi nand + * MTD known nothing about multi nand, so we should tell it + * the real pagesize and anything necessery */ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); denali->nand.chipsize <<= (denali->devnum - 1); @@ -1511,9 +1571,11 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; denali->bbtskipbytes *= denali->devnum; - /* second stage of the NAND scan + /* + * second stage of the NAND scan * this stage requires information regarding ECC and - * bad block management. */ + * bad block management. + */ /* Bad block management */ denali->nand.bbt_td = &bbt_main_descr; @@ -1524,7 +1586,8 @@ int denali_init(struct denali_nand_info *denali) denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; - /* Denali Controller only support 15bit and 8bit ECC in MRST, + /* + * Denali Controller only support 15bit and 8bit ECC in MRST, * so just let controller do 15bit ECC for MLC and 8bit ECC for * SLC if possible. * */ @@ -1560,18 +1623,20 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - denali->bbtskipbytes; - /* Let driver know the total blocks number and - * how many blocks contained by each nand chip. - * blksperchip will help driver to know how many - * blocks is taken by FW. - * */ + /* + * Let driver know the total blocks number and how many blocks + * contained by each nand chip. blksperchip will help driver to + * know how many blocks is taken by FW. + */ denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; - /* These functions are required by the NAND core framework, otherwise, + /* + * These functions are required by the NAND core framework, otherwise, * the NAND core will assert. However, we don't need them, so we'll stub - * them out. */ + * them out. + */ denali->nand.ecc.calculate = denali_ecc_calculate; denali->nand.ecc.correct = denali_ecc_correct; denali->nand.ecc.hwctl = denali_ecc_hwctl; -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:12 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:12 +0900 Subject: [PATCH 6/7] mtd: denali: remove unnecessary parentheses In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-7-git-send-email-yamada.m@jp.panasonic.com> We should use parentheses only when they are necessary or they really improve the readability. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d37c2e1..ed37b76 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -267,10 +267,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, acc_clks = CEIL_DIV(Trea[mode], CLK_X); - while (((acc_clks * CLK_X) - Trea[mode]) < 3) + while (acc_clks * CLK_X - Trea[mode] < 3) acc_clks++; - if ((data_invalid - acc_clks * CLK_X) < 2) + if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", __FILE__, __LINE__); @@ -285,7 +285,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, cs_cnt = 1; if (Tcea[mode]) { - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) + while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) cs_cnt++; } @@ -295,8 +295,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, #endif /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && - (ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) + if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && + ioread32(denali->flash_reg + DEVICE_ID) == 0x88) acc_clks = 6; iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); @@ -577,7 +577,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, */ static inline bool is_flash_bank_valid(int flash_bank) { - return (flash_bank >= 0 && flash_bank < 4); + return flash_bank >= 0 && flash_bank < 4; } static void denali_irq_init(struct denali_nand_info *denali) @@ -1103,7 +1103,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, "timeout on write_page (type = %d)\n", raw_xfer); denali->status = - (irq_status & INTR_STATUS__PROGRAM_FAIL) ? + irq_status & INTR_STATUS__PROGRAM_FAIL ? NAND_STATUS_FAIL : PASS; } @@ -1296,7 +1296,7 @@ static int denali_erase(struct mtd_info *mtd, int page) irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | INTR_STATUS__ERASE_FAIL); - return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:09 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:09 +0900 Subject: [PATCH 3/7] mtd: denali: remove unnecessary casts In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-4-git-send-email-yamada.m@jp.panasonic.com> Useless casts result in unreadable source code. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3836828..dcd6771 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -423,10 +423,10 @@ static void find_valid_banks(struct denali_nand_info *denali) denali->total_used_banks = 1; for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90); - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0); + index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); + index_addr(denali, MODE_11 | (i << 24) | 1, 0); index_addr_read_data(denali, - (uint32_t)(MODE_11 | (i << 24) | 2), &id[i]); + MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -510,9 +510,9 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) * For some NAND chips, controller can't report the correct * device ID by reading from DEVICE_ID register */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) index_addr_read_data(denali, addr | 2, &id_bytes[i]); maf_id = id_bytes[0]; @@ -782,14 +782,14 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { /* read spare area */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_READ) { /* setup page read request for access type */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); /* * page 33 of the NAND controller spec indicates we should not @@ -800,7 +800,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else { - index_addr(denali, (uint32_t)cmd, + index_addr(denali, cmd, PIPELINE_ACCESS | op | page_count); /* @@ -929,7 +929,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ addr = BANK(denali->flash_bank) | denali->page; cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, MAIN_ACCESS); + index_addr(denali, cmd, MAIN_ACCESS); } } @@ -1035,7 +1035,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) { uint32_t mode; const int page_count = 1; - dma_addr_t addr = denali->buf.dma_buf; + uint32_t addr = denali->buf.dma_buf; mode = MODE_10 | BANK(denali->flash_bank); @@ -1045,10 +1045,10 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) index_addr(denali, mode | denali->page, 0x2000 | op | page_count); /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)(addr >> 16) << 8), 0x2200); + index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); + index_addr(denali, mode | ((addr & 0xff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); @@ -1289,7 +1289,7 @@ static int denali_erase(struct mtd_info *mtd, int page) /* setup page read request for access type */ cmd = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, (uint32_t)cmd, 0x1); + index_addr(denali, cmd, 0x1); /* wait for erase to complete or failure to occur */ irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | @@ -1319,12 +1319,12 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { index_addr_read_data(denali, - (uint32_t)addr | 2, + addr | 2, &id); write_byte_to_buf(denali, id); } -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:11 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:11 +0900 Subject: [PATCH 5/7] mtd: denali: remove a set-but-unused variable In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-6-git-send-email-yamada.m@jp.panasonic.com> The variable "retry" in wait_for_irq() is set, but not referenced. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 259ca0ba..d37c2e1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -697,7 +697,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { unsigned long comp_res; uint32_t intr_status; - bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); do { @@ -717,7 +716,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) * need to wait again */ spin_unlock_irq(&denali->irq_lock); - retry = true; } } while (comp_res != 0); -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:08 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:08 +0900 Subject: [PATCH 2/7] mtd: denali: remove unnecessary variable initializations In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-3-git-send-email-yamada.m@jp.panasonic.com> All of these variables are initialized to zero and then set to a different value below. Zero-initializing is redundant. Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 59 ++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 44a5f159..3836828 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -146,7 +146,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) /* reads the status of the device */ static void read_status(struct denali_nand_info *denali) { - uint32_t cmd = 0x0; + uint32_t cmd; /* initialize the data buffer to store status */ reset_buf(denali); @@ -161,7 +161,7 @@ static void read_status(struct denali_nand_info *denali) /* resets a specific device connected to the core */ static void reset_bank(struct denali_nand_info *denali) { - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; @@ -581,7 +581,7 @@ static inline bool is_flash_bank_valid(int flash_bank) static void denali_irq_init(struct denali_nand_info *denali) { - uint32_t int_mask = 0; + uint32_t int_mask; int i; /* Disable global interrupts */ @@ -624,7 +624,7 @@ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) static inline void clear_interrupt(struct denali_nand_info *denali, uint32_t irq_mask) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -633,7 +633,8 @@ static inline void clear_interrupt(struct denali_nand_info *denali, static void clear_interrupts(struct denali_nand_info *denali) { - uint32_t status = 0x0; + uint32_t status; + spin_lock_irq(&denali->irq_lock); status = read_interrupt_status(denali); @@ -645,7 +646,7 @@ static void clear_interrupts(struct denali_nand_info *denali) static uint32_t read_interrupt_status(struct denali_nand_info *denali) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -659,7 +660,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) static irqreturn_t denali_isr(int irq, void *dev_id) { struct denali_nand_info *denali = dev_id; - uint32_t irq_status = 0x0; + uint32_t irq_status; irqreturn_t result = IRQ_NONE; spin_lock(&denali->irq_lock); @@ -693,8 +694,8 @@ static irqreturn_t denali_isr(int irq, void *dev_id) static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { - unsigned long comp_res = 0; - uint32_t intr_status = 0; + unsigned long comp_res; + uint32_t intr_status; bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); @@ -736,7 +737,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { - int ecc_en_flag = 0, transfer_spare_flag = 0; + int ecc_en_flag, transfer_spare_flag; /* set ECC, transfer spare bits if needed */ ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; @@ -759,8 +760,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int op) { int status = PASS; - uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, - irq_mask = 0; + uint32_t page_count = 1; + uint32_t addr, cmd, irq_status, irq_mask; if (op == DENALI_READ) irq_mask = INTR_STATUS__LOAD_COMP; @@ -829,7 +830,7 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * verify that the len is a multiple of 4. @@ -849,7 +850,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * we assume that len will be a multiple of 4, if not it would be nice @@ -870,7 +871,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | INTR_STATUS__PROGRAM_FAIL; int status = 0; @@ -899,8 +900,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR_STATUS__LOAD_COMP, - irq_status = 0, addr = 0x0, cmd = 0x0; + uint32_t irq_mask = INTR_STATUS__LOAD_COMP; + uint32_t irq_status, addr, cmd; denali->page = page; @@ -938,7 +939,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ static bool is_erased(uint8_t *buf, int len) { - int i = 0; + int i; for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -961,9 +962,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, if (irq_status & INTR_STATUS__ECC_ERR) { /* read the ECC errors. we'll ignore them for now */ - uint32_t err_address = 0, err_correction_info = 0; - uint32_t err_byte = 0, err_sector = 0, err_device = 0; - uint32_t err_correction_value = 0; + uint32_t err_address, err_correction_info, err_byte, + err_sector, err_device, err_correction_value; denali_set_intr_modes(denali, false); do { @@ -1026,19 +1026,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, /* programs the controller to either enable/disable DMA transfers */ static void denali_enable_dma(struct denali_nand_info *denali, bool en) { - uint32_t reg_val = 0x0; - - if (en) - reg_val = DMA_ENABLE__FLAG; - - iowrite32(reg_val, denali->flash_reg + DMA_ENABLE); + iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); ioread32(denali->flash_reg + DMA_ENABLE); } /* setups the HW to perform the data DMA */ static void denali_setup_dma(struct denali_nand_info *denali, int op) { - uint32_t mode = 0x0; + uint32_t mode; const int page_count = 1; dma_addr_t addr = denali->buf.dma_buf; @@ -1071,7 +1066,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1172,7 +1167,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR; bool check_erased_page = false; @@ -1224,7 +1219,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1288,7 +1283,7 @@ static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t cmd = 0x0, irq_status = 0; + uint32_t cmd, irq_status; clear_interrupts(denali); -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:06 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:06 +0900 Subject: [PATCH 0/7] mtd: denali: A collection of trivial coding style fixes Message-ID: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Masahiro Yamada (7): mtd: denali: fix the format of comment blocks mtd: denali: remove unnecessary variable initializations mtd: denali: remove unnecessary casts mtd: denali: change the type of "i" to int mtd: denali: remove a set-but-unused variable mtd: denali: remove unnecessary parentheses mtd: denali: fix indentations and other trivial things drivers/mtd/nand/denali.c | 532 +++++++++++++++++++++++++--------------------- 1 file changed, 290 insertions(+), 242 deletions(-) -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 01:10:13 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 8 Sep 2014 17:10:13 +0900 Subject: [PATCH 7/7] mtd: denali: fix indentations and other trivial things In-Reply-To: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410163813-31783-8-git-send-email-yamada.m@jp.panasonic.com> - Fix indentations - Do not break a line unless it is longer than 80 columns - Do not insert a whitespace before ';' - Use braces for a "else" block where the "if" block uses ones. Additionally, fix the following "checkpatch.pl" warnings: - WARNING: else is not generally useful after a break or return - WARNING: Missing a blank line after declarations - WARNING: Avoid line continuations in quoted strings Signed-off-by: Masahiro Yamada --- drivers/mtd/nand/denali.c | 113 ++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 63 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ed37b76..4d26e11 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -162,8 +162,7 @@ static void read_status(struct denali_nand_info *denali) static void reset_bank(struct denali_nand_info *denali) { uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__RST_COMP | - INTR_STATUS__TIME_OUT; + uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; clear_interrupts(denali); @@ -181,16 +180,15 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); - for (i = 0 ; i < denali->max_banks; i++) + for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, denali->flash_reg + INTR_STATUS(i)); - for (i = 0 ; i < denali->max_banks; i++) { + for (i = 0; i < denali->max_banks; i++) { iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + - INTR_STATUS(i)) & + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) cpu_relax(); if (ioread32(denali->flash_reg + INTR_STATUS(i)) & @@ -201,7 +199,7 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + denali->flash_reg + INTR_STATUS(i)); return PASS; } @@ -235,7 +233,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); en_lo = CEIL_DIV(Trp[mode], CLK_X); en_hi = CEIL_DIV(Treh[mode], CLK_X); @@ -272,7 +270,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); + __FILE__, __LINE__); addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); re_2_we = CEIL_DIV(Trhw[mode], CLK_X); @@ -406,9 +404,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, break; default: dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." - "Will use default parameter values instead.\n", - device_id); + "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." + "Will use default parameter values instead.\n", + device_id); } } @@ -425,8 +423,7 @@ static void find_valid_banks(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) { index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, - MODE_11 | (i << 24) | 2, &id[i]); + index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -489,10 +486,12 @@ static void detect_partition_feature(struct denali_nand_info *denali) + (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & MIN_BLK_ADDR__VALUE); - } else + } else { denali->fwblks = SPECTRA_START_BLOCK; - } else + } + } else { denali->fwblks = SPECTRA_START_BLOCK; + } } static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) @@ -502,8 +501,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) uint8_t maf_id, device_id; int i; - dev_dbg(denali->dev, - "%s, Line %d, Function: %s\n", + dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); /* @@ -563,7 +561,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); if (INT_ENABLE) iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); @@ -710,13 +708,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) spin_unlock_irq(&denali->irq_lock); /* our interrupt was detected */ break; - } else { - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); } + + /* + * these are not the interrupts you are looking for - + * need to wait again + */ + spin_unlock_irq(&denali->irq_lock); } while (comp_res != 0); if (comp_res == 0) { @@ -744,8 +742,7 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, /* Enable spare area/ECC per user's request. */ iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, - denali->flash_reg + TRANSFER_SPARE_REG); + iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } /* @@ -753,10 +750,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, - bool ecc_en, - bool transfer_spare, - int access_type, - int op) + bool ecc_en, bool transfer_spare, + int access_type, int op) { int status = PASS; uint32_t page_count = 1; @@ -826,8 +821,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, - const uint8_t *buf, - int len) + const uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -842,13 +836,12 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) iowrite32(*buf32++, denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* helper function that simply reads a buffer from the flash */ static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, - int len) + uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -865,7 +858,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) *buf32++ = ioread32(denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* writes OOB data to the device */ @@ -941,6 +934,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static bool is_erased(uint8_t *buf, int len) { int i; + for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -990,6 +984,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, */ if (err_byte < ECC_SECTOR_SIZE) { int offset; + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * @@ -1063,10 +1058,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1099,12 +1092,10 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { - dev_err(denali->dev, - "timeout on write_page (type = %d)\n", - raw_xfer); - denali->status = - irq_status & INTR_STATUS__PROGRAM_FAIL ? - NAND_STATUS_FAIL : PASS; + dev_err(denali->dev, "timeout on write_page (type = %d)\n", + raw_xfer); + denali->status = irq_status & INTR_STATUS__PROGRAM_FAIL ? + NAND_STATUS_FAIL : PASS; } denali_enable_dma(denali, false); @@ -1216,10 +1207,8 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; @@ -1275,6 +1264,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); int status = denali->status; + denali->status = 0; return status; @@ -1324,9 +1314,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, index_addr(denali, addr | 0, 0x90); index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { - index_addr_read_data(denali, - addr | 2, - &id); + index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } break; @@ -1351,8 +1339,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc_code) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_calculate called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n"); BUG(); return -EIO; } @@ -1361,8 +1349,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, uint8_t *read_ecc, uint8_t *calc_ecc) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_correct called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n"); BUG(); return -EIO; } @@ -1370,8 +1358,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_hwctl called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n"); BUG(); } /* end NAND core entry points */ @@ -1599,8 +1587,8 @@ int denali_init(struct denali_nand_info *denali) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to \ - contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to " + "contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1624,8 +1612,7 @@ int denali_init(struct denali_nand_info *denali) * contained by each nand chip. blksperchip will help driver to * know how many blocks is taken by FW. */ - denali->totalblks = denali->mtd.size >> - denali->nand.phys_erase_shift; + denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; /* @@ -1672,7 +1659,7 @@ void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, - denali->mtd.writesize + denali->mtd.oobsize, - DMA_BIDIRECTIONAL); + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); -- 1.9.1 From josh at joshtriplett.org Mon Sep 8 01:29:00 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Mon, 8 Sep 2014 01:29:00 -0700 Subject: [PATCH 1/7] mtd: denali: fix the format of comment blocks In-Reply-To: <1410163813-31783-2-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> <1410163813-31783-2-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140908082900.GA5361@thin> On Mon, Sep 08, 2014 at 05:10:07PM +0900, Masahiro Yamada wrote: > We should use > /* > * Blah Blah ... > * ... > */ > > for multi-line comment blocks. > > In addition, refactor some comments where it seems reasonable and > remove some comments where the code is clear enough such as: > > /* clear interrupts */ > clear_interrupts(denali); > > Signed-off-by: Masahiro Yamada All of the cases seem to match the preferred style; seems reasonable. And thanks for applying the additional cleanup of removing entirely unnecessary comments. Reviewed-by: Josh Triplett > > drivers/mtd/nand/denali.c | 311 ++++++++++++++++++++++++++++------------------ > 1 file changed, 188 insertions(+), 123 deletions(-) > > diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c > index da0fcc2..44a5f159 100644 > --- a/drivers/mtd/nand/denali.c > +++ b/drivers/mtd/nand/denali.c > @@ -29,7 +29,8 @@ > > MODULE_LICENSE("GPL"); > > -/* We define a module parameter that allows the user to override > +/* > + * We define a module parameter that allows the user to override > * the hardware and decide what timing mode should be used. > */ > #define NAND_DEFAULT_TIMINGS -1 > @@ -41,8 +42,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." > > #define DENALI_NAND_NAME "denali-nand" > > -/* We define a macro here that combines all interrupts this driver uses into > - * a single constant value, for convenience. */ > +/* > + * We define a macro here that combines all interrupts this driver uses into > + * a single constant value, for convenience. > + */ > #define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ > INTR_STATUS__ECC_TRANSACTION_DONE | \ > INTR_STATUS__ECC_ERR | \ > @@ -54,23 +57,30 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." > INTR_STATUS__RST_COMP | \ > INTR_STATUS__ERASE_COMP) > > -/* indicates whether or not the internal value for the flash bank is > - * valid or not */ > +/* > + * indicates whether or not the internal value for the flash bank is > + * valid or not > + */ > #define CHIP_SELECT_INVALID -1 > > #define SUPPORT_8BITECC 1 > > -/* This macro divides two integers and rounds fractional values up > - * to the nearest integer value. */ > +/* > + * This macro divides two integers and rounds fractional values up > + * to the nearest integer value. > + */ > #define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) > > -/* this macro allows us to convert from an MTD structure to our own > +/* > + * this macro allows us to convert from an MTD structure to our own > * device context (denali) structure. > */ > #define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) > > -/* These constants are defined by the driver to enable common driver > - * configuration options. */ > +/* > + * These constants are defined by the driver to enable common driver > + * configuration options. > + */ > #define SPARE_ACCESS 0x41 > #define MAIN_ACCESS 0x42 > #define MAIN_SPARE_ACCESS 0x43 > @@ -84,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." > #define ADDR_CYCLE 1 > #define STATUS_CYCLE 2 > > -/* this is a helper macro that allows us to > - * format the bank into the proper bits for the controller */ > +/* > + * this is a helper macro that allows us to > + * format the bank into the proper bits for the controller > + */ > #define BANK(x) ((x) << 24) > > /* forward declarations */ > @@ -96,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali, > uint32_t int_mask); > static uint32_t read_interrupt_status(struct denali_nand_info *denali); > > -/* Certain operations for the denali NAND controller use > - * an indexed mode to read/write data. The operation is > - * performed by writing the address value of the command > - * to the device memory followed by the data. This function > +/* > + * Certain operations for the denali NAND controller use an indexed mode to > + * read/write data. The operation is performed by writing the address value > + * of the command to the device memory followed by the data. This function > * abstracts this common operation. > -*/ > + */ > static void index_addr(struct denali_nand_info *denali, > uint32_t address, uint32_t data) > { > @@ -117,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali, > *pdata = ioread32(denali->flash_mem + 0x10); > } > > -/* We need to buffer some data for some of the NAND core routines. > - * The operations manage buffering that data. */ > +/* > + * We need to buffer some data for some of the NAND core routines. > + * The operations manage buffering that data. > + */ > static void reset_buf(struct denali_nand_info *denali) > { > denali->buf.head = denali->buf.tail = 0; > @@ -192,7 +206,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) > return PASS; > } > > -/* this routine calculates the ONFI timing values for a given mode and > +/* > + * this routine calculates the ONFI timing values for a given mode and > * programs the clocking register accordingly. The mode is determined by > * the get_onfi_nand_para routine. > */ > @@ -298,9 +313,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, > static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) > { > int i; > - /* we needn't to do a reset here because driver has already > + > + /* > + * we needn't to do a reset here because driver has already > * reset all the banks before > - * */ > + */ > if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & > ONFI_TIMING_MODE__VALUE)) > return FAIL; > @@ -313,8 +330,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) > > nand_onfi_timing_set(denali, i); > > - /* By now, all the ONFI devices we know support the page cache */ > - /* rw feature. So here we enable the pipeline_rw_ahead feature */ > + /* > + * By now, all the ONFI devices we know support the page cache > + * rw feature. So here we enable the pipeline_rw_ahead feature > + */ > /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ > /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ > > @@ -340,8 +359,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) > { > uint32_t tmp; > > - /* Workaround to fix a controller bug which reports a wrong */ > - /* spare area size for some kind of Toshiba NAND device */ > + /* > + * Workaround to fix a controller bug which reports a wrong > + * spare area size for some kind of Toshiba NAND device > + */ > if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && > (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { > iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); > @@ -391,7 +412,8 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, > } > } > > -/* determines how many NAND chips are connected to the controller. Note for > +/* > + * determines how many NAND chips are connected to the controller. Note for > * Intel CE4100 devices we don't support more than one device. > */ > static void find_valid_banks(struct denali_nand_info *denali) > @@ -421,7 +443,8 @@ static void find_valid_banks(struct denali_nand_info *denali) > } > > if (denali->platform == INTEL_CE4100) { > - /* Platform limitations of the CE4100 device limit > + /* > + * Platform limitations of the CE4100 device limit > * users to a single chip solution for NAND. > * Multichip support is not enabled. > */ > @@ -449,12 +472,13 @@ static void detect_max_banks(struct denali_nand_info *denali) > > static void detect_partition_feature(struct denali_nand_info *denali) > { > - /* For MRST platform, denali->fwblks represent the > + /* > + * For MRST platform, denali->fwblks represent the > * number of blocks firmware is taken, > * FW is in protect partition and MTD driver has no > * permission to access it. So let driver know how many > * blocks it can't touch. > - * */ > + */ > if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { > if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & > PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { > @@ -481,11 +505,11 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) > "%s, Line %d, Function: %s\n", > __FILE__, __LINE__, __func__); > > - /* Use read id method to get device ID and other > - * params. For some NAND chips, controller can't > - * report the correct device ID by reading from > - * DEVICE_ID register > - * */ > + /* > + * Use read id method to get device ID and other params. > + * For some NAND chips, controller can't report the correct > + * device ID by reading from DEVICE_ID register > + */ > addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); > index_addr(denali, (uint32_t)addr | 0, 0x90); > index_addr(denali, (uint32_t)addr | 1, 0); > @@ -524,7 +548,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) > > detect_partition_feature(denali); > > - /* If the user specified to override the default timings > + /* > + * If the user specified to override the default timings > * with a specific ONFI mode, we apply those changes here. > */ > if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) > @@ -545,7 +570,8 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, > iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); > } > > -/* validation function to verify that the controlling software is making > +/* > + * validation function to verify that the controlling software is making > * a valid request > */ > static inline bool is_flash_bank_valid(int flash_bank) > @@ -585,7 +611,8 @@ static void denali_irq_enable(struct denali_nand_info *denali, > iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); > } > > -/* This function only returns when an interrupt that this driver cares about > +/* > + * This function only returns when an interrupt that this driver cares about > * occurs. This is to reduce the overhead of servicing interrupts > */ > static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) > @@ -625,9 +652,9 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) > return ioread32(denali->flash_reg + intr_status_reg); > } > > -/* This is the interrupt service routine. It handles all interrupts > - * sent to this device. Note that on CE4100, this is a shared > - * interrupt. > +/* > + * This is the interrupt service routine. It handles all interrupts > + * sent to this device. Note that on CE4100, this is a shared interrupt. > */ > static irqreturn_t denali_isr(int irq, void *dev_id) > { > @@ -637,19 +664,21 @@ static irqreturn_t denali_isr(int irq, void *dev_id) > > spin_lock(&denali->irq_lock); > > - /* check to see if a valid NAND chip has > - * been selected. > - */ > + /* check to see if a valid NAND chip has been selected. */ > if (is_flash_bank_valid(denali->flash_bank)) { > - /* check to see if controller generated > - * the interrupt, since this is a shared interrupt */ > + /* > + * check to see if controller generated the interrupt, > + * since this is a shared interrupt > + */ > irq_status = denali_irq_detected(denali); > if (irq_status != 0) { > /* handle interrupt */ > /* first acknowledge it */ > clear_interrupt(denali, irq_status); > - /* store the status in the device context for someone > - to read */ > + /* > + * store the status in the device context for someone > + * to read > + */ > denali->irq_status |= irq_status; > /* notify anyone who cares that it happened */ > complete(&denali->complete); > @@ -681,8 +710,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) > /* our interrupt was detected */ > break; > } else { > - /* these are not the interrupts you are looking for - > - * need to wait again */ > + /* > + * these are not the interrupts you are looking for - > + * need to wait again > + */ > spin_unlock_irq(&denali->irq_lock); > retry = true; > } > @@ -698,8 +729,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) > return intr_status; > } > > -/* This helper function setups the registers for ECC and whether or not > - * the spare area will be transferred. */ > +/* > + * This helper function setups the registers for ECC and whether or not > + * the spare area will be transferred. > + */ > static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, > bool transfer_spare) > { > @@ -715,7 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, > denali->flash_reg + TRANSFER_SPARE_REG); > } > > -/* sends a pipeline command operation to the controller. See the Denali NAND > +/* > + * sends a pipeline command operation to the controller. See the Denali NAND > * controller's user guide for more information (section 4.2.3.6). > */ > static int denali_send_pipeline_cmd(struct denali_nand_info *denali, > @@ -737,7 +771,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, > > setup_ecc_for_xfer(denali, ecc_en, transfer_spare); > > - /* clear interrupts */ > clear_interrupts(denali); > > addr = BANK(denali->flash_bank) | denali->page; > @@ -757,9 +790,10 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, > cmd = MODE_10 | addr; > index_addr(denali, (uint32_t)cmd, access_type); > > - /* page 33 of the NAND controller spec indicates we should not > - use the pipeline commands in Spare area only mode. So we > - don't. > + /* > + * page 33 of the NAND controller spec indicates we should not > + * use the pipeline commands in Spare area only mode. > + * So we don't. > */ > if (access_type == SPARE_ACCESS) { > cmd = MODE_01 | addr; > @@ -768,10 +802,11 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, > index_addr(denali, (uint32_t)cmd, > PIPELINE_ACCESS | op | page_count); > > - /* wait for command to be accepted > + /* > + * wait for command to be accepted > * can always use status0 bit as the > - * mask is identical for each > - * bank. */ > + * mask is identical for each bank. > + */ > irq_status = wait_for_irq(denali, irq_mask); > > if (irq_status == 0) { > @@ -796,8 +831,10 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, > { > uint32_t i = 0, *buf32; > > - /* verify that the len is a multiple of 4. see comment in > - * read_data_from_flash_mem() */ > + /* > + * verify that the len is a multiple of 4. > + * see comment in read_data_from_flash_mem() > + */ > BUG_ON((len % 4) != 0); > > /* write the data to the flash memory */ > @@ -814,14 +851,12 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, > { > uint32_t i = 0, *buf32; > > - /* we assume that len will be a multiple of 4, if not > - * it would be nice to know about it ASAP rather than > - * have random failures... > - * This assumption is based on the fact that this > - * function is designed to be used to read flash pages, > - * which are typically multiples of 4... > + /* > + * we assume that len will be a multiple of 4, if not it would be nice > + * to know about it ASAP rather than have random failures... > + * This assumption is based on the fact that this function is designed > + * to be used to read flash pages, which are typically multiples of 4. > */ > - > BUG_ON((len % 4) != 0); > > /* transfer the data from the flash */ > @@ -873,16 +908,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) > DENALI_READ) == PASS) { > read_data_from_flash_mem(denali, buf, mtd->oobsize); > > - /* wait for command to be accepted > - * can always use status0 bit as the mask is identical for each > - * bank. */ > + /* > + * wait for command to be accepted > + * can always use status0 bit as the > + * mask is identical for each bank. > + */ > irq_status = wait_for_irq(denali, irq_mask); > > if (irq_status == 0) > dev_err(denali->dev, "page on OOB timeout %d\n", > denali->page); > > - /* We set the device back to MAIN_ACCESS here as I observed > + /* > + * We set the device back to MAIN_ACCESS here as I observed > * instability with the controller if you do a block erase > * and the last transaction was a SPARE_ACCESS. Block erase > * is reliable (according to the MTD test infrastructure) > @@ -894,7 +932,8 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) > } > } > > -/* this function examines buffers to see if they contain data that > +/* > + * this function examines buffers to see if they contain data that > * indicate that the buffer is part of an erased region of flash. > */ > static bool is_erased(uint8_t *buf, int len) > @@ -940,13 +979,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, > err_device = ECC_ERR_DEVICE(err_correction_info); > > if (ECC_ERROR_CORRECTABLE(err_correction_info)) { > - /* If err_byte is larger than ECC_SECTOR_SIZE, > + /* > + * If err_byte is larger than ECC_SECTOR_SIZE, > * means error happened in OOB, so we ignore > * it. It's no need for us to correct it > * err_device is represented the NAND error > * bits are happened in if there are more > * than one NAND connected. > - * */ > + */ > if (err_byte < ECC_SECTOR_SIZE) { > int offset; > offset = (err_sector * > @@ -960,17 +1000,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, > bitflips++; > } > } else { > - /* if the error is not correctable, need to > + /* > + * if the error is not correctable, need to > * look at the page to see if it is an erased > * page. if so, then it's not a real ECC error > - * */ > + */ > check_erased_page = true; > } > } while (!ECC_LAST_ERR(err_correction_info)); > - /* Once handle all ecc errors, controller will triger > + /* > + * Once handle all ecc errors, controller will triger > * a ECC_TRANSACTION_DONE interrupt, so here just wait > * for a while for this interrupt > - * */ > + */ > while (!(read_interrupt_status(denali) & > INTR_STATUS__ECC_TRANSACTION_DONE)) > cpu_relax(); > @@ -1013,12 +1055,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) > /* 3. set memory low address bits 23:8 */ > index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); > > - /* 4. interrupt when complete, burst len = 64 bytes*/ > + /* 4. interrupt when complete, burst len = 64 bytes */ > index_addr(denali, mode | 0x14000, 0x2400); > } > > -/* writes a page. user specifies type, and this function handles the > - * configuration details. */ > +/* > + * writes a page. user specifies type, and this function handles the > + * configuration details. > + */ > static int write_page(struct mtd_info *mtd, struct nand_chip *chip, > const uint8_t *buf, bool raw_xfer) > { > @@ -1031,8 +1075,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, > uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | > INTR_STATUS__PROGRAM_FAIL; > > - /* if it is a raw xfer, we want to disable ecc, and send > - * the spare area. > + /* > + * if it is a raw xfer, we want to disable ecc and send the spare area. > * !raw_xfer - enable ecc > * raw_xfer - transfer spare > */ > @@ -1075,27 +1119,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, > > /* NAND core entry points */ > > -/* this is the callback that the NAND core calls to write a page. Since > +/* > + * this is the callback that the NAND core calls to write a page. Since > * writing a page with ECC or without is similar, all the work is done > * by write_page above. > - * */ > + */ > static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, > const uint8_t *buf, int oob_required) > { > - /* for regular page writes, we let HW handle all the ECC > - * data written to the device. */ > + /* > + * for regular page writes, we let HW handle all the ECC > + * data written to the device. > + */ > return write_page(mtd, chip, buf, false); > } > > -/* This is the callback that the NAND core calls to write a page without ECC. > +/* > + * This is the callback that the NAND core calls to write a page without ECC. > * raw access is similar to ECC page writes, so all the work is done in the > * write_page() function above. > */ > static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, > const uint8_t *buf, int oob_required) > { > - /* for raw page writes, we want to disable ECC and simply write > - whatever data is in the buffer. */ > + /* > + * for raw page writes, we want to disable ECC and simply write > + * whatever data is in the buffer. > + */ > return write_page(mtd, chip, buf, true); > } > > @@ -1240,7 +1290,6 @@ static int denali_erase(struct mtd_info *mtd, int page) > > uint32_t cmd = 0x0, irq_status = 0; > > - /* clear interrupts */ > clear_interrupts(denali); > > /* setup page read request for access type */ > @@ -1270,10 +1319,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, > case NAND_CMD_READID: > case NAND_CMD_PARAM: > reset_buf(denali); > - /*sometimes ManufactureId read from register is not right > + /* > + * sometimes ManufactureId read from register is not right > * e.g. some of Micron MT29F32G08QAA MLC NAND chips > * So here we send READID cmd to NAND insteand > - * */ > + */ > addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); > index_addr(denali, (uint32_t)addr | 0, 0x90); > index_addr(denali, (uint32_t)addr | 1, 0); > @@ -1333,11 +1383,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) > /* Initialization code to bring the device up to a known good state */ > static void denali_hw_init(struct denali_nand_info *denali) > { > - /* tell driver how many bit controller will skip before > + /* > + * tell driver how many bit controller will skip before > * writing ECC code in OOB, this register may be already > * set by firmware. So we read this value out. > * if this value is 0, just let it be. > - * */ > + */ > denali->bbtskipbytes = ioread32(denali->flash_reg + > SPARE_AREA_SKIP_BYTES); > detect_max_banks(denali); > @@ -1355,10 +1406,11 @@ static void denali_hw_init(struct denali_nand_info *denali) > denali_irq_init(denali); > } > > -/* Althogh controller spec said SLC ECC is forceb to be 4bit, > +/* > + * Althogh controller spec said SLC ECC is forceb to be 4bit, > * but denali controller in MRST only support 15bit and 8bit ECC > * correction > - * */ > + */ > #define ECC_8BITS 14 > static struct nand_ecclayout nand_8bit_oob = { > .eccbytes = 14, > @@ -1398,13 +1450,16 @@ static void denali_drv_init(struct denali_nand_info *denali) > denali->idx = 0; > > /* setup interrupt handler */ > - /* the completion object will be used to notify > - * the callee that the interrupt is done */ > + /* > + * the completion object will be used to notify > + * the callee that the interrupt is done > + */ > init_completion(&denali->complete); > > - /* the spinlock will be used to synchronize the ISR > - * with any element that might be access shared > - * data (interrupt status) */ > + /* > + * the spinlock will be used to synchronize the ISR with any > + * element that might be access shared data (interrupt status) > + */ > spin_lock_init(&denali->irq_lock); > > /* indicate that MTD has not selected a valid bank yet */ > @@ -1419,7 +1474,8 @@ int denali_init(struct denali_nand_info *denali) > int ret; > > if (denali->platform == INTEL_CE4100) { > - /* Due to a silicon limitation, we can only support > + /* > + * Due to a silicon limitation, we can only support > * ONFI timing mode 1 and below. > */ > if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { > @@ -1438,8 +1494,10 @@ int denali_init(struct denali_nand_info *denali) > denali_hw_init(denali); > denali_drv_init(denali); > > - /* denali_isr register is done after all the hardware > - * initilization is finished*/ > + /* > + * denali_isr register is done after all the hardware > + * initilization is finished > + */ > if (request_irq(denali->irq, denali_isr, IRQF_SHARED, > DENALI_NAND_NAME, denali)) { > pr_err("Spectra: Unable to allocate IRQ\n"); > @@ -1458,9 +1516,11 @@ int denali_init(struct denali_nand_info *denali) > denali->nand.read_byte = denali_read_byte; > denali->nand.waitfunc = denali_waitfunc; > > - /* scan for NAND devices attached to the controller > + /* > + * scan for NAND devices attached to the controller > * this is the first stage in a two step process to register > - * with the nand subsystem */ > + * with the nand subsystem > + */ > if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { > ret = -ENXIO; > goto failed_req_irq; > @@ -1492,10 +1552,10 @@ int denali_init(struct denali_nand_info *denali) > goto failed_req_irq; > } > > - /* support for multi nand > - * MTD known nothing about multi nand, > - * so we should tell it the real pagesize > - * and anything necessery > + /* > + * support for multi nand > + * MTD known nothing about multi nand, so we should tell it > + * the real pagesize and anything necessery > */ > denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); > denali->nand.chipsize <<= (denali->devnum - 1); > @@ -1511,9 +1571,11 @@ int denali_init(struct denali_nand_info *denali) > denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; > denali->bbtskipbytes *= denali->devnum; > > - /* second stage of the NAND scan > + /* > + * second stage of the NAND scan > * this stage requires information regarding ECC and > - * bad block management. */ > + * bad block management. > + */ > > /* Bad block management */ > denali->nand.bbt_td = &bbt_main_descr; > @@ -1524,7 +1586,8 @@ int denali_init(struct denali_nand_info *denali) > denali->nand.options |= NAND_SKIP_BBTSCAN; > denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; > > - /* Denali Controller only support 15bit and 8bit ECC in MRST, > + /* > + * Denali Controller only support 15bit and 8bit ECC in MRST, > * so just let controller do 15bit ECC for MLC and 8bit ECC for > * SLC if possible. > * */ > @@ -1560,18 +1623,20 @@ int denali_init(struct denali_nand_info *denali) > denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - > denali->bbtskipbytes; > > - /* Let driver know the total blocks number and > - * how many blocks contained by each nand chip. > - * blksperchip will help driver to know how many > - * blocks is taken by FW. > - * */ > + /* > + * Let driver know the total blocks number and how many blocks > + * contained by each nand chip. blksperchip will help driver to > + * know how many blocks is taken by FW. > + */ > denali->totalblks = denali->mtd.size >> > denali->nand.phys_erase_shift; > denali->blksperchip = denali->totalblks / denali->nand.numchips; > > - /* These functions are required by the NAND core framework, otherwise, > + /* > + * These functions are required by the NAND core framework, otherwise, > * the NAND core will assert. However, we don't need them, so we'll stub > - * them out. */ > + * them out. > + */ > denali->nand.ecc.calculate = denali_ecc_calculate; > denali->nand.ecc.correct = denali_ecc_correct; > denali->nand.ecc.hwctl = denali_ecc_hwctl; > -- > 1.9.1 > From rogerq at ti.com Mon Sep 8 01:30:19 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 8 Sep 2014 11:30:19 +0300 Subject: [PATCH 0/3] nand: omap2: Two and a half improvements In-Reply-To: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <540D691B.2060202@ti.com> Hi Ezequiel, On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > Hi Brian, Roger: > > Pekon's attempt to add flash BBT support for this driver made me realise > the addition made sense and there were good reasons for it. The first patch > adds support for enabling a flash BBT either from legacy board files or > from devicetree. > > While testing this, I noticed how the driver relied on a whole bunch of > horrible #ifdefs, which prevented me from loading the driver as a module. > The second patch attempts to fix that. > > The third patch is just a dummy cleanup replacing pr_errs with dev_errs. > This driver is abusing from user messages, but I'm not sure fixing them > worths the trouble. > > Roger, do you think you can test patches 1 and 2 with different ECCs > and configurations? It's an invasive patch and I don't want to see more > regressions with this driver. Yes. I will run them through all the boards that I have and let you know in a day or two. > > And speaking of modules, the driver loads as "modprobe omap2". And it's not > the only one with a clumsy name: "modprobe elm". I guess we cannot fix it now, > but it would be great to be more careful with driver naming in the future. Why can't we fix it now? It seems nobody ever used it as a module before so now is the right time to fix. Unless Tony has any objections. cheers, -roger > > Ezequiel Garcia (3): > nand: omap2: Add support for a flash-based bad block table > nand: omap2: Refactor the code to remove horrible ifdefs > nand: omap2: Replace pr_err with dev_err > > arch/arm/mach-omap2/gpmc.c | 2 + > drivers/mtd/nand/omap2.c | 166 +++++++++++++++------------ > include/linux/platform_data/elm.h | 14 +++ > include/linux/platform_data/mtd-nand-omap2.h | 1 + > 4 files changed, 108 insertions(+), 75 deletions(-) > From josh at joshtriplett.org Mon Sep 8 01:30:57 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Mon, 8 Sep 2014 01:30:57 -0700 Subject: [PATCH 5/7] mtd: denali: remove a set-but-unused variable In-Reply-To: <1410163813-31783-6-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> <1410163813-31783-6-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140908083057.GB5361@thin> On Mon, Sep 08, 2014 at 05:10:11PM +0900, Masahiro Yamada wrote: > The variable "retry" in wait_for_irq() is set, but not referenced. > > Signed-off-by: Masahiro Yamada Sure enough. Reviewed-by: Josh Triplett > > drivers/mtd/nand/denali.c | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c > index 259ca0ba..d37c2e1 100644 > --- a/drivers/mtd/nand/denali.c > +++ b/drivers/mtd/nand/denali.c > @@ -697,7 +697,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) > { > unsigned long comp_res; > uint32_t intr_status; > - bool retry = false; > unsigned long timeout = msecs_to_jiffies(1000); > > do { > @@ -717,7 +716,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) > * need to wait again > */ > spin_unlock_irq(&denali->irq_lock); > - retry = true; > } > } while (comp_res != 0); > > -- > 1.9.1 > From josh at joshtriplett.org Mon Sep 8 01:34:48 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Mon, 8 Sep 2014 01:34:48 -0700 Subject: [PATCH 6/7] mtd: denali: remove unnecessary parentheses In-Reply-To: <1410163813-31783-7-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> <1410163813-31783-7-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140908083443.GC5361@thin> On Mon, Sep 08, 2014 at 05:10:12PM +0900, Masahiro Yamada wrote: > We should use parentheses only when they are necessary > or they really improve the readability. > > Signed-off-by: Masahiro Yamada This seems fine; none of these parentheses are needed, since the relative precedence of the relevant operators is always clear. Reviewed-by: Josh Triplett > > drivers/mtd/nand/denali.c | 16 ++++++++-------- > 1 file changed, 8 insertions(+), 8 deletions(-) > > diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c > index d37c2e1..ed37b76 100644 > --- a/drivers/mtd/nand/denali.c > +++ b/drivers/mtd/nand/denali.c > @@ -267,10 +267,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, > > acc_clks = CEIL_DIV(Trea[mode], CLK_X); > > - while (((acc_clks * CLK_X) - Trea[mode]) < 3) > + while (acc_clks * CLK_X - Trea[mode] < 3) > acc_clks++; > > - if ((data_invalid - acc_clks * CLK_X) < 2) > + if (data_invalid - acc_clks * CLK_X < 2) > dev_warn(denali->dev, "%s, Line %d: Warning!\n", > __FILE__, __LINE__); > > @@ -285,7 +285,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, > cs_cnt = 1; > > if (Tcea[mode]) { > - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) > + while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) > cs_cnt++; > } > > @@ -295,8 +295,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, > #endif > > /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ > - if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && > - (ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) > + if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && > + ioread32(denali->flash_reg + DEVICE_ID) == 0x88) > acc_clks = 6; > > iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); > @@ -577,7 +577,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, > */ > static inline bool is_flash_bank_valid(int flash_bank) > { > - return (flash_bank >= 0 && flash_bank < 4); > + return flash_bank >= 0 && flash_bank < 4; > } > > static void denali_irq_init(struct denali_nand_info *denali) > @@ -1103,7 +1103,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, > "timeout on write_page (type = %d)\n", > raw_xfer); > denali->status = > - (irq_status & INTR_STATUS__PROGRAM_FAIL) ? > + irq_status & INTR_STATUS__PROGRAM_FAIL ? > NAND_STATUS_FAIL : PASS; > } > > @@ -1296,7 +1296,7 @@ static int denali_erase(struct mtd_info *mtd, int page) > irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | > INTR_STATUS__ERASE_FAIL); > > - return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; > + return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; > } > > static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, > -- > 1.9.1 > From josh at joshtriplett.org Mon Sep 8 01:39:20 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Mon, 8 Sep 2014 01:39:20 -0700 Subject: [PATCH 7/7] mtd: denali: fix indentations and other trivial things In-Reply-To: <1410163813-31783-8-git-send-email-yamada.m@jp.panasonic.com> References: <1410163813-31783-1-git-send-email-yamada.m@jp.panasonic.com> <1410163813-31783-8-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140908083920.GD5361@thin> On Mon, Sep 08, 2014 at 05:10:13PM +0900, Masahiro Yamada wrote: > @@ -406,9 +404,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, > break; > default: > dev_warn(denali->dev, > - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > - "Will use default parameter values instead.\n", > - device_id); > + "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > + "Will use default parameter values instead.\n", > + device_id); Please join quoted strings into a single line. > - pr_err("Your NAND chip OOB is not large enough to \ > - contain 8bit ECC correction codes"); > + pr_err("Your NAND chip OOB is not large enough to " > + "contain 8bit ECC correction codes"); Likewise. - Josh Triplett From rogerq at ti.com Mon Sep 8 01:45:31 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 8 Sep 2014 11:45:31 +0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <540D6CAB.7020501@ti.com> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > The current code abuses ifdefs to determine if the selected ECC scheme > is supported by the running kernel. As a result the code is hard to read, > and it also fails to load as a module. > > This commit removes all the ifdefs and instead introduces a function > omap2_nand_ecc_check() to check if the ECC is supported by using > IS_ENABLED(CONFIG_xxx). > > Since IS_ENABLED() is true when a config is =y or =m, this change fixes the > module so it can be loaded with no issues. > > Signed-off-by: Ezequiel Garcia Didn't apply cleanly on 3.17-rc4. Needs a rebase? > --- > drivers/mtd/nand/omap2.c | 134 +++++++++++++++++++++----------------- > include/linux/platform_data/elm.h | 14 ++++ > 2 files changed, 87 insertions(+), 61 deletions(-) > > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c > index 1170389..987dd94 100644 > --- a/drivers/mtd/nand/omap2.c > +++ b/drivers/mtd/nand/omap2.c > @@ -136,7 +136,6 @@ > > #define BADBLOCK_MARKER_LENGTH 2 > > -#ifdef CONFIG_MTD_NAND_OMAP_BCH > static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, > 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, > 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, > @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, > static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, > 0xac, 0x6b, 0xff, 0x99, 0x7b}; > static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; > -#endif > > /* oob info generated runtime depending on ecc algorithm and layout selected */ > static struct nand_ecclayout omap_oobinfo; > @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, > return 0; > } > > -#ifdef CONFIG_MTD_NAND_OMAP_BCH > /** > * erased_sector_bitflips - count bit flips > * @data: data sector buffer > @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, > /** > * is_elm_present - checks for presence of ELM module by scanning DT nodes > * @omap_nand_info: NAND device structure containing platform data > - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 > */ > -static int is_elm_present(struct omap_nand_info *info, > - struct device_node *elm_node, enum bch_ecc bch_type) > +static bool is_elm_present(struct omap_nand_info *info, > + struct device_node *elm_node) > { > struct platform_device *pdev; > - struct nand_ecc_ctrl *ecc = &info->nand.ecc; > - int err; > + > /* check whether elm-id is passed via DT */ > if (!elm_node) { > - pr_err("nand: error: ELM DT node not found\n"); > - return -ENODEV; > + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); > + return false; > } > pdev = of_find_device_by_node(elm_node); > /* check whether ELM device is registered */ > if (!pdev) { > - pr_err("nand: error: ELM device not found\n"); > - return -ENODEV; > + dev_err(&info->pdev->dev, "ELM device not found\n"); > + return false; > } > /* ELM module available, now configure it */ > info->elm_dev = &pdev->dev; > - err = elm_config(info->elm_dev, bch_type, > - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); > + return true; > +} > > - return err; > +static bool omap2_nand_ecc_check(struct omap_nand_info *info, > + struct omap_nand_platform_data *pdata) > +{ I like the idea of this function and it being called in probe. It would be also be nice (maybe later) to get rid of all the ECC decision making done in gpmc_probe_nand_child() based on presence/absence of the elm_of_node. I guess we need to add new DT entries for "bch4sw" and "bch8sw" so that DT/platform data can explicitly specify what it needs. I don't see how ELM works with the non-DT boot way as there is no elm_of_node there. Also, the elm_of_node should not be set via platform data or in gpmc.c but parsed here directly in the NAND driver. But changes should be done in a separate patch. Just brought them out here for discussion. > + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; > + > + switch (info->ecc_opt) { > + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: > + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: > + ecc_needs_omap_bch = false; > + ecc_needs_bch = true; > + ecc_needs_elm = false; > + break; > + case OMAP_ECC_BCH4_CODE_HW: > + case OMAP_ECC_BCH8_CODE_HW: > + case OMAP_ECC_BCH16_CODE_HW: > + ecc_needs_omap_bch = true; > + ecc_needs_bch = false; > + ecc_needs_elm = true; > + break; > + default: > + ecc_needs_omap_bch = false; > + ecc_needs_bch = false; > + ecc_needs_elm = false; > + break; > + } > + > + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { > + dev_err(&info->pdev->dev, > + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); > + return false; > + } > + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { > + dev_err(&info->pdev->dev, > + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > + return false; > + } > + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { > + dev_err(&info->pdev->dev, "ELM not available\n"); > + return false; > + } > + > + return true; > } > -#endif /* CONFIG_MTD_NAND_ECC_BCH */ > > static int omap_nand_probe(struct platform_device *pdev) > { > @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) > goto return_error; > } > > + if (!omap2_nand_ecc_check(info, pdata)) { > + err = -EINVAL; > + goto return_error; > + } > + > /* populate MTD interface based on ECC scheme */ > nand_chip->ecc.layout = &omap_oobinfo; > ecclayout = &omap_oobinfo; > @@ -1826,7 +1866,6 @@ static int omap_nand_probe(struct platform_device *pdev) > break; > > case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: > -#ifdef CONFIG_MTD_NAND_ECC_BCH > pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); > nand_chip->ecc.mode = NAND_ECC_HW; > nand_chip->ecc.size = 512; > @@ -1858,14 +1897,8 @@ static int omap_nand_probe(struct platform_device *pdev) > err = -EINVAL; > } > break; > -#else > - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); > - err = -EINVAL; > - goto return_error; > -#endif > > case OMAP_ECC_BCH4_CODE_HW: > -#ifdef CONFIG_MTD_NAND_OMAP_BCH > pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); > nand_chip->ecc.mode = NAND_ECC_HW; > nand_chip->ecc.size = 512; > @@ -1887,21 +1920,15 @@ static int omap_nand_probe(struct platform_device *pdev) > /* reserved marker already included in ecclayout->eccbytes */ > ecclayout->oobfree->offset = > ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; > - /* This ECC scheme requires ELM H/W block */ > - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { > - pr_err("nand: error: could not initialize ELM\n"); > - err = -ENODEV; > + > + err = elm_config(info->elm_dev, BCH4_ECC, > + info->mtd.writesize / nand_chip->ecc.size, > + nand_chip->ecc.size, nand_chip->ecc.bytes); > + if (err < 0) > goto return_error; > - } > break; > -#else > - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > - err = -EINVAL; > - goto return_error; > -#endif > > case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: > -#ifdef CONFIG_MTD_NAND_ECC_BCH > pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); > nand_chip->ecc.mode = NAND_ECC_HW; > nand_chip->ecc.size = 512; > @@ -1934,14 +1961,8 @@ static int omap_nand_probe(struct platform_device *pdev) > goto return_error; > } > break; > -#else > - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); > - err = -EINVAL; > - goto return_error; > -#endif > > case OMAP_ECC_BCH8_CODE_HW: > -#ifdef CONFIG_MTD_NAND_OMAP_BCH > pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); > nand_chip->ecc.mode = NAND_ECC_HW; > nand_chip->ecc.size = 512; > @@ -1953,12 +1974,13 @@ static int omap_nand_probe(struct platform_device *pdev) > nand_chip->ecc.calculate = omap_calculate_ecc_bch; > nand_chip->ecc.read_page = omap_read_page_bch; > nand_chip->ecc.write_page = omap_write_page_bch; > - /* This ECC scheme requires ELM H/W block */ > - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); > - if (err < 0) { > - pr_err("nand: error: could not initialize ELM\n"); > + > + err = elm_config(info->elm_dev, BCH8_ECC, > + info->mtd.writesize / nand_chip->ecc.size, > + nand_chip->ecc.size, nand_chip->ecc.bytes); > + if (err < 0) > goto return_error; > - } > + > /* define ECC layout */ > ecclayout->eccbytes = nand_chip->ecc.bytes * > (mtd->writesize / > @@ -1970,14 +1992,8 @@ static int omap_nand_probe(struct platform_device *pdev) > ecclayout->oobfree->offset = > ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; > break; > -#else > - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > - err = -EINVAL; > - goto return_error; > -#endif > > case OMAP_ECC_BCH16_CODE_HW: > -#ifdef CONFIG_MTD_NAND_OMAP_BCH > pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); > nand_chip->ecc.mode = NAND_ECC_HW; > nand_chip->ecc.size = 512; > @@ -1988,12 +2004,13 @@ static int omap_nand_probe(struct platform_device *pdev) > nand_chip->ecc.calculate = omap_calculate_ecc_bch; > nand_chip->ecc.read_page = omap_read_page_bch; > nand_chip->ecc.write_page = omap_write_page_bch; > - /* This ECC scheme requires ELM H/W block */ > - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); > - if (err < 0) { > - pr_err("ELM is required for this ECC scheme\n"); > + > + err = elm_config(info->elm_dev, BCH16_ECC, > + info->mtd.writesize / nand_chip->ecc.size, > + nand_chip->ecc.size, nand_chip->ecc.bytes); > + if (err < 0) > goto return_error; > - } > + > /* define ECC layout */ > ecclayout->eccbytes = nand_chip->ecc.bytes * > (mtd->writesize / > @@ -2005,11 +2022,6 @@ static int omap_nand_probe(struct platform_device *pdev) > ecclayout->oobfree->offset = > ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; > break; > -#else > - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); > - err = -EINVAL; > - goto return_error; > -#endif > default: > pr_err("nand: error: invalid or unsupported ECC scheme\n"); > err = -EINVAL; > diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h > index 780d1e9..25d1bca 100644 > --- a/include/linux/platform_data/elm.h > +++ b/include/linux/platform_data/elm.h > @@ -42,8 +42,22 @@ struct elm_errorvec { > int error_loc[16]; > }; > > +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) > void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > struct elm_errorvec *err_vec); > int elm_config(struct device *dev, enum bch_ecc bch_type, > int ecc_steps, int ecc_step_size, int ecc_syndrome_size); > +#else > +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > + struct elm_errorvec *err_vec) > +{ > +} > + > +int elm_config(struct device *dev, enum bch_ecc bch_type, > + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) > +{ > + return -ENOSYS; > +} > +#endif /* CONFIG_MTD_NAND_ECC_BCH */ > + > #endif /* __ELM_H */ > Patch looks good to me. I'll give it a spin on all platforms that I have and keep you posted. cheers, -roger From yamada.m at jp.panasonic.com Mon Sep 8 02:14:48 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 08 Sep 2014 18:14:48 +0900 Subject: [PATCH 7/7] mtd: denali: fix indentations and other trivial things In-Reply-To: <20140908083920.GD5361@thin> References: <1410163813-31783-8-git-send-email-yamada.m@jp.panasonic.com> <20140908083920.GD5361@thin> Message-ID: <20140908181447.C428.AA925319@jp.panasonic.com> Hi Josh, On Mon, 8 Sep 2014 01:39:20 -0700 Josh Triplett wrote: > On Mon, Sep 08, 2014 at 05:10:13PM +0900, Masahiro Yamada wrote: > > @@ -406,9 +404,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, > > break; > > default: > > dev_warn(denali->dev, > > - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > > - "Will use default parameter values instead.\n", > > - device_id); > > + "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > > + "Will use default parameter values instead.\n", > > + device_id); > > Please join quoted strings into a single line. > > > - pr_err("Your NAND chip OOB is not large enough to \ > > - contain 8bit ECC correction codes"); > > + pr_err("Your NAND chip OOB is not large enough to " > > + "contain 8bit ECC correction codes"); > > Likewise. > Thanks for your review, but the quoted strings are too long to be joined into a single line. (exceed 80 columns) Best Regards Masahiro Yamada From dedekind1 at gmail.com Mon Sep 8 02:43:17 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 12:43:17 +0300 Subject: [PATCH 1/2] UBIFS: fix free log space calculation In-Reply-To: <53E836A7.8040806@huawei.com> References: <1405514528-14649-1-git-send-email-dedekind1@gmail.com> <53E836A7.8040806@huawei.com> Message-ID: <1410169397.10764.106.camel@sauron.fi.intel.com> On Mon, 2014-08-11 at 11:21 +0800, hujianyang wrote: > > --- > > fs/ubifs/log.c | 8 ++++++-- > > 1 file changed, 6 insertions(+), 2 deletions(-) > > > > diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c > > index ed24422..7e818ec 100644 > > --- a/fs/ubifs/log.c > > +++ b/fs/ubifs/log.c > > @@ -106,10 +106,14 @@ static inline long long empty_log_bytes(const struct ubifs_info *c) > > h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs; > > t = (long long)c->ltail_lnum * c->leb_size; > > > > - if (h >= t) > > + if (h > t) > > return c->log_bytes - h + t; > > - else > > + else if (h != t) > > return t - h; > > + else if (c->lhead_lnum != c->ltail_lnum) > > + return 0; > > + else > > + return c->log_bytes; > > } > > > > /** > > > > Hi Artem, > > After almost one month test, the error I've reported > > UBIFS: background thread "ubifs_bgt0_0" started, PID 2222 > UBIFS: recovery needed > UBIFS error (pid 2220): replay_log_leb: first log node at LEB 4:0 is not CS node > UBIFS error (pid 2220): replay_log_leb: log error detected while replaying the log at LEB 4:0 > magic 0x6101831 > crc 0x81e22cd5 > node_type 8 (reference node) > group_type 0 (no node group) > sqnum 2375337 > len 64 > lnum 5273 > offs 122880 > jhead 2 > UBIFS: background thread "ubifs_bgt0_0" stops > > never came out again. > > I think this patch really solve that problem. Now I want to show my > analysis and wish you add "Cc stable" for this patch. > > With the help of ubidump tool, I got the MST NODEs and LOG NODEs of > the image which is broken. > > master node: > > look at LEB 1:20480 (106496 bytes left) > scanning master node at LEB 1:20480 > magic 0x6101831 > crc 0x38ff5c67 > node_type 7 (master node) > group_type 0 (no node group) > sqnum 15799802 > len 512 > highest_inum 161 > commit number 7954 > flags 0x3 > log_lnum 4 > root_lnum 2258 > root_offs 7048 > root_len 148 > gc_lnum 2324 > ihead_lnum 2258 > ihead_offs 8192 > index_size 2511408 > lpt_lnum 15 > lpt_offs 113571 > nhead_lnum 15 > nhead_offs 114688 > ltab_lnum 15 > ltab_offs 110592 > lsave_lnum 0 > lsave_offs 0 > lscan_lnum 2930 > leb_cnt 6844 > empty_lebs 3362 > idx_lebs 23 > total_free 430188544 > total_dirty 56069504 > total_used 377968720 > total_dead 7032 > total_dark 31196320 > look at LEB 1:20992 (105984 bytes left) > scanning padding node at LEB 1:20992 > 1508 bytes padded at LEB 1:20992, offset now 22528 > look at LEB 1:22528 (104448 bytes left) > hit empty space at LEB 1:22528 > stop scanning LEB 1 at offset 126976 > > log nodes: > > leb number first sqnum first node type full/not full > 3 15801163 ref node full > 4 15801288 ref node full > 5 15801433 ref node full > 6 15801598 ref node full > 7 15801966 ref node not full > 8 15800414 ref node full > 9 15800538 ref node full > 10 15800664 ref node full > 11 15800789 ref node full > 12 15800915 ref node full > 13 15801039 ref node full > > The min_io_size of this device is 2048 and the leb_size of it is > 126976. Each of leb is full except 7 means no frequently power > cutting happen because log leb will change into next one if the > volume is remount. > > We know cs node must in leb 4 as @log_lnum is 4 in mst node. But > it is a ref node as we see it in leb 4. What happened? > > Leb 7 has the highest sqnum and it is not full, that means it is > the last log leb before an unclean power off. So we know leb 8 is > the oldest log leb exist. But it has a higher sqnum than mst node, > 15799802, that means mst node is written before the oldest node > in current log area. > > Each time we write a cs node, we write a new mst node. The sqnum > of this mst node should higher than cs node. So the cs node in > leb 4 is overlapped. > > We keep an empty leb in log area by @min_log_bytes to start-up a > new commit. When commit start, we may use this leb and set > @min_log_bytes to zero. > > Suppose old ltail_lnum is 5 and lhead_lnum is 3, leb 3 is full and > a new commit start. We write a new cs node at the beginning of leb > 4 and set @min_log_bytes to zero. Now, as empty_log_bytes() is wrong, > ubifs_add_bud_to_log() may wrap leb 5, leb 6... At last, overlap > the leb 4 which has the newest cs node and mst_node would point to, > why not? we don't have any assertion or any protection to void this > except the check of empty_log_bytes() with an error shows above. > > Now an unfortunately power cut happens, this volume is broken. > > I think this patch fixed this problem by correctly protect the log > area. So maybe you can add "Cc stable" before you send it to mainline. > > By the way, commit 8989cd69b9d2 "UBIFS: fix a race condition" fix > a real potential race and useful for avoiding errors in log area. > Could you please add "Cc stable" for it too? OK, I am adding these tags: Cc: stable at vger.kernel.org Tested-by: hujianyang And putting the patches to the linux-next queue. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 02:47:10 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 12:47:10 +0300 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <5407914B.302@nod.at> References: <5404EA4F.1040508@nod.at> <20140901220258.GA28791@kroah.com> <5407914B.302@nod.at> Message-ID: <1410169630.10764.109.camel@sauron.fi.intel.com> On Thu, 2014-09-04 at 00:08 +0200, Richard Weinberger wrote: > e8c235b UBI: init_volumes: Ignore volumes with no LEBs > 44305eb UBI: fastmap: do not miss bit-flips > 604b592 UBI: fix rb_tree node comparison in add_map > 5547fec UBI: fix some use after free bugs > fe24c6e UBI: Fix memory leak in ubi_attach_fastmap() error path > c22301a UBI: fastmap: fix backward compatibility with image_seq > 4b3e0a2 UBI: Call scan_all() with correct offset in error case > f240dca UBI: Fix error path in scan_pool() > fb10e4d UBI: fix refill_wl_user_pool() > 8930fa5 UBI: Fix invalidate_fastmap() The entire "fastmap" feature is classified as "experimental", why would we need to be submit these to stable? I mean, we do not treat the feature as bullet proof anyway yet. -- Best Regards, Artem Bityutskiy From richard at nod.at Mon Sep 8 02:51:20 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 08 Sep 2014 11:51:20 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <1410169630.10764.109.camel@sauron.fi.intel.com> References: <5404EA4F.1040508@nod.at> <20140901220258.GA28791@kroah.com> <5407914B.302@nod.at> <1410169630.10764.109.camel@sauron.fi.intel.com> Message-ID: <540D7C18.2060104@nod.at> Artem, Am 08.09.2014 11:47, schrieb Artem Bityutskiy: > On Thu, 2014-09-04 at 00:08 +0200, Richard Weinberger wrote: >> e8c235b UBI: init_volumes: Ignore volumes with no LEBs >> 44305eb UBI: fastmap: do not miss bit-flips >> 604b592 UBI: fix rb_tree node comparison in add_map >> 5547fec UBI: fix some use after free bugs >> fe24c6e UBI: Fix memory leak in ubi_attach_fastmap() error path >> c22301a UBI: fastmap: fix backward compatibility with image_seq >> 4b3e0a2 UBI: Call scan_all() with correct offset in error case >> f240dca UBI: Fix error path in scan_pool() >> fb10e4d UBI: fix refill_wl_user_pool() >> 8930fa5 UBI: Fix invalidate_fastmap() > > The entire "fastmap" feature is classified as "experimental", why would > we need to be submit these to stable? I mean, we do not treat the > feature as bullet proof anyway yet. but people want to test it. And we can get Fastmap only stable by having users. As you know embedded folks tend to use rather old kernels. Let's give them a chance to use the most current version of Fastmap on these kernels. Thanks, //richard From dedekind1 at gmail.com Mon Sep 8 02:58:38 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 12:58:38 +0300 Subject: Ubi patch proposition for 3.10.y In-Reply-To: References: Message-ID: <1410170318.10764.119.camel@sauron.fi.intel.com> On Fri, 2014-08-29 at 14:26 +0200, jean-philippe francois wrote: > Hi, > > I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct > offset in error case) should be added to 3.10.y stable branch. This is the "fastmap" fix, and fastmap is called experimental. We do not have enough confidence it is production ready. Specifically, I'd like to hear someone doing extensive power-cut testing with this feature. The power-cut tolerance is one of the "selling features" of UBI/UBIFS, after all. Therefore I never added fastmap fixes to the stable queue. But if someone is willing to put all the fastmap fixes together, add the "stable tags" with the right kernel version "markings", and test for few older kernels, then I will recommend them to be included to the stable. Although I am not sure the stable maintainers would like accept them. But I do not recommend adding this single patch to the stable queue. But better, if people started paying more attention to "fastmap", we may agree that from now on we are careful about the sending the fixes to the stable queue. Thanks! -- Best Regards, Artem Bityutskiy From sudipm.mukherjee at gmail.com Mon Sep 8 03:00:19 2014 From: sudipm.mukherjee at gmail.com (Sudip Mukherjee) Date: Mon, 8 Sep 2014 15:30:19 +0530 Subject: [PATCH 7/7] mtd: denali: fix indentations and other trivial things In-Reply-To: <20140908181447.C428.AA925319@jp.panasonic.com> References: <1410163813-31783-8-git-send-email-yamada.m@jp.panasonic.com> <20140908083920.GD5361@thin> <20140908181447.C428.AA925319@jp.panasonic.com> Message-ID: <20140908100019.GA3840@sudip-PC> On Mon, Sep 08, 2014 at 06:14:48PM +0900, Masahiro Yamada wrote: > Hi Josh, > > > On Mon, 8 Sep 2014 01:39:20 -0700 > Josh Triplett wrote: > > > On Mon, Sep 08, 2014 at 05:10:13PM +0900, Masahiro Yamada wrote: > > > @@ -406,9 +404,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, > > > break; > > > default: > > > dev_warn(denali->dev, > > > - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > > > - "Will use default parameter values instead.\n", > > > - device_id); > > > + "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." > > > + "Will use default parameter values instead.\n", > > > + device_id); > > > > Please join quoted strings into a single line. > > > > > - pr_err("Your NAND chip OOB is not large enough to \ > > > - contain 8bit ECC correction codes"); > > > + pr_err("Your NAND chip OOB is not large enough to " > > > + "contain 8bit ECC correction codes"); > > > > Likewise. > > > > Thanks for your review, but > the quoted strings are too long to be joined into a single line. > (exceed 80 columns) > These are user-visible strings and they can be more than 80 char. If you see CodingStyle document , it is mentioned that : However, never break user-visible strings such as printk messages, because that breaks the ability to grep for them. thanks sudip > > Best Regards > Masahiro Yamada > > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ From dedekind1 at gmail.com Mon Sep 8 03:03:55 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:03:55 +0300 Subject: UBI, no sub-pages support In-Reply-To: <53F334D9.5030902@gmail.com> References: <53F334D9.5030902@gmail.com> Message-ID: <1410170635.10764.123.camel@sauron.fi.intel.com> On Tue, 2014-08-19 at 13:28 +0200, Angelo Dureghello wrote: > Another question is: is there a UBI performance loss using pages as > minimal I/O (no subpages) or i can consider it insignificant ? I can only comment on this question - you should not lose performance, but you'll have more NAND flash space consumed by UBI for its own purposes, comparing to what you'd have if you had sub-pages. IOW, sub-pages are mostly lessening the UBI space overhead. The MTD web page has a section about the space overhead with some more information. -- Best Regards, Artem Bityutskiy From w at 1wt.eu Mon Sep 8 03:04:53 2014 From: w at 1wt.eu (Willy Tarreau) Date: Mon, 8 Sep 2014 12:04:53 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <1410170318.10764.119.camel@sauron.fi.intel.com> References: <1410170318.10764.119.camel@sauron.fi.intel.com> Message-ID: <20140908100453.GA28903@1wt.eu> Hi Artem, On Mon, Sep 08, 2014 at 12:58:38PM +0300, Artem Bityutskiy wrote: > On Fri, 2014-08-29 at 14:26 +0200, jean-philippe francois wrote: > > Hi, > > > > I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct > > offset in error case) should be added to 3.10.y stable branch. > > This is the "fastmap" fix, and fastmap is called experimental. We do not > have enough confidence it is production ready. Specifically, I'd like to > hear someone doing extensive power-cut testing with this feature. The > power-cut tolerance is one of the "selling features" of UBI/UBIFS, after > all. > > Therefore I never added fastmap fixes to the stable queue. > > But if someone is willing to put all the fastmap fixes together, add the > "stable tags" with the right kernel version "markings", and test for few > older kernels, then I will recommend them to be included to the stable. > Although I am not sure the stable maintainers would like accept them. > > But I do not recommend adding this single patch to the stable queue. > > But better, if people started paying more attention to "fastmap", we may > agree that from now on we are careful about the sending the fixes to the > stable queue. Personally, I think that whatever feature provided in a kernel release is subject to being used and deserves its fixes. There are some cases where we *know* that some features are not used (eg: when they don't work without a lot of patching or tweaking), but if they seem to work for end users, they are likely to be used. Just my two cents, Willy From dedekind1 at gmail.com Mon Sep 8 03:13:41 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:13:41 +0300 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <20140908100453.GA28903@1wt.eu> References: <1410170318.10764.119.camel@sauron.fi.intel.com> <20140908100453.GA28903@1wt.eu> Message-ID: <1410171221.10764.132.camel@sauron.fi.intel.com> On Mon, 2014-09-08 at 12:04 +0200, Willy Tarreau wrote: > > But better, if people started paying more attention to "fastmap", we may > > agree that from now on we are careful about the sending the fixes to the > > stable queue. > > Personally, I think that whatever feature provided in a kernel release is > subject to being used and deserves its fixes. There are some cases where > we *know* that some features are not used (eg: when they don't work without > a lot of patching or tweaking), but if they seem to work for end users, they > are likely to be used. Well, adding stable tags is does not come for free. Whey you add a stable tag, you need to make sure it applies to the older kernel, and you need to also pick the possible dependencies. You need test it with older kernel. While in general what you say makes sense, for this specific "fastmap" case the maintainers (me and Richard) did not think the overhead is worth the benefits. If now the situation has changed, we may start being more careful. -- Best Regards, Artem Bityutskiy From richard.genoud at gmail.com Mon Sep 8 03:13:39 2014 From: richard.genoud at gmail.com (Richard Genoud) Date: Mon, 8 Sep 2014 12:13:39 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <20140908100453.GA28903@1wt.eu> References: <1410170318.10764.119.camel@sauron.fi.intel.com> <20140908100453.GA28903@1wt.eu> Message-ID: 2014-09-08 12:04 GMT+02:00 Willy Tarreau : > Hi Artem, > > On Mon, Sep 08, 2014 at 12:58:38PM +0300, Artem Bityutskiy wrote: >> On Fri, 2014-08-29 at 14:26 +0200, jean-philippe francois wrote: >> > Hi, >> > >> > I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct >> > offset in error case) should be added to 3.10.y stable branch. >> >> This is the "fastmap" fix, and fastmap is called experimental. We do not >> have enough confidence it is production ready. Specifically, I'd like to >> hear someone doing extensive power-cut testing with this feature. The >> power-cut tolerance is one of the "selling features" of UBI/UBIFS, after >> all. >> >> Therefore I never added fastmap fixes to the stable queue. >> >> But if someone is willing to put all the fastmap fixes together, add the >> "stable tags" with the right kernel version "markings", and test for few >> older kernels, then I will recommend them to be included to the stable. >> Although I am not sure the stable maintainers would like accept them. >> >> But I do not recommend adding this single patch to the stable queue. >> >> But better, if people started paying more attention to "fastmap", we may >> agree that from now on we are careful about the sending the fixes to the >> stable queue. > > Personally, I think that whatever feature provided in a kernel release is > subject to being used and deserves its fixes. There are some cases where > we *know* that some features are not used (eg: when they don't work without > a lot of patching or tweaking), but if they seem to work for end users, they > are likely to be used. > > Just my two cents, > Willy And fastmap is a really sexy feature... I couldn't resist adding it to my project. We are not in production yet, but we will be soon. For now, I'm letting end users playing with it. That's a good test usually :). And for the record, I'm stuck with 3.14.18 for now, so I'll welcome fixes on fastmap. Richard. From richard at nod.at Mon Sep 8 03:16:02 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 08 Sep 2014 12:16:02 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <1410170318.10764.119.camel@sauron.fi.intel.com> References: <1410170318.10764.119.camel@sauron.fi.intel.com> Message-ID: <540D81E2.5010203@nod.at> Am 08.09.2014 11:58, schrieb Artem Bityutskiy: > On Fri, 2014-08-29 at 14:26 +0200, jean-philippe francois wrote: >> Hi, >> >> I think commit 4b3e0a25... [1] (UBI: Call scan_all() with correct >> offset in error case) should be added to 3.10.y stable branch. > > This is the "fastmap" fix, and fastmap is called experimental. We do not > have enough confidence it is production ready. Specifically, I'd like to > hear someone doing extensive power-cut testing with this feature. The > power-cut tolerance is one of the "selling features" of UBI/UBIFS, after > all. > > Therefore I never added fastmap fixes to the stable queue. > > But if someone is willing to put all the fastmap fixes together, add the > "stable tags" with the right kernel version "markings", and test for few > older kernels, then I will recommend them to be included to the stable. > Although I am not sure the stable maintainers would like accept them. I'll take care of that from now on. Thanks, //richard From dedekind1 at gmail.com Mon Sep 8 03:26:49 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:26:49 +0300 Subject: [PATCH][V2] UBI: block: fix dereference on uninitialized dev In-Reply-To: <20140821191246.GA13322@arch.cereza> References: <1408526378-12972-1-git-send-email-colin.king@canonical.com> <20140821191246.GA13322@arch.cereza> Message-ID: <1410172009.10764.135.camel@sauron.fi.intel.com> On Thu, 2014-08-21 at 16:12 -0300, Ezequiel Garcia wrote: > On 20 Aug 10:19 AM, Colin King wrote: > > From: Colin Ian King > > > > commit 4df38926f337 ("UBI: block: Avoid disk size integer overflow") > > introduced a dereference on dev (which is not initialized at that > > point) when printing a warning message. Re-order disk_capacity check > > after the dev is found. > > > > Found by cppcheck: > > [drivers/mtd/ubi/block.c:509]: (error) Uninitialized variable: dev > > > > Signed-off-by: Colin Ian King > > Acked-by: Ezequiel Garcia Do we want to have this patch in @stable? -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 03:30:18 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:30:18 +0300 Subject: [PATCH] nandtest: fix --reads argument In-Reply-To: <1408033785-20264-1-git-send-email-guido@vanguardiasur.com.ar> References: <1408033785-20264-1-git-send-email-guido@vanguardiasur.com.ar> Message-ID: <1410172218.10764.136.camel@sauron.fi.intel.com> On Thu, 2014-08-14 at 13:29 -0300, Guido Mart?nez wrote: > The --reads option specifies the argument as optional, but doesn't check > for a null optarg, which means that nandtest segfaults when run as > "nandtest --reads". > > Fix this by making the argument required, and changing the help text to > not specify it as optional. Argument -r already specifies the argument > as required, so we fix this inconsistency too. > > Signed-off-by: Guido Mart?nez Pushed, thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 03:50:01 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:50:01 +0300 Subject: ubifs_dump_node must bounds check ubifs_ch->len In-Reply-To: References: Message-ID: <1410173401.10764.145.camel@sauron.fi.intel.com> On Thu, 2014-08-28 at 15:37 -0700, Daniel Mentz wrote: > I believe that ubifs_dump_node() must bounds check ch->len in the > UBIFS_DATA_NODE case. It currently does not which resulted in a crash > on a system. See below. > > This is the source code as it stands today: > > int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ; > print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, > (void *)&dn->data, dlen, 0); Yes, I agree. This is a bug. The problem is that this function tries to print the node even though it may be corrupted and the data are garbage. So we should assume that any field may contain garbage. I see similar potential problems. 1. case UBIFS_DENT_NODE: case UBIFS_XENT_NODE: nlen < 0 is not verified. 2. case UBIFS_DATA_NODE: you reported - dlen is not validated. Here we could use 'c->ranges' to validate it before using, see 'ubifs_check_node()' for an example. 3. case UBIFS_IDX_NODE: fanout is not validated 4. case UBIFS_ORPH_NODE: "n" is not validated. Will I feel lucky asking you whether you was going to send a patch? :-) Thanks for the report! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 03:52:44 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:52:44 +0300 Subject: [PATCH 1/3] UBI: block: Fix block device size setting In-Reply-To: <1409348550-27768-2-git-send-email-ezequiel.garcia@free-electrons.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-2-git-send-email-ezequiel.garcia@free-electrons.com> Message-ID: <1410173564.10764.146.camel@sauron.fi.intel.com> On Fri, 2014-08-29 at 18:42 -0300, Ezequiel Garcia wrote: > We are currently taking the block device size from the ubi_volume_info.size > field. However, this is not the amount of data in the volume, but the > number of reserved physical eraseblocks, and hence leads to an incorrect > representation of the volume. > > In particular, this produces I/O errors on static volumes as the block > interface may attempt to read unmapped PEBs: > > $ cat /dev/ubiblock0_0 > /dev/null > UBI error: ubiblock_read_to_buf: ubiblock0_0 ubi_read error -22 > end_request: I/O error, dev ubiblock0_0, sector 9536 > Buffer I/O error on device ubiblock0_0, logical block 2384 > [snip] > > Fix this by using the ubi_volume_info.used_bytes field which is set to the > actual number of data bytes for both static and dynamic volumes. > > While here, improve the error message to be less stupid and more useful: > UBI error: ubiblock_read_to_buf: ubiblock0_1 ubi_read error -9 on LEB=0, off=15872, len=512 > > It's worth noticing that the 512-byte sector representation of the volume > is only correct if the volume size is multiple of 512-bytes. This is true for > virtually any NAND device, given eraseblocks and pages are 512-byte multiple > and hence so is the LEB size. > > Fixes: 9d54c8a33eec ("UBI: R/O block driver on top of UBI volumes") > Signed-off-by: Ezequiel Garcia Looks good, do we want this one in stable? -- Best Regards, Artem Bityutskiy From rogerq at ti.com Mon Sep 8 03:53:06 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 8 Sep 2014 13:53:06 +0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540D6CAB.7020501@ti.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> Message-ID: <540D8A92.2040209@ti.com> On 09/08/2014 11:45 AM, Roger Quadros wrote: > On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: >> The current code abuses ifdefs to determine if the selected ECC scheme >> is supported by the running kernel. As a result the code is hard to read, >> and it also fails to load as a module. >> >> This commit removes all the ifdefs and instead introduces a function >> omap2_nand_ecc_check() to check if the ECC is supported by using >> IS_ENABLED(CONFIG_xxx). >> >> Since IS_ENABLED() is true when a config is =y or =m, this change fixes the >> module so it can be loaded with no issues. >> >> Signed-off-by: Ezequiel Garcia > > Didn't apply cleanly on 3.17-rc4. Needs a rebase? > >> --- >> drivers/mtd/nand/omap2.c | 134 +++++++++++++++++++++----------------- >> include/linux/platform_data/elm.h | 14 ++++ >> 2 files changed, 87 insertions(+), 61 deletions(-) >> >> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c >> index 1170389..987dd94 100644 >> --- a/drivers/mtd/nand/omap2.c >> +++ b/drivers/mtd/nand/omap2.c >> @@ -136,7 +136,6 @@ >> >> #define BADBLOCK_MARKER_LENGTH 2 >> >> -#ifdef CONFIG_MTD_NAND_OMAP_BCH >> static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, >> 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, >> 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, >> @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, >> static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, >> 0xac, 0x6b, 0xff, 0x99, 0x7b}; >> static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; >> -#endif >> >> /* oob info generated runtime depending on ecc algorithm and layout selected */ >> static struct nand_ecclayout omap_oobinfo; >> @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, >> return 0; >> } >> >> -#ifdef CONFIG_MTD_NAND_OMAP_BCH >> /** >> * erased_sector_bitflips - count bit flips >> * @data: data sector buffer >> @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, >> /** >> * is_elm_present - checks for presence of ELM module by scanning DT nodes >> * @omap_nand_info: NAND device structure containing platform data >> - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 >> */ >> -static int is_elm_present(struct omap_nand_info *info, >> - struct device_node *elm_node, enum bch_ecc bch_type) >> +static bool is_elm_present(struct omap_nand_info *info, >> + struct device_node *elm_node) >> { >> struct platform_device *pdev; >> - struct nand_ecc_ctrl *ecc = &info->nand.ecc; >> - int err; >> + >> /* check whether elm-id is passed via DT */ >> if (!elm_node) { >> - pr_err("nand: error: ELM DT node not found\n"); >> - return -ENODEV; >> + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); >> + return false; >> } >> pdev = of_find_device_by_node(elm_node); >> /* check whether ELM device is registered */ >> if (!pdev) { >> - pr_err("nand: error: ELM device not found\n"); >> - return -ENODEV; >> + dev_err(&info->pdev->dev, "ELM device not found\n"); >> + return false; >> } >> /* ELM module available, now configure it */ >> info->elm_dev = &pdev->dev; >> - err = elm_config(info->elm_dev, bch_type, >> - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); >> + return true; >> +} >> >> - return err; >> +static bool omap2_nand_ecc_check(struct omap_nand_info *info, >> + struct omap_nand_platform_data *pdata) >> +{ > > I like the idea of this function and it being called in probe. > > It would be also be nice (maybe later) to get rid of all the ECC decision making > done in gpmc_probe_nand_child() based on presence/absence of the elm_of_node. > I guess we need to add new DT entries for "bch4sw" and "bch8sw" so that DT/platform data > can explicitly specify what it needs. I don't see how ELM works with the non-DT boot > way as there is no elm_of_node there. > > Also, the elm_of_node should not be set via platform data or in gpmc.c but parsed here > directly in the NAND driver. > > But changes should be done in a separate patch. Just brought them out > here for discussion. > >> + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; >> + >> + switch (info->ecc_opt) { >> + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: >> + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: >> + ecc_needs_omap_bch = false; >> + ecc_needs_bch = true; >> + ecc_needs_elm = false; >> + break; >> + case OMAP_ECC_BCH4_CODE_HW: >> + case OMAP_ECC_BCH8_CODE_HW: >> + case OMAP_ECC_BCH16_CODE_HW: >> + ecc_needs_omap_bch = true; >> + ecc_needs_bch = false; >> + ecc_needs_elm = true; >> + break; >> + default: >> + ecc_needs_omap_bch = false; >> + ecc_needs_bch = false; >> + ecc_needs_elm = false; >> + break; >> + } >> + >> + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { >> + dev_err(&info->pdev->dev, >> + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); >> + return false; >> + } >> + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { >> + dev_err(&info->pdev->dev, >> + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); >> + return false; >> + } >> + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { >> + dev_err(&info->pdev->dev, "ELM not available\n"); >> + return false; >> + } >> + >> + return true; >> } >> -#endif /* CONFIG_MTD_NAND_ECC_BCH */ >> >> static int omap_nand_probe(struct platform_device *pdev) >> { >> @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) >> goto return_error; >> } >> >> + if (!omap2_nand_ecc_check(info, pdata)) { >> + err = -EINVAL; >> + goto return_error; >> + } >> + >> /* populate MTD interface based on ECC scheme */ >> nand_chip->ecc.layout = &omap_oobinfo; >> ecclayout = &omap_oobinfo; >> @@ -1826,7 +1866,6 @@ static int omap_nand_probe(struct platform_device *pdev) >> break; >> >> case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: >> -#ifdef CONFIG_MTD_NAND_ECC_BCH >> pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); >> nand_chip->ecc.mode = NAND_ECC_HW; >> nand_chip->ecc.size = 512; >> @@ -1858,14 +1897,8 @@ static int omap_nand_probe(struct platform_device *pdev) >> err = -EINVAL; >> } >> break; >> -#else >> - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); >> - err = -EINVAL; >> - goto return_error; >> -#endif >> >> case OMAP_ECC_BCH4_CODE_HW: >> -#ifdef CONFIG_MTD_NAND_OMAP_BCH >> pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); >> nand_chip->ecc.mode = NAND_ECC_HW; >> nand_chip->ecc.size = 512; >> @@ -1887,21 +1920,15 @@ static int omap_nand_probe(struct platform_device *pdev) >> /* reserved marker already included in ecclayout->eccbytes */ >> ecclayout->oobfree->offset = >> ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; >> - /* This ECC scheme requires ELM H/W block */ >> - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { >> - pr_err("nand: error: could not initialize ELM\n"); >> - err = -ENODEV; >> + >> + err = elm_config(info->elm_dev, BCH4_ECC, >> + info->mtd.writesize / nand_chip->ecc.size, >> + nand_chip->ecc.size, nand_chip->ecc.bytes); >> + if (err < 0) >> goto return_error; >> - } >> break; >> -#else >> - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); >> - err = -EINVAL; >> - goto return_error; >> -#endif >> >> case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: >> -#ifdef CONFIG_MTD_NAND_ECC_BCH >> pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); >> nand_chip->ecc.mode = NAND_ECC_HW; >> nand_chip->ecc.size = 512; >> @@ -1934,14 +1961,8 @@ static int omap_nand_probe(struct platform_device *pdev) >> goto return_error; >> } >> break; >> -#else >> - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); >> - err = -EINVAL; >> - goto return_error; >> -#endif >> >> case OMAP_ECC_BCH8_CODE_HW: >> -#ifdef CONFIG_MTD_NAND_OMAP_BCH >> pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); >> nand_chip->ecc.mode = NAND_ECC_HW; >> nand_chip->ecc.size = 512; >> @@ -1953,12 +1974,13 @@ static int omap_nand_probe(struct platform_device *pdev) >> nand_chip->ecc.calculate = omap_calculate_ecc_bch; >> nand_chip->ecc.read_page = omap_read_page_bch; >> nand_chip->ecc.write_page = omap_write_page_bch; >> - /* This ECC scheme requires ELM H/W block */ >> - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); >> - if (err < 0) { >> - pr_err("nand: error: could not initialize ELM\n"); >> + >> + err = elm_config(info->elm_dev, BCH8_ECC, >> + info->mtd.writesize / nand_chip->ecc.size, >> + nand_chip->ecc.size, nand_chip->ecc.bytes); >> + if (err < 0) >> goto return_error; >> - } >> + >> /* define ECC layout */ >> ecclayout->eccbytes = nand_chip->ecc.bytes * >> (mtd->writesize / >> @@ -1970,14 +1992,8 @@ static int omap_nand_probe(struct platform_device *pdev) >> ecclayout->oobfree->offset = >> ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; >> break; >> -#else >> - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); >> - err = -EINVAL; >> - goto return_error; >> -#endif >> >> case OMAP_ECC_BCH16_CODE_HW: >> -#ifdef CONFIG_MTD_NAND_OMAP_BCH >> pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); >> nand_chip->ecc.mode = NAND_ECC_HW; >> nand_chip->ecc.size = 512; >> @@ -1988,12 +2004,13 @@ static int omap_nand_probe(struct platform_device *pdev) >> nand_chip->ecc.calculate = omap_calculate_ecc_bch; >> nand_chip->ecc.read_page = omap_read_page_bch; >> nand_chip->ecc.write_page = omap_write_page_bch; >> - /* This ECC scheme requires ELM H/W block */ >> - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); >> - if (err < 0) { >> - pr_err("ELM is required for this ECC scheme\n"); >> + >> + err = elm_config(info->elm_dev, BCH16_ECC, >> + info->mtd.writesize / nand_chip->ecc.size, >> + nand_chip->ecc.size, nand_chip->ecc.bytes); >> + if (err < 0) >> goto return_error; >> - } >> + >> /* define ECC layout */ >> ecclayout->eccbytes = nand_chip->ecc.bytes * >> (mtd->writesize / >> @@ -2005,11 +2022,6 @@ static int omap_nand_probe(struct platform_device *pdev) >> ecclayout->oobfree->offset = >> ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; >> break; >> -#else >> - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); >> - err = -EINVAL; >> - goto return_error; >> -#endif >> default: >> pr_err("nand: error: invalid or unsupported ECC scheme\n"); >> err = -EINVAL; >> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h >> index 780d1e9..25d1bca 100644 >> --- a/include/linux/platform_data/elm.h >> +++ b/include/linux/platform_data/elm.h >> @@ -42,8 +42,22 @@ struct elm_errorvec { >> int error_loc[16]; >> }; >> >> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and CONFIG_MTD_NAND_OMAP_BCH to m. CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. Maybe it should be a sub option of CONFIG_MTD_NAND_OMAP2. IMHO the elm.c file must be moved from mtd/devices to mtd/nand and renamed to omap_elm.c drivers/built-in.o: In function `omap_nand_probe': /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' drivers/built-in.o: In function `omap_elm_correct_data': /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' make: *** [vmlinux] Error 1 >> void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >> struct elm_errorvec *err_vec); >> int elm_config(struct device *dev, enum bch_ecc bch_type, >> int ecc_steps, int ecc_step_size, int ecc_syndrome_size); >> +#else >> +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >> + struct elm_errorvec *err_vec) >> +{ >> +} >> + >> +int elm_config(struct device *dev, enum bch_ecc bch_type, >> + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) >> +{ >> + return -ENOSYS; >> +} >> +#endif /* CONFIG_MTD_NAND_ECC_BCH */ >> + >> #endif /* __ELM_H */ >> > cheers, -roger From w at 1wt.eu Mon Sep 8 03:53:59 2014 From: w at 1wt.eu (Willy Tarreau) Date: Mon, 8 Sep 2014 12:53:59 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <1410171221.10764.132.camel@sauron.fi.intel.com> References: <1410170318.10764.119.camel@sauron.fi.intel.com> <20140908100453.GA28903@1wt.eu> <1410171221.10764.132.camel@sauron.fi.intel.com> Message-ID: <20140908105359.GB28903@1wt.eu> On Mon, Sep 08, 2014 at 01:13:41PM +0300, Artem Bityutskiy wrote: > Well, adding stable tags is does not come for free. Whey you add a > stable tag, you need to make sure it applies to the older kernel, and > you need to also pick the possible dependencies. You need test it with > older kernel. > > While in general what you say makes sense, for this specific "fastmap" > case the maintainers (me and Richard) did not think the overhead is > worth the benefits. I understand and am not pressuring anyone to do the backport. Sometimes if something appears to be clearly broken, for example to the point where data corruption may result from the use of any feature, a patch to disable the feature or make it depend on CONFIG_BROKEN might be good as well to warn users they must not use it because it's too broken. Regards, Willy From dedekind1 at gmail.com Mon Sep 8 03:54:17 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 13:54:17 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> Message-ID: <1410173657.10764.148.camel@sauron.fi.intel.com> On Fri, 2014-08-29 at 18:42 -0300, Ezequiel Garcia wrote: > Static volumes can change its 'used_bytes' when they get updated, > and so the block interface must listen to the UBI_VOLUME_UPDATED > notification to resize the block device accordingly. > > Signed-off-by: Ezequiel Garcia Looks like a good fix. If you want this in stable, you please, let me know and also make sure you actually tested it and verified that block device size actually gets changed. -- Best Regards, Artem Bityutskiy From jp.francois at cynove.com Mon Sep 8 04:03:25 2014 From: jp.francois at cynove.com (jean-philippe francois) Date: Mon, 8 Sep 2014 13:03:25 +0200 Subject: Ubi patch proposition for 3.10.y In-Reply-To: <1410171221.10764.132.camel@sauron.fi.intel.com> References: <1410170318.10764.119.camel@sauron.fi.intel.com> <20140908100453.GA28903@1wt.eu> <1410171221.10764.132.camel@sauron.fi.intel.com> Message-ID: 2014-09-08 12:13 GMT+02:00 Artem Bityutskiy : > On Mon, 2014-09-08 at 12:04 +0200, Willy Tarreau wrote: >> > But better, if people started paying more attention to "fastmap", we may >> > agree that from now on we are careful about the sending the fixes to the >> > stable queue. >> >> Personally, I think that whatever feature provided in a kernel release is >> subject to being used and deserves its fixes. There are some cases where >> we *know* that some features are not used (eg: when they don't work without >> a lot of patching or tweaking), but if they seem to work for end users, they >> are likely to be used. > > Well, adding stable tags is does not come for free. Whey you add a > stable tag, you need to make sure it applies to the older kernel, and > you need to also pick the possible dependencies. You need test it with > older kernel. > > While in general what you say makes sense, for this specific "fastmap" > case the maintainers (me and Richard) did not think the overhead is > worth the benefits. > > If now the situation has changed, we may start being more careful. > Well for the original commit case : - it applies - it has been tested (by me at least) - it solves a power cut fs corruption issue. You ask for power cut testing, but when presented with the results, patch is dismissed because I am foolish enough to use a long term stable kernel, and not jump version each time a new kernel comes up. Hopefully, dts will greatly help with migrating kernel, but unoftunately, our camera was developped at the wrong moment (no more board file accepted, yet no dts support for vital peripheral like ISP). It started with one patch, and now tens of them are mentionned, so I understand your concern. Regards, Jean-Philippe Fran?ois > Best Regards, > Artem Bityutskiy > From ezequiel.garcia at free-electrons.com Mon Sep 8 04:18:32 2014 From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:18:32 -0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1410173657.10764.148.camel@sauron.fi.intel.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> Message-ID: <20140908111832.GA1676@arch.hh.imgtec.org> On 08 Sep 01:54 PM, Artem Bityutskiy wrote: > On Fri, 2014-08-29 at 18:42 -0300, Ezequiel Garcia wrote: > > Static volumes can change its 'used_bytes' when they get updated, > > and so the block interface must listen to the UBI_VOLUME_UPDATED > > notification to resize the block device accordingly. > > > > Signed-off-by: Ezequiel Garcia > > Looks like a good fix. If you want this in stable, you please, let me > know and also make sure you actually tested it and verified that block > device size actually gets changed. > Yes, gave this series a good test, with gluebi and ubiblock enabled, updating/resizing a volume and then reading back the contents from the ubi0_0, ubiblock0_0 and mtdX (gluebi) devices. However, it would be awesome if we could get someone else to test this and report. Regarding -stable, I think it's worth to pull the whole series. -- Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:27:13 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:27:13 -0300 Subject: [PATCH v2 0/3] nand: omap2: Two and a half improvements Message-ID: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> Changes from v1: * Rebased on v3.14-rc2. * Removed a few s/pr_err/dev_err change from patch two, and added it to patch three. This was some git-rebase leftover. Pekon's attempt to add flash BBT support for this driver made me realise the addition made sense and there were good reasons for it. The first patch adds support for enabling a flash BBT either from legacy board files or from devicetree. While testing this, I noticed how the driver relied on a whole bunch of horrible #ifdefs, which prevented me from loading the driver as a module. The second patch attempts to fix that. The third patch is just a dummy cleanup replacing pr_errs with dev_errs. This driver is abusing from user messages, but I'm not sure fixing them worths the trouble. Ezequiel Garcia (3): nand: omap2: Add support for flash-based bad block table nand: omap2: Remove horrible ifdefs to fix module probe nand: omap2: Replace pr_err with dev_err arch/arm/mach-omap2/gpmc.c | 2 + drivers/mtd/nand/omap2.c | 162 +++++++++++++++------------ include/linux/platform_data/elm.h | 14 +++ include/linux/platform_data/mtd-nand-omap2.h | 1 + 4 files changed, 107 insertions(+), 72 deletions(-) -- 2.0.1 From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:27:14 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:27:14 -0300 Subject: [PATCH v2 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410175636-4036-2-git-send-email-ezequiel@vanguardiasur.com.ar> This commit adds a new platform-data boolean property that enables use of a flash-based bad block table. This can also be enabled by setting the 'nand-on-flash-bbt' devicetree property. If the flash BBT is not enabled, the driver falls back to use OOB bad block markers only, as before. If the flash BBT is enabled the kernel will keep track of bad blocks using a BBT, in addition to the OOB markers. As explained by Brian Norris the reasons for using a BBT are: "" The primary reason would be that NAND datasheets specify it these days. A better argument is that nobody guarantees that you can write a bad block marker to a worn out block; you may just get program failures. This has been acknowledged by several developers over the last several years. Additionally, you get a boot-time performance improvement if you only have to read a few pages, instead of a page or two from every block on the flash. "" Signed-off-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 2 ++ drivers/mtd/nand/omap2.c | 6 +++++- include/linux/platform_data/mtd-nand-omap2.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 2f97228..b55a225 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5967b38..e1a9b31 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) mtd->owner = THIS_MODULE; nand_chip = &info->nand; nand_chip->ecc.priv = NULL; - nand_chip->options |= NAND_SKIP_BBTSCAN; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 50; } + if (pdata->flash_bbt) + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + else + nand_chip->options |= NAND_SKIP_BBTSCAN; + /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 16ec262..090bbab 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -71,6 +71,7 @@ struct omap_nand_platform_data { struct mtd_partition *parts; int nr_parts; bool dev_ready; + bool flash_bbt; enum nand_io xfer_type; int devsize; enum omap_ecc ecc_opt; -- 2.0.1 From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:27:16 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:27:16 -0300 Subject: [PATCH v2 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410175636-4036-4-git-send-email-ezequiel@vanguardiasur.com.ar> Usage of pr_err is frowned upon, so replace it with dev_err. Aditionally, the message on nand_bch_init() error is redundant, since proper error is showed if the function fails. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f97a4ff..eb5e898 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, erased_ecc_vec = bch16_vector; break; default: - pr_err("invalid driver configuration\n"); + dev_err(&info->pdev->dev, "invalid driver configuration\n"); return -EINVAL; } @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, err = 0; for (i = 0; i < eccsteps; i++) { if (err_vec[i].error_uncorrectable) { - pr_err("nand: uncorrectable bit-flips found\n"); + dev_err(&info->pdev->dev, + "uncorrectable bit-flips found\n"); err = -EBADMSG; } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, 1 << bit_pos; } } else { - pr_err("invalid bit-flip @ %d:%d\n", - byte_pos, bit_pos); + dev_err(&info->pdev->dev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); err = -EBADMSG; } } @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, /* check whether elm-id is passed via DT */ if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { - pr_err("nand: error: ELM device not found\n"); + dev_err(&info->pdev->dev, "ELM device not found\n"); return false; } /* ELM module available, now configure it */ @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); err = -ENXIO; goto return_error; } /* check for small page devices */ if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); + dev_err(&info->pdev->dev, "small page devices are not supported\n"); err = -EINVAL; goto return_error; } @@ -1959,7 +1961,6 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); err = -EINVAL; goto return_error; } @@ -2026,7 +2027,7 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); err = -EINVAL; goto return_error; } @@ -2038,8 +2039,9 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); + dev_err(&info->pdev->dev, + "not enough OOB bytes required = %d, available=%d\n", + ecclayout->eccbytes, mtd->oobsize); err = -EINVAL; goto return_error; } -- 2.0.1 From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:27:15 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:27:15 -0300 Subject: [PATCH v2 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410175636-4036-3-git-send-email-ezequiel@vanguardiasur.com.ar> The current code abuses ifdefs to determine if the selected ECC scheme is supported by the running kernel. As a result the code is hard to read, and it also fails to load as a module. This commit removes all the ifdefs and instead introduces a function omap2_nand_ecc_check() to check if the ECC is supported by using IS_ENABLED(CONFIG_xxx). Since IS_ENABLED() is true when a config is =y or =m, this change fixes the module so it can be loaded with no issues. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 130 +++++++++++++++++++++----------------- include/linux/platform_data/elm.h | 14 ++++ 2 files changed, 85 insertions(+), 59 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index e1a9b31..f97a4ff 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -136,7 +136,6 @@ #define BADBLOCK_MARKER_LENGTH 2 -#ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -#endif /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, /** * is_elm_present - checks for presence of ELM module by scanning DT nodes * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static bool is_elm_present(struct omap_nand_info *info, + struct device_node *elm_node) { struct platform_device *pdev; - struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int err; + /* check whether elm-id is passed via DT */ if (!elm_node) { pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { pr_err("nand: error: ELM device not found\n"); - return -ENODEV; + return false; } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - err = elm_config(info->elm_dev, bch_type, - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + return true; +} - return err; +static bool omap2_nand_ecc_check(struct omap_nand_info *info, + struct omap_nand_platform_data *pdata) +{ + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; + + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + ecc_needs_omap_bch = false; + ecc_needs_bch = true; + ecc_needs_elm = false; + break; + case OMAP_ECC_BCH4_CODE_HW: + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + ecc_needs_omap_bch = true; + ecc_needs_bch = false; + ecc_needs_elm = true; + break; + default: + ecc_needs_omap_bch = false; + ecc_needs_bch = false; + ecc_needs_elm = false; + break; + } + + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + return false; + } + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + return false; + } + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { + dev_err(&info->pdev->dev, "ELM not available\n"); + return false; + } + + return true; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ static int omap_nand_probe(struct platform_device *pdev) { @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } + if (!omap2_nand_ecc_check(info, pdata)) { + err = -EINVAL; + goto return_error; + } + /* populate MTD interface based on ECC scheme */ ecclayout = &omap_oobinfo; switch (info->ecc_opt) { @@ -1829,7 +1869,6 @@ static int omap_nand_probe(struct platform_device *pdev) break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1861,14 +1900,8 @@ static int omap_nand_probe(struct platform_device *pdev) err = -EINVAL; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1890,21 +1923,15 @@ static int omap_nand_probe(struct platform_device *pdev) /* reserved marker already included in ecclayout->eccbytes */ ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; + + err = elm_config(info->elm_dev, BCH4_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1937,14 +1964,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1956,12 +1977,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); + + err = elm_config(info->elm_dev, BCH8_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1973,14 +1995,8 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1991,12 +2007,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); - if (err < 0) { - pr_err("ELM is required for this ECC scheme\n"); + + err = elm_config(info->elm_dev, BCH16_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -2008,11 +2025,6 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 780d1e9..25d1bca 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,8 +42,22 @@ struct elm_errorvec { int error_loc[16]; }; +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size); +#else +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ +} + +int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_MTD_NAND_ECC_BCH */ + #endif /* __ELM_H */ -- 2.0.1 From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:28:52 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:28:52 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540D6CAB.7020501@ti.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> Message-ID: <20140908112852.GB1676@arch.hh.imgtec.org> On 08 Sep 11:45 AM, Roger Quadros wrote: > On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > > The current code abuses ifdefs to determine if the selected ECC scheme > > is supported by the running kernel. As a result the code is hard to read, > > and it also fails to load as a module. > > > > This commit removes all the ifdefs and instead introduces a function > > omap2_nand_ecc_check() to check if the ECC is supported by using > > IS_ENABLED(CONFIG_xxx). > > > > Since IS_ENABLED() is true when a config is =y or =m, this change fixes the > > module so it can be loaded with no issues. > > > > Signed-off-by: Ezequiel Garcia > > Didn't apply cleanly on 3.17-rc4. Needs a rebase? > Just sent a new version rebased on v3.17-rc4. Thanks a lot for the test! -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Mon Sep 8 04:31:09 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 08:31:09 -0300 Subject: [PATCH 0/3] nand: omap2: Two and a half improvements In-Reply-To: <540D691B.2060202@ti.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <540D691B.2060202@ti.com> Message-ID: <20140908113109.GC1676@arch.hh.imgtec.org> On 08 Sep 11:30 AM, Roger Quadros wrote: [..] > > > > And speaking of modules, the driver loads as "modprobe omap2". And it's not > > the only one with a clumsy name: "modprobe elm". I guess we cannot fix it now, > > but it would be great to be more careful with driver naming in the future. > > Why can't we fix it now? It seems nobody ever used it as a module before so now > is the right time to fix. Unless Tony has any objections. > That would be great. "omap2-nand" or something like that would be optimal. Regarding the ELM driver, I agree with your suggestion in the other thread, we could just move it into drivers/mtd/nand and rework it to not be a module but just a pack of helpers for the NAND driver. Do you think that would work? -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From dedekind1 at gmail.com Mon Sep 8 04:43:59 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 14:43:59 +0300 Subject: Question about ubiformat and how to better use UBIFS In-Reply-To: References: Message-ID: <1410176639.10764.157.camel@sauron.fi.intel.com> On Thu, 2014-09-04 at 20:17 +0800, t kevin wrote: > So here are my questions. > 1. (Generally speaking) Which one is better? I know ubiformat is going > to erase every PEB so right now I prefer the second approach since I > don't have to do ubiformat everytime. It sounds like the erase counter > grows slower. If the second way works for you, you may stick to it. Back when I was working in Nokia, where we had to flash newly produced devices in the factory pipeline, we had to have a flash-able image. So we used the mkfs.ubifs approach. So generally, the mkfs.ubifs approach was designed for real production, and the mount approach was originally supported just to make developers' life easier. But use whatever is better for your needs. > 2. I'm working on an embedded device which has limited CPU power so > I'd like to use compressed_method=none. It can be done by passing -x > none to mkfs.ubifs. But I don't see similar option in ubiformat or > ubimkvol. Well, there is no compression involved in the UBI level, and both of these tools work on the UBI level, they do not know anything about UBIFS. That's why you do not see this option. > So when I go to the 2nd approach the mounted rootfs is > always compressed. Use 'mount -o compr=none', check Documentation/filesystems/ubifs.txt. > http://www.linux-mtd.infradead.org/faq/ubifs.html#L_comproff > This method is not helping much. I want to disable compression on the > entire fs, just like mkfs.ubifs -x none did. Yeah, that section misses -o compre=none. I've just fixed it up, thanks! -- Best Regards, Artem Bityutskiy From rogerq at ti.com Mon Sep 8 04:47:57 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 8 Sep 2014 14:47:57 +0300 Subject: [PATCH 0/3] nand: omap2: Two and a half improvements In-Reply-To: <20140908113109.GC1676@arch.hh.imgtec.org> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <540D691B.2060202@ti.com> <20140908113109.GC1676@arch.hh.imgtec.org> Message-ID: <540D976D.1050403@ti.com> On 09/08/2014 02:31 PM, Ezequiel Garcia wrote: > On 08 Sep 11:30 AM, Roger Quadros wrote: > [..] >>> >>> And speaking of modules, the driver loads as "modprobe omap2". And it's not >>> the only one with a clumsy name: "modprobe elm". I guess we cannot fix it now, >>> but it would be great to be more careful with driver naming in the future. >> >> Why can't we fix it now? It seems nobody ever used it as a module before so now >> is the right time to fix. Unless Tony has any objections. >> > > That would be great. "omap2-nand" or something like that would be optimal. Other drivers seem to use and underscore e.g. pxa3xx_nand.c, orion_nand.c so "omap2_nand" is fine by me. > > Regarding the ELM driver, I agree with your suggestion in the other thread, > we could just move it into drivers/mtd/nand and rework it to not be a module > but just a pack of helpers for the NAND driver. > > Do you think that would work? > The ELM is in fact a separate IP block on the SoC with its own Clocking, reset mechanism and memory resource. Clocking and reset is handled by OMAP hwmod framework, so it might not be that easy to get rid of the ELM device driver and make it just a library. For now just moving it to mtd/nand and naming it omap_elm (or omap4_elm since it was added in OMAP4) is good enough IMO. cheers, -roger From dedekind1 at gmail.com Mon Sep 8 04:50:01 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 14:50:01 +0300 Subject: mtd-utils-1.5.1 bug report In-Reply-To: References: Message-ID: <1410177001.10764.158.camel@sauron.fi.intel.com> On Sun, 2014-09-07 at 14:58 +0000, David Binderman wrote: > Hello there, > > ubi-utils/ubiformat.c:636:28: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] > > if (!args.subpage_size != mtd->min_io_size) > normsg("may be sub-page size is " > "incorrect?"); > > Something boolean compared to a size. Looks a possible problem to me. > Removal of the double negative might also help. Care to send a patch? -- Best Regards, Artem Bityutskiy From rogerq at ti.com Mon Sep 8 04:57:48 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 8 Sep 2014 14:57:48 +0300 Subject: [PATCH v2 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1410175636-4036-4-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-4-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <540D99BC.5040209@ti.com> Hi Ezequiel, On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: > Usage of pr_err is frowned upon, so replace it with dev_err. > Aditionally, the message on nand_bch_init() error is redundant, > since proper error is showed if the function fails. > > Signed-off-by: Ezequiel Garcia > --- > drivers/mtd/nand/omap2.c | 26 ++++++++++++++------------ > 1 file changed, 14 insertions(+), 12 deletions(-) > > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c > index f97a4ff..eb5e898 100644 > --- a/drivers/mtd/nand/omap2.c > +++ b/drivers/mtd/nand/omap2.c > @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > erased_ecc_vec = bch16_vector; > break; > default: > - pr_err("invalid driver configuration\n"); > + dev_err(&info->pdev->dev, "invalid driver configuration\n"); > return -EINVAL; > } > > @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > err = 0; > for (i = 0; i < eccsteps; i++) { > if (err_vec[i].error_uncorrectable) { > - pr_err("nand: uncorrectable bit-flips found\n"); > + dev_err(&info->pdev->dev, > + "uncorrectable bit-flips found\n"); > err = -EBADMSG; > } else if (err_vec[i].error_reported) { > for (j = 0; j < err_vec[i].error_count; j++) { > @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > 1 << bit_pos; > } > } else { > - pr_err("invalid bit-flip @ %d:%d\n", > - byte_pos, bit_pos); > + dev_err(&info->pdev->dev, > + "invalid bit-flip @ %d:%d\n", > + byte_pos, bit_pos); > err = -EBADMSG; > } > } > @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, > > /* check whether elm-id is passed via DT */ > if (!elm_node) { > - pr_err("nand: error: ELM DT node not found\n"); > + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); > return false; > } > pdev = of_find_device_by_node(elm_node); > /* check whether ELM device is registered */ > if (!pdev) { > - pr_err("nand: error: ELM device not found\n"); > + dev_err(&info->pdev->dev, "ELM device not found\n"); > return false; > } > /* ELM module available, now configure it */ > @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) > /* scan NAND device connected to chip controller */ > nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; > if (nand_scan_ident(mtd, 1, NULL)) { > - pr_err("nand device scan failed, may be bus-width mismatch\n"); > + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); > err = -ENXIO; > goto return_error; > } > > /* check for small page devices */ > if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { > - pr_err("small page devices are not supported\n"); > + dev_err(&info->pdev->dev, "small page devices are not supported\n"); > err = -EINVAL; > goto return_error; > } > @@ -1959,7 +1961,6 @@ static int omap_nand_probe(struct platform_device *pdev) > nand_chip->ecc.bytes, > &ecclayout); > if (!nand_chip->ecc.priv) { > - pr_err("nand: error: unable to use s/w BCH library\n"); Where would the error be printed in this case? I also noticed a similar message in the OMAP_ECC_BCH4_CODE_HW_DETECTION_SW case. And it seems to be missing a "goto return_error" there. > err = -EINVAL; > goto return_error; > } > @@ -2026,7 +2027,7 @@ static int omap_nand_probe(struct platform_device *pdev) > ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; > break; > default: > - pr_err("nand: error: invalid or unsupported ECC scheme\n"); > + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); > err = -EINVAL; > goto return_error; > } > @@ -2038,8 +2039,9 @@ static int omap_nand_probe(struct platform_device *pdev) > ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; > /* check if NAND device's OOB is enough to store ECC signatures */ > if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { > - pr_err("not enough OOB bytes required = %d, available=%d\n", > - ecclayout->eccbytes, mtd->oobsize); > + dev_err(&info->pdev->dev, > + "not enough OOB bytes required = %d, available=%d\n", > + ecclayout->eccbytes, mtd->oobsize); > err = -EINVAL; > goto return_error; > } > cheers, -roger From dedekind1 at gmail.com Mon Sep 8 05:09:48 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 15:09:48 +0300 Subject: mtd-utils-1.5.1 bug report In-Reply-To: References: Message-ID: <1410178188.10764.159.camel@sauron.fi.intel.com> On Sun, 2014-09-07 at 14:58 +0000, David Binderman wrote: > Hello there, > > ubi-utils/ubiformat.c:636:28: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] > > if (!args.subpage_size != mtd->min_io_size) > normsg("may be sub-page size is " > "incorrect?"); Hi, I'd propose this patch to fix the issue: Subject: [PATCH] ubiformat: fix the subpage size hint on the error path David Binderman reports that the following piece of looks wrong: if (!args.subpage_size != mtd->min_io_size) normsg("may be sub-page size is incorrect?"); I totally agree with him and I believe that we actually meant to have no negation in fron to f 'args.subpage_size', so instead, the code should look like this: if (args.subpage_size != mtd->min_io_size) normsg("may be sub-page size is incorrect?"); Signed-off-by: Artem Bityutskiy --- ubi-utils/ubiformat.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ubi-utils/ubiformat.c b/ubi-utils/ubiformat.c index 1b8f6fb..21409ca 100644 --- a/ubi-utils/ubiformat.c +++ b/ubi-utils/ubiformat.c @@ -633,9 +633,8 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd, write_size, eb); if (errno != EIO) { - if (!args.subpage_size != mtd->min_io_size) - normsg("may be sub-page size is " - "incorrect?"); + if (args.subpage_size != mtd->min_io_size) + normsg("may be sub-page size is incorrect?"); goto out_free; } -- 1.9.3 -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 05:47:40 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 15:47:40 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <20140908111832.GA1676@arch.hh.imgtec.org> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> Message-ID: <1410180460.10764.163.camel@sauron.fi.intel.com> On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: > Regarding -stable, I think it's worth to pull the whole series. I've checked and the patches do not apply to 3.16 with many conflicts. Are you enthusiastic enough to try this and fined out the missing dependencies? The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and also mentioned the commits we depend on in the commit messages. At this point I pushed your patches to the master branch. If you are going to check the stable story, please, use this branch. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Mon Sep 8 05:56:30 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Mon, 08 Sep 2014 15:56:30 +0300 Subject: [PATCH][V2] UBI: block: fix dereference on uninitialized dev In-Reply-To: <1408526378-12972-1-git-send-email-colin.king@canonical.com> References: <1408526378-12972-1-git-send-email-colin.king@canonical.com> Message-ID: <1410180990.10764.164.camel@sauron.fi.intel.com> On Wed, 2014-08-20 at 10:19 +0100, Colin King wrote: > From: Colin Ian King > > commit 4df38926f337 ("UBI: block: Avoid disk size integer overflow") > introduced a dereference on dev (which is not initialized at that > point) when printing a warning message. Re-order disk_capacity check > after the dev is found. > > Found by cppcheck: > [drivers/mtd/ubi/block.c:509]: (error) Uninitialized variable: dev Picked this one, thanks! -- Best Regards, Artem Bityutskiy From ezequiel at vanguardiasur.com.ar Mon Sep 8 07:35:50 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 8 Sep 2014 11:35:50 -0300 Subject: [PATCH v2 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <540D99BC.5040209@ti.com> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-4-git-send-email-ezequiel@vanguardiasur.com.ar> <540D99BC.5040209@ti.com> Message-ID: <20140908143550.GA4306@arch.hh.imgtec.org> On 08 Sep 02:57 PM, Roger Quadros wrote: > Hi Ezequiel, > > On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: > > Usage of pr_err is frowned upon, so replace it with dev_err. > > Aditionally, the message on nand_bch_init() error is redundant, > > since proper error is showed if the function fails. > > > > Signed-off-by: Ezequiel Garcia > > --- > > drivers/mtd/nand/omap2.c | 26 ++++++++++++++------------ > > 1 file changed, 14 insertions(+), 12 deletions(-) > > > > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c > > index f97a4ff..eb5e898 100644 > > --- a/drivers/mtd/nand/omap2.c > > +++ b/drivers/mtd/nand/omap2.c > > @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > > erased_ecc_vec = bch16_vector; > > break; > > default: > > - pr_err("invalid driver configuration\n"); > > + dev_err(&info->pdev->dev, "invalid driver configuration\n"); > > return -EINVAL; > > } > > > > @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > > err = 0; > > for (i = 0; i < eccsteps; i++) { > > if (err_vec[i].error_uncorrectable) { > > - pr_err("nand: uncorrectable bit-flips found\n"); > > + dev_err(&info->pdev->dev, > > + "uncorrectable bit-flips found\n"); > > err = -EBADMSG; > > } else if (err_vec[i].error_reported) { > > for (j = 0; j < err_vec[i].error_count; j++) { > > @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, > > 1 << bit_pos; > > } > > } else { > > - pr_err("invalid bit-flip @ %d:%d\n", > > - byte_pos, bit_pos); > > + dev_err(&info->pdev->dev, > > + "invalid bit-flip @ %d:%d\n", > > + byte_pos, bit_pos); > > err = -EBADMSG; > > } > > } > > @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, > > > > /* check whether elm-id is passed via DT */ > > if (!elm_node) { > > - pr_err("nand: error: ELM DT node not found\n"); > > + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); > > return false; > > } > > pdev = of_find_device_by_node(elm_node); > > /* check whether ELM device is registered */ > > if (!pdev) { > > - pr_err("nand: error: ELM device not found\n"); > > + dev_err(&info->pdev->dev, "ELM device not found\n"); > > return false; > > } > > /* ELM module available, now configure it */ > > @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) > > /* scan NAND device connected to chip controller */ > > nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; > > if (nand_scan_ident(mtd, 1, NULL)) { > > - pr_err("nand device scan failed, may be bus-width mismatch\n"); > > + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); > > err = -ENXIO; > > goto return_error; > > } > > > > /* check for small page devices */ > > if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { > > - pr_err("small page devices are not supported\n"); > > + dev_err(&info->pdev->dev, "small page devices are not supported\n"); > > err = -EINVAL; > > goto return_error; > > } > > @@ -1959,7 +1961,6 @@ static int omap_nand_probe(struct platform_device *pdev) > > nand_chip->ecc.bytes, > > &ecclayout); > > if (!nand_chip->ecc.priv) { > > - pr_err("nand: error: unable to use s/w BCH library\n"); > > Where would the error be printed in this case? > Well, nand_bch_init() has a lot of messages for the errors, but I just noticed some cases where there's no message printed. Would you prefer to leave these untouched? > I also noticed a similar message in the OMAP_ECC_BCH4_CODE_HW_DETECTION_SW case. > And it seems to be missing a "goto return_error" there. > Argh, right. I'll have to resend this one. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From ezequiel.garcia at free-electrons.com Mon Sep 8 11:27:50 2014 From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia) Date: Mon, 8 Sep 2014 15:27:50 -0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1410180460.10764.163.camel@sauron.fi.intel.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> Message-ID: <20140908182750.GA9222@arch.hh.imgtec.org> On 08 Sep 03:47 PM, Artem Bityutskiy wrote: > On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: > > Regarding -stable, I think it's worth to pull the whole series. > > I've checked and the patches do not apply to 3.16 with many conflicts. > Are you enthusiastic enough to try this and fined out the missing > dependencies? > > The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and > also mentioned the commits we depend on in the commit messages. > > At this point I pushed your patches to the master branch. If you are > going to check the stable story, please, use this branch. > Sure, I'll prepare the list of commits and let you know. Meanwhile, it would be very useful to have someone test these patches. Rafa?, do you think you can do some testing? It would be nice to check these fixes are correct, and maybe you can pick them for OpenWRT. -- Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com From rfreire at redhat.com Mon Sep 8 13:04:40 2014 From: rfreire at redhat.com (Rodrigo Freire) Date: Mon, 8 Sep 2014 16:04:40 -0400 (EDT) Subject: [PATCH] block2mtd: mtd: Present block2mtd timely on boot time In-Reply-To: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> Message-ID: <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> From: Felix Fietkau block2mtd: Ensure that block2mtd is presented in a timely fashion Currently, a block MTD device is not presented to the system on time, in order to start mounting the filesystems. This patch ensures that block2mtd is presented at the right time, so filesystems can be mounted on boot time. This issue was seen on BCM2708 (Raspberry Pi) systems when mounting JFFS2 block2mtd filesystems. This patchset also adds a MTD device name and a timeout option to the driver. Original patchset: https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/440-block2mtd_init.patch?rev=40444 https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/441-block2mtd_probe.patch?rev=40444 Signed-off-by: Felix Fietkau Signed-off-by: Rodrigo Freire --- a/drivers/mtd/devices/block2mtd.c 2014-09-05 11:13:39.143698413 -0300 +++ b/drivers/mtd/devices/block2mtd.c 2014-09-05 17:50:28.107366433 -0300 @@ -9,7 +9,15 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* +* When the first attempt at device initialization fails, we may need to +* wait a little bit and retry. This timeout, by default 3 seconds, gives +* device time to start up. Required on BCM2708 and a few other chipsets. +*/ +#define MTD_DEFAULT_TIMEOUT 3 + #include +#include #include #include #include @@ -17,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -209,12 +218,14 @@ static void block2mtd_free_device(struct } -static struct block2mtd_dev *add_device(char *devname, int erase_size) +static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout) { const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev; + struct block_device *bdev = ERR_PTR(-ENODEV); struct block2mtd_dev *dev; + struct mtd_partition *part; char *name; + int i; if (!devname) return NULL; @@ -225,15 +236,28 @@ static struct block2mtd_dev *add_device( /* Get a handle on the device */ bdev = blkdev_get_by_path(devname, mode, dev); -#ifndef MODULE - if (IS_ERR(bdev)) { - /* We might not have rootfs mounted at this point. Try - to resolve the device name by other means. */ - - dev_t devt = name_to_dev_t(devname); - if (devt) - bdev = blkdev_get_by_dev(devt, mode, dev); +#ifndef MODULE +/* +* We might not have the root device mounted at this point. +* Try to resolve the device name by other means. +*/ + for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { + dev_t devt; + + if (i) + /* + * Calling wait_for_device_probe in the first loop + * was not enough, sleep for a bit in subsequent + * go-arounds. + */ + msleep(1000); + wait_for_device_probe(); + + devt = name_to_dev_t(devname); + if (!devt) + continue; + bdev = blkdev_get_by_dev(devt, mode, dev); } #endif @@ -257,13 +281,15 @@ static struct block2mtd_dev *add_device( /* Setup the MTD structure */ /* make the name contain the block device in */ - name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); + if (!mtdname) + mtdname = devname; + name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); if (!name) goto err_destroy_mutex; + strcpy(name, mtdname); dev->mtd.name = name; - - dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; + dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); dev->mtd.erasesize = erase_size; dev->mtd.writesize = 1; dev->mtd.writebufsize = PAGE_SIZE; @@ -276,15 +302,19 @@ static struct block2mtd_dev *add_device( dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; - if (mtd_device_register(&dev->mtd, NULL, 0)) { + part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); + part->name = name; + part->offset = 0; + part->size = dev->mtd.size; + if (mtd_device_register(&dev->mtd, part, 1)) { /* Device didn't get added, so free the entry */ goto err_destroy_mutex; } + list_add(&dev->list, &blkmtd_device_list); pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", dev->mtd.index, - dev->mtd.name + strlen("block2mtd: "), - dev->mtd.erasesize >> 10, dev->mtd.erasesize); + mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); return dev; err_destroy_mutex: @@ -353,11 +383,12 @@ static char block2mtd_paramline[80 + 12] static int block2mtd_setup2(const char *val) { - char buf[80 + 12]; /* 80 for device, 12 for erase size */ + char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ char *str = buf; - char *token[2]; + char *token[4]; char *name; size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { @@ -368,7 +399,7 @@ static int block2mtd_setup2(const char * strcpy(str, val); kill_final_newline(str); - for (i = 0; i < 2; i++) + for (i = 0; i < 4; i++) token[i] = strsep(&str, ","); if (str) { @@ -395,7 +426,13 @@ static int block2mtd_setup2(const char * } } - add_device(name, erase_size); + if (token[2] && (strlen(token[2]) + 1 > 80)) + pr_err("mtd device name too long"); + + + if (token[3] && kstrtoul(token[3], 0, &timeout)) + pr_err("invalid timeout"); + add_device(name, erase_size, token[2], timeout); return 0; } @@ -429,7 +466,7 @@ static int block2mtd_setup(const char *v module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); -MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); +MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); static int __init block2mtd_init(void) { @@ -463,8 +500,7 @@ static void block2mtd_exit(void) } } - -module_init(block2mtd_init); +late_initcall(block2mtd_init); module_exit(block2mtd_exit); MODULE_LICENSE("GPL"); From yamada.m at jp.panasonic.com Mon Sep 8 19:01:55 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:55 +0900 Subject: [PATCH v2 5/7] mtd: denali: remove a set-but-unused variable In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-6-git-send-email-yamada.m@jp.panasonic.com> The variable "retry" in wait_for_irq() is set, but not used. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett --- Changes in v2: None drivers/mtd/nand/denali.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 259ca0ba..d37c2e1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -697,7 +697,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { unsigned long comp_res; uint32_t intr_status; - bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); do { @@ -717,7 +716,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) * need to wait again */ spin_unlock_irq(&denali->irq_lock); - retry = true; } } while (comp_res != 0); -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:54 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:54 +0900 Subject: [PATCH v2 4/7] mtd: denali: change the type of iterators to int In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-5-git-send-email-yamada.m@jp.panasonic.com> We should rathar use "int" type for loop iterators. Signed-off-by: Masahiro Yamada --- Changes in v2: None drivers/mtd/nand/denali.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index dcd6771..259ca0ba 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -178,7 +178,7 @@ static void reset_bank(struct denali_nand_info *denali) /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { - uint32_t i; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); @@ -499,7 +499,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) { uint16_t status = PASS; uint32_t id_bytes[8], addr; - uint8_t i, maf_id, device_id; + uint8_t maf_id, device_id; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", @@ -830,7 +831,8 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * verify that the len is a multiple of 4. @@ -850,7 +852,8 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * we assume that len will be a multiple of 4, if not it would be nice -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:53 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:53 +0900 Subject: [PATCH v2 3/7] mtd: denali: remove unnecessary casts In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-4-git-send-email-yamada.m@jp.panasonic.com> Useless casts result in unreadable source code. Signed-off-by: Masahiro Yamada --- Changes in v2: None drivers/mtd/nand/denali.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3836828..dcd6771 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -423,10 +423,10 @@ static void find_valid_banks(struct denali_nand_info *denali) denali->total_used_banks = 1; for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90); - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0); + index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); + index_addr(denali, MODE_11 | (i << 24) | 1, 0); index_addr_read_data(denali, - (uint32_t)(MODE_11 | (i << 24) | 2), &id[i]); + MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -510,9 +510,9 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) * For some NAND chips, controller can't report the correct * device ID by reading from DEVICE_ID register */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) index_addr_read_data(denali, addr | 2, &id_bytes[i]); maf_id = id_bytes[0]; @@ -782,14 +782,14 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { /* read spare area */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_READ) { /* setup page read request for access type */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); /* * page 33 of the NAND controller spec indicates we should not @@ -800,7 +800,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else { - index_addr(denali, (uint32_t)cmd, + index_addr(denali, cmd, PIPELINE_ACCESS | op | page_count); /* @@ -929,7 +929,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ addr = BANK(denali->flash_bank) | denali->page; cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, MAIN_ACCESS); + index_addr(denali, cmd, MAIN_ACCESS); } } @@ -1035,7 +1035,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) { uint32_t mode; const int page_count = 1; - dma_addr_t addr = denali->buf.dma_buf; + uint32_t addr = denali->buf.dma_buf; mode = MODE_10 | BANK(denali->flash_bank); @@ -1045,10 +1045,10 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) index_addr(denali, mode | denali->page, 0x2000 | op | page_count); /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)(addr >> 16) << 8), 0x2200); + index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); + index_addr(denali, mode | ((addr & 0xff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); @@ -1289,7 +1289,7 @@ static int denali_erase(struct mtd_info *mtd, int page) /* setup page read request for access type */ cmd = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, (uint32_t)cmd, 0x1); + index_addr(denali, cmd, 0x1); /* wait for erase to complete or failure to occur */ irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | @@ -1319,12 +1319,12 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { index_addr_read_data(denali, - (uint32_t)addr | 2, + addr | 2, &id); write_byte_to_buf(denali, id); } -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:56 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:56 +0900 Subject: [PATCH v2 6/7] mtd: denali: remove unnecessary parentheses In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-7-git-send-email-yamada.m@jp.panasonic.com> We should use parentheses only when they are necessary or they really improve the readability. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett --- Changes in v2: None drivers/mtd/nand/denali.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d37c2e1..ed37b76 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -267,10 +267,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, acc_clks = CEIL_DIV(Trea[mode], CLK_X); - while (((acc_clks * CLK_X) - Trea[mode]) < 3) + while (acc_clks * CLK_X - Trea[mode] < 3) acc_clks++; - if ((data_invalid - acc_clks * CLK_X) < 2) + if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", __FILE__, __LINE__); @@ -285,7 +285,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, cs_cnt = 1; if (Tcea[mode]) { - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) + while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) cs_cnt++; } @@ -295,8 +295,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, #endif /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && - (ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) + if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && + ioread32(denali->flash_reg + DEVICE_ID) == 0x88) acc_clks = 6; iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); @@ -577,7 +577,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, */ static inline bool is_flash_bank_valid(int flash_bank) { - return (flash_bank >= 0 && flash_bank < 4); + return flash_bank >= 0 && flash_bank < 4; } static void denali_irq_init(struct denali_nand_info *denali) @@ -1103,7 +1103,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, "timeout on write_page (type = %d)\n", raw_xfer); denali->status = - (irq_status & INTR_STATUS__PROGRAM_FAIL) ? + irq_status & INTR_STATUS__PROGRAM_FAIL ? NAND_STATUS_FAIL : PASS; } @@ -1296,7 +1296,7 @@ static int denali_erase(struct mtd_info *mtd, int page) irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | INTR_STATUS__ERASE_FAIL); - return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:52 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:52 +0900 Subject: [PATCH v2 2/7] mtd: denali: remove unnecessary variable initializations In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-3-git-send-email-yamada.m@jp.panasonic.com> All of these variables are initialized to zero and then set to a different value below. Zero-initializing is redundant. Signed-off-by: Masahiro Yamada --- Changes in v2: None drivers/mtd/nand/denali.c | 59 ++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 44a5f159..3836828 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -146,7 +146,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) /* reads the status of the device */ static void read_status(struct denali_nand_info *denali) { - uint32_t cmd = 0x0; + uint32_t cmd; /* initialize the data buffer to store status */ reset_buf(denali); @@ -161,7 +161,7 @@ static void read_status(struct denali_nand_info *denali) /* resets a specific device connected to the core */ static void reset_bank(struct denali_nand_info *denali) { - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; @@ -581,7 +581,7 @@ static inline bool is_flash_bank_valid(int flash_bank) static void denali_irq_init(struct denali_nand_info *denali) { - uint32_t int_mask = 0; + uint32_t int_mask; int i; /* Disable global interrupts */ @@ -624,7 +624,7 @@ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) static inline void clear_interrupt(struct denali_nand_info *denali, uint32_t irq_mask) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -633,7 +633,8 @@ static inline void clear_interrupt(struct denali_nand_info *denali, static void clear_interrupts(struct denali_nand_info *denali) { - uint32_t status = 0x0; + uint32_t status; + spin_lock_irq(&denali->irq_lock); status = read_interrupt_status(denali); @@ -645,7 +646,7 @@ static void clear_interrupts(struct denali_nand_info *denali) static uint32_t read_interrupt_status(struct denali_nand_info *denali) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -659,7 +660,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) static irqreturn_t denali_isr(int irq, void *dev_id) { struct denali_nand_info *denali = dev_id; - uint32_t irq_status = 0x0; + uint32_t irq_status; irqreturn_t result = IRQ_NONE; spin_lock(&denali->irq_lock); @@ -693,8 +694,8 @@ static irqreturn_t denali_isr(int irq, void *dev_id) static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { - unsigned long comp_res = 0; - uint32_t intr_status = 0; + unsigned long comp_res; + uint32_t intr_status; bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); @@ -736,7 +737,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { - int ecc_en_flag = 0, transfer_spare_flag = 0; + int ecc_en_flag, transfer_spare_flag; /* set ECC, transfer spare bits if needed */ ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; @@ -759,8 +760,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int op) { int status = PASS; - uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, - irq_mask = 0; + uint32_t page_count = 1; + uint32_t addr, cmd, irq_status, irq_mask; if (op == DENALI_READ) irq_mask = INTR_STATUS__LOAD_COMP; @@ -829,7 +830,7 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * verify that the len is a multiple of 4. @@ -849,7 +850,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * we assume that len will be a multiple of 4, if not it would be nice @@ -870,7 +871,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | INTR_STATUS__PROGRAM_FAIL; int status = 0; @@ -899,8 +900,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR_STATUS__LOAD_COMP, - irq_status = 0, addr = 0x0, cmd = 0x0; + uint32_t irq_mask = INTR_STATUS__LOAD_COMP; + uint32_t irq_status, addr, cmd; denali->page = page; @@ -938,7 +939,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ static bool is_erased(uint8_t *buf, int len) { - int i = 0; + int i; for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -961,9 +962,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, if (irq_status & INTR_STATUS__ECC_ERR) { /* read the ECC errors. we'll ignore them for now */ - uint32_t err_address = 0, err_correction_info = 0; - uint32_t err_byte = 0, err_sector = 0, err_device = 0; - uint32_t err_correction_value = 0; + uint32_t err_address, err_correction_info, err_byte, + err_sector, err_device, err_correction_value; denali_set_intr_modes(denali, false); do { @@ -1026,19 +1026,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, /* programs the controller to either enable/disable DMA transfers */ static void denali_enable_dma(struct denali_nand_info *denali, bool en) { - uint32_t reg_val = 0x0; - - if (en) - reg_val = DMA_ENABLE__FLAG; - - iowrite32(reg_val, denali->flash_reg + DMA_ENABLE); + iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); ioread32(denali->flash_reg + DMA_ENABLE); } /* setups the HW to perform the data DMA */ static void denali_setup_dma(struct denali_nand_info *denali, int op) { - uint32_t mode = 0x0; + uint32_t mode; const int page_count = 1; dma_addr_t addr = denali->buf.dma_buf; @@ -1071,7 +1066,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1172,7 +1167,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR; bool check_erased_page = false; @@ -1224,7 +1219,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1288,7 +1283,7 @@ static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t cmd = 0x0, irq_status = 0; + uint32_t cmd, irq_status; clear_interrupts(denali); -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:51 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:51 +0900 Subject: [PATCH v2 1/7] mtd: denali: fix the format of comment blocks In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-2-git-send-email-yamada.m@jp.panasonic.com> We should use /* * Blah Blah ... * ... */ for multi-line comment blocks. In addition, refactor some comments where it seems reasonable and remove some comments where the code is clear enough such as: /* clear interrupts */ clear_interrupts(denali); Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett --- Changes in v2: None drivers/mtd/nand/denali.c | 311 ++++++++++++++++++++++++++++------------------ 1 file changed, 188 insertions(+), 123 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index da0fcc2..44a5f159 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -29,7 +29,8 @@ MODULE_LICENSE("GPL"); -/* We define a module parameter that allows the user to override +/* + * We define a module parameter that allows the user to override * the hardware and decide what timing mode should be used. */ #define NAND_DEFAULT_TIMINGS -1 @@ -41,8 +42,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define DENALI_NAND_NAME "denali-nand" -/* We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. */ +/* + * We define a macro here that combines all interrupts this driver uses into + * a single constant value, for convenience. + */ #define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ INTR_STATUS__ECC_TRANSACTION_DONE | \ INTR_STATUS__ECC_ERR | \ @@ -54,23 +57,30 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." INTR_STATUS__RST_COMP | \ INTR_STATUS__ERASE_COMP) -/* indicates whether or not the internal value for the flash bank is - * valid or not */ +/* + * indicates whether or not the internal value for the flash bank is + * valid or not + */ #define CHIP_SELECT_INVALID -1 #define SUPPORT_8BITECC 1 -/* This macro divides two integers and rounds fractional values up - * to the nearest integer value. */ +/* + * This macro divides two integers and rounds fractional values up + * to the nearest integer value. + */ #define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) -/* this macro allows us to convert from an MTD structure to our own +/* + * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ #define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) -/* These constants are defined by the driver to enable common driver - * configuration options. */ +/* + * These constants are defined by the driver to enable common driver + * configuration options. + */ #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 @@ -84,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define ADDR_CYCLE 1 #define STATUS_CYCLE 2 -/* this is a helper macro that allows us to - * format the bank into the proper bits for the controller */ +/* + * this is a helper macro that allows us to + * format the bank into the proper bits for the controller + */ #define BANK(x) ((x) << 24) /* forward declarations */ @@ -96,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali, uint32_t int_mask); static uint32_t read_interrupt_status(struct denali_nand_info *denali); -/* Certain operations for the denali NAND controller use - * an indexed mode to read/write data. The operation is - * performed by writing the address value of the command - * to the device memory followed by the data. This function +/* + * Certain operations for the denali NAND controller use an indexed mode to + * read/write data. The operation is performed by writing the address value + * of the command to the device memory followed by the data. This function * abstracts this common operation. -*/ + */ static void index_addr(struct denali_nand_info *denali, uint32_t address, uint32_t data) { @@ -117,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali, *pdata = ioread32(denali->flash_mem + 0x10); } -/* We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. */ +/* + * We need to buffer some data for some of the NAND core routines. + * The operations manage buffering that data. + */ static void reset_buf(struct denali_nand_info *denali) { denali->buf.head = denali->buf.tail = 0; @@ -192,7 +206,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) return PASS; } -/* this routine calculates the ONFI timing values for a given mode and +/* + * this routine calculates the ONFI timing values for a given mode and * programs the clocking register accordingly. The mode is determined by * the get_onfi_nand_para routine. */ @@ -298,9 +313,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) { int i; - /* we needn't to do a reset here because driver has already + + /* + * we needn't to do a reset here because driver has already * reset all the banks before - * */ + */ if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & ONFI_TIMING_MODE__VALUE)) return FAIL; @@ -313,8 +330,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) nand_onfi_timing_set(denali, i); - /* By now, all the ONFI devices we know support the page cache */ - /* rw feature. So here we enable the pipeline_rw_ahead feature */ + /* + * By now, all the ONFI devices we know support the page cache + * rw feature. So here we enable the pipeline_rw_ahead feature + */ /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ @@ -340,8 +359,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) { uint32_t tmp; - /* Workaround to fix a controller bug which reports a wrong */ - /* spare area size for some kind of Toshiba NAND device */ + /* + * Workaround to fix a controller bug which reports a wrong + * spare area size for some kind of Toshiba NAND device + */ if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); @@ -391,7 +412,8 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, } } -/* determines how many NAND chips are connected to the controller. Note for +/* + * determines how many NAND chips are connected to the controller. Note for * Intel CE4100 devices we don't support more than one device. */ static void find_valid_banks(struct denali_nand_info *denali) @@ -421,7 +443,8 @@ static void find_valid_banks(struct denali_nand_info *denali) } if (denali->platform == INTEL_CE4100) { - /* Platform limitations of the CE4100 device limit + /* + * Platform limitations of the CE4100 device limit * users to a single chip solution for NAND. * Multichip support is not enabled. */ @@ -449,12 +472,13 @@ static void detect_max_banks(struct denali_nand_info *denali) static void detect_partition_feature(struct denali_nand_info *denali) { - /* For MRST platform, denali->fwblks represent the + /* + * For MRST platform, denali->fwblks represent the * number of blocks firmware is taken, * FW is in protect partition and MTD driver has no * permission to access it. So let driver know how many * blocks it can't touch. - * */ + */ if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { @@ -481,11 +505,11 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - /* Use read id method to get device ID and other - * params. For some NAND chips, controller can't - * report the correct device ID by reading from - * DEVICE_ID register - * */ + /* + * Use read id method to get device ID and other params. + * For some NAND chips, controller can't report the correct + * device ID by reading from DEVICE_ID register + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -524,7 +548,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) detect_partition_feature(denali); - /* If the user specified to override the default timings + /* + * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. */ if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) @@ -545,7 +570,8 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); } -/* validation function to verify that the controlling software is making +/* + * validation function to verify that the controlling software is making * a valid request */ static inline bool is_flash_bank_valid(int flash_bank) @@ -585,7 +611,8 @@ static void denali_irq_enable(struct denali_nand_info *denali, iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); } -/* This function only returns when an interrupt that this driver cares about +/* + * This function only returns when an interrupt that this driver cares about * occurs. This is to reduce the overhead of servicing interrupts */ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) @@ -625,9 +652,9 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) return ioread32(denali->flash_reg + intr_status_reg); } -/* This is the interrupt service routine. It handles all interrupts - * sent to this device. Note that on CE4100, this is a shared - * interrupt. +/* + * This is the interrupt service routine. It handles all interrupts + * sent to this device. Note that on CE4100, this is a shared interrupt. */ static irqreturn_t denali_isr(int irq, void *dev_id) { @@ -637,19 +664,21 @@ static irqreturn_t denali_isr(int irq, void *dev_id) spin_lock(&denali->irq_lock); - /* check to see if a valid NAND chip has - * been selected. - */ + /* check to see if a valid NAND chip has been selected. */ if (is_flash_bank_valid(denali->flash_bank)) { - /* check to see if controller generated - * the interrupt, since this is a shared interrupt */ + /* + * check to see if controller generated the interrupt, + * since this is a shared interrupt + */ irq_status = denali_irq_detected(denali); if (irq_status != 0) { /* handle interrupt */ /* first acknowledge it */ clear_interrupt(denali, irq_status); - /* store the status in the device context for someone - to read */ + /* + * store the status in the device context for someone + * to read + */ denali->irq_status |= irq_status; /* notify anyone who cares that it happened */ complete(&denali->complete); @@ -681,8 +710,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) /* our interrupt was detected */ break; } else { - /* these are not the interrupts you are looking for - - * need to wait again */ + /* + * these are not the interrupts you are looking for - + * need to wait again + */ spin_unlock_irq(&denali->irq_lock); retry = true; } @@ -698,8 +729,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) return intr_status; } -/* This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. */ +/* + * This helper function setups the registers for ECC and whether or not + * the spare area will be transferred. + */ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { @@ -715,7 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, denali->flash_reg + TRANSFER_SPARE_REG); } -/* sends a pipeline command operation to the controller. See the Denali NAND +/* + * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, @@ -737,7 +771,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - /* clear interrupts */ clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; @@ -757,9 +790,10 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); - /* page 33 of the NAND controller spec indicates we should not - use the pipeline commands in Spare area only mode. So we - don't. + /* + * page 33 of the NAND controller spec indicates we should not + * use the pipeline commands in Spare area only mode. + * So we don't. */ if (access_type == SPARE_ACCESS) { cmd = MODE_01 | addr; @@ -768,10 +802,11 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, index_addr(denali, (uint32_t)cmd, PIPELINE_ACCESS | op | page_count); - /* wait for command to be accepted + /* + * wait for command to be accepted * can always use status0 bit as the - * mask is identical for each - * bank. */ + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { @@ -796,8 +831,10 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* verify that the len is a multiple of 4. see comment in - * read_data_from_flash_mem() */ + /* + * verify that the len is a multiple of 4. + * see comment in read_data_from_flash_mem() + */ BUG_ON((len % 4) != 0); /* write the data to the flash memory */ @@ -814,14 +851,12 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* we assume that len will be a multiple of 4, if not - * it would be nice to know about it ASAP rather than - * have random failures... - * This assumption is based on the fact that this - * function is designed to be used to read flash pages, - * which are typically multiples of 4... + /* + * we assume that len will be a multiple of 4, if not it would be nice + * to know about it ASAP rather than have random failures... + * This assumption is based on the fact that this function is designed + * to be used to read flash pages, which are typically multiples of 4. */ - BUG_ON((len % 4) != 0); /* transfer the data from the flash */ @@ -873,16 +908,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) DENALI_READ) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); - /* wait for command to be accepted - * can always use status0 bit as the mask is identical for each - * bank. */ + /* + * wait for command to be accepted + * can always use status0 bit as the + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) dev_err(denali->dev, "page on OOB timeout %d\n", denali->page); - /* We set the device back to MAIN_ACCESS here as I observed + /* + * We set the device back to MAIN_ACCESS here as I observed * instability with the controller if you do a block erase * and the last transaction was a SPARE_ACCESS. Block erase * is reliable (according to the MTD test infrastructure) @@ -894,7 +932,8 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) } } -/* this function examines buffers to see if they contain data that +/* + * this function examines buffers to see if they contain data that * indicate that the buffer is part of an erased region of flash. */ static bool is_erased(uint8_t *buf, int len) @@ -940,13 +979,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_device = ECC_ERR_DEVICE(err_correction_info); if (ECC_ERROR_CORRECTABLE(err_correction_info)) { - /* If err_byte is larger than ECC_SECTOR_SIZE, + /* + * If err_byte is larger than ECC_SECTOR_SIZE, * means error happened in OOB, so we ignore * it. It's no need for us to correct it * err_device is represented the NAND error * bits are happened in if there are more * than one NAND connected. - * */ + */ if (err_byte < ECC_SECTOR_SIZE) { int offset; offset = (err_sector * @@ -960,17 +1000,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, bitflips++; } } else { - /* if the error is not correctable, need to + /* + * if the error is not correctable, need to * look at the page to see if it is an erased * page. if so, then it's not a real ECC error - * */ + */ check_erased_page = true; } } while (!ECC_LAST_ERR(err_correction_info)); - /* Once handle all ecc errors, controller will triger + /* + * Once handle all ecc errors, controller will triger * a ECC_TRANSACTION_DONE interrupt, so here just wait * for a while for this interrupt - * */ + */ while (!(read_interrupt_status(denali) & INTR_STATUS__ECC_TRANSACTION_DONE)) cpu_relax(); @@ -1013,12 +1055,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) /* 3. set memory low address bits 23:8 */ index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); - /* 4. interrupt when complete, burst len = 64 bytes*/ + /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); } -/* writes a page. user specifies type, and this function handles the - * configuration details. */ +/* + * writes a page. user specifies type, and this function handles the + * configuration details. + */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { @@ -1031,8 +1075,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; - /* if it is a raw xfer, we want to disable ecc, and send - * the spare area. + /* + * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc * raw_xfer - transfer spare */ @@ -1075,27 +1119,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, /* NAND core entry points */ -/* this is the callback that the NAND core calls to write a page. Since +/* + * this is the callback that the NAND core calls to write a page. Since * writing a page with ECC or without is similar, all the work is done * by write_page above. - * */ + */ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for regular page writes, we let HW handle all the ECC - * data written to the device. */ + /* + * for regular page writes, we let HW handle all the ECC + * data written to the device. + */ return write_page(mtd, chip, buf, false); } -/* This is the callback that the NAND core calls to write a page without ECC. +/* + * This is the callback that the NAND core calls to write a page without ECC. * raw access is similar to ECC page writes, so all the work is done in the * write_page() function above. */ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for raw page writes, we want to disable ECC and simply write - whatever data is in the buffer. */ + /* + * for raw page writes, we want to disable ECC and simply write + * whatever data is in the buffer. + */ return write_page(mtd, chip, buf, true); } @@ -1240,7 +1290,6 @@ static int denali_erase(struct mtd_info *mtd, int page) uint32_t cmd = 0x0, irq_status = 0; - /* clear interrupts */ clear_interrupts(denali); /* setup page read request for access type */ @@ -1270,10 +1319,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, case NAND_CMD_READID: case NAND_CMD_PARAM: reset_buf(denali); - /*sometimes ManufactureId read from register is not right + /* + * sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand - * */ + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -1333,11 +1383,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) { - /* tell driver how many bit controller will skip before + /* + * tell driver how many bit controller will skip before * writing ECC code in OOB, this register may be already * set by firmware. So we read this value out. * if this value is 0, just let it be. - * */ + */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); @@ -1355,10 +1406,11 @@ static void denali_hw_init(struct denali_nand_info *denali) denali_irq_init(denali); } -/* Althogh controller spec said SLC ECC is forceb to be 4bit, +/* + * Althogh controller spec said SLC ECC is forceb to be 4bit, * but denali controller in MRST only support 15bit and 8bit ECC * correction - * */ + */ #define ECC_8BITS 14 static struct nand_ecclayout nand_8bit_oob = { .eccbytes = 14, @@ -1398,13 +1450,16 @@ static void denali_drv_init(struct denali_nand_info *denali) denali->idx = 0; /* setup interrupt handler */ - /* the completion object will be used to notify - * the callee that the interrupt is done */ + /* + * the completion object will be used to notify + * the callee that the interrupt is done + */ init_completion(&denali->complete); - /* the spinlock will be used to synchronize the ISR - * with any element that might be access shared - * data (interrupt status) */ + /* + * the spinlock will be used to synchronize the ISR with any + * element that might be access shared data (interrupt status) + */ spin_lock_init(&denali->irq_lock); /* indicate that MTD has not selected a valid bank yet */ @@ -1419,7 +1474,8 @@ int denali_init(struct denali_nand_info *denali) int ret; if (denali->platform == INTEL_CE4100) { - /* Due to a silicon limitation, we can only support + /* + * Due to a silicon limitation, we can only support * ONFI timing mode 1 and below. */ if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { @@ -1438,8 +1494,10 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); - /* denali_isr register is done after all the hardware - * initilization is finished*/ + /* + * denali_isr register is done after all the hardware + * initilization is finished + */ if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { pr_err("Spectra: Unable to allocate IRQ\n"); @@ -1458,9 +1516,11 @@ int denali_init(struct denali_nand_info *denali) denali->nand.read_byte = denali_read_byte; denali->nand.waitfunc = denali_waitfunc; - /* scan for NAND devices attached to the controller + /* + * scan for NAND devices attached to the controller * this is the first stage in a two step process to register - * with the nand subsystem */ + * with the nand subsystem + */ if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { ret = -ENXIO; goto failed_req_irq; @@ -1492,10 +1552,10 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* support for multi nand - * MTD known nothing about multi nand, - * so we should tell it the real pagesize - * and anything necessery + /* + * support for multi nand + * MTD known nothing about multi nand, so we should tell it + * the real pagesize and anything necessery */ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); denali->nand.chipsize <<= (denali->devnum - 1); @@ -1511,9 +1571,11 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; denali->bbtskipbytes *= denali->devnum; - /* second stage of the NAND scan + /* + * second stage of the NAND scan * this stage requires information regarding ECC and - * bad block management. */ + * bad block management. + */ /* Bad block management */ denali->nand.bbt_td = &bbt_main_descr; @@ -1524,7 +1586,8 @@ int denali_init(struct denali_nand_info *denali) denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; - /* Denali Controller only support 15bit and 8bit ECC in MRST, + /* + * Denali Controller only support 15bit and 8bit ECC in MRST, * so just let controller do 15bit ECC for MLC and 8bit ECC for * SLC if possible. * */ @@ -1560,18 +1623,20 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - denali->bbtskipbytes; - /* Let driver know the total blocks number and - * how many blocks contained by each nand chip. - * blksperchip will help driver to know how many - * blocks is taken by FW. - * */ + /* + * Let driver know the total blocks number and how many blocks + * contained by each nand chip. blksperchip will help driver to + * know how many blocks is taken by FW. + */ denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; - /* These functions are required by the NAND core framework, otherwise, + /* + * These functions are required by the NAND core framework, otherwise, * the NAND core will assert. However, we don't need them, so we'll stub - * them out. */ + * them out. + */ denali->nand.ecc.calculate = denali_ecc_calculate; denali->nand.ecc.correct = denali_ecc_correct; denali->nand.ecc.hwctl = denali_ecc_hwctl; -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:50 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:50 +0900 Subject: [PATCH v2 0/7] mtd: denali: A collection of trivial coding style fixes Message-ID: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Changes in v2: - Join quotes strings into a single line Masahiro Yamada (7): mtd: denali: fix the format of comment blocks mtd: denali: remove unnecessary variable initializations mtd: denali: remove unnecessary casts mtd: denali: change the type of iterators to int mtd: denali: remove a set-but-unused variable mtd: denali: remove unnecessary parentheses mtd: denali: fix indents and other trivial things drivers/mtd/nand/denali.c | 562 +++++++++++++++++++++++++--------------------- 1 file changed, 303 insertions(+), 259 deletions(-) -- 1.9.1 From yamada.m at jp.panasonic.com Mon Sep 8 19:01:57 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 9 Sep 2014 11:01:57 +0900 Subject: [PATCH v2 7/7] mtd: denali: fix indents and other trivial things In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410228117-14820-8-git-send-email-yamada.m@jp.panasonic.com> - Fix indents - Do not break a line unless it is longer than 80 columns - Do not insert a whitespace before ';' - Use whitespaces around operators - Use braces for a "else" block where the "if" block uses ones. Besides, eliminate all the warnings reported by checkpatch.pl: - WARNING: quoted string split across lines - WARNING: else is not generally useful after a break or return - WARNING: Missing a blank line after declarations - WARNING: Avoid line continuations in quoted strings Signed-off-by: Masahiro Yamada --- Changes in v2: - Join quotes strings into a single line drivers/mtd/nand/denali.c | 143 ++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 80 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ed37b76..9da5432 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -37,8 +37,8 @@ MODULE_LICENSE("GPL"); static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; module_param(onfi_timing_mode, int, S_IRUGO); -MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." - " -1 indicates use default timings"); +MODULE_PARM_DESC(onfi_timing_mode, + "Overrides default ONFI setting. -1 indicates use default timings"); #define DENALI_NAND_NAME "denali-nand" @@ -162,8 +162,7 @@ static void read_status(struct denali_nand_info *denali) static void reset_bank(struct denali_nand_info *denali) { uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__RST_COMP | - INTR_STATUS__TIME_OUT; + uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; clear_interrupts(denali); @@ -181,16 +180,15 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); - for (i = 0 ; i < denali->max_banks; i++) + for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, denali->flash_reg + INTR_STATUS(i)); - for (i = 0 ; i < denali->max_banks; i++) { + for (i = 0; i < denali->max_banks; i++) { iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + - INTR_STATUS(i)) & + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) cpu_relax(); if (ioread32(denali->flash_reg + INTR_STATUS(i)) & @@ -201,7 +199,7 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + denali->flash_reg + INTR_STATUS(i)); return PASS; } @@ -235,7 +233,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); en_lo = CEIL_DIV(Trp[mode], CLK_X); en_hi = CEIL_DIV(Treh[mode], CLK_X); @@ -255,9 +253,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - data_invalid = - data_invalid_rhoh < - data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh; + data_invalid = data_invalid_rhoh < data_invalid_rloh ? + data_invalid_rhoh : data_invalid_rloh; dv_window = data_invalid - Trea[mode]; @@ -272,7 +269,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); + __FILE__, __LINE__); addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); re_2_we = CEIL_DIV(Trhw[mode], CLK_X); @@ -406,9 +403,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, break; default: dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." - "Will use default parameter values instead.\n", - device_id); + "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" + "Will use default parameter values instead.\n", + device_id); } } @@ -425,8 +422,7 @@ static void find_valid_banks(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) { index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, - MODE_11 | (i << 24) | 2, &id[i]); + index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -450,8 +446,7 @@ static void find_valid_banks(struct denali_nand_info *denali) */ if (denali->total_used_banks != 1) { dev_err(denali->dev, - "Sorry, Intel CE4100 only supports " - "a single NAND device.\n"); + "Sorry, Intel CE4100 only supports a single NAND device.\n"); BUG(); } } @@ -489,10 +484,12 @@ static void detect_partition_feature(struct denali_nand_info *denali) + (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & MIN_BLK_ADDR__VALUE); - } else + } else { denali->fwblks = SPECTRA_START_BLOCK; - } else + } + } else { denali->fwblks = SPECTRA_START_BLOCK; + } } static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) @@ -502,8 +499,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) uint8_t maf_id, device_id; int i; - dev_dbg(denali->dev, - "%s, Line %d, Function: %s\n", + dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); /* @@ -532,7 +528,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) } dev_info(denali->dev, - "Dump timing register values:" + "Dump timing register values:\n" "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", @@ -563,7 +559,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); if (INT_ENABLE) iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); @@ -710,13 +706,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) spin_unlock_irq(&denali->irq_lock); /* our interrupt was detected */ break; - } else { - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); } + + /* + * these are not the interrupts you are looking for - + * need to wait again + */ + spin_unlock_irq(&denali->irq_lock); } while (comp_res != 0); if (comp_res == 0) { @@ -744,8 +740,7 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, /* Enable spare area/ECC per user's request. */ iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, - denali->flash_reg + TRANSFER_SPARE_REG); + iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } /* @@ -753,10 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, - bool ecc_en, - bool transfer_spare, - int access_type, - int op) + bool ecc_en, bool transfer_spare, + int access_type, int op) { int status = PASS; uint32_t page_count = 1; @@ -811,9 +804,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, if (irq_status == 0) { dev_err(denali->dev, - "cmd, page, addr on timeout " - "(0x%x, 0x%x, 0x%x)\n", - cmd, denali->page, addr); + "cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n", + cmd, denali->page, addr); status = FAIL; } else { cmd = MODE_01 | addr; @@ -826,8 +818,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, - const uint8_t *buf, - int len) + const uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -842,13 +833,12 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) iowrite32(*buf32++, denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* helper function that simply reads a buffer from the flash */ static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, - int len) + uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -865,7 +855,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) *buf32++ = ioread32(denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* writes OOB data to the device */ @@ -941,6 +931,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static bool is_erased(uint8_t *buf, int len) { int i; + for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -990,6 +981,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, */ if (err_byte < ECC_SECTOR_SIZE) { int offset; + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * @@ -1063,10 +1055,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1099,12 +1089,10 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { - dev_err(denali->dev, - "timeout on write_page (type = %d)\n", - raw_xfer); - denali->status = - irq_status & INTR_STATUS__PROGRAM_FAIL ? - NAND_STATUS_FAIL : PASS; + dev_err(denali->dev, "timeout on write_page (type = %d)\n", + raw_xfer); + denali->status = irq_status & INTR_STATUS__PROGRAM_FAIL ? + NAND_STATUS_FAIL : PASS; } denali_enable_dma(denali, false); @@ -1174,9 +1162,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, bool check_erased_page = false; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1216,17 +1204,15 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1275,6 +1261,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); int status = denali->status; + denali->status = 0; return status; @@ -1324,9 +1311,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, index_addr(denali, addr | 0, 0x90); index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { - index_addr_read_data(denali, - addr | 2, - &id); + index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } break; @@ -1351,8 +1336,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc_code) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_calculate called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n"); BUG(); return -EIO; } @@ -1361,8 +1346,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, uint8_t *read_ecc, uint8_t *calc_ecc) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_correct called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n"); BUG(); return -EIO; } @@ -1370,8 +1355,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_hwctl called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n"); BUG(); } /* end NAND core entry points */ @@ -1599,8 +1584,7 @@ int denali_init(struct denali_nand_info *denali) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to \ - contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1624,8 +1608,7 @@ int denali_init(struct denali_nand_info *denali) * contained by each nand chip. blksperchip will help driver to * know how many blocks is taken by FW. */ - denali->totalblks = denali->mtd.size >> - denali->nand.phys_erase_shift; + denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; /* @@ -1672,7 +1655,7 @@ void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, - denali->mtd.writesize + denali->mtd.oobsize, - DMA_BIDIRECTIONAL); + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); -- 1.9.1 From annulen at yandex.ru Tue Sep 9 01:23:57 2014 From: annulen at yandex.ru (Konstantin Tokarev) Date: Tue, 09 Sep 2014 12:23:57 +0400 Subject: Question about ubiformat and how to better use UBIFS In-Reply-To: References: Message-ID: <3666331410251037@web21h.yandex.ru> 04.09.2014, 16:21, "t kevin" : > Hi , > > Currently I'm trying to create ubifs for rootfs on my device which has > a Nand flash on board. > > Right now I know two approaches to do that. > 1. On host,mkfs.ubifs+ubinize to generate one ubi.img. On target > board, ubiformat -f ubi.img on the MTD device, ubiattach then mount > and it's done. > or > 2. On host, just tar -cz rootfs to generate root.tgz. On target board, > (for the first time)ubiformat the mtd device, ubiattach,ubimkvol, then > mount ubifs. Then untar the root.tgz to the mounted ubi volume. > > Eventually the mountpoint should contain same files. > > So here are my questions. > 1. (Generally speaking) Which one is better? I know ubiformat is going > to erase every PEB ?so right now I prefer the second approach since I > don't have to do ubiformat everytime. It sounds like the erase counter > grows slower. > > 2. I'm working on an embedded device which has limited CPU power so > I'd like to use compressed_method=none. It can be done by passing -x > none to mkfs.ubifs. But I don't see similar option in ubiformat or > ubimkvol. So when I go to the 2nd approach the mounted rootfs is > always compressed. > http://www.linux-mtd.infradead.org/faq/ubifs.html#L_comproff > This method is not helping much. I want to disable compression on the > entire fs, just like mkfs.ubifs -x none did. > Why do you want to do ubiformat everytime? You can prepare UBIFS image with mkfs.ubifs and flash it with ubiupdatevol to existing UBI volume. -- Regards, Konstantin From rogerq at ti.com Tue Sep 9 01:33:14 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 9 Sep 2014 11:33:14 +0300 Subject: [PATCH v2 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <20140908143550.GA4306@arch.hh.imgtec.org> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-4-git-send-email-ezequiel@vanguardiasur.com.ar> <540D99BC.5040209@ti.com> <20140908143550.GA4306@arch.hh.imgtec.org> Message-ID: <540EBB4A.7050709@ti.com> On 09/08/2014 05:35 PM, Ezequiel Garcia wrote: > On 08 Sep 02:57 PM, Roger Quadros wrote: >> Hi Ezequiel, >> >> On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: >>> Usage of pr_err is frowned upon, so replace it with dev_err. >>> Aditionally, the message on nand_bch_init() error is redundant, >>> since proper error is showed if the function fails. >>> >>> Signed-off-by: Ezequiel Garcia >>> --- >>> drivers/mtd/nand/omap2.c | 26 ++++++++++++++------------ >>> 1 file changed, 14 insertions(+), 12 deletions(-) >>> >>> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c >>> index f97a4ff..eb5e898 100644 >>> --- a/drivers/mtd/nand/omap2.c >>> +++ b/drivers/mtd/nand/omap2.c >>> @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, >>> erased_ecc_vec = bch16_vector; >>> break; >>> default: >>> - pr_err("invalid driver configuration\n"); >>> + dev_err(&info->pdev->dev, "invalid driver configuration\n"); >>> return -EINVAL; >>> } >>> >>> @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, >>> err = 0; >>> for (i = 0; i < eccsteps; i++) { >>> if (err_vec[i].error_uncorrectable) { >>> - pr_err("nand: uncorrectable bit-flips found\n"); >>> + dev_err(&info->pdev->dev, >>> + "uncorrectable bit-flips found\n"); >>> err = -EBADMSG; >>> } else if (err_vec[i].error_reported) { >>> for (j = 0; j < err_vec[i].error_count; j++) { >>> @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, >>> 1 << bit_pos; >>> } >>> } else { >>> - pr_err("invalid bit-flip @ %d:%d\n", >>> - byte_pos, bit_pos); >>> + dev_err(&info->pdev->dev, >>> + "invalid bit-flip @ %d:%d\n", >>> + byte_pos, bit_pos); >>> err = -EBADMSG; >>> } >>> } >>> @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, >>> >>> /* check whether elm-id is passed via DT */ >>> if (!elm_node) { >>> - pr_err("nand: error: ELM DT node not found\n"); >>> + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); >>> return false; >>> } >>> pdev = of_find_device_by_node(elm_node); >>> /* check whether ELM device is registered */ >>> if (!pdev) { >>> - pr_err("nand: error: ELM device not found\n"); >>> + dev_err(&info->pdev->dev, "ELM device not found\n"); >>> return false; >>> } >>> /* ELM module available, now configure it */ >>> @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) >>> /* scan NAND device connected to chip controller */ >>> nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; >>> if (nand_scan_ident(mtd, 1, NULL)) { >>> - pr_err("nand device scan failed, may be bus-width mismatch\n"); >>> + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); >>> err = -ENXIO; >>> goto return_error; >>> } >>> >>> /* check for small page devices */ >>> if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { >>> - pr_err("small page devices are not supported\n"); >>> + dev_err(&info->pdev->dev, "small page devices are not supported\n"); >>> err = -EINVAL; >>> goto return_error; >>> } >>> @@ -1959,7 +1961,6 @@ static int omap_nand_probe(struct platform_device *pdev) >>> nand_chip->ecc.bytes, >>> &ecclayout); >>> if (!nand_chip->ecc.priv) { >>> - pr_err("nand: error: unable to use s/w BCH library\n"); >> >> Where would the error be printed in this case? >> > > Well, nand_bch_init() has a lot of messages for the errors, but I just noticed > some cases where there's no message printed. Would you prefer to leave these > untouched? Yes, let's leave these messages here to tackle the cases where error messages aren't printed in nand_bch_init(). > >> I also noticed a similar message in the OMAP_ECC_BCH4_CODE_HW_DETECTION_SW case. >> And it seems to be missing a "goto return_error" there. >> > > Argh, right. I'll have to resend this one. > cheers, -roger From rogerq at ti.com Tue Sep 9 01:35:56 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 9 Sep 2014 11:35:56 +0300 Subject: [PATCH v2 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <1410175636-4036-2-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-2-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <540EBBEC.0@ti.com> Ezequiel, On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: > This commit adds a new platform-data boolean property that enables use > of a flash-based bad block table. This can also be enabled by setting > the 'nand-on-flash-bbt' devicetree property. I'm not much aware of how on-flash-BBT works internally, but will it break things if we keep on-flash-BBT "enabled" as the default option and add a DT property only to explicitly disable the on-flash-BBT? > > If the flash BBT is not enabled, the driver falls back to use OOB > bad block markers only, as before. If the flash BBT is enabled the > kernel will keep track of bad blocks using a BBT, in addition to > the OOB markers. > > As explained by Brian Norris the reasons for using a BBT are: > > "" > The primary reason would be that NAND datasheets specify it these days. > A better argument is that nobody guarantees that you can write a > bad block marker to a worn out block; you may just get program failures. > > This has been acknowledged by several developers over the last several > years. > > Additionally, you get a boot-time performance improvement if you only > have to read a few pages, instead of a page or two from every block on > the flash. > "" cheers, -roger > > Signed-off-by: Ezequiel Garcia > --- > arch/arm/mach-omap2/gpmc.c | 2 ++ > drivers/mtd/nand/omap2.c | 6 +++++- > include/linux/platform_data/mtd-nand-omap2.h | 1 + > 3 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c > index 2f97228..b55a225 100644 > --- a/arch/arm/mach-omap2/gpmc.c > +++ b/arch/arm/mach-omap2/gpmc.c > @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, > break; > } > > + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); > + > val = of_get_nand_bus_width(child); > if (val == 16) > gpmc_nand_data->devsize = NAND_BUSWIDTH_16; > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c > index 5967b38..e1a9b31 100644 > --- a/drivers/mtd/nand/omap2.c > +++ b/drivers/mtd/nand/omap2.c > @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) > mtd->owner = THIS_MODULE; > nand_chip = &info->nand; > nand_chip->ecc.priv = NULL; > - nand_chip->options |= NAND_SKIP_BBTSCAN; > > res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); > @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) > nand_chip->chip_delay = 50; > } > > + if (pdata->flash_bbt) > + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; > + else > + nand_chip->options |= NAND_SKIP_BBTSCAN; > + > /* scan NAND device connected to chip controller */ > nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; > if (nand_scan_ident(mtd, 1, NULL)) { > diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h > index 16ec262..090bbab 100644 > --- a/include/linux/platform_data/mtd-nand-omap2.h > +++ b/include/linux/platform_data/mtd-nand-omap2.h > @@ -71,6 +71,7 @@ struct omap_nand_platform_data { > struct mtd_partition *parts; > int nr_parts; > bool dev_ready; > + bool flash_bbt; > enum nand_io xfer_type; > int devsize; > enum omap_ecc ecc_opt; > From richard.genoud at gmail.com Tue Sep 9 05:25:01 2014 From: richard.genoud at gmail.com (Richard Genoud) Date: Tue, 9 Sep 2014 14:25:01 +0200 Subject: [PATCH] UBI: add missing kmem_cache_free() in process_pool_aeb error path Message-ID: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> I ran into this error after a ubiupdatevol, because I forgot to backport e9110361a9a4 UBI: fix the volumes tree sorting criteria. UBI error: process_pool_aeb: orphaned volume in fastmap pool UBI error: ubi_scan_fastmap: Attach by fastmap failed, doing a full scan! kmem_cache_destroy ubi_ainf_peb_slab: Slab cache still has objects CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.18-00053-gf05cac8dbf85 #1 [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (destroy_ai+0x230/0x244) [] (destroy_ai) from [] (ubi_attach+0x98/0x1ec) [] (ubi_attach) from [] (ubi_attach_mtd_dev+0x2b8/0x868) [] (ubi_attach_mtd_dev) from [] (ubi_init+0x1dc/0x2ac) [] (ubi_init) from [] (do_one_initcall+0x94/0x140) [] (do_one_initcall) from [] (kernel_init_freeable+0xe8/0x1b0) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) UBI: scanning is finished Freeing the cache in the error path fixes the Slab error. Tested on at91sam9g35 (3.14.18+fastmap backports) Signed-off-by: Richard Genoud Cc: stable # >= 3.10 --- drivers/mtd/ubi/fastmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 0431b46d9fd9..c701369090fb 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -330,6 +330,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, av = tmp_av; else { ubi_err("orphaned volume in fastmap pool!"); + kmem_cache_free(ai->aeb_slab_cache, new_aeb); return UBI_BAD_FASTMAP; } -- 2.0.0 From ezequiel at vanguardiasur.com.ar Tue Sep 9 06:27:08 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Tue, 9 Sep 2014 10:27:08 -0300 Subject: [PATCH v2 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <540EBBEC.0@ti.com> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-2-git-send-email-ezequiel@vanguardiasur.com.ar> <540EBBEC.0@ti.com> Message-ID: <20140909132708.GA3315@arch.hh.imgtec.org> On 09 Sep 11:35 AM, Roger Quadros wrote: > Ezequiel, > > On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: > > This commit adds a new platform-data boolean property that enables use > > of a flash-based bad block table. This can also be enabled by setting > > the 'nand-on-flash-bbt' devicetree property. > > I'm not much aware of how on-flash-BBT works internally, but will it break things if > we keep on-flash-BBT "enabled" as the default option and add a DT property only to > explicitly disable the on-flash-BBT? > No, that wouldn't work because the DT property already exists and it works to enable the flash BBT when it's present. Documentation/devicetree/bindings/mtd/nand.txt Of course, we can add a new no-nand-on-flash-bbt, but I really don't see the point. Users can just put the property in all the devicetree board files where it's needed. And moreover, I don't want to change the default behavior of the driver; it's better to allow to *add* a new feature, if such feature is desired. Otherwise, users with some data in a flash's last blocks would be wiped and replaced with the BBT. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From rogerq at ti.com Tue Sep 9 06:33:21 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 9 Sep 2014 16:33:21 +0300 Subject: [PATCH v2 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <20140909132708.GA3315@arch.hh.imgtec.org> References: <1410175636-4036-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410175636-4036-2-git-send-email-ezequiel@vanguardiasur.com.ar> <540EBBEC.0@ti.com> <20140909132708.GA3315@arch.hh.imgtec.org> Message-ID: <540F01A1.3050903@ti.com> On 09/09/2014 04:27 PM, Ezequiel Garcia wrote: > On 09 Sep 11:35 AM, Roger Quadros wrote: >> Ezequiel, >> >> On 09/08/2014 02:27 PM, Ezequiel Garcia wrote: >>> This commit adds a new platform-data boolean property that enables use >>> of a flash-based bad block table. This can also be enabled by setting >>> the 'nand-on-flash-bbt' devicetree property. >> >> I'm not much aware of how on-flash-BBT works internally, but will it break things if >> we keep on-flash-BBT "enabled" as the default option and add a DT property only to >> explicitly disable the on-flash-BBT? >> > > No, that wouldn't work because the DT property already exists and it works to > enable the flash BBT when it's present. > > Documentation/devicetree/bindings/mtd/nand.txt > > Of course, we can add a new no-nand-on-flash-bbt, but I really don't see the > point. Users can just put the property in all the devicetree board files where > it's needed. > > And moreover, I don't want to change the default behavior of the driver; it's > better to allow to *add* a new feature, if such feature is desired. > Otherwise, users with some data in a flash's last blocks would be wiped and > replaced with the BBT. > OK. Let's stick with your patch then. cheers, -roger From jason at lakedaemon.net Tue Sep 9 08:53:34 2014 From: jason at lakedaemon.net (Jason Cooper) Date: Tue, 9 Sep 2014 11:53:34 -0400 Subject: [PATCH 0/2] ARM: mvebu: Use Hardware BCH ECC for RN104 and RN2120 In-Reply-To: References: Message-ID: <20140909155334.GO30828@titan.lakedaemon.net> On Sat, Sep 06, 2014 at 10:48:44PM +0200, Arnaud Ebalard wrote: > Hi, > > Following Ben's report and fix for RN102, I did some tests > on RN104 and RN2120 (they have the same Hynix H27U1G8F2BTR > flash and setup) and came up w/ the exact same fixes for > their respective .dts files. With those patches, it is now > possible to update kernel from userland and u-boot will > happily load and boot it on those devices. > > Both patches should be candidates for stable, I guess. > > Cheers, > > a+ > > Arnaud Ebalard (2): > ARM: mvebu: Netgear RN104: Use Hardware BCH ECC > ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC > > arch/arm/boot/dts/armada-370-netgear-rn104.dts | 4 ++++ > arch/arm/boot/dts/armada-xp-netgear-rn2120.dts | 4 ++++ > 2 files changed, 8 insertions(+) I've applied both patches to mvebu/fixes and flagged them for stable, v3.14+. I removed the 'Depends' line from each, as Thomas mentioned, there is no build dependency between these dts changes and the code supporting it (as it should be). thx, Jason. From joern at logfs.org Tue Sep 9 10:02:31 2014 From: joern at logfs.org (=?utf-8?B?SsO2cm4=?= Engel) Date: Tue, 9 Sep 2014 13:02:31 -0400 Subject: [PATCH] block2mtd: mtd: Present block2mtd timely on boot time In-Reply-To: <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> References: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> Message-ID: <20140909170231.GA14429@logfs.org> On Mon, 8 September 2014 16:04:40 -0400, Rodrigo Freire wrote: > > From: Felix Fietkau > > block2mtd: Ensure that block2mtd is presented in a timely fashion > > Currently, a block MTD device is not presented to the system on time, in > order to start mounting the filesystems. This patch ensures that block2mtd > is presented at the right time, so filesystems can be mounted on boot time. > This issue was seen on BCM2708 (Raspberry Pi) systems when mounting JFFS2 > block2mtd filesystems. > This patchset also adds a MTD device name and a timeout option to the driver. Looks fine once the comments below are addressed. > Original patchset: > https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/440-block2mtd_init.patch?rev=40444 > https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/441-block2mtd_probe.patch?rev=40444 > > Signed-off-by: Felix Fietkau > Signed-off-by: Rodrigo Freire > > --- a/drivers/mtd/devices/block2mtd.c 2014-09-05 11:13:39.143698413 -0300 > +++ b/drivers/mtd/devices/block2mtd.c 2014-09-05 17:50:28.107366433 -0300 > @@ -9,7 +9,15 @@ > > #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > +/* > +* When the first attempt at device initialization fails, we may need to > +* wait a little bit and retry. This timeout, by default 3 seconds, gives > +* device time to start up. Required on BCM2708 and a few other chipsets. > +*/ > +#define MTD_DEFAULT_TIMEOUT 3 > + > #include > +#include > #include > #include > #include > @@ -17,6 +25,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -209,12 +218,14 @@ static void block2mtd_free_device(struct > } > > > -static struct block2mtd_dev *add_device(char *devname, int erase_size) > +static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout) > { > const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; > - struct block_device *bdev; > + struct block_device *bdev = ERR_PTR(-ENODEV); > struct block2mtd_dev *dev; > + struct mtd_partition *part; > char *name; > + int i; > > if (!devname) > return NULL; > @@ -225,15 +236,28 @@ static struct block2mtd_dev *add_device( > > /* Get a handle on the device */ > bdev = blkdev_get_by_path(devname, mode, dev); > -#ifndef MODULE > - if (IS_ERR(bdev)) { > > - /* We might not have rootfs mounted at this point. Try > - to resolve the device name by other means. */ > - > - dev_t devt = name_to_dev_t(devname); > - if (devt) > - bdev = blkdev_get_by_dev(devt, mode, dev); > +#ifndef MODULE > +/* > +* We might not have the root device mounted at this point. > +* Try to resolve the device name by other means. > +*/ > + for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { > + dev_t devt; > + > + if (i) > + /* > + * Calling wait_for_device_probe in the first loop > + * was not enough, sleep for a bit in subsequent > + * go-arounds. > + */ > + msleep(1000); > + wait_for_device_probe(); > + > + devt = name_to_dev_t(devname); > + if (!devt) > + continue; > + bdev = blkdev_get_by_dev(devt, mode, dev); > } > #endif > > @@ -257,13 +281,15 @@ static struct block2mtd_dev *add_device( > > /* Setup the MTD structure */ > /* make the name contain the block device in */ > - name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); > + if (!mtdname) > + mtdname = devname; > + name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); > if (!name) > goto err_destroy_mutex; > > + strcpy(name, mtdname); kstrdup. And see below for the ABI change. > dev->mtd.name = name; > - > - dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; > + dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); PAGE_MASK is no longer needed with the new term. Or does anyone seriously want to support erase_size < PAGE_SIZE? > dev->mtd.erasesize = erase_size; > dev->mtd.writesize = 1; > dev->mtd.writebufsize = PAGE_SIZE; > @@ -276,15 +302,19 @@ static struct block2mtd_dev *add_device( > dev->mtd.priv = dev; > dev->mtd.owner = THIS_MODULE; > > - if (mtd_device_register(&dev->mtd, NULL, 0)) { > + part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); > + part->name = name; > + part->offset = 0; > + part->size = dev->mtd.size; > + if (mtd_device_register(&dev->mtd, part, 1)) { > /* Device didn't get added, so free the entry */ > goto err_destroy_mutex; > } > + > list_add(&dev->list, &blkmtd_device_list); > pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", > dev->mtd.index, > - dev->mtd.name + strlen("block2mtd: "), > - dev->mtd.erasesize >> 10, dev->mtd.erasesize); > + mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); > return dev; > > err_destroy_mutex: > @@ -353,11 +383,12 @@ static char block2mtd_paramline[80 + 12] > > static int block2mtd_setup2(const char *val) > { > - char buf[80 + 12]; /* 80 for device, 12 for erase size */ > + char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ > char *str = buf; > - char *token[2]; > + char *token[4]; > char *name; > size_t erase_size = PAGE_SIZE; > + unsigned long timeout = MTD_DEFAULT_TIMEOUT; > int i, ret; > > if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { > @@ -368,7 +399,7 @@ static int block2mtd_setup2(const char * > strcpy(str, val); > kill_final_newline(str); > > - for (i = 0; i < 2; i++) > + for (i = 0; i < 4; i++) > token[i] = strsep(&str, ","); > > if (str) { > @@ -395,7 +426,13 @@ static int block2mtd_setup2(const char * > } > } > > - add_device(name, erase_size); > + if (token[2] && (strlen(token[2]) + 1 > 80)) > + pr_err("mtd device name too long"); Timeout has a default value, but name defaults to NULL. Add three devices without specifying the name and you get funny results. If we handled the NULL case by doing what the driver used to do before this patch, I think this would be fine. > + > + if (token[3] && kstrtoul(token[3], 0, &timeout)) > + pr_err("invalid timeout"); > + add_device(name, erase_size, token[2], timeout); > > return 0; > } > @@ -429,7 +466,7 @@ static int block2mtd_setup(const char *v > > > module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); > -MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); > +MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); > > static int __init block2mtd_init(void) > { > @@ -463,8 +500,7 @@ static void block2mtd_exit(void) > } > } > > - > -module_init(block2mtd_init); > +late_initcall(block2mtd_init); > module_exit(block2mtd_exit); > > MODULE_LICENSE("GPL"); J?rn -- Most compromises I've seen have been have been a result of gross stupidity, not incredible technical skill on the part of the attacker. -- pr0f From richard at nod.at Tue Sep 9 14:43:55 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 09 Sep 2014 23:43:55 +0200 Subject: [PATCH] UBI: add missing kmem_cache_free() in process_pool_aeb error path In-Reply-To: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> References: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> Message-ID: <540F749B.6080607@nod.at> Am 09.09.2014 14:25, schrieb Richard Genoud: > I ran into this error after a ubiupdatevol, because I forgot to backport > e9110361a9a4 UBI: fix the volumes tree sorting criteria. > > UBI error: process_pool_aeb: orphaned volume in fastmap pool > UBI error: ubi_scan_fastmap: Attach by fastmap failed, doing a full scan! > kmem_cache_destroy ubi_ainf_peb_slab: Slab cache still has objects > CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.18-00053-gf05cac8dbf85 #1 > [] (unwind_backtrace) from [] (show_stack+0x10/0x14) > [] (show_stack) from [] (destroy_ai+0x230/0x244) > [] (destroy_ai) from [] (ubi_attach+0x98/0x1ec) > [] (ubi_attach) from [] (ubi_attach_mtd_dev+0x2b8/0x868) > [] (ubi_attach_mtd_dev) from [] (ubi_init+0x1dc/0x2ac) > [] (ubi_init) from [] (do_one_initcall+0x94/0x140) > [] (do_one_initcall) from [] (kernel_init_freeable+0xe8/0x1b0) > [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) > [] (kernel_init) from [] (ret_from_fork+0x14/0x24) > UBI: scanning is finished > > Freeing the cache in the error path fixes the Slab error. > > Tested on at91sam9g35 (3.14.18+fastmap backports) > > Signed-off-by: Richard Genoud > Cc: stable # >= 3.10 I guess you wrote 3.10 because there is no stable kernel between >= 3.7 and < 3.10? Patch looks good otherwise. Acked-by: Richard Weinberger Thanks, //richard From danielmentz at google.com Tue Sep 9 16:25:28 2014 From: danielmentz at google.com (Daniel Mentz) Date: Tue, 9 Sep 2014 16:25:28 -0700 Subject: ubifs_dump_node must bounds check ubifs_ch->len In-Reply-To: <1410173401.10764.145.camel@sauron.fi.intel.com> References: <1410173401.10764.145.camel@sauron.fi.intel.com> Message-ID: On Mon, Sep 8, 2014 at 3:50 AM, Artem Bityutskiy wrote: > On Thu, 2014-08-28 at 15:37 -0700, Daniel Mentz wrote: >> I believe that ubifs_dump_node() must bounds check ch->len in the >> UBIFS_DATA_NODE case. It currently does not which resulted in a crash >> on a system. See below. > Will I feel lucky asking you whether you was going to send a patch? :-) Thanks for your comments. Yes I'm working on a patch, but I'm not sure when it's going to be ready. From computersforpeace at gmail.com Tue Sep 9 23:00:04 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Tue, 9 Sep 2014 23:00:04 -0700 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: References: <1409673299.14324.43.camel@dagon.hellion.org.uk> <1409796689.27524.34.camel@decadent.org.uk> Message-ID: <20140910060004.GA5732@norris-Latitude-E6410> On Thu, Sep 04, 2014 at 09:02:04AM +0200, Geert Uytterhoeven wrote: > On Thu, Sep 4, 2014 at 4:11 AM, Ben Hutchings wrote: > >> I noticed that many platforms declare the flash chip as compatible = > >> "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried > >> changing that and it didn't help. In any case without spi-nor.ko being > >> autoloaded I don't support m25p80.ko ever would be. > > > > m25p80.c has: > > > > static struct spi_driver m25p80_driver = { > > ... > > .id_table = spi_nor_ids, > > ... > > }; > > > > while spi_nor_ids is defined in spi-nor.c. Since they end up as two > > separate modules, modpost can't read the ID table and add the device ID > > aliases to m25p80.ko. > > Woops. This indeed doesn't work. > Note that the MODULE_DEVICE_TABLE() is also gone from m25p80.c > > So m25p80.c needs to contain the IDs, while spi-nor.c also needs the IDs > because it's a framework/library. Actually, m25p80.c only needs the strings (i.e., the named aliases -- character data), and for the most part, spi-nor.c only needs the IDs (i.e., the identification bytes). What's more, I don't think that any modern SPI NOR user really needs to be specifying exactly which SPI device it is via a specific string. Our driver code pretty much always re-detects the device by reading its device ID. All the SPI NOR code needs to know is how to read its ID. > A quick solution would be to move the ID table to a header file, and include > that by both, and re-add the lost MODULE_DEVICE_TABLE() to m25p80.c. > That duplicates the data, though. > > Hmm, for the built-in case, we can avoid the duplication by letting m25p80.c > refer to the table in spi-nor.c if !MODULE. > Does anyone see a better solution? A little bit of a shot in the dark, as I haven't fleshed this one out: Would it work to just copy the SPI ID strings into m25p80.c, keep the full table in spi-nor.c, stop adding SPI ID string (and DT) bindings to the m25p80 table (force platforms to use "m25p80"-compatible probing, or maybe something generic like "spi-nor-rdid", "spi-nor-sfdp", etc.) and eventually kill the strings from spi-nor.c entirely? I really don't want to propagate string-binding much further into the SPI NOR library, since everything should be auto-detectable--partly just by an ID table as we have now, but eventually we can use CFI or SFDP parameters provided by relatively new SPI NOR chips. I'm not sure if this is great for the short-term problem of fixing module-autoloading. Perhaps we should do a short-term hack to duplicate the SPI ID strings to m25p80.c by including them in a header (and backport for 3.16.y stable?), but I'd like to disentangle this. Brian From computersforpeace at gmail.com Tue Sep 9 23:11:18 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Tue, 9 Sep 2014 23:11:18 -0700 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: <20140910060004.GA5732@norris-Latitude-E6410> References: <1409673299.14324.43.camel@dagon.hellion.org.uk> <1409796689.27524.34.camel@decadent.org.uk> <20140910060004.GA5732@norris-Latitude-E6410> Message-ID: + Huang (his Freescale address is bouncing), Rafal On Tue, Sep 9, 2014 at 11:00 PM, Brian Norris wrote: > On Thu, Sep 04, 2014 at 09:02:04AM +0200, Geert Uytterhoeven wrote: >> On Thu, Sep 4, 2014 at 4:11 AM, Ben Hutchings wrote: >> >> I noticed that many platforms declare the flash chip as compatible = >> >> "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried >> >> changing that and it didn't help. In any case without spi-nor.ko being >> >> autoloaded I don't support m25p80.ko ever would be. >> > >> > m25p80.c has: >> > >> > static struct spi_driver m25p80_driver = { >> > ... >> > .id_table = spi_nor_ids, >> > ... >> > }; >> > >> > while spi_nor_ids is defined in spi-nor.c. Since they end up as two >> > separate modules, modpost can't read the ID table and add the device ID >> > aliases to m25p80.ko. >> >> Woops. This indeed doesn't work. >> Note that the MODULE_DEVICE_TABLE() is also gone from m25p80.c >> >> So m25p80.c needs to contain the IDs, while spi-nor.c also needs the IDs >> because it's a framework/library. > > Actually, m25p80.c only needs the strings (i.e., the named aliases -- > character data), and for the most part, spi-nor.c only needs the IDs (i.e., > the identification bytes). > > What's more, I don't think that any modern SPI NOR user really needs to > be specifying exactly which SPI device it is via a specific string. Our > driver code pretty much always re-detects the device by reading its > device ID. All the SPI NOR code needs to know is how to read its ID. > >> A quick solution would be to move the ID table to a header file, and include >> that by both, and re-add the lost MODULE_DEVICE_TABLE() to m25p80.c. >> That duplicates the data, though. >> >> Hmm, for the built-in case, we can avoid the duplication by letting m25p80.c >> refer to the table in spi-nor.c if !MODULE. >> Does anyone see a better solution? > > A little bit of a shot in the dark, as I haven't fleshed this one out: > > Would it work to just copy the SPI ID strings into m25p80.c, keep the > full table in spi-nor.c, stop adding SPI ID string (and DT) bindings to > the m25p80 table (force platforms to use "m25p80"-compatible probing, or > maybe something generic like "spi-nor-rdid", "spi-nor-sfdp", etc.) and > eventually kill the strings from spi-nor.c entirely? I really don't want > to propagate string-binding much further into the SPI NOR library, since > everything should be auto-detectable--partly just by an ID table as we > have now, but eventually we can use CFI or SFDP parameters provided by > relatively new SPI NOR chips. > > I'm not sure if this is great for the short-term problem of fixing > module-autoloading. Perhaps we should do a short-term hack to duplicate > the SPI ID strings to m25p80.c by including them in a header (and > backport for 3.16.y stable?), but I'd like to disentangle this. > > Brian From computersforpeace at gmail.com Wed Sep 10 00:02:30 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 10 Sep 2014 00:02:30 -0700 Subject: [PATCH 6/8] mtd: spi-nor: drop replaceable wait-till-ready function pointer In-Reply-To: <20140812011607.GA2065@shldeISGChi005.sh.intel.com> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-7-git-send-email-computersforpeace@gmail.com> <20140809095301.GA1076@localhost.localdomain> <20140811184311.GX3711@ld-irv-0074> <20140812011607.GA2065@shldeISGChi005.sh.intel.com> Message-ID: <20140910070230.GB5732@norris-Latitude-E6410> On Tue, Aug 12, 2014 at 09:16:07AM +0800, Huang Shijie wrote: > On Mon, Aug 11, 2014 at 11:43:11AM -0700, Brian Norris wrote: > > On Sat, Aug 09, 2014 at 05:53:03PM +0800, Huang Shijie wrote: > > > On Wed, Aug 06, 2014 at 06:17:00PM -0700, Brian Norris wrote: > > > > We don't need to expose a 'wait-till-ready' interface to drivers. Status > > > > register polling should be handled by the core spi-nor.c library, and as > > > > of now, I see no need to provide a special driver-specific hook for it. > > > > > > Please do not drop this hook, please see why we add this hook: > > > http://lists.infradead.org/pipermail/linux-mtd/2013-December/050561.html > > > > > > " > > > The default implementation would do just as you suggest, and I would > > > expect most H/W drivers to use the default implementation. However, some H/W > > > Controllers can automate the polling of status registers, so having a hook allows > > > the driver override the default behaviour. > > > " > > > > > > The spi-nor framework will used by more drivers besides the m25p80 and > > > fsl-quadspi. Some NOR flash controller may be very strange. > > > > OK, but the wait-till-ready hook should not look like the current one. > > If it is used as an optimization of sorts, then we can provide it in > > *addition* to the checks we do, but not *instead of*. I sincerely doubt > > that any specialized SPI NOR controller will know how to check both SR > > and FSR where appropriate, and it probably won't understand other > > specialized sequences as they are developed / thrown on our lap by flash > > vendors. > > > > So, the spi-nor.c "wait until ready" might have a sequence like this: > > > > 1. (Optionally) use low-level driver's "wait" function; skip if not > > present > > > > 2. use the read register hooks to check SR/FSR to confirm completion > > > > I do not want to toss #2 into the low-level driver, so if there is a > > need for #1, it should be done in addition to our spi-nor.c code, not > > instead. (To this end, I believe Marek also complained about this when > > we were adding the FSR-checking code; we should not have drivers and > > spi-nor.c fighting over callback functions.) > > > > So I'm inclined to at most address #1 through an optional callback, and > > but where to put the optional callback? in the spi_nor{} ? Probably. > > possibly even to ignore that until we see an actual driver that needs > > it. > If you insist to remove it, i will be okay too. > anyway, we can add it back when an actual driver appears. Yeah. The point of this series is that without users, the current callback is both ambiguously defined (it was allegedly serving both a flash-specific and a controller-specific purpose) and unncecessary. It's easier to add back once we have a clear purpose. Brian From computersforpeace at gmail.com Wed Sep 10 00:05:37 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 10 Sep 2014 00:05:37 -0700 Subject: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands In-Reply-To: <20140812005912.GA1850@shldeISGChi005.sh.intel.com> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-8-git-send-email-computersforpeace@gmail.com> <20140809105232.GA1571@localhost.localdomain> <20140811184818.GY3711@ld-irv-0074> <20140812005912.GA1850@shldeISGChi005.sh.intel.com> Message-ID: <20140910070537.GC5732@norris-Latitude-E6410> Hi Huang, On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote: > On Mon, Aug 11, 2014 at 11:48:18AM -0700, Brian Norris wrote: > > On Sat, Aug 09, 2014 at 06:52:34PM +0800, Huang Shijie wrote: > > > On Wed, Aug 06, 2014 at 06:17:01PM -0700, Brian Norris wrote: > > > > diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c > > > > index 9c13622a0c7a..07fbfb0a7738 100644 > > > > --- a/drivers/mtd/spi-nor/fsl-quadspi.c > > > > +++ b/drivers/mtd/spi-nor/fsl-quadspi.c > > > > @@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) > > > > dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", > > > > nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs); > > > > > > > > - /* Send write enable, then erase commands. */ > > > > - ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); > > > > - if (ret) > > > > - return ret; > > > > - > > > This write-enable is used for per-sector-erase, not for the whole chip > > > erase. > > > > > > So if you really want to remove this code, you should add an extra write-enable > > > in the spi_nor_erase. > > > > I don't understand your comment. > > > > Before this patch, there is a write-enable command in: > > * m25p80.c, per-sector erase > > * fsl-quadspi, per-sector erase > > * spi-nor.c, whole-chip erase > > > > With this patch, I am factoring all of these out into spi_nor_erase(). > > > > What is the problem? > Hi Brian: > For the spi_nor_erase(), the patch should like this: > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index c130bf7..26c48bc 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > /* whole-chip erase? */ > if (len == mtd->size) { > + write_enable(nor); > if (erase_chip(nor)) { > ret = -EIO; > goto erase_err; > @@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > /* "sector"-at-a-time erase */ > } else { > while (len) { > + write_enable(nor); > if (nor->erase(nor, addr)) { > ret = -EIO; > goto erase_err; > How is your patch any different than mine? Mine has the exact same code, except it covers both paths by putting the write_enable() outside the conditional entirely. Brian From shijie.huang at intel.com Wed Sep 10 08:20:21 2014 From: shijie.huang at intel.com (Huang Shijie) Date: Wed, 10 Sep 2014 23:20:21 +0800 Subject: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands In-Reply-To: <20140910070537.GC5732@norris-Latitude-E6410> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-8-git-send-email-computersforpeace@gmail.com> <20140809105232.GA1571@localhost.localdomain> <20140811184818.GY3711@ld-irv-0074> <20140812005912.GA1850@shldeISGChi005.sh.intel.com> <20140910070537.GC5732@norris-Latitude-E6410> Message-ID: <20140910152021.GB13016@shldeISGChi005.sh.intel.com> On Wed, Sep 10, 2014 at 12:05:37AM -0700, Brian Norris wrote: > Hi Huang, > > On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote: > > On Mon, Aug 11, 2014 at 11:48:18AM -0700, Brian Norris wrote: > > > On Sat, Aug 09, 2014 at 06:52:34PM +0800, Huang Shijie wrote: > > > > On Wed, Aug 06, 2014 at 06:17:01PM -0700, Brian Norris wrote: > > > > > diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c > > > > > index 9c13622a0c7a..07fbfb0a7738 100644 > > > > > --- a/drivers/mtd/spi-nor/fsl-quadspi.c > > > > > +++ b/drivers/mtd/spi-nor/fsl-quadspi.c > > > > > @@ -738,11 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) > > > > > dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", > > > > > nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs); > > > > > > > > > > - /* Send write enable, then erase commands. */ > > > > > - ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0); > > > > > - if (ret) > > > > > - return ret; > > > > > - > > > > This write-enable is used for per-sector-erase, not for the whole chip > > > > erase. > > > > > > > > So if you really want to remove this code, you should add an extra write-enable > > > > in the spi_nor_erase. > > > > > > I don't understand your comment. > > > > > > Before this patch, there is a write-enable command in: > > > * m25p80.c, per-sector erase > > > * fsl-quadspi, per-sector erase > > > * spi-nor.c, whole-chip erase > > > > > > With this patch, I am factoring all of these out into spi_nor_erase(). > > > > > > What is the problem? > > Hi Brian: > > For the spi_nor_erase(), the patch should like this: > > > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > > index c130bf7..26c48bc 100644 > > --- a/drivers/mtd/spi-nor/spi-nor.c > > +++ b/drivers/mtd/spi-nor/spi-nor.c > > @@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > > > /* whole-chip erase? */ > > if (len == mtd->size) { > > + write_enable(nor); > > if (erase_chip(nor)) { > > ret = -EIO; > > goto erase_err; > > @@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > /* "sector"-at-a-time erase */ > > } else { > > while (len) { > > + write_enable(nor); The difference is here. you miss a write_enable for each sector's erase. thanks Huang Shijie > > if (nor->erase(nor, addr)) { > > ret = -EIO; > > goto erase_err; > > > > How is your patch any different than mine? Mine has the exact same code, > except it covers both paths by putting the write_enable() outside the > conditional entirely. From computersforpeace at gmail.com Wed Sep 10 00:26:16 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 10 Sep 2014 00:26:16 -0700 Subject: [PATCH v2 1/10] mtd: spi-nor: eliminate duplicate spi_nor_wait_till_{, fsr}_ready() code In-Reply-To: <1407374222-8448-2-git-send-email-computersforpeace@gmail.com> References: <1407374222-8448-2-git-send-email-computersforpeace@gmail.com> Message-ID: <1410333976-19252-1-git-send-email-computersforpeace@gmail.com> These functions were near-carbon-copies due to a small per-flash quirk. Let's add a new spi_nor::flags bitfield to support these types of quirks. Signed-off-by: Brian Norris Reviewed-by: Marek Vasut Cc: Graham Moore Cc: Huang Shijie Signed-off-by: Brian Norris --- v2: replace 'sr' with 'fsr' (typo) I think this was the only patch (of the first 7) that required changes due to review. I may rework patch 8 eventually, but it was not meant for inclusion in its current form. drivers/mtd/spi-nor/spi-nor.c | 66 ++++++++++++++++++++++--------------------- include/linux/mtd/spi-nor.h | 6 ++++ 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 03e0ab8b2086..ba324e293645 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -163,48 +163,51 @@ static inline int set_4byte(struct spi_nor *nor, u32 jedec_id, int enable) return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1, 0); } } - -static int spi_nor_wait_till_ready(struct spi_nor *nor) +static inline int spi_nor_sr_ready(struct spi_nor *nor) { - unsigned long deadline; - int sr; - - deadline = jiffies + MAX_READY_WAIT_JIFFIES; - - do { - cond_resched(); + int sr = read_sr(nor); + if (sr < 0) + return sr; + else + return !(sr & SR_WIP); +} - sr = read_sr(nor); - if (sr < 0) - break; - else if (!(sr & SR_WIP)) - return 0; - } while (!time_after_eq(jiffies, deadline)); +static inline int spi_nor_fsr_ready(struct spi_nor *nor) +{ + int fsr = read_fsr(nor); + if (fsr < 0) + return fsr; + else + return fsr & FSR_READY; +} - return -ETIMEDOUT; +static int spi_nor_ready(struct spi_nor *nor) +{ + int sr, fsr; + sr = spi_nor_sr_ready(nor); + if (sr < 0) + return sr; + fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1; + if (fsr < 0) + return fsr; + return sr && fsr; } -static int spi_nor_wait_till_fsr_ready(struct spi_nor *nor) +static int spi_nor_wait_till_ready(struct spi_nor *nor) { unsigned long deadline; - int sr; - int fsr; + int ret; deadline = jiffies + MAX_READY_WAIT_JIFFIES; do { cond_resched(); - sr = read_sr(nor); - if (sr < 0) { - break; - } else if (!(sr & SR_WIP)) { - fsr = read_fsr(nor); - if (fsr < 0) - break; - if (fsr & FSR_READY) - return 0; - } + ret = spi_nor_ready(nor); + if (ret < 0) + return ret; + if (ret) + return 0; } while (!time_after_eq(jiffies, deadline)); return -ETIMEDOUT; @@ -1009,9 +1012,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, else mtd->_write = spi_nor_write; - if ((info->flags & USE_FSR) && - nor->wait_till_ready == spi_nor_wait_till_ready) - nor->wait_till_ready = spi_nor_wait_till_fsr_ready; + if (info->flags & USE_FSR) + nor->flags |= SNOR_F_USE_FSR; /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f32ba8..603ac0306663 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -116,6 +116,10 @@ enum spi_nor_ops { SPI_NOR_OPS_UNLOCK, }; +enum spi_nor_option_flags { + SNOR_F_USE_FSR = BIT(0), +}; + /** * struct spi_nor - Structure for defining a the SPI NOR layer * @mtd: point to a mtd_info structure @@ -129,6 +133,7 @@ enum spi_nor_ops { * @program_opcode: the program opcode * @flash_read: the mode of the read * @sst_write_second: used by the SST write operation + * @flags: flag options for the current SPI-NOR (SNOR_F_*) * @cfg: used by the read_xfer/write_xfer * @cmd_buf: used by the write_reg * @prepare: [OPTIONAL] do some preparations for the @@ -160,6 +165,7 @@ struct spi_nor { u8 program_opcode; enum read_mode flash_read; bool sst_write_second; + u32 flags; struct spi_nor_xfer_cfg cfg; u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; -- 1.9.1 From computersforpeace at gmail.com Wed Sep 10 00:47:08 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 10 Sep 2014 00:47:08 -0700 Subject: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands In-Reply-To: <20140910152021.GB13016@shldeISGChi005.sh.intel.com> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-8-git-send-email-computersforpeace@gmail.com> <20140809105232.GA1571@localhost.localdomain> <20140811184818.GY3711@ld-irv-0074> <20140812005912.GA1850@shldeISGChi005.sh.intel.com> <20140910070537.GC5732@norris-Latitude-E6410> <20140910152021.GB13016@shldeISGChi005.sh.intel.com> Message-ID: <20140910074708.GD5732@norris-Latitude-E6410> On Wed, Sep 10, 2014 at 11:20:21PM +0800, Huang Shijie wrote: > On Wed, Sep 10, 2014 at 12:05:37AM -0700, Brian Norris wrote: > > On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote: > > > For the spi_nor_erase(), the patch should like this: > > > > > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > > > index c130bf7..26c48bc 100644 > > > --- a/drivers/mtd/spi-nor/spi-nor.c > > > +++ b/drivers/mtd/spi-nor/spi-nor.c > > > @@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > > > > > /* whole-chip erase? */ > > > if (len == mtd->size) { > > > + write_enable(nor); > > > if (erase_chip(nor)) { > > > ret = -EIO; > > > goto erase_err; > > > @@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > > /* "sector"-at-a-time erase */ > > > } else { > > > while (len) { > > > + write_enable(nor); > The difference is here. OK. > you miss a write_enable for each sector's erase. But is that necessary? I thought 'write-enabled' was retained across operations, so why would you have to perform it before each sector's erase? Or do you have a flash datasheet which says you must send WREN before each sector erase? I do see, now that I'm looking a little closer, that spi-nor doesn't actually have any concurrency protection (!). So it looks like we could potentially have other operations interleaved in this sequence of sector erasures, potentially running a write_disable() in the midst of this loop. I really hope I'm wrong about that last paragraph. If I'm correct though, the solution to this is not, AIUI, to add more write_enable() calls in this loop; the solution is to add some kind of concurrency protections, a la nand_get_device(). > > > if (nor->erase(nor, addr)) { > > > ret = -EIO; > > > goto erase_err; > > > > > > > How is your patch any different than mine? Mine has the exact same code, > > except it covers both paths by putting the write_enable() outside the > > conditional entirely. Brian From geert at linux-m68k.org Wed Sep 10 00:59:49 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Wed, 10 Sep 2014 09:59:49 +0200 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: References: <1409673299.14324.43.camel@dagon.hellion.org.uk> <1409796689.27524.34.camel@decadent.org.uk> <20140910060004.GA5732@norris-Latitude-E6410> Message-ID: + devicetree, as the names are used in DTS file. On Wed, Sep 10, 2014 at 8:11 AM, Brian Norris wrote: > + Huang (his Freescale address is bouncing), Rafal > > On Tue, Sep 9, 2014 at 11:00 PM, Brian Norris > wrote: >> On Thu, Sep 04, 2014 at 09:02:04AM +0200, Geert Uytterhoeven wrote: >>> On Thu, Sep 4, 2014 at 4:11 AM, Ben Hutchings wrote: >>> >> I noticed that many platforms declare the flash chip as compatible = >>> >> "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried >>> >> changing that and it didn't help. In any case without spi-nor.ko being >>> >> autoloaded I don't support m25p80.ko ever would be. >>> > >>> > m25p80.c has: >>> > >>> > static struct spi_driver m25p80_driver = { >>> > ... >>> > .id_table = spi_nor_ids, >>> > ... >>> > }; >>> > >>> > while spi_nor_ids is defined in spi-nor.c. Since they end up as two >>> > separate modules, modpost can't read the ID table and add the device ID >>> > aliases to m25p80.ko. >>> >>> Woops. This indeed doesn't work. >>> Note that the MODULE_DEVICE_TABLE() is also gone from m25p80.c >>> >>> So m25p80.c needs to contain the IDs, while spi-nor.c also needs the IDs >>> because it's a framework/library. >> >> Actually, m25p80.c only needs the strings (i.e., the named aliases -- >> character data), and for the most part, spi-nor.c only needs the IDs (i.e., >> the identification bytes). >> >> What's more, I don't think that any modern SPI NOR user really needs to >> be specifying exactly which SPI device it is via a specific string. Our >> driver code pretty much always re-detects the device by reading its >> device ID. All the SPI NOR code needs to know is how to read its ID. But the proper name should be in the compatible property. >>> A quick solution would be to move the ID table to a header file, and include >>> that by both, and re-add the lost MODULE_DEVICE_TABLE() to m25p80.c. >>> That duplicates the data, though. >>> >>> Hmm, for the built-in case, we can avoid the duplication by letting m25p80.c >>> refer to the table in spi-nor.c if !MODULE. >>> Does anyone see a better solution? >> >> A little bit of a shot in the dark, as I haven't fleshed this one out: >> >> Would it work to just copy the SPI ID strings into m25p80.c, keep the >> full table in spi-nor.c, stop adding SPI ID string (and DT) bindings to >> the m25p80 table (force platforms to use "m25p80"-compatible probing, or >> maybe something generic like "spi-nor-rdid", "spi-nor-sfdp", etc.) and >> eventually kill the strings from spi-nor.c entirely? I really don't want >> to propagate string-binding much further into the SPI NOR library, since >> everything should be auto-detectable--partly just by an ID table as we >> have now, but eventually we can use CFI or SFDP parameters provided by >> relatively new SPI NOR chips. How does the SPI core know to use m25p80? From the ids, and the compatible value. If you won't add new names, all devices should declare compatiblity with "m25p80" (that's "spansion,m25p80", right?) as a fallback. However, are all devices really compatible with m25p80? I.e. does m25p80.c work will all devices, in the absense of support for the real device? If not, the fallback must not be there, and new device names must be added. >> I'm not sure if this is great for the short-term problem of fixing >> module-autoloading. Perhaps we should do a short-term hack to duplicate >> the SPI ID strings to m25p80.c by including them in a header (and >> backport for 3.16.y stable?), but I'd like to disentangle this. >> >> Brian Autoloading is based on "spi:". If new names aren't added, m25p80 won't be loaded for new SPI FLASHes, unless I'm missing something? Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From richard.genoud at gmail.com Wed Sep 10 01:06:58 2014 From: richard.genoud at gmail.com (Richard Genoud) Date: Wed, 10 Sep 2014 10:06:58 +0200 Subject: [PATCH] UBI: add missing kmem_cache_free() in process_pool_aeb error path In-Reply-To: <540F749B.6080607@nod.at> References: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> <540F749B.6080607@nod.at> Message-ID: 2014-09-09 23:43 GMT+02:00 Richard Weinberger : > Am 09.09.2014 14:25, schrieb Richard Genoud: >> I ran into this error after a ubiupdatevol, because I forgot to backport >> e9110361a9a4 UBI: fix the volumes tree sorting criteria. >> >> UBI error: process_pool_aeb: orphaned volume in fastmap pool >> UBI error: ubi_scan_fastmap: Attach by fastmap failed, doing a full scan! >> kmem_cache_destroy ubi_ainf_peb_slab: Slab cache still has objects >> CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.18-00053-gf05cac8dbf85 #1 >> [] (unwind_backtrace) from [] (show_stack+0x10/0x14) >> [] (show_stack) from [] (destroy_ai+0x230/0x244) >> [] (destroy_ai) from [] (ubi_attach+0x98/0x1ec) >> [] (ubi_attach) from [] (ubi_attach_mtd_dev+0x2b8/0x868) >> [] (ubi_attach_mtd_dev) from [] (ubi_init+0x1dc/0x2ac) >> [] (ubi_init) from [] (do_one_initcall+0x94/0x140) >> [] (do_one_initcall) from [] (kernel_init_freeable+0xe8/0x1b0) >> [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) >> [] (kernel_init) from [] (ret_from_fork+0x14/0x24) >> UBI: scanning is finished >> >> Freeing the cache in the error path fixes the Slab error. >> >> Tested on at91sam9g35 (3.14.18+fastmap backports) >> >> Signed-off-by: Richard Genoud >> Cc: stable # >= 3.10 > > I guess you wrote 3.10 because there is no stable kernel between >= 3.7 and < 3.10? Yes, that's right. I checked that git am 0001-UBI-add-missing-kmem_cache_free-in-process_pool_aeb-.patch Applied correctly on 3.10.54, 3.12.28, 3.14.18, 3.16.2 and 3.17-rc4 > Patch looks good otherwise. > > Acked-by: Richard Weinberger > > Thanks, > //richard From shijie.huang at intel.com Wed Sep 10 09:12:37 2014 From: shijie.huang at intel.com (Huang Shijie) Date: Thu, 11 Sep 2014 00:12:37 +0800 Subject: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands In-Reply-To: <20140910074708.GD5732@norris-Latitude-E6410> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-8-git-send-email-computersforpeace@gmail.com> <20140809105232.GA1571@localhost.localdomain> <20140811184818.GY3711@ld-irv-0074> <20140812005912.GA1850@shldeISGChi005.sh.intel.com> <20140910070537.GC5732@norris-Latitude-E6410> <20140910152021.GB13016@shldeISGChi005.sh.intel.com> <20140910074708.GD5732@norris-Latitude-E6410> Message-ID: <20140910161237.GB13736@shldeISGChi005.sh.intel.com> On Wed, Sep 10, 2014 at 12:47:08AM -0700, Brian Norris wrote: > On Wed, Sep 10, 2014 at 11:20:21PM +0800, Huang Shijie wrote: > > On Wed, Sep 10, 2014 at 12:05:37AM -0700, Brian Norris wrote: > > > On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote: > > > > For the spi_nor_erase(), the patch should like this: > > > > > > > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > > > > index c130bf7..26c48bc 100644 > > > > --- a/drivers/mtd/spi-nor/spi-nor.c > > > > +++ b/drivers/mtd/spi-nor/spi-nor.c > > > > @@ -324,6 +324,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > > > > > > > /* whole-chip erase? */ > > > > if (len == mtd->size) { > > > > + write_enable(nor); > > > > if (erase_chip(nor)) { > > > > ret = -EIO; > > > > goto erase_err; > > > > @@ -337,6 +338,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) > > > > /* "sector"-at-a-time erase */ > > > > } else { > > > > while (len) { > > > > + write_enable(nor); > > The difference is here. > > OK. > > > you miss a write_enable for each sector's erase. > > But is that necessary? I thought 'write-enabled' was retained across > operations, so why would you have to perform it before each sector's > erase? The legacy code did so. > > Or do you have a flash datasheet which says you must send WREN before > each sector erase? See the belowing from Spansion Nor S25fl129: " The Sector Erase (SE) command sets all bits at all addresses within a specified sector to a logic 1. A WREN command is required prior to writing the SE command. " It does not tell we send a WREN for each sector erase, but i am not sure if we can remove it. thanks Huang Shijie > > I do see, now that I'm looking a little closer, that spi-nor doesn't > actually have any concurrency protection (!). So it looks like we could > potentially have other operations interleaved in this sequence of sector > erasures, potentially running a write_disable() in the midst of this loop. > > I really hope I'm wrong about that last paragraph. > > If I'm correct though, the solution to this is not, AIUI, to add more > write_enable() calls in this loop; the solution is to add some kind of > concurrency protections, a la nand_get_device(). From lisovy at gmail.com Wed Sep 10 01:53:50 2014 From: lisovy at gmail.com (Rostislav Lisovy) Date: Wed, 10 Sep 2014 10:53:50 +0200 Subject: [PATCH] mtd: spi-nor: Add support for Fujitsu MB85RS1MT FRAM Message-ID: <1410339230-13007-1-git-send-email-lisovy@merica.cz> Tested with this particular FRAM chip Signed-off-by: Rostislav Lisovy --- drivers/mtd/spi-nor/spi-nor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..a914be9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -505,6 +505,9 @@ const struct spi_device_id spi_nor_ids[] = { { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + /* Fujitsu */ + { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, + /* GigaDevice */ { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, -- 1.9.1 From boris.brezillon at free-electrons.com Wed Sep 10 01:55:39 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Wed, 10 Sep 2014 10:55:39 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support Message-ID: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> Several MTD users (either in user or kernel space) expect a valid raw access support to NAND chip devices. This is particularly true for testing tools which are often touching the data stored in a NAND chip in raw mode to artificially generate errors. The GPMI drivers do not implemenent raw access functions, and thus rely on default HW_ECC scheme implementation. The default implementation consider the data and OOB area as properly separated in their respective NAND section, which is not true for the GPMI controller. In this driver/controller some OOB data are stored at the beginning of the NAND data area (these data are called metadata in the driver), then ECC bytes are interleaved with data chunk (which is similar to the HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as OOB data. Signed-off-by: Boris BREZILLON --- Hello, This patch is providing raw access support to the GPMI driver which is particularly useful to run some tests on the NAND (the one coming in mind is the mtd_nandbiterrs testsuite). I know this rework might break several user space tools which are relying on the default raw access implementation (I already experienced an issue with the kobs-ng tool provided by freescale), but many other tools will now work as expected. Huang, Brian, let me know what you think of this approach ? Best Regards, Boris drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 119 ++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 959cb9b..b26e032 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -831,7 +831,13 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) * power of two and is much larger than four, which guarantees the * auxiliary buffer will appear on a 32-bit boundary. */ - this->page_buffer_size = geo->payload_size + geo->auxiliary_size; + if (geo->payload_size + geo->auxiliary_size > + mtd->writesize + mtd->oobsize) + this->page_buffer_size = + geo->payload_size + geo->auxiliary_size; + else + this->page_buffer_size = mtd->writesize + mtd->oobsize; + this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, &this->page_buffer_phys, GFP_DMA); if (!this->page_buffer_virt) @@ -1347,6 +1353,115 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) return status & NAND_STATUS_FAIL ? -EIO : 0; } +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbytes = DIV_ROUND_UP(nfc_geo->ecc_strength * nfc_geo->gf_len, + 8); + uint8_t *oob = chip->oob_poi; + int step; + int column = 0; + uint8_t *orig_buf = buf; + + chip->read_buf(mtd, oob, nfc_geo->metadata_size); + oob += nfc_geo->metadata_size; + + column += nfc_geo->metadata_size; + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + chip->read_buf(mtd, buf, eccsize); + buf += eccsize; + column += eccsize; + chip->read_buf(mtd, oob, eccbytes); + oob += eccbytes; + column += eccbytes; + } + + if (column < mtd->writesize + mtd->oobsize) + chip->read_buf(mtd, oob, + mtd->writesize + mtd->oobsize - column); + + block_mark_swapping(this, orig_buf, chip->oob_poi); + + return 0; +} + +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbytes = DIV_ROUND_UP(nfc_geo->ecc_strength * nfc_geo->gf_len, + 8); + uint8_t *oob = chip->oob_poi; + int step; + int column = 0; + + if (this->swap_block_mark) { + /* + * If control arrives here, we're doing block mark swapping. + * Since we can't modify the caller's buffers, we must copy them + * into our own. + */ + memcpy(this->page_buffer_virt, buf, mtd->writesize); + if (oob_required) + memcpy(this->page_buffer_virt + mtd->writesize, + chip->oob_poi, mtd->oobsize); + else + memset(this->page_buffer_virt + mtd->writesize, + 0xff, mtd->oobsize); + + /* Handle block mark swapping. */ + block_mark_swapping(this, this->page_buffer_virt, + this->page_buffer_virt + mtd->writesize); + + oob = this->page_buffer_virt + mtd->writesize; + buf = this->page_buffer_virt; + } + + if (oob_required) { + chip->write_buf(mtd, oob, nfc_geo->metadata_size); + oob += nfc_geo->metadata_size; + } else { + /* + * Write the data byte in the OOB area if BB marker swapping + * is requested. + */ + if (this->swap_block_mark) + chip->write_buf(mtd, oob, 1); + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, + column, -1); + } + column += nfc_geo->metadata_size; + + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + chip->write_buf(mtd, buf, eccsize); + buf += eccsize; + column += eccsize; + if (oob_required) { + chip->write_buf(mtd, oob, eccbytes); + oob += eccbytes; + } else { + chip->cmdfunc(mtd, NAND_CMD_SEQIN, + column + eccbytes, -1); + } + column += eccbytes; + } + + if (oob_required && column < mtd->writesize + mtd->oobsize) + chip->write_buf(mtd, oob, + mtd->writesize + mtd->oobsize - column); + + return 0; +} + static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; @@ -1664,6 +1779,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ecc->write_page = gpmi_ecc_write_page; ecc->read_oob = gpmi_ecc_read_oob; ecc->write_oob = gpmi_ecc_write_oob; + ecc->read_page_raw = gpmi_ecc_read_page_raw; + ecc->write_page_raw = gpmi_ecc_write_page_raw; ecc->mode = NAND_ECC_HW; ecc->size = bch_geo->ecc_chunk_size; ecc->strength = bch_geo->ecc_strength; -- 1.9.1 From klightspeed at killerwolves.net Wed Sep 10 01:55:41 2014 From: klightspeed at killerwolves.net (klightspeed at killerwolves.net) Date: Wed, 10 Sep 2014 18:55:41 +1000 Subject: [PATCH reword] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC Message-ID: <1410339341-3372-1-git-send-email-klightspeed@killerwolves.net> The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC (strength = 4), while the pxa3xx NAND driver by default uses Hamming ECC (strength = 1). This patch changes the ECC mode on these machines to match that of the bootloader and of the stock firmware. That way, it is now possible to update the kernel from userland (e.g. using standard tools from mtd-utils package); u-boot will happily load and boot it. Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") Signed-off-by: Ben Peddell Acked-by: Ezequiel Garcia Tested-by: Arnaud Ebalard --- arch/arm/boot/dts/armada-370-netgear-rn102.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts index d6d572e..285524f 100644 --- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts +++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts @@ -143,6 +143,10 @@ marvell,nand-enable-arbiter; nand-on-flash-bbt; + /* Use Hardware BCH ECC */ + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + partition at 0 { label = "u-boot"; reg = <0x0000000 0x180000>; /* 1.5MB */ -- 1.8.5.5 From ezequiel at vanguardiasur.com.ar Wed Sep 10 05:48:49 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Wed, 10 Sep 2014 09:48:49 -0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <540D8A92.2040209@ti.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> Message-ID: <20140910124849.GA25308@arch.hh.imgtec.org> On 08 Sep 01:53 PM, Roger Quadros wrote: > On 09/08/2014 11:45 AM, Roger Quadros wrote: > > On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: [..] > >> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h > >> index 780d1e9..25d1bca 100644 > >> --- a/include/linux/platform_data/elm.h > >> +++ b/include/linux/platform_data/elm.h > >> @@ -42,8 +42,22 @@ struct elm_errorvec { > >> int error_loc[16]; > >> }; > >> > >> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) > > I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and > CONFIG_MTD_NAND_OMAP_BCH to m. > > CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to > be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From rogerq at ti.com Wed Sep 10 06:05:56 2014 From: rogerq at ti.com (Roger Quadros) Date: Wed, 10 Sep 2014 16:05:56 +0300 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <20140910124849.GA25308@arch.hh.imgtec.org> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> <20140910124849.GA25308@arch.hh.imgtec.org> Message-ID: <54104CB4.4020703@ti.com> On 09/10/2014 03:48 PM, Ezequiel Garcia wrote: > On 08 Sep 01:53 PM, Roger Quadros wrote: >> On 09/08/2014 11:45 AM, Roger Quadros wrote: >>> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > [..] >>>> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h >>>> index 780d1e9..25d1bca 100644 >>>> --- a/include/linux/platform_data/elm.h >>>> +++ b/include/linux/platform_data/elm.h >>>> @@ -42,8 +42,22 @@ struct elm_errorvec { >>>> int error_loc[16]; >>>> }; >>>> >>>> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) >> >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and >> CONFIG_MTD_NAND_OMAP_BCH to m. >> >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. >> > > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( > > Mine neither ;). I'm unaware of any other method than making CONFIG_MTD_NAND_OMAP_BCH to bool. cheers, -roger From guido at vanguardiasur.com.ar Wed Sep 10 07:56:40 2014 From: guido at vanguardiasur.com.ar (=?UTF-8?q?Guido=20Mart=C3=ADnez?=) Date: Wed, 10 Sep 2014 11:56:40 -0300 Subject: [PATCH] libmtd: fix mtd_dev_present return value on legacy systems Message-ID: <1410361000-4821-1-git-send-email-guido@vanguardiasur.com.ar> On legacy systems, if "/proc/mtd" doesn't exist or gives a read error, mtd_dev_present returns -1 (since it calls legacy_dev_present), contrary to what's specified in the header file. This causes checks like if (mtd_dev_present(n)) { ... } to give false positives. Fix this by comparing the return value to 1. Signed-off-by: Guido Mart?nez --- lib/libmtd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/libmtd.c b/lib/libmtd.c index 2089373..aff4c8b 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -647,9 +647,9 @@ int mtd_dev_present(libmtd_t desc, int mtd_num) { struct stat st; struct libmtd *lib = (struct libmtd *)desc; - if (!lib->sysfs_supported) - return legacy_dev_present(mtd_num); - else { + if (!lib->sysfs_supported) { + return legacy_dev_present(mtd_num) == 1; + } else { char file[strlen(lib->mtd) + 10]; sprintf(file, lib->mtd, mtd_num); -- 2.1.0 From marex at denx.de Wed Sep 10 07:55:19 2014 From: marex at denx.de (Marek Vasut) Date: Wed, 10 Sep 2014 16:55:19 +0200 Subject: [PATCH] mtd: spi-nor: Add support for Fujitsu MB85RS1MT FRAM In-Reply-To: <1410339230-13007-1-git-send-email-lisovy@merica.cz> References: <1410339230-13007-1-git-send-email-lisovy@merica.cz> Message-ID: <201409101655.19155.marex@denx.de> On Wednesday, September 10, 2014 at 10:53:50 AM, Rostislav Lisovy wrote: > Tested with this particular FRAM chip > > Signed-off-by: Rostislav Lisovy > --- > drivers/mtd/spi-nor/spi-nor.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index b5ad6be..a914be9 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -505,6 +505,9 @@ const struct spi_device_id spi_nor_ids[] = { > { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | > SPI_NOR_NO_FR) }, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, > SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, > > + /* Fujitsu */ > + { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, > + > /* GigaDevice */ > { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, > { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, Looks OK, Acked-by: Marek Vasut Best regards, Marek Vasut From pekon at pek-sem.com Wed Sep 10 13:15:15 2014 From: pekon at pek-sem.com (pekon) Date: Thu, 11 Sep 2014 01:45:15 +0530 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <20140910124849.GA25308@arch.hh.imgtec.org> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> <20140910124849.GA25308@arch.hh.imgtec.org> Message-ID: <5410B153.80303@pek-sem.com> On Wednesday 10 September 2014 06:18 PM, Ezequiel Garcia wrote: > On 08 Sep 01:53 PM, Roger Quadros wrote: >> On 09/08/2014 11:45 AM, Roger Quadros wrote: >>> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > [..] >>>> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h >>>> index 780d1e9..25d1bca 100644 >>>> --- a/include/linux/platform_data/elm.h >>>> +++ b/include/linux/platform_data/elm.h >>>> @@ -42,8 +42,22 @@ struct elm_errorvec { >>>> int error_loc[16]; >>>> }; >>>> >>>> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) >> >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and >> CONFIG_MTD_NAND_OMAP_BCH to m. >> >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. >> > > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( > > Does following work ? config MTD_NAND_OMAP_BCH depends on MTD_NAND_OMAP2 tristate "" if (MTD_NAND_OMAP2 && m) bool "" if (MTD_NAND_OMAP2 && y) default n ... Sorry, I don't have tools to check myself. If not following should help: $KERNEL/Documentation/kbuild/kconfig-language.txt with regards, pekon ------------------------ Powered by BigRock.com From computersforpeace at gmail.com Wed Sep 10 16:25:26 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 10 Sep 2014 16:25:26 -0700 Subject: [PATCH 7/8] mtd: spi-nor: factor out write_enable() for erase commands In-Reply-To: <20140910161237.GB13736@shldeISGChi005.sh.intel.com> References: <1407374222-8448-1-git-send-email-computersforpeace@gmail.com> <1407374222-8448-8-git-send-email-computersforpeace@gmail.com> <20140809105232.GA1571@localhost.localdomain> <20140811184818.GY3711@ld-irv-0074> <20140812005912.GA1850@shldeISGChi005.sh.intel.com> <20140910070537.GC5732@norris-Latitude-E6410> <20140910152021.GB13016@shldeISGChi005.sh.intel.com> <20140910074708.GD5732@norris-Latitude-E6410> <20140910161237.GB13736@shldeISGChi005.sh.intel.com> Message-ID: <20140910232526.GI18411@ld-irv-0074> On Thu, Sep 11, 2014 at 12:12:37AM +0800, Huang Shijie wrote: > On Wed, Sep 10, 2014 at 12:47:08AM -0700, Brian Norris wrote: > > On Wed, Sep 10, 2014 at 11:20:21PM +0800, Huang Shijie wrote: > > > On Wed, Sep 10, 2014 at 12:05:37AM -0700, Brian Norris wrote: > > > > On Tue, Aug 12, 2014 at 08:59:12AM +0800, Huang Shijie wrote: > > > you miss a write_enable for each sector's erase. > > > > But is that necessary? I thought 'write-enabled' was retained across > > operations, so why would you have to perform it before each sector's > > erase? > The legacy code did so. > > > > > Or do you have a flash datasheet which says you must send WREN before > > each sector erase? > See the belowing from Spansion Nor S25fl129: > > " > The Sector Erase (SE) command sets all bits at all addresses within a > specified sector to a logic 1. A WREN > command is required prior to writing the SE command. > " > > It does not tell we send a WREN for each sector erase, but i am not sure if we can remove it. OK, well I guess I can rework this to retain the original behavior. That was in fact, an oversight (thanks for catching), although I'm not convinced it's actually necessary. (Edit: I think you may be right that WREN is necessary before every erased command. From a Micron N25Q256 datasheet: The write enable latch bit must be set before every PROGRAM, ERASE, WRITE, ENTER 4-BYTE ADDRESS MODE, and EXIT 4-BYTE ADDRESS MODE command. But I don't recall seeing any ill effects last time I tested this on my Micron SPI flash, so I'm still mildly confused.) Brian From shijie8 at gmail.com Thu Sep 11 05:09:30 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Thu, 11 Sep 2014 20:09:30 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140911120928.GA1585@localhost.localdomain> On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > Several MTD users (either in user or kernel space) expect a valid raw > access support to NAND chip devices. > This is particularly true for testing tools which are often touching the > data stored in a NAND chip in raw mode to artificially generate errors. > > The GPMI drivers do not implemenent raw access functions, and thus rely on > default HW_ECC scheme implementation. > The default implementation consider the data and OOB area as properly > separated in their respective NAND section, which is not true for the GPMI > controller. > In this driver/controller some OOB data are stored at the beginning of the > NAND data area (these data are called metadata in the driver), then ECC > bytes are interleaved with data chunk (which is similar to the > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > OOB data. > > Signed-off-by: Boris BREZILLON > --- > Hello, > > This patch is providing raw access support to the GPMI driver which is > particularly useful to run some tests on the NAND (the one coming in > mind is the mtd_nandbiterrs testsuite). > > I know this rework might break several user space tools which are relying > on the default raw access implementation (I already experienced an issue > with the kobs-ng tool provided by freescale), but many other tools will > now work as expected. If the kobs-ng can not works, there is no meaning that other tools works. So I do not think we need to implement these hooks. sorry, I will not Ack this patch. thanks Huang Shijie From boris.brezillon at free-electrons.com Thu Sep 11 05:36:16 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Thu, 11 Sep 2014 14:36:16 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911120928.GA1585@localhost.localdomain> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> Message-ID: <20140911143616.3ebb025a@bbrezillon> Hi Huang, On Thu, 11 Sep 2014 20:09:30 +0800 Huang Shijie wrote: > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > Several MTD users (either in user or kernel space) expect a valid raw > > access support to NAND chip devices. > > This is particularly true for testing tools which are often touching the > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > default HW_ECC scheme implementation. > > The default implementation consider the data and OOB area as properly > > separated in their respective NAND section, which is not true for the GPMI > > controller. > > In this driver/controller some OOB data are stored at the beginning of the > > NAND data area (these data are called metadata in the driver), then ECC > > bytes are interleaved with data chunk (which is similar to the > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > OOB data. > > > > Signed-off-by: Boris BREZILLON > > --- > > Hello, > > > > This patch is providing raw access support to the GPMI driver which is > > particularly useful to run some tests on the NAND (the one coming in > > mind is the mtd_nandbiterrs testsuite). > > > > I know this rework might break several user space tools which are relying > > on the default raw access implementation (I already experienced an issue > > with the kobs-ng tool provided by freescale), but many other tools will > > now work as expected. > If the kobs-ng can not works, there is no meaning that other tools > works. So I do not think we need to implement these hooks. Well, I don't know about freescale specific tools, but at least I have an example with mtd_nandbiterrs module. This module is assuming it can write only the data part of a NAND page without modifying the OOB area (see [1]), which in GPMI controller case is impossible because raw write function store the data as if there were no specific scheme, while there is one: (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). Moreover, IMHO, nanddump and nandwrite tools (which can use raw access mode when passing the appropriate option) should always return the same kind of data no matter what NAND controller is in use on the system => (DATA + OOB_DATA), and this is definitely not the case with the GPMI driver. See how raw access on HW_ECC_SYNDROME scheme is implemented in nand_base.c [2]. It hides to the mtd user the fact that DATA and ECC bytes are interleaved, and give him the expected (DATA + OOB_DATA) representation. Best Regards, Boris [1]http://lxr.free-electrons.com/source/drivers/mtd/tests/nandbiterrs.c#L112 [2]http://lxr.free-electrons.com/source/drivers/mtd/nand/nand_base.c#L1364 -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From ezequiel at vanguardiasur.com.ar Thu Sep 11 06:47:01 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 10:47:01 -0300 Subject: [PATCH 0/3] nand: Renaming, moving and fixing NAND and ELM drivers Message-ID: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> Following the recent discussion with Roger, here's a few patches that (hopefully) fix all the issues. The first patches rename the OMAP NAND drivers, so they are now called omap2_nand and omap_elm. The last patch picks an idea from Yann E. Morin and fixes the build issue reported by Roger. Quoting Roger: "" I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and CONFIG_MTD_NAND_OMAP_BCH to m. CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. Maybe it should be a sub option of CONFIG_MTD_NAND_OMAP2. IMHO the elm.c file must be moved from mtd/devices to mtd/nand and renamed to omap_elm.c drivers/built-in.o: In function `omap_nand_probe': /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' drivers/built-in.o: In function `omap_elm_correct_data': /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' make: *** [vmlinux] Error 1 "" [1] https://lkml.org/lkml/2013/5/4/84 Ezequiel Garcia (3): mtd: nand: Move ELM driver and rename as omap_elm mtd: nand: Rename OMAP NAND driver mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module drivers/mtd/devices/Makefile | 1 - drivers/mtd/nand/Kconfig | 8 +++++++- drivers/mtd/nand/Makefile | 3 ++- drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 5 files changed, 9 insertions(+), 3 deletions(-) rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 06:47:02 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 10:47:02 -0300 Subject: [PATCH 1/3] mtd: nand: Move ELM driver and rename as omap_elm In-Reply-To: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410443224-18477-2-git-send-email-ezequiel@vanguardiasur.com.ar> The ELM driver is only used by the OMAP NAND driver, so let's move it to the nand/ directory. Additionally, let's rename it to a less confusing name, so the module is built with a meaningful name, instead of the previous 'elm.ko'. Signed-off-by: Ezequiel Garcia --- drivers/mtd/devices/Makefile | 1 - drivers/mtd/nand/Makefile | 1 + drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f..f0b0e61 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a035e7c..b3237b7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/nand/omap_elm.c similarity index 100% rename from drivers/mtd/devices/elm.c rename to drivers/mtd/nand/omap_elm.c -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 06:47:03 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 10:47:03 -0300 Subject: [PATCH 2/3] mtd: nand: Rename OMAP NAND driver In-Reply-To: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410443224-18477-3-git-send-email-ezequiel@vanguardiasur.com.ar> Rename it to a less generic name, so the module is built with a meaningful name instead of the previous 'omap2.ko'. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b3237b7..4bcdeb0 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2_nand.c similarity index 100% rename from drivers/mtd/nand/omap2.c rename to drivers/mtd/nand/omap2_nand.c -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 06:47:04 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 10:47:04 -0300 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> This commit adds a hidden option to build the omap_elm as a module, if omap2_nand is a module (and similarly in the built-in case). This fixes the following build error when omap2_nand is chosen built-in, and omap_elm is chosen as a module: drivers/built-in.o: In function `omap_nand_probe': /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' drivers/built-in.o: In function `omap_elm_correct_data': /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/Kconfig | 8 +++++++- drivers/mtd/nand/Makefile | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1cf503..12e8ee8 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 config MTD_NAND_OMAP_BCH depends on MTD_NAND_OMAP2 - tristate "Support hardware based BCH error correction" + bool "Support hardware based BCH error correction" default n select BCH help @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine so they should not enable this config symbol. +config MTD_NAND_OMAP_BCH_BUILD + tristate + depends on MTD_NAND_OMAP2 + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH + config MTD_NAND_IDS tristate diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 4bcdeb0..3580188 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o -- 2.1.0 From shijie8 at gmail.com Thu Sep 11 07:25:13 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Thu, 11 Sep 2014 22:25:13 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911143616.3ebb025a@bbrezillon> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> Message-ID: <20140911142511.GA2543@localhost.localdomain> Hi Boris, On Thu, Sep 11, 2014 at 02:36:16PM +0200, Boris BREZILLON wrote: > Hi Huang, > > On Thu, 11 Sep 2014 20:09:30 +0800 > Huang Shijie wrote: > > > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > > Several MTD users (either in user or kernel space) expect a valid raw > > > access support to NAND chip devices. > > > This is particularly true for testing tools which are often touching the > > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > > default HW_ECC scheme implementation. > > > The default implementation consider the data and OOB area as properly > > > separated in their respective NAND section, which is not true for the GPMI > > > controller. > > > In this driver/controller some OOB data are stored at the beginning of the > > > NAND data area (these data are called metadata in the driver), then ECC > > > bytes are interleaved with data chunk (which is similar to the > > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > > OOB data. > > > > > > Signed-off-by: Boris BREZILLON > > > --- > > > Hello, > > > > > > This patch is providing raw access support to the GPMI driver which is > > > particularly useful to run some tests on the NAND (the one coming in > > > mind is the mtd_nandbiterrs testsuite). > > > > > > I know this rework might break several user space tools which are relying > > > on the default raw access implementation (I already experienced an issue > > > with the kobs-ng tool provided by freescale), but many other tools will > > > now work as expected. > > If the kobs-ng can not works, there is no meaning that other tools > > works. So I do not think we need to implement these hooks. > > Well, I don't know about freescale specific tools, but at least I have > an example with mtd_nandbiterrs module. The gpmi uses the hardware ECC for the bitflips. I really do not know why the mtd_nandbiterrs is needed. IMHO, the mtd_nandbiterrs is useless for the gpmi. > This module is assuming it can write only the data part of a NAND page > without modifying the OOB area (see [1]), which in GPMI controller case > is impossible because raw write function store the data as if there > were no specific scheme, while there is one: > (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). > > Moreover, IMHO, nanddump and nandwrite tools (which can use raw > access mode when passing the appropriate option) should always return > the same kind of data no matter what NAND controller is in use on the > system => (DATA + OOB_DATA), and this is definitely not the case with > the GPMI driver. > > See how raw access on HW_ECC_SYNDROME scheme is implemented in The gpmi uses the NAND_ECC_HW, not the NAND_ECC_HW_SYNDROME. Even you really want to support the nanddump, i do not agree to add the write hook, it may crash the system. thanks Huang Shijie From shijie8 at gmail.com Thu Sep 11 07:29:32 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Thu, 11 Sep 2014 22:29:32 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140911142930.GB2543@localhost.localdomain> On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > + struct nand_chip *chip, uint8_t *buf, > + int oob_required, int page) > +{ > + struct gpmi_nand_data *this = chip->priv; > + struct bch_geometry *nfc_geo = &this->bch_geometry; > + int eccsize = nfc_geo->ecc_chunk_size; > + int eccbytes = DIV_ROUND_UP(nfc_geo->ecc_strength * nfc_geo->gf_len, > + 8); In actually, the ECC can be _NOT_ bytes aligned. you should not round up to byte. it's hard to implement this hook. thanks Huang Shijie > + uint8_t *oob = chip->oob_poi; > + int step; > + int column = 0; > + uint8_t *orig_buf = buf; > + > + chip->read_buf(mtd, oob, nfc_geo->metadata_size); > + oob += nfc_geo->metadata_size; > + > + column += nfc_geo->metadata_size; > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > + chip->read_buf(mtd, buf, eccsize); > + buf += eccsize; > + column += eccsize; > + chip->read_buf(mtd, oob, eccbytes); > + oob += eccbytes; > + column += eccbytes; > + } > + > + if (column < mtd->writesize + mtd->oobsize) > + chip->read_buf(mtd, oob, > + mtd->writesize + mtd->oobsize - column); > + > + block_mark_swapping(this, orig_buf, chip->oob_poi); > + > + return 0; > +} From boris.brezillon at free-electrons.com Thu Sep 11 07:38:47 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Thu, 11 Sep 2014 16:38:47 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911142511.GA2543@localhost.localdomain> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> Message-ID: <20140911163847.5e2f85c7@bbrezillon> Hi Huang, On Thu, 11 Sep 2014 22:25:13 +0800 Huang Shijie wrote: > Hi Boris, > > On Thu, Sep 11, 2014 at 02:36:16PM +0200, Boris BREZILLON wrote: > > Hi Huang, > > > > On Thu, 11 Sep 2014 20:09:30 +0800 > > Huang Shijie wrote: > > > > > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > > > Several MTD users (either in user or kernel space) expect a valid raw > > > > access support to NAND chip devices. > > > > This is particularly true for testing tools which are often touching the > > > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > > > default HW_ECC scheme implementation. > > > > The default implementation consider the data and OOB area as properly > > > > separated in their respective NAND section, which is not true for the GPMI > > > > controller. > > > > In this driver/controller some OOB data are stored at the beginning of the > > > > NAND data area (these data are called metadata in the driver), then ECC > > > > bytes are interleaved with data chunk (which is similar to the > > > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > > > OOB data. > > > > > > > > Signed-off-by: Boris BREZILLON > > > > --- > > > > Hello, > > > > > > > > This patch is providing raw access support to the GPMI driver which is > > > > particularly useful to run some tests on the NAND (the one coming in > > > > mind is the mtd_nandbiterrs testsuite). > > > > > > > > I know this rework might break several user space tools which are relying > > > > on the default raw access implementation (I already experienced an issue > > > > with the kobs-ng tool provided by freescale), but many other tools will > > > > now work as expected. > > > If the kobs-ng can not works, there is no meaning that other tools > > > works. So I do not think we need to implement these hooks. > > > > Well, I don't know about freescale specific tools, but at least I have > > an example with mtd_nandbiterrs module. > > The gpmi uses the hardware ECC for the bitflips. > I really do not know why the mtd_nandbiterrs is needed. > IMHO, the mtd_nandbiterrs is useless for the gpmi. Because some folks would like to test their NAND controller/chip on their system. Just because you don't need it, doesn't mean others won't, and actually the reason I worked on these raw function is becaused I needed to validate the ECC capabilities of the GPMI ECC controller. > > > This module is assuming it can write only the data part of a NAND page > > without modifying the OOB area (see [1]), which in GPMI controller case > > is impossible because raw write function store the data as if there > > were no specific scheme, while there is one: > > (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). > > > > Moreover, IMHO, nanddump and nandwrite tools (which can use raw > > access mode when passing the appropriate option) should always return > > the same kind of data no matter what NAND controller is in use on the > > system => (DATA + OOB_DATA), and this is definitely not the case with > > the GPMI driver. > > > > See how raw access on HW_ECC_SYNDROME scheme is implemented in > The gpmi uses the NAND_ECC_HW, not the NAND_ECC_HW_SYNDROME. Yes I know. I pointed out the NAND_ECC_HW_SYNDROME scheme as an example to show you that NAND controller specific layout should be hidden to the MTD user. > Even you really want to support the nanddump, i do not agree to add the > write hook, it may crash the system. We can't have an asymetric behaviour here, either we move both read and write raw functions or none. Moving only one of them would make the MTD user work even more complicated. I really don't get your point here. What's really bothering you (BTW, I fixed kobs-ng to handle this new behaviour) ? Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From alexandre.belloni at free-electrons.com Thu Sep 11 07:43:37 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Thu, 11 Sep 2014 16:43:37 +0200 Subject: [PATCH] mtd: nand: atmel_nand: retrieve NFC clock Message-ID: <1410446617-29572-1-git-send-email-alexandre.belloni@free-electrons.com> From: Boris BREZILLON Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/atmel_nand.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717bda54..ba64b1c91314 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2276,6 +2280,16 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) } } + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(nfc->clk)) { + dev_warn(&pdev->dev, "NFC clock is missing"); + return 0; + } + + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ @@ -2284,6 +2298,16 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) return 0; } +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + + return 0; +} + static const struct of_device_id atmel_nand_nfc_match[] = { { .compatible = "atmel,sama5d3-nfc" }, { /* sentinel */ } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- 1.9.1 From boris.brezillon at free-electrons.com Thu Sep 11 07:45:36 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Thu, 11 Sep 2014 16:45:36 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911142930.GB2543@localhost.localdomain> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911142930.GB2543@localhost.localdomain> Message-ID: <20140911164536.796f1012@bbrezillon> On Thu, 11 Sep 2014 22:29:32 +0800 Huang Shijie wrote: > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > > + struct nand_chip *chip, uint8_t *buf, > > + int oob_required, int page) > > +{ > > + struct gpmi_nand_data *this = chip->priv; > > + struct bch_geometry *nfc_geo = &this->bch_geometry; > > + int eccsize = nfc_geo->ecc_chunk_size; > > + int eccbytes = DIV_ROUND_UP(nfc_geo->ecc_strength * nfc_geo->gf_len, > > + 8); > > In actually, the ECC can be _NOT_ bytes aligned. > you should not round up to byte. You mean, on the NAND storage ? That would be weird, but I'll check. When accessing in raw mode I'm not using the ECC engine (or at least that's what I'm trying to achieve when using read_buf and not gpmi_ecc_read_page). -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From ezequiel at vanguardiasur.com.ar Thu Sep 11 08:02:08 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 12:02:08 -0300 Subject: [PATCH v3 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> This commit adds a new platform-data boolean property that enables use of a flash-based bad block table. This can also be enabled by setting the 'nand-on-flash-bbt' devicetree property. If the flash BBT is not enabled, the driver falls back to use OOB bad block markers only, as before. If the flash BBT is enabled the kernel will keep track of bad blocks using a BBT, in addition to the OOB markers. As explained by Brian Norris the reasons for using a BBT are: "" The primary reason would be that NAND datasheets specify it these days. A better argument is that nobody guarantees that you can write a bad block marker to a worn out block; you may just get program failures. This has been acknowledged by several developers over the last several years. Additionally, you get a boot-time performance improvement if you only have to read a few pages, instead of a page or two from every block on the flash. "" Signed-off-by: Ezequiel Garcia --- arch/arm/mach-omap2/gpmc.c | 2 ++ drivers/mtd/nand/omap2.c | 6 +++++- include/linux/platform_data/mtd-nand-omap2.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 2f97228..b55a225 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5967b38..e1a9b31 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) mtd->owner = THIS_MODULE; nand_chip = &info->nand; nand_chip->ecc.priv = NULL; - nand_chip->options |= NAND_SKIP_BBTSCAN; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 50; } + if (pdata->flash_bbt) + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + else + nand_chip->options |= NAND_SKIP_BBTSCAN; + /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 16ec262..090bbab 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -71,6 +71,7 @@ struct omap_nand_platform_data { struct mtd_partition *parts; int nr_parts; bool dev_ready; + bool flash_bbt; enum nand_io xfer_type; int devsize; enum omap_ecc ecc_opt; -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 08:02:07 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 12:02:07 -0300 Subject: [PATCH v3 0/3] nand: omap2: Two and a half improvements Message-ID: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> Changes from v2: * Fixed some silly mistakes in patch 3, and reverted the removed error messages when nand_bch_init fails. Changes from v1: * Rebased on v3.14-rc2. * Removed a few s/pr_err/dev_err change from patch two, and added it to patch three. This was some git-rebase leftover. Pekon's attempt to add flash BBT support for this driver made me realise the addition made sense and there were good reasons for it. The first patch adds support for enabling a flash BBT either from legacy board files or from devicetree. While testing this, I noticed how the driver relied on a whole bunch of horrible #ifdefs, which prevented me from loading the driver as a module. The second patch attempts to fix that. The third patch is just a dummy cleanup replacing pr_errs with dev_errs. This driver is abusing from user messages, but I'm not sure fixing them worths the trouble. Ezequiel Garcia (3): nand: omap2: Add support for flash-based bad block table nand: omap2: Remove horrible ifdefs to fix module probe nand: omap2: Replace pr_err with dev_err arch/arm/mach-omap2/gpmc.c | 2 + drivers/mtd/nand/omap2.c | 166 +++++++++++++++------------ include/linux/platform_data/elm.h | 14 +++ include/linux/platform_data/mtd-nand-omap2.h | 1 + 4 files changed, 110 insertions(+), 73 deletions(-) -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 08:02:09 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 12:02:09 -0300 Subject: [PATCH v3 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> The current code abuses ifdefs to determine if the selected ECC scheme is supported by the running kernel. As a result the code is hard to read, and it also fails to load as a module. This commit removes all the ifdefs and instead introduces a function omap2_nand_ecc_check() to check if the ECC is supported by using IS_ENABLED(CONFIG_xxx). Since IS_ENABLED() is true when a config is =y or =m, this change fixes the module so it can be loaded with no issues. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 130 +++++++++++++++++++++----------------- include/linux/platform_data/elm.h | 14 ++++ 2 files changed, 85 insertions(+), 59 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index e1a9b31..f97a4ff 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -136,7 +136,6 @@ #define BADBLOCK_MARKER_LENGTH 2 -#ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -#endif /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, /** * is_elm_present - checks for presence of ELM module by scanning DT nodes * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static bool is_elm_present(struct omap_nand_info *info, + struct device_node *elm_node) { struct platform_device *pdev; - struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int err; + /* check whether elm-id is passed via DT */ if (!elm_node) { pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { pr_err("nand: error: ELM device not found\n"); - return -ENODEV; + return false; } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - err = elm_config(info->elm_dev, bch_type, - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + return true; +} - return err; +static bool omap2_nand_ecc_check(struct omap_nand_info *info, + struct omap_nand_platform_data *pdata) +{ + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; + + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + ecc_needs_omap_bch = false; + ecc_needs_bch = true; + ecc_needs_elm = false; + break; + case OMAP_ECC_BCH4_CODE_HW: + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + ecc_needs_omap_bch = true; + ecc_needs_bch = false; + ecc_needs_elm = true; + break; + default: + ecc_needs_omap_bch = false; + ecc_needs_bch = false; + ecc_needs_elm = false; + break; + } + + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + return false; + } + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + return false; + } + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { + dev_err(&info->pdev->dev, "ELM not available\n"); + return false; + } + + return true; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ static int omap_nand_probe(struct platform_device *pdev) { @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } + if (!omap2_nand_ecc_check(info, pdata)) { + err = -EINVAL; + goto return_error; + } + /* populate MTD interface based on ECC scheme */ ecclayout = &omap_oobinfo; switch (info->ecc_opt) { @@ -1829,7 +1869,6 @@ static int omap_nand_probe(struct platform_device *pdev) break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1861,14 +1900,8 @@ static int omap_nand_probe(struct platform_device *pdev) err = -EINVAL; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1890,21 +1923,15 @@ static int omap_nand_probe(struct platform_device *pdev) /* reserved marker already included in ecclayout->eccbytes */ ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; + + err = elm_config(info->elm_dev, BCH4_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1937,14 +1964,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1956,12 +1977,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); + + err = elm_config(info->elm_dev, BCH8_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1973,14 +1995,8 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1991,12 +2007,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); - if (err < 0) { - pr_err("ELM is required for this ECC scheme\n"); + + err = elm_config(info->elm_dev, BCH16_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -2008,11 +2025,6 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 780d1e9..25d1bca 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,8 +42,22 @@ struct elm_errorvec { int error_loc[16]; }; +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size); +#else +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ +} + +int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_MTD_NAND_ECC_BCH */ + #endif /* __ELM_H */ -- 2.1.0 From ezequiel at vanguardiasur.com.ar Thu Sep 11 08:02:10 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 11 Sep 2014 12:02:10 -0300 Subject: [PATCH v3 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1410447730-16087-4-git-send-email-ezequiel@vanguardiasur.com.ar> Usage of pr_err is frowned upon, so replace it with dev_err. Aditionally, the message on nand_bch_init() error is redundant, since proper error is showed if the function fails. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f97a4ff..3b357e9 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, erased_ecc_vec = bch16_vector; break; default: - pr_err("invalid driver configuration\n"); + dev_err(&info->pdev->dev, "invalid driver configuration\n"); return -EINVAL; } @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, err = 0; for (i = 0; i < eccsteps; i++) { if (err_vec[i].error_uncorrectable) { - pr_err("nand: uncorrectable bit-flips found\n"); + dev_err(&info->pdev->dev, + "uncorrectable bit-flips found\n"); err = -EBADMSG; } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, 1 << bit_pos; } } else { - pr_err("invalid bit-flip @ %d:%d\n", - byte_pos, bit_pos); + dev_err(&info->pdev->dev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); err = -EBADMSG; } } @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, /* check whether elm-id is passed via DT */ if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { - pr_err("nand: error: ELM device not found\n"); + dev_err(&info->pdev->dev, "ELM device not found\n"); return false; } /* ELM module available, now configure it */ @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); err = -ENXIO; goto return_error; } /* check for small page devices */ if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); + dev_err(&info->pdev->dev, "small page devices are not supported\n"); err = -EINVAL; goto return_error; } @@ -1896,8 +1898,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; + goto return_error; } break; @@ -1959,7 +1962,7 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; goto return_error; } @@ -2026,7 +2029,7 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); err = -EINVAL; goto return_error; } @@ -2038,8 +2041,9 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); + dev_err(&info->pdev->dev, + "not enough OOB bytes required = %d, available=%d\n", + ecclayout->eccbytes, mtd->oobsize); err = -EINVAL; goto return_error; } -- 2.1.0 From ezequiel.garcia at free-electrons.com Thu Sep 11 08:20:30 2014 From: ezequiel.garcia at free-electrons.com (Ezequiel Garcia) Date: Thu, 11 Sep 2014 12:20:30 -0300 Subject: [PATCH] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410446617-29572-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410446617-29572-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <20140911152029.GA16666@arch> Hi Alexandre, On 11 Sep 04:43 PM, Alexandre Belloni wrote: > @@ -2276,6 +2280,16 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > } > } > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (IS_ERR(nfc->clk)) { > + dev_warn(&pdev->dev, "NFC clock is missing"); > + return 0; > + } > + The binding documentation makes no mention to a clock. Anyway, with or without the docs I think this patch breaks DT backward compatibility. Or am I missing something? -- Ezequiel Garc?a, Free Electrons Embedded Linux, Kernel and Android Engineering http://free-electrons.com From boris.brezillon at free-electrons.com Thu Sep 11 08:38:54 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Thu, 11 Sep 2014 17:38:54 +0200 Subject: [PATCH] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <20140911152029.GA16666@arch> References: <1410446617-29572-1-git-send-email-alexandre.belloni@free-electrons.com> <20140911152029.GA16666@arch> Message-ID: <20140911173854.73b201e7@bbrezillon> Hi Ezequiel, On Thu, 11 Sep 2014 12:20:30 -0300 Ezequiel Garcia wrote: > Hi Alexandre, > > On 11 Sep 04:43 PM, Alexandre Belloni wrote: > > @@ -2276,6 +2280,16 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > > } > > } > > > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > > + if (IS_ERR(nfc->clk)) { > > + dev_warn(&pdev->dev, "NFC clock is missing"); > > + return 0; > > + } > > + > > The binding documentation makes no mention to a clock. You're right, I didn't update atmel,nand DT binding doc. > > Anyway, with or without the docs I think this patch breaks DT backward > compatibility. > > Or am I missing something? Indeed, this block of code should be placed at the end of the probe function. I'll fix that. Note that if the clk is missing it just print a warning message and return 0, so after moving the code, it should not break DT backward compat ;-). Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From alexandre.belloni at free-electrons.com Thu Sep 11 10:52:17 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Thu, 11 Sep 2014 19:52:17 +0200 Subject: [PATCHv2] mtd: nand: atmel_nand: retrieve NFC clock Message-ID: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> From: Boris BREZILLON Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni --- Changes in v2: - reworked the error path to really make the clock optional - Documented the new optional property .../devicetree/bindings/mtd/atmel-nand.txt | 1 + drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index c4728839d0c1..f71e2ebab15b 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -38,6 +38,7 @@ Optional properties: if don't want to use it. - Optional properties: - atmel,write-by-sram: boolean to enable NFC write by sram. + - clocks: phandle to the peripheral clock if it exists Examples: nand0: nand at 40000000,0 { diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717bda54..69e0eb1ace54 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2281,6 +2285,26 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); + + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(nfc->clk)) { + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + } else { + dev_warn(&pdev->dev, "NFC clock is missing"); + } + + return 0; +} + +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + return 0; } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- 1.9.1 From thomas.petazzoni at free-electrons.com Thu Sep 11 15:05:00 2014 From: thomas.petazzoni at free-electrons.com (Thomas Petazzoni) Date: Fri, 12 Sep 2014 00:05:00 +0200 Subject: [PATCH] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <20140911173854.73b201e7@bbrezillon> References: <1410446617-29572-1-git-send-email-alexandre.belloni@free-electrons.com> <20140911152029.GA16666@arch> <20140911173854.73b201e7@bbrezillon> Message-ID: <20140912000500.5a1d5f75@free-electrons.com> Dear Boris BREZILLON, On Thu, 11 Sep 2014 17:38:54 +0200, Boris BREZILLON wrote: > > Anyway, with or without the docs I think this patch breaks DT backward > > compatibility. > > > > Or am I missing something? > > Indeed, this block of code should be placed at the end of the probe > function. I'll fix that. > > Note that if the clk is missing it just print a warning message and > return 0, so after moving the code, it should not break DT backward > compat ;-). You may want to use: dev_warn(FW_WARN "NFC clock missing, update your Device Tree\n"); Thomas -- Thomas Petazzoni, CTO, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com From shijie.huang at intel.com Thu Sep 11 17:40:47 2014 From: shijie.huang at intel.com (Huang Shijie) Date: Fri, 12 Sep 2014 08:40:47 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911164536.796f1012@bbrezillon> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911142930.GB2543@localhost.localdomain> <20140911164536.796f1012@bbrezillon> Message-ID: <20140912004047.GA26904@shldeISGChi005.sh.intel.com> On Thu, Sep 11, 2014 at 04:45:36PM +0200, Boris BREZILLON wrote: > On Thu, 11 Sep 2014 22:29:32 +0800 > Huang Shijie wrote: > > > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > > > + struct nand_chip *chip, uint8_t *buf, > > > + int oob_required, int page) > > > +{ > > > + struct gpmi_nand_data *this = chip->priv; > > > + struct bch_geometry *nfc_geo = &this->bch_geometry; > > > + int eccsize = nfc_geo->ecc_chunk_size; > > > + int eccbytes = DIV_ROUND_UP(nfc_geo->ecc_strength * nfc_geo->gf_len, > > > + 8); > > > > In actually, the ECC can be _NOT_ bytes aligned. > > you should not round up to byte. > > You mean, on the NAND storage ? That would be weird, but I'll check. yes. it is weird. thanks Huang Shijie From shijie.huang at intel.com Thu Sep 11 17:45:50 2014 From: shijie.huang at intel.com (Huang Shijie) Date: Fri, 12 Sep 2014 08:45:50 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911163847.5e2f85c7@bbrezillon> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> Message-ID: <20140912004550.GB26904@shldeISGChi005.sh.intel.com> On Thu, Sep 11, 2014 at 04:38:47PM +0200, Boris BREZILLON wrote: > Hi Huang, > > On Thu, 11 Sep 2014 22:25:13 +0800 > Huang Shijie wrote: > > > Hi Boris, > > > > On Thu, Sep 11, 2014 at 02:36:16PM +0200, Boris BREZILLON wrote: > > > Hi Huang, > > > > > > On Thu, 11 Sep 2014 20:09:30 +0800 > > > Huang Shijie wrote: > > > > > > > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > > > > Several MTD users (either in user or kernel space) expect a valid raw > > > > > access support to NAND chip devices. > > > > > This is particularly true for testing tools which are often touching the > > > > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > > > > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > > > > default HW_ECC scheme implementation. > > > > > The default implementation consider the data and OOB area as properly > > > > > separated in their respective NAND section, which is not true for the GPMI > > > > > controller. > > > > > In this driver/controller some OOB data are stored at the beginning of the > > > > > NAND data area (these data are called metadata in the driver), then ECC > > > > > bytes are interleaved with data chunk (which is similar to the > > > > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > > > > OOB data. > > > > > > > > > > Signed-off-by: Boris BREZILLON > > > > > --- > > > > > Hello, > > > > > > > > > > This patch is providing raw access support to the GPMI driver which is > > > > > particularly useful to run some tests on the NAND (the one coming in > > > > > mind is the mtd_nandbiterrs testsuite). > > > > > > > > > > I know this rework might break several user space tools which are relying > > > > > on the default raw access implementation (I already experienced an issue > > > > > with the kobs-ng tool provided by freescale), but many other tools will > > > > > now work as expected. > > > > If the kobs-ng can not works, there is no meaning that other tools > > > > works. So I do not think we need to implement these hooks. > > > > > > Well, I don't know about freescale specific tools, but at least I have > > > an example with mtd_nandbiterrs module. > > > > The gpmi uses the hardware ECC for the bitflips. > > I really do not know why the mtd_nandbiterrs is needed. > > IMHO, the mtd_nandbiterrs is useless for the gpmi. > > Because some folks would like to test their NAND controller/chip on > their system. > > Just because you don't need it, doesn't mean others won't, and actually > the reason I worked on these raw function is becaused I needed to > validate the ECC capabilities of the GPMI ECC controller. The BCH's algorithm is confidential to Freescale. How can you validate the ECC capabilities? So You can not emulate the BCH to create the ECC data, even you can fake some bitflips in the data chunk. > > > > > > This module is assuming it can write only the data part of a NAND page > > > without modifying the OOB area (see [1]), which in GPMI controller case > > > is impossible because raw write function store the data as if there > > > were no specific scheme, while there is one: > > > (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). > > > > > > Moreover, IMHO, nanddump and nandwrite tools (which can use raw > > > access mode when passing the appropriate option) should always return > > > the same kind of data no matter what NAND controller is in use on the > > > system => (DATA + OOB_DATA), and this is definitely not the case with > > > the GPMI driver. > > > > > > See how raw access on HW_ECC_SYNDROME scheme is implemented in > > The gpmi uses the NAND_ECC_HW, not the NAND_ECC_HW_SYNDROME. > > Yes I know. I pointed out the NAND_ECC_HW_SYNDROME scheme as an example > to show you that NAND controller specific layout should be hidden to > the MTD user. > > > Even you really want to support the nanddump, i do not agree to add the > > write hook, it may crash the system. > > We can't have an asymetric behaviour here, either we move both read and > write raw functions or none. Moving only one of them would make the MTD > user work even more complicated. > > I really don't get your point here. What's really bothering you (BTW, I > fixed kobs-ng to handle this new behaviour) ? see the comment above. thanks Huang Shijie From nicolas.ferre at atmel.com Fri Sep 12 00:52:48 2014 From: nicolas.ferre at atmel.com (Nicolas Ferre) Date: Fri, 12 Sep 2014 09:52:48 +0200 Subject: [PATCHv2] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <5412A650.60102@atmel.com> On 11/09/2014 19:52, Alexandre Belloni : > From: Boris BREZILLON > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni You may need to add Josh Wu to the list because he is the "de-facto" Maintainer of this driver. Bye, > --- > > Changes in v2: > - reworked the error path to really make the clock optional > - Documented the new optional property > > .../devicetree/bindings/mtd/atmel-nand.txt | 1 + > drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c4728839d0c1..f71e2ebab15b 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -38,6 +38,7 @@ Optional properties: > if don't want to use it. > - Optional properties: > - atmel,write-by-sram: boolean to enable NFC write by sram. > + - clocks: phandle to the peripheral clock if it exists > > Examples: > nand0: nand at 40000000,0 { > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717bda54..69e0eb1ace54 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,7 @@ > * > */ > > +#include > #include > #include > #include > @@ -96,6 +97,8 @@ struct atmel_nfc { > bool use_nfc_sram; > bool write_by_sram; > > + struct clk *clk; > + > bool is_initialized; > struct completion comp_ready; > struct completion comp_cmd_done; > @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > { > struct atmel_nfc *nfc = &nand_nfc; > struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; > + int ret; > > nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); > @@ -2281,6 +2285,26 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > > nfc->is_initialized = true; > dev_info(&pdev->dev, "NFC is probed.\n"); > + > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (!IS_ERR(nfc->clk)) { > + ret = clk_prepare_enable(nfc->clk); > + if (ret) > + return ret; > + } else { > + dev_warn(&pdev->dev, "NFC clock is missing"); > + } > + > + return 0; > +} > + > +static int atmel_nand_nfc_remove(struct platform_device *pdev) > +{ > + struct atmel_nfc *nfc = &nand_nfc; > + > + if (!IS_ERR(nfc->clk)) > + clk_disable_unprepare(nfc->clk); > + > return 0; > } > > @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { > .of_match_table = of_match_ptr(atmel_nand_nfc_match), > }, > .probe = atmel_nand_nfc_probe, > + .remove = atmel_nand_nfc_remove, > }; > > static struct platform_driver atmel_nand_driver = { > -- Nicolas Ferre From josh.wu at atmel.com Fri Sep 12 01:40:22 2014 From: josh.wu at atmel.com (Josh Wu) Date: Fri, 12 Sep 2014 16:40:22 +0800 Subject: [PATCHv2] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <5412B176.9020507@atmel.com> Hi, Alexandre On 9/12/2014 1:52 AM, Alexandre Belloni wrote: > From: Boris BREZILLON > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > --- > > Changes in v2: > - reworked the error path to really make the clock optional > - Documented the new optional property > > .../devicetree/bindings/mtd/atmel-nand.txt | 1 + > drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c4728839d0c1..f71e2ebab15b 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -38,6 +38,7 @@ Optional properties: > if don't want to use it. > - Optional properties: > - atmel,write-by-sram: boolean to enable NFC write by sram. > + - clocks: phandle to the peripheral clock if it exists > > Examples: > nand0: nand at 40000000,0 { > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717bda54..69e0eb1ace54 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,7 @@ > * > */ > > +#include > #include > #include > #include > @@ -96,6 +97,8 @@ struct atmel_nfc { > bool use_nfc_sram; > bool write_by_sram; > > + struct clk *clk; > + > bool is_initialized; > struct completion comp_ready; > struct completion comp_cmd_done; > @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > { > struct atmel_nfc *nfc = &nand_nfc; > struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; > + int ret; > > nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); > @@ -2281,6 +2285,26 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > > nfc->is_initialized = true; > dev_info(&pdev->dev, "NFC is probed.\n"); > + > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (!IS_ERR(nfc->clk)) { > + ret = clk_prepare_enable(nfc->clk); > + if (ret) > + return ret; In this case, the NFC clock is not enabled, so I think nfc->is_initialized should set to false. Otherwise, the nand driver will try to use the NFC without enabled the clock. Is it better to move the code block nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); to just before the: return 0; Best Regards, Josh Wu > + } else { > + dev_warn(&pdev->dev, "NFC clock is missing"); > + } > + > + return 0; > +} > + > +static int atmel_nand_nfc_remove(struct platform_device *pdev) > +{ > + struct atmel_nfc *nfc = &nand_nfc; > + > + if (!IS_ERR(nfc->clk)) > + clk_disable_unprepare(nfc->clk); > + > return 0; > } > > @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { > .of_match_table = of_match_ptr(atmel_nand_nfc_match), > }, > .probe = atmel_nand_nfc_probe, > + .remove = atmel_nand_nfc_remove, > }; > > static struct platform_driver atmel_nand_driver = { From josh.wu at atmel.com Fri Sep 12 01:48:34 2014 From: josh.wu at atmel.com (Josh Wu) Date: Fri, 12 Sep 2014 16:48:34 +0800 Subject: [PATCHv2] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <5412A650.60102@atmel.com> References: <1410457937-14575-1-git-send-email-alexandre.belloni@free-electrons.com> <5412A650.60102@atmel.com> Message-ID: <5412B362.1090206@atmel.com> Hi, Nicolas On 9/12/2014 3:52 PM, Nicolas Ferre wrote: > On 11/09/2014 19:52, Alexandre Belloni : >> From: Boris BREZILLON >> >> Signed-off-by: Boris BREZILLON >> Signed-off-by: Alexandre Belloni > You may need to add Josh Wu to the list because he is the "de-facto" > Maintainer of this driver. Thanks for the email. I almost miss it. Best Regards, Josh Wu > > Bye, > >> --- >> >> Changes in v2: >> - reworked the error path to really make the clock optional >> - Documented the new optional property >> >> .../devicetree/bindings/mtd/atmel-nand.txt | 1 + >> drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ >> 2 files changed, 26 insertions(+) >> >> diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> index c4728839d0c1..f71e2ebab15b 100644 >> --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> @@ -38,6 +38,7 @@ Optional properties: >> if don't want to use it. >> - Optional properties: >> - atmel,write-by-sram: boolean to enable NFC write by sram. >> + - clocks: phandle to the peripheral clock if it exists >> >> Examples: >> nand0: nand at 40000000,0 { >> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c >> index 9c5f717bda54..69e0eb1ace54 100644 >> --- a/drivers/mtd/nand/atmel_nand.c >> +++ b/drivers/mtd/nand/atmel_nand.c >> @@ -27,6 +27,7 @@ >> * >> */ >> >> +#include >> #include >> #include >> #include >> @@ -96,6 +97,8 @@ struct atmel_nfc { >> bool use_nfc_sram; >> bool write_by_sram; >> >> + struct clk *clk; >> + >> bool is_initialized; >> struct completion comp_ready; >> struct completion comp_cmd_done; >> @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) >> { >> struct atmel_nfc *nfc = &nand_nfc; >> struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; >> + int ret; >> >> nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); >> @@ -2281,6 +2285,26 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) >> >> nfc->is_initialized = true; >> dev_info(&pdev->dev, "NFC is probed.\n"); >> + >> + nfc->clk = devm_clk_get(&pdev->dev, NULL); >> + if (!IS_ERR(nfc->clk)) { >> + ret = clk_prepare_enable(nfc->clk); >> + if (ret) >> + return ret; >> + } else { >> + dev_warn(&pdev->dev, "NFC clock is missing"); >> + } >> + >> + return 0; >> +} >> + >> +static int atmel_nand_nfc_remove(struct platform_device *pdev) >> +{ >> + struct atmel_nfc *nfc = &nand_nfc; >> + >> + if (!IS_ERR(nfc->clk)) >> + clk_disable_unprepare(nfc->clk); >> + >> return 0; >> } >> >> @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { >> .of_match_table = of_match_ptr(atmel_nand_nfc_match), >> }, >> .probe = atmel_nand_nfc_probe, >> + .remove = atmel_nand_nfc_remove, >> }; >> >> static struct platform_driver atmel_nand_driver = { >> > From rogerq at ti.com Fri Sep 12 01:54:24 2014 From: rogerq at ti.com (Roger Quadros) Date: Fri, 12 Sep 2014 11:54:24 +0300 Subject: [PATCH 0/3] nand: Renaming, moving and fixing NAND and ELM drivers In-Reply-To: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5412B4C0.505@ti.com> Hi Ezequiel, On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > Following the recent discussion with Roger, here's a few patches that > (hopefully) fix all the issues. > > The first patches rename the OMAP NAND drivers, so they are now called > omap2_nand and omap_elm. > > The last patch picks an idea from Yann E. Morin and fixes the build issue > reported by Roger. Quoting Roger: > > "" > I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and > CONFIG_MTD_NAND_OMAP_BCH to m. > > CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to > be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. > > Maybe it should be a sub option of CONFIG_MTD_NAND_OMAP2. > IMHO the elm.c file must be moved from mtd/devices to mtd/nand and renamed to omap_elm.c > > drivers/built-in.o: In function `omap_nand_probe': > /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > drivers/built-in.o: In function `omap_elm_correct_data': > /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > make: *** [vmlinux] Error 1 > "" > > [1] https://lkml.org/lkml/2013/5/4/84 > > Ezequiel Garcia (3): > mtd: nand: Move ELM driver and rename as omap_elm > mtd: nand: Rename OMAP NAND driver > mtd: nand: Force omap_elm to be built as a module if omap2_nand is a > module Thanks for the patches. I see a lot of errors reported by checkpatch.pl which need fixing. cheers, -roger > > drivers/mtd/devices/Makefile | 1 - > drivers/mtd/nand/Kconfig | 8 +++++++- > drivers/mtd/nand/Makefile | 3 ++- > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 > drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 > 5 files changed, 9 insertions(+), 3 deletions(-) > rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) > rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) > From rogerq at ti.com Fri Sep 12 01:55:30 2014 From: rogerq at ti.com (Roger Quadros) Date: Fri, 12 Sep 2014 11:55:30 +0300 Subject: [PATCH 2/3] mtd: nand: Rename OMAP NAND driver In-Reply-To: <1410443224-18477-3-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-3-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5412B502.3090305@ti.com> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > Rename it to a less generic name, so the module is built with a meaningful > name instead of the previous 'omap2.ko'. > > Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros > --- > drivers/mtd/nand/Makefile | 2 +- > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 > 2 files changed, 1 insertion(+), 1 deletion(-) > rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) > > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile > index b3237b7..4bcdeb0 100644 > --- a/drivers/mtd/nand/Makefile > +++ b/drivers/mtd/nand/Makefile > @@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o > obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o > obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o > obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o > -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o > +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o > obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o > obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o > obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2_nand.c > similarity index 100% > rename from drivers/mtd/nand/omap2.c > rename to drivers/mtd/nand/omap2_nand.c > From rogerq at ti.com Fri Sep 12 01:55:06 2014 From: rogerq at ti.com (Roger Quadros) Date: Fri, 12 Sep 2014 11:55:06 +0300 Subject: [PATCH 1/3] mtd: nand: Move ELM driver and rename as omap_elm In-Reply-To: <1410443224-18477-2-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-2-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5412B4EA.6080201@ti.com> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > The ELM driver is only used by the OMAP NAND driver, so let's move it > to the nand/ directory. Additionally, let's rename it to a less confusing > name, so the module is built with a meaningful name, instead of the previous > 'elm.ko'. > > Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros > --- > drivers/mtd/devices/Makefile | 1 - > drivers/mtd/nand/Makefile | 1 + > drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 > 3 files changed, 1 insertion(+), 1 deletion(-) > rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) > > diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile > index c68868f..f0b0e61 100644 > --- a/drivers/mtd/devices/Makefile > +++ b/drivers/mtd/devices/Makefile > @@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o > obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o > obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o > obj-$(CONFIG_MTD_M25P80) += m25p80.o > -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o > obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o > obj-$(CONFIG_MTD_SST25L) += sst25l.o > obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile > index a035e7c..b3237b7 100644 > --- a/drivers/mtd/nand/Makefile > +++ b/drivers/mtd/nand/Makefile > @@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o > obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o > obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o > obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o > +obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o > obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o > obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o > obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o > diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/nand/omap_elm.c > similarity index 100% > rename from drivers/mtd/devices/elm.c > rename to drivers/mtd/nand/omap_elm.c > From rogerq at ti.com Fri Sep 12 02:01:35 2014 From: rogerq at ti.com (Roger Quadros) Date: Fri, 12 Sep 2014 12:01:35 +0300 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5412B66F.8050505@ti.com> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > This commit adds a hidden option to build the omap_elm as a module, if > omap2_nand is a module (and similarly in the built-in case). > > This fixes the following build error when omap2_nand is chosen built-in, > and omap_elm is chosen as a module: > > drivers/built-in.o: In function `omap_nand_probe': > /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > drivers/built-in.o: In function `omap_elm_correct_data': > /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > > Signed-off-by: Ezequiel Garcia > --- > drivers/mtd/nand/Kconfig | 8 +++++++- > drivers/mtd/nand/Makefile | 2 +- > 2 files changed, 8 insertions(+), 2 deletions(-) > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > index f1cf503..12e8ee8 100644 > --- a/drivers/mtd/nand/Kconfig > +++ b/drivers/mtd/nand/Kconfig > @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 > > config MTD_NAND_OMAP_BCH > depends on MTD_NAND_OMAP2 > - tristate "Support hardware based BCH error correction" > + bool "Support hardware based BCH error correction" > default n > select BCH > help > @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH > legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine > so they should not enable this config symbol. > > +config MTD_NAND_OMAP_BCH_BUILD > + tristate > + depends on MTD_NAND_OMAP2 > + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH > + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH > + > config MTD_NAND_IDS > tristate > > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile > index 4bcdeb0..3580188 100644 > --- a/drivers/mtd/nand/Makefile > +++ b/drivers/mtd/nand/Makefile > @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o > obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o > obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o > obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o > -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o > +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o > obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o > obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o > obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o > The overall logic seems to work but I still see the following issue. In menuconfig, the OMAP_BCH option is still visible as a boolean even though the ELM module finally gets built as a module. This can be confusing to the user and I'd avoid that behaviour. cheers, -roger From alexandre.belloni at free-electrons.com Fri Sep 12 02:07:46 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Fri, 12 Sep 2014 11:07:46 +0200 Subject: [PATCHv3] mtd: nand: atmel_nand: retrieve NFC clock Message-ID: <1410512866-24546-1-git-send-email-alexandre.belloni@free-electrons.com> From: Boris BREZILLON Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni --- Changes in v3: - changed the warning message to ask to update the DT - made the clocks property mandatory in the documentation - Stop claiming the NFC is probed if there is an issue when enabling the clock .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index c4728839d0c1..cb6cd4f8ae7a 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -36,6 +36,7 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - clocks: phandle to the peripheral clock - Optional properties: - atmel,write-by-sram: boolean to enable NFC write by sram. @@ -98,6 +99,7 @@ nand0: nand at 40000000 { compatible = "atmel,sama5d3-nfc"; #address-cells = <1>; #size-cells = <1>; + clocks = <&&hsmc_clk> reg = < 0x70000000 0x10000000 /* NFC Command Registers */ 0xffffc000 0x00000070 /* NFC HSMC regs */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717bda54..d1e502f8dbd0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(nfc->clk)) { + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + } else { + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); + } + nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); + + return 0; +} + +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + return 0; } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- 1.9.1 From josh.wu at atmel.com Fri Sep 12 02:21:05 2014 From: josh.wu at atmel.com (Josh Wu) Date: Fri, 12 Sep 2014 17:21:05 +0800 Subject: [PATCHv3] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410512866-24546-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410512866-24546-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <5412BB01.6070401@atmel.com> Hi, Alexandre On 9/12/2014 5:07 PM, Alexandre Belloni wrote: > From: Boris BREZILLON > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > --- > > Changes in v3: > - changed the warning message to ask to update the DT > - made the clocks property mandatory in the documentation > - Stop claiming the NFC is probed if there is an issue when enabling the clock > > .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ > drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ > 2 files changed, 27 insertions(+) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c4728839d0c1..cb6cd4f8ae7a 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -36,6 +36,7 @@ Optional properties: > - reg : should specify the address and size used for NFC command registers, > NFC registers and NFC Sram. NFC Sram address and size can be absent > if don't want to use it. > + - clocks: phandle to the peripheral clock > - Optional properties: > - atmel,write-by-sram: boolean to enable NFC write by sram. > > @@ -98,6 +99,7 @@ nand0: nand at 40000000 { > compatible = "atmel,sama5d3-nfc"; > #address-cells = <1>; > #size-cells = <1>; > + clocks = <&&hsmc_clk> Is it a typo here? Do you mean clocks = <&hsmc_clk> Best Regards, Josh Wu > reg = < > 0x70000000 0x10000000 /* NFC Command Registers */ > 0xffffc000 0x00000070 /* NFC HSMC regs */ > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717bda54..d1e502f8dbd0 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,7 @@ > * > */ > > +#include > #include > #include > #include > @@ -96,6 +97,8 @@ struct atmel_nfc { > bool use_nfc_sram; > bool write_by_sram; > > + struct clk *clk; > + > bool is_initialized; > struct completion comp_ready; > struct completion comp_cmd_done; > @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > { > struct atmel_nfc *nfc = &nand_nfc; > struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; > + int ret; > > nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); > @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); > nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (!IS_ERR(nfc->clk)) { > + ret = clk_prepare_enable(nfc->clk); > + if (ret) > + return ret; > + } else { > + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); > + } > + > nfc->is_initialized = true; > dev_info(&pdev->dev, "NFC is probed.\n"); > + > + return 0; > +} > + > +static int atmel_nand_nfc_remove(struct platform_device *pdev) > +{ > + struct atmel_nfc *nfc = &nand_nfc; > + > + if (!IS_ERR(nfc->clk)) > + clk_disable_unprepare(nfc->clk); > + > return 0; > } > > @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { > .of_match_table = of_match_ptr(atmel_nand_nfc_match), > }, > .probe = atmel_nand_nfc_probe, > + .remove = atmel_nand_nfc_remove, > }; > > static struct platform_driver atmel_nand_driver = { From alexandre.belloni at free-electrons.com Fri Sep 12 02:40:09 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Fri, 12 Sep 2014 11:40:09 +0200 Subject: [PATCHv4] mtd: nand: atmel_nand: retrieve NFC clock Message-ID: <1410514809-25650-1-git-send-email-alexandre.belloni@free-electrons.com> From: Boris BREZILLON Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni --- Changes in v4: - fix typo in the documentation .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index c4728839d0c1..6edc3b616e98 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -36,6 +36,7 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - clocks: phandle to the peripheral clock - Optional properties: - atmel,write-by-sram: boolean to enable NFC write by sram. @@ -98,6 +99,7 @@ nand0: nand at 40000000 { compatible = "atmel,sama5d3-nfc"; #address-cells = <1>; #size-cells = <1>; + clocks = <&hsmc_clk> reg = < 0x70000000 0x10000000 /* NFC Command Registers */ 0xffffc000 0x00000070 /* NFC HSMC regs */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717bda54..d1e502f8dbd0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(nfc->clk)) { + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + } else { + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); + } + nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); + + return 0; +} + +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + return 0; } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- 1.9.1 From josh.wu at atmel.com Fri Sep 12 02:54:46 2014 From: josh.wu at atmel.com (Josh Wu) Date: Fri, 12 Sep 2014 17:54:46 +0800 Subject: [PATCHv4] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410514809-25650-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410514809-25650-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <5412C2E6.8030602@atmel.com> Hi, Alexandre On 9/12/2014 5:40 PM, Alexandre Belloni wrote: > From: Boris BREZILLON > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > --- Thanks for the patch. Acked-by: Josh Wu Best Regards, Josh Wu > > Changes in v4: > - fix typo in the documentation > > .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ > drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ > 2 files changed, 27 insertions(+) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c4728839d0c1..6edc3b616e98 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -36,6 +36,7 @@ Optional properties: > - reg : should specify the address and size used for NFC command registers, > NFC registers and NFC Sram. NFC Sram address and size can be absent > if don't want to use it. > + - clocks: phandle to the peripheral clock > - Optional properties: > - atmel,write-by-sram: boolean to enable NFC write by sram. > > @@ -98,6 +99,7 @@ nand0: nand at 40000000 { > compatible = "atmel,sama5d3-nfc"; > #address-cells = <1>; > #size-cells = <1>; > + clocks = <&hsmc_clk> > reg = < > 0x70000000 0x10000000 /* NFC Command Registers */ > 0xffffc000 0x00000070 /* NFC HSMC regs */ > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717bda54..d1e502f8dbd0 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,7 @@ > * > */ > > +#include > #include > #include > #include > @@ -96,6 +97,8 @@ struct atmel_nfc { > bool use_nfc_sram; > bool write_by_sram; > > + struct clk *clk; > + > bool is_initialized; > struct completion comp_ready; > struct completion comp_cmd_done; > @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > { > struct atmel_nfc *nfc = &nand_nfc; > struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; > + int ret; > > nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); > @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); > nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (!IS_ERR(nfc->clk)) { > + ret = clk_prepare_enable(nfc->clk); > + if (ret) > + return ret; > + } else { > + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); > + } > + > nfc->is_initialized = true; > dev_info(&pdev->dev, "NFC is probed.\n"); > + > + return 0; > +} > + > +static int atmel_nand_nfc_remove(struct platform_device *pdev) > +{ > + struct atmel_nfc *nfc = &nand_nfc; > + > + if (!IS_ERR(nfc->clk)) > + clk_disable_unprepare(nfc->clk); > + > return 0; > } > > @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { > .of_match_table = of_match_ptr(atmel_nand_nfc_match), > }, > .probe = atmel_nand_nfc_probe, > + .remove = atmel_nand_nfc_remove, > }; > > static struct platform_driver atmel_nand_driver = { From boris.brezillon at free-electrons.com Fri Sep 12 05:30:50 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Fri, 12 Sep 2014 14:30:50 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140912004550.GB26904@shldeISGChi005.sh.intel.com> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> Message-ID: <20140912143050.014ad4c3@bbrezillon> On Fri, 12 Sep 2014 08:45:50 +0800 Huang Shijie wrote: > On Thu, Sep 11, 2014 at 04:38:47PM +0200, Boris BREZILLON wrote: > > Hi Huang, > > > > On Thu, 11 Sep 2014 22:25:13 +0800 > > Huang Shijie wrote: > > > > > Hi Boris, > > > > > > On Thu, Sep 11, 2014 at 02:36:16PM +0200, Boris BREZILLON wrote: > > > > Hi Huang, > > > > > > > > On Thu, 11 Sep 2014 20:09:30 +0800 > > > > Huang Shijie wrote: > > > > > > > > > On Wed, Sep 10, 2014 at 10:55:39AM +0200, Boris BREZILLON wrote: > > > > > > Several MTD users (either in user or kernel space) expect a valid raw > > > > > > access support to NAND chip devices. > > > > > > This is particularly true for testing tools which are often touching the > > > > > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > > > > > > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > > > > > default HW_ECC scheme implementation. > > > > > > The default implementation consider the data and OOB area as properly > > > > > > separated in their respective NAND section, which is not true for the GPMI > > > > > > controller. > > > > > > In this driver/controller some OOB data are stored at the beginning of the > > > > > > NAND data area (these data are called metadata in the driver), then ECC > > > > > > bytes are interleaved with data chunk (which is similar to the > > > > > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > > > > > OOB data. > > > > > > > > > > > > Signed-off-by: Boris BREZILLON > > > > > > --- > > > > > > Hello, > > > > > > > > > > > > This patch is providing raw access support to the GPMI driver which is > > > > > > particularly useful to run some tests on the NAND (the one coming in > > > > > > mind is the mtd_nandbiterrs testsuite). > > > > > > > > > > > > I know this rework might break several user space tools which are relying > > > > > > on the default raw access implementation (I already experienced an issue > > > > > > with the kobs-ng tool provided by freescale), but many other tools will > > > > > > now work as expected. > > > > > If the kobs-ng can not works, there is no meaning that other tools > > > > > works. So I do not think we need to implement these hooks. > > > > > > > > Well, I don't know about freescale specific tools, but at least I have > > > > an example with mtd_nandbiterrs module. > > > > > > The gpmi uses the hardware ECC for the bitflips. > > > I really do not know why the mtd_nandbiterrs is needed. > > > IMHO, the mtd_nandbiterrs is useless for the gpmi. > > > > Because some folks would like to test their NAND controller/chip on > > their system. > > > > Just because you don't need it, doesn't mean others won't, and actually > > the reason I worked on these raw function is becaused I needed to > > validate the ECC capabilities of the GPMI ECC controller. > The BCH's algorithm is confidential to Freescale. > How can you validate the ECC capabilities? My bad, capabilities might not be the appropriate word in this context. I meant ECC algorithm strength, and that's exactly the purpose of nandbiterrs testsuite: insert bitflips in in-band data until the MTD layer complains about uncorrectable errors. This test validates what's returned by ecc_strength file in sysfs (which in turn is specified by the NAND controller when initializing the NAND chip). Doing this should not imply knowing the ECC algorithm in use in the NAND controller or the layout used to store data on NAND. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From ezequiel at vanguardiasur.com.ar Fri Sep 12 09:46:37 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Fri, 12 Sep 2014 17:46:37 +0100 Subject: [PATCH 0/3] nand: Renaming, moving and fixing NAND and ELM drivers In-Reply-To: <5412B4C0.505@ti.com> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B4C0.505@ti.com> Message-ID: On 12 September 2014 09:54, Roger Quadros wrote: > Hi Ezequiel, > > On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >> Following the recent discussion with Roger, here's a few patches that >> (hopefully) fix all the issues. >> >> The first patches rename the OMAP NAND drivers, so they are now called >> omap2_nand and omap_elm. >> >> The last patch picks an idea from Yann E. Morin and fixes the build issue >> reported by Roger. Quoting Roger: >> >> "" >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and >> CONFIG_MTD_NAND_OMAP_BCH to m. >> >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. >> >> Maybe it should be a sub option of CONFIG_MTD_NAND_OMAP2. >> IMHO the elm.c file must be moved from mtd/devices to mtd/nand and renamed to omap_elm.c >> >> drivers/built-in.o: In function `omap_nand_probe': >> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >> drivers/built-in.o: In function `omap_elm_correct_data': >> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >> make: *** [vmlinux] Error 1 >> "" >> >> [1] https://lkml.org/lkml/2013/5/4/84 >> >> Ezequiel Garcia (3): >> mtd: nand: Move ELM driver and rename as omap_elm >> mtd: nand: Rename OMAP NAND driver >> mtd: nand: Force omap_elm to be built as a module if omap2_nand is a >> module > > Thanks for the patches. I see a lot of errors reported by checkpatch.pl which need fixing. > You mean on these patches or across the file? -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Fri Sep 12 09:56:36 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Fri, 12 Sep 2014 17:56:36 +0100 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <5412B66F.8050505@ti.com> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> Message-ID: <20140912165636.GA7276@arch> On 12 Sep 12:01 PM, Roger Quadros wrote: > On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > > This commit adds a hidden option to build the omap_elm as a module, if > > omap2_nand is a module (and similarly in the built-in case). > > > > This fixes the following build error when omap2_nand is chosen built-in, > > and omap_elm is chosen as a module: > > > > drivers/built-in.o: In function `omap_nand_probe': > > /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > > /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > > /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > > drivers/built-in.o: In function `omap_elm_correct_data': > > /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > > > > Signed-off-by: Ezequiel Garcia > > --- > > drivers/mtd/nand/Kconfig | 8 +++++++- > > drivers/mtd/nand/Makefile | 2 +- > > 2 files changed, 8 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > > index f1cf503..12e8ee8 100644 > > --- a/drivers/mtd/nand/Kconfig > > +++ b/drivers/mtd/nand/Kconfig > > @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 > > > > config MTD_NAND_OMAP_BCH > > depends on MTD_NAND_OMAP2 > > - tristate "Support hardware based BCH error correction" > > + bool "Support hardware based BCH error correction" > > default n > > select BCH > > help > > @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH > > legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine > > so they should not enable this config symbol. > > > > +config MTD_NAND_OMAP_BCH_BUILD > > + tristate > > + depends on MTD_NAND_OMAP2 > > + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH > > + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH > > + > > config MTD_NAND_IDS > > tristate > > > > diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile > > index 4bcdeb0..3580188 100644 > > --- a/drivers/mtd/nand/Makefile > > +++ b/drivers/mtd/nand/Makefile > > @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o > > obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o > > obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o > > obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o > > -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o > > +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o > > obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o > > obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o > > obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o > > > > The overall logic seems to work but I still see the following issue. > > In menuconfig, the OMAP_BCH option is still visible as a boolean even though > the ELM module finally gets built as a module. > This can be confusing to the user and I'd avoid that behaviour. > Yes, I know. But it's either this solution or no solution at all, I think. Let me give some further context about this patch, so we can have more information to decide. First of all (and IMO) the user doesn't have to know about the ELM being a module or not, because modprobe will load it (since omap2_nand depends on omap_elm's symbols). So, the new way seems a bit more intuitive for me. The user choses if he wants to have hardware BCH support, and such support gets built the right way. If we still consider this highly confusing, and we want to avoid it, then it seems we can only make omap_elm a boolean, which means it'll always be built-in. I crafted this patch in an effort to avoid making it boolean. Finally, the solution is taken from media/usb/stk1160. For good or for bad, we have a precedent in doing things this way. Ultimately, I don't care much as I don't think anyone will build it as a module, except maybe for testing the driver under probe/remove cycles. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Fri Sep 12 10:06:19 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Fri, 12 Sep 2014 18:06:19 +0100 Subject: [PATCHv4] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410514809-25650-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410514809-25650-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: On 12 September 2014 10:40, Alexandre Belloni wrote: > From: Boris BREZILLON > This patch needs a commit log. > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > --- > -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From alexandre.belloni at free-electrons.com Fri Sep 12 16:23:59 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Sat, 13 Sep 2014 01:23:59 +0200 Subject: [PATCHv5] mtd: nand: atmel_nand: retrieve NFC clock Message-ID: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> From: Boris BREZILLON Retrieve the NFC clock to make sure it is enabled. Make that optional to ensure compatibility with previous device trees but document it as mandatory so newer device trees will include it. Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni Acked-by: Josh Wu --- Changes in v5: - Added a proper commit log .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index c4728839d0c1..6edc3b616e98 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -36,6 +36,7 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - clocks: phandle to the peripheral clock - Optional properties: - atmel,write-by-sram: boolean to enable NFC write by sram. @@ -98,6 +99,7 @@ nand0: nand at 40000000 { compatible = "atmel,sama5d3-nfc"; #address-cells = <1>; #size-cells = <1>; + clocks = <&hsmc_clk> reg = < 0x70000000 0x10000000 /* NFC Command Registers */ 0xffffc000 0x00000070 /* NFC HSMC regs */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717bda54..d1e502f8dbd0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(nfc->clk)) { + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + } else { + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); + } + nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); + + return 0; +} + +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + return 0; } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- 1.9.1 From ezequiel at vanguardiasur.com.ar Sat Sep 13 02:26:18 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 13 Sep 2014 10:26:18 +0100 Subject: [PATCHv5] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: On 13 September 2014 00:23, Alexandre Belloni wrote: > From: Boris BREZILLON > > Retrieve the NFC clock to make sure it is enabled. Make that optional to ensure > compatibility with previous device trees but document it as mandatory so newer > device trees will include it. > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > Acked-by: Josh Wu > --- > Changes in v5: > - Added a proper commit log > > .../devicetree/bindings/mtd/atmel-nand.txt | 2 ++ > drivers/mtd/nand/atmel_nand.c | 25 ++++++++++++++++++++++ > 2 files changed, 27 insertions(+) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c4728839d0c1..6edc3b616e98 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -36,6 +36,7 @@ Optional properties: > - reg : should specify the address and size used for NFC command registers, > NFC registers and NFC Sram. NFC Sram address and size can be absent > if don't want to use it. > + - clocks: phandle to the peripheral clock > - Optional properties: > - atmel,write-by-sram: boolean to enable NFC write by sram. > > @@ -98,6 +99,7 @@ nand0: nand at 40000000 { > compatible = "atmel,sama5d3-nfc"; > #address-cells = <1>; > #size-cells = <1>; > + clocks = <&hsmc_clk> > reg = < > 0x70000000 0x10000000 /* NFC Command Registers */ > 0xffffc000 0x00000070 /* NFC HSMC regs */ > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717bda54..d1e502f8dbd0 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -27,6 +27,7 @@ > * > */ > > +#include > #include > #include > #include > @@ -96,6 +97,8 @@ struct atmel_nfc { > bool use_nfc_sram; > bool write_by_sram; > > + struct clk *clk; > + > bool is_initialized; > struct completion comp_ready; > struct completion comp_cmd_done; > @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > { > struct atmel_nfc *nfc = &nand_nfc; > struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; > + int ret; > > nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); > @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) > nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); > nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > + if (!IS_ERR(nfc->clk)) { > + ret = clk_prepare_enable(nfc->clk); > + if (ret) > + return ret; > + } else { > + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); Looks much better now thanks. If the clock is not really optional, you can consider this a firmware bug. We've used FW_BUG messages for these cases (see vim drivers/watchdog/orion_wdt.c), so you could write something like: dev_warn(..., FW_BUG "devicetree clock missing"); Just a suggestion. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From alexandre.belloni at free-electrons.com Sat Sep 13 03:59:14 2014 From: alexandre.belloni at free-electrons.com (Alexandre Belloni) Date: Sat, 13 Sep 2014 12:59:14 +0200 Subject: [PATCHv5] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: References: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <20140913105914.GD26281@piout.net> Hi, On 13/09/2014 at 10:26:18 +0100, Ezequiel Garcia wrote : > > + nfc->clk = devm_clk_get(&pdev->dev, NULL); > > + if (!IS_ERR(nfc->clk)) { > > + ret = clk_prepare_enable(nfc->clk); > > + if (ret) > > + return ret; > > + } else { > > + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); > > Looks much better now thanks. If the clock is not really optional, you > can consider this a firmware bug. We've used FW_BUG messages for these > cases > (see vim drivers/watchdog/orion_wdt.c), so you could write something like: > > dev_warn(..., FW_BUG "devicetree clock missing"); > Yeah, I've considered using FW_WARN like Thomas suggested but I'm not sure it really relates to device tree. Apart from x86, FW_WARN and FW_BUG are only used on mvebu stuff ;) -- Alexandre Belloni, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com From shijie8 at gmail.com Sat Sep 13 08:36:24 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Sat, 13 Sep 2014 23:36:24 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140912143050.014ad4c3@bbrezillon> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> Message-ID: <20140913153622.GA10132@localhost.localdomain> On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > On Fri, 12 Sep 2014 08:45:50 +0800 > > My bad, capabilities might not be the appropriate word in this context. > I meant ECC algorithm strength, and that's exactly the purpose of > nandbiterrs testsuite: insert bitflips in in-band data until the MTD > layer complains about uncorrectable errors. okay. > This test validates what's returned by ecc_strength file in sysfs > (which in turn is specified by the NAND controller when initializing > the NAND chip). > > Doing this should not imply knowing the ECC algorithm in use in the > NAND controller or the layout used to store data on NAND. the difficulty is that the ECC parity area can be not byte aligned. As I ever said, it is hard to implement the two hooks. thanks Huang Shijie From computersforpeace at gmail.com Sat Sep 13 10:38:41 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 13 Sep 2014 10:38:41 -0700 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140913153622.GA10132@localhost.localdomain> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> Message-ID: <20140913173841.GA18093@brian-ubuntu> On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > This test validates what's returned by ecc_strength file in sysfs > > (which in turn is specified by the NAND controller when initializing > > the NAND chip). > > > > Doing this should not imply knowing the ECC algorithm in use in the > > NAND controller or the layout used to store data on NAND. > the difficulty is that the ECC parity area can be not byte aligned. Is there a problem with just rounding up to the nearest byte alignment and ignoring the few bits that are wasted? > As I ever said, it is hard to implement the two hooks. "Hard" doesn't mean we shouldn't. I really would like to encourage more NAND drivers to be programmed against the expected MTD behavior -- that (if possible with the given hardware) they can pass the MTD tests (drivers/mtd/tests/*). Brian From jason at lakedaemon.net Sat Sep 13 14:08:29 2014 From: jason at lakedaemon.net (Jason Cooper) Date: Sat, 13 Sep 2014 17:08:29 -0400 Subject: [PATCH reword] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC In-Reply-To: <1410339341-3372-1-git-send-email-klightspeed@killerwolves.net> References: <1410339341-3372-1-git-send-email-klightspeed@killerwolves.net> Message-ID: <20140913210829.GI30828@titan.lakedaemon.net> On Wed, Sep 10, 2014 at 06:55:41PM +1000, klightspeed at killerwolves.net wrote: > The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC > (strength = 4), while the pxa3xx NAND driver by default uses > Hamming ECC (strength = 1). > > This patch changes the ECC mode on these machines to match that > of the bootloader and of the stock firmware. That way, it is > now possible to update the kernel from userland (e.g. using > standard tools from mtd-utils package); u-boot will happily > load and boot it. > > Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") > Signed-off-by: Ben Peddell > Acked-by: Ezequiel Garcia > Tested-by: Arnaud Ebalard > --- > arch/arm/boot/dts/armada-370-netgear-rn102.dts | 4 ++++ > 1 file changed, 4 insertions(+) I've already applied this the mvebu/fixes: 500abb6ccb9e ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC thx, Jason. From ben at decadent.org.uk Sat Sep 13 19:00:09 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 03:00:09 +0100 Subject: Autoloading of SPI/nor driver on kirkwood (qnap devices) In-Reply-To: <20140910060004.GA5732@norris-Latitude-E6410> References: <1409673299.14324.43.camel@dagon.hellion.org.uk> <1409796689.27524.34.camel@decadent.org.uk> <20140910060004.GA5732@norris-Latitude-E6410> Message-ID: <1410660009.3040.29.camel@decadent.org.uk> On Tue, 2014-09-09 at 23:00 -0700, Brian Norris wrote: > On Thu, Sep 04, 2014 at 09:02:04AM +0200, Geert Uytterhoeven wrote: > > On Thu, Sep 4, 2014 at 4:11 AM, Ben Hutchings wrote: > > >> I noticed that many platforms declare the flash chip as compatible = > > >> "st,m25pXXX" whereas the ts219.dtsi just said m25p128 but I tried > > >> changing that and it didn't help. In any case without spi-nor.ko being > > >> autoloaded I don't support m25p80.ko ever would be. > > > > > > m25p80.c has: > > > > > > static struct spi_driver m25p80_driver = { > > > ... > > > .id_table = spi_nor_ids, > > > ... > > > }; > > > > > > while spi_nor_ids is defined in spi-nor.c. Since they end up as two > > > separate modules, modpost can't read the ID table and add the device ID > > > aliases to m25p80.ko. > > > > Woops. This indeed doesn't work. > > Note that the MODULE_DEVICE_TABLE() is also gone from m25p80.c > > > > So m25p80.c needs to contain the IDs, while spi-nor.c also needs the IDs > > because it's a framework/library. > > Actually, m25p80.c only needs the strings (i.e., the named aliases -- > character data), and for the most part, spi-nor.c only needs the IDs (i.e., > the identification bytes). Unfortunately, spi-nor.c also needs the strings to implement spi_nor_match_id() (which is only used by fsl-quadspi.c) and to report mismatches in spi_nor_scan(). But spi_nor_match_id(), spi_nor_scan() and spi_nor::read_id should work with something like struct flash_info, not struct spi_device_id. > What's more, I don't think that any modern SPI NOR user really needs to > be specifying exactly which SPI device it is via a specific string. Our > driver code pretty much always re-detects the device by reading its > device ID. All the SPI NOR code needs to know is how to read its ID. > > > A quick solution would be to move the ID table to a header file, and include > > that by both, and re-add the lost MODULE_DEVICE_TABLE() to m25p80.c. > > That duplicates the data, though. > > > > Hmm, for the built-in case, we can avoid the duplication by letting m25p80.c > > refer to the table in spi-nor.c if !MODULE. > > Does anyone see a better solution? > > A little bit of a shot in the dark, as I haven't fleshed this one out: > > Would it work to just copy the SPI ID strings into m25p80.c, keep the > full table in spi-nor.c, stop adding SPI ID string (and DT) bindings to > the m25p80 table (force platforms to use "m25p80"-compatible probing, or > maybe something generic like "spi-nor-rdid", "spi-nor-sfdp", etc.) and > eventually kill the strings from spi-nor.c entirely? I think that a DT node is always supposed to include a compatible string for the specific device. It could also include a generic compatible string for SPI NOR chips, but the *only* thing a driver can do with that is to use the JEDEC ID command. It can't even generically read a single byte, since addresses may be either 3 or 4 bytes long! So I think that if a generic compatible string is defined, the DT binding must also define the properties that spi-nor currently reads out of its static table. > I really don't want > to propagate string-binding much further into the SPI NOR library, since > everything should be auto-detectable--partly just by an ID table as we > have now, but eventually we can use CFI or SFDP parameters provided by > relatively new SPI NOR chips. > > I'm not sure if this is great for the short-term problem of fixing > module-autoloading. Perhaps we should do a short-term hack to duplicate > the SPI ID strings to m25p80.c by including them in a header (and > backport for 3.16.y stable?), but I'd like to disentangle this. I'll have a go at doing that. Ben. -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From klightspeed at killerwolves.net Sat Sep 13 19:54:01 2014 From: klightspeed at killerwolves.net (Ben Peddell) Date: Sun, 14 Sep 2014 12:54:01 +1000 Subject: [PATCH reword] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC In-Reply-To: <20140913210829.GI30828@titan.lakedaemon.net> References: <1410339341-3372-1-git-send-email-klightspeed@killerwolves.net> <20140913210829.GI30828@titan.lakedaemon.net> Message-ID: <54150349.7050503@killerwolves.net> On 14/09/14 07:08, Jason Cooper wrote: > On Wed, Sep 10, 2014 at 06:55:41PM +1000, klightspeed at killerwolves.net wrote: >> The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC >> (strength = 4), while the pxa3xx NAND driver by default uses >> Hamming ECC (strength = 1). >> >> This patch changes the ECC mode on these machines to match that >> of the bootloader and of the stock firmware. That way, it is >> now possible to update the kernel from userland (e.g. using >> standard tools from mtd-utils package); u-boot will happily >> load and boot it. >> >> Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") >> Signed-off-by: Ben Peddell >> Acked-by: Ezequiel Garcia >> Tested-by: Arnaud Ebalard >> --- >> arch/arm/boot/dts/armada-370-netgear-rn102.dts | 4 ++++ >> 1 file changed, 4 insertions(+) > > I've already applied this the mvebu/fixes: > > 500abb6ccb9e ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC That patch only affects arch/arm/boot/dts/armada-xp-netgear-rn2120.dts The patch I posted affects arch/arm/boot/dts/armada-370-netgear-rn102.dts From jason at lakedaemon.net Sat Sep 13 21:18:47 2014 From: jason at lakedaemon.net (Jason Cooper) Date: Sun, 14 Sep 2014 00:18:47 -0400 Subject: [PATCH reword] ARM: MVEBU: Netgear RN102: Use Hardware BCH ECC In-Reply-To: <54150349.7050503@killerwolves.net> References: <1410339341-3372-1-git-send-email-klightspeed@killerwolves.net> <20140913210829.GI30828@titan.lakedaemon.net> <54150349.7050503@killerwolves.net> Message-ID: <20140914041847.GB21986@titan.lakedaemon.net> On Sun, Sep 14, 2014 at 12:54:01PM +1000, Ben Peddell wrote: > On 14/09/14 07:08, Jason Cooper wrote: > > On Wed, Sep 10, 2014 at 06:55:41PM +1000, klightspeed at killerwolves.net wrote: > >> The bootloader on the Netgear ReadyNAS RN102 uses Hardware BCH ECC > >> (strength = 4), while the pxa3xx NAND driver by default uses > >> Hamming ECC (strength = 1). > >> > >> This patch changes the ECC mode on these machines to match that > >> of the bootloader and of the stock firmware. That way, it is > >> now possible to update the kernel from userland (e.g. using > >> standard tools from mtd-utils package); u-boot will happily > >> load and boot it. > >> > >> Fixes: 92beaccd8b49 ("ARM: mvebu: Enable NAND controller in ReadyNAS 102 .dts file") > >> Signed-off-by: Ben Peddell > >> Acked-by: Ezequiel Garcia > >> Tested-by: Arnaud Ebalard > >> --- > >> arch/arm/boot/dts/armada-370-netgear-rn102.dts | 4 ++++ > >> 1 file changed, 4 insertions(+) > > > > I've already applied this the mvebu/fixes: > > > > 500abb6ccb9e ARM: mvebu: Netgear RN2120: Use Hardware BCH ECC > > That patch only affects arch/arm/boot/dts/armada-xp-netgear-rn2120.dts > > The patch I posted affects arch/arm/boot/dts/armada-370-netgear-rn102.dts Gah! You're right. Applied to mvebu/fixes and Cc'd the stable v3.14+ thx, Jason. From boris.brezillon at free-electrons.com Sun Sep 14 07:07:52 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Sun, 14 Sep 2014 16:07:52 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140913173841.GA18093@brian-ubuntu> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> <20140913173841.GA18093@brian-ubuntu> Message-ID: <20140914160752.1cb404cc@bbrezillon> Hi Brian, Huang, On Sat, 13 Sep 2014 10:38:41 -0700 Brian Norris wrote: > On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > > This test validates what's returned by ecc_strength file in sysfs > > > (which in turn is specified by the NAND controller when initializing > > > the NAND chip). > > > > > > Doing this should not imply knowing the ECC algorithm in use in the > > > NAND controller or the layout used to store data on NAND. > > the difficulty is that the ECC parity area can be not byte aligned. > > Is there a problem with just rounding up to the nearest byte alignment > and ignoring the few bits that are wasted? > > > As I ever said, it is hard to implement the two hooks. > > "Hard" doesn't mean we shouldn't. I really would like to encourage more > NAND drivers to be programmed against the expected MTD behavior -- that > (if possible with the given hardware) they can pass the MTD tests > (drivers/mtd/tests/*). Here is a draft for a gpmi_move_bits function we could use to move bits (not bytes :-) from one memory region to another: void gpmi_move_bits(u8 *dst, size_t dst_bit_off, const u8 *src, size_t src_bit_off, size_t nbits) { size_t i; size_t nbytes; u32 src_byte = 0; src += src_bit_off / 8; src_bit_off %= 8; dst += dst_bit_off / 8; dst_bit_off %= 8; if (src_bit_off) { src_byte = src[0] >> src_bit_off; nbits -= 8 - src_bit_off; src++; } nbytes = nbits / 8; if (src_bit_off <= dst_bit_off) { dst[0] &= GENMASK(dst_bit_off - 1, 0); dst[0] |= src_byte << dst_bit_off; src_bit_off += (8 - dst_bit_off); src_byte >>= (8 - dst_bit_off); dst_bit_off = 0; dst++; } else if (nbytes) { src_byte |= src[0] << (8 - src_bit_off); dst[0] &= GENMASK(dst_bit_off - 1, 0); dst[0] |= src_byte << dst_bit_off; src_bit_off += dst_bit_off; src_byte >>= (8 - dst_bit_off); dst_bit_off = 0; dst++; nbytes--; src++; if (src_bit_off > 7) { src_bit_off -= 8; dst[0] = src_byte; dst++; src_byte >>= 8; } } if (!src_bit_off && !dst_bit_off) { if (nbytes) memcpy(dst, src, nbytes); } else { for (i = 0; i < nbytes; i++) { src_byte |= src[i] << (8 - src_bit_off); dst[i] = src_byte; src_byte >>= 8; } } dst += nbytes; src += nbytes; nbits %= 8; if (!nbits && !src_bit_off) return; if (nbits) src_byte |= (*src & GENMASK(nbits - 1, 0)) << ((8 - src_bit_off) % 8); nbits += (8 - src_bit_off) % 8; if (dst_bit_off) src_byte = (src_byte << dst_bit_off) | (*dst & GENMASK(dst_bit_off - 1, 0)); nbits += dst_bit_off; if (nbits % 8) src_byte |= (dst[nbits / 8] & GENMASK(7, nbits % 8)) << (nbits / 8); nbytes = DIV_ROUND_UP(nbits, 8); for (i = 0; i < nbytes; i++) { dst[i] = src_byte; src_byte >>= 8; } } I haven't tested it, and I think there is room for optimization. My point is that performance is not a key aspect of raw functions (those are often used by testing and debugging tools), hence we could rely on this move_bits function to address the ECC bit alignment problem. Let me know what's your opinion on this approach. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From ben at decadent.org.uk Sun Sep 14 10:10:24 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:10:24 +0100 Subject: [PATCH 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification Message-ID: <1410714624.3040.38.camel@decadent.org.uk> The first patch in the series restores the module aliases to m25p80, but it does so by duplicating the list of names. This should be suitable for stable, but it isn't viable in the longer term. The following patches change the spi-nor interface so that this duplication is no longer necessary. This includes removing spi_nor::read_id, but it could be re-added after this with a different interface, e.g. returning a flash_info structure (which would need to be defined in spi_nor.h). Ben. Ben Hutchings (5): m25p80,spi-nor: Fix module aliases for m25p80 spi-nor: Remove spi_nor::read_id operation spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id spi-nor: Replace struct spi_device_id with struct flash_info m25p80,spi-nor: Share the list of supported chip type names again drivers/mtd/devices/m25p80.c | 13 +- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +- drivers/mtd/spi-nor/spi-nor.c | 383 +++++++++++++++++++------------------- include/linux/mtd/spi-nor.h | 87 +++++++-- 4 files changed, 279 insertions(+), 211 deletions(-) -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:11:10 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:11:10 +0100 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714670.3040.39.camel@decadent.org.uk> m25p80's device ID table is now spi_nor_ids, defined in spi-nor. The MODULE_DEVICE_TABLE() macro doesn't work with extern definitions, but its use was also removed at the same time. Now if m25p80 is built as a module it doesn't get the necessary aliases to be loaded automatically. A clean solution to this will involve defining the list of device IDs in spi-nor.h and removing struct spi_device_id from the spi-nor API, but this is quite a large change. As a quick fix suitable for stable, copy the device IDs back into m25p80. Fixes: 03e296f613af ("mtd: m25p80: use the SPI nor framework") Cc: stable # 3.16 Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 58 +++++++++++++++++++++++++++++++++++++++++-- drivers/mtd/spi-nor/spi-nor.c | 5 ++-- include/linux/mtd/spi-nor.h | 3 +-- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ed7e0a1b..3f0fe86 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -196,6 +196,7 @@ static int m25p_probe(struct spi_device *spi) struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; + const struct spi_device_id *id; int ret; flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); @@ -223,7 +224,10 @@ static int m25p_probe(struct spi_device *spi) mode = SPI_NOR_QUAD; else if (spi->mode & SPI_RX_DUAL) mode = SPI_NOR_DUAL; - ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); + id = spi_nor_match_id(spi_get_device_id(spi)->name); + if (WARN_ON(!id)) + return -ENODEV; + ret = spi_nor_scan(nor, id, mode); if (ret) return ret; @@ -245,12 +249,62 @@ static int m25p_remove(struct spi_device *spi) } +/* + * XXX This needs to be kept in sync with spi_nor_ids. We can't share + * it with spi-nor, because if this is built as a module then modpost + * won't be able to read it and add appropriate aliases. + */ +static const struct spi_device_id m25p_ids[] = { + {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, + {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, + {"at26df321"}, {"at45db081d"}, + {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, + {"en25q64"}, {"en25qh128"}, {"en25qh256"}, + {"f25l32pa"}, + {"mr25h256"}, {"mr25h10"}, + {"gd25q32"}, {"gd25q64"}, + {"160s33b"}, {"320s33b"}, {"640s33b"}, + {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, + {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, + {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, + {"mx66l1g55g"}, + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, + {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, + {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, + {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, + {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, + {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, + {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, + {"s25fl016k"}, {"s25fl064k"}, + {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, + {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, + {"sst25wf040"}, + {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, + {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, + {"m25p128"}, {"n25q032"}, + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, + {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, + {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, + {"m25px64"}, + {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, + {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, + {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, + {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, + {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, + { }, +}; +MODULE_DEVICE_TABLE(spi, m25p_ids); + + static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .owner = THIS_MODULE, }, - .id_table = spi_nor_ids, + .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 03e0ab8..6b1bda2 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -473,7 +473,7 @@ struct flash_info { * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ -const struct spi_device_id spi_nor_ids[] = { +static const struct spi_device_id spi_nor_ids[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, @@ -637,7 +637,6 @@ const struct spi_device_id spi_nor_ids[] = { { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { }, }; -EXPORT_SYMBOL_GPL(spi_nor_ids); static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) { @@ -1136,7 +1135,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(char *name) +const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..5ec84cc 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -201,7 +201,6 @@ struct spi_nor { */ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode); -extern const struct spi_device_id spi_nor_ids[]; /** * spi_nor_match_id() - find the spi_device_id by the name @@ -213,6 +212,6 @@ extern const struct spi_device_id spi_nor_ids[]; * Return: returns the right spi_device_id pointer on success, * and returns NULL on failure. */ -const struct spi_device_id *spi_nor_match_id(char *name); +const struct spi_device_id *spi_nor_match_id(const char *name); #endif -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:11:16 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:11:16 +0100 Subject: [PATCH 2/5] spi-nor: Remove spi_nor::read_id operation In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714676.3040.40.camel@decadent.org.uk> There is currently no useful way to override the default implementation of this operation. The returned struct spi_device_id must have a pointer to struct flash_info in its private data, but this structure is defined inside spi-nor. Signed-off-by: Ben Hutchings --- drivers/mtd/spi-nor/spi-nor.c | 4 +--- include/linux/mtd/spi-nor.h | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6b1bda2..6f699c5 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -902,8 +902,6 @@ static int spi_nor_check(struct spi_nor *nor) return -EINVAL; } - if (!nor->read_id) - nor->read_id = spi_nor_read_id; if (!nor->wait_till_ready) nor->wait_till_ready = spi_nor_wait_till_ready; @@ -952,7 +950,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (info->jedec_id) { const struct spi_device_id *jid; - jid = nor->read_id(nor); + jid = spi_nor_read_id(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 5ec84cc..66af67a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -139,8 +139,6 @@ enum spi_nor_ops { * @write_xfer: [OPTIONAL] the writefundamental primitive * @read_reg: [DRIVER-SPECIFIC] read out the register * @write_reg: [DRIVER-SPECIFIC] write data to the register - * @read_id: [REPLACEABLE] read out the ID data, and find - * the proper spi_device_id * @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready * @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR @@ -172,7 +170,6 @@ struct spi_nor { int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len, int write_enable); - const struct spi_device_id *(*read_id)(struct spi_nor *nor); int (*wait_till_ready)(struct spi_nor *nor); int (*read)(struct spi_nor *nor, loff_t from, -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:11:28 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:11:28 +0100 Subject: [PATCH 3/5] spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714688.3040.41.camel@decadent.org.uk> Drivers currently call spi_nor_match_id() and then spi_nor_scan(). This adds a dependency on struct spi_device_id which we want to avoid. Make spi_nor_scan() do it for them. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 6 +----- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +------ drivers/mtd/spi-nor/spi-nor.c | 29 +++++++++++++---------------- include/linux/mtd/spi-nor.h | 21 ++++----------------- 4 files changed, 19 insertions(+), 44 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 3f0fe86..b547c39 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -196,7 +196,6 @@ static int m25p_probe(struct spi_device *spi) struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; - const struct spi_device_id *id; int ret; flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); @@ -224,10 +223,7 @@ static int m25p_probe(struct spi_device *spi) mode = SPI_NOR_QUAD; else if (spi->mode & SPI_RX_DUAL) mode = SPI_NOR_DUAL; - id = spi_nor_match_id(spi_get_device_id(spi)->name); - if (WARN_ON(!id)) - return -ENODEV; - ret = spi_nor_scan(nor, id, mode); + ret = spi_nor_scan(nor, spi_get_device_id(spi)->name, mode); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 8d659a2..d5269a2 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -881,7 +881,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { - const struct spi_device_id *id; char modalias[40]; /* skip the holes */ @@ -909,10 +908,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) goto map_failed; - id = spi_nor_match_id(modalias); - if (!id) - goto map_failed; - ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) @@ -921,7 +916,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); - ret = spi_nor_scan(nor, id, SPI_NOR_QUAD); + ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) goto map_failed; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6f699c5..40d6f70 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,6 +28,8 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) +static const struct spi_device_id *spi_nor_match_id(const char *name); + /* * Read the status register, returning its value in the location * Return the status register value. @@ -908,9 +910,9 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode) +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { + const struct spi_device_id *id = NULL; struct flash_info *info; struct flash_platform_data *data; struct device *dev = nor->dev; @@ -930,21 +932,17 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, */ data = dev_get_platdata(dev); if (data && data->type) { - const struct spi_device_id *plat_id; - - for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { - plat_id = &spi_nor_ids[i]; - if (strcmp(data->type, plat_id->name)) - continue; - break; - } - - if (i < ARRAY_SIZE(spi_nor_ids) - 1) - id = plat_id; - else + id = spi_nor_match_id(data->type); + if (!id) dev_warn(dev, "unrecognized id %s\n", data->type); } + if (!id && name) + id = spi_nor_match_id(name); + + if (!id) + return -ENODEV; + info = (void *)id->driver_data; if (info->jedec_id) { @@ -1133,7 +1131,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(const char *name) +static const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; @@ -1144,7 +1142,6 @@ const struct spi_device_id *spi_nor_match_id(const char *name) } return NULL; } -EXPORT_SYMBOL_GPL(spi_nor_match_id); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 66af67a..6f92b4b 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -184,31 +184,18 @@ struct spi_nor { /** * spi_nor_scan() - scan the SPI NOR * @nor: the spi_nor structure - * @id: the spi_device_id provided by the driver + * @name: the chip type name * @mode: the read mode supported by the driver * * The drivers can use this fuction to scan the SPI NOR. * In the scanning, it will try to get all the necessary information to * fill the mtd_info{} and the spi_nor{}. * - * The board may assigns a spi_device_id with @id which be used to compared with - * the spi_device_id detected by the scanning. + * The chip type name can be provided either through platform data or + * through the @name parameter. Platform data takes precedence. * * Return: 0 for success, others for failure. */ -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode); - -/** - * spi_nor_match_id() - find the spi_device_id by the name - * @name: the name of the spi_device_id - * - * The drivers use this function to find the spi_device_id - * specified by the @name. - * - * Return: returns the right spi_device_id pointer on success, - * and returns NULL on failure. - */ -const struct spi_device_id *spi_nor_match_id(const char *name); +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); #endif -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:11:38 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:11:38 +0100 Subject: [PATCH 4/5] spi-nor: Replace struct spi_device_id with struct flash_info In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714698.3040.42.camel@decadent.org.uk> spi-nor does not depend on the SPI layer, so its use of struct spi_device_id adds an unnecessary indirection. Add the chip type name to struct flash_info and remove the wrapping struct spi_device_id. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 2 +- drivers/mtd/spi-nor/spi-nor.c | 344 +++++++++++++++++++++--------------------- 2 files changed, 172 insertions(+), 174 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index b547c39..271d83f 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -246,7 +246,7 @@ static int m25p_remove(struct spi_device *spi) /* - * XXX This needs to be kept in sync with spi_nor_ids. We can't share + * XXX This needs to be kept in sync with spi_nor_info. We can't share * it with spi-nor, because if this is built as a module then modpost * won't be able to read it and add appropriate aliases. */ diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 40d6f70..3b88c6b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,8 +28,6 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) -static const struct spi_device_id *spi_nor_match_id(const char *name); - /* * Read the status register, returning its value in the location * Return the status register value. @@ -425,6 +423,8 @@ err: } struct flash_info { + const char name[SPI_NAME_SIZE]; + /* JEDEC id zero means "no ID" (most older chips); otherwise it has * a high byte of zero plus three data bytes: the manufacturer id, * then a two byte device id. @@ -452,201 +452,215 @@ struct flash_info { #define USE_FSR 0x80 /* use flag status register */ }; -#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ +#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + { \ + .name = (_name), \ .jedec_id = (_jedec_id), \ .ext_id = (_ext_id), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ .flags = (_flags), \ - }) + } -#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ +#define CAT25_INFO(_name, _sector_size, _n_sectors, _page_size, \ + _addr_width, _flags) \ + { \ + .name = (_name), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ .addr_width = (_addr_width), \ .flags = (_flags), \ - }) + } /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ -static const struct spi_device_id spi_nor_ids[] = { +static const struct flash_info spi_nor_info[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, - { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), + INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), - { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, - { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K), + INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K), + INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K), - { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, - { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, - { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K), + INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K), + INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K), + INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K), - { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K), /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, - { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, - { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, + INFO("en25f32", 0x1c3116, 0, 64 * 1024, 64, SECT_4K), + INFO("en25p32", 0x1c2016, 0, 64 * 1024, 64, 0), + INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0), + INFO("en25p64", 0x1c2017, 0, 64 * 1024, 128, 0), + INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K), + INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0), + INFO("en25qh256", 0x1c7019, 0, 64 * 1024, 512, 0), /* ESMT */ - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + INFO("f25l32pa", 0x8c2016, 0, 64 * 1024, 64, SECT_4K), /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + CAT25_INFO("mr25h256", 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("mr25h10", 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), /* GigaDevice */ - { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, - { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, + INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, SECT_4K), + INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, SECT_4K), /* Intel/Numonyx -- xxxs33b */ - { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, - { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, - { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + INFO("160s33b", 0x898911, 0, 64 * 1024, 32, 0), + INFO("320s33b", 0x898912, 0, 64 * 1024, 64, 0), + INFO("640s33b", 0x898913, 0, 64 * 1024, 128, 0), /* Macronix */ - { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, - { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, - { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, - { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, - { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K), + INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K), + INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0), + INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K), + INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, 0), + INFO("mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, SECT_4K), + INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, 0), + INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0), + INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0), + INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, 0), + INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0), + INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), + INFO("mx66l1g55g", 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, - { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) }, - { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) }, + INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, 0), + INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, 0), + INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, 0), + INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K), + INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), + INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), + INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), /* PMC */ - { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, - { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, - { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + INFO("pm25lv512", 0, 0, 32 * 1024, 2, SECT_4K_PMC), + INFO("pm25lv010", 0, 0, 32 * 1024, 4, SECT_4K_PMC), + INFO("pm25lq032", 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ - { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, - { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, - { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, - { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, - { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, - { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, - { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, - { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, - { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, - { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, 0), + INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 0), + INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s25fl512s", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s70fl01gs", 0x010221, 0x4d00, 256 * 1024, 256, 0), + INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0), + INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0), + INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, 0), + INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, 0), + INFO("s25sl004a", 0x010212, 0, 64 * 1024, 8, 0), + INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0), + INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0), + INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0), + INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0), + INFO("s25fl008k", 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO("s25fl016k", 0xef4015, 0, 64 * 1024, 32, SECT_4K), + INFO("s25fl064k", 0xef4017, 0, 64 * 1024, 128, SECT_4K), /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), + INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), + INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), + INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), + INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K), + INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), + INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), + INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), + INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), /* ST Microelectronics -- newer production may have feature updates */ - { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, - { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, - { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, - { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, - { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, - { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, - { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, - { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, - { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, - { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, - - { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, - { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, - { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, - { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, - { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, - { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, - { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, - { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, - { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, - - { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, - { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, - { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, - - { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, - { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, - { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, - - { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, - { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, - { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, + INFO("m25p05", 0x202010, 0, 32 * 1024, 2, 0), + INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0), + INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0), + INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0), + INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0), + INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0), + INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0), + INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0), + INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0), + INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, 0), + + INFO("m25p05-nonjedec", 0, 0, 32 * 1024, 2, 0), + INFO("m25p10-nonjedec", 0, 0, 32 * 1024, 4, 0), + INFO("m25p20-nonjedec", 0, 0, 64 * 1024, 4, 0), + INFO("m25p40-nonjedec", 0, 0, 64 * 1024, 8, 0), + INFO("m25p80-nonjedec", 0, 0, 64 * 1024, 16, 0), + INFO("m25p16-nonjedec", 0, 0, 64 * 1024, 32, 0), + INFO("m25p32-nonjedec", 0, 0, 64 * 1024, 64, 0), + INFO("m25p64-nonjedec", 0, 0, 64 * 1024, 128, 0), + INFO("m25p128-nonjedec", 0, 0, 256 * 1024, 64, 0), + + INFO("m45pe10", 0x204011, 0, 64 * 1024, 2, 0), + INFO("m45pe80", 0x204014, 0, 64 * 1024, 16, 0), + INFO("m45pe16", 0x204015, 0, 64 * 1024, 32, 0), + + INFO("m25pe20", 0x208012, 0, 64 * 1024, 4, 0), + INFO("m25pe80", 0x208014, 0, 64 * 1024, 16, 0), + INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K), + + INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K), + INFO("m25px32", 0x207116, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px32-s0", 0x207316, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px32-s1", 0x206316, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0), /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, - { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, - { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, + INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K), + INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K), + INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K), + INFO("w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K), + INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K), + INFO("w25q64", 0xef4017, 0, 64 * 1024, 128, SECT_4K), + INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K), + INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K), /* Catalyst / On Semiconductor -- non-JEDEC */ - { "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c03", CAT25_INFO( 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + CAT25_INFO("cat25c11", 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c03", 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c09", 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c17", 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25128", 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), { }, }; -static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) +static const struct flash_info *spi_nor_info_by_name(const char *name) +{ + const struct flash_info *info = spi_nor_info; + + while (info->name[0]) { + if (!strcmp(name, info->name)) + return info; + info++; + } + return NULL; +} + +static const struct flash_info *spi_nor_info_probe(struct spi_nor *nor) { int tmp; u8 id[5]; u32 jedec; u16 ext_jedec; - struct flash_info *info; + const struct flash_info *info; tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, 5); if (tmp < 0) { @@ -661,11 +675,11 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) ext_jedec = id[3] << 8 | id[4]; - for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { - info = (void *)spi_nor_ids[tmp].driver_data; + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_info) - 1; tmp++) { + info = &spi_nor_info[tmp]; if (info->jedec_id == jedec) { if (info->ext_id == 0 || info->ext_id == ext_jedec) - return &spi_nor_ids[tmp]; + return info; } } dev_err(nor->dev, "unrecognized JEDEC id %06x\n", jedec); @@ -912,8 +926,7 @@ static int spi_nor_check(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { - const struct spi_device_id *id = NULL; - struct flash_info *info; + const struct flash_info *info = NULL; struct flash_platform_data *data; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; @@ -932,26 +945,24 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) */ data = dev_get_platdata(dev); if (data && data->type) { - id = spi_nor_match_id(data->type); - if (!id) + info = spi_nor_info_by_name(data->type); + if (!info) dev_warn(dev, "unrecognized id %s\n", data->type); } - if (!id && name) - id = spi_nor_match_id(name); + if (!info && name) + info = spi_nor_info_by_name(name); - if (!id) + if (!info) return -ENODEV; - info = (void *)id->driver_data; - if (info->jedec_id) { - const struct spi_device_id *jid; + const struct flash_info *jinfo; - jid = spi_nor_read_id(nor); - if (IS_ERR(jid)) { - return PTR_ERR(jid); - } else if (jid != id) { + jinfo = spi_nor_info_probe(nor); + if (IS_ERR(jinfo)) { + return PTR_ERR(jinfo); + } else if (jinfo != info) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let @@ -960,9 +971,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", - jid->name, id->name); - id = jid; - info = (void *)jid->driver_data; + jinfo->name, info->name); + info = jinfo; } } @@ -1108,7 +1118,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) nor->read_dummy = spi_nor_read_dummy_cycles(nor); - dev_info(dev, "%s (%lld Kbytes)\n", id->name, + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); dev_dbg(dev, @@ -1131,18 +1141,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) } EXPORT_SYMBOL_GPL(spi_nor_scan); -static const struct spi_device_id *spi_nor_match_id(const char *name) -{ - const struct spi_device_id *id = spi_nor_ids; - - while (id->name[0]) { - if (!strcmp(name, id->name)) - return id; - id++; - } - return NULL; -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); MODULE_AUTHOR("Mike Lavender"); -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:11:48 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:11:48 +0100 Subject: [PATCH 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714708.3040.43.camel@decadent.org.uk> Move the list of chip type names to spi-nor.h. To avoid putting all the chip type information there, we define this list as a macro SPI_NOR_ENUM_TYPES() that invokes another macro SPI_NOR_ENUM_TYPE() that must be defined to expand each name to whatever form it's needed. In spi-nor.c, use it to define enumerators, then use the enumerators as indices when defining spi_nor_info so that we cannot accidentally use a name that's not on the list. This is somewhat complicated by the fact that some names include hyphens. SPI_NOR_ENUM_TYPE() therefore takes separate string and C identifier parameters. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 47 +------ drivers/mtd/spi-nor/spi-nor.c | 287 ++++++++++++++++++++++-------------------- include/linux/mtd/spi-nor.h | 72 +++++++++++ 3 files changed, 227 insertions(+), 179 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 271d83f..368eb9a 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -245,51 +245,10 @@ static int m25p_remove(struct spi_device *spi) } -/* - * XXX This needs to be kept in sync with spi_nor_info. We can't share - * it with spi-nor, because if this is built as a module then modpost - * won't be able to read it and add appropriate aliases. - */ static const struct spi_device_id m25p_ids[] = { - {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, - {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, - {"at26df321"}, {"at45db081d"}, - {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, - {"en25q64"}, {"en25qh128"}, {"en25qh256"}, - {"f25l32pa"}, - {"mr25h256"}, {"mr25h10"}, - {"gd25q32"}, {"gd25q64"}, - {"160s33b"}, {"320s33b"}, {"640s33b"}, - {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, - {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, - {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, - {"mx66l1g55g"}, - {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, - {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, - {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, - {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, - {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, - {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, - {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, - {"s25fl016k"}, {"s25fl064k"}, - {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, - {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, - {"sst25wf040"}, - {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, - {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, - {"m25p128"}, {"n25q032"}, - {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, - {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, - {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, - {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, - {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, - {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, - {"m25px64"}, - {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, - {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, - {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, - {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, - {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, +#define SPI_NOR_ENUM_TYPE(s, c) { s }, + SPI_NOR_ENUM_TYPES() +#undef SPI_NOR_ENUM_TYPE { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 3b88c6b..68fedce 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -452,9 +452,16 @@ struct flash_info { #define USE_FSR 0x80 /* use flag status register */ }; +enum { +#define SPI_NOR_ENUM_TYPE(s, c) CHIP_TYPE_ ## c, + SPI_NOR_ENUM_TYPES() +#undef SPI_NOR_ENUM_TYPE + CHIP_TYPE_COUNT +}; + #define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + [CHIP_TYPE_ ## _name] = \ { \ - .name = (_name), \ .jedec_id = (_jedec_id), \ .ext_id = (_ext_id), \ .sector_size = (_sector_size), \ @@ -465,8 +472,8 @@ struct flash_info { #define CAT25_INFO(_name, _sector_size, _n_sectors, _page_size, \ _addr_width, _flags) \ + [CHIP_TYPE_ ## _name] = \ { \ - .name = (_name), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ @@ -477,169 +484,179 @@ struct flash_info { /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. + * + * All chip type names must be added to __SPI_NOR_ENUM_TYPES in + * spi-nor.h before they can be used here (enforced by using the + * names to index this array). */ static const struct flash_info spi_nor_info[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), - INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), + INFO(at25fs010, 0x1f6601, 0, 32 * 1024, 4, SECT_4K), + INFO(at25fs040, 0x1f6604, 0, 64 * 1024, 8, SECT_4K), - INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K), - INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K), - INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K), + INFO(at25df041a, 0x1f4401, 0, 64 * 1024, 8, SECT_4K), + INFO(at25df321a, 0x1f4701, 0, 64 * 1024, 64, SECT_4K), + INFO(at25df641, 0x1f4800, 0, 64 * 1024, 128, SECT_4K), - INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K), - INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K), - INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K), - INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K), + INFO(at26f004, 0x1f0400, 0, 64 * 1024, 8, SECT_4K), + INFO(at26df081a, 0x1f4501, 0, 64 * 1024, 16, SECT_4K), + INFO(at26df161a, 0x1f4601, 0, 64 * 1024, 32, SECT_4K), + INFO(at26df321, 0x1f4700, 0, 64 * 1024, 64, SECT_4K), - INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K), + INFO(at45db081d, 0x1f2500, 0, 64 * 1024, 16, SECT_4K), /* EON -- en25xxx */ - INFO("en25f32", 0x1c3116, 0, 64 * 1024, 64, SECT_4K), - INFO("en25p32", 0x1c2016, 0, 64 * 1024, 64, 0), - INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0), - INFO("en25p64", 0x1c2017, 0, 64 * 1024, 128, 0), - INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K), - INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0), - INFO("en25qh256", 0x1c7019, 0, 64 * 1024, 512, 0), + INFO(en25f32, 0x1c3116, 0, 64 * 1024, 64, SECT_4K), + INFO(en25p32, 0x1c2016, 0, 64 * 1024, 64, 0), + INFO(en25q32b, 0x1c3016, 0, 64 * 1024, 64, 0), + INFO(en25p64, 0x1c2017, 0, 64 * 1024, 128, 0), + INFO(en25q64, 0x1c3017, 0, 64 * 1024, 128, SECT_4K), + INFO(en25qh128, 0x1c7018, 0, 64 * 1024, 256, 0), + INFO(en25qh256, 0x1c7019, 0, 64 * 1024, 512, 0), /* ESMT */ - INFO("f25l32pa", 0x8c2016, 0, 64 * 1024, 64, SECT_4K), + INFO(f25l32pa, 0x8c2016, 0, 64 * 1024, 64, SECT_4K), /* Everspin */ - CAT25_INFO("mr25h256", 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("mr25h10", 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(mr25h256, 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(mr25h10, 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), /* GigaDevice */ - INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, SECT_4K), - INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, SECT_4K), + INFO(gd25q32, 0xc84016, 0, 64 * 1024, 64, SECT_4K), + INFO(gd25q64, 0xc84017, 0, 64 * 1024, 128, SECT_4K), /* Intel/Numonyx -- xxxs33b */ - INFO("160s33b", 0x898911, 0, 64 * 1024, 32, 0), - INFO("320s33b", 0x898912, 0, 64 * 1024, 64, 0), - INFO("640s33b", 0x898913, 0, 64 * 1024, 128, 0), + INFO(160s33b, 0x898911, 0, 64 * 1024, 32, 0), + INFO(320s33b, 0x898912, 0, 64 * 1024, 64, 0), + INFO(640s33b, 0x898913, 0, 64 * 1024, 128, 0), /* Macronix */ - INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K), - INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K), - INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0), - INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K), - INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, 0), - INFO("mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, SECT_4K), - INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, 0), - INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0), - INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0), - INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, 0), - INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0), - INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), - INFO("mx66l1g55g", 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), + INFO(mx25l2005a, 0xc22012, 0, 64 * 1024, 4, SECT_4K), + INFO(mx25l4005a, 0xc22013, 0, 64 * 1024, 8, SECT_4K), + INFO(mx25l8005, 0xc22014, 0, 64 * 1024, 16, 0), + INFO(mx25l1606e, 0xc22015, 0, 64 * 1024, 32, SECT_4K), + INFO(mx25l3205d, 0xc22016, 0, 64 * 1024, 64, 0), + INFO(mx25l3255e, 0xc29e16, 0, 64 * 1024, 64, SECT_4K), + INFO(mx25l6405d, 0xc22017, 0, 64 * 1024, 128, 0), + INFO(mx25l12805d, 0xc22018, 0, 64 * 1024, 256, 0), + INFO(mx25l12855e, 0xc22618, 0, 64 * 1024, 256, 0), + INFO(mx25l25635e, 0xc22019, 0, 64 * 1024, 512, 0), + INFO(mx25l25655e, 0xc22619, 0, 64 * 1024, 512, 0), + INFO(mx66l51235l, 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), + INFO(mx66l1g55g, 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), /* Micron */ - INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, 0), - INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, 0), - INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, 0), - INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K), - INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), - INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), - INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), + INFO(n25q064, 0x20ba17, 0, 64 * 1024, 128, 0), + INFO(n25q128a11, 0x20bb18, 0, 64 * 1024, 256, 0), + INFO(n25q128a13, 0x20ba18, 0, 64 * 1024, 256, 0), + INFO(n25q256a, 0x20ba19, 0, 64 * 1024, 512, SECT_4K), + INFO(n25q512a, 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), + INFO(n25q512ax3, 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), + INFO(n25q00, 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), /* PMC */ - INFO("pm25lv512", 0, 0, 32 * 1024, 2, SECT_4K_PMC), - INFO("pm25lv010", 0, 0, 32 * 1024, 4, SECT_4K_PMC), - INFO("pm25lq032", 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), + INFO(pm25lv512, 0, 0, 32 * 1024, 2, SECT_4K_PMC), + INFO(pm25lv010, 0, 0, 32 * 1024, 4, SECT_4K_PMC), + INFO(pm25lq032, 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ - INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, 0), - INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 0), - INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s25fl512s", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s70fl01gs", 0x010221, 0x4d00, 256 * 1024, 256, 0), - INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0), - INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0), - INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, 0), - INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, 0), - INFO("s25sl004a", 0x010212, 0, 64 * 1024, 8, 0), - INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0), - INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0), - INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0), - INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0), - INFO("s25fl008k", 0xef4014, 0, 64 * 1024, 16, SECT_4K), - INFO("s25fl016k", 0xef4015, 0, 64 * 1024, 32, SECT_4K), - INFO("s25fl064k", 0xef4017, 0, 64 * 1024, 128, SECT_4K), - - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), - INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), - INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), - INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), - INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K), - INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), - INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), - INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), - INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), + INFO(s25sl032p, 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO(s25sl064p, 0x010216, 0x4d00, 64 * 1024, 128, 0), + INFO(s25fl256s0, 0x010219, 0x4d00, 256 * 1024, 128, 0), + INFO(s25fl256s1, 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO(s25fl512s, 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO(s70fl01gs, 0x010221, 0x4d00, 256 * 1024, 256, 0), + INFO(s25sl12800, 0x012018, 0x0300, 256 * 1024, 64, 0), + INFO(s25sl12801, 0x012018, 0x0301, 64 * 1024, 256, 0), + INFO(s25fl129p0, 0x012018, 0x4d00, 256 * 1024, 64, 0), + INFO(s25fl129p1, 0x012018, 0x4d01, 64 * 1024, 256, 0), + INFO(s25sl004a, 0x010212, 0, 64 * 1024, 8, 0), + INFO(s25sl008a, 0x010213, 0, 64 * 1024, 16, 0), + INFO(s25sl016a, 0x010214, 0, 64 * 1024, 32, 0), + INFO(s25sl032a, 0x010215, 0, 64 * 1024, 64, 0), + INFO(s25sl064a, 0x010216, 0, 64 * 1024, 128, 0), + INFO(s25fl008k, 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO(s25fl016k, 0xef4015, 0, 64 * 1024, 32, SECT_4K), + INFO(s25fl064k, 0xef4017, 0, 64 * 1024, 128, SECT_4K), + + /* SST -- large erase sizes are overlays, sectors are 4K */ + INFO(sst25vf040b, 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), + INFO(sst25vf080b, 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), + INFO(sst25vf016b, 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), + INFO(sst25vf032b, 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), + INFO(sst25vf064c, 0xbf254b, 0, 64 * 1024, 128, SECT_4K), + INFO(sst25wf512, 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), + INFO(sst25wf010, 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), + INFO(sst25wf020, 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), + INFO(sst25wf040, 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), /* ST Microelectronics -- newer production may have feature updates */ - INFO("m25p05", 0x202010, 0, 32 * 1024, 2, 0), - INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0), - INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0), - INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0), - INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0), - INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0), - INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0), - INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0), - INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0), - INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, 0), - - INFO("m25p05-nonjedec", 0, 0, 32 * 1024, 2, 0), - INFO("m25p10-nonjedec", 0, 0, 32 * 1024, 4, 0), - INFO("m25p20-nonjedec", 0, 0, 64 * 1024, 4, 0), - INFO("m25p40-nonjedec", 0, 0, 64 * 1024, 8, 0), - INFO("m25p80-nonjedec", 0, 0, 64 * 1024, 16, 0), - INFO("m25p16-nonjedec", 0, 0, 64 * 1024, 32, 0), - INFO("m25p32-nonjedec", 0, 0, 64 * 1024, 64, 0), - INFO("m25p64-nonjedec", 0, 0, 64 * 1024, 128, 0), - INFO("m25p128-nonjedec", 0, 0, 256 * 1024, 64, 0), - - INFO("m45pe10", 0x204011, 0, 64 * 1024, 2, 0), - INFO("m45pe80", 0x204014, 0, 64 * 1024, 16, 0), - INFO("m45pe16", 0x204015, 0, 64 * 1024, 32, 0), - - INFO("m25pe20", 0x208012, 0, 64 * 1024, 4, 0), - INFO("m25pe80", 0x208014, 0, 64 * 1024, 16, 0), - INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K), - - INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K), - INFO("m25px32", 0x207116, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px32-s0", 0x207316, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px32-s1", 0x206316, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0), - - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K), - INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K), - INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K), - INFO("w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K), - INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K), - INFO("w25q64", 0xef4017, 0, 64 * 1024, 128, SECT_4K), - INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K), - INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K), + INFO(m25p05, 0x202010, 0, 32 * 1024, 2, 0), + INFO(m25p10, 0x202011, 0, 32 * 1024, 4, 0), + INFO(m25p20, 0x202012, 0, 64 * 1024, 4, 0), + INFO(m25p40, 0x202013, 0, 64 * 1024, 8, 0), + INFO(m25p80, 0x202014, 0, 64 * 1024, 16, 0), + INFO(m25p16, 0x202015, 0, 64 * 1024, 32, 0), + INFO(m25p32, 0x202016, 0, 64 * 1024, 64, 0), + INFO(m25p64, 0x202017, 0, 64 * 1024, 128, 0), + INFO(m25p128, 0x202018, 0, 256 * 1024, 64, 0), + INFO(n25q032, 0x20ba16, 0, 64 * 1024, 64, 0), + + INFO(m25p05_nonjedec, 0, 0, 32 * 1024, 2, 0), + INFO(m25p10_nonjedec, 0, 0, 32 * 1024, 4, 0), + INFO(m25p20_nonjedec, 0, 0, 64 * 1024, 4, 0), + INFO(m25p40_nonjedec, 0, 0, 64 * 1024, 8, 0), + INFO(m25p80_nonjedec, 0, 0, 64 * 1024, 16, 0), + INFO(m25p16_nonjedec, 0, 0, 64 * 1024, 32, 0), + INFO(m25p32_nonjedec, 0, 0, 64 * 1024, 64, 0), + INFO(m25p64_nonjedec, 0, 0, 64 * 1024, 128, 0), + INFO(m25p128_nonjedec, 0, 0, 256 * 1024, 64, 0), + + INFO(m45pe10, 0x204011, 0, 64 * 1024, 2, 0), + INFO(m45pe80, 0x204014, 0, 64 * 1024, 16, 0), + INFO(m45pe16, 0x204015, 0, 64 * 1024, 32, 0), + + INFO(m25pe20, 0x208012, 0, 64 * 1024, 4, 0), + INFO(m25pe80, 0x208014, 0, 64 * 1024, 16, 0), + INFO(m25pe16, 0x208015, 0, 64 * 1024, 32, SECT_4K), + + INFO(m25px16, 0x207115, 0, 64 * 1024, 32, SECT_4K), + INFO(m25px32, 0x207116, 0, 64 * 1024, 64, SECT_4K), + INFO(m25px32_s0, 0x207316, 0, 64 * 1024, 64, SECT_4K), + INFO(m25px32_s1, 0x206316, 0, 64 * 1024, 64, SECT_4K), + INFO(m25px64, 0x207117, 0, 64 * 1024, 128, 0), + + /* Winbond -- w25x blocks are 64K, sectors are 4KiB */ + INFO(w25x10, 0xef3011, 0, 64 * 1024, 2, SECT_4K), + INFO(w25x20, 0xef3012, 0, 64 * 1024, 4, SECT_4K), + INFO(w25x40, 0xef3013, 0, 64 * 1024, 8, SECT_4K), + INFO(w25x80, 0xef3014, 0, 64 * 1024, 16, SECT_4K), + INFO(w25x16, 0xef3015, 0, 64 * 1024, 32, SECT_4K), + INFO(w25x32, 0xef3016, 0, 64 * 1024, 64, SECT_4K), + INFO(w25q32, 0xef4016, 0, 64 * 1024, 64, SECT_4K), + INFO(w25q32dw, 0xef6016, 0, 64 * 1024, 64, SECT_4K), + INFO(w25x64, 0xef3017, 0, 64 * 1024, 128, SECT_4K), + INFO(w25q64, 0xef4017, 0, 64 * 1024, 128, SECT_4K), + INFO(w25q80, 0xef5014, 0, 64 * 1024, 16, SECT_4K), + INFO(w25q80bl, 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO(w25q128, 0xef4018, 0, 64 * 1024, 256, SECT_4K), + INFO(w25q256, 0xef4019, 0, 64 * 1024, 512, SECT_4K), /* Catalyst / On Semiconductor -- non-JEDEC */ - CAT25_INFO("cat25c11", 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c03", 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c09", 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c17", 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25128", 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - { }, + CAT25_INFO(cat25c11, 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(cat25c03, 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(cat25c09, 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(cat25c17, 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO(cat25128, 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + + /* Fill in name fields */ +#define SPI_NOR_ENUM_TYPE(s, c) [CHIP_TYPE_ ## c].name = s, + SPI_NOR_ENUM_TYPES() +#undef SPI_NOR_ENUM_TYPE + + [CHIP_TYPE_COUNT] = { }, }; static const struct flash_info *spi_nor_info_by_name(const char *name) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 6f92b4b..03b7959 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -198,4 +198,76 @@ struct spi_nor { */ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); +#define __SPI_NOR_ENUM_TYPES(c_id, str_and_c_id) \ + c_id(at25fs010) c_id(at25fs040) c_id(at25df041a) \ + c_id(at25df321a) c_id(at25df641) c_id(at26f004) \ + c_id(at26df081a) c_id(at26df161a) c_id(at26df321) \ + c_id(at45db081d) \ + c_id(en25f32) c_id(en25p32) c_id(en25q32b) \ + c_id(en25p64) c_id(en25q64) c_id(en25qh128) \ + c_id(en25qh256) \ + c_id(f25l32pa) \ + c_id(mr25h256) c_id(mr25h10) \ + c_id(gd25q32) c_id(gd25q64) \ + c_id(160s33b) c_id(320s33b) c_id(640s33b) \ + c_id(mx25l2005a) c_id(mx25l4005a) c_id(mx25l8005) \ + c_id(mx25l1606e) c_id(mx25l3205d) c_id(mx25l3255e) \ + c_id(mx25l6405d) c_id(mx25l12805d) c_id(mx25l12855e) \ + c_id(mx25l25635e) c_id(mx25l25655e) c_id(mx66l51235l) \ + c_id(mx66l1g55g) \ + c_id(n25q064) c_id(n25q128a11) c_id(n25q128a13) \ + c_id(n25q256a) c_id(n25q512a) c_id(n25q512ax3) \ + c_id(n25q00) \ + c_id(pm25lv512) c_id(pm25lv010) c_id(pm25lq032) \ + c_id(s25sl032p) c_id(s25sl064p) c_id(s25fl256s0) \ + c_id(s25fl256s1) c_id(s25fl512s) c_id(s70fl01gs) \ + c_id(s25sl12800) c_id(s25sl12801) c_id(s25fl129p0) \ + c_id(s25fl129p1) c_id(s25sl004a) c_id(s25sl008a) \ + c_id(s25sl016a) c_id(s25sl032a) c_id(s25sl064a) \ + c_id(s25fl008k) c_id(s25fl016k) c_id(s25fl064k) \ + c_id(sst25vf040b) c_id(sst25vf080b) c_id(sst25vf016b) \ + c_id(sst25vf032b) c_id(sst25vf064c) c_id(sst25wf512) \ + c_id(sst25wf010) c_id(sst25wf020) c_id(sst25wf040) \ + c_id(m25p05) c_id(m25p10) c_id(m25p20) \ + c_id(m25p40) c_id(m25p80) c_id(m25p16) \ + c_id(m25p32) c_id(m25p64) c_id(m25p128) \ + c_id(n25q032) \ + str_and_c_id("m25p05-nonjedec", m25p05_nonjedec) \ + str_and_c_id("m25p10-nonjedec", m25p10_nonjedec) \ + str_and_c_id("m25p20-nonjedec", m25p20_nonjedec) \ + str_and_c_id("m25p40-nonjedec", m25p40_nonjedec) \ + str_and_c_id("m25p80-nonjedec", m25p80_nonjedec) \ + str_and_c_id("m25p16-nonjedec", m25p16_nonjedec) \ + str_and_c_id("m25p32-nonjedec", m25p32_nonjedec) \ + str_and_c_id("m25p64-nonjedec", m25p64_nonjedec) \ + str_and_c_id("m25p128-nonjedec", m25p128_nonjedec) \ + c_id(m45pe10) c_id(m45pe80) c_id(m45pe16) \ + c_id(m25pe20) c_id(m25pe80) c_id(m25pe16) \ + c_id(m25px16) c_id(m25px32) \ + str_and_c_id("m25px32-s0", m25px32_s0) \ + str_and_c_id("m25px32-s1", m25px32_s1) \ + c_id(m25px64) \ + c_id(w25x10) c_id(w25x20) c_id(w25x40) \ + c_id(w25x80) c_id(w25x16) c_id(w25x32) \ + c_id(w25q32) c_id(w25q32dw) c_id(w25x64) \ + c_id(w25q64) c_id(w25q80) c_id(w25q80bl) \ + c_id(w25q128) c_id(w25q256) \ + c_id(cat25c11) c_id(cat25c03) c_id(cat25c09) \ + c_id(cat25c17) c_id(cat25128) +#define __SPI_NOR_ENUM_TYPE_C_ID(id) SPI_NOR_ENUM_TYPE(#id, id) + +/** + * SPI_NOR_ENUM_TYPES - invoke SPI_NOR_ENUM_TYPE() for each SPI NOR chip type + * + * This will expand to SPI_NOR_ENUM_TYPE(string, c_id) for each chip + * type recognised by the spi-nor library. The first argument is the + * string literal version of the chip type name. The second argument + * is a version of the name suitable for including in a C identifier, + * though it may begin with a digit. + * + * The caller must define SPI_NOR_ENUM_TYPE before invoking this macro. + */ +#define SPI_NOR_ENUM_TYPES() \ + __SPI_NOR_ENUM_TYPES(__SPI_NOR_ENUM_TYPE_C_ID, SPI_NOR_ENUM_TYPE) + #endif -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Sun Sep 14 10:13:15 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Sun, 14 Sep 2014 18:13:15 +0100 Subject: [PATCH 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <1410714795.3040.45.camel@decadent.org.uk> On Sun, 2014-09-14 at 18:10 +0100, Ben Hutchings wrote: > The first patch in the series restores the module aliases to m25p80, but > it does so by duplicating the list of names. This should be suitable > for stable, but it isn't viable in the longer term. > > The following patches change the spi-nor interface so that this > duplication is no longer necessary. This includes removing > spi_nor::read_id, but it could be re-added after this with a different > interface, e.g. returning a flash_info structure (which would need to be > defined in spi_nor.h). Note that these patch are: - Based on your 'testing' branch - Untested by me, aside from compiling and checking that m25p80 has the expected module aliases Ben. -- Ben Hutchings The world is coming to an end. Please log off. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ryazanov.s.a at gmail.com Sun Sep 14 12:33:27 2014 From: ryazanov.s.a at gmail.com (Sergey Ryazanov) Date: Sun, 14 Sep 2014 23:33:27 +0400 Subject: [RFC 12/18] mtd: add Atheros AR2315 SPI Flash driver In-Reply-To: <1410723213-22440-1-git-send-email-ryazanov.s.a@gmail.com> References: <1410723213-22440-1-git-send-email-ryazanov.s.a@gmail.com> Message-ID: <1410723213-22440-13-git-send-email-ryazanov.s.a@gmail.com> Atheros AR2315 SoC have a SPI Flash unit with hybrid flash access: flash read is performed via memory mapping, on the other hand flash write is performed by explicitly issued SPI command. Signed-off-by: Sergey Ryazanov Cc: David Woodhouse Cc: Brian Norris Cc: linux-mtd at lists.infradead.org --- This driver is not ready for merging since it should be rewrited using spi-nor framework. --- arch/mips/ar231x/ar2315.c | 23 ++ drivers/mtd/devices/Kconfig | 5 + drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/ar2315.c | 459 ++++++++++++++++++++++++++++++++++ drivers/mtd/devices/ar2315_spiflash.h | 106 ++++++++ 5 files changed, 594 insertions(+) create mode 100644 drivers/mtd/devices/ar2315.c create mode 100644 drivers/mtd/devices/ar2315_spiflash.h diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c index ab38ad4..cab3b76 100644 --- a/arch/mips/ar231x/ar2315.c +++ b/arch/mips/ar231x/ar2315.c @@ -126,6 +126,28 @@ void __init ar2315_arch_init_irq(void) irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler); } +static struct resource ar2315_spiflash_res[] = { + { + .name = "spiflash_read", + .flags = IORESOURCE_MEM, + .start = AR2315_SPI_READ, + .end = AR2315_SPI_READ + 0x1000000 - 1, + }, + { + .name = "spiflash_mmr", + .flags = IORESOURCE_MEM, + .start = AR2315_SPI_MMR, + .end = AR2315_SPI_MMR + 12 - 1, + }, +}; + +static struct platform_device ar2315_spiflash = { + .id = -1, + .name = "ar2315-spiflash", + .resource = ar2315_spiflash_res, + .num_resources = ARRAY_SIZE(ar2315_spiflash_res) +}; + static struct resource ar2315_gpio_res[] = { { .name = "ar2315-gpio", @@ -171,6 +193,7 @@ void __init ar2315_init_devices(void) ar231x_find_config(ar2315_flash_limit); platform_device_register(&ar2315_gpio); + platform_device_register(&ar2315_spiflash); } static void ar2315_restart(char *command) diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index c49d0b1..9533867 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -112,6 +112,11 @@ config MTD_SST25L Set up your spi devices with the right board-specific platform data, if you want to specify device partitioning. +config MTD_AR2315 + tristate "Atheros AR2315+ SPI Flash support" + depends on SOC_AR2315 + default y + config MTD_BCM47XXSFLASH tristate "R/O support for serial flash on BCMA bus" depends on BCMA_SFLASH diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f..eaec8fb 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o +obj-$(CONFIG_MTD_AR2315) += ar2315.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o diff --git a/drivers/mtd/devices/ar2315.c b/drivers/mtd/devices/ar2315.c new file mode 100644 index 0000000..f2a5e28 --- /dev/null +++ b/drivers/mtd/devices/ar2315.c @@ -0,0 +1,459 @@ + +/* + * MTD driver for the SPI Flash Memory support on Atheros AR2315 + * + * Copyright (c) 2005-2006 Atheros Communications Inc. + * Copyright (C) 2006-2007 FON Technology, SL. + * Copyright (C) 2006-2007 Imre Kaloz + * Copyright (C) 2006-2009 Felix Fietkau + * Copyright (C) 2012 Alexandros C. Couloumbis + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar2315_spiflash.h" + +#define DRIVER_NAME "ar2315-spiflash" + +#define busy_wait(_priv, _condition, _wait) do { \ + while (_condition) { \ + if (_wait > 1) \ + msleep(_wait); \ + else if ((_wait == 1) && need_resched()) \ + schedule(); \ + else \ + udelay(1); \ + } \ +} while (0) + +enum { + FLASH_NONE, + FLASH_1MB, + FLASH_2MB, + FLASH_4MB, + FLASH_8MB, + FLASH_16MB, +}; + +/* Flash configuration table */ +struct flashconfig { + u32 byte_cnt; + u32 sector_cnt; + u32 sector_size; +}; + +static const struct flashconfig flashconfig_tbl[] = { + [FLASH_NONE] = { 0, 0, 0}, + [FLASH_1MB] = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, + STM_1MB_SECTOR_SIZE}, + [FLASH_2MB] = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, + STM_2MB_SECTOR_SIZE}, + [FLASH_4MB] = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, + STM_4MB_SECTOR_SIZE}, + [FLASH_8MB] = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, + STM_8MB_SECTOR_SIZE}, + [FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT, + STM_16MB_SECTOR_SIZE} +}; + +/* Mapping of generic opcodes to STM serial flash opcodes */ +enum { + SPI_WRITE_ENABLE, + SPI_WRITE_DISABLE, + SPI_RD_STATUS, + SPI_WR_STATUS, + SPI_RD_DATA, + SPI_FAST_RD_DATA, + SPI_PAGE_PROGRAM, + SPI_SECTOR_ERASE, + SPI_BULK_ERASE, + SPI_DEEP_PWRDOWN, + SPI_RD_SIG, +}; + +struct opcodes { + __u16 code; + __s8 tx_cnt; + __s8 rx_cnt; +}; + +static const struct opcodes stm_opcodes[] = { + [SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0}, + [SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0}, + [SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1}, + [SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0}, + [SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4}, + [SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0}, + [SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0}, + [SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0}, + [SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0}, + [SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0}, + [SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1}, +}; + +/* Driver private data structure */ +struct spiflash_priv { + struct mtd_info mtd; + void __iomem *readaddr; /* memory mapped data for read */ + void __iomem *mmraddr; /* memory mapped register space */ + struct mutex lock; /* serialize registers access */ +}; + +#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd) + +enum { + FL_READY, + FL_READING, + FL_ERASING, + FL_WRITING +}; + +/*****************************************************************************/ + +static u32 +spiflash_read_reg(struct spiflash_priv *priv, int reg) +{ + return ioread32(priv->mmraddr + reg); +} + +static void +spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data) +{ + iowrite32(data, priv->mmraddr + reg); +} + +static u32 +spiflash_wait_busy(struct spiflash_priv *priv) +{ + u32 reg; + + busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) & + SPI_CTL_BUSY, 0); + return reg; +} + +static u32 +spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr) +{ + const struct opcodes *op; + u32 reg, mask; + + op = &stm_opcodes[opcode]; + reg = spiflash_wait_busy(priv); + spiflash_write_reg(priv, SPI_FLASH_OPCODE, + ((u32)op->code) | (addr << 8)); + + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4); + + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + spiflash_wait_busy(priv); + + if (!op->rx_cnt) + return 0; + + reg = spiflash_read_reg(priv, SPI_FLASH_DATA); + + switch (op->rx_cnt) { + case 1: + mask = 0x000000ff; + break; + case 2: + mask = 0x0000ffff; + break; + case 3: + mask = 0x00ffffff; + break; + default: + mask = 0xffffffff; + break; + } + reg &= mask; + + return reg; +} + +/* + * Probe SPI flash device + * Function returns 0 for failure. + * and flashconfig_tbl array index for success. + */ +static int +spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv) +{ + u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0); + int flash_size; + + switch (sig) { + case STM_8MBIT_SIGNATURE: + flash_size = FLASH_1MB; + break; + case STM_16MBIT_SIGNATURE: + flash_size = FLASH_2MB; + break; + case STM_32MBIT_SIGNATURE: + flash_size = FLASH_4MB; + break; + case STM_64MBIT_SIGNATURE: + flash_size = FLASH_8MB; + break; + case STM_128MBIT_SIGNATURE: + flash_size = FLASH_16MB; + break; + default: + dev_warn(&pdev->dev, "read of flash device signature failed!\n"); + return 0; + } + + return flash_size; +} + +static void +spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout) +{ + busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) & + SPI_STATUS_WIP, timeout); +} + +static int +spiflash_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + const struct opcodes *op; + u32 temp, reg; + + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + + mutex_lock(&priv->lock); + + spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); + reg = spiflash_wait_busy(priv); + + op = &stm_opcodes[SPI_SECTOR_ERASE]; + temp = ((u32)instr->addr << 8) | (u32)(op->code); + spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp); + + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= op->tx_cnt | SPI_CTL_START; + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + + spiflash_wait_complete(priv, 20); + + mutex_unlock(&priv->lock); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +static int +spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, + u_char *buf) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + + if (!len) + return 0; + + if (from + len > mtd->size) + return -EINVAL; + + *retlen = len; + + mutex_lock(&priv->lock); + + memcpy_fromio(buf, priv->readaddr + from, len); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int +spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u8 *buf) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + u32 opcode, bytes_left; + + *retlen = 0; + + if (!len) + return 0; + + if (to + len > mtd->size) + return -EINVAL; + + bytes_left = len; + + do { + u32 read_len, reg, page_offset, spi_data = 0; + + read_len = min(bytes_left, sizeof(u32)); + + /* 32-bit writes cannot span across a page boundary + * (256 bytes). This types of writes require two page + * program operations to handle it correctly. The STM part + * will write the overflow data to the beginning of the + * current page as opposed to the subsequent page. + */ + page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len; + + if (page_offset > STM_PAGE_SIZE) + read_len -= (page_offset - STM_PAGE_SIZE); + + mutex_lock(&priv->lock); + + spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); + spi_data = 0; + switch (read_len) { + case 4: + spi_data |= buf[3] << 24; + /* fall through */ + case 3: + spi_data |= buf[2] << 16; + /* fall through */ + case 2: + spi_data |= buf[1] << 8; + /* fall through */ + case 1: + spi_data |= buf[0] & 0xff; + break; + default: + break; + } + + spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data); + opcode = stm_opcodes[SPI_PAGE_PROGRAM].code | + (to & 0x00ffffff) << 8; + spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode); + + reg = spiflash_read_reg(priv, SPI_FLASH_CTL); + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= (read_len + 4) | SPI_CTL_START; + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + + spiflash_wait_complete(priv, 1); + + mutex_unlock(&priv->lock); + + bytes_left -= read_len; + to += read_len; + buf += read_len; + + *retlen += read_len; + } while (bytes_left != 0); + + return 0; +} + +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS +static const char * const part_probe_types[] = { + "cmdlinepart", "RedBoot", "MyLoader", NULL +}; +#endif + +static int +spiflash_probe(struct platform_device *pdev) +{ + struct spiflash_priv *priv; + struct mtd_info *mtd; + struct resource *res; + int index; + int result = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->lock); + mtd = &priv->mtd; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->mmraddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->mmraddr)) { + dev_warn(&pdev->dev, "failed to map flash MMR\n"); + return PTR_ERR(priv->mmraddr); + } + + index = spiflash_probe_chip(pdev, priv); + if (!index) { + dev_warn(&pdev->dev, "found no flash device\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->readaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->readaddr)) { + dev_warn(&pdev->dev, "failed to map flash read mem\n"); + return PTR_ERR(priv->readaddr); + } + + platform_set_drvdata(pdev, priv); + mtd->name = "spiflash"; + mtd->type = MTD_NORFLASH; + mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE); + mtd->size = flashconfig_tbl[index].byte_cnt; + mtd->erasesize = flashconfig_tbl[index].sector_size; + mtd->writesize = 1; + mtd->numeraseregions = 0; + mtd->eraseregions = NULL; + mtd->_erase = spiflash_erase; + mtd->_read = spiflash_read; + mtd->_write = spiflash_write; + mtd->owner = THIS_MODULE; + + dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10); + +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS + /* parse redboot partitions */ + + result = mtd_device_parse_register(mtd, part_probe_types, + NULL, NULL, 0); +#endif + + return result; +} + +static int +spiflash_remove(struct platform_device *pdev) +{ + struct spiflash_priv *priv = platform_get_drvdata(pdev); + + mtd_device_unregister(&priv->mtd); + + return 0; +} + +static struct platform_driver spiflash_driver = { + .driver.name = DRIVER_NAME, + .probe = spiflash_probe, + .remove = spiflash_remove, +}; + +module_platform_driver(spiflash_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("OpenWrt.org"); +MODULE_AUTHOR("Atheros Communications Inc"); +MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC"); +MODULE_ALIAS("platform:" DRIVER_NAME); + diff --git a/drivers/mtd/devices/ar2315_spiflash.h b/drivers/mtd/devices/ar2315_spiflash.h new file mode 100644 index 0000000..17b0903 --- /dev/null +++ b/drivers/mtd/devices/ar2315_spiflash.h @@ -0,0 +1,106 @@ +/* + * Atheros AR2315 SPI Flash Memory support header file. + * + * Copyright (c) 2005, Atheros Communications Inc. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz + * Copyright (C) 2006-2009 Felix Fietkau + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __AR2315_SPIFLASH_H +#define __AR2315_SPIFLASH_H + +#define STM_PAGE_SIZE 256 + +#define SFI_WRITE_BUFFER_SIZE 4 +#define SFI_FLASH_ADDR_MASK 0x00ffffff + +#define STM_8MBIT_SIGNATURE 0x13 +#define STM_M25P80_BYTE_COUNT 1048576 +#define STM_M25P80_SECTOR_COUNT 16 +#define STM_M25P80_SECTOR_SIZE 0x10000 + +#define STM_16MBIT_SIGNATURE 0x14 +#define STM_M25P16_BYTE_COUNT 2097152 +#define STM_M25P16_SECTOR_COUNT 32 +#define STM_M25P16_SECTOR_SIZE 0x10000 + +#define STM_32MBIT_SIGNATURE 0x15 +#define STM_M25P32_BYTE_COUNT 4194304 +#define STM_M25P32_SECTOR_COUNT 64 +#define STM_M25P32_SECTOR_SIZE 0x10000 + +#define STM_64MBIT_SIGNATURE 0x16 +#define STM_M25P64_BYTE_COUNT 8388608 +#define STM_M25P64_SECTOR_COUNT 128 +#define STM_M25P64_SECTOR_SIZE 0x10000 + +#define STM_128MBIT_SIGNATURE 0x17 +#define STM_M25P128_BYTE_COUNT 16777216 +#define STM_M25P128_SECTOR_COUNT 256 +#define STM_M25P128_SECTOR_SIZE 0x10000 + +#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT +#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT +#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE +#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT +#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT +#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE +#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT +#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT +#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE +#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT +#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT +#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE +#define STM_16MB_BYTE_COUNT STM_M25P128_BYTE_COUNT +#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT +#define STM_16MB_SECTOR_SIZE STM_M25P128_SECTOR_SIZE + +/* + * ST Microelectronics Opcodes for Serial Flash + */ + +#define STM_OP_WR_ENABLE 0x06 /* Write Enable */ +#define STM_OP_WR_DISABLE 0x04 /* Write Disable */ +#define STM_OP_RD_STATUS 0x05 /* Read Status */ +#define STM_OP_WR_STATUS 0x01 /* Write Status */ +#define STM_OP_RD_DATA 0x03 /* Read Data */ +#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */ +#define STM_OP_PAGE_PGRM 0x02 /* Page Program */ +#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */ +#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */ +#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */ +#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */ + +#define STM_STATUS_WIP 0x01 /* Write-In-Progress */ +#define STM_STATUS_WEL 0x02 /* Write Enable Latch */ +#define STM_STATUS_BP0 0x04 /* Block Protect 0 */ +#define STM_STATUS_BP1 0x08 /* Block Protect 1 */ +#define STM_STATUS_BP2 0x10 /* Block Protect 2 */ +#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */ + +/* + * SPI Flash Interface Registers + */ + +#define SPI_FLASH_CTL 0x00 +#define SPI_FLASH_OPCODE 0x04 +#define SPI_FLASH_DATA 0x08 + +#define SPI_CTL_START 0x00000100 +#define SPI_CTL_BUSY 0x00010000 +#define SPI_CTL_TXCNT_MASK 0x0000000f +#define SPI_CTL_RXCNT_MASK 0x000000f0 +#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff +#define SPI_CTL_SIZE_MASK 0x00060000 + +#define SPI_CTL_CLK_SEL_MASK 0x03000000 +#define SPI_OPCODE_MASK 0x000000ff + +#define SPI_STATUS_WIP STM_STATUS_WIP + +#endif -- 1.8.1.5 From hauke at hauke-m.de Sun Sep 14 14:45:02 2014 From: hauke at hauke-m.de (Hauke Mehrtens) Date: Sun, 14 Sep 2014 23:45:02 +0200 Subject: [PATCH] mtd: nand: fix return code for uncorrectable error Message-ID: <1410731102-26765-1-git-send-email-hauke@hauke-m.de> nand_correct_data() should return -EBADMSG when it finds an uncorrectable error and not just -1. This is based on OpenWrt patch: https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.10/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patcht Signed-off-by: Hauke Mehrtens --- drivers/mtd/nand/nand_ecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 97c4c02..244a634 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf, return 1; /* error in ECC data; no action needed */ pr_err("%s: uncorrectable ECC error\n", __func__); - return -1; + return -EBADMSG; } EXPORT_SYMBOL(__nand_correct_data); -- 1.9.1 From hauke at hauke-m.de Sun Sep 14 14:46:41 2014 From: hauke at hauke-m.de (Hauke Mehrtens) Date: Sun, 14 Sep 2014 23:46:41 +0200 Subject: [PATCH] mtd: spi-nor: add support for the Winbond W25X05 flash Message-ID: <1410731201-27521-1-git-send-email-hauke@hauke-m.de> Signed-off-by: Gabor Juhos Signed-off-by: Hauke Mehrtens --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 03e0ab8..7a08076 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -614,6 +614,7 @@ const struct spi_device_id spi_nor_ids[] = { { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, -- 1.9.1 From geert at linux-m68k.org Mon Sep 15 00:55:36 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Mon, 15 Sep 2014 09:55:36 +0200 Subject: [PATCH 5/5] m25p80, spi-nor: Share the list of supported chip type names again In-Reply-To: <1410714708.3040.43.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714708.3040.43.camel@decadent.org.uk> Message-ID: Hi Ben, On Sun, Sep 14, 2014 at 7:11 PM, Ben Hutchings wrote: > Move the list of chip type names to spi-nor.h. To avoid putting all > the chip type information there, we define this list as a macro > SPI_NOR_ENUM_TYPES() that invokes another macro SPI_NOR_ENUM_TYPE() > that must be defined to expand each name to whatever form it's needed. > > In spi-nor.c, use it to define enumerators, then use the enumerators > as indices when defining spi_nor_info so that we cannot accidentally > use a name that's not on the list. > > This is somewhat complicated by the fact that some names include > hyphens. SPI_NOR_ENUM_TYPE() therefore takes separate string and C > identifier parameters. Thanks for doing this! However, the table generation still looks overly complicated to me, with too much duplication which needs to be kept in sync. > --- a/drivers/mtd/devices/m25p80.c > +++ b/drivers/mtd/devices/m25p80.c > @@ -245,51 +245,10 @@ static int m25p_remove(struct spi_device *spi) > } > > > -/* > - * XXX This needs to be kept in sync with spi_nor_info. We can't share > - * it with spi-nor, because if this is built as a module then modpost > - * won't be able to read it and add appropriate aliases. > - */ > static const struct spi_device_id m25p_ids[] = { [...] > +#define SPI_NOR_ENUM_TYPE(s, c) { s }, > + SPI_NOR_ENUM_TYPES() > +#undef SPI_NOR_ENUM_TYPE > { }, > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > /* NOTE: double check command sets and memory organization when you add > * more nor chips. This current list focusses on newer chips, which > * have been converging on command sets which including JEDEC ID. > + * > + * All chip type names must be added to __SPI_NOR_ENUM_TYPES in Oops... These will get out of sync. > + * spi-nor.h before they can be used here (enforced by using the > + * names to index this array). > */ > static const struct flash_info spi_nor_info[] = { > /* Atmel -- some are (confusingly) marketed as "DataFlash" */ > - INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), > - INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), > + INFO(at25fs010, 0x1f6601, 0, 32 * 1024, 4, SECT_4K), > + INFO(at25fs040, 0x1f6604, 0, 64 * 1024, 8, SECT_4K), [...] > --- a/include/linux/mtd/spi-nor.h > +++ b/include/linux/mtd/spi-nor.h > @@ -198,4 +198,76 @@ struct spi_nor { > */ > int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); > > +#define __SPI_NOR_ENUM_TYPES(c_id, str_and_c_id) \ > + c_id(at25fs010) c_id(at25fs040) c_id(at25df041a) \ > + c_id(at25df321a) c_id(at25df641) c_id(at26f004) \ Can't you just have the IDs in a header file only, and let the header file generate either a struct flash_info or a struct spi_device_id table, using a macro defined by the file that includes it? Cfr. include/uapi/asm-generic/unistd.h and its use of __SYSCALL()? Or am I missing something (e.g. this is impossible due to the hyphens in the names?). Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From rogerq at ti.com Mon Sep 15 01:20:56 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 15 Sep 2014 11:20:56 +0300 Subject: [PATCH 0/3] nand: Renaming, moving and fixing NAND and ELM drivers In-Reply-To: References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B4C0.505@ti.com> Message-ID: <5416A168.2040604@ti.com> On 09/12/2014 07:46 PM, Ezequiel Garcia wrote: > On 12 September 2014 09:54, Roger Quadros wrote: >> Hi Ezequiel, >> >> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >>> Following the recent discussion with Roger, here's a few patches that >>> (hopefully) fix all the issues. >>> >>> The first patches rename the OMAP NAND drivers, so they are now called >>> omap2_nand and omap_elm. >>> >>> The last patch picks an idea from Yann E. Morin and fixes the build issue >>> reported by Roger. Quoting Roger: >>> >>> "" >>> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and >>> CONFIG_MTD_NAND_OMAP_BCH to m. >>> >>> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to >>> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. >>> >>> Maybe it should be a sub option of CONFIG_MTD_NAND_OMAP2. >>> IMHO the elm.c file must be moved from mtd/devices to mtd/nand and renamed to omap_elm.c >>> >>> drivers/built-in.o: In function `omap_nand_probe': >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >>> drivers/built-in.o: In function `omap_elm_correct_data': >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >>> make: *** [vmlinux] Error 1 >>> "" >>> >>> [1] https://lkml.org/lkml/2013/5/4/84 >>> >>> Ezequiel Garcia (3): >>> mtd: nand: Move ELM driver and rename as omap_elm >>> mtd: nand: Rename OMAP NAND driver >>> mtd: nand: Force omap_elm to be built as a module if omap2_nand is a >>> module >> >> Thanks for the patches. I see a lot of errors reported by checkpatch.pl which need fixing. >> > > You mean on these patches or across the file? > Just in these patches. cheers, -roger From rogerq at ti.com Mon Sep 15 01:27:43 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 15 Sep 2014 11:27:43 +0300 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <20140912165636.GA7276@arch> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> Message-ID: <5416A2FF.3050503@ti.com> On 09/12/2014 07:56 PM, Ezequiel Garcia wrote: > On 12 Sep 12:01 PM, Roger Quadros wrote: >> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >>> This commit adds a hidden option to build the omap_elm as a module, if >>> omap2_nand is a module (and similarly in the built-in case). >>> >>> This fixes the following build error when omap2_nand is chosen built-in, >>> and omap_elm is chosen as a module: >>> >>> drivers/built-in.o: In function `omap_nand_probe': >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >>> drivers/built-in.o: In function `omap_elm_correct_data': >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >>> >>> Signed-off-by: Ezequiel Garcia >>> --- >>> drivers/mtd/nand/Kconfig | 8 +++++++- >>> drivers/mtd/nand/Makefile | 2 +- >>> 2 files changed, 8 insertions(+), 2 deletions(-) >>> >>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >>> index f1cf503..12e8ee8 100644 >>> --- a/drivers/mtd/nand/Kconfig >>> +++ b/drivers/mtd/nand/Kconfig >>> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 >>> >>> config MTD_NAND_OMAP_BCH >>> depends on MTD_NAND_OMAP2 >>> - tristate "Support hardware based BCH error correction" >>> + bool "Support hardware based BCH error correction" >>> default n >>> select BCH >>> help >>> @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH >>> legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine >>> so they should not enable this config symbol. >>> >>> +config MTD_NAND_OMAP_BCH_BUILD >>> + tristate >>> + depends on MTD_NAND_OMAP2 >>> + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH >>> + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH >>> + >>> config MTD_NAND_IDS >>> tristate >>> >>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile >>> index 4bcdeb0..3580188 100644 >>> --- a/drivers/mtd/nand/Makefile >>> +++ b/drivers/mtd/nand/Makefile >>> @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o >>> obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o >>> obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o >>> obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o >>> -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o >>> +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o >>> obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o >>> obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o >>> obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o >>> >> >> The overall logic seems to work but I still see the following issue. >> >> In menuconfig, the OMAP_BCH option is still visible as a boolean even though >> the ELM module finally gets built as a module. >> This can be confusing to the user and I'd avoid that behaviour. >> > > Yes, I know. But it's either this solution or no solution at all, I think. > > Let me give some further context about this patch, so we can have more > information to decide. > > First of all (and IMO) the user doesn't have to know about the ELM being > a module or not, because modprobe will load it (since omap2_nand depends > on omap_elm's symbols). > > So, the new way seems a bit more intuitive for me. The user choses if he > wants to have hardware BCH support, and such support gets built the right > way. > > If we still consider this highly confusing, and we want to avoid it, > then it seems we can only make omap_elm a boolean, which means it'll always > be built-in. I crafted this patch in an effort to avoid making it boolean. > > Finally, the solution is taken from media/usb/stk1160. For good or for bad, > we have a precedent in doing things this way. > > Ultimately, I don't care much as I don't think anyone will build it as a module, > except maybe for testing the driver under probe/remove cycles. > OK. I personally prefer boolean than the Kconfig magic as it makes my life a bit easier and less confusing to the user i.e. wysiwyg ;). Let's see what the MTD maintainers prefer. Brian and David, any insights on this problem? cheers, -roger From richard at nod.at Mon Sep 15 02:11:20 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 15 Sep 2014 11:11:20 +0200 Subject: [PATCH] Add UBIFS support Message-ID: <1410772280-9771-1-git-send-email-richard@nod.at> UBIFS needs some extra care, the device node is of type character and it has no fsck tool. Signed-off-by: Richard Weinberger --- README | 1 + check | 2 ++ common/config | 4 ++-- common/rc | 18 ++++++++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/README b/README index 8a362bd..96adc44 100644 --- a/README +++ b/README @@ -100,6 +100,7 @@ Running tests: Running all the udf tests: ./check -udf -g udf - for running nfs tests: ./check -nfs [test(s)] - for running cifs/smb3 tests: ./check -cifs [test(s)] + - for running ubifs tests: ./check -ubifs [test(s)] - To randomize test order: ./check -r [test(s)] diff --git a/check b/check index 42a1ac2..57ec612 100755 --- a/check +++ b/check @@ -70,6 +70,7 @@ check options -nfs test NFS -cifs test CIFS -tmpfs test TMPFS + -ubifs test UBIFS -l line mode diff -udiff show unified diff (default) -n show me, do not run tests @@ -208,6 +209,7 @@ while [ $# -gt 0 ]; do -nfs) FSTYP=nfs ;; -cifs) FSTYP=cifs ;; -tmpfs) FSTYP=tmpfs ;; + -ubifs) FSTYP=ubifs ;; -g) group=$2 ; shift ; GROUP_LIST="$GROUP_LIST $group" diff --git a/common/config b/common/config index fc21b37..af082ea 100644 --- a/common/config +++ b/common/config @@ -430,7 +430,7 @@ get_next_config() { exit 1 fi - echo $TEST_DEV | grep -qE ":|//" > /dev/null 2>&1 + echo $TEST_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 if [ ! -b "$TEST_DEV" -a "$?" != "0" ]; then echo "common/config: Error: \$TEST_DEV ($TEST_DEV) is not a block device or a network filesystem" exit 1 @@ -453,7 +453,7 @@ get_next_config() { export SCRATCH_DEV_NOT_SET=true fi - echo $SCRATCH_DEV | grep -qE ":|//" > /dev/null 2>&1 + echo $SCRATCH_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" -a "$?" != "0" ]; then echo "common/config: Error: \$SCRATCH_DEV ($SCRATCH_DEV) is not a block device or a network filesystem" exit 1 diff --git a/common/rc b/common/rc index b8f711a..064b987 100644 --- a/common/rc +++ b/common/rc @@ -1034,6 +1034,12 @@ _require_scratch_nocheck() _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" fi ;; + ubifs) + if [ -z "$SCRATCH_DEV" -o ! -c "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ]; + then + _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" + fi + ;; *) if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ] then @@ -1100,6 +1106,12 @@ _require_test() _notrun "this test requires a valid \$TEST_DIR and unique $TEST_DEV" fi ;; + ubifs) + if [ -z "$TEST_DEV" -o ! -c "$TEST_DEV" -o ! -d "$TEST_DIR" ]; + then + _notrun "this test requires a valid \$TEST_DIR and a valid $TEST_DEV" + fi + ;; *) if [ -z "$TEST_DEV" -o "`_is_block_dev $TEST_DEV`" = "" ] then @@ -1897,6 +1909,9 @@ _check_test_fs() tmpfs) # no way to check consistency for tmpfs ;; + ubifs) + # ubifs has no fsck :-( + ;; *) _check_generic_filesystem $TEST_DEV ;; @@ -1935,6 +1950,9 @@ _check_scratch_fs() tmpfs) # no way to check consistency for tmpfs ;; + ubifs) + # ubifs has no fsck :-( + ;; *) _check_generic_filesystem $device ;; -- 1.8.4.5 From richard at nod.at Mon Sep 15 02:12:34 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 15 Sep 2014 11:12:34 +0200 Subject: [PATCH] Add UBIFS support In-Reply-To: <1410772280-9771-1-git-send-email-richard@nod.at> References: <1410772280-9771-1-git-send-email-richard@nod.at> Message-ID: <5416AD82.5070206@nod.at> Am 15.09.2014 11:11, schrieb Richard Weinberger: > UBIFS needs some extra care, the device node is of type character and > it has no fsck tool. > > Signed-off-by: Richard Weinberger > --- > README | 1 + > check | 2 ++ > common/config | 4 ++-- > common/rc | 18 ++++++++++++++++++ > 4 files changed, 23 insertions(+), 2 deletions(-) To avoid confusion, this patch is for xfstests. :-) Thanks, //richard From richard at nod.at Mon Sep 15 02:13:28 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 15 Sep 2014 11:13:28 +0200 Subject: xfstests on UBIFS - first findings Message-ID: <5416ADB8.80301@nod.at> Hi! Running xfstests on UBIFS exposed some issues. Out of 76 tests 20 failed, hopefully most of them are false positives. Please see the attached test log. I'm sharing my findings very early to work together on it. xfstests manages also to trigger an UBIFS assert: ---cut--- [ 141.072471] UBIFS assert failed in ubifs_jnl_update at 558 (pid 2622) [ 141.074984] CPU: 2 PID: 2622 Comm: setfattr Not tainted 3.17.0-rc4+ #62 [ 141.077540] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140816_022509-build35 04/01/2014 [ 141.081974] ffff88003ae8bd00 ffff88003ae8bc40 ffffffff818b4563 0000000000000000 [ 141.083765] ffff88003ae8bcd0 ffffffff81299da4 ffff880000000004 0000000000000246 [ 141.085564] ffffffff812c4964 ffff88003aed0560 ffffffff00000000 ffff88003bd604a0 [ 141.087373] Call Trace: [ 141.087941] [] dump_stack+0x4d/0x66 [ 141.089131] [] ubifs_jnl_update+0x5e4/0x690 [ 141.090464] [] ? ubifs_setxattr+0x294/0x680 [ 141.091804] [] ubifs_setxattr+0x301/0x680 [ 141.093101] [] __vfs_setxattr_noperm+0x63/0x1b0 [ 141.094522] [] vfs_setxattr+0xad/0xb0 [ 141.095735] [] setxattr+0x116/0x1a0 [ 141.096920] [] ? mnt_want_write+0x1f/0x50 [ 141.098211] [] ? __sb_start_write+0xed/0x1a0 [ 141.099489] [] ? mnt_want_write+0x1f/0x50 [ 141.100704] [] ? mnt_want_write+0x1f/0x50 [ 141.101937] [] SyS_lsetxattr+0x87/0xd0 [ 141.103098] [] system_call_fastpath+0x16/0x1b ---cut--- One can simple trigger it by doing: # mknod foo c 0 0 # setfattr -h -n trusted.name foo dir_ui->data_len is 4 instead of 0. Thanks, //richard -------------- next part -------------- A non-text attachment was scrubbed... Name: test.log Type: text/x-log Size: 20841 bytes Desc: not available URL: From shijie8 at gmail.com Mon Sep 15 07:43:02 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Mon, 15 Sep 2014 22:43:02 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140913173841.GA18093@brian-ubuntu> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> <20140913173841.GA18093@brian-ubuntu> Message-ID: <20140915144259.GA1947@localhost.localdomain> On Sat, Sep 13, 2014 at 10:38:41AM -0700, Brian Norris wrote: > On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > > This test validates what's returned by ecc_strength file in sysfs > > > (which in turn is specified by the NAND controller when initializing > > > the NAND chip). > > > > > > Doing this should not imply knowing the ECC algorithm in use in the > > > NAND controller or the layout used to store data on NAND. > > the difficulty is that the ECC parity area can be not byte aligned. > > Is there a problem with just rounding up to the nearest byte alignment > and ignoring the few bits that are wasted? I feel a little confused with the two hooks. does the ecc->write_page_raw need to write the ECC parity data? The page's layout after an ecc->write_page will look like this: (Block Mark) | | | D | |<---->| V V +---+----------+-+----------+-+----------+-+----------+-+ | M | data |E| data |E| data |E| data |E| +---+----------+-+----------+-+----------+-+----------+-+ What will the page's layout look like after the ecc->write_page_raw? thanks Huang Shijie From shijie8 at gmail.com Mon Sep 15 07:55:24 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Mon, 15 Sep 2014 22:55:24 +0800 Subject: [PATCH 2/5] spi-nor: Remove spi_nor::read_id operation In-Reply-To: <1410714676.3040.40.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714676.3040.40.camel@decadent.org.uk> Message-ID: <20140915145523.GA1963@localhost.localdomain> On Sun, Sep 14, 2014 at 06:11:16PM +0100, Ben Hutchings wrote: > There is currently no useful way to override the default > implementation of this operation. The returned struct spi_device_id > must have a pointer to struct flash_info in its private data, but this > structure is defined inside spi-nor. > > Signed-off-by: Ben Hutchings > --- > drivers/mtd/spi-nor/spi-nor.c | 4 +--- > include/linux/mtd/spi-nor.h | 3 --- > 2 files changed, 1 insertion(+), 6 deletions(-) > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index 6b1bda2..6f699c5 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -902,8 +902,6 @@ static int spi_nor_check(struct spi_nor *nor) > return -EINVAL; > } > > - if (!nor->read_id) > - nor->read_id = spi_nor_read_id; > if (!nor->wait_till_ready) > nor->wait_till_ready = spi_nor_wait_till_ready; > > @@ -952,7 +950,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > if (info->jedec_id) { > const struct spi_device_id *jid; > > - jid = nor->read_id(nor); > + jid = spi_nor_read_id(nor); > if (IS_ERR(jid)) { > return PTR_ERR(jid); > } else if (jid != id) { > diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h > index 5ec84cc..66af67a 100644 > --- a/include/linux/mtd/spi-nor.h > +++ b/include/linux/mtd/spi-nor.h > @@ -139,8 +139,6 @@ enum spi_nor_ops { > * @write_xfer: [OPTIONAL] the writefundamental primitive > * @read_reg: [DRIVER-SPECIFIC] read out the register > * @write_reg: [DRIVER-SPECIFIC] write data to the register > - * @read_id: [REPLACEABLE] read out the ID data, and find > - * the proper spi_device_id If we remove this hook, i guess we will add it back in the later. Other new drivers will use this hook. so i suggest to keep it as it is. thanks Huang Shijie From ben at decadent.org.uk Mon Sep 15 08:07:07 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Mon, 15 Sep 2014 16:07:07 +0100 Subject: [PATCH 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: References: <1410714624.3040.38.camel@decadent.org.uk> <1410714708.3040.43.camel@decadent.org.uk> Message-ID: <1410793627.3040.61.camel@decadent.org.uk> On Mon, 2014-09-15 at 09:55 +0200, Geert Uytterhoeven wrote: > Hi Ben, > > On Sun, Sep 14, 2014 at 7:11 PM, Ben Hutchings wrote: > > Move the list of chip type names to spi-nor.h. To avoid putting all > > the chip type information there, we define this list as a macro > > SPI_NOR_ENUM_TYPES() that invokes another macro SPI_NOR_ENUM_TYPE() > > that must be defined to expand each name to whatever form it's needed. > > > > In spi-nor.c, use it to define enumerators, then use the enumerators > > as indices when defining spi_nor_info so that we cannot accidentally > > use a name that's not on the list. > > > > This is somewhat complicated by the fact that some names include > > hyphens. SPI_NOR_ENUM_TYPE() therefore takes separate string and C > > identifier parameters. > > Thanks for doing this! > > However, the table generation still looks overly complicated to me, with > too much duplication which needs to be kept in sync. It does need to be kept in sync, but the compiler will check that. [...] > > --- a/include/linux/mtd/spi-nor.h > > +++ b/include/linux/mtd/spi-nor.h > > @@ -198,4 +198,76 @@ struct spi_nor { > > */ > > int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); > > > > +#define __SPI_NOR_ENUM_TYPES(c_id, str_and_c_id) \ > > + c_id(at25fs010) c_id(at25fs040) c_id(at25df041a) \ > > + c_id(at25df321a) c_id(at25df641) c_id(at26f004) \ > > Can't you just have the IDs in a header file only, and let the header file > generate either a struct flash_info or a struct spi_device_id table, using > a macro defined by the file that includes it? How would we match up the rest of the struct flash_info to the name? > Cfr. include/uapi/asm-generic/unistd.h and its use of __SYSCALL()? > > Or am I missing something (e.g. this is impossible due to the hyphens in the > names?). Well the hyphens are only a problem because we want C identifiers. But we only need C identifiers so we can enforce that each struct flash_info matches a name on the list. If you can find a way to match them up without having to define enumerators, that would of course be preferable. Ben. -- Ben Hutchings Make three consecutive correct guesses and you will be considered an expert. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 15 08:08:00 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Mon, 15 Sep 2014 16:08:00 +0100 Subject: [PATCH 2/5] spi-nor: Remove spi_nor::read_id operation In-Reply-To: <20140915145523.GA1963@localhost.localdomain> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714676.3040.40.camel@decadent.org.uk> <20140915145523.GA1963@localhost.localdomain> Message-ID: <1410793680.3040.62.camel@decadent.org.uk> On Mon, 2014-09-15 at 22:55 +0800, Huang Shijie wrote: > On Sun, Sep 14, 2014 at 06:11:16PM +0100, Ben Hutchings wrote: > > There is currently no useful way to override the default > > implementation of this operation. The returned struct spi_device_id > > must have a pointer to struct flash_info in its private data, but this > > structure is defined inside spi-nor. > > > > Signed-off-by: Ben Hutchings > > --- > > drivers/mtd/spi-nor/spi-nor.c | 4 +--- > > include/linux/mtd/spi-nor.h | 3 --- > > 2 files changed, 1 insertion(+), 6 deletions(-) > > > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > > index 6b1bda2..6f699c5 100644 > > --- a/drivers/mtd/spi-nor/spi-nor.c > > +++ b/drivers/mtd/spi-nor/spi-nor.c > > @@ -902,8 +902,6 @@ static int spi_nor_check(struct spi_nor *nor) > > return -EINVAL; > > } > > > > - if (!nor->read_id) > > - nor->read_id = spi_nor_read_id; > > if (!nor->wait_till_ready) > > nor->wait_till_ready = spi_nor_wait_till_ready; > > > > @@ -952,7 +950,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > > if (info->jedec_id) { > > const struct spi_device_id *jid; > > > > - jid = nor->read_id(nor); > > + jid = spi_nor_read_id(nor); > > if (IS_ERR(jid)) { > > return PTR_ERR(jid); > > } else if (jid != id) { > > diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h > > index 5ec84cc..66af67a 100644 > > --- a/include/linux/mtd/spi-nor.h > > +++ b/include/linux/mtd/spi-nor.h > > @@ -139,8 +139,6 @@ enum spi_nor_ops { > > * @write_xfer: [OPTIONAL] the writefundamental primitive > > * @read_reg: [DRIVER-SPECIFIC] read out the register > > * @write_reg: [DRIVER-SPECIFIC] write data to the register > > - * @read_id: [REPLACEABLE] read out the ID data, and find > > - * the proper spi_device_id > If we remove this hook, i guess we will add it back in the later. > Other new drivers will use this hook. > > so i suggest to keep it as it is. It may well be needed, but it can't be implemented in its current form. Ben. -- Ben Hutchings Make three consecutive correct guesses and you will be considered an expert. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From computersforpeace at gmail.com Mon Sep 15 10:31:52 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 10:31:52 -0700 Subject: [PATCH v1] mtdinfo: Initialize reginfo variable before invoking mtd_regioninfo In-Reply-To: <1407294015-27884-1-git-send-email-Wei.Yang@windriver.com> References: <1407294015-27884-1-git-send-email-Wei.Yang@windriver.com> Message-ID: <20140915173152.GA14832@ld-irv-0074> Hi Yang, On Wed, Aug 06, 2014 at 11:00:15AM +0800, Wei.Yang at windriver.com wrote: > From: Yang Wei > > If not initializing this variable, its value would be random. So > once the value of the regionindex field of region_info_user structure > is greater than mtd->numeraseregions. ioctl,which comes with MEMGETREGIONINFO, > would return -EINVAL > > Signed-off-by: Yang Wei > --- > ubi-utils/mtdinfo.c | 2 ++ > 1 file changed, 2 insertions(+) > > Hi Guys, > > I got the following errors when running "mtdinfo /dev/mtd0" on Cavium 6100 board, > > > root at CN61XX:~# mtdinfo /dev/mtd0 > mtd0 > Name: phys_mapped_flash > Type: nor > Eraseblock size: 65536 bytes, 64.0 KiB > Amount of eraseblocks: 128 (8388608 bytes, 8.0 MiB) > Minimum input/output unit size: 1 byte > Sub-page size: 1 byte > Additional erase regions: 0 > Character device major/minor: 90:0 > Bad blocks are allowed: false > Device is writable: true > libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 0 > error 22 (Invalid argument) > Eraseblock region 0: info is unavailable > libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 1 > error 22 (Invalid argument) > Eraseblock region 1: info is unavailable These error messages look deceptive. The problem is that while mtd_regioninfo() takes a region index parameter, it only uses it for printing the error message; its value is not actually propagated to the ioctl(). > > This patch is to fix the above errors. I have already verified it > > root at CN61XX:~# ./mtdinfo /dev/mtd0 > mtd0 > Name: phys_mapped_flash > Type: nor > Eraseblock size: 65536 bytes, 64.0 KiB > Amount of eraseblocks: 128 (8388608 bytes, 8.0 MiB) > Minimum input/output unit size: 1 byte > Sub-page size: 1 byte > Additional erase regions: 0 > Character device major/minor: 90:0 > Bad blocks are allowed: false > Device is writable: true > Eraseblock region 0: offset: 0 size: 0x10000 numblocks: 0x7f > Eraseblock region 1: offset: 0 size: 0x10000 numblocks: 0x7f These last two lines look wrong. Why would the device have two identical erase regions? In fact, it looks like your patch just means that we'll call ioctl(MEMGETREGIONINFO) repeatedly for region 0, instead of once for each indexed region. > > root at CN61XX:~# > > > diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c > index 5ac95aa..a70db00 100644 > --- a/ubi-utils/mtdinfo.c > +++ b/ubi-utils/mtdinfo.c > @@ -253,6 +253,8 @@ static void print_region_info(const struct mtd_dev_info *mtd) > if (!args.node || (!args.map && mtd->region_cnt == 0)) > return; > > + memset(®info, 0, sizeof(region_info_t)); > + This might be good for security (to make sure that we never leak garbage or use garbage stack data), but it doesn't actually fix anything. > /* First open the device so we can query it */ > fd = open(args.node, O_RDONLY | O_CLOEXEC); > if (fd == -1) { I think you need a patch like this instead (untested): diff --git a/lib/libmtd.c b/lib/libmtd.c index aff4c8be01b5..a6665f08018e 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -901,6 +901,8 @@ int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo) return -1; } + reginfo->regionindex = regidx; + ret = ioctl(fd, MEMGETREGIONINFO, reginfo); if (ret < 0) return sys_errmsg("%s ioctl failed for erase region %d", diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c index 5ac95aaabb8a..cd61105c5c01 100644 --- a/ubi-utils/mtdinfo.c +++ b/ubi-utils/mtdinfo.c @@ -253,6 +253,9 @@ static void print_region_info(const struct mtd_dev_info *mtd) if (!args.node || (!args.map && mtd->region_cnt == 0)) return; + /* Just in case */ + memset(®info, 0, sizeof(reginfo)); + /* First open the device so we can query it */ fd = open(args.node, O_RDONLY | O_CLOEXEC); if (fd == -1) { Brian From computersforpeace at gmail.com Mon Sep 15 10:48:21 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 10:48:21 -0700 Subject: [PATCH mtd-utils] libmtd: don't ignore "region index" parameter in mtd_regioninfo() In-Reply-To: <20140915173152.GA14832@ld-irv-0074> References: <1407294015-27884-1-git-send-email-Wei.Yang@windriver.com> <20140915173152.GA14832@ld-irv-0074> Message-ID: <20140915174821.GB14832@ld-irv-0074> ioctl(MEMGETREGIONINFO) has one input parameter (regionindex) and three output parameters (info about the erase region). There are two problems in mtdinfo/libmtd here: 1. mtdinfo.c doesn't initialize its region_info_user struct, instead passing uninitialized data to mtd_regioninfo() 2. mtd_regioninfo() fails to utilize the 'regidx' parameter to fill out the regionindex parameter properly, so the garbage from mtdinfo.c is propagated to the ioctl() This means that mtdinfo will continuously probe the same (possibly out-of-range) erase region, instead of looping over the valid regions. Let's fix this in the mtd_regioninfo() helper, and at the same time, let's zero out the mtdinfo.c buffer, as an additional precaution to keep from using uninitialized data. Initial error report from Yang, when running "mtdinfo /dev/mtd0" on a Cavium 6100 board: root at CN61XX:~# mtdinfo /dev/mtd0 mtd0 Name: phys_mapped_flash Type: nor Eraseblock size: 65536 bytes, 64.0 KiB Amount of eraseblocks: 128 (8388608 bytes, 8.0 MiB) Minimum input/output unit size: 1 byte Sub-page size: 1 byte Additional erase regions: 0 Character device major/minor: 90:0 Bad blocks are allowed: false Device is writable: true libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 0 error 22 (Invalid argument) Eraseblock region 0: info is unavailable libmtd: error!: MEMGETREGIONINFO ioctl failed for erase region 1 error 22 (Invalid argument) Eraseblock region 1: info is unavailable Reported-by: Yang Wei Signed-off-by: Brian Norris --- Untested so far. Can you give this a run, Yang? lib/libmtd.c | 2 ++ ubi-utils/mtdinfo.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/libmtd.c b/lib/libmtd.c index aff4c8be01b5..a6665f08018e 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -901,6 +901,8 @@ int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo) return -1; } + reginfo->regionindex = regidx; + ret = ioctl(fd, MEMGETREGIONINFO, reginfo); if (ret < 0) return sys_errmsg("%s ioctl failed for erase region %d", diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c index 5ac95aaabb8a..a86abd1542b4 100644 --- a/ubi-utils/mtdinfo.c +++ b/ubi-utils/mtdinfo.c @@ -253,6 +253,8 @@ static void print_region_info(const struct mtd_dev_info *mtd) if (!args.node || (!args.map && mtd->region_cnt == 0)) return; + memset(®info, 0, sizeof(reginfo)); + /* First open the device so we can query it */ fd = open(args.node, O_RDONLY | O_CLOEXEC); if (fd == -1) { -- 1.9.1 From computersforpeace at gmail.com Mon Sep 15 10:49:49 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 10:49:49 -0700 Subject: [PATCH] libmtd: fix mtd_dev_present return value on legacy systems In-Reply-To: <1410361000-4821-1-git-send-email-guido@vanguardiasur.com.ar> References: <1410361000-4821-1-git-send-email-guido@vanguardiasur.com.ar> Message-ID: <20140915174949.GC14832@ld-irv-0074> On Wed, Sep 10, 2014 at 11:56:40AM -0300, Guido Mart?nez wrote: > On legacy systems, if "/proc/mtd" doesn't exist or gives a read error, > mtd_dev_present returns -1 (since it calls legacy_dev_present), contrary > to what's specified in the header file. > > This causes checks like > > if (mtd_dev_present(n)) { > ... > } > > to give false positives. Fix this by comparing the return value to 1. > > Signed-off-by: Guido Mart?nez Pushed to mtd-utils.git. Thanks! Brian From boris.brezillon at free-electrons.com Mon Sep 15 13:12:10 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 15 Sep 2014 22:12:10 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140915144259.GA1947@localhost.localdomain> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> <20140913173841.GA18093@brian-ubuntu> <20140915144259.GA1947@localhost.localdomain> Message-ID: <20140915221210.5d9871fb@bbrezillon> On Mon, 15 Sep 2014 22:43:02 +0800 Huang Shijie wrote: > On Sat, Sep 13, 2014 at 10:38:41AM -0700, Brian Norris wrote: > > On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > > > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > > > This test validates what's returned by ecc_strength file in sysfs > > > > (which in turn is specified by the NAND controller when initializing > > > > the NAND chip). > > > > > > > > Doing this should not imply knowing the ECC algorithm in use in the > > > > NAND controller or the layout used to store data on NAND. > > > the difficulty is that the ECC parity area can be not byte aligned. > > > > Is there a problem with just rounding up to the nearest byte alignment > > and ignoring the few bits that are wasted? > > I feel a little confused with the two hooks. > > does the ecc->write_page_raw need to write the ECC parity data? Depending on the oob_required argument, it might be allowed to overwrite the ECC bytes even if this implies breaking page reliability (which is exactly what's expected). When using raw write with with oob write option the writer should take care of regenerating ECC bytes (which you said was impossible in GPMI case) or copying them from a previous raw read. Here is a real example of what one could test with raw write + oob: 1) read a page in raw mode 2) flip some bits in the generated ECC bytes (or what you references as parity data) (this case can actually happen in real life) 3) write the modified page in raw mode 4) read back the same page in normal and check that ECC correction still works as expected > > The page's layout after an ecc->write_page will look like this: > (Block Mark) > | | > | D | > |<---->| > V V > +---+----------+-+----------+-+----------+-+----------+-+ > | M | data |E| data |E| data |E| data |E| > +---+----------+-+----------+-+----------+-+----------+-+ > > What will the page's layout look like after the ecc->write_page_raw? The same, but the user won't see this specific layout when reading a page in raw mode, and won't have to bother about disposing data a described above when writing in raw mode. Here is the layout as seen by an MTD user, even though the real one is the one you previously described. (Block Mark) | | | V +------------------------------------------+-----+-------+---+ | data | M | E | R | +------------------------------------------+-----+-------+---+ <------OOB-------> Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From boris.brezillon at free-electrons.com Mon Sep 15 13:24:01 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 15 Sep 2014 22:24:01 +0200 Subject: [PATCH v2 0/2] mtd: nand: gpmi: add proper raw access support Message-ID: <1410812643-14041-1-git-send-email-boris.brezillon@free-electrons.com> Hello Huang, Brian, This is just a new proposal to support raw accesses in a more standard way in the GPMI driver. This series was not tested (just compile tested), and I won't be able to test it until next week. Thus I don't expect to get it accepted, but rather to serve as a starting point for our future discussions. Any suggestions are welcome. Best Regards, Boris Boris BREZILLON (2): mtd: nand: gpmi: add gpmi_move_bits function mtd: nand: gpmi: add proper raw access support drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 86 ++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 118 ++++++++++++++++++++++++++++++++- drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ 3 files changed, 207 insertions(+), 1 deletion(-) -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 15 13:24:03 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 15 Sep 2014 22:24:03 +0200 Subject: [PATCH v2 2/2] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1410812643-14041-1-git-send-email-boris.brezillon@free-electrons.com> References: <1410812643-14041-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1410812643-14041-3-git-send-email-boris.brezillon@free-electrons.com> Several MTD users (either in user or kernel space) expect a valid raw access support to NAND chip devices. This is particularly true for testing tools which are often touching the data stored in a NAND chip in raw mode to artificially generate errors. The GPMI drivers do not implemenent raw access functions, and thus rely on default HW_ECC scheme implementation. The default implementation consider the data and OOB area as properly separated in their respective NAND section, which is not true for the GPMI controller. In this driver/controller some OOB data are stored at the beginning of the NAND data area (these data are called metadata in the driver), then ECC bytes are interleaved with data chunk (which is similar to the HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as OOB data. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 118 ++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 959cb9b..4945273 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -831,7 +831,13 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) * power of two and is much larger than four, which guarantees the * auxiliary buffer will appear on a 32-bit boundary. */ - this->page_buffer_size = geo->payload_size + geo->auxiliary_size; + if (geo->payload_size + geo->auxiliary_size > + mtd->writesize + mtd->oobsize) + this->page_buffer_size = + geo->payload_size + geo->auxiliary_size; + else + this->page_buffer_size = mtd->writesize + mtd->oobsize; + this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, &this->page_buffer_phys, GFP_DMA); if (!this->page_buffer_virt) @@ -1347,6 +1353,114 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) return status & NAND_STATUS_FAIL ? -EIO : 0; } +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; + u8 *tmp_buf = this->page_buffer_virt; + size_t src_bit_off; + size_t oob_bit_off; + size_t oob_byte_off; + uint8_t *oob = chip->oob_poi; + int step; + + chip->read_buf(mtd, tmp_buf, + mtd->writesize + mtd->oobsize); + + if (this->swap_block_mark) { + u8 swap = tmp_buf[0]; + + tmp_buf[0] = tmp_buf[mtd->writesize]; + tmp_buf[mtd->writesize] = swap; + } + + memcpy(oob, tmp_buf, nfc_geo->metadata_size); + oob_bit_off = nfc_geo->metadata_size * 8; + src_bit_off = oob_bit_off; + + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + gpmi_move_bits(buf, step * eccsize * 8, + tmp_buf, src_bit_off, + eccsize * 8); + src_bit_off += eccsize * 8; + gpmi_move_bits(oob, oob_bit_off, + tmp_buf, src_bit_off, + eccbits); + src_bit_off += eccbits; + oob_bit_off += eccbits; + } + + if (oob_bit_off % 8) + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); + + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); + + if (oob_byte_off < mtd->oobsize) + memcpy(oob + oob_byte_off, + tmp_buf + mtd->writesize + oob_byte_off, + mtd->oobsize - oob_byte_off); + + return 0; +} + +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; + u8 *tmp_buf = this->page_buffer_virt; + uint8_t *oob = chip->oob_poi; + size_t dst_bit_off; + size_t oob_bit_off; + size_t oob_byte_off; + int step; + + memcpy(tmp_buf, oob, nfc_geo->metadata_size); + oob_bit_off = nfc_geo->metadata_size * 8; + dst_bit_off = oob_bit_off; + + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + gpmi_move_bits(tmp_buf, dst_bit_off, + buf, step * eccsize * 8, eccsize * 8); + dst_bit_off += eccsize * 8; + + /* Pad last ECC block to align following data on a byte */ + if (step == nfc_geo->ecc_chunk_count - 1 && + (oob_bit_off + eccbits) % 8) + eccbits += 8 - ((oob_bit_off + eccbits) % 8); + + gpmi_move_bits(tmp_buf, dst_bit_off, + oob, oob_bit_off, eccbits); + dst_bit_off += eccbits; + oob_bit_off += eccbits; + } + + oob_byte_off = oob_bit_off / 8; + + if (oob_required && oob_byte_off < mtd->oobsize) + memcpy(tmp_buf + mtd->writesize + oob_byte_off, + oob + oob_byte_off, mtd->oobsize - oob_byte_off); + + if (this->swap_block_mark) { + u8 swap = tmp_buf[0]; + + tmp_buf[0] = tmp_buf[mtd->writesize]; + tmp_buf[mtd->writesize] = swap; + } + + chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize); + + return 0; +} + static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; @@ -1664,6 +1778,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ecc->write_page = gpmi_ecc_write_page; ecc->read_oob = gpmi_ecc_read_oob; ecc->write_oob = gpmi_ecc_write_oob; + ecc->read_page_raw = gpmi_ecc_read_page_raw; + ecc->write_page_raw = gpmi_ecc_write_page_raw; ecc->mode = NAND_ECC_HW; ecc->size = bch_geo->ecc_chunk_size; ecc->strength = bch_geo->ecc_strength; -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 15 13:24:02 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 15 Sep 2014 22:24:02 +0200 Subject: [PATCH v2 1/2] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <1410812643-14041-1-git-send-email-boris.brezillon@free-electrons.com> References: <1410812643-14041-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1410812643-14041-2-git-send-email-boris.brezillon@free-electrons.com> Add a new function to move bits (not bytes) from a memory region to another one. This function is similar to memmove except it acts at bit level. This function is needed to implement GPMI raw access functions, given the fact that ECC engine does not pad ECC bits to the next byte boundary. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 86 ++++++++++++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ 2 files changed, 90 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 87e658c..5a83f0f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -1353,3 +1353,89 @@ int gpmi_read_page(struct gpmi_nand_data *this, set_dma_type(this, DMA_FOR_READ_ECC_PAGE); return start_dma_with_bch_irq(this, desc); } + +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits) +{ + size_t i; + size_t nbytes; + u32 src_byte = 0; + + src += src_bit_off / 8; + src_bit_off %= 8; + + dst += dst_bit_off / 8; + dst_bit_off %= 8; + + if (src_bit_off) { + src_byte = src[0] >> src_bit_off; + nbits -= 8 - src_bit_off; + src++; + } + + nbytes = nbits / 8; + + if (src_bit_off <= dst_bit_off) { + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += (8 - dst_bit_off); + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + } else if (nbytes) { + src_byte |= src[0] << (8 - src_bit_off); + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += dst_bit_off; + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + nbytes--; + src++; + if (src_bit_off > 7) { + src_bit_off -= 8; + dst[0] = src_byte; + dst++; + src_byte >>= 8; + } + } + + if (!src_bit_off && !dst_bit_off) { + if (nbytes) + memcpy(dst, src, nbytes); + } else { + for (i = 0; i < nbytes; i++) { + src_byte |= src[i] << (8 - src_bit_off); + dst[i] = src_byte; + src_byte >>= 8; + } + } + + dst += nbytes; + src += nbytes; + nbits %= 8; + + if (!nbits && !src_bit_off) + return; + + if (nbits) + src_byte |= (*src & GENMASK(nbits - 1, 0)) << + ((8 - src_bit_off) % 8); + nbits += (8 - src_bit_off) % 8; + + if (dst_bit_off) + src_byte = (src_byte << dst_bit_off) | + (*dst & GENMASK(dst_bit_off - 1, 0)); + nbits += dst_bit_off; + + if (nbits % 8) + src_byte |= (dst[nbits / 8] & GENMASK(7, nbits % 8)) << + (nbits / 8); + + nbytes = DIV_ROUND_UP(nbits, 8); + for (i = 0; i < nbytes; i++) { + dst[i] = src_byte; + src_byte >>= 8; + } +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 32c6ba4..17d0736 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -290,6 +290,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *, extern int gpmi_read_page(struct gpmi_nand_data *, dma_addr_t payload, dma_addr_t auxiliary); +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits); + /* BCH : Status Block Completion Codes */ #define STATUS_GOOD 0x00 #define STATUS_ERASED 0xff -- 1.9.1 From david at fromorbit.com Mon Sep 15 14:52:18 2014 From: david at fromorbit.com (Dave Chinner) Date: Tue, 16 Sep 2014 07:52:18 +1000 Subject: [PATCH] Add UBIFS support In-Reply-To: <1410772280-9771-1-git-send-email-richard@nod.at> References: <1410772280-9771-1-git-send-email-richard@nod.at> Message-ID: <20140915215218.GH4322@dastard> On Mon, Sep 15, 2014 at 11:11:20AM +0200, Richard Weinberger wrote: > UBIFS needs some extra care, the device node is of type character and > it has no fsck tool. Not being familiar with UBIFS, the explaination is rather brief and doesn't explain anything to me. Can you document how where supposed to treat a filesystem that doesn't exist on a block device for all the tests that assume that the local fileystem is on a block device? e.g. how do all the generic tests that use loopback devices work? What about dm-flakey? > Signed-off-by: Richard Weinberger > --- > README | 1 + > check | 2 ++ > common/config | 4 ++-- > common/rc | 18 ++++++++++++++++++ > 4 files changed, 23 insertions(+), 2 deletions(-) > > diff --git a/README b/README > index 8a362bd..96adc44 100644 > --- a/README > +++ b/README > @@ -100,6 +100,7 @@ Running tests: > Running all the udf tests: ./check -udf -g udf > - for running nfs tests: ./check -nfs [test(s)] > - for running cifs/smb3 tests: ./check -cifs [test(s)] > + - for running ubifs tests: ./check -ubifs [test(s)] > - To randomize test order: ./check -r [test(s)] > > > diff --git a/check b/check > index 42a1ac2..57ec612 100755 > --- a/check > +++ b/check > @@ -70,6 +70,7 @@ check options > -nfs test NFS > -cifs test CIFS > -tmpfs test TMPFS > + -ubifs test UBIFS > -l line mode diff > -udiff show unified diff (default) > -n show me, do not run tests I'd like to avoid adding command line switches for random filesystem types if at all possible. I'd much prefer that it be derived from the current TEST_DEV if at all possible. Can you probe for UBIFS similar to using blkid for local filesystems? > diff --git a/common/config b/common/config > index fc21b37..af082ea 100644 > --- a/common/config > +++ b/common/config > @@ -430,7 +430,7 @@ get_next_config() { > exit 1 > fi > > - echo $TEST_DEV | grep -qE ":|//" > /dev/null 2>&1 > + echo $TEST_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 > if [ ! -b "$TEST_DEV" -a "$?" != "0" ]; then > echo "common/config: Error: \$TEST_DEV ($TEST_DEV) is not a block device or a network filesystem" > exit 1 Needs a comment explaining what format we are searching for there? > @@ -453,7 +453,7 @@ get_next_config() { > export SCRATCH_DEV_NOT_SET=true > fi > > - echo $SCRATCH_DEV | grep -qE ":|//" > /dev/null 2>&1 > + echo $SCRATCH_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 > if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" -a "$?" != "0" ]; then > echo "common/config: Error: \$SCRATCH_DEV ($SCRATCH_DEV) is not a block device or a network filesystem" > exit 1 > diff --git a/common/rc b/common/rc > index b8f711a..064b987 100644 > --- a/common/rc > +++ b/common/rc > @@ -1034,6 +1034,12 @@ _require_scratch_nocheck() > _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" > fi > ;; > + ubifs) > + if [ -z "$SCRATCH_DEV" -o ! -c "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ]; > + then > + _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" > + fi > + ;; s/unique/valid/ Cheers, Dave. -- Dave Chinner david at fromorbit.com From computersforpeace at gmail.com Mon Sep 15 17:36:20 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 17:36:20 -0700 Subject: [PATCH v2 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140916003620.GA1193@ld-irv-0074> On Tue, Sep 09, 2014 at 11:01:50AM +0900, Masahiro Yamada wrote: > Changes in v2: > - Join quotes strings into a single line > > Masahiro Yamada (7): > mtd: denali: fix the format of comment blocks > mtd: denali: remove unnecessary variable initializations > mtd: denali: remove unnecessary casts > mtd: denali: change the type of iterators to int > mtd: denali: remove a set-but-unused variable > mtd: denali: remove unnecessary parentheses > mtd: denali: fix indents and other trivial things > > drivers/mtd/nand/denali.c | 562 +++++++++++++++++++++++++--------------------- > 1 file changed, 303 insertions(+), 259 deletions(-) Pushed patches 1 to 5 to l2-mtd.git. Thanks! Patch 6 has a conflict with another fix already in l2-mtd.git. Can you rebase and resend? BTW, my automatic build tests show that there's at least one other 'unused' warning left, in case you want to tackle it too: drivers/mtd/nand/denali.c: In function ?denali_read_page_raw?: drivers/mtd/nand/denali.c:1221:11: warning: variable ?irq_status? set but not used [-Wunused-but-set-variable] uint32_t irq_status; Brian From yamada.m at jp.panasonic.com Mon Sep 15 19:11:58 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 11:11:58 +0900 Subject: [PATCH v2 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140916003620.GA1193@ld-irv-0074> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> <20140916003620.GA1193@ld-irv-0074> Message-ID: <20140916111154.58F0.AA925319@jp.panasonic.com> Hi Brian, On Mon, 15 Sep 2014 17:36:20 -0700 Brian Norris wrote: > On Tue, Sep 09, 2014 at 11:01:50AM +0900, Masahiro Yamada wrote: > > Changes in v2: > > - Join quotes strings into a single line > > > > Masahiro Yamada (7): > > mtd: denali: fix the format of comment blocks > > mtd: denali: remove unnecessary variable initializations > > mtd: denali: remove unnecessary casts > > mtd: denali: change the type of iterators to int > > mtd: denali: remove a set-but-unused variable > > mtd: denali: remove unnecessary parentheses > > mtd: denali: fix indents and other trivial things > > > > drivers/mtd/nand/denali.c | 562 +++++++++++++++++++++++++--------------------- > > 1 file changed, 303 insertions(+), 259 deletions(-) > > Pushed patches 1 to 5 to l2-mtd.git. Thanks! > > Patch 6 has a conflict with another fix already in l2-mtd.git. Can you > rebase and resend? Sorry for my ignorance, but where can I find l2-mtd.git? In my understanding, the subsystem repositories should be documented in MAINTAINERS, so I looked for it but just found T: git git://git.infradead.org/linux-mtd.git. I do not think it is the one you mentioned. > BTW, my automatic build tests show that there's at least one other > 'unused' warning left, in case you want to tackle it too: > > drivers/mtd/nand/denali.c: In function ?denali_read_page_raw?: > drivers/mtd/nand/denali.c:1221:11: warning: variable ?irq_status? set but not used [-Wunused-but-set-variable] > uint32_t irq_status; > You are right. (What is odd enough is this warning was not displayed on my build test. I do not know why.) Is there a chance for me to resend 5/7 to include this fix? Or is it too late? Best Regards Masahiro Yamada From computersforpeace at gmail.com Mon Sep 15 21:56:17 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 21:56:17 -0700 Subject: [PATCH] MAINTAINERS: add l2-mtd.git, 'next' tree for MTD Message-ID: <1410843377-30159-1-git-send-email-computersforpeace@gmail.com> We've been semi-officially queueing patches here for a while, and it's in linux-next, so let's advertise it in MAINTAINERS. Signed-off-by: Brian Norris --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 809ecd680d88..55a61f242991 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5898,6 +5898,7 @@ L: linux-mtd at lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git +T: git git://git.infradead.org/l2-mtd.git S: Maintained F: drivers/mtd/ F: include/linux/mtd/ -- 1.9.1 From computersforpeace at gmail.com Mon Sep 15 22:07:32 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 15 Sep 2014 22:07:32 -0700 Subject: [PATCH v2 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140916111154.58F0.AA925319@jp.panasonic.com> References: <1410228117-14820-1-git-send-email-yamada.m@jp.panasonic.com> <20140916003620.GA1193@ld-irv-0074> <20140916111154.58F0.AA925319@jp.panasonic.com> Message-ID: <20140916050732.GB18093@brian-ubuntu> Hi Masahiro, On Tue, Sep 16, 2014 at 11:11:58AM +0900, Masahiro Yamada wrote: > On Mon, 15 Sep 2014 17:36:20 -0700 Brian Norris wrote: > > On Tue, Sep 09, 2014 at 11:01:50AM +0900, Masahiro Yamada wrote: > > > Changes in v2: > > > - Join quotes strings into a single line > > > > > > Masahiro Yamada (7): > > > mtd: denali: fix the format of comment blocks > > > mtd: denali: remove unnecessary variable initializations > > > mtd: denali: remove unnecessary casts > > > mtd: denali: change the type of iterators to int > > > mtd: denali: remove a set-but-unused variable > > > mtd: denali: remove unnecessary parentheses > > > mtd: denali: fix indents and other trivial things > > > > > > drivers/mtd/nand/denali.c | 562 +++++++++++++++++++++++++--------------------- > > > 1 file changed, 303 insertions(+), 259 deletions(-) > > > > Pushed patches 1 to 5 to l2-mtd.git. Thanks! > > > > Patch 6 has a conflict with another fix already in l2-mtd.git. Can you > > rebase and resend? > > Sorry for my ignorance, but where can I find l2-mtd.git? git://git.infradead.org/l2-mtd.git > In my understanding, the subsystem repositories should be documented > in MAINTAINERS, so I looked for it but just found > T: git git://git.infradead.org/linux-mtd.git. > I do not think it is the one you mentioned. Sorry, apparently l2-mtd.git is not in MAINTAINERS. It historically has been a kind of queue for the official repo (linux-mtd.git), especially when work was split up between two people. I handle most of it now. I guess it should be in MAINTAINERS, though, since most people will need to base patches on it. I just sent a patch to add it. > > BTW, my automatic build tests show that there's at least one other > > 'unused' warning left, in case you want to tackle it too: > > > > drivers/mtd/nand/denali.c: In function ?denali_read_page_raw?: > > drivers/mtd/nand/denali.c:1221:11: warning: variable ?irq_status? set but not used [-Wunused-but-set-variable] > > uint32_t irq_status; > > > > You are right. > (What is odd enough is this warning was not displayed on my build test. > I do not know why.) I enabled extra warnings. I think you can get most of those with 'make W=1'. > Is there a chance for me to resend 5/7 to include this fix? > Or is it too late? Just send a new patch, please. Thanks, Brian From richard at nod.at Tue Sep 16 00:48:22 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 09:48:22 +0200 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() Message-ID: <1410853702-11616-1-git-send-email-richard@nod.at> If sync_erase() failes with EINTR, ENOMEM, EAGAIN or EBUSY erase_worker() re-schedules the failed work. This will lead to a deadlock because erase_worker() is called with work_sem held in read mode. And schedule_erase() will take this lock again. Fix this issue by adding a locked flag to schedule_erase(), it indicates whether the caller owns work_sem already. [ 16.571519] [ INFO: possible recursive locking detected ] [ 16.571519] 3.17.0-rc4+ #69 Not tainted [ 16.571519] --------------------------------------------- [ 16.571519] ubi_bgt0d/2607 is trying to acquire lock: [ 16.571519] (&ubi->work_sem){.+.+..}, at: [] schedule_ubi_work+0x1e/0x40 [ 16.571519] [ 16.571519] but task is already holding lock: [ 16.571519] (&ubi->work_sem){.+.+..}, at: [] do_work+0x3c/0x110 [ 16.571519] [ 16.571519] other info that might help us debug this: [ 16.571519] Possible unsafe locking scenario: [ 16.571519] [ 16.571519] CPU0 [ 16.571519] ---- [ 16.571519] lock(&ubi->work_sem); [ 16.571519] lock(&ubi->work_sem); [ 16.571519] [ 16.571519] *** DEADLOCK *** [ 16.571519] [ 16.571519] May be due to missing lock nesting notation [ 16.571519] [ 16.571519] 1 lock held by ubi_bgt0d/2607: [ 16.571519] #0: (&ubi->work_sem){.+.+..}, at: [] do_work+0x3c/0x110 [ 16.571519] [ 16.571519] stack backtrace: [ 16.571519] CPU: 1 PID: 2607 Comm: ubi_bgt0d Not tainted 3.17.0-rc4+ #69 [ 16.571519] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140816_022509-build35 04/01/2014 [ 16.571519] ffffffff829ee740 ffff88003c32fba8 ffffffff818b4693 ffffffff829ee740 [ 16.571519] ffff88003c32fc70 ffffffff8108bb4b ffff88003cc65400 ffff88003c32c000 [ 16.571519] 000000003e1d37c0 ffffffff810855f1 ffffffff00000000 0000000000a2c516 [ 16.571519] Call Trace: [ 16.571519] [] dump_stack+0x4d/0x66 [ 16.571519] [] __lock_acquire+0x1b3b/0x1ce0 [ 16.571519] [] ? up+0x11/0x50 [ 16.571519] [] ? console_unlock+0x1d4/0x4b0 [ 16.571519] [] ? trace_hardirqs_on+0xd/0x10 [ 16.571519] [] lock_acquire+0xa8/0x140 [ 16.571519] [] ? schedule_ubi_work+0x1e/0x40 [ 16.571519] [] down_read+0x4c/0xa0 [ 16.571519] [] ? schedule_ubi_work+0x1e/0x40 [ 16.571519] [] schedule_ubi_work+0x1e/0x40 [ 16.571519] [] schedule_erase+0xa8/0x130 [ 16.571519] [] erase_worker+0x40a/0x710 [ 16.571519] [] do_work+0x7d/0x110 [ 16.571519] [] ubi_thread+0x128/0x1e0 [ 16.571519] [] ? ubi_wl_flush+0x180/0x180 [ 16.571519] [] kthread+0xeb/0x110 [ 16.571519] [] ? kthread_create_on_node+0x210/0x210 [ 16.571519] [] ret_from_fork+0x7c/0xb0 [ 16.571519] [] ? kthread_create_on_node+0x210/0x210 Cc: Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..e985f29 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -884,21 +884,20 @@ int ubi_is_erase_work(struct ubi_work *wrk) * @vol_id: the volume ID that last used this PEB * @lnum: the last used logical eraseblock number for the PEB * @torture: if the physical eraseblock has to be tortured + * @locked: non-zero if this function is called with @ubi->work_sem held in + * read mode. Never call it with @ubi->work_sem held in write mode! * * This function returns zero in case of success and a %-ENOMEM in case of * failure. */ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, - int vol_id, int lnum, int torture) + int vol_id, int lnum, int torture, int locked) { struct ubi_work *wl_wrk; ubi_assert(e); ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); - dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", - e->pnum, e->ec, torture); - wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); if (!wl_wrk) return -ENOMEM; @@ -909,7 +908,13 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, wl_wrk->lnum = lnum; wl_wrk->torture = torture; - schedule_ubi_work(ubi, wl_wrk); + dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", + e->pnum, e->ec, torture); + + if (locked) + __schedule_ubi_work(ubi, wl_wrk); + else + schedule_ubi_work(ubi, wl_wrk); return 0; } @@ -982,7 +987,7 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e, spin_unlock(&ubi->wl_lock); vol_id = lnum ? UBI_FM_DATA_VOLUME_ID : UBI_FM_SB_VOLUME_ID; - return schedule_erase(ubi, e, vol_id, lnum, torture); + return schedule_erase(ubi, e, vol_id, lnum, torture, 1); } #endif @@ -1464,7 +1469,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, int err1; /* Re-schedule the LEB for erasure */ - err1 = schedule_erase(ubi, e, vol_id, lnum, 0); + err1 = schedule_erase(ubi, e, vol_id, lnum, 0, 1); if (err1) { err = err1; goto out_ro; @@ -1620,7 +1625,7 @@ retry: } spin_unlock(&ubi->wl_lock); - err = schedule_erase(ubi, e, vol_id, lnum, torture); + err = schedule_erase(ubi, e, vol_id, lnum, torture, 0); if (err) { spin_lock(&ubi->wl_lock); wl_tree_add(e, &ubi->used); @@ -1909,7 +1914,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) e->ec = aeb->ec; ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); ubi->lookuptbl[e->pnum] = e; - if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { + if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0, 0)) { kmem_cache_free(ubi_wl_entry_slab, e); goto out_free; } -- 1.8.4.5 From rogerq at ti.com Tue Sep 16 01:43:12 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 16 Sep 2014 11:43:12 +0300 Subject: [PATCH v3 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5417F820.5000202@ti.com> On 09/11/2014 06:02 PM, Ezequiel Garcia wrote: > This commit adds a new platform-data boolean property that enables use > of a flash-based bad block table. This can also be enabled by setting > the 'nand-on-flash-bbt' devicetree property. > > If the flash BBT is not enabled, the driver falls back to use OOB > bad block markers only, as before. If the flash BBT is enabled the > kernel will keep track of bad blocks using a BBT, in addition to > the OOB markers. > > As explained by Brian Norris the reasons for using a BBT are: > > "" > The primary reason would be that NAND datasheets specify it these days. > A better argument is that nobody guarantees that you can write a > bad block marker to a worn out block; you may just get program failures. > > This has been acknowledged by several developers over the last several > years. > > Additionally, you get a boot-time performance improvement if you only > have to read a few pages, instead of a page or two from every block on > the flash. > "" > > Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros cheers, -roger From rogerq at ti.com Tue Sep 16 01:43:59 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 16 Sep 2014 11:43:59 +0300 Subject: [PATCH v3 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5417F84F.1010602@ti.com> On 09/11/2014 06:02 PM, Ezequiel Garcia wrote: > The current code abuses ifdefs to determine if the selected ECC scheme > is supported by the running kernel. As a result the code is hard to read, > and it also fails to load as a module. > > This commit removes all the ifdefs and instead introduces a function > omap2_nand_ecc_check() to check if the ECC is supported by using > IS_ENABLED(CONFIG_xxx). > > Since IS_ENABLED() is true when a config is =y or =m, this change fixes the > module so it can be loaded with no issues. > > Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros cheers, -roger From rogerq at ti.com Tue Sep 16 01:48:13 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 16 Sep 2014 11:48:13 +0300 Subject: [PATCH v3 3/3] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1410447730-16087-4-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-4-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <5417F94D.40902@ti.com> On 09/11/2014 06:02 PM, Ezequiel Garcia wrote: > Usage of pr_err is frowned upon, so replace it with dev_err. > Aditionally, the message on nand_bch_init() error is redundant, > since proper error is showed if the function fails. You could have omitted the details about nand_bch_init() in the commit message. > > Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros cheers, -roger From yamada.m at jp.panasonic.com Tue Sep 16 04:04:24 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 20:04:24 +0900 Subject: [PATCH v3 6/7] mtd: denali: remove unnecessary parentheses In-Reply-To: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410865465-17941-7-git-send-email-yamada.m@jp.panasonic.com> We should use parentheses only when they are necessary or they really improve the readability. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett --- Changes in v3: - Rebase on l2-mtd.git Changes in v2: None drivers/mtd/nand/denali.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e5c39d2..945943e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -267,10 +267,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, acc_clks = CEIL_DIV(Trea[mode], CLK_X); - while (((acc_clks * CLK_X) - Trea[mode]) < 3) + while (acc_clks * CLK_X - Trea[mode] < 3) acc_clks++; - if ((data_invalid - acc_clks * CLK_X) < 2) + if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", __FILE__, __LINE__); @@ -285,7 +285,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, cs_cnt = 1; if (Tcea[mode]) { - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) + while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) cs_cnt++; } @@ -295,8 +295,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, #endif /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && - (ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) + if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && + ioread32(denali->flash_reg + DEVICE_ID) == 0x88) acc_clks = 6; iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); @@ -577,7 +577,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, */ static inline bool is_flash_bank_valid(int flash_bank) { - return (flash_bank >= 0 && flash_bank < 4); + return flash_bank >= 0 && flash_bank < 4; } static void denali_irq_init(struct denali_nand_info *denali) @@ -1293,7 +1293,7 @@ static int denali_erase(struct mtd_info *mtd, int page) irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | INTR_STATUS__ERASE_FAIL); - return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, -- 1.9.1 From yamada.m at jp.panasonic.com Tue Sep 16 04:04:23 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 20:04:23 +0900 Subject: [PATCH v3 5/7] mtd: denali: remove a set-but-unused variable In-Reply-To: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410865465-17941-6-git-send-email-yamada.m@jp.panasonic.com> The variable "retry" in wait_for_irq() is set, but not used. Likewise, for "irq_status" in denali_read_page_raw(). Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett --- Changes in v3: - Remove also set-but-unused irq_status Changes in v2: None drivers/mtd/nand/denali.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4cb1497..e5c39d2 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -697,7 +697,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { unsigned long comp_res; uint32_t intr_status; - bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); do { @@ -717,7 +716,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) * need to wait again */ spin_unlock_irq(&denali->irq_lock); - retry = true; } } while (comp_res != 0); @@ -1220,7 +1218,6 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1239,7 +1236,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); -- 1.9.1 From yamada.m at jp.panasonic.com Tue Sep 16 04:04:18 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 20:04:18 +0900 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes Message-ID: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Masahiro Yamada (7): mtd: denali: fix the format of comment blocks mtd: denali: remove unnecessary variable initializations mtd: denali: remove unnecessary casts mtd: denali: change the type of iterators to int mtd: denali: remove a set-but-unused variable mtd: denali: remove unnecessary parentheses mtd: denali: fix indents and other trivial things drivers/mtd/nand/denali.c | 558 +++++++++++++++++++++++++--------------------- 1 file changed, 301 insertions(+), 257 deletions(-) -- 1.9.1 From yamada.m at jp.panasonic.com Tue Sep 16 04:04:25 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 20:04:25 +0900 Subject: [PATCH v3 7/7] mtd: denali: fix indents and other trivial things In-Reply-To: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <1410865465-17941-8-git-send-email-yamada.m@jp.panasonic.com> - Fix indents - Do not break a line unless it is longer than 80 columns - Do not insert a whitespace before ';' - Use whitespaces around operators - Use braces for a "else" block where the "if" block uses ones. Besides, eliminate all the warnings reported by checkpatch.pl: - WARNING: quoted string split across lines - WARNING: else is not generally useful after a break or return - WARNING: Missing a blank line after declarations - WARNING: Avoid line continuations in quoted strings Signed-off-by: Masahiro Yamada --- Changes in v3: - Rebase on l2-mtd.git Changes in v2: - Join quotes strings into a single line drivers/mtd/nand/denali.c | 138 ++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 77 deletions(-) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 945943e..b3b7ca1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -37,8 +37,8 @@ MODULE_LICENSE("GPL"); static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; module_param(onfi_timing_mode, int, S_IRUGO); -MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." - " -1 indicates use default timings"); +MODULE_PARM_DESC(onfi_timing_mode, + "Overrides default ONFI setting. -1 indicates use default timings"); #define DENALI_NAND_NAME "denali-nand" @@ -162,8 +162,7 @@ static void read_status(struct denali_nand_info *denali) static void reset_bank(struct denali_nand_info *denali) { uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__RST_COMP | - INTR_STATUS__TIME_OUT; + uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; clear_interrupts(denali); @@ -181,16 +180,15 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); - for (i = 0 ; i < denali->max_banks; i++) + for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, denali->flash_reg + INTR_STATUS(i)); - for (i = 0 ; i < denali->max_banks; i++) { + for (i = 0; i < denali->max_banks; i++) { iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + - INTR_STATUS(i)) & + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) cpu_relax(); if (ioread32(denali->flash_reg + INTR_STATUS(i)) & @@ -201,7 +199,7 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + denali->flash_reg + INTR_STATUS(i)); return PASS; } @@ -235,7 +233,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); en_lo = CEIL_DIV(Trp[mode], CLK_X); en_hi = CEIL_DIV(Treh[mode], CLK_X); @@ -255,9 +253,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - data_invalid = - data_invalid_rhoh < - data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh; + data_invalid = data_invalid_rhoh < data_invalid_rloh ? + data_invalid_rhoh : data_invalid_rloh; dv_window = data_invalid - Trea[mode]; @@ -272,7 +269,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); + __FILE__, __LINE__); addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); re_2_we = CEIL_DIV(Trhw[mode], CLK_X); @@ -406,9 +403,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, break; default: dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." - "Will use default parameter values instead.\n", - device_id); + "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" + "Will use default parameter values instead.\n", + device_id); } } @@ -425,8 +422,7 @@ static void find_valid_banks(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) { index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, - MODE_11 | (i << 24) | 2, &id[i]); + index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -450,8 +446,7 @@ static void find_valid_banks(struct denali_nand_info *denali) */ if (denali->total_used_banks != 1) { dev_err(denali->dev, - "Sorry, Intel CE4100 only supports " - "a single NAND device.\n"); + "Sorry, Intel CE4100 only supports a single NAND device.\n"); BUG(); } } @@ -489,10 +484,12 @@ static void detect_partition_feature(struct denali_nand_info *denali) + (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & MIN_BLK_ADDR__VALUE); - } else + } else { denali->fwblks = SPECTRA_START_BLOCK; - } else + } + } else { denali->fwblks = SPECTRA_START_BLOCK; + } } static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) @@ -502,8 +499,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) uint8_t maf_id, device_id; int i; - dev_dbg(denali->dev, - "%s, Line %d, Function: %s\n", + dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); /* @@ -532,7 +528,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) } dev_info(denali->dev, - "Dump timing register values:" + "Dump timing register values:\n" "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", @@ -563,7 +559,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); if (INT_ENABLE) iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); @@ -710,13 +706,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) spin_unlock_irq(&denali->irq_lock); /* our interrupt was detected */ break; - } else { - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); } + + /* + * these are not the interrupts you are looking for - + * need to wait again + */ + spin_unlock_irq(&denali->irq_lock); } while (comp_res != 0); if (comp_res == 0) { @@ -744,8 +740,7 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, /* Enable spare area/ECC per user's request. */ iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, - denali->flash_reg + TRANSFER_SPARE_REG); + iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } /* @@ -753,10 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, - bool ecc_en, - bool transfer_spare, - int access_type, - int op) + bool ecc_en, bool transfer_spare, + int access_type, int op) { int status = PASS; uint32_t page_count = 1; @@ -811,9 +804,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, if (irq_status == 0) { dev_err(denali->dev, - "cmd, page, addr on timeout " - "(0x%x, 0x%x, 0x%x)\n", - cmd, denali->page, addr); + "cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n", + cmd, denali->page, addr); status = FAIL; } else { cmd = MODE_01 | addr; @@ -826,8 +818,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, - const uint8_t *buf, - int len) + const uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -842,13 +833,12 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) iowrite32(*buf32++, denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* helper function that simply reads a buffer from the flash */ static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, - int len) + uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -865,7 +855,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) *buf32++ = ioread32(denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* writes OOB data to the device */ @@ -941,6 +931,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static bool is_erased(uint8_t *buf, int len) { int i; + for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -990,6 +981,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, */ if (err_byte < ECC_SECTOR_SIZE) { int offset; + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * @@ -1063,10 +1055,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1099,9 +1089,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { - dev_err(denali->dev, - "timeout on write_page (type = %d)\n", - raw_xfer); + dev_err(denali->dev, "timeout on write_page (type = %d)\n", + raw_xfer); denali->status = NAND_STATUS_FAIL; } @@ -1172,9 +1161,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, bool check_erased_page = false; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1214,16 +1203,14 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1272,6 +1259,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); int status = denali->status; + denali->status = 0; return status; @@ -1321,9 +1309,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, index_addr(denali, addr | 0, 0x90); index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { - index_addr_read_data(denali, - addr | 2, - &id); + index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } break; @@ -1348,8 +1334,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc_code) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_calculate called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n"); BUG(); return -EIO; } @@ -1358,8 +1344,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, uint8_t *read_ecc, uint8_t *calc_ecc) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_correct called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n"); BUG(); return -EIO; } @@ -1367,8 +1353,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_hwctl called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n"); BUG(); } /* end NAND core entry points */ @@ -1596,8 +1582,7 @@ int denali_init(struct denali_nand_info *denali) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to \ - contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1621,8 +1606,7 @@ int denali_init(struct denali_nand_info *denali) * contained by each nand chip. blksperchip will help driver to * know how many blocks is taken by FW. */ - denali->totalblks = denali->mtd.size >> - denali->nand.phys_erase_shift; + denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; /* @@ -1669,7 +1653,7 @@ void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, - denali->mtd.writesize + denali->mtd.oobsize, - DMA_BIDIRECTIONAL); + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); -- 1.9.1 From yamada.m at jp.panasonic.com Tue Sep 16 04:08:41 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Tue, 16 Sep 2014 20:08:41 +0900 Subject: [PATCH v2 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140916050732.GB18093@brian-ubuntu> References: <20140916111154.58F0.AA925319@jp.panasonic.com> <20140916050732.GB18093@brian-ubuntu> Message-ID: <20140916200840.A4CC.AA925319@jp.panasonic.com> Hi Brian, On Mon, 15 Sep 2014 22:07:32 -0700 Brian Norris wrote: > Hi Masahiro, > > On Tue, Sep 16, 2014 at 11:11:58AM +0900, Masahiro Yamada wrote: > > On Mon, 15 Sep 2014 17:36:20 -0700 Brian Norris wrote: > > > On Tue, Sep 09, 2014 at 11:01:50AM +0900, Masahiro Yamada wrote: > > > > Changes in v2: > > > > - Join quotes strings into a single line > > > > > > > > Masahiro Yamada (7): > > > > mtd: denali: fix the format of comment blocks > > > > mtd: denali: remove unnecessary variable initializations > > > > mtd: denali: remove unnecessary casts > > > > mtd: denali: change the type of iterators to int > > > > mtd: denali: remove a set-but-unused variable > > > > mtd: denali: remove unnecessary parentheses > > > > mtd: denali: fix indents and other trivial things > > > > > > > > drivers/mtd/nand/denali.c | 562 +++++++++++++++++++++++++--------------------- > > > > 1 file changed, 303 insertions(+), 259 deletions(-) > > > > > > Pushed patches 1 to 5 to l2-mtd.git. Thanks! > > > > > > Patch 6 has a conflict with another fix already in l2-mtd.git. Can you > > > rebase and resend? > > > > Sorry for my ignorance, but where can I find l2-mtd.git? > > git://git.infradead.org/l2-mtd.git > > > In my understanding, the subsystem repositories should be documented > > in MAINTAINERS, so I looked for it but just found > > T: git git://git.infradead.org/linux-mtd.git. > > I do not think it is the one you mentioned. > > Sorry, apparently l2-mtd.git is not in MAINTAINERS. It historically has > been a kind of queue for the official repo (linux-mtd.git), especially > when work was split up between two people. I handle most of it now. > > I guess it should be in MAINTAINERS, though, since most people will need > to base patches on it. I just sent a patch to add it. Thanks for explaining this, and I also appreciate your patch! > > > BTW, my automatic build tests show that there's at least one other > > > 'unused' warning left, in case you want to tackle it too: > > > > > > drivers/mtd/nand/denali.c: In function ?denali_read_page_raw?: > > > drivers/mtd/nand/denali.c:1221:11: warning: variable ?irq_status? set but not used [-Wunused-but-set-variable] > > > uint32_t irq_status; > > > > > > > You are right. > > (What is odd enough is this warning was not displayed on my build test. > > I do not know why.) > > I enabled extra warnings. I think you can get most of those with 'make > W=1'. I missed it. Thanks! > > Is there a chance for me to resend 5/7 to include this fix? > > Or is it too late? > > Just send a new patch, please. I've resent 5/7 thru 7/7. Best Regards Masahiro Yamada From richard at nod.at Tue Sep 16 06:26:36 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:26:36 +0200 Subject: [RFC] Don'd hold work_sem while calling worker functions Message-ID: <1410873998-2955-1-git-send-email-richard@nod.at> I fail to see why we need work_sem while wrk->func() is executed. Artem, do you have an idea? Having the wear_leveling_worker() called without work_sem held would simplify the fastmap code too. I'm currently reworking some of it's code and I'm in locking hell. 8-) Thanks, //richard [PATCH 1/2] UBI: Call worker functions without work_sem held [PATCH 2/2] UBI: Get rid of __schedule_ubi_work() From richard at nod.at Tue Sep 16 06:26:37 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:26:37 +0200 Subject: [PATCH 1/2] UBI: Call worker functions without work_sem held In-Reply-To: <1410873998-2955-1-git-send-email-richard@nod.at> References: <1410873998-2955-1-git-send-email-richard@nod.at> Message-ID: <1410873998-2955-2-git-send-email-richard@nod.at> There is no need to call the worker function with work_sem held. We only need the semaphore to synchronize workers and protect the work list. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..b1e2ed1 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -245,6 +245,7 @@ static int do_work(struct ubi_device *ubi) ubi->works_count -= 1; ubi_assert(ubi->works_count >= 0); spin_unlock(&ubi->wl_lock); + up_read(&ubi->work_sem); /* * Call the worker function. Do not touch the work structure @@ -254,7 +255,6 @@ static int do_work(struct ubi_device *ubi) err = wrk->func(ubi, wrk, 0); if (err) ubi_err("work failed with error code %d", err); - up_read(&ubi->work_sem); return err; } @@ -1452,7 +1452,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, serve_prot_queue(ubi); /* And take care about wear-leveling */ - err = ensure_wear_leveling(ubi, 1); + err = ensure_wear_leveling(ubi, 0); return err; } @@ -1730,13 +1730,14 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum) ubi->works_count -= 1; ubi_assert(ubi->works_count >= 0); spin_unlock(&ubi->wl_lock); + up_read(&ubi->work_sem); err = wrk->func(ubi, wrk, 0); if (err) { - up_read(&ubi->work_sem); return err; } + down_read(&ubi->work_sem); spin_lock(&ubi->wl_lock); found = 1; break; -- 1.8.4.5 From richard at nod.at Tue Sep 16 06:26:38 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:26:38 +0200 Subject: [PATCH 2/2] UBI: Get rid of __schedule_ubi_work() In-Reply-To: <1410873998-2955-1-git-send-email-richard@nod.at> References: <1410873998-2955-1-git-send-email-richard@nod.at> Message-ID: <1410873998-2955-3-git-send-email-richard@nod.at> As we got rid of work_sem held in workers we can remove __schedule_ubi_work() too. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index b1e2ed1..ba15d33 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -830,15 +830,16 @@ repeat: } /** - * __schedule_ubi_work - schedule a work. + * schedule_ubi_work - schedule a work. * @ubi: UBI device description object * @wrk: the work to schedule * * This function adds a work defined by @wrk to the tail of the pending works - * list. Can only be used of ubi->work_sem is already held in read mode! + * list. */ -static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) +static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) { + down_read(&ubi->work_sem); spin_lock(&ubi->wl_lock); list_add_tail(&wrk->list, &ubi->works); ubi_assert(ubi->works_count >= 0); @@ -846,20 +847,6 @@ static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled(ubi)) wake_up_process(ubi->bgt_thread); spin_unlock(&ubi->wl_lock); -} - -/** - * schedule_ubi_work - schedule a work. - * @ubi: UBI device description object - * @wrk: the work to schedule - * - * This function adds a work defined by @wrk to the tail of the pending works - * list. - */ -static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) -{ - down_read(&ubi->work_sem); - __schedule_ubi_work(ubi, wrk); up_read(&ubi->work_sem); } @@ -1304,13 +1291,12 @@ out_cancel: /** * ensure_wear_leveling - schedule wear-leveling if it is needed. * @ubi: UBI device description object - * @nested: set to non-zero if this function is called from UBI worker * * This function checks if it is time to start wear-leveling and schedules it * if yes. This function returns zero in case of success and a negative error * code in case of failure. */ -static int ensure_wear_leveling(struct ubi_device *ubi, int nested) +static int ensure_wear_leveling(struct ubi_device *ubi) { int err = 0; struct ubi_wl_entry *e1; @@ -1357,10 +1343,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested) wrk->anchor = 0; wrk->func = &wear_leveling_worker; - if (nested) - __schedule_ubi_work(ubi, wrk); - else - schedule_ubi_work(ubi, wrk); + schedule_ubi_work(ubi, wrk); return err; out_cancel: @@ -1452,7 +1435,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, serve_prot_queue(ubi); /* And take care about wear-leveling */ - err = ensure_wear_leveling(ubi, 0); + err = ensure_wear_leveling(ubi); return err; } @@ -1690,7 +1673,7 @@ retry: * Technically scrubbing is the same as wear-leveling, so it is done * by the WL worker. */ - return ensure_wear_leveling(ubi, 0); + return ensure_wear_leveling(ubi); } /** @@ -1991,7 +1974,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ubi->rsvd_pebs += reserved_pebs; /* Schedule wear-leveling if needed */ - err = ensure_wear_leveling(ubi, 0); + err = ensure_wear_leveling(ubi); if (err) goto out_free; -- 1.8.4.5 From richard at nod.at Tue Sep 16 06:30:36 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:30:36 +0200 Subject: [PATCH 2/2] UBIFS: Fix trivial typo in power_cut_emulated() In-Reply-To: <1410874236-3125-1-git-send-email-richard@nod.at> References: <1410874236-3125-1-git-send-email-richard@nod.at> Message-ID: <1410874236-3125-3-git-send-email-richard@nod.at> s/withing/within/ Signed-off-by: Richard Weinberger --- fs/ubifs/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 177b015..b439e84 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -2462,7 +2462,7 @@ static int power_cut_emulated(struct ubifs_info *c, int lnum, int write) if (chance(1, 2)) { d->pc_delay = 1; - /* Fail withing 1 minute */ + /* Fail within 1 minute */ delay = prandom_u32() % 60000; d->pc_timeout = jiffies; d->pc_timeout += msecs_to_jiffies(delay); -- 1.8.4.5 From richard at nod.at Tue Sep 16 06:30:34 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:30:34 +0200 Subject: Two lame typo fixes Message-ID: <1410874236-3125-1-git-send-email-richard@nod.at> ...found them while browsing. Thanks, //richard [PATCH 1/2] UBI: Fix trivial typo in __schedule_ubi_work [PATCH 2/2] UBIFS: Fix trivial typo in power_cut_emulated() From richard at nod.at Tue Sep 16 06:30:35 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:30:35 +0200 Subject: [PATCH 1/2] UBI: Fix trivial typo in __schedule_ubi_work In-Reply-To: <1410874236-3125-1-git-send-email-richard@nod.at> References: <1410874236-3125-1-git-send-email-richard@nod.at> Message-ID: <1410874236-3125-2-git-send-email-richard@nod.at> s/of/if/ Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..e61d799 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -835,7 +835,7 @@ repeat: * @wrk: the work to schedule * * This function adds a work defined by @wrk to the tail of the pending works - * list. Can only be used of ubi->work_sem is already held in read mode! + * list. Can only be used if ubi->work_sem is already held in read mode! */ static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) { -- 1.8.4.5 From richard at nod.at Tue Sep 16 06:50:50 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 15:50:50 +0200 Subject: [PATCH] Add UBIFS support In-Reply-To: <20140915215218.GH4322@dastard> References: <1410772280-9771-1-git-send-email-richard@nod.at> <20140915215218.GH4322@dastard> Message-ID: <5418403A.8020004@nod.at> Am 15.09.2014 23:52, schrieb Dave Chinner: > On Mon, Sep 15, 2014 at 11:11:20AM +0200, Richard Weinberger wrote: >> UBIFS needs some extra care, the device node is of type character and >> it has no fsck tool. > > Not being familiar with UBIFS, the explaination is rather brief and > doesn't explain anything to me. Can you document how where supposed > to treat a filesystem that doesn't exist on a block device for all > the tests that assume that the local fileystem is on a block device? > e.g. how do all the generic tests that use loopback devices work? > What about dm-flakey? UBIFS is a filesystem designed for MTD devices. It works on top of UBI which is kind of a LVM for NAND and NOR flashes. On Linux MTD devices are represented as character devices, this is why the UBI device nodes are of type character. For more details please see: http://www.linux-mtd.infradead.org/doc/ubi.html http://www.linux-mtd.infradead.org/doc/ubifs.html Of course UBIFS will not work on top of loop or dm-flakey. AFAIK the generic tests don't use them anyway. I'd like to have UBIFS tested with xfstests because xfstests has a very good set of generic fs tests. Currently UBIFS fails 20 out of 76 generic tests. At least one issue is real. As soon I have the time I'll inspect all other failures in detail. >> Signed-off-by: Richard Weinberger >> --- >> README | 1 + >> check | 2 ++ >> common/config | 4 ++-- >> common/rc | 18 ++++++++++++++++++ >> 4 files changed, 23 insertions(+), 2 deletions(-) >> >> diff --git a/README b/README >> index 8a362bd..96adc44 100644 >> --- a/README >> +++ b/README >> @@ -100,6 +100,7 @@ Running tests: >> Running all the udf tests: ./check -udf -g udf >> - for running nfs tests: ./check -nfs [test(s)] >> - for running cifs/smb3 tests: ./check -cifs [test(s)] >> + - for running ubifs tests: ./check -ubifs [test(s)] >> - To randomize test order: ./check -r [test(s)] >> >> >> diff --git a/check b/check >> index 42a1ac2..57ec612 100755 >> --- a/check >> +++ b/check >> @@ -70,6 +70,7 @@ check options >> -nfs test NFS >> -cifs test CIFS >> -tmpfs test TMPFS >> + -ubifs test UBIFS >> -l line mode diff >> -udiff show unified diff (default) >> -n show me, do not run tests > > I'd like to avoid adding command line switches for random filesystem > types if at all possible. I'd much prefer that it be derived from > the current TEST_DEV if at all possible. Can you probe for UBIFS > similar to using blkid for local filesystems? I fear blkid does not detect UBIFS, but we can match it from the device node name. UBIFS can only work on top of an UBI volume. UBI volumes have names like /dev/ubiX_Y. Where X is the UBI image number and Y the volume number. >> diff --git a/common/config b/common/config >> index fc21b37..af082ea 100644 >> --- a/common/config >> +++ b/common/config >> @@ -430,7 +430,7 @@ get_next_config() { >> exit 1 >> fi >> >> - echo $TEST_DEV | grep -qE ":|//" > /dev/null 2>&1 >> + echo $TEST_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 >> if [ ! -b "$TEST_DEV" -a "$?" != "0" ]; then >> echo "common/config: Error: \$TEST_DEV ($TEST_DEV) is not a block device or a network filesystem" >> exit 1 > > Needs a comment explaining what format we are searching for there? See above. I match the string "ubi" in /dev/ubiX_Y. >> @@ -453,7 +453,7 @@ get_next_config() { >> export SCRATCH_DEV_NOT_SET=true >> fi >> >> - echo $SCRATCH_DEV | grep -qE ":|//" > /dev/null 2>&1 >> + echo $SCRATCH_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 >> if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" -a "$?" != "0" ]; then >> echo "common/config: Error: \$SCRATCH_DEV ($SCRATCH_DEV) is not a block device or a network filesystem" >> exit 1 >> diff --git a/common/rc b/common/rc >> index b8f711a..064b987 100644 >> --- a/common/rc >> +++ b/common/rc >> @@ -1034,6 +1034,12 @@ _require_scratch_nocheck() >> _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" >> fi >> ;; >> + ubifs) >> + if [ -z "$SCRATCH_DEV" -o ! -c "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ]; >> + then >> + _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" >> + fi >> + ;; > > s/unique/valid/ Will fix! Thanks, //richard From yegorslists at googlemail.com Tue Sep 16 06:57:32 2014 From: yegorslists at googlemail.com (Yegor Yefremov) Date: Tue, 16 Sep 2014 15:57:32 +0200 Subject: MTD autorepartitioning Message-ID: I've found an old discussion, that references following commits (mtd: add BLKPG API based repartition support) and also this patch https://patchwork.ozlabs.org/patch/60224/. What user space tool can I use to repartition my NAND flash? There is no "master" /dev/mtdblock device, that I can pass to fdisk or do I see it wrong? Regards, Yegor From aschmidt at dekaresearch.com Tue Sep 16 07:04:29 2014 From: aschmidt at dekaresearch.com (Atlant Schmidt) Date: Tue, 16 Sep 2014 10:04:29 -0400 Subject: Does UBI LEB-level access interlock happily with UBIfs access? Message-ID: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> Folks: We use the ordinary MTD/UBI/UBIfs stack on our Embedded Linux system. For the purposes of scrubbing-out single bit errors, I'd like to read through all of the LEBs stored in the UBI device and whenever the ECC information indicates that any correctable errors occurred, I'd like to *RE-WRITE* that LEB (thereby forcing it to be scrubbed). (Note: I might do this page-by-page rather than LEB- by-LEB.) But I would expect that because I'd have a hard (impossible?) time doing an atomic read/re-write of a LEB (or page), the UBIfs and my scrubber would interact badly with my scrubber eventually corrupting the UBIfs file system. Is there any easy way to interlock these accesses (from the UBIfs and from my UBI-level scrubber)? A way to temporarily suspend activity from the UBIfs? One kludge that might work is that I'm operating in a real-time environment. If I made my scrubbing requests from a very high priority (higher than the "System" tasks that run around Priority 50), could I be sure my read + rewrite scrubbing requests would at least enter the UBI's work queue immediately adjacent to each other (and without UBIfs requests intermingled)? Alternatively, I could probably dismount the UBIfs before doing scrubbing, but I'd rather not have to do that. Atlant This e-mail and the information, including any attachments it contains, are intended to be a confidential communication only to the person or entity to whom it is addressed and may contain information that is privileged. If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please immediately notify the sender and destroy the original message. Thank you. Please consider the environment before printing this email. From dedekind1 at gmail.com Tue Sep 16 08:13:36 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:13:36 +0300 Subject: mtd-utils-1.5.1 bug report In-Reply-To: <1410178188.10764.159.camel@sauron.fi.intel.com> References: <1410178188.10764.159.camel@sauron.fi.intel.com> Message-ID: <1410880416.28850.47.camel@sauron.fi.intel.com> On Mon, 2014-09-08 at 15:09 +0300, Artem Bityutskiy wrote: > On Sun, 2014-09-07 at 14:58 +0000, David Binderman wrote: > > Hello there, > > > > ubi-utils/ubiformat.c:636:28: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses] > > > > if (!args.subpage_size != mtd->min_io_size) > > normsg("may be sub-page size is " > > "incorrect?"); > > Hi, > > I'd propose this patch to fix the issue: > > Subject: [PATCH] ubiformat: fix the subpage size hint on the error path I've just pushed this patch to mtd-utils.git. I did not test it, but hopefully it is trivial enough and not so risky since it changes the error path. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Tue Sep 16 08:15:24 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:15:24 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <20140908182750.GA9222@arch.hh.imgtec.org> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> Message-ID: <1410880524.28850.49.camel@sauron.fi.intel.com> On Mon, 2014-09-08 at 15:27 -0300, Ezequiel Garcia wrote: > On 08 Sep 03:47 PM, Artem Bityutskiy wrote: > > On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: > > > Regarding -stable, I think it's worth to pull the whole series. > > > > I've checked and the patches do not apply to 3.16 with many conflicts. > > Are you enthusiastic enough to try this and fined out the missing > > dependencies? > > > > The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and > > also mentioned the commits we depend on in the commit messages. > > > > At this point I pushed your patches to the master branch. If you are > > going to check the stable story, please, use this branch. > > > > Sure, I'll prepare the list of commits and let you know. Should I wait some more or assume we won't add the stable tags and add these patches to the 'next' branch? It is about time, I guess. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Tue Sep 16 08:21:47 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:21:47 +0300 Subject: [PATCH] UBI: add missing kmem_cache_free() in process_pool_aeb error path In-Reply-To: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> References: <1410265519-25111-1-git-send-email-richard.genoud@gmail.com> Message-ID: <1410880907.28850.50.camel@sauron.fi.intel.com> On Tue, 2014-09-09 at 14:25 +0200, Richard Genoud wrote: > I ran into this error after a ubiupdatevol, because I forgot to backport > e9110361a9a4 UBI: fix the volumes tree sorting criteria. Pushed, thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Tue Sep 16 08:26:22 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:26:22 +0300 Subject: [PATCH mtd-utils] libmtd: don't ignore "region index" parameter in mtd_regioninfo() In-Reply-To: <20140915174821.GB14832@ld-irv-0074> References: <1407294015-27884-1-git-send-email-Wei.Yang@windriver.com> <20140915173152.GA14832@ld-irv-0074> <20140915174821.GB14832@ld-irv-0074> Message-ID: <1410881182.28850.53.camel@sauron.fi.intel.com> On Mon, 2014-09-15 at 10:48 -0700, Brian Norris wrote: > ioctl(MEMGETREGIONINFO) has one input parameter (regionindex) and three > output parameters (info about the erase region). There are two problems > in mtdinfo/libmtd here: > > 1. mtdinfo.c doesn't initialize its region_info_user struct, instead > passing uninitialized data to mtd_regioninfo() > > 2. mtd_regioninfo() fails to utilize the 'regidx' parameter to fill out > the regionindex parameter properly, so the garbage from mtdinfo.c is > propagated to the ioctl() Thanks, I never had flashes with multiple regions so this code path was probably never tested. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Tue Sep 16 08:23:40 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:23:40 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1410880524.28850.49.camel@sauron.fi.intel.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> Message-ID: <1410881020.28850.52.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 18:15 +0300, Artem Bityutskiy wrote: > On Mon, 2014-09-08 at 15:27 -0300, Ezequiel Garcia wrote: > > On 08 Sep 03:47 PM, Artem Bityutskiy wrote: > > > On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: > > > > Regarding -stable, I think it's worth to pull the whole series. > > > > > > I've checked and the patches do not apply to 3.16 with many conflicts. > > > Are you enthusiastic enough to try this and fined out the missing > > > dependencies? > > > > > > The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and > > > also mentioned the commits we depend on in the commit messages. > > > > > > At this point I pushed your patches to the master branch. If you are > > > going to check the stable story, please, use this branch. > > > > > > > Sure, I'll prepare the list of commits and let you know. > > Should I wait some more or assume we won't add the stable tags and add > these patches to the 'next' branch? It is about time, I guess. I've moved your patch-set to the 'ubiblock' branch so far. -- Best Regards, Artem Bityutskiy From ezequiel at vanguardiasur.com.ar Tue Sep 16 08:32:05 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Tue, 16 Sep 2014 16:32:05 +0100 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1410880524.28850.49.camel@sauron.fi.intel.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> Message-ID: On 16 September 2014 16:15, Artem Bityutskiy wrote: > On Mon, 2014-09-08 at 15:27 -0300, Ezequiel Garcia wrote: >> On 08 Sep 03:47 PM, Artem Bityutskiy wrote: >> > On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: >> > > Regarding -stable, I think it's worth to pull the whole series. >> > >> > I've checked and the patches do not apply to 3.16 with many conflicts. >> > Are you enthusiastic enough to try this and fined out the missing >> > dependencies? >> > >> > The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and >> > also mentioned the commits we depend on in the commit messages. >> > >> > At this point I pushed your patches to the master branch. If you are >> > going to check the stable story, please, use this branch. >> > >> >> Sure, I'll prepare the list of commits and let you know. > > Should I wait some more or assume we won't add the stable tags and add > these patches to the 'next' branch? It is about time, I guess. > Yeah, I have the list of commits ready a couple weeks ago: 4fda380 UBI: Dispatch update notification if the volume is updated 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification db95429 UBI: block: Fix block device size setting 3170403 UBI: block: Avoid disk size integer overflow b6c7b28 UBI: block: Set disk_capacity out of the mutex 1860e37 Linux 3.15 I just got delayed thinking if it was OK to pick so many commits into stable. As an alternative, we can mark only the ones on this patchset, namely: 4fda380 UBI: Dispatch update notification if the volume is updated 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification db95429 UBI: block: Fix block device size setting And I can provide a backport when the -stable people ask for one. Of course, it's a bit more work on everyone, so... what do you think? -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Tue Sep 16 08:35:04 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Tue, 16 Sep 2014 16:35:04 +0100 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> Message-ID: On 16 September 2014 16:32, Ezequiel Garcia wrote: > On 16 September 2014 16:15, Artem Bityutskiy wrote: >> On Mon, 2014-09-08 at 15:27 -0300, Ezequiel Garcia wrote: >>> On 08 Sep 03:47 PM, Artem Bityutskiy wrote: >>> > On Mon, 2014-09-08 at 08:18 -0300, Ezequiel Garcia wrote: >>> > > Regarding -stable, I think it's worth to pull the whole series. >>> > >>> > I've checked and the patches do not apply to 3.16 with many conflicts. >>> > Are you enthusiastic enough to try this and fined out the missing >>> > dependencies? >>> > >>> > The we could add the "Cc: stable at vger.kernel.org # v3.16+" tags, and >>> > also mentioned the commits we depend on in the commit messages. >>> > >>> > At this point I pushed your patches to the master branch. If you are >>> > going to check the stable story, please, use this branch. >>> > >>> >>> Sure, I'll prepare the list of commits and let you know. >> >> Should I wait some more or assume we won't add the stable tags and add >> these patches to the 'next' branch? It is about time, I guess. >> > > Yeah, I have the list of commits ready a couple weeks ago: > > 4fda380 UBI: Dispatch update notification if the volume is updated > 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification > db95429 UBI: block: Fix block device size setting > 3170403 UBI: block: Avoid disk size integer overflow > b6c7b28 UBI: block: Set disk_capacity out of the mutex > 1860e37 Linux 3.15 > > I just got delayed thinking if it was OK to pick so many commits into > stable. As an alternative, > we can mark only the ones on this patchset, namely: > > 4fda380 UBI: Dispatch update notification if the volume is updated > 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification > db95429 UBI: block: Fix block device size setting > Of course, the commit hashes above are all wrong. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From dedekind1 at gmail.com Tue Sep 16 08:44:52 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:44:52 +0300 Subject: xfstests on UBIFS - first findings In-Reply-To: <5416ADB8.80301@nod.at> References: <5416ADB8.80301@nod.at> Message-ID: <1410882292.28850.60.camel@sauron.fi.intel.com> On Mon, 2014-09-15 at 11:13 +0200, Richard Weinberger wrote: > One can simple trigger it by doing: > # mknod foo c 0 0 > # setfattr -h -n trusted.name foo > > dir_ui->data_len is 4 instead of 0. I think the assertion is bogus. It was correct before the xattr support was added. The assertion basically is: if the inode is a directory inode, it should not have data in it. In that function, dir_ui (directory UBIFS inode) may be also be the "host" inode for the xattr entry, so it is not necessarily a directory inode at all. So the variable should be re-named to "host_ui" instead of "dir_ui". -- Best Regards, Artem Bityutskiy From richard at nod.at Tue Sep 16 08:50:55 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 16 Sep 2014 17:50:55 +0200 Subject: xfstests on UBIFS - first findings In-Reply-To: <1410882292.28850.60.camel@sauron.fi.intel.com> References: <5416ADB8.80301@nod.at> <1410882292.28850.60.camel@sauron.fi.intel.com> Message-ID: <54185C5F.1050609@nod.at> Am 16.09.2014 17:44, schrieb Artem Bityutskiy: > On Mon, 2014-09-15 at 11:13 +0200, Richard Weinberger wrote: >> One can simple trigger it by doing: >> # mknod foo c 0 0 >> # setfattr -h -n trusted.name foo >> >> dir_ui->data_len is 4 instead of 0. > > I think the assertion is bogus. It was correct before the xattr support > was added. > > The assertion basically is: if the inode is a directory inode, it should > not have data in it. > > In that function, dir_ui (directory UBIFS inode) may be also be the > "host" inode for the xattr entry, so it is not necessarily a directory > inode at all. > > So the variable should be re-named to "host_ui" instead of "dir_ui". Thanks for the explanation. I'll prepare a patch for that and give more testing tomorrow! Thanks, //richard From dedekind1 at gmail.com Tue Sep 16 08:53:48 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 18:53:48 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> Message-ID: <1410882828.28850.69.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 16:32 +0100, Ezequiel Garcia wrote: > 4fda380 UBI: Dispatch update notification if the volume is updated > 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification > db95429 UBI: block: Fix block device size setting > 3170403 UBI: block: Avoid disk size integer overflow > b6c7b28 UBI: block: Set disk_capacity out of the mutex > 1860e37 Linux 3.15 > > I just got delayed thinking if it was OK to pick so many commits into > stable. As an alternative, > we can mark only the ones on this patchset, namely: > > 4fda380 UBI: Dispatch update notification if the volume is updated > 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification > db95429 UBI: block: Fix block device size setting Yeah, these 3 look like the more important ones. So do we put Cc: stable at vger.kernel.org # v3.16+ or Cc: stable at vger.kernel.org # v3.15+ ? -- Best Regards, Artem Bityutskiy From ezequiel at vanguardiasur.com.ar Tue Sep 16 08:56:06 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Tue, 16 Sep 2014 16:56:06 +0100 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: <1410882828.28850.69.camel@sauron.fi.intel.com> References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> <1410882828.28850.69.camel@sauron.fi.intel.com> Message-ID: On 16 September 2014 16:53, Artem Bityutskiy wrote: > On Tue, 2014-09-16 at 16:32 +0100, Ezequiel Garcia wrote: >> 4fda380 UBI: Dispatch update notification if the volume is updated >> 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification >> db95429 UBI: block: Fix block device size setting >> 3170403 UBI: block: Avoid disk size integer overflow >> b6c7b28 UBI: block: Set disk_capacity out of the mutex >> 1860e37 Linux 3.15 >> >> I just got delayed thinking if it was OK to pick so many commits into >> stable. As an alternative, >> we can mark only the ones on this patchset, namely: >> >> 4fda380 UBI: Dispatch update notification if the volume is updated >> 46a5b80 UBI: block: Add support for the UBI_VOLUME_UPDATED notification >> db95429 UBI: block: Fix block device size setting > > Yeah, these 3 look like the more important ones. So do we put > > Cc: stable at vger.kernel.org # v3.16+ > > or > > Cc: stable at vger.kernel.org # v3.15+ > Cc: stable at vger.kernel.org # v3.15+ I'll backport them when -stable guys ask to. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From dedekind1 at gmail.com Tue Sep 16 09:04:54 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 16 Sep 2014 19:04:54 +0300 Subject: [PATCH 2/3] UBI: block: Add support for the UBI_VOLUME_UPDATED notification In-Reply-To: References: <1409348550-27768-1-git-send-email-ezequiel.garcia@free-electrons.com> <1409348550-27768-3-git-send-email-ezequiel.garcia@free-electrons.com> <1410173657.10764.148.camel@sauron.fi.intel.com> <20140908111832.GA1676@arch.hh.imgtec.org> <1410180460.10764.163.camel@sauron.fi.intel.com> <20140908182750.GA9222@arch.hh.imgtec.org> <1410880524.28850.49.camel@sauron.fi.intel.com> <1410882828.28850.69.camel@sauron.fi.intel.com> Message-ID: <1410883494.28850.70.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 16:56 +0100, Ezequiel Garcia wrote: > Cc: stable at vger.kernel.org # v3.15+ > > I'll backport them when -stable guys ask to. OK, just did it, and pushed out, thanks! -- Best Regards, Artem Bityutskiy From lisovy at gmail.com Tue Sep 16 09:22:35 2014 From: lisovy at gmail.com (Rostislav Lisovy) Date: Tue, 16 Sep 2014 18:22:35 +0200 Subject: Destructive nandtest? Message-ID: <1410884555.23903.13.camel@lp-lvrv.comap.cz> Hello; I need to test a NAND flash on my embedded device running GNU/Linux. I thought the nandtest utility will work just fine, however I hit some unpleasant behavior. My requirement is to perform a non-destructive test. The nandtest utility seems to support it with the "-k, --keep Restore existing contents after test" option, however the reality is different. The testing scenario (performed by the nandtest) is * Backup the original eraseblock (EB) data * Generate some random data * Erase the EB * Store the random data * Read the stored data and compare with the generated buffer * Erase the EB, Write the original content Everything seems to make sense until we ask the question "what about the OOB data?". Is the original OOB data saved? The answer is: No, it is not. This will somehow work in cases the OOB stores only the ECC for the written pages -- if we read the page (OOB contains the ECC), erase the EB and then write the same page back, the OOB will once again contain the same ECC. What if there will be some "extra data" stored in the OOB (I think JFFS2 does this)? This data will be lost. Another sneaky misbehavior is "restoring of erased pages". If the EB is erased (all 0xFF), the nandtest reads the "data stored in the EB", performs the tests and then restores the "data" back by filling all the pages with 0xFF -- this will not only fill the OOB with ECC for the newly written "data" but will deplete the "maximum per-page-write limit" (which is either 1x after each erase or more if the sub-page write is supported by the device). All this described behavior was discovered after long hours of analyzing different nanddumps. What do you think about the issue? Is this the "normal nanddump" behavior or a hidden fault? Do we need a new nandtest or at least remove the "-k, --keep Restore existing contents after test" option? I will appreciate your thoughts. Best regards; Rostislav Lisovy From computersforpeace at gmail.com Tue Sep 16 12:26:10 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Tue, 16 Sep 2014 12:26:10 -0700 Subject: Destructive nandtest? In-Reply-To: <1410884555.23903.13.camel@lp-lvrv.comap.cz> References: <1410884555.23903.13.camel@lp-lvrv.comap.cz> Message-ID: <20140916192610.GB1193@ld-irv-0074> Hi, On Tue, Sep 16, 2014 at 06:22:35PM +0200, Rostislav Lisovy wrote: > I need to test a NAND flash on my embedded device running GNU/Linux. > I thought the nandtest utility will work just fine, however I hit some > unpleasant behavior. > My requirement is to perform a non-destructive test. The nandtest > utility seems to support it with the "-k, --keep Restore existing > contents after test" option, however the reality is different. > The testing scenario (performed by the nandtest) is > * Backup the original eraseblock (EB) data > * Generate some random data > * Erase the EB > * Store the random data > * Read the stored data and compare with the generated buffer > * Erase the EB, Write the original content > > Everything seems to make sense until we ask the question "what about the > OOB data?". Is the original OOB data saved? The answer is: No, it is > not. > This will somehow work in cases the OOB stores only the ECC for the > written pages -- if we read the page (OOB contains the ECC), erase the > EB and then write the same page back, the OOB will once again contain > the same ECC. What if there will be some "extra data" stored in the OOB > (I think JFFS2 does this)? This data will be lost. Right. BTW, this may be acceptable for UBI-based systems, where OOB is never used for metadata. But I agree it's broken in general. > Another sneaky misbehavior is "restoring of erased pages". If the EB is > erased (all 0xFF), the nandtest reads the "data stored in the EB", > performs the tests and then restores the "data" back by filling all the > pages with 0xFF -- this will not only fill the OOB with ECC for the > newly written "data" but will deplete the "maximum per-page-write > limit" (which is either 1x after each erase or more if the sub-page > write is supported by the device). Correct. That's the one I noticed most prominently, and I believe I've seen a few others trip over this. > All this described behavior was discovered after long hours of analyzing > different nanddumps. Sorry :( > What do you think about the issue? Is this the "normal nanddump" > behavior or a hidden fault? Do we need a new nandtest or at least remove > the "-k, --keep Restore existing contents after test" option? > I will appreciate your thoughts. All of your analysis looks accurate to me. Personally, I never used 'nandtest' much myself, because of glaring ommissions like you've noticed. I wouldn't mind just dropping the '--keep' option, since it's a lot of work to try to do correctly, and in its current state, it is completely broken and misleading. Brian From david at fromorbit.com Tue Sep 16 21:47:23 2014 From: david at fromorbit.com (Dave Chinner) Date: Wed, 17 Sep 2014 14:47:23 +1000 Subject: [PATCH] Add UBIFS support In-Reply-To: <5418403A.8020004@nod.at> References: <1410772280-9771-1-git-send-email-richard@nod.at> <20140915215218.GH4322@dastard> <5418403A.8020004@nod.at> Message-ID: <20140917044723.GH4267@dastard> On Tue, Sep 16, 2014 at 03:50:50PM +0200, Richard Weinberger wrote: > Am 15.09.2014 23:52, schrieb Dave Chinner: > > On Mon, Sep 15, 2014 at 11:11:20AM +0200, Richard Weinberger wrote: > >> UBIFS needs some extra care, the device node is of type character and > >> it has no fsck tool. > > > > Not being familiar with UBIFS, the explaination is rather brief and > > doesn't explain anything to me. Can you document how where supposed > > to treat a filesystem that doesn't exist on a block device for all > > the tests that assume that the local fileystem is on a block device? > > e.g. how do all the generic tests that use loopback devices work? > > What about dm-flakey? > > UBIFS is a filesystem designed for MTD devices. > It works on top of UBI which is kind of a LVM for NAND and NOR flashes. > On Linux MTD devices are represented as character devices, this is why > the UBI device nodes are of type character. Ok, so that needs to be in the commit message, and a comment where we validate the device config on startup. ;) > For more details please see: > http://www.linux-mtd.infradead.org/doc/ubi.html > http://www.linux-mtd.infradead.org/doc/ubifs.html > > Of course UBIFS will not work on top of loop or dm-flakey. > AFAIK the generic tests don't use them anyway. Generic tests do use dm-flakey: $ git grep _require_dm_flakey tests/generic tests/generic/311:_require_dm_flakey tests/generic/321:_require_dm_flakey tests/generic/322:_require_dm_flakey tests/generic/325:_require_dm_flakey $ There's no reason why generic tests can't use the loop device, either. Indeed, 10 days ago we added an abstraction to allow generic tests to easily use the loop device (i.e. added _mkfs_dev). > I'd like to have UBIFS tested with xfstests because xfstests has a very > good set of generic fs tests. Understood - all I'm trying to do is work out what exactly what the impact of TEST_DEV/SCRATCH_DEV not being block devices on a local filesystem. Network filesystems are sufficiently different that this isn't an issue, but char vs block local devices is a little more subtle. > Currently UBIFS fails 20 out of 76 generic tests. Hmmm - there's ~140 generic tests in the auto group - I would have expected a lot more of them to run than 76.... > At least one issue is real. As soon I have the time I'll > inspect all other failures in detail. ... and what I'm particularly interested in is how many of those are a result of tests assumes that they are running on a block or network device. > >> diff --git a/check b/check > >> index 42a1ac2..57ec612 100755 > >> --- a/check > >> +++ b/check > >> @@ -70,6 +70,7 @@ check options > >> -nfs test NFS > >> -cifs test CIFS > >> -tmpfs test TMPFS > >> + -ubifs test UBIFS > >> -l line mode diff > >> -udiff show unified diff (default) > >> -n show me, do not run tests > > > > I'd like to avoid adding command line switches for random filesystem > > types if at all possible. I'd much prefer that it be derived from > > the current TEST_DEV if at all possible. Can you probe for UBIFS > > similar to using blkid for local filesystems? > > I fear blkid does not detect UBIFS, but we can match it from the device node name. > UBIFS can only work on top of an UBI volume. UBI volumes have names like /dev/ubiX_Y. > Where X is the UBI image number and Y the volume number. Ok, so that probing can be done fairly easily. Right at the end of common/config there's a blkid command run to grab the FSTYP value from the $TEST_DEV. If returns a null, then we can check for it being a UBI volume and set FSTYP automatically. > >> diff --git a/common/config b/common/config > >> index fc21b37..af082ea 100644 > >> --- a/common/config > >> +++ b/common/config > >> @@ -430,7 +430,7 @@ get_next_config() { > >> exit 1 > >> fi > >> > >> - echo $TEST_DEV | grep -qE ":|//" > /dev/null 2>&1 > >> + echo $TEST_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 > >> if [ ! -b "$TEST_DEV" -a "$?" != "0" ]; then > >> echo "common/config: Error: \$TEST_DEV ($TEST_DEV) is not a block device or a network filesystem" > >> exit 1 > > > > Needs a comment explaining what format we are searching for there? > > See above. I match the string "ubi" in /dev/ubiX_Y. Ok, I can see the match, but you're not validating that it is a char device once you have a match, and so that will accept anything with "/ubi" in it.... > >> @@ -453,7 +453,7 @@ get_next_config() { > >> export SCRATCH_DEV_NOT_SET=true > >> fi > >> > >> - echo $SCRATCH_DEV | grep -qE ":|//" > /dev/null 2>&1 > >> + echo $SCRATCH_DEV | grep -qE ":|//|ubi" > /dev/null 2>&1 > >> if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" -a "$?" != "0" ]; then > >> echo "common/config: Error: \$SCRATCH_DEV ($SCRATCH_DEV) is not a block device or a network filesystem" > >> exit 1 > >> diff --git a/common/rc b/common/rc > >> index b8f711a..064b987 100644 > >> --- a/common/rc > >> +++ b/common/rc > >> @@ -1034,6 +1034,12 @@ _require_scratch_nocheck() > >> _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" > >> fi > >> ;; > >> + ubifs) > >> + if [ -z "$SCRATCH_DEV" -o ! -c "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ]; > >> + then > >> + _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV" > >> + fi > >> + ;; Hmmm, now I see you check for char device here - it shouldn't be necessary as we shouldn't even have got to this statement if the SCRATCH_DEV is not a char device. i.e. validate it when pulling in the config, then it can simply be assumed valid everywhere else if it is set. Cheers, Dave. -- Dave Chinner david at fromorbit.com From computersforpeace at gmail.com Wed Sep 17 01:00:00 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 01:00:00 -0700 Subject: [PATCH] mtd: nand: fix return code for uncorrectable error In-Reply-To: <1410731102-26765-1-git-send-email-hauke@hauke-m.de> References: <1410731102-26765-1-git-send-email-hauke@hauke-m.de> Message-ID: <20140917080000.GA7362@norris-Latitude-E6410> On Sun, Sep 14, 2014 at 11:45:02PM +0200, Hauke Mehrtens wrote: > nand_correct_data() should return -EBADMSG when it finds an > uncorrectable error and not just -1. Why should it? Is there any bug here, or is this just a cosmetic fix along the lines of "we should use meaningful error codes"? > This is based on OpenWrt patch: > https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.10/451-mtd-nand-fix-return-code-of-nand_correct_data-function.patcht > > Signed-off-by: Hauke Mehrtens > --- > drivers/mtd/nand/nand_ecc.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c > index 97c4c02..244a634 100644 > --- a/drivers/mtd/nand/nand_ecc.c > +++ b/drivers/mtd/nand/nand_ecc.c > @@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf, > return 1; /* error in ECC data; no action needed */ > > pr_err("%s: uncorrectable ECC error\n", __func__); > - return -1; > + return -EBADMSG; I think this will break at least one piece of code which relies on the fact that the implicit standard for the correct() function is that it returns -1 for ECC errors; see drivers/mtd/tests/mtd_nandecctest.c: static int double_bit_error_detect(void *error_data, void *error_ecc, void *correct_data, const size_t size) { unsigned char calc_ecc[3]; int ret; __nand_calculate_ecc(error_data, size, calc_ecc); ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size); return (ret == -1) ? 0 : -EINVAL; } So, if you're going to change error codes like this, I'd prefer a little more explanation and a more comprehensive look at the existing body of code. > } > EXPORT_SYMBOL(__nand_correct_data); > Brian From dedekind1 at gmail.com Wed Sep 17 01:17:57 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 11:17:57 +0300 Subject: [PATCH] MAINTAINERS: add l2-mtd.git, 'next' tree for MTD In-Reply-To: <1410843377-30159-1-git-send-email-computersforpeace@gmail.com> References: <1410843377-30159-1-git-send-email-computersforpeace@gmail.com> Message-ID: <1410941877.28850.74.camel@sauron.fi.intel.com> On Mon, 2014-09-15 at 21:56 -0700, Brian Norris wrote: > We've been semi-officially queueing patches here for a while, and it's > in linux-next, so let's advertise it in MAINTAINERS. > > Signed-off-by: Brian Norris Acked-by: Artem Bityutskiy -- Best Regards, Artem Bityutskiy From geert at linux-m68k.org Wed Sep 17 01:23:26 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Wed, 17 Sep 2014 10:23:26 +0200 Subject: [PATCH 5/5] m25p80, spi-nor: Share the list of supported chip type names again In-Reply-To: <1410793627.3040.61.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714708.3040.43.camel@decadent.org.uk> <1410793627.3040.61.camel@decadent.org.uk> Message-ID: Hi Ben, On Mon, Sep 15, 2014 at 5:07 PM, Ben Hutchings wrote: >> > >> > +#define __SPI_NOR_ENUM_TYPES(c_id, str_and_c_id) \ >> > + c_id(at25fs010) c_id(at25fs040) c_id(at25df041a) \ >> > + c_id(at25df321a) c_id(at25df641) c_id(at26f004) \ >> >> Can't you just have the IDs in a header file only, and let the header file >> generate either a struct flash_info or a struct spi_device_id table, using >> a macro defined by the file that includes it? > > How would we match up the rest of the struct flash_info to the name? Ah, you use the enums to match the names to the rest of the flash_info. But you can do it in one-shot, can't you? spi-nor-data.h: FLASH_ENTRY("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), FLASH_ENTRY("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), ... m25p80.c: #define FLASH_ENTRY(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ { .name = _name }, static const struct spi_device_id m25p_ids[] = { #include "spi-nor-data.h" }; spi-nor.c: #define FLASH_ENTRY(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ { \ .name = _name, \ .jedec_id = (_jedec_id), \ .ext_id = (_ext_id), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ .flags = (_flags), \ } static const struct flash_info spi_nor_info[] = { #include "spi-nor-data.h" }; Then the whole table data in contained in one place (spi-nor-data.h). Am I still missing something? Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From dedekind1 at gmail.com Wed Sep 17 01:28:27 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 11:28:27 +0300 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1410853702-11616-1-git-send-email-richard@nod.at> References: <1410853702-11616-1-git-send-email-richard@nod.at> Message-ID: <1410942507.28850.78.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 09:48 +0200, Richard Weinberger wrote: > If sync_erase() failes with EINTR, ENOMEM, EAGAIN or > EBUSY erase_worker() re-schedules the failed work. > This will lead to a deadlock because erase_worker() is called > with work_sem held in read mode. And schedule_erase() will take > this lock again. IIRC, the assumption was that the R/W semaphore may be taken in read mode many times, so it wouldn't hurt to do: down_read() down_read() up_read() up_read() If this is right, then the lockdep warning is incorrect. -- Best Regards, Artem Bityutskiy From josh.wu at atmel.com Wed Sep 17 01:31:29 2014 From: josh.wu at atmel.com (Josh Wu) Date: Wed, 17 Sep 2014 16:31:29 +0800 Subject: [PATCH v2] mtd: atmel_nand: make PMECC lookup table and offset property optional In-Reply-To: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> References: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> Message-ID: <541946E1.1070808@atmel.com> Hi, Ping... Is it any feedback for the patch? Best Regards, Josh Wu On 8/18/2014 3:08 PM, Josh Wu wrote: > If there is no PMECC lookup table stored in ROM, or lookup table offset is > not specified, PMECC driver should build it in DDR by itself. > > That make the PMECC driver work for some board which doesn't has PMECC > lookup table in ROM. > > Signed-off-by: Josh Wu > Cc: devicetree at vger.kernel.org > --- > This patch is based on mtd-l2/next branch > > v1 -> v2: > make create_lookup_table() static. > > > .../devicetree/bindings/mtd/atmel-nand.txt | 6 +- > drivers/mtd/nand/atmel_nand.c | 136 ++++++++++++++++++++- > 2 files changed, 136 insertions(+), 6 deletions(-) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c472883..75d1847 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -5,7 +5,9 @@ Required properties: > - reg : should specify localbus address and size used for the chip, > and hardware ECC controller if available. > If the hardware ECC is PMECC, it should contain address and size for > - PMECC, PMECC Error Location controller and ROM which has lookup tables. > + PMECC and PMECC Error Location controller. > + The PMECC lookup table address and size in ROM is optional. If not > + specified, driver will build it in runtime. > - atmel,nand-addr-offset : offset for the address latch. > - atmel,nand-cmd-offset : offset for the command latch. > - #address-cells, #size-cells : Must be present if the device has sub-nodes > @@ -27,7 +29,7 @@ Optional properties: > are: 512, 1024. > - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM > for different sector size. First one is for sector size 512, the next is for > - sector size 1024. > + sector size 1024. If not specified, driver will build the table in runtime. > - nand-bus-width : 8 or 16 bus width if not present 8 > - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false > - Nand Flash Controller(NFC) is a slave driver under Atmel nand flash > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index effa7a29..84af313 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -124,6 +124,7 @@ struct atmel_nand_host { > bool has_pmecc; > u8 pmecc_corr_cap; > u16 pmecc_sector_size; > + bool has_no_lookup_table; > u32 pmecc_lookup_table_offset; > u32 pmecc_lookup_table_offset_512; > u32 pmecc_lookup_table_offset_1024; > @@ -1109,12 +1110,121 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, > return 0; > } > > +static int pmecc_build_galois_table(int mm, > + int16_t *index_of, int16_t *alpha_to) > +{ > + unsigned int i, mask, nn; > + unsigned int p[PMECC_GF_DIMENSION_14 + 1]; > + > + nn = (1 << mm) - 1; > + /* set default value */ > + for (i = 1; i < mm; i++) > + p[i] = 0; > + > + /* 1 + X^mm */ > + p[0] = 1; > + p[mm] = 1; > + > + /* others */ > + switch (mm) { > + case 3: > + case 4: > + case 6: > + case 15: > + p[1] = 1; > + break; > + case 5: > + case 11: > + p[2] = 1; > + break; > + case 7: > + case 10: > + p[3] = 1; > + break; > + case 8: > + p[2] = p[3] = p[4] = 1; > + break; > + case 9: > + p[4] = 1; > + break; > + case 12: > + p[1] = p[4] = p[6] = 1; > + break; > + case 13: > + p[1] = p[3] = p[4] = 1; > + break; > + case 14: > + p[1] = p[6] = p[10] = 1; > + break; > + default: > + /* Error */ > + return -EINVAL; > + } > + > + /* Build alpha ^ mm it will help to generate the field (primitiv) */ > + alpha_to[mm] = 0; > + for (i = 0; i < mm; i++) > + if (p[i]) > + alpha_to[mm] |= 1 << i; > + > + /* > + * Then build elements from 0 to mm - 1. As degree is less than mm > + * so it is just a logical shift. > + */ > + mask = 1; > + for (i = 0; i < mm; i++) { > + alpha_to[i] = mask; > + index_of[alpha_to[i]] = i; > + mask <<= 1; > + } > + > + index_of[alpha_to[mm]] = mm; > + > + /* use a mask to select the MSB bit of the LFSR */ > + mask >>= 1; > + > + /* then finish the building */ > + for (i = mm + 1; i <= nn; i++) { > + /* check if the msb bit of the lfsr is set */ > + if (alpha_to[i - 1] & mask) > + alpha_to[i] = alpha_to[mm] ^ > + ((alpha_to[i - 1] ^ mask) << 1); > + else > + alpha_to[i] = alpha_to[i - 1] << 1; > + > + index_of[alpha_to[i]] = i % nn; > + } > + > + /* index of 0 is undefined in a multiplicative field */ > + index_of[0] = -1; > + > + return 0; > +} > + > +static uint16_t *create_lookup_table(struct device *dev, int sector_size) > +{ > + int table_size = (sector_size == 512) ? > + PMECC_LOOKUP_TABLE_SIZE_512 : > + PMECC_LOOKUP_TABLE_SIZE_1024; > + int degree = (sector_size == 512) ? > + PMECC_GF_DIMENSION_13 : > + PMECC_GF_DIMENSION_14; > + uint16_t *addr = devm_kzalloc(dev, 2 * table_size * sizeof(uint16_t), > + GFP_KERNEL); > + > + if (addr) > + pmecc_build_galois_table(degree, addr, addr + table_size); > + > + return addr; > +} > + > static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > struct atmel_nand_host *host) > { > struct mtd_info *mtd = &host->mtd; > struct nand_chip *nand_chip = &host->nand_chip; > struct resource *regs, *regs_pmerr, *regs_rom; > + uint16_t *galois_table; > int cap, sector_size, err_no; > > err_no = pmecc_choose_ecc(host, &cap, §or_size); > @@ -1160,8 +1270,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); > host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); > if (IS_ERR(host->pmecc_rom_base)) { > - err_no = PTR_ERR(host->pmecc_rom_base); > - goto err; > + if (!host->has_no_lookup_table) > + /* Don't display the information again */ > + dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); > + > + host->has_no_lookup_table = true; > + } > + > + if (host->has_no_lookup_table) { > + /* Build the look-up table in runtime */ > + galois_table = create_lookup_table(host->dev, sector_size); > + if (!galois_table) { > + dev_err(host->dev, "Failed to build a lookup table in runtime!\n"); > + err_no = -ENOMEM; > + goto err; > + } > + > + host->pmecc_rom_base = galois_table; > + host->pmecc_lookup_table_offset = 0; > } > > nand_chip->ecc.size = sector_size; > @@ -1498,8 +1624,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host, > > if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", > offset, 2) != 0) { > - dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); > - return -EINVAL; > + dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n"); > + host->has_no_lookup_table = true; > + /* Will build a lookup table and initialize the offset later */ > + return 0; > } > if (!offset[0] && !offset[1]) { > dev_err(host->dev, "Invalid PMECC lookup table offset\n"); From josh.wu at atmel.com Wed Sep 17 01:33:01 2014 From: josh.wu at atmel.com (Josh Wu) Date: Wed, 17 Sep 2014 16:33:01 +0800 Subject: [PATCH 1/2] mtd: atmel_nand: remove pmecc_sector_number, use ecc.steps instead In-Reply-To: <1407489155-16545-1-git-send-email-josh.wu@atmel.com> References: <1407489155-16545-1-git-send-email-josh.wu@atmel.com> Message-ID: <5419473D.7060007@atmel.com> Hi, Brian Any feedback for this patch series? Best Regards, Josh Wu On 8/8/2014 5:12 PM, Josh Wu wrote: > For PMECC, the pmecc_sector_number has same meaning as ecc.steps. > So use ecc.steps to replace the pmecc_sector_number. > > Signed-off-by: Josh Wu > --- > drivers/mtd/nand/atmel_nand.c | 14 ++++++-------- > 1 file changed, 6 insertions(+), 8 deletions(-) > > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717..1dc3988 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -129,7 +129,6 @@ struct atmel_nand_host { > u32 pmecc_lookup_table_offset_1024; > > int pmecc_bytes_per_sector; > - int pmecc_sector_number; > int pmecc_degree; /* Degree of remainders */ > int pmecc_cw_len; /* Length of codeword */ > > @@ -874,7 +873,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, > return 0; > > normal_check: > - for (i = 0; i < host->pmecc_sector_number; i++) { > + for (i = 0; i < nand_chip->ecc.steps; i++) { > err_nbr = 0; > if (pmecc_stat & 0x1) { > buf_pos = buf + i * host->pmecc_sector_size; > @@ -984,7 +983,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, > cpu_relax(); > } > > - for (i = 0; i < host->pmecc_sector_number; i++) { > + for (i = 0; i < chip->ecc.steps; i++) { > for (j = 0; j < host->pmecc_bytes_per_sector; j++) { > int pos; > > @@ -1031,7 +1030,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) > else if (host->pmecc_sector_size == 1024) > val |= PMECC_CFG_SECTOR1024; > > - switch (host->pmecc_sector_number) { > + switch (nand_chip->ecc.steps) { > case 1: > val |= PMECC_CFG_PAGE_1SECTOR; > break; > @@ -1184,18 +1183,17 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > host->pmecc_degree = (sector_size == 512) ? > PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; > host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; > - host->pmecc_sector_number = mtd->writesize / sector_size; > host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( > cap, sector_size); > host->pmecc_alpha_to = pmecc_get_alpha_to(host); > host->pmecc_index_of = host->pmecc_rom_base + > host->pmecc_lookup_table_offset; > > - nand_chip->ecc.steps = host->pmecc_sector_number; > nand_chip->ecc.strength = cap; > nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; > - nand_chip->ecc.total = host->pmecc_bytes_per_sector * > - host->pmecc_sector_number; > + nand_chip->ecc.steps = mtd->writesize / sector_size; > + nand_chip->ecc.total = nand_chip->ecc.bytes * > + nand_chip->ecc.steps; > if (nand_chip->ecc.total > mtd->oobsize - 2) { > dev_err(host->dev, "No room for ECC bytes\n"); > err_no = -EINVAL; From computersforpeace at gmail.com Wed Sep 17 01:33:53 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 01:33:53 -0700 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <54104CB4.4020703@ti.com> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> <20140910124849.GA25308@arch.hh.imgtec.org> <54104CB4.4020703@ti.com> Message-ID: <20140917083353.GB7362@norris-Latitude-E6410> On Wed, Sep 10, 2014 at 04:05:56PM +0300, Roger Quadros wrote: > On 09/10/2014 03:48 PM, Ezequiel Garcia wrote: > > On 08 Sep 01:53 PM, Roger Quadros wrote: > >> On 09/08/2014 11:45 AM, Roger Quadros wrote: > >>> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and > >> CONFIG_MTD_NAND_OMAP_BCH to m. > >> > >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to > >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. > >> > > > > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( > > Mine neither ;). I'm unaware of any other method than making CONFIG_MTD_NAND_OMAP_BCH to bool. That could be part of the solution. Does the following patch work? It now forces elm and omap to be built the same -- either both as modules or both built-in -- but it solves the rest of the problem I think. (This also has the side effect of causing transition pains for any .config file that had CONFIG_MTD_NAND_OMAP_BCH=m, since this becomes boolean now.) diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f60588..4dc8990898dc 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1cf503517fd..6390b2b58edb 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,9 +96,8 @@ config MTD_NAND_OMAP2 config MTD_NAND_OMAP_BCH depends on MTD_NAND_OMAP2 - tristate "Support hardware based BCH error correction" + bool "Support hardware based BCH error correction" default n - select BCH help This config enables the ELM hardware engine, which can be used to locate and correct errors when using BCH ECC scheme. This offloads @@ -106,6 +105,12 @@ config MTD_NAND_OMAP_BCH legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine so they should not enable this config symbol. +config MTD_NAND_OMAP_BCH_BUILD + tristate + depends on MTD_NAND_OMAP_BCH + default MTD_NAND_OMAP2 + select BCH + config MTD_NAND_IDS tristate From richard at nod.at Wed Sep 17 01:40:03 2014 From: richard at nod.at (Richard Weinberger) Date: Wed, 17 Sep 2014 10:40:03 +0200 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1410942507.28850.78.camel@sauron.fi.intel.com> References: <1410853702-11616-1-git-send-email-richard@nod.at> <1410942507.28850.78.camel@sauron.fi.intel.com> Message-ID: <541948E3.3080602@nod.at> Am 17.09.2014 10:28, schrieb Artem Bityutskiy: > On Tue, 2014-09-16 at 09:48 +0200, Richard Weinberger wrote: >> If sync_erase() failes with EINTR, ENOMEM, EAGAIN or >> EBUSY erase_worker() re-schedules the failed work. >> This will lead to a deadlock because erase_worker() is called >> with work_sem held in read mode. And schedule_erase() will take >> this lock again. > > IIRC, the assumption was that the R/W semaphore may be taken in read > mode many times, so it wouldn't hurt to do: > > down_read() > down_read() > up_read() > up_read() Hmm, are you sure that this is legal? Quoting rwsem.h: /* * nested locking. NOTE: rwsems are not allowed to recurse * (which occurs if the same task tries to acquire the same * lock instance multiple times), but multiple locks of the * same lock class might be taken, if the order of the locks * is always the same. This ordering rule can be expressed * to lockdep via the _nested() APIs, but enumerating the * subclasses that are used. (If the nesting relationship is * static then another method for expressing nested locking is * the explicit definition of lock class keys and the use of * lockdep_set_class() at lock initialization time. * See Documentation/lockdep-design.txt for more details.) */ In this case the same task is taking the same lock multiple times, which is not allowed according to rwsem.h. Thanks, //richard From dedekind1 at gmail.com Wed Sep 17 01:42:35 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 11:42:35 +0300 Subject: [RFC] Don'd hold work_sem while calling worker functions In-Reply-To: <1410873998-2955-1-git-send-email-richard@nod.at> References: <1410873998-2955-1-git-send-email-richard@nod.at> Message-ID: <1410943355.28850.92.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 15:26 +0200, Richard Weinberger wrote: > I fail to see why we need work_sem while wrk->func() is executed. > Artem, do you have an idea? > > Having the wear_leveling_worker() called without work_sem held > would simplify the fastmap code too. I'm currently reworking some > of it's code and I'm in locking hell. 8-) Well, the best way for getting clue about the meaning of an R/W semaphore with an unlimited amount of read-takers I found for myself is to focus on the write-takers. Read-takers are non-interesting, because they can race freely. So let's check write-takers. There are 2 of them - one in your code, one in the one I wrote many years ago. "Mine" is in 'ubi_wl_flush()': down_write(&ubi->work_sem); up_write(&ubi->work_sem); And the only reason it is there is to make sure that flush() really flushes the queue, and when 'ubi_wl_flush()' returns, you may be sure that all the in-flight works were finished. There are other ways to achieve this, but I probably found using the R/W semaphore to be the easiest. Indeed, just make all the works have it in read mode, and when you have to wait for all the in-flight works to complete, you take it in write mode - easy. IOW, this is a bit of an unusual use of R/W semaphores. HTH. P.S. Generally, if you have a trouble with a lock, start with checking the place where it is defined, I tried to document locks there briefly. And there may be pices of useful comments elsewhere. This should be true for both UBI and UBIFS. So just a general hint. For 'work_sem' you'd need to check ubi.h. But unfortunately, the comment there is not helpful, and even has a typo which makes it confusing. While on it, would you refine the comment and say something like: work_sem: used to wait for all the scheduled works to finish and prevent new works from being submitted -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Wed Sep 17 01:43:41 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 11:43:41 +0300 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <541948E3.3080602@nod.at> References: <1410853702-11616-1-git-send-email-richard@nod.at> <1410942507.28850.78.camel@sauron.fi.intel.com> <541948E3.3080602@nod.at> Message-ID: <1410943421.28850.93.camel@sauron.fi.intel.com> On Wed, 2014-09-17 at 10:40 +0200, Richard Weinberger wrote: > /* > * nested locking. NOTE: rwsems are not allowed to recurse > * (which occurs if the same task tries to acquire the same > * lock instance multiple times), but multiple locks of the > * same lock class might be taken, if the order of the locks > * is always the same. This ordering rule can be expressed > * to lockdep via the _nested() APIs, but enumerating the > * subclasses that are used. (If the nesting relationship is > * static then another method for expressing nested locking is > * the explicit definition of lock class keys and the use of > * lockdep_set_class() at lock initialization time. > * See Documentation/lockdep-design.txt for more details.) > */ > > In this case the same task is taking the same lock multiple times, > which is not allowed according to rwsem.h. Yes, this part was missed, thanks. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Wed Sep 17 02:35:26 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 12:35:26 +0300 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1410853702-11616-1-git-send-email-richard@nod.at> References: <1410853702-11616-1-git-send-email-richard@nod.at> Message-ID: <1410946526.28850.120.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 09:48 +0200, Richard Weinberger wrote: > If sync_erase() failes with EINTR, ENOMEM, EAGAIN or > EBUSY erase_worker() re-schedules the failed work. > This will lead to a deadlock because erase_worker() is called > with work_sem held in read mode. And schedule_erase() will take > this lock again. There is this code snippet: ubi_err("failed to erase PEB %d, error %d", pnum, err); kfree(wl_wrk); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || err == -EBUSY) { int err1; /* Re-schedule the LEB for erasure */ err1 = schedule_erase(ubi, e, vol_id, lnum, 0); if (err1) { err = err1; goto out_ro; } return err; } How about move 'kfree(wl_wrk)' down, and execute __schedule_ubi_work(ubi, wl_wrk) inside the 'if' clause instead? The fix would seem to be more elegant then. Hmm? -- Best Regards, Artem Bityutskiy From ezequiel at vanguardiasur.com.ar Wed Sep 17 02:54:03 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Wed, 17 Sep 2014 10:54:03 +0100 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <20140917083353.GB7362@norris-Latitude-E6410> References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> <20140910124849.GA25308@arch.hh.imgtec.org> <54104CB4.4020703@ti.com> <20140917083353.GB7362@norris-Latitude-E6410> Message-ID: On 17 September 2014 09:33, Brian Norris wrote: > On Wed, Sep 10, 2014 at 04:05:56PM +0300, Roger Quadros wrote: >> On 09/10/2014 03:48 PM, Ezequiel Garcia wrote: >> > On 08 Sep 01:53 PM, Roger Quadros wrote: >> >> On 09/08/2014 11:45 AM, Roger Quadros wrote: >> >>> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: >> >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and >> >> CONFIG_MTD_NAND_OMAP_BCH to m. >> >> >> >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to >> >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. >> >> >> > >> > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( >> >> Mine neither ;). I'm unaware of any other method than making CONFIG_MTD_NAND_OMAP_BCH to bool. > > That could be part of the solution. Does the following patch work? It > now forces elm and omap to be built the same -- either both as modules > or both built-in -- but it solves the rest of the problem I think. > > (This also has the side effect of causing transition pains for any > .config file that had CONFIG_MTD_NAND_OMAP_BCH=m, since this becomes > boolean now.) > http://patchwork.ozlabs.org/patch/388249/ I used my time-machine to go back in time and submitted the patch for you :-) -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From shijie8 at gmail.com Wed Sep 17 08:26:11 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Wed, 17 Sep 2014 23:26:11 +0800 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140915221210.5d9871fb@bbrezillon> References: <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> <20140913173841.GA18093@brian-ubuntu> <20140915144259.GA1947@localhost.localdomain> <20140915221210.5d9871fb@bbrezillon> Message-ID: <20140917152609.GA2111@localhost.localdomain> On Mon, Sep 15, 2014 at 10:12:10PM +0200, Boris BREZILLON wrote: > On Mon, 15 Sep 2014 22:43:02 +0800 > Huang Shijie wrote: > > > On Sat, Sep 13, 2014 at 10:38:41AM -0700, Brian Norris wrote: > > > On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > > > > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > > > > This test validates what's returned by ecc_strength file in sysfs > > > > > (which in turn is specified by the NAND controller when initializing > > > > > the NAND chip). > > > > > > > > > > Doing this should not imply knowing the ECC algorithm in use in the > > > > > NAND controller or the layout used to store data on NAND. > > > > the difficulty is that the ECC parity area can be not byte aligned. > > > > > > Is there a problem with just rounding up to the nearest byte alignment > > > and ignoring the few bits that are wasted? > > > > I feel a little confused with the two hooks. > > > > does the ecc->write_page_raw need to write the ECC parity data? > > Depending on the oob_required argument, it might be allowed to > overwrite the ECC bytes even if this implies breaking page reliability > (which is exactly what's expected). > > When using raw write with with oob write option the writer should take > care of regenerating ECC bytes (which you said was impossible in GPMI > case) or copying them from a previous raw read. Thanks for the explanation. If we do not write the OOB, should we write the ECC bytes? The hooks should comment clearly about how to implement them :( > > Here is a real example of what one could test with raw write + oob: > 1) read a page in raw mode > 2) flip some bits in the generated ECC bytes (or what you references as > parity data) (this case can actually happen in real life) > 3) write the modified page in raw mode > 4) read back the same page in normal and check that ECC correction still > works as expected the nandbiterr test mode does the test as above. But i think the multi-writes to the same page should occur only for the SLC nand. I will read your new patch set carefully in this weekend. thanks Huang Shijie From lisovy at gmail.com Wed Sep 17 08:31:20 2014 From: lisovy at gmail.com (Rostislav Lisovy) Date: Wed, 17 Sep 2014 17:31:20 +0200 Subject: Destructive nandtest? In-Reply-To: <20140916192610.GB1193@ld-irv-0074> References: <1410884555.23903.13.camel@lp-lvrv.comap.cz> <20140916192610.GB1193@ld-irv-0074> Message-ID: <1410967880.5542.8.camel@lp-lvrv.comap.cz> Hello Brian; Thanks for your reply. On ?t, 2014-09-16 at 12:26 -0700, Brian Norris wrote: > All of your analysis looks accurate to me. Personally, I never used > 'nandtest' much myself, because of glaring ommissions like you've > noticed. I wouldn't mind just dropping the '--keep' option, since it's > a lot of work to try to do correctly, and in its current state, it is > completely broken and misleading. I have some proof-of-concept code that does store the OOB (and restores it later) and is able to distinguish if the page is erased or not (in a bit naive manner -- if the page is all 0xff and particular ECCs as well) and decide is the data should be restored or not. I hope I will be able to post the code soon. Best regards; Rostislav From dedekind1 at gmail.com Wed Sep 17 08:59:40 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 17 Sep 2014 18:59:40 +0300 Subject: Destructive nandtest? In-Reply-To: <1410967880.5542.8.camel@lp-lvrv.comap.cz> References: <1410884555.23903.13.camel@lp-lvrv.comap.cz> <20140916192610.GB1193@ld-irv-0074> <1410967880.5542.8.camel@lp-lvrv.comap.cz> Message-ID: <1410969580.28850.125.camel@sauron.fi.intel.com> On Wed, 2014-09-17 at 17:31 +0200, Rostislav Lisovy wrote: > I have some proof-of-concept code that does store the OOB (and > restores > it later) and is able to distinguish if the page is erased or not (in > a > bit naive manner -- if the page is all 0xff and particular ECCs as > well) > and decide is the data should be restored or not. > I hope I will be able to post the code soon. Ideally, the relevant pieces of code should be shared between nanddump, nandwrite, and nanttest. -- Best Regards, Artem Bityutskiy From stefan at agner.ch Wed Sep 17 10:02:11 2014 From: stefan at agner.ch (Stefan Agner) Date: Wed, 17 Sep 2014 19:02:11 +0200 Subject: [RFC 2/5] =?UTF-8?Q?mtd=3Afsl=5Fnfc=3A=20Add=20hardware=20=34?= =?UTF-8?Q?=35=20byte=20BHC-ECC=20support=20for=20=32=34=20bit=20correctio?= =?UTF-8?Q?ns=2E?= In-Reply-To: <1389222441-4322-3-git-send-email-bpringlemeir@nbsps.com> References: <87siupheou.fsf@nbsps.com> <1389222441-4322-1-git-send-email-bpringlemeir@nbsps.com> <1389222441-4322-3-git-send-email-bpringlemeir@nbsps.com> Message-ID: <127db6b73356442d2ba12e8c011038cc@agner.ch> Hi Bill, On one of our Colibri VF61 modules I discovered an issue using this driver: [ 0.758327] ECC failed to correct all errors (ebd9fd80) [ 0.767005] ECC failed to correct all errors (ebd9fd80) [ 0.775525] ECC failed to correct all errors (ebd9fd80) [ 0.784004] ECC failed to correct all errors (ebd9fd80) [ 0.791938] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 28:2048, read 2048 bytes That page supposed to be empty, and I got several of this messages. Hence I did not believe that they have really ECC errors, so I digged a bit deeper: @@ -673,11 +673,13 @@ static int fsl_nfc_check_ecc_status(struct mtd_info *mtd, u_char *dat) return ecc_count; /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ - flip = count_written_bits(dat, chip->ecc.size, ecc_count); + flip = count_written_bits(dat, chip->ecc.size, 100); if (flip > ecc_count) { - printk("ECC failed to correct all errors (%08x)\n", ecc_status); + printk("ECC failed to correct all errors (%08x, flips %d)\n", + ecc_status, flip); return -1; } [ 0.758624] ECC failed to correct all errors (ebdded80, flips 1) [ 0.768123] ECC failed to correct all errors (ebdded80, flips 1) [ 0.777468] ECC failed to correct all errors (ebdded80, flips 1) [ 0.786773] ECC failed to correct all errors (ebdded80, flips 1) [ 0.795535] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 28:2048, read 2048 bytes [ 1.462183] ECC failed to correct all errors (ebdded82, flips 3) [ 1.471623] ECC failed to correct all errors (ebdded82, flips 3) [ 1.481025] ECC failed to correct all errors (ebdded82, flips 3) [ 1.490336] ECC failed to correct all errors (ebdded82, flips 3) [ 1.498953] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 664:2048, read 2048 bytes [ 1.551421] ECC failed to correct all errors (ebdded80, flips 1) [ 1.560616] ECC failed to correct all errors (ebdded80, flips 1) [ 1.569695] ECC failed to correct all errors (ebdded80, flips 1) [ 1.578711] ECC failed to correct all errors (ebdded80, flips 1) [ 1.587192] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 666:2048, read 2048 bytes [ 1.744612] ECC failed to correct all errors (ebdded81, flips 2) [ 1.753943] ECC failed to correct all errors (ebdded81, flips 2) [ 1.763146] ECC failed to correct all errors (ebdded81, flips 2) [ 1.772247] ECC failed to correct all errors (ebdded81, flips 2) [ 1.780722] UBI error: ubi_io_read: error -74 (ECC error) while reading 2048 bytes from PEB 776:2048, read 2048 bytes Interesting thought, the returned ecc_count is exactly one below the actual flipped bytes counted... One comment below regarding this... Am 2014-01-09 00:07, schrieb Bill Pringlemeir: > Signed-off-by: Bill Pringlemeir > --- > drivers/mtd/nand/Kconfig | 5 +- > drivers/mtd/nand/fsl_nfc.c | 114 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 117 insertions(+), 2 deletions(-) > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > index 7e0c695..8ac9923 100644 > --- a/drivers/mtd/nand/Kconfig > +++ b/drivers/mtd/nand/Kconfig > @@ -458,8 +458,9 @@ config MTD_NAND_FSL_NFC > help > Enables support for NAND Flash controller on some Freescale > processors like the MPC5125, VF610, MCF54418, and Kinetis K70. > - The driver supports a maximum 2k page size. > - The driver currently does not support hardware ECC. > + The driver supports a maximum 2k page size. With 2k pages and > + 64 bytes or more of OOB, hardware ECC with 24bit correction is > + supported. Only MTD_OF (device tree) can enable the hardware ECC. > > config MTD_NAND_MXC > tristate "MXC NAND support" > diff --git a/drivers/mtd/nand/fsl_nfc.c b/drivers/mtd/nand/fsl_nfc.c > index eb4e353..703511d 100644 > --- a/drivers/mtd/nand/fsl_nfc.c > +++ b/drivers/mtd/nand/fsl_nfc.c > @@ -17,6 +17,7 @@ > * - Untested on MPC5125 and M54418. > * - DMA not used. > * - 2K pages or less. > + * - Only 2K page w. 64+OOB and hardware ECC. > */ > > #include > @@ -68,6 +69,7 @@ > > /* NFC ECC mode define */ > #define ECC_BYPASS 0 > +#define ECC_45_BYTE 6 > > /*** Register Mask and bit definitions */ > > @@ -100,6 +102,8 @@ > #define STATUS_BYTE1_MASK 0x000000FF > > /* NFC_FLASH_CONFIG Field */ > +#define CONFIG_ECC_SRAM_ADDR_MASK 0x7FC00000 > +#define CONFIG_ECC_SRAM_ADDR_SHIFT 22 > #define CONFIG_ECC_SRAM_REQ_BIT (1<<21) > #define CONFIG_DMA_REQ_BIT (1<<20) > #define CONFIG_ECC_MODE_MASK 0x000E0000 > @@ -120,6 +124,11 @@ > > #define NFC_TIMEOUT (HZ) > > +/* ECC status placed at end of buffers. */ > +#define ECC_SRAM_ADDR ((PAGE_2K+256-8) >> 3) > +#define ECC_STATUS_MASK 0x80 > +#define ECC_ERR_COUNT 0x3F > + > struct fsl_nfc { > struct mtd_info mtd; > struct nand_chip chip; > @@ -160,6 +169,19 @@ static struct nand_bbt_descr bbt_mirror_descr = { > .pattern = mirror_pattern, > }; > > +static struct nand_ecclayout nfc_ecc45 = { > + .eccbytes = 45, > + .eccpos = {19, 20, 21, 22, 23, > + 24, 25, 26, 27, 28, 29, 30, 31, > + 32, 33, 34, 35, 36, 37, 38, 39, > + 40, 41, 42, 43, 44, 45, 46, 47, > + 48, 49, 50, 51, 52, 53, 54, 55, > + 56, 57, 58, 59, 60, 61, 62, 63}, > + .oobfree = { > + {.offset = 8, > + .length = 11} } > +}; > + > static u32 nfc_read(struct mtd_info *mtd, uint reg) > { > struct fsl_nfc *nfc = mtd_to_nfc(mtd); > @@ -458,7 +480,61 @@ nfc_select_chip(struct mtd_info *mtd, int chip) > #endif > } > > +/* Count the number of 0's in buff upto max_bits */ > +static int count_written_bits(uint8_t *buff, int size, int max_bits) > +{ > + int k, written_bits = 0; > + > + for (k = 0; k < size; k++) { > + written_bits += hweight8(~buff[k]); > + if (written_bits > max_bits) > + break; > + } > + > + return written_bits; > +} > + > +static int nfc_correct_data(struct mtd_info *mtd, u_char *dat, > + u_char *read_ecc, u_char *calc_ecc) > +{ > + struct fsl_nfc *nfc = mtd_to_nfc(mtd); > + u32 ecc_status; > + u8 ecc_count; > + int flip; > + > + /* Errata: ECC status is stored at NFC_CFG[ECCADD] +4 for > + little-endian and +7 for big-endian SOC. Access as 32 bits > + and use low byte. > + */ > + ecc_status = __raw_readl(nfc->regs + ECC_SRAM_ADDR * 8 + 4); > + ecc_count = ecc_status & ECC_ERR_COUNT; > + if (!(ecc_status & ECC_STATUS_MASK)) > + return ecc_count; > + > + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ > + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); Also, I could not find that the reference manual states that ecc_count represents the amount of flipped byte in a empty page. Is this given by the ECC algorithm? > + > + /* ECC failed. */ > + if (flip > ecc_count) > + return -1; > + > + /* Erased page. */ > + memset(dat, 0xff, nfc->chip.ecc.size); > + return 0; > +} > + > +static int nfc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, > + u_char *ecc_code) > +{ > + return 0; > +} > + > +static void nfc_enable_hwecc(struct mtd_info *mtd, int mode) > +{ > +} > + > struct nfc_config { > + int hardware_ecc; > int width; > int flash_bbt; > u32 clkrate; > @@ -483,6 +559,9 @@ static int __init nfc_probe_dt(struct device *dev, > struct nfc_config *cfg) > if (!np) > return 1; > > + if (of_get_nand_ecc_mode(np) >= NAND_ECC_HW) > + cfg->hardware_ecc = 1; > + > cfg->flash_bbt = of_get_nand_on_flash_bbt(np); > > if (!of_property_read_u32(np, "clock-frequency", &clkrate)) > @@ -608,6 +687,11 @@ static int nfc_probe(struct platform_device *pdev) > nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK, > CONFIG_PAGE_CNT_SHIFT, 1); > > + /* Set ECC_STATUS offset */ > + nfc_set_field(mtd, NFC_FLASH_CONFIG, > + CONFIG_ECC_SRAM_ADDR_MASK, > + CONFIG_ECC_SRAM_ADDR_SHIFT, ECC_SRAM_ADDR); > + > /* first scan to find the device and get the page size */ > if (nand_scan_ident(mtd, 1, NULL)) { > err = -ENXIO; > @@ -627,6 +711,36 @@ static int nfc_probe(struct platform_device *pdev) > page_sz += cfg.width == 16 ? 1 : 0; > nfc_write(mtd, NFC_SECTOR_SIZE, page_sz); > > + if (cfg.hardware_ecc) { > + if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) { > + dev_err(nfc->dev, "Unsupported flash with hwecc\n"); > + err = -ENXIO; > + goto error; > + } > + > + chip->ecc.layout = &nfc_ecc45; > + > + /* propagate ecc.layout to mtd_info */ > + mtd->ecclayout = chip->ecc.layout; > + chip->ecc.calculate = nfc_calculate_ecc; > + chip->ecc.hwctl = nfc_enable_hwecc; > + chip->ecc.correct = nfc_correct_data; > + chip->ecc.mode = NAND_ECC_HW; > + > + chip->ecc.bytes = 45; > + chip->ecc.size = PAGE_2K; > + chip->ecc.strength = 24; > + > + /* set ECC mode to 45 bytes OOB with 24 bits correction */ > + nfc_set_field(mtd, NFC_FLASH_CONFIG, > + CONFIG_ECC_MODE_MASK, > + CONFIG_ECC_MODE_SHIFT, ECC_45_BYTE); > + > + /* Enable ECC_STATUS */ > + nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT); > + > + } > + > /* second phase scan */ > if (nand_scan_tail(mtd)) { > err = -ENXIO; -- Stefan From computersforpeace at gmail.com Wed Sep 17 10:13:08 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 10:13:08 -0700 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140917171308.GC1193@ld-irv-0074> On Tue, Sep 16, 2014 at 08:04:18PM +0900, Masahiro Yamada wrote: > > > Masahiro Yamada (7): > mtd: denali: fix the format of comment blocks > mtd: denali: remove unnecessary variable initializations > mtd: denali: remove unnecessary casts > mtd: denali: change the type of iterators to int > mtd: denali: remove a set-but-unused variable > mtd: denali: remove unnecessary parentheses > mtd: denali: fix indents and other trivial things This series still doesn't apply to l2-mtd.git. Brian From bpringlemeir at nbsps.com Wed Sep 17 11:06:08 2014 From: bpringlemeir at nbsps.com (Bill Pringlemeir) Date: Wed, 17 Sep 2014 14:06:08 -0400 Subject: [RFC 2/5] mtd:fsl_nfc: Add hardware 45 byte BHC-ECC support for 24 bit corrections. References: <87siupheou.fsf@nbsps.com> <1389222441-4322-1-git-send-email-bpringlemeir@nbsps.com> <1389222441-4322-3-git-send-email-bpringlemeir@nbsps.com> <127db6b73356442d2ba12e8c011038cc@agner.ch> Message-ID: <87r3zaxgtr.fsf@nbsps.com> On 17 Sep 2014, stefan at agner.ch wrote: > On one of our Colibri VF61 modules I discovered an issue using this > driver: > [ 0.758327] ECC failed to correct all errors (ebd9fd80) > [ 0.767005] ECC failed to correct all errors (ebd9fd80) > [ 0.775525] ECC failed to correct all errors (ebd9fd80) > [ 0.784004] ECC failed to correct all errors (ebd9fd80) > [ 0.791938] UBI error: ubi_io_read: error -74 (ECC error) while > reading 2048 bytes from PEB 28:2048, > read 2048 bytes > That page supposed to be empty, and I got several of this messages. > Hence I did not believe that they have really ECC errors, so I digged > a bit deeper: >>> -673,11 +673,13 @@ static int fsl_nfc_check_ecc_status(struct > mtd_info *mtd, u_char *dat) > return ecc_count; > /* If 'ecc_count' zero or less then buffer is all 0xff or > erased. */ > - flip = count_written_bits(dat, chip->ecc.size, ecc_count); > + flip = count_written_bits(dat, chip->ecc.size, 100); > if (flip > ecc_count) { > - printk("ECC failed to correct all errors (%08x)\n", > ecc_status); > + printk("ECC failed to correct all errors (%08x, flips > %d)\n", > + ecc_status, flip); > return -1; > } > [ 0.758624] ECC failed to correct all errors (ebdded80, flips 1) > [ 0.768123] ECC failed to correct all errors (ebdded80, flips 1) > [ 0.777468] ECC failed to correct all errors (ebdded80, flips 1) > [ 0.786773] ECC failed to correct all errors (ebdded80, flips 1) > [ 0.795535] UBI error: ubi_io_read: error -74 (ECC error) while > reading 2048 bytes from PEB 28:2048, read 2048 bytes [snip] > Interesting thought, the returned ecc_count is exactly one below the > actual flipped bytes counted... > > One comment below regarding this... [snip] >> + >> + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ >> + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); > Also, I could not find that the reference manual states that ecc_count > represents the amount of flipped byte in a empty page. Is this given > by the ECC algorithm? I was using this information. Table 31-18. ECC Status Word Field Definition 7 0 Page has been successfully corrected CORFAIL 1 Page is uncorrectable 5?0 Number of errors that have been corrected in this page ERROR_COUNT This is from the Vybrid RM, but the MPC5125RM has the same information. I have definitely tested the detection of 'erased pages'. However, I don't know that I ever had actual bit flips. The ECC controller has no idea whether the page is empty or not. Are you saying you have an erased page with bit flips? I have definitely not tested this. >> + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ >> + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); There are two issues. 1) erased page with some physical flipped bits (zero). 2) erased page were controller flipped some bits. Currently, the code is only handling case 2 (that is what the controller counts). I believe that your physical page has actual 'stuck at zero' bits. The current driver gives up. If you want to handle this then we should replace the lines, > + /* ECC failed. */ > + if (flip > ecc_count) > + return -1; With something like, + /* Not completely empty. */ + if (flip > ecc_count) { + re_read_page_w_ecc_off(); + if (count_written_bits() > strength) /* strength/2 ? */ + return -1; + } There is also a discussion on this here, http://lists.infradead.org/pipermail/linux-mtd/2014-March/052507.html http://lists.infradead.org/pipermail/linux-mtd/2014-March/052508.html http://lists.infradead.org/pipermail/linux-mtd/2014-March/052509.html http://lists.infradead.org/pipermail/linux-mtd/2014-March/052526.html http://lists.infradead.org/pipermail/linux-mtd/2014-March/052527.html http://lists.infradead.org/pipermail/linux-mtd/2014-March/052619.html ... etc. Use the view thread. Especially, http://lists.infradead.org/pipermail/linux-mtd/2014-March/052647.html Here Brian says that 3b applies to SLC NAND. I guess this is you :). It is fairly common to read an erased page. Doing 'raw reads' all the time on an erased page will slow the file system. However, doing re-reads for an erased page with bit flips is probably fairly uncommon. A flash in this state maybe near EOL or the sector was bad from the factory but not marked so. I am chasing an DDR2 issue on another CPU and haven't had much more time to the look at the Vybrid nor follow the MTD mailing list. I don't know if the 'NAND_ECC_NEED_CHECK_FF' feature has been merged? It may also solve the issue. Regards, Bill Pringlemeir. From asierra at xes-inc.com Wed Sep 17 11:08:18 2014 From: asierra at xes-inc.com (Aaron Sierra) Date: Wed, 17 Sep 2014 13:08:18 -0500 (CDT) Subject: [PATCH 1/2] mtd: physmap_of: Fix ROM support via OF In-Reply-To: <1388169775.233775.1410977001530.JavaMail.zimbra@xes-inc.com> Message-ID: <1456841230.234377.1410977298299.JavaMail.zimbra@xes-inc.com> The "ROM" and unknown probe types within the obsolete "direct-mapped" probe function used the nonexistent "mtd_rom" probe instead of the intended "map_rom". Signed-off-by: Aaron Sierra --- drivers/mtd/maps/physmap_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 217c25d..63d82da 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev, if (strcmp(of_probe, "ROM") != 0) dev_warn(&dev->dev, "obsolete_probe: don't know probe " "type '%s', mapping as rom\n", of_probe); - return do_map_probe("mtd_rom", map); + return do_map_probe("map_rom", map); } } -- 1.9.1 From asierra at xes-inc.com Wed Sep 17 11:08:28 2014 From: asierra at xes-inc.com (Aaron Sierra) Date: Wed, 17 Sep 2014 13:08:28 -0500 (CDT) Subject: [PATCH 2/2] mtd: physmap_of: Add non-obsolete map_rom probe In-Reply-To: <1723729858.233869.1410977102931.JavaMail.zimbra@xes-inc.com> Message-ID: <850734862.234398.1410977308984.JavaMail.zimbra@xes-inc.com> Previously, the only way to map a NOR device as a simple ROM was to use the obsolete "direct-mapped" compatible binding (which further requires device_type = "nor" and probe-type = "NOR" properties). This patch adds an "mtd-rom" compatible binding to the "map_rom" probe type. Signed-off-by: Aaron Sierra --- Documentation/devicetree/bindings/mtd/mtd-physmap.txt | 4 ++-- drivers/mtd/maps/physmap_of.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 61c5ec8..6b9f680 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. - compatible : should contain the specific model of mtd chip(s) - used, if known, followed by either "cfi-flash", "jedec-flash" - or "mtd-ram". + used, if known, followed by either "cfi-flash", "jedec-flash", + "mtd-ram" or "mtd-rom". - reg : Address range(s) of the mtd chip(s) It's possible to (optionally) define multiple "reg" tuples so that non-identical chips can be described in one node. diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 63d82da..c1d21cb 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -340,6 +340,10 @@ static struct of_device_id of_flash_match[] = { .data = (void *)"map_ram", }, { + .compatible = "mtd-rom", + .data = (void *)"map_rom", + }, + { .type = "rom", .compatible = "direct-mapped" }, -- 1.9.1 From boris.brezillon at free-electrons.com Wed Sep 17 11:16:44 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Wed, 17 Sep 2014 20:16:44 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140917152609.GA2111@localhost.localdomain> References: <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> <20140911142511.GA2543@localhost.localdomain> <20140911163847.5e2f85c7@bbrezillon> <20140912004550.GB26904@shldeISGChi005.sh.intel.com> <20140912143050.014ad4c3@bbrezillon> <20140913153622.GA10132@localhost.localdomain> <20140913173841.GA18093@brian-ubuntu> <20140915144259.GA1947@localhost.localdomain> <20140915221210.5d9871fb@bbrezillon> <20140917152609.GA2111@localhost.localdomain> Message-ID: <20140917201644.43df2cd7@bbrezillon> Hi Huang, On Wed, 17 Sep 2014 23:26:11 +0800 Huang Shijie wrote: > On Mon, Sep 15, 2014 at 10:12:10PM +0200, Boris BREZILLON wrote: > > On Mon, 15 Sep 2014 22:43:02 +0800 > > Huang Shijie wrote: > > > > > On Sat, Sep 13, 2014 at 10:38:41AM -0700, Brian Norris wrote: > > > > On Sat, Sep 13, 2014 at 11:36:24PM +0800, Huang Shijie wrote: > > > > > On Fri, Sep 12, 2014 at 02:30:50PM +0200, Boris BREZILLON wrote: > > > > > > This test validates what's returned by ecc_strength file in sysfs > > > > > > (which in turn is specified by the NAND controller when initializing > > > > > > the NAND chip). > > > > > > > > > > > > Doing this should not imply knowing the ECC algorithm in use in the > > > > > > NAND controller or the layout used to store data on NAND. > > > > > the difficulty is that the ECC parity area can be not byte aligned. > > > > > > > > Is there a problem with just rounding up to the nearest byte alignment > > > > and ignoring the few bits that are wasted? > > > > > > I feel a little confused with the two hooks. > > > > > > does the ecc->write_page_raw need to write the ECC parity data? > > > > Depending on the oob_required argument, it might be allowed to > > overwrite the ECC bytes even if this implies breaking page reliability > > (which is exactly what's expected). > > > > When using raw write with with oob write option the writer should take > > care of regenerating ECC bytes (which you said was impossible in GPMI > > case) or copying them from a previous raw read. > Thanks for the explanation. > > If we do not write the OOB, should we write the ECC bytes? No we shouldn't, and if you take a look at my new proposal you'll see that I always write ECC bytes even when oob_required is not required, but this is not a problem because in this case the nand_base code has already set the oob area to 0xff and, if I'm correct, writing 0xff is just like leaving the area unwritten. Of course leaving the ECC bytes to 0xff after a page erase will certainly trigger ECC errors when reading the page back in normal mode, but this is the MTD user responsibility to know what he's doing. > The hooks should comment clearly about how to implement them :( Absolutely, and if we all agree on the expected behavior, I'll be happy to document it ;-). > > > > > Here is a real example of what one could test with raw write + oob: > > 1) read a page in raw mode > > 2) flip some bits in the generated ECC bytes (or what you references as > > parity data) (this case can actually happen in real life) > > 3) write the modified page in raw mode > > 4) read back the same page in normal and check that ECC correction still > > works as expected > the nandbiterr test mode does the test as above. > But i think the multi-writes to the same page should occur only for the > SLC nand. I already have a patch for that :-): http://code.bulix.org/f69wuu-87021 This patch is erasing the NAND block between each bitflip insertion so that it can work on MLC nandflashes too. Anyway, IMHO this nandbiterrs testsuite should be implemented in a user-space tool (which could be part of mtd-utils) because we already have all the primitives we need to do it from there (ioctls to access NAND chips in raw mode). > > I will read your new patch set carefully in this weekend. Thanks. Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From stefan at agner.ch Wed Sep 17 13:08:04 2014 From: stefan at agner.ch (Stefan Agner) Date: Wed, 17 Sep 2014 22:08:04 +0200 Subject: [RFC 2/5] =?UTF-8?Q?mtd=3Afsl=5Fnfc=3A=20Add=20hardware=20=34?= =?UTF-8?Q?=35=20byte=20BHC-ECC=20support=20for=20=32=34=20bit=20correctio?= =?UTF-8?Q?ns=2E?= In-Reply-To: <87r3zaxgtr.fsf@nbsps.com> References: <87siupheou.fsf@nbsps.com> <1389222441-4322-1-git-send-email-bpringlemeir@nbsps.com> <1389222441-4322-3-git-send-email-bpringlemeir@nbsps.com> <127db6b73356442d2ba12e8c011038cc@agner.ch> <87r3zaxgtr.fsf@nbsps.com> Message-ID: Am 2014-09-17 20:06, schrieb Bill Pringlemeir: > On 17 Sep 2014, stefan at agner.ch wrote: > >> On one of our Colibri VF61 modules I discovered an issue using this >> driver: > >> [ 0.758327] ECC failed to correct all errors (ebd9fd80) >> [ 0.767005] ECC failed to correct all errors (ebd9fd80) >> [ 0.775525] ECC failed to correct all errors (ebd9fd80) >> [ 0.784004] ECC failed to correct all errors (ebd9fd80) >> [ 0.791938] UBI error: ubi_io_read: error -74 (ECC error) while >> reading 2048 bytes from PEB 28:2048, >> read 2048 bytes > >> That page supposed to be empty, and I got several of this messages. >> Hence I did not believe that they have really ECC errors, so I digged >> a bit deeper: > >>>> -673,11 +673,13 @@ static int fsl_nfc_check_ecc_status(struct >> mtd_info *mtd, u_char *dat) >> return ecc_count; > >> /* If 'ecc_count' zero or less then buffer is all 0xff or >> erased. */ >> - flip = count_written_bits(dat, chip->ecc.size, ecc_count); >> + flip = count_written_bits(dat, chip->ecc.size, 100); > >> if (flip > ecc_count) { >> - printk("ECC failed to correct all errors (%08x)\n", >> ecc_status); >> + printk("ECC failed to correct all errors (%08x, flips >> %d)\n", >> + ecc_status, flip); >> return -1; >> } > >> [ 0.758624] ECC failed to correct all errors (ebdded80, flips 1) >> [ 0.768123] ECC failed to correct all errors (ebdded80, flips 1) >> [ 0.777468] ECC failed to correct all errors (ebdded80, flips 1) >> [ 0.786773] ECC failed to correct all errors (ebdded80, flips 1) >> [ 0.795535] UBI error: ubi_io_read: error -74 (ECC error) while >> reading 2048 bytes from PEB 28:2048, read 2048 bytes > > [snip] > >> Interesting thought, the returned ecc_count is exactly one below the >> actual flipped bytes counted... >> >> One comment below regarding this... > > [snip] > >>> + >>> + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ >>> + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); > >> Also, I could not find that the reference manual states that ecc_count >> represents the amount of flipped byte in a empty page. Is this given >> by the ECC algorithm? > > I was using this information. > > Table 31-18. ECC Status Word Field Definition > > 7 0 Page has been successfully corrected > CORFAIL 1 Page is uncorrectable > > 5?0 Number of errors that have been corrected in this page > ERROR_COUNT > > This is from the Vybrid RM, but the MPC5125RM has the same information. > > I have definitely tested the detection of 'erased pages'. However, I > don't know that I ever had actual bit flips. > > The ECC controller has no idea whether the page is empty or not. Are > you saying you have an erased page with bit flips? I have definitely > not tested this. Yes, that's what it looks like. Note that this output is on first boot after flashing the device (with the UBI auto-grow option). I guess UBI is reading all pages once to verify that they are empty. >>> + /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */ >>> + flip = count_written_bits(dat, nfc->chip.ecc.size, ecc_count); > > There are two issues. > > 1) erased page with some physical flipped bits (zero). > 2) erased page were controller flipped some bits. I did not know that issue 2 exists. How can 2 happen on a erased page? With a 'stuck at zero' in OOB? > Currently, the code is only handling case 2 (that is what the controller > counts). I believe that your physical page has actual 'stuck at zero' > bits. The current driver gives up. If you want to handle this then we > should replace the lines, > I assumed that your code assumes that the controller returns the flipped bit count when reading an erase page (case 1), which I did not found in the documentation. >> + /* ECC failed. */ >> + if (flip > ecc_count) >> + return -1; > > With something like, > > + /* Not completely empty. */ > + if (flip > ecc_count) { > + re_read_page_w_ecc_off(); > + if (count_written_bits() > strength) /* strength/2 ? */ > + return -1; > + } > > There is also a discussion on this here, > > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052507.html > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052508.html > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052509.html > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052526.html > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052527.html > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052619.html > ... etc. Use the view thread. > > Especially, > http://lists.infradead.org/pipermail/linux-mtd/2014-March/052647.html > > Here Brian says that 3b applies to SLC NAND. I guess this is you :). Yes, we are using Macronix SLC NAND. > > It is fairly common to read an erased page. Doing 'raw reads' all the > time on an erased page will slow the file system. However, doing > re-reads for an erased page with bit flips is probably fairly uncommon. > A flash in this state maybe near EOL or the sector was bad from the > factory but not marked so. This is a new device, but its one out of several dozens. The device had two factory marked bad page. This four page would then be 6 bad pages. I would say that your guess is probably the case at hand (should be considered bad, but were marked by factory). > > I am chasing an DDR2 issue on another CPU and haven't had much more time > to the look at the Vybrid nor follow the MTD mailing list. I don't know > if the 'NAND_ECC_NEED_CHECK_FF' feature has been merged? It may also > solve the issue. A quick search through 3.17-rc3 didn't found that string. I will read the pages using raw again and check how many bit flips it shows. But I guess regarding Brian's comment to 3b, the driver actually behaves correct and return -1, because we have bit flips on erased page which is not good... UBI starts to scrub & torture those 4 pages then, but starts doing this with other pages too. All the pages start to fail then! I'm still investigating that issue. [ 30.901345] UBI: scrubbed PEB 1436 (LEB 0:356), data moved to PEB 3965 [ 31.100247] UBI: run torture test for PEB 1436 [ 31.280845] UBI error: torture_peb: read problems on freshly erased PEB 1436, must be bad [ 31.300656] UBI error: erase_worker: failed to erase PEB 1436, error -5 [ 31.312626] UBI: mark PEB 1436 as bad [ 31.338216] UBI: 12 PEBs left in the reserve [ 31.519044] UBI: scrubbed PEB 1390 (LEB 0:313), data moved to PEB 3963 [ 31.697812] UBI: run torture test for PEB 1390 [ 31.880470] UBI error: torture_peb: read problems on freshly erased PEB 1390, must be bad [ 31.898220] UBI error: erase_worker: failed to erase PEB 1390, error -5 [ 31.909687] UBI: mark PEB 1390 as bad [ 31.931620] UBI: 11 PEBs left in the reserve [ 32.170599] UBI: scrubbed PEB 1470 (LEB 0:389), data moved to PEB 3961 [ 32.344564] UBI: run torture test for PEB 1470 [ 32.522842] UBI error: torture_peb: read problems on freshly erased PEB 1470, must be bad [ 32.540587] UBI error: erase_worker: failed to erase PEB 1470, error -5 [ 32.552060] UBI: mark PEB 1470 as bad From rfreire at redhat.com Wed Sep 17 13:18:33 2014 From: rfreire at redhat.com (Rodrigo Freire) Date: Wed, 17 Sep 2014 16:18:33 -0400 (EDT) Subject: [PATCH] block2mtd: mtd: Present block2mtd timely on boot time In-Reply-To: <20140909170231.GA14429@logfs.org> References: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> <20140909170231.GA14429@logfs.org> Message-ID: <1761405154.40124217.1410985113708.JavaMail.zimbra@redhat.com> Hi J?rn, ----- Original Message ----- From: "J?rn Engel" > On Mon, 8 September 2014 16:04:40 -0400, Rodrigo Freire wrote: > > > > @@ -257,13 +281,15 @@ static struct block2mtd_dev *add_device( > > > > /* Setup the MTD structure */ > > /* make the name contain the block device in */ > > - name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); > > + if (!mtdname) > > + mtdname = devname; > > + name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL); > > if (!name) > > goto err_destroy_mutex; > > > > + strcpy(name, mtdname); > kstrdup. > And see below for the ABI change. Thanks for pointing. Fixed. > > dev->mtd.name = name; > > - > > - dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; > > + dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1); > > PAGE_MASK is no longer needed with the new term. Or does anyone > seriously want to support erase_size < PAGE_SIZE? Makes sense. I was talking to Felix and indeed there are some MTD devices which have 4k erase page size. Unheard of something smaller. But it is on the MTD land and not block2mtd. > Timeout has a default value, but name defaults to NULL. Add three > devices without specifying the name and you get funny results. > If we handled the NULL case by doing what the driver used to do before > this patch, I think this would be fine. Please see the fragment below: @@ -257,13 +281,15 @@ static struct block2mtd_dev *add_device( /* Setup the MTD structure */ /* make the name contain the block device in */ - name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); + if (!mtdname) + mtdname = devname; + name = kstrdup(mtdname, GFP_KERNEL); if (!name) goto err_destroy_mutex; If the name is a NULL or not provided, the mtdname will then become the mtd device name. I also tried mounting several partitions, with both specified name and not and everything seemed to work nicely. See a V2 patch on the next message. From rfreire at redhat.com Wed Sep 17 13:28:03 2014 From: rfreire at redhat.com (Rodrigo Freire) Date: Wed, 17 Sep 2014 16:28:03 -0400 (EDT) Subject: [PATCH V2] mtd: block2mtd: Present block2mtd timely on boot time In-Reply-To: <20140909170231.GA14429@logfs.org> References: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> <20140909170231.GA14429@logfs.org> Message-ID: <1807144344.40128259.1410985683342.JavaMail.zimbra@redhat.com> From: Felix Fietkau mtd: block2mtd: Ensure that block2mtd is presented in a timely fashion Currently, a block MTD device is not presented to the system on time, in order to start mounting the filesystems. This patch ensures that block2mtd is presented at the right time, so filesystems can be mounted on boot time. This issue was seen on BCM2835 (Raspberry Pi) systems when mounting JFFS2 block2mtd filesystems. This patchset also adds a MTD device name and a timeout option to the driver. Original patchset: https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/440-block2mtd_init.patch?rev=40444 https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.12/441-block2mtd_probe.patch?rev=40444 Signed-off-by: Felix Fietkau Signed-off-by: Rodrigo Freire Signed-off-by: Herton Krzesinski --- V2: Uses kstrdup, removed PAGE_MASK. --- a/drivers/mtd/devices/block2mtd.c 2014-09-16 21:38:12.543952627 -0300 +++ b/drivers/mtd/devices/block2mtd.c 2014-09-17 17:43:21.424944394 -0300 @@ -9,7 +9,15 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* +* When the first attempt at device initialization fails, we may need to +* wait a little bit and retry. This timeout, by default 3 seconds, gives +* device time to start up. Required on BCM2708 and a few other chipsets. +*/ +#define MTD_DEFAULT_TIMEOUT 3 + #include +#include #include #include #include @@ -17,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -209,12 +218,14 @@ static void block2mtd_free_device(struct } -static struct block2mtd_dev *add_device(char *devname, int erase_size) +static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname, int timeout) { const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev; + struct block_device *bdev = ERR_PTR(-ENODEV); struct block2mtd_dev *dev; + struct mtd_partition *part; char *name; + int i; if (!devname) return NULL; @@ -225,15 +236,28 @@ static struct block2mtd_dev *add_device( /* Get a handle on the device */ bdev = blkdev_get_by_path(devname, mode, dev); -#ifndef MODULE - if (IS_ERR(bdev)) { - /* We might not have rootfs mounted at this point. Try - to resolve the device name by other means. */ - - dev_t devt = name_to_dev_t(devname); - if (devt) - bdev = blkdev_get_by_dev(devt, mode, dev); +#ifndef MODULE +/* +* We might not have the root device mounted at this point. +* Try to resolve the device name by other means. +*/ + for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { + dev_t devt; + + if (i) + /* + * Calling wait_for_device_probe in the first loop + * was not enough, sleep for a bit in subsequent + * go-arounds. + */ + msleep(1000); + wait_for_device_probe(); + + devt = name_to_dev_t(devname); + if (!devt) + continue; + bdev = blkdev_get_by_dev(devt, mode, dev); } #endif @@ -257,13 +281,14 @@ static struct block2mtd_dev *add_device( /* Setup the MTD structure */ /* make the name contain the block device in */ - name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname); + if (!mtdname) + mtdname = devname; + name = kstrdup (mtdname, GFP_KERNEL); if (!name) goto err_destroy_mutex; dev->mtd.name = name; - - dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; + dev->mtd.size = dev->blkdev->bd_inode->i_size & ~(erase_size - 1); dev->mtd.erasesize = erase_size; dev->mtd.writesize = 1; dev->mtd.writebufsize = PAGE_SIZE; @@ -276,15 +301,19 @@ static struct block2mtd_dev *add_device( dev->mtd.priv = dev; dev->mtd.owner = THIS_MODULE; - if (mtd_device_register(&dev->mtd, NULL, 0)) { + part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); + part->name = name; + part->offset = 0; + part->size = dev->mtd.size; + if (mtd_device_register(&dev->mtd, part, 1)) { /* Device didn't get added, so free the entry */ goto err_destroy_mutex; } + list_add(&dev->list, &blkmtd_device_list); pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", dev->mtd.index, - dev->mtd.name + strlen("block2mtd: "), - dev->mtd.erasesize >> 10, dev->mtd.erasesize); + mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize); return dev; err_destroy_mutex: @@ -353,11 +382,12 @@ static char block2mtd_paramline[80 + 12] static int block2mtd_setup2(const char *val) { - char buf[80 + 12]; /* 80 for device, 12 for erase size */ + char buf[80 + 12 + 80 + 8]; /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ char *str = buf; - char *token[2]; + char *token[4]; char *name; size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { @@ -368,7 +398,7 @@ static int block2mtd_setup2(const char * strcpy(str, val); kill_final_newline(str); - for (i = 0; i < 2; i++) + for (i = 0; i < 4; i++) token[i] = strsep(&str, ","); if (str) { @@ -395,7 +425,13 @@ static int block2mtd_setup2(const char * } } - add_device(name, erase_size); + if (token[2] && (strlen(token[2]) + 1 > 80)) + pr_err("mtd device name too long"); + + + if (token[3] && kstrtoul(token[3], 0, &timeout)) + pr_err("invalid timeout"); + add_device(name, erase_size, token[2], timeout); return 0; } @@ -429,7 +465,7 @@ static int block2mtd_setup(const char *v module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200); -MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,]\""); +MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=[,[,[,]]]\""); static int __init block2mtd_init(void) { @@ -463,8 +499,7 @@ static void block2mtd_exit(void) } } - -module_init(block2mtd_init); +late_initcall(block2mtd_init); module_exit(block2mtd_exit); MODULE_LICENSE("GPL"); --- 1.7.1 From ezequiel at vanguardiasur.com.ar Wed Sep 17 14:21:37 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Wed, 17 Sep 2014 22:21:37 +0100 Subject: [PATCH V2] mtd: block2mtd: Present block2mtd timely on boot time In-Reply-To: <1807144344.40128259.1410985683342.JavaMail.zimbra@redhat.com> References: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> <20140909170231.GA14429@logfs.org> <1807144344.40128259.1410985683342.JavaMail.zimbra@redhat.com> Message-ID: On 17 September 2014 21:28, Rodrigo Freire wrote: > > mtd: block2mtd: Ensure that block2mtd is presented in a timely fashion > Using block2mtd sounds a bit unusual. I see that you are trying to get a more robust fs.... have you tried using f2fs instead of jffs2? > Currently, a block MTD device is not presented to the system on time, in > order to start mounting the filesystems. This patch ensures that block2mtd > is presented at the right time, so filesystems can be mounted on boot time. It worries me a bit to add such a long delay to the boot. If for some reason the SD is not working, then the kernel will wait (by default) 3 seconds now? -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From rfreire at redhat.com Wed Sep 17 14:41:54 2014 From: rfreire at redhat.com (Rodrigo Freire) Date: Wed, 17 Sep 2014 17:41:54 -0400 (EDT) Subject: [PATCH V2] mtd: block2mtd: Present block2mtd timely on boot time In-Reply-To: References: <371358190.34795877.1410204429882.JavaMail.zimbra@redhat.com> <1444809468.34812041.1410206680931.JavaMail.zimbra@redhat.com> <20140909170231.GA14429@logfs.org> <1807144344.40128259.1410985683342.JavaMail.zimbra@redhat.com> Message-ID: <86761077.40163293.1410990114756.JavaMail.zimbra@redhat.com> Holas Ezequiel, ----- Original Message ----- From: "Ezequiel Garcia" > On 17 September 2014 21:28, Rodrigo Freire wrote: > > Using block2mtd sounds a bit unusual. I see that you are trying to get > a more robust fs.... have you tried using f2fs instead of jffs2? I see that it is still marked as Experimental as of latest (3.17-RC5) kernel. But will take a look in the future, thanks for pointing. > > Currently, a block MTD device is not presented to the system on time, in > > order to start mounting the filesystems. This patch ensures that block2mtd > > is presented at the right time, so filesystems can be mounted on boot time. > > It worries me a bit to add such a long delay to the boot. If for some > reason the SD is not working, then the kernel will wait (by default) 3 > seconds now? Not really; see the decision path: IF block2mtd is not a module (is builtin), AND IF there is a valid block2mtd= clause on kernel cmdline, AND IF the device specified device on block2mtd= clause is still not present THEN wait *up to* 3 seconds (or seconds=n if specified on block2mtd= cmdline) to the device to show up. If the device shows up earlier, the device is created and boot proceeds. ELSE Fail to create the block2mtd device. ELSE keep booting the kernel normally, without any further delays. Best regards, - RF. From RHurdle at Rugged.com Wed Sep 17 14:59:22 2014 From: RHurdle at Rugged.com (Robert Hurdle) Date: Wed, 17 Sep 2014 14:59:22 -0700 Subject: Question about adding a NAND device Message-ID: <5498E86A4A68B14A8A06D0380640D04A01FA6854E73D@atca01em01.adsi.aitech.ent> Hello, I have ported some of u-boot to our board, and I am booting successfully from EEPROM. I am now in the process of adding the NAND and flash file system support for our non-standard flash interface (there's an FPGA interface between the software and the 1 giga-byte NAND) to u-boot and also to the Linux kernel. In addition, it is our intention to support UBIFS on our board. It appears that I need to understand how the structures mtd_info and nand_chip (and whatever they point at) and code in nand_base.c work, in order to provide working routines at the NAND level. I have looked at some of the files in u-boot/drivers/mtd/nand for other boards, and see a wide variety of models, no doubt based on the hardware differences. Because of our FPGA interface, I need to have all commands to the NAND chip get re-packaged into commands that get passed to the FPGA. Am I on the right path? My other question is how long would one guess that this task would take for someone fairly competent, but uninitiated in UBIFS, UBI, MTD, NAND, etc. ? Any advice is appreciated. Thank you, Robert Hurdle Aitech Defense Systems (Space Division) From bpringlemeir at nbsps.com Wed Sep 17 15:21:35 2014 From: bpringlemeir at nbsps.com (Bill Pringlemeir) Date: Wed, 17 Sep 2014 18:21:35 -0400 Subject: [RFC 2/5] mtd:fsl_nfc: Add hardware 45 byte BHC-ECC support for 24 bit corrections. In-Reply-To: (Stefan Agner's message of "Wed, 17 Sep 2014 22:08:04 +0200") References: <87siupheou.fsf@nbsps.com> <1389222441-4322-1-git-send-email-bpringlemeir@nbsps.com> <1389222441-4322-3-git-send-email-bpringlemeir@nbsps.com> <127db6b73356442d2ba12e8c011038cc@agner.ch> <87r3zaxgtr.fsf@nbsps.com> Message-ID: <87lhphyjkg.fsf@nbsps.com> On 17 Sep 2014, stefan at agner.ch wrote: > Am 2014-09-17 20:06, schrieb Bill Pringlemeir: >> On 17 Sep 2014, stefan at agner.ch wrote: >>> On one of our Colibri VF61 modules I discovered an issue using this >>> driver: >>> [ 0.758327] ECC failed to correct all errors (ebd9fd80) >>> [ 0.767005] ECC failed to correct all errors (ebd9fd80) >>> [ 0.775525] ECC failed to correct all errors (ebd9fd80) >>> [ 0.784004] ECC failed to correct all errors (ebd9fd80) >>> [ 0.791938] UBI error: ubi_io_read: error -74 (ECC error) while >>> reading 2048 bytes from PEB 28:2048, >>> read 2048 bytes [snip] >>> Also, I could not find that the reference manual states that >>> ecc_count represents the amount of flipped byte in a empty page. Is >>> this given by the ECC algorithm? >> I was using this information. >> >> Table 31-18. ECC Status Word Field Definition >> >> 7 0 Page has been successfully corrected >> CORFAIL 1 Page is uncorrectable >> >> 5?0 Number of errors that have been corrected in this page >> ERROR_COUNT >> >> This is from the Vybrid RM, but the MPC5125RM has the same >> information. >> >> I have definitely tested the detection of 'erased pages'. However, I >> don't know that I ever had actual bit flips. >> The ECC controller has no idea whether the page is empty or not. Are >> you saying you have an erased page with bit flips? I have definitely >> not tested this. > Yes, that's what it looks like. Note that this output is on first boot > after flashing the device (with the UBI auto-grow option). I guess UBI > is reading all pages once to verify that they are empty. >>>> + /* If 'ecc_count' zero or less then buffer is all 0xff or >>>> erased. */ + flip = count_written_bits(dat, nfc->chip.ecc.size, >>>> ecc_count); >> >> There are two issues. >> >> 1) erased page with some physical flipped bits (zero). >> 2) erased page were controller flipped some bits. > I did not know that issue 2 exists. How can 2 happen on a erased page? > With a 'stuck at zero' in OOB? Issue 2 is always an issue when reading an erased page with hardware ECC. So we have, Main Spare Good program: Data OOB-data+HW-ECC Good erased: FF FF FF Stuck erased1: FF FF xx Stuck erased2: xx xx FF For the 'good erased' the controller goes about like it is case 'good program'. It reads a sector (raw read or software ECC case) and a the same time, the error corrector is running. This examines the 'OOB data', which is 0xff for the erased sector and it blindly begins to apply the error correction to the main data section. The 'correction' for an erased block will always flip '1' to '0'. So for 'good erased', the 'error_count' will equal the flipped bits. Now, your sectors aren't that bad. I believe you only have one bit error on an erase. However, it is really hairy to know what the ECC logic will do when you have bit flips in the ECC code. It is also next to impossible to examine the buffer and know if zero bits are due to the ECC engine flipping the bits and/or the actual physical flash having the stuck bit. It appears that the ECC engine runs from start to finish. So most of the ECC corrections should be at the start; use this info for diagnostics, but not coding! The best course IMHO is to do what Brian (and other) did and do a 'raw' read, so you take the ECC engine out of the picture and stop it from flipping bits. You can experiment with always doing the raw read, but I believe you will see a decrease in performance (as others mentioned and I saw). >> Currently, the code is only handling case 2 (that is what the >> controller counts). I believe that your physical page has actual >> 'stuck at zero' bits. The current driver gives up. If you want to >> handle this then we should replace the lines, > I assumed that your code assumes that the controller returns the > flipped bit count when reading an erase page (case 1), which I did not > found in the documentation. >>> + /* ECC failed. */ >>> + if (flip > ecc_count) >>> + return -1; >> With something like, >> >> + /* Not completely empty. */ >> + if (flip > ecc_count) { >> + re_read_page_w_ecc_off(); >> + if (count_written_bits() > strength) /* strength/2 ? */ >> + return -1; >> + } >> >> There is also a discussion on this here, >> >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052507.html >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052508.html >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052509.html >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052526.html >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052527.html >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052619.html >> ... etc. Use the view thread. >> >> Especially, >> http://lists.infradead.org/pipermail/linux-mtd/2014-March/052647.html >> >> Here Brian says that 3b applies to SLC NAND. I guess this is you :). > Yes, we are using Macronix SLC NAND. Well, it is everyone. Sorry, I made the assumption this wouldn't happen, but apparently it does. >> It is fairly common to read an erased page. Doing 'raw reads' all >> the time on an erased page will slow the file system. However, doing >> re-reads for an erased page with bit flips is probably fairly >> uncommon. A flash in this state maybe near EOL or the sector was bad >> from the factory but not marked so. > This is a new device, but its one out of several dozens. The device > had two factory marked bad page. This four page would then be 6 bad > pages. I would say that your guess is probably the case at hand > (should be considered bad, but were marked by factory). >> I am chasing an DDR2 issue on another CPU and haven't had much more >> time to the look at the Vybrid nor follow the MTD mailing list. I >> don't know if the 'NAND_ECC_NEED_CHECK_FF' feature has been merged? >> It may also solve the issue. > > A quick search through 3.17-rc3 didn't found that string. > I will read the pages using raw again and check how many bit flips it > shows. But I guess regarding Brian's comment to 3b, the driver > actually behaves correct and return -1, because we have bit flips on > erased page which is not good... Hmm. No, it should be ok; I think Brian meant we should accept and expect this. We had this conversation after the RFC. However, we should probably only accept strength/2 zero values at most; I believe what to accept was kind of hanging in that conversation. If the zeros are below our threshold with a raw read, then we can report the page is all '\xff' and return a 'bit flip' count as the number of zeros found in a raw read. Also, in the 'all FFs' case we should probably memset the OOB data. I see that other patches mentioned in the MTD threads above do this. + /* Not completely empty. */ + if (flip > ecc_count) { + re_read_page_w_ecc_off(); + ecc_count = count_zero_bits(); + if (ecc_count > strength/2) + return -1; + } else + ecc_count = 0; /* 'normal' case all ff */ + + /* Erased page. */ + memset(dat, 0xff, nfc->chip.ecc.size); + memset(oob, 0xff, ???); /* ??? */ + return ecc_count; I don't think that UBI/UbiFs use the OOB data at all, but that is something that I don't think is completely correct in this path? > UBI starts to scrub & torture those 4 pages then, but starts doing > this with other pages too. All the pages start to fail then! I'm still > investigating that issue. Arg. I am not quite sure. It seems ok to have a few 'stuck at one' errors. As you move closer to the ECC strength this seems a little crazy. At some point the sector/erase block is becoming useless. I am not sure if this is an issue with this device; it seems a little suspect. Maybe you could code something that emulates the stuck bits on a good device and see if it still behaves the same; triggers a software condition. You might also reduce the NFC bus clock just to see on the 'stuck zero' device. Hth, Bill Pringlemeir. From computersforpeace at gmail.com Wed Sep 17 17:32:58 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 17:32:58 -0700 Subject: [PATCH v2] mtd: atmel_nand: make PMECC lookup table and offset property optional In-Reply-To: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> References: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> Message-ID: <20140918003258.GD1193@ld-irv-0074> On Mon, Aug 18, 2014 at 03:08:40PM +0800, Josh Wu wrote: > If there is no PMECC lookup table stored in ROM, or lookup table offset is > not specified, PMECC driver should build it in DDR by itself. > > That make the PMECC driver work for some board which doesn't has PMECC > lookup table in ROM. > > Signed-off-by: Josh Wu > Cc: devicetree at vger.kernel.org > --- > This patch is based on mtd-l2/next branch > > v1 -> v2: > make create_lookup_table() static. sparse gives me several new complaints: +drivers/mtd/nand/atmel_nand.c:1219:50: warning: incorrect type in argument 2 (different signedness) [sparse] +drivers/mtd/nand/atmel_nand.c:1219:50: expected signed short [usertype] *index_of [sparse] +drivers/mtd/nand/atmel_nand.c:1219:50: got unsigned short [usertype] *addr [sparse] +drivers/mtd/nand/atmel_nand.c:1219:61: warning: incorrect type in argument 3 (different signedness) [sparse] +drivers/mtd/nand/atmel_nand.c:1219:61: expected signed short [usertype] *alpha_to [sparse] +drivers/mtd/nand/atmel_nand.c:1219:61: got unsigned short [usertype] * [sparse] +drivers/mtd/nand/atmel_nand.c:1292:38: warning: incorrect type in assignment (different address spaces) [sparse] +drivers/mtd/nand/atmel_nand.c:1292:38: expected void [noderef] *pmecc_rom_base [sparse] +drivers/mtd/nand/atmel_nand.c:1292:38: got unsigned short [usertype] *[assigned] galois_table [sparse] The third one might be a false positive. I suppose it's safe to use regular memory with __iomem accessors (but not vice versa). > .../devicetree/bindings/mtd/atmel-nand.txt | 6 +- > drivers/mtd/nand/atmel_nand.c | 136 ++++++++++++++++++++- > 2 files changed, 136 insertions(+), 6 deletions(-) > > diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > index c472883..75d1847 100644 > --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt > +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt > @@ -5,7 +5,9 @@ Required properties: > - reg : should specify localbus address and size used for the chip, > and hardware ECC controller if available. > If the hardware ECC is PMECC, it should contain address and size for > - PMECC, PMECC Error Location controller and ROM which has lookup tables. > + PMECC and PMECC Error Location controller. > + The PMECC lookup table address and size in ROM is optional. If not > + specified, driver will build it in runtime. > - atmel,nand-addr-offset : offset for the address latch. > - atmel,nand-cmd-offset : offset for the command latch. > - #address-cells, #size-cells : Must be present if the device has sub-nodes > @@ -27,7 +29,7 @@ Optional properties: > are: 512, 1024. > - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM > for different sector size. First one is for sector size 512, the next is for > - sector size 1024. > + sector size 1024. If not specified, driver will build the table in runtime. > - nand-bus-width : 8 or 16 bus width if not present 8 > - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false > - Nand Flash Controller(NFC) is a slave driver under Atmel nand flash > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index effa7a29..84af313 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -124,6 +124,7 @@ struct atmel_nand_host { > bool has_pmecc; > u8 pmecc_corr_cap; > u16 pmecc_sector_size; > + bool has_no_lookup_table; > u32 pmecc_lookup_table_offset; > u32 pmecc_lookup_table_offset_512; > u32 pmecc_lookup_table_offset_1024; > @@ -1109,12 +1110,121 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, > return 0; > } > > +static int pmecc_build_galois_table(int mm, > + int16_t *index_of, int16_t *alpha_to) > +{ > + unsigned int i, mask, nn; > + unsigned int p[PMECC_GF_DIMENSION_14 + 1]; > + > + nn = (1 << mm) - 1; > + /* set default value */ > + for (i = 1; i < mm; i++) > + p[i] = 0; > + > + /* 1 + X^mm */ > + p[0] = 1; > + p[mm] = 1; > + > + /* others */ > + switch (mm) { > + case 3: > + case 4: > + case 6: > + case 15: > + p[1] = 1; > + break; > + case 5: > + case 11: > + p[2] = 1; > + break; > + case 7: > + case 10: > + p[3] = 1; > + break; > + case 8: > + p[2] = p[3] = p[4] = 1; > + break; > + case 9: > + p[4] = 1; > + break; > + case 12: > + p[1] = p[4] = p[6] = 1; > + break; > + case 13: > + p[1] = p[3] = p[4] = 1; > + break; > + case 14: > + p[1] = p[6] = p[10] = 1; > + break; > + default: > + /* Error */ > + return -EINVAL; > + } > + > + /* Build alpha ^ mm it will help to generate the field (primitiv) */ > + alpha_to[mm] = 0; > + for (i = 0; i < mm; i++) > + if (p[i]) > + alpha_to[mm] |= 1 << i; > + > + /* > + * Then build elements from 0 to mm - 1. As degree is less than mm > + * so it is just a logical shift. > + */ > + mask = 1; > + for (i = 0; i < mm; i++) { > + alpha_to[i] = mask; > + index_of[alpha_to[i]] = i; > + mask <<= 1; > + } > + > + index_of[alpha_to[mm]] = mm; > + > + /* use a mask to select the MSB bit of the LFSR */ > + mask >>= 1; > + > + /* then finish the building */ > + for (i = mm + 1; i <= nn; i++) { > + /* check if the msb bit of the lfsr is set */ > + if (alpha_to[i - 1] & mask) > + alpha_to[i] = alpha_to[mm] ^ > + ((alpha_to[i - 1] ^ mask) << 1); > + else > + alpha_to[i] = alpha_to[i - 1] << 1; > + > + index_of[alpha_to[i]] = i % nn; > + } > + > + /* index of 0 is undefined in a multiplicative field */ > + index_of[0] = -1; > + > + return 0; > +} Is this algorithm documented? How did you come up with this? > + > +static uint16_t *create_lookup_table(struct device *dev, int sector_size) > +{ > + int table_size = (sector_size == 512) ? > + PMECC_LOOKUP_TABLE_SIZE_512 : > + PMECC_LOOKUP_TABLE_SIZE_1024; > + int degree = (sector_size == 512) ? > + PMECC_GF_DIMENSION_13 : > + PMECC_GF_DIMENSION_14; > + uint16_t *addr = devm_kzalloc(dev, 2 * table_size * sizeof(uint16_t), > + GFP_KERNEL); > + > + if (addr) > + pmecc_build_galois_table(degree, addr, addr + table_size); > + > + return addr; > +} > + > static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > struct atmel_nand_host *host) > { > struct mtd_info *mtd = &host->mtd; > struct nand_chip *nand_chip = &host->nand_chip; > struct resource *regs, *regs_pmerr, *regs_rom; > + uint16_t *galois_table; > int cap, sector_size, err_no; > > err_no = pmecc_choose_ecc(host, &cap, §or_size); > @@ -1160,8 +1270,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); > host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); > if (IS_ERR(host->pmecc_rom_base)) { > - err_no = PTR_ERR(host->pmecc_rom_base); > - goto err; > + if (!host->has_no_lookup_table) > + /* Don't display the information again */ > + dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); > + > + host->has_no_lookup_table = true; > + } > + > + if (host->has_no_lookup_table) { > + /* Build the look-up table in runtime */ > + galois_table = create_lookup_table(host->dev, sector_size); > + if (!galois_table) { > + dev_err(host->dev, "Failed to build a lookup table in runtime!\n"); > + err_no = -ENOMEM; > + goto err; > + } > + > + host->pmecc_rom_base = galois_table; > + host->pmecc_lookup_table_offset = 0; > } > > nand_chip->ecc.size = sector_size; > @@ -1498,8 +1624,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host, > > if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", > offset, 2) != 0) { > - dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); > - return -EINVAL; > + dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n"); > + host->has_no_lookup_table = true; > + /* Will build a lookup table and initialize the offset later */ > + return 0; > } > if (!offset[0] && !offset[1]) { > dev_err(host->dev, "Invalid PMECC lookup table offset\n"); Brian From yamada.m at jp.panasonic.com Wed Sep 17 19:31:35 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Thu, 18 Sep 2014 11:31:35 +0900 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140917171308.GC1193@ld-irv-0074> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> <20140917171308.GC1193@ld-irv-0074> Message-ID: <20140918113135.70D0.AA925319@jp.panasonic.com> Hi Brian, On Wed, 17 Sep 2014 10:13:08 -0700 Brian Norris wrote: > On Tue, Sep 16, 2014 at 08:04:18PM +0900, Masahiro Yamada wrote: > > > > > > Masahiro Yamada (7): > > mtd: denali: fix the format of comment blocks > > mtd: denali: remove unnecessary variable initializations > > mtd: denali: remove unnecessary casts > > mtd: denali: change the type of iterators to int > > mtd: denali: remove a set-but-unused variable > > mtd: denali: remove unnecessary parentheses > > mtd: denali: fix indents and other trivial things > > This series still doesn't apply to l2-mtd.git. > > Brian I resent the last three patches as v3. v3 5/7 mtd: denali: remove a set-but-unused variable v3 6/7 mtd: denali: remove unnecessary parentheses v3 7/7 mtd: denali: fix indents and other trivial things I confirmed they are applicable onto commit 93e3c8adf6fcf2204ca334237b92c7f8cdafce6f of l2-mtd.git You said as follow: On Mon, 15 Sep 2014 22:07:32 -0700 Brian Norris wrote: > > Is there a chance for me to resend 5/7 to include this fix? > > Or is it too late? > > Just send a new patch, please. That's why I sent a new patch (v3 5/7) to replace commit 55ab9ec99bbfb4450dfa9bc0fd9e2c5052f4c3f7 Did I do wrong? Best Regards Masahiro Yamada From computersforpeace at gmail.com Wed Sep 17 19:54:47 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 19:54:47 -0700 Subject: [PATCH 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: References: <1410033389-32357-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410033389-32357-3-git-send-email-ezequiel@vanguardiasur.com.ar> <540D6CAB.7020501@ti.com> <540D8A92.2040209@ti.com> <20140910124849.GA25308@arch.hh.imgtec.org> <54104CB4.4020703@ti.com> <20140917083353.GB7362@norris-Latitude-E6410> Message-ID: <20140918025447.GA8127@brian-ubuntu> On Wed, Sep 17, 2014 at 10:54:03AM +0100, Ezequiel Garcia wrote: > On 17 September 2014 09:33, Brian Norris wrote: > > On Wed, Sep 10, 2014 at 04:05:56PM +0300, Roger Quadros wrote: > >> On 09/10/2014 03:48 PM, Ezequiel Garcia wrote: > >> > On 08 Sep 01:53 PM, Roger Quadros wrote: > >> >> On 09/08/2014 11:45 AM, Roger Quadros wrote: > >> >>> On 09/06/2014 10:56 PM, Ezequiel Garcia wrote: > >> >> I still get the following error if I set CONFIG_MTD_NAND_OMAP2 to y and > >> >> CONFIG_MTD_NAND_OMAP_BCH to m. > >> >> > >> >> CONFIG_MTD_NAND_OMAP_BCH is used to select the ELM driver and it must be limited to > >> >> be built-in if CONFIG_MTD_NAND_OMAP2 is built-in. > >> >> > >> > > >> > Hm, yup. Any ideas on how to accomplish that? My Kconfig-foo is not strong enough :( > >> > >> Mine neither ;). I'm unaware of any other method than making CONFIG_MTD_NAND_OMAP_BCH to bool. > > > > That could be part of the solution. Does the following patch work? It > > now forces elm and omap to be built the same -- either both as modules > > or both built-in -- but it solves the rest of the problem I think. > > > > (This also has the side effect of causing transition pains for any > > .config file that had CONFIG_MTD_NAND_OMAP_BCH=m, since this becomes > > boolean now.) > > > > http://patchwork.ozlabs.org/patch/388249/ > > I used my time-machine to go back in time and submitted the patch for you :-) I'm glad you prioritized MTD over all the other cool things you could do with your time machine. But I guess, you really don't need to prioritize much when you have infinite time, do you? I can get lost when I only pay 50% attention for a few weeks, then try to sort through the accumulated pile of email. Brian From computersforpeace at gmail.com Wed Sep 17 20:00:49 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 20:00:49 -0700 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <5416A2FF.3050503@ti.com> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> <5416A2FF.3050503@ti.com> Message-ID: <20140918030049.GB8127@brian-ubuntu> On Mon, Sep 15, 2014 at 11:27:43AM +0300, Roger Quadros wrote: > On 09/12/2014 07:56 PM, Ezequiel Garcia wrote: > > On 12 Sep 12:01 PM, Roger Quadros wrote: > >> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: > >>> This commit adds a hidden option to build the omap_elm as a module, if > >>> omap2_nand is a module (and similarly in the built-in case). > >>> > >>> This fixes the following build error when omap2_nand is chosen built-in, > >>> and omap_elm is chosen as a module: > >>> > >>> drivers/built-in.o: In function `omap_nand_probe': > >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > >>> drivers/built-in.o: In function `omap_elm_correct_data': > >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > >>> > >>> Signed-off-by: Ezequiel Garcia > >>> --- > >>> drivers/mtd/nand/Kconfig | 8 +++++++- > >>> drivers/mtd/nand/Makefile | 2 +- > >>> 2 files changed, 8 insertions(+), 2 deletions(-) > >>> > >>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > >>> index f1cf503..12e8ee8 100644 > >>> --- a/drivers/mtd/nand/Kconfig > >>> +++ b/drivers/mtd/nand/Kconfig > >>> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 > >>> > >>> config MTD_NAND_OMAP_BCH > >>> depends on MTD_NAND_OMAP2 > >>> - tristate "Support hardware based BCH error correction" > >>> + bool "Support hardware based BCH error correction" > >>> default n > >>> select BCH > >>> help > >>> @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH > >>> legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine > >>> so they should not enable this config symbol. > >>> > >>> +config MTD_NAND_OMAP_BCH_BUILD > >>> + tristate > >>> + depends on MTD_NAND_OMAP2 > >>> + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH > >>> + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH I think the last 2 lines could be combined: default MTD_NAND_OMAP2 if MTD_NAND_OMAP_BCH > >>> + > >>> config MTD_NAND_IDS > >>> tristate > >>> > >>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile > >>> index 4bcdeb0..3580188 100644 > >>> --- a/drivers/mtd/nand/Makefile > >>> +++ b/drivers/mtd/nand/Makefile > >>> @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o > >>> obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o > >>> obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o > >>> obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o > >>> -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o > >>> +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o > >>> obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o > >>> obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o > >>> obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o Apparently I came up with a nearly identical solution, so it must be good! ;) > >> The overall logic seems to work but I still see the following issue. > >> > >> In menuconfig, the OMAP_BCH option is still visible as a boolean even though > >> the ELM module finally gets built as a module. > >> This can be confusing to the user and I'd avoid that behaviour. > >> > > > > Yes, I know. But it's either this solution or no solution at all, I think. > > > > Let me give some further context about this patch, so we can have more > > information to decide. > > > > First of all (and IMO) the user doesn't have to know about the ELM being > > a module or not, because modprobe will load it (since omap2_nand depends > > on omap_elm's symbols). > > > > So, the new way seems a bit more intuitive for me. The user choses if he > > wants to have hardware BCH support, and such support gets built the right > > way. > > > > If we still consider this highly confusing, and we want to avoid it, > > then it seems we can only make omap_elm a boolean, which means it'll always > > be built-in. I crafted this patch in an effort to avoid making it boolean. > > > > Finally, the solution is taken from media/usb/stk1160. For good or for bad, > > we have a precedent in doing things this way. > > > > Ultimately, I don't care much as I don't think anyone will build it as a module, > > except maybe for testing the driver under probe/remove cycles. > > > OK. I personally prefer boolean than the Kconfig magic as it makes my life a bit > easier and less confusing to the user i.e. wysiwyg ;). > > Let's see what the MTD maintainers prefer. > Brian and David, any insights on this problem? It seems like 'elm' serves more as an accessory piece of omap2.{o,ko}, not really a separate module, so it's possible it'd make your life even easier to just link elm.o into omap2.o. There's no requirement that two source files create two separate kernel modules. I think this would present the simplest possible interface to the user. Thoughts? Brian From computersforpeace at gmail.com Wed Sep 17 20:03:50 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 20:03:50 -0700 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140918113135.70D0.AA925319@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> <20140917171308.GC1193@ld-irv-0074> <20140918113135.70D0.AA925319@jp.panasonic.com> Message-ID: <20140918030350.GC8127@brian-ubuntu> On Thu, Sep 18, 2014 at 11:31:35AM +0900, Masahiro Yamada wrote: > On Wed, 17 Sep 2014 10:13:08 -0700 Brian Norris wrote: > > On Tue, Sep 16, 2014 at 08:04:18PM +0900, Masahiro Yamada wrote: > > > Masahiro Yamada (7): > > > mtd: denali: fix the format of comment blocks > > > mtd: denali: remove unnecessary variable initializations > > > mtd: denali: remove unnecessary casts > > > mtd: denali: change the type of iterators to int > > > mtd: denali: remove a set-but-unused variable > > > mtd: denali: remove unnecessary parentheses > > > mtd: denali: fix indents and other trivial things > > > > This series still doesn't apply to l2-mtd.git. > > I resent the last three patches as v3. > > v3 5/7 mtd: denali: remove a set-but-unused variable > v3 6/7 mtd: denali: remove unnecessary parentheses > v3 7/7 mtd: denali: fix indents and other trivial things > > I confirmed they are applicable onto > commit 93e3c8adf6fcf2204ca334237b92c7f8cdafce6f > of l2-mtd.git > > You said as follow: > > On Mon, 15 Sep 2014 22:07:32 -0700 > Brian Norris wrote: > > > > Is there a chance for me to resend 5/7 to include this fix? > > > Or is it too late? > > > > Just send a new patch, please. I mean "a new patch [on top of l2-mtd.git]", but I see that wasn't clear. > That's why I sent a new patch (v3 5/7) to replace > commit 55ab9ec99bbfb4450dfa9bc0fd9e2c5052f4c3f7 > > > Did I do wrong? Eh, just miscommunication from my end. I don't like to back out patches for no good reason, but I suppose I can back out patch 5/7 v2, and look at applying v3 instead. Brian From computersforpeace at gmail.com Wed Sep 17 22:49:40 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 22:49:40 -0700 Subject: [PATCHv5] mtd: nand: atmel_nand: retrieve NFC clock In-Reply-To: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> References: <1410564239-8411-1-git-send-email-alexandre.belloni@free-electrons.com> Message-ID: <20140918054940.GC7362@norris-Latitude-E6410> On Sat, Sep 13, 2014 at 01:23:59AM +0200, Alexandre Belloni wrote: > From: Boris BREZILLON > > Retrieve the NFC clock to make sure it is enabled. Make that optional to ensure > compatibility with previous device trees but document it as mandatory so newer > device trees will include it. > > Signed-off-by: Boris BREZILLON > Signed-off-by: Alexandre Belloni > Acked-by: Josh Wu > --- > Changes in v5: > - Added a proper commit log Pushed to l2-mtd.git. Thanks! Brian From computersforpeace at gmail.com Wed Sep 17 22:59:48 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 22:59:48 -0700 Subject: [PATCH v3 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <20140918055948.GD7362@norris-Latitude-E6410> On Thu, Sep 11, 2014 at 12:02:08PM -0300, Ezequiel Garcia wrote: > This commit adds a new platform-data boolean property that enables use > of a flash-based bad block table. This can also be enabled by setting > the 'nand-on-flash-bbt' devicetree property. > > If the flash BBT is not enabled, the driver falls back to use OOB > bad block markers only, as before. If the flash BBT is enabled the > kernel will keep track of bad blocks using a BBT, in addition to > the OOB markers. > > As explained by Brian Norris the reasons for using a BBT are: > > "" > The primary reason would be that NAND datasheets specify it these days. > A better argument is that nobody guarantees that you can write a > bad block marker to a worn out block; you may just get program failures. > > This has been acknowledged by several developers over the last several > years. > > Additionally, you get a boot-time performance improvement if you only > have to read a few pages, instead of a page or two from every block on > the flash. > "" > > Signed-off-by: Ezequiel Garcia Pushed this one to l2-mtd.git. Thanks! But I do have one question below, and I have comments for patch 2. > --- > arch/arm/mach-omap2/gpmc.c | 2 ++ > drivers/mtd/nand/omap2.c | 6 +++++- > include/linux/platform_data/mtd-nand-omap2.h | 1 + > 3 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c > index 2f97228..b55a225 100644 > --- a/arch/arm/mach-omap2/gpmc.c > +++ b/arch/arm/mach-omap2/gpmc.c > @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, > break; > } > > + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); > + > val = of_get_nand_bus_width(child); > if (val == 16) > gpmc_nand_data->devsize = NAND_BUSWIDTH_16; > diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c > index 5967b38..e1a9b31 100644 > --- a/drivers/mtd/nand/omap2.c > +++ b/drivers/mtd/nand/omap2.c > @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) > mtd->owner = THIS_MODULE; > nand_chip = &info->nand; > nand_chip->ecc.priv = NULL; > - nand_chip->options |= NAND_SKIP_BBTSCAN; > > res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); > @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) > nand_chip->chip_delay = 50; > } > > + if (pdata->flash_bbt) > + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; > + else > + nand_chip->options |= NAND_SKIP_BBTSCAN; Can you remind me: why do you use SKIP_BBTSCAN? Doesn't that mean you're skipping all boot-time scanning for bad blocks, and resorting to on-demand scanning (chip->block_bad()) every time you need to check for bad blocks? > + > /* scan NAND device connected to chip controller */ > nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; > if (nand_scan_ident(mtd, 1, NULL)) { > diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h > index 16ec262..090bbab 100644 > --- a/include/linux/platform_data/mtd-nand-omap2.h > +++ b/include/linux/platform_data/mtd-nand-omap2.h > @@ -71,6 +71,7 @@ struct omap_nand_platform_data { > struct mtd_partition *parts; > int nr_parts; > bool dev_ready; > + bool flash_bbt; > enum nand_io xfer_type; > int devsize; > enum omap_ecc ecc_opt; Brian From computersforpeace at gmail.com Wed Sep 17 23:03:36 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:03:36 -0700 Subject: [PATCH v3 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <20140918060336.GE7362@norris-Latitude-E6410> On Thu, Sep 11, 2014 at 12:02:09PM -0300, Ezequiel Garcia wrote: > The current code abuses ifdefs to determine if the selected ECC scheme > is supported by the running kernel. As a result the code is hard to read, > and it also fails to load as a module. Yes, a real eyesore, with little benefit from the #ifdef's. > This commit removes all the ifdefs and instead introduces a function > omap2_nand_ecc_check() to check if the ECC is supported by using > IS_ENABLED(CONFIG_xxx). > > Since IS_ENABLED() is true when a config is =y or =m, this change fixes the > module so it can be loaded with no issues. > > Signed-off-by: Ezequiel Garcia [...] > diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h > index 780d1e9..25d1bca 100644 > --- a/include/linux/platform_data/elm.h > +++ b/include/linux/platform_data/elm.h > @@ -42,8 +42,22 @@ struct elm_errorvec { > int error_loc[16]; > }; > > +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) > void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > struct elm_errorvec *err_vec); > int elm_config(struct device *dev, enum bch_ecc bch_type, > int ecc_steps, int ecc_step_size, int ecc_syndrome_size); > +#else > +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, > + struct elm_errorvec *err_vec) You should not be defining non-static functions in a header. Now these functions will be uselessly placed in every compilation unit that includes this header. You should probably make this function 'static inline'. > +{ > +} > + > +int elm_config(struct device *dev, enum bch_ecc bch_type, > + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) And same here. > +{ > + return -ENOSYS; > +} > +#endif /* CONFIG_MTD_NAND_ECC_BCH */ > + > #endif /* __ELM_H */ Brian From computersforpeace at gmail.com Wed Sep 17 23:12:41 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:12:41 -0700 Subject: [PATCH 1/2] mtd: atmel_nand: remove pmecc_sector_number, use ecc.steps instead In-Reply-To: <1407489155-16545-1-git-send-email-josh.wu@atmel.com> References: <1407489155-16545-1-git-send-email-josh.wu@atmel.com> Message-ID: <20140918061241.GF7362@norris-Latitude-E6410> On Fri, Aug 08, 2014 at 05:12:34PM +0800, Josh Wu wrote: > For PMECC, the pmecc_sector_number has same meaning as ecc.steps. > So use ecc.steps to replace the pmecc_sector_number. > > Signed-off-by: Josh Wu Pushed both to l2-mtd.git. Thanks! One comment below. > --- > drivers/mtd/nand/atmel_nand.c | 14 ++++++-------- > 1 file changed, 6 insertions(+), 8 deletions(-) > > diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c > index 9c5f717..1dc3988 100644 > --- a/drivers/mtd/nand/atmel_nand.c > +++ b/drivers/mtd/nand/atmel_nand.c > @@ -129,7 +129,6 @@ struct atmel_nand_host { > u32 pmecc_lookup_table_offset_1024; > > int pmecc_bytes_per_sector; > - int pmecc_sector_number; > int pmecc_degree; /* Degree of remainders */ > int pmecc_cw_len; /* Length of codeword */ > > @@ -874,7 +873,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, > return 0; > > normal_check: > - for (i = 0; i < host->pmecc_sector_number; i++) { > + for (i = 0; i < nand_chip->ecc.steps; i++) { > err_nbr = 0; > if (pmecc_stat & 0x1) { > buf_pos = buf + i * host->pmecc_sector_size; > @@ -984,7 +983,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, > cpu_relax(); > } > > - for (i = 0; i < host->pmecc_sector_number; i++) { > + for (i = 0; i < chip->ecc.steps; i++) { > for (j = 0; j < host->pmecc_bytes_per_sector; j++) { > int pos; > > @@ -1031,7 +1030,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) > else if (host->pmecc_sector_size == 1024) > val |= PMECC_CFG_SECTOR1024; > > - switch (host->pmecc_sector_number) { > + switch (nand_chip->ecc.steps) { > case 1: > val |= PMECC_CFG_PAGE_1SECTOR; > break; > @@ -1184,18 +1183,17 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, > host->pmecc_degree = (sector_size == 512) ? > PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; > host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; > - host->pmecc_sector_number = mtd->writesize / sector_size; > host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( > cap, sector_size); > host->pmecc_alpha_to = pmecc_get_alpha_to(host); > host->pmecc_index_of = host->pmecc_rom_base + > host->pmecc_lookup_table_offset; > > - nand_chip->ecc.steps = host->pmecc_sector_number; > nand_chip->ecc.strength = cap; > nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; > - nand_chip->ecc.total = host->pmecc_bytes_per_sector * > - host->pmecc_sector_number; > + nand_chip->ecc.steps = mtd->writesize / sector_size; > + nand_chip->ecc.total = nand_chip->ecc.bytes * > + nand_chip->ecc.steps; Do you really need to do all this initialization here? nand_scan_tail() would do most of this for you. > if (nand_chip->ecc.total > mtd->oobsize - 2) { > dev_err(host->dev, "No room for ECC bytes\n"); > err_no = -EINVAL; Brian From computersforpeace at gmail.com Wed Sep 17 23:16:46 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:16:46 -0700 Subject: [PATCH V2] mtd: bcm47xxpart: find NVRAM partitions in middle blocks In-Reply-To: <1408386027-12120-1-git-send-email-zajec5@gmail.com> References: <1408004566-22271-1-git-send-email-zajec5@gmail.com> <1408386027-12120-1-git-send-email-zajec5@gmail.com> Message-ID: <20140918061646.GG7362@norris-Latitude-E6410> On Mon, Aug 18, 2014 at 08:20:27PM +0200, Rafa? Mi?ecki wrote: > Old devices used to have NVRAM at the very end of flash and they could > be unaligned (starting at some offset in a block). > In new devices NVRAM can be located quite randomly, however it seems to > always start at the beginning of a block. For example Netgear R6250 has > NVRAM located right after the bootloader, before the kernel partition. > > Signed-off-by: Rafa? Mi?ecki > --- > V2: Ignore last block to avoid having two "nvram" partitions. Tweaked the multi-line comment style and pushed to l2-mtd.git. Thanks! > --- > drivers/mtd/bcm47xxpart.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c > index 035690e..da641ac 100644 > --- a/drivers/mtd/bcm47xxpart.c > +++ b/drivers/mtd/bcm47xxpart.c > @@ -224,6 +224,16 @@ static int bcm47xxpart_parse(struct mtd_info *master, > continue; > } > > + /* New (ARM?) devices may have NVRAM in some middle block. Last > + * block will be checked later, so skip it. > + */ > + if (offset != master->size - blocksize && > + buf[0x000 / 4] == NVRAM_HEADER) { > + bcm47xxpart_add_part(&parts[curr_part++], "nvram", > + offset, 0); > + continue; > + } > + > /* Read middle of the block */ > if (mtd_read(master, offset + 0x8000, 0x4, > &bytes_read, (uint8_t *)buf) < 0) { Brian From computersforpeace at gmail.com Wed Sep 17 23:25:41 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:25:41 -0700 Subject: [PATCH 1/4] mtd: bcm47xxnflash: fix typo in freq calculation In-Reply-To: <1408432456-27280-1-git-send-email-zajec5@gmail.com> References: <1408432456-27280-1-git-send-email-zajec5@gmail.com> Message-ID: <20140918062541.GH7362@norris-Latitude-E6410> On Tue, Aug 19, 2014 at 09:14:13AM +0200, Rafa? Mi?ecki wrote: > We are supposed to mask value, not multiply it. Add some comments btw. > > Signed-off-by: Rafa? Mi?ecki Pushed all 4 to l2-mtd.git. Thanks! Brian From computersforpeace at gmail.com Wed Sep 17 23:27:22 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:27:22 -0700 Subject: [PATCH 2/4] mtd: bcm47xxnflash: add dev_ready and fill chip_delay In-Reply-To: <1408432456-27280-2-git-send-email-zajec5@gmail.com> References: <1408432456-27280-1-git-send-email-zajec5@gmail.com> <1408432456-27280-2-git-send-email-zajec5@gmail.com> Message-ID: <20140918062722.GI7362@norris-Latitude-E6410> On Tue, Aug 19, 2014 at 09:14:14AM +0200, Rafa? Mi?ecki wrote: > Signed-off-by: Rafa? Mi?ecki > --- > drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c > index dc204f3..1ea5e77 100644 > --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c > +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c > @@ -174,6 +174,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, > return; > } > > +static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd) > +{ > + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; > + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; > + > + return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY); BTW, you don't actually need the double negation, since chip->dev_ready() is always used as a bool anyway. But no matter. > +} > + > /* > * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. > * For example, reading chip id is performed in a non-standard way. > @@ -341,6 +349,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, > > int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) > { > + struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip; > int err; > u32 freq; > u16 clock; > @@ -351,10 +360,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) > u32 val; > > b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; > + nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; > b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; > b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; > b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; > b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; > + > + nand_chip->chip_delay = 50; I'm curious, did you have a good reason to use something other than the default provided by nand_base? > b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; > b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ > Brian From computersforpeace at gmail.com Wed Sep 17 23:28:01 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:28:01 -0700 Subject: [PATCH] mtd: bcm47xxnflash: replace some magic numbers In-Reply-To: <1408440504-6802-1-git-send-email-zajec5@gmail.com> References: <1408440504-6802-1-git-send-email-zajec5@gmail.com> Message-ID: <20140918062801.GJ7362@norris-Latitude-E6410> On Tue, Aug 19, 2014 at 11:28:24AM +0200, Rafa? Mi?ecki wrote: > Signed-off-by: Rafa? Mi?ecki Pushed to l2-mtd.git. Thanks! Brian From computersforpeace at gmail.com Wed Sep 17 23:30:43 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:30:43 -0700 Subject: [PATCH] mtd: nand: don't break long print messages In-Reply-To: <1408449334-6440-1-git-send-email-zajec5@gmail.com> References: <1408449334-6440-1-git-send-email-zajec5@gmail.com> Message-ID: <20140918063043.GK7362@norris-Latitude-E6410> On Tue, Aug 19, 2014 at 01:55:34PM +0200, Rafa? Mi?ecki wrote: > This follows Chapter 2 of Linux's CodingStyle: > > However, never break user-visible strings such as printk messages, > > because that breaks the ability to grep for them. > > Signed-off-by: Rafa? Mi?ecki Pushed to l2-mtd.git. Thanks! Brian From computersforpeace at gmail.com Wed Sep 17 23:33:26 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:33:26 -0700 Subject: [PATCH] mtd: denali: fix include guard and license block of denali.h In-Reply-To: <1409310051-25726-1-git-send-email-yamada.m@jp.panasonic.com> References: <1409310051-25726-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140918063326.GL7362@norris-Latitude-E6410> On Fri, Aug 29, 2014 at 08:00:51PM +0900, Masahiro Yamada wrote: > It looks like this header file is a concatenation of two headers. > Anyway, the include guard should be renamed and placed at the correct > postion and the license block in the middle should be deleted. > > Signed-off-by: Masahiro Yamada Pushed to l2-mtd.git. Thanks! Brian From zajec5 at gmail.com Wed Sep 17 23:43:05 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Thu, 18 Sep 2014 08:43:05 +0200 Subject: [PATCH 2/4] mtd: bcm47xxnflash: add dev_ready and fill chip_delay In-Reply-To: <20140918062722.GI7362@norris-Latitude-E6410> References: <1408432456-27280-1-git-send-email-zajec5@gmail.com> <1408432456-27280-2-git-send-email-zajec5@gmail.com> <20140918062722.GI7362@norris-Latitude-E6410> Message-ID: On 18 September 2014 08:27, Brian Norris wrote: > On Tue, Aug 19, 2014 at 09:14:14AM +0200, Rafa? Mi?ecki wrote: >> + >> + nand_chip->chip_delay = 50; > > I'm curious, did you have a good reason to use something other than the > default provided by nand_base? I simply followed what Broadcom used in their ugly code (don't look to deep into that file, or you'll go crazy): http://svn.dd-wrt.com/browser/src/linux/universal/linux-3.8/drivers/mtd/bcm947xx/nand/brcmnand_47xx.c?rev=22249#L2240 They set "dev_ready" as well as "chip_delay" (to the 50), so the only case where they use this delay is NAND_CMD_STATUS_ERROR NAND_CMD_STATUS_ERROR[0-3] Do you think we should try to stay with the default value? -- Rafa? From computersforpeace at gmail.com Wed Sep 17 23:54:05 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Wed, 17 Sep 2014 23:54:05 -0700 Subject: [PATCH 2/4] mtd: bcm47xxnflash: add dev_ready and fill chip_delay In-Reply-To: References: <1408432456-27280-1-git-send-email-zajec5@gmail.com> <1408432456-27280-2-git-send-email-zajec5@gmail.com> <20140918062722.GI7362@norris-Latitude-E6410> Message-ID: On Wed, Sep 17, 2014 at 11:43 PM, Rafa? Mi?ecki wrote: > On 18 September 2014 08:27, Brian Norris wrote: >> On Tue, Aug 19, 2014 at 09:14:14AM +0200, Rafa? Mi?ecki wrote: >>> + >>> + nand_chip->chip_delay = 50; >> >> I'm curious, did you have a good reason to use something other than the >> default provided by nand_base? > > I simply followed what Broadcom used in their ugly code (don't look to > deep into that file, or you'll go crazy): > http://svn.dd-wrt.com/browser/src/linux/universal/linux-3.8/drivers/mtd/bcm947xx/nand/brcmnand_47xx.c?rev=22249#L2240 > > They set "dev_ready" as well as "chip_delay" (to the 50), so the only > case where they use this delay is > NAND_CMD_STATUS_ERROR > NAND_CMD_STATUS_ERROR[0-3] > > Do you think we should try to stay with the default value? No, it's fine as-is. Brian From ezequiel at vanguardiasur.com.ar Thu Sep 18 00:46:15 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 18 Sep 2014 08:46:15 +0100 Subject: [PATCH v3 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: <20140918055948.GD7362@norris-Latitude-E6410> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> <20140918055948.GD7362@norris-Latitude-E6410> Message-ID: On 18 September 2014 06:59, Brian Norris wrote: > On Thu, Sep 11, 2014 at 12:02:08PM -0300, Ezequiel Garcia wrote: >> This commit adds a new platform-data boolean property that enables use >> of a flash-based bad block table. This can also be enabled by setting >> the 'nand-on-flash-bbt' devicetree property. >> >> If the flash BBT is not enabled, the driver falls back to use OOB >> bad block markers only, as before. If the flash BBT is enabled the >> kernel will keep track of bad blocks using a BBT, in addition to >> the OOB markers. >> >> As explained by Brian Norris the reasons for using a BBT are: >> >> "" >> The primary reason would be that NAND datasheets specify it these days. >> A better argument is that nobody guarantees that you can write a >> bad block marker to a worn out block; you may just get program failures. >> >> This has been acknowledged by several developers over the last several >> years. >> >> Additionally, you get a boot-time performance improvement if you only >> have to read a few pages, instead of a page or two from every block on >> the flash. >> "" >> >> Signed-off-by: Ezequiel Garcia > > Pushed this one to l2-mtd.git. Thanks! > > But I do have one question below, and I have comments for patch 2. > >> --- >> arch/arm/mach-omap2/gpmc.c | 2 ++ >> drivers/mtd/nand/omap2.c | 6 +++++- >> include/linux/platform_data/mtd-nand-omap2.h | 1 + >> 3 files changed, 8 insertions(+), 1 deletion(-) >> >> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c >> index 2f97228..b55a225 100644 >> --- a/arch/arm/mach-omap2/gpmc.c >> +++ b/arch/arm/mach-omap2/gpmc.c >> @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, >> break; >> } >> >> + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); >> + >> val = of_get_nand_bus_width(child); >> if (val == 16) >> gpmc_nand_data->devsize = NAND_BUSWIDTH_16; >> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c >> index 5967b38..e1a9b31 100644 >> --- a/drivers/mtd/nand/omap2.c >> +++ b/drivers/mtd/nand/omap2.c >> @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) >> mtd->owner = THIS_MODULE; >> nand_chip = &info->nand; >> nand_chip->ecc.priv = NULL; >> - nand_chip->options |= NAND_SKIP_BBTSCAN; >> >> res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >> nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); >> @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) >> nand_chip->chip_delay = 50; >> } >> >> + if (pdata->flash_bbt) >> + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; >> + else >> + nand_chip->options |= NAND_SKIP_BBTSCAN; > > Can you remind me: why do you use SKIP_BBTSCAN? Doesn't that mean you're > skipping all boot-time scanning for bad blocks, and resorting to > on-demand scanning (chip->block_bad()) every time you need to check for > bad blocks? > Honestly, I have *no* idea, I just retained the previous flag, so to keep the exact same behavior. Roger, any ideas? If I have to guess, I'd say this is an attempt to save some boot time. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From ezequiel at vanguardiasur.com.ar Thu Sep 18 00:48:06 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 18 Sep 2014 08:48:06 +0100 Subject: [PATCH v3 2/3] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <20140918060336.GE7362@norris-Latitude-E6410> References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-3-git-send-email-ezequiel@vanguardiasur.com.ar> <20140918060336.GE7362@norris-Latitude-E6410> Message-ID: On 18 September 2014 07:03, Brian Norris wrote: > On Thu, Sep 11, 2014 at 12:02:09PM -0300, Ezequiel Garcia wrote: >> The current code abuses ifdefs to determine if the selected ECC scheme >> is supported by the running kernel. As a result the code is hard to read, >> and it also fails to load as a module. > > Yes, a real eyesore, with little benefit from the #ifdef's. > >> This commit removes all the ifdefs and instead introduces a function >> omap2_nand_ecc_check() to check if the ECC is supported by using >> IS_ENABLED(CONFIG_xxx). >> >> Since IS_ENABLED() is true when a config is =y or =m, this change fixes the >> module so it can be loaded with no issues. >> >> Signed-off-by: Ezequiel Garcia > [...] >> diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h >> index 780d1e9..25d1bca 100644 >> --- a/include/linux/platform_data/elm.h >> +++ b/include/linux/platform_data/elm.h >> @@ -42,8 +42,22 @@ struct elm_errorvec { >> int error_loc[16]; >> }; >> >> +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) >> void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >> struct elm_errorvec *err_vec); >> int elm_config(struct device *dev, enum bch_ecc bch_type, >> int ecc_steps, int ecc_step_size, int ecc_syndrome_size); >> +#else >> +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, >> + struct elm_errorvec *err_vec) > > You should not be defining non-static functions in a header. Now these > functions will be uselessly placed in every compilation unit that > includes this header. You should probably make this function 'static > inline'. > Darn, of course they must be static! Thanks for spotting this. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From ricard.wanderlof at axis.com Thu Sep 18 01:02:35 2014 From: ricard.wanderlof at axis.com (Ricard Wanderlof) Date: Thu, 18 Sep 2014 10:02:35 +0200 Subject: Question about adding a NAND device In-Reply-To: <5498E86A4A68B14A8A06D0380640D04A01FA6854E73D@atca01em01.adsi.aitech.ent> References: <5498E86A4A68B14A8A06D0380640D04A01FA6854E73D@atca01em01.adsi.aitech.ent> Message-ID: On Wed, 17 Sep 2014, Robert Hurdle wrote: > Hello, > > I have ported some of u-boot to our board, and I am booting successfully from EEPROM. > I am now in the process of adding the NAND and flash file system support for our non-standard > flash interface (there's an FPGA interface between the software and the 1 giga-byte NAND) to > u-boot and also to the Linux kernel. In addition, it is our intention to support UBIFS on our board. > > It appears that I need to understand how the structures mtd_info and nand_chip (and whatever > they point at) and code in nand_base.c work, in order to provide working routines at the NAND > level. I have looked at some of the files in u-boot/drivers/mtd/nand for other boards, and see > a wide variety of models, no doubt based on the hardware differences. Because of our FPGA > interface, I need to have all commands to the NAND chip get re-packaged into commands that > get passed to the FPGA. Am I on the right path? > > My other question is how long would one guess that this task would take for someone fairly > competent, but uninitiated in UBIFS, UBI, MTD, NAND, etc. ? It's very hard to predict any form of time frame, especially when not knowing much about the hardware. If your FPGA basically just passes data between the CPU and flash on a byte-by-byte level, then you can probably take some simple driver and rewrite that. If the FPGA contains a more advanced NAND flash controller, which performs ECC, or does something else on a higher level you need to study the way nand_base.c goes about things and also of course the controller implementation in the FPGA. Basically, mtd was originally written with a byte-by-byte interface in mind. So that case is fairly easy to implement: your driver will just have to be able to send data to and read from the flash via FPGA (in this case), and also control the NAND flash CLE and ALE lines, as well as read the READY/BUSY line from the flash. All command sequencing, data transfer and ECC will be handled in software by the mtd layer. For more advanced cases, there are numerous hooks which can be used where the NAND flash controller accelerate specific functions. In my experience though it requires a lot more understanding of exactly how nand_base.c goes about things, and there is often more than one way to implement the required functionality. Looking at driver code for other NAND flash controllers also helps. /Ricard -- Ricard Wolf Wanderl?f ricardw(at)axis.com Axis Communications AB, Lund, Sweden www.axis.com Phone +46 46 272 2016 Fax +46 46 13 61 30 From josh.wu at atmel.com Thu Sep 18 01:08:03 2014 From: josh.wu at atmel.com (Josh Wu) Date: Thu, 18 Sep 2014 16:08:03 +0800 Subject: [PATCH v2] mtd: atmel_nand: make PMECC lookup table and offset property optional In-Reply-To: <20140918003258.GD1193@ld-irv-0074> References: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> <20140918003258.GD1193@ld-irv-0074> Message-ID: <541A92E3.60906@atmel.com> Hi, Brain On 9/18/2014 8:32 AM, Brian Norris wrote: > On Mon, Aug 18, 2014 at 03:08:40PM +0800, Josh Wu wrote: >> If there is no PMECC lookup table stored in ROM, or lookup table offset is >> not specified, PMECC driver should build it in DDR by itself. >> >> That make the PMECC driver work for some board which doesn't has PMECC >> lookup table in ROM. >> >> Signed-off-by: Josh Wu >> Cc: devicetree at vger.kernel.org >> --- >> This patch is based on mtd-l2/next branch >> >> v1 -> v2: >> make create_lookup_table() static. > sparse gives me several new complaints: > > +drivers/mtd/nand/atmel_nand.c:1219:50: warning: incorrect type in argument 2 (different signedness) [sparse] > +drivers/mtd/nand/atmel_nand.c:1219:50: expected signed short [usertype] *index_of [sparse] > +drivers/mtd/nand/atmel_nand.c:1219:50: got unsigned short [usertype] *addr [sparse] > +drivers/mtd/nand/atmel_nand.c:1219:61: warning: incorrect type in argument 3 (different signedness) [sparse] > +drivers/mtd/nand/atmel_nand.c:1219:61: expected signed short [usertype] *alpha_to [sparse] > +drivers/mtd/nand/atmel_nand.c:1219:61: got unsigned short [usertype] * [sparse] > +drivers/mtd/nand/atmel_nand.c:1292:38: warning: incorrect type in assignment (different address spaces) [sparse] > +drivers/mtd/nand/atmel_nand.c:1292:38: expected void [noderef] *pmecc_rom_base [sparse] > +drivers/mtd/nand/atmel_nand.c:1292:38: got unsigned short [usertype] *[assigned] galois_table [sparse] > > The third one might be a false positive. I suppose it's safe to use > regular memory with __iomem accessors (but not vice versa). Thanks. I will check this. > >> .../devicetree/bindings/mtd/atmel-nand.txt | 6 +- >> drivers/mtd/nand/atmel_nand.c | 136 ++++++++++++++++++++- >> 2 files changed, 136 insertions(+), 6 deletions(-) >> >> diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> index c472883..75d1847 100644 >> --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt >> @@ -5,7 +5,9 @@ Required properties: >> - reg : should specify localbus address and size used for the chip, >> and hardware ECC controller if available. >> If the hardware ECC is PMECC, it should contain address and size for >> - PMECC, PMECC Error Location controller and ROM which has lookup tables. >> + PMECC and PMECC Error Location controller. >> + The PMECC lookup table address and size in ROM is optional. If not >> + specified, driver will build it in runtime. >> - atmel,nand-addr-offset : offset for the address latch. >> - atmel,nand-cmd-offset : offset for the command latch. >> - #address-cells, #size-cells : Must be present if the device has sub-nodes >> @@ -27,7 +29,7 @@ Optional properties: >> are: 512, 1024. >> - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM >> for different sector size. First one is for sector size 512, the next is for >> - sector size 1024. >> + sector size 1024. If not specified, driver will build the table in runtime. >> - nand-bus-width : 8 or 16 bus width if not present 8 >> - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false >> - Nand Flash Controller(NFC) is a slave driver under Atmel nand flash >> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c >> index effa7a29..84af313 100644 >> --- a/drivers/mtd/nand/atmel_nand.c >> +++ b/drivers/mtd/nand/atmel_nand.c >> @@ -124,6 +124,7 @@ struct atmel_nand_host { >> bool has_pmecc; >> u8 pmecc_corr_cap; >> u16 pmecc_sector_size; >> + bool has_no_lookup_table; >> u32 pmecc_lookup_table_offset; >> u32 pmecc_lookup_table_offset_512; >> u32 pmecc_lookup_table_offset_1024; >> @@ -1109,12 +1110,121 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, >> return 0; >> } >> >> +static int pmecc_build_galois_table(int mm, >> + int16_t *index_of, int16_t *alpha_to) >> +{ >> + unsigned int i, mask, nn; >> + unsigned int p[PMECC_GF_DIMENSION_14 + 1]; >> + >> + nn = (1 << mm) - 1; >> + /* set default value */ >> + for (i = 1; i < mm; i++) >> + p[i] = 0; >> + >> + /* 1 + X^mm */ >> + p[0] = 1; >> + p[mm] = 1; >> + >> + /* others */ >> + switch (mm) { >> + case 3: >> + case 4: >> + case 6: >> + case 15: >> + p[1] = 1; >> + break; >> + case 5: >> + case 11: >> + p[2] = 1; >> + break; >> + case 7: >> + case 10: >> + p[3] = 1; >> + break; >> + case 8: >> + p[2] = p[3] = p[4] = 1; >> + break; >> + case 9: >> + p[4] = 1; >> + break; >> + case 12: >> + p[1] = p[4] = p[6] = 1; >> + break; >> + case 13: >> + p[1] = p[3] = p[4] = 1; >> + break; >> + case 14: >> + p[1] = p[6] = p[10] = 1; >> + break; >> + default: >> + /* Error */ >> + return -EINVAL; >> + } >> + >> + /* Build alpha ^ mm it will help to generate the field (primitiv) */ >> + alpha_to[mm] = 0; >> + for (i = 0; i < mm; i++) >> + if (p[i]) >> + alpha_to[mm] |= 1 << i; >> + >> + /* >> + * Then build elements from 0 to mm - 1. As degree is less than mm >> + * so it is just a logical shift. >> + */ >> + mask = 1; >> + for (i = 0; i < mm; i++) { >> + alpha_to[i] = mask; >> + index_of[alpha_to[i]] = i; >> + mask <<= 1; >> + } >> + >> + index_of[alpha_to[mm]] = mm; >> + >> + /* use a mask to select the MSB bit of the LFSR */ >> + mask >>= 1; >> + >> + /* then finish the building */ >> + for (i = mm + 1; i <= nn; i++) { >> + /* check if the msb bit of the lfsr is set */ >> + if (alpha_to[i - 1] & mask) >> + alpha_to[i] = alpha_to[mm] ^ >> + ((alpha_to[i - 1] ^ mask) << 1); >> + else >> + alpha_to[i] = alpha_to[i - 1] << 1; >> + >> + index_of[alpha_to[i]] = i % nn; >> + } >> + >> + /* index of 0 is undefined in a multiplicative field */ >> + index_of[0] = -1; >> + >> + return 0; >> +} > Is this algorithm documented? How did you come up with this? It is not documented in datasheet. It is based BCH algorithm. But do you know if the soft BCH use a same table like this? Best Regards, Josh Wu > >> + >> +static uint16_t *create_lookup_table(struct device *dev, int sector_size) >> +{ >> + int table_size = (sector_size == 512) ? >> + PMECC_LOOKUP_TABLE_SIZE_512 : >> + PMECC_LOOKUP_TABLE_SIZE_1024; >> + int degree = (sector_size == 512) ? >> + PMECC_GF_DIMENSION_13 : >> + PMECC_GF_DIMENSION_14; >> + uint16_t *addr = devm_kzalloc(dev, 2 * table_size * sizeof(uint16_t), >> + GFP_KERNEL); >> + >> + if (addr) >> + pmecc_build_galois_table(degree, addr, addr + table_size); >> + >> + return addr; >> +} >> + >> static int atmel_pmecc_nand_init_params(struct platform_device *pdev, >> struct atmel_nand_host *host) >> { >> struct mtd_info *mtd = &host->mtd; >> struct nand_chip *nand_chip = &host->nand_chip; >> struct resource *regs, *regs_pmerr, *regs_rom; >> + uint16_t *galois_table; >> int cap, sector_size, err_no; >> >> err_no = pmecc_choose_ecc(host, &cap, §or_size); >> @@ -1160,8 +1270,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, >> regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); >> host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); >> if (IS_ERR(host->pmecc_rom_base)) { >> - err_no = PTR_ERR(host->pmecc_rom_base); >> - goto err; >> + if (!host->has_no_lookup_table) >> + /* Don't display the information again */ >> + dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); >> + >> + host->has_no_lookup_table = true; >> + } >> + >> + if (host->has_no_lookup_table) { >> + /* Build the look-up table in runtime */ >> + galois_table = create_lookup_table(host->dev, sector_size); >> + if (!galois_table) { >> + dev_err(host->dev, "Failed to build a lookup table in runtime!\n"); >> + err_no = -ENOMEM; >> + goto err; >> + } >> + >> + host->pmecc_rom_base = galois_table; >> + host->pmecc_lookup_table_offset = 0; >> } >> >> nand_chip->ecc.size = sector_size; >> @@ -1498,8 +1624,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host, >> >> if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", >> offset, 2) != 0) { >> - dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); >> - return -EINVAL; >> + dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n"); >> + host->has_no_lookup_table = true; >> + /* Will build a lookup table and initialize the offset later */ >> + return 0; >> } >> if (!offset[0] && !offset[1]) { >> dev_err(host->dev, "Invalid PMECC lookup table offset\n"); > Brian From rogerq at ti.com Thu Sep 18 01:26:55 2014 From: rogerq at ti.com (Roger Quadros) Date: Thu, 18 Sep 2014 11:26:55 +0300 Subject: [PATCH v3 1/3] nand: omap2: Add support for flash-based bad block table In-Reply-To: References: <1410447730-16087-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410447730-16087-2-git-send-email-ezequiel@vanguardiasur.com.ar> <20140918055948.GD7362@norris-Latitude-E6410> Message-ID: <541A974F.5010408@ti.com> On 09/18/2014 10:46 AM, Ezequiel Garcia wrote: > On 18 September 2014 06:59, Brian Norris wrote: >> On Thu, Sep 11, 2014 at 12:02:08PM -0300, Ezequiel Garcia wrote: >>> This commit adds a new platform-data boolean property that enables use >>> of a flash-based bad block table. This can also be enabled by setting >>> the 'nand-on-flash-bbt' devicetree property. >>> >>> If the flash BBT is not enabled, the driver falls back to use OOB >>> bad block markers only, as before. If the flash BBT is enabled the >>> kernel will keep track of bad blocks using a BBT, in addition to >>> the OOB markers. >>> >>> As explained by Brian Norris the reasons for using a BBT are: >>> >>> "" >>> The primary reason would be that NAND datasheets specify it these days. >>> A better argument is that nobody guarantees that you can write a >>> bad block marker to a worn out block; you may just get program failures. >>> >>> This has been acknowledged by several developers over the last several >>> years. >>> >>> Additionally, you get a boot-time performance improvement if you only >>> have to read a few pages, instead of a page or two from every block on >>> the flash. >>> "" >>> >>> Signed-off-by: Ezequiel Garcia >> >> Pushed this one to l2-mtd.git. Thanks! >> >> But I do have one question below, and I have comments for patch 2. >> >>> --- >>> arch/arm/mach-omap2/gpmc.c | 2 ++ >>> drivers/mtd/nand/omap2.c | 6 +++++- >>> include/linux/platform_data/mtd-nand-omap2.h | 1 + >>> 3 files changed, 8 insertions(+), 1 deletion(-) >>> >>> diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c >>> index 2f97228..b55a225 100644 >>> --- a/arch/arm/mach-omap2/gpmc.c >>> +++ b/arch/arm/mach-omap2/gpmc.c >>> @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, >>> break; >>> } >>> >>> + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); >>> + >>> val = of_get_nand_bus_width(child); >>> if (val == 16) >>> gpmc_nand_data->devsize = NAND_BUSWIDTH_16; >>> diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c >>> index 5967b38..e1a9b31 100644 >>> --- a/drivers/mtd/nand/omap2.c >>> +++ b/drivers/mtd/nand/omap2.c >>> @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) >>> mtd->owner = THIS_MODULE; >>> nand_chip = &info->nand; >>> nand_chip->ecc.priv = NULL; >>> - nand_chip->options |= NAND_SKIP_BBTSCAN; >>> >>> res = platform_get_resource(pdev, IORESOURCE_MEM, 0); >>> nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); >>> @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) >>> nand_chip->chip_delay = 50; >>> } >>> >>> + if (pdata->flash_bbt) >>> + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; >>> + else >>> + nand_chip->options |= NAND_SKIP_BBTSCAN; >> >> Can you remind me: why do you use SKIP_BBTSCAN? Doesn't that mean you're >> skipping all boot-time scanning for bad blocks, and resorting to >> on-demand scanning (chip->block_bad()) every time you need to check for >> bad blocks? >> > > Honestly, I have *no* idea, I just retained the previous flag, so to > keep the exact same behavior. > > Roger, any ideas? If I have to guess, I'd say this is an attempt to > save some boot time. > The SKIP_BBTSCAN has been there ever since this driver was introduced in 2009. by commit 67ce04bf2746. I'm not sure why it is preferred. cheers, -roger From ezequiel at vanguardiasur.com.ar Thu Sep 18 01:40:19 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Thu, 18 Sep 2014 09:40:19 +0100 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <20140918030049.GB8127@brian-ubuntu> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> <5416A2FF.3050503@ti.com> <20140918030049.GB8127@brian-ubuntu> Message-ID: On 18 September 2014 04:00, Brian Norris wrote: > On Mon, Sep 15, 2014 at 11:27:43AM +0300, Roger Quadros wrote: >> On 09/12/2014 07:56 PM, Ezequiel Garcia wrote: >> > On 12 Sep 12:01 PM, Roger Quadros wrote: >> >> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >> >>> This commit adds a hidden option to build the omap_elm as a module, if >> >>> omap2_nand is a module (and similarly in the built-in case). >> >>> >> >>> This fixes the following build error when omap2_nand is chosen built-in, >> >>> and omap_elm is chosen as a module: >> >>> >> >>> drivers/built-in.o: In function `omap_nand_probe': >> >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >> >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >> >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >> >>> drivers/built-in.o: In function `omap_elm_correct_data': >> >>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >> >>> >> >>> Signed-off-by: Ezequiel Garcia >> >>> --- >> >>> drivers/mtd/nand/Kconfig | 8 +++++++- >> >>> drivers/mtd/nand/Makefile | 2 +- >> >>> 2 files changed, 8 insertions(+), 2 deletions(-) >> >>> >> >>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >> >>> index f1cf503..12e8ee8 100644 >> >>> --- a/drivers/mtd/nand/Kconfig >> >>> +++ b/drivers/mtd/nand/Kconfig >> >>> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 >> >>> >> >>> config MTD_NAND_OMAP_BCH >> >>> depends on MTD_NAND_OMAP2 >> >>> - tristate "Support hardware based BCH error correction" >> >>> + bool "Support hardware based BCH error correction" >> >>> default n >> >>> select BCH >> >>> help >> >>> @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH >> >>> legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine >> >>> so they should not enable this config symbol. >> >>> >> >>> +config MTD_NAND_OMAP_BCH_BUILD >> >>> + tristate >> >>> + depends on MTD_NAND_OMAP2 >> >>> + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH >> >>> + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH > > I think the last 2 lines could be combined: > > default MTD_NAND_OMAP2 if MTD_NAND_OMAP_BCH > >> >>> + >> >>> config MTD_NAND_IDS >> >>> tristate >> >>> >> >>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile >> >>> index 4bcdeb0..3580188 100644 >> >>> --- a/drivers/mtd/nand/Makefile >> >>> +++ b/drivers/mtd/nand/Makefile >> >>> @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o >> >>> obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o >> >>> obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o >> >>> obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o >> >>> -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o >> >>> +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o >> >>> obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o >> >>> obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o >> >>> obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o > > Apparently I came up with a nearly identical solution, so it must be > good! ;) > >> >> The overall logic seems to work but I still see the following issue. >> >> >> >> In menuconfig, the OMAP_BCH option is still visible as a boolean even though >> >> the ELM module finally gets built as a module. >> >> This can be confusing to the user and I'd avoid that behaviour. >> >> >> > >> > Yes, I know. But it's either this solution or no solution at all, I think. >> > >> > Let me give some further context about this patch, so we can have more >> > information to decide. >> > >> > First of all (and IMO) the user doesn't have to know about the ELM being >> > a module or not, because modprobe will load it (since omap2_nand depends >> > on omap_elm's symbols). >> > >> > So, the new way seems a bit more intuitive for me. The user choses if he >> > wants to have hardware BCH support, and such support gets built the right >> > way. >> > >> > If we still consider this highly confusing, and we want to avoid it, >> > then it seems we can only make omap_elm a boolean, which means it'll always >> > be built-in. I crafted this patch in an effort to avoid making it boolean. >> > >> > Finally, the solution is taken from media/usb/stk1160. For good or for bad, >> > we have a precedent in doing things this way. >> > >> > Ultimately, I don't care much as I don't think anyone will build it as a module, >> > except maybe for testing the driver under probe/remove cycles. >> > >> OK. I personally prefer boolean than the Kconfig magic as it makes my life a bit >> easier and less confusing to the user i.e. wysiwyg ;). >> >> Let's see what the MTD maintainers prefer. >> Brian and David, any insights on this problem? > > It seems like 'elm' serves more as an accessory piece of omap2.{o,ko}, > not really a separate module, so it's possible it'd make your life even > easier to just link elm.o into omap2.o. There's no requirement that two > source files create two separate kernel modules. I think this would > present the simplest possible interface to the user. > > Thoughts? > Yeah, but that means a larger refactoring, because now you'd have to call the ELM driver probe() from the NAND driver probe(). It'd be a nice cleanup, but maybe this is the second step? -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar From rogerq at ti.com Thu Sep 18 01:40:39 2014 From: rogerq at ti.com (Roger Quadros) Date: Thu, 18 Sep 2014 11:40:39 +0300 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <20140918030049.GB8127@brian-ubuntu> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> <5416A2FF.3050503@ti.com> <20140918030049.GB8127@brian-ubuntu> Message-ID: <541A9A87.9060901@ti.com> On 09/18/2014 06:00 AM, Brian Norris wrote: > On Mon, Sep 15, 2014 at 11:27:43AM +0300, Roger Quadros wrote: >> On 09/12/2014 07:56 PM, Ezequiel Garcia wrote: >>> On 12 Sep 12:01 PM, Roger Quadros wrote: >>>> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >>>>> This commit adds a hidden option to build the omap_elm as a module, if >>>>> omap2_nand is a module (and similarly in the built-in case). >>>>> >>>>> This fixes the following build error when omap2_nand is chosen built-in, >>>>> and omap_elm is chosen as a module: >>>>> >>>>> drivers/built-in.o: In function `omap_nand_probe': >>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >>>>> drivers/built-in.o: In function `omap_elm_correct_data': >>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >>>>> >>>>> Signed-off-by: Ezequiel Garcia >>>>> --- >>>>> drivers/mtd/nand/Kconfig | 8 +++++++- >>>>> drivers/mtd/nand/Makefile | 2 +- >>>>> 2 files changed, 8 insertions(+), 2 deletions(-) >>>>> >>>>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >>>>> index f1cf503..12e8ee8 100644 >>>>> --- a/drivers/mtd/nand/Kconfig >>>>> +++ b/drivers/mtd/nand/Kconfig >>>>> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 >>>>> >>>>> config MTD_NAND_OMAP_BCH >>>>> depends on MTD_NAND_OMAP2 >>>>> - tristate "Support hardware based BCH error correction" >>>>> + bool "Support hardware based BCH error correction" >>>>> default n >>>>> select BCH >>>>> help >>>>> @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH >>>>> legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine >>>>> so they should not enable this config symbol. >>>>> >>>>> +config MTD_NAND_OMAP_BCH_BUILD >>>>> + tristate >>>>> + depends on MTD_NAND_OMAP2 >>>>> + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH >>>>> + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH > > I think the last 2 lines could be combined: > > default MTD_NAND_OMAP2 if MTD_NAND_OMAP_BCH > >>>>> + >>>>> config MTD_NAND_IDS >>>>> tristate >>>>> >>>>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile >>>>> index 4bcdeb0..3580188 100644 >>>>> --- a/drivers/mtd/nand/Makefile >>>>> +++ b/drivers/mtd/nand/Makefile >>>>> @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o >>>>> obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o >>>>> obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o >>>>> obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o >>>>> -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o >>>>> +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o >>>>> obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o >>>>> obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o >>>>> obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o > > Apparently I came up with a nearly identical solution, so it must be > good! ;) > >>>> The overall logic seems to work but I still see the following issue. >>>> >>>> In menuconfig, the OMAP_BCH option is still visible as a boolean even though >>>> the ELM module finally gets built as a module. >>>> This can be confusing to the user and I'd avoid that behaviour. >>>> >>> >>> Yes, I know. But it's either this solution or no solution at all, I think. >>> >>> Let me give some further context about this patch, so we can have more >>> information to decide. >>> >>> First of all (and IMO) the user doesn't have to know about the ELM being >>> a module or not, because modprobe will load it (since omap2_nand depends >>> on omap_elm's symbols). >>> >>> So, the new way seems a bit more intuitive for me. The user choses if he >>> wants to have hardware BCH support, and such support gets built the right >>> way. >>> >>> If we still consider this highly confusing, and we want to avoid it, >>> then it seems we can only make omap_elm a boolean, which means it'll always >>> be built-in. I crafted this patch in an effort to avoid making it boolean. >>> >>> Finally, the solution is taken from media/usb/stk1160. For good or for bad, >>> we have a precedent in doing things this way. >>> >>> Ultimately, I don't care much as I don't think anyone will build it as a module, >>> except maybe for testing the driver under probe/remove cycles. >>> >> OK. I personally prefer boolean than the Kconfig magic as it makes my life a bit >> easier and less confusing to the user i.e. wysiwyg ;). >> >> Let's see what the MTD maintainers prefer. >> Brian and David, any insights on this problem? > > It seems like 'elm' serves more as an accessory piece of omap2.{o,ko}, > not really a separate module, so it's possible it'd make your life even > easier to just link elm.o into omap2.o. There's no requirement that two > source files create two separate kernel modules. I think this would > present the simplest possible interface to the user. Sounds fine to me. Point to note is that ELM is not present on all OMAPs and has its own device tree node and compatible id which is different from the NAND controller node. So in theory it needs to have it's own separate driver, but since the only user is OMAP NAND driver I don't see why they can't be combined. ELM code is not that big so having it always built with the NAND driver shouldn't be a problem. This means you can get rid of the OMAP_BCH Kconfig option as well :). All newer SoCs (am33x+, OMAP4+) have the ELM module anyways. cheers, -roger From rogerq at ti.com Thu Sep 18 01:42:23 2014 From: rogerq at ti.com (Roger Quadros) Date: Thu, 18 Sep 2014 11:42:23 +0300 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> <5416A2FF.3050503@ti.com> <20140918030049.GB8127@brian-ubuntu> Message-ID: <541A9AEF.7090606@ti.com> On 09/18/2014 11:40 AM, Ezequiel Garcia wrote: > On 18 September 2014 04:00, Brian Norris wrote: >> On Mon, Sep 15, 2014 at 11:27:43AM +0300, Roger Quadros wrote: >>> On 09/12/2014 07:56 PM, Ezequiel Garcia wrote: >>>> On 12 Sep 12:01 PM, Roger Quadros wrote: >>>>> On 09/11/2014 04:47 PM, Ezequiel Garcia wrote: >>>>>> This commit adds a hidden option to build the omap_elm as a module, if >>>>>> omap2_nand is a module (and similarly in the built-in case). >>>>>> >>>>>> This fixes the following build error when omap2_nand is chosen built-in, >>>>>> and omap_elm is chosen as a module: >>>>>> >>>>>> drivers/built-in.o: In function `omap_nand_probe': >>>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >>>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >>>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >>>>>> drivers/built-in.o: In function `omap_elm_correct_data': >>>>>> /work/linux-2.6/drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >>>>>> >>>>>> Signed-off-by: Ezequiel Garcia >>>>>> --- >>>>>> drivers/mtd/nand/Kconfig | 8 +++++++- >>>>>> drivers/mtd/nand/Makefile | 2 +- >>>>>> 2 files changed, 8 insertions(+), 2 deletions(-) >>>>>> >>>>>> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >>>>>> index f1cf503..12e8ee8 100644 >>>>>> --- a/drivers/mtd/nand/Kconfig >>>>>> +++ b/drivers/mtd/nand/Kconfig >>>>>> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 >>>>>> >>>>>> config MTD_NAND_OMAP_BCH >>>>>> depends on MTD_NAND_OMAP2 >>>>>> - tristate "Support hardware based BCH error correction" >>>>>> + bool "Support hardware based BCH error correction" >>>>>> default n >>>>>> select BCH >>>>>> help >>>>>> @@ -106,6 +106,12 @@ config MTD_NAND_OMAP_BCH >>>>>> legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine >>>>>> so they should not enable this config symbol. >>>>>> >>>>>> +config MTD_NAND_OMAP_BCH_BUILD >>>>>> + tristate >>>>>> + depends on MTD_NAND_OMAP2 >>>>>> + default m if MTD_NAND_OMAP2=m && MTD_NAND_OMAP_BCH >>>>>> + default y if MTD_NAND_OMAP2=y && MTD_NAND_OMAP_BCH >> >> I think the last 2 lines could be combined: >> >> default MTD_NAND_OMAP2 if MTD_NAND_OMAP_BCH >> >>>>>> + >>>>>> config MTD_NAND_IDS >>>>>> tristate >>>>>> >>>>>> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile >>>>>> index 4bcdeb0..3580188 100644 >>>>>> --- a/drivers/mtd/nand/Makefile >>>>>> +++ b/drivers/mtd/nand/Makefile >>>>>> @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o >>>>>> obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o >>>>>> obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o >>>>>> obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o >>>>>> -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o >>>>>> +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o >>>>>> obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o >>>>>> obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o >>>>>> obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o >> >> Apparently I came up with a nearly identical solution, so it must be >> good! ;) >> >>>>> The overall logic seems to work but I still see the following issue. >>>>> >>>>> In menuconfig, the OMAP_BCH option is still visible as a boolean even though >>>>> the ELM module finally gets built as a module. >>>>> This can be confusing to the user and I'd avoid that behaviour. >>>>> >>>> >>>> Yes, I know. But it's either this solution or no solution at all, I think. >>>> >>>> Let me give some further context about this patch, so we can have more >>>> information to decide. >>>> >>>> First of all (and IMO) the user doesn't have to know about the ELM being >>>> a module or not, because modprobe will load it (since omap2_nand depends >>>> on omap_elm's symbols). >>>> >>>> So, the new way seems a bit more intuitive for me. The user choses if he >>>> wants to have hardware BCH support, and such support gets built the right >>>> way. >>>> >>>> If we still consider this highly confusing, and we want to avoid it, >>>> then it seems we can only make omap_elm a boolean, which means it'll always >>>> be built-in. I crafted this patch in an effort to avoid making it boolean. >>>> >>>> Finally, the solution is taken from media/usb/stk1160. For good or for bad, >>>> we have a precedent in doing things this way. >>>> >>>> Ultimately, I don't care much as I don't think anyone will build it as a module, >>>> except maybe for testing the driver under probe/remove cycles. >>>> >>> OK. I personally prefer boolean than the Kconfig magic as it makes my life a bit >>> easier and less confusing to the user i.e. wysiwyg ;). >>> >>> Let's see what the MTD maintainers prefer. >>> Brian and David, any insights on this problem? >> >> It seems like 'elm' serves more as an accessory piece of omap2.{o,ko}, >> not really a separate module, so it's possible it'd make your life even >> easier to just link elm.o into omap2.o. There's no requirement that two >> source files create two separate kernel modules. I think this would >> present the simplest possible interface to the user. >> >> Thoughts? >> > > Yeah, but that means a larger refactoring, because now you'd have to > call the ELM driver probe() from the NAND driver probe(). > > It'd be a nice cleanup, but maybe this is the second step? > Yes, let's do this as a next step. For now I prefer OMAP_BCH to be boolean over module. Keeping BCH as module gives no added benefit. cheers, -roger From RHurdle at Rugged.com Thu Sep 18 09:17:56 2014 From: RHurdle at Rugged.com (Robert Hurdle) Date: Thu, 18 Sep 2014 09:17:56 -0700 Subject: Question about adding a NAND device In-Reply-To: References: <5498E86A4A68B14A8A06D0380640D04A01FA6854E73D@atca01em01.adsi.aitech.ent> Message-ID: <5498E86A4A68B14A8A06D0380640D04A01FA685FDFDD@atca01em01.adsi.aitech.ent> Thank you. Robert Hurdle -----Original Message----- From: Ricard Wanderlof [mailto:ricard.wanderlof at axis.com] Sent: Thursday, September 18, 2014 1:03 AM To: Robert Hurdle Cc: linux-mtd at lists.infradead.org Subject: Re: Question about adding a NAND device On Wed, 17 Sep 2014, Robert Hurdle wrote: > Hello, > > I have ported some of u-boot to our board, and I am booting successfully from EEPROM. > I am now in the process of adding the NAND and flash file system support for our non-standard > flash interface (there's an FPGA interface between the software and the 1 giga-byte NAND) to > u-boot and also to the Linux kernel. In addition, it is our intention to support UBIFS on our board. > > It appears that I need to understand how the structures mtd_info and nand_chip (and whatever > they point at) and code in nand_base.c work, in order to provide working routines at the NAND > level. I have looked at some of the files in u-boot/drivers/mtd/nand for other boards, and see > a wide variety of models, no doubt based on the hardware differences. Because of our FPGA > interface, I need to have all commands to the NAND chip get re-packaged into commands that > get passed to the FPGA. Am I on the right path? > > My other question is how long would one guess that this task would take for someone fairly > competent, but uninitiated in UBIFS, UBI, MTD, NAND, etc. ? It's very hard to predict any form of time frame, especially when not knowing much about the hardware. If your FPGA basically just passes data between the CPU and flash on a byte-by-byte level, then you can probably take some simple driver and rewrite that. If the FPGA contains a more advanced NAND flash controller, which performs ECC, or does something else on a higher level you need to study the way nand_base.c goes about things and also of course the controller implementation in the FPGA. Basically, mtd was originally written with a byte-by-byte interface in mind. So that case is fairly easy to implement: your driver will just have to be able to send data to and read from the flash via FPGA (in this case), and also control the NAND flash CLE and ALE lines, as well as read the READY/BUSY line from the flash. All command sequencing, data transfer and ECC will be handled in software by the mtd layer. For more advanced cases, there are numerous hooks which can be used where the NAND flash controller accelerate specific functions. In my experience though it requires a lot more understanding of exactly how nand_base.c goes about things, and there is often more than one way to implement the required functionality. Looking at driver code for other NAND flash controllers also helps. /Ricard -- Ricard Wolf Wanderl?f ricardw(at)axis.com Axis Communications AB, Lund, Sweden www.axis.com Phone +46 46 272 2016 Fax +46 46 13 61 30 From fabf at skynet.be Thu Sep 18 11:46:16 2014 From: fabf at skynet.be (Fabian Frederick) Date: Thu, 18 Sep 2014 20:46:16 +0200 Subject: [PATCH 1/1] jffs2: fix sparse warning: unexpected unlock Message-ID: <1411065976-20386-1-git-send-email-fabf@skynet.be> fs/jffs2/summary.c:846:5: warning: context imbalance in 'jffs2_sum_write_sumnode' - unexpected unlock Signed-off-by: Fabian Frederick --- fs/jffs2/summary.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index c522d09..a0bac7b 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -844,6 +844,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock /* Write out summary information - called from jffs2_do_reserve_space */ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) + __releases(&c->erase_completion_lock) + __acquires(&c->erase_completion_lock) { int datasize, infosize, padsize; struct jffs2_eraseblock *jeb; -- 1.9.1 From richard at nod.at Fri Sep 19 02:46:21 2014 From: richard at nod.at (Richard Weinberger) Date: Fri, 19 Sep 2014 11:46:21 +0200 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1410946526.28850.120.camel@sauron.fi.intel.com> References: <1410853702-11616-1-git-send-email-richard@nod.at> <1410946526.28850.120.camel@sauron.fi.intel.com> Message-ID: <541BFB6D.3040903@nod.at> Am 17.09.2014 11:35, schrieb Artem Bityutskiy: > On Tue, 2014-09-16 at 09:48 +0200, Richard Weinberger wrote: >> If sync_erase() failes with EINTR, ENOMEM, EAGAIN or >> EBUSY erase_worker() re-schedules the failed work. >> This will lead to a deadlock because erase_worker() is called >> with work_sem held in read mode. And schedule_erase() will take >> this lock again. > > There is this code snippet: > > ubi_err("failed to erase PEB %d, error %d", pnum, err); > kfree(wl_wrk); > > if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || > err == -EBUSY) { > int err1; > > /* Re-schedule the LEB for erasure */ > err1 = schedule_erase(ubi, e, vol_id, lnum, 0); > if (err1) { > err = err1; > goto out_ro; > } > return err; > } > > How about move 'kfree(wl_wrk)' down, and execute > > __schedule_ubi_work(ubi, wl_wrk) > > inside the 'if' clause instead? The fix would seem to be more elegant > then. > > Hmm? Yes, that would work too. Or we apply "[PATCH 1/2] UBI: Call worker functions without work_sem held". :) Thanks, //richard From richard at nod.at Fri Sep 19 02:48:47 2014 From: richard at nod.at (Richard Weinberger) Date: Fri, 19 Sep 2014 11:48:47 +0200 Subject: [PATCH 2/2] UBI: Improve comment on work_sem In-Reply-To: <1411120127-18787-1-git-send-email-richard@nod.at> References: <1411120127-18787-1-git-send-email-richard@nod.at> Message-ID: <1411120127-18787-2-git-send-email-richard@nod.at> Make clear what work_sem really does. Suggested-by: Artem Bityutskiy Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/ubi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..f2933df 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -439,7 +439,8 @@ struct ubi_debug_info { * @move_to, @move_to_put @erase_pending, @wl_scheduled, @works, * @erroneous, and @erroneous_peb_count fields * @move_mutex: serializes eraseblock moves - * @work_sem: synchronizes the WL worker with use tasks + * @work_sem: used to wait for all the scheduled works to finish and prevent + * new works from being submitted * @wl_scheduled: non-zero if the wear-leveling was scheduled * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any * physical eraseblock -- 1.8.4.5 From richard at nod.at Fri Sep 19 02:48:46 2014 From: richard at nod.at (Richard Weinberger) Date: Fri, 19 Sep 2014 11:48:46 +0200 Subject: [PATCH 1/2] UBIFS: Remove bogus assert Message-ID: <1411120127-18787-1-git-send-email-richard@nod.at> This assertion was only correct before UBIFS had xattr support. Now with xattr support also a directory node can carry data and can act as host node. Suggested-by: Artem Bityutskiy Signed-off-by: Richard Weinberger --- fs/ubifs/journal.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 0e045e7..fb166e2 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -546,15 +546,14 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, int aligned_dlen, aligned_ilen, sync = IS_DIRSYNC(dir); int last_reference = !!(deletion && inode->i_nlink == 0); struct ubifs_inode *ui = ubifs_inode(inode); - struct ubifs_inode *dir_ui = ubifs_inode(dir); + struct ubifs_inode *host_ui = ubifs_inode(dir); struct ubifs_dent_node *dent; struct ubifs_ino_node *ino; union ubifs_key dent_key, ino_key; dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu", inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino); - ubifs_assert(dir_ui->data_len == 0); - ubifs_assert(mutex_is_locked(&dir_ui->ui_mutex)); + ubifs_assert(mutex_is_locked(&host_ui->ui_mutex)); dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; ilen = UBIFS_INO_NODE_SZ; @@ -658,7 +657,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ui->synced_i_size = ui->ui_size; spin_unlock(&ui->ui_lock); mark_inode_clean(c, ui); - mark_inode_clean(c, dir_ui); + mark_inode_clean(c, host_ui); return 0; out_finish: -- 1.8.4.5 From dedekind1 at gmail.com Fri Sep 19 03:47:27 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 13:47:27 +0300 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <541BFB6D.3040903@nod.at> References: <1410853702-11616-1-git-send-email-richard@nod.at> <1410946526.28850.120.camel@sauron.fi.intel.com> <541BFB6D.3040903@nod.at> Message-ID: <1411123647.28850.138.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 11:46 +0200, Richard Weinberg > Or we apply "[PATCH 1/2] UBI: Call worker functions without work_sem held". :) But I explained in the other e-mail that the semaphore is needed, and why. -- Best Regards, Artem Bityutskiy From dan.carpenter at oracle.com Fri Sep 19 03:56:56 2014 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Fri, 19 Sep 2014 13:56:56 +0300 Subject: [patch] UBI: return on error in rename_volumes() Message-ID: <20140919104848.GC26391@mwanda> I noticed this during a code review. We are checking that the strlen() of ->name is not less than the ->name_len which the user gave us. I believe this bug is harmless but clearly we meant to return here instead of setting an error code and then not using it. Signed-off-by: Dan Carpenter --- I'm not totally familiar with the code so please review extra carefully. diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 20aeb27..59de69a 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -701,7 +701,7 @@ static int rename_volumes(struct ubi_device *ubi, req->ents[i].name[req->ents[i].name_len] = '\0'; n = strlen(req->ents[i].name); if (n != req->ents[i].name_len) - err = -EINVAL; + return -EINVAL; } /* Make sure volume IDs and names are unique */ From richard at nod.at Fri Sep 19 04:01:18 2014 From: richard at nod.at (Richard Weinberger) Date: Fri, 19 Sep 2014 13:01:18 +0200 Subject: [PATCH] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1411123647.28850.138.camel@sauron.fi.intel.com> References: <1410853702-11616-1-git-send-email-richard@nod.at> <1410946526.28850.120.camel@sauron.fi.intel.com> <541BFB6D.3040903@nod.at> <1411123647.28850.138.camel@sauron.fi.intel.com> Message-ID: <541C0CFE.2090609@nod.at> Am 19.09.2014 12:47, schrieb Artem Bityutskiy: > On Fri, 2014-09-19 at 11:46 +0200, Richard Weinberg >> Or we apply "[PATCH 1/2] UBI: Call worker functions without work_sem held". :) > > But I explained in the other e-mail that the semaphore is needed, and > why. Sorry, I completely misunderstood your mail. Rereading it now. Thanks, //richard From dedekind1 at gmail.com Fri Sep 19 08:15:31 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 18:15:31 +0300 Subject: [PATCH 1/2] UBIFS: Remove bogus assert In-Reply-To: <1411120127-18787-1-git-send-email-richard@nod.at> References: <1411120127-18787-1-git-send-email-richard@nod.at> Message-ID: <1411139731.28850.145.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 11:48 +0200, Richard Weinberger wrote: > This assertion was only correct before UBIFS had xattr support. > Now with xattr support also a directory node can carry data > and can act as host node. > > Suggested-by: Artem Bityutskiy > Signed-off-by: Richard Weinberger Pushed both, thank you! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 19 08:15:21 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 18:15:21 +0300 Subject: [patch] UBI: return on error in rename_volumes() In-Reply-To: <20140919104848.GC26391@mwanda> References: <20140919104848.GC26391@mwanda> Message-ID: <1411139721.28850.143.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 13:56 +0300, Dan Carpenter wrote: > I noticed this during a code review. We are checking that the strlen() > of ->name is not less than the ->name_len which the user gave us. I > believe this bug is harmless but clearly we meant to return here instead > of setting an error code and then not using it. Pushed to linux-ubifs.git, thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 19 08:27:29 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 18:27:29 +0300 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> Message-ID: <1411140449.28850.152.camel@sauron.fi.intel.com> On Tue, 2014-09-16 at 10:04 -0400, Atlant Schmidt wrote: > Folks: > > We use the ordinary MTD/UBI/UBIfs stack on our > Embedded Linux system. > > For the purposes of scrubbing-out single bit errors, > I'd like to read through all of the LEBs stored in the > UBI device and whenever the ECC information indicates > that any correctable errors occurred, I'd like to > *RE-WRITE* that LEB (thereby forcing it to be scrubbed). > (Note: I might do this page-by-page rather than LEB- > by-LEB.) Well, you may do something like dd if=/dev/ubiX_Y of=/dev/null For all volumes, and this will make UBI real all pages from all volumes and whenever there was a bit-flip, schedule the LEB for scrubbing. The volume table LEBs wont'd be read, though. To cover even that, you one could introduce a special ioctl. In case of fastmap, this ioctl would cover all the fatmap special LEBs too. > But I would expect that because I'd have a hard > (impossible?) time doing an atomic read/re-write of a > LEB (or page), the UBIfs and my scrubber would interact > badly with my scrubber eventually corrupting the UBIfs > file system. Is there any easy way to interlock these > accesses (from the UBIfs and from my UBI-level scrubber)? > A way to temporarily suspend activity from the UBIfs? > > One kludge that might work is that I'm operating in a > real-time environment. If I made my scrubbing requests > from a very high priority (higher than the "System" > tasks that run around Priority 50), could I be sure > my read + rewrite scrubbing requests would at least > enter the UBI's work queue immediately adjacent to > each other (and without UBIfs requests intermingled)? > > Alternatively, I could probably dismount the UBIfs > before doing scrubbing, but I'd rather not have to > do that. You do not need to do unmount anything with the above technique. If, say, UBI scheduled an LEB 0:1 (volume 0, LEB 1) for scrubbing, and UBIFS (which has volume 0 mounted) writes to LEB 1, UBI will block the writer until the scrubbing finishes, so you do not have to worry. HTH. -- Best Regards, Artem Bityutskiy From richard at nod.at Fri Sep 19 08:37:56 2014 From: richard at nod.at (Richard Weinberger) Date: Fri, 19 Sep 2014 17:37:56 +0200 Subject: [PATCH] UBI: Fix livelock in produce_free_peb() Message-ID: <1411141076-21489-1-git-send-email-richard@nod.at> The while loop in produce_free_peb() assumes that each work will produce a free PEB. This is not true. If ubi->works_count is 1 and the only scheduled work is the wear_leveling_worker() produce_free_peb() can loop forever in case nobody schedules an erase work. Fix this issue by checking in the while loop whether work is scheduled. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 0509c8a..6add739 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -272,7 +272,7 @@ static int produce_free_peb(struct ubi_device *ubi) { int err; - while (!ubi->free.rb_node) { + while (!ubi->free.rb_node && ubi->works_count) { spin_unlock(&ubi->wl_lock); dbg_wl("do one work synchronously"); -- 1.8.4.5 From computersforpeace at gmail.com Fri Sep 19 09:34:31 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 09:34:31 -0700 Subject: [PATCH v2] mtd: atmel_nand: make PMECC lookup table and offset property optional In-Reply-To: <541A92E3.60906@atmel.com> References: <1408345720-5402-1-git-send-email-josh.wu@atmel.com> <20140918003258.GD1193@ld-irv-0074> <541A92E3.60906@atmel.com> Message-ID: <20140919163431.GE1193@ld-irv-0074> On Thu, Sep 18, 2014 at 04:08:03PM +0800, Josh Wu wrote: > On 9/18/2014 8:32 AM, Brian Norris wrote: > >On Mon, Aug 18, 2014 at 03:08:40PM +0800, Josh Wu wrote: > >>+static int pmecc_build_galois_table(int mm, > >>+ int16_t *index_of, int16_t *alpha_to) > >>+{ ... > >>+} > >Is this algorithm documented? How did you come up with this? > > It is not documented in datasheet. It is based BCH algorithm. But do > you know if the soft BCH use a same table like this? I haven't delved into the algorithms here too much. Other BCH/ECC codes do similar steps, but either (1) there's usually a few comments about their origin or else (2) they're transparently handled by hardware ECC engines and software doesn't need to care about the details much. Brian From aschmidt at dekaresearch.com Fri Sep 19 09:58:45 2014 From: aschmidt at dekaresearch.com (Atlant Schmidt) Date: Fri, 19 Sep 2014 12:58:45 -0400 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <1411140449.28850.152.camel@sauron.fi.intel.com> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> Message-ID: <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> Artem: Thanks, but the key was in this line of my question: > For the purposes of scrubbing-out *SINGLE BIT* errors, Single bit errors are below the threshold set by either current UBI software or newer NAND Flash chips that contain on-board ECC and set a "Rewrite recommended" Status Register bit. That's why I proposed doing the UBI-level LEB rewrites myself, any time even a single bit-flip was reported as being corrected. For software ECC done in the UBI code, I guess one strategy (as we discussed a few months back) is to modify the UBI code so it schedules a block for scrubbing even if a single-bit correctable error occurs. For ONFI Flash with hardware ECC, I'm not sure there is a solution; I don't see where the ONFI Flash reports "correctable error but not at the rewrite threshold"; a read seems to either: o Succeed (with no or few corrections; no special report generated) o Succeed (with "Rewrite" being recommended) o Fail Maybe I'll ask Micron's tech-support folks if there's more info available than is made obvious in the datasheet. Atlant -----Original Message----- From: Artem Bityutskiy [mailto:dedekind1 at gmail.com] Sent: Friday, September 19, 2014 11:27 AM To: Atlant Schmidt Cc: linux-mtd at lists.infradead.org Subject: Re: Does UBI LEB-level access interlock happily with UBIfs access? On Tue, 2014-09-16 at 10:04 -0400, Atlant Schmidt wrote: > Folks: > > We use the ordinary MTD/UBI/UBIfs stack on our > Embedded Linux system. > > For the purposes of scrubbing-out single bit errors, > I'd like to read through all of the LEBs stored in the > UBI device and whenever the ECC information indicates > that any correctable errors occurred, I'd like to > *RE-WRITE* that LEB (thereby forcing it to be scrubbed). > (Note: I might do this page-by-page rather than LEB- > by-LEB.) Well, you may do something like dd if=/dev/ubiX_Y of=/dev/null For all volumes, and this will make UBI real all pages from all volumes and whenever there was a bit-flip, schedule the LEB for scrubbing. The volume table LEBs wont'd be read, though. To cover even that, you one could introduce a special ioctl. In case of fastmap, this ioctl would cover all the fatmap special LEBs too. > But I would expect that because I'd have a hard > (impossible?) time doing an atomic read/re-write of a > LEB (or page), the UBIfs and my scrubber would interact > badly with my scrubber eventually corrupting the UBIfs > file system. Is there any easy way to interlock these > accesses (from the UBIfs and from my UBI-level scrubber)? > A way to temporarily suspend activity from the UBIfs? > > One kludge that might work is that I'm operating in a > real-time environment. If I made my scrubbing requests > from a very high priority (higher than the "System" > tasks that run around Priority 50), could I be sure > my read + rewrite scrubbing requests would at least > enter the UBI's work queue immediately adjacent to > each other (and without UBIfs requests intermingled)? > > Alternatively, I could probably dismount the UBIfs > before doing scrubbing, but I'd rather not have to > do that. You do not need to do unmount anything with the above technique. If, say, UBI scheduled an LEB 0:1 (volume 0, LEB 1) for scrubbing, and UBIFS (which has volume 0 mounted) writes to LEB 1, UBI will block the writer until the scrubbing finishes, so you do not have to worry. HTH. -- Best Regards, Artem Bityutskiy This e-mail and the information, including any attachments it contains, are intended to be a confidential communication only to the person or entity to whom it is addressed and may contain information that is privileged. If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please immediately notify the sender and destroy the original message. Thank you. Please consider the environment before printing this email. From computersforpeace at gmail.com Fri Sep 19 10:00:20 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 10:00:20 -0700 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> Message-ID: <20140919170020.GF1193@ld-irv-0074> On Tue, Sep 16, 2014 at 08:04:18PM +0900, Masahiro Yamada wrote: > > > Masahiro Yamada (7): > mtd: denali: fix the format of comment blocks > mtd: denali: remove unnecessary variable initializations > mtd: denali: remove unnecessary casts > mtd: denali: change the type of iterators to int I already merged these 4. > mtd: denali: remove a set-but-unused variable This one was merged but you changed it (and falsely kept the 'Reviewed-by' tag). So I split it out into its own patch and dropped the 'Reviewed-by'. > mtd: denali: remove unnecessary parentheses > mtd: denali: fix indents and other trivial things Applied a modified version of the last three, to l2-mtd.git. Feel free to check my work, but git tells me that the end result is identical. > drivers/mtd/nand/denali.c | 558 +++++++++++++++++++++++++--------------------- > 1 file changed, 301 insertions(+), 257 deletions(-) > Brian From computersforpeace at gmail.com Fri Sep 19 10:01:48 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 10:01:48 -0700 Subject: [PATCH] MAINTAINERS: add l2-mtd.git, 'next' tree for MTD In-Reply-To: <1410843377-30159-1-git-send-email-computersforpeace@gmail.com> References: <1410843377-30159-1-git-send-email-computersforpeace@gmail.com> Message-ID: <20140919170148.GG1193@ld-irv-0074> On Mon, Sep 15, 2014 at 09:56:17PM -0700, Brian Norris wrote: > We've been semi-officially queueing patches here for a while, and it's > in linux-next, so let's advertise it in MAINTAINERS. > > Signed-off-by: Brian Norris Applied to l2-mtd.git. Brian From computersforpeace at gmail.com Fri Sep 19 10:06:52 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 10:06:52 -0700 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> Message-ID: <20140919170652.GH1193@ld-irv-0074> On Tue, Sep 16, 2014 at 10:04:29AM -0400, Atlant Schmidt wrote: > This e-mail and the information, including any attachments it > contains, are intended to be a confidential communication only to the > person or entity to whom it is addressed and may contain information > that is privileged. If the reader of this message is not the intended > recipient, you are hereby notified that any dissemination, > distribution or copying of this communication is strictly prohibited. > If you have received this communication in error, please immediately > notify the sender and destroy the original message. Can you please consider dropping this notice from your email? It's effectively useless when you're sending mail to a publicly-accessible (and indefinitely archived) mailing list. Thanks, Brian From dedekind1 at gmail.com Fri Sep 19 10:13:53 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 20:13:53 +0300 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> Message-ID: <1411146833.23429.11.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 12:58 -0400, Atlant Schmidt wrote: > Artem: > > Thanks, but the key was in this line of my question: > > > For the purposes of scrubbing-out *SINGLE BIT* errors, > > > Single bit errors are below the threshold set by either > current UBI software or newer NAND Flash chips that > contain on-board ECC and set a "Rewrite recommended" > Status Register bit. This is MTD hiding these bit-flips from UBI. The idea is that depending on the flash/controller, you may want to scrub or ignore bit-flips lower than certain level. Indeed, for some NANDs 1-bit flips happen on nearly every read, scrubbing them all is not feasible. Sow what you say sounds like you want to lower the bit-flip handling threshold. To do this, you either need to amend your driver to have the default threshold that you need, or change the /sys/class/mtd/mtdX/bitflip_threshold value (do not remember for sure, but I believe it is writable). Please, refer to the documentation here: Documentation/ABI/testing/sysfs-class-mtd > That's why I proposed doing the UBI-level LEB rewrites > myself, any time even a single bit-flip was reported as > being corrected. Well, if you feel comfortable with this, go ahead, but without knowing the particulars of your systems, this sounds like asking for troubles. Indeed, changing something underneath the live volume manager (UBI) and file-system (UBIFS) is error-prone at the very least. Asking UBI to do this sounds a lot better. But again, I do not know the specific of the system you are designing. > For software ECC done in the UBI code, I guess one > strategy (as we discussed a few months back) is to > modify the UBI code so it schedules a block for > scrubbing even if a single-bit correctable error > occurs. All you need to do is to lower 'bitflip_threshold' instead. But note, this will be "passive" scrubbing, meaning that UBI will scrub only when there is a read operation. But the read operation may be extremely rare for certain LEBs, and the data may bit-rot due to various "radiation" effects (doing I/O on the neighbor PEBs). So I suggested you to just read all volumes periodically from the user-space, may be from a background cron task. But as I pointed, this will not force re-read of the volume table LEBs. To address this, you'd need to do some additional, not very difficult work. -- Best Regards, Artem Bityutskiy From aschmidt at dekaresearch.com Fri Sep 19 10:17:30 2014 From: aschmidt at dekaresearch.com (Atlant Schmidt) Date: Fri, 19 Sep 2014 13:17:30 -0400 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <1411146833.23429.11.camel@sauron.fi.intel.com> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> <1411146833.23429.11.camel@sauron.fi.intel.com> Message-ID: <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> Artem: Thanks -- that's all consistent with my current thinking. Atlant -----Original Message----- From: Artem Bityutskiy [mailto:dedekind1 at gmail.com] Sent: Friday, September 19, 2014 1:14 PM To: Atlant Schmidt Cc: linux-mtd at lists.infradead.org Subject: Re: Does UBI LEB-level access interlock happily with UBIfs access? On Fri, 2014-09-19 at 12:58 -0400, Atlant Schmidt wrote: > Artem: > > Thanks, but the key was in this line of my question: > > > For the purposes of scrubbing-out *SINGLE BIT* errors, > > > Single bit errors are below the threshold set by either > current UBI software or newer NAND Flash chips that > contain on-board ECC and set a "Rewrite recommended" > Status Register bit. This is MTD hiding these bit-flips from UBI. The idea is that depending on the flash/controller, you may want to scrub or ignore bit-flips lower than certain level. Indeed, for some NANDs 1-bit flips happen on nearly every read, scrubbing them all is not feasible. Sow what you say sounds like you want to lower the bit-flip handling threshold. To do this, you either need to amend your driver to have the default threshold that you need, or change the /sys/class/mtd/mtdX/bitflip_threshold value (do not remember for sure, but I believe it is writable). Please, refer to the documentation here: Documentation/ABI/testing/sysfs-class-mtd > That's why I proposed doing the UBI-level LEB rewrites > myself, any time even a single bit-flip was reported as > being corrected. Well, if you feel comfortable with this, go ahead, but without knowing the particulars of your systems, this sounds like asking for troubles. Indeed, changing something underneath the live volume manager (UBI) and file-system (UBIFS) is error-prone at the very least. Asking UBI to do this sounds a lot better. But again, I do not know the specific of the system you are designing. > For software ECC done in the UBI code, I guess one > strategy (as we discussed a few months back) is to > modify the UBI code so it schedules a block for > scrubbing even if a single-bit correctable error > occurs. All you need to do is to lower 'bitflip_threshold' instead. But note, this will be "passive" scrubbing, meaning that UBI will scrub only when there is a read operation. But the read operation may be extremely rare for certain LEBs, and the data may bit-rot due to various "radiation" effects (doing I/O on the neighbor PEBs). So I suggested you to just read all volumes periodically from the user-space, may be from a background cron task. But as I pointed, this will not force re-read of the volume table LEBs. To address this, you'd need to do some additional, not very difficult work. -- Best Regards, Artem Bityutskiy This e-mail and the information, including any attachments it contains, are intended to be a confidential communication only to the person or entity to whom it is addressed and may contain information that is privileged. If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please immediately notify the sender and destroy the original message. Thank you. Please consider the environment before printing this email. From dedekind1 at gmail.com Fri Sep 19 10:24:11 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 19 Sep 2014 20:24:11 +0300 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> <1411146833.23429.11.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> Message-ID: <1411147451.23429.20.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 13:17 -0400, Atlant Schmidt wrote: > But as I pointed, this will not force re-read of the volume table LEBs. > To address this, you'd need to do some additional, not very difficult > work. Oh, and this won't make UBI re-read the EC and VID headers, so they may bit-rot too. So indeed it sounds like UBI needs a separate interface for this kind of "scrub all bit-flips" issues. I do not think it is hard to do - all the mechanisms are already implemented, so this would mostly be about inventing good API. -- Best Regards, Artem Bityutskiy From computersforpeace at gmail.com Fri Sep 19 21:34:38 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 21:34:38 -0700 Subject: [PATCH v4 0/2] mtd: nand: add sunxi NAND flash controller support In-Reply-To: <1408382788-32153-1-git-send-email-boris.brezillon@free-electrons.com> References: <1408382788-32153-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140920043438.GD8127@brian-ubuntu> Hi Boris, On Mon, Aug 18, 2014 at 07:26:26PM +0200, Boris BREZILLON wrote: > This patch series adds support for the sunxi NAND Flash Controller (NFC) > block. > > These two patches only add support for the basic NAND stuff: > - NAND controller operations > - SW and HW ECC handling (with both syndrome and normal ECC scheme) > > If you want support for advanced features you can find it on my github > repo [1]: > - HW randomization support > - per partition ECC/Randomizer to handle bootloader partitions > > DMA transfers are not supported yet, but I have reworked the OOB layout > when using the HW ECC scheme to match the one used when accessing the NAND > with DMA transfers (the available OOB bytes are placed at the end of the > OOB area). > > This patch series depends on this other one [2] which adds support for ONFI > timing mode retrieval on non-ONFI NANDs. Were you planning to send v2 of your series [2]? I see you made a mistake you were planning on fixing: https://lkml.org/lkml/2014/7/30/423 Brian > Best Regards, > > Boris > > [1]https://github.com/bbrezillon/linux-sunxi/tree/sunxi-nand-v4 > [2]https://lkml.org/lkml/2014/7/28/156 > > Changes since v3: > - removed nand core code modifications from the patch series (submitted > separately) > - added documentation to the code > - forced timeout (a default timeout is used when none is provided by the > caller) on controller operations > - fixed coding style issues > - removed unneeded irq field from the sunxi_nfc struct > - fixed several memory leaks > - reworked the NFC reset code (to avoid potential garbage config from the > bootloader) > - made use of ECC_EXCEPTION flag to prevent erased page from generating > ECC errors > - changed the OOB layout for HW ECC scheme > > Changes since v2: > - merge HW ECC implementation in base implementation patch > - fix timing config when interfacing with an ONFI compatible chip > > Changes since v1: > - add HW ECC support > - rework NAND timings retrieval (use ONFI timing mode instead of raw timings) > - add nand-ecc-level property to specify NAND ECC requirements from DT > > Boris BREZILLON (2): > mtd: nand: add sunxi NAND flash controller support > mtd: nand: add sunxi NFC dt bindings doc > > .../devicetree/bindings/mtd/sunxi-nand.txt | 45 + > drivers/mtd/nand/Kconfig | 6 + > drivers/mtd/nand/Makefile | 1 + > drivers/mtd/nand/sunxi_nand.c | 1362 ++++++++++++++++++++ > 4 files changed, 1414 insertions(+) > create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt > create mode 100644 drivers/mtd/nand/sunxi_nand.c > From computersforpeace at gmail.com Fri Sep 19 21:46:07 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Fri, 19 Sep 2014 21:46:07 -0700 Subject: [PATCH 1/2] mtd: nand: support ONFI timings mode retrieval for non-ONFI NANDs In-Reply-To: <1406539012-16320-2-git-send-email-boris.brezillon@free-electrons.com> References: <1406539012-16320-1-git-send-email-boris.brezillon@free-electrons.com> <1406539012-16320-2-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140920044607.GE8127@brian-ubuntu> Since you were asking about this series, I have a comment: On Mon, Jul 28, 2014 at 11:16:51AM +0200, Boris BREZILLON wrote: > Add an onfi_timing_mode_ds field to nand_chip and nand_flash_dev in order > to support NAND timings definition for non-ONFI NAND. > > NAND that support better timings mode than the default one (timings mode 0) > have to define a new entry in the nand_ids table. > > The timings mode should be deduced from timings description from the > datasheet and the ONFI specification > (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 > "Timing Parameters"). > You should choose the closest mode that fit the timings requirements of > your NAND chip. > > Signed-off-by: Boris BREZILLON > --- > drivers/mtd/nand/nand_base.c | 1 + > include/linux/mtd/nand.h | 7 +++++++ > 2 files changed, 8 insertions(+) > > diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c > index d8cdf06..c952c21 100644 > --- a/drivers/mtd/nand/nand_base.c > +++ b/drivers/mtd/nand/nand_base.c > @@ -3576,6 +3576,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, > chip->options |= type->options; > chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); > chip->ecc_step_ds = NAND_ECC_STEP(type); > + chip->onfi_timing_mode_ds = type->onfi_timing_mode_ds; > > *busw = type->options & NAND_BUSWIDTH_16; > > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h > index 3083c53..435c005 100644 > --- a/include/linux/mtd/nand.h > +++ b/include/linux/mtd/nand.h > @@ -587,6 +587,7 @@ struct nand_buffers { > * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, > * also from the datasheet. It is the recommended ECC step > * size, if known; if unknown, set to zero. > + * @onfi_timing_mode_ds:[INTERN] ONFI timing mode deduced from datasheet. Might want at least one space between '[INTERN]' and 'ONFI'? > * @numchips: [INTERN] number of physical chips > * @chipsize: [INTERN] the size of one chip for multichip arrays > * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 > @@ -671,6 +672,7 @@ struct nand_chip { > uint8_t bits_per_cell; > uint16_t ecc_strength_ds; > uint16_t ecc_step_ds; > + int onfi_timing_mode_ds; I'm not sure if we'll just want a field specific to non-ONFI chips, faking an ONFI timing mode; can we make this into a more generally useful field, that represents something consistent across all NAND types? I was thinking a "highest mode supported", but that actually isn't great, since for true ONFI modes (except mode 0) require a SET FEATURES command to change to a higher mode. Maybe just something like onfi_timing_mode_default, which we could then use as mode 0 for ONFI chips. Ideally, we could centralize as much of this as possible, so that a NAND driver only has to know the mechanics of "how do I translate an ONFI mode to a timing configuration for my NAND controller," instead of any details of how to choose from one of many supported ONFI modes. i.e., it could implement something like the following hook: int (*set_timing_mode)(struct nand_sdr_timings *timing); But anyway, that's out of the scope of this series, and it may be harder than I make it sound. I just wanted to throw that out there. > int badblockpos; > int badblockbits; > > @@ -772,6 +774,10 @@ struct nand_chip { > * @ecc_step_ds in nand_chip{}, also from the datasheet. > * For example, the "4bit ECC for each 512Byte" can be set with > * NAND_ECC_INFO(4, 512). > + * @onfi_timing_mode_ds: the ONFI timing mode supported by this NAND chip. This > + * should be deduced from timings described in the > + * datasheet. > + * > */ > struct nand_flash_dev { > char *name; > @@ -792,6 +798,7 @@ struct nand_flash_dev { > uint16_t strength_ds; > uint16_t step_ds; > } ecc; > + int onfi_timing_mode_ds; > }; > > /** Brian From hujianyang at huawei.com Fri Sep 19 21:59:53 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 12:59:53 +0800 Subject: [PATCH RFC v3] ubi-utils: Introduce a utility ubidump Message-ID: <541D09C9.4080004@huawei.com> Hi all, It's about two months after the pushing of my v2 patches. I'd like to resend these v3 patches and discuss with you about the debugging of UBIFS. I wish you are not tried with this stuff. I have to say these v3 patches don't make a great difference with the previous versions. Just simplify, I've removed ubi-level dump. So the lpt-leb dump is not supported as before. I want to know if we could start at this version and add other functionality step by step. Thanks~! v1: http://lists.infradead.org/pipermail/linux-mtd/2014-July/054541.html v2: http://lists.infradead.org/pipermail/linux-mtd/2014-July/054831.html Changes in v3: - Remove ubi-level dump so we don't need to worry about how to get ubi-level info from an UBI device. - Read ubifs stuff by read() ops which is provided by UBI driver. From hujianyang at huawei.com Fri Sep 19 22:03:29 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 13:03:29 +0800 Subject: [PATCH 1/4] ubi-utils: ubidump compile enable In-Reply-To: <541D09C9.4080004@huawei.com> References: <541D09C9.4080004@huawei.com> Message-ID: <541D0AA1.60006@huawei.com> Signed-off-by: hujianyang --- Makefile | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eade234..9dc9645 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ MTD_BINS = \ sumtool jffs2reader UBI_BINS = \ ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ - ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock + ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock \ + ubidump BINS = $(MTD_BINS) BINS += mkfs.ubifs/mkfs.ubifs @@ -115,10 +116,12 @@ obj-libiniparser.a = libiniparser.o dictionary.o obj-libscan.a = libscan.o obj-libubi.a = libubi.o obj-libubigen.a = libubigen.o +obj-libdump.a = libdump.o obj-mtdinfo = libubigen.a obj-ubinize = libubigen.a libiniparser.a obj-ubiformat = libubigen.a libscan.a +obj-ubidump = libdump.a -$(foreach v,libubi.a libubigen.a libiniparser.a libscan.a,$(eval $(call _mkdep,ubi-utils/,$(v)))) +$(foreach v,libubi.a libubigen.a libiniparser.a libscan.a libdump.a,$(eval $(call _mkdep,ubi-utils/,$(v)))) $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-common.o))) -- 1.6.0.2 From hujianyang at huawei.com Fri Sep 19 22:05:22 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 13:05:22 +0800 Subject: [PATCH 2/4] ubi-utils: ubidump add libdump In-Reply-To: <541D09C9.4080004@huawei.com> References: <541D09C9.4080004@huawei.com> Message-ID: <541D0B12.9050703@huawei.com> Signed-off-by: hujianyang --- ubi-utils/include/libdump.h | 72 ++++++++ ubi-utils/libdump.c | 414 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 486 insertions(+), 0 deletions(-) create mode 100644 ubi-utils/include/libdump.h create mode 100644 ubi-utils/libdump.c diff --git a/ubi-utils/include/libdump.h b/ubi-utils/include/libdump.h new file mode 100644 index 0000000..ee0ff77 --- /dev/null +++ b/ubi-utils/include/libdump.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * Author: Hu Jianyang + * + * UBIFS library. + */ + +#ifndef __LIBDUMP_H__ +#define __LIBDUMP_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + +#define min_t(t,x,y) ({ \ + typeof((x)) _x = (x); \ + typeof((y)) _y = (y); \ + (_x < _y) ? _x : _y; \ +}) + +/** + * ubidump - dump ubi/ubifs information + * @lnum: logical eraseblock number + * @buf: buffer to dump + * @leb_size: size of buffer/logical eraseblock size + * @info: print NODEs detailed info + * + * This function dump ubi/ubifs information on the buffer. + */ +int ubi_dump(int lnum, void *buf, int leb_size, int info); + +/* + * 'ubifs_scan_a_node()' return values. + * + * SCANNED_GARBAGE: scanned garbage + * SCANNED_EMPTY_SPACE: scanned empty space + * SCANNED_A_NODE: scanned a valid node + * SCANNED_A_CORRUPT_NODE: scanned a corrupted node + * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length + * + * Greater than zero means: 'scanned that number of padding bytes' + */ +enum { + SCANNED_GARBAGE = 0, + SCANNED_EMPTY_SPACE = -1, + SCANNED_A_NODE = -2, + SCANNED_A_CORRUPT_NODE = -3, + SCANNED_A_BAD_PAD_NODE = -4, +}; + +#ifdef __cplusplus +} +#endif + +#endif /*!__LIBDUMP_H__ */ diff --git a/ubi-utils/libdump.c b/ubi-utils/libdump.c new file mode 100644 index 0000000..72cda0c --- /dev/null +++ b/ubi-utils/libdump.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * Author: Hu Jianyang + * + * UBIFS library. + */ + +#define PROGRAM_NAME "libdump" + +#include +#include +#include +#include +#include "common.h" + +static const char *get_key_fmt(int fmt) +{ + switch (fmt) { + case UBIFS_SIMPLE_KEY_FMT: + return "simple"; + default: + return "unknown/invalid format"; + } +} + +static const char *get_key_hash(int hash) +{ + switch (hash) { + case UBIFS_KEY_HASH_R5: + return "R5"; + case UBIFS_KEY_HASH_TEST: + return "test"; + default: + return "unknown/invalid name hash"; + } +} + +static const char *node_ntype(int type) +{ + switch (type) { + case UBIFS_PAD_NODE: + return "padding node"; + case UBIFS_SB_NODE: + return "superblock node"; + case UBIFS_MST_NODE: + return "master node"; + case UBIFS_REF_NODE: + return "reference node"; + case UBIFS_INO_NODE: + return "inode node"; + case UBIFS_DENT_NODE: + return "direntry node"; + case UBIFS_XENT_NODE: + return "xentry node"; + case UBIFS_DATA_NODE: + return "data node"; + case UBIFS_TRUN_NODE: + return "truncate node"; + case UBIFS_IDX_NODE: + return "indexing node"; + case UBIFS_CS_NODE: + return "commit start node"; + case UBIFS_ORPH_NODE: + return "orphan node"; + default: + return "unknown node"; + } +} + +static const char *node_gtype(int type) +{ + switch (type) { + case UBIFS_NO_NODE_GROUP: + return "no node group"; + case UBIFS_IN_NODE_GROUP: + return "in node group"; + case UBIFS_LAST_OF_NODE_GROUP: + return "last of node group"; + default: + return "unknown"; + } +} + +static void dump_ch(const struct ubifs_ch *ch) +{ + printf("\tmagic %#x\n", le32_to_cpu(ch->magic)); + printf("\tcrc %#x\n", le32_to_cpu(ch->crc)); + printf("\tnode_type %d (%s)\n", ch->node_type, + node_ntype(ch->node_type)); + printf("\tgroup_type %d (%s)\n", ch->group_type, + node_gtype(ch->group_type)); + printf("\tsqnum %llu\n", + (unsigned long long)le64_to_cpu(ch->sqnum)); + printf("\tlen %u\n", le32_to_cpu(ch->len)); +} + +static void ubifs_dump_node(const void *node) +{ + const struct ubifs_ch *ch = node; + + if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { + printf("Not a node, first %zu bytes:\n", UBIFS_CH_SZ); + return; + } + + dump_ch(node); + + switch (ch->node_type) { + case UBIFS_PAD_NODE: + { + const struct ubifs_pad_node *pad = node; + + printf("\tpad_len %u\n", le32_to_cpu(pad->pad_len)); + break; + } + case UBIFS_SB_NODE: + { + const struct ubifs_sb_node *sup = node; + unsigned int sup_flags = le32_to_cpu(sup->flags); + + printf("\tkey_hash %d (%s)\n", + (int)sup->key_hash, get_key_hash(sup->key_hash)); + printf("\tkey_fmt %d (%s)\n", + (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); + printf("\tflags %#x\n", sup_flags); + printf("\tbig_lpt %u\n", + !!(sup_flags & UBIFS_FLG_BIGLPT)); + printf("\tspace_fixup %u\n", + !!(sup_flags & UBIFS_FLG_SPACE_FIXUP)); + printf("\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size)); + printf("\tleb_size %u\n", le32_to_cpu(sup->leb_size)); + printf("\tleb_cnt %u\n", le32_to_cpu(sup->leb_cnt)); + printf("\tmax_leb_cnt %u\n", le32_to_cpu(sup->max_leb_cnt)); + printf("\tmax_bud_bytes %llu\n", + (unsigned long long)le64_to_cpu(sup->max_bud_bytes)); + printf("\tlog_lebs %u\n", le32_to_cpu(sup->log_lebs)); + printf("\tlpt_lebs %u\n", le32_to_cpu(sup->lpt_lebs)); + printf("\torph_lebs %u\n", le32_to_cpu(sup->orph_lebs)); + printf("\tjhead_cnt %u\n", le32_to_cpu(sup->jhead_cnt)); + printf("\tfanout %u\n", le32_to_cpu(sup->fanout)); + printf("\tlsave_cnt %u\n", le32_to_cpu(sup->lsave_cnt)); + printf("\tdefault_compr %u\n", + (int)le16_to_cpu(sup->default_compr)); + printf("\trp_size %llu\n", + (unsigned long long)le64_to_cpu(sup->rp_size)); + printf("\trp_uid %u\n", le32_to_cpu(sup->rp_uid)); + printf("\trp_gid %u\n", le32_to_cpu(sup->rp_gid)); + printf("\tfmt_version %u\n", le32_to_cpu(sup->fmt_version)); + printf("\ttime_gran %u\n", le32_to_cpu(sup->time_gran)); + printf("\tUUID %pUB\n", sup->uuid); + break; + } + case UBIFS_MST_NODE: + { + const struct ubifs_mst_node *mst = node; + + printf("\thighest_inum %llu\n", + (unsigned long long)le64_to_cpu(mst->highest_inum)); + printf("\tcommit number %llu\n", + (unsigned long long)le64_to_cpu(mst->cmt_no)); + printf("\tflags %#x\n", le32_to_cpu(mst->flags)); + printf("\tlog_lnum %u\n", le32_to_cpu(mst->log_lnum)); + printf("\troot_lnum %u\n", le32_to_cpu(mst->root_lnum)); + printf("\troot_offs %u\n", le32_to_cpu(mst->root_offs)); + printf("\troot_len %u\n", le32_to_cpu(mst->root_len)); + printf("\tgc_lnum %u\n", le32_to_cpu(mst->gc_lnum)); + printf("\tihead_lnum %u\n", le32_to_cpu(mst->ihead_lnum)); + printf("\tihead_offs %u\n", le32_to_cpu(mst->ihead_offs)); + printf("\tindex_size %llu\n", + (unsigned long long)le64_to_cpu(mst->index_size)); + printf("\tlpt_lnum %u\n", le32_to_cpu(mst->lpt_lnum)); + printf("\tlpt_offs %u\n", le32_to_cpu(mst->lpt_offs)); + printf("\tnhead_lnum %u\n", le32_to_cpu(mst->nhead_lnum)); + printf("\tnhead_offs %u\n", le32_to_cpu(mst->nhead_offs)); + printf("\tltab_lnum %u\n", le32_to_cpu(mst->ltab_lnum)); + printf("\tltab_offs %u\n", le32_to_cpu(mst->ltab_offs)); + printf("\tlsave_lnum %u\n", le32_to_cpu(mst->lsave_lnum)); + printf("\tlsave_offs %u\n", le32_to_cpu(mst->lsave_offs)); + printf("\tlscan_lnum %u\n", le32_to_cpu(mst->lscan_lnum)); + printf("\tleb_cnt %u\n", le32_to_cpu(mst->leb_cnt)); + printf("\tempty_lebs %u\n", le32_to_cpu(mst->empty_lebs)); + printf("\tidx_lebs %u\n", le32_to_cpu(mst->idx_lebs)); + printf("\ttotal_free %llu\n", + (unsigned long long)le64_to_cpu(mst->total_free)); + printf("\ttotal_dirty %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dirty)); + printf("\ttotal_used %llu\n", + (unsigned long long)le64_to_cpu(mst->total_used)); + printf("\ttotal_dead %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dead)); + printf("\ttotal_dark %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dark)); + break; + } + case UBIFS_REF_NODE: + { + const struct ubifs_ref_node *ref = node; + + printf("\tlnum %u\n", le32_to_cpu(ref->lnum)); + printf("\toffs %u\n", le32_to_cpu(ref->offs)); + printf("\tjhead %u\n", le32_to_cpu(ref->jhead)); + break; + } + case UBIFS_CS_NODE: + break; + case UBIFS_INO_NODE: + case UBIFS_DENT_NODE: + case UBIFS_XENT_NODE: + case UBIFS_DATA_NODE: + case UBIFS_TRUN_NODE: + case UBIFS_IDX_NODE: + case UBIFS_ORPH_NODE: + printf("cannot dump node, type not support\n"); + default: + printf("node type %d was not recognized\n", + (int)ch->node_type); + } +} + +/** + * scan_padding_bytes - scan for padding bytes. + * @buf: buffer to scan + * @len: length of buffer + * + * This function returns the number of padding bytes on success and + * %SCANNED_GARBAGE on failure. + */ +static int scan_padding_bytes(void *buf, int len) +{ + int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len); + uint8_t *p = buf; + + printf("not a node\n"); + + while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE) + pad_len += 1; + + if (!pad_len || (pad_len & 7)) + return SCANNED_GARBAGE; + + printf("%d padding bytes\n", pad_len); + + return pad_len; +} + +/** + * ubifs_scan_a_node - scan for a node or padding. + * @buf: buffer to scan + * @size: logical eraseblock size + * @len: length of buffer + * @lnum: logical eraseblock number + * @offs: offset within the logical eraseblock + * + * This function returns a scanning code to indicate what was scanned. + */ +static int ubifs_scan_a_node(void *buf, int leb_size, int len, int lnum, int offs) +{ + struct ubifs_ch *ch = buf; + uint32_t magic; + + magic = le32_to_cpu(ch->magic); + + if (magic == 0xFFFFFFFF) { + printf("hit empty space at LEB %d:%d\n", lnum, offs); + return SCANNED_EMPTY_SPACE; + } + + if (magic != UBIFS_NODE_MAGIC) + return scan_padding_bytes(buf, len); + + if (len < UBIFS_CH_SZ) + return SCANNED_GARBAGE; + + printf("scanning %s at LEB %d:%d\n", + node_ntype(ch->node_type), lnum, offs); + + /* No ubifs_check_nodei() perform here */ + + if (ch->node_type == UBIFS_PAD_NODE) { + struct ubifs_pad_node *pad = buf; + int pad_len = le32_to_cpu(pad->pad_len); + int node_len = le32_to_cpu(ch->len); + + /* Validate the padding node */ + if (pad_len < 0 || + offs + node_len + pad_len > leb_size) { + printf("bad pad node at LEB %d:%d\n", lnum, offs); + ubifs_dump_node(pad); + return SCANNED_A_BAD_PAD_NODE; + } + + /* Make the node pads to 8-byte boundary */ + if ((node_len + pad_len) & 7) { + printf("bad padding length %d - %d\n", + offs, offs + node_len + pad_len); + return SCANNED_A_BAD_PAD_NODE; + } + + printf("%d bytes padded at LEB %d:%d, offset now %d\n", pad_len, + lnum, offs, ALIGN(offs + node_len + pad_len, 8)); + + return node_len + pad_len; + } + + return SCANNED_A_NODE; +} + +/** + * ubifs_scan - scan a logical eraseblock. + * @lnum: logical eraseblock number + * @sbuf: scan buffer + * @size: size of @buf in bytes + * @offs: offset to start at (usually zero) + * @info: print NODEs detailed info + * + * This function scans LEB and prints complete information about + * its contents. + */ +static void ubifs_scan(int lnum, void *sbuf, int leb_size, int offs, int info) +{ + void *buf = sbuf + offs; + int err, len = leb_size - offs; + + printf("scan LEB %d:%d\n", lnum, offs); + + while (len >= 8) { + struct ubifs_ch *ch = buf; + int node_len, ret; + + printf("look at LEB %d:%d (%d bytes left)\n", + lnum, offs, len); + + ret = ubifs_scan_a_node(buf, leb_size, len, lnum, offs); + if (ret > 0) { + /* Padding bytes or a valid padding node */ + offs += ret; + buf += ret; + len -= ret; + continue; + } + + if (ret == SCANNED_EMPTY_SPACE) + /* Empty space is checked later */ + break; + + switch (ret) { + case SCANNED_GARBAGE: + printf("garbage\n"); + goto corrupted; + case SCANNED_A_NODE: + if (info) + ubifs_dump_node(buf); + break; + case SCANNED_A_CORRUPT_NODE: + case SCANNED_A_BAD_PAD_NODE: + printf("bad node\n"); + goto corrupted; + default: + printf("unknown\n"); + err = -EINVAL; + goto error; + } + + node_len = ALIGN(le32_to_cpu(ch->len), 8); + offs += node_len; + buf += node_len; + len -= node_len; + } + + for (; len > 4; offs += 4, buf = buf + 4, len -= 4) + if (*(uint32_t *)buf != 0xffffffff) + break; + for (; len; offs++, buf++, len--) + if (*(uint8_t *)buf != 0xff) { + printf("corrupt empty space at LEB %d:%d\n", + lnum, offs); + goto corrupted; + } + + printf("stop scanning LEB %d at offset %d\n", lnum, offs); + return; + +corrupted: + printf("corruption at LEB %d:%d\n", lnum, offs); + err = -EUCLEAN; +error: + printf("LEB %d scanning failed, error %d\n", lnum, err); +} + +/** + * ubidump - dump ubi/ubifs information + * @lnum: logical eraseblock number + * @buf: buffer to dump + * @leb_size: size of buffer/logical eraseblock size + * @info: print NODEs detailed info + * + * This function dump ubi/ubifs information on the buffer. + */ +int ubi_dump(int lnum, void *buf, int leb_size, int info) +{ + ubifs_scan(lnum, buf, leb_size, 0, info); + return 0; +} -- 1.6.0.2 From hujianyang at huawei.com Fri Sep 19 22:06:36 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 13:06:36 +0800 Subject: [PATCH 3/4] ubi-utils: ubidump add ubifs-media In-Reply-To: <541D09C9.4080004@huawei.com> References: <541D09C9.4080004@huawei.com> Message-ID: <541D0B5C.2080802@huawei.com> Signed-off-by: hujianyang --- include/mtd/ubifs-media.h | 295 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 295 insertions(+), 0 deletions(-) create mode 100644 include/mtd/ubifs-media.h diff --git a/include/mtd/ubifs-media.h b/include/mtd/ubifs-media.h new file mode 100644 index 0000000..e1767fb --- /dev/null +++ b/include/mtd/ubifs-media.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * Author: Hu Jianyang + * + * UBIFS library. + */ + +/* + * This file defines the layout of UBI headers and all the other UBIiFS + * on-flash data structures. + */ + +#ifndef __UBIFS_MEDIA_H__ +#define __UBIFS_MEDIA_H__ + +#include + +/* UBIFS node magic number (must not have the padding byte first or last) */ +#define UBIFS_NODE_MAGIC 0x06101831 + +/* UBIFS padding byte pattern (must not be first or last byte of node magic) */ +#define UBIFS_PADDING_BYTE 0xCE + +/* Node sizes (N.B. these are guaranteed to be multiples of 8) */ +#define UBIFS_CH_SZ sizeof(struct ubifs_ch) +#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node) + +/* + * UBIFS node types. + * + * UBIFS_INO_NODE: inode node + * UBIFS_DATA_NODE: data node + * UBIFS_DENT_NODE: directory entry node + * UBIFS_XENT_NODE: extended attribute node + * UBIFS_TRUN_NODE: truncation node + * UBIFS_PAD_NODE: padding node + * UBIFS_SB_NODE: superblock node + * UBIFS_MST_NODE: master node + * UBIFS_REF_NODE: LEB reference node + * UBIFS_IDX_NODE: index node + * UBIFS_CS_NODE: commit start node + * UBIFS_ORPH_NODE: orphan node + * UBIFS_NODE_TYPES_CNT: count of supported node types + * + * Note, we index arrays by these numbers, so keep them low and contiguous. + * Node type constants for inodes, direntries and so on have to be the same as + * corresponding key type constants. + */ +enum { + UBIFS_INO_NODE, + UBIFS_DATA_NODE, + UBIFS_DENT_NODE, + UBIFS_XENT_NODE, + UBIFS_TRUN_NODE, + UBIFS_PAD_NODE, + UBIFS_SB_NODE, + UBIFS_MST_NODE, + UBIFS_REF_NODE, + UBIFS_IDX_NODE, + UBIFS_CS_NODE, + UBIFS_ORPH_NODE, + UBIFS_NODE_TYPES_CNT, +}; + +/* + * Supported key hash functions. + * + * UBIFS_KEY_HASH_R5: R5 hash + * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name + */ +enum { + UBIFS_KEY_HASH_R5, + UBIFS_KEY_HASH_TEST, +}; + +/* + * Supported key formats. + * + * UBIFS_SIMPLE_KEY_FMT: simple key format + */ +enum { + UBIFS_SIMPLE_KEY_FMT, +}; + +/* + * Node group type (used by recovery to recover whole group or none). + * + * UBIFS_NO_NODE_GROUP: this node is not part of a group + * UBIFS_IN_NODE_GROUP: this node is a part of a group + * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group + */ +enum { + UBIFS_NO_NODE_GROUP = 0, + UBIFS_IN_NODE_GROUP, + UBIFS_LAST_OF_NODE_GROUP, +}; + +/* + * Superblock flags. + * + * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set + * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed + */ +enum { + UBIFS_FLG_BIGLPT = 0x02, + UBIFS_FLG_SPACE_FIXUP = 0x04, +}; + +/** + * struct ubifs_ch - common header node. + * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) + * @crc: CRC-32 checksum of the node header + * @sqnum: sequence number + * @len: full node length + * @node_type: node type + * @group_type: node group type + * @padding: reserved for future, zeroes + * + * Every UBIFS node starts with this common part. If the node has a key, the + * key always goes next. + */ +struct ubifs_ch { + __le32 magic; + __le32 crc; + __le64 sqnum; + __le32 len; + __u8 node_type; + __u8 group_type; + __u8 padding[2]; +} __attribute__ ((packed)); + +/** + * struct ubifs_pad_node - padding node. + * @ch: common header + * @pad_len: how many bytes after this node are unused (because padded) + * @padding: reserved for future, zeroes + */ +struct ubifs_pad_node { + struct ubifs_ch ch; + __le32 pad_len; +} __attribute__ ((packed)); + +/** + * struct ubifs_sb_node - superblock node. + * @ch: common header + * @padding: reserved for future, zeroes + * @key_hash: type of hash function used in keys + * @key_fmt: format of the key + * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) + * @min_io_size: minimal input/output unit size + * @leb_size: logical eraseblock size in bytes + * @leb_cnt: count of LEBs used by file-system + * @max_leb_cnt: maximum count of LEBs used by file-system + * @max_bud_bytes: maximum amount of data stored in buds + * @log_lebs: log size in logical eraseblocks + * @lpt_lebs: number of LEBs used for lprops table + * @orph_lebs: number of LEBs used for recording orphans + * @jhead_cnt: count of journal heads + * @fanout: tree fanout (max. number of links per indexing node) + * @lsave_cnt: number of LEB numbers in LPT's save table + * @fmt_version: UBIFS on-flash format version + * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) + * @padding1: reserved for future, zeroes + * @rp_uid: reserve pool UID + * @rp_gid: reserve pool GID + * @rp_size: size of the reserved pool in bytes + * @padding2: reserved for future, zeroes + * @time_gran: time granularity in nanoseconds + * @uuid: UUID generated when the file system image was created + * @ro_compat_version: UBIFS R/O compatibility version + */ +struct ubifs_sb_node { + struct ubifs_ch ch; + __u8 padding[2]; + __u8 key_hash; + __u8 key_fmt; + __le32 flags; + __le32 min_io_size; + __le32 leb_size; + __le32 leb_cnt; + __le32 max_leb_cnt; + __le64 max_bud_bytes; + __le32 log_lebs; + __le32 lpt_lebs; + __le32 orph_lebs; + __le32 jhead_cnt; + __le32 fanout; + __le32 lsave_cnt; + __le32 fmt_version; + __le16 default_compr; + __u8 padding1[2]; + __le32 rp_uid; + __le32 rp_gid; + __le64 rp_size; + __le32 time_gran; + __u8 uuid[16]; + __le32 ro_compat_version; + __u8 padding2[3968]; +} __attribute__ ((packed)); + +/** + * struct ubifs_mst_node - master node. + * @ch: common header + * @highest_inum: highest inode number in the committed index + * @cmt_no: commit number + * @flags: various flags (%UBIFS_MST_DIRTY, etc) + * @log_lnum: start of the log + * @root_lnum: LEB number of the root indexing node + * @root_offs: offset within @root_lnum + * @root_len: root indexing node length + * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was + * not reserved and should be reserved on mount) + * @ihead_lnum: LEB number of index head + * @ihead_offs: offset of index head + * @index_size: size of index on flash + * @total_free: total free space in bytes + * @total_dirty: total dirty space in bytes + * @total_used: total used space in bytes (includes only data LEBs) + * @total_dead: total dead space in bytes (includes only data LEBs) + * @total_dark: total dark space in bytes (includes only data LEBs) + * @lpt_lnum: LEB number of LPT root nnode + * @lpt_offs: offset of LPT root nnode + * @nhead_lnum: LEB number of LPT head + * @nhead_offs: offset of LPT head + * @ltab_lnum: LEB number of LPT's own lprops table + * @ltab_offs: offset of LPT's own lprops table + * @lsave_lnum: LEB number of LPT's save table (big model only) + * @lsave_offs: offset of LPT's save table (big model only) + * @lscan_lnum: LEB number of last LPT scan + * @empty_lebs: number of empty logical eraseblocks + * @idx_lebs: number of indexing logical eraseblocks + * @leb_cnt: count of LEBs used by file-system + * @padding: reserved for future, zeroes + */ +struct ubifs_mst_node { + struct ubifs_ch ch; + __le64 highest_inum; + __le64 cmt_no; + __le32 flags; + __le32 log_lnum; + __le32 root_lnum; + __le32 root_offs; + __le32 root_len; + __le32 gc_lnum; + __le32 ihead_lnum; + __le32 ihead_offs; + __le64 index_size; + __le64 total_free; + __le64 total_dirty; + __le64 total_used; + __le64 total_dead; + __le64 total_dark; + __le32 lpt_lnum; + __le32 lpt_offs; + __le32 nhead_lnum; + __le32 nhead_offs; + __le32 ltab_lnum; + __le32 ltab_offs; + __le32 lsave_lnum; + __le32 lsave_offs; + __le32 lscan_lnum; + __le32 empty_lebs; + __le32 idx_lebs; + __le32 leb_cnt; + __u8 padding[344]; +} __attribute__ ((packed)); + +/** + * struct ubifs_ref_node - logical eraseblock reference node. + * @ch: common header + * @lnum: the referred logical eraseblock number + * @offs: start offset in the referred LEB + * @jhead: journal head number + * @padding: reserved for future, zeroes + */ +struct ubifs_ref_node { + struct ubifs_ch ch; + __le32 lnum; + __le32 offs; + __le32 jhead; + __u8 padding[28]; +} __attribute__ ((packed)); + +#endif /*!__UBIFS_MEDIA_H__ */ -- 1.6.0.2 From hujianyang at huawei.com Fri Sep 19 22:08:34 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 13:08:34 +0800 Subject: [PATCH 4/4] ubi-utils: introduce ubidump In-Reply-To: <541D09C9.4080004@huawei.com> References: <541D09C9.4080004@huawei.com> Message-ID: <541D0BD2.9080908@huawei.com> Signed-off-by: hujianyang --- ubi-utils/ubidump.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 217 insertions(+), 0 deletions(-) create mode 100644 ubi-utils/ubidump.c diff --git a/ubi-utils/ubidump.c b/ubi-utils/ubidump.c new file mode 100644 index 0000000..d96d7fb --- /dev/null +++ b/ubi-utils/ubidump.c @@ -0,0 +1,217 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + */ + +/* + * An utility to dump UBI/UBIFS format data in eraseblock + * + * Author: Hu Jianyang + */ + +#define PROGRAM_NAME "ubidump" + +#include +#include +#include + +#include +#include +#include +#include "common.h" +#include "ubiutils-common.h" + +/* The variables below are set by command line arguments */ +struct args { + const char *vol; + int lnum; + int info:1; +}; + +static struct args args = +{ + .vol = NULL, + .lnum = -1, + .info = 0, +}; + +static const char doc[] = PROGRAM_NAME " version " VERSION + " - an utility to dump UBI/UBIFS format data in eraseblock"; + +static const char optionsstr[] = +"-h, --help print help message\n" +"-l, --lnum logic eraseblock num to dump\n" +"-i, --info show explicit information about ubifs-level\n" +"-V, --version print program version"; + +static const char usage[] = +"Usage: " PROGRAM_NAME " [-l ] [-i]\n" +"\t\t\t[--help] [--version]\n\n" +"Example 1: " PROGRAM_NAME " /dev/ubi0_1 --lnum 2 - dump leb 2 in volume 1\n" +"Example 2: " PROGRAM_NAME " /dev/ubi0_0 -l 1234 -i - dump leb 1234 with explicit info\n"; + +static const struct option long_options[] = { + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = "lnum", .has_arg = 1, .flag = NULL, .val = 'l' }, + { .name = "info", .has_arg = 0, .flag = NULL, .val = 'i' }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { NULL, 0, NULL, 0} +}; + +static int parse_opt(int argc, char * const argv[]) +{ + while (1) { + int key, error = 0; + + key = getopt_long(argc, argv, "h?il:", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'l': + args.lnum = simple_strtoul(optarg, &error); + if (error || args.lnum < 0) + return errmsg("bad lnum: \"%s\"", optarg); + break; + + case 'i': + args.info = 1; + break; + + case 'h': + case '?': + printf("%s\n\n", doc); + printf("%s\n\n", usage); + printf("%s\n", optionsstr); + exit(EXIT_SUCCESS); + + case 'V': + common_print_version(); + exit(EXIT_SUCCESS); + + case ':': + return errmsg("parameter is missing"); + + default: + fprintf(stderr, "Use -h for help\n"); + return -1; + } + } + if (optind == argc) + return errmsg("UBI device name was not specified (use -h for help)"); + else if (optind != argc - 1) + return errmsg("more then one UBI device specified (use -h for help)"); + + args.vol = argv[optind]; + + if (args.lnum < 0) + return errmsg("lnum was not specified (use -h for help)"); + + return 0; +} + +static int dump_eraseblock(int fd, struct ubi_vol_info *vol_info) +{ + int ret, leb_size, lnum; + off_t offs; + char *buf; + + leb_size = vol_info->leb_size; + lnum = args.lnum; + + ret = ubi_is_mapped(fd, lnum); + if (ret == 0) { + errmsg("lnum %d is not mapped", lnum); + goto out; + } else if (ret < 0) { + sys_errmsg("ubi_is_mapped() failed"); + goto out; + } + + buf = malloc(leb_size); + if (!buf) + return errmsg("cannot allocate %d bytes of memory", + leb_size); + offs = lnum * leb_size; + + ret = pread(fd, buf, leb_size, offs); + if (ret != leb_size) { + errmsg("cannot read %d bytes at lnum %d, read %d", + leb_size, lnum, ret); + goto out_free; + } + + ret = ubi_dump(lnum, buf, leb_size, args.info); + +out_free: + free(buf); +out: + return ret; +} + +int main(int argc, char * const argv[]) +{ + int err, fd; + libubi_t libubi; + struct ubi_vol_info vol_info; + + err = parse_opt(argc, argv); + if (err) + return -1; + + libubi = libubi_open(); + if (!libubi) { + if (errno == 0) + errmsg("UBI is not present in the system"); + else + sys_errmsg("cannot open libubi"); + goto out_libubi; + } + + err = ubi_probe_node(libubi, args.vol); + if (err == 1) { + errmsg("\"%s\" is an UBI device node, not an UBI volume node", + args.vol); + goto out_libubi; + } else if (err < 0) { + if (errno == ENODEV) + errmsg("\"%s\" is not an UBI volume node", args.vol); + else + sys_errmsg("error while probing \"%s\"", args.vol); + goto out_libubi; + } + + err = ubi_get_vol_info(libubi, args.vol, &vol_info); + if (err) { + sys_errmsg("cannot get information about UBI volume \"%s\"", + args.vol); + goto out_libubi; + } + + fd = open(args.vol, O_RDONLY); + if (fd == -1) { + sys_errmsg("cannot open UBI volume \"%s\"", args.vol); + goto out_libubi; + } + + err = dump_eraseblock(fd, &vol_info); + if (err) + goto out_fd; + + close(fd); + libubi_close(libubi); + return 0; + +out_fd: + close(fd); +out_libubi: + libubi_close(libubi); + return -1; +} -- 1.6.0.2 From hujianyang at huawei.com Fri Sep 19 23:55:11 2014 From: hujianyang at huawei.com (hujianyang) Date: Sat, 20 Sep 2014 14:55:11 +0800 Subject: [PATCH] UBIFS: Align the dump messages of SB_NODE Message-ID: <541D24CF.1040705@huawei.com> I found the dump messages of UBIFS_SB_NODE is not aligned. This patch remove the extra space from the line which is retracted. Signed-off-by: hujianyang --- fs/ubifs/debug.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 177b015..d0bcf92 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -334,9 +334,9 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) pr_err("\tkey_fmt %d (%s)\n", (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); pr_err("\tflags %#x\n", sup_flags); - pr_err("\t big_lpt %u\n", + pr_err("\tbig_lpt %u\n", !!(sup_flags & UBIFS_FLG_BIGLPT)); - pr_err("\t space_fixup %u\n", + pr_err("\tspace_fixup %u\n", !!(sup_flags & UBIFS_FLG_SPACE_FIXUP)); pr_err("\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size)); pr_err("\tleb_size %u\n", le32_to_cpu(sup->leb_size)); -- 1.6.0.2 From boris.brezillon at free-electrons.com Sat Sep 20 04:03:15 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Sat, 20 Sep 2014 13:03:15 +0200 Subject: [PATCH v4 0/2] mtd: nand: add sunxi NAND flash controller support In-Reply-To: <20140920043438.GD8127@brian-ubuntu> References: <1408382788-32153-1-git-send-email-boris.brezillon@free-electrons.com> <20140920043438.GD8127@brian-ubuntu> Message-ID: <20140920130315.197ab359@bbrezillon> Hi Brian, On Fri, 19 Sep 2014 21:34:38 -0700 Brian Norris wrote: > Hi Boris, > > On Mon, Aug 18, 2014 at 07:26:26PM +0200, Boris BREZILLON wrote: > > This patch series adds support for the sunxi NAND Flash Controller (NFC) > > block. > > > > These two patches only add support for the basic NAND stuff: > > - NAND controller operations > > - SW and HW ECC handling (with both syndrome and normal ECC scheme) > > > > If you want support for advanced features you can find it on my github > > repo [1]: > > - HW randomization support > > - per partition ECC/Randomizer to handle bootloader partitions > > > > DMA transfers are not supported yet, but I have reworked the OOB layout > > when using the HW ECC scheme to match the one used when accessing the NAND > > with DMA transfers (the available OOB bytes are placed at the end of the > > OOB area). > > > > This patch series depends on this other one [2] which adds support for ONFI > > timing mode retrieval on non-ONFI NANDs. > > Were you planning to send v2 of your series [2]? I see you made a > mistake you were planning on fixing: > > https://lkml.org/lkml/2014/7/30/423 Yep, I was just waiting for your feedback before fixing it ;-). Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From boris.brezillon at free-electrons.com Sat Sep 20 04:29:43 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Sat, 20 Sep 2014 13:29:43 +0200 Subject: [PATCH 1/2] mtd: nand: support ONFI timings mode retrieval for non-ONFI NANDs In-Reply-To: <20140920044607.GE8127@brian-ubuntu> References: <1406539012-16320-1-git-send-email-boris.brezillon@free-electrons.com> <1406539012-16320-2-git-send-email-boris.brezillon@free-electrons.com> <20140920044607.GE8127@brian-ubuntu> Message-ID: <20140920132943.7775f318@bbrezillon> On Fri, 19 Sep 2014 21:46:07 -0700 Brian Norris wrote: > Since you were asking about this series, I have a comment: > > On Mon, Jul 28, 2014 at 11:16:51AM +0200, Boris BREZILLON wrote: > > Add an onfi_timing_mode_ds field to nand_chip and nand_flash_dev in order > > to support NAND timings definition for non-ONFI NAND. > > > > NAND that support better timings mode than the default one (timings mode 0) > > have to define a new entry in the nand_ids table. > > > > The timings mode should be deduced from timings description from the > > datasheet and the ONFI specification > > (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 > > "Timing Parameters"). > > You should choose the closest mode that fit the timings requirements of > > your NAND chip. > > > > Signed-off-by: Boris BREZILLON > > --- > > drivers/mtd/nand/nand_base.c | 1 + > > include/linux/mtd/nand.h | 7 +++++++ > > 2 files changed, 8 insertions(+) > > > > diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c > > index d8cdf06..c952c21 100644 > > --- a/drivers/mtd/nand/nand_base.c > > +++ b/drivers/mtd/nand/nand_base.c > > @@ -3576,6 +3576,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, > > chip->options |= type->options; > > chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); > > chip->ecc_step_ds = NAND_ECC_STEP(type); > > + chip->onfi_timing_mode_ds = type->onfi_timing_mode_ds; > > > > *busw = type->options & NAND_BUSWIDTH_16; > > > > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h > > index 3083c53..435c005 100644 > > --- a/include/linux/mtd/nand.h > > +++ b/include/linux/mtd/nand.h > > @@ -587,6 +587,7 @@ struct nand_buffers { > > * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, > > * also from the datasheet. It is the recommended ECC step > > * size, if known; if unknown, set to zero. > > + * @onfi_timing_mode_ds:[INTERN] ONFI timing mode deduced from datasheet. > > Might want at least one space between '[INTERN]' and 'ONFI'? You mean between the colon and '[INTERN]', right ? > > > * @numchips: [INTERN] number of physical chips > > * @chipsize: [INTERN] the size of one chip for multichip arrays > > * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 > > @@ -671,6 +672,7 @@ struct nand_chip { > > uint8_t bits_per_cell; > > uint16_t ecc_strength_ds; > > uint16_t ecc_step_ds; > > + int onfi_timing_mode_ds; > > I'm not sure if we'll just want a field specific to non-ONFI chips, > faking an ONFI timing mode; can we make this into a more generally > useful field, that represents something consistent across all NAND > types? I was thinking a "highest mode supported", but that actually > isn't great, since for true ONFI modes (except mode 0) require a SET > FEATURES command to change to a higher mode. > > Maybe just something like onfi_timing_mode_default, which we could then > use as mode 0 for ONFI chips. > > Ideally, we could centralize as much of this as possible, so that a NAND > driver only has to know the mechanics of "how do I translate an ONFI > mode to a timing configuration for my NAND controller," I guess you meant "how do I translate a NAND timing config given by nand_sdr_timings to my specific NAND controller config", right ? > instead of any > details of how to choose from one of many supported ONFI modes. i.e., it > could implement something like the following hook: > > int (*set_timing_mode)(struct nand_sdr_timings *timing); I'm not opposed to this solution (I actually think this is how it should be done :-), and, IIRC, Jason proposed to do the same kind of things a while ago), but this means the conversion would be done by the NAND FW and passed to the NAND driver, and this implies reworking the drivers already directly using ONFI modes to configure their NAND timings to make use nand_sdr_timings instead. Moreover, I think we should define a union to handle several kind of timings (ddr NAND are coming :-P): enum nand_timings_type /* or nand_bus_type or something else ;-) */ { SDR_NAND, DDR_NAND, } struct nand_timings { enum nand_timings_type type; union { struct nand_sdr_timings sdr; struct nand_ddr_timings ddr; } timings; }; But this is another story ;-). > > But anyway, that's out of the scope of this series, and it may be harder > than I make it sound. I just wanted to throw that out there. If you don't mind I'd like to get something simple first: just renaming onfi_timing_mode_ds is fine, but adding the whole conversion stuff to the core implies much more changes. And I can work on a more integrated solution as a second step. Let me know what you think. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From richard.weinberger at gmail.com Sat Sep 20 05:54:57 2014 From: richard.weinberger at gmail.com (Richard Weinberger) Date: Sat, 20 Sep 2014 14:54:57 +0200 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: <1411147451.23429.20.camel@sauron.fi.intel.com> References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> <1411146833.23429.11.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> <1411147451.23429.20.camel@sauron.fi.intel.com> Message-ID: On Fri, Sep 19, 2014 at 7:24 PM, Artem Bityutskiy wrote: > On Fri, 2014-09-19 at 13:17 -0400, Atlant Schmidt wrote: >> But as I pointed, this will not force re-read of the volume table LEBs. >> To address this, you'd need to do some additional, not very difficult >> work. > > Oh, and this won't make UBI re-read the EC and VID headers, so they may > bit-rot too. > > So indeed it sounds like UBI needs a separate interface for this kind of > "scrub all bit-flips" issues. I do not think it is hard to do - all the > mechanisms are already implemented, so this would mostly be about > inventing good API. We could implement a trivial knob to trigger such a check in kernel. I.e. you trigger the check via an ioctl() or whatever and UBI schedules such a read-check for every PEB into the UBI background thread. I'd volunteer to implement this. -- Thanks, //richard From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:11 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:11 +0100 Subject: [PATCH v4 0/5] nand: OMAP collected fixes Message-ID: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> I've collected all the changes recently discussed in a whole patchset. If you are just reading this for the first time please take a look at: [1] http://www.spinics.net/lists/linux-omap/msg110965.html [2] http://www.spinics.net/lists/linux-omap/msg110958.html As requested by Roger, the omap_elm is a 'bool' driver now. The plan is to merge it inside omap2_nand, but my queue is really filled, so if anyone feels like doing, please be my guest. Although I'm hoping this to be the last round, feedback and testing is welcome. Brian: I wonder if it's too late for v3.18? Thanks! Ezequiel Garcia (5): nand: omap2: Remove horrible ifdefs to fix module probe nand: omap2: Replace pr_err with dev_err mtd: nand: Move ELM driver and rename as omap_elm mtd: nand: Rename OMAP NAND driver mtd: nand: Constrain omap_elm to built-in drivers/mtd/devices/Makefile | 1 - drivers/mtd/nand/Kconfig | 2 +- drivers/mtd/nand/Makefile | 3 +- drivers/mtd/nand/{omap2.c => omap2_nand.c} | 160 ++++++++++++++----------- drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 include/linux/platform_data/elm.h | 16 +++ 6 files changed, 107 insertions(+), 75 deletions(-) rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (95%) rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) -- 2.1.0 From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:12 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:12 +0100 Subject: [PATCH v4 1/5] nand: omap2: Remove horrible ifdefs to fix module probe In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1411231996-6387-2-git-send-email-ezequiel@vanguardiasur.com.ar> The current code abuses ifdefs to determine if the selected ECC scheme is supported by the running kernel. As a result the code is hard to read, and it also fails to load as a module. This commit removes all the ifdefs and instead introduces a function omap2_nand_ecc_check() to check if the ECC is supported by using IS_ENABLED(CONFIG_xxx). Since IS_ENABLED() is true when a config is =y or =m, this change fixes the module so it can be loaded with no issues. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 130 +++++++++++++++++++++----------------- include/linux/platform_data/elm.h | 16 +++++ 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index e1a9b31..f97a4ff 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -136,7 +136,6 @@ #define BADBLOCK_MARKER_LENGTH 2 -#ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -#endif /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, /** * is_elm_present - checks for presence of ELM module by scanning DT nodes * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static bool is_elm_present(struct omap_nand_info *info, + struct device_node *elm_node) { struct platform_device *pdev; - struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int err; + /* check whether elm-id is passed via DT */ if (!elm_node) { pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { pr_err("nand: error: ELM device not found\n"); - return -ENODEV; + return false; } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - err = elm_config(info->elm_dev, bch_type, - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + return true; +} - return err; +static bool omap2_nand_ecc_check(struct omap_nand_info *info, + struct omap_nand_platform_data *pdata) +{ + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; + + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + ecc_needs_omap_bch = false; + ecc_needs_bch = true; + ecc_needs_elm = false; + break; + case OMAP_ECC_BCH4_CODE_HW: + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + ecc_needs_omap_bch = true; + ecc_needs_bch = false; + ecc_needs_elm = true; + break; + default: + ecc_needs_omap_bch = false; + ecc_needs_bch = false; + ecc_needs_elm = false; + break; + } + + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + return false; + } + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + return false; + } + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { + dev_err(&info->pdev->dev, "ELM not available\n"); + return false; + } + + return true; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ static int omap_nand_probe(struct platform_device *pdev) { @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } + if (!omap2_nand_ecc_check(info, pdata)) { + err = -EINVAL; + goto return_error; + } + /* populate MTD interface based on ECC scheme */ ecclayout = &omap_oobinfo; switch (info->ecc_opt) { @@ -1829,7 +1869,6 @@ static int omap_nand_probe(struct platform_device *pdev) break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1861,14 +1900,8 @@ static int omap_nand_probe(struct platform_device *pdev) err = -EINVAL; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1890,21 +1923,15 @@ static int omap_nand_probe(struct platform_device *pdev) /* reserved marker already included in ecclayout->eccbytes */ ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; + + err = elm_config(info->elm_dev, BCH4_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1937,14 +1964,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1956,12 +1977,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); + + err = elm_config(info->elm_dev, BCH8_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1973,14 +1995,8 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1991,12 +2007,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); - if (err < 0) { - pr_err("ELM is required for this ECC scheme\n"); + + err = elm_config(info->elm_dev, BCH16_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -2008,11 +2025,6 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 780d1e9..b8686c0 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,8 +42,24 @@ struct elm_errorvec { int error_loc[16]; }; +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size); +#else +static inline void +elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ +} + +static inline int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, + int ecc_syndrome_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_MTD_NAND_ECC_BCH */ + #endif /* __ELM_H */ -- 2.1.0 From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:13 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:13 +0100 Subject: [PATCH v4 2/5] nand: omap2: Replace pr_err with dev_err In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1411231996-6387-3-git-send-email-ezequiel@vanguardiasur.com.ar> Usage of pr_err is frowned upon, so replace it with dev_err. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/omap2.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f97a4ff..3b357e9 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, erased_ecc_vec = bch16_vector; break; default: - pr_err("invalid driver configuration\n"); + dev_err(&info->pdev->dev, "invalid driver configuration\n"); return -EINVAL; } @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, err = 0; for (i = 0; i < eccsteps; i++) { if (err_vec[i].error_uncorrectable) { - pr_err("nand: uncorrectable bit-flips found\n"); + dev_err(&info->pdev->dev, + "uncorrectable bit-flips found\n"); err = -EBADMSG; } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, 1 << bit_pos; } } else { - pr_err("invalid bit-flip @ %d:%d\n", - byte_pos, bit_pos); + dev_err(&info->pdev->dev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); err = -EBADMSG; } } @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, /* check whether elm-id is passed via DT */ if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { - pr_err("nand: error: ELM device not found\n"); + dev_err(&info->pdev->dev, "ELM device not found\n"); return false; } /* ELM module available, now configure it */ @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); err = -ENXIO; goto return_error; } /* check for small page devices */ if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); + dev_err(&info->pdev->dev, "small page devices are not supported\n"); err = -EINVAL; goto return_error; } @@ -1896,8 +1898,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; + goto return_error; } break; @@ -1959,7 +1962,7 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; goto return_error; } @@ -2026,7 +2029,7 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); err = -EINVAL; goto return_error; } @@ -2038,8 +2041,9 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); + dev_err(&info->pdev->dev, + "not enough OOB bytes required = %d, available=%d\n", + ecclayout->eccbytes, mtd->oobsize); err = -EINVAL; goto return_error; } -- 2.1.0 From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:14 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:14 +0100 Subject: [PATCH v4 3/5] mtd: nand: Move ELM driver and rename as omap_elm In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1411231996-6387-4-git-send-email-ezequiel@vanguardiasur.com.ar> The ELM driver is only used by the OMAP NAND driver, so let's move it to the nand/ directory. Additionally, let's rename it to a less confusing name, so the module is built with a meaningful name, instead of the previous 'elm.ko'. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia --- drivers/mtd/devices/Makefile | 1 - drivers/mtd/nand/Makefile | 1 + drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f..f0b0e61 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a035e7c..b3237b7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/nand/omap_elm.c similarity index 100% rename from drivers/mtd/devices/elm.c rename to drivers/mtd/nand/omap_elm.c -- 2.1.0 From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:15 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:15 +0100 Subject: [PATCH v4 4/5] mtd: nand: Rename OMAP NAND driver In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1411231996-6387-5-git-send-email-ezequiel@vanguardiasur.com.ar> Rename it to a less generic name, so the module is built with a meaningful name instead of the previous 'omap2.ko'. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b3237b7..4bcdeb0 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2_nand.c similarity index 100% rename from drivers/mtd/nand/omap2.c rename to drivers/mtd/nand/omap2_nand.c -- 2.1.0 From ezequiel at vanguardiasur.com.ar Sat Sep 20 09:53:16 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 20 Sep 2014 17:53:16 +0100 Subject: [PATCH v4 5/5] mtd: nand: Constrain omap_elm to built-in In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> This fixes the following build error when omap2_nand is chosen built-in, and omap_elm is chosen as a module: drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' Fix this by making omap_elm a 'bool' driver. Signed-off-by: Ezequiel Garcia --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1cf503..549c0cb 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 config MTD_NAND_OMAP_BCH depends on MTD_NAND_OMAP2 - tristate "Support hardware based BCH error correction" + bool "Support hardware based BCH error correction" default n select BCH help -- 2.1.0 From heart_breaker_0708 at yahoo.co.jp Sat Sep 20 10:54:38 2014 From: heart_breaker_0708 at yahoo.co.jp (Obuariver Goldmines) Date: Sun, 21 Sep 2014 02:54:38 +0900 (JST) Subject: Dear Sir, We are gold mining company located in sub region of West Africa in San Pedro-Cote D'Ivoire looking for real and potential gold buyers and mandates to buy or market our gold nuggets, dust and Dore bars. We have been in the mining business in Cote D' Ivoire for many years and have good experience in international trade from West Africa. You can expect good clean deals through us as we have built a loyal clientele all across the world who are seeking gold from the West Africa region. Our prices are very attractive in the International market.We look forward to a good business relationship with your company. If you have any questions please call or email us anytime. We look forward to your prompt reply and are ready, willing and able to deliver upon your request. Best Regards, CHIEF.YAPI AMAN Message-ID: <194336.15596.qm@web100516.mail.kks.yahoo.co.jp> From computersforpeace at gmail.com Sat Sep 20 12:46:55 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 20 Sep 2014 12:46:55 -0700 Subject: [PATCH 1/2] mtd: nand: support ONFI timings mode retrieval for non-ONFI NANDs In-Reply-To: <20140920132943.7775f318@bbrezillon> References: <1406539012-16320-1-git-send-email-boris.brezillon@free-electrons.com> <1406539012-16320-2-git-send-email-boris.brezillon@free-electrons.com> <20140920044607.GE8127@brian-ubuntu> <20140920132943.7775f318@bbrezillon> Message-ID: <20140920194655.GM7362@norris-Latitude-E6410> On Sat, Sep 20, 2014 at 01:29:43PM +0200, Boris BREZILLON wrote: > On Fri, 19 Sep 2014 21:46:07 -0700 > Brian Norris wrote: > > > Since you were asking about this series, I have a comment: > > > > On Mon, Jul 28, 2014 at 11:16:51AM +0200, Boris BREZILLON wrote: > > > Add an onfi_timing_mode_ds field to nand_chip and nand_flash_dev in order > > > to support NAND timings definition for non-ONFI NAND. > > > > > > NAND that support better timings mode than the default one (timings mode 0) > > > have to define a new entry in the nand_ids table. > > > > > > The timings mode should be deduced from timings description from the > > > datasheet and the ONFI specification > > > (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 > > > "Timing Parameters"). > > > You should choose the closest mode that fit the timings requirements of > > > your NAND chip. > > > > > > Signed-off-by: Boris BREZILLON > > > --- > > > drivers/mtd/nand/nand_base.c | 1 + > > > include/linux/mtd/nand.h | 7 +++++++ > > > 2 files changed, 8 insertions(+) > > > > > > diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c > > > index d8cdf06..c952c21 100644 > > > --- a/drivers/mtd/nand/nand_base.c > > > +++ b/drivers/mtd/nand/nand_base.c > > > @@ -3576,6 +3576,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, > > > chip->options |= type->options; > > > chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); > > > chip->ecc_step_ds = NAND_ECC_STEP(type); > > > + chip->onfi_timing_mode_ds = type->onfi_timing_mode_ds; > > > > > > *busw = type->options & NAND_BUSWIDTH_16; > > > > > > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h > > > index 3083c53..435c005 100644 > > > --- a/include/linux/mtd/nand.h > > > +++ b/include/linux/mtd/nand.h > > > @@ -587,6 +587,7 @@ struct nand_buffers { > > > * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, > > > * also from the datasheet. It is the recommended ECC step > > > * size, if known; if unknown, set to zero. > > > + * @onfi_timing_mode_ds:[INTERN] ONFI timing mode deduced from datasheet. > > > > Might want at least one space between '[INTERN]' and 'ONFI'? > > You mean between the colon and '[INTERN]', right ? Yep! My mistake. > > > > > * @numchips: [INTERN] number of physical chips > > > * @chipsize: [INTERN] the size of one chip for multichip arrays > > > * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 > > > @@ -671,6 +672,7 @@ struct nand_chip { > > > uint8_t bits_per_cell; > > > uint16_t ecc_strength_ds; > > > uint16_t ecc_step_ds; > > > + int onfi_timing_mode_ds; > > > > I'm not sure if we'll just want a field specific to non-ONFI chips, > > faking an ONFI timing mode; can we make this into a more generally > > useful field, that represents something consistent across all NAND > > types? I was thinking a "highest mode supported", but that actually > > isn't great, since for true ONFI modes (except mode 0) require a SET > > FEATURES command to change to a higher mode. > > > > Maybe just something like onfi_timing_mode_default, which we could then > > use as mode 0 for ONFI chips. > > > > Ideally, we could centralize as much of this as possible, so that a NAND > > driver only has to know the mechanics of "how do I translate an ONFI > > mode to a timing configuration for my NAND controller," > > I guess you meant "how do I translate a NAND timing config given by > nand_sdr_timings to my specific NAND controller config", right ? Yes. > > instead of any > > details of how to choose from one of many supported ONFI modes. i.e., it > > could implement something like the following hook: > > > > int (*set_timing_mode)(struct nand_sdr_timings *timing); > > I'm not opposed to this solution (I actually think this is how it > should be done :-), and, IIRC, Jason proposed to do the same kind of > things a while ago), but this means the conversion would be done by the > NAND FW and passed to the NAND driver, and this implies reworking the > drivers already directly using ONFI modes to configure their NAND > timings to make use nand_sdr_timings instead. I think we can safely ignore most of how drivers already configured timings (I see at least denali.c with its own custom boot parameter), and try to work out a solution that can be used by more than one driver eventually. Conversion may or may not happen for some drivers, so we should plan to have some sort of opt-in or opt-out ability. > Moreover, I think we should define a union to handle several kind of > timings (ddr NAND are coming :-P): > > enum nand_timings_type /* or nand_bus_type or something else ;-) */ { > SDR_NAND, > DDR_NAND, > } > > struct nand_timings { > enum nand_timings_type type; > union { > struct nand_sdr_timings sdr; > struct nand_ddr_timings ddr; > } timings; > }; Perhaps. Although it's not immediately clear to me why we would need to represent them in the same struct; I'm pretty sure we will have some controllers that can handle one but not the other, so we might just have two independent interfaces, and no need for the enum. But anyway, I'm not 100% clear on how this would look, until one of us provides a patch set, and we can work from there. > But this is another story ;-). Yes, I think so. > > > > But anyway, that's out of the scope of this series, and it may be harder > > than I make it sound. I just wanted to throw that out there. > > If you don't mind I'd like to get something simple first: just renaming > onfi_timing_mode_ds is fine, but adding the whole conversion stuff to > the core implies much more changes. And I can work on a more > integrated solution as a second step. Sounds good. I really didn't expect much modification to this patch set, but since you needed to fix the second patch, I though I'd give you my nitpicks too. One last random thought: if we ever integrate the SET_FEATURES commands to set timing modes (async or synchronous ONFI modes) in the core code, I think we'll need to ensure that we resend the SET_FEATURES command after any NAND_CMD_RESET, as well as after any resume from suspend (nand_resume()?). Brian From hauke at hauke-m.de Sun Sep 21 15:33:13 2014 From: hauke at hauke-m.de (Hauke Mehrtens) Date: Mon, 22 Sep 2014 00:33:13 +0200 Subject: [PATCH] mtd: bcm47xxpart: only register partitions if the trx header was filled Message-ID: <1411338793-21245-1-git-send-email-hauke@hauke-m.de> Sometimes the trx offsets are 0, in that case there is no partition and we should not try to add one. Signed-off-by: Hauke Mehrtens --- drivers/mtd/bcm47xxpart.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 8057f52..c3f4454 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -168,18 +168,22 @@ static int bcm47xxpart_parse(struct mtd_info *master, i++; } - bcm47xxpart_add_part(&parts[curr_part++], "linux", - offset + trx->offset[i], 0); - i++; + if (trx->offset[i]) { + bcm47xxpart_add_part(&parts[curr_part++], "linux", + offset + trx->offset[i], 0); + i++; + } /* * Pure rootfs size is known and can be calculated as: * trx->length - trx->offset[i]. We don't fill it as * we want to have jffs2 (overlay) in the same mtd. */ - bcm47xxpart_add_part(&parts[curr_part++], "rootfs", - offset + trx->offset[i], 0); - i++; + if (trx->offset[i]) { + bcm47xxpart_add_part(&parts[curr_part++], "rootfs", + offset + trx->offset[i], 0); + i++; + } last_trx_part = curr_part - 1; -- 1.9.1 From yamada.m at jp.panasonic.com Sun Sep 21 18:15:56 2014 From: yamada.m at jp.panasonic.com (Masahiro Yamada) Date: Mon, 22 Sep 2014 10:15:56 +0900 Subject: [PATCH v3 0/7] mtd: denali: A collection of trivial coding style fixes In-Reply-To: <20140919170020.GF1193@ld-irv-0074> References: <1410865465-17941-1-git-send-email-yamada.m@jp.panasonic.com> <20140919170020.GF1193@ld-irv-0074> Message-ID: <20140922101555.0A05.AA925319@jp.panasonic.com> Hi Brian, On Fri, 19 Sep 2014 10:00:20 -0700 Brian Norris wrote: > On Tue, Sep 16, 2014 at 08:04:18PM +0900, Masahiro Yamada wrote: > > > > > > Masahiro Yamada (7): > > mtd: denali: fix the format of comment blocks > > mtd: denali: remove unnecessary variable initializations > > mtd: denali: remove unnecessary casts > > mtd: denali: change the type of iterators to int > > I already merged these 4. > > > mtd: denali: remove a set-but-unused variable > > This one was merged but you changed it (and falsely kept the > 'Reviewed-by' tag). So I split it out into its own patch and dropped the > 'Reviewed-by'. > > > mtd: denali: remove unnecessary parentheses > > mtd: denali: fix indents and other trivial things > > Applied a modified version of the last three, to l2-mtd.git. Feel free > to check my work, but git tells me that the end result is identical. Everything looks good. Many thanks!! Best Regards Masahiro Yamada From rogerq at ti.com Mon Sep 22 01:17:13 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 22 Sep 2014 11:17:13 +0300 Subject: [PATCH v4 5/5] mtd: nand: Constrain omap_elm to built-in In-Reply-To: <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <541FDB09.1080209@ti.com> On 09/20/2014 07:53 PM, Ezequiel Garcia wrote: > This fixes the following build error when omap2_nand is chosen built-in, > and omap_elm is chosen as a module: > > drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > > Fix this by making omap_elm a 'bool' driver. > > Signed-off-by: Ezequiel Garcia Acked-by: -- cheers, -roger > --- > drivers/mtd/nand/Kconfig | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > index f1cf503..549c0cb 100644 > --- a/drivers/mtd/nand/Kconfig > +++ b/drivers/mtd/nand/Kconfig > @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 > > config MTD_NAND_OMAP_BCH > depends on MTD_NAND_OMAP2 > - tristate "Support hardware based BCH error correction" > + bool "Support hardware based BCH error correction" > default n > select BCH > help > From rogerq at ti.com Mon Sep 22 01:22:07 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 22 Sep 2014 11:22:07 +0300 Subject: [PATCH v4 0/5] nand: OMAP collected fixes In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <541FDC2F.4020103@ti.com> Hi Ezequiel, On 09/20/2014 07:53 PM, Ezequiel Garcia wrote: > I've collected all the changes recently discussed in a whole patchset. > If you are just reading this for the first time please take a look at: > > [1] http://www.spinics.net/lists/linux-omap/msg110965.html > [2] http://www.spinics.net/lists/linux-omap/msg110958.html > > As requested by Roger, the omap_elm is a 'bool' driver now. The plan > is to merge it inside omap2_nand, but my queue is really filled, so > if anyone feels like doing, please be my guest. > > Although I'm hoping this to be the last round, feedback and testing > is welcome. Patches 3 and 4 still have checkpatch issues. cheers, -roger > > Brian: I wonder if it's too late for v3.18? > > Thanks! > > Ezequiel Garcia (5): > nand: omap2: Remove horrible ifdefs to fix module probe > nand: omap2: Replace pr_err with dev_err > mtd: nand: Move ELM driver and rename as omap_elm > mtd: nand: Rename OMAP NAND driver > mtd: nand: Constrain omap_elm to built-in > > drivers/mtd/devices/Makefile | 1 - > drivers/mtd/nand/Kconfig | 2 +- > drivers/mtd/nand/Makefile | 3 +- > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 160 ++++++++++++++----------- > drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 > include/linux/platform_data/elm.h | 16 +++ > 6 files changed, 107 insertions(+), 75 deletions(-) > rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (95%) > rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) > From ricard.wanderlof at axis.com Mon Sep 22 01:34:25 2014 From: ricard.wanderlof at axis.com (Ricard Wanderlof) Date: Mon, 22 Sep 2014 10:34:25 +0200 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> <1411146833.23429.11.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> <1411147451.23429.20.camel@sauron.fi.intel.com> Message-ID: On Sat, 20 Sep 2014, Richard Weinberger wrote: > On Fri, Sep 19, 2014 at 7:24 PM, Artem Bityutskiy wrote: >> On Fri, 2014-09-19 at 13:17 -0400, Atlant Schmidt wrote: >>> But as I pointed, this will not force re-read of the volume table LEBs. >>> To address this, you'd need to do some additional, not very difficult >>> work. >> >> Oh, and this won't make UBI re-read the EC and VID headers, so they may >> bit-rot too. >> >> So indeed it sounds like UBI needs a separate interface for this kind of >> "scrub all bit-flips" issues. I do not think it is hard to do - all the >> mechanisms are already implemented, so this would mostly be about >> inventing good API. > > We could implement a trivial knob to trigger such a check in kernel. > I.e. you trigger the check via an ioctl() or whatever and UBI schedules > such a read-check for every PEB into the UBI background thread. During the scanning operation that takes place when a partition is attached, doesn't this also trigger a check of all headers, as all the data needs to be read as part of the ubiattach process? Not that that would be a practical solution for many systems where it is not practical to detach and re-attach, for instance the partition where the root volume is located, as that would in practice require a reboot. > I'd volunteer to implement this. I think it would be good if such a forced re-read could be set to happen automatically at a specified interval, say by default once a day. /Ricard -- Ricard Wolf Wanderl?f ricardw(at)axis.com Axis Communications AB, Lund, Sweden www.axis.com Phone +46 46 272 2016 Fax +46 46 13 61 30 From richard at nod.at Mon Sep 22 01:42:40 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 22 Sep 2014 10:42:40 +0200 Subject: Does UBI LEB-level access interlock happily with UBIfs access? In-Reply-To: References: <0A40042D85E7C84DB443060EC44B3FD36D986A3009@dekaexchange07.deka.local> <1411140449.28850.152.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301A@dekaexchange07.deka.local> <1411146833.23429.11.camel@sauron.fi.intel.com> <0A40042D85E7C84DB443060EC44B3FD36D986A301C@dekaexchange07.deka.local> <1411147451.23429.20.camel@sauron.fi.intel.com> Message-ID: <541FE100.5040802@nod.at> Am 22.09.2014 10:34, schrieb Ricard Wanderlof: > > On Sat, 20 Sep 2014, Richard Weinberger wrote: > >> On Fri, Sep 19, 2014 at 7:24 PM, Artem Bityutskiy wrote: >>> On Fri, 2014-09-19 at 13:17 -0400, Atlant Schmidt wrote: >>>> But as I pointed, this will not force re-read of the volume table LEBs. >>>> To address this, you'd need to do some additional, not very difficult >>>> work. >>> >>> Oh, and this won't make UBI re-read the EC and VID headers, so they may >>> bit-rot too. >>> >>> So indeed it sounds like UBI needs a separate interface for this kind of >>> "scrub all bit-flips" issues. I do not think it is hard to do - all the >>> mechanisms are already implemented, so this would mostly be about >>> inventing good API. >> >> We could implement a trivial knob to trigger such a check in kernel. >> I.e. you trigger the check via an ioctl() or whatever and UBI schedules >> such a read-check for every PEB into the UBI background thread. > > During the scanning operation that takes place when a partition is attached, doesn't this also trigger a check of all headers, as all the data needs to be read as part of the > ubiattach process? Only headers will be read. And with fastmap enabled only very few of these headers are read. > Not that that would be a practical solution for many systems where it is not practical to detach and re-attach, for instance the partition where the root volume is located, as that > would in practice require a reboot. > >> I'd volunteer to implement this. > > I think it would be good if such a forced re-read could be set to happen automatically at a specified interval, say by default once a day. cron can trigger that easily. Thanks, //richard From richard at nod.at Mon Sep 22 01:45:34 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 22 Sep 2014 10:45:34 +0200 Subject: [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Message-ID: <1411375536-20067-1-git-send-email-richard@nod.at> There is no need to set err, it will be overwritten in any case later at: if (scrub) err = ubi_wl_scrub_peb(ubi, pnum); Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/eba.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0e11671d..2402d3b 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -441,10 +441,9 @@ retry: err = ubi_io_read_data(ubi, buf, pnum, offset, len); if (err) { - if (err == UBI_IO_BITFLIPS) { + if (err == UBI_IO_BITFLIPS) scrub = 1; - err = 0; - } else if (mtd_is_eccerr(err)) { + else if (mtd_is_eccerr(err)) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; -- 1.8.4.5 From richard at nod.at Mon Sep 22 01:45:36 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 22 Sep 2014 10:45:36 +0200 Subject: [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1411375536-20067-1-git-send-email-richard@nod.at> References: <1411375536-20067-1-git-send-email-richard@nod.at> Message-ID: <1411375536-20067-3-git-send-email-richard@nod.at> If sync_erase() fails with EINTR, ENOMEM, EAGAIN or EBUSY erase_worker() re-schedules the failed work. This will lead to a deadlock because erase_worker() is called with work_sem held in read mode. And schedule_erase() will take this lock again. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 253ec9b..637ffff 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1421,8 +1421,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, { struct ubi_wl_entry *e = wl_wrk->e; int pnum = e->pnum; - int vol_id = wl_wrk->vol_id; - int lnum = wl_wrk->lnum; int err, available_consumed = 0; if (shutdown) { @@ -1459,21 +1457,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, } ubi_err("failed to erase PEB %d, error %d", pnum, err); - kfree(wl_wrk); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || err == -EBUSY) { - int err1; - /* Re-schedule the LEB for erasure */ - err1 = schedule_erase(ubi, e, vol_id, lnum, 0); - if (err1) { - err = err1; - goto out_ro; - } + __schedule_ubi_work(ubi, wl_wrk); return err; } + kfree(wl_wrk); kmem_cache_free(ubi_wl_entry_slab, e); if (err != -EIO) /* -- 1.8.4.5 From richard at nod.at Mon Sep 22 01:45:35 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 22 Sep 2014 10:45:35 +0200 Subject: [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown In-Reply-To: <1411375536-20067-1-git-send-email-richard@nod.at> References: <1411375536-20067-1-git-send-email-richard@nod.at> Message-ID: <1411375536-20067-2-git-send-email-richard@nod.at> It confused me more than once that the cancel flag of the work function does not indicate the cancellation of a single work. In fact it indicates the WL sub-system shutdown and therefore worker functions have to free their wl_entries too. That's why you cannot cancel a single work, you can only shutdown all works. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/ubi.h | 9 +++++---- drivers/mtd/ubi/wl.c | 24 +++++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..7dad704 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -713,14 +713,15 @@ struct ubi_attach_info { * @torture: if the physical eraseblock has to be tortured * @anchor: produce a anchor PEB to by used by fastmap * - * The @func pointer points to the worker function. If the @cancel argument is - * not zero, the worker has to free the resources and exit immediately. The - * worker has to return zero in case of success and a negative error code in + * The @func pointer points to the worker function. If the @shutdown argument is + * not zero, the worker has to free the resources and exit immediately as the + * WL sub-system is shutting down. + * The worker has to return zero in case of success and a negative error code in * case of failure. */ struct ubi_work { struct list_head list; - int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); + int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int shutdown); /* The below fields are only relevant to erasure works */ struct ubi_wl_entry *e; int vol_id; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..253ec9b 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -864,7 +864,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) } static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel); + int shutdown); #ifdef CONFIG_MTD_UBI_FASTMAP /** @@ -990,14 +990,15 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e, * wear_leveling_worker - wear-leveling worker function. * @ubi: UBI device description object * @wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit + * @shutdown: non-zero if the worker has to free memory and exit + * because the WL-subsystem is shutting down * * This function copies a more worn out physical eraseblock to a less worn out * one. Returns zero in case of success and a negative error code in case of * failure. */ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, - int cancel) + int shutdown) { int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0; int vol_id = -1, uninitialized_var(lnum); @@ -1008,7 +1009,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, struct ubi_vid_hdr *vid_hdr; kfree(wrk); - if (cancel) + if (shutdown) return 0; vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); @@ -1407,7 +1408,8 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi) * erase_worker - physical eraseblock erase worker function. * @ubi: UBI device description object * @wl_wrk: the work object - * @cancel: non-zero if the worker has to free memory and exit + * @shutdown: non-zero if the worker has to free memory and exit + * because the WL sub-system is shutting down * * This function erases a physical eraseblock and perform torture testing if * needed. It also takes care about marking the physical eraseblock bad if @@ -1415,7 +1417,7 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi) * failure. */ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, - int cancel) + int shutdown) { struct ubi_wl_entry *e = wl_wrk->e; int pnum = e->pnum; @@ -1423,7 +1425,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, int lnum = wl_wrk->lnum; int err, available_consumed = 0; - if (cancel) { + if (shutdown) { dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); kfree(wl_wrk); kmem_cache_free(ubi_wl_entry_slab, e); @@ -1845,10 +1847,10 @@ int ubi_thread(void *u) } /** - * cancel_pending - cancel all pending works. + * shutdown_work - shutdown all pending works. * @ubi: UBI device description object */ -static void cancel_pending(struct ubi_device *ubi) +static void shutdown_work(struct ubi_device *ubi) { while (!list_empty(&ubi->works)) { struct ubi_work *wrk; @@ -1997,7 +1999,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) return 0; out_free: - cancel_pending(ubi); + shutdown_work(ubi); tree_destroy(&ubi->used); tree_destroy(&ubi->free); tree_destroy(&ubi->scrub); @@ -2029,7 +2031,7 @@ static void protection_queue_destroy(struct ubi_device *ubi) void ubi_wl_close(struct ubi_device *ubi) { dbg_wl("close the WL sub-system"); - cancel_pending(ubi); + shutdown_work(ubi); protection_queue_destroy(ubi); tree_destroy(&ubi->used); tree_destroy(&ubi->erroneous); -- 1.8.4.5 From ezequiel at vanguardiasur.com.ar Mon Sep 22 05:51:07 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 22 Sep 2014 13:51:07 +0100 Subject: [PATCH v4 0/5] nand: OMAP collected fixes In-Reply-To: <541FDC2F.4020103@ti.com> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <541FDC2F.4020103@ti.com> Message-ID: <54201B3B.50007@vanguardiasur.com.ar> On 09/22/2014 09:22 AM, Roger Quadros wrote: > Hi Ezequiel, > > On 09/20/2014 07:53 PM, Ezequiel Garcia wrote: >> I've collected all the changes recently discussed in a whole patchset. >> If you are just reading this for the first time please take a look at: >> >> [1] http://www.spinics.net/lists/linux-omap/msg110965.html >> [2] http://www.spinics.net/lists/linux-omap/msg110958.html >> >> As requested by Roger, the omap_elm is a 'bool' driver now. The plan >> is to merge it inside omap2_nand, but my queue is really filled, so >> if anyone feels like doing, please be my guest. >> >> Although I'm hoping this to be the last round, feedback and testing >> is welcome. > > Patches 3 and 4 still have checkpatch issues. > I think you didn't look at them in detail. Unless I'm missing something, it's just warning about MAINTAINERS update: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #16: drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #13: drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 This driver is not in MAINTAINERS. If you want to start maintaining it, it'd be good to add you to MAINTAINERS so people Cc you properly on patches. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From boris.brezillon at free-electrons.com Mon Sep 22 07:25:09 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:25:09 +0200 Subject: [PATCH v2 0/2] mtd: nand: support ONFI timings mode retrieval for non-ONFI NANDs Message-ID: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> Hi, Following the series adding ONFI timing mode support, here is a series adding support for timing mode retrieval on non-ONFI NANDs. It just adds a new field to the nand_chip and nand_flash_dev struct so that anyone can define its chip requirements in the nand_ids table. The 2nd patch serves as an example and adds an entry for the Hynix H27UCG8T2ATR-BC NAND chip used on the Cubietruck board. Best Regards, Boris Changes since v1: - fix H27UCG8T2ATR-BC definition - rename onfi_timing_mode_ds field into onfi_timing_mode_default Boris BREZILLON (2): mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table drivers/mtd/nand/nand_base.c | 2 ++ drivers/mtd/nand/nand_ids.c | 4 ++++ include/linux/mtd/nand.h | 11 +++++++++++ 3 files changed, 17 insertions(+) -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 07:25:11 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:25:11 +0200 Subject: [PATCH v2 2/2] mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table In-Reply-To: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411395911-30365-3-git-send-email-boris.brezillon@free-electrons.com> Add the full description of the Hynix H27UCG8T2ATR-BC NAND chip in the nand_ids table so that we can later use the NAND ECC infos and ONFI timings mode in controller drivers. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/nand_ids.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 3d7c89f..fbde8910 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = { {"SDTNRGAMA 64G 3.3V 8-bit", { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, + {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, + SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K), + 4 }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 07:25:10 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:25:10 +0200 Subject: [PATCH v2 1/2] mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs In-Reply-To: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411395911-30365-2-git-send-email-boris.brezillon@free-electrons.com> Add an onfi_timing_mode_default field to nand_chip and nand_flash_dev in order to support NAND timings definition for non-ONFI NAND. NAND that support better timings mode than the default one have to define a new entry in the nand_ids table. The default timing mode should be deduced from timings description from the datasheet and the ONFI specification (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 "Timing Parameters"). You should choose the closest mode that fit the timings requirements of your NAND chip. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/nand_base.c | 2 ++ include/linux/mtd/nand.h | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ae6e7c4..c37fa2a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3594,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, chip->options |= type->options; chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->onfi_timing_mode_default = + type->onfi_timing_mode_default; *busw = type->options & NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index b7c1199..e795fbf 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -587,6 +587,11 @@ struct nand_buffers { * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, * also from the datasheet. It is the recommended ECC step * size, if known; if unknown, set to zero. + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is + * either deduced from the datasheet if the NAND + * chip is not ONFI compliant or set to 0 if it is + * (an ONFI chip is always configured in mode 0 + * after a NAND reset) * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 @@ -671,6 +676,7 @@ struct nand_chip { uint8_t bits_per_cell; uint16_t ecc_strength_ds; uint16_t ecc_step_ds; + int onfi_timing_mode_default; int badblockpos; int badblockbits; @@ -773,6 +779,10 @@ struct nand_chip { * @ecc_step_ds in nand_chip{}, also from the datasheet. * For example, the "4bit ECC for each 512Byte" can be set with * NAND_ECC_INFO(4, 512). + * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND + * reset. Should be deduced from timings described + * in the datasheet. + * */ struct nand_flash_dev { char *name; @@ -793,6 +803,7 @@ struct nand_flash_dev { uint16_t strength_ds; uint16_t step_ds; } ecc; + int onfi_timing_mode_default; }; /** -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 07:42:51 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:42:51 +0200 Subject: [PATCH v5 2/2] mtd: nand: add sunxi NFC dt bindings doc In-Reply-To: <1411396971-30801-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411396971-30801-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411396971-30801-3-git-send-email-boris.brezillon@free-electrons.com> Add the sunxi NAND Flash Controller dt bindings documentation. Signed-off-by: Boris BREZILLON --- .../devicetree/bindings/mtd/sunxi-nand.txt | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt new file mode 100644 index 0000000..0273adb --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt @@ -0,0 +1,45 @@ +Allwinner NAND Flash Controller (NFC) + +Required properties: +- compatible : "allwinner,sun4i-a10-nand". +- reg : shall contain registers location and length for data and reg. +- interrupts : shall define the nand controller interrupt. +- #address-cells: shall be set to 1. Encode the nand CS. +- #size-cells : shall be set to 0. +- clocks : shall reference nand controller clocks. +- clock-names : nand controller internal clock names. Shall contain : + * "ahb" : AHB gating clock + * "mod" : nand controller clock + +Optional children nodes: +Children nodes represent the available nand chips. + +Optional properties: +- allwinner,rb : shall contain the native Ready/Busy ids. + or +- rb-gpios : shall contain the gpios used as R/B pins. +- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", + "soft_bch" or "none") + +see Documentation/devicetree/mtd/nand.txt for generic bindings. + + +Examples: +nfc: nand at 01c03000 { + compatible = "allwinner,sun4i-a10-nand"; + reg = <0x01c03000 0x1000>; + interrupts = <0 37 1>; + clocks = <&ahb_gates 13>, <&nand_clk>; + clock-names = "ahb", "mod"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; + status = "okay"; + + nand at 0 { + reg = <0>; + allwinner,rb = <0>; + nand-ecc-mode = "soft_bch"; + }; +}; -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 07:42:49 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:42:49 +0200 Subject: [PATCH v5 0/2] mtd: nand: add sunxi NAND flash controller support Message-ID: <1411396971-30801-1-git-send-email-boris.brezillon@free-electrons.com> Hi, This patch series adds support for the sunxi NAND Flash Controller (NFC) block. These two patches only add support for the basic NAND stuff: - NAND controller operations - SW and HW ECC handling (with both syndrome and normal ECC scheme) If you want support for advanced features you can find it on my github repo [1]: - HW randomization support - per partition ECC/Randomizer to handle bootloader partitions DMA transfers are not supported yet, but I have reworked the OOB layout when using the HW ECC scheme to match the one used when accessing the NAND with DMA transfers (the available OOB bytes are placed at the end of the OOB area). This patch series depends on this patch [2] adding support for ONFI timing mode retrieval on non-ONFI NANDs. Best Regards, Boris [1]https://github.com/bbrezillon/linux-sunxi/tree/sunxi-nand-v5 [2]https://patchwork.ozlabs.org/patch/391968/ Changes since v4: - adapt to v2 of "mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs" series Changes since v3: - removed nand core code modifications from the patch series (submitted separately) - added documentation to the code - forced timeout (a default timeout is used when none is provided by the caller) on controller operations - fixed coding style issues - removed unneeded irq field from the sunxi_nfc struct - fixed several memory leaks - reworked the NFC reset code (to avoid potential garbage config from the bootloader) - made use of ECC_EXCEPTION flag to prevent erased page from generating ECC errors - changed the OOB layout for HW ECC scheme Changes since v2: - merge HW ECC implementation in base implementation patch - fix timing config when interfacing with an ONFI compatible chip Changes since v1: - add HW ECC support - rework NAND timings retrieval (use ONFI timing mode instead of raw timings) - add nand-ecc-level property to specify NAND ECC requirements from DT Boris BREZILLON (2): mtd: nand: add sunxi NAND flash controller support mtd: nand: add sunxi NFC dt bindings doc Boris BREZILLON (2): mtd: nand: add sunxi NAND flash controller support mtd: nand: add sunxi NFC dt bindings doc .../devicetree/bindings/mtd/sunxi-nand.txt | 45 + drivers/mtd/nand/Kconfig | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand.c | 1362 ++++++++++++++++++++ 4 files changed, 1414 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/sunxi-nand.txt create mode 100644 drivers/mtd/nand/sunxi_nand.c -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 07:42:50 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 16:42:50 +0200 Subject: [PATCH v5 1/2] mtd: nand: add sunxi NAND flash controller support In-Reply-To: <1411396971-30801-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411396971-30801-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411396971-30801-2-git-send-email-boris.brezillon@free-electrons.com> Add support for the sunxi NAND Flash Controller (NFC). Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/Kconfig | 6 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/sunxi_nand.c | 1362 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1369 insertions(+) create mode 100644 drivers/mtd/nand/sunxi_nand.c diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1cf503..bd94d12 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -513,4 +513,10 @@ config MTD_NAND_XWAY Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached to the External Bus Unit (EBU). +config MTD_NAND_SUNXI + tristate "Support for NAND on Allwinner SoCs" + depends on ARCH_SUNXI + help + Enables support for NAND Flash chips on Allwinner SoCs. + endif # MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a035e7c..ff56eaf 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ +obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o nand-objs := nand_base.o nand_bbt.o nand_timings.o diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c new file mode 100644 index 0000000..4fcecfb --- /dev/null +++ b/drivers/mtd/nand/sunxi_nand.c @@ -0,0 +1,1362 @@ +/* + * Copyright (C) 2013 Boris BREZILLON + * + * Derived from: + * https://github.com/yuq/sunxi-nfc-mtd + * Copyright (C) 2013 Qiang Yu + * + * https://github.com/hno/Allwinner-Info + * Copyright (C) 2013 Henrik Nordstr?m + * + * Copyright (C) 2013 Dmitriy B. + * Copyright (C) 2013 Sergey Lapin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NFC_REG_CTL 0x0000 +#define NFC_REG_ST 0x0004 +#define NFC_REG_INT 0x0008 +#define NFC_REG_TIMING_CTL 0x000C +#define NFC_REG_TIMING_CFG 0x0010 +#define NFC_REG_ADDR_LOW 0x0014 +#define NFC_REG_ADDR_HIGH 0x0018 +#define NFC_REG_SECTOR_NUM 0x001C +#define NFC_REG_CNT 0x0020 +#define NFC_REG_CMD 0x0024 +#define NFC_REG_RCMD_SET 0x0028 +#define NFC_REG_WCMD_SET 0x002C +#define NFC_REG_IO_DATA 0x0030 +#define NFC_REG_ECC_CTL 0x0034 +#define NFC_REG_ECC_ST 0x0038 +#define NFC_REG_DEBUG 0x003C +#define NFC_REG_ECC_CNT0 0x0040 +#define NFC_REG_ECC_CNT1 0x0044 +#define NFC_REG_ECC_CNT2 0x0048 +#define NFC_REG_ECC_CNT3 0x004c +#define NFC_REG_USER_DATA_BASE 0x0050 +#define NFC_REG_SPARE_AREA 0x00A0 +#define NFC_RAM0_BASE 0x0400 +#define NFC_RAM1_BASE 0x0800 + +/* define bit use in NFC_CTL */ +#define NFC_EN BIT(0) +#define NFC_RESET BIT(1) +#define NFC_BUS_WIDYH BIT(2) +#define NFC_RB_SEL BIT(3) +#define NFC_CE_SEL GENMASK(26, 24) +#define NFC_CE_CTL BIT(6) +#define NFC_CE_CTL1 BIT(7) +#define NFC_PAGE_SIZE GENMASK(11, 8) +#define NFC_SAM BIT(12) +#define NFC_RAM_METHOD BIT(14) +#define NFC_DEBUG_CTL BIT(31) + +/* define bit use in NFC_ST */ +#define NFC_RB_B2R BIT(0) +#define NFC_CMD_INT_FLAG BIT(1) +#define NFC_DMA_INT_FLAG BIT(2) +#define NFC_CMD_FIFO_STATUS BIT(3) +#define NFC_STA BIT(4) +#define NFC_NATCH_INT_FLAG BIT(5) +#define NFC_RB_STATE0 BIT(8) +#define NFC_RB_STATE1 BIT(9) +#define NFC_RB_STATE2 BIT(10) +#define NFC_RB_STATE3 BIT(11) + +/* define bit use in NFC_INT */ +#define NFC_B2R_INT_ENABLE BIT(0) +#define NFC_CMD_INT_ENABLE BIT(1) +#define NFC_DMA_INT_ENABLE BIT(2) +#define NFC_INT_MASK (NFC_B2R_INT_ENABLE | \ + NFC_CMD_INT_ENABLE | \ + NFC_DMA_INT_ENABLE) + +/* define bit use in NFC_CMD */ +#define NFC_CMD_LOW_BYTE GENMASK(7, 0) +#define NFC_CMD_HIGH_BYTE GENMASK(15, 8) +#define NFC_ADR_NUM GENMASK(18, 16) +#define NFC_SEND_ADR BIT(19) +#define NFC_ACCESS_DIR BIT(20) +#define NFC_DATA_TRANS BIT(21) +#define NFC_SEND_CMD1 BIT(22) +#define NFC_WAIT_FLAG BIT(23) +#define NFC_SEND_CMD2 BIT(24) +#define NFC_SEQ BIT(25) +#define NFC_DATA_SWAP_METHOD BIT(26) +#define NFC_ROW_AUTO_INC BIT(27) +#define NFC_SEND_CMD3 BIT(28) +#define NFC_SEND_CMD4 BIT(29) +#define NFC_CMD_TYPE GENMASK(31, 30) + +/* define bit use in NFC_RCMD_SET */ +#define NFC_READ_CMD GENMASK(7, 0) +#define NFC_RANDOM_READ_CMD0 GENMASK(15, 8) +#define NFC_RANDOM_READ_CMD1 GENMASK(23, 16) + +/* define bit use in NFC_WCMD_SET */ +#define NFC_PROGRAM_CMD GENMASK(7, 0) +#define NFC_RANDOM_WRITE_CMD GENMASK(15, 8) +#define NFC_READ_CMD0 GENMASK(23, 16) +#define NFC_READ_CMD1 GENMASK(31, 24) + +/* define bit use in NFC_ECC_CTL */ +#define NFC_ECC_EN BIT(0) +#define NFC_ECC_PIPELINE BIT(3) +#define NFC_ECC_EXCEPTION BIT(4) +#define NFC_ECC_BLOCK_SIZE BIT(5) +#define NFC_RANDOM_EN BIT(9) +#define NFC_RANDOM_DIRECTION BIT(10) +#define NFC_ECC_MODE_SHIFT 12 +#define NFC_ECC_MODE GENMASK(15, 12) +#define NFC_RANDOM_SEED GENMASK(30, 16) + +#define DEFAULT_NAME_FORMAT "nand@%d" +#define MAX_NAME_SIZE (sizeof("nand@") + 2) + +#define NFC_DEFAULT_TIMEOUT_MS 1000 + +/* + * Ready/Busy detection type: describes the Ready/Busy detection modes + * + * @RB_NONE: no external detection available, rely on STATUS command + * and software timeouts + * @RB_NATIVE: use sunxi NAND controller Ready/Busy support. The Ready/Busy + * pin of the NAND flash chip must be connected to one of the + * native NAND R/B pins (those which can be muxed to the NAND + * Controller) + * @RB_GPIO: use a simple GPIO to handle Ready/Busy status. The Ready/Busy + * pin of the NAND flash chip must be connected to a GPIO capable + * pin. + */ +enum sunxi_nand_rb_type { + RB_NONE, + RB_NATIVE, + RB_GPIO, +}; + +/* + * Ready/Busy structure: stores informations related to Ready/Busy detection + * + * @type: the Ready/Busy detection mode + * @info: information related to the R/B detection mode. Either a gpio + * id or a native R/B id (those supported by the NAND controller). + */ +struct sunxi_nand_rb { + enum sunxi_nand_rb_type type; + union { + int gpio; + int nativeid; + } info; +}; + +/* + * Chip Select structure: stores informations related to NAND Chip Select + * + * @cs: the NAND CS id used to communicate with a NAND Chip + * @rb: the Ready/Busy description + */ +struct sunxi_nand_chip_sel { + u8 cs; + struct sunxi_nand_rb rb; +}; + +/* + * sunxi HW ECC infos: stores informations related to HW ECC support + * + * @mode: the sunxi ECC mode field deduced from ECC requirements + * @layout: the OOB layout depending on the ECC requirements and the + * selected ECC mode + */ +struct sunxi_nand_hw_ecc { + int mode; + struct nand_ecclayout layout; +}; + +/* + * NAND chip structure: stores NAND chip device related informations + * + * @node: used to store NAND chips into a list + * @nand: base NAND chip structure + * @mtd: base MTD structure + * @default_name: name used if no name was provided by the DT + * @clk_rate: clk_rate required for this NAND chip + * @selected: current active CS + * @nsels: number of CS lines required by the NAND chip + * @sels: array of CS lines descriptions + */ +struct sunxi_nand_chip { + struct list_head node; + struct nand_chip nand; + struct mtd_info mtd; + char default_name[MAX_NAME_SIZE]; + unsigned long clk_rate; + int selected; + int nsels; + struct sunxi_nand_chip_sel sels[0]; +}; + +static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand) +{ + return container_of(nand, struct sunxi_nand_chip, nand); +} + +/* + * NAND Controller structure: stores sunxi NAND controller informations + * + * @controller: base controller structure + * @regs: NAND controller registers + * @ahb_clk: NAND Controller AHB clock + * @mod_clk: NAND Controller mod clock + * @assigned_cs: bitmask describing already assigned CS lines + * @clk_rate: NAND controller current clock rate + * @chips: a list containing all the NAND chips attached to + * this NAND controller + * @complete: a completion object used to wait for NAND + * controller events + */ +struct sunxi_nfc { + struct nand_hw_control controller; + void __iomem *regs; + struct clk *ahb_clk; + struct clk *mod_clk; + unsigned long assigned_cs; + unsigned long clk_rate; + struct list_head chips; + struct completion complete; +}; + +static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl) +{ + return container_of(ctrl, struct sunxi_nfc, controller); +} + +static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id) +{ + struct sunxi_nfc *nfc = dev_id; + u32 st = readl(nfc->regs + NFC_REG_ST); + u32 ien = readl(nfc->regs + NFC_REG_INT); + + if (!(ien & st)) + return IRQ_NONE; + + if ((ien & st) == ien) + complete(&nfc->complete); + + writel(st & NFC_INT_MASK, nfc->regs + NFC_REG_ST); + writel(~st & ien & NFC_INT_MASK, nfc->regs + NFC_REG_INT); + + return IRQ_HANDLED; +} + +static int sunxi_nfc_wait_int(struct sunxi_nfc *nfc, u32 flags, + unsigned int timeout_ms) +{ + init_completion(&nfc->complete); + + writel(flags, nfc->regs + NFC_REG_INT); + + if (!timeout_ms) + timeout_ms = NFC_DEFAULT_TIMEOUT_MS; + + if (!wait_for_completion_timeout(&nfc->complete, + msecs_to_jiffies(timeout_ms))) + return -ETIMEDOUT; + + return 0; +} + +static void sunxi_nfc_wait_cmd_fifo_empty(struct sunxi_nfc *nfc) +{ + unsigned long timeout = jiffies + + msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS); + + while ((readl(nfc->regs + NFC_REG_ST) & NFC_CMD_FIFO_STATUS) && + time_before(jiffies, timeout)) + ; +} + +static void sunxi_nfc_rst(struct sunxi_nfc *nfc) +{ + unsigned long timeout = jiffies + + msecs_to_jiffies(NFC_DEFAULT_TIMEOUT_MS); + + writel(0, nfc->regs + NFC_REG_ECC_CTL); + writel(NFC_RESET, nfc->regs + NFC_REG_CTL); + while ((readl(nfc->regs + NFC_REG_CTL) & NFC_RESET) && + time_before(jiffies, timeout)) + ; +} + +static int sunxi_nfc_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); + struct sunxi_nand_rb *rb; + unsigned long timeo = (sunxi_nand->nand.state == FL_ERASING ? 400 : 20); + int ret; + + if (sunxi_nand->selected < 0) + return 0; + + rb = &sunxi_nand->sels[sunxi_nand->selected].rb; + + switch (rb->type) { + case RB_NATIVE: + ret = !!(readl(nfc->regs + NFC_REG_ST) & + (NFC_RB_STATE0 << rb->info.nativeid)); + if (ret) + break; + + sunxi_nfc_wait_int(nfc, NFC_RB_B2R, timeo); + ret = !!(readl(nfc->regs + NFC_REG_ST) & + (NFC_RB_STATE0 << rb->info.nativeid)); + break; + case RB_GPIO: + ret = gpio_get_value(rb->info.gpio); + break; + case RB_NONE: + default: + ret = 0; + pr_err("cannot check R/B NAND status!"); + break; + } + + return ret; +} + +static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); + struct sunxi_nand_chip_sel *sel; + u32 ctl; + + if (chip > 0 && chip >= sunxi_nand->nsels) + return; + + if (chip == sunxi_nand->selected) + return; + + ctl = readl(nfc->regs + NFC_REG_CTL) & + ~(NFC_CE_SEL | NFC_RB_SEL | NFC_EN); + + if (chip >= 0) { + sel = &sunxi_nand->sels[chip]; + + ctl |= (sel->cs << 24) | NFC_EN | + (((nand->page_shift - 10) & 0xf) << 8); + if (sel->rb.type == RB_NONE) { + nand->dev_ready = NULL; + } else { + nand->dev_ready = sunxi_nfc_dev_ready; + if (sel->rb.type == RB_NATIVE) + ctl |= (sel->rb.info.nativeid << 3); + } + + writel(mtd->writesize, nfc->regs + NFC_REG_SPARE_AREA); + + if (nfc->clk_rate != sunxi_nand->clk_rate) { + clk_set_rate(nfc->mod_clk, sunxi_nand->clk_rate); + nfc->clk_rate = sunxi_nand->clk_rate; + } + } + + writel(ctl, nfc->regs + NFC_REG_CTL); + + sunxi_nand->selected = chip; +} + +static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); + int cnt; + int offs = 0; + u32 tmp; + + while (len > offs) { + cnt = len - offs; + if (cnt > 1024) + cnt = 1024; + + sunxi_nfc_wait_cmd_fifo_empty(nfc); + writel(cnt, nfc->regs + NFC_REG_CNT); + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + if (buf) + memcpy_fromio(buf + offs, nfc->regs + NFC_RAM0_BASE, + cnt); + offs += cnt; + } +} + +static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); + int cnt; + int offs = 0; + u32 tmp; + + while (len > offs) { + cnt = len - offs; + if (cnt > 1024) + cnt = 1024; + + sunxi_nfc_wait_cmd_fifo_empty(nfc); + writel(cnt, nfc->regs + NFC_REG_CNT); + memcpy_toio(nfc->regs + NFC_RAM0_BASE, buf + offs, cnt); + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | + NFC_ACCESS_DIR; + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + offs += cnt; + } +} + +static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd) +{ + uint8_t ret; + + sunxi_nfc_read_buf(mtd, &ret, 1); + + return ret; +} + +static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, + unsigned int ctrl) +{ + struct nand_chip *nand = mtd->priv; + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); + u32 tmp; + + sunxi_nfc_wait_cmd_fifo_empty(nfc); + + if (ctrl & NAND_CTRL_CHANGE) { + tmp = readl(nfc->regs + NFC_REG_CTL); + if (ctrl & NAND_NCE) + tmp |= NFC_CE_CTL; + else + tmp &= ~NFC_CE_CTL; + writel(tmp, nfc->regs + NFC_REG_CTL); + } + + if (dat == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) { + writel(NFC_SEND_CMD1 | dat, nfc->regs + NFC_REG_CMD); + } else { + writel(dat, nfc->regs + NFC_REG_ADDR_LOW); + writel(NFC_SEND_ADR, nfc->regs + NFC_REG_CMD); + } + + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); +} + +static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct nand_ecclayout *layout = ecc->layout; + struct sunxi_nand_hw_ecc *data = ecc->priv; + int steps = mtd->writesize / ecc->size; + unsigned int max_bitflips = 0; + int offset; + u32 tmp; + int i; + int cnt; + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); + tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | + NFC_ECC_EXCEPTION; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + for (i = 0; i < steps; i++) { + if (i) + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1); + + offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4; + + chip->read_buf(mtd, NULL, ecc->size); + + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + sunxi_nfc_wait_cmd_fifo_empty(nfc); + + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + memcpy_fromio(buf + (i * ecc->size), + nfc->regs + NFC_RAM0_BASE, ecc->size); + + if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { + mtd->ecc_stats.failed++; + } else { + tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; + mtd->ecc_stats.corrected += tmp; + max_bitflips = max_t(unsigned int, max_bitflips, tmp); + } + + if (oob_required) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + sunxi_nfc_wait_cmd_fifo_empty(nfc); + offset -= mtd->writesize; + chip->read_buf(mtd, chip->oob_poi + offset, + ecc->bytes + 4); + } + } + + if (oob_required) { + cnt = ecc->layout->oobfree[steps].length; + if (cnt > 0) { + offset = mtd->writesize + + ecc->layout->oobfree[steps].offset; + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + offset -= mtd->writesize; + chip->read_buf(mtd, chip->oob_poi + offset, cnt); + } + } + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~NFC_ECC_EN; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + return max_bitflips; +} + +static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) +{ + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct nand_ecclayout *layout = ecc->layout; + struct sunxi_nand_hw_ecc *data = ecc->priv; + int offset; + u32 tmp; + int i; + int cnt; + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); + tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | + NFC_ECC_EXCEPTION; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + for (i = 0; i < mtd->writesize / ecc->size; i++) { + if (i) + chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1); + + chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); + + offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize; + + /* Fill OOB data in */ + if (oob_required) { + tmp = 0xffffffff; + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp, + 4); + } else { + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, + chip->oob_poi + offset - mtd->writesize, + 4); + } + + chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); + sunxi_nfc_wait_cmd_fifo_empty(nfc); + + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | + (1 << 30); + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + } + + if (oob_required) { + cnt = ecc->layout->oobfree[i].length; + if (cnt > 0) { + offset = mtd->writesize + + ecc->layout->oobfree[i].offset; + chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); + offset -= mtd->writesize; + chip->write_buf(mtd, chip->oob_poi + offset, cnt); + } + } + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~NFC_ECC_EN; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + return 0; +} + +static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int oob_required, + int page) +{ + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct sunxi_nand_hw_ecc *data = ecc->priv; + int steps = mtd->writesize / ecc->size; + unsigned int max_bitflips = 0; + uint8_t *oob = chip->oob_poi; + int offset = 0; + int cnt; + u32 tmp; + int i; + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); + tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | + NFC_ECC_EXCEPTION; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + for (i = 0; i < steps; i++) { + chip->read_buf(mtd, NULL, ecc->size); + + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30); + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + memcpy_fromio(buf, nfc->regs + NFC_RAM0_BASE, ecc->size); + buf += ecc->size; + offset += ecc->size; + + if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) { + mtd->ecc_stats.failed++; + } else { + tmp = readl(nfc->regs + NFC_REG_ECC_CNT0) & 0xff; + mtd->ecc_stats.corrected += tmp; + max_bitflips = max_t(unsigned int, max_bitflips, tmp); + } + + if (oob_required) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad); + oob += ecc->bytes + ecc->prepad; + } + + offset += ecc->bytes + ecc->prepad; + } + + if (oob_required) { + cnt = mtd->oobsize - (oob - chip->oob_poi); + if (cnt > 0) { + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1); + chip->read_buf(mtd, oob, cnt); + } + } + + writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN, + nfc->regs + NFC_REG_ECC_CTL); + + return max_bitflips; +} + +static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller); + struct nand_ecc_ctrl *ecc = &chip->ecc; + struct sunxi_nand_hw_ecc *data = ecc->priv; + int steps = mtd->writesize / ecc->size; + uint8_t *oob = chip->oob_poi; + int offset = 0; + int cnt; + u32 tmp; + int i; + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE); + tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) | + NFC_ECC_EXCEPTION; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + for (i = 0; i < steps; i++) { + chip->write_buf(mtd, buf + (i * ecc->size), ecc->size); + offset += ecc->size; + + /* Fill OOB data in */ + if (oob_required) { + tmp = 0xffffffff; + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, &tmp, + 4); + } else { + memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob , + 4); + } + + tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR | + (1 << 30); + writel(tmp, nfc->regs + NFC_REG_CMD); + sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0); + + offset += ecc->bytes + ecc->prepad; + oob += ecc->bytes + ecc->prepad; + } + + if (oob_required) { + cnt = mtd->oobsize - (oob - chip->oob_poi); + if (cnt > 0) { + chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1); + chip->write_buf(mtd, oob, cnt); + } + } + + tmp = readl(nfc->regs + NFC_REG_ECC_CTL); + tmp &= ~NFC_ECC_EN; + + writel(tmp, nfc->regs + NFC_REG_ECC_CTL); + + return 0; +} + +static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, + const struct nand_sdr_timings *timings) +{ + u32 min_clk_period = 0; + + /* T1 <=> tCLS */ + if (timings->tCLS_min > min_clk_period) + min_clk_period = timings->tCLS_min; + + /* T2 <=> tCLH */ + if (timings->tCLH_min > min_clk_period) + min_clk_period = timings->tCLH_min; + + /* T3 <=> tCS */ + if (timings->tCS_min > min_clk_period) + min_clk_period = timings->tCS_min; + + /* T4 <=> tCH */ + if (timings->tCH_min > min_clk_period) + min_clk_period = timings->tCH_min; + + /* T5 <=> tWP */ + if (timings->tWP_min > min_clk_period) + min_clk_period = timings->tWP_min; + + /* T6 <=> tWH */ + if (timings->tWH_min > min_clk_period) + min_clk_period = timings->tWH_min; + + /* T7 <=> tALS */ + if (timings->tALS_min > min_clk_period) + min_clk_period = timings->tALS_min; + + /* T8 <=> tDS */ + if (timings->tDS_min > min_clk_period) + min_clk_period = timings->tDS_min; + + /* T9 <=> tDH */ + if (timings->tDH_min > min_clk_period) + min_clk_period = timings->tDH_min; + + /* T10 <=> tRR */ + if (timings->tRR_min > (min_clk_period * 3)) + min_clk_period = (timings->tRR_min + 2) / 3; + + /* T11 <=> tALH */ + if (timings->tALH_min > min_clk_period) + min_clk_period = timings->tALH_min; + + /* T12 <=> tRP */ + if (timings->tRP_min > min_clk_period) + min_clk_period = timings->tRP_min; + + /* T13 <=> tREH */ + if (timings->tREH_min > min_clk_period) + min_clk_period = timings->tREH_min; + + /* T14 <=> tRC */ + if (timings->tRC_min > (min_clk_period * 2)) + min_clk_period = (timings->tRC_min + 1) / 2; + + /* T15 <=> tWC */ + if (timings->tWC_min > (min_clk_period * 2)) + min_clk_period = (timings->tWC_min + 1) / 2; + + + /* min_clk_period = (NAND-clk-period * 2) */ + if (min_clk_period < 1000) + min_clk_period = 1000; + + min_clk_period /= 1000; + chip->clk_rate = (2 * 1000000000) / min_clk_period; + + /* TODO: configure T16-T19 */ + + return 0; +} + +static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip, + struct device_node *np) +{ + const struct nand_sdr_timings *timings; + int ret; + int mode; + + mode = onfi_get_async_timing_mode(&chip->nand); + if (mode == ONFI_TIMING_MODE_UNKNOWN) { + mode = chip->nand.onfi_timing_mode_default; + } else { + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; + + mode = fls(mode) - 1; + if (mode < 0) + mode = 0; + + feature[0] = mode; + ret = chip->nand.onfi_set_features(&chip->mtd, &chip->nand, + ONFI_FEATURE_ADDR_TIMING_MODE, + feature); + if (ret) + return ret; + } + + timings = onfi_async_timing_mode_to_sdr_timings(mode); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + return sunxi_nand_chip_set_timings(chip, timings); +} + +static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc, + struct device_node *np) +{ + struct sunxi_nand_hw_ecc *data; + struct nand_ecclayout *layout; + int nsectors; + int ret; + + if (!ecc->strength || !ecc->size) + return -EINVAL; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Add ECC info retrieval from DT */ + if (ecc->strength <= 16) { + ecc->strength = 16; + data->mode = 0; + } else if (ecc->strength <= 24) { + ecc->strength = 24; + data->mode = 1; + } else if (ecc->strength <= 28) { + ecc->strength = 28; + data->mode = 2; + } else if (ecc->strength <= 32) { + ecc->strength = 32; + data->mode = 3; + } else if (ecc->strength <= 40) { + ecc->strength = 40; + data->mode = 4; + } else if (ecc->strength <= 48) { + ecc->strength = 48; + data->mode = 5; + } else if (ecc->strength <= 56) { + ecc->strength = 56; + data->mode = 6; + } else if (ecc->strength <= 60) { + ecc->strength = 60; + data->mode = 7; + } else if (ecc->strength <= 64) { + ecc->strength = 64; + data->mode = 8; + } else { + pr_err("unsupported strength\n"); + ret = -ENOTSUPP; + goto err; + } + + /* HW ECC always request ECC bytes for 1024 bytes blocks */ + ecc->bytes = ((ecc->strength * fls(8 * 1024)) + 7) / 8; + + /* HW ECC always work with even numbers of ECC bytes */ + if (ecc->bytes % 2) + ecc->bytes++; + + layout = &data->layout; + nsectors = mtd->writesize / ecc->size; + + if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { + ret = -EINVAL; + goto err; + } + + layout->eccbytes = (ecc->bytes * nsectors); + + ecc->layout = layout; + ecc->priv = data; + + return 0; + +err: + kfree(data); + + return ret; +} + +static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) +{ + kfree(ecc->priv); +} + +static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc, + struct device_node *np) +{ + struct nand_ecclayout *layout; + int nsectors; + int i, j; + int ret; + + ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); + if (ret) + return ret; + + ecc->read_page = sunxi_nfc_hw_ecc_read_page; + ecc->write_page = sunxi_nfc_hw_ecc_write_page; + layout = ecc->layout; + nsectors = mtd->writesize / ecc->size; + + for (i = 0; i < nsectors; i++) { + if (i) { + layout->oobfree[i].offset = + layout->oobfree[i - 1].offset + + layout->oobfree[i - 1].length + + ecc->bytes; + layout->oobfree[i].length = 4; + } else { + /* + * The first 2 bytes are used for BB markers, hence we + * only have 2 bytes available in the first user data + * section. + */ + layout->oobfree[i].length = 2; + layout->oobfree[i].offset = 2; + } + + for (j = 0; j < ecc->bytes; j++) + layout->eccpos[(ecc->bytes * i) + j] = + layout->oobfree[i].offset + + layout->oobfree[i].length + j; + } + + if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { + layout->oobfree[nsectors].offset = + layout->oobfree[nsectors - 1].offset + + layout->oobfree[nsectors - 1].length + + ecc->bytes; + layout->oobfree[nsectors].length = mtd->oobsize - + ((ecc->bytes + 4) * nsectors); + } + + return 0; +} + +static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, + struct nand_ecc_ctrl *ecc, + struct device_node *np) +{ + struct nand_ecclayout *layout; + int nsectors; + int i; + int ret; + + ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np); + if (ret) + return ret; + + ecc->prepad = 4; + ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; + ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; + + layout = ecc->layout; + nsectors = mtd->writesize / ecc->size; + + for (i = 0; i < (ecc->bytes * nsectors); i++) + layout->eccpos[i] = i; + + layout->oobfree[0].length = mtd->oobsize - i; + layout->oobfree[0].offset = i; + + return 0; +} + +static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc) +{ + switch (ecc->mode) { + case NAND_ECC_HW: + case NAND_ECC_HW_SYNDROME: + sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc); + break; + default: + break; + } +} + +static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, + struct device_node *np) +{ + struct nand_chip *nand = mtd->priv; + u32 strength; + u32 blk_size; + int ret; + + if (!of_property_read_u32(np, "nand-ecc-step-size", &blk_size) && + !of_property_read_u32(np, "nand-ecc-strength", &strength)) { + ecc->size = blk_size; + ecc->strength = strength; + } else { + ecc->size = nand->ecc_step_ds; + ecc->strength = nand->ecc_strength_ds; + } + + ecc->mode = NAND_ECC_HW; + + ret = of_get_nand_ecc_mode(np); + if (ret >= 0) + ecc->mode = ret; + + switch (ecc->mode) { + case NAND_ECC_SOFT_BCH: + if (!ecc->size || !ecc->strength) + return -EINVAL; + ecc->bytes = ((ecc->strength * fls(8 * ecc->size)) + 7) / 8; + break; + case NAND_ECC_HW: + ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np); + if (ret) + return ret; + break; + case NAND_ECC_HW_SYNDROME: + ret = sunxi_nand_hw_syndrome_ecc_ctrl_init(mtd, ecc, np); + if (ret) + return ret; + break; + case NAND_ECC_NONE: + case NAND_ECC_SOFT: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, + struct device_node *np) +{ + const struct nand_sdr_timings *timings; + struct sunxi_nand_chip *chip; + struct mtd_part_parser_data ppdata; + struct mtd_info *mtd; + struct nand_chip *nand; + int nsels; + int ret; + int i; + u32 tmp; + + if (!of_get_property(np, "reg", &nsels)) + return -EINVAL; + + nsels /= sizeof(u32); + if (!nsels) + return -EINVAL; + + chip = devm_kzalloc(dev, + sizeof(*chip) + + (nsels * sizeof(struct sunxi_nand_chip_sel)), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->nsels = nsels; + chip->selected = -1; + + for (i = 0; i < nsels; i++) { + ret = of_property_read_u32_index(np, "reg", i, &tmp); + if (ret) + return ret; + + if (tmp > 7) + return -EINVAL; + + if (test_and_set_bit(tmp, &nfc->assigned_cs)) + return -EINVAL; + + chip->sels[i].cs = tmp; + + if (!of_property_read_u32_index(np, "allwinner,rb", i, &tmp) && + tmp < 2) { + chip->sels[i].rb.type = RB_NATIVE; + chip->sels[i].rb.info.nativeid = tmp; + } else { + ret = of_get_named_gpio(np, "rb-gpios", i); + if (ret >= 0) { + tmp = ret; + chip->sels[i].rb.type = RB_GPIO; + chip->sels[i].rb.info.gpio = tmp; + ret = devm_gpio_request(dev, tmp, "nand-rb"); + if (ret) + return ret; + + ret = gpio_direction_input(tmp); + if (ret) + return ret; + } else { + chip->sels[i].rb.type = RB_NONE; + } + } + } + + timings = onfi_async_timing_mode_to_sdr_timings(0); + if (IS_ERR(timings)) + return PTR_ERR(timings); + + ret = sunxi_nand_chip_set_timings(chip, timings); + + nand = &chip->nand; + /* Default tR value specified in the ONFI spec (chapter 4.15.1) */ + nand->chip_delay = 200; + nand->controller = &nfc->controller; + nand->select_chip = sunxi_nfc_select_chip; + nand->cmd_ctrl = sunxi_nfc_cmd_ctrl; + nand->read_buf = sunxi_nfc_read_buf; + nand->write_buf = sunxi_nfc_write_buf; + nand->read_byte = sunxi_nfc_read_byte; + + if (of_get_nand_on_flash_bbt(np)) + nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + + mtd = &chip->mtd; + mtd->dev.parent = dev; + mtd->priv = nand; + mtd->owner = THIS_MODULE; + + ret = nand_scan_ident(mtd, nsels, NULL); + if (ret) + return ret; + + ret = sunxi_nand_chip_init_timings(chip, np); + if (ret) + return ret; + + ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np); + if (ret) + return ret; + + ret = nand_scan_tail(mtd); + if (ret) + return ret; + + if (of_property_read_string(np, "nand-name", &mtd->name)) { + snprintf(chip->default_name, MAX_NAME_SIZE, + DEFAULT_NAME_FORMAT, chip->sels[i].cs); + mtd->name = chip->default_name; + } + + ppdata.of_node = np; + ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); + if (ret) { + nand_release(mtd); + return ret; + } + + list_add_tail(&chip->node, &nfc->chips); + + return 0; +} + +static int sunxi_nand_chips_init(struct device *dev, struct sunxi_nfc *nfc) +{ + struct device_node *np = dev->of_node; + struct device_node *nand_np; + int nchips = of_get_child_count(np); + int ret; + + if (nchips > 8) + return -EINVAL; + + for_each_child_of_node(np, nand_np) { + ret = sunxi_nand_chip_init(dev, nfc, nand_np); + if (ret) + return ret; + } + + return 0; +} + +static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) +{ + struct sunxi_nand_chip *chip; + + while (!list_empty(&nfc->chips)) { + chip = list_first_entry(&nfc->chips, struct sunxi_nand_chip, + node); + nand_release(&chip->mtd); + sunxi_nand_ecc_cleanup(&chip->nand.ecc); + } +} + +static int sunxi_nfc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *r; + struct sunxi_nfc *nfc; + int irq; + int ret; + + nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); + if (!nfc) + return -ENOMEM; + + spin_lock_init(&nfc->controller.lock); + init_waitqueue_head(&nfc->controller.wq); + INIT_LIST_HEAD(&nfc->chips); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + nfc->regs = devm_ioremap_resource(dev, r); + if (IS_ERR(nfc->regs)) + return PTR_ERR(nfc->regs); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to retrieve irq\n"); + return irq; + } + + nfc->ahb_clk = devm_clk_get(dev, "ahb"); + if (IS_ERR(nfc->ahb_clk)) { + dev_err(dev, "failed to retrieve ahb clk\n"); + return PTR_ERR(nfc->ahb_clk); + } + + ret = clk_prepare_enable(nfc->ahb_clk); + if (ret) + return ret; + + nfc->mod_clk = devm_clk_get(dev, "mod"); + if (IS_ERR(nfc->mod_clk)) { + dev_err(dev, "failed to retrieve mod clk\n"); + ret = PTR_ERR(nfc->mod_clk); + goto out_ahb_clk_unprepare; + } + + ret = clk_prepare_enable(nfc->mod_clk); + if (ret) + goto out_ahb_clk_unprepare; + + sunxi_nfc_rst(nfc); + + writel(0, nfc->regs + NFC_REG_INT); + ret = devm_request_irq(dev, irq, sunxi_nfc_interrupt, + 0, "sunxi-nand", nfc); + if (ret) + goto out_mod_clk_unprepare; + + platform_set_drvdata(pdev, nfc); + + /* + * TODO: replace these magic values with proper flags as soon as we + * know what they are encoding. + */ + writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); + writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG); + + ret = sunxi_nand_chips_init(dev, nfc); + if (ret) { + dev_err(dev, "failed to init nand chips\n"); + goto out_mod_clk_unprepare; + } + + return 0; + +out_mod_clk_unprepare: + clk_disable_unprepare(nfc->mod_clk); +out_ahb_clk_unprepare: + clk_disable_unprepare(nfc->ahb_clk); + + return ret; +} + +static int sunxi_nfc_remove(struct platform_device *pdev) +{ + struct sunxi_nfc *nfc = platform_get_drvdata(pdev); + + sunxi_nand_chips_cleanup(nfc); + + return 0; +} + +static const struct of_device_id sunxi_nfc_ids[] = { + { .compatible = "allwinner,sun4i-a10-nand" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sunxi_nfc_ids); + +static struct platform_driver sunxi_nfc_driver = { + .driver = { + .name = "sunxi_nand", + .owner = THIS_MODULE, + .of_match_table = sunxi_nfc_ids, + }, + .probe = sunxi_nfc_probe, + .remove = sunxi_nfc_remove, +}; +module_platform_driver(sunxi_nfc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Boris BREZILLON"); +MODULE_DESCRIPTION("Allwinner NAND Flash Controller driver"); +MODULE_ALIAS("platform:sunxi_nand"); -- 1.9.1 From rogerq at ti.com Mon Sep 22 08:13:58 2014 From: rogerq at ti.com (Roger Quadros) Date: Mon, 22 Sep 2014 18:13:58 +0300 Subject: [PATCH v4 0/5] nand: OMAP collected fixes In-Reply-To: <54201B3B.50007@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <541FDC2F.4020103@ti.com> <54201B3B.50007@vanguardiasur.com.ar> Message-ID: <54203CB6.8080702@ti.com> On 09/22/2014 03:51 PM, Ezequiel Garcia wrote: > > > On 09/22/2014 09:22 AM, Roger Quadros wrote: >> Hi Ezequiel, >> >> On 09/20/2014 07:53 PM, Ezequiel Garcia wrote: >>> I've collected all the changes recently discussed in a whole patchset. >>> If you are just reading this for the first time please take a look at: >>> >>> [1] http://www.spinics.net/lists/linux-omap/msg110965.html >>> [2] http://www.spinics.net/lists/linux-omap/msg110958.html >>> >>> As requested by Roger, the omap_elm is a 'bool' driver now. The plan >>> is to merge it inside omap2_nand, but my queue is really filled, so >>> if anyone feels like doing, please be my guest. >>> >>> Although I'm hoping this to be the last round, feedback and testing >>> is welcome. >> >> Patches 3 and 4 still have checkpatch issues. >> > > I think you didn't look at them in detail. Unless I'm missing something, > it's just warning about MAINTAINERS update: > > WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? > #16: > drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 > > WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? > #13: > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 > > This driver is not in MAINTAINERS. If you want to start maintaining it, > it'd be good to add you to MAINTAINERS so people Cc you properly on patches. > Sorry for the noise. I was re-generating the patch without the rename detection flag causing errors which are present in the original file itself. cheers, -roger From yba at tkos.co.il Mon Sep 22 08:47:16 2014 From: yba at tkos.co.il (Jonathan Ben Avraham) Date: Mon, 22 Sep 2014 18:47:16 +0300 (IDT) Subject: Question: Why not build libmtd as shared object? Message-ID: Dear colleagues, In order to do MTD operations in-process rather than forking a shell to run an mdt-utils command line utility, I am using my own functions written on top of libmtd. Is there any reason then not to build and install libmtd as a shared object? Is there a specific reason that the command line utils are statically linked? Best regards, - yba -- 9590 8E58 D30D 1660 C349 673D B205 4FC4 B8F5 B7F9 ~. .~ Tk Open Systems =}-------- Jonathan Ben-Avraham ("yba") ----------ooO--U--Ooo------------{= mailto:yba at tkos.co.il tel:+972.52.486.3386 http://tkos.co.il skype:benavrhm From computersforpeace at gmail.com Mon Sep 22 10:58:34 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 10:58:34 -0700 Subject: [PATCH v2 1/2] mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs In-Reply-To: <1411395911-30365-2-git-send-email-boris.brezillon@free-electrons.com> References: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> <1411395911-30365-2-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140922175834.GM1193@ld-irv-0074> On Mon, Sep 22, 2014 at 04:25:10PM +0200, Boris BREZILLON wrote: > Add an onfi_timing_mode_default field to nand_chip and nand_flash_dev in > order to support NAND timings definition for non-ONFI NAND. > > NAND that support better timings mode than the default one have to define > a new entry in the nand_ids table. > > The default timing mode should be deduced from timings description from > the datasheet and the ONFI specification > (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 > "Timing Parameters"). > You should choose the closest mode that fit the timings requirements of > your NAND chip. > > Signed-off-by: Boris BREZILLON You have some (new?) checkpatch warnings: WARNING: please, no space before tabs #49: FILE: include/linux/mtd/nand.h:591: + * ^I^I^I either deduced from the datasheet if the NAND$ WARNING: please, no space before tabs #50: FILE: include/linux/mtd/nand.h:592: + * ^I^I^I chip is not ONFI compliant or set to 0 if it is$ WARNING: please, no space before tabs #51: FILE: include/linux/mtd/nand.h:593: + * ^I^I^I (an ONFI chip is always configured in mode 0$ WARNING: please, no space before tabs #52: FILE: include/linux/mtd/nand.h:594: + * ^I^I^I after a NAND reset)$ total: 0 errors, 4 warnings, 43 lines checked Your patch has style problems, please review. If any of these errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS. Brian > --- > drivers/mtd/nand/nand_base.c | 2 ++ > include/linux/mtd/nand.h | 11 +++++++++++ > 2 files changed, 13 insertions(+) > > diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c > index ae6e7c4..c37fa2a 100644 > --- a/drivers/mtd/nand/nand_base.c > +++ b/drivers/mtd/nand/nand_base.c > @@ -3594,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, > chip->options |= type->options; > chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); > chip->ecc_step_ds = NAND_ECC_STEP(type); > + chip->onfi_timing_mode_default = > + type->onfi_timing_mode_default; > > *busw = type->options & NAND_BUSWIDTH_16; > > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h > index b7c1199..e795fbf 100644 > --- a/include/linux/mtd/nand.h > +++ b/include/linux/mtd/nand.h > @@ -587,6 +587,11 @@ struct nand_buffers { > * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, > * also from the datasheet. It is the recommended ECC step > * size, if known; if unknown, set to zero. > + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is > + * either deduced from the datasheet if the NAND > + * chip is not ONFI compliant or set to 0 if it is > + * (an ONFI chip is always configured in mode 0 > + * after a NAND reset) > * @numchips: [INTERN] number of physical chips > * @chipsize: [INTERN] the size of one chip for multichip arrays > * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 > @@ -671,6 +676,7 @@ struct nand_chip { > uint8_t bits_per_cell; > uint16_t ecc_strength_ds; > uint16_t ecc_step_ds; > + int onfi_timing_mode_default; > int badblockpos; > int badblockbits; > > @@ -773,6 +779,10 @@ struct nand_chip { > * @ecc_step_ds in nand_chip{}, also from the datasheet. > * For example, the "4bit ECC for each 512Byte" can be set with > * NAND_ECC_INFO(4, 512). > + * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND > + * reset. Should be deduced from timings described > + * in the datasheet. > + * > */ > struct nand_flash_dev { > char *name; > @@ -793,6 +803,7 @@ struct nand_flash_dev { > uint16_t strength_ds; > uint16_t step_ds; > } ecc; > + int onfi_timing_mode_default; > }; > > /** > -- > 1.9.1 > From boris.brezillon at free-electrons.com Mon Sep 22 11:11:49 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 20:11:49 +0200 Subject: [PATCH v3 0/2] mtd: nand: support ONFI timings mode retrieval for non-ONFI NANDs Message-ID: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> Hi, Following the series adding ONFI timing mode support, here is a series adding support for timing mode retrieval on non-ONFI NANDs. It just adds a new field to the nand_chip and nand_flash_dev struct so that anyone can define its chip requirements in the nand_ids table. The 2nd patch serves as an example and adds an entry for the Hynix H27UCG8T2ATR-BC NAND chip used on the Cubietruck board. Best Regards, Boris Changes since v2: - fix checkpatch warnings Changes since v1: - fix H27UCG8T2ATR-BC definition - rename onfi_timing_mode_ds field into onfi_timing_mode_default Boris BREZILLON (2): mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table drivers/mtd/nand/nand_base.c | 2 ++ drivers/mtd/nand/nand_ids.c | 4 ++++ include/linux/mtd/nand.h | 11 +++++++++++ 3 files changed, 17 insertions(+) -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 11:11:51 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 20:11:51 +0200 Subject: [PATCH v3 2/2] mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table In-Reply-To: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411409511-4381-3-git-send-email-boris.brezillon@free-electrons.com> Add the full description of the Hynix H27UCG8T2ATR-BC NAND chip in the nand_ids table so that we can later use the NAND ECC infos and ONFI timings mode in controller drivers. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/nand_ids.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 3d7c89f..fbde8910 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = { {"SDTNRGAMA 64G 3.3V 8-bit", { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, + {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, + SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K), + 4 }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), -- 1.9.1 From boris.brezillon at free-electrons.com Mon Sep 22 11:11:50 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 20:11:50 +0200 Subject: [PATCH v3 1/2] mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs In-Reply-To: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411409511-4381-2-git-send-email-boris.brezillon@free-electrons.com> Add an onfi_timing_mode_default field to nand_chip and nand_flash_dev in order to support NAND timings definition for non-ONFI NAND. NAND that support better timings mode than the default one have to define a new entry in the nand_ids table. The default timing mode should be deduced from timings description from the datasheet and the ONFI specification (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 "Timing Parameters"). You should choose the closest mode that fit the timings requirements of your NAND chip. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/nand_base.c | 2 ++ include/linux/mtd/nand.h | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ae6e7c4..c37fa2a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3594,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, chip->options |= type->options; chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->onfi_timing_mode_default = + type->onfi_timing_mode_default; *busw = type->options & NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index b7c1199..b0b74cc 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -587,6 +587,11 @@ struct nand_buffers { * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, * also from the datasheet. It is the recommended ECC step * size, if known; if unknown, set to zero. + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is + * either deduced from the datasheet if the NAND + * chip is not ONFI compliant or set to 0 if it is + * (an ONFI chip is always configured in mode 0 + * after a NAND reset) * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 @@ -671,6 +676,7 @@ struct nand_chip { uint8_t bits_per_cell; uint16_t ecc_strength_ds; uint16_t ecc_step_ds; + int onfi_timing_mode_default; int badblockpos; int badblockbits; @@ -773,6 +779,10 @@ struct nand_chip { * @ecc_step_ds in nand_chip{}, also from the datasheet. * For example, the "4bit ECC for each 512Byte" can be set with * NAND_ECC_INFO(4, 512). + * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND + * reset. Should be deduced from timings described + * in the datasheet. + * */ struct nand_flash_dev { char *name; @@ -793,6 +803,7 @@ struct nand_flash_dev { uint16_t strength_ds; uint16_t step_ds; } ecc; + int onfi_timing_mode_default; }; /** -- 1.9.1 From computersforpeace at gmail.com Mon Sep 22 11:12:50 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:12:50 -0700 Subject: [PATCH 1/1] jffs2: fix sparse warning: unexpected unlock In-Reply-To: <1411065976-20386-1-git-send-email-fabf@skynet.be> References: <1411065976-20386-1-git-send-email-fabf@skynet.be> Message-ID: <20140922181250.GN1193@ld-irv-0074> + linux-sparse On Thu, Sep 18, 2014 at 08:46:16PM +0200, Fabian Frederick wrote: > fs/jffs2/summary.c:846:5: warning: context imbalance in 'jffs2_sum_write_sumnode' - unexpected unlock > > Signed-off-by: Fabian Frederick > --- > fs/jffs2/summary.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c > index c522d09..a0bac7b 100644 > --- a/fs/jffs2/summary.c > +++ b/fs/jffs2/summary.c > @@ -844,6 +844,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock > /* Write out summary information - called from jffs2_do_reserve_space */ > > int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) > + __releases(&c->erase_completion_lock) > + __acquires(&c->erase_completion_lock) I'm not too familiar with sparse notations, but Documentation/sparse.txt suggests the above is wrong, and the following is more accurate: __must_hold(&c->erase_completion_lock) But it looks like there are several other examples which do this. Anyway, here's the relevant doc text, in case someone wants to clarify it for me, or else tell me the documentation is wrong: __must_hold - The specified lock is held on function entry and exit. __acquires - The specified lock is held on function exit, but not entry. __releases - The specified lock is held on function entry, but not exit. So __acquires and __releases look mutually exclusive, but it's not clear if __must_hold will actually cover what we want. (I haven't tested it.) > { > int datasize, infosize, padsize; > struct jffs2_eraseblock *jeb; Brian From boris.brezillon at free-electrons.com Mon Sep 22 11:13:15 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Mon, 22 Sep 2014 20:13:15 +0200 Subject: [PATCH v2 1/2] mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs In-Reply-To: <20140922175834.GM1193@ld-irv-0074> References: <1411395911-30365-1-git-send-email-boris.brezillon@free-electrons.com> <1411395911-30365-2-git-send-email-boris.brezillon@free-electrons.com> <20140922175834.GM1193@ld-irv-0074> Message-ID: <20140922201315.022fefea@bbrezillon> On Mon, 22 Sep 2014 10:58:34 -0700 Brian Norris wrote: > On Mon, Sep 22, 2014 at 04:25:10PM +0200, Boris BREZILLON wrote: > > Add an onfi_timing_mode_default field to nand_chip and nand_flash_dev in > > order to support NAND timings definition for non-ONFI NAND. > > > > NAND that support better timings mode than the default one have to define > > a new entry in the nand_ids table. > > > > The default timing mode should be deduced from timings description from > > the datasheet and the ONFI specification > > (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 > > "Timing Parameters"). > > You should choose the closest mode that fit the timings requirements of > > your NAND chip. > > > > Signed-off-by: Boris BREZILLON > > You have some (new?) checkpatch warnings: > Sorry for that. I just sent a new version fixing those warnings. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From computersforpeace at gmail.com Mon Sep 22 11:19:26 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:19:26 -0700 Subject: [PATCH 1/2] mtd: physmap_of: Fix ROM support via OF In-Reply-To: <1456841230.234377.1410977298299.JavaMail.zimbra@xes-inc.com> References: <1388169775.233775.1410977001530.JavaMail.zimbra@xes-inc.com> <1456841230.234377.1410977298299.JavaMail.zimbra@xes-inc.com> Message-ID: <20140922181926.GO1193@ld-irv-0074> On Wed, Sep 17, 2014 at 01:08:18PM -0500, Aaron Sierra wrote: > The "ROM" and unknown probe types within the obsolete "direct-mapped" > probe function used the nonexistent "mtd_rom" probe instead of the > intended "map_rom". > > Signed-off-by: Aaron Sierra Pushed both to l2-mtd.git. Thanks! Brian From computersforpeace at gmail.com Mon Sep 22 11:28:37 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:28:37 -0700 Subject: [PATCH] mtd: bcm47xxpart: only register partitions if the trx header was filled In-Reply-To: <1411338793-21245-1-git-send-email-hauke@hauke-m.de> References: <1411338793-21245-1-git-send-email-hauke@hauke-m.de> Message-ID: <20140922182837.GP1193@ld-irv-0074> On Mon, Sep 22, 2014 at 12:33:13AM +0200, Hauke Mehrtens wrote: > Sometimes the trx offsets are 0, in that case there is no partition and > we should not try to add one. > > Signed-off-by: Hauke Mehrtens > --- > drivers/mtd/bcm47xxpart.c | 16 ++++++++++------ > 1 file changed, 10 insertions(+), 6 deletions(-) > > diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c > index 8057f52..c3f4454 100644 > --- a/drivers/mtd/bcm47xxpart.c > +++ b/drivers/mtd/bcm47xxpart.c > @@ -168,18 +168,22 @@ static int bcm47xxpart_parse(struct mtd_info *master, > i++; > } > > - bcm47xxpart_add_part(&parts[curr_part++], "linux", > - offset + trx->offset[i], 0); > - i++; > + if (trx->offset[i]) { > + bcm47xxpart_add_part(&parts[curr_part++], "linux", > + offset + trx->offset[i], 0); Hmm, this indentation is getting large, and it fails checkpatch now. But I'm not sure the alternatives are much better right now. > + i++; > + } > > /* > * Pure rootfs size is known and can be calculated as: > * trx->length - trx->offset[i]. We don't fill it as > * we want to have jffs2 (overlay) in the same mtd. > */ > - bcm47xxpart_add_part(&parts[curr_part++], "rootfs", > - offset + trx->offset[i], 0); > - i++; > + if (trx->offset[i]) { > + bcm47xxpart_add_part(&parts[curr_part++], "rootfs", > + offset + trx->offset[i], 0); Same here. > + i++; > + } > > last_trx_part = curr_part - 1; > I'll take this soon if there are no other complaints. Brian From computersforpeace at gmail.com Mon Sep 22 11:35:36 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:35:36 -0700 Subject: [PATCH v3 1/2] mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs In-Reply-To: <1411409511-4381-2-git-send-email-boris.brezillon@free-electrons.com> References: <1411409511-4381-1-git-send-email-boris.brezillon@free-electrons.com> <1411409511-4381-2-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140922183536.GQ1193@ld-irv-0074> > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h > index b7c1199..b0b74cc 100644 > --- a/include/linux/mtd/nand.h > +++ b/include/linux/mtd/nand.h > @@ -587,6 +587,11 @@ struct nand_buffers { > * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, > * also from the datasheet. It is the recommended ECC step > * size, if known; if unknown, set to zero. > + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is > + * either deduced from the datasheet if the NAND > + * chip is not ONFI compliant or set to 0 if it is > + * (an ONFI chip is always configured in mode 0 > + * after a NAND reset) This is probably OK only if every NAND chip is at least as fast as ONFI mode 0. For older / legacy flash, I'm not sure if that's 100% true. Maybe we'll need an UNKNOWN value, for those whose timing information is not known? Anyway, I think this is OK for now. Pushed the series to l2-mtd.git. Thanks! > * @numchips: [INTERN] number of physical chips > * @chipsize: [INTERN] the size of one chip for multichip arrays > * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 Brian From computersforpeace at gmail.com Mon Sep 22 11:42:28 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:42:28 -0700 Subject: [PATCH v4 0/5] nand: OMAP collected fixes In-Reply-To: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <20140922184228.GR1193@ld-irv-0074> On Sat, Sep 20, 2014 at 05:53:11PM +0100, Ezequiel Garcia wrote: > I've collected all the changes recently discussed in a whole patchset. > If you are just reading this for the first time please take a look at: > > [1] http://www.spinics.net/lists/linux-omap/msg110965.html > [2] http://www.spinics.net/lists/linux-omap/msg110958.html > > As requested by Roger, the omap_elm is a 'bool' driver now. The plan > is to merge it inside omap2_nand, but my queue is really filled, so > if anyone feels like doing, please be my guest. > > Although I'm hoping this to be the last round, feedback and testing > is welcome. > > Brian: I wonder if it's too late for v3.18? > > Thanks! > > Ezequiel Garcia (5): > nand: omap2: Remove horrible ifdefs to fix module probe > nand: omap2: Replace pr_err with dev_err > mtd: nand: Move ELM driver and rename as omap_elm Pushed the first 3 to l2-mtd.git. Thanks! > mtd: nand: Rename OMAP NAND driver One comment on this one, which I'll poast on its patch. > mtd: nand: Constrain omap_elm to built-in > > drivers/mtd/devices/Makefile | 1 - > drivers/mtd/nand/Kconfig | 2 +- > drivers/mtd/nand/Makefile | 3 +- > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 160 ++++++++++++++----------- > drivers/mtd/{devices/elm.c => nand/omap_elm.c} | 0 > include/linux/platform_data/elm.h | 16 +++ > 6 files changed, 107 insertions(+), 75 deletions(-) > rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (95%) > rename drivers/mtd/{devices/elm.c => nand/omap_elm.c} (100%) > Brian From computersforpeace at gmail.com Mon Sep 22 11:49:09 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:49:09 -0700 Subject: [PATCH v4 4/5] mtd: nand: Rename OMAP NAND driver In-Reply-To: <1411231996-6387-5-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1411231996-6387-5-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <20140922184909.GS1193@ld-irv-0074> On Sat, Sep 20, 2014 at 05:53:15PM +0100, Ezequiel Garcia wrote: > Rename it to a less generic name, so the module is built with a meaningful > name instead of the previous 'omap2.ko'. You mention renaming only so that you can change the module name, but you also (partly at my prompting) argued for future merging of omap_nand and omap_elm into a single module. So it seems like you might have to do several renamings, in that case, right? omap2.c => omap_nand.c (this patch) omap_nand.c => .c (later) ...so you can link somethingelse.o and omap_elm.o into omap_nand.{o,ko} If I'm right here, then maybe (rather than multiple renames), you just want this patch for now? (untested) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b3237b742eb5..1a4d5e9db75b 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o @@ -52,3 +52,4 @@ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ nand-objs := nand_base.o nand_bbt.o nand_timings.o +omap_nand-objs := omap2.o > Acked-by: Roger Quadros > Signed-off-by: Ezequiel Garcia > --- > drivers/mtd/nand/Makefile | 2 +- > drivers/mtd/nand/{omap2.c => omap2_nand.c} | 0 > 2 files changed, 1 insertion(+), 1 deletion(-) > rename drivers/mtd/nand/{omap2.c => omap2_nand.c} (100%) [snip] Brian From computersforpeace at gmail.com Mon Sep 22 11:58:49 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 11:58:49 -0700 Subject: [PATCH v4 5/5] mtd: nand: Constrain omap_elm to built-in In-Reply-To: <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> Message-ID: <20140922185849.GT1193@ld-irv-0074> On Sat, Sep 20, 2014 at 05:53:16PM +0100, Ezequiel Garcia wrote: > This fixes the following build error when omap2_nand is chosen built-in, > and omap_elm is chosen as a module: > > drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' > drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' > > Fix this by making omap_elm a 'bool' driver. Hmm, so we're sacrificing a "feature" (that omap2 + omap_elm can both be built as modules) because we haven't solved one particular developer UI inconsistency (that we don't prevent the config combination of MTD_NAND_OMAP2=y and MTD_NAND_OMAP_BCH=m)? I wouldn't tend to sacrifice the feature for the sake of a bad config. Do you have any guesstimate as to whether the linker failure affects many people? Are people just hitting this with randconfig? Do you know if anyone ships loadable modules for this driver? e.g., any embedded distros? I could go either way on this, but I just wasn't sure if these sorts of questions had been asked/answered. > Signed-off-by: Ezequiel Garcia > --- > drivers/mtd/nand/Kconfig | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig > index f1cf503..549c0cb 100644 > --- a/drivers/mtd/nand/Kconfig > +++ b/drivers/mtd/nand/Kconfig > @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 > > config MTD_NAND_OMAP_BCH > depends on MTD_NAND_OMAP2 > - tristate "Support hardware based BCH error correction" > + bool "Support hardware based BCH error correction" > default n > select BCH > help Brian From computersforpeace at gmail.com Mon Sep 22 12:04:07 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 22 Sep 2014 12:04:07 -0700 Subject: [PATCH 3/3] mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module In-Reply-To: <20140912165636.GA7276@arch> References: <1410443224-18477-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1410443224-18477-4-git-send-email-ezequiel@vanguardiasur.com.ar> <5412B66F.8050505@ti.com> <20140912165636.GA7276@arch> Message-ID: <20140922190407.GU1193@ld-irv-0074> On Fri, Sep 12, 2014 at 05:56:36PM +0100, Ezequiel Garcia wrote: > Ultimately, I don't care much as I don't think anyone will build it as a module, > except maybe for testing the driver under probe/remove cycles. I see that you sort of answered one of my questions here. On what do you base this claim? I see maintstream distros are gaining support for some common ARM platforms, and I bet they ship loadable modules. Or are you seeing otherwise? Brian From ezequiel at vanguardiasur.com.ar Mon Sep 22 12:15:00 2014 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 22 Sep 2014 16:15:00 -0300 Subject: [PATCH v4 5/5] mtd: nand: Constrain omap_elm to built-in In-Reply-To: <20140922185849.GT1193@ld-irv-0074> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> <20140922185849.GT1193@ld-irv-0074> Message-ID: <54207534.9040104@vanguardiasur.com.ar> On 09/22/2014 03:58 PM, Brian Norris wrote: > On Sat, Sep 20, 2014 at 05:53:16PM +0100, Ezequiel Garcia wrote: >> This fixes the following build error when omap2_nand is chosen built-in, >> and omap_elm is chosen as a module: >> >> drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >> >> Fix this by making omap_elm a 'bool' driver. > > Hmm, so we're sacrificing a "feature" (that omap2 + omap_elm can both be > built as modules) because we haven't solved one particular developer UI > inconsistency (that we don't prevent the config combination of > MTD_NAND_OMAP2=y and MTD_NAND_OMAP_BCH=m)? I wouldn't tend to sacrifice > the feature for the sake of a bad config. > FWIW, I agree with you, as already said to Roger. -- Ezequiel Garcia, VanguardiaSur www.vanguardiasur.com.ar -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From RHurdle at Rugged.com Mon Sep 22 18:32:06 2014 From: RHurdle at Rugged.com (Robert Hurdle) Date: Mon, 22 Sep 2014 18:32:06 -0700 Subject: MTD Commands Message-ID: <5498E86A4A68B14A8A06D0380640D04A01FA685FE455@atca01em01.adsi.aitech.ent> Hello, I am trying to port a NAND flash driver for a board that has an FPGA between the software and the NAND flash. I have made some progress, but now I am stuck because I don't know how the command NAND_CMD_RNDOUT should be implemented. So far I have not found any detailed documentation on any of the commands (NAND_CMD_ERASE1, NAND_CMD_ERASE2, etc.) processed by cmdfunc() in the hardware specific driver files. The driver file I chose to copy did not support NAND_CMD_RNDOUT, but even examining other driver files in the drivers/mtd/nand directory, it looks sort of cryptic. What does MTD expect the command NAND_CMD_RNDOUT to accomplish? Is there a reference on-line that describes the what these various NAND commands are expected to accomplish, how data is provided to MTD, inputs and outputs, etc. ? Thanks for any advice. Robert Hurdle From lisovy at gmail.com Tue Sep 23 01:16:42 2014 From: lisovy at gmail.com (Rostislav Lisovy) Date: Tue, 23 Sep 2014 10:16:42 +0200 Subject: [PATCH RESEND] mtd: spi-nor: Add support for Fujitsu MB85RS1MT FRAM Message-ID: <1411460202-457-1-git-send-email-lisovy@merica.cz> Tested with this particular FRAM chip Signed-off-by: Rostislav Lisovy Acked-by: Marek Vasut --- drivers/mtd/spi-nor/spi-nor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..a914be9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -505,6 +505,9 @@ const struct spi_device_id spi_nor_ids[] = { { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + /* Fujitsu */ + { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, + /* GigaDevice */ { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, -- 1.9.1 From rogerq at ti.com Tue Sep 23 01:51:25 2014 From: rogerq at ti.com (Roger Quadros) Date: Tue, 23 Sep 2014 11:51:25 +0300 Subject: [PATCH v4 5/5] mtd: nand: Constrain omap_elm to built-in In-Reply-To: <20140922185849.GT1193@ld-irv-0074> References: <1411231996-6387-1-git-send-email-ezequiel@vanguardiasur.com.ar> <1411231996-6387-6-git-send-email-ezequiel@vanguardiasur.com.ar> <20140922185849.GT1193@ld-irv-0074> Message-ID: <5421348D.90606@ti.com> On 09/22/2014 09:58 PM, Brian Norris wrote: > On Sat, Sep 20, 2014 at 05:53:16PM +0100, Ezequiel Garcia wrote: >> This fixes the following build error when omap2_nand is chosen built-in, >> and omap_elm is chosen as a module: >> >> drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' >> drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' >> >> Fix this by making omap_elm a 'bool' driver. > > Hmm, so we're sacrificing a "feature" (that omap2 + omap_elm can both be > built as modules) because we haven't solved one particular developer UI > inconsistency (that we don't prevent the config combination of > MTD_NAND_OMAP2=y and MTD_NAND_OMAP_BCH=m)? I wouldn't tend to sacrifice > the feature for the sake of a bad config. > > Do you have any guesstimate as to whether the linker failure affects > many people? Are people just hitting this with randconfig? I think this issue was hit only during a manual menuconfig setting. > > Do you know if anyone ships loadable modules for this driver? e.g., any > embedded distros? Not sure about other distros but TI releases always set both OMAP_NAND and OMAP_BCH as built-in. cheers, -roger > > I could go either way on this, but I just wasn't sure if these sorts of > questions had been asked/answered. > >> Signed-off-by: Ezequiel Garcia >> --- >> drivers/mtd/nand/Kconfig | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig >> index f1cf503..549c0cb 100644 >> --- a/drivers/mtd/nand/Kconfig >> +++ b/drivers/mtd/nand/Kconfig >> @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 >> >> config MTD_NAND_OMAP_BCH >> depends on MTD_NAND_OMAP2 >> - tristate "Support hardware based BCH error correction" >> + bool "Support hardware based BCH error correction" >> default n >> select BCH >> help > > Brian > From zajec5 at gmail.com Tue Sep 23 05:27:59 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Tue, 23 Sep 2014 14:27:59 +0200 Subject: [PATCH] mtd: bcm47xxpart: only register partitions if the trx header was filled In-Reply-To: <1411338793-21245-1-git-send-email-hauke@hauke-m.de> References: <1411338793-21245-1-git-send-email-hauke@hauke-m.de> Message-ID: On 22 September 2014 00:33, Hauke Mehrtens wrote: > diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c > index 8057f52..c3f4454 100644 > --- a/drivers/mtd/bcm47xxpart.c > +++ b/drivers/mtd/bcm47xxpart.c > @@ -168,18 +168,22 @@ static int bcm47xxpart_parse(struct mtd_info *master, > i++; > } > > - bcm47xxpart_add_part(&parts[curr_part++], "linux", > - offset + trx->offset[i], 0); > - i++; > + if (trx->offset[i]) { > + bcm47xxpart_add_part(&parts[curr_part++], "linux", > + offset + trx->offset[i], 0); You may at least move "linux" to the next line to don't exceed 80 chars limit. Same for "rootfs" below. -- Rafa? From lisovy at gmail.com Tue Sep 23 06:19:12 2014 From: lisovy at gmail.com (Rostislav Lisovy) Date: Tue, 23 Sep 2014 15:19:12 +0200 Subject: [RFC] nondestructive nandtest Message-ID: <1411478352.2030.11.camel@lp-lvrv.comap.cz> This is a simple nondestructive nandtest utility. The testing logic is similar to the original nandtest however the OOB data is properly restored and the erased pages are kept as erased (for more detailed information see the source file header). The test tries to be nondestructive as much as possible however if it will be interrupted (by the user or power loss) during testing, it is very likely that the data on the NAND flash will be corrupted (this is not a bug but a feature of the r/w testing). To use it just run the program and use the full MTD device path as its only parameter (i.e. nandtest /dev/mtd7). It can test only the whole mtd device for now, it still lacks all the "offset/length" parameters that the original nandtest has (and printing information about the operation performed). Libmtd is needed to compile. Very simple benchmark ("real runtime" measured by "time" command): | original nandtest | new nandtest | /-------------------+-------------------+--------------| | 8MiB mtd device | 0m 6.00s | 0m 9.29s | | 256MiB mtd device | 3m 18.88s | 5m 9.82s | Your feedback is highly appreciated. Best regards; Rostislav -- /* * Nondestructive NAND flash testing utility for Linux MTD subsystem * * Copyright (c) ComAp a.s. 2014, http://www.comap.cz/ * Author: Rostislav Lisovy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * The test consists of the following phases (performed on each EB): * * Store the original content of the EB (including OOB) * * Multiple times (defined in PER_EB_RUNS) * - Generate random test_pattern (of size eb_size) * - Erase EB * - Write test_pattern * - Read content of the EB * - Compare read data with the test_pattern * * Restore the previously stored data * * Reasons for the test to fail: * * New bad block was discovered * * Single non-correctable bit-flip occurred * * More than 'CORRECTABLE_BIT_FLIPS_THRESHOLD' correctable * bit-flips occurred * * Any of the syscalls (ioctl/open/...) failed * * Side note: * When storing EB, all the data can be read at once * (copied into the buffer of the size eb_size), however * when reading OOB, we have to read it for each page in * the EB separately (copying to the buffer of size * pages_cnt * oob_size). * * When restoring data (writing from buffers back to flash), * we have to check carefully for each page if it was originally * erased or not. The check is simply performed by matching the * data stored in buffers (data + oob) with the 0xffffffff pattern. * (One may thing that 0xff data may be valid "stored value", that's * true, however 0xff data do not have 0xff ECC in OOB). * If the page was not empty (erased), write the data, otherwise * do not touch the page, skip it and continue with the next one. * This is done due to the NAND flash HW limitation of single * write operation allowed per page (or sub-page) after the erase * command (i.e. even storing of the 0xffffffff pattern is legal * write operation which depletes this "single write" requirement). * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libmtd.h" libmtd_t mtd_desc; struct mtd_dev_info meminfo; int fd; void *eb; /* Store EB content */ void *oob; /* Store OOB of each page */ void *test_pattern; /* Randomly generated pattern to write to en EB */ void *tmp_buff; /* * How many correctable bit-flips may occur * until the test will fail */ #define CORRECTABLE_BIT_FLIPS_THRESHOLD 100 /* * Pattern that matches if the page is erased * (page + OOB should match at the same time) */ #define NAND_FLASH_ERASED_U32 0xffffffff /* * Number of pages in an EB * FIXME is this fragile or will it always work? */ #define PAGE_CNT (meminfo.eb_size / meminfo.min_io_size) /* * How many times should be a single EB tested * with a r/w access */ #define PER_EB_RUNS 1 static int store_eb_content(int eb_nr) { int ret; int page_nr; ret = mtd_read(&meminfo, fd, eb_nr, 0, eb, meminfo.eb_size); if (ret == -1) return ret; /* For each page */ for (page_nr = 0; page_nr < PAGE_CNT; page_nr++) { ret = mtd_read_oob(mtd_desc, &meminfo, fd, (eb_nr * meminfo.eb_size) + (page_nr * meminfo.min_io_size), meminfo.oob_size, oob + (page_nr * meminfo.oob_size)); if (ret == -1) return ret; } return 0; } static int restore_eb_content(int eb_nr) { int ret; int i; bool page_is_erased; int page_nr; /* FIXME Assume that data length is 4B (32-bit) multiple */ assert(!(meminfo.eb_size & 0x2)); ret = mtd_erase(mtd_desc, &meminfo, fd, eb_nr); if (ret == -1) return ret; /* For each page in the EB */ for (page_nr = 0; page_nr < PAGE_CNT; page_nr++) { /* Make the life easier with the pointers to the exact page */ void *pg_data = eb + (page_nr * meminfo.min_io_size); void *pg_oob = oob + (page_nr * meminfo.oob_size); page_is_erased = true; /* For each 4B in OOB */ for (i = 0; i < meminfo.oob_size; i += sizeof(uint32_t)) { if (*((uint32_t *)(pg_oob + i)) != NAND_FLASH_ERASED_U32) { page_is_erased = false; break; } } /* For each 4B in page */ for (i = 0; i < meminfo.min_io_size; i += sizeof(uint32_t)) { if (*((uint32_t *)(pg_data + i)) != NAND_FLASH_ERASED_U32) { page_is_erased = false; break; } } /* * If the page does contain some data (!page_is_erased) * do write them, otherwise do not touch it) */ if (!page_is_erased) { /* * Can only write to a single page at a time * if writing to OOB. */ ret = mtd_write(mtd_desc, &meminfo, fd, eb_nr, page_nr * meminfo.min_io_size, pg_data, meminfo.min_io_size, pg_oob, meminfo.oob_size, MTD_OPS_RAW); if (ret == -1) return ret; } } return 0; } static int eb_rw_testing(int eb_nr) { int ret; int i; ret = mtd_erase(mtd_desc, &meminfo, fd, eb_nr); if (ret == -1) return ret; ret = mtd_write(mtd_desc, &meminfo, fd, eb_nr, 0, test_pattern, meminfo.eb_size, NULL, 0, MTD_OPS_AUTO_OOB); if (ret == -1) return ret; ret = mtd_read(&meminfo, fd, eb_nr, 0, tmp_buff, meminfo.eb_size); if (ret == -1) return ret; /* Compare the test_pattern with the data read from the EB */ for (i = 0; i < meminfo.eb_size; i += sizeof(uint32_t)) { if (*((uint32_t*)(tmp_buff + i)) != *((uint32_t*)(test_pattern + i))) { /* * FIXME what should be done if we newly discover a bad block? * Should we run mtd_torture? Or mark this EB as bad? * In such case a flashed FS will not be usable anymore */ fprintf(stderr, "New badblock discovered. This is bad. " "Stopping the test.\n"); return -1; } } return 0; } static int run_test(void) { int ret = -1; int eb_nr; int i, j; eb = malloc(meminfo.eb_size); if (!eb) return -1; oob = malloc(meminfo.oob_size * PAGE_CNT); if (!oob) goto leave_free_eb; /* Prepare test pattern */ srand(time(NULL)); test_pattern = malloc(meminfo.eb_size); if (!test_pattern) goto leave_free_oob; tmp_buff = malloc(meminfo.eb_size); if (!tmp_buff) goto leave_free_test_pattern; /* For each eraseblock */ for (eb_nr = 0; eb_nr < meminfo.eb_cnt; eb_nr++) { /* Skip bad blocks */ ret = mtd_is_bad(&meminfo, fd, eb_nr); if (ret == 1) continue; if (ret == -1) goto leave_free_all; /* Store the EBs data before testing (including OOB) */ ret = store_eb_content(eb_nr); if (ret) goto leave_free_all; /* Run RW tests */ for (i = 0; i < PER_EB_RUNS; i++) { /* Generate test pattern */ for (j = 0; j < meminfo.eb_size; j++) *((char *)(test_pattern + j)) = (char)rand(); ret = eb_rw_testing(eb_nr); if (ret) goto leave_free_all; } /* Restore the original data */ ret = restore_eb_content(eb_nr); if (ret) goto leave_free_all; } printf("Test finished. Everything OK.\n"); ret = EXIT_SUCCESS; leave_free_all: free(tmp_buff); leave_free_test_pattern: free(test_pattern); leave_free_oob: free(oob); leave_free_eb: free(eb); return ret; } int main(int argc, char* argv[]) { struct mtd_ecc_stats eccstats_orig; struct mtd_ecc_stats eccstats_new; int ret = EXIT_FAILURE; char *dev; if (argc < 2) { fprintf(stderr, "Usage: %s MTD_DEVICE\n", argv[0]); exit(EXIT_FAILURE); } /* Initialize libmtd */ mtd_desc = libmtd_open(); if (!mtd_desc) { fprintf(stderr, "can't initialize libmtd"); exit(EXIT_FAILURE); } dev = argv[1]; /* Open MTD device */ fd = open(dev, O_RDWR); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } /* Fill in MTD device capability structure */ if (mtd_get_dev_info(mtd_desc, dev, &meminfo) < 0) { fprintf(stderr, "mtd_get_dev_info failed"); goto close_fd; } if (ioctl(fd, ECCGETSTATS, &eccstats_orig)) { perror("ECCGETSTATS"); goto close_fd; } ret = run_test(); if (ioctl(fd, ECCGETSTATS, &eccstats_new)) { perror("ECCGETSTATS"); goto close_fd; } /* Fail the test even if there was a single uncorrectable 'bit-flip' */ if (eccstats_new.failed > eccstats_orig.failed) { ret = EXIT_FAILURE; goto close_fd; } /* If there is more correctable bitflips than the threshold, fail the test */ if ((eccstats_new.corrected - eccstats_orig.corrected) > CORRECTABLE_BIT_FLIPS_THRESHOLD) { ret = EXIT_FAILURE; goto close_fd; } close_fd: close(fd); exit(ret); } From boris.brezillon at free-electrons.com Tue Sep 23 07:07:36 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 16:07:36 +0200 Subject: [PATCH v3 3/3] mtd: nand: gpmi: add raw oob access functions In-Reply-To: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411481256-29141-4-git-send-email-boris.brezillon@free-electrons.com> Implement raw OOB access functions to retrieve OOB bytes when accessing the NAND in raw mode. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 7921ba7..850356a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1471,6 +1471,22 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, return 0; } +static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page); +} + +static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); + + return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1); +} + static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; @@ -1790,6 +1806,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ecc->write_oob = gpmi_ecc_write_oob; ecc->read_page_raw = gpmi_ecc_read_page_raw; ecc->write_page_raw = gpmi_ecc_write_page_raw; + ecc->read_oob_raw = gpmi_ecc_read_oob_raw; + ecc->write_oob_raw = gpmi_ecc_write_oob_raw; ecc->mode = NAND_ECC_HW; ecc->size = bch_geo->ecc_chunk_size; ecc->strength = bch_geo->ecc_strength; -- 1.9.1 From boris.brezillon at free-electrons.com Tue Sep 23 07:07:33 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 16:07:33 +0200 Subject: [PATCH v3 0/3] mtd: nand: gpmi: add proper raw access support Message-ID: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> Hello Huang, Brian, This is just a new proposal to support raw accesses in a more standard way in the GPMI driver. This series has been tested on an imx28 board. Any suggestions are welcome. Best Regards, Boris Changes since v2: - fixed a bug in gpmi_move_bits - add a raw_buffer field to be used when using raw access methods (experienced memory corruptions when directly using page_buffer_virt buffer) - add raw OOB access functions Boris BREZILLON (3): mtd: nand: gpmi: add gpmi_move_bits function mtd: nand: gpmi: add proper raw access support mtd: nand: gpmi: add raw oob access functions drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 144 +++++++++++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 6 ++ 3 files changed, 238 insertions(+) -- 1.9.1 From boris.brezillon at free-electrons.com Tue Sep 23 07:07:34 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 16:07:34 +0200 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> Add a new function to move bits (not bytes) from a memory region to another one. This function is similar to memmove except it acts at bit level. This function is needed to implement GPMI raw access functions, given the fact that ECC engine does not pad ECC bits to the next byte boundary. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ 2 files changed, 92 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 87e658c..e2f706a 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, set_dma_type(this, DMA_FOR_READ_ECC_PAGE); return start_dma_with_bch_irq(this, desc); } + +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits) +{ + size_t i; + size_t nbytes; + u32 src_byte = 0; + + src += src_bit_off / 8; + src_bit_off %= 8; + + dst += dst_bit_off / 8; + dst_bit_off %= 8; + + if (src_bit_off) { + src_byte = src[0] >> src_bit_off; + nbits -= 8 - src_bit_off; + src++; + } + + nbytes = nbits / 8; + + if (dst_bit_off) { + if (src_bit_off <= dst_bit_off) { + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += (8 - dst_bit_off); + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + } else if (nbytes) { + src_byte |= src[0] << (8 - src_bit_off); + dst[0] &= GENMASK(dst_bit_off - 1, 0); + dst[0] |= src_byte << dst_bit_off; + src_bit_off += dst_bit_off; + src_byte >>= (8 - dst_bit_off); + dst_bit_off = 0; + dst++; + nbytes--; + src++; + if (src_bit_off > 7) { + src_bit_off -= 8; + dst[0] = src_byte; + dst++; + src_byte >>= 8; + } + } + } + + if (!src_bit_off && !dst_bit_off) { + if (nbytes) + memcpy(dst, src, nbytes); + } else { + for (i = 0; i < nbytes; i++) { + src_byte |= src[i] << (8 - src_bit_off); + dst[i] = src_byte; + src_byte >>= 8; + } + } + + dst += nbytes; + src += nbytes; + nbits %= 8; + + if (!nbits && !src_bit_off) + return; + + if (nbits) + src_byte |= (*src & GENMASK(nbits - 1, 0)) << + ((8 - src_bit_off) % 8); + nbits += (8 - src_bit_off) % 8; + + if (dst_bit_off) + src_byte = (src_byte << dst_bit_off) | + (*dst & GENMASK(dst_bit_off - 1, 0)); + nbits += dst_bit_off; + + if (nbits % 8) + src_byte |= (dst[nbits / 8] & GENMASK(7, nbits % 8)) << + (nbits / 8); + + nbytes = DIV_ROUND_UP(nbits, 8); + for (i = 0; i < nbytes; i++) { + dst[i] = src_byte; + src_byte >>= 8; + } +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 32c6ba4..17d0736 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -290,6 +290,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *, extern int gpmi_read_page(struct gpmi_nand_data *, dma_addr_t payload, dma_addr_t auxiliary); +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, + const u8 *src, size_t src_bit_off, + size_t nbits); + /* BCH : Status Block Completion Codes */ #define STATUS_GOOD 0x00 #define STATUS_ERASED 0xff -- 1.9.1 From boris.brezillon at free-electrons.com Tue Sep 23 07:07:35 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 16:07:35 +0200 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> Several MTD users (either in user or kernel space) expect a valid raw access support to NAND chip devices. This is particularly true for testing tools which are often touching the data stored in a NAND chip in raw mode to artificially generate errors. The GPMI drivers do not implemenent raw access functions, and thus rely on default HW_ECC scheme implementation. The default implementation consider the data and OOB area as properly separated in their respective NAND section, which is not true for the GPMI controller. In this driver/controller some OOB data are stored at the beginning of the NAND data area (these data are called metadata in the driver), then ECC bytes are interleaved with data chunk (which is similar to the HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as OOB data. Signed-off-by: Boris BREZILLON --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + 2 files changed, 128 insertions(+) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 959cb9b..7921ba7 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) this->page_buffer_phys); kfree(this->cmd_buffer); kfree(this->data_buffer_dma); + kfree(this->raw_buffer); this->cmd_buffer = NULL; this->data_buffer_dma = NULL; @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) if (!this->page_buffer_virt) goto error_alloc; + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); + if (!this->raw_buffer) + goto error_alloc; /* Slice up the page buffer. */ this->payload_virt = this->page_buffer_virt; @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) return status & NAND_STATUS_FAIL ? -EIO : 0; } +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; + u8 *tmp_buf = this->raw_buffer; + size_t src_bit_off; + size_t oob_bit_off; + size_t oob_byte_off; + uint8_t *oob = chip->oob_poi; + int step; + + chip->read_buf(mtd, tmp_buf, + mtd->writesize + mtd->oobsize); + + if (this->swap_block_mark) { + u8 swap = tmp_buf[0]; + + tmp_buf[0] = tmp_buf[mtd->writesize]; + tmp_buf[mtd->writesize] = swap; + } + + if (oob_required) + memcpy(oob, tmp_buf, nfc_geo->metadata_size); + + oob_bit_off = nfc_geo->metadata_size * 8; + src_bit_off = oob_bit_off; + + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + if (buf) + gpmi_move_bits(buf, step * eccsize * 8, + tmp_buf, src_bit_off, + eccsize * 8); + src_bit_off += eccsize * 8; + + if (oob_required) + gpmi_move_bits(oob, oob_bit_off, + tmp_buf, src_bit_off, + eccbits); + + src_bit_off += eccbits; + oob_bit_off += eccbits; + } + + if (oob_required && oob_bit_off % 8) + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); + + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); + + if (oob_required && oob_byte_off < mtd->oobsize) + memcpy(oob + oob_byte_off, + tmp_buf + mtd->writesize + oob_byte_off, + mtd->oobsize - oob_byte_off); + + return 0; +} + +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, + int oob_required) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + int eccsize = nfc_geo->ecc_chunk_size; + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; + u8 *tmp_buf = this->raw_buffer; + uint8_t *oob = chip->oob_poi; + size_t dst_bit_off; + size_t oob_bit_off; + size_t oob_byte_off; + int step; + + if (!buf || !oob_required) + memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize); + + memcpy(tmp_buf, oob, nfc_geo->metadata_size); + oob_bit_off = nfc_geo->metadata_size * 8; + dst_bit_off = oob_bit_off; + + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { + if (buf) + gpmi_move_bits(tmp_buf, dst_bit_off, + buf, step * eccsize * 8, eccsize * 8); + dst_bit_off += eccsize * 8; + + /* Pad last ECC block to align following data on a byte */ + if (step == nfc_geo->ecc_chunk_count - 1 && + (oob_bit_off + eccbits) % 8) + eccbits += 8 - ((oob_bit_off + eccbits) % 8); + + if (oob_required) + gpmi_move_bits(tmp_buf, dst_bit_off, + oob, oob_bit_off, eccbits); + + dst_bit_off += eccbits; + oob_bit_off += eccbits; + } + + oob_byte_off = oob_bit_off / 8; + + if (oob_required && oob_byte_off < mtd->oobsize) + memcpy(tmp_buf + mtd->writesize + oob_byte_off, + oob + oob_byte_off, mtd->oobsize - oob_byte_off); + + if (this->swap_block_mark) { + u8 swap = tmp_buf[0]; + + tmp_buf[0] = tmp_buf[mtd->writesize]; + tmp_buf[mtd->writesize] = swap; + } + + chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize); + + return 0; +} + static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; @@ -1664,6 +1788,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ecc->write_page = gpmi_ecc_write_page; ecc->read_oob = gpmi_ecc_read_oob; ecc->write_oob = gpmi_ecc_write_oob; + ecc->read_page_raw = gpmi_ecc_read_page_raw; + ecc->write_page_raw = gpmi_ecc_write_page_raw; ecc->mode = NAND_ECC_HW; ecc->size = bch_geo->ecc_chunk_size; ecc->strength = bch_geo->ecc_strength; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 17d0736..89ab5c8 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -189,6 +189,8 @@ struct gpmi_nand_data { void *auxiliary_virt; dma_addr_t auxiliary_phys; + void *raw_buffer; + /* DMA channels */ #define DMA_CHANS 8 struct dma_chan *dma_chans[DMA_CHANS]; -- 1.9.1 From shijie8 at gmail.com Tue Sep 23 07:54:15 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Tue, 23 Sep 2014 22:54:15 +0800 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140923145413.GA1633@localhost.localdomain> On Tue, Sep 23, 2014 at 04:07:34PM +0200, Boris BREZILLON wrote: > Add a new function to move bits (not bytes) from a memory region to > another one. > This function is similar to memmove except it acts at bit level. > This function is needed to implement GPMI raw access functions, given the > fact that ECC engine does not pad ECC bits to the next byte boundary. sorry for not comment your v2 patch set. > > Signed-off-by: Boris BREZILLON > --- > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ > 2 files changed, 92 insertions(+) > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > index 87e658c..e2f706a 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, > set_dma_type(this, DMA_FOR_READ_ECC_PAGE); > return start_dma_with_bch_irq(this, desc); > } > + > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > + const u8 *src, size_t src_bit_off, > + size_t nbits) we can simplify the code. We could use the bytes to replace the @nbits. The chunk data is always byte aligned. Btw: please add more comments in this function. thanks Huang Shijie From boris.brezillon at free-electrons.com Tue Sep 23 07:58:22 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 16:58:22 +0200 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <20140923145413.GA1633@localhost.localdomain> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> <20140923145413.GA1633@localhost.localdomain> Message-ID: <20140923165822.27cfde69@bbrezillon> On Tue, 23 Sep 2014 22:54:15 +0800 Huang Shijie wrote: > On Tue, Sep 23, 2014 at 04:07:34PM +0200, Boris BREZILLON wrote: > > Add a new function to move bits (not bytes) from a memory region to > > another one. > > This function is similar to memmove except it acts at bit level. > > This function is needed to implement GPMI raw access functions, given the > > fact that ECC engine does not pad ECC bits to the next byte boundary. > sorry for not comment your v2 patch set. > > > > > Signed-off-by: Boris BREZILLON > > --- > > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ > > 2 files changed, 92 insertions(+) > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > index 87e658c..e2f706a 100644 > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, > > set_dma_type(this, DMA_FOR_READ_ECC_PAGE); > > return start_dma_with_bch_irq(this, desc); > > } > > + > > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > > + const u8 *src, size_t src_bit_off, > > + size_t nbits) > we can simplify the code. Any suggestions ? > > We could use the bytes to replace the @nbits. > > The chunk data is always byte aligned. This function is also used to store ECC bits in the OOB buffer and these chunk of data are not byte aligned :-). > > > Btw: please add more comments in this function. Yep, I should definitely comment it, and I'll do. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From shijie8 at gmail.com Tue Sep 23 08:04:28 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Tue, 23 Sep 2014 23:04:28 +0800 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <20140923165822.27cfde69@bbrezillon> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> <20140923145413.GA1633@localhost.localdomain> <20140923165822.27cfde69@bbrezillon> Message-ID: <20140923150427.GB1633@localhost.localdomain> On Tue, Sep 23, 2014 at 04:58:22PM +0200, Boris BREZILLON wrote: > On Tue, 23 Sep 2014 22:54:15 +0800 > Huang Shijie wrote: > > > On Tue, Sep 23, 2014 at 04:07:34PM +0200, Boris BREZILLON wrote: > > > Add a new function to move bits (not bytes) from a memory region to > > > another one. > > > This function is similar to memmove except it acts at bit level. > > > This function is needed to implement GPMI raw access functions, given the > > > fact that ECC engine does not pad ECC bits to the next byte boundary. > > sorry for not comment your v2 patch set. > > > > > > > > Signed-off-by: Boris BREZILLON > > > --- > > > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ > > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ > > > 2 files changed, 92 insertions(+) > > > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > index 87e658c..e2f706a 100644 > > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, > > > set_dma_type(this, DMA_FOR_READ_ECC_PAGE); > > > return start_dma_with_bch_irq(this, desc); > > > } > > > + > > > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > > > + const u8 *src, size_t src_bit_off, > > > + size_t nbits) > > we can simplify the code. > > Any suggestions ? > > > > > We could use the bytes to replace the @nbits. > > > > The chunk data is always byte aligned. > > This function is also used to store ECC bits in the OOB buffer and > these chunk of data are not byte aligned :-). yes. you are right. I missed it. could you also comment these two hooks in the patch set. I hope Brian also can check it, and we can make it more clear about how to implement them. thanks Huang Shijie From shijie8 at gmail.com Tue Sep 23 08:17:41 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Tue, 23 Sep 2014 23:17:41 +0800 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140923151739.GA1791@localhost.localdomain> On Tue, Sep 23, 2014 at 04:07:35PM +0200, Boris BREZILLON wrote: > Several MTD users (either in user or kernel space) expect a valid raw > access support to NAND chip devices. > This is particularly true for testing tools which are often touching the > data stored in a NAND chip in raw mode to artificially generate errors. > > The GPMI drivers do not implemenent raw access functions, and thus rely on > default HW_ECC scheme implementation. > The default implementation consider the data and OOB area as properly > separated in their respective NAND section, which is not true for the GPMI > controller. > In this driver/controller some OOB data are stored at the beginning of the > NAND data area (these data are called metadata in the driver), then ECC > bytes are interleaved with data chunk (which is similar to the > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > OOB data. > > Signed-off-by: Boris BREZILLON > --- > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + > 2 files changed, 128 insertions(+) > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > index 959cb9b..7921ba7 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) > this->page_buffer_phys); > kfree(this->cmd_buffer); > kfree(this->data_buffer_dma); > + kfree(this->raw_buffer); > > this->cmd_buffer = NULL; > this->data_buffer_dma = NULL; > @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) > if (!this->page_buffer_virt) > goto error_alloc; > > + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); why add this buffer? did you meet some data overlapped? > + if (!this->raw_buffer) > + goto error_alloc; > > /* Slice up the page buffer. */ > this->payload_virt = this->page_buffer_virt; > @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) > return status & NAND_STATUS_FAIL ? -EIO : 0; > } > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > + struct nand_chip *chip, uint8_t *buf, > + int oob_required, int page) > +{ > + struct gpmi_nand_data *this = chip->priv; > + struct bch_geometry *nfc_geo = &this->bch_geometry; > + int eccsize = nfc_geo->ecc_chunk_size; > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > + u8 *tmp_buf = this->raw_buffer; > + size_t src_bit_off; > + size_t oob_bit_off; > + size_t oob_byte_off; > + uint8_t *oob = chip->oob_poi; > + int step; > + > + chip->read_buf(mtd, tmp_buf, > + mtd->writesize + mtd->oobsize); > + > + if (this->swap_block_mark) { > + u8 swap = tmp_buf[0]; > + > + tmp_buf[0] = tmp_buf[mtd->writesize]; > + tmp_buf[mtd->writesize] = swap; > + } > + > + if (oob_required) > + memcpy(oob, tmp_buf, nfc_geo->metadata_size); > + > + oob_bit_off = nfc_geo->metadata_size * 8; > + src_bit_off = oob_bit_off; > + > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > + if (buf) could this @buf become NULL? > + gpmi_move_bits(buf, step * eccsize * 8, > + tmp_buf, src_bit_off, > + eccsize * 8); > + src_bit_off += eccsize * 8; > + > + if (oob_required) > + gpmi_move_bits(oob, oob_bit_off, > + tmp_buf, src_bit_off, > + eccbits); > + > + src_bit_off += eccbits; > + oob_bit_off += eccbits; > + } > + > + if (oob_required && oob_bit_off % 8) > + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); > + > + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); > + > + if (oob_required && oob_byte_off < mtd->oobsize) > + memcpy(oob + oob_byte_off, > + tmp_buf + mtd->writesize + oob_byte_off, > + mtd->oobsize - oob_byte_off); For the above 9 lines, we'd better add a condition check here to make code more clear: if (oob_required) { .... } thanks Huang Shijie > + > + return 0; > +} > + > +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, > + struct nand_chip *chip, > + const uint8_t *buf, > + int oob_required) > +{ > + struct gpmi_nand_data *this = chip->priv; > + struct bch_geometry *nfc_geo = &this->bch_geometry; > + int eccsize = nfc_geo->ecc_chunk_size; > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > + u8 *tmp_buf = this->raw_buffer; > + uint8_t *oob = chip->oob_poi; > + size_t dst_bit_off; > + size_t oob_bit_off; > + size_t oob_byte_off; > + int step; > + > + if (!buf || !oob_required) > + memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize); > + > + memcpy(tmp_buf, oob, nfc_geo->metadata_size); > + oob_bit_off = nfc_geo->metadata_size * 8; > + dst_bit_off = oob_bit_off; > + > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > + if (buf) > + gpmi_move_bits(tmp_buf, dst_bit_off, > + buf, step * eccsize * 8, eccsize * 8); > + dst_bit_off += eccsize * 8; > + > + /* Pad last ECC block to align following data on a byte */ > + if (step == nfc_geo->ecc_chunk_count - 1 && > + (oob_bit_off + eccbits) % 8) > + eccbits += 8 - ((oob_bit_off + eccbits) % 8); > + > + if (oob_required) > + gpmi_move_bits(tmp_buf, dst_bit_off, > + oob, oob_bit_off, eccbits); > + > + dst_bit_off += eccbits; > + oob_bit_off += eccbits; > + } > + > + oob_byte_off = oob_bit_off / 8; > + > + if (oob_required && oob_byte_off < mtd->oobsize) > + memcpy(tmp_buf + mtd->writesize + oob_byte_off, > + oob + oob_byte_off, mtd->oobsize - oob_byte_off); > + > + if (this->swap_block_mark) { > + u8 swap = tmp_buf[0]; > + > + tmp_buf[0] = tmp_buf[mtd->writesize]; > + tmp_buf[mtd->writesize] = swap; > + } > + > + chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize); > + > + return 0; > +} > + > static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) > { > struct nand_chip *chip = mtd->priv; > @@ -1664,6 +1788,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) > ecc->write_page = gpmi_ecc_write_page; > ecc->read_oob = gpmi_ecc_read_oob; > ecc->write_oob = gpmi_ecc_write_oob; > + ecc->read_page_raw = gpmi_ecc_read_page_raw; > + ecc->write_page_raw = gpmi_ecc_write_page_raw; > ecc->mode = NAND_ECC_HW; > ecc->size = bch_geo->ecc_chunk_size; > ecc->strength = bch_geo->ecc_strength; > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > index 17d0736..89ab5c8 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > @@ -189,6 +189,8 @@ struct gpmi_nand_data { > void *auxiliary_virt; > dma_addr_t auxiliary_phys; > > + void *raw_buffer; > + > /* DMA channels */ > #define DMA_CHANS 8 > struct dma_chan *dma_chans[DMA_CHANS]; > -- > 1.9.1 > From shijie8 at gmail.com Tue Sep 23 08:20:25 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Tue, 23 Sep 2014 23:20:25 +0800 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <20140923150427.GB1633@localhost.localdomain> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> <20140923145413.GA1633@localhost.localdomain> <20140923165822.27cfde69@bbrezillon> <20140923150427.GB1633@localhost.localdomain> Message-ID: <20140923152023.GB1791@localhost.localdomain> On Tue, Sep 23, 2014 at 11:04:28PM +0800, Huang Shijie wrote: > On Tue, Sep 23, 2014 at 04:58:22PM +0200, Boris BREZILLON wrote: > > On Tue, 23 Sep 2014 22:54:15 +0800 > > Huang Shijie wrote: > > > > > On Tue, Sep 23, 2014 at 04:07:34PM +0200, Boris BREZILLON wrote: > > > > Add a new function to move bits (not bytes) from a memory region to > > > > another one. > > > > This function is similar to memmove except it acts at bit level. > > > > This function is needed to implement GPMI raw access functions, given the > > > > fact that ECC engine does not pad ECC bits to the next byte boundary. > > > sorry for not comment your v2 patch set. > > > > > > > > > > > Signed-off-by: Boris BREZILLON > > > > --- > > > > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ > > > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ > > > > 2 files changed, 92 insertions(+) > > > > > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > > index 87e658c..e2f706a 100644 > > > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > > > > @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, > > > > set_dma_type(this, DMA_FOR_READ_ECC_PAGE); > > > > return start_dma_with_bch_irq(this, desc); > > > > } > > > > + > > > > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > > > > + const u8 *src, size_t src_bit_off, > > > > + size_t nbits) > > > we can simplify the code. > > > > Any suggestions ? > > > > > > > > We could use the bytes to replace the @nbits. > > > > > > The chunk data is always byte aligned. > > > > This function is also used to store ECC bits in the OOB buffer and > > these chunk of data are not byte aligned :-). > yes. you are right. I missed it. > > could you also comment these two hooks in the patch set. I mean the @ecc->read_page_raw and @ecc->write_page_raw. thanks Huang Shijie From boris.brezillon at free-electrons.com Tue Sep 23 08:25:58 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 17:25:58 +0200 Subject: [PATCH v3 1/3] mtd: nand: gpmi: add gpmi_move_bits function In-Reply-To: <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-2-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140923172558.3f6a161c@bbrezillon> Hi Huang, I've added some code comments inline (and I'll squash them in my next version). On Tue, 23 Sep 2014 16:07:34 +0200 Boris BREZILLON wrote: > Add a new function to move bits (not bytes) from a memory region to > another one. > This function is similar to memmove except it acts at bit level. > This function is needed to implement GPMI raw access functions, given the > fact that ECC engine does not pad ECC bits to the next byte boundary. > > Signed-off-by: Boris BREZILLON > --- > drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 88 ++++++++++++++++++++++++++++++++++ > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 4 ++ > 2 files changed, 92 insertions(+) > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > index 87e658c..e2f706a 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c > @@ -1353,3 +1353,91 @@ int gpmi_read_page(struct gpmi_nand_data *this, > set_dma_type(this, DMA_FOR_READ_ECC_PAGE); > return start_dma_with_bch_irq(this, desc); > } > + > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > + const u8 *src, size_t src_bit_off, > + size_t nbits) > +{ > + size_t i; > + size_t nbytes; > + u32 src_byte = 0; > + /* * Move src and dst pointers to the closest byte pointer and * store bit offsets within a byte. */ > + src += src_bit_off / 8; > + src_bit_off %= 8; > + > + dst += dst_bit_off / 8; > + dst_bit_off %= 8; > + /* * Initialize the src_byte value with bits available in the * first byte of data so that we end up with a byte aligned * src pointer. */ > + if (src_bit_off) { > + src_byte = src[0] >> src_bit_off; > + nbits -= 8 - src_bit_off; > + src++; > + } > + /* * Calculate the number of bytes that can be copied from src to * dst. */ > + nbytes = nbits / 8; > + /* * Try to align dst to a byte boundary by peeking some bits * from the source. */ > + if (dst_bit_off) { > + if (src_bit_off <= dst_bit_off) { > + dst[0] &= GENMASK(dst_bit_off - 1, 0); > + dst[0] |= src_byte << dst_bit_off; > + src_bit_off += (8 - dst_bit_off); > + src_byte >>= (8 - dst_bit_off); > + dst_bit_off = 0; > + dst++; > + } else if (nbytes) { > + src_byte |= src[0] << (8 - src_bit_off); > + dst[0] &= GENMASK(dst_bit_off - 1, 0); > + dst[0] |= src_byte << dst_bit_off; > + src_bit_off += dst_bit_off; > + src_byte >>= (8 - dst_bit_off); > + dst_bit_off = 0; > + dst++; > + nbytes--; > + src++; > + if (src_bit_off > 7) { > + src_bit_off -= 8; > + dst[0] = src_byte; > + dst++; > + src_byte >>= 8; > + } > + } > + } > + > + if (!src_bit_off && !dst_bit_off) { /* * Both src and dst pointers are byte aligned, thus we * can just use the optimized memcpy function */ > + if (nbytes) > + memcpy(dst, src, nbytes); > + } else { /* * src buffer is not byte aligned, hence we have to copy * each src byte to the src_byte variable (after * applying the appropriate shift depending on the * src bit offset). * We still try to work on bytes until there's not * enough available data in the src buffer. */ > + for (i = 0; i < nbytes; i++) { > + src_byte |= src[i] << (8 - src_bit_off); > + dst[i] = src_byte; > + src_byte >>= 8; > + } > + } > + /* move dst and src buffers */ > + dst += nbytes; > + src += nbytes; /* * nbits is the number of remaining bits. It should not exceed * 8 as we've already worked on bytes as much as possible. */ > + nbits %= 8; > + /* * if there's no more bits to copy to the destination and src * buffer was already byte aligned, then we're done. */ > + if (!nbits && !src_bit_off) > + return; > + /* Copy the remaining bits to the src_byte variable */ > + if (nbits) > + src_byte |= (*src & GENMASK(nbits - 1, 0)) << > + ((8 - src_bit_off) % 8); > + nbits += (8 - src_bit_off) % 8; > + /* * There were not enough bits to copy from src to dst to get a * byte aligned dst buffer. In this case prepare the src_byte * variable to match the dst organization (just shift src_byte * by dst bit offset and retrieve least significant bits from * dst). */ > + if (dst_bit_off) > + src_byte = (src_byte << dst_bit_off) | > + (*dst & GENMASK(dst_bit_off - 1, 0)); > + nbits += dst_bit_off; > + /* * Keep most significant bits from dst if we end up with an * unaligned number bits. */ > + if (nbits % 8) > + src_byte |= (dst[nbits / 8] & GENMASK(7, nbits % 8)) << > + (nbits / 8); > + /* Copy the remaining bytes to the destination */ > + nbytes = DIV_ROUND_UP(nbits, 8); > + for (i = 0; i < nbytes; i++) { > + dst[i] = src_byte; > + src_byte >>= 8; > + } > +} > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > index 32c6ba4..17d0736 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > @@ -290,6 +290,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *, > extern int gpmi_read_page(struct gpmi_nand_data *, > dma_addr_t payload, dma_addr_t auxiliary); > > +void gpmi_move_bits(u8 *dst, size_t dst_bit_off, > + const u8 *src, size_t src_bit_off, > + size_t nbits); > + > /* BCH : Status Block Completion Codes */ > #define STATUS_GOOD 0x00 > #define STATUS_ERASED 0xff -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From boris.brezillon at free-electrons.com Tue Sep 23 08:34:36 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 17:34:36 +0200 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140923151739.GA1791@localhost.localdomain> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> <20140923151739.GA1791@localhost.localdomain> Message-ID: <20140923173436.17ab0d36@bbrezillon> On Tue, 23 Sep 2014 23:17:41 +0800 Huang Shijie wrote: > On Tue, Sep 23, 2014 at 04:07:35PM +0200, Boris BREZILLON wrote: > > Several MTD users (either in user or kernel space) expect a valid raw > > access support to NAND chip devices. > > This is particularly true for testing tools which are often touching the > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > default HW_ECC scheme implementation. > > The default implementation consider the data and OOB area as properly > > separated in their respective NAND section, which is not true for the GPMI > > controller. > > In this driver/controller some OOB data are stored at the beginning of the > > NAND data area (these data are called metadata in the driver), then ECC > > bytes are interleaved with data chunk (which is similar to the > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > OOB data. > > > > Signed-off-by: Boris BREZILLON > > --- > > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + > > 2 files changed, 128 insertions(+) > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > index 959cb9b..7921ba7 100644 > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) > > this->page_buffer_phys); > > kfree(this->cmd_buffer); > > kfree(this->data_buffer_dma); > > + kfree(this->raw_buffer); > > > > this->cmd_buffer = NULL; > > this->data_buffer_dma = NULL; > > @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) > > if (!this->page_buffer_virt) > > goto error_alloc; > > > > + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); > why add this buffer? I don't why, but I experienced memory corruptions (triggering kernel panics) when using the page_buffer_virt, even though I had resized it according to the NAND writesize and oobsize (see my previous version). Do you see anything that could generate an overflow ? It seems to work when I allocate my own buffer... > > did you meet some data overlapped? > > > > + if (!this->raw_buffer) > > + goto error_alloc; > > > > /* Slice up the page buffer. */ > > this->payload_virt = this->page_buffer_virt; > > @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) > > return status & NAND_STATUS_FAIL ? -EIO : 0; > > } > > > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > > + struct nand_chip *chip, uint8_t *buf, > > + int oob_required, int page) > > +{ > > + struct gpmi_nand_data *this = chip->priv; > > + struct bch_geometry *nfc_geo = &this->bch_geometry; > > + int eccsize = nfc_geo->ecc_chunk_size; > > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > > + u8 *tmp_buf = this->raw_buffer; > > + size_t src_bit_off; > > + size_t oob_bit_off; > > + size_t oob_byte_off; > > + uint8_t *oob = chip->oob_poi; > > + int step; > > + > > + chip->read_buf(mtd, tmp_buf, > > + mtd->writesize + mtd->oobsize); > > + > > + if (this->swap_block_mark) { > > + u8 swap = tmp_buf[0]; > > + > > + tmp_buf[0] = tmp_buf[mtd->writesize]; > > + tmp_buf[mtd->writesize] = swap; > > + } > > + > > + if (oob_required) > > + memcpy(oob, tmp_buf, nfc_geo->metadata_size); > > + > > + oob_bit_off = nfc_geo->metadata_size * 8; > > + src_bit_off = oob_bit_off; > > + > > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > > + if (buf) > could this @buf become NULL? It's just a check to later support raw OOB accesses (see patch 3) ;-). > > > > + gpmi_move_bits(buf, step * eccsize * 8, > > + tmp_buf, src_bit_off, > > + eccsize * 8); > > + src_bit_off += eccsize * 8; > > + > > + if (oob_required) > > + gpmi_move_bits(oob, oob_bit_off, > > + tmp_buf, src_bit_off, > > + eccbits); > > + > > + src_bit_off += eccbits; > > + oob_bit_off += eccbits; > > + } > > + > > + if (oob_required && oob_bit_off % 8) > > + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); > > + > > + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); > > + > > + if (oob_required && oob_byte_off < mtd->oobsize) > > + memcpy(oob + oob_byte_off, > > + tmp_buf + mtd->writesize + oob_byte_off, > > + mtd->oobsize - oob_byte_off); > > For the above 9 lines, we'd better add a condition check here to make code more clear: > if (oob_required) { > > .... > > } Absolutely, I'll change that. Thanks, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From shijie8 at gmail.com Tue Sep 23 09:10:44 2014 From: shijie8 at gmail.com (Huang Shijie) Date: Wed, 24 Sep 2014 00:10:44 +0800 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140923161041.GA2147@localhost.localdomain> On Tue, Sep 23, 2014 at 04:07:35PM +0200, Boris BREZILLON wrote: > Several MTD users (either in user or kernel space) expect a valid raw > access support to NAND chip devices. > This is particularly true for testing tools which are often touching the > data stored in a NAND chip in raw mode to artificially generate errors. > > The GPMI drivers do not implemenent raw access functions, and thus rely on > default HW_ECC scheme implementation. > The default implementation consider the data and OOB area as properly > separated in their respective NAND section, which is not true for the GPMI > controller. > In this driver/controller some OOB data are stored at the beginning of the > NAND data area (these data are called metadata in the driver), then ECC > bytes are interleaved with data chunk (which is similar to the > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > OOB data. > > Signed-off-by: Boris BREZILLON > --- > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + > 2 files changed, 128 insertions(+) > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > index 959cb9b..7921ba7 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) > this->page_buffer_phys); > kfree(this->cmd_buffer); > kfree(this->data_buffer_dma); > + kfree(this->raw_buffer); > > this->cmd_buffer = NULL; > this->data_buffer_dma = NULL; > @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) > if (!this->page_buffer_virt) > goto error_alloc; > > + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); > + if (!this->raw_buffer) > + goto error_alloc; > > /* Slice up the page buffer. */ > this->payload_virt = this->page_buffer_virt; > @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) > return status & NAND_STATUS_FAIL ? -EIO : 0; > } > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > + struct nand_chip *chip, uint8_t *buf, > + int oob_required, int page) In actually, i suggest to call the ecc->read_page() in this hook. And after the ecc->read_page(), copy the relative data to the relative buffers. Is my suggestion right? please correct me. > +{ > + struct gpmi_nand_data *this = chip->priv; > + struct bch_geometry *nfc_geo = &this->bch_geometry; > + int eccsize = nfc_geo->ecc_chunk_size; > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > + u8 *tmp_buf = this->raw_buffer; > + size_t src_bit_off; > + size_t oob_bit_off; > + size_t oob_byte_off; > + uint8_t *oob = chip->oob_poi; > + int step; > + > + chip->read_buf(mtd, tmp_buf, > + mtd->writesize + mtd->oobsize); > + > + if (this->swap_block_mark) { > + u8 swap = tmp_buf[0]; > + > + tmp_buf[0] = tmp_buf[mtd->writesize]; > + tmp_buf[mtd->writesize] = swap; > + } > + > + if (oob_required) > + memcpy(oob, tmp_buf, nfc_geo->metadata_size); > + > + oob_bit_off = nfc_geo->metadata_size * 8; > + src_bit_off = oob_bit_off; > + > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > + if (buf) > + gpmi_move_bits(buf, step * eccsize * 8, > + tmp_buf, src_bit_off, > + eccsize * 8); > + src_bit_off += eccsize * 8; > + > + if (oob_required) > + gpmi_move_bits(oob, oob_bit_off, > + tmp_buf, src_bit_off, > + eccbits); > + > + src_bit_off += eccbits; > + oob_bit_off += eccbits; > + } > + > + if (oob_required && oob_bit_off % 8) > + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); > + > + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); > + > + if (oob_required && oob_byte_off < mtd->oobsize) > + memcpy(oob + oob_byte_off, > + tmp_buf + mtd->writesize + oob_byte_off, > + mtd->oobsize - oob_byte_off); > + > + return 0; > +} > + > +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, > + struct nand_chip *chip, > + const uint8_t *buf, > + int oob_required) > +{ give me more time to think over this hook :( sorry. thanks Huang Shijie > + struct gpmi_nand_data *this = chip->priv; > + struct bch_geometry *nfc_geo = &this->bch_geometry; > + int eccsize = nfc_geo->ecc_chunk_size; > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > + u8 *tmp_buf = this->raw_buffer; > + uint8_t *oob = chip->oob_poi; > + size_t dst_bit_off; > + size_t oob_bit_off; > + size_t oob_byte_off; > + int step; > + > + if (!buf || !oob_required) > + memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize); > + > + memcpy(tmp_buf, oob, nfc_geo->metadata_size); > + oob_bit_off = nfc_geo->metadata_size * 8; > + dst_bit_off = oob_bit_off; > + > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > + if (buf) > + gpmi_move_bits(tmp_buf, dst_bit_off, > + buf, step * eccsize * 8, eccsize * 8); > + dst_bit_off += eccsize * 8; > + > + /* Pad last ECC block to align following data on a byte */ > + if (step == nfc_geo->ecc_chunk_count - 1 && > + (oob_bit_off + eccbits) % 8) > + eccbits += 8 - ((oob_bit_off + eccbits) % 8); > + > + if (oob_required) > + gpmi_move_bits(tmp_buf, dst_bit_off, > + oob, oob_bit_off, eccbits); > + > + dst_bit_off += eccbits; > + oob_bit_off += eccbits; > + } > + > + oob_byte_off = oob_bit_off / 8; > + > + if (oob_required && oob_byte_off < mtd->oobsize) > + memcpy(tmp_buf + mtd->writesize + oob_byte_off, > + oob + oob_byte_off, mtd->oobsize - oob_byte_off); > + > + if (this->swap_block_mark) { > + u8 swap = tmp_buf[0]; > + > + tmp_buf[0] = tmp_buf[mtd->writesize]; > + tmp_buf[mtd->writesize] = swap; > + } > + > + chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize); > + > + return 0; > +} > + > static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) > { > struct nand_chip *chip = mtd->priv; > @@ -1664,6 +1788,8 @@ static int gpmi_init_last(struct gpmi_nand_data *this) > ecc->write_page = gpmi_ecc_write_page; > ecc->read_oob = gpmi_ecc_read_oob; > ecc->write_oob = gpmi_ecc_write_oob; > + ecc->read_page_raw = gpmi_ecc_read_page_raw; > + ecc->write_page_raw = gpmi_ecc_write_page_raw; > ecc->mode = NAND_ECC_HW; > ecc->size = bch_geo->ecc_chunk_size; > ecc->strength = bch_geo->ecc_strength; > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > index 17d0736..89ab5c8 100644 > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h > @@ -189,6 +189,8 @@ struct gpmi_nand_data { > void *auxiliary_virt; > dma_addr_t auxiliary_phys; > > + void *raw_buffer; > + > /* DMA channels */ > #define DMA_CHANS 8 > struct dma_chan *dma_chans[DMA_CHANS]; > -- > 1.9.1 > From boris.brezillon at free-electrons.com Tue Sep 23 10:16:19 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 19:16:19 +0200 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140923161041.GA2147@localhost.localdomain> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> <20140923161041.GA2147@localhost.localdomain> Message-ID: <20140923191619.0c0a667e@bbrezillon> On Wed, 24 Sep 2014 00:10:44 +0800 Huang Shijie wrote: > On Tue, Sep 23, 2014 at 04:07:35PM +0200, Boris BREZILLON wrote: > > Several MTD users (either in user or kernel space) expect a valid raw > > access support to NAND chip devices. > > This is particularly true for testing tools which are often touching the > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > default HW_ECC scheme implementation. > > The default implementation consider the data and OOB area as properly > > separated in their respective NAND section, which is not true for the GPMI > > controller. > > In this driver/controller some OOB data are stored at the beginning of the > > NAND data area (these data are called metadata in the driver), then ECC > > bytes are interleaved with data chunk (which is similar to the > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > OOB data. > > > > Signed-off-by: Boris BREZILLON > > --- > > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + > > 2 files changed, 128 insertions(+) > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > index 959cb9b..7921ba7 100644 > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) > > this->page_buffer_phys); > > kfree(this->cmd_buffer); > > kfree(this->data_buffer_dma); > > + kfree(this->raw_buffer); > > > > this->cmd_buffer = NULL; > > this->data_buffer_dma = NULL; > > @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) > > if (!this->page_buffer_virt) > > goto error_alloc; > > > > + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); > > + if (!this->raw_buffer) > > + goto error_alloc; > > > > /* Slice up the page buffer. */ > > this->payload_virt = this->page_buffer_virt; > > @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) > > return status & NAND_STATUS_FAIL ? -EIO : 0; > > } > > > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > > + struct nand_chip *chip, uint8_t *buf, > > + int oob_required, int page) > > In actually, i suggest to call the ecc->read_page() in this > hook. And after the ecc->read_page(), copy the relative data to > the relative buffers. Is my suggestion right? please correct me. Unfortunately it's not. The user expect that ECC correction is not involved when accessing the NAND in raw mode, which is not the case in your read_page implementation. This is particularly useful when one want to see the real page status (including bitflips). Moreover, I like to see the generated ECC bytes/bits when using raw access (but I'm not sure this is a requirement). This will help deducing the BCH algorithm and/or XOR mask applied after producing these bits if someone ever want to spend some time reverse engineering it. > > > > > +{ > > + struct gpmi_nand_data *this = chip->priv; > > + struct bch_geometry *nfc_geo = &this->bch_geometry; > > + int eccsize = nfc_geo->ecc_chunk_size; > > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > > + u8 *tmp_buf = this->raw_buffer; > > + size_t src_bit_off; > > + size_t oob_bit_off; > > + size_t oob_byte_off; > > + uint8_t *oob = chip->oob_poi; > > + int step; > > + > > + chip->read_buf(mtd, tmp_buf, > > + mtd->writesize + mtd->oobsize); > > + > > + if (this->swap_block_mark) { > > + u8 swap = tmp_buf[0]; > > + > > + tmp_buf[0] = tmp_buf[mtd->writesize]; > > + tmp_buf[mtd->writesize] = swap; > > + } > > + > > + if (oob_required) > > + memcpy(oob, tmp_buf, nfc_geo->metadata_size); > > + > > + oob_bit_off = nfc_geo->metadata_size * 8; > > + src_bit_off = oob_bit_off; > > + > > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > > + if (buf) > > + gpmi_move_bits(buf, step * eccsize * 8, > > + tmp_buf, src_bit_off, > > + eccsize * 8); > > + src_bit_off += eccsize * 8; > > + > > + if (oob_required) > > + gpmi_move_bits(oob, oob_bit_off, > > + tmp_buf, src_bit_off, > > + eccbits); > > + > > + src_bit_off += eccbits; > > + oob_bit_off += eccbits; > > + } > > + > > + if (oob_required && oob_bit_off % 8) > > + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); > > + > > + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); > > + > > + if (oob_required && oob_byte_off < mtd->oobsize) > > + memcpy(oob + oob_byte_off, > > + tmp_buf + mtd->writesize + oob_byte_off, > > + mtd->oobsize - oob_byte_off); > > + > > + return 0; > > +} > > + > > +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, > > + struct nand_chip *chip, > > + const uint8_t *buf, > > + int oob_required) > > +{ > > > give me more time to think over this hook :( Sure, no problem. Actually it's doing the exact same thing read_page_raw is doing expect it's applying on a write access. I copy the provided data (in-band and out-of-band is required) into a temporary buffer to match the GPMI controller layout, then write it without involving the BCH block (which means no ECC bits generation). Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From boris.brezillon at free-electrons.com Tue Sep 23 10:21:14 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Tue, 23 Sep 2014 19:21:14 +0200 Subject: [PATCH v3 2/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140923191619.0c0a667e@bbrezillon> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> <1411481256-29141-3-git-send-email-boris.brezillon@free-electrons.com> <20140923161041.GA2147@localhost.localdomain> <20140923191619.0c0a667e@bbrezillon> Message-ID: <20140923192114.44ea48bd@bbrezillon> On Tue, 23 Sep 2014 19:16:19 +0200 Boris BREZILLON wrote: > On Wed, 24 Sep 2014 00:10:44 +0800 > Huang Shijie wrote: > > > On Tue, Sep 23, 2014 at 04:07:35PM +0200, Boris BREZILLON wrote: > > > Several MTD users (either in user or kernel space) expect a valid raw > > > access support to NAND chip devices. > > > This is particularly true for testing tools which are often touching the > > > data stored in a NAND chip in raw mode to artificially generate errors. > > > > > > The GPMI drivers do not implemenent raw access functions, and thus rely on > > > default HW_ECC scheme implementation. > > > The default implementation consider the data and OOB area as properly > > > separated in their respective NAND section, which is not true for the GPMI > > > controller. > > > In this driver/controller some OOB data are stored at the beginning of the > > > NAND data area (these data are called metadata in the driver), then ECC > > > bytes are interleaved with data chunk (which is similar to the > > > HW_ECC_SYNDROME scheme), and eventually the remaining bytes are used as > > > OOB data. > > > > > > Signed-off-by: Boris BREZILLON > > > --- > > > drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 126 +++++++++++++++++++++++++++++++++ > > > drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 + > > > 2 files changed, 128 insertions(+) > > > > > > diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > > index 959cb9b..7921ba7 100644 > > > --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > > +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c > > > @@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) > > > this->page_buffer_phys); > > > kfree(this->cmd_buffer); > > > kfree(this->data_buffer_dma); > > > + kfree(this->raw_buffer); > > > > > > this->cmd_buffer = NULL; > > > this->data_buffer_dma = NULL; > > > @@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) > > > if (!this->page_buffer_virt) > > > goto error_alloc; > > > > > > + this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); > > > + if (!this->raw_buffer) > > > + goto error_alloc; > > > > > > /* Slice up the page buffer. */ > > > this->payload_virt = this->page_buffer_virt; > > > @@ -1347,6 +1351,126 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) > > > return status & NAND_STATUS_FAIL ? -EIO : 0; > > > } > > > > > > +static int gpmi_ecc_read_page_raw(struct mtd_info *mtd, > > > + struct nand_chip *chip, uint8_t *buf, > > > + int oob_required, int page) > > > > In actually, i suggest to call the ecc->read_page() in this > > hook. And after the ecc->read_page(), copy the relative data to > > the relative buffers. Is my suggestion right? please correct me. > > Unfortunately it's not. The user expect that ECC correction is not > involved when accessing the NAND in raw mode, which is not the case in > your read_page implementation. > This is particularly useful when one want to see the real page status > (including bitflips). > > Moreover, I like to see the generated ECC bytes/bits when using raw > access (but I'm not sure this is a requirement). This will help > deducing the BCH algorithm and/or XOR mask applied after producing > these bits if someone ever want to spend some time reverse engineering > it. > > > > > > > > > > +{ > > > + struct gpmi_nand_data *this = chip->priv; > > > + struct bch_geometry *nfc_geo = &this->bch_geometry; > > > + int eccsize = nfc_geo->ecc_chunk_size; > > > + int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len; > > > + u8 *tmp_buf = this->raw_buffer; > > > + size_t src_bit_off; > > > + size_t oob_bit_off; > > > + size_t oob_byte_off; > > > + uint8_t *oob = chip->oob_poi; > > > + int step; > > > + > > > + chip->read_buf(mtd, tmp_buf, > > > + mtd->writesize + mtd->oobsize); > > > + > > > + if (this->swap_block_mark) { > > > + u8 swap = tmp_buf[0]; > > > + > > > + tmp_buf[0] = tmp_buf[mtd->writesize]; > > > + tmp_buf[mtd->writesize] = swap; > > > + } > > > + > > > + if (oob_required) > > > + memcpy(oob, tmp_buf, nfc_geo->metadata_size); > > > + > > > + oob_bit_off = nfc_geo->metadata_size * 8; > > > + src_bit_off = oob_bit_off; > > > + > > > + for (step = 0; step < nfc_geo->ecc_chunk_count; step++) { > > > + if (buf) > > > + gpmi_move_bits(buf, step * eccsize * 8, > > > + tmp_buf, src_bit_off, > > > + eccsize * 8); > > > + src_bit_off += eccsize * 8; > > > + > > > + if (oob_required) > > > + gpmi_move_bits(oob, oob_bit_off, > > > + tmp_buf, src_bit_off, > > > + eccbits); > > > + > > > + src_bit_off += eccbits; > > > + oob_bit_off += eccbits; > > > + } > > > + > > > + if (oob_required && oob_bit_off % 8) > > > + oob[oob_bit_off / 8] &= GENMASK(oob_bit_off - 1, 0); > > > + > > > + oob_byte_off = DIV_ROUND_UP(oob_bit_off, 8); > > > + > > > + if (oob_required && oob_byte_off < mtd->oobsize) > > > + memcpy(oob + oob_byte_off, > > > + tmp_buf + mtd->writesize + oob_byte_off, > > > + mtd->oobsize - oob_byte_off); > > > + > > > + return 0; > > > +} > > > + > > > +static int gpmi_ecc_write_page_raw(struct mtd_info *mtd, > > > + struct nand_chip *chip, > > > + const uint8_t *buf, > > > + int oob_required) > > > +{ > > > > > > give me more time to think over this hook :( > > Sure, no problem. > > Actually it's doing the exact same thing read_page_raw is doing expect > it's applying on a write access. > I copy the provided data (in-band and out-of-band is required) into a ^ if > temporary buffer to match the GPMI controller layout, then write it > without involving the BCH block (which means no ECC bits generation). > > Best Regards, > > Boris > -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From asierra at xes-inc.com Tue Sep 23 12:07:24 2014 From: asierra at xes-inc.com (Aaron Sierra) Date: Tue, 23 Sep 2014 14:07:24 -0500 (CDT) Subject: [PATCH] mtd: bfin-async-flash: Remove unused variable In-Reply-To: <1106241329.302591.1411499010840.JavaMail.zimbra@xes-inc.com> Message-ID: <1931039891.303225.1411499244022.JavaMail.zimbra@xes-inc.com> Avoid the following compile warning: drivers/mtd/maps/bfin-async-flash.c: In function 'bfin_flash_probe': drivers/mtd/maps/bfin-async-flash.c:129: warning: unused variable 'ret' Signed-off-by: Aaron Sierra --- drivers/mtd/maps/bfin-async-flash.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 6ea51e5..41730fe 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -126,7 +126,6 @@ static const char * const part_probe_types[] = { static int bfin_flash_probe(struct platform_device *pdev) { - int ret; struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev); struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); -- 1.9.1 From richard at nod.at Tue Sep 23 15:06:15 2014 From: richard at nod.at (Richard Weinberger) Date: Wed, 24 Sep 2014 00:06:15 +0200 Subject: [RFC] UBI bitrot checking Message-ID: <1411509976-12636-1-git-send-email-richard@nod.at> This is a very initial draft for one possibility of bitrot checking in UBI. The basic idea is to have a worker function which reads a complete PEB and schedules scrubbing if bit flips are detected. Currently this check is triggered by accessing any UBI debugfs file (yes, I'm lazy!). We have to agree on an interface first. Do we want a debugfs file? Another ioctl()? Automatic in-kernel schedules? Of course this interface has to return EBUSY if currently a check is running... The current implementation has one limitation, it can only check PEBs which are used. As of now ubi_wl_scrub_peb() works only for used PEBs but I think we could change that. Thanks, //richard From richard at nod.at Tue Sep 23 15:06:16 2014 From: richard at nod.at (Richard Weinberger) Date: Wed, 24 Sep 2014 00:06:16 +0200 Subject: [PATCH] [RFC] UBI: Implement bitrot checking In-Reply-To: <1411509976-12636-1-git-send-email-richard@nod.at> References: <1411509976-12636-1-git-send-email-richard@nod.at> Message-ID: <1411509976-12636-2-git-send-email-richard@nod.at> This patch implements bitrot checking for UBI. ubi_wl_trigger_bitrot_check() triggers a re-read of every PEB which is currently in use. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/debug.c | 3 ++ drivers/mtd/ubi/eba.c | 2 +- drivers/mtd/ubi/ubi.h | 3 +- drivers/mtd/ubi/wl.c | 115 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 112 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 63cb1d7..80d7832 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -332,6 +332,9 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, goto out; } + //XXX + ubi_wl_trigger_bitrot_check(ubi); + if (dent == d->dfs_chk_gen) d->chk_gen = val; else if (dent == d->dfs_chk_io) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0e11671d..78109e7 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -468,7 +468,7 @@ retry: } if (scrub) - err = ubi_wl_scrub_peb(ubi, pnum); + err = ubi_wl_scrub_peb(ubi, pnum, 0); leb_read_unlock(ubi, vol_id, lnum); return err; diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..ad004bd 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -806,7 +806,7 @@ int ubi_wl_get_peb(struct ubi_device *ubi); int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, int pnum, int torture); int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum); -int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); +int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum, int nested); int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai); void ubi_wl_close(struct ubi_device *ubi); int ubi_thread(void *u); @@ -816,6 +816,7 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *used_e, int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); +void ubi_wl_trigger_bitrot_check(struct ubi_device *ubi); /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..80e451f 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -325,6 +325,20 @@ static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root) return 0; } +static inline int in_pg(const struct ubi_device *ubi, struct ubi_wl_entry *e) +{ + struct ubi_wl_entry *p; + int i; + + for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) + list_for_each_entry(p, &ubi->pq[i], u.list) + if (p == e) + return 1; + + return 0; +} + + /** * prot_queue_add - add physical eraseblock to the protection queue. * @ubi: UBI device description object @@ -914,6 +928,93 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, } /** + * bitrot_check_worker - physical eraseblock bitrot check worker function. + * @ubi: UBI device description object + * @wl_wrk: the work object + * @shutdown: non-zero if the worker has to free memory and exit + * + * This function read a physical eraseblock and schedules scrubbing if + * bit flips are detected. + */ +static int bitrot_check_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, + int shutdown) +{ + struct ubi_wl_entry *e = wl_wrk->e; + int err; + + kfree(wl_wrk); + if (shutdown) { + dbg_wl("cancel bitrot check of PEB %d", e->pnum); + kmem_cache_free(ubi_wl_entry_slab, e); + return 0; + } + + if (!in_wl_tree(e, &ubi->used) && !in_pg(ubi, e)) { + dbg_wl("PEB %d not in used tree nor in protection queue", e->pnum); + return 0; + } + + mutex_lock(&ubi->buf_mutex); + err = ubi_io_read(ubi, ubi->peb_buf, e->pnum, 0, ubi->peb_size); + mutex_unlock(&ubi->buf_mutex); + if (err == UBI_IO_BITFLIPS) + err = ubi_wl_scrub_peb(ubi, e->pnum, 1); + else + /* Ignore read errors as we return only work related errors. + * Read errors will be logged by ubi_io_read(). */ + err = 0; + + return err; +} + +/** + * schedule_bitrot_check - schedule a bitrot check work. + * @ubi: UBI device description object + * @e: the WL entry of the physical eraseblock to check + * + * This function returns zero in case of success and a %-ENOMEM in case of + * failure. + */ +static int schedule_bitrot_check(struct ubi_device *ubi, + struct ubi_wl_entry *e) +{ + struct ubi_work *wl_wrk; + + ubi_assert(e); + + dbg_wl("schedule bitrot check of PEB %d", e->pnum); + + wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); + if (!wl_wrk) + return -ENOMEM; + + wl_wrk->func = &bitrot_check_worker; + wl_wrk->e = e; + + schedule_ubi_work(ubi, wl_wrk); + return 0; +} + +/** + * ubi_wl_trigger_bitrot_check - triggers a re-read of all physical erase + * blocks in use. + * @ubi: UBI device description object + */ +void ubi_wl_trigger_bitrot_check(struct ubi_device *ubi) +{ + int i; + struct ubi_wl_entry *e; + + for (i = 0; i < ubi->peb_count; i++) { + spin_lock(&ubi->wl_lock); + e = ubi->lookuptbl[i]; + spin_unlock(&ubi->wl_lock); + if (e) + schedule_bitrot_check(ubi, e); + } +} + +/** * do_sync_erase - run the erase worker synchronously. * @ubi: UBI device description object * @e: the WL entry of the physical eraseblock to erase @@ -1634,13 +1735,14 @@ retry: * ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing. * @ubi: UBI device description object * @pnum: the physical eraseblock to schedule + * @nested: set to non-zero if this function is called from UBI worker * * If a bit-flip in a physical eraseblock is detected, this physical eraseblock * needs scrubbing. This function schedules a physical eraseblock for * scrubbing which is done in background. This function returns zero in case of * success and a negative error code in case of failure. */ -int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) +int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum, int nested) { struct ubi_wl_entry *e; @@ -1690,7 +1792,7 @@ retry: * Technically scrubbing is the same as wear-leveling, so it is done * by the WL worker. */ - return ensure_wear_leveling(ubi, 0); + return ensure_wear_leveling(ubi, nested); } /** @@ -2117,16 +2219,11 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, static int self_check_in_pq(const struct ubi_device *ubi, struct ubi_wl_entry *e) { - struct ubi_wl_entry *p; - int i; - if (!ubi_dbg_chk_gen(ubi)) return 0; - for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i) - list_for_each_entry(p, &ubi->pq[i], u.list) - if (p == e) - return 0; + if (!in_pg(ubi, e)) + return 0; ubi_err("self-check failed for PEB %d, EC %d, Protect queue", e->pnum, e->ec); -- 1.8.4.5 From dedekind1 at gmail.com Wed Sep 24 05:36:45 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Wed, 24 Sep 2014 15:36:45 +0300 Subject: [PATCH] UBI: Fix livelock in produce_free_peb() In-Reply-To: <1411141076-21489-1-git-send-email-richard@nod.at> References: <1411141076-21489-1-git-send-email-richard@nod.at> Message-ID: <1411562205.23429.40.camel@sauron.fi.intel.com> On Fri, 2014-09-19 at 17:37 +0200, Richard Weinberger wrote: > The while loop in produce_free_peb() assumes that each work will produce a > free PEB. This is not true. > If ubi->works_count is 1 and the only scheduled work is the > wear_leveling_worker() produce_free_peb() can loop forever in case > nobody schedules an erase work. > Fix this issue by checking in the while loop whether work is scheduled. > > Signed-off-by: Richard Weinberger Pushed, thanks! -- Best Regards, Artem Bityutskiy From bpqw at micron.com Wed Sep 24 23:20:35 2014 From: bpqw at micron.com (bpqw) Date: Thu, 25 Sep 2014 06:20:35 +0000 Subject: [PATCH 1/1] driver:mtd:spi-nor: Add Micron quad I/O support Message-ID: For Micron spi norflash,you can enable Quad spi transfer by clear EVCR(Enhanced Volatile Configuration Register) Quad I/O protocol bit. Signed-off-by: bean huo --- drivers/mtd/spi-nor/spi-nor.c | 45 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 6 ++++++ 2 files changed, 51 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..e72894f 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -878,6 +878,44 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int micron_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return -EINVAL; + } + + write_enable(nor); + + /* set EVCR ,enable quad I/O */ + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); + if (ret < 0) { + dev_err(nor->dev, + "error while writing EVCR register\n"); + return -EINVAL; + } + + if (wait_till_ready(nor)) + return 1; + + /* read EVCR and check it */ + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return -EINVAL; + } + if (val & EVCR_QUAD_EN_MICRON) { + dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + return -EINVAL; + } + + return 0; +} + static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) { int status; @@ -890,6 +928,13 @@ static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) return -EINVAL; } return status; + case CFI_MFR_ST: + status = micron_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Micron quad-read not enabled\n"); + return -EINVAL; + } + return status; default: status = spansion_quad_enable(nor); if (status) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..d71b659 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -56,6 +56,10 @@ /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ +/* Used for Micron flashes only. */ +#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ +#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ + /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ @@ -67,6 +71,8 @@ #define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ +#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */ + /* Flag Status Register bits */ #define FSR_READY 0x80 -- 1.7.9.5 From marex at denx.de Thu Sep 25 03:11:57 2014 From: marex at denx.de (Marek Vasut) Date: Thu, 25 Sep 2014 12:11:57 +0200 Subject: [PATCH 1/1] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: References: Message-ID: <201409251211.57183.marex@denx.de> On Thursday, September 25, 2014 at 08:20:35 AM, bpqw wrote: > For Micron spi norflash,you can enable Quad spi transfer > by clear EVCR(Enhanced Volatile Configuration Register) > Quad I/O protocol bit. > > Signed-off-by: bean huo > --- > drivers/mtd/spi-nor/spi-nor.c | 45 > +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | > 6 ++++++ > 2 files changed, 51 insertions(+) > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index b5ad6be..e72894f 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -878,6 +878,44 @@ static int spansion_quad_enable(struct spi_nor *nor) > return 0; > } > > +static int micron_quad_enable(struct spi_nor *nor) > +{ > + int ret, val; > + > + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); > + if (ret < 0) { > + dev_err(nor->dev, "error %d reading EVCR\n", ret); > + return -EINVAL; > + } > + > + write_enable(nor); > + > + /* set EVCR ,enable quad I/O */ > + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; > + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); > + if (ret < 0) { > + dev_err(nor->dev, > + "error while writing EVCR register\n"); > + return -EINVAL; > + } > + > + if (wait_till_ready(nor)) > + return 1; Why does this not return proper error code or even better, return value from wait_till_ready() ? Other than that, there's nothing wrong with the patch I think. Best regards, Marek Vasut From asierra at xes-inc.com Thu Sep 25 10:20:08 2014 From: asierra at xes-inc.com (Aaron Sierra) Date: Thu, 25 Sep 2014 12:20:08 -0500 (CDT) Subject: [PATCH 1/2] mtd: physmap_of: Add read-only fallback In-Reply-To: <103889901.65008.1411665422229.JavaMail.zimbra@xes-inc.com> Message-ID: <2002674283.65675.1411665608272.JavaMail.zimbra@xes-inc.com> From: Joe Schultz Previously, when probing a CFI chip which was write-protected at the hardware level, the probe would fail due to the fact it could not put the chip into QUERY mode. This would result in no MTD devices being created. Add a fallback to probe using the map_rom driver if the user-selected probe fails. Signed-off-by: Joe Schultz Signed-off-by: Aaron Sierra --- drivers/mtd/maps/physmap_of.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index c62e1c3..efbf416 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -272,6 +272,16 @@ static int of_flash_probe(struct platform_device *dev) info->list[i].mtd = obsolete_probe(dev, &info->list[i].map); } + + /* Fall back to mapping region as ROM */ + if (!info->list[i].mtd) { + dev_warn(&dev->dev, + "do_map_probe() failed for type %s\n", + probe_type); + + info->list[i].mtd = do_map_probe("map_rom", + &info->list[i].map); + } mtd_list[i] = info->list[i].mtd; err = -ENXIO; -- 1.9.1 From asierra at xes-inc.com Thu Sep 25 10:20:24 2014 From: asierra at xes-inc.com (Aaron Sierra) Date: Thu, 25 Sep 2014 12:20:24 -0500 (CDT) Subject: [PATCH 2/2] mtd: map_rom: Support UBI on ROM In-Reply-To: <1683475520.65208.1411665491176.JavaMail.zimbra@xes-inc.com> Message-ID: <673100209.65720.1411665624206.JavaMail.zimbra@xes-inc.com> UBI needs to know the physical erase block size, even on read-only devices, since it defines the on-device layout. Use a device-tree provided value to support previously written UBI on read-only NOR. UBI also needs a non-zero writebufsize, so we set it to one. Note: This was implemented because hardware write-protected CFI NOR cannot be probed for the physical erase block size. Signed-off-by: Joe Schultz Signed-off-by: Aaron Sierra --- Documentation/devicetree/bindings/mtd/mtd-physmap.txt | 5 +++++ drivers/mtd/chips/map_rom.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 6b9f680..8ab16df 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -36,6 +36,11 @@ are defined: - vendor-id : Contains the flash chip's vendor id (1 byte). - device-id : Contains the flash chip's device id (1 byte). +For ROM compatible devices (and ROM fallback from cfi-flash), the following +additional property is defined: + + - erase-size : The chip's physical erase block size in bytes. + The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c index 47a43cf..a831265 100644 --- a/drivers/mtd/chips/map_rom.c +++ b/drivers/mtd/chips/map_rom.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,15 @@ static struct mtd_chip_driver maprom_chipdrv = { .module = THIS_MODULE }; +static unsigned int default_erasesize(struct map_info *map) +{ + const __be32 *erase_size = NULL; +#ifdef CONFIG_OF + erase_size = of_get_property(map->device_node, "erase-size", NULL); +#endif + return !erase_size ? map->size : be32_to_cpu(*erase_size); +} + static struct mtd_info *map_rom_probe(struct map_info *map) { struct mtd_info *mtd; @@ -47,8 +57,9 @@ static struct mtd_info *map_rom_probe(struct map_info *map) mtd->_sync = maprom_nop; mtd->_erase = maprom_erase; mtd->flags = MTD_CAP_ROM; - mtd->erasesize = map->size; + mtd->erasesize = default_erasesize(map); mtd->writesize = 1; + mtd->writebufsize = 1; __module_get(THIS_MODULE); return mtd; -- 1.9.1 From rams.rsu at gmail.com Thu Sep 25 10:51:37 2014 From: rams.rsu at gmail.com (Rams Subramanian) Date: Thu, 25 Sep 2014 19:51:37 +0200 Subject: NOR Flash regions mapped to non contiguous physical memory Message-ID: Hi, We have a special case where the chip selects for external memory interface has the addressing range of 32MB per chip select. We have interfaced 128MB NOR flash and our addressable regions are non-contiguous. E.g Flash Map * CS0 : 0x30000000 - 0x32000000 : (32MB) * CS1 : 0x34000000 - 0x36000000 : (32MB) * CS2 : 0x38000000 - 0x3A000000 : (32MB) * CS3 : 0x3C000000 - 0x3E000000 : (32MB) We tried to define mtd map to force it to detect 4 physical chips so that mtdconcat can handle the rest. But mtdconcat does not work well for this case as we dont have 4 physical chips. The mtd driver does parallel accesses assuming 4 physical chips. So we could not have flash file system spanning over 4 regions. It is fine to work with single region at a time. What we actually want is to define a flash which has 4 non contiguous regions. Can this be done with existing mtd drivers? Is that possible to get contiguous virtual memory from non contiguous physical memory? Thanks in advance Rams From marex at denx.de Thu Sep 25 10:09:41 2014 From: marex at denx.de (Marek Vasut) Date: Thu, 25 Sep 2014 19:09:41 +0200 Subject: [PATCH] spi-nor: Fix for Freescale i.MX6 reboot issue when using a N25Q00A boot device. In-Reply-To: References: Message-ID: <201409251909.41740.marex@denx.de> On Saturday, August 16, 2014 at 08:14:05 PM, Jeremy Garff wrote: > This is my first submission to the linux-mtd list. I found Found yes > and fixed Fixed no ;-) > a issue related to the i.MX6 when using a N25Q00A spi-nor as the boot > device. The following is a patch and more detailed description. As > this is my first submission to this list, so please let me know you > have any questions or concerns. Well, the problem is that the SPI NOR ends in undefined state when you reset the board. The problem is not in Linux, the problem is in your board. You should use the RESET-OUTPUT pin of your MX6 to implement proper reset sequencing for the SPI NOR. This patch would not work in case you were doing a PageProgram operation and I came around and mashed the 'reset' button on your board. The SPI NOR would be somewhere in the middle of the PP and your MX6 would simply not boot. So the solution here is to fix your hardware ;-) btw this is a common issue, we should really document this before more people get hurt. btw2 Spansion does much better job, their SPI NORs have RESET pin, so you don't need to implement logic to power cycle the SPI NOR. Best regards, Marek Vasut From robert.jarzmik at free.fr Thu Sep 25 15:33:16 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Fri, 26 Sep 2014 00:33:16 +0200 Subject: [PATCH v1 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> References: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> Message-ID: <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> Add documentation for the sandisk docg3 chip. Signed-off-by: Robert Jarzmik Cc: devicetree at vger.kernel.org --- Documentation/devicetree/bindings/mtd/docg3.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/docg3.txt diff --git a/Documentation/devicetree/bindings/mtd/docg3.txt b/Documentation/devicetree/bindings/mtd/docg3.txt new file mode 100644 index 0000000..3fcc163 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/docg3.txt @@ -0,0 +1,14 @@ +Sandisk docg3 device +==================== + +The Sandisk (former MSystems) docg3 is a nand device of 64M to 256MB. + +Required properties: + - compatible: Should be "sandisk,docg3" + - reg: register base and size + +Example: + docg3 { + compatible = "sandisk,docg3"; + reg = <0x0 0x2000>; + }; -- 2.0.0.rc2 From robert.jarzmik at free.fr Thu Sep 25 15:33:15 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Fri, 26 Sep 2014 00:33:15 +0200 Subject: [PATCH v1 1/2] mtd: docg3: add device-tree support Message-ID: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> Add device-tree support. This is straightforward as docg3 only uses the standard IOMEM resources. Signed-off-by: Robert Jarzmik Cc: devicetree at vger.kernel.org --- drivers/mtd/devices/docg3.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 91a169c..fc05f81 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -2126,10 +2127,17 @@ static int __exit docg3_release(struct platform_device *pdev) return 0; } +static struct of_device_id docg3_dt_ids[] = { + { .compatible = "sandisk,docg3" }, + {} +}; +MODULE_DEVICE_TABLE(of, docg3_dt_ids); + static struct platform_driver g3_driver = { .driver = { .name = "docg3", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(docg3_dt_ids), }, .suspend = docg3_suspend, .resume = docg3_resume, -- 2.0.0.rc2 From bpqw at micron.com Fri Sep 26 01:39:38 2014 From: bpqw at micron.com (bpqw) Date: Fri, 26 Sep 2014 08:39:38 +0000 Subject: [PATCH 1/1] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: <201409251211.57183.marex@denx.de> References: <201409251211.57183.marex@denx.de> Message-ID: >> + /* set EVCR ,enable quad I/O */ >> + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; >> + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); >> + if (ret < 0) { >> + dev_err(nor->dev, >> + "error while writing EVCR register\n"); >> + return -EINVAL; >> + } >> + >> + if (wait_till_ready(nor)) >> + return 1; >Why does this not return proper error code or even better, return value from >wait_till_ready() ? > >Other than that, there's nothing wrong with the patch I think. Hi,Marek Thanks for your review,you can find the same usage in the spi-nor.c. Below method is OK? Or you can give me some suggestion. if (wait_till_ready(nor)) return - EINVAL; From marex at denx.de Fri Sep 26 01:46:07 2014 From: marex at denx.de (Marek Vasut) Date: Fri, 26 Sep 2014 10:46:07 +0200 Subject: [PATCH 1/1] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: References: <201409251211.57183.marex@denx.de> Message-ID: <201409261046.07132.marex@denx.de> On Friday, September 26, 2014 at 10:39:38 AM, bpqw wrote: > >> + /* set EVCR ,enable quad I/O */ > >> + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; > >> + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); > >> + if (ret < 0) { > >> + dev_err(nor->dev, > >> + "error while writing EVCR register\n"); > >> + return -EINVAL; > >> + } > >> + > >> + if (wait_till_ready(nor)) > >> + return 1; > > > >Why does this not return proper error code or even better, return value > >from wait_till_ready() ? > > > >Other than that, there's nothing wrong with the patch I think. > > Hi,Marek > Thanks for your review,you can find the same usage in the spi-nor.c. > Below method is OK? Or you can give me some suggestion. > > if (wait_till_ready(nor)) > return - EINVAL; ret = wait_till_readynor() if (ret) return ret; But all right, this means the subsystem isn't perfect. Well, others, what do you think ? Best regards, Marek Vasut From dedekind1 at gmail.com Fri Sep 26 03:24:35 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:24:35 +0300 Subject: [PATCH 1/4] ubi-utils: ubidump compile enable In-Reply-To: <541D0AA1.60006@huawei.com> References: <541D09C9.4080004@huawei.com> <541D0AA1.60006@huawei.com> Message-ID: <1411727075.23429.50.camel@sauron.fi.intel.com> On Sat, 2014-09-20 at 13:03 +0800, hujianyang wrote: > Signed-off-by: hujianyang > --- > Makefile | 7 +++++-- > 1 files changed, 5 insertions(+), 2 deletions(-) Could you please make it to be the last patch in the series. This will make sure the tree compilation does not break when you are in the middle of the series. Thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:28:31 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:28:31 +0300 Subject: [PATCH 2/4] ubi-utils: ubidump add libdump In-Reply-To: <541D0B12.9050703@huawei.com> References: <541D09C9.4080004@huawei.com> <541D0B12.9050703@huawei.com> Message-ID: <1411727311.23429.54.camel@sauron.fi.intel.com> On Sat, 2014-09-20 at 13:05 +0800, hujianyang wrote: > Signed-off-by: hujianyang > --- > ubi-utils/include/libdump.h | 72 ++++++++ > ubi-utils/libdump.c | 414 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 486 insertions(+), 0 deletions(-) > create mode 100644 ubi-utils/include/libdump.h > create mode 100644 ubi-utils/libdump.c > > diff --git a/ubi-utils/include/libdump.h b/ubi-utils/include/libdump.h > new file mode 100644 > index 0000000..ee0ff77 > --- /dev/null > +++ b/ubi-utils/include/libdump.h > @@ -0,0 +1,72 @@ > +/* > + * Copyright (c) International Business Machines Corp., 2006 > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > + * the GNU General Public License for more details. > + * > + * Author: Hu Jianyang If you did not write this code, you should not add yourself as author. Instead, please, preserve the kernel header comment as it is. If you mad significant changes, you may add a comment about this with the attribution to yourself. > + * > + * UBIFS library. > + */ Am I right that this is almost an exact copy of the kernel header (after 'make headersinstall')? If yes, please, add a comment telling this here, just to make sure the reader knows that he/she is dealing with a copy, and the original is in the kernel. > +/* > + * Copyright (c) International Business Machines Corp., 2006 > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > + * the GNU General Public License for more details. > + * > + * Author: Hu Jianyang > + * > + * UBIFS library. > + */ And the same requests apply here. Thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:29:22 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:29:22 +0300 Subject: [PATCH 3/4] ubi-utils: ubidump add ubifs-media In-Reply-To: <541D0B5C.2080802@huawei.com> References: <541D09C9.4080004@huawei.com> <541D0B5C.2080802@huawei.com> Message-ID: <1411727362.23429.55.camel@sauron.fi.intel.com> On Sat, 2014-09-20 at 13:06 +0800, hujianyang wrote: > +/* > + * Copyright (c) International Business Machines Corp., 2006 > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > + * the GNU General Public License for more details. > + * > + * Author: Hu Jianyang > + * > + * UBIFS library. > + */ And the same comments as in the "2/4" patch apply here. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:31:50 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:31:50 +0300 Subject: [PATCH 4/4] ubi-utils: introduce ubidump In-Reply-To: <541D0BD2.9080908@huawei.com> References: <541D09C9.4080004@huawei.com> <541D0BD2.9080908@huawei.com> Message-ID: <1411727510.23429.58.camel@sauron.fi.intel.com> On Sat, 2014-09-20 at 13:08 +0800, hujianyang wrote: > Signed-off-by: hujianyang > --- > ubi-utils/ubidump.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 217 insertions(+), 0 deletions(-) > create mode 100644 ubi-utils/ubidump.c > > diff --git a/ubi-utils/ubidump.c b/ubi-utils/ubidump.c > new file mode 100644 > index 0000000..d96d7fb > --- /dev/null > +++ b/ubi-utils/ubidump.c > @@ -0,0 +1,217 @@ > +/* > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See > + * the GNU General Public License for more details. > + */ > + > +/* > + * An utility to dump UBI/UBIFS format data in eraseblock > + * > + * Author: Hu Jianyang > + */ If what you did was you took and existing tool, and stripped it down, and add few things, you should preserve the original copyright. And you can also add your own copyright too, for the changes you made. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:36:05 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:36:05 +0300 Subject: [PATCH] UBIFS: Align the dump messages of SB_NODE In-Reply-To: <541D24CF.1040705@huawei.com> References: <541D24CF.1040705@huawei.com> Message-ID: <1411727765.23429.61.camel@sauron.fi.intel.com> On Sat, 2014-09-20 at 14:55 +0800, hujianyang wrote: > I found the dump messages of UBIFS_SB_NODE is not aligned. This > patch remove the extra space from the line which is retracted. > > > Signed-off-by: hujianyang This was not a typo, this was intentional. We first print the all flags in a hex format, and then we "decode" it and print the values of the individual flags with an additional indent. The indent is to make it clear that these line belong to the flags, and they are not independent values. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:40:32 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:40:32 +0300 Subject: [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1411375536-20067-3-git-send-email-richard@nod.at> References: <1411375536-20067-1-git-send-email-richard@nod.at> <1411375536-20067-3-git-send-email-richard@nod.at> Message-ID: <1411728032.23429.63.camel@sauron.fi.intel.com> On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote: > If sync_erase() fails with EINTR, ENOMEM, EAGAIN or > EBUSY erase_worker() re-schedules the failed work. > This will lead to a deadlock because erase_worker() is called > with work_sem held in read mode. And schedule_erase() will take > this lock again. > > Signed-off-by: Richard Weinberger Did you manage to test it? Why no -stable this time? Not that important, or just something theoretical and you never actually hit this bug? Thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Fri Sep 26 03:46:08 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Fri, 26 Sep 2014 13:46:08 +0300 Subject: [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment In-Reply-To: <1411375536-20067-1-git-send-email-richard@nod.at> References: <1411375536-20067-1-git-send-email-richard@nod.at> Message-ID: <1411728368.23429.64.camel@sauron.fi.intel.com> On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote: > There is no need to set err, it will be overwritten in any case > later at: > if (scrub) > err = ubi_wl_scrub_peb(ubi, pnum); > > Signed-off-by: Richard Weinberger Pushed the first 2 patches, thanks! -- Best Regards, Artem Bityutskiy From mark.rutland at arm.com Fri Sep 26 04:05:47 2014 From: mark.rutland at arm.com (Mark Rutland) Date: Fri, 26 Sep 2014 12:05:47 +0100 Subject: [PATCH v1 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> References: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> Message-ID: <20140926110546.GA7422@leverpostej> On Thu, Sep 25, 2014 at 11:33:16PM +0100, Robert Jarzmik wrote: > Add documentation for the sandisk docg3 chip. > > Signed-off-by: Robert Jarzmik > Cc: devicetree at vger.kernel.org > --- > Documentation/devicetree/bindings/mtd/docg3.txt | 14 ++++++++++++++ > 1 file changed, 14 insertions(+) > create mode 100644 Documentation/devicetree/bindings/mtd/docg3.txt > > diff --git a/Documentation/devicetree/bindings/mtd/docg3.txt b/Documentation/devicetree/bindings/mtd/docg3.txt > new file mode 100644 > index 0000000..3fcc163 > --- /dev/null > +++ b/Documentation/devicetree/bindings/mtd/docg3.txt > @@ -0,0 +1,14 @@ > +Sandisk docg3 device > +==================== > + > +The Sandisk (former MSystems) docg3 is a nand device of 64M to 256MB. I think that should be: "(formerly M-Systems)". I'd rather we used the full name (DiskOnChip G3), as "docg3" is a Linux-specific abbreviation. So I think the compatible string should be something like "sandisk,diskonchip-g3". Arguably we should have M-Systems as the vendor. Are we able to detect the particular variant by reading registers on the device? Are there any differences that we can probe dynamically (even if we don't care about those at the moment)? > + > +Required properties: > + - compatible: Should be "sandisk,docg3" > + - reg: register base and size > + > +Example: > + docg3 { > + compatible = "sandisk,docg3"; > + reg = <0x0 0x2000>; There should be a unit-address on the node to match the address in the first reg entry. Mark. From robert.jarzmik at free.fr Fri Sep 26 10:19:49 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Fri, 26 Sep 2014 19:19:49 +0200 Subject: [PATCH v1 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <20140926110546.GA7422@leverpostej> (Mark Rutland's message of "Fri, 26 Sep 2014 12:05:47 +0100") References: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> <20140926110546.GA7422@leverpostej> Message-ID: <87h9zupadm.fsf@free.fr> Mark Rutland writes: >> +The Sandisk (former MSystems) docg3 is a nand device of 64M to 256MB. > > I think that should be: "(formerly M-Systems)". Right. > I'd rather we used the full name (DiskOnChip G3), as "docg3" is a > Linux-specific abbreviation. So I think the compatible string should be > something like "sandisk,diskonchip-g3". Arguably we should have > M-Systems as the vendor. "sandisk,diskonchip-g3" : full ack, for v2 For M-Systems, it's as you wish. Just so that you have the broad view, this is my understanding of M-Systems / Sandisk : - M-Systems creates several diskonchip chips, especially docg3 - M-Systems is bought and absorbed by Sandisk - Sandisk creates and ships other diskonchip, under sandisk brand Now I'll put in the compat whatever you advice for, I have no opinion on that. I'm telling you this because I have another patch to submit for a camera sensor made by Aptina. Aptina was absorbed by Micron, and the sensor was released under Aptina/Micron brand (ie. Aptina team in Micron corp. if I understood correctly). Therefore, I'll take your advice for both sandisk/msystems and aptina/micron :) > Are we able to detect the particular variant by reading registers on the > device? Are there any differences that we can probe dynamically (even if > we don't care about those at the moment)? Yes, what defines a docg3 is : - a device mapped at address 0 - a read of the chip id gives DOC_CHIPID_G3 But there is a catch : the read is not a simple memory read, it's a write to a register to set the "register to read", then a read in the iospace. Doing this implies you know you are in the iospace of a docg3 ... > >> + >> +Required properties: >> + - compatible: Should be "sandisk,docg3" >> + - reg: register base and size >> + >> +Example: >> + docg3 { >> + compatible = "sandisk,docg3"; >> + reg = <0x0 0x2000>; > > There should be a unit-address on the node to match the address in the > first reg entry. You mean "#address-cells = <1>;", right ? Cheers. -- Robert From mark.rutland at arm.com Fri Sep 26 10:50:13 2014 From: mark.rutland at arm.com (Mark Rutland) Date: Fri, 26 Sep 2014 18:50:13 +0100 Subject: [PATCH v1 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <87h9zupadm.fsf@free.fr> References: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> <20140926110546.GA7422@leverpostej> <87h9zupadm.fsf@free.fr> Message-ID: <20140926175013.GL7422@leverpostej> On Fri, Sep 26, 2014 at 06:19:49PM +0100, Robert Jarzmik wrote: > Mark Rutland writes: > > >> +The Sandisk (former MSystems) docg3 is a nand device of 64M to 256MB. > > > > I think that should be: "(formerly M-Systems)". > Right. > > > I'd rather we used the full name (DiskOnChip G3), as "docg3" is a > > Linux-specific abbreviation. So I think the compatible string should be > > something like "sandisk,diskonchip-g3". Arguably we should have > > M-Systems as the vendor. > "sandisk,diskonchip-g3" : full ack, for v2 ok. > For M-Systems, it's as you wish. Just so that you have the broad view, this is > my understanding of M-Systems / Sandisk : > - M-Systems creates several diskonchip chips, especially docg3 Ok, so I'd label those devices with an M-Systems vendor prefix ("m-systems", I guess, if we don't already have one). > - M-Systems is bought and absorbed by Sandisk For the devices sold during this time where nothing has changed other than the label, I'd keep the M-Systems vendor. > - Sandisk creates and ships other diskonchip, under sandisk brand These new devices I would label with a sandisk vendor-prefix. > Now I'll put in the compat whatever you advice for, I have no opinion on > that. I'm telling you this because I have another patch to submit for a camera > sensor made by Aptina. Aptina was absorbed by Micron, and the sensor was > released under Aptina/Micron brand (ie. Aptina team in Micron corp. if I > understood correctly). > > Therefore, I'll take your advice for both sandisk/msystems and aptina/micron :) I'd label something as the original brand it shipped under, unless there's a compelling reason not to. We can add notes in the binding documentation to make the bindings easier to find where a device has been labelled by different manufacturers. > > Are we able to detect the particular variant by reading registers on the > > device? Are there any differences that we can probe dynamically (even if > > we don't care about those at the moment)? > > Yes, what defines a docg3 is : > - a device mapped at address 0 > - a read of the chip id gives DOC_CHIPID_G3 > > But there is a catch : the read is not a simple memory read, it's a write to a > register to set the "register to read", then a read in the iospace. Doing this > implies you know you are in the iospace of a docg3 ... I was more concerned with the identifying information that we can acquire from the device than the precise sequence of steps that have to be performed to extract that information. You mention that the size of the flash is variable (it could be 64MB, 256MB, etc), but this isn't described in the binding. Therefore I assume there is some mechanism by which I can query this from the device? Are there other parameters that vary across instances? Even those for which we currently don't care? If so, can these be queried from the device? > > > >> + > >> +Required properties: > >> + - compatible: Should be "sandisk,docg3" > >> + - reg: register base and size > >> + > >> +Example: > >> + docg3 { > >> + compatible = "sandisk,docg3"; > >> + reg = <0x0 0x2000>; > > > > There should be a unit-address on the node to match the address in the > > first reg entry. > You mean "#address-cells = <1>;", right ? No, the unit-address is the bit after the '@' on the node name. I'm asking for: docg3: flash at 0 { ... reg = <0x0 0x2000>; ... }; Thanks, Mark. From robert.jarzmik at free.fr Fri Sep 26 11:12:03 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Fri, 26 Sep 2014 20:12:03 +0200 Subject: [PATCH v1 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <20140926175013.GL7422@leverpostej> (Mark Rutland's message of "Fri, 26 Sep 2014 18:50:13 +0100") References: <1411684396-12094-1-git-send-email-robert.jarzmik@free.fr> <1411684396-12094-2-git-send-email-robert.jarzmik@free.fr> <20140926110546.GA7422@leverpostej> <87h9zupadm.fsf@free.fr> <20140926175013.GL7422@leverpostej> Message-ID: <87d2aip7yk.fsf@free.fr> Mark Rutland writes: > Ok, so I'd label those devices with an M-Systems vendor prefix > ("m-systems", I guess, if we don't already have one). OK. We don't have it, so I'll add that patch for review too (I have submitted one for sandisk, should have been m-systems ...) > >> - M-Systems is bought and absorbed by Sandisk > > For the devices sold during this time where nothing has changed other > than the label, I'd keep the M-Systems vendor. OK. > >> - Sandisk creates and ships other diskonchip, under sandisk brand > > These new devices I would label with a sandisk vendor-prefix. OK. > >> Now I'll put in the compat whatever you advice for, I have no opinion on >> that. I'm telling you this because I have another patch to submit for a camera >> sensor made by Aptina. Aptina was absorbed by Micron, and the sensor was >> released under Aptina/Micron brand (ie. Aptina team in Micron corp. if I >> understood correctly). >> >> Therefore, I'll take your advice for both sandisk/msystems and aptina/micron :) > > I'd label something as the original brand it shipped under, unless > there's a compelling reason not to. We can add notes in the binding > documentation to make the bindings easier to find where a device has > been labelled by different manufacturers. OK. > >> > Are we able to detect the particular variant by reading registers on the >> > device? Are there any differences that we can probe dynamically (even if >> > we don't care about those at the moment)? >> >> Yes, what defines a docg3 is : >> - a device mapped at address 0 >> - a read of the chip id gives DOC_CHIPID_G3 >> >> But there is a catch : the read is not a simple memory read, it's a write to a >> register to set the "register to read", then a read in the iospace. Doing this >> implies you know you are in the iospace of a docg3 ... > > I was more concerned with the identifying information that we can > acquire from the device than the precise sequence of steps that have to > be performed to extract that information. > > You mention that the size of the flash is variable (it could be 64MB, > 256MB, etc), but this isn't described in the binding. Therefore I assume > there is some mechanism by which I can query this from the device? Ah you know what, you made me understand something in here. As there is no spec of this device, I had created the driver by observing its behaviour under another OS on a single chip, a 512 Mbits (ie. 64MBi) one. I had assumed that the identification string, "0x200" (ie. DOC_CHIPID_G3) was the identifier of a G3 chip. But you opened my eyes in here : it's the size of the docg3 ! So your answer is : - a docg3 cannot be identified (from another diskonchip) - the variant of the docg3, ie. its size, can be identified (even if that doesn't change anything from a device-tree perspective). It's just something the driver should take into account. - I'm not aware of any other kind of variations nor any way to query them > Are there other parameters that vary across instances? Even those for > which we currently don't care? If so, can these be queried from the > device? Ah, no spec, no answer I'm afraid. There might be variations in the ECC algorith, block size, etc ... but still no spec. I'm pretty sure the device has an interrupt line, and a requestor line for a DMA most probably. No clue but heavy presomptions. > No, the unit-address is the bit after the '@' on the node name. I'm > asking for: > > docg3: flash at 0 { > ... > reg = <0x0 0x2000>; > ... > }; Ah ok, I'll put that in v2. Cheers. -- Robert From boris.brezillon at free-electrons.com Fri Sep 26 12:03:08 2014 From: boris.brezillon at free-electrons.com (Boris BREZILLON) Date: Fri, 26 Sep 2014 21:03:08 +0200 Subject: [PATCH v4 0/2] mtd: nand: add sunxi NAND flash controller support In-Reply-To: <9855a145-713d-4481-9c4e-94b30dd39a3c@googlegroups.com> References: <1408382788-32153-1-git-send-email-boris.brezillon@free-electrons.com> <9855a145-713d-4481-9c4e-94b30dd39a3c@googlegroups.com> Message-ID: <20140926210308.716c019b@bbrezillon> On Fri, 26 Sep 2014 11:11:18 -0700 (PDT) Ezaul Zillmer wrote: > Good afternoon everyone > > I've been doing some test patches Emilio L?pez > > dma: sun4i: Add support for the DMA engine on sun [457] i SoCs > spi: sun4i: add DMA support > ARM: sun7i: Add node to Represent the DMA controller > ARM: sun7i: enable DMA on SPI > > But Patches Boris BREZILLON > Add the sunxi NAND Flash Controller V5 > > Result I have is this: > > Image Name: Linux-3.16.0-rc6 > > [ 0.000000] Booting Linux on physical CPU 0x0 > [ 0.000000] Linux version 3.16.0-rc6-g40a77a5-dirty (root at vbi7) (gcc > version 4.7.2 (Debian 4.7.2-5) ) #3 SMP Fri Sep 26 11:56:35 BRT 2014 > [ 0.000000] CPU: ARMv7 Processor [410fc074] revision 4 (ARMv7), > cr=30c5387d > [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing > instruction cache > [ 0.000000] Machine model: Cubietech Cubieboard2 > [ 0.000000] Forcing write-allocate cache policy for SMP > [ 0.000000] Memory policy: Data cache writealloc > [ 0.000000] psci: probing for conduit method from DT. > [ 0.000000] psci: Using PSCI v0.1 Function IDs from DT > [ 0.000000] PERCPU: Embedded 7 pages/cpu @eefd0000 s7936 r8192 d12544 > u32768 > [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. > Total pages: 260624 > [ 0.000000] Kernel command line: console=tty0 console=ttyS0,115200 > hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1280x800p60 > root=/dev/mmcblk0p1 rootfstype=ext4 0 > [ 0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes) > [ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 > bytes) > [ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 > bytes) > [ 0.000000] Memory: 1026836K/1048576K available (8121K kernel code, 779K > rwdata, 2716K rodata, 595K init, 321K bss, 21740K reserved, 270336K highmem) > [ 0.000000] Virtual kernel memory layout: > [ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB) > [ 0.000000] fixmap : 0xffc00000 - 0xffe00000 (2048 kB) > [ 0.000000] vmalloc : 0xf0000000 - 0xff000000 ( 240 MB) > [ 0.000000] lowmem : 0xc0000000 - 0xef800000 ( 760 MB) > [ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB) > [ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB) > [ 0.000000] .text : 0xc0008000 - 0xc0a9d7c0 (10838 kB) > [ 0.000000] .init : 0xc0a9e000 - 0xc0b32f00 ( 596 kB) > [ 0.000000] .data : 0xc0b34000 - 0xc0bf6c48 ( 780 kB) > [ 0.000000] .bss : 0xc0bf6c50 - 0xc0c47070 ( 322 kB) > [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1 > [ 0.000000] Hierarchical RCU implementation. > [ 0.000000] RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=2. > [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2 > [ 0.000000] NR_IRQS:16 nr_irqs:16 16 > [ 0.000000] Architected cp15 timer(s) running at 24.00MHz (phys). > [ 0.000007] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every > 2863311519744ns > [ 0.000014] Switching to timer-based delay loop > [ 0.001052] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every > 178956969942ns > [ 0.001378] sched_clock: 32 bits at 160MHz, resolution 6ns, wraps every > 26843545593ns > [ 0.001587] Console: colour dummy device 80x30 > [ 0.002002] console [tty0] enabled > [ 0.002035] Calibrating delay loop (skipped), value calculated using > timer frequency.. 48.00 BogoMIPS (lpj=240000) > [ 0.002063] pid_max: default: 32768 minimum: 301 > [ 0.002197] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes) > [ 0.002220] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 > bytes) > [ 0.002811] CPU: Testing write buffer coherency: ok > [ 0.003090] /cpus/cpu at 0 missing clock-frequency property > [ 0.003119] /cpus/cpu at 1 missing clock-frequency property > [ 0.003140] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000 > [ 0.003311] Setting up static identity map for 0x407b1ec0 - 0x407b1f58 > [ 0.005296] CPU1: Booted secondary processor > [ 0.005341] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001 > [ 0.005426] Brought up 2 CPUs > [ 0.005476] SMP: Total of 2 processors activated. > [ 0.005490] CPU: All CPU(s) started in HYP mode. > [ 0.005501] CPU: Virtualization extensions available. > [ 0.006172] devtmpfs: initialized > [ 0.010413] VFP support v0.3: implementor 41 architecture 2 part 30 > variant 7 rev 4 > [ 0.010862] pinctrl core: initialized pinctrl subsystem > [ 0.011360] regulator-dummy: no parameters > [ 0.017149] NET: Registered protocol family 16 > [ 0.017683] DMA: preallocated 256 KiB pool for atomic coherent > allocations > [ 0.026000] Serial: AMBA PL011 UART driver > [ 0.039029] edma-dma-engine edma-dma-engine.0: Can't allocate PaRAM > dummy slot > [ 0.039082] edma-dma-engine: probe of edma-dma-engine.0 failed with > error -5 > [ 0.039546] reg-fixed-voltage ahci-5v: could not find pctldev for node > /soc at 01c00000/pinctrl at 01c20800/ahci_pwr_pin at 0, deferring probe > [ 0.039585] platform ahci-5v: Driver reg-fixed-voltage requests probe > deferral > [ 0.039621] reg-fixed-voltage usb1-vbus: could not find pctldev for node > /soc at 01c00000/pinctrl at 01c20800/usb1_vbus_pin at 0, deferring probe > [ 0.039650] platform usb1-vbus: Driver reg-fixed-voltage requests probe > deferral > [ 0.039681] reg-fixed-voltage usb2-vbus: could not find pctldev for node > /soc at 01c00000/pinctrl at 01c20800/usb2_vbus_pin at 0, deferring probe > [ 0.039710] platform usb2-vbus: Driver reg-fixed-voltage requests probe > deferral > [ 0.039899] vcc3v0: 3000 mV > [ 0.040216] vcc3v3: 3300 mV > [ 0.041627] SCSI subsystem initialized > [ 0.042259] usbcore: registered new interface driver usbfs > [ 0.042343] usbcore: registered new interface driver hub > [ 0.042466] usbcore: registered new device driver usb > [ 0.043205] pps_core: LinuxPPS API ver. 1 registered > [ 0.043225] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo > Giometti > [ 0.043268] PTP clock support registered > [ 0.043360] EDAC MC: Ver: 3.0.0 > [ 0.044601] Bluetooth: Core ver 2.19 > [ 0.044676] NET: Registered protocol family 31 > [ 0.044691] Bluetooth: HCI device and connection manager initialized > [ 0.044718] Bluetooth: HCI socket layer initialized > [ 0.044737] Bluetooth: L2CAP socket layer initialized > [ 0.044773] Bluetooth: SCO socket layer initialized > [ 0.045283] Switched to clocksource arch_sys_counter > [ 0.045659] FS-Cache: Loaded > [ 0.055161] NET: Registered protocol family 2 > [ 0.055906] TCP established hash table entries: 8192 (order: 3, 32768 > bytes) > [ 0.056001] TCP bind hash table entries: 8192 (order: 4, 65536 bytes) > [ 0.056130] TCP: Hash tables configured (established 8192 bind 8192) > [ 0.056214] TCP: reno registered > [ 0.056236] UDP hash table entries: 512 (order: 2, 16384 bytes) > [ 0.056296] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes) > [ 0.056557] NET: Registered protocol family 1 > [ 0.056921] RPC: Registered named UNIX socket transport module. > [ 0.056951] RPC: Registered udp transport module. > [ 0.056965] RPC: Registered tcp transport module. > [ 0.056978] RPC: Registered tcp NFSv4.1 backchannel transport module. > [ 0.057745] kvm [1]: Using HYP init bounce page @6e1ef000 > [ 0.058071] kvm [1]: interrupt-controller at 1c84000 IRQ25 > [ 0.058278] kvm [1]: timer IRQ27 > [ 0.058317] kvm [1]: Hyp mode initialized successfully > [ 0.059885] futex hash table entries: 512 (order: 3, 32768 bytes) > [ 0.060498] HugeTLB registered 2 MB page size, pre-allocated 0 pages > [ 0.070185] VFS: Disk quotas dquot_6.5.2 > [ 0.070444] Dquot-cache hash table entries: 1024 (order 0, 4096 bytes) > [ 0.072364] FS-Cache: Netfs 'nfs' registered for caching > [ 0.072989] NFS: Registering the id_resolver key type > [ 0.073059] Key type id_resolver registered > [ 0.073075] Key type id_legacy registered > [ 0.073103] nfs4filelayout_init: NFSv4 File Layout Driver Registering... > [ 0.073135] Installing knfsd (copyright (C) 1996 okir at monad.swb.de). > [ 0.073686] FS-Cache: Netfs 'cifs' registered for caching > [ 0.074116] ntfs: driver 2.1.30 [Flags: R/W DEBUG]. > [ 0.074506] fuse init (API version 7.23) > [ 0.075114] msgmni has been set to 1477 > [ 0.076386] bounce: pool size: 64 pages > [ 0.076674] Block layer SCSI generic (bsg) driver version 0.4 loaded > (major 250) > [ 0.076708] io scheduler noop registered > [ 0.076727] io scheduler deadline registered > [ 0.076933] io scheduler cfq registered (default) > [ 0.077552] platform 1c13400.phy: Driver sun4i-usb-phy requests probe > deferral > [ 0.080305] sun7i-a20-pinctrl 1c20800.pinctrl: initialized sunXi PIO > driver > [ 0.080827] gpio-sch311xI/O address 0x002e already in use > [ 0.080850] gpio-sch311xI/O address 0x004e already in use > [ 0.080865] gpio-sch311xI/O address 0x162e already in use > [ 0.080879] gpio-sch311xI/O address 0x164e already in use > [ 0.082490] ipmi message handler version 39.2 > [ 0.082543] ipmi device interface > [ 0.082701] IPMI System Interface driver. > [ 0.082749] ipmi_si: Unable to find any System Interface(s) > [ 0.082782] IPMI Watchdog: driver initialized > [ 0.082804] Copyright (C) 2004 MontaVista Software - IPMI Powerdown via > sys_reboot. > [ 0.090613] xenfs: not registering filesystem on non-xen platform > [ 0.147908] Serial: 8250/16550 driver, 8 ports, IRQ sharing disabled > [ 0.150995] console [ttyS0] disabled > [ 0.171179] 1c28000.serial: ttyS0 at MMIO 0x1c28000 (irq = 33, base_baud > = 1500000) is a U6_16550A > [ 0.968467] console [ttyS0] enabled > [ 0.972364] Serial: IMX driver > [ 0.976408] serial: Freescale lpuart driver > [ 0.981436] [drm] Initialized drm 1.1.0 20060810 > [ 0.996285] drbd: initialized. Version: 8.4.3 (api:1/proto:86-101) > [ 1.002491] drbd: built-in > [ 1.005199] drbd: registered as block device major 147 > [ 1.011934] platform 1c18000.sata: Driver ahci-sunxi requests probe > deferral > [ 1.019707] SSFDC read-only Flash Translation layer > [ 1.047215] nand: Could not find valid JEDEC parameter page; aborting > [ 1.053679] nand: device found, Manufacturer ID: 0xec, Chip ID: 0xd7 > [ 1.060066] nand: Samsung NAND 4GiB 3,3V 8-bit > [ 1.064513] nand: 4096MiB, MLC, page size: 8192, OOB size: 640 > [ 1.070444] sunxi_nand 1c03000.nand: failed to init nand chips > [ 1.076380] sunxi_nand: probe of 1c03000.nand failed with error -22 > > > What could I do to fix this error? > will be I did something wrong? First of all, what platform (board/SoC) are you testing on ? Can you paste your dts/dtsi files ? Can you add some traces in sunxi_nand_chip_init so that we can figure out where it fails ? Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From jer at jers.net Fri Sep 26 12:46:10 2014 From: jer at jers.net (Jeremy Garff) Date: Fri, 26 Sep 2014 13:46:10 -0600 Subject: [PATCH] spi-nor: Fix for Freescale i.MX6 reboot issue when using a N25Q00A boot device. In-Reply-To: <201409251909.41740.marex@denx.de> References: <201409251909.41740.marex@denx.de> Message-ID: On Thu, Sep 25, 2014 at 11:09 AM, Marek Vasut wrote: > On Saturday, August 16, 2014 at 08:14:05 PM, Jeremy Garff wrote: >> This is my first submission to the linux-mtd list. I found > > Found yes > >> and fixed > > Fixed no ;-) > >> a issue related to the i.MX6 when using a N25Q00A spi-nor as the boot >> device. The following is a patch and more detailed description. As >> this is my first submission to this list, so please let me know you >> have any questions or concerns. > > Well, the problem is that the SPI NOR ends in undefined state when you reset the > board. The problem is not in Linux, the problem is in your board. You should use > the RESET-OUTPUT pin of your MX6 to implement proper reset sequencing for the > SPI NOR. There is no reset pin on this particular SPI NOR device, therein lies the problem. http://www.micron.com/-/media/documents/products/data%20sheet/nor%20flash/serial%20nor/n25q/n25q_1gb_1_8v_65nm.pdf > > This patch would not work in case you were doing a PageProgram operation and I > came around and mashed the 'reset' button on your board. The SPI NOR would be > somewhere in the middle of the PP and your MX6 would simply not boot. > It's actually worse than this. _Any_ time the reset button is pushed after linux initializes the device, the system won't boot. Not just during a page program. Obviously this problem is outside the scope of my fix, but it does however fix the case where the user initiates the reboot. > So the solution here is to fix your hardware ;-) > Easier said than done. In many circumstances, hardware fixes like the one you suggest are outside the control of the developer and/or incur additional board and part costs. In my opinion, the real fix for this issue is in the Freescale boot ROM, which should do a soft reset of the SPI NOR prior to any reads. Unfortunately it doesn't do this, and can't be changed except by Freescale. > btw this is a common issue, we should really document this before more people > get hurt. > What you are effectively saying is that you simply can't and shouldn't use this part with a i.MX6. But why not implement the fix if the following are true? - It's as you say, a common issue. - A hardware fix may be outside the developers control or parts are fielded. - The fix simply puts the part in a consistent state on reboot/shutdown and seems reasonable. Thanks, Jeremy From josh at joshtriplett.org Fri Sep 26 16:17:27 2014 From: josh at joshtriplett.org (josh at joshtriplett.org) Date: Fri, 26 Sep 2014 16:17:27 -0700 Subject: [PATCH 1/1] jffs2: fix sparse warning: unexpected unlock In-Reply-To: <20140922181250.GN1193@ld-irv-0074> References: <1411065976-20386-1-git-send-email-fabf@skynet.be> <20140922181250.GN1193@ld-irv-0074> Message-ID: <20140926231727.GD20917@cloud> On Mon, Sep 22, 2014 at 11:12:50AM -0700, Brian Norris wrote: > + linux-sparse > > On Thu, Sep 18, 2014 at 08:46:16PM +0200, Fabian Frederick wrote: > > fs/jffs2/summary.c:846:5: warning: context imbalance in 'jffs2_sum_write_sumnode' - unexpected unlock > > > > Signed-off-by: Fabian Frederick > > --- > > fs/jffs2/summary.c | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c > > index c522d09..a0bac7b 100644 > > --- a/fs/jffs2/summary.c > > +++ b/fs/jffs2/summary.c > > @@ -844,6 +844,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock > > /* Write out summary information - called from jffs2_do_reserve_space */ > > > > int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) > > + __releases(&c->erase_completion_lock) > > + __acquires(&c->erase_completion_lock) > > I'm not too familiar with sparse notations, but Documentation/sparse.txt > suggests the above is wrong, and the following is more accurate: > > __must_hold(&c->erase_completion_lock) > > But it looks like there are several other examples which do this. > Anyway, here's the relevant doc text, in case someone wants to clarify > it for me, or else tell me the documentation is wrong: > > __must_hold - The specified lock is held on function entry and exit. > > __acquires - The specified lock is held on function exit, but not entry. > > __releases - The specified lock is held on function entry, but not exit. > > So __acquires and __releases look mutually exclusive, but it's not clear > if __must_hold will actually cover what we want. (I haven't tested it.) __must_hold is indeed the correct annotation. (There isn't currently anything enforcing that, though.) - Josh Triplett From marex at denx.de Fri Sep 26 16:42:10 2014 From: marex at denx.de (Marek Vasut) Date: Sat, 27 Sep 2014 01:42:10 +0200 Subject: [PATCH] spi-nor: Fix for Freescale i.MX6 reboot issue when using a N25Q00A boot device. In-Reply-To: References: <201409251909.41740.marex@denx.de> Message-ID: <201409270142.10226.marex@denx.de> On Friday, September 26, 2014 at 09:46:10 PM, Jeremy Garff wrote: [...] > > This patch would not work in case you were doing a PageProgram operation > > and I came around and mashed the 'reset' button on your board. The SPI > > NOR would be somewhere in the middle of the PP and your MX6 would simply > > not boot. > > It's actually worse than this. _Any_ time the reset button is pushed > after linux initializes the device, the system won't boot. Not just > during a page program. Obviously this problem is outside the scope of > my fix, but it does however fix the case where the user initiates the > reboot. That's just papering over bugs. > > So the solution here is to fix your hardware ;-) > > Easier said than done. In many circumstances, hardware fixes like the > one you suggest are outside the control of the developer and/or incur > additional board and part costs. Again, this doesn't justify papering over bugs. It's a plain and simple hardware bug. > In my opinion, the real fix for this issue is in the Freescale boot > ROM, which should do a soft reset of the SPI NOR prior to any reads. > Unfortunately it doesn't do this, and can't be changed except by > Freescale. In case the SPI NOR is completely stuck, the only way to bring it into defined state is to power-cycle it or toggle it's reset pin. Software reset would again be just a plaster as the SPI NOR might ignore it. > > btw this is a common issue, we should really document this before more > > people get hurt. > > What you are effectively saying is that you simply can't and shouldn't > use this part with a i.MX6. Does MX6 not have an Reset Out ? I recall it does have one. > But why not implement the fix if the > following are true? > > - It's as you say, a common issue. > - A hardware fix may be outside the developers control or parts are > fielded. - The fix simply puts the part in a consistent state on > reboot/shutdown and seems reasonable. Because this just hides the bug ; the real solution is to make hardware which has correct reset routing, the software in this case cannot solve the problem. Best regards, Marek Vasut From fabf at skynet.be Sat Sep 27 01:41:55 2014 From: fabf at skynet.be (Fabian Frederick) Date: Sat, 27 Sep 2014 10:41:55 +0200 (CEST) Subject: [PATCH 1/1] jffs2: fix sparse warning: unexpected unlock In-Reply-To: <20140926231727.GD20917@cloud> References: <1411065976-20386-1-git-send-email-fabf@skynet.be> <20140922181250.GN1193@ld-irv-0074> <20140926231727.GD20917@cloud> Message-ID: <1745266822.710655.1411807315752.open-xchange@webmail.nmp.skynet.be> > On 27 September 2014 at 01:17 josh at joshtriplett.org wrote: > > > On Mon, Sep 22, 2014 at 11:12:50AM -0700, Brian Norris wrote: > > + linux-sparse > > > > On Thu, Sep 18, 2014 at 08:46:16PM +0200, Fabian Frederick wrote: > > > fs/jffs2/summary.c:846:5: warning: context imbalance in > > > 'jffs2_sum_write_sumnode' - unexpected unlock > > > > > > Signed-off-by: Fabian Frederick > > > --- > > >? fs/jffs2/summary.c | 2 ++ > > >? 1 file changed, 2 insertions(+) > > > > > > diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c > > > index c522d09..a0bac7b 100644 > > > --- a/fs/jffs2/summary.c > > > +++ b/fs/jffs2/summary.c > > > @@ -844,6 +844,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info > > > *c, struct jffs2_eraseblock > > >? /* Write out summary information - called from jffs2_do_reserve_space */ > > >? > > >? int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) > > > + __releases(&c->erase_completion_lock) > > > + __acquires(&c->erase_completion_lock) > > > > I'm not too familiar with sparse notations, but Documentation/sparse.txt > > suggests the above is wrong, and the following is more accurate: > > > >? ? ?__must_hold(&c->erase_completion_lock) > > > > But it looks like there are several other examples which do this. > > Anyway, here's the relevant doc text, in case someone wants to clarify > > it for me, or else tell me the documentation is wrong: > > > >? ? ?__must_hold - The specified lock is held on function entry and exit. > > > >? ? ?__acquires - The specified lock is held on function exit, but not entry. > > > >? ? ?__releases - The specified lock is held on function entry, but not exit. > > > > So __acquires and __releases look mutually exclusive, but it's not clear > > if __must_hold will actually cover what we want. (I haven't tested it.) > > __must_hold is indeed the correct annotation.? (There isn't currently > anything enforcing that, though.) > > - Josh Triplett There are 137 __releases && __acquires annotated functions in stable. AFAICS those are based on lock held on function entry / lock held on exit See fs/fuse/file.c:1527 fs/kernfs/dir.c:341 drivers/block/nbd.c:564 Does it mean that all of these should be updated to __must_hold ? Fabian From robert.jarzmik at free.fr Sat Sep 27 12:34:29 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Sat, 27 Sep 2014 21:34:29 +0200 Subject: [PATCH v2 1/2] mtd: docg3: add device-tree support Message-ID: <1411846470-30041-1-git-send-email-robert.jarzmik@free.fr> Add device-tree support. This is straightforward as docg3 only uses the standard IOMEM resources. Signed-off-by: Robert Jarzmik Cc: devicetree at vger.kernel.org Cc: Mark Rutland --- Since v1: Mark's review: changed compatible string --- drivers/mtd/devices/docg3.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 91a169c..e2e0713 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -2126,10 +2127,17 @@ static int __exit docg3_release(struct platform_device *pdev) return 0; } +static struct of_device_id docg3_dt_ids[] = { + { .compatible = "m-systems,diskonchip-g3" }, + {} +}; +MODULE_DEVICE_TABLE(of, docg3_dt_ids); + static struct platform_driver g3_driver = { .driver = { .name = "docg3", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(docg3_dt_ids), }, .suspend = docg3_suspend, .resume = docg3_resume, -- 2.1.0 From robert.jarzmik at free.fr Sat Sep 27 12:34:30 2014 From: robert.jarzmik at free.fr (Robert Jarzmik) Date: Sat, 27 Sep 2014 21:34:30 +0200 Subject: [PATCH v2 2/2] mtd: docg3: add device-tree documentation In-Reply-To: <1411846470-30041-1-git-send-email-robert.jarzmik@free.fr> References: <1411846470-30041-1-git-send-email-robert.jarzmik@free.fr> Message-ID: <1411846470-30041-2-git-send-email-robert.jarzmik@free.fr> Add documentation for the sandisk docg3 chip. Signed-off-by: Robert Jarzmik Cc: devicetree at vger.kernel.org Cc: Mark Rutland --- Since v1: Mark's review : use m-systems,diskonchip-g3, add flash at 0, grammar --- Documentation/devicetree/bindings/mtd/diskonchip.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/diskonchip.txt diff --git a/Documentation/devicetree/bindings/mtd/diskonchip.txt b/Documentation/devicetree/bindings/mtd/diskonchip.txt new file mode 100644 index 0000000..3e13bfd --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/diskonchip.txt @@ -0,0 +1,15 @@ +M-Systems and Sandisk DiskOnChip devices + +M-System DiskOnChip G3 +====================== +The Sandisk (formerly M-Systems) docg3 is a nand device of 64M to 256MB. + +Required properties: + - compatible: should be "m-systems,diskonchip-g3" + - reg: register base and size + +Example: + docg3: flash at 0 { + compatible = "m-systems,diskonchip-g3"; + reg = <0x0 0x2000>; + }; -- 2.1.0 From computersforpeace at gmail.com Sat Sep 27 17:19:48 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 27 Sep 2014 17:19:48 -0700 Subject: [PATCH 1/2] mtd: fsl_ifc_nand: Use devm_* throughout driver In-Reply-To: <2056273149.70335.1408150004992.JavaMail.zimbra@xes-inc.com> References: <2056273149.70335.1408150004992.JavaMail.zimbra@xes-inc.com> Message-ID: <20140928001948.GO7362@norris-Latitude-E6410> Hi Aaron, Hmm, you're not the only one to send a patch like this. But I'm not sure if it's correct; this driver is written awkwardly. On Fri, Aug 15, 2014 at 07:46:44PM -0500, Aaron Sierra wrote: > For consistency, use managed resources for allocations and remaps > throughout the driver. > > Signed-off-by: Aaron Sierra > --- > drivers/mtd/nand/fsl_ifc_nand.c | 12 ++++-------- > 1 file changed, 4 insertions(+), 8 deletions(-) > > diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c > index 2338124..7861909 100644 > --- a/drivers/mtd/nand/fsl_ifc_nand.c > +++ b/drivers/mtd/nand/fsl_ifc_nand.c > @@ -997,9 +997,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) > > kfree(priv->mtd.name); > > - if (priv->vbase) > - iounmap(priv->vbase); > - > ifc_nand_ctrl->chips[priv->bank] = NULL; > > return 0; > @@ -1062,7 +1059,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) > > mutex_lock(&fsl_ifc_nand_mutex); > if (!fsl_ifc_ctrl_dev->nand) { > - ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); > + ifc_nand_ctrl = devm_kzalloc(&dev->dev, > + sizeof(*ifc_nand_ctrl), GFP_KERNEL); This structure is static, and it looks like it's written with an attempt of sharing the same controller structure across potentially many instances of the device (multiple banks / chip selects?). And it has a refcount for freeing the struct, but that refcount is wrong (see below). > if (!ifc_nand_ctrl) { > mutex_unlock(&fsl_ifc_nand_mutex); > return -ENOMEM; > @@ -1085,7 +1083,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) > priv->ctrl = fsl_ifc_ctrl_dev; > priv->dev = &dev->dev; > > - priv->vbase = ioremap(res.start, resource_size(&res)); > + priv->vbase = devm_ioremap(priv->dev, res.start, resource_size(&res)); > if (!priv->vbase) { > dev_err(priv->dev, "%s: failed to map chip region\n", __func__); > ret = -ENOMEM; > @@ -1148,10 +1146,8 @@ static int fsl_ifc_nand_remove(struct platform_device *dev) > > mutex_lock(&fsl_ifc_nand_mutex); > ifc_nand_ctrl->counter--; > - if (!ifc_nand_ctrl->counter) { > + if (!ifc_nand_ctrl->counter) Notice here, that there is an attempt at refcounting the ->nand structure. It is wrong (see how 'counter' is never incremented, only decremented). I don't know if anyone uses this driver in a "removed" context (e.g., rmmod or device unbinding), but this patch is potentially circumventing the (incorrect) refcounting, and instead will free the memory when it's possibly still used by another device. IMO, it's better to have a potential memory leak than a potential use-after-free, so I will not apply this patch. Feel free to provide an actual bugfix for this driver to fix the refcounting instead, though! Or work with the original authors/users to see if this driver actually needs all the global/static info that's being used here. Perhaps the driver could be refactored. > fsl_ifc_ctrl_dev->nand = NULL; > - kfree(ifc_nand_ctrl); > - } > mutex_unlock(&fsl_ifc_nand_mutex); > > return 0; BTW, I see that an earlier incarnation of this type of patch says it was based on an automated semantic patch. I'd suggest taking a hard look at the automated tools you're using, so you don't inadverently add more bugs while you're making "cleanups." Regards, Brian From computersforpeace at gmail.com Sat Sep 27 17:28:13 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 27 Sep 2014 17:28:13 -0700 Subject: [PATCH V2] mtd: spi-nor: add Kconfig option to disable 4K sectors In-Reply-To: <1408267646-6643-1-git-send-email-zajec5@gmail.com> References: <1408220271-21455-1-git-send-email-zajec5@gmail.com> <1408267646-6643-1-git-send-email-zajec5@gmail.com> Message-ID: <20140928002813.GP7362@norris-Latitude-E6410> On Sun, Aug 17, 2014 at 11:27:26AM +0200, Rafa? Mi?ecki wrote: > Current situation with 4K sectors is quite messy. First of all, some > MTD "users" don't work with such small size. An example may be UBIFS > which requires 15 KiB erase blocks as a minimum. In theory spi-nor > should provide multiple erase regions and MTD "users" should use the > one they need. Unforunately that is not implemented. > > In the result our flashes database in spi-nor is hackish. For some > flashes we pretend they don't support 4K sectors just because some > distribution uses UBIFS on it. This ofc leads to conflicts, like > Samsung using w25q128 with 4K sectors vs. OpenWrt requiring it to > pretend it's 64 KiB blocks only. > > My idea (plan?) for fixing this situation: > 1) Use real hw info (this requires a way for disabling 4K for now) > 2) Provide detailed info about erase regions > 3) Make UBIFS work with devices that support 4K sectors > > Signed-off-by: Rafa? Mi?ecki > --- > V2: Add extra info about performance in Kconfig. Thanks Kevin. > Fix typo s/users/uses/ in commit message. Pushed to l2-mtd.git. Thanks! Now we should probably try to handle (1), at least, so that the data table holds fully accurate info about the flash. Brian From computersforpeace at gmail.com Sat Sep 27 17:40:52 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 27 Sep 2014 17:40:52 -0700 Subject: [PATCH] mtdtest: Check bbt at index of (eb + 1) when we access 2 EBs. In-Reply-To: <1408328879-22771-1-git-send-email-yangds.fnst@cn.fujitsu.com> References: <1408328879-22771-1-git-send-email-yangds.fnst@cn.fujitsu.com> Message-ID: <20140928004052.GQ7362@norris-Latitude-E6410> On Mon, Aug 18, 2014 at 10:27:59AM +0800, Dongsheng Yang wrote: > When we want to access 2 eraseblocks, we need to make sure the > two eraseblocks both are not bad. > > Signed-off-by: Dongsheng Yang > --- > drivers/mtd/tests/stresstest.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c > index c9d42cc..076d409 100644 > --- a/drivers/mtd/tests/stresstest.c > +++ b/drivers/mtd/tests/stresstest.c > @@ -60,7 +60,7 @@ again: > eb = prandom_u32(); > /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ > eb %= (ebcnt - 1); > - if (bbt[eb]) > + if (bbt[eb] || bbt[eb + 1]) Was this change actually needed? Did you see some kind of test failure without it? >From what I can see, stresstest.c already handles the second block just fine; it skips the block with code like this: static int do_read(void) { ... if (bbt[eb + 1]) { if (offs >= mtd->erasesize) offs -= mtd->erasesize; if (offs + len > mtd->erasesize) len = mtd->erasesize - offs; } ... } and similar in do_write(). Plus, your patch actually skips *any* block where the subsequent block is bad. That is not ideal, as it skews the randomness. So unless I'm missing something, I will not take this patch. > goto again; > return eb; > } Regards, Brian From computersforpeace at gmail.com Sat Sep 27 17:53:41 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sat, 27 Sep 2014 17:53:41 -0700 Subject: [PATCH] mtd: fsl_ifc_nand: use devm_ functions consistently In-Reply-To: <20140803101707.GA8018@himangi-Dell> References: <20140803101707.GA8018@himangi-Dell> Message-ID: + linux-mtd FYI, I addressed a similar patch over here: http://lists.infradead.org/pipermail/linux-mtd/2014-September/055563.html I'm pretty sure this patch is wrong, and the semantic match is incorrect (or at least, it has false positives). Just because devm_* is used in some part of the driver doesn't mean that all allocations should be. Admittedly, this driver is not the best written (this patch drew my attention to at least one bug), but I just wanted to let y'all know. Regards, Brian On Sun, Aug 3, 2014 at 3:17 AM, Himangi Saraogi wrote: > Use devm_kzalloc for all calls to kzalloc and not just the first. Use > devm functions for other allocations as well. The calls to free the > allocated memory in the remove function are done away with. > > The semantic match that finds the inconsistency is as follows: > > // > @@ > @@ > > *devm_kzalloc(...) > ... > *kzalloc(...) > // > > Signed-off-by: Himangi Saraogi > Acked-by: Julia Lawall > --- > Not compile tested. > drivers/mtd/nand/fsl_ifc_nand.c | 17 ++++++----------- > 1 file changed, 6 insertions(+), 11 deletions(-) > > diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c > index 2338124..b403a77 100644 > --- a/drivers/mtd/nand/fsl_ifc_nand.c > +++ b/drivers/mtd/nand/fsl_ifc_nand.c > @@ -995,11 +995,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) > { > nand_release(&priv->mtd); > > - kfree(priv->mtd.name); > - > - if (priv->vbase) > - iounmap(priv->vbase); > - > ifc_nand_ctrl->chips[priv->bank] = NULL; > > return 0; > @@ -1062,7 +1057,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) > > mutex_lock(&fsl_ifc_nand_mutex); > if (!fsl_ifc_ctrl_dev->nand) { > - ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); > + ifc_nand_ctrl = devm_kzalloc(&dev->dev, sizeof(*ifc_nand_ctrl), > + GFP_KERNEL); > if (!ifc_nand_ctrl) { > mutex_unlock(&fsl_ifc_nand_mutex); > return -ENOMEM; > @@ -1085,7 +1081,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) > priv->ctrl = fsl_ifc_ctrl_dev; > priv->dev = &dev->dev; > > - priv->vbase = ioremap(res.start, resource_size(&res)); > + priv->vbase = devm_ioremap(&dev->dev, res.start, resource_size(&res)); > if (!priv->vbase) { > dev_err(priv->dev, "%s: failed to map chip region\n", __func__); > ret = -ENOMEM; > @@ -1104,7 +1100,8 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) > IFC_NAND_EVTER_INTR_FTOERIR_EN | > IFC_NAND_EVTER_INTR_WPERIR_EN, > &ifc->ifc_nand.nand_evter_intr_en); > - priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); > + priv->mtd.name = devm_kasprintf(&dev->dev, GFP_KERNEL, "%llx.flash", > + (u64)res.start); > if (!priv->mtd.name) { > ret = -ENOMEM; > goto err; > @@ -1148,10 +1145,8 @@ static int fsl_ifc_nand_remove(struct platform_device *dev) > > mutex_lock(&fsl_ifc_nand_mutex); > ifc_nand_ctrl->counter--; > - if (!ifc_nand_ctrl->counter) { > + if (!ifc_nand_ctrl->counter) > fsl_ifc_ctrl_dev->nand = NULL; > - kfree(ifc_nand_ctrl); > - } > mutex_unlock(&fsl_ifc_nand_mutex); > > return 0; > -- > 1.9.1 > From hujianyang at huawei.com Sat Sep 27 18:58:17 2014 From: hujianyang at huawei.com (hujianyang) Date: Sun, 28 Sep 2014 09:58:17 +0800 Subject: [PATCH] UBIFS: Align the dump messages of SB_NODE In-Reply-To: <1411727765.23429.61.camel@sauron.fi.intel.com> References: <541D24CF.1040705@huawei.com> <1411727765.23429.61.camel@sauron.fi.intel.com> Message-ID: <54276B39.6000603@huawei.com> On 2014/9/26 18:36, Artem Bityutskiy wrote: > On Sat, 2014-09-20 at 14:55 +0800, hujianyang wrote: >> I found the dump messages of UBIFS_SB_NODE is not aligned. This >> patch remove the extra space from the line which is retracted. >> >> >> Signed-off-by: hujianyang > > This was not a typo, this was intentional. We first print the all flags > in a hex format, and then we "decode" it and print the values of the > individual flags with an additional indent. The indent is to make it > clear that these line belong to the flags, and they are not independent > values. > Oh, thanks for your explanation~! Hu From bpqw at micron.com Sat Sep 27 18:59:42 2014 From: bpqw at micron.com (bpqw) Date: Sun, 28 Sep 2014 01:59:42 +0000 Subject: [PATCH 1/1 v2] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: <201409261046.07132.marex@denx.de> References: <201409251211.57183.marex@denx.de> <201409261046.07132.marex@denx.de> Message-ID: For Micron spi norflash,you can enable Quad spi transfer by clear EVCR(Enhanced Volatile Configuration Register) Quad I/O protocol bit. Signed-off-by: bean huo --- v1-v2:modified to that capture wait_till_ready() return value,if error,directly return its the value. drivers/mtd/spi-nor/spi-nor.c | 46 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 6 ++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..0c3b4fd 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -878,6 +878,45 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int micron_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return -EINVAL; + } + + write_enable(nor); + + /* set EVCR ,enable quad I/O */ + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); + if (ret < 0) { + dev_err(nor->dev, + "error while writing EVCR register\n"); + return -EINVAL; + } + + ret = wait_till_ready(nor); + if (ret) + return ret; + + /* read EVCR and check it */ + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return -EINVAL; + } + if (val & EVCR_QUAD_EN_MICRON) { + dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + return -EINVAL; + } + + return 0; +} + static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) { int status; @@ -890,6 +929,13 @@ static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) return -EINVAL; } return status; + case CFI_MFR_ST: + status = micron_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Micron quad-read not enabled\n"); + return -EINVAL; + } + return status; default: status = spansion_quad_enable(nor); if (status) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..d71b659 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -56,6 +56,10 @@ /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ +/* Used for Micron flashes only. */ +#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ +#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ + /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ @@ -67,6 +71,8 @@ #define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ +#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */ + /* Flag Status Register bits */ #define FSR_READY 0x80 -- 1.7.9.5 From recruitment at sednaoilrefineries.com Sat Sep 27 14:47:04 2014 From: recruitment at sednaoilrefineries.com (Sedna Oil Refineries) Date: Sat, 27 Sep 2014 15:47:04 -0600 Subject: JOB VACANCY IN CANADA, 2014 Message-ID: JOB VACANCY IN CANADA, 2014 Sedna Oil Refinery is a leading global resources company in oil refining. We are now creating new career opportunities for both experienced and fresh graduates outside Australia. We offer challenging job opportunities to the right people on our latest career and job opportunities. With a global portfolio of businesses and commodities, we are always seeking talented, skilled and enthusiastic people to join our team. It is a diverse and challenging environment offering great career opportunities for people who share our values. Sedna Oil Refinery will be responsible for applicants Flight Ticket and also assist in securing successful applicants and directs on how to obtain work permit with visa through Canadian Immigration CIC office in Canada and United Kingdom. Interested applicants should contact Sedna Oil Refinery. Any interested applicants, should kindly send his or her CV/resume. Email id: recruitment at sednaoilrefineries.com Regards, Vincent Hugo Senior Manager Human Resources Sedna Oil Refineries Canada From tlinder at codeaurora.org Sat Sep 27 23:36:25 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:36:25 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities Message-ID: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> If there is more then one UBI device mounted, there is no way to distinguish between messages from different UBI devices. Add device number to all ubi layer message types. Signed-off-by: Tanya Brokhman --- drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- drivers/mtd/ubi/cdev.c | 37 +++++----- drivers/mtd/ubi/debug.c | 9 +-- drivers/mtd/ubi/eba.c | 54 +++++++------- drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- drivers/mtd/ubi/kapi.c | 6 +- drivers/mtd/ubi/misc.c | 6 +- drivers/mtd/ubi/ubi.h | 13 ++-- drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- drivers/mtd/ubi/vtbl.c | 54 ++++++++------ drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- 13 files changed, 521 insertions(+), 374 deletions(-) diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 6f27d9a..3f11561 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -176,6 +176,7 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) /** * validate_vid_hdr - check volume identifier header. + * @ubi: UBI device description object * @vid_hdr: the volume identifier header to check * @av: information about the volume this logical eraseblock belongs to * @pnum: physical eraseblock number the VID header came from @@ -188,7 +189,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) * information in the VID header is consistent to the information in other VID * headers of the same volume. */ -static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, +static int validate_vid_hdr(const struct ubi_device *ubi, + const struct ubi_vid_hdr *vid_hdr, const struct ubi_ainf_volume *av, int pnum) { int vol_type = vid_hdr->vol_type; @@ -206,7 +208,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, */ if (vol_id != av->vol_id) { - ubi_err("inconsistent vol_id"); + ubi_err(ubi->ubi_num, "inconsistent vol_id"); goto bad; } @@ -216,17 +218,17 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, av_vol_type = UBI_VID_DYNAMIC; if (vol_type != av_vol_type) { - ubi_err("inconsistent vol_type"); + ubi_err(ubi->ubi_num, "inconsistent vol_type"); goto bad; } if (used_ebs != av->used_ebs) { - ubi_err("inconsistent used_ebs"); + ubi_err(ubi->ubi_num, "inconsistent used_ebs"); goto bad; } if (data_pad != av->data_pad) { - ubi_err("inconsistent data_pad"); + ubi_err(ubi->ubi_num, "inconsistent data_pad"); goto bad; } } @@ -234,7 +236,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, return 0; bad: - ubi_err("inconsistent VID header at PEB %d", pnum); + ubi_err(ubi->ubi_num, "inconsistent VID header at PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); ubi_dump_av(av); return -EINVAL; @@ -336,7 +338,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, * support these images anymore. Well, those images still work, * but only if no unclean reboots happened. */ - ubi_err("unsupported on-flash UBI format"); + ubi_err(ubi->ubi_num, "unsupported on-flash UBI format"); return -EINVAL; } @@ -377,7 +379,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, if (err == UBI_IO_BITFLIPS) bitflips = 1; else { - ubi_err("VID of PEB %d header is bad, but it was OK earlier, err %d", + ubi_err(ubi->ubi_num, "VID of PEB %d header is bad, but it was OK earlier, err %d", pnum, err); if (err > 0) err = -EIO; @@ -507,7 +509,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * logical eraseblocks because there was an unclean reboot. */ if (aeb->sqnum == sqnum && sqnum != 0) { - ubi_err("two LEBs with same sequence number %llu", + ubi_err(ubi->ubi_num, "two LEBs with same sequence number %llu", sqnum); ubi_dump_aeb(aeb, 0); ubi_dump_vid_hdr(vid_hdr); @@ -527,7 +529,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * This logical eraseblock is newer than the one * found earlier. */ - err = validate_vid_hdr(vid_hdr, av, pnum); + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); if (err) return err; @@ -565,7 +567,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * attaching information. */ - err = validate_vid_hdr(vid_hdr, av, pnum); + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); if (err) return err; @@ -668,7 +670,8 @@ static int early_erase_peb(struct ubi_device *ubi, * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ - ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); + ubi_err(ubi->ubi_num, + "erase counter overflow at PEB %d, EC %d", pnum, ec); return -EINVAL; } @@ -736,7 +739,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, return aeb; } - ubi_err("no free eraseblocks"); + ubi_err(ubi->ubi_num, "no free eraseblocks"); return ERR_PTR(-ENOSPC); } @@ -785,9 +788,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size)) goto out_unlock; - ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF", + ubi_err(ubi->ubi_num, "PEB %d contains corrupted VID header, and the data does not contain all 0xFF", pnum); - ubi_err("this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); + ubi_err(ubi->ubi_num, "this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); ubi_dump_vid_hdr(vid_hdr); pr_err("hexdump of PEB %d offset %d, length %d", pnum, ubi->leb_start, ubi->leb_size); @@ -859,7 +862,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, bitflips = 1; break; default: - ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err); + ubi_err(ubi->ubi_num, + "'ubi_io_read_ec_hdr()' returned unknown code %d", err); return -EINVAL; } @@ -868,7 +872,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, /* Make sure UBI version is OK */ if (ech->version != UBI_VERSION) { - ubi_err("this UBI version is %d, image version is %d", + ubi_err(ubi->ubi_num, "this UBI version is %d, image version is %d", UBI_VERSION, (int)ech->version); return -EINVAL; } @@ -882,7 +886,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, * flash. Upgrade UBI and use 64-bit erase counters * internally. */ - ubi_err("erase counter overflow, max is %d", + ubi_err(ubi->ubi_num, "erase counter overflow, max is %d", UBI_MAX_ERASECOUNTER); ubi_dump_ec_hdr(ech); return -EINVAL; @@ -903,7 +907,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, if (!ubi->image_seq) ubi->image_seq = image_seq; if (image_seq && ubi->image_seq != image_seq) { - ubi_err("bad image sequence number %d in PEB %d, expected %d", + ubi_err("ubi->ubi_num, bad image sequence number %d in PEB %d, expected %d", image_seq, pnum, ubi->image_seq); ubi_dump_ec_hdr(ech); return -EINVAL; @@ -981,7 +985,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return err; goto adjust_mean_ec; default: - ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d", + ubi_err(ubi->ubi_num, "'ubi_io_read_vid_hdr()' returned unknown code %d", err); return -EINVAL; } @@ -999,7 +1003,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, case UBI_COMPAT_DELETE: if (vol_id != UBI_FM_SB_VOLUME_ID && vol_id != UBI_FM_DATA_VOLUME_ID) { - ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it", + ubi_msg(ubi->ubi_num, + "\"delete\" compatible internal volume %d:%d found, will remove it", vol_id, lnum); } err = add_to_list(ai, pnum, vol_id, lnum, @@ -1009,13 +1014,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; case UBI_COMPAT_RO: - ubi_msg("read-only compatible internal volume %d:%d found, switch to read-only mode", + ubi_msg(ubi->ubi_num, + "read-only compatible internal volume %d:%d found, switch to read-only mode", vol_id, lnum); ubi->ro_mode = 1; break; case UBI_COMPAT_PRESERVE: - ubi_msg("\"preserve\" compatible internal volume %d:%d found", + ubi_msg(ubi->ubi_num, + "\"preserve\" compatible internal volume %d:%d found", vol_id, lnum); err = add_to_list(ai, pnum, vol_id, lnum, ec, 0, &ai->alien); @@ -1024,14 +1031,14 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; case UBI_COMPAT_REJECT: - ubi_err("incompatible internal volume %d:%d found", + ubi_err(ubi->ubi_num, "incompatible internal volume %d:%d found", vol_id, lnum); return -EINVAL; } } if (ec_err) - ubi_warn("valid VID header but corrupted EC header at PEB %d", + ubi_warn(ubi->ubi_num, "valid VID header but corrupted EC header at PEB %d", pnum); err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips); if (err) @@ -1075,7 +1082,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) * with the flash HW or driver. */ if (ai->corr_peb_count) { - ubi_err("%d PEBs are corrupted and preserved", + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and preserved", ai->corr_peb_count); pr_err("Corrupted PEBs are:"); list_for_each_entry(aeb, &ai->corr, u.list) @@ -1087,7 +1094,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) * otherwise, only print a warning. */ if (ai->corr_peb_count >= max_corr) { - ubi_err("too many corrupted PEBs, refusing"); + ubi_err(ubi->ubi_num, "too many corrupted PEBs, refusing"); return -EINVAL; } } @@ -1110,11 +1117,11 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) */ if (ai->maybe_bad_peb_count <= 2) { ai->is_empty = 1; - ubi_msg("empty MTD device detected"); + ubi_msg(ubi->ubi_num, "empty MTD device detected"); get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq)); } else { - ubi_err("MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); + ubi_err(ubi->ubi_num, "MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); return -EINVAL; } @@ -1248,7 +1255,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, goto out_vidh; } - ubi_msg("scanning is finished"); + ubi_msg(ubi->ubi_num, "scanning is finished"); /* Calculate mean erase counter */ if (ai->ec_count) @@ -1515,37 +1522,37 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) vols_found += 1; if (ai->is_empty) { - ubi_err("bad is_empty flag"); + ubi_err(ubi->ubi_num, "bad is_empty flag"); goto bad_av; } if (av->vol_id < 0 || av->highest_lnum < 0 || av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 || av->data_pad < 0 || av->last_data_size < 0) { - ubi_err("negative values"); + ubi_err(ubi->ubi_num, "negative values"); goto bad_av; } if (av->vol_id >= UBI_MAX_VOLUMES && av->vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("bad vol_id"); + ubi_err(ubi->ubi_num, "bad vol_id"); goto bad_av; } if (av->vol_id > ai->highest_vol_id) { - ubi_err("highest_vol_id is %d, but vol_id %d is there", + ubi_err(ubi->ubi_num, "highest_vol_id is %d, but vol_id %d is there", ai->highest_vol_id, av->vol_id); goto out; } if (av->vol_type != UBI_DYNAMIC_VOLUME && av->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); + ubi_err(ubi->ubi_num, "bad vol_type"); goto bad_av; } if (av->data_pad > ubi->leb_size / 2) { - ubi_err("bad data_pad"); + ubi_err(ubi->ubi_num, "bad data_pad"); goto bad_av; } @@ -1557,48 +1564,48 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) leb_count += 1; if (aeb->pnum < 0 || aeb->ec < 0) { - ubi_err("negative values"); + ubi_err(ubi->ubi_num, "negative values"); goto bad_aeb; } if (aeb->ec < ai->min_ec) { - ubi_err("bad ai->min_ec (%d), %d found", + ubi_err(ubi->ubi_num, "bad ai->min_ec (%d), %d found", ai->min_ec, aeb->ec); goto bad_aeb; } if (aeb->ec > ai->max_ec) { - ubi_err("bad ai->max_ec (%d), %d found", + ubi_err(ubi->ubi_num, "bad ai->max_ec (%d), %d found", ai->max_ec, aeb->ec); goto bad_aeb; } if (aeb->pnum >= ubi->peb_count) { - ubi_err("too high PEB number %d, total PEBs %d", + ubi_err(ubi->ubi_num, "too high PEB number %d, total PEBs %d", aeb->pnum, ubi->peb_count); goto bad_aeb; } if (av->vol_type == UBI_STATIC_VOLUME) { if (aeb->lnum >= av->used_ebs) { - ubi_err("bad lnum or used_ebs"); + ubi_err(ubi->ubi_num, "bad lnum or used_ebs"); goto bad_aeb; } } else { if (av->used_ebs != 0) { - ubi_err("non-zero used_ebs"); + ubi_err(ubi->ubi_num, "non-zero used_ebs"); goto bad_aeb; } } if (aeb->lnum > av->highest_lnum) { - ubi_err("incorrect highest_lnum or lnum"); + ubi_err(ubi->ubi_num, "incorrect highest_lnum or lnum"); goto bad_aeb; } } if (av->leb_count != leb_count) { - ubi_err("bad leb_count, %d objects in the tree", + ubi_err(ubi->ubi_num, "bad leb_count, %d objects in the tree", leb_count); goto bad_av; } @@ -1609,13 +1616,13 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) aeb = last_aeb; if (aeb->lnum != av->highest_lnum) { - ubi_err("bad highest_lnum"); + ubi_err(ubi->ubi_num, "bad highest_lnum"); goto bad_aeb; } } if (vols_found != ai->vols_found) { - ubi_err("bad ai->vols_found %d, should be %d", + ubi_err(ubi->ubi_num, "bad ai->vols_found %d, should be %d", ai->vols_found, vols_found); goto out; } @@ -1632,7 +1639,8 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("VID header is not OK (%d)", err); + ubi_err(ubi->ubi_num, + "VID header is not OK (%d)", err); if (err > 0) err = -EIO; return err; @@ -1641,37 +1649,42 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; if (av->vol_type != vol_type) { - ubi_err("bad vol_type"); + ubi_err(ubi->ubi_num, "bad vol_type"); goto bad_vid_hdr; } if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) { - ubi_err("bad sqnum %llu", aeb->sqnum); + ubi_err(ubi->ubi_num, + "bad sqnum %llu", aeb->sqnum); goto bad_vid_hdr; } if (av->vol_id != be32_to_cpu(vidh->vol_id)) { - ubi_err("bad vol_id %d", av->vol_id); + ubi_err(ubi->ubi_num, + "bad vol_id %d", av->vol_id); goto bad_vid_hdr; } if (av->compat != vidh->compat) { - ubi_err("bad compat %d", vidh->compat); + ubi_err(ubi->ubi_num, + "bad compat %d", vidh->compat); goto bad_vid_hdr; } if (aeb->lnum != be32_to_cpu(vidh->lnum)) { - ubi_err("bad lnum %d", aeb->lnum); + ubi_err(ubi->ubi_num, "bad lnum %d", aeb->lnum); goto bad_vid_hdr; } if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) { - ubi_err("bad used_ebs %d", av->used_ebs); + ubi_err(ubi->ubi_num, + "bad used_ebs %d", av->used_ebs); goto bad_vid_hdr; } if (av->data_pad != be32_to_cpu(vidh->data_pad)) { - ubi_err("bad data_pad %d", av->data_pad); + ubi_err(ubi->ubi_num, + "bad data_pad %d", av->data_pad); goto bad_vid_hdr; } } @@ -1680,12 +1693,14 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) continue; if (av->highest_lnum != be32_to_cpu(vidh->lnum)) { - ubi_err("bad highest_lnum %d", av->highest_lnum); + ubi_err(ubi->ubi_num, + "bad highest_lnum %d", av->highest_lnum); goto bad_vid_hdr; } if (av->last_data_size != be32_to_cpu(vidh->data_size)) { - ubi_err("bad last_data_size %d", av->last_data_size); + ubi_err(ubi->ubi_num, + "bad last_data_size %d", av->last_data_size); goto bad_vid_hdr; } } @@ -1726,7 +1741,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) err = 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) if (!buf[pnum]) { - ubi_err("PEB %d is not referred", pnum); + ubi_err(ubi->ubi_num, "PEB %d is not referred", pnum); err = 1; } @@ -1736,18 +1751,21 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) return 0; bad_aeb: - ubi_err("bad attaching information about LEB %d", aeb->lnum); + ubi_err(ubi->ubi_num, "bad attaching information about LEB %d", + aeb->lnum); ubi_dump_aeb(aeb, 0); ubi_dump_av(av); goto out; bad_av: - ubi_err("bad attaching information about volume %d", av->vol_id); + ubi_err(ubi->ubi_num, "bad attaching information about volume %d", + av->vol_id); ubi_dump_av(av); goto out; bad_vid_hdr: - ubi_err("bad attaching information about volume %d", av->vol_id); + ubi_err(ubi->ubi_num, "bad attaching information about volume %d", + av->vol_id); ubi_dump_av(av); ubi_dump_vid_hdr(vidh); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6e30a3c..2b7dbd0 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -166,7 +166,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype) case UBI_VOLUME_RESIZED: case UBI_VOLUME_RENAMED: if (ubi_update_fastmap(ubi)) { - ubi_err("Unable to update fastmap!"); + ubi_err(ubi->ubi_num, "Unable to update fastmap!"); ubi_ro_mode(ubi); } } @@ -517,7 +517,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) */ err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); if (err) { - ubi_err("cannot register UBI character devices"); + ubi_err(ubi->ubi_num, "cannot register UBI character devices"); return err; } @@ -528,7 +528,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) err = cdev_add(&ubi->cdev, dev, 1); if (err) { - ubi_err("cannot add character device"); + ubi_err(ubi->ubi_num, "cannot add character device"); goto out_unreg; } @@ -540,7 +540,8 @@ static int uif_init(struct ubi_device *ubi, int *ref) if (ubi->volumes[i]) { err = ubi_add_volume(ubi, ubi->volumes[i]); if (err) { - ubi_err("cannot add volume %d", i); + ubi_err(ubi->ubi_num, + "cannot add volume %d", i); goto out_volumes; } } @@ -556,7 +557,8 @@ out_sysfs: cdev_del(&ubi->cdev); out_unreg: unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); - ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); + ubi_err(ubi->ubi_num, "cannot initialize UBI %s, error %d", + ubi->ubi_name, err); return err; } @@ -650,7 +652,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * guess we should just pick the largest region. But this is * not implemented. */ - ubi_err("multiple regions, not implemented"); + ubi_err(ubi->ubi_num, "multiple regions, not implemented"); return -EINVAL; } @@ -685,7 +687,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * which allows us to avoid costly division operations. */ if (!is_power_of_2(ubi->min_io_size)) { - ubi_err("min. I/O unit (%d) is not power of 2", + ubi_err(ubi->ubi_num, "min. I/O unit (%d) is not power of 2", ubi->min_io_size); return -EINVAL; } @@ -702,7 +704,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) if (ubi->max_write_size < ubi->min_io_size || ubi->max_write_size % ubi->min_io_size || !is_power_of_2(ubi->max_write_size)) { - ubi_err("bad write buffer size %d for %d min. I/O unit", + ubi_err(ubi->ubi_num, "bad write buffer size %d for %d min. I/O unit", ubi->max_write_size, ubi->min_io_size); return -EINVAL; } @@ -739,7 +741,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) /* The shift must be aligned to 32-bit boundary */ if (ubi->vid_hdr_shift % 4) { - ubi_err("unaligned VID header shift %d", + ubi_err(ubi->ubi_num, "unaligned VID header shift %d", ubi->vid_hdr_shift); return -EINVAL; } @@ -749,7 +751,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || ubi->leb_start & (ubi->min_io_size - 1)) { - ubi_err("bad VID header (%d) or data offsets (%d)", + ubi_err(ubi->ubi_num, "bad VID header (%d) or data offsets (%d)", ubi->vid_hdr_offset, ubi->leb_start); return -EINVAL; } @@ -769,14 +771,15 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * read-only mode. */ if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { - ubi_warn("EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); + ubi_warn(ubi->ubi_num, "EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); ubi->ro_mode = 1; } ubi->leb_size = ubi->peb_size - ubi->leb_start; if (!(ubi->mtd->flags & MTD_WRITEABLE)) { - ubi_msg("MTD device %d is write-protected, attach in read-only mode", + ubi_msg(ubi->ubi_num, + "MTD device %d is write-protected, attach in read-only mode", ubi->mtd->index); ubi->ro_mode = 1; } @@ -809,7 +812,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) int err, old_reserved_pebs = vol->reserved_pebs; if (ubi->ro_mode) { - ubi_warn("skip auto-resize because of R/O mode"); + ubi_warn(ubi->ubi_num, "skip auto-resize because of R/O mode"); return 0; } @@ -830,20 +833,23 @@ static int autoresize(struct ubi_device *ubi, int vol_id) vtbl_rec = ubi->vtbl[vol_id]; err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) - ubi_err("cannot clean auto-resize flag for volume %d", + ubi_err(ubi->ubi_num, + "cannot clean auto-resize flag for volume %d", vol_id); } else { desc.vol = vol; err = ubi_resize_volume(&desc, old_reserved_pebs + ubi->avail_pebs); if (err) - ubi_err("cannot auto-resize volume %d", vol_id); + ubi_err(ubi->ubi_num, "cannot auto-resize volume %d", + vol_id); } if (err) return err; - ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + ubi_msg(ubi->ubi_num, "volume %d (\"%s\") re-sized from %d to %d LEBs", + vol_id, vol->name, old_reserved_pebs, vol->reserved_pebs); return 0; } @@ -885,7 +891,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, for (i = 0; i < UBI_MAX_DEVICES; i++) { ubi = ubi_devices[i]; if (ubi && mtd->index == ubi->mtd->index) { - ubi_err("mtd%d is already attached to ubi%d", + ubi_err(ubi->ubi_num, + "mtd%d is already attached to ubi%d", mtd->index, i); return -EEXIST; } @@ -900,7 +907,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, * no sense to attach emulated MTD devices, so we prohibit this. */ if (mtd->type == MTD_UBIVOLUME) { - ubi_err("refuse attaching mtd%d - it is already emulated on top of UBI", + ubi_err(ubi->ubi_num, "refuse attaching mtd%d - it is already emulated on top of UBI", mtd->index); return -EINVAL; } @@ -911,7 +918,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, if (!ubi_devices[ubi_num]) break; if (ubi_num == UBI_MAX_DEVICES) { - ubi_err("only %d UBI devices may be created", + ubi_err(ubi->ubi_num, + "only %d UBI devices may be created", UBI_MAX_DEVICES); return -ENFILE; } @@ -921,7 +929,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, /* Make sure ubi_num is not busy */ if (ubi_devices[ubi_num]) { - ubi_err("ubi%d already exists", ubi_num); + ubi_err(ubi_num, "ubi%d already exists", ubi_num); return -EEXIST; } } @@ -953,13 +961,15 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) <= UBI_FM_MAX_START) { - ubi_err("More than %i PEBs are needed for fastmap, sorry.", + ubi_err(ubi->ubi_num, "More than %i PEBs are needed for fastmap, sorry.", UBI_FM_MAX_START); ubi->fm_disabled = 1; } - ubi_msg("default fastmap pool size: %d", ubi->fm_pool.max_size); - ubi_msg("default fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); + ubi_msg(ubi->ubi_num, "default fastmap pool size: %d", + ubi->fm_pool.max_size); + ubi_msg(ubi->ubi_num, "default fastmap WL pool size: %d", + ubi->fm_wl_pool.max_size); #else ubi->fm_disabled = 1; #endif @@ -970,7 +980,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, mutex_init(&ubi->fm_mutex); init_rwsem(&ubi->fm_sem); - ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); + ubi_msg(ubi->ubi_num, "attaching mtd%d to ubi%d", mtd->index, ubi_num); err = io_init(ubi, max_beb_per1024); if (err) @@ -989,7 +999,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, #endif err = ubi_attach(ubi, 0); if (err) { - ubi_err("failed to attach mtd%d, error %d", mtd->index, err); + ubi_err(ubi->ubi_num, "failed to attach mtd%d, error %d", + mtd->index, err); goto out_free; } @@ -1010,28 +1021,32 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name); if (IS_ERR(ubi->bgt_thread)) { err = PTR_ERR(ubi->bgt_thread); - ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, + ubi_err(ubi->ubi_num, "cannot spawn \"%s\", error %d", + ubi->bgt_name, err); goto out_debugfs; } - ubi_msg("attached mtd%d (name \"%s\", size %llu MiB) to ubi%d", - mtd->index, mtd->name, ubi->flash_size >> 20, ubi_num); - ubi_msg("PEB size: %d bytes (%d KiB), LEB size: %d bytes", + ubi_msg(ubi_num, "attached mtd%d (name \"%s\", size %llu MiB)", + mtd->index, mtd->name, ubi->flash_size >> 20); + ubi_msg(ubi_num, "PEB size: %d bytes (%d KiB), LEB size: %d bytes", ubi->peb_size, ubi->peb_size >> 10, ubi->leb_size); - ubi_msg("min./max. I/O unit sizes: %d/%d, sub-page size %d", + ubi_msg(ubi_num, "min./max. I/O unit sizes: %d/%d, sub-page size %d", ubi->min_io_size, ubi->max_write_size, ubi->hdrs_min_io_size); - ubi_msg("VID header offset: %d (aligned %d), data offset: %d", + ubi_msg(ubi_num, "VID header offset: %d (aligned %d), data offset: %d", ubi->vid_hdr_offset, ubi->vid_hdr_aloffset, ubi->leb_start); - ubi_msg("good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", + ubi_msg(ubi_num, "good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", ubi->good_peb_count, ubi->bad_peb_count, ubi->corr_peb_count); - ubi_msg("user volume: %d, internal volumes: %d, max. volumes count: %d", + ubi_msg(ubi_num, + "user volume: %d, internal volumes: %d, max. volumes count: %d", ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT, ubi->vtbl_slots); - ubi_msg("max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", + ubi_msg(ubi_num, + "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD, ubi->image_seq); - ubi_msg("available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", + ubi_msg(ubi_num, + "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs); /* @@ -1100,7 +1115,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) return -EBUSY; } /* This may only happen if there is a bug */ - ubi_err("%s reference count %d, destroy anyway", + ubi_err(ubi->ubi_num, "%s reference count %d, destroy anyway", ubi->ubi_name, ubi->ref_count); } ubi_devices[ubi_num] = NULL; @@ -1108,7 +1123,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ubi_assert(ubi_num == ubi->ubi_num); ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL); - ubi_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); + ubi_msg(ubi->ubi_num, "detaching mtd%d", ubi->mtd->index); #ifdef CONFIG_MTD_UBI_FASTMAP /* If we don't write a new fastmap at detach time we lose all * EC updates that have been made since the last written fastmap. */ @@ -1136,7 +1151,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) put_mtd_device(ubi->mtd); vfree(ubi->peb_buf); vfree(ubi->fm_buf); - ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); + ubi_msg(ubi->ubi_num, "mtd%d is detached", ubi->mtd->index); put_device(&ubi->dev); return 0; } @@ -1218,7 +1233,8 @@ static int __init ubi_init(void) BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); if (mtd_devs > UBI_MAX_DEVICES) { - ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); + ubi_err(UBI_MAX_DEVICES, "too many MTD devices, maximum is %d", + UBI_MAX_DEVICES); return -EINVAL; } @@ -1226,19 +1242,19 @@ static int __init ubi_init(void) ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); if (IS_ERR(ubi_class)) { err = PTR_ERR(ubi_class); - ubi_err("cannot create UBI class"); + ubi_err(UBI_MAX_DEVICES, "cannot create UBI class"); goto out; } err = class_create_file(ubi_class, &ubi_version); if (err) { - ubi_err("cannot create sysfs file"); + ubi_err(UBI_MAX_DEVICES, "cannot create sysfs file"); goto out_class; } err = misc_register(&ubi_ctrl_cdev); if (err) { - ubi_err("cannot register device"); + ubi_err(UBI_MAX_DEVICES, "cannot register device"); goto out_version; } @@ -1265,7 +1281,9 @@ static int __init ubi_init(void) mtd = open_mtd_device(p->name); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - ubi_err("cannot open mtd %s, error %d", p->name, err); + ubi_err(UBI_MAX_DEVICES, + "cannot open mtd %s, error %d", + p->name, err); /* See comment below re-ubi_is_module(). */ if (ubi_is_module()) goto out_detach; @@ -1277,7 +1295,8 @@ static int __init ubi_init(void) p->vid_hdr_offs, p->max_beb_per1024); mutex_unlock(&ubi_devices_mutex); if (err < 0) { - ubi_err("cannot attach mtd%d", mtd->index); + ubi_err(UBI_MAX_DEVICES, "cannot attach mtd%d", + mtd->index); put_mtd_device(mtd); /* @@ -1326,7 +1345,8 @@ out_version: out_class: class_destroy(ubi_class); out: - ubi_err("cannot initialize UBI, error %d", err); + ubi_err(UBI_MAX_DEVICES, + "cannot initialize UBI, error %d", err); return err; } late_initcall(ubi_init); @@ -1365,7 +1385,8 @@ static int __init bytes_str_to_int(const char *str) result = simple_strtoul(str, &endp, 0); if (str == endp || result >= INT_MAX) { - ubi_err("incorrect bytes count: \"%s\"\n", str); + ubi_err(UBI_MAX_DEVICES, + "incorrect bytes count: \"%s\"\n", str); return -EINVAL; } @@ -1381,7 +1402,8 @@ static int __init bytes_str_to_int(const char *str) case '\0': break; default: - ubi_err("incorrect bytes count: \"%s\"\n", str); + ubi_err(UBI_MAX_DEVICES, + "incorrect bytes count: \"%s\"\n", str); return -EINVAL; } @@ -1408,20 +1430,22 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) return -EINVAL; if (mtd_devs == UBI_MAX_DEVICES) { - ubi_err("too many parameters, max. is %d\n", + ubi_err(UBI_MAX_DEVICES, + "too many parameters, max. is %d\n", UBI_MAX_DEVICES); return -EINVAL; } len = strnlen(val, MTD_PARAM_LEN_MAX); if (len == MTD_PARAM_LEN_MAX) { - ubi_err("parameter \"%s\" is too long, max. is %d\n", + ubi_err(UBI_MAX_DEVICES, + "parameter \"%s\" is too long, max. is %d\n", val, MTD_PARAM_LEN_MAX); return -EINVAL; } if (len == 0) { - pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n"); + ubi_warn(UBI_MAX_DEVICES, "empty 'mtd=' parameter - ignored\n"); return 0; } @@ -1435,7 +1459,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) tokens[i] = strsep(&pbuf, ","); if (pbuf) { - ubi_err("too many arguments at \"%s\"\n", val); + ubi_err(UBI_MAX_DEVICES, "too many arguments at \"%s\"\n", + val); return -EINVAL; } @@ -1455,7 +1480,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) int err = kstrtoint(token, 10, &p->max_beb_per1024); if (err) { - ubi_err("bad value for max_beb_per1024 parameter: %s", + ubi_err(UBI_MAX_DEVICES, + "bad value for max_beb_per1024 parameter: %s", token); return -EINVAL; } diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 7646220..81d64b3 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -48,13 +48,14 @@ /** * get_exclusive - get exclusive access to an UBI volume. + * @ubi: UBI device description object * @desc: volume descriptor * * This function changes UBI volume open mode to "exclusive". Returns previous * mode value (positive integer) in case of success and a negative error code * in case of failure. */ -static int get_exclusive(struct ubi_volume_desc *desc) +static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc) { int users, err; struct ubi_volume *vol = desc->vol; @@ -63,7 +64,8 @@ static int get_exclusive(struct ubi_volume_desc *desc) users = vol->readers + vol->writers + vol->exclusive; ubi_assert(users > 0); if (users > 1) { - ubi_err("%d users for volume %d", users, vol->vol_id); + ubi_err(ubi->ubi_num, "%d users for volume %d", + users, vol->vol_id); err = -EBUSY; } else { vol->readers = vol->writers = 0; @@ -134,7 +136,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) vol->ubi->ubi_num, vol->vol_id, desc->mode); if (vol->updating) { - ubi_warn("update of volume %d not finished, volume is damaged", + ubi_warn(vol->ubi->ubi_num, "update of volume %d not finished, volume is damaged", vol->vol_id); ubi_assert(!vol->changing_leb); vol->updating = 0; @@ -158,7 +160,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) if (vol->updating) { /* Update is in progress, seeking is prohibited */ - ubi_err("updating"); + ubi_err(vol->ubi->ubi_num, "updating"); return -EBUSY; } @@ -193,11 +195,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, count, *offp, vol->vol_id); if (vol->updating) { - ubi_err("updating"); + ubi_err(vol->ubi->ubi_num, "updating"); return -EBUSY; } if (vol->upd_marker) { - ubi_err("damaged volume, update marker is set"); + ubi_err(vol->ubi->ubi_num, "damaged volume, update marker is set"); return -EBADF; } if (*offp == vol->used_bytes || count == 0) @@ -277,7 +279,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, lnum = div_u64_rem(*offp, vol->usable_leb_size, &off); if (off & (ubi->min_io_size - 1)) { - ubi_err("unaligned position"); + ubi_err(ubi->ubi_num, "unaligned position"); return -EINVAL; } @@ -286,7 +288,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, /* We can write only in fractions of the minimum I/O unit */ if (count & (ubi->min_io_size - 1)) { - ubi_err("unaligned write length"); + ubi_err(ubi->ubi_num, "unaligned write length"); return -EINVAL; } @@ -348,7 +350,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, err = ubi_more_leb_change_data(ubi, vol, buf, count); if (err < 0) { - ubi_err("cannot accept more %zd bytes of data, error %d", + ubi_err(ubi->ubi_num, "cannot accept more %zd bytes of data, error %d", count, err); return err; } @@ -370,7 +372,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, return err; if (err) { - ubi_warn("volume %d on UBI device %d is corrupted", + ubi_warn(ubi->ubi_num, "volume %d on UBI device %d is corrupted", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } @@ -420,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, break; } - err = get_exclusive(desc); + err = get_exclusive(ubi, desc); if (err < 0) break; @@ -454,7 +456,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, req.bytes < 0 || req.lnum >= vol->usable_leb_size) break; - err = get_exclusive(desc); + err = get_exclusive(ubi, desc); if (err < 0) break; @@ -640,7 +642,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi, return 0; bad: - ubi_err("bad volume creation request"); + ubi_err(ubi->ubi_num, "bad volume creation request"); ubi_dump_mkvol_req(req); return err; } @@ -706,12 +708,12 @@ static int rename_volumes(struct ubi_device *ubi, for (i = 0; i < req->count - 1; i++) { for (n = i + 1; n < req->count; n++) { if (req->ents[i].vol_id == req->ents[n].vol_id) { - ubi_err("duplicated volume id %d", + ubi_err(ubi->ubi_num, "duplicated volume id %d", req->ents[i].vol_id); return -EINVAL; } if (!strcmp(req->ents[i].name, req->ents[n].name)) { - ubi_err("duplicated volume name \"%s\"", + ubi_err(ubi->ubi_num, "duplicated volume name \"%s\"", req->ents[i].name); return -EINVAL; } @@ -734,7 +736,8 @@ static int rename_volumes(struct ubi_device *ubi, re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE); if (IS_ERR(re->desc)) { err = PTR_ERR(re->desc); - ubi_err("cannot open volume %d, error %d", vol_id, err); + ubi_err(ubi->ubi_num, + "cannot open volume %d, error %d", vol_id, err); kfree(re); goto out_free; } @@ -793,7 +796,7 @@ static int rename_volumes(struct ubi_device *ubi, continue; /* The volume exists but busy, or an error occurred */ - ubi_err("cannot open volume \"%s\", error %d", + ubi_err(ubi->ubi_num, "cannot open volume \"%s\", error %d", re->new_name, err); goto out_free; } diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 63cb1d7..e92bc1c 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -43,12 +43,13 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) return; err = mtd_read(ubi->mtd, addr, len, &read, buf); if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi->ubi_num, + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", err, len, pnum, offset, read); goto out; } - ubi_msg("dumping %d bytes of data from PEB %d, offset %d", + ubi_msg(ubi->ubi_num, "dumping %d bytes of data from PEB %d, offset %d", len, pnum, offset); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); out: @@ -238,7 +239,7 @@ int ubi_debugfs_init(void) if (IS_ERR_OR_NULL(dfs_rootdir)) { int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); - ubi_err("cannot create \"ubi\" debugfs directory, error %d\n", + ubi_err(UBI_MAX_DEVICES, "cannot create \"ubi\" debugfs directory, error %d\n", err); return err; } @@ -433,7 +434,7 @@ out_remove: debugfs_remove_recursive(d->dfs_dir); out: err = dent ? PTR_ERR(dent) : -ENODEV; - ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n", + ubi_err(ubi->ubi_num, "cannot create \"%s\" debugfs file or directory, error %d\n", fname, err); return err; } diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0e11671d..eb93dfd 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -422,7 +422,7 @@ retry: */ if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_BAD_HDR) { - ubi_warn("corrupted VID header at PEB %d, LEB %d:%d", + ubi_warn(ubi->ubi_num, "corrupted VID header at PEB %d, LEB %d:%d", pnum, vol_id, lnum); err = -EBADMSG; } else @@ -449,7 +449,7 @@ retry: goto out_unlock; scrub = 1; if (!check) { - ubi_msg("force data checking"); + ubi_msg(ubi->ubi_num, "force data checking"); check = 1; goto retry; } @@ -460,7 +460,7 @@ retry: if (check) { uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len); if (crc1 != crc) { - ubi_warn("CRC error: calculated %#08x, must be %#08x", + ubi_warn(ubi->ubi_num, "CRC error: calculated %#08x, must be %#08x", crc1, crc); err = -EBADMSG; goto out_unlock; @@ -514,7 +514,8 @@ retry: return new_pnum; } - ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); + ubi_msg(ubi->ubi_num, "recover PEB %d, move data to PEB %d", + pnum, new_pnum); err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); if (err && err != UBI_IO_BITFLIPS) { @@ -555,7 +556,7 @@ retry: up_read(&ubi->fm_sem); ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); - ubi_msg("data was successfully recovered"); + ubi_msg(ubi->ubi_num, "data was successfully recovered"); return 0; out_unlock: @@ -570,13 +571,13 @@ write_error: * Bad luck? This physical eraseblock is bad too? Crud. Let's try to * get another one. */ - ubi_warn("failed to write to PEB %d", new_pnum); + ubi_warn(ubi->ubi_num, "failed to write to PEB %d", new_pnum); ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); if (++tries > UBI_IO_RETRIES) { ubi_free_vid_hdr(ubi, vid_hdr); return err; } - ubi_msg("try again"); + ubi_msg(ubi->ubi_num, "try again"); goto retry; } @@ -614,7 +615,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { - ubi_warn("failed to write data to PEB %d", pnum); + ubi_warn(ubi->ubi_num, + "failed to write data to PEB %d", pnum); if (err == -EIO && ubi->bad_allowed) err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); @@ -655,7 +657,7 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } @@ -663,7 +665,7 @@ retry: if (len) { err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { - ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", + ubi_warn(ubi->ubi_num, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); goto write_error; } @@ -699,7 +701,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi->ubi_num, "try another PEB"); goto retry; } @@ -776,14 +778,14 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", + ubi_warn(ubi->ubi_num, "failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } @@ -819,7 +821,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi->ubi_num, "try another PEB"); goto retry; } @@ -894,14 +896,14 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", + ubi_warn(ubi->ubi_num, "failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } @@ -941,7 +943,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi->ubi_num, "try another PEB"); goto retry; } @@ -1064,7 +1066,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, dbg_wl("read %d bytes of data", aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data from PEB %d", + ubi_warn(ubi->ubi_num, "error %d while reading data from PEB %d", err, from); err = MOVE_SOURCE_RD_ERR; goto out_unlock_buf; @@ -1114,7 +1116,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading VID header back from PEB %d", + ubi_warn(ubi->ubi_num, "error %d while reading VID header back from PEB %d", err, to); if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; @@ -1141,7 +1143,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data back from PEB %d", + ubi_warn(ubi->ubi_num, "error %d while reading data back from PEB %d", err, to); if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; @@ -1153,7 +1155,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) { - ubi_warn("read data back from PEB %d and it is different", + ubi_warn(ubi->ubi_num, "read data back from PEB %d and it is different", to); err = -EINVAL; goto out_unlock_buf; @@ -1206,10 +1208,10 @@ static void print_rsvd_warning(struct ubi_device *ubi, return; } - ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", + ubi_warn(ubi->ubi_num, "cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); if (ubi->corr_peb_count) - ubi_warn("%d PEBs are corrupted and not used", + ubi_warn(ubi->ubi_num, "%d PEBs are corrupted and not used", ubi->corr_peb_count); } @@ -1287,7 +1289,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, fm_eba[i][j] == UBI_LEB_UNMAPPED) continue; - ubi_err("LEB:%i:%i is PEB:%i instead of %i!", + ubi_err(ubi->ubi_num, "LEB:%i:%i is PEB:%i instead of %i!", vol->vol_id, i, fm_eba[i][j], scan_eba[i][j]); ubi_assert(0); @@ -1367,10 +1369,10 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai) } if (ubi->avail_pebs < EBA_RESERVED_PEBS) { - ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi_err(ubi->ubi_num, "no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, EBA_RESERVED_PEBS); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", ubi->corr_peb_count); err = -ENOSPC; goto out_free; diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 0431b46..35f5d44 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -329,7 +329,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, if (found) av = tmp_av; else { - ubi_err("orphaned volume in fastmap pool!"); + ubi_err(ubi->ubi_num, "orphaned volume in fastmap pool!"); return UBI_BAD_FASTMAP; } @@ -412,14 +412,14 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, pnum = be32_to_cpu(pebs[i]); if (ubi_io_is_bad(ubi, pnum)) { - ubi_err("bad PEB in fastmap pool!"); + ubi_err(ubi->ubi_num, "bad PEB in fastmap pool!"); ret = UBI_BAD_FASTMAP; goto out; } err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("unable to read EC header! PEB:%i err:%i", + ubi_err(ubi->ubi_num, "unable to read EC header! PEB:%i err:%i", pnum, err); ret = err > 0 ? UBI_BAD_FASTMAP : err; goto out; @@ -433,7 +433,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, image_seq = be32_to_cpu(ech->image_seq); if (image_seq && (image_seq != ubi->image_seq)) { - ubi_err("bad image seq: 0x%x, expected: 0x%x", + ubi_err(ubi->ubi_num, "bad image seq: 0x%x, expected: 0x%x", be32_to_cpu(ech->image_seq), ubi->image_seq); ret = UBI_BAD_FASTMAP; goto out; @@ -491,7 +491,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } } else { /* We are paranoid and fall back to scanning mode */ - ubi_err("fastmap pool PEBs contains damaged PEBs!"); + ubi_err(ubi->ubi_num, "fastmap pool PEBs contains damaged PEBs!"); ret = err > 0 ? UBI_BAD_FASTMAP : err; goto out; } @@ -586,7 +586,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) { - ubi_err("bad fastmap header magic: 0x%x, expected: 0x%x", + ubi_err(ubi->ubi_num, "bad fastmap header magic: 0x%x, expected: 0x%x", be32_to_cpu(fmhdr->magic), UBI_FM_HDR_MAGIC); goto fail_bad; } @@ -596,7 +596,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; if (be32_to_cpu(fmpl1->magic) != UBI_FM_POOL_MAGIC) { - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", + ubi_err(ubi->ubi_num, "bad fastmap pool magic: 0x%x, expected: 0x%x", be32_to_cpu(fmpl1->magic), UBI_FM_POOL_MAGIC); goto fail_bad; } @@ -606,7 +606,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; if (be32_to_cpu(fmpl2->magic) != UBI_FM_POOL_MAGIC) { - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", + ubi_err(ubi->ubi_num, "bad fastmap pool magic: 0x%x, expected: 0x%x", be32_to_cpu(fmpl2->magic), UBI_FM_POOL_MAGIC); goto fail_bad; } @@ -617,25 +617,27 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, fm->max_wl_pool_size = be16_to_cpu(fmpl2->max_size); if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) { - ubi_err("bad pool size: %i", pool_size); + ubi_err(ubi->ubi_num, "bad pool size: %i", pool_size); goto fail_bad; } if (wl_pool_size > UBI_FM_MAX_POOL_SIZE || wl_pool_size < 0) { - ubi_err("bad WL pool size: %i", wl_pool_size); + ubi_err(ubi->ubi_num, "bad WL pool size: %i", wl_pool_size); goto fail_bad; } if (fm->max_pool_size > UBI_FM_MAX_POOL_SIZE || fm->max_pool_size < 0) { - ubi_err("bad maximal pool size: %i", fm->max_pool_size); + ubi_err(ubi->ubi_num, "bad maximal pool size: %i", + fm->max_pool_size); goto fail_bad; } if (fm->max_wl_pool_size > UBI_FM_MAX_POOL_SIZE || fm->max_wl_pool_size < 0) { - ubi_err("bad maximal WL pool size: %i", fm->max_wl_pool_size); + ubi_err(ubi->ubi_num, "bad maximal WL pool size: %i", + fm->max_wl_pool_size); goto fail_bad; } @@ -694,8 +696,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fmvhdr->magic) != UBI_FM_VHDR_MAGIC) { - ubi_err("bad fastmap vol header magic: 0x%x, " \ - "expected: 0x%x", + ubi_err(ubi->ubi_num, + "bad fastmap vol header magic: 0x%x, expected: 0x%x", be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC); goto fail_bad; } @@ -720,7 +722,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fm_eba->magic) != UBI_FM_EBA_MAGIC) { - ubi_err("bad fastmap EBA header magic: 0x%x, " \ + ubi_err(ubi->ubi_num, "bad fastmap EBA header magic: 0x%x, " "expected: 0x%x", be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC); goto fail_bad; @@ -786,7 +788,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, int err; if (ubi_io_is_bad(ubi, tmp_aeb->pnum)) { - ubi_err("bad PEB in fastmap EBA orphan list"); + ubi_err(ubi->ubi_num, "bad PEB in fastmap EBA orphan list"); ret = UBI_BAD_FASTMAP; kfree(ech); goto fail; @@ -794,8 +796,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, err = ubi_io_read_ec_hdr(ubi, tmp_aeb->pnum, ech, 0); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("unable to read EC header! PEB:%i " \ - "err:%i", tmp_aeb->pnum, err); + ubi_err(ubi->ubi_num, + "unable to read EC header! PEB:%i err:%i", + tmp_aeb->pnum, err); ret = err > 0 ? UBI_BAD_FASTMAP : err; kfree(ech); @@ -906,14 +909,14 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, fm->to_be_tortured[0] = 1; if (be32_to_cpu(fmsb->magic) != UBI_FM_SB_MAGIC) { - ubi_err("bad super block magic: 0x%x, expected: 0x%x", + ubi_err(ubi->ubi_num, "bad super block magic: 0x%x, expected: 0x%x", be32_to_cpu(fmsb->magic), UBI_FM_SB_MAGIC); ret = UBI_BAD_FASTMAP; goto free_fm_sb; } if (fmsb->version != UBI_FM_FMT_VERSION) { - ubi_err("bad fastmap version: %i, expected: %i", + ubi_err(ubi->ubi_num, "bad fastmap version: %i, expected: %i", fmsb->version, UBI_FM_FMT_VERSION); ret = UBI_BAD_FASTMAP; goto free_fm_sb; @@ -921,14 +924,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, used_blocks = be32_to_cpu(fmsb->used_blocks); if (used_blocks > UBI_FM_MAX_BLOCKS || used_blocks < 1) { - ubi_err("number of fastmap blocks is invalid: %i", used_blocks); + ubi_err(ubi->ubi_num, + "number of fastmap blocks is invalid: %i", used_blocks); ret = UBI_BAD_FASTMAP; goto free_fm_sb; } fm_size = ubi->leb_size * used_blocks; if (fm_size != ubi->fm_size) { - ubi_err("bad fastmap size: %zi, expected: %zi", fm_size, + ubi_err(ubi->ubi_num, + "bad fastmap size: %zi, expected: %zi", fm_size, ubi->fm_size); ret = UBI_BAD_FASTMAP; goto free_fm_sb; @@ -958,7 +963,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i EC (PEB: %i)", + ubi_err(ubi->ubi_num, + "unable to read fastmap block# %i EC (PEB: %i)", i, pnum); if (ret > 0) ret = UBI_BAD_FASTMAP; @@ -975,7 +981,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, * we shouldn't fail if image_seq == 0. */ if (image_seq && (image_seq != ubi->image_seq)) { - ubi_err("wrong image seq:%d instead of %d", + ubi_err(ubi->ubi_num, + "wrong image seq:%d instead of %d", be32_to_cpu(ech->image_seq), ubi->image_seq); ret = UBI_BAD_FASTMAP; goto free_hdr; @@ -983,14 +990,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i (PEB: %i)", + ubi_err(ubi->ubi_num, + "unable to read fastmap block# %i (PEB: %i)", i, pnum); goto free_hdr; } if (i == 0) { if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { - ubi_err("bad fastmap anchor vol_id: 0x%x," \ + ubi_err(ubi->ubi_num, + "bad fastmap anchor vol_id: 0x%x," " expected: 0x%x", be32_to_cpu(vh->vol_id), UBI_FM_SB_VOLUME_ID); @@ -999,7 +1008,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, } } else { if (be32_to_cpu(vh->vol_id) != UBI_FM_DATA_VOLUME_ID) { - ubi_err("bad fastmap data vol_id: 0x%x," \ + ubi_err(ubi->ubi_num, + "bad fastmap data vol_id: 0x%x," " expected: 0x%x", be32_to_cpu(vh->vol_id), UBI_FM_DATA_VOLUME_ID); @@ -1014,7 +1024,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum, ubi->leb_start, ubi->leb_size); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i (PEB: %i, " \ + ubi_err(ubi->ubi_num, + "unable to read fastmap block# %i (PEB: %i, " "err: %i)", i, pnum, ret); goto free_hdr; } @@ -1028,8 +1039,9 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, fmsb2->data_crc = 0; crc = crc32(UBI_CRC32_INIT, ubi->fm_buf, fm_size); if (crc != tmp_crc) { - ubi_err("fastmap data CRC is invalid"); - ubi_err("CRC should be: 0x%x, calc: 0x%x", tmp_crc, crc); + ubi_err(ubi->ubi_num, "fastmap data CRC is invalid"); + ubi_err(ubi->ubi_num, "CRC should be: 0x%x, calc: 0x%x", + tmp_crc, crc); ret = UBI_BAD_FASTMAP; goto free_hdr; } @@ -1065,9 +1077,10 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ubi->fm = fm; ubi->fm_pool.max_size = ubi->fm->max_pool_size; ubi->fm_wl_pool.max_size = ubi->fm->max_wl_pool_size; - ubi_msg("attached by fastmap"); - ubi_msg("fastmap pool size: %d", ubi->fm_pool.max_size); - ubi_msg("fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); + ubi_msg(ubi->ubi_num, "attached by fastmap"); + ubi_msg(ubi->ubi_num, "fastmap pool size: %d", ubi->fm_pool.max_size); + ubi_msg(ubi->ubi_num, "fastmap WL pool size: %d", + ubi->fm_wl_pool.max_size); ubi->fm_disabled = 0; ubi_free_vid_hdr(ubi, vh); @@ -1075,7 +1088,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, out: mutex_unlock(&ubi->fm_mutex); if (ret == UBI_BAD_FASTMAP) - ubi_err("Attach by fastmap failed, doing a full scan!"); + ubi_err(ubi->ubi_num, + "Attach by fastmap failed, doing a full scan!"); return ret; free_hdr: @@ -1271,7 +1285,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum); ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avhdr); if (ret) { - ubi_err("unable to write vid_hdr to fastmap SB!"); + ubi_err(ubi->ubi_num, "unable to write vid_hdr to fastmap SB!"); goto out_kfree; } @@ -1291,7 +1305,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum)); ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvhdr); if (ret) { - ubi_err("unable to write vid_hdr to PEB %i!", + ubi_err(ubi->ubi_num, + "unable to write vid_hdr to PEB %i!", new_fm->e[i]->pnum); goto out_kfree; } @@ -1301,7 +1316,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size), new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size); if (ret) { - ubi_err("unable to write fastmap to PEB %i!", + ubi_err(ubi->ubi_num, + "unable to write fastmap to PEB %i!", new_fm->e[i]->pnum); goto out_kfree; } @@ -1448,7 +1464,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) ubi->fm = NULL; if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) { - ubi_err("fastmap too large"); + ubi_err(ubi->ubi_num, "fastmap too large"); ret = -ENOSPC; goto err; } @@ -1460,7 +1476,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) if (!tmp_e && !old_fm) { int j; - ubi_err("could not get any free erase block"); + ubi_err(ubi->ubi_num, + "could not get any free erase block"); for (j = 1; j < i; j++) ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); @@ -1476,7 +1493,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); - ubi_err("could not erase old fastmap PEB"); + ubi_err(ubi->ubi_num, + "could not erase old fastmap PEB"); goto err; } @@ -1502,7 +1520,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) ret = erase_block(ubi, old_fm->e[0]->pnum); if (ret < 0) { int i; - ubi_err("could not erase old anchor PEB"); + ubi_err(ubi->ubi_num, + "could not erase old anchor PEB"); for (i = 1; i < new_fm->used_blocks; i++) ubi_wl_put_fm_peb(ubi, new_fm->e[i], @@ -1523,7 +1542,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) } else { if (!tmp_e) { int i; - ubi_err("could not find any anchor PEB"); + ubi_err(ubi->ubi_num, "could not find any anchor PEB"); for (i = 1; i < new_fm->used_blocks; i++) ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0); @@ -1553,13 +1572,14 @@ out_unlock: err: kfree(new_fm); - ubi_warn("Unable to write new fastmap, err=%i", ret); + ubi_warn(ubi->ubi_num, "Unable to write new fastmap, err=%i", ret); ret = 0; if (old_fm) { ret = invalidate_fastmap(ubi, old_fm); if (ret < 0) - ubi_err("Unable to invalidiate current fastmap!"); + ubi_err(ubi->ubi_num, + "Unable to invalidiate current fastmap!"); else if (ret) ret = 0; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index d361349..237c902 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -177,19 +177,22 @@ retry: * enabled. A corresponding message will be printed * later, when it is has been scrubbed. */ - ubi_msg("fixable bit-flip detected at PEB %d", pnum); + ubi_msg(ubi->ubi_num, + "fixable bit-flip detected at PEB %d", pnum); ubi_assert(len == read); return UBI_IO_BITFLIPS; } if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", + ubi_warn(ubi->ubi_num, + "error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", err, errstr, len, pnum, offset, read); yield(); goto retry; } - ubi_err("error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi->ubi_num, + "error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", err, errstr, len, pnum, offset, read); dump_stack(); @@ -246,7 +249,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi->ubi_num, "read-only mode"); return -EROFS; } @@ -273,7 +276,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, } if (ubi_dbg_is_write_failure(ubi)) { - ubi_err("cannot write %d bytes to PEB %d:%d (emulated)", + ubi_err(ubi->ubi_num, + "cannot write %d bytes to PEB %d:%d (emulated)", len, pnum, offset); dump_stack(); return -EIO; @@ -282,7 +286,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, addr = (loff_t)pnum * ubi->peb_size + offset; err = mtd_write(ubi->mtd, addr, len, &written, buf); if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written %zd bytes", + ubi_err(ubi->ubi_num, + "error %d while writing %d bytes to PEB %d:%d, written %zd bytes", err, len, pnum, offset, written); dump_stack(); ubi_dump_flash(ubi, pnum, offset, len); @@ -338,7 +343,7 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) ubi_assert(pnum >= 0 && pnum < ubi->peb_count); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi->ubi_num, "read-only mode"); return -EROFS; } @@ -355,12 +360,14 @@ retry: err = mtd_erase(ubi->mtd, &ei); if (err) { if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error %d while erasing PEB %d, retry", + ubi_warn(ubi->ubi_num, + "error %d while erasing PEB %d, retry", err, pnum); yield(); goto retry; } - ubi_err("cannot erase PEB %d, error %d", pnum, err); + ubi_err(ubi->ubi_num, + "cannot erase PEB %d, error %d", pnum, err); dump_stack(); return err; } @@ -368,17 +375,18 @@ retry: err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || ei.state == MTD_ERASE_FAILED); if (err) { - ubi_err("interrupted PEB %d erasure", pnum); + ubi_err(ubi->ubi_num, "interrupted PEB %d erasure", pnum); return -EINTR; } if (ei.state == MTD_ERASE_FAILED) { if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error while erasing PEB %d, retry", pnum); + ubi_warn(ubi->ubi_num, + "error while erasing PEB %d, retry", pnum); yield(); goto retry; } - ubi_err("cannot erase PEB %d", pnum); + ubi_err(ubi->ubi_num, "cannot erase PEB %d", pnum); dump_stack(); return -EIO; } @@ -388,7 +396,7 @@ retry: return err; if (ubi_dbg_is_erase_failure(ubi)) { - ubi_err("cannot erase PEB %d (emulated)", pnum); + ubi_err(ubi->ubi_num, "cannot erase PEB %d (emulated)", pnum); return -EIO; } @@ -411,7 +419,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) { int err, i, patt_count; - ubi_msg("run torture test for PEB %d", pnum); + ubi_msg(ubi->ubi_num, "run torture test for PEB %d", pnum); patt_count = ARRAY_SIZE(patterns); ubi_assert(patt_count > 0); @@ -428,7 +436,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size); if (err == 0) { - ubi_err("erased PEB %d, but a non-0xFF byte found", + ubi_err(ubi->ubi_num, + "erased PEB %d, but a non-0xFF byte found", pnum); err = -EIO; goto out; @@ -448,7 +457,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) err = ubi_check_pattern(ubi->peb_buf, patterns[i], ubi->peb_size); if (err == 0) { - ubi_err("pattern %x checking failed for PEB %d", + ubi_err(ubi->ubi_num, + "pattern %x checking failed for PEB %d", patterns[i], pnum); err = -EIO; goto out; @@ -456,7 +466,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) } err = patt_count; - ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum); + ubi_msg(ubi->ubi_num, + "PEB %d passed torture test, do not mark it as bad", pnum); out: mutex_unlock(&ubi->buf_mutex); @@ -466,7 +477,8 @@ out: * has not passed because it happened on a freshly erased * physical eraseblock which means something is wrong with it. */ - ubi_err("read problems on freshly erased PEB %d, must be bad", + ubi_err(ubi->ubi_num, + "read problems on freshly erased PEB %d, must be bad", pnum); err = -EIO; } @@ -542,7 +554,8 @@ error: * it. Supposedly the flash media or the driver is screwed up, so * return an error. */ - ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err); + ubi_err(ubi->ubi_num, + "cannot invalidate PEB %d, write returned %d", pnum, err); ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); return -EIO; } @@ -574,7 +587,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) return err; if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi->ubi_num, "read-only mode"); return -EROFS; } @@ -616,7 +629,8 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size); if (ret < 0) - ubi_err("error %d while checking if PEB %d is bad", + ubi_err(ubi->ubi_num, + "error %d while checking if PEB %d is bad", ret, pnum); else if (ret) dbg_io("PEB %d is bad", pnum); @@ -642,7 +656,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) ubi_assert(pnum >= 0 && pnum < ubi->peb_count); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi->ubi_num, "read-only mode"); return -EROFS; } @@ -651,7 +665,8 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size); if (err) - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); + ubi_err(ubi->ubi_num, + "cannot mark PEB %d bad, error %d", pnum, err); return err; } @@ -674,32 +689,33 @@ static int validate_ec_hdr(const struct ubi_device *ubi, leb_start = be32_to_cpu(ec_hdr->data_offset); if (ec_hdr->version != UBI_VERSION) { - ubi_err("node with incompatible UBI version found: this UBI version is %d, image version is %d", + ubi_err(ubi->ubi_num, + "node with incompatible UBI version found: this UBI version is %d, image version is %d", UBI_VERSION, (int)ec_hdr->version); goto bad; } if (vid_hdr_offset != ubi->vid_hdr_offset) { - ubi_err("bad VID header offset %d, expected %d", + ubi_err(ubi->ubi_num, "bad VID header offset %d, expected %d", vid_hdr_offset, ubi->vid_hdr_offset); goto bad; } if (leb_start != ubi->leb_start) { - ubi_err("bad data offset %d, expected %d", + ubi_err(ubi->ubi_num, "bad data offset %d, expected %d", leb_start, ubi->leb_start); goto bad; } if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) { - ubi_err("bad erase counter %lld", ec); + ubi_err(ubi->ubi_num, "bad erase counter %lld", ec); goto bad; } return 0; bad: - ubi_err("bad EC header"); + ubi_err(ubi->ubi_num, "bad EC header"); ubi_dump_ec_hdr(ec_hdr); dump_stack(); return 1; @@ -765,7 +781,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ if (verbose) - ubi_warn("no EC header found at PEB %d, only 0xFF bytes", + ubi_warn(ubi->ubi_num, + "no EC header found at PEB %d, only 0xFF bytes", pnum); dbg_bld("no EC header found at PEB %d, only 0xFF bytes", pnum); @@ -780,7 +797,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, * 0xFF bytes. Report that the header is corrupted. */ if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", + ubi_warn(ubi->ubi_num, + "bad magic number at PEB %d: %08x instead of %08x", pnum, magic, UBI_EC_HDR_MAGIC); ubi_dump_ec_hdr(ec_hdr); } @@ -794,7 +812,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (hdr_crc != crc) { if (verbose) { - ubi_warn("bad EC header CRC at PEB %d, calculated %#08x, read %#08x", + ubi_warn(ubi->ubi_num, + "bad EC header CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); ubi_dump_ec_hdr(ec_hdr); } @@ -810,7 +829,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, /* And of course validate what has just been read from the media */ err = validate_ec_hdr(ubi, ec_hdr); if (err) { - ubi_err("validation failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "validation failed for PEB %d", pnum); return -EINVAL; } @@ -884,40 +903,40 @@ static int validate_vid_hdr(const struct ubi_device *ubi, int usable_leb_size = ubi->leb_size - data_pad; if (copy_flag != 0 && copy_flag != 1) { - ubi_err("bad copy_flag"); + ubi_err(ubi->ubi_num, "bad copy_flag"); goto bad; } if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 || data_pad < 0) { - ubi_err("negative values"); + ubi_err(ubi->ubi_num, "negative values"); goto bad; } if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("bad vol_id"); + ubi_err(ubi->ubi_num, "bad vol_id"); goto bad; } if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) { - ubi_err("bad compat"); + ubi_err(ubi->ubi_num, "bad compat"); goto bad; } if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE && compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE && compat != UBI_COMPAT_REJECT) { - ubi_err("bad compat"); + ubi_err(ubi->ubi_num, "bad compat"); goto bad; } if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { - ubi_err("bad vol_type"); + ubi_err(ubi->ubi_num, "bad vol_type"); goto bad; } if (data_pad >= ubi->leb_size / 2) { - ubi_err("bad data_pad"); + ubi_err(ubi->ubi_num, "bad data_pad"); goto bad; } @@ -929,45 +948,46 @@ static int validate_vid_hdr(const struct ubi_device *ubi, * mapped logical eraseblocks. */ if (used_ebs == 0) { - ubi_err("zero used_ebs"); + ubi_err(ubi->ubi_num, "zero used_ebs"); goto bad; } if (data_size == 0) { - ubi_err("zero data_size"); + ubi_err(ubi->ubi_num, "zero data_size"); goto bad; } if (lnum < used_ebs - 1) { if (data_size != usable_leb_size) { - ubi_err("bad data_size"); + ubi_err(ubi->ubi_num, "bad data_size"); goto bad; } } else if (lnum == used_ebs - 1) { if (data_size == 0) { - ubi_err("bad data_size at last LEB"); + ubi_err(ubi->ubi_num, + "bad data_size at last LEB"); goto bad; } } else { - ubi_err("too high lnum"); + ubi_err(ubi->ubi_num, "too high lnum"); goto bad; } } else { if (copy_flag == 0) { if (data_crc != 0) { - ubi_err("non-zero data CRC"); + ubi_err(ubi->ubi_num, "non-zero data CRC"); goto bad; } if (data_size != 0) { - ubi_err("non-zero data_size"); + ubi_err(ubi->ubi_num, "non-zero data_size"); goto bad; } } else { if (data_size == 0) { - ubi_err("zero data_size of copy"); + ubi_err(ubi->ubi_num, "zero data_size of copy"); goto bad; } } if (used_ebs != 0) { - ubi_err("bad used_ebs"); + ubi_err(ubi->ubi_num, "bad used_ebs"); goto bad; } } @@ -975,7 +995,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, return 0; bad: - ubi_err("bad VID header"); + ubi_err(ubi->ubi_num, "bad VID header"); ubi_dump_vid_hdr(vid_hdr); dump_stack(); return 1; @@ -1020,7 +1040,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { if (verbose) - ubi_warn("no VID header found at PEB %d, only 0xFF bytes", + ubi_warn(ubi->ubi_num, + "no VID header found at PEB %d, only 0xFF bytes", pnum); dbg_bld("no VID header found at PEB %d, only 0xFF bytes", pnum); @@ -1031,7 +1052,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", + ubi_warn(ubi->ubi_num, + "bad magic number at PEB %d: %08x instead of %08x", pnum, magic, UBI_VID_HDR_MAGIC); ubi_dump_vid_hdr(vid_hdr); } @@ -1045,7 +1067,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, if (hdr_crc != crc) { if (verbose) { - ubi_warn("bad CRC at PEB %d, calculated %#08x, read %#08x", + ubi_warn(ubi->ubi_num, + "bad CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); ubi_dump_vid_hdr(vid_hdr); } @@ -1059,7 +1082,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, err = validate_vid_hdr(ubi, vid_hdr); if (err) { - ubi_err("validation failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "validation failed for PEB %d", pnum); return -EINVAL; } @@ -1129,7 +1152,7 @@ static int self_check_not_bad(const struct ubi_device *ubi, int pnum) if (!err) return err; - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); dump_stack(); return err > 0 ? -EINVAL : err; } @@ -1154,14 +1177,14 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum, magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - ubi_err("bad magic %#08x, must be %#08x", + ubi_err(ubi->ubi_num, "bad magic %#08x, must be %#08x", magic, UBI_EC_HDR_MAGIC); goto fail; } err = validate_ec_hdr(ubi, ec_hdr); if (err) { - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); goto fail; } @@ -1201,8 +1224,9 @@ static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); if (hdr_crc != crc) { - ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "bad CRC, calculated %#08x, read %#08x", + crc, hdr_crc); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); ubi_dump_ec_hdr(ec_hdr); dump_stack(); err = -EINVAL; @@ -1236,21 +1260,22 @@ static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum, magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", + ubi_err(ubi->ubi_num, + "bad VID header magic %#08x at PEB %d, must be %#08x", magic, pnum, UBI_VID_HDR_MAGIC); goto fail; } err = validate_vid_hdr(ubi, vid_hdr); if (err) { - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); goto fail; } return err; fail: - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); dump_stack(); return -EINVAL; @@ -1288,9 +1313,10 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); if (hdr_crc != crc) { - ubi_err("bad VID header CRC at PEB %d, calculated %#08x, read %#08x", + ubi_err(ubi->ubi_num, + "bad VID header CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); dump_stack(); err = -EINVAL; @@ -1329,7 +1355,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf1) { - ubi_err("cannot allocate memory to check writes"); + ubi_err(ubi->ubi_num, "cannot allocate memory to check writes"); return 0; } @@ -1345,15 +1371,17 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, if (c == c1) continue; - ubi_err("self-check failed for PEB %d:%d, len %d", + ubi_err(ubi->ubi_num, "self-check failed for PEB %d:%d, len %d", pnum, offset, len); - ubi_msg("data differ at position %d", i); + ubi_msg(ubi->ubi_num, "data differ at position %d", i); dump_len = max_t(int, 128, len - i); - ubi_msg("hex dump of the original buffer from %d to %d", + ubi_msg(ubi->ubi_num, + "hex dump of the original buffer from %d to %d", i, i + dump_len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf + i, dump_len, 1); - ubi_msg("hex dump of the read buffer from %d to %d", + ubi_msg(ubi->ubi_num, + "hex dump of the read buffer from %d to %d", i, i + dump_len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf1 + i, dump_len, 1); @@ -1393,20 +1421,22 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf) { - ubi_err("cannot allocate memory to check for 0xFFs"); + ubi_err(ubi->ubi_num, "cannot allocate memory to check for 0xFFs"); return 0; } err = mtd_read(ubi->mtd, addr, len, &read, buf); if (err && !mtd_is_bitflip(err)) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi->ubi_num, + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", err, len, pnum, offset, read); goto error; } err = ubi_check_pattern(buf, 0xFF, len); if (err == 0) { - ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", + ubi_err(ubi->ubi_num, + "flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", pnum, offset, len); goto fail; } @@ -1415,8 +1445,9 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) return 0; fail: - ubi_err("self-check failed for PEB %d", pnum); - ubi_msg("hex dump of the %d-%d region", offset, offset + len); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); + ubi_msg(ubi->ubi_num, "hex dump of the %d-%d region", + offset, offset + len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); err = -EINVAL; error: diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 3aac1ac..e19d4ba 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -204,7 +204,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) return ERR_PTR(err); } if (err == 1) { - ubi_warn("volume %d on UBI device %d is corrupted", + ubi_warn(ubi->ubi_num, "volume %d on UBI device %d is corrupted", vol_id, ubi->ubi_num); vol->corrupted = 1; } @@ -221,7 +221,7 @@ out_free: kfree(desc); out_put_ubi: ubi_put_device(ubi); - ubi_err("cannot open device %d, volume %d, error %d", + ubi_err(ubi->ubi_num, "cannot open device %d, volume %d, error %d", ubi_num, vol_id, err); return ERR_PTR(err); } @@ -411,7 +411,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { - ubi_warn("mark volume %d as corrupted", vol_id); + ubi_warn(ubi->ubi_num, "mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index f913d70..113947f 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -111,7 +111,8 @@ void ubi_update_reserved(struct ubi_device *ubi) ubi->avail_pebs -= need; ubi->rsvd_pebs += need; ubi->beb_rsvd_pebs += need; - ubi_msg("reserved more %d PEBs for bad PEB handling", need); + ubi_msg(ubi->ubi_num, + "reserved more %d PEBs for bad PEB handling", need); } /** @@ -128,7 +129,8 @@ void ubi_calculate_reserved(struct ubi_device *ubi) ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count; if (ubi->beb_rsvd_level < 0) { ubi->beb_rsvd_level = 0; - ubi_warn("number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", + ubi_warn(ubi->ubi_num, + "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", ubi->bad_peb_count, ubi->bad_peb_limit); } } diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..956e5ff 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -50,13 +50,14 @@ #define UBI_NAME_STR "ubi" /* Normal UBI messages */ -#define ubi_msg(fmt, ...) pr_notice("UBI: " fmt "\n", ##__VA_ARGS__) +#define ubi_msg(ubi_num, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", ubi_num, \ + __func__, ##__VA_ARGS__) /* UBI warning messages */ -#define ubi_warn(fmt, ...) pr_warn("UBI warning: %s: " fmt "\n", \ - __func__, ##__VA_ARGS__) +#define ubi_warn(ubi_num, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \ + ubi_num, __func__, ##__VA_ARGS__) /* UBI error messages */ -#define ubi_err(fmt, ...) pr_err("UBI error: %s: " fmt "\n", \ - __func__, ##__VA_ARGS__) +#define ubi_err(ubi_num, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \ + ubi_num, __func__, ##__VA_ARGS__) /* Background thread name pattern */ #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd" @@ -985,7 +986,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi) { if (!ubi->ro_mode) { ubi->ro_mode = 1; - ubi_warn("switch to read-only mode"); + ubi_warn(ubi->ubi_num, "switch to read-only mode"); dump_stack(); } } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 8330703..6f1b996 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -223,7 +223,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) } if (vol_id == UBI_VOL_NUM_AUTO) { - ubi_err("out of volume IDs"); + ubi_err(ubi->ubi_num, "out of volume IDs"); err = -ENFILE; goto out_unlock; } @@ -237,7 +237,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Ensure that this volume does not exist */ err = -EEXIST; if (ubi->volumes[vol_id]) { - ubi_err("volume %d already exists", vol_id); + ubi_err(ubi->ubi_num, "volume %d already exists", vol_id); goto out_unlock; } @@ -246,7 +246,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) if (ubi->volumes[i] && ubi->volumes[i]->name_len == req->name_len && !strcmp(ubi->volumes[i]->name, req->name)) { - ubi_err("volume \"%s\" exists (ID %d)", req->name, i); + ubi_err(ubi->ubi_num, "volume \"%s\" exists (ID %d)", + req->name, i); goto out_unlock; } @@ -257,9 +258,11 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs, only %d available", ubi->avail_pebs); + ubi_err(ubi->ubi_num, "not enough PEBs, only %d available", + ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi->ubi_num, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); err = -ENOSPC; goto out_unlock; @@ -314,7 +317,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); err = cdev_add(&vol->cdev, dev, 1); if (err) { - ubi_err("cannot add character device"); + ubi_err(ubi->ubi_num, "cannot add character device"); goto out_mapping; } @@ -326,7 +329,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); err = device_register(&vol->dev); if (err) { - ubi_err("cannot register device"); + ubi_err(ubi->ubi_num, "cannot register device"); goto out_cdev; } @@ -386,7 +389,7 @@ out_unlock: kfree(vol); else put_device(&vol->dev); - ubi_err("cannot create volume %d, error %d", vol_id, err); + ubi_err(ubi->ubi_num, "cannot create volume %d, error %d", vol_id, err); return err; } @@ -454,7 +457,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) return err; out_err: - ubi_err("cannot remove volume %d, error %d", vol_id, err); + ubi_err(ubi->ubi_num, "cannot remove volume %d, error %d", vol_id, err); spin_lock(&ubi->volumes_lock); ubi->volumes[vol_id] = vol; out_unlock: @@ -487,7 +490,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (vol->vol_type == UBI_STATIC_VOLUME && reserved_pebs < vol->used_ebs) { - ubi_err("too small size %d, %d LEBs contain data", + ubi_err(ubi->ubi_num, "too small size %d, %d LEBs contain data", reserved_pebs, vol->used_ebs); return -EINVAL; } @@ -516,10 +519,12 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (pebs > 0) { spin_lock(&ubi->volumes_lock); if (pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs: requested %d, available %d", + ubi_err(ubi->ubi_num, + "not enough PEBs: requested %d, available %d", pebs, ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi->ubi_num, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); spin_unlock(&ubi->volumes_lock); err = -ENOSPC; @@ -643,7 +648,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); err = cdev_add(&vol->cdev, dev, 1); if (err) { - ubi_err("cannot add character device for volume %d, error %d", + ubi_err(ubi->ubi_num, + "cannot add character device for volume %d, error %d", vol_id, err); return err; } @@ -710,7 +716,8 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (!vol) { if (reserved_pebs) { - ubi_err("no volume info, but volume exists"); + ubi_err(ubi->ubi_num, + "no volume info, but volume exists"); goto fail; } spin_unlock(&ubi->volumes_lock); @@ -719,90 +726,93 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || vol->name_len < 0) { - ubi_err("negative values"); + ubi_err(ubi->ubi_num, "negative values"); goto fail; } if (vol->alignment > ubi->leb_size || vol->alignment == 0) { - ubi_err("bad alignment"); + ubi_err(ubi->ubi_num, "bad alignment"); goto fail; } n = vol->alignment & (ubi->min_io_size - 1); if (vol->alignment != 1 && n) { - ubi_err("alignment is not multiple of min I/O unit"); + ubi_err(ubi->ubi_num, + "alignment is not multiple of min I/O unit"); goto fail; } n = ubi->leb_size % vol->alignment; if (vol->data_pad != n) { - ubi_err("bad data_pad, has to be %lld", n); + ubi_err(ubi->ubi_num, "bad data_pad, has to be %lld", n); goto fail; } if (vol->vol_type != UBI_DYNAMIC_VOLUME && vol->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); + ubi_err(ubi->ubi_num, "bad vol_type"); goto fail; } if (vol->upd_marker && vol->corrupted) { - ubi_err("update marker and corrupted simultaneously"); + ubi_err(ubi->ubi_num, + "update marker and corrupted simultaneously"); goto fail; } if (vol->reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs"); + ubi_err(ubi->ubi_num, "too large reserved_pebs"); goto fail; } n = ubi->leb_size - vol->data_pad; if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { - ubi_err("bad usable_leb_size, has to be %lld", n); + ubi_err(ubi->ubi_num, "bad usable_leb_size, has to be %lld", n); goto fail; } if (vol->name_len > UBI_VOL_NAME_MAX) { - ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); + ubi_err(ubi->ubi_num, "too long volume name, max is %d", + UBI_VOL_NAME_MAX); goto fail; } n = strnlen(vol->name, vol->name_len + 1); if (n != vol->name_len) { - ubi_err("bad name_len %lld", n); + ubi_err(ubi->ubi_num, "bad name_len %lld", n); goto fail; } n = (long long)vol->used_ebs * vol->usable_leb_size; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->corrupted) { - ubi_err("corrupted dynamic volume"); + ubi_err(ubi->ubi_num, "corrupted dynamic volume"); goto fail; } if (vol->used_ebs != vol->reserved_pebs) { - ubi_err("bad used_ebs"); + ubi_err(ubi->ubi_num, "bad used_ebs"); goto fail; } if (vol->last_eb_bytes != vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); + ubi_err(ubi->ubi_num, "bad last_eb_bytes"); goto fail; } if (vol->used_bytes != n) { - ubi_err("bad used_bytes"); + ubi_err(ubi->ubi_num, "bad used_bytes"); goto fail; } } else { if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { - ubi_err("bad used_ebs"); + ubi_err(ubi->ubi_num, "bad used_ebs"); goto fail; } if (vol->last_eb_bytes < 0 || vol->last_eb_bytes > vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); + ubi_err(ubi->ubi_num, "bad last_eb_bytes"); goto fail; } if (vol->used_bytes < 0 || vol->used_bytes > n || vol->used_bytes < n - vol->usable_leb_size) { - ubi_err("bad used_bytes"); + ubi_err(ubi->ubi_num, "bad used_bytes"); goto fail; } } @@ -820,7 +830,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (alignment != vol->alignment || data_pad != vol->data_pad || upd_marker != vol->upd_marker || vol_type != vol->vol_type || name_len != vol->name_len || strncmp(name, vol->name, name_len)) { - ubi_err("volume info is different"); + ubi_err(ubi->ubi_num, "volume info is different"); goto fail; } @@ -828,7 +838,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) return 0; fail: - ubi_err("self-check failed for volume %d", vol_id); + ubi_err(ubi->ubi_num, "self-check failed for volume %d", vol_id); if (vol) ubi_dump_vol_info(vol); ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 07cac5f..f01aab7 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -190,7 +190,7 @@ static int vtbl_check(const struct ubi_device *ubi, crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); if (be32_to_cpu(vtbl[i].crc) != crc) { - ubi_err("bad CRC at record %u: %#08x, not %#08x", + ubi_err(ubi->ubi_num, "bad CRC at record %u: %#08x, not %#08x", i, crc, be32_to_cpu(vtbl[i].crc)); ubi_dump_vtbl_record(&vtbl[i], i); return 1; @@ -224,7 +224,7 @@ static int vtbl_check(const struct ubi_device *ubi, n = ubi->leb_size % alignment; if (data_pad != n) { - ubi_err("bad data_pad, has to be %d", n); + ubi_err(ubi->ubi_num, "bad data_pad, has to be %d", n); err = 6; goto bad; } @@ -240,7 +240,7 @@ static int vtbl_check(const struct ubi_device *ubi, } if (reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs %d, good PEBs %d", + ubi_err(ubi->ubi_num, "too large reserved_pebs %d, good PEBs %d", reserved_pebs, ubi->good_peb_count); err = 9; goto bad; @@ -270,7 +270,8 @@ static int vtbl_check(const struct ubi_device *ubi, if (len1 > 0 && len1 == len2 && !strncmp(vtbl[i].name, vtbl[n].name, len1)) { - ubi_err("volumes %d and %d have the same name \"%s\"", + ubi_err(ubi->ubi_num, + "volumes %d and %d have the same name \"%s\"", i, n, vtbl[i].name); ubi_dump_vtbl_record(&vtbl[i], i); ubi_dump_vtbl_record(&vtbl[n], n); @@ -282,7 +283,8 @@ static int vtbl_check(const struct ubi_device *ubi, return 0; bad: - ubi_err("volume table check failed: record %d, error %d", i, err); + ubi_err(ubi->ubi_num, + "volume table check failed: record %d, error %d", i, err); ubi_dump_vtbl_record(&vtbl[i], i); return -EINVAL; } @@ -446,11 +448,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); if (leb_corrupted[1]) { - ubi_warn("volume table copy #2 is corrupted"); + ubi_warn(ubi->ubi_num, "volume table copy #2 is corrupted"); err = create_vtbl(ubi, ai, 1, leb[0]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi->ubi_num, "volume table was restored"); } /* Both LEB 1 and LEB 2 are OK and consistent */ @@ -465,15 +467,15 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, } if (leb_corrupted[1]) { /* Both LEB 0 and LEB 1 are corrupted */ - ubi_err("both volume tables are corrupted"); + ubi_err(ubi->ubi_num, "both volume tables are corrupted"); goto out_free; } - ubi_warn("volume table copy #1 is corrupted"); + ubi_warn(ubi->ubi_num, "volume table copy #1 is corrupted"); err = create_vtbl(ubi, ai, 0, leb[1]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi->ubi_num, "volume table was restored"); vfree(leb[0]); return leb[1]; @@ -562,7 +564,7 @@ static int init_volumes(struct ubi_device *ubi, if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { - ubi_err("more than one auto-resize volume (%d and %d)", + ubi_err(ubi->ubi_num, "more than one auto-resize volume (%d and %d)", ubi->autoresize_vol_id, i); kfree(vol); return -EINVAL; @@ -608,7 +610,7 @@ static int init_volumes(struct ubi_device *ubi, * We found a static volume which misses several * eraseblocks. Treat it as corrupted. */ - ubi_warn("static volume %d misses %d LEBs - corrupted", + ubi_warn(ubi->ubi_num, "static volume %d misses %d LEBs - corrupted", av->vol_id, av->used_ebs - av->leb_count); vol->corrupted = 1; continue; @@ -646,10 +648,10 @@ static int init_volumes(struct ubi_device *ubi, vol->ubi = ubi; if (reserved_pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs, required %d, available %d", + ubi_err(ubi->ubi_num, "not enough PEBs, required %d, available %d", reserved_pebs, ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", ubi->corr_peb_count); } ubi->rsvd_pebs += reserved_pebs; @@ -660,13 +662,14 @@ static int init_volumes(struct ubi_device *ubi, /** * check_av - check volume attaching information. + * @ubi: UBI device description object * @vol: UBI volume description object * @av: volume attaching information * * This function returns zero if the volume attaching information is consistent * to the data read from the volume tabla, and %-EINVAL if not. */ -static int check_av(const struct ubi_volume *vol, +static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, const struct ubi_ainf_volume *av) { int err; @@ -694,7 +697,7 @@ static int check_av(const struct ubi_volume *vol, return 0; bad: - ubi_err("bad attaching information, error %d", err); + ubi_err(ubi->ubi_num, "bad attaching information, error %d", err); ubi_dump_av(av); ubi_dump_vol_info(vol); return -EINVAL; @@ -718,14 +721,16 @@ static int check_attaching_info(const struct ubi_device *ubi, struct ubi_volume *vol; if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { - ubi_err("found %d volumes while attaching, maximum is %d + %d", + ubi_err(ubi->ubi_num, + "found %d volumes while attaching, maximum is %d + %d", ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); return -EINVAL; } if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && ai->highest_vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("too large volume ID %d found", ai->highest_vol_id); + ubi_err(ubi->ubi_num, "too large volume ID %d found", + ai->highest_vol_id); return -EINVAL; } @@ -753,10 +758,11 @@ static int check_attaching_info(const struct ubi_device *ubi, * reboot while the volume was being removed. Discard * these eraseblocks. */ - ubi_msg("finish volume %d removal", av->vol_id); + ubi_msg(ubi->ubi_num, "finish volume %d removal", + av->vol_id); ubi_remove_av(ai, av); } else if (av) { - err = check_av(vol, av); + err = check_av(ubi, vol, av); if (err) return err; } @@ -807,13 +813,15 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) if (IS_ERR(ubi->vtbl)) return PTR_ERR(ubi->vtbl); } else { - ubi_err("the layout volume was not found"); + ubi_err(ubi->ubi_num, + "the layout volume was not found"); return -EINVAL; } } else { if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { /* This must not happen with proper UBI images */ - ubi_err("too many LEBs (%d) in layout volume", + ubi_err(ubi->ubi_num, + "too many LEBs (%d) in layout volume", av->leb_count); return -EINVAL; } @@ -862,7 +870,7 @@ static void self_vtbl_check(const struct ubi_device *ubi) return; if (vtbl_check(ubi, ubi->vtbl)) { - ubi_err("self-check failed"); + ubi_err(ubi->ubi_num, "self-check failed"); BUG(); } } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..ae6cbb6 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -253,7 +253,7 @@ static int do_work(struct ubi_device *ubi) */ err = wrk->func(ubi, wrk, 0); if (err) - ubi_err("work failed with error code %d", err); + ubi_err(ubi->ubi_num, "work failed with error code %d", err); up_read(&ubi->work_sem); return err; @@ -470,8 +470,12 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) { struct ubi_wl_entry *e = NULL; - if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) + if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) { + ubi_warn(ubi->ubi_num, + "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d", + anchor, ubi->free_count, ubi->beb_rsvd_pebs); goto out; + } if (anchor) e = find_anchor_wl_entry(&ubi->free); @@ -507,7 +511,7 @@ static int __wl_get_peb(struct ubi_device *ubi) retry: if (!ubi->free.rb_node) { if (ubi->works_count == 0) { - ubi_err("no free eraseblocks"); + ubi_err(ubi->ubi_num, "no free eraseblocks"); ubi_assert(list_empty(&ubi->works)); return -ENOSPC; } @@ -520,7 +524,7 @@ retry: e = find_mean_wl_entry(ubi, &ubi->free); if (!e) { - ubi_err("no free eraseblocks"); + ubi_err(ubi->ubi_num, "no free eraseblocks"); return -ENOSPC; } @@ -692,7 +696,8 @@ int ubi_wl_get_peb(struct ubi_device *ubi) err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, ubi->peb_size - ubi->vid_hdr_aloffset); if (err) { - ubi_err("new PEB %d does not contain all 0xFF bytes", peb); + ubi_err(ubi->ubi_num, + "new PEB %d does not contain all 0xFF bytes", peb); return err; } @@ -760,7 +765,8 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ - ubi_err("erase counter overflow at PEB %d, EC %llu", + ubi_err(ubi->ubi_num, + "erase counter overflow at PEB %d, EC %llu", e->pnum, ec); err = -EINVAL; goto out_free; @@ -1136,7 +1142,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, goto out_not_moved; } - ubi_err("error %d while reading VID header from PEB %d", + ubi_err(ubi->ubi_num, + "error %d while reading VID header from PEB %d", err, e1->pnum); goto out_error; } @@ -1180,7 +1187,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * UBI from trying to move it over and over again. */ if (ubi->erroneous_peb_count > ubi->max_erroneous) { - ubi_err("too many erroneous eraseblocks (%d)", + ubi_err(ubi->ubi_num, + "too many erroneous eraseblocks (%d)", ubi->erroneous_peb_count); goto out_error; } @@ -1196,7 +1204,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, /* The PEB has been successfully moved */ if (scrubbing) - ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", + ubi_msg(ubi->ubi_num, + "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", e1->pnum, vol_id, lnum, e2->pnum); ubi_free_vid_hdr(ubi, vid_hdr); @@ -1273,10 +1282,11 @@ out_not_moved: out_error: if (vol_id != -1) - ubi_err("error %d while moving PEB %d to PEB %d", + ubi_err(ubi->ubi_num, "error %d while moving PEB %d to PEB %d", err, e1->pnum, e2->pnum); else - ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d", + ubi_err(ubi->ubi_num, + "error %d while moving PEB %d (LEB %d:%d) to PEB %d", err, e1->pnum, vol_id, lnum, e2->pnum); spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; @@ -1456,7 +1466,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, return err; } - ubi_err("failed to erase PEB %d, error %d", pnum, err); + ubi_err(ubi->ubi_num, "failed to erase PEB %d, error %d", pnum, err); kfree(wl_wrk); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || @@ -1484,7 +1494,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, /* It is %-EIO, the PEB went bad */ if (!ubi->bad_allowed) { - ubi_err("bad physical eraseblock %d detected", pnum); + ubi_err(ubi->ubi_num, "bad physical eraseblock %d detected", + pnum); goto out_ro; } @@ -1492,7 +1503,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, if (ubi->beb_rsvd_pebs == 0) { if (ubi->avail_pebs == 0) { spin_unlock(&ubi->volumes_lock); - ubi_err("no reserved/available physical eraseblocks"); + ubi_err(ubi->ubi_num, + "no reserved/available physical eraseblocks"); goto out_ro; } ubi->avail_pebs -= 1; @@ -1500,7 +1512,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, } spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); + ubi_msg(ubi->ubi_num, "mark PEB %d as bad", pnum); err = ubi_io_mark_bad(ubi, pnum); if (err) goto out_ro; @@ -1521,11 +1533,13 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ubi->good_peb_count -= 1; ubi_calculate_reserved(ubi); if (available_consumed) - ubi_warn("no PEBs in the reserved pool, used an available PEB"); + ubi_warn(ubi->ubi_num, + "no PEBs in the reserved pool, used an available PEB"); else if (ubi->beb_rsvd_pebs) - ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs); + ubi_msg(ubi->ubi_num, "%d PEBs left in the reserve", + ubi->beb_rsvd_pebs); else - ubi_warn("last PEB from the reserve was used"); + ubi_warn(ubi->ubi_num, "last PEB from the reserve was used"); spin_unlock(&ubi->volumes_lock); return err; @@ -1611,7 +1625,7 @@ retry: } else { err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi->ubi_num, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); return err; @@ -1676,7 +1690,7 @@ retry: err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi->ubi_num, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); return err; @@ -1796,15 +1810,19 @@ int ubi_thread(void *u) int failures = 0; struct ubi_device *ubi = u; - ubi_msg("background thread \"%s\" started, PID %d", + ubi_msg(ubi->ubi_num, "background thread \"%s\" started, PID %d", ubi->bgt_name, task_pid_nr(current)); set_freezable(); for (;;) { int err; - if (kthread_should_stop()) + if (kthread_should_stop()) { + ubi_msg(ubi->ubi_num, + "background thread \"%s\" should stop, PID %d", + ubi->bgt_name, task_pid_nr(current)); break; + } if (try_to_freeze()) continue; @@ -1821,14 +1839,16 @@ int ubi_thread(void *u) err = do_work(ubi); if (err) { - ubi_err("%s: work failed with error code %d", + ubi_err(ubi->ubi_num, + "%s: work failed with error code %d", ubi->bgt_name, err); if (failures++ > WL_MAX_FAILURES) { /* * Too many failures, disable the thread and * switch to read-only mode. */ - ubi_msg("%s: %d consecutive failures", + ubi_msg(ubi->ubi_num, + "%s: %d consecutive failures", ubi->bgt_name, WL_MAX_FAILURES); ubi_ro_mode(ubi); ubi->thread_enabled = 0; @@ -1979,10 +1999,12 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) #endif if (ubi->avail_pebs < reserved_pebs) { - ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi_err(ubi->ubi_num, + "no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, reserved_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi->ubi_num, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); goto out_free; } @@ -2028,7 +2050,7 @@ static void protection_queue_destroy(struct ubi_device *ubi) */ void ubi_wl_close(struct ubi_device *ubi) { - dbg_wl("close the WL sub-system"); + ubi_msg(ubi->ubi_num, "close the WL sub-system"); cancel_pending(ubi); protection_queue_destroy(ubi); tree_destroy(&ubi->used); @@ -2070,8 +2092,9 @@ static int self_check_ec(struct ubi_device *ubi, int pnum, int ec) read_ec = be64_to_cpu(ec_hdr->ec); if (ec != read_ec && read_ec - ec > 1) { - ubi_err("self-check failed for PEB %d", pnum); - ubi_err("read EC is %lld, should be %d", read_ec, ec); + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); + ubi_err(ubi->ubi_num, "read EC is %lld, should be %d", + read_ec, ec); dump_stack(); err = 1; } else @@ -2100,7 +2123,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, if (in_wl_tree(e, root)) return 0; - ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ", + ubi_err(ubi->ubi_num, + "self-check failed for PEB %d, EC %d, RB-tree %p ", e->pnum, e->ec, root); dump_stack(); return -EINVAL; @@ -2128,7 +2152,8 @@ static int self_check_in_pq(const struct ubi_device *ubi, if (p == e) return 0; - ubi_err("self-check failed for PEB %d, EC %d, Protect queue", + ubi_err(ubi->ubi_num, + "self-check failed for PEB %d, EC %d, Protect queue", e->pnum, e->ec); dump_stack(); return -EINVAL; -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:36:47 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:36:47 +0300 Subject: [RFC/PATCH 0/5] mtd:ubi: Read disturb and Data retention handling Message-ID: <1411886207-8028-1-git-send-email-tlinder@codeaurora.org> One of the limitations of the NAND devices is the method used to read NAND flash memory may cause bit-flips on the surrounding cells and result in uncorrectable ECC errors. This is known as the read disturb or data retention. Today?s Linux NAND drivers implementation doesn?t address the read disturb and the data retention limitations of the NAND devices. To date these issues could be overlooked since the possibility of their occurrence in today?s NAND devices is very low. With the evolution of NAND devices and the requirement for a ?long life? NAND flash, read disturb and data retention can no longer be ignored otherwise there will be data loss over time. The following patch set implements handling of Read-disturb and Data retention by the UBI layer. Tanya Brokhman (2): mtd: ubi: Read disturb infrastructure mtd: ubi: Add sysfs entry to force all pebs' scan Tatyana Brokhman (3): mtd: ubi: Fill read disturb statistics mtd: ubi: Make in_wl_tree function public mtd: ubi: Read threshold verification drivers/mtd/ubi/attach.c | 137 ++++++++++++++++------ drivers/mtd/ubi/build.c | 81 +++++++++++++ drivers/mtd/ubi/debug.c | 11 ++ drivers/mtd/ubi/eba.c | 7 +- drivers/mtd/ubi/fastmap.c | 132 ++++++++++++++++++---- drivers/mtd/ubi/io.c | 28 +++++ drivers/mtd/ubi/ubi-media.h | 32 +++++- drivers/mtd/ubi/ubi.h | 62 +++++++++- drivers/mtd/ubi/vtbl.c | 6 +- drivers/mtd/ubi/wl.c | 270 +++++++++++++++++++++++++++++++++++++++++--- 10 files changed, 690 insertions(+), 76 deletions(-) -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:37:00 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:37:00 +0300 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure Message-ID: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> The need for performing read disturb is determined according to new statistics collected per eraseblock: - read counter: incremented at each read operation reset at each erase - last erase time stamp: updated at each erase This patch adds the infrastructure for the above statistics Signed-off-by: Tanya Brokhman --- drivers/mtd/ubi/build.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/ubi/fastmap.c | 14 +++++++---- drivers/mtd/ubi/ubi-media.h | 32 ++++++++++++++++++++++--- drivers/mtd/ubi/ubi.h | 34 +++++++++++++++++++++++++++ drivers/mtd/ubi/wl.c | 6 +++++ 5 files changed, 135 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6e30a3c..34fe23a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1,6 +1,9 @@ /* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2007 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -118,6 +121,10 @@ static struct class_attribute ubi_version = static ssize_t dev_attribute_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t dev_attribute_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count); + /* UBI device attributes (correspond to files in '//class/ubi/ubiX') */ static struct device_attribute dev_eraseblock_size = __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL); @@ -141,6 +148,12 @@ static struct device_attribute dev_bgt_enabled = __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); static struct device_attribute dev_mtd_num = __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_dt_threshold = + __ATTR(dt_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, + dev_attribute_store); +static struct device_attribute dev_rd_threshold = + __ATTR(rd_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, + dev_attribute_store); /** * ubi_volume_notify - send a volume change notification. @@ -378,6 +391,10 @@ static ssize_t dev_attribute_show(struct device *dev, ret = sprintf(buf, "%d\n", ubi->thread_enabled); else if (attr == &dev_mtd_num) ret = sprintf(buf, "%d\n", ubi->mtd->index); + else if (attr == &dev_dt_threshold) + ret = sprintf(buf, "%d\n", ubi->dt_threshold); + else if (attr == &dev_rd_threshold) + ret = sprintf(buf, "%d\n", ubi->rd_threshold); else ret = -EINVAL; @@ -385,6 +402,38 @@ static ssize_t dev_attribute_show(struct device *dev, return ret; } +static ssize_t dev_attribute_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int value; + struct ubi_device *ubi; + + ubi = container_of(dev, struct ubi_device, dev); + ubi = ubi_get_device(ubi->ubi_num); + if (!ubi) + return -ENODEV; + + if (kstrtos32(buf, 10, &value)) + return -EINVAL; + /* Consider triggering full scan if threshods change */ + else if (attr == &dev_dt_threshold) { + if (value < UBI_MAX_DT_THRESHOLD) + ubi->dt_threshold = value; + else + pr_err("Max supported threshold value is %d", + UBI_MAX_DT_THRESHOLD); + } else if (attr == &dev_rd_threshold) { + if (value < UBI_MAX_READCOUNTER) + ubi->rd_threshold = value; + else + pr_err("Max supported threshold value is %d", + UBI_MAX_READCOUNTER); + } + + return count; +} + static void dev_release(struct device *dev) { struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); @@ -445,6 +494,12 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) if (err) return err; err = device_create_file(&ubi->dev, &dev_mtd_num); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_dt_threshold); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_rd_threshold); return err; } @@ -455,6 +510,8 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) static void ubi_sysfs_close(struct ubi_device *ubi) { device_remove_file(&ubi->dev, &dev_mtd_num); + device_remove_file(&ubi->dev, &dev_dt_threshold); + device_remove_file(&ubi->dev, &dev_rd_threshold); device_remove_file(&ubi->dev, &dev_bgt_enabled); device_remove_file(&ubi->dev, &dev_min_io_size); device_remove_file(&ubi->dev, &dev_max_vol_count); diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 0431b46..5399aa2 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2012 Linutronix GmbH + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * * Author: Richard Weinberger * * This program is free software; you can redistribute it and/or modify @@ -727,9 +729,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, } for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { - int pnum = be32_to_cpu(fm_eba->pnum[j]); + int pnum = be32_to_cpu(fm_eba->peb_data[j].pnum); - if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0) + if ((int)be32_to_cpu(fm_eba->peb_data[j].pnum) < 0) continue; aeb = NULL; @@ -757,7 +759,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, } aeb->lnum = j; - aeb->pnum = be32_to_cpu(fm_eba->pnum[j]); + aeb->pnum = + be32_to_cpu(fm_eba->peb_data[j].pnum); aeb->ec = -1; aeb->scrub = aeb->copy_flag = aeb->sqnum = 0; list_add_tail(&aeb->u.list, &eba_orphans); @@ -1250,11 +1253,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi, vol->vol_type == UBI_STATIC_VOLUME); feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); - fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs); + fm_pos += sizeof(*feba) + + 2 * (sizeof(__be32) * vol->reserved_pebs); ubi_assert(fm_pos <= ubi->fm_size); for (j = 0; j < vol->reserved_pebs; j++) - feba->pnum[j] = cpu_to_be32(vol->eba_tbl[j]); + feba->peb_data[j].pnum = cpu_to_be32(vol->eba_tbl[j]); feba->reserved_pebs = cpu_to_be32(j); feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index ac2b24d..da418ad 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -1,5 +1,8 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,6 +41,15 @@ /* The highest erase counter value supported by this implementation */ #define UBI_MAX_ERASECOUNTER 0x7FFFFFFF +/* The highest read counter value supported by this implementation */ +#define UBI_MAX_READCOUNTER 0x7FFFFFFD /* (0x7FFFFFFF - 2)*/ + +/* + * The highest data retention threshold value supported + * by this implementation + */ +#define UBI_MAX_DT_THRESHOLD 0x7FFFFFFF + /* The initial CRC32 value used when calculating CRC checksums */ #define UBI_CRC32_INIT 0xFFFFFFFFU @@ -130,6 +142,7 @@ enum { * @vid_hdr_offset: where the VID header starts * @data_offset: where the user data start * @image_seq: image sequence number + * @last_erase_time: time stamp of the last erase operation * @padding2: reserved for future, zeroes * @hdr_crc: erase counter header CRC checksum * @@ -162,7 +175,8 @@ struct ubi_ec_hdr { __be32 vid_hdr_offset; __be32 data_offset; __be32 image_seq; - __u8 padding2[32]; + __be64 last_erase_time; /*curr time in sec == unsigned long time_t*/ + __u8 padding2[24]; __be32 hdr_crc; } __packed; @@ -413,6 +427,8 @@ struct ubi_vtbl_record { * @used_blocks: number of PEBs used by this fastmap * @block_loc: an array containing the location of all PEBs of the fastmap * @block_ec: the erase counter of each used PEB + * @block_rc: the read counter of each used PEB + * @block_let: the last erase timestamp of each used PEB * @sqnum: highest sequence number value at the time while taking the fastmap * */ @@ -424,6 +440,8 @@ struct ubi_fm_sb { __be32 used_blocks; __be32 block_loc[UBI_FM_MAX_BLOCKS]; __be32 block_ec[UBI_FM_MAX_BLOCKS]; + __be32 block_rc[UBI_FM_MAX_BLOCKS]; + __be64 block_let[UBI_FM_MAX_BLOCKS]; __be64 sqnum; __u8 padding2[32]; } __packed; @@ -469,13 +487,17 @@ struct ubi_fm_scan_pool { /* ubi_fm_scan_pool is followed by nfree+nused struct ubi_fm_ec records */ /** - * struct ubi_fm_ec - stores the erase counter of a PEB + * struct ubi_fm_ec - stores the erase/read counter of a PEB * @pnum: PEB number * @ec: ec of this PEB + * @rc: rc of this PEB + * @last_erase_time: last erase time stamp of this PEB */ struct ubi_fm_ec { __be32 pnum; __be32 ec; + __be32 rc; + __be64 last_erase_time; } __packed; /** @@ -506,10 +528,14 @@ struct ubi_fm_volhdr { * @magic: EBA table magic number * @reserved_pebs: number of table entries * @pnum: PEB number of LEB (LEB is the index) + * @rc: Read counter of the LEBs PEB (LEB is the index) */ struct ubi_fm_eba { __be32 magic; __be32 reserved_pebs; - __be32 pnum[0]; + struct { + __be32 pnum; + __be32 rc; + } peb_data[0]; } __packed; #endif /* !__UBI_MEDIA_H__ */ diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..6c7e53e 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -1,6 +1,9 @@ /* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2006, 2007 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -84,6 +87,22 @@ #define UBI_UNKNOWN -1 /* + * This parameter defines the maximum read counter of eraseblocks + * of UBI devices. When this threshold is exceeded, UBI starts performing + * wear leveling by means of moving data from eraseblock with low erase + * counter to eraseblocks with high erase counter. + */ +#define UBI_RD_THRESHOLD 100000 + +/* + * This parameter defines the maximun interval (in days) between two + * erasures of an eraseblock. When this interval is reached, UBI starts + * performing wear leveling by means of moving data from eraseblock with + * low erase counter to eraseblocks with high erase counter. + */ +#define UBI_DT_THRESHOLD 120 + +/* * The UBI debugfs directory name pattern and maximum name length (3 for "ubi" * + 2 for the number plus 1 for the trailing zero byte. */ @@ -155,6 +174,8 @@ enum { * @u.rb: link in the corresponding (free/used) RB-tree * @u.list: link in the protection queue * @ec: erase counter + * @last_erase_time: time stamp of the last erase opp + * @rc: read counter * @pnum: physical eraseblock number * * This data structure is used in the WL sub-system. Each physical eraseblock @@ -167,6 +188,8 @@ struct ubi_wl_entry { struct list_head list; } u; int ec; + long last_erase_time; + int rc; int pnum; }; @@ -451,6 +474,10 @@ struct ubi_debug_info { * @bgt_thread: background thread description object * @thread_enabled: if the background thread is enabled * @bgt_name: background thread name + * @rd_threshold: read counter threshold See UBI_RD_THRESHOLD + * for more info + * @dt_threshold: data retention threshold. See UBI_DT_THRESHOLD + * for more info * * @flash_size: underlying MTD device size (in bytes) * @peb_count: count of physical eraseblocks on the MTD device @@ -553,6 +580,9 @@ struct ubi_device { struct task_struct *bgt_thread; int thread_enabled; char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; + int rd_threshold; + int dt_threshold; + /* I/O sub-system's stuff */ long long flash_size; @@ -588,6 +618,8 @@ struct ubi_device { /** * struct ubi_ainf_peb - attach information about a physical eraseblock. * @ec: erase counter (%UBI_UNKNOWN if it is unknown) + * @rc: read counter (%UBI_UNKNOWN if it is unknown) + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it is unknown) * @pnum: physical eraseblock number * @vol_id: ID of the volume this LEB belongs to * @lnum: logical eraseblock number @@ -604,6 +636,8 @@ struct ubi_device { */ struct ubi_ainf_peb { int ec; + int rc; + long last_erase_time; int pnum; int vol_id; int lnum; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..33d33e43 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1,5 +1,8 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1898,6 +1901,9 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) INIT_LIST_HEAD(&ubi->pq[i]); ubi->pq_head = 0; + ubi->rd_threshold = UBI_RD_THRESHOLD; + ubi->dt_threshold = UBI_DT_THRESHOLD; + list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) { cond_resched(); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:37:21 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:37:21 +0300 Subject: [RFC/PATCH 2/5] mtd: ubi: Fill read disturb statistics Message-ID: <1411886241-8434-1-git-send-email-tlinder@codeaurora.org> From: Tatyana Brokhman Fill in eraseblock statistics needed for read disturb decision making: 1. read counter: incremented at each read operation reset at each erase operation Saved only as part of the meta data in RAM On attach: if fastmap data is missing a default value is assigned 2. last erase time stamp: updated at each erase operation. Saved as part of PEB OOB info on flash On attach: if fastmap data is missing retrieved from PEB EC Header on NAND. If fastmap data is corrupted a default value is assigned. The above parameters are saved as part of the fastmap data. Signed-off-by: Tatyana Brokhman Signed-off-by: Dolev Raviv --- drivers/mtd/ubi/attach.c | 137 +++++++++++++++++++++++++++++++++++----------- drivers/mtd/ubi/debug.c | 11 ++++ drivers/mtd/ubi/fastmap.c | 118 ++++++++++++++++++++++++++++++++++----- drivers/mtd/ubi/io.c | 28 ++++++++++ drivers/mtd/ubi/ubi.h | 24 +++++++- drivers/mtd/ubi/vtbl.c | 6 +- drivers/mtd/ubi/wl.c | 47 ++++++++++++++++ 7 files changed, 322 insertions(+), 49 deletions(-) diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 6f27d9a..e102cac 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1,5 +1,8 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,8 +90,21 @@ #include #include #include +#include #include "ubi.h" +#define set_aeb_default_values(aeb, ai) \ + do { \ + if (aeb->ec == UBI_UNKNOWN) { \ + aeb->ec = ai->mean_ec; \ + if (ai->mean_last_erase_time) \ + aeb->last_erase_time = \ + ai->mean_last_erase_time; \ + else \ + aeb->last_erase_time = UBI_DT_THRESHOLD / 2; \ + } \ + } while (0) + static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai); /* Temporary variables used during scanning */ @@ -102,6 +118,9 @@ static struct ubi_vid_hdr *vidh; * @vol_id: the last used volume id for the PEB * @lnum: the last used LEB number for the PEB * @ec: erase counter of the physical eraseblock + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it + * is unknown) + * @rc: read counter (%UBI_UNKNOWN if it is unknown) * @to_head: if not zero, add to the head of the list * @list: the list to add to * @@ -117,7 +136,8 @@ static struct ubi_vid_hdr *vidh; * failure. */ static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id, - int lnum, int ec, int to_head, struct list_head *list) + int lnum, int ec, long last_erase_time, long rc, + int to_head, struct list_head *list) { struct ubi_ainf_peb *aeb; @@ -139,6 +159,9 @@ static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id, aeb->vol_id = vol_id; aeb->lnum = lnum; aeb->ec = ec; + aeb->rc = rc; + aeb->last_erase_time = last_erase_time; + if (to_head) list_add(&aeb->u.list, list); else @@ -151,13 +174,17 @@ static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id, * @ai: attaching information * @pnum: physical eraseblock number to add * @ec: erase counter of the physical eraseblock + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it + * is unknown) + * @rc: read counter (%UBI_UNKNOWN if it is unknown) * * This function allocates a 'struct ubi_ainf_peb' object for a corrupted * physical eraseblock @pnum and adds it to the 'corr' list. The corruption * was presumably not caused by a power cut. Returns zero in case of success * and a negative error code in case of failure. */ -static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) +static int add_corrupted(struct ubi_attach_info *ai, int pnum, + int ec, long rc, long last_erase_time) { struct ubi_ainf_peb *aeb; @@ -170,6 +197,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) ai->corr_peb_count += 1; aeb->pnum = pnum; aeb->ec = ec; + aeb->rc = rc; + aeb->last_erase_time = last_erase_time; list_add(&aeb->u.list, &ai->corr); return 0; } @@ -434,6 +463,9 @@ out_free_vidh: * @ai: attaching information * @pnum: the physical eraseblock number * @ec: erase counter + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it + * is unknown) + * @rc: read counter (%UBI_UNKNOWN if it is unknown) * @vid_hdr: the volume identifier header * @bitflips: if bit-flips were detected when this physical eraseblock was read * @@ -445,7 +477,8 @@ out_free_vidh: * zero in case of success and a negative error code in case of failure. */ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, - int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips) + int ec, long last_erase_time, long rc, + const struct ubi_vid_hdr *vid_hdr, int bitflips) { int err, vol_id, lnum; unsigned long long sqnum; @@ -532,12 +565,16 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, return err; err = add_to_list(ai, aeb->pnum, aeb->vol_id, - aeb->lnum, aeb->ec, cmp_res & 4, + aeb->lnum, aeb->ec, + aeb->last_erase_time, + aeb->rc, cmp_res & 4, &ai->erase); if (err) return err; aeb->ec = ec; + aeb->last_erase_time = last_erase_time; + aeb->rc = rc; aeb->pnum = pnum; aeb->vol_id = vol_id; aeb->lnum = lnum; @@ -556,7 +593,8 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * previously. */ return add_to_list(ai, pnum, vol_id, lnum, ec, - cmp_res & 4, &ai->erase); + last_erase_time, rc, cmp_res & 4, + &ai->erase); } } @@ -574,6 +612,8 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, return -ENOMEM; aeb->ec = ec; + aeb->last_erase_time = last_erase_time; + aeb->rc = rc; aeb->pnum = pnum; aeb->vol_id = vol_id; aeb->lnum = lnum; @@ -650,6 +690,8 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av) * @ai: attaching information * @pnum: physical eraseblock number to erase; * @ec: erase counter value to write (%UBI_UNKNOWN if it is unknown) + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it + * is unknown) * * This function erases physical eraseblock 'pnum', and writes the erase * counter header to it. This function should only be used on UBI device @@ -658,7 +700,8 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av) * case of failure. */ static int early_erase_peb(struct ubi_device *ubi, - const struct ubi_attach_info *ai, int pnum, int ec) + const struct ubi_attach_info *ai, + int pnum, int ec, long last_erase_time) { int err; struct ubi_ec_hdr *ec_hdr; @@ -677,7 +720,7 @@ static int early_erase_peb(struct ubi_device *ubi, return -ENOMEM; ec_hdr->ec = cpu_to_be64(ec); - + ec_hdr->last_erase_time = cpu_to_be64(last_erase_time); err = ubi_io_sync_erase(ubi, pnum, 0); if (err < 0) goto out_free; @@ -708,6 +751,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, { int err = 0; struct ubi_ainf_peb *aeb, *tmp_aeb; + struct timeval tv; if (!list_empty(&ai->free)) { aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list); @@ -722,15 +766,20 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, * so forth. We don't want to take care about bad eraseblocks here - * they'll be handled later. */ + do_gettimeofday(&tv); list_for_each_entry_safe(aeb, tmp_aeb, &ai->erase, u.list) { if (aeb->ec == UBI_UNKNOWN) aeb->ec = ai->mean_ec; - err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1); + /* The last erase time resolution is in days */ + err = early_erase_peb(ubi, ai, aeb->pnum, + aeb->ec+1, tv.tv_sec / NUM_SEC_IN_DAY); if (err) continue; aeb->ec += 1; + aeb->last_erase_time = tv.tv_sec / NUM_SEC_IN_DAY; + aeb->rc = 0; list_del(&aeb->u.list); dbg_bld("return PEB %d, EC %d", aeb->pnum, aeb->ec); return aeb; @@ -817,6 +866,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, int *vid, unsigned long long *sqnum) { long long uninitialized_var(ec); + long long uninitialized_var(rc); + long long uninitialized_var(last_erase_time); int err, bitflips = 0, vol_id = -1, ec_err = 0; dbg_bld("scan PEB %d", pnum); @@ -842,11 +893,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, case UBI_IO_FF: ai->empty_peb_count += 1; return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN, - UBI_UNKNOWN, 0, &ai->erase); + UBI_UNKNOWN, UBI_UNKNOWN, UBI_UNKNOWN, + 0, &ai->erase); case UBI_IO_FF_BITFLIPS: ai->empty_peb_count += 1; return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN, - UBI_UNKNOWN, 1, &ai->erase); + UBI_UNKNOWN, UBI_UNKNOWN, UBI_UNKNOWN, + 1, &ai->erase); case UBI_IO_BAD_HDR_EBADMSG: case UBI_IO_BAD_HDR: /* @@ -856,6 +909,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, */ ec_err = err; ec = UBI_UNKNOWN; + last_erase_time = UBI_UNKNOWN; + rc = UBI_UNKNOWN; bitflips = 1; break; default: @@ -874,6 +929,16 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, } ec = be64_to_cpu(ech->ec); + last_erase_time = be64_to_cpu(ech->last_erase_time); + /* + * Default value for read counter should be 0. If this is a + * free or erased peb, the counter has no meaning. + * If this peb is used, later code will schedule the peb for + * scrubbing. We can afford erasing all used blocks in this + * case as this is a rear case, and not doing so might have + * destructive implication on the system. + */ + rc = 0; if (ec > UBI_MAX_ERASECOUNTER) { /* * Erase counter overflow. The EC headers have 64 bits @@ -957,29 +1022,32 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, else if (!err) /* This corruption is caused by a power cut */ err = add_to_list(ai, pnum, UBI_UNKNOWN, - UBI_UNKNOWN, ec, 1, &ai->erase); + UBI_UNKNOWN, ec, last_erase_time, rc, + 1, &ai->erase); else /* This is an unexpected corruption */ - err = add_corrupted(ai, pnum, ec); + err = add_corrupted(ai, pnum, ec, rc, last_erase_time); if (err) return err; - goto adjust_mean_ec; + goto adjust_mean_av_stat; case UBI_IO_FF_BITFLIPS: err = add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN, - ec, 1, &ai->erase); + ec, last_erase_time, rc, 1, &ai->erase); if (err) return err; - goto adjust_mean_ec; + goto adjust_mean_av_stat; case UBI_IO_FF: if (ec_err || bitflips) err = add_to_list(ai, pnum, UBI_UNKNOWN, - UBI_UNKNOWN, ec, 1, &ai->erase); + UBI_UNKNOWN, ec, last_erase_time, rc, + 1, &ai->erase); else err = add_to_list(ai, pnum, UBI_UNKNOWN, - UBI_UNKNOWN, ec, 0, &ai->free); + UBI_UNKNOWN, ec, last_erase_time, 0, + 0, &ai->free); if (err) return err; - goto adjust_mean_ec; + goto adjust_mean_av_stat; default: ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d", err); @@ -1003,7 +1071,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, vol_id, lnum); } err = add_to_list(ai, pnum, vol_id, lnum, - ec, 1, &ai->erase); + ec, last_erase_time, + rc, 1, &ai->erase); if (err) return err; return 0; @@ -1018,7 +1087,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, ubi_msg("\"preserve\" compatible internal volume %d:%d found", vol_id, lnum); err = add_to_list(ai, pnum, vol_id, lnum, - ec, 0, &ai->alien); + ec, last_erase_time, + rc, 0, &ai->alien); if (err) return err; return 0; @@ -1033,11 +1103,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, if (ec_err) ubi_warn("valid VID header but corrupted EC header at PEB %d", pnum); - err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips); + + err = ubi_add_to_av(ubi, ai, pnum, ec, last_erase_time, + UBI_DEF_RD_THRESHOLD, vidh, bitflips); if (err) return err; -adjust_mean_ec: +adjust_mean_av_stat: if (!ec_err) { ai->ec_sum += ec; ai->ec_count += 1; @@ -1045,6 +1117,8 @@ adjust_mean_ec: ai->max_ec = ec; if (ec < ai->min_ec) ai->min_ec = ec; + ai->last_erase_time_sum += last_erase_time; + ai->last_erase_time_count++; } return 0; @@ -1254,6 +1328,10 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, if (ai->ec_count) ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count); + if (ai->last_erase_time_count) + ai->mean_last_erase_time = div_u64(ai->last_erase_time_sum, + ai->last_erase_time_count); + err = late_analysis(ubi, ai); if (err) goto out_vidh; @@ -1264,22 +1342,17 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, */ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) { ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) - if (aeb->ec == UBI_UNKNOWN) - aeb->ec = ai->mean_ec; + set_aeb_default_values(aeb, ai); } - list_for_each_entry(aeb, &ai->free, u.list) { - if (aeb->ec == UBI_UNKNOWN) - aeb->ec = ai->mean_ec; - } + list_for_each_entry(aeb, &ai->free, u.list) + set_aeb_default_values(aeb, ai); list_for_each_entry(aeb, &ai->corr, u.list) - if (aeb->ec == UBI_UNKNOWN) - aeb->ec = ai->mean_ec; + set_aeb_default_values(aeb, ai); list_for_each_entry(aeb, &ai->erase, u.list) - if (aeb->ec == UBI_UNKNOWN) - aeb->ec = ai->mean_ec; + set_aeb_default_values(aeb, ai); err = self_check_ai(ubi, ai); if (err) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 63cb1d7..d172c7c 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -1,5 +1,8 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +50,14 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) err, len, pnum, offset, read); goto out; } + if (ubi->lookuptbl) { + if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER) + ubi->lookuptbl[pnum]->rc++; + else + ubi_err("read counter overflow at PEB %d, RC %d", + pnum, ubi->lookuptbl[pnum]->rc); + } else + ubi_err("Can't update RC. No lookuptbl"); ubi_msg("dumping %d bytes of data from PEB %d, offset %d", len, pnum, offset); diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 5399aa2..f72980b 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -31,6 +31,7 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi) sizeof(struct ubi_fm_scan_pool) + \ (ubi->peb_count * sizeof(struct ubi_fm_ec)) + \ (sizeof(struct ubi_fm_eba) + \ + (ubi->peb_count * sizeof(__be32)) + \ (ubi->peb_count * sizeof(__be32))) + \ sizeof(struct ubi_fm_volhdr) * UBI_MAX_VOLUMES; return roundup(size, ubi->leb_size); @@ -71,12 +72,16 @@ out: * @list: the target list * @pnum: PEB number of the new attach erase block * @ec: erease counter of the new LEB + * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it + * is unknown) + * @rc: read counter (%UBI_UNKNOWN if it is unknown) * @scrub: scrub this PEB after attaching * * Returns 0 on success, < 0 indicates an internal error. */ static int add_aeb(struct ubi_attach_info *ai, struct list_head *list, - int pnum, int ec, int scrub) + int pnum, int ec, unsigned long last_erase_time, + int rc, int scrub) { struct ubi_ainf_peb *aeb; @@ -86,6 +91,8 @@ static int add_aeb(struct ubi_attach_info *ai, struct list_head *list, aeb->pnum = pnum; aeb->ec = ec; + aeb->rc = rc; + aeb->last_erase_time = last_erase_time; aeb->lnum = -1; aeb->scrub = scrub; aeb->copy_flag = aeb->sqnum = 0; @@ -99,6 +106,9 @@ static int add_aeb(struct ubi_attach_info *ai, struct list_head *list, if (ai->min_ec > aeb->ec) ai->min_ec = aeb->ec; + ai->last_erase_time_sum += aeb->last_erase_time; + ai->last_erase_time_count++; + list_add_tail(&aeb->u.list, list); return 0; @@ -246,6 +256,8 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, return -ENOMEM; victim->ec = aeb->ec; + victim->last_erase_time = aeb->last_erase_time; + victim->rc = aeb->rc; victim->pnum = aeb->pnum; list_add_tail(&victim->u.list, &ai->erase); @@ -257,6 +269,8 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, av->vol_id, aeb->lnum, new_aeb->pnum); aeb->ec = new_aeb->ec; + aeb->last_erase_time = new_aeb->last_erase_time; + aeb->rc = new_aeb->rc; aeb->pnum = new_aeb->pnum; aeb->copy_flag = new_vh->copy_flag; aeb->scrub = new_aeb->scrub; @@ -271,7 +285,7 @@ static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; } - /* This LEB is new, let's add it to the volume */ + /* This LEB is new, last_erase_time's add it to the volume */ if (av->highest_lnum <= be32_to_cpu(new_vh->lnum)) { av->highest_lnum = be32_to_cpu(new_vh->lnum); @@ -444,12 +458,16 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (err == UBI_IO_FF || err == UBI_IO_FF_BITFLIPS) { unsigned long long ec = be64_to_cpu(ech->ec); + unsigned long long last_erase_time = + be64_to_cpu(ech->last_erase_time); unmap_peb(ai, pnum); dbg_bld("Adding PEB to free: %i", pnum); if (err == UBI_IO_FF_BITFLIPS) - add_aeb(ai, free, pnum, ec, 1); + add_aeb(ai, free, pnum, ec, last_erase_time, + 0, 1); else - add_aeb(ai, free, pnum, ec, 0); + add_aeb(ai, free, pnum, ec, last_erase_time, + 0, 0); continue; } else if (err == 0 || err == UBI_IO_BITFLIPS) { dbg_bld("Found non empty PEB:%i in pool", pnum); @@ -477,6 +495,9 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } new_aeb->ec = be64_to_cpu(ech->ec); + new_aeb->last_erase_time = + be64_to_cpu(ech->last_erase_time); + new_aeb->rc = UBI_DEF_RD_THRESHOLD; new_aeb->pnum = pnum; new_aeb->lnum = be32_to_cpu(vh->lnum); new_aeb->sqnum = be64_to_cpu(vh->sqnum); @@ -649,7 +670,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; add_aeb(ai, &ai->free, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); + be32_to_cpu(fmec->ec), + be64_to_cpu(fmec->last_erase_time), + be32_to_cpu(fmec->rc), 0); } /* read EC values from used list */ @@ -660,7 +683,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 0); + be32_to_cpu(fmec->ec), + be64_to_cpu(fmec->last_erase_time), + be32_to_cpu(fmec->rc), 0); } /* read EC values from scrub list */ @@ -671,7 +696,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; add_aeb(ai, &used, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); + be32_to_cpu(fmec->ec), + be64_to_cpu(fmec->last_erase_time), + be32_to_cpu(fmec->rc), 1); } /* read EC values from erase list */ @@ -682,10 +709,14 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; add_aeb(ai, &ai->erase, be32_to_cpu(fmec->pnum), - be32_to_cpu(fmec->ec), 1); + be32_to_cpu(fmec->ec), + be64_to_cpu(fmec->last_erase_time), + be32_to_cpu(fmec->rc), 1); } ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count); + ai->mean_last_erase_time = div_u64(ai->last_erase_time_sum, + ai->last_erase_time_count); ai->bad_peb_count = be32_to_cpu(fmhdr->bad_peb_count); /* Iterate over all volumes and read their EBA table */ @@ -717,7 +748,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, fm_eba = (struct ubi_fm_eba *)(fm_raw + fm_pos); fm_pos += sizeof(*fm_eba); - fm_pos += (sizeof(__be32) * be32_to_cpu(fm_eba->reserved_pebs)); + fm_pos += 2 * (sizeof(__be32) * + be32_to_cpu(fm_eba->reserved_pebs)); if (fm_pos >= fm_size) goto fail_bad; @@ -761,7 +793,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, aeb->lnum = j; aeb->pnum = be32_to_cpu(fm_eba->peb_data[j].pnum); - aeb->ec = -1; + aeb->ec = UBI_UNKNOWN; + aeb->rc = be32_to_cpu(fm_eba->peb_data[j].rc); + aeb->last_erase_time = UBI_UNKNOWN; aeb->scrub = aeb->copy_flag = aeb->sqnum = 0; list_add_tail(&aeb->u.list, &eba_orphans); continue; @@ -807,6 +841,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, tmp_aeb->scrub = 1; tmp_aeb->ec = be64_to_cpu(ech->ec); + tmp_aeb->last_erase_time = + be64_to_cpu(ech->last_erase_time); + tmp_aeb->rc = UBI_DEF_RD_THRESHOLD; assign_aeb_to_av(ai, tmp_aeb, av); } @@ -1062,6 +1099,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, e->pnum = be32_to_cpu(fmsb2->block_loc[i]); e->ec = be32_to_cpu(fmsb2->block_ec[i]); + e->last_erase_time = be64_to_cpu(fmsb2->block_let[i]); + e->rc = be32_to_cpu(fmsb2->block_rc[i]); fm->e[i] = e; } @@ -1179,7 +1218,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fec->pnum = cpu_to_be32(wl_e->pnum); fec->ec = cpu_to_be32(wl_e->ec); - + fec->last_erase_time = cpu_to_be64(wl_e->last_erase_time); + fec->rc = cpu_to_be32(wl_e->rc); free_peb_count++; fm_pos += sizeof(*fec); ubi_assert(fm_pos <= ubi->fm_size); @@ -1192,7 +1232,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fec->pnum = cpu_to_be32(wl_e->pnum); fec->ec = cpu_to_be32(wl_e->ec); - + fec->last_erase_time = cpu_to_be64(wl_e->last_erase_time); + fec->rc = cpu_to_be32(wl_e->rc); used_peb_count++; fm_pos += sizeof(*fec); ubi_assert(fm_pos <= ubi->fm_size); @@ -1205,6 +1246,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fec->pnum = cpu_to_be32(wl_e->pnum); fec->ec = cpu_to_be32(wl_e->ec); + fec->last_erase_time = cpu_to_be64(wl_e->last_erase_time); + fec->rc = cpu_to_be32(wl_e->rc); scrub_peb_count++; fm_pos += sizeof(*fec); @@ -1222,6 +1265,9 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fec->pnum = cpu_to_be32(wl_e->pnum); fec->ec = cpu_to_be32(wl_e->ec); + fec->last_erase_time = + cpu_to_be64(wl_e->last_erase_time); + fec->rc = cpu_to_be32(wl_e->rc); erase_peb_count++; fm_pos += sizeof(*fec); @@ -1257,8 +1303,15 @@ static int ubi_write_fastmap(struct ubi_device *ubi, 2 * (sizeof(__be32) * vol->reserved_pebs); ubi_assert(fm_pos <= ubi->fm_size); - for (j = 0; j < vol->reserved_pebs; j++) + for (j = 0; j < vol->reserved_pebs; j++) { feba->peb_data[j].pnum = cpu_to_be32(vol->eba_tbl[j]); + feba->peb_data[j].rc = cpu_to_be32(UBI_UNKNOWN); + if (vol->eba_tbl[j] >= 0 && + ubi->lookuptbl[vol->eba_tbl[j]]) + feba->peb_data[j].rc = + cpu_to_be32( + ubi->lookuptbl[vol->eba_tbl[j]]->rc); + } feba->reserved_pebs = cpu_to_be32(j); feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); @@ -1282,6 +1335,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, for (i = 0; i < new_fm->used_blocks; i++) { fmsb->block_loc[i] = cpu_to_be32(new_fm->e[i]->pnum); fmsb->block_ec[i] = cpu_to_be32(new_fm->e[i]->ec); + fmsb->block_let[i] = cpu_to_be64(new_fm->e[i]->last_erase_time); + fmsb->block_rc[i] = cpu_to_be32(new_fm->e[i]->rc); } fmsb->data_crc = 0; @@ -1335,6 +1390,7 @@ static int erase_block(struct ubi_device *ubi, int pnum) int ret; struct ubi_ec_hdr *ec_hdr; long long ec; + struct timeval tv; ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); if (!ec_hdr) @@ -1360,6 +1416,9 @@ static int erase_block(struct ubi_device *ubi, int pnum) } ec_hdr->ec = cpu_to_be64(ec); + do_gettimeofday(&tv); + /* The last erase time resolution is in days */ + ec_hdr->last_erase_time = cpu_to_be64(tv.tv_sec / NUM_SEC_IN_DAY); ret = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr); if (ret < 0) goto out; @@ -1382,10 +1441,17 @@ static int invalidate_fastmap(struct ubi_device *ubi, { int ret; struct ubi_vid_hdr *vh; + struct timeval tv; ret = erase_block(ubi, fm->e[0]->pnum); if (ret < 0) return ret; + fm->e[0]->ec = ret; + + do_gettimeofday(&tv); + /* The last erase time resolution is in days */ + fm->e[0]->last_erase_time = tv.tv_sec / NUM_SEC_IN_DAY; + fm->e[0]->rc = 0; vh = new_fm_vhdr(ubi, UBI_FM_SB_VOLUME_ID); if (!vh) @@ -1412,6 +1478,9 @@ int ubi_update_fastmap(struct ubi_device *ubi) int ret, i; struct ubi_fastmap_layout *new_fm, *old_fm; struct ubi_wl_entry *tmp_e; + struct timeval tv; + + do_gettimeofday(&tv); mutex_lock(&ubi->fm_mutex); @@ -1485,10 +1554,19 @@ int ubi_update_fastmap(struct ubi_device *ubi) } new_fm->e[i]->pnum = old_fm->e[i]->pnum; - new_fm->e[i]->ec = old_fm->e[i]->ec; + new_fm->e[i]->ec = old_fm->e[i]->ec = ret; + + /* The last erase time resolution is in days */ + new_fm->e[i]->last_erase_time = + tv.tv_sec / NUM_SEC_IN_DAY; + old_fm->e[i]->last_erase_time = + tv.tv_sec / NUM_SEC_IN_DAY; + new_fm->e[i]->rc = old_fm->e[i]->rc = 0; } else { new_fm->e[i]->pnum = tmp_e->pnum; new_fm->e[i]->ec = tmp_e->ec; + new_fm->e[i]->rc = tmp_e->rc; + new_fm->e[i]->last_erase_time = tmp_e->last_erase_time; if (old_fm) ubi_wl_put_fm_peb(ubi, old_fm->e[i], i, @@ -1515,7 +1593,13 @@ int ubi_update_fastmap(struct ubi_device *ubi) } new_fm->e[0]->pnum = old_fm->e[0]->pnum; - new_fm->e[0]->ec = ret; + new_fm->e[0]->ec = old_fm->e[0]->ec = ret; + /* The last erase time resolution is in days */ + new_fm->e[0]->last_erase_time = + tv.tv_sec / NUM_SEC_IN_DAY; + old_fm->e[0]->last_erase_time = + tv.tv_sec / NUM_SEC_IN_DAY; + new_fm->e[0]->rc = old_fm->e[0]->rc = 0; } else { /* we've got a new anchor PEB, return the old one */ ubi_wl_put_fm_peb(ubi, old_fm->e[0], 0, @@ -1523,6 +1607,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) new_fm->e[0]->pnum = tmp_e->pnum; new_fm->e[0]->ec = tmp_e->ec; + new_fm->e[0]->last_erase_time = tmp_e->last_erase_time; + new_fm->e[0]->rc = tmp_e->rc; } } else { if (!tmp_e) { @@ -1538,6 +1624,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) new_fm->e[0]->pnum = tmp_e->pnum; new_fm->e[0]->ec = tmp_e->ec; + new_fm->e[0]->last_erase_time = tmp_e->last_erase_time; + new_fm->e[0]->rc = tmp_e->rc; } down_write(&ubi->work_sem); diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index d361349..444d552 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -1,6 +1,9 @@ /* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2006, 2007 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -204,6 +207,14 @@ retry: } } else { ubi_assert(len == read); + if (ubi->lookuptbl && ubi->lookuptbl[pnum]) { + if (ubi->lookuptbl[pnum]->rc < + UBI_MAX_READCOUNTER) + ubi->lookuptbl[pnum]->rc++; + else + ubi_err("read counter overflow at PEB %d, RC %d", + pnum, ubi->lookuptbl[pnum]->rc); + } if (ubi_dbg_is_bitflip(ubi)) { dbg_gen("bit-flip (emulated)"); @@ -1337,6 +1348,15 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, if (err && !mtd_is_bitflip(err)) goto out_free; + if (ubi->lookuptbl && ubi->lookuptbl[pnum]) { + if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER) + ubi->lookuptbl[pnum]->rc++; + else + ubi_err("read counter overflow at PEB %d, RC %d", + pnum, ubi->lookuptbl[pnum]->rc); + } else + ubi_err("Can't update RC. No lookuptbl"); + for (i = 0; i < len; i++) { uint8_t c = ((uint8_t *)buf)[i]; uint8_t c1 = ((uint8_t *)buf1)[i]; @@ -1403,6 +1423,14 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) err, len, pnum, offset, read); goto error; } + if (ubi->lookuptbl && ubi->lookuptbl[pnum]) { + if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER) + ubi->lookuptbl[pnum]->rc++; + else + ubi_err("read counter overflow at PEB %d, RC %d", + pnum, ubi->lookuptbl[pnum]->rc); + } else + ubi_err("Can't update RC. No lookuptbl"); err = ubi_check_pattern(buf, 0xFF, len); if (err == 0) { diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 6c7e53e..e4c97ad 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -95,6 +95,16 @@ #define UBI_RD_THRESHOLD 100000 /* + * This is the default read counter to be assigned to blocks lacking + * read counter value on attach. The value was choosen as mean between + * just_erased_block (rc = 0) and needs_scrubbibg_block + * (rc = UBI_RD_THRESHOLD). On the one hand we don't want to miss + * blocks that needs scrubbing but on the other, we dont want to + * abuse scrubbing. + */ +#define UBI_DEF_RD_THRESHOLD (UBI_RD_THRESHOLD / 2) + +/* * This parameter defines the maximun interval (in days) between two * erasures of an eraseblock. When this interval is reached, UBI starts * performing wear leveling by means of moving data from eraseblock with @@ -102,6 +112,9 @@ */ #define UBI_DT_THRESHOLD 120 +/* Used when calculaing the lats erase timestamp of a PEB */ +#define NUM_SEC_IN_DAY (60*60*24) + /* * The UBI debugfs directory name pattern and maximum name length (3 for "ubi" * + 2 for the number plus 1 for the trailing zero byte. @@ -709,6 +722,11 @@ struct ubi_ainf_volume { * @ec_sum: a temporary variable used when calculating @mean_ec * @ec_count: a temporary variable used when calculating @mean_ec * @aeb_slab_cache: slab cache for &struct ubi_ainf_peb objects + * @mean_last_erase_time: mean late erase timestamp value + * @last_erase_time_sum: temporary variable, used to calculate + * @mean_last_erase_time + * @last_erase_time_count: temporary variable, used to calculate + * @mean_last_erase_time * * This data structure contains the result of attaching an MTD device and may * be used by other UBI sub-systems to build final UBI data structures, further @@ -735,6 +753,9 @@ struct ubi_attach_info { uint64_t ec_sum; int ec_count; struct kmem_cache *aeb_slab_cache; + long long mean_last_erase_time; + long long last_erase_time_sum; + int last_erase_time_count; }; /** @@ -775,7 +796,8 @@ extern struct blocking_notifier_head ubi_notifiers; /* attach.c */ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, - int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips); + int ec, long last_erase_time, long rc, + const struct ubi_vid_hdr *vid_hdr, int bitflips); struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai, int vol_id); void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av); diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 07cac5f..625a9b4 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -1,6 +1,9 @@ /* * Copyright (c) International Business Machines Corp., 2006 * Copyright (c) Nokia Corporation, 2006, 2007 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -339,7 +342,8 @@ retry: * And add it to the attaching information. Don't delete the old version * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'. */ - err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0); + err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, + new_aeb->last_erase_time, new_aeb->rc, vid_hdr, 0); kmem_cache_free(ai->aeb_slab_cache, new_aeb); ubi_free_vid_hdr(ubi, vid_hdr); return err; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 33d33e43..2b4e6fe 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -105,6 +105,7 @@ #include #include #include +#include #include "ubi.h" /* Number of physical eraseblocks reserved for wear-leveling purposes */ @@ -742,6 +743,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int err; struct ubi_ec_hdr *ec_hdr; unsigned long long ec = e->ec; + struct timeval tv; dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec); @@ -773,11 +775,16 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, ec_hdr->ec = cpu_to_be64(ec); + do_gettimeofday(&tv); + /* The last erase time resolution is in days */ + ec_hdr->last_erase_time = cpu_to_be64(tv.tv_sec / NUM_SEC_IN_DAY); err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr); if (err) goto out_free; e->ec = ec; + e->last_erase_time = tv.tv_sec / NUM_SEC_IN_DAY; + e->rc = 0; spin_lock(&ubi->wl_lock); if (e->ec > ubi->max_ec) ubi->max_ec = e->ec; @@ -979,6 +986,8 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e, ubi->lookuptbl[pnum] = e; } else { e->ec = fm_e->ec; + e->rc = fm_e->rc; + e->last_erase_time = fm_e->last_erase_time; kfree(fm_e); } @@ -1913,6 +1922,19 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) e->pnum = aeb->pnum; e->ec = aeb->ec; + e->last_erase_time = aeb->last_erase_time; + e->rc = aeb->rc; + if (!ubi->fm) { + if (e->rc < UBI_MAX_READCOUNTER) { + e->rc++; + } else { + ubi_err("read counter overflow at PEB %d, RC %d", + e->pnum, e->rc); + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + + } ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); ubi->lookuptbl[e->pnum] = e; if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { @@ -1933,6 +1955,19 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) e->pnum = aeb->pnum; e->ec = aeb->ec; + e->rc = aeb->rc; + if (!ubi->fm) { + if (e->rc < UBI_MAX_READCOUNTER) { + e->rc++; + } else { + ubi_err("rc overflow at PEB %d, RC %d", + e->pnum, e->rc); + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + + } + e->last_erase_time = aeb->last_erase_time; ubi_assert(e->ec >= 0); ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); @@ -1954,6 +1989,18 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) e->pnum = aeb->pnum; e->ec = aeb->ec; + e->rc = aeb->rc; + if (!ubi->fm) { + if (e->rc < UBI_MAX_READCOUNTER) { + e->rc++; + } else { + ubi_err("rc overflow at PEB %d, RC %d", + e->pnum, e->rc); + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + } + e->last_erase_time = aeb->last_erase_time; ubi->lookuptbl[e->pnum] = e; if (!aeb->scrub) { -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:37:37 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:37:37 +0300 Subject: [RFC/PATCH 3/5] mtd: ubi: Make in_wl_tree function public Message-ID: <1411886257-8603-1-git-send-email-tlinder@codeaurora.org> From: Tatyana Brokhman Make the in_wl_tree function public to be used outside of wl.c. Rename it to ubi_in_wl_tree. Signed-off-by: Tanya Brokhman --- drivers/mtd/ubi/ubi.h | 1 + drivers/mtd/ubi/wl.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index e4c97ad..ed04de2 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -872,6 +872,7 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *used_e, int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); +int ubi_in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root); /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 2b4e6fe..64c7dfd 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -291,14 +291,14 @@ static int produce_free_peb(struct ubi_device *ubi) } /** - * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree. + * ubi_in_wl_tree - check if wear-leveling entry is present in a WL RB-tree. * @e: the wear-leveling entry to check * @root: the root of the tree * * This function returns non-zero if @e is in the @root RB-tree and zero if it * is not. */ -static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root) +int ubi_in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root) { struct rb_node *p; @@ -1607,13 +1607,13 @@ retry: spin_unlock(&ubi->wl_lock); return 0; } else { - if (in_wl_tree(e, &ubi->used)) { + if (ubi_in_wl_tree(e, &ubi->used)) { self_check_in_wl_tree(ubi, e, &ubi->used); rb_erase(&e->u.rb, &ubi->used); - } else if (in_wl_tree(e, &ubi->scrub)) { + } else if (ubi_in_wl_tree(e, &ubi->scrub)) { self_check_in_wl_tree(ubi, e, &ubi->scrub); rb_erase(&e->u.rb, &ubi->scrub); - } else if (in_wl_tree(e, &ubi->erroneous)) { + } else if (ubi_in_wl_tree(e, &ubi->erroneous)) { self_check_in_wl_tree(ubi, e, &ubi->erroneous); rb_erase(&e->u.rb, &ubi->erroneous); ubi->erroneous_peb_count -= 1; @@ -1661,8 +1661,8 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; - if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub) || - in_wl_tree(e, &ubi->erroneous)) { + if (e == ubi->move_from || ubi_in_wl_tree(e, &ubi->scrub) || + ubi_in_wl_tree(e, &ubi->erroneous)) { spin_unlock(&ubi->wl_lock); return 0; } @@ -1680,7 +1680,7 @@ retry: goto retry; } - if (in_wl_tree(e, &ubi->used)) { + if (ubi_in_wl_tree(e, &ubi->used)) { self_check_in_wl_tree(ubi, e, &ubi->used); rb_erase(&e->u.rb, &ubi->used); } else { @@ -2150,7 +2150,7 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, if (!ubi_dbg_chk_gen(ubi)) return 0; - if (in_wl_tree(e, root)) + if (ubi_in_wl_tree(e, root)) return 0; ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ", -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:37:51 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:37:51 +0300 Subject: [RFC/PATCH 4/5] mtd: ubi: Read threshold verification Message-ID: <1411886271-8773-1-git-send-email-tlinder@codeaurora.org> From: Tatyana Brokhman One of the criteria to scrub an eraseblock due to read disturb issue is if that eraseblock was read from more times then a pre-defined threshold. This is verified at each LEB read according to the read counter parameter of the read PEB. An eraseblock that is found needs scrubbing is added to the ubi->scrub list. Signed-off-by: Tanya Brokhman --- drivers/mtd/ubi/eba.c | 7 ++++++- drivers/mtd/ubi/wl.c | 56 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0e11671d..1c7b5f9 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1,5 +1,8 @@ /* * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) 2014, Linux Foundation. All rights reserved. + * Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -466,8 +469,10 @@ retry: goto out_unlock; } } + if (ubi->lookuptbl[pnum]->rc >= ubi->rd_threshold) + scrub = 1; - if (scrub) + if (scrub && !ubi_in_wl_tree(ubi->lookuptbl[pnum], &ubi->scrub)) err = ubi_wl_scrub_peb(ubi, pnum); leb_read_unlock(ubi, vol_id, lnum); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 64c7dfd..a5d754f 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -449,7 +449,7 @@ static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root) return victim; } -static int anchor_pebs_avalible(struct rb_root *root) +static int anchor_pebs_avalible(struct rb_root *root, int rd_threshold) { struct rb_node *p; struct ubi_wl_entry *e; @@ -560,6 +560,12 @@ static void return_unused_pool_pebs(struct ubi_device *ubi, for (i = pool->used; i < pool->size; i++) { e = ubi->lookuptbl[pool->pebs[i]]; + /* If given PEB pending to be scrubbed - remove it */ + if (ubi_in_wl_tree(e, &ubi->scrub)) { + ubi_err("PEB %d was pending scrubb", e->pnum); + self_check_in_wl_tree(ubi, e, &ubi->scrub); + rb_erase(&e->u.rb, &ubi->scrub); + } wl_tree_add(e, &ubi->free); ubi->free_count++; } @@ -919,6 +925,13 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, wl_wrk->lnum = lnum; wl_wrk->torture = torture; + /* If given PEB pending to be scrubbed - remove it */ + if (ubi_in_wl_tree(e, &ubi->scrub)) { + self_check_in_wl_tree(ubi, e, &ubi->scrub); + rb_erase(&e->u.rb, &ubi->scrub); + ubi_msg("PEB %d was pending scrubb", + e->pnum); + } schedule_ubi_work(ubi, wl_wrk); return 0; } @@ -948,6 +961,14 @@ static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, wl_wrk->lnum = lnum; wl_wrk->torture = torture; + /* If given PEB pending to be scrubbed - remove it */ + if (ubi_in_wl_tree(e, &ubi->scrub)) { + self_check_in_wl_tree(ubi, e, &ubi->scrub); + rb_erase(&e->u.rb, &ubi->scrub); + ubi_msg("PEB %d was pending scrubb", + e->pnum); + } + return erase_worker(ubi, wl_wrk, 0); } @@ -1052,7 +1073,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, #ifdef CONFIG_MTD_UBI_FASTMAP /* Check whether we need to produce an anchor PEB */ if (!anchor) - anchor = !anchor_pebs_avalible(&ubi->free); + anchor = !anchor_pebs_avalible(&ubi->free, ubi->rd_threshold); if (anchor) { e1 = find_anchor_wl_entry(&ubi->used); @@ -1613,6 +1634,8 @@ retry: } else if (ubi_in_wl_tree(e, &ubi->scrub)) { self_check_in_wl_tree(ubi, e, &ubi->scrub); rb_erase(&e->u.rb, &ubi->scrub); + ubi_msg("PEB %d was pending scrubb", + e->pnum); } else if (ubi_in_wl_tree(e, &ubi->erroneous)) { self_check_in_wl_tree(ubi, e, &ubi->erroneous); rb_erase(&e->u.rb, &ubi->erroneous); @@ -1656,8 +1679,6 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) { struct ubi_wl_entry *e; - ubi_msg("schedule PEB %d for scrubbing", pnum); - retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; @@ -1695,6 +1716,7 @@ retry: } } + ubi_msg("schedule PEB %d for scrubbing", pnum); wl_tree_add(e, &ubi->scrub); spin_unlock(&ubi->wl_lock); @@ -1888,7 +1910,9 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) struct ubi_ainf_volume *av; struct ubi_ainf_peb *aeb, *tmp; struct ubi_wl_entry *e; + struct timeval tv; + do_gettimeofday(&tv); ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT; spin_lock_init(&ubi->wl_lock); mutex_init(&ubi->move_mutex); @@ -1971,8 +1995,17 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ubi_assert(e->ec >= 0); ubi_assert(!ubi_is_fm_block(ubi, e->pnum)); - wl_tree_add(e, &ubi->free); - ubi->free_count++; + /* Check last erase timestamp (in days) */ + if (e->last_erase_time + ubi->dt_threshold < + (tv.tv_sec / NUM_SEC_IN_DAY)) { + if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) { + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + } else { + wl_tree_add(e, &ubi->free); + ubi->free_count++; + } ubi->lookuptbl[e->pnum] = e; @@ -2003,6 +2036,17 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) e->last_erase_time = aeb->last_erase_time; ubi->lookuptbl[e->pnum] = e; + /* + * Verify last erase timestamp + * (in days) and read counter + */ + if (e->last_erase_time + ubi->dt_threshold < + (tv.tv_sec / NUM_SEC_IN_DAY) || + e->rc > ubi->rd_threshold) { + ubi_msg("scrub PEB %d rc = %d", + e->pnum, e->rc); + aeb->scrub = 1; + } if (!aeb->scrub) { dbg_wl("add PEB %d EC %d to the used tree", e->pnum, e->ec); -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sat Sep 27 23:38:07 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 09:38:07 +0300 Subject: [RFC/PATCH 5/5] mtd: ubi: Add sysfs entry to force all pebs' scan Message-ID: <1411886287-8947-1-git-send-email-tlinder@codeaurora.org> A given eraseblock can be read many times or not at all. We do not have the account of such eraseblocks that have not been accessed since a pre-defined threshold interval. By means of scanning the entire flash device it is possible to identify all such eraseblocks. Add a sysfs entry to force scan on all the PEBs on demand basis. The sysfs entry would be available under /sys/class/ubi/ubiX/peb_scan - echo 1 to this entry would trigger the scan, ignored if in progress - On reading returns the scan status (1 = Scan executing, 0 = Scan not executing) Signed-off-by: Pratibhasagar V Signed-off-by: Tatyana Brokhman --- drivers/mtd/ubi/build.c | 32 +++++++++-- drivers/mtd/ubi/ubi.h | 3 + drivers/mtd/ubi/wl.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 34fe23a..a7464f8 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -154,6 +154,9 @@ static struct device_attribute dev_dt_threshold = static struct device_attribute dev_rd_threshold = __ATTR(rd_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, dev_attribute_store); +static struct device_attribute dev_mtd_trigger_scan = + __ATTR(peb_scan, (S_IWUSR | S_IRUGO), + dev_attribute_show, dev_attribute_store); /** * ubi_volume_notify - send a volume change notification. @@ -395,6 +398,8 @@ static ssize_t dev_attribute_show(struct device *dev, ret = sprintf(buf, "%d\n", ubi->dt_threshold); else if (attr == &dev_rd_threshold) ret = sprintf(buf, "%d\n", ubi->rd_threshold); + else if (attr == &dev_mtd_trigger_scan) + ret = sprintf(buf, "%d\n", ubi->scan_in_progress); else ret = -EINVAL; @@ -406,7 +411,7 @@ static ssize_t dev_attribute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int value; + int value, ret; struct ubi_device *ubi; ubi = container_of(dev, struct ubi_device, dev); @@ -414,8 +419,11 @@ static ssize_t dev_attribute_store(struct device *dev, if (!ubi) return -ENODEV; - if (kstrtos32(buf, 10, &value)) - return -EINVAL; + ret = count; + if (kstrtos32(buf, 10, &value)) { + ret = -EINVAL; + goto out; + } /* Consider triggering full scan if threshods change */ else if (attr == &dev_dt_threshold) { if (value < UBI_MAX_DT_THRESHOLD) @@ -429,9 +437,21 @@ static ssize_t dev_attribute_store(struct device *dev, else pr_err("Max supported threshold value is %d", UBI_MAX_READCOUNTER); + } else if (attr == &dev_mtd_trigger_scan) { + if (value != 1) { + pr_err("Invalid input. Echo 1 to start trigger"); + goto out; + } + if (!ubi->lookuptbl) { + pr_err("lookuptbl is null"); + goto out; + } + ret = ubi_wl_scan_all(ubi); } - return count; +out: + ubi_put_device(ubi); + return ret; } static void dev_release(struct device *dev) @@ -500,6 +520,9 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) if (err) return err; err = device_create_file(&ubi->dev, &dev_rd_threshold); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_mtd_trigger_scan); return err; } @@ -509,6 +532,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) */ static void ubi_sysfs_close(struct ubi_device *ubi) { + device_remove_file(&ubi->dev, &dev_mtd_trigger_scan); device_remove_file(&ubi->dev, &dev_mtd_num); device_remove_file(&ubi->dev, &dev_dt_threshold); device_remove_file(&ubi->dev, &dev_rd_threshold); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index ed04de2..1079517 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -491,6 +491,7 @@ struct ubi_debug_info { * for more info * @dt_threshold: data retention threshold. See UBI_DT_THRESHOLD * for more info + * @scan_in_progress: true if scanning of device PEBs is in progress * * @flash_size: underlying MTD device size (in bytes) * @peb_count: count of physical eraseblocks on the MTD device @@ -595,6 +596,7 @@ struct ubi_device { char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; int rd_threshold; int dt_threshold; + bool scan_in_progress; /* I/O sub-system's stuff */ @@ -873,6 +875,7 @@ int ubi_is_erase_work(struct ubi_work *wrk); void ubi_refill_pools(struct ubi_device *ubi); int ubi_ensure_anchor_pebs(struct ubi_device *ubi); int ubi_in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root); +int ubi_wl_scan_all(struct ubi_device *ubi); /* io.c */ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index a5d754f..4edbb4c 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -143,6 +143,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, struct ubi_wl_entry *e, struct rb_root *root); static int self_check_in_pq(const struct ubi_device *ubi, struct ubi_wl_entry *e); +static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, + int vol_id, int lnum, int torture); #ifdef CONFIG_MTD_UBI_FASTMAP /** @@ -555,8 +557,11 @@ retry: static void return_unused_pool_pebs(struct ubi_device *ubi, struct ubi_fm_pool *pool) { - int i; + int i, err; struct ubi_wl_entry *e; + struct timeval tv; + + do_gettimeofday(&tv); for (i = pool->used; i < pool->size; i++) { e = ubi->lookuptbl[pool->pebs[i]]; @@ -566,8 +571,22 @@ static void return_unused_pool_pebs(struct ubi_device *ubi, self_check_in_wl_tree(ubi, e, &ubi->scrub); rb_erase(&e->u.rb, &ubi->scrub); } - wl_tree_add(e, &ubi->free); - ubi->free_count++; + if (e->last_erase_time + UBI_DT_THRESHOLD < + (tv.tv_sec / NUM_SEC_IN_DAY)) { + spin_unlock(&ubi->wl_lock); + err = schedule_erase(ubi, e, UBI_UNKNOWN, + UBI_UNKNOWN, 0); + spin_lock(&ubi->wl_lock); + if (err) { + ubi_err( + "Failed to schedule erase for PEB %d (err=%d)", + e->pnum, err); + ubi_ro_mode(ubi); + } + } else { + wl_tree_add(e, &ubi->free); + ubi->free_count++; + } } } @@ -711,6 +730,124 @@ int ubi_wl_get_peb(struct ubi_device *ubi) #endif /** + * ubi_wl_scan_all - Scan all PEB's + * @ubi: UBI device description object + * + * This function scans all device PEBs in order to locate once + * need scrubbing; due to read disturb threashold or last erase + * timestamp. + * + * Return 0 in case of sucsess, (negative) error code otherwise + * + */ +int ubi_wl_scan_all(struct ubi_device *ubi) +{ + struct timeval tv; + struct rb_node *node; + struct ubi_wl_entry *wl_e, *tmp; + int used_cnt, free_cnt; + int err; + + do_gettimeofday(&tv); + if (!ubi->lookuptbl) { + ubi_err("lookuptbl is null"); + return -ENOENT; + } + + spin_lock(&ubi->wl_lock); + if (ubi->scan_in_progress) { + ubi_err("Scan already in progress, ignoring the trigger"); + err = -EPERM; + goto out; + } + ubi->scan_in_progress = true; + + ubi_msg("Scanning all PEBs for read-disturb/erasures"); + /* For PEBs in free list rc=0 */ + free_cnt = 0; + node = rb_first(&ubi->free); + while (node) { + wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); + node = rb_next(node); + if (wl_e->last_erase_time + UBI_DT_THRESHOLD < + (tv.tv_sec / NUM_SEC_IN_DAY)) { + if (self_check_in_wl_tree(ubi, wl_e, &ubi->free)) { + ubi_err("PEB %d moved from free tree", + wl_e->pnum); + err = -EAGAIN; + goto out; + } + rb_erase(&wl_e->u.rb, &ubi->free); + ubi->free_count--; + spin_unlock(&ubi->wl_lock); + err = schedule_erase(ubi, wl_e, UBI_UNKNOWN, + UBI_UNKNOWN, 0); + spin_lock(&ubi->wl_lock); + if (err) { + ubi_err( + "Failed to schedule erase for PEB %d (err=%d)", + wl_e->pnum, err); + ubi_ro_mode(ubi); + goto out; + } + free_cnt++; + } + } + + used_cnt = 0; + node = rb_first(&ubi->used); + while (node) { + wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); + node = rb_next(node); + if ((wl_e->rc >= UBI_RD_THRESHOLD) || + (wl_e->last_erase_time + + UBI_DT_THRESHOLD < (tv.tv_sec / NUM_SEC_IN_DAY))) { + spin_unlock(&ubi->wl_lock); + err = ubi_wl_scrub_peb(ubi, wl_e->pnum); + if (err) + ubi_err( + "Failed to schedule scrub for PEB %d (err=%d)", + wl_e->pnum, err); + else + used_cnt++; + spin_lock(&ubi->wl_lock); + } + } + + /* Go over protection queue */ + list_for_each_entry_safe(wl_e, tmp, &ubi->pq[ubi->pq_head], u.list) { + if ((wl_e->rc >= UBI_RD_THRESHOLD) || + (wl_e->last_erase_time + + UBI_DT_THRESHOLD < (tv.tv_sec / NUM_SEC_IN_DAY))) { + spin_unlock(&ubi->wl_lock); + err = ubi_wl_scrub_peb(ubi, wl_e->pnum); + if (err) + ubi_err( + "Failed to schedule scrub for PEB %d (err=%d)", + wl_e->pnum, err); + else + used_cnt++; + spin_lock(&ubi->wl_lock); + } + } + spin_unlock(&ubi->wl_lock); + ubi_msg("Scheduled %d for erasure", free_cnt); + ubi_msg("Scehduled %d for scrubbing", used_cnt); + err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); + if (err) + ubi_err("Failed to flush ubi wq. err = %d", err); + else + ubi_msg("Flashed ubi wq"); + + spin_lock(&ubi->wl_lock); +out: + ubi->scan_in_progress = false; + spin_unlock(&ubi->wl_lock); + ubi_msg("Scanning all PEBs completed. err = %d", err); + return err; +} + +/** * prot_queue_del - remove a physical eraseblock from the protection queue. * @ubi: UBI device description object * @pnum: the physical eraseblock to remove -- 1.8.5.2 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From richard at nod.at Sun Sep 28 01:01:10 2014 From: richard at nod.at (Richard Weinberger) Date: Sun, 28 Sep 2014 10:01:10 +0200 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> Message-ID: <5427C046.5030608@nod.at> Tanya, Am 28.09.2014 08:36, schrieb Tanya Brokhman: > If there is more then one UBI device mounted, there is no way to > distinguish between messages from different UBI devices. > Add device number to all ubi layer message types. > > > Signed-off-by: Tanya Brokhman Artem's mail is dedekind1@ not dedeking1 at . :) Anyway, instead of passing ubi->ubi_num down to every log function you can just pass the ubi object itself and let the log function access ->ubi_num. Thanks, //richard > --- > drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- > drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- > drivers/mtd/ubi/cdev.c | 37 +++++----- > drivers/mtd/ubi/debug.c | 9 +-- > drivers/mtd/ubi/eba.c | 54 +++++++------- > drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ > drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- > drivers/mtd/ubi/kapi.c | 6 +- > drivers/mtd/ubi/misc.c | 6 +- > drivers/mtd/ubi/ubi.h | 13 ++-- > drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- > drivers/mtd/ubi/vtbl.c | 54 ++++++++------ > drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- > 13 files changed, 521 insertions(+), 374 deletions(-) > > diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c > index 6f27d9a..3f11561 100644 > --- a/drivers/mtd/ubi/attach.c > +++ b/drivers/mtd/ubi/attach.c > @@ -176,6 +176,7 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) > > /** > * validate_vid_hdr - check volume identifier header. > + * @ubi: UBI device description object > * @vid_hdr: the volume identifier header to check > * @av: information about the volume this logical eraseblock belongs to > * @pnum: physical eraseblock number the VID header came from > @@ -188,7 +189,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) > * information in the VID header is consistent to the information in other VID > * headers of the same volume. > */ > -static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, > +static int validate_vid_hdr(const struct ubi_device *ubi, > + const struct ubi_vid_hdr *vid_hdr, > const struct ubi_ainf_volume *av, int pnum) > { > int vol_type = vid_hdr->vol_type; > @@ -206,7 +208,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, > */ > > if (vol_id != av->vol_id) { > - ubi_err("inconsistent vol_id"); > + ubi_err(ubi->ubi_num, "inconsistent vol_id"); > goto bad; > } > > @@ -216,17 +218,17 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, > av_vol_type = UBI_VID_DYNAMIC; > > if (vol_type != av_vol_type) { > - ubi_err("inconsistent vol_type"); > + ubi_err(ubi->ubi_num, "inconsistent vol_type"); > goto bad; > } > > if (used_ebs != av->used_ebs) { > - ubi_err("inconsistent used_ebs"); > + ubi_err(ubi->ubi_num, "inconsistent used_ebs"); > goto bad; > } > > if (data_pad != av->data_pad) { > - ubi_err("inconsistent data_pad"); > + ubi_err(ubi->ubi_num, "inconsistent data_pad"); > goto bad; > } > } > @@ -234,7 +236,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, > return 0; > > bad: > - ubi_err("inconsistent VID header at PEB %d", pnum); > + ubi_err(ubi->ubi_num, "inconsistent VID header at PEB %d", pnum); > ubi_dump_vid_hdr(vid_hdr); > ubi_dump_av(av); > return -EINVAL; > @@ -336,7 +338,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, > * support these images anymore. Well, those images still work, > * but only if no unclean reboots happened. > */ > - ubi_err("unsupported on-flash UBI format"); > + ubi_err(ubi->ubi_num, "unsupported on-flash UBI format"); > return -EINVAL; > } > > @@ -377,7 +379,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, > if (err == UBI_IO_BITFLIPS) > bitflips = 1; > else { > - ubi_err("VID of PEB %d header is bad, but it was OK earlier, err %d", > + ubi_err(ubi->ubi_num, "VID of PEB %d header is bad, but it was OK earlier, err %d", > pnum, err); > if (err > 0) > err = -EIO; > @@ -507,7 +509,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, > * logical eraseblocks because there was an unclean reboot. > */ > if (aeb->sqnum == sqnum && sqnum != 0) { > - ubi_err("two LEBs with same sequence number %llu", > + ubi_err(ubi->ubi_num, "two LEBs with same sequence number %llu", > sqnum); > ubi_dump_aeb(aeb, 0); > ubi_dump_vid_hdr(vid_hdr); > @@ -527,7 +529,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, > * This logical eraseblock is newer than the one > * found earlier. > */ > - err = validate_vid_hdr(vid_hdr, av, pnum); > + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); > if (err) > return err; > > @@ -565,7 +567,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, > * attaching information. > */ > > - err = validate_vid_hdr(vid_hdr, av, pnum); > + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); > if (err) > return err; > > @@ -668,7 +670,8 @@ static int early_erase_peb(struct ubi_device *ubi, > * Erase counter overflow. Upgrade UBI and use 64-bit > * erase counters internally. > */ > - ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); > + ubi_err(ubi->ubi_num, > + "erase counter overflow at PEB %d, EC %d", pnum, ec); > return -EINVAL; > } > > @@ -736,7 +739,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, > return aeb; > } > > - ubi_err("no free eraseblocks"); > + ubi_err(ubi->ubi_num, "no free eraseblocks"); > return ERR_PTR(-ENOSPC); > } > > @@ -785,9 +788,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, > if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size)) > goto out_unlock; > > - ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF", > + ubi_err(ubi->ubi_num, "PEB %d contains corrupted VID header, and the data does not contain all 0xFF", > pnum); > - ubi_err("this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); > + ubi_err(ubi->ubi_num, "this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); > ubi_dump_vid_hdr(vid_hdr); > pr_err("hexdump of PEB %d offset %d, length %d", > pnum, ubi->leb_start, ubi->leb_size); > @@ -859,7 +862,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > bitflips = 1; > break; > default: > - ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err); > + ubi_err(ubi->ubi_num, > + "'ubi_io_read_ec_hdr()' returned unknown code %d", err); > return -EINVAL; > } > > @@ -868,7 +872,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > > /* Make sure UBI version is OK */ > if (ech->version != UBI_VERSION) { > - ubi_err("this UBI version is %d, image version is %d", > + ubi_err(ubi->ubi_num, "this UBI version is %d, image version is %d", > UBI_VERSION, (int)ech->version); > return -EINVAL; > } > @@ -882,7 +886,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > * flash. Upgrade UBI and use 64-bit erase counters > * internally. > */ > - ubi_err("erase counter overflow, max is %d", > + ubi_err(ubi->ubi_num, "erase counter overflow, max is %d", > UBI_MAX_ERASECOUNTER); > ubi_dump_ec_hdr(ech); > return -EINVAL; > @@ -903,7 +907,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > if (!ubi->image_seq) > ubi->image_seq = image_seq; > if (image_seq && ubi->image_seq != image_seq) { > - ubi_err("bad image sequence number %d in PEB %d, expected %d", > + ubi_err("ubi->ubi_num, bad image sequence number %d in PEB %d, expected %d", > image_seq, pnum, ubi->image_seq); > ubi_dump_ec_hdr(ech); > return -EINVAL; > @@ -981,7 +985,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > return err; > goto adjust_mean_ec; > default: > - ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d", > + ubi_err(ubi->ubi_num, "'ubi_io_read_vid_hdr()' returned unknown code %d", > err); > return -EINVAL; > } > @@ -999,7 +1003,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > case UBI_COMPAT_DELETE: > if (vol_id != UBI_FM_SB_VOLUME_ID > && vol_id != UBI_FM_DATA_VOLUME_ID) { > - ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it", > + ubi_msg(ubi->ubi_num, > + "\"delete\" compatible internal volume %d:%d found, will remove it", > vol_id, lnum); > } > err = add_to_list(ai, pnum, vol_id, lnum, > @@ -1009,13 +1014,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > return 0; > > case UBI_COMPAT_RO: > - ubi_msg("read-only compatible internal volume %d:%d found, switch to read-only mode", > + ubi_msg(ubi->ubi_num, > + "read-only compatible internal volume %d:%d found, switch to read-only mode", > vol_id, lnum); > ubi->ro_mode = 1; > break; > > case UBI_COMPAT_PRESERVE: > - ubi_msg("\"preserve\" compatible internal volume %d:%d found", > + ubi_msg(ubi->ubi_num, > + "\"preserve\" compatible internal volume %d:%d found", > vol_id, lnum); > err = add_to_list(ai, pnum, vol_id, lnum, > ec, 0, &ai->alien); > @@ -1024,14 +1031,14 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, > return 0; > > case UBI_COMPAT_REJECT: > - ubi_err("incompatible internal volume %d:%d found", > + ubi_err(ubi->ubi_num, "incompatible internal volume %d:%d found", > vol_id, lnum); > return -EINVAL; > } > } > > if (ec_err) > - ubi_warn("valid VID header but corrupted EC header at PEB %d", > + ubi_warn(ubi->ubi_num, "valid VID header but corrupted EC header at PEB %d", > pnum); > err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips); > if (err) > @@ -1075,7 +1082,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) > * with the flash HW or driver. > */ > if (ai->corr_peb_count) { > - ubi_err("%d PEBs are corrupted and preserved", > + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and preserved", > ai->corr_peb_count); > pr_err("Corrupted PEBs are:"); > list_for_each_entry(aeb, &ai->corr, u.list) > @@ -1087,7 +1094,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) > * otherwise, only print a warning. > */ > if (ai->corr_peb_count >= max_corr) { > - ubi_err("too many corrupted PEBs, refusing"); > + ubi_err(ubi->ubi_num, "too many corrupted PEBs, refusing"); > return -EINVAL; > } > } > @@ -1110,11 +1117,11 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) > */ > if (ai->maybe_bad_peb_count <= 2) { > ai->is_empty = 1; > - ubi_msg("empty MTD device detected"); > + ubi_msg(ubi->ubi_num, "empty MTD device detected"); > get_random_bytes(&ubi->image_seq, > sizeof(ubi->image_seq)); > } else { > - ubi_err("MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); > + ubi_err(ubi->ubi_num, "MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); > return -EINVAL; > } > > @@ -1248,7 +1255,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, > goto out_vidh; > } > > - ubi_msg("scanning is finished"); > + ubi_msg(ubi->ubi_num, "scanning is finished"); > > /* Calculate mean erase counter */ > if (ai->ec_count) > @@ -1515,37 +1522,37 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > vols_found += 1; > > if (ai->is_empty) { > - ubi_err("bad is_empty flag"); > + ubi_err(ubi->ubi_num, "bad is_empty flag"); > goto bad_av; > } > > if (av->vol_id < 0 || av->highest_lnum < 0 || > av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 || > av->data_pad < 0 || av->last_data_size < 0) { > - ubi_err("negative values"); > + ubi_err(ubi->ubi_num, "negative values"); > goto bad_av; > } > > if (av->vol_id >= UBI_MAX_VOLUMES && > av->vol_id < UBI_INTERNAL_VOL_START) { > - ubi_err("bad vol_id"); > + ubi_err(ubi->ubi_num, "bad vol_id"); > goto bad_av; > } > > if (av->vol_id > ai->highest_vol_id) { > - ubi_err("highest_vol_id is %d, but vol_id %d is there", > + ubi_err(ubi->ubi_num, "highest_vol_id is %d, but vol_id %d is there", > ai->highest_vol_id, av->vol_id); > goto out; > } > > if (av->vol_type != UBI_DYNAMIC_VOLUME && > av->vol_type != UBI_STATIC_VOLUME) { > - ubi_err("bad vol_type"); > + ubi_err(ubi->ubi_num, "bad vol_type"); > goto bad_av; > } > > if (av->data_pad > ubi->leb_size / 2) { > - ubi_err("bad data_pad"); > + ubi_err(ubi->ubi_num, "bad data_pad"); > goto bad_av; > } > > @@ -1557,48 +1564,48 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > leb_count += 1; > > if (aeb->pnum < 0 || aeb->ec < 0) { > - ubi_err("negative values"); > + ubi_err(ubi->ubi_num, "negative values"); > goto bad_aeb; > } > > if (aeb->ec < ai->min_ec) { > - ubi_err("bad ai->min_ec (%d), %d found", > + ubi_err(ubi->ubi_num, "bad ai->min_ec (%d), %d found", > ai->min_ec, aeb->ec); > goto bad_aeb; > } > > if (aeb->ec > ai->max_ec) { > - ubi_err("bad ai->max_ec (%d), %d found", > + ubi_err(ubi->ubi_num, "bad ai->max_ec (%d), %d found", > ai->max_ec, aeb->ec); > goto bad_aeb; > } > > if (aeb->pnum >= ubi->peb_count) { > - ubi_err("too high PEB number %d, total PEBs %d", > + ubi_err(ubi->ubi_num, "too high PEB number %d, total PEBs %d", > aeb->pnum, ubi->peb_count); > goto bad_aeb; > } > > if (av->vol_type == UBI_STATIC_VOLUME) { > if (aeb->lnum >= av->used_ebs) { > - ubi_err("bad lnum or used_ebs"); > + ubi_err(ubi->ubi_num, "bad lnum or used_ebs"); > goto bad_aeb; > } > } else { > if (av->used_ebs != 0) { > - ubi_err("non-zero used_ebs"); > + ubi_err(ubi->ubi_num, "non-zero used_ebs"); > goto bad_aeb; > } > } > > if (aeb->lnum > av->highest_lnum) { > - ubi_err("incorrect highest_lnum or lnum"); > + ubi_err(ubi->ubi_num, "incorrect highest_lnum or lnum"); > goto bad_aeb; > } > } > > if (av->leb_count != leb_count) { > - ubi_err("bad leb_count, %d objects in the tree", > + ubi_err(ubi->ubi_num, "bad leb_count, %d objects in the tree", > leb_count); > goto bad_av; > } > @@ -1609,13 +1616,13 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > aeb = last_aeb; > > if (aeb->lnum != av->highest_lnum) { > - ubi_err("bad highest_lnum"); > + ubi_err(ubi->ubi_num, "bad highest_lnum"); > goto bad_aeb; > } > } > > if (vols_found != ai->vols_found) { > - ubi_err("bad ai->vols_found %d, should be %d", > + ubi_err(ubi->ubi_num, "bad ai->vols_found %d, should be %d", > ai->vols_found, vols_found); > goto out; > } > @@ -1632,7 +1639,8 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > > err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1); > if (err && err != UBI_IO_BITFLIPS) { > - ubi_err("VID header is not OK (%d)", err); > + ubi_err(ubi->ubi_num, > + "VID header is not OK (%d)", err); > if (err > 0) > err = -EIO; > return err; > @@ -1641,37 +1649,42 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? > UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; > if (av->vol_type != vol_type) { > - ubi_err("bad vol_type"); > + ubi_err(ubi->ubi_num, "bad vol_type"); > goto bad_vid_hdr; > } > > if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) { > - ubi_err("bad sqnum %llu", aeb->sqnum); > + ubi_err(ubi->ubi_num, > + "bad sqnum %llu", aeb->sqnum); > goto bad_vid_hdr; > } > > if (av->vol_id != be32_to_cpu(vidh->vol_id)) { > - ubi_err("bad vol_id %d", av->vol_id); > + ubi_err(ubi->ubi_num, > + "bad vol_id %d", av->vol_id); > goto bad_vid_hdr; > } > > if (av->compat != vidh->compat) { > - ubi_err("bad compat %d", vidh->compat); > + ubi_err(ubi->ubi_num, > + "bad compat %d", vidh->compat); > goto bad_vid_hdr; > } > > if (aeb->lnum != be32_to_cpu(vidh->lnum)) { > - ubi_err("bad lnum %d", aeb->lnum); > + ubi_err(ubi->ubi_num, "bad lnum %d", aeb->lnum); > goto bad_vid_hdr; > } > > if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) { > - ubi_err("bad used_ebs %d", av->used_ebs); > + ubi_err(ubi->ubi_num, > + "bad used_ebs %d", av->used_ebs); > goto bad_vid_hdr; > } > > if (av->data_pad != be32_to_cpu(vidh->data_pad)) { > - ubi_err("bad data_pad %d", av->data_pad); > + ubi_err(ubi->ubi_num, > + "bad data_pad %d", av->data_pad); > goto bad_vid_hdr; > } > } > @@ -1680,12 +1693,14 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > continue; > > if (av->highest_lnum != be32_to_cpu(vidh->lnum)) { > - ubi_err("bad highest_lnum %d", av->highest_lnum); > + ubi_err(ubi->ubi_num, > + "bad highest_lnum %d", av->highest_lnum); > goto bad_vid_hdr; > } > > if (av->last_data_size != be32_to_cpu(vidh->data_size)) { > - ubi_err("bad last_data_size %d", av->last_data_size); > + ubi_err(ubi->ubi_num, > + "bad last_data_size %d", av->last_data_size); > goto bad_vid_hdr; > } > } > @@ -1726,7 +1741,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > err = 0; > for (pnum = 0; pnum < ubi->peb_count; pnum++) > if (!buf[pnum]) { > - ubi_err("PEB %d is not referred", pnum); > + ubi_err(ubi->ubi_num, "PEB %d is not referred", pnum); > err = 1; > } > > @@ -1736,18 +1751,21 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) > return 0; > > bad_aeb: > - ubi_err("bad attaching information about LEB %d", aeb->lnum); > + ubi_err(ubi->ubi_num, "bad attaching information about LEB %d", > + aeb->lnum); > ubi_dump_aeb(aeb, 0); > ubi_dump_av(av); > goto out; > > bad_av: > - ubi_err("bad attaching information about volume %d", av->vol_id); > + ubi_err(ubi->ubi_num, "bad attaching information about volume %d", > + av->vol_id); > ubi_dump_av(av); > goto out; > > bad_vid_hdr: > - ubi_err("bad attaching information about volume %d", av->vol_id); > + ubi_err(ubi->ubi_num, "bad attaching information about volume %d", > + av->vol_id); > ubi_dump_av(av); > ubi_dump_vid_hdr(vidh); > > diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c > index 6e30a3c..2b7dbd0 100644 > --- a/drivers/mtd/ubi/build.c > +++ b/drivers/mtd/ubi/build.c > @@ -166,7 +166,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype) > case UBI_VOLUME_RESIZED: > case UBI_VOLUME_RENAMED: > if (ubi_update_fastmap(ubi)) { > - ubi_err("Unable to update fastmap!"); > + ubi_err(ubi->ubi_num, "Unable to update fastmap!"); > ubi_ro_mode(ubi); > } > } > @@ -517,7 +517,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) > */ > err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); > if (err) { > - ubi_err("cannot register UBI character devices"); > + ubi_err(ubi->ubi_num, "cannot register UBI character devices"); > return err; > } > > @@ -528,7 +528,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) > > err = cdev_add(&ubi->cdev, dev, 1); > if (err) { > - ubi_err("cannot add character device"); > + ubi_err(ubi->ubi_num, "cannot add character device"); > goto out_unreg; > } > > @@ -540,7 +540,8 @@ static int uif_init(struct ubi_device *ubi, int *ref) > if (ubi->volumes[i]) { > err = ubi_add_volume(ubi, ubi->volumes[i]); > if (err) { > - ubi_err("cannot add volume %d", i); > + ubi_err(ubi->ubi_num, > + "cannot add volume %d", i); > goto out_volumes; > } > } > @@ -556,7 +557,8 @@ out_sysfs: > cdev_del(&ubi->cdev); > out_unreg: > unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); > - ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); > + ubi_err(ubi->ubi_num, "cannot initialize UBI %s, error %d", > + ubi->ubi_name, err); > return err; > } > > @@ -650,7 +652,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > * guess we should just pick the largest region. But this is > * not implemented. > */ > - ubi_err("multiple regions, not implemented"); > + ubi_err(ubi->ubi_num, "multiple regions, not implemented"); > return -EINVAL; > } > > @@ -685,7 +687,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > * which allows us to avoid costly division operations. > */ > if (!is_power_of_2(ubi->min_io_size)) { > - ubi_err("min. I/O unit (%d) is not power of 2", > + ubi_err(ubi->ubi_num, "min. I/O unit (%d) is not power of 2", > ubi->min_io_size); > return -EINVAL; > } > @@ -702,7 +704,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > if (ubi->max_write_size < ubi->min_io_size || > ubi->max_write_size % ubi->min_io_size || > !is_power_of_2(ubi->max_write_size)) { > - ubi_err("bad write buffer size %d for %d min. I/O unit", > + ubi_err(ubi->ubi_num, "bad write buffer size %d for %d min. I/O unit", > ubi->max_write_size, ubi->min_io_size); > return -EINVAL; > } > @@ -739,7 +741,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > > /* The shift must be aligned to 32-bit boundary */ > if (ubi->vid_hdr_shift % 4) { > - ubi_err("unaligned VID header shift %d", > + ubi_err(ubi->ubi_num, "unaligned VID header shift %d", > ubi->vid_hdr_shift); > return -EINVAL; > } > @@ -749,7 +751,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || > ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || > ubi->leb_start & (ubi->min_io_size - 1)) { > - ubi_err("bad VID header (%d) or data offsets (%d)", > + ubi_err(ubi->ubi_num, "bad VID header (%d) or data offsets (%d)", > ubi->vid_hdr_offset, ubi->leb_start); > return -EINVAL; > } > @@ -769,14 +771,15 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) > * read-only mode. > */ > if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { > - ubi_warn("EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); > + ubi_warn(ubi->ubi_num, "EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); > ubi->ro_mode = 1; > } > > ubi->leb_size = ubi->peb_size - ubi->leb_start; > > if (!(ubi->mtd->flags & MTD_WRITEABLE)) { > - ubi_msg("MTD device %d is write-protected, attach in read-only mode", > + ubi_msg(ubi->ubi_num, > + "MTD device %d is write-protected, attach in read-only mode", > ubi->mtd->index); > ubi->ro_mode = 1; > } > @@ -809,7 +812,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) > int err, old_reserved_pebs = vol->reserved_pebs; > > if (ubi->ro_mode) { > - ubi_warn("skip auto-resize because of R/O mode"); > + ubi_warn(ubi->ubi_num, "skip auto-resize because of R/O mode"); > return 0; > } > > @@ -830,20 +833,23 @@ static int autoresize(struct ubi_device *ubi, int vol_id) > vtbl_rec = ubi->vtbl[vol_id]; > err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); > if (err) > - ubi_err("cannot clean auto-resize flag for volume %d", > + ubi_err(ubi->ubi_num, > + "cannot clean auto-resize flag for volume %d", > vol_id); > } else { > desc.vol = vol; > err = ubi_resize_volume(&desc, > old_reserved_pebs + ubi->avail_pebs); > if (err) > - ubi_err("cannot auto-resize volume %d", vol_id); > + ubi_err(ubi->ubi_num, "cannot auto-resize volume %d", > + vol_id); > } > > if (err) > return err; > > - ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, > + ubi_msg(ubi->ubi_num, "volume %d (\"%s\") re-sized from %d to %d LEBs", > + vol_id, > vol->name, old_reserved_pebs, vol->reserved_pebs); > return 0; > } > @@ -885,7 +891,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > for (i = 0; i < UBI_MAX_DEVICES; i++) { > ubi = ubi_devices[i]; > if (ubi && mtd->index == ubi->mtd->index) { > - ubi_err("mtd%d is already attached to ubi%d", > + ubi_err(ubi->ubi_num, > + "mtd%d is already attached to ubi%d", > mtd->index, i); > return -EEXIST; > } > @@ -900,7 +907,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > * no sense to attach emulated MTD devices, so we prohibit this. > */ > if (mtd->type == MTD_UBIVOLUME) { > - ubi_err("refuse attaching mtd%d - it is already emulated on top of UBI", > + ubi_err(ubi->ubi_num, "refuse attaching mtd%d - it is already emulated on top of UBI", > mtd->index); > return -EINVAL; > } > @@ -911,7 +918,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > if (!ubi_devices[ubi_num]) > break; > if (ubi_num == UBI_MAX_DEVICES) { > - ubi_err("only %d UBI devices may be created", > + ubi_err(ubi->ubi_num, > + "only %d UBI devices may be created", > UBI_MAX_DEVICES); > return -ENFILE; > } > @@ -921,7 +929,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > > /* Make sure ubi_num is not busy */ > if (ubi_devices[ubi_num]) { > - ubi_err("ubi%d already exists", ubi_num); > + ubi_err(ubi_num, "ubi%d already exists", ubi_num); > return -EEXIST; > } > } > @@ -953,13 +961,15 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > > if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) > <= UBI_FM_MAX_START) { > - ubi_err("More than %i PEBs are needed for fastmap, sorry.", > + ubi_err(ubi->ubi_num, "More than %i PEBs are needed for fastmap, sorry.", > UBI_FM_MAX_START); > ubi->fm_disabled = 1; > } > > - ubi_msg("default fastmap pool size: %d", ubi->fm_pool.max_size); > - ubi_msg("default fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); > + ubi_msg(ubi->ubi_num, "default fastmap pool size: %d", > + ubi->fm_pool.max_size); > + ubi_msg(ubi->ubi_num, "default fastmap WL pool size: %d", > + ubi->fm_wl_pool.max_size); > #else > ubi->fm_disabled = 1; > #endif > @@ -970,7 +980,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > mutex_init(&ubi->fm_mutex); > init_rwsem(&ubi->fm_sem); > > - ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); > + ubi_msg(ubi->ubi_num, "attaching mtd%d to ubi%d", mtd->index, ubi_num); > > err = io_init(ubi, max_beb_per1024); > if (err) > @@ -989,7 +999,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > #endif > err = ubi_attach(ubi, 0); > if (err) { > - ubi_err("failed to attach mtd%d, error %d", mtd->index, err); > + ubi_err(ubi->ubi_num, "failed to attach mtd%d, error %d", > + mtd->index, err); > goto out_free; > } > > @@ -1010,28 +1021,32 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, > ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name); > if (IS_ERR(ubi->bgt_thread)) { > err = PTR_ERR(ubi->bgt_thread); > - ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, > + ubi_err(ubi->ubi_num, "cannot spawn \"%s\", error %d", > + ubi->bgt_name, > err); > goto out_debugfs; > } > > - ubi_msg("attached mtd%d (name \"%s\", size %llu MiB) to ubi%d", > - mtd->index, mtd->name, ubi->flash_size >> 20, ubi_num); > - ubi_msg("PEB size: %d bytes (%d KiB), LEB size: %d bytes", > + ubi_msg(ubi_num, "attached mtd%d (name \"%s\", size %llu MiB)", > + mtd->index, mtd->name, ubi->flash_size >> 20); > + ubi_msg(ubi_num, "PEB size: %d bytes (%d KiB), LEB size: %d bytes", > ubi->peb_size, ubi->peb_size >> 10, ubi->leb_size); > - ubi_msg("min./max. I/O unit sizes: %d/%d, sub-page size %d", > + ubi_msg(ubi_num, "min./max. I/O unit sizes: %d/%d, sub-page size %d", > ubi->min_io_size, ubi->max_write_size, ubi->hdrs_min_io_size); > - ubi_msg("VID header offset: %d (aligned %d), data offset: %d", > + ubi_msg(ubi_num, "VID header offset: %d (aligned %d), data offset: %d", > ubi->vid_hdr_offset, ubi->vid_hdr_aloffset, ubi->leb_start); > - ubi_msg("good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", > + ubi_msg(ubi_num, "good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", > ubi->good_peb_count, ubi->bad_peb_count, ubi->corr_peb_count); > - ubi_msg("user volume: %d, internal volumes: %d, max. volumes count: %d", > + ubi_msg(ubi_num, > + "user volume: %d, internal volumes: %d, max. volumes count: %d", > ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT, > ubi->vtbl_slots); > - ubi_msg("max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", > + ubi_msg(ubi_num, > + "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", > ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD, > ubi->image_seq); > - ubi_msg("available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", > + ubi_msg(ubi_num, > + "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", > ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs); > > /* > @@ -1100,7 +1115,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) > return -EBUSY; > } > /* This may only happen if there is a bug */ > - ubi_err("%s reference count %d, destroy anyway", > + ubi_err(ubi->ubi_num, "%s reference count %d, destroy anyway", > ubi->ubi_name, ubi->ref_count); > } > ubi_devices[ubi_num] = NULL; > @@ -1108,7 +1123,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) > > ubi_assert(ubi_num == ubi->ubi_num); > ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL); > - ubi_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); > + ubi_msg(ubi->ubi_num, "detaching mtd%d", ubi->mtd->index); > #ifdef CONFIG_MTD_UBI_FASTMAP > /* If we don't write a new fastmap at detach time we lose all > * EC updates that have been made since the last written fastmap. */ > @@ -1136,7 +1151,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) > put_mtd_device(ubi->mtd); > vfree(ubi->peb_buf); > vfree(ubi->fm_buf); > - ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); > + ubi_msg(ubi->ubi_num, "mtd%d is detached", ubi->mtd->index); > put_device(&ubi->dev); > return 0; > } > @@ -1218,7 +1233,8 @@ static int __init ubi_init(void) > BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); > > if (mtd_devs > UBI_MAX_DEVICES) { > - ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); > + ubi_err(UBI_MAX_DEVICES, "too many MTD devices, maximum is %d", > + UBI_MAX_DEVICES); > return -EINVAL; > } > > @@ -1226,19 +1242,19 @@ static int __init ubi_init(void) > ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); > if (IS_ERR(ubi_class)) { > err = PTR_ERR(ubi_class); > - ubi_err("cannot create UBI class"); > + ubi_err(UBI_MAX_DEVICES, "cannot create UBI class"); > goto out; > } > > err = class_create_file(ubi_class, &ubi_version); > if (err) { > - ubi_err("cannot create sysfs file"); > + ubi_err(UBI_MAX_DEVICES, "cannot create sysfs file"); > goto out_class; > } > > err = misc_register(&ubi_ctrl_cdev); > if (err) { > - ubi_err("cannot register device"); > + ubi_err(UBI_MAX_DEVICES, "cannot register device"); > goto out_version; > } > > @@ -1265,7 +1281,9 @@ static int __init ubi_init(void) > mtd = open_mtd_device(p->name); > if (IS_ERR(mtd)) { > err = PTR_ERR(mtd); > - ubi_err("cannot open mtd %s, error %d", p->name, err); > + ubi_err(UBI_MAX_DEVICES, > + "cannot open mtd %s, error %d", > + p->name, err); > /* See comment below re-ubi_is_module(). */ > if (ubi_is_module()) > goto out_detach; > @@ -1277,7 +1295,8 @@ static int __init ubi_init(void) > p->vid_hdr_offs, p->max_beb_per1024); > mutex_unlock(&ubi_devices_mutex); > if (err < 0) { > - ubi_err("cannot attach mtd%d", mtd->index); > + ubi_err(UBI_MAX_DEVICES, "cannot attach mtd%d", > + mtd->index); > put_mtd_device(mtd); > > /* > @@ -1326,7 +1345,8 @@ out_version: > out_class: > class_destroy(ubi_class); > out: > - ubi_err("cannot initialize UBI, error %d", err); > + ubi_err(UBI_MAX_DEVICES, > + "cannot initialize UBI, error %d", err); > return err; > } > late_initcall(ubi_init); > @@ -1365,7 +1385,8 @@ static int __init bytes_str_to_int(const char *str) > > result = simple_strtoul(str, &endp, 0); > if (str == endp || result >= INT_MAX) { > - ubi_err("incorrect bytes count: \"%s\"\n", str); > + ubi_err(UBI_MAX_DEVICES, > + "incorrect bytes count: \"%s\"\n", str); > return -EINVAL; > } > > @@ -1381,7 +1402,8 @@ static int __init bytes_str_to_int(const char *str) > case '\0': > break; > default: > - ubi_err("incorrect bytes count: \"%s\"\n", str); > + ubi_err(UBI_MAX_DEVICES, > + "incorrect bytes count: \"%s\"\n", str); > return -EINVAL; > } > > @@ -1408,20 +1430,22 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) > return -EINVAL; > > if (mtd_devs == UBI_MAX_DEVICES) { > - ubi_err("too many parameters, max. is %d\n", > + ubi_err(UBI_MAX_DEVICES, > + "too many parameters, max. is %d\n", > UBI_MAX_DEVICES); > return -EINVAL; > } > > len = strnlen(val, MTD_PARAM_LEN_MAX); > if (len == MTD_PARAM_LEN_MAX) { > - ubi_err("parameter \"%s\" is too long, max. is %d\n", > + ubi_err(UBI_MAX_DEVICES, > + "parameter \"%s\" is too long, max. is %d\n", > val, MTD_PARAM_LEN_MAX); > return -EINVAL; > } > > if (len == 0) { > - pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n"); > + ubi_warn(UBI_MAX_DEVICES, "empty 'mtd=' parameter - ignored\n"); > return 0; > } > > @@ -1435,7 +1459,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) > tokens[i] = strsep(&pbuf, ","); > > if (pbuf) { > - ubi_err("too many arguments at \"%s\"\n", val); > + ubi_err(UBI_MAX_DEVICES, "too many arguments at \"%s\"\n", > + val); > return -EINVAL; > } > > @@ -1455,7 +1480,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) > int err = kstrtoint(token, 10, &p->max_beb_per1024); > > if (err) { > - ubi_err("bad value for max_beb_per1024 parameter: %s", > + ubi_err(UBI_MAX_DEVICES, > + "bad value for max_beb_per1024 parameter: %s", > token); > return -EINVAL; > } > diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c > index 7646220..81d64b3 100644 > --- a/drivers/mtd/ubi/cdev.c > +++ b/drivers/mtd/ubi/cdev.c > @@ -48,13 +48,14 @@ > > /** > * get_exclusive - get exclusive access to an UBI volume. > + * @ubi: UBI device description object > * @desc: volume descriptor > * > * This function changes UBI volume open mode to "exclusive". Returns previous > * mode value (positive integer) in case of success and a negative error code > * in case of failure. > */ > -static int get_exclusive(struct ubi_volume_desc *desc) > +static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc) > { > int users, err; > struct ubi_volume *vol = desc->vol; > @@ -63,7 +64,8 @@ static int get_exclusive(struct ubi_volume_desc *desc) > users = vol->readers + vol->writers + vol->exclusive; > ubi_assert(users > 0); > if (users > 1) { > - ubi_err("%d users for volume %d", users, vol->vol_id); > + ubi_err(ubi->ubi_num, "%d users for volume %d", > + users, vol->vol_id); > err = -EBUSY; > } else { > vol->readers = vol->writers = 0; > @@ -134,7 +136,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) > vol->ubi->ubi_num, vol->vol_id, desc->mode); > > if (vol->updating) { > - ubi_warn("update of volume %d not finished, volume is damaged", > + ubi_warn(vol->ubi->ubi_num, "update of volume %d not finished, volume is damaged", > vol->vol_id); > ubi_assert(!vol->changing_leb); > vol->updating = 0; > @@ -158,7 +160,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) > > if (vol->updating) { > /* Update is in progress, seeking is prohibited */ > - ubi_err("updating"); > + ubi_err(vol->ubi->ubi_num, "updating"); > return -EBUSY; > } > > @@ -193,11 +195,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, > count, *offp, vol->vol_id); > > if (vol->updating) { > - ubi_err("updating"); > + ubi_err(vol->ubi->ubi_num, "updating"); > return -EBUSY; > } > if (vol->upd_marker) { > - ubi_err("damaged volume, update marker is set"); > + ubi_err(vol->ubi->ubi_num, "damaged volume, update marker is set"); > return -EBADF; > } > if (*offp == vol->used_bytes || count == 0) > @@ -277,7 +279,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, > > lnum = div_u64_rem(*offp, vol->usable_leb_size, &off); > if (off & (ubi->min_io_size - 1)) { > - ubi_err("unaligned position"); > + ubi_err(ubi->ubi_num, "unaligned position"); > return -EINVAL; > } > > @@ -286,7 +288,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, > > /* We can write only in fractions of the minimum I/O unit */ > if (count & (ubi->min_io_size - 1)) { > - ubi_err("unaligned write length"); > + ubi_err(ubi->ubi_num, "unaligned write length"); > return -EINVAL; > } > > @@ -348,7 +350,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, > err = ubi_more_leb_change_data(ubi, vol, buf, count); > > if (err < 0) { > - ubi_err("cannot accept more %zd bytes of data, error %d", > + ubi_err(ubi->ubi_num, "cannot accept more %zd bytes of data, error %d", > count, err); > return err; > } > @@ -370,7 +372,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, > return err; > > if (err) { > - ubi_warn("volume %d on UBI device %d is corrupted", > + ubi_warn(ubi->ubi_num, "volume %d on UBI device %d is corrupted", > vol->vol_id, ubi->ubi_num); > vol->corrupted = 1; > } > @@ -420,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, > break; > } > > - err = get_exclusive(desc); > + err = get_exclusive(ubi, desc); > if (err < 0) > break; > > @@ -454,7 +456,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, > req.bytes < 0 || req.lnum >= vol->usable_leb_size) > break; > > - err = get_exclusive(desc); > + err = get_exclusive(ubi, desc); > if (err < 0) > break; > > @@ -640,7 +642,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi, > return 0; > > bad: > - ubi_err("bad volume creation request"); > + ubi_err(ubi->ubi_num, "bad volume creation request"); > ubi_dump_mkvol_req(req); > return err; > } > @@ -706,12 +708,12 @@ static int rename_volumes(struct ubi_device *ubi, > for (i = 0; i < req->count - 1; i++) { > for (n = i + 1; n < req->count; n++) { > if (req->ents[i].vol_id == req->ents[n].vol_id) { > - ubi_err("duplicated volume id %d", > + ubi_err(ubi->ubi_num, "duplicated volume id %d", > req->ents[i].vol_id); > return -EINVAL; > } > if (!strcmp(req->ents[i].name, req->ents[n].name)) { > - ubi_err("duplicated volume name \"%s\"", > + ubi_err(ubi->ubi_num, "duplicated volume name \"%s\"", > req->ents[i].name); > return -EINVAL; > } > @@ -734,7 +736,8 @@ static int rename_volumes(struct ubi_device *ubi, > re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE); > if (IS_ERR(re->desc)) { > err = PTR_ERR(re->desc); > - ubi_err("cannot open volume %d, error %d", vol_id, err); > + ubi_err(ubi->ubi_num, > + "cannot open volume %d, error %d", vol_id, err); > kfree(re); > goto out_free; > } > @@ -793,7 +796,7 @@ static int rename_volumes(struct ubi_device *ubi, > continue; > > /* The volume exists but busy, or an error occurred */ > - ubi_err("cannot open volume \"%s\", error %d", > + ubi_err(ubi->ubi_num, "cannot open volume \"%s\", error %d", > re->new_name, err); > goto out_free; > } > diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c > index 63cb1d7..e92bc1c 100644 > --- a/drivers/mtd/ubi/debug.c > +++ b/drivers/mtd/ubi/debug.c > @@ -43,12 +43,13 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) > return; > err = mtd_read(ubi->mtd, addr, len, &read, buf); > if (err && err != -EUCLEAN) { > - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", > + ubi_err(ubi->ubi_num, > + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", > err, len, pnum, offset, read); > goto out; > } > > - ubi_msg("dumping %d bytes of data from PEB %d, offset %d", > + ubi_msg(ubi->ubi_num, "dumping %d bytes of data from PEB %d, offset %d", > len, pnum, offset); > print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); > out: > @@ -238,7 +239,7 @@ int ubi_debugfs_init(void) > if (IS_ERR_OR_NULL(dfs_rootdir)) { > int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); > > - ubi_err("cannot create \"ubi\" debugfs directory, error %d\n", > + ubi_err(UBI_MAX_DEVICES, "cannot create \"ubi\" debugfs directory, error %d\n", > err); > return err; > } > @@ -433,7 +434,7 @@ out_remove: > debugfs_remove_recursive(d->dfs_dir); > out: > err = dent ? PTR_ERR(dent) : -ENODEV; > - ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n", > + ubi_err(ubi->ubi_num, "cannot create \"%s\" debugfs file or directory, error %d\n", > fname, err); > return err; > } > diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c > index 0e11671d..eb93dfd 100644 > --- a/drivers/mtd/ubi/eba.c > +++ b/drivers/mtd/ubi/eba.c > @@ -422,7 +422,7 @@ retry: > */ > if (err == UBI_IO_BAD_HDR_EBADMSG || > err == UBI_IO_BAD_HDR) { > - ubi_warn("corrupted VID header at PEB %d, LEB %d:%d", > + ubi_warn(ubi->ubi_num, "corrupted VID header at PEB %d, LEB %d:%d", > pnum, vol_id, lnum); > err = -EBADMSG; > } else > @@ -449,7 +449,7 @@ retry: > goto out_unlock; > scrub = 1; > if (!check) { > - ubi_msg("force data checking"); > + ubi_msg(ubi->ubi_num, "force data checking"); > check = 1; > goto retry; > } > @@ -460,7 +460,7 @@ retry: > if (check) { > uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len); > if (crc1 != crc) { > - ubi_warn("CRC error: calculated %#08x, must be %#08x", > + ubi_warn(ubi->ubi_num, "CRC error: calculated %#08x, must be %#08x", > crc1, crc); > err = -EBADMSG; > goto out_unlock; > @@ -514,7 +514,8 @@ retry: > return new_pnum; > } > > - ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); > + ubi_msg(ubi->ubi_num, "recover PEB %d, move data to PEB %d", > + pnum, new_pnum); > > err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); > if (err && err != UBI_IO_BITFLIPS) { > @@ -555,7 +556,7 @@ retry: > up_read(&ubi->fm_sem); > ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); > > - ubi_msg("data was successfully recovered"); > + ubi_msg(ubi->ubi_num, "data was successfully recovered"); > return 0; > > out_unlock: > @@ -570,13 +571,13 @@ write_error: > * Bad luck? This physical eraseblock is bad too? Crud. Let's try to > * get another one. > */ > - ubi_warn("failed to write to PEB %d", new_pnum); > + ubi_warn(ubi->ubi_num, "failed to write to PEB %d", new_pnum); > ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); > if (++tries > UBI_IO_RETRIES) { > ubi_free_vid_hdr(ubi, vid_hdr); > return err; > } > - ubi_msg("try again"); > + ubi_msg(ubi->ubi_num, "try again"); > goto retry; > } > > @@ -614,7 +615,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, > > err = ubi_io_write_data(ubi, buf, pnum, offset, len); > if (err) { > - ubi_warn("failed to write data to PEB %d", pnum); > + ubi_warn(ubi->ubi_num, > + "failed to write data to PEB %d", pnum); > if (err == -EIO && ubi->bad_allowed) > err = recover_peb(ubi, pnum, vol_id, lnum, buf, > offset, len); > @@ -655,7 +657,7 @@ retry: > > err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); > if (err) { > - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", > vol_id, lnum, pnum); > goto write_error; > } > @@ -663,7 +665,7 @@ retry: > if (len) { > err = ubi_io_write_data(ubi, buf, pnum, offset, len); > if (err) { > - ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", > len, offset, vol_id, lnum, pnum); > goto write_error; > } > @@ -699,7 +701,7 @@ write_error: > } > > vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); > - ubi_msg("try another PEB"); > + ubi_msg(ubi->ubi_num, "try another PEB"); > goto retry; > } > > @@ -776,14 +778,14 @@ retry: > > err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); > if (err) { > - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", > vol_id, lnum, pnum); > goto write_error; > } > > err = ubi_io_write_data(ubi, buf, pnum, 0, len); > if (err) { > - ubi_warn("failed to write %d bytes of data to PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write %d bytes of data to PEB %d", > len, pnum); > goto write_error; > } > @@ -819,7 +821,7 @@ write_error: > } > > vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); > - ubi_msg("try another PEB"); > + ubi_msg(ubi->ubi_num, "try another PEB"); > goto retry; > } > > @@ -894,14 +896,14 @@ retry: > > err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); > if (err) { > - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write VID header to LEB %d:%d, PEB %d", > vol_id, lnum, pnum); > goto write_error; > } > > err = ubi_io_write_data(ubi, buf, pnum, 0, len); > if (err) { > - ubi_warn("failed to write %d bytes of data to PEB %d", > + ubi_warn(ubi->ubi_num, "failed to write %d bytes of data to PEB %d", > len, pnum); > goto write_error; > } > @@ -941,7 +943,7 @@ write_error: > } > > vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); > - ubi_msg("try another PEB"); > + ubi_msg(ubi->ubi_num, "try another PEB"); > goto retry; > } > > @@ -1064,7 +1066,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, > dbg_wl("read %d bytes of data", aldata_size); > err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size); > if (err && err != UBI_IO_BITFLIPS) { > - ubi_warn("error %d while reading data from PEB %d", > + ubi_warn(ubi->ubi_num, "error %d while reading data from PEB %d", > err, from); > err = MOVE_SOURCE_RD_ERR; > goto out_unlock_buf; > @@ -1114,7 +1116,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, > err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); > if (err) { > if (err != UBI_IO_BITFLIPS) { > - ubi_warn("error %d while reading VID header back from PEB %d", > + ubi_warn(ubi->ubi_num, "error %d while reading VID header back from PEB %d", > err, to); > if (is_error_sane(err)) > err = MOVE_TARGET_RD_ERR; > @@ -1141,7 +1143,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, > err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size); > if (err) { > if (err != UBI_IO_BITFLIPS) { > - ubi_warn("error %d while reading data back from PEB %d", > + ubi_warn(ubi->ubi_num, "error %d while reading data back from PEB %d", > err, to); > if (is_error_sane(err)) > err = MOVE_TARGET_RD_ERR; > @@ -1153,7 +1155,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, > cond_resched(); > > if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) { > - ubi_warn("read data back from PEB %d and it is different", > + ubi_warn(ubi->ubi_num, "read data back from PEB %d and it is different", > to); > err = -EINVAL; > goto out_unlock_buf; > @@ -1206,10 +1208,10 @@ static void print_rsvd_warning(struct ubi_device *ubi, > return; > } > > - ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", > + ubi_warn(ubi->ubi_num, "cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", > ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); > if (ubi->corr_peb_count) > - ubi_warn("%d PEBs are corrupted and not used", > + ubi_warn(ubi->ubi_num, "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > } > > @@ -1287,7 +1289,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, > fm_eba[i][j] == UBI_LEB_UNMAPPED) > continue; > > - ubi_err("LEB:%i:%i is PEB:%i instead of %i!", > + ubi_err(ubi->ubi_num, "LEB:%i:%i is PEB:%i instead of %i!", > vol->vol_id, i, fm_eba[i][j], > scan_eba[i][j]); > ubi_assert(0); > @@ -1367,10 +1369,10 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai) > } > > if (ubi->avail_pebs < EBA_RESERVED_PEBS) { > - ubi_err("no enough physical eraseblocks (%d, need %d)", > + ubi_err(ubi->ubi_num, "no enough physical eraseblocks (%d, need %d)", > ubi->avail_pebs, EBA_RESERVED_PEBS); > if (ubi->corr_peb_count) > - ubi_err("%d PEBs are corrupted and not used", > + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > err = -ENOSPC; > goto out_free; > diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c > index 0431b46..35f5d44 100644 > --- a/drivers/mtd/ubi/fastmap.c > +++ b/drivers/mtd/ubi/fastmap.c > @@ -329,7 +329,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, > if (found) > av = tmp_av; > else { > - ubi_err("orphaned volume in fastmap pool!"); > + ubi_err(ubi->ubi_num, "orphaned volume in fastmap pool!"); > return UBI_BAD_FASTMAP; > } > > @@ -412,14 +412,14 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, > pnum = be32_to_cpu(pebs[i]); > > if (ubi_io_is_bad(ubi, pnum)) { > - ubi_err("bad PEB in fastmap pool!"); > + ubi_err(ubi->ubi_num, "bad PEB in fastmap pool!"); > ret = UBI_BAD_FASTMAP; > goto out; > } > > err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); > if (err && err != UBI_IO_BITFLIPS) { > - ubi_err("unable to read EC header! PEB:%i err:%i", > + ubi_err(ubi->ubi_num, "unable to read EC header! PEB:%i err:%i", > pnum, err); > ret = err > 0 ? UBI_BAD_FASTMAP : err; > goto out; > @@ -433,7 +433,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, > image_seq = be32_to_cpu(ech->image_seq); > > if (image_seq && (image_seq != ubi->image_seq)) { > - ubi_err("bad image seq: 0x%x, expected: 0x%x", > + ubi_err(ubi->ubi_num, "bad image seq: 0x%x, expected: 0x%x", > be32_to_cpu(ech->image_seq), ubi->image_seq); > ret = UBI_BAD_FASTMAP; > goto out; > @@ -491,7 +491,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, > } > } else { > /* We are paranoid and fall back to scanning mode */ > - ubi_err("fastmap pool PEBs contains damaged PEBs!"); > + ubi_err(ubi->ubi_num, "fastmap pool PEBs contains damaged PEBs!"); > ret = err > 0 ? UBI_BAD_FASTMAP : err; > goto out; > } > @@ -586,7 +586,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > goto fail_bad; > > if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) { > - ubi_err("bad fastmap header magic: 0x%x, expected: 0x%x", > + ubi_err(ubi->ubi_num, "bad fastmap header magic: 0x%x, expected: 0x%x", > be32_to_cpu(fmhdr->magic), UBI_FM_HDR_MAGIC); > goto fail_bad; > } > @@ -596,7 +596,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > if (fm_pos >= fm_size) > goto fail_bad; > if (be32_to_cpu(fmpl1->magic) != UBI_FM_POOL_MAGIC) { > - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", > + ubi_err(ubi->ubi_num, "bad fastmap pool magic: 0x%x, expected: 0x%x", > be32_to_cpu(fmpl1->magic), UBI_FM_POOL_MAGIC); > goto fail_bad; > } > @@ -606,7 +606,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > if (fm_pos >= fm_size) > goto fail_bad; > if (be32_to_cpu(fmpl2->magic) != UBI_FM_POOL_MAGIC) { > - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", > + ubi_err(ubi->ubi_num, "bad fastmap pool magic: 0x%x, expected: 0x%x", > be32_to_cpu(fmpl2->magic), UBI_FM_POOL_MAGIC); > goto fail_bad; > } > @@ -617,25 +617,27 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > fm->max_wl_pool_size = be16_to_cpu(fmpl2->max_size); > > if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) { > - ubi_err("bad pool size: %i", pool_size); > + ubi_err(ubi->ubi_num, "bad pool size: %i", pool_size); > goto fail_bad; > } > > if (wl_pool_size > UBI_FM_MAX_POOL_SIZE || wl_pool_size < 0) { > - ubi_err("bad WL pool size: %i", wl_pool_size); > + ubi_err(ubi->ubi_num, "bad WL pool size: %i", wl_pool_size); > goto fail_bad; > } > > > if (fm->max_pool_size > UBI_FM_MAX_POOL_SIZE || > fm->max_pool_size < 0) { > - ubi_err("bad maximal pool size: %i", fm->max_pool_size); > + ubi_err(ubi->ubi_num, "bad maximal pool size: %i", > + fm->max_pool_size); > goto fail_bad; > } > > if (fm->max_wl_pool_size > UBI_FM_MAX_POOL_SIZE || > fm->max_wl_pool_size < 0) { > - ubi_err("bad maximal WL pool size: %i", fm->max_wl_pool_size); > + ubi_err(ubi->ubi_num, "bad maximal WL pool size: %i", > + fm->max_wl_pool_size); > goto fail_bad; > } > > @@ -694,8 +696,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > goto fail_bad; > > if (be32_to_cpu(fmvhdr->magic) != UBI_FM_VHDR_MAGIC) { > - ubi_err("bad fastmap vol header magic: 0x%x, " \ > - "expected: 0x%x", > + ubi_err(ubi->ubi_num, > + "bad fastmap vol header magic: 0x%x, expected: 0x%x", > be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC); > goto fail_bad; > } > @@ -720,7 +722,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > goto fail_bad; > > if (be32_to_cpu(fm_eba->magic) != UBI_FM_EBA_MAGIC) { > - ubi_err("bad fastmap EBA header magic: 0x%x, " \ > + ubi_err(ubi->ubi_num, "bad fastmap EBA header magic: 0x%x, " > "expected: 0x%x", > be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC); > goto fail_bad; > @@ -786,7 +788,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > int err; > > if (ubi_io_is_bad(ubi, tmp_aeb->pnum)) { > - ubi_err("bad PEB in fastmap EBA orphan list"); > + ubi_err(ubi->ubi_num, "bad PEB in fastmap EBA orphan list"); > ret = UBI_BAD_FASTMAP; > kfree(ech); > goto fail; > @@ -794,8 +796,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > > err = ubi_io_read_ec_hdr(ubi, tmp_aeb->pnum, ech, 0); > if (err && err != UBI_IO_BITFLIPS) { > - ubi_err("unable to read EC header! PEB:%i " \ > - "err:%i", tmp_aeb->pnum, err); > + ubi_err(ubi->ubi_num, > + "unable to read EC header! PEB:%i err:%i", > + tmp_aeb->pnum, err); > ret = err > 0 ? UBI_BAD_FASTMAP : err; > kfree(ech); > > @@ -906,14 +909,14 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > fm->to_be_tortured[0] = 1; > > if (be32_to_cpu(fmsb->magic) != UBI_FM_SB_MAGIC) { > - ubi_err("bad super block magic: 0x%x, expected: 0x%x", > + ubi_err(ubi->ubi_num, "bad super block magic: 0x%x, expected: 0x%x", > be32_to_cpu(fmsb->magic), UBI_FM_SB_MAGIC); > ret = UBI_BAD_FASTMAP; > goto free_fm_sb; > } > > if (fmsb->version != UBI_FM_FMT_VERSION) { > - ubi_err("bad fastmap version: %i, expected: %i", > + ubi_err(ubi->ubi_num, "bad fastmap version: %i, expected: %i", > fmsb->version, UBI_FM_FMT_VERSION); > ret = UBI_BAD_FASTMAP; > goto free_fm_sb; > @@ -921,14 +924,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > > used_blocks = be32_to_cpu(fmsb->used_blocks); > if (used_blocks > UBI_FM_MAX_BLOCKS || used_blocks < 1) { > - ubi_err("number of fastmap blocks is invalid: %i", used_blocks); > + ubi_err(ubi->ubi_num, > + "number of fastmap blocks is invalid: %i", used_blocks); > ret = UBI_BAD_FASTMAP; > goto free_fm_sb; > } > > fm_size = ubi->leb_size * used_blocks; > if (fm_size != ubi->fm_size) { > - ubi_err("bad fastmap size: %zi, expected: %zi", fm_size, > + ubi_err(ubi->ubi_num, > + "bad fastmap size: %zi, expected: %zi", fm_size, > ubi->fm_size); > ret = UBI_BAD_FASTMAP; > goto free_fm_sb; > @@ -958,7 +963,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > > ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); > if (ret && ret != UBI_IO_BITFLIPS) { > - ubi_err("unable to read fastmap block# %i EC (PEB: %i)", > + ubi_err(ubi->ubi_num, > + "unable to read fastmap block# %i EC (PEB: %i)", > i, pnum); > if (ret > 0) > ret = UBI_BAD_FASTMAP; > @@ -975,7 +981,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > * we shouldn't fail if image_seq == 0. > */ > if (image_seq && (image_seq != ubi->image_seq)) { > - ubi_err("wrong image seq:%d instead of %d", > + ubi_err(ubi->ubi_num, > + "wrong image seq:%d instead of %d", > be32_to_cpu(ech->image_seq), ubi->image_seq); > ret = UBI_BAD_FASTMAP; > goto free_hdr; > @@ -983,14 +990,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > > ret = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); > if (ret && ret != UBI_IO_BITFLIPS) { > - ubi_err("unable to read fastmap block# %i (PEB: %i)", > + ubi_err(ubi->ubi_num, > + "unable to read fastmap block# %i (PEB: %i)", > i, pnum); > goto free_hdr; > } > > if (i == 0) { > if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { > - ubi_err("bad fastmap anchor vol_id: 0x%x," \ > + ubi_err(ubi->ubi_num, > + "bad fastmap anchor vol_id: 0x%x," > " expected: 0x%x", > be32_to_cpu(vh->vol_id), > UBI_FM_SB_VOLUME_ID); > @@ -999,7 +1008,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > } > } else { > if (be32_to_cpu(vh->vol_id) != UBI_FM_DATA_VOLUME_ID) { > - ubi_err("bad fastmap data vol_id: 0x%x," \ > + ubi_err(ubi->ubi_num, > + "bad fastmap data vol_id: 0x%x," > " expected: 0x%x", > be32_to_cpu(vh->vol_id), > UBI_FM_DATA_VOLUME_ID); > @@ -1014,7 +1024,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum, > ubi->leb_start, ubi->leb_size); > if (ret && ret != UBI_IO_BITFLIPS) { > - ubi_err("unable to read fastmap block# %i (PEB: %i, " \ > + ubi_err(ubi->ubi_num, > + "unable to read fastmap block# %i (PEB: %i, " > "err: %i)", i, pnum, ret); > goto free_hdr; > } > @@ -1028,8 +1039,9 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > fmsb2->data_crc = 0; > crc = crc32(UBI_CRC32_INIT, ubi->fm_buf, fm_size); > if (crc != tmp_crc) { > - ubi_err("fastmap data CRC is invalid"); > - ubi_err("CRC should be: 0x%x, calc: 0x%x", tmp_crc, crc); > + ubi_err(ubi->ubi_num, "fastmap data CRC is invalid"); > + ubi_err(ubi->ubi_num, "CRC should be: 0x%x, calc: 0x%x", > + tmp_crc, crc); > ret = UBI_BAD_FASTMAP; > goto free_hdr; > } > @@ -1065,9 +1077,10 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > ubi->fm = fm; > ubi->fm_pool.max_size = ubi->fm->max_pool_size; > ubi->fm_wl_pool.max_size = ubi->fm->max_wl_pool_size; > - ubi_msg("attached by fastmap"); > - ubi_msg("fastmap pool size: %d", ubi->fm_pool.max_size); > - ubi_msg("fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); > + ubi_msg(ubi->ubi_num, "attached by fastmap"); > + ubi_msg(ubi->ubi_num, "fastmap pool size: %d", ubi->fm_pool.max_size); > + ubi_msg(ubi->ubi_num, "fastmap WL pool size: %d", > + ubi->fm_wl_pool.max_size); > ubi->fm_disabled = 0; > > ubi_free_vid_hdr(ubi, vh); > @@ -1075,7 +1088,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, > out: > mutex_unlock(&ubi->fm_mutex); > if (ret == UBI_BAD_FASTMAP) > - ubi_err("Attach by fastmap failed, doing a full scan!"); > + ubi_err(ubi->ubi_num, > + "Attach by fastmap failed, doing a full scan!"); > return ret; > > free_hdr: > @@ -1271,7 +1285,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, > dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum); > ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avhdr); > if (ret) { > - ubi_err("unable to write vid_hdr to fastmap SB!"); > + ubi_err(ubi->ubi_num, "unable to write vid_hdr to fastmap SB!"); > goto out_kfree; > } > > @@ -1291,7 +1305,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, > new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum)); > ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvhdr); > if (ret) { > - ubi_err("unable to write vid_hdr to PEB %i!", > + ubi_err(ubi->ubi_num, > + "unable to write vid_hdr to PEB %i!", > new_fm->e[i]->pnum); > goto out_kfree; > } > @@ -1301,7 +1316,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, > ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size), > new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size); > if (ret) { > - ubi_err("unable to write fastmap to PEB %i!", > + ubi_err(ubi->ubi_num, > + "unable to write fastmap to PEB %i!", > new_fm->e[i]->pnum); > goto out_kfree; > } > @@ -1448,7 +1464,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) > ubi->fm = NULL; > > if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) { > - ubi_err("fastmap too large"); > + ubi_err(ubi->ubi_num, "fastmap too large"); > ret = -ENOSPC; > goto err; > } > @@ -1460,7 +1476,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) > > if (!tmp_e && !old_fm) { > int j; > - ubi_err("could not get any free erase block"); > + ubi_err(ubi->ubi_num, > + "could not get any free erase block"); > > for (j = 1; j < i; j++) > ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); > @@ -1476,7 +1493,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) > ubi_wl_put_fm_peb(ubi, new_fm->e[j], > j, 0); > > - ubi_err("could not erase old fastmap PEB"); > + ubi_err(ubi->ubi_num, > + "could not erase old fastmap PEB"); > goto err; > } > > @@ -1502,7 +1520,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) > ret = erase_block(ubi, old_fm->e[0]->pnum); > if (ret < 0) { > int i; > - ubi_err("could not erase old anchor PEB"); > + ubi_err(ubi->ubi_num, > + "could not erase old anchor PEB"); > > for (i = 1; i < new_fm->used_blocks; i++) > ubi_wl_put_fm_peb(ubi, new_fm->e[i], > @@ -1523,7 +1542,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) > } else { > if (!tmp_e) { > int i; > - ubi_err("could not find any anchor PEB"); > + ubi_err(ubi->ubi_num, "could not find any anchor PEB"); > > for (i = 1; i < new_fm->used_blocks; i++) > ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0); > @@ -1553,13 +1572,14 @@ out_unlock: > err: > kfree(new_fm); > > - ubi_warn("Unable to write new fastmap, err=%i", ret); > + ubi_warn(ubi->ubi_num, "Unable to write new fastmap, err=%i", ret); > > ret = 0; > if (old_fm) { > ret = invalidate_fastmap(ubi, old_fm); > if (ret < 0) > - ubi_err("Unable to invalidiate current fastmap!"); > + ubi_err(ubi->ubi_num, > + "Unable to invalidiate current fastmap!"); > else if (ret) > ret = 0; > } > diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c > index d361349..237c902 100644 > --- a/drivers/mtd/ubi/io.c > +++ b/drivers/mtd/ubi/io.c > @@ -177,19 +177,22 @@ retry: > * enabled. A corresponding message will be printed > * later, when it is has been scrubbed. > */ > - ubi_msg("fixable bit-flip detected at PEB %d", pnum); > + ubi_msg(ubi->ubi_num, > + "fixable bit-flip detected at PEB %d", pnum); > ubi_assert(len == read); > return UBI_IO_BITFLIPS; > } > > if (retries++ < UBI_IO_RETRIES) { > - ubi_warn("error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", > + ubi_warn(ubi->ubi_num, > + "error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", > err, errstr, len, pnum, offset, read); > yield(); > goto retry; > } > > - ubi_err("error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", > + ubi_err(ubi->ubi_num, > + "error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", > err, errstr, len, pnum, offset, read); > dump_stack(); > > @@ -246,7 +249,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, > ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0); > > if (ubi->ro_mode) { > - ubi_err("read-only mode"); > + ubi_err(ubi->ubi_num, "read-only mode"); > return -EROFS; > } > > @@ -273,7 +276,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, > } > > if (ubi_dbg_is_write_failure(ubi)) { > - ubi_err("cannot write %d bytes to PEB %d:%d (emulated)", > + ubi_err(ubi->ubi_num, > + "cannot write %d bytes to PEB %d:%d (emulated)", > len, pnum, offset); > dump_stack(); > return -EIO; > @@ -282,7 +286,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, > addr = (loff_t)pnum * ubi->peb_size + offset; > err = mtd_write(ubi->mtd, addr, len, &written, buf); > if (err) { > - ubi_err("error %d while writing %d bytes to PEB %d:%d, written %zd bytes", > + ubi_err(ubi->ubi_num, > + "error %d while writing %d bytes to PEB %d:%d, written %zd bytes", > err, len, pnum, offset, written); > dump_stack(); > ubi_dump_flash(ubi, pnum, offset, len); > @@ -338,7 +343,7 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) > ubi_assert(pnum >= 0 && pnum < ubi->peb_count); > > if (ubi->ro_mode) { > - ubi_err("read-only mode"); > + ubi_err(ubi->ubi_num, "read-only mode"); > return -EROFS; > } > > @@ -355,12 +360,14 @@ retry: > err = mtd_erase(ubi->mtd, &ei); > if (err) { > if (retries++ < UBI_IO_RETRIES) { > - ubi_warn("error %d while erasing PEB %d, retry", > + ubi_warn(ubi->ubi_num, > + "error %d while erasing PEB %d, retry", > err, pnum); > yield(); > goto retry; > } > - ubi_err("cannot erase PEB %d, error %d", pnum, err); > + ubi_err(ubi->ubi_num, > + "cannot erase PEB %d, error %d", pnum, err); > dump_stack(); > return err; > } > @@ -368,17 +375,18 @@ retry: > err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || > ei.state == MTD_ERASE_FAILED); > if (err) { > - ubi_err("interrupted PEB %d erasure", pnum); > + ubi_err(ubi->ubi_num, "interrupted PEB %d erasure", pnum); > return -EINTR; > } > > if (ei.state == MTD_ERASE_FAILED) { > if (retries++ < UBI_IO_RETRIES) { > - ubi_warn("error while erasing PEB %d, retry", pnum); > + ubi_warn(ubi->ubi_num, > + "error while erasing PEB %d, retry", pnum); > yield(); > goto retry; > } > - ubi_err("cannot erase PEB %d", pnum); > + ubi_err(ubi->ubi_num, "cannot erase PEB %d", pnum); > dump_stack(); > return -EIO; > } > @@ -388,7 +396,7 @@ retry: > return err; > > if (ubi_dbg_is_erase_failure(ubi)) { > - ubi_err("cannot erase PEB %d (emulated)", pnum); > + ubi_err(ubi->ubi_num, "cannot erase PEB %d (emulated)", pnum); > return -EIO; > } > > @@ -411,7 +419,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) > { > int err, i, patt_count; > > - ubi_msg("run torture test for PEB %d", pnum); > + ubi_msg(ubi->ubi_num, "run torture test for PEB %d", pnum); > patt_count = ARRAY_SIZE(patterns); > ubi_assert(patt_count > 0); > > @@ -428,7 +436,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) > > err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size); > if (err == 0) { > - ubi_err("erased PEB %d, but a non-0xFF byte found", > + ubi_err(ubi->ubi_num, > + "erased PEB %d, but a non-0xFF byte found", > pnum); > err = -EIO; > goto out; > @@ -448,7 +457,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) > err = ubi_check_pattern(ubi->peb_buf, patterns[i], > ubi->peb_size); > if (err == 0) { > - ubi_err("pattern %x checking failed for PEB %d", > + ubi_err(ubi->ubi_num, > + "pattern %x checking failed for PEB %d", > patterns[i], pnum); > err = -EIO; > goto out; > @@ -456,7 +466,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) > } > > err = patt_count; > - ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum); > + ubi_msg(ubi->ubi_num, > + "PEB %d passed torture test, do not mark it as bad", pnum); > > out: > mutex_unlock(&ubi->buf_mutex); > @@ -466,7 +477,8 @@ out: > * has not passed because it happened on a freshly erased > * physical eraseblock which means something is wrong with it. > */ > - ubi_err("read problems on freshly erased PEB %d, must be bad", > + ubi_err(ubi->ubi_num, > + "read problems on freshly erased PEB %d, must be bad", > pnum); > err = -EIO; > } > @@ -542,7 +554,8 @@ error: > * it. Supposedly the flash media or the driver is screwed up, so > * return an error. > */ > - ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err); > + ubi_err(ubi->ubi_num, > + "cannot invalidate PEB %d, write returned %d", pnum, err); > ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); > return -EIO; > } > @@ -574,7 +587,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) > return err; > > if (ubi->ro_mode) { > - ubi_err("read-only mode"); > + ubi_err(ubi->ubi_num, "read-only mode"); > return -EROFS; > } > > @@ -616,7 +629,8 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) > > ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size); > if (ret < 0) > - ubi_err("error %d while checking if PEB %d is bad", > + ubi_err(ubi->ubi_num, > + "error %d while checking if PEB %d is bad", > ret, pnum); > else if (ret) > dbg_io("PEB %d is bad", pnum); > @@ -642,7 +656,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) > ubi_assert(pnum >= 0 && pnum < ubi->peb_count); > > if (ubi->ro_mode) { > - ubi_err("read-only mode"); > + ubi_err(ubi->ubi_num, "read-only mode"); > return -EROFS; > } > > @@ -651,7 +665,8 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) > > err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size); > if (err) > - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); > + ubi_err(ubi->ubi_num, > + "cannot mark PEB %d bad, error %d", pnum, err); > return err; > } > > @@ -674,32 +689,33 @@ static int validate_ec_hdr(const struct ubi_device *ubi, > leb_start = be32_to_cpu(ec_hdr->data_offset); > > if (ec_hdr->version != UBI_VERSION) { > - ubi_err("node with incompatible UBI version found: this UBI version is %d, image version is %d", > + ubi_err(ubi->ubi_num, > + "node with incompatible UBI version found: this UBI version is %d, image version is %d", > UBI_VERSION, (int)ec_hdr->version); > goto bad; > } > > if (vid_hdr_offset != ubi->vid_hdr_offset) { > - ubi_err("bad VID header offset %d, expected %d", > + ubi_err(ubi->ubi_num, "bad VID header offset %d, expected %d", > vid_hdr_offset, ubi->vid_hdr_offset); > goto bad; > } > > if (leb_start != ubi->leb_start) { > - ubi_err("bad data offset %d, expected %d", > + ubi_err(ubi->ubi_num, "bad data offset %d, expected %d", > leb_start, ubi->leb_start); > goto bad; > } > > if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) { > - ubi_err("bad erase counter %lld", ec); > + ubi_err(ubi->ubi_num, "bad erase counter %lld", ec); > goto bad; > } > > return 0; > > bad: > - ubi_err("bad EC header"); > + ubi_err(ubi->ubi_num, "bad EC header"); > ubi_dump_ec_hdr(ec_hdr); > dump_stack(); > return 1; > @@ -765,7 +781,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, > if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { > /* The physical eraseblock is supposedly empty */ > if (verbose) > - ubi_warn("no EC header found at PEB %d, only 0xFF bytes", > + ubi_warn(ubi->ubi_num, > + "no EC header found at PEB %d, only 0xFF bytes", > pnum); > dbg_bld("no EC header found at PEB %d, only 0xFF bytes", > pnum); > @@ -780,7 +797,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, > * 0xFF bytes. Report that the header is corrupted. > */ > if (verbose) { > - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", > + ubi_warn(ubi->ubi_num, > + "bad magic number at PEB %d: %08x instead of %08x", > pnum, magic, UBI_EC_HDR_MAGIC); > ubi_dump_ec_hdr(ec_hdr); > } > @@ -794,7 +812,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, > > if (hdr_crc != crc) { > if (verbose) { > - ubi_warn("bad EC header CRC at PEB %d, calculated %#08x, read %#08x", > + ubi_warn(ubi->ubi_num, > + "bad EC header CRC at PEB %d, calculated %#08x, read %#08x", > pnum, crc, hdr_crc); > ubi_dump_ec_hdr(ec_hdr); > } > @@ -810,7 +829,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, > /* And of course validate what has just been read from the media */ > err = validate_ec_hdr(ubi, ec_hdr); > if (err) { > - ubi_err("validation failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "validation failed for PEB %d", pnum); > return -EINVAL; > } > > @@ -884,40 +903,40 @@ static int validate_vid_hdr(const struct ubi_device *ubi, > int usable_leb_size = ubi->leb_size - data_pad; > > if (copy_flag != 0 && copy_flag != 1) { > - ubi_err("bad copy_flag"); > + ubi_err(ubi->ubi_num, "bad copy_flag"); > goto bad; > } > > if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 || > data_pad < 0) { > - ubi_err("negative values"); > + ubi_err(ubi->ubi_num, "negative values"); > goto bad; > } > > if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) { > - ubi_err("bad vol_id"); > + ubi_err(ubi->ubi_num, "bad vol_id"); > goto bad; > } > > if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) { > - ubi_err("bad compat"); > + ubi_err(ubi->ubi_num, "bad compat"); > goto bad; > } > > if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE && > compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE && > compat != UBI_COMPAT_REJECT) { > - ubi_err("bad compat"); > + ubi_err(ubi->ubi_num, "bad compat"); > goto bad; > } > > if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { > - ubi_err("bad vol_type"); > + ubi_err(ubi->ubi_num, "bad vol_type"); > goto bad; > } > > if (data_pad >= ubi->leb_size / 2) { > - ubi_err("bad data_pad"); > + ubi_err(ubi->ubi_num, "bad data_pad"); > goto bad; > } > > @@ -929,45 +948,46 @@ static int validate_vid_hdr(const struct ubi_device *ubi, > * mapped logical eraseblocks. > */ > if (used_ebs == 0) { > - ubi_err("zero used_ebs"); > + ubi_err(ubi->ubi_num, "zero used_ebs"); > goto bad; > } > if (data_size == 0) { > - ubi_err("zero data_size"); > + ubi_err(ubi->ubi_num, "zero data_size"); > goto bad; > } > if (lnum < used_ebs - 1) { > if (data_size != usable_leb_size) { > - ubi_err("bad data_size"); > + ubi_err(ubi->ubi_num, "bad data_size"); > goto bad; > } > } else if (lnum == used_ebs - 1) { > if (data_size == 0) { > - ubi_err("bad data_size at last LEB"); > + ubi_err(ubi->ubi_num, > + "bad data_size at last LEB"); > goto bad; > } > } else { > - ubi_err("too high lnum"); > + ubi_err(ubi->ubi_num, "too high lnum"); > goto bad; > } > } else { > if (copy_flag == 0) { > if (data_crc != 0) { > - ubi_err("non-zero data CRC"); > + ubi_err(ubi->ubi_num, "non-zero data CRC"); > goto bad; > } > if (data_size != 0) { > - ubi_err("non-zero data_size"); > + ubi_err(ubi->ubi_num, "non-zero data_size"); > goto bad; > } > } else { > if (data_size == 0) { > - ubi_err("zero data_size of copy"); > + ubi_err(ubi->ubi_num, "zero data_size of copy"); > goto bad; > } > } > if (used_ebs != 0) { > - ubi_err("bad used_ebs"); > + ubi_err(ubi->ubi_num, "bad used_ebs"); > goto bad; > } > } > @@ -975,7 +995,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, > return 0; > > bad: > - ubi_err("bad VID header"); > + ubi_err(ubi->ubi_num, "bad VID header"); > ubi_dump_vid_hdr(vid_hdr); > dump_stack(); > return 1; > @@ -1020,7 +1040,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, > > if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { > if (verbose) > - ubi_warn("no VID header found at PEB %d, only 0xFF bytes", > + ubi_warn(ubi->ubi_num, > + "no VID header found at PEB %d, only 0xFF bytes", > pnum); > dbg_bld("no VID header found at PEB %d, only 0xFF bytes", > pnum); > @@ -1031,7 +1052,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, > } > > if (verbose) { > - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", > + ubi_warn(ubi->ubi_num, > + "bad magic number at PEB %d: %08x instead of %08x", > pnum, magic, UBI_VID_HDR_MAGIC); > ubi_dump_vid_hdr(vid_hdr); > } > @@ -1045,7 +1067,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, > > if (hdr_crc != crc) { > if (verbose) { > - ubi_warn("bad CRC at PEB %d, calculated %#08x, read %#08x", > + ubi_warn(ubi->ubi_num, > + "bad CRC at PEB %d, calculated %#08x, read %#08x", > pnum, crc, hdr_crc); > ubi_dump_vid_hdr(vid_hdr); > } > @@ -1059,7 +1082,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, > > err = validate_vid_hdr(ubi, vid_hdr); > if (err) { > - ubi_err("validation failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "validation failed for PEB %d", pnum); > return -EINVAL; > } > > @@ -1129,7 +1152,7 @@ static int self_check_not_bad(const struct ubi_device *ubi, int pnum) > if (!err) > return err; > > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > dump_stack(); > return err > 0 ? -EINVAL : err; > } > @@ -1154,14 +1177,14 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum, > > magic = be32_to_cpu(ec_hdr->magic); > if (magic != UBI_EC_HDR_MAGIC) { > - ubi_err("bad magic %#08x, must be %#08x", > + ubi_err(ubi->ubi_num, "bad magic %#08x, must be %#08x", > magic, UBI_EC_HDR_MAGIC); > goto fail; > } > > err = validate_ec_hdr(ubi, ec_hdr); > if (err) { > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > goto fail; > } > > @@ -1201,8 +1224,9 @@ static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) > crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); > hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); > if (hdr_crc != crc) { > - ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "bad CRC, calculated %#08x, read %#08x", > + crc, hdr_crc); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > ubi_dump_ec_hdr(ec_hdr); > dump_stack(); > err = -EINVAL; > @@ -1236,21 +1260,22 @@ static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum, > > magic = be32_to_cpu(vid_hdr->magic); > if (magic != UBI_VID_HDR_MAGIC) { > - ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", > + ubi_err(ubi->ubi_num, > + "bad VID header magic %#08x at PEB %d, must be %#08x", > magic, pnum, UBI_VID_HDR_MAGIC); > goto fail; > } > > err = validate_vid_hdr(ubi, vid_hdr); > if (err) { > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > goto fail; > } > > return err; > > fail: > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > ubi_dump_vid_hdr(vid_hdr); > dump_stack(); > return -EINVAL; > @@ -1288,9 +1313,10 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) > crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); > hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); > if (hdr_crc != crc) { > - ubi_err("bad VID header CRC at PEB %d, calculated %#08x, read %#08x", > + ubi_err(ubi->ubi_num, > + "bad VID header CRC at PEB %d, calculated %#08x, read %#08x", > pnum, crc, hdr_crc); > - ubi_err("self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > ubi_dump_vid_hdr(vid_hdr); > dump_stack(); > err = -EINVAL; > @@ -1329,7 +1355,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, > > buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); > if (!buf1) { > - ubi_err("cannot allocate memory to check writes"); > + ubi_err(ubi->ubi_num, "cannot allocate memory to check writes"); > return 0; > } > > @@ -1345,15 +1371,17 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, > if (c == c1) > continue; > > - ubi_err("self-check failed for PEB %d:%d, len %d", > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d:%d, len %d", > pnum, offset, len); > - ubi_msg("data differ at position %d", i); > + ubi_msg(ubi->ubi_num, "data differ at position %d", i); > dump_len = max_t(int, 128, len - i); > - ubi_msg("hex dump of the original buffer from %d to %d", > + ubi_msg(ubi->ubi_num, > + "hex dump of the original buffer from %d to %d", > i, i + dump_len); > print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, > buf + i, dump_len, 1); > - ubi_msg("hex dump of the read buffer from %d to %d", > + ubi_msg(ubi->ubi_num, > + "hex dump of the read buffer from %d to %d", > i, i + dump_len); > print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, > buf1 + i, dump_len, 1); > @@ -1393,20 +1421,22 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) > > buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); > if (!buf) { > - ubi_err("cannot allocate memory to check for 0xFFs"); > + ubi_err(ubi->ubi_num, "cannot allocate memory to check for 0xFFs"); > return 0; > } > > err = mtd_read(ubi->mtd, addr, len, &read, buf); > if (err && !mtd_is_bitflip(err)) { > - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", > + ubi_err(ubi->ubi_num, > + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", > err, len, pnum, offset, read); > goto error; > } > > err = ubi_check_pattern(buf, 0xFF, len); > if (err == 0) { > - ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", > + ubi_err(ubi->ubi_num, > + "flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", > pnum, offset, len); > goto fail; > } > @@ -1415,8 +1445,9 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) > return 0; > > fail: > - ubi_err("self-check failed for PEB %d", pnum); > - ubi_msg("hex dump of the %d-%d region", offset, offset + len); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > + ubi_msg(ubi->ubi_num, "hex dump of the %d-%d region", > + offset, offset + len); > print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); > err = -EINVAL; > error: > diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c > index 3aac1ac..e19d4ba 100644 > --- a/drivers/mtd/ubi/kapi.c > +++ b/drivers/mtd/ubi/kapi.c > @@ -204,7 +204,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) > return ERR_PTR(err); > } > if (err == 1) { > - ubi_warn("volume %d on UBI device %d is corrupted", > + ubi_warn(ubi->ubi_num, "volume %d on UBI device %d is corrupted", > vol_id, ubi->ubi_num); > vol->corrupted = 1; > } > @@ -221,7 +221,7 @@ out_free: > kfree(desc); > out_put_ubi: > ubi_put_device(ubi); > - ubi_err("cannot open device %d, volume %d, error %d", > + ubi_err(ubi->ubi_num, "cannot open device %d, volume %d, error %d", > ubi_num, vol_id, err); > return ERR_PTR(err); > } > @@ -411,7 +411,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, > > err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); > if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { > - ubi_warn("mark volume %d as corrupted", vol_id); > + ubi_warn(ubi->ubi_num, "mark volume %d as corrupted", vol_id); > vol->corrupted = 1; > } > > diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c > index f913d70..113947f 100644 > --- a/drivers/mtd/ubi/misc.c > +++ b/drivers/mtd/ubi/misc.c > @@ -111,7 +111,8 @@ void ubi_update_reserved(struct ubi_device *ubi) > ubi->avail_pebs -= need; > ubi->rsvd_pebs += need; > ubi->beb_rsvd_pebs += need; > - ubi_msg("reserved more %d PEBs for bad PEB handling", need); > + ubi_msg(ubi->ubi_num, > + "reserved more %d PEBs for bad PEB handling", need); > } > > /** > @@ -128,7 +129,8 @@ void ubi_calculate_reserved(struct ubi_device *ubi) > ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count; > if (ubi->beb_rsvd_level < 0) { > ubi->beb_rsvd_level = 0; > - ubi_warn("number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", > + ubi_warn(ubi->ubi_num, > + "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", > ubi->bad_peb_count, ubi->bad_peb_limit); > } > } > diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h > index 7bf4163..956e5ff 100644 > --- a/drivers/mtd/ubi/ubi.h > +++ b/drivers/mtd/ubi/ubi.h > @@ -50,13 +50,14 @@ > #define UBI_NAME_STR "ubi" > > /* Normal UBI messages */ > -#define ubi_msg(fmt, ...) pr_notice("UBI: " fmt "\n", ##__VA_ARGS__) > +#define ubi_msg(ubi_num, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", ubi_num, \ > + __func__, ##__VA_ARGS__) > /* UBI warning messages */ > -#define ubi_warn(fmt, ...) pr_warn("UBI warning: %s: " fmt "\n", \ > - __func__, ##__VA_ARGS__) > +#define ubi_warn(ubi_num, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \ > + ubi_num, __func__, ##__VA_ARGS__) > /* UBI error messages */ > -#define ubi_err(fmt, ...) pr_err("UBI error: %s: " fmt "\n", \ > - __func__, ##__VA_ARGS__) > +#define ubi_err(ubi_num, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \ > + ubi_num, __func__, ##__VA_ARGS__) > > /* Background thread name pattern */ > #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd" > @@ -985,7 +986,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi) > { > if (!ubi->ro_mode) { > ubi->ro_mode = 1; > - ubi_warn("switch to read-only mode"); > + ubi_warn(ubi->ubi_num, "switch to read-only mode"); > dump_stack(); > } > } > diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c > index 8330703..6f1b996 100644 > --- a/drivers/mtd/ubi/vmt.c > +++ b/drivers/mtd/ubi/vmt.c > @@ -223,7 +223,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > } > > if (vol_id == UBI_VOL_NUM_AUTO) { > - ubi_err("out of volume IDs"); > + ubi_err(ubi->ubi_num, "out of volume IDs"); > err = -ENFILE; > goto out_unlock; > } > @@ -237,7 +237,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > /* Ensure that this volume does not exist */ > err = -EEXIST; > if (ubi->volumes[vol_id]) { > - ubi_err("volume %d already exists", vol_id); > + ubi_err(ubi->ubi_num, "volume %d already exists", vol_id); > goto out_unlock; > } > > @@ -246,7 +246,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > if (ubi->volumes[i] && > ubi->volumes[i]->name_len == req->name_len && > !strcmp(ubi->volumes[i]->name, req->name)) { > - ubi_err("volume \"%s\" exists (ID %d)", req->name, i); > + ubi_err(ubi->ubi_num, "volume \"%s\" exists (ID %d)", > + req->name, i); > goto out_unlock; > } > > @@ -257,9 +258,11 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > > /* Reserve physical eraseblocks */ > if (vol->reserved_pebs > ubi->avail_pebs) { > - ubi_err("not enough PEBs, only %d available", ubi->avail_pebs); > + ubi_err(ubi->ubi_num, "not enough PEBs, only %d available", > + ubi->avail_pebs); > if (ubi->corr_peb_count) > - ubi_err("%d PEBs are corrupted and not used", > + ubi_err(ubi->ubi_num, > + "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > err = -ENOSPC; > goto out_unlock; > @@ -314,7 +317,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); > err = cdev_add(&vol->cdev, dev, 1); > if (err) { > - ubi_err("cannot add character device"); > + ubi_err(ubi->ubi_num, "cannot add character device"); > goto out_mapping; > } > > @@ -326,7 +329,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) > dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); > err = device_register(&vol->dev); > if (err) { > - ubi_err("cannot register device"); > + ubi_err(ubi->ubi_num, "cannot register device"); > goto out_cdev; > } > > @@ -386,7 +389,7 @@ out_unlock: > kfree(vol); > else > put_device(&vol->dev); > - ubi_err("cannot create volume %d, error %d", vol_id, err); > + ubi_err(ubi->ubi_num, "cannot create volume %d, error %d", vol_id, err); > return err; > } > > @@ -454,7 +457,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) > return err; > > out_err: > - ubi_err("cannot remove volume %d, error %d", vol_id, err); > + ubi_err(ubi->ubi_num, "cannot remove volume %d, error %d", vol_id, err); > spin_lock(&ubi->volumes_lock); > ubi->volumes[vol_id] = vol; > out_unlock: > @@ -487,7 +490,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) > > if (vol->vol_type == UBI_STATIC_VOLUME && > reserved_pebs < vol->used_ebs) { > - ubi_err("too small size %d, %d LEBs contain data", > + ubi_err(ubi->ubi_num, "too small size %d, %d LEBs contain data", > reserved_pebs, vol->used_ebs); > return -EINVAL; > } > @@ -516,10 +519,12 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) > if (pebs > 0) { > spin_lock(&ubi->volumes_lock); > if (pebs > ubi->avail_pebs) { > - ubi_err("not enough PEBs: requested %d, available %d", > + ubi_err(ubi->ubi_num, > + "not enough PEBs: requested %d, available %d", > pebs, ubi->avail_pebs); > if (ubi->corr_peb_count) > - ubi_err("%d PEBs are corrupted and not used", > + ubi_err(ubi->ubi_num, > + "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > spin_unlock(&ubi->volumes_lock); > err = -ENOSPC; > @@ -643,7 +648,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) > dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); > err = cdev_add(&vol->cdev, dev, 1); > if (err) { > - ubi_err("cannot add character device for volume %d, error %d", > + ubi_err(ubi->ubi_num, > + "cannot add character device for volume %d, error %d", > vol_id, err); > return err; > } > @@ -710,7 +716,8 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) > > if (!vol) { > if (reserved_pebs) { > - ubi_err("no volume info, but volume exists"); > + ubi_err(ubi->ubi_num, > + "no volume info, but volume exists"); > goto fail; > } > spin_unlock(&ubi->volumes_lock); > @@ -719,90 +726,93 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) > > if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || > vol->name_len < 0) { > - ubi_err("negative values"); > + ubi_err(ubi->ubi_num, "negative values"); > goto fail; > } > if (vol->alignment > ubi->leb_size || vol->alignment == 0) { > - ubi_err("bad alignment"); > + ubi_err(ubi->ubi_num, "bad alignment"); > goto fail; > } > > n = vol->alignment & (ubi->min_io_size - 1); > if (vol->alignment != 1 && n) { > - ubi_err("alignment is not multiple of min I/O unit"); > + ubi_err(ubi->ubi_num, > + "alignment is not multiple of min I/O unit"); > goto fail; > } > > n = ubi->leb_size % vol->alignment; > if (vol->data_pad != n) { > - ubi_err("bad data_pad, has to be %lld", n); > + ubi_err(ubi->ubi_num, "bad data_pad, has to be %lld", n); > goto fail; > } > > if (vol->vol_type != UBI_DYNAMIC_VOLUME && > vol->vol_type != UBI_STATIC_VOLUME) { > - ubi_err("bad vol_type"); > + ubi_err(ubi->ubi_num, "bad vol_type"); > goto fail; > } > > if (vol->upd_marker && vol->corrupted) { > - ubi_err("update marker and corrupted simultaneously"); > + ubi_err(ubi->ubi_num, > + "update marker and corrupted simultaneously"); > goto fail; > } > > if (vol->reserved_pebs > ubi->good_peb_count) { > - ubi_err("too large reserved_pebs"); > + ubi_err(ubi->ubi_num, "too large reserved_pebs"); > goto fail; > } > > n = ubi->leb_size - vol->data_pad; > if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { > - ubi_err("bad usable_leb_size, has to be %lld", n); > + ubi_err(ubi->ubi_num, "bad usable_leb_size, has to be %lld", n); > goto fail; > } > > if (vol->name_len > UBI_VOL_NAME_MAX) { > - ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); > + ubi_err(ubi->ubi_num, "too long volume name, max is %d", > + UBI_VOL_NAME_MAX); > goto fail; > } > > n = strnlen(vol->name, vol->name_len + 1); > if (n != vol->name_len) { > - ubi_err("bad name_len %lld", n); > + ubi_err(ubi->ubi_num, "bad name_len %lld", n); > goto fail; > } > > n = (long long)vol->used_ebs * vol->usable_leb_size; > if (vol->vol_type == UBI_DYNAMIC_VOLUME) { > if (vol->corrupted) { > - ubi_err("corrupted dynamic volume"); > + ubi_err(ubi->ubi_num, "corrupted dynamic volume"); > goto fail; > } > if (vol->used_ebs != vol->reserved_pebs) { > - ubi_err("bad used_ebs"); > + ubi_err(ubi->ubi_num, "bad used_ebs"); > goto fail; > } > if (vol->last_eb_bytes != vol->usable_leb_size) { > - ubi_err("bad last_eb_bytes"); > + ubi_err(ubi->ubi_num, "bad last_eb_bytes"); > goto fail; > } > if (vol->used_bytes != n) { > - ubi_err("bad used_bytes"); > + ubi_err(ubi->ubi_num, "bad used_bytes"); > goto fail; > } > } else { > if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { > - ubi_err("bad used_ebs"); > + ubi_err(ubi->ubi_num, "bad used_ebs"); > goto fail; > } > if (vol->last_eb_bytes < 0 || > vol->last_eb_bytes > vol->usable_leb_size) { > - ubi_err("bad last_eb_bytes"); > + ubi_err(ubi->ubi_num, "bad last_eb_bytes"); > goto fail; > } > if (vol->used_bytes < 0 || vol->used_bytes > n || > vol->used_bytes < n - vol->usable_leb_size) { > - ubi_err("bad used_bytes"); > + ubi_err(ubi->ubi_num, "bad used_bytes"); > goto fail; > } > } > @@ -820,7 +830,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) > if (alignment != vol->alignment || data_pad != vol->data_pad || > upd_marker != vol->upd_marker || vol_type != vol->vol_type || > name_len != vol->name_len || strncmp(name, vol->name, name_len)) { > - ubi_err("volume info is different"); > + ubi_err(ubi->ubi_num, "volume info is different"); > goto fail; > } > > @@ -828,7 +838,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) > return 0; > > fail: > - ubi_err("self-check failed for volume %d", vol_id); > + ubi_err(ubi->ubi_num, "self-check failed for volume %d", vol_id); > if (vol) > ubi_dump_vol_info(vol); > ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); > diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c > index 07cac5f..f01aab7 100644 > --- a/drivers/mtd/ubi/vtbl.c > +++ b/drivers/mtd/ubi/vtbl.c > @@ -190,7 +190,7 @@ static int vtbl_check(const struct ubi_device *ubi, > > crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); > if (be32_to_cpu(vtbl[i].crc) != crc) { > - ubi_err("bad CRC at record %u: %#08x, not %#08x", > + ubi_err(ubi->ubi_num, "bad CRC at record %u: %#08x, not %#08x", > i, crc, be32_to_cpu(vtbl[i].crc)); > ubi_dump_vtbl_record(&vtbl[i], i); > return 1; > @@ -224,7 +224,7 @@ static int vtbl_check(const struct ubi_device *ubi, > > n = ubi->leb_size % alignment; > if (data_pad != n) { > - ubi_err("bad data_pad, has to be %d", n); > + ubi_err(ubi->ubi_num, "bad data_pad, has to be %d", n); > err = 6; > goto bad; > } > @@ -240,7 +240,7 @@ static int vtbl_check(const struct ubi_device *ubi, > } > > if (reserved_pebs > ubi->good_peb_count) { > - ubi_err("too large reserved_pebs %d, good PEBs %d", > + ubi_err(ubi->ubi_num, "too large reserved_pebs %d, good PEBs %d", > reserved_pebs, ubi->good_peb_count); > err = 9; > goto bad; > @@ -270,7 +270,8 @@ static int vtbl_check(const struct ubi_device *ubi, > > if (len1 > 0 && len1 == len2 && > !strncmp(vtbl[i].name, vtbl[n].name, len1)) { > - ubi_err("volumes %d and %d have the same name \"%s\"", > + ubi_err(ubi->ubi_num, > + "volumes %d and %d have the same name \"%s\"", > i, n, vtbl[i].name); > ubi_dump_vtbl_record(&vtbl[i], i); > ubi_dump_vtbl_record(&vtbl[n], n); > @@ -282,7 +283,8 @@ static int vtbl_check(const struct ubi_device *ubi, > return 0; > > bad: > - ubi_err("volume table check failed: record %d, error %d", i, err); > + ubi_err(ubi->ubi_num, > + "volume table check failed: record %d, error %d", i, err); > ubi_dump_vtbl_record(&vtbl[i], i); > return -EINVAL; > } > @@ -446,11 +448,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, > leb_corrupted[1] = memcmp(leb[0], leb[1], > ubi->vtbl_size); > if (leb_corrupted[1]) { > - ubi_warn("volume table copy #2 is corrupted"); > + ubi_warn(ubi->ubi_num, "volume table copy #2 is corrupted"); > err = create_vtbl(ubi, ai, 1, leb[0]); > if (err) > goto out_free; > - ubi_msg("volume table was restored"); > + ubi_msg(ubi->ubi_num, "volume table was restored"); > } > > /* Both LEB 1 and LEB 2 are OK and consistent */ > @@ -465,15 +467,15 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, > } > if (leb_corrupted[1]) { > /* Both LEB 0 and LEB 1 are corrupted */ > - ubi_err("both volume tables are corrupted"); > + ubi_err(ubi->ubi_num, "both volume tables are corrupted"); > goto out_free; > } > > - ubi_warn("volume table copy #1 is corrupted"); > + ubi_warn(ubi->ubi_num, "volume table copy #1 is corrupted"); > err = create_vtbl(ubi, ai, 0, leb[1]); > if (err) > goto out_free; > - ubi_msg("volume table was restored"); > + ubi_msg(ubi->ubi_num, "volume table was restored"); > > vfree(leb[0]); > return leb[1]; > @@ -562,7 +564,7 @@ static int init_volumes(struct ubi_device *ubi, > if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { > /* Auto re-size flag may be set only for one volume */ > if (ubi->autoresize_vol_id != -1) { > - ubi_err("more than one auto-resize volume (%d and %d)", > + ubi_err(ubi->ubi_num, "more than one auto-resize volume (%d and %d)", > ubi->autoresize_vol_id, i); > kfree(vol); > return -EINVAL; > @@ -608,7 +610,7 @@ static int init_volumes(struct ubi_device *ubi, > * We found a static volume which misses several > * eraseblocks. Treat it as corrupted. > */ > - ubi_warn("static volume %d misses %d LEBs - corrupted", > + ubi_warn(ubi->ubi_num, "static volume %d misses %d LEBs - corrupted", > av->vol_id, av->used_ebs - av->leb_count); > vol->corrupted = 1; > continue; > @@ -646,10 +648,10 @@ static int init_volumes(struct ubi_device *ubi, > vol->ubi = ubi; > > if (reserved_pebs > ubi->avail_pebs) { > - ubi_err("not enough PEBs, required %d, available %d", > + ubi_err(ubi->ubi_num, "not enough PEBs, required %d, available %d", > reserved_pebs, ubi->avail_pebs); > if (ubi->corr_peb_count) > - ubi_err("%d PEBs are corrupted and not used", > + ubi_err(ubi->ubi_num, "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > } > ubi->rsvd_pebs += reserved_pebs; > @@ -660,13 +662,14 @@ static int init_volumes(struct ubi_device *ubi, > > /** > * check_av - check volume attaching information. > + * @ubi: UBI device description object > * @vol: UBI volume description object > * @av: volume attaching information > * > * This function returns zero if the volume attaching information is consistent > * to the data read from the volume tabla, and %-EINVAL if not. > */ > -static int check_av(const struct ubi_volume *vol, > +static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, > const struct ubi_ainf_volume *av) > { > int err; > @@ -694,7 +697,7 @@ static int check_av(const struct ubi_volume *vol, > return 0; > > bad: > - ubi_err("bad attaching information, error %d", err); > + ubi_err(ubi->ubi_num, "bad attaching information, error %d", err); > ubi_dump_av(av); > ubi_dump_vol_info(vol); > return -EINVAL; > @@ -718,14 +721,16 @@ static int check_attaching_info(const struct ubi_device *ubi, > struct ubi_volume *vol; > > if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { > - ubi_err("found %d volumes while attaching, maximum is %d + %d", > + ubi_err(ubi->ubi_num, > + "found %d volumes while attaching, maximum is %d + %d", > ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); > return -EINVAL; > } > > if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && > ai->highest_vol_id < UBI_INTERNAL_VOL_START) { > - ubi_err("too large volume ID %d found", ai->highest_vol_id); > + ubi_err(ubi->ubi_num, "too large volume ID %d found", > + ai->highest_vol_id); > return -EINVAL; > } > > @@ -753,10 +758,11 @@ static int check_attaching_info(const struct ubi_device *ubi, > * reboot while the volume was being removed. Discard > * these eraseblocks. > */ > - ubi_msg("finish volume %d removal", av->vol_id); > + ubi_msg(ubi->ubi_num, "finish volume %d removal", > + av->vol_id); > ubi_remove_av(ai, av); > } else if (av) { > - err = check_av(vol, av); > + err = check_av(ubi, vol, av); > if (err) > return err; > } > @@ -807,13 +813,15 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) > if (IS_ERR(ubi->vtbl)) > return PTR_ERR(ubi->vtbl); > } else { > - ubi_err("the layout volume was not found"); > + ubi_err(ubi->ubi_num, > + "the layout volume was not found"); > return -EINVAL; > } > } else { > if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { > /* This must not happen with proper UBI images */ > - ubi_err("too many LEBs (%d) in layout volume", > + ubi_err(ubi->ubi_num, > + "too many LEBs (%d) in layout volume", > av->leb_count); > return -EINVAL; > } > @@ -862,7 +870,7 @@ static void self_vtbl_check(const struct ubi_device *ubi) > return; > > if (vtbl_check(ubi, ubi->vtbl)) { > - ubi_err("self-check failed"); > + ubi_err(ubi->ubi_num, "self-check failed"); > BUG(); > } > } > diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c > index 20f4917..ae6cbb6 100644 > --- a/drivers/mtd/ubi/wl.c > +++ b/drivers/mtd/ubi/wl.c > @@ -253,7 +253,7 @@ static int do_work(struct ubi_device *ubi) > */ > err = wrk->func(ubi, wrk, 0); > if (err) > - ubi_err("work failed with error code %d", err); > + ubi_err(ubi->ubi_num, "work failed with error code %d", err); > up_read(&ubi->work_sem); > > return err; > @@ -470,8 +470,12 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) > { > struct ubi_wl_entry *e = NULL; > > - if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) > + if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) { > + ubi_warn(ubi->ubi_num, > + "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d", > + anchor, ubi->free_count, ubi->beb_rsvd_pebs); > goto out; > + } > > if (anchor) > e = find_anchor_wl_entry(&ubi->free); > @@ -507,7 +511,7 @@ static int __wl_get_peb(struct ubi_device *ubi) > retry: > if (!ubi->free.rb_node) { > if (ubi->works_count == 0) { > - ubi_err("no free eraseblocks"); > + ubi_err(ubi->ubi_num, "no free eraseblocks"); > ubi_assert(list_empty(&ubi->works)); > return -ENOSPC; > } > @@ -520,7 +524,7 @@ retry: > > e = find_mean_wl_entry(ubi, &ubi->free); > if (!e) { > - ubi_err("no free eraseblocks"); > + ubi_err(ubi->ubi_num, "no free eraseblocks"); > return -ENOSPC; > } > > @@ -692,7 +696,8 @@ int ubi_wl_get_peb(struct ubi_device *ubi) > err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, > ubi->peb_size - ubi->vid_hdr_aloffset); > if (err) { > - ubi_err("new PEB %d does not contain all 0xFF bytes", peb); > + ubi_err(ubi->ubi_num, > + "new PEB %d does not contain all 0xFF bytes", peb); > return err; > } > > @@ -760,7 +765,8 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, > * Erase counter overflow. Upgrade UBI and use 64-bit > * erase counters internally. > */ > - ubi_err("erase counter overflow at PEB %d, EC %llu", > + ubi_err(ubi->ubi_num, > + "erase counter overflow at PEB %d, EC %llu", > e->pnum, ec); > err = -EINVAL; > goto out_free; > @@ -1136,7 +1142,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, > goto out_not_moved; > } > > - ubi_err("error %d while reading VID header from PEB %d", > + ubi_err(ubi->ubi_num, > + "error %d while reading VID header from PEB %d", > err, e1->pnum); > goto out_error; > } > @@ -1180,7 +1187,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, > * UBI from trying to move it over and over again. > */ > if (ubi->erroneous_peb_count > ubi->max_erroneous) { > - ubi_err("too many erroneous eraseblocks (%d)", > + ubi_err(ubi->ubi_num, > + "too many erroneous eraseblocks (%d)", > ubi->erroneous_peb_count); > goto out_error; > } > @@ -1196,7 +1204,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, > > /* The PEB has been successfully moved */ > if (scrubbing) > - ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", > + ubi_msg(ubi->ubi_num, > + "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", > e1->pnum, vol_id, lnum, e2->pnum); > ubi_free_vid_hdr(ubi, vid_hdr); > > @@ -1273,10 +1282,11 @@ out_not_moved: > > out_error: > if (vol_id != -1) > - ubi_err("error %d while moving PEB %d to PEB %d", > + ubi_err(ubi->ubi_num, "error %d while moving PEB %d to PEB %d", > err, e1->pnum, e2->pnum); > else > - ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d", > + ubi_err(ubi->ubi_num, > + "error %d while moving PEB %d (LEB %d:%d) to PEB %d", > err, e1->pnum, vol_id, lnum, e2->pnum); > spin_lock(&ubi->wl_lock); > ubi->move_from = ubi->move_to = NULL; > @@ -1456,7 +1466,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, > return err; > } > > - ubi_err("failed to erase PEB %d, error %d", pnum, err); > + ubi_err(ubi->ubi_num, "failed to erase PEB %d, error %d", pnum, err); > kfree(wl_wrk); > > if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || > @@ -1484,7 +1494,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, > /* It is %-EIO, the PEB went bad */ > > if (!ubi->bad_allowed) { > - ubi_err("bad physical eraseblock %d detected", pnum); > + ubi_err(ubi->ubi_num, "bad physical eraseblock %d detected", > + pnum); > goto out_ro; > } > > @@ -1492,7 +1503,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, > if (ubi->beb_rsvd_pebs == 0) { > if (ubi->avail_pebs == 0) { > spin_unlock(&ubi->volumes_lock); > - ubi_err("no reserved/available physical eraseblocks"); > + ubi_err(ubi->ubi_num, > + "no reserved/available physical eraseblocks"); > goto out_ro; > } > ubi->avail_pebs -= 1; > @@ -1500,7 +1512,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, > } > spin_unlock(&ubi->volumes_lock); > > - ubi_msg("mark PEB %d as bad", pnum); > + ubi_msg(ubi->ubi_num, "mark PEB %d as bad", pnum); > err = ubi_io_mark_bad(ubi, pnum); > if (err) > goto out_ro; > @@ -1521,11 +1533,13 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, > ubi->good_peb_count -= 1; > ubi_calculate_reserved(ubi); > if (available_consumed) > - ubi_warn("no PEBs in the reserved pool, used an available PEB"); > + ubi_warn(ubi->ubi_num, > + "no PEBs in the reserved pool, used an available PEB"); > else if (ubi->beb_rsvd_pebs) > - ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs); > + ubi_msg(ubi->ubi_num, "%d PEBs left in the reserve", > + ubi->beb_rsvd_pebs); > else > - ubi_warn("last PEB from the reserve was used"); > + ubi_warn(ubi->ubi_num, "last PEB from the reserve was used"); > spin_unlock(&ubi->volumes_lock); > > return err; > @@ -1611,7 +1625,7 @@ retry: > } else { > err = prot_queue_del(ubi, e->pnum); > if (err) { > - ubi_err("PEB %d not found", pnum); > + ubi_err(ubi->ubi_num, "PEB %d not found", pnum); > ubi_ro_mode(ubi); > spin_unlock(&ubi->wl_lock); > return err; > @@ -1676,7 +1690,7 @@ retry: > > err = prot_queue_del(ubi, e->pnum); > if (err) { > - ubi_err("PEB %d not found", pnum); > + ubi_err(ubi->ubi_num, "PEB %d not found", pnum); > ubi_ro_mode(ubi); > spin_unlock(&ubi->wl_lock); > return err; > @@ -1796,15 +1810,19 @@ int ubi_thread(void *u) > int failures = 0; > struct ubi_device *ubi = u; > > - ubi_msg("background thread \"%s\" started, PID %d", > + ubi_msg(ubi->ubi_num, "background thread \"%s\" started, PID %d", > ubi->bgt_name, task_pid_nr(current)); > > set_freezable(); > for (;;) { > int err; > > - if (kthread_should_stop()) > + if (kthread_should_stop()) { > + ubi_msg(ubi->ubi_num, > + "background thread \"%s\" should stop, PID %d", > + ubi->bgt_name, task_pid_nr(current)); > break; > + } > > if (try_to_freeze()) > continue; > @@ -1821,14 +1839,16 @@ int ubi_thread(void *u) > > err = do_work(ubi); > if (err) { > - ubi_err("%s: work failed with error code %d", > + ubi_err(ubi->ubi_num, > + "%s: work failed with error code %d", > ubi->bgt_name, err); > if (failures++ > WL_MAX_FAILURES) { > /* > * Too many failures, disable the thread and > * switch to read-only mode. > */ > - ubi_msg("%s: %d consecutive failures", > + ubi_msg(ubi->ubi_num, > + "%s: %d consecutive failures", > ubi->bgt_name, WL_MAX_FAILURES); > ubi_ro_mode(ubi); > ubi->thread_enabled = 0; > @@ -1979,10 +1999,12 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) > #endif > > if (ubi->avail_pebs < reserved_pebs) { > - ubi_err("no enough physical eraseblocks (%d, need %d)", > + ubi_err(ubi->ubi_num, > + "no enough physical eraseblocks (%d, need %d)", > ubi->avail_pebs, reserved_pebs); > if (ubi->corr_peb_count) > - ubi_err("%d PEBs are corrupted and not used", > + ubi_err(ubi->ubi_num, > + "%d PEBs are corrupted and not used", > ubi->corr_peb_count); > goto out_free; > } > @@ -2028,7 +2050,7 @@ static void protection_queue_destroy(struct ubi_device *ubi) > */ > void ubi_wl_close(struct ubi_device *ubi) > { > - dbg_wl("close the WL sub-system"); > + ubi_msg(ubi->ubi_num, "close the WL sub-system"); > cancel_pending(ubi); > protection_queue_destroy(ubi); > tree_destroy(&ubi->used); > @@ -2070,8 +2092,9 @@ static int self_check_ec(struct ubi_device *ubi, int pnum, int ec) > > read_ec = be64_to_cpu(ec_hdr->ec); > if (ec != read_ec && read_ec - ec > 1) { > - ubi_err("self-check failed for PEB %d", pnum); > - ubi_err("read EC is %lld, should be %d", read_ec, ec); > + ubi_err(ubi->ubi_num, "self-check failed for PEB %d", pnum); > + ubi_err(ubi->ubi_num, "read EC is %lld, should be %d", > + read_ec, ec); > dump_stack(); > err = 1; > } else > @@ -2100,7 +2123,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, > if (in_wl_tree(e, root)) > return 0; > > - ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ", > + ubi_err(ubi->ubi_num, > + "self-check failed for PEB %d, EC %d, RB-tree %p ", > e->pnum, e->ec, root); > dump_stack(); > return -EINVAL; > @@ -2128,7 +2152,8 @@ static int self_check_in_pq(const struct ubi_device *ubi, > if (p == e) > return 0; > > - ubi_err("self-check failed for PEB %d, EC %d, Protect queue", > + ubi_err(ubi->ubi_num, > + "self-check failed for PEB %d, EC %d, Protect queue", > e->pnum, e->ec); > dump_stack(); > return -EINVAL; > From richard at nod.at Sun Sep 28 01:18:36 2014 From: richard at nod.at (Richard Weinberger) Date: Sun, 28 Sep 2014 10:18:36 +0200 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> Message-ID: <5427C45C.2080506@nod.at> Tanya, Am 28.09.2014 08:37, schrieb Tanya Brokhman: > The need for performing read disturb is determined according to new > statistics collected per eraseblock: > - read counter: incremented at each read operation > reset at each erase > - last erase time stamp: updated at each erase > This patch adds the infrastructure for the above statistics > > Signed-off-by: Tanya Brokhman > --- > drivers/mtd/ubi/build.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ > drivers/mtd/ubi/fastmap.c | 14 +++++++---- > drivers/mtd/ubi/ubi-media.h | 32 ++++++++++++++++++++++--- > drivers/mtd/ubi/ubi.h | 34 +++++++++++++++++++++++++++ > drivers/mtd/ubi/wl.c | 6 +++++ > 5 files changed, 135 insertions(+), 8 deletions(-) > > diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c > index 6e30a3c..34fe23a 100644 > --- a/drivers/mtd/ubi/build.c > +++ b/drivers/mtd/ubi/build.c > @@ -1,6 +1,9 @@ > /* > * Copyright (c) International Business Machines Corp., 2006 > * Copyright (c) Nokia Corporation, 2007 > + * Copyright (c) 2014, Linux Foundation. All rights reserved. > + * Linux Foundation chooses to take subject only to the GPLv2 > + * license terms, and distributes only under these terms. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -118,6 +121,10 @@ static struct class_attribute ubi_version = > static ssize_t dev_attribute_show(struct device *dev, > struct device_attribute *attr, char *buf); > > +static ssize_t dev_attribute_store(struct device *dev, > + struct device_attribute *attr, const char *buf, > + size_t count); > + > /* UBI device attributes (correspond to files in '//class/ubi/ubiX') */ > static struct device_attribute dev_eraseblock_size = > __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL); > @@ -141,6 +148,12 @@ static struct device_attribute dev_bgt_enabled = > __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); > static struct device_attribute dev_mtd_num = > __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); > +static struct device_attribute dev_dt_threshold = > + __ATTR(dt_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, > + dev_attribute_store); > +static struct device_attribute dev_rd_threshold = > + __ATTR(rd_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, > + dev_attribute_store); > > /** > * ubi_volume_notify - send a volume change notification. > @@ -378,6 +391,10 @@ static ssize_t dev_attribute_show(struct device *dev, > ret = sprintf(buf, "%d\n", ubi->thread_enabled); > else if (attr == &dev_mtd_num) > ret = sprintf(buf, "%d\n", ubi->mtd->index); > + else if (attr == &dev_dt_threshold) > + ret = sprintf(buf, "%d\n", ubi->dt_threshold); > + else if (attr == &dev_rd_threshold) > + ret = sprintf(buf, "%d\n", ubi->rd_threshold); > else > ret = -EINVAL; > > @@ -385,6 +402,38 @@ static ssize_t dev_attribute_show(struct device *dev, > return ret; > } > > +static ssize_t dev_attribute_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + int value; > + struct ubi_device *ubi; > + > + ubi = container_of(dev, struct ubi_device, dev); > + ubi = ubi_get_device(ubi->ubi_num); > + if (!ubi) > + return -ENODEV; > + > + if (kstrtos32(buf, 10, &value)) > + return -EINVAL; > + /* Consider triggering full scan if threshods change */ > + else if (attr == &dev_dt_threshold) { > + if (value < UBI_MAX_DT_THRESHOLD) > + ubi->dt_threshold = value; > + else > + pr_err("Max supported threshold value is %d", > + UBI_MAX_DT_THRESHOLD); > + } else if (attr == &dev_rd_threshold) { > + if (value < UBI_MAX_READCOUNTER) > + ubi->rd_threshold = value; > + else > + pr_err("Max supported threshold value is %d", > + UBI_MAX_READCOUNTER); > + } > + > + return count; > +} > + > static void dev_release(struct device *dev) > { > struct ubi_device *ubi = container_of(dev, struct ubi_device, dev); > @@ -445,6 +494,12 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) > if (err) > return err; > err = device_create_file(&ubi->dev, &dev_mtd_num); > + if (err) > + return err; > + err = device_create_file(&ubi->dev, &dev_dt_threshold); > + if (err) > + return err; > + err = device_create_file(&ubi->dev, &dev_rd_threshold); > return err; > } > > @@ -455,6 +510,8 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) > static void ubi_sysfs_close(struct ubi_device *ubi) > { > device_remove_file(&ubi->dev, &dev_mtd_num); > + device_remove_file(&ubi->dev, &dev_dt_threshold); > + device_remove_file(&ubi->dev, &dev_rd_threshold); > device_remove_file(&ubi->dev, &dev_bgt_enabled); > device_remove_file(&ubi->dev, &dev_min_io_size); > device_remove_file(&ubi->dev, &dev_max_vol_count); > diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c > index 0431b46..5399aa2 100644 > --- a/drivers/mtd/ubi/fastmap.c > +++ b/drivers/mtd/ubi/fastmap.c > @@ -1,5 +1,7 @@ > /* > * Copyright (c) 2012 Linutronix GmbH > + * Copyright (c) 2014, Linux Foundation. All rights reserved. > + * Diffstat says "drivers/mtd/ubi/fastmap.c | 14 +++++++----", does this really justify a new copyright line? If so I'll have to add the new company I work for here too. > * Author: Richard Weinberger > * > * This program is free software; you can redistribute it and/or modify > @@ -727,9 +729,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > } > > for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { > - int pnum = be32_to_cpu(fm_eba->pnum[j]); > + int pnum = be32_to_cpu(fm_eba->peb_data[j].pnum); > > - if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0) > + if ((int)be32_to_cpu(fm_eba->peb_data[j].pnum) < 0) > continue; > > aeb = NULL; > @@ -757,7 +759,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, > } > > aeb->lnum = j; > - aeb->pnum = be32_to_cpu(fm_eba->pnum[j]); > + aeb->pnum = > + be32_to_cpu(fm_eba->peb_data[j].pnum); > aeb->ec = -1; > aeb->scrub = aeb->copy_flag = aeb->sqnum = 0; > list_add_tail(&aeb->u.list, &eba_orphans); > @@ -1250,11 +1253,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi, > vol->vol_type == UBI_STATIC_VOLUME); > > feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); > - fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs); > + fm_pos += sizeof(*feba) + > + 2 * (sizeof(__be32) * vol->reserved_pebs); > ubi_assert(fm_pos <= ubi->fm_size); > > for (j = 0; j < vol->reserved_pebs; j++) > - feba->pnum[j] = cpu_to_be32(vol->eba_tbl[j]); > + feba->peb_data[j].pnum = cpu_to_be32(vol->eba_tbl[j]); > > feba->reserved_pebs = cpu_to_be32(j); > feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); > diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h > index ac2b24d..da418ad 100644 > --- a/drivers/mtd/ubi/ubi-media.h > +++ b/drivers/mtd/ubi/ubi-media.h > @@ -1,5 +1,8 @@ > /* > * Copyright (c) International Business Machines Corp., 2006 > + * Copyright (c) 2014, Linux Foundation. All rights reserved. > + * Linux Foundation chooses to take subject only to the GPLv2 > + * license terms, and distributes only under these terms. > * > * This program is free software; you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > @@ -38,6 +41,15 @@ > /* The highest erase counter value supported by this implementation */ > #define UBI_MAX_ERASECOUNTER 0x7FFFFFFF > > +/* The highest read counter value supported by this implementation */ > +#define UBI_MAX_READCOUNTER 0x7FFFFFFD /* (0x7FFFFFFF - 2)*/ > + > +/* > + * The highest data retention threshold value supported > + * by this implementation > + */ > +#define UBI_MAX_DT_THRESHOLD 0x7FFFFFFF > + > /* The initial CRC32 value used when calculating CRC checksums */ > #define UBI_CRC32_INIT 0xFFFFFFFFU > > @@ -130,6 +142,7 @@ enum { > * @vid_hdr_offset: where the VID header starts > * @data_offset: where the user data start > * @image_seq: image sequence number > + * @last_erase_time: time stamp of the last erase operation > * @padding2: reserved for future, zeroes > * @hdr_crc: erase counter header CRC checksum > * > @@ -162,7 +175,8 @@ struct ubi_ec_hdr { > __be32 vid_hdr_offset; > __be32 data_offset; > __be32 image_seq; > - __u8 padding2[32]; > + __be64 last_erase_time; /*curr time in sec == unsigned long time_t*/ > + __u8 padding2[24]; > __be32 hdr_crc; > } __packed; > > @@ -413,6 +427,8 @@ struct ubi_vtbl_record { > * @used_blocks: number of PEBs used by this fastmap > * @block_loc: an array containing the location of all PEBs of the fastmap > * @block_ec: the erase counter of each used PEB > + * @block_rc: the read counter of each used PEB > + * @block_let: the last erase timestamp of each used PEB > * @sqnum: highest sequence number value at the time while taking the fastmap > * > */ > @@ -424,6 +440,8 @@ struct ubi_fm_sb { > __be32 used_blocks; > __be32 block_loc[UBI_FM_MAX_BLOCKS]; > __be32 block_ec[UBI_FM_MAX_BLOCKS]; > + __be32 block_rc[UBI_FM_MAX_BLOCKS]; > + __be64 block_let[UBI_FM_MAX_BLOCKS]; Doesn't this break the fastmap on-disk layout? > __be64 sqnum; > __u8 padding2[32]; > } __packed; > @@ -469,13 +487,17 @@ struct ubi_fm_scan_pool { > /* ubi_fm_scan_pool is followed by nfree+nused struct ubi_fm_ec records */ > > /** > - * struct ubi_fm_ec - stores the erase counter of a PEB > + * struct ubi_fm_ec - stores the erase/read counter of a PEB > * @pnum: PEB number > * @ec: ec of this PEB > + * @rc: rc of this PEB > + * @last_erase_time: last erase time stamp of this PEB > */ > struct ubi_fm_ec { > __be32 pnum; > __be32 ec; > + __be32 rc; > + __be64 last_erase_time; Same here. > } __packed; > > /** > @@ -506,10 +528,14 @@ struct ubi_fm_volhdr { > * @magic: EBA table magic number > * @reserved_pebs: number of table entries > * @pnum: PEB number of LEB (LEB is the index) > + * @rc: Read counter of the LEBs PEB (LEB is the index) > */ > struct ubi_fm_eba { > __be32 magic; > __be32 reserved_pebs; > - __be32 pnum[0]; > + struct { > + __be32 pnum; > + __be32 rc; > + } peb_data[0]; And here. Thanks, //richard From tlinder at codeaurora.org Sun Sep 28 01:24:36 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 11:24:36 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <5427C046.5030608@nod.at> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <5427C046.5030608@nod.at> Message-ID: <5427C5C4.40508@codeaurora.org> On 9/28/2014 11:01 AM, Richard Weinberger wrote: > Tanya, > > Am 28.09.2014 08:36, schrieb Tanya Brokhman: >> If there is more then one UBI device mounted, there is no way to >> distinguish between messages from different UBI devices. >> Add device number to all ubi layer message types. >> >> >> Signed-off-by: Tanya Brokhman > > Artem's mail is dedekind1@ not dedeking1 at . :) oops.... sorry about that. thanks for the fix. > Anyway, instead of passing ubi->ubi_num down to every log function you can > just pass the ubi object itself and let the log function access ->ubi_num. This is how I first implemented this patch. But then I cam across some ubi_err prints during the init process (in build.c ubi_init()) when we still don't have the ubi structure, so we need to pass some number to the message. I overcame this by using UBI_MAX_DEVICES. -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From richard.weinberger at gmail.com Sun Sep 28 01:42:48 2014 From: richard.weinberger at gmail.com (Richard Weinberger) Date: Sun, 28 Sep 2014 10:42:48 +0200 Subject: [RFC/PATCH 5/5] mtd: ubi: Add sysfs entry to force all pebs' scan In-Reply-To: <1411886287-8947-1-git-send-email-tlinder@codeaurora.org> References: <1411886287-8947-1-git-send-email-tlinder@codeaurora.org> Message-ID: Tanya, On Sun, Sep 28, 2014 at 8:38 AM, Tanya Brokhman wrote: > A given eraseblock can be read many times or not at all. > We do not have the account of such eraseblocks that have > not been accessed since a pre-defined threshold interval. > By means of scanning the entire flash device it is possible to identify > all such eraseblocks. > > Add a sysfs entry to force scan on all the PEBs on demand basis. > > The sysfs entry would be available under /sys/class/ubi/ubiX/peb_scan > - echo 1 to this entry would trigger the scan, ignored if in progress > - On reading returns the scan status (1 = Scan executing, 0 = Scan not > executing) Did you see that? http://linux-kernel.2935.n7.nabble.com/RFC-UBI-bitrot-checking-td949453.html Maybe we can combine our work. Although your patch seems to be in better shape than mine. :) > Signed-off-by: Pratibhasagar V > Signed-off-by: Tatyana Brokhman > --- > drivers/mtd/ubi/build.c | 32 +++++++++-- > drivers/mtd/ubi/ubi.h | 3 + > drivers/mtd/ubi/wl.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 171 insertions(+), 7 deletions(-) > > diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c > index 34fe23a..a7464f8 100644 > --- a/drivers/mtd/ubi/build.c > +++ b/drivers/mtd/ubi/build.c > @@ -154,6 +154,9 @@ static struct device_attribute dev_dt_threshold = > static struct device_attribute dev_rd_threshold = > __ATTR(rd_threshold, (S_IWUSR | S_IRUGO), dev_attribute_show, > dev_attribute_store); > +static struct device_attribute dev_mtd_trigger_scan = > + __ATTR(peb_scan, (S_IWUSR | S_IRUGO), > + dev_attribute_show, dev_attribute_store); > > /** > * ubi_volume_notify - send a volume change notification. > @@ -395,6 +398,8 @@ static ssize_t dev_attribute_show(struct device *dev, > ret = sprintf(buf, "%d\n", ubi->dt_threshold); > else if (attr == &dev_rd_threshold) > ret = sprintf(buf, "%d\n", ubi->rd_threshold); > + else if (attr == &dev_mtd_trigger_scan) > + ret = sprintf(buf, "%d\n", ubi->scan_in_progress); > else > ret = -EINVAL; > > @@ -406,7 +411,7 @@ static ssize_t dev_attribute_store(struct device *dev, > struct device_attribute *attr, > const char *buf, size_t count) > { > - int value; > + int value, ret; > struct ubi_device *ubi; > > ubi = container_of(dev, struct ubi_device, dev); > @@ -414,8 +419,11 @@ static ssize_t dev_attribute_store(struct device *dev, > if (!ubi) > return -ENODEV; > > - if (kstrtos32(buf, 10, &value)) > - return -EINVAL; > + ret = count; > + if (kstrtos32(buf, 10, &value)) { > + ret = -EINVAL; > + goto out; > + } > /* Consider triggering full scan if threshods change */ > else if (attr == &dev_dt_threshold) { > if (value < UBI_MAX_DT_THRESHOLD) > @@ -429,9 +437,21 @@ static ssize_t dev_attribute_store(struct device *dev, > else > pr_err("Max supported threshold value is %d", > UBI_MAX_READCOUNTER); > + } else if (attr == &dev_mtd_trigger_scan) { > + if (value != 1) { > + pr_err("Invalid input. Echo 1 to start trigger"); > + goto out; > + } > + if (!ubi->lookuptbl) { > + pr_err("lookuptbl is null"); > + goto out; > + } > + ret = ubi_wl_scan_all(ubi); > } > > - return count; > +out: > + ubi_put_device(ubi); > + return ret; > } > > static void dev_release(struct device *dev) > @@ -500,6 +520,9 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) > if (err) > return err; > err = device_create_file(&ubi->dev, &dev_rd_threshold); > + if (err) > + return err; > + err = device_create_file(&ubi->dev, &dev_mtd_trigger_scan); > return err; > } > > @@ -509,6 +532,7 @@ static int ubi_sysfs_init(struct ubi_device *ubi, int *ref) > */ > static void ubi_sysfs_close(struct ubi_device *ubi) > { > + device_remove_file(&ubi->dev, &dev_mtd_trigger_scan); > device_remove_file(&ubi->dev, &dev_mtd_num); > device_remove_file(&ubi->dev, &dev_dt_threshold); > device_remove_file(&ubi->dev, &dev_rd_threshold); > diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h > index ed04de2..1079517 100644 > --- a/drivers/mtd/ubi/ubi.h > +++ b/drivers/mtd/ubi/ubi.h > @@ -491,6 +491,7 @@ struct ubi_debug_info { > * for more info > * @dt_threshold: data retention threshold. See UBI_DT_THRESHOLD > * for more info > + * @scan_in_progress: true if scanning of device PEBs is in progress > * > * @flash_size: underlying MTD device size (in bytes) > * @peb_count: count of physical eraseblocks on the MTD device > @@ -595,6 +596,7 @@ struct ubi_device { > char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; > int rd_threshold; > int dt_threshold; > + bool scan_in_progress; > > > /* I/O sub-system's stuff */ > @@ -873,6 +875,7 @@ int ubi_is_erase_work(struct ubi_work *wrk); > void ubi_refill_pools(struct ubi_device *ubi); > int ubi_ensure_anchor_pebs(struct ubi_device *ubi); > int ubi_in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root); > +int ubi_wl_scan_all(struct ubi_device *ubi); > > /* io.c */ > int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, > diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c > index a5d754f..4edbb4c 100644 > --- a/drivers/mtd/ubi/wl.c > +++ b/drivers/mtd/ubi/wl.c > @@ -143,6 +143,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, > struct ubi_wl_entry *e, struct rb_root *root); > static int self_check_in_pq(const struct ubi_device *ubi, > struct ubi_wl_entry *e); > +static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, > + int vol_id, int lnum, int torture); > > #ifdef CONFIG_MTD_UBI_FASTMAP > /** > @@ -555,8 +557,11 @@ retry: > static void return_unused_pool_pebs(struct ubi_device *ubi, > struct ubi_fm_pool *pool) > { > - int i; > + int i, err; > struct ubi_wl_entry *e; > + struct timeval tv; > + > + do_gettimeofday(&tv); > > for (i = pool->used; i < pool->size; i++) { > e = ubi->lookuptbl[pool->pebs[i]]; > @@ -566,8 +571,22 @@ static void return_unused_pool_pebs(struct ubi_device *ubi, > self_check_in_wl_tree(ubi, e, &ubi->scrub); > rb_erase(&e->u.rb, &ubi->scrub); > } > - wl_tree_add(e, &ubi->free); > - ubi->free_count++; > + if (e->last_erase_time + UBI_DT_THRESHOLD < > + (tv.tv_sec / NUM_SEC_IN_DAY)) { > + spin_unlock(&ubi->wl_lock); > + err = schedule_erase(ubi, e, UBI_UNKNOWN, > + UBI_UNKNOWN, 0); > + spin_lock(&ubi->wl_lock); > + if (err) { > + ubi_err( > + "Failed to schedule erase for PEB %d (err=%d)", > + e->pnum, err); > + ubi_ro_mode(ubi); > + } > + } else { > + wl_tree_add(e, &ubi->free); > + ubi->free_count++; > + } > } > } > > @@ -711,6 +730,124 @@ int ubi_wl_get_peb(struct ubi_device *ubi) > #endif > > /** > + * ubi_wl_scan_all - Scan all PEB's > + * @ubi: UBI device description object > + * > + * This function scans all device PEBs in order to locate once > + * need scrubbing; due to read disturb threashold or last erase > + * timestamp. > + * > + * Return 0 in case of sucsess, (negative) error code otherwise > + * > + */ > +int ubi_wl_scan_all(struct ubi_device *ubi) > +{ > + struct timeval tv; > + struct rb_node *node; > + struct ubi_wl_entry *wl_e, *tmp; > + int used_cnt, free_cnt; > + int err; > + > + do_gettimeofday(&tv); > + if (!ubi->lookuptbl) { > + ubi_err("lookuptbl is null"); > + return -ENOENT; > + } > + > + spin_lock(&ubi->wl_lock); > + if (ubi->scan_in_progress) { > + ubi_err("Scan already in progress, ignoring the trigger"); > + err = -EPERM; > + goto out; > + } > + ubi->scan_in_progress = true; > + > + ubi_msg("Scanning all PEBs for read-disturb/erasures"); > + /* For PEBs in free list rc=0 */ > + free_cnt = 0; > + node = rb_first(&ubi->free); > + while (node) { > + wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); > + node = rb_next(node); > + if (wl_e->last_erase_time + UBI_DT_THRESHOLD < > + (tv.tv_sec / NUM_SEC_IN_DAY)) { > + if (self_check_in_wl_tree(ubi, wl_e, &ubi->free)) { > + ubi_err("PEB %d moved from free tree", > + wl_e->pnum); > + err = -EAGAIN; > + goto out; > + } > + rb_erase(&wl_e->u.rb, &ubi->free); > + ubi->free_count--; > + spin_unlock(&ubi->wl_lock); > + err = schedule_erase(ubi, wl_e, UBI_UNKNOWN, > + UBI_UNKNOWN, 0); > + spin_lock(&ubi->wl_lock); > + if (err) { > + ubi_err( > + "Failed to schedule erase for PEB %d (err=%d)", > + wl_e->pnum, err); > + ubi_ro_mode(ubi); > + goto out; > + } > + free_cnt++; > + } > + } > + > + used_cnt = 0; > + node = rb_first(&ubi->used); > + while (node) { > + wl_e = rb_entry(node, struct ubi_wl_entry, u.rb); > + node = rb_next(node); > + if ((wl_e->rc >= UBI_RD_THRESHOLD) || > + (wl_e->last_erase_time + > + UBI_DT_THRESHOLD < (tv.tv_sec / NUM_SEC_IN_DAY))) { > + spin_unlock(&ubi->wl_lock); > + err = ubi_wl_scrub_peb(ubi, wl_e->pnum); > + if (err) > + ubi_err( > + "Failed to schedule scrub for PEB %d (err=%d)", > + wl_e->pnum, err); > + else > + used_cnt++; > + spin_lock(&ubi->wl_lock); > + } > + } > + > + /* Go over protection queue */ > + list_for_each_entry_safe(wl_e, tmp, &ubi->pq[ubi->pq_head], u.list) { > + if ((wl_e->rc >= UBI_RD_THRESHOLD) || > + (wl_e->last_erase_time + > + UBI_DT_THRESHOLD < (tv.tv_sec / NUM_SEC_IN_DAY))) { > + spin_unlock(&ubi->wl_lock); > + err = ubi_wl_scrub_peb(ubi, wl_e->pnum); > + if (err) > + ubi_err( > + "Failed to schedule scrub for PEB %d (err=%d)", > + wl_e->pnum, err); > + else > + used_cnt++; > + spin_lock(&ubi->wl_lock); > + } > + } > + spin_unlock(&ubi->wl_lock); > + ubi_msg("Scheduled %d for erasure", free_cnt); > + ubi_msg("Scehduled %d for scrubbing", used_cnt); > + err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL); > + if (err) > + ubi_err("Failed to flush ubi wq. err = %d", err); > + else > + ubi_msg("Flashed ubi wq"); > + > + spin_lock(&ubi->wl_lock); > +out: > + ubi->scan_in_progress = false; > + spin_unlock(&ubi->wl_lock); > + ubi_msg("Scanning all PEBs completed. err = %d", err); > + return err; > +} > + > +/** > * prot_queue_del - remove a physical eraseblock from the protection queue. > * @ubi: UBI device description object > * @pnum: the physical eraseblock to remove > -- > 1.8.5.2 > -- > QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member > of Code Aurora Forum, hosted by The Linux Foundation > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ -- Thanks, //richard From tlinder at codeaurora.org Sun Sep 28 01:48:46 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 11:48:46 +0300 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <5427C45C.2080506@nod.at> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> <5427C45C.2080506@nod.at> Message-ID: <5427CB6E.7010007@codeaurora.org> Hi Richard On 9/28/2014 11:18 AM, Richard Weinberger wrote: >> index 0431b46..5399aa2 100644 >> --- a/drivers/mtd/ubi/fastmap.c >> +++ b/drivers/mtd/ubi/fastmap.c >> @@ -1,5 +1,7 @@ >> /* >> * Copyright (c) 2012 Linutronix GmbH >> + * Copyright (c) 2014, Linux Foundation. All rights reserved. >> + * > > Diffstat says "drivers/mtd/ubi/fastmap.c | 14 +++++++----", does this really justify > a new copyright line? > If so I'll have to add the new company I work for here too. You're right. my bad. added it at the beginning but decides against it later on. Will remove. > >> * Author: Richard Weinberger >> * >> * This program is free software; you can redistribute it and/or modify >> @@ -727,9 +729,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, >> } >> >> for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { >> - int pnum = be32_to_cpu(fm_eba->pnum[j]); >> + int pnum = be32_to_cpu(fm_eba->peb_data[j].pnum); >> >> - if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0) >> + if ((int)be32_to_cpu(fm_eba->peb_data[j].pnum) < 0) >> continue; >> >> aeb = NULL; >> @@ -757,7 +759,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, >> } >> >> aeb->lnum = j; >> - aeb->pnum = be32_to_cpu(fm_eba->pnum[j]); >> + aeb->pnum = >> + be32_to_cpu(fm_eba->peb_data[j].pnum); >> aeb->ec = -1; >> aeb->scrub = aeb->copy_flag = aeb->sqnum = 0; >> list_add_tail(&aeb->u.list, &eba_orphans); >> @@ -1250,11 +1253,12 @@ static int ubi_write_fastmap(struct ubi_device *ubi, >> vol->vol_type == UBI_STATIC_VOLUME); >> >> feba = (struct ubi_fm_eba *)(fm_raw + fm_pos); >> - fm_pos += sizeof(*feba) + (sizeof(__be32) * vol->reserved_pebs); >> + fm_pos += sizeof(*feba) + >> + 2 * (sizeof(__be32) * vol->reserved_pebs); >> ubi_assert(fm_pos <= ubi->fm_size); >> >> for (j = 0; j < vol->reserved_pebs; j++) >> - feba->pnum[j] = cpu_to_be32(vol->eba_tbl[j]); >> + feba->peb_data[j].pnum = cpu_to_be32(vol->eba_tbl[j]); >> >> feba->reserved_pebs = cpu_to_be32(j); >> feba->magic = cpu_to_be32(UBI_FM_EBA_MAGIC); >> diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h >> index ac2b24d..da418ad 100644 >> --- a/drivers/mtd/ubi/ubi-media.h >> +++ b/drivers/mtd/ubi/ubi-media.h >> @@ -1,5 +1,8 @@ >> /* >> * Copyright (c) International Business Machines Corp., 2006 >> + * Copyright (c) 2014, Linux Foundation. All rights reserved. >> + * Linux Foundation chooses to take subject only to the GPLv2 >> + * license terms, and distributes only under these terms. >> * >> * This program is free software; you can redistribute it and/or modify >> * it under the terms of the GNU General Public License as published by >> @@ -38,6 +41,15 @@ >> /* The highest erase counter value supported by this implementation */ >> #define UBI_MAX_ERASECOUNTER 0x7FFFFFFF >> >> +/* The highest read counter value supported by this implementation */ >> +#define UBI_MAX_READCOUNTER 0x7FFFFFFD /* (0x7FFFFFFF - 2)*/ >> + >> +/* >> + * The highest data retention threshold value supported >> + * by this implementation >> + */ >> +#define UBI_MAX_DT_THRESHOLD 0x7FFFFFFF >> + >> /* The initial CRC32 value used when calculating CRC checksums */ >> #define UBI_CRC32_INIT 0xFFFFFFFFU >> >> @@ -130,6 +142,7 @@ enum { >> * @vid_hdr_offset: where the VID header starts >> * @data_offset: where the user data start >> * @image_seq: image sequence number >> + * @last_erase_time: time stamp of the last erase operation >> * @padding2: reserved for future, zeroes >> * @hdr_crc: erase counter header CRC checksum >> * >> @@ -162,7 +175,8 @@ struct ubi_ec_hdr { >> __be32 vid_hdr_offset; >> __be32 data_offset; >> __be32 image_seq; >> - __u8 padding2[32]; >> + __be64 last_erase_time; /*curr time in sec == unsigned long time_t*/ >> + __u8 padding2[24]; >> __be32 hdr_crc; >> } __packed; >> >> @@ -413,6 +427,8 @@ struct ubi_vtbl_record { >> * @used_blocks: number of PEBs used by this fastmap >> * @block_loc: an array containing the location of all PEBs of the fastmap >> * @block_ec: the erase counter of each used PEB >> + * @block_rc: the read counter of each used PEB >> + * @block_let: the last erase timestamp of each used PEB >> * @sqnum: highest sequence number value at the time while taking the fastmap >> * >> */ >> @@ -424,6 +440,8 @@ struct ubi_fm_sb { >> __be32 used_blocks; >> __be32 block_loc[UBI_FM_MAX_BLOCKS]; >> __be32 block_ec[UBI_FM_MAX_BLOCKS]; >> + __be32 block_rc[UBI_FM_MAX_BLOCKS]; >> + __be64 block_let[UBI_FM_MAX_BLOCKS]; > > Doesn't this break the fastmap on-disk layout? What do you mean "break"? I verified fastmap feature is working. the whole read-disturb depends on it so I tested this thoroughly. > >> __be64 sqnum; >> __u8 padding2[32]; >> } __packed; >> @@ -469,13 +487,17 @@ struct ubi_fm_scan_pool { >> /* ubi_fm_scan_pool is followed by nfree+nused struct ubi_fm_ec records */ >> >> /** >> - * struct ubi_fm_ec - stores the erase counter of a PEB >> + * struct ubi_fm_ec - stores the erase/read counter of a PEB >> * @pnum: PEB number >> * @ec: ec of this PEB >> + * @rc: rc of this PEB >> + * @last_erase_time: last erase time stamp of this PEB >> */ >> struct ubi_fm_ec { >> __be32 pnum; >> __be32 ec; >> + __be32 rc; >> + __be64 last_erase_time; > > Same here. fastmap was thoroughly tested. all works. > >> } __packed; >> >> /** >> @@ -506,10 +528,14 @@ struct ubi_fm_volhdr { >> * @magic: EBA table magic number >> * @reserved_pebs: number of table entries >> * @pnum: PEB number of LEB (LEB is the index) >> + * @rc: Read counter of the LEBs PEB (LEB is the index) >> */ >> struct ubi_fm_eba { >> __be32 magic; >> __be32 reserved_pebs; >> - __be32 pnum[0]; >> + struct { >> + __be32 pnum; >> + __be32 rc; >> + } peb_data[0]; > > And here. fastmap was thoroughly tested. all works. > > Thanks, > //richard > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ > -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From tlinder at codeaurora.org Sun Sep 28 01:53:56 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 11:53:56 +0300 Subject: [RFC/PATCH 5/5] mtd: ubi: Add sysfs entry to force all pebs' scan In-Reply-To: References: <1411886287-8947-1-git-send-email-tlinder@codeaurora.org> Message-ID: <5427CCA4.6060909@codeaurora.org> On 9/28/2014 11:42 AM, Richard Weinberger wrote: > Tanya, > > On Sun, Sep 28, 2014 at 8:38 AM, Tanya Brokhman wrote: >> A given eraseblock can be read many times or not at all. >> We do not have the account of such eraseblocks that have >> not been accessed since a pre-defined threshold interval. >> By means of scanning the entire flash device it is possible to identify >> all such eraseblocks. >> >> Add a sysfs entry to force scan on all the PEBs on demand basis. >> >> The sysfs entry would be available under /sys/class/ubi/ubiX/peb_scan >> - echo 1 to this entry would trigger the scan, ignored if in progress >> - On reading returns the scan status (1 = Scan executing, 0 = Scan not >> executing) > > Did you see that? > http://linux-kernel.2935.n7.nabble.com/RFC-UBI-bitrot-checking-td949453.html > Maybe we can combine our work. > Although your patch seems to be in better shape than mine. :) oh, I'm sorry, missed that (its new :) ) this patch was tested thoroughly and working. I would appreciate if you could review this patch and perhaps we could improve it if required. -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From richard at nod.at Sun Sep 28 01:54:48 2014 From: richard at nod.at (Richard Weinberger) Date: Sun, 28 Sep 2014 10:54:48 +0200 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <5427CB6E.7010007@codeaurora.org> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> <5427C45C.2080506@nod.at> <5427CB6E.7010007@codeaurora.org> Message-ID: <5427CCD8.2090605@nod.at> Am 28.09.2014 10:48, schrieb Tanya Brokhman: >>> @@ -424,6 +440,8 @@ struct ubi_fm_sb { >>> __be32 used_blocks; >>> __be32 block_loc[UBI_FM_MAX_BLOCKS]; >>> __be32 block_ec[UBI_FM_MAX_BLOCKS]; >>> + __be32 block_rc[UBI_FM_MAX_BLOCKS]; >>> + __be64 block_let[UBI_FM_MAX_BLOCKS]; >> >> Doesn't this break the fastmap on-disk layout? > > What do you mean "break"? I verified fastmap feature is working. the whole read-disturb depends on it so I tested this thoroughly. Did you write a fastmap with your changes applied and then an attach using a fastmap implementation *without* you changes? I bet it will not work because the disk layout is now different. Linux is not the only user of fastmap. We need to be very careful here. Thanks, //richard From josh at joshtriplett.org Sun Sep 28 02:56:50 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Sun, 28 Sep 2014 02:56:50 -0700 Subject: [PATCH 1/1] jffs2: fix sparse warning: unexpected unlock In-Reply-To: <1745266822.710655.1411807315752.open-xchange@webmail.nmp.skynet.be> References: <1411065976-20386-1-git-send-email-fabf@skynet.be> <20140922181250.GN1193@ld-irv-0074> <20140926231727.GD20917@cloud> <1745266822.710655.1411807315752.open-xchange@webmail.nmp.skynet.be> Message-ID: <20140928095650.GA24178@thin> On Sat, Sep 27, 2014 at 10:41:55AM +0200, Fabian Frederick wrote: > > > > On 27 September 2014 at 01:17 josh at joshtriplett.org wrote: > > > > > > On Mon, Sep 22, 2014 at 11:12:50AM -0700, Brian Norris wrote: > > > + linux-sparse > > > > > > On Thu, Sep 18, 2014 at 08:46:16PM +0200, Fabian Frederick wrote: > > > > fs/jffs2/summary.c:846:5: warning: context imbalance in > > > > 'jffs2_sum_write_sumnode' - unexpected unlock > > > > > > > > Signed-off-by: Fabian Frederick > > > > --- > > > >? fs/jffs2/summary.c | 2 ++ > > > >? 1 file changed, 2 insertions(+) > > > > > > > > diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c > > > > index c522d09..a0bac7b 100644 > > > > --- a/fs/jffs2/summary.c > > > > +++ b/fs/jffs2/summary.c > > > > @@ -844,6 +844,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info > > > > *c, struct jffs2_eraseblock > > > >? /* Write out summary information - called from jffs2_do_reserve_space */ > > > >? > > > >? int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) > > > > + __releases(&c->erase_completion_lock) > > > > + __acquires(&c->erase_completion_lock) > > > > > > I'm not too familiar with sparse notations, but Documentation/sparse.txt > > > suggests the above is wrong, and the following is more accurate: > > > > > >? ? ?__must_hold(&c->erase_completion_lock) > > > > > > But it looks like there are several other examples which do this. > > > Anyway, here's the relevant doc text, in case someone wants to clarify > > > it for me, or else tell me the documentation is wrong: > > > > > >? ? ?__must_hold - The specified lock is held on function entry and exit. > > > > > >? ? ?__acquires - The specified lock is held on function exit, but not entry. > > > > > >? ? ?__releases - The specified lock is held on function entry, but not exit. > > > > > > So __acquires and __releases look mutually exclusive, but it's not clear > > > if __must_hold will actually cover what we want. (I haven't tested it.) > > > > __must_hold is indeed the correct annotation.? (There isn't currently > > anything enforcing that, though.) > > > > - Josh Triplett > > There are 137 __releases && __acquires annotated functions in stable. > > AFAICS those are based on lock held on function entry / lock held on exit > > See > fs/fuse/file.c:1527 > fs/kernfs/dir.c:341 > drivers/block/nbd.c:564 > > Does it mean that all of these should be updated to __must_hold ? Not really worth changing yet until something actually pays closer attention to those annotations. - Josh Triplett From tlinder at codeaurora.org Sun Sep 28 03:46:22 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 13:46:22 +0300 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <5427CCD8.2090605@nod.at> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> <5427C45C.2080506@nod.at> <5427CB6E.7010007@codeaurora.org> <5427CCD8.2090605@nod.at> Message-ID: <5427E6FE.3090906@codeaurora.org> On 9/28/2014 11:54 AM, Richard Weinberger wrote: > Am 28.09.2014 10:48, schrieb Tanya Brokhman: >>>> @@ -424,6 +440,8 @@ struct ubi_fm_sb { >>>> __be32 used_blocks; >>>> __be32 block_loc[UBI_FM_MAX_BLOCKS]; >>>> __be32 block_ec[UBI_FM_MAX_BLOCKS]; >>>> + __be32 block_rc[UBI_FM_MAX_BLOCKS]; >>>> + __be64 block_let[UBI_FM_MAX_BLOCKS]; >>> >>> Doesn't this break the fastmap on-disk layout? >> >> What do you mean "break"? I verified fastmap feature is working. the whole read-disturb depends on it so I tested this thoroughly. > > Did you write a fastmap with your changes applied and then an attach using a fastmap implementation *without* > you changes? > I bet it will not work because the disk layout is now different. you're right, it wont work. I did a set of attach/detach tests to verify fastmap, but of course with my changes. > Linux is not the only user of fastmap. We need to be very careful here. Could you please elaborate here? I'm not sure I understand the use case you're referring to. > > Thanks, > //richard > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ > -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From richard at nod.at Sun Sep 28 03:54:02 2014 From: richard at nod.at (Richard Weinberger) Date: Sun, 28 Sep 2014 12:54:02 +0200 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <5427E6FE.3090906@codeaurora.org> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> <5427C45C.2080506@nod.at> <5427CB6E.7010007@codeaurora.org> <5427CCD8.2090605@nod.at> <5427E6FE.3090906@codeaurora.org> Message-ID: <5427E8CA.8000904@nod.at> Am 28.09.2014 12:46, schrieb Tanya Brokhman: > On 9/28/2014 11:54 AM, Richard Weinberger wrote: >> Am 28.09.2014 10:48, schrieb Tanya Brokhman: >>>>> @@ -424,6 +440,8 @@ struct ubi_fm_sb { >>>>> __be32 used_blocks; >>>>> __be32 block_loc[UBI_FM_MAX_BLOCKS]; >>>>> __be32 block_ec[UBI_FM_MAX_BLOCKS]; >>>>> + __be32 block_rc[UBI_FM_MAX_BLOCKS]; >>>>> + __be64 block_let[UBI_FM_MAX_BLOCKS]; >>>> >>>> Doesn't this break the fastmap on-disk layout? >>> >>> What do you mean "break"? I verified fastmap feature is working. the whole read-disturb depends on it so I tested this thoroughly. >> >> Did you write a fastmap with your changes applied and then an attach using a fastmap implementation *without* >> you changes? >> I bet it will not work because the disk layout is now different. > > you're right, it wont work. I did a set of attach/detach tests to verify fastmap, but of course with my changes. > >> Linux is not the only user of fastmap. We need to be very careful here. > > Could you please elaborate here? I'm not sure I understand the use case you're referring to. Consider the case where you have a board with a fastmap enabled bootloader and a Linux OS. The bootloader does a fastmap attach and boots the kernel from UBI and the kernel it self has the rootfs on UBI too. If you install a new kernel with your changes applied it will write the fastmap in a different format and the bootloader will fail badly. In worst case the board bricks, in best case the bootloader can fall back to scanning mode but it will be slow and the customer unhappy. Thanks, //richard From broonie at debian.org Sun Sep 28 04:35:11 2014 From: broonie at debian.org (Mark Brown) Date: Sun, 28 Sep 2014 12:35:11 +0100 Subject: [PATCH 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification In-Reply-To: <1410714624.3040.38.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> Message-ID: <20140928113511.GX27755@sirena.org.uk> On Sun, Sep 14, 2014 at 06:10:24PM +0100, Ben Hutchings wrote: > The first patch in the series restores the module aliases to m25p80, but > it does so by duplicating the list of names. This should be suitable > for stable, but it isn't viable in the longer term. Please don't CC patches not for the SPI subsystem to linux-spi, they just clog up patchwork for no benefit. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 473 bytes Desc: Digital signature URL: From dedekind1 at gmail.com Sun Sep 28 05:01:05 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Sun, 28 Sep 2014 15:01:05 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> Message-ID: <1411905665.11836.15.camel@karhu> On Sun, 2014-09-28 at 09:36 +0300, Tanya Brokhman wrote: > If there is more then one UBI device mounted, there is no way to > distinguish between messages from different UBI devices. > Add device number to all ubi layer message types. Hi, the goal looks legit to me, but the patch is so large that I do not think that I can really review it in this form. a) A patch which changes the macros (ubi_err(), etc) b) A set of patches which do not change messages at all, but add the 'ubi' parameter to the places where it is missing. c) A patch which changes the messages. So a) will be the most important patch for the reviewer. b) - more or less mechanical changes of a similar kind. c) - the same. Also, if you add a parameter to 'ubi_err()' and the other printing wrappers, add 'ubi' there, not 'ubi_num'. This will allow to prefix messages with vary different things, not just the device number in the future. So the calls would look like ubi_err(ubi, "inconsistent used_ebs"); Once this is done, the series should be more reviewable. The next thing I'd check is whether we really need to change all the messages, or most of them, or we actually need to change only a small part of them. In the former case, it is OK to do what you do, I guess. In the latter case we probably better off with introducing a separate set of printing macros and leave the existing ones as they are. Thanks! -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Sun Sep 28 05:11:16 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Sun, 28 Sep 2014 15:11:16 +0300 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> Message-ID: <1411906276.11836.21.camel@karhu> On Sun, 2014-09-28 at 09:37 +0300, Tanya Brokhman wrote: > The need for performing read disturb is determined according to new > statistics collected per eraseblock: > - read counter: incremented at each read operation > reset at each erase > - last erase time stamp: updated at each erase > > This patch adds the infrastructure for the above statistics Would you please provide some kind of high level description for this stuff. What is the problem at hand, how is it solved. Right off-the top of my head I have the following comment. Adding more fields to 'struct ubi_wl_entry' should be well-justified. These objects are per-PEB, so there may be really a lot of them, and they may consume a lot of memory. Increasing the size of the object may be affect the memory consumption a lot. So I wonder if these read counters solve a big enough problem, so that they are worth having in this data structure. So I am really missing the bigger picture here. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Sun Sep 28 05:14:02 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Sun, 28 Sep 2014 15:14:02 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <5427C046.5030608@nod.at> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <5427C046.5030608@nod.at> Message-ID: <1411906442.11836.24.camel@karhu> On Sun, 2014-09-28 at 10:01 +0200, Richard Weinberger wrote: > Tanya, > > Am 28.09.2014 08:36, schrieb Tanya Brokhman: > > If there is more then one UBI device mounted, there is no way to > > distinguish between messages from different UBI devices. > > Add device number to all ubi layer message types. > > > > > > Signed-off-by: Tanya Brokhman > > Artem's mail is dedekind1@ not dedeking1 at . :) Yeah, it is not after a King named "Dede" :-) I just liked the Richard Dedekind's theorem back in the University days :-) > Anyway, instead of passing ubi->ubi_num down to every log function you can > just pass the ubi object itself and let the log function access ->ubi_num. Yes, then we potentially may add more than just the device number to the messages, if we ever need. -- Best Regards, Artem Bityutskiy From dedekind1 at gmail.com Sun Sep 28 05:15:56 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Sun, 28 Sep 2014 15:15:56 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <5427C5C4.40508@codeaurora.org> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <5427C046.5030608@nod.at> <5427C5C4.40508@codeaurora.org> Message-ID: <1411906556.11836.26.camel@karhu> On Sun, 2014-09-28 at 11:24 +0300, Tanya Brokhman wrote: > This is how I first implemented this patch. But then I cam across > some > ubi_err prints during the init process (in build.c ubi_init()) when > we > still don't have the ubi structure, so we need to pass some number to > the message. I overcame this by using UBI_MAX_DEVICES. Well, may be having two sets of wrappers would make sense then? Or if there are few of those, just using 'printk()' would be a solution? -- Best Regards, Artem Bityutskiy From tlinder at codeaurora.org Sun Sep 28 07:54:21 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Sun, 28 Sep 2014 17:54:21 +0300 Subject: [RFC/PATCH 1/5] mtd: ubi: Read disturb infrastructure In-Reply-To: <1411906276.11836.21.camel@karhu> References: <1411886220-8208-1-git-send-email-tlinder@codeaurora.org> <1411906276.11836.21.camel@karhu> Message-ID: <5428211D.5090005@codeaurora.org> On 9/28/2014 3:11 PM, Artem Bityutskiy wrote: > On Sun, 2014-09-28 at 09:37 +0300, Tanya Brokhman wrote: >> The need for performing read disturb is determined according to new >> statistics collected per eraseblock: >> - read counter: incremented at each read operation >> reset at each erase >> - last erase time stamp: updated at each erase >> >> This patch adds the infrastructure for the above statistics > > Would you please provide some kind of high level description for this > stuff. What is the problem at hand, how is it solved. Right off-the top > of my head I have the following comment. > > Adding more fields to 'struct ubi_wl_entry' should be well-justified. > These objects are per-PEB, so there may be really a lot of them, and > they may consume a lot of memory. Increasing the size of the object may > be affect the memory consumption a lot. > > So I wonder if these read counters solve a big enough problem, so that > they are worth having in this data structure. > > So I am really missing the bigger picture here. > Sure, will add a documentation file to describe the need for this and the algorithm itself. -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From ryazanov.s.a at gmail.com Sun Sep 28 11:33:10 2014 From: ryazanov.s.a at gmail.com (Sergey Ryazanov) Date: Sun, 28 Sep 2014 22:33:10 +0400 Subject: [PATCH 11/16] mtd: add Atheros AR2315 SPI Flash driver In-Reply-To: <1411929195-23775-1-git-send-email-ryazanov.s.a@gmail.com> References: <1411929195-23775-1-git-send-email-ryazanov.s.a@gmail.com> Message-ID: <1411929195-23775-12-git-send-email-ryazanov.s.a@gmail.com> Atheros AR2315 SoC have a SPI Flash unit with hybrid flash access: flash read is performed via memory mapping, on the other hand flash write is performed by explicitly issued SPI command. Signed-off-by: Sergey Ryazanov Cc: David Woodhouse Cc: Brian Norris Cc: linux-mtd at lists.infradead.org --- This driver is not ready for merging since it should be rewrited using spi-nor framework. Changes since RFC: - move device registration to separate patch drivers/mtd/devices/Kconfig | 5 + drivers/mtd/devices/Makefile | 1 + drivers/mtd/devices/ar2315.c | 459 ++++++++++++++++++++++++++++++++++ drivers/mtd/devices/ar2315_spiflash.h | 106 ++++++++ 4 files changed, 571 insertions(+) create mode 100644 drivers/mtd/devices/ar2315.c create mode 100644 drivers/mtd/devices/ar2315_spiflash.h diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index c49d0b1..9533867 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -112,6 +112,11 @@ config MTD_SST25L Set up your spi devices with the right board-specific platform data, if you want to specify device partitioning. +config MTD_AR2315 + tristate "Atheros AR2315+ SPI Flash support" + depends on SOC_AR2315 + default y + config MTD_BCM47XXSFLASH tristate "R/O support for serial flash on BCMA bus" depends on BCMA_SFLASH diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f..eaec8fb 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o +obj-$(CONFIG_MTD_AR2315) += ar2315.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o obj-$(CONFIG_MTD_ST_SPI_FSM) += st_spi_fsm.o diff --git a/drivers/mtd/devices/ar2315.c b/drivers/mtd/devices/ar2315.c new file mode 100644 index 0000000..f2a5e28 --- /dev/null +++ b/drivers/mtd/devices/ar2315.c @@ -0,0 +1,459 @@ + +/* + * MTD driver for the SPI Flash Memory support on Atheros AR2315 + * + * Copyright (c) 2005-2006 Atheros Communications Inc. + * Copyright (C) 2006-2007 FON Technology, SL. + * Copyright (C) 2006-2007 Imre Kaloz + * Copyright (C) 2006-2009 Felix Fietkau + * Copyright (C) 2012 Alexandros C. Couloumbis + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ar2315_spiflash.h" + +#define DRIVER_NAME "ar2315-spiflash" + +#define busy_wait(_priv, _condition, _wait) do { \ + while (_condition) { \ + if (_wait > 1) \ + msleep(_wait); \ + else if ((_wait == 1) && need_resched()) \ + schedule(); \ + else \ + udelay(1); \ + } \ +} while (0) + +enum { + FLASH_NONE, + FLASH_1MB, + FLASH_2MB, + FLASH_4MB, + FLASH_8MB, + FLASH_16MB, +}; + +/* Flash configuration table */ +struct flashconfig { + u32 byte_cnt; + u32 sector_cnt; + u32 sector_size; +}; + +static const struct flashconfig flashconfig_tbl[] = { + [FLASH_NONE] = { 0, 0, 0}, + [FLASH_1MB] = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, + STM_1MB_SECTOR_SIZE}, + [FLASH_2MB] = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, + STM_2MB_SECTOR_SIZE}, + [FLASH_4MB] = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, + STM_4MB_SECTOR_SIZE}, + [FLASH_8MB] = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT, + STM_8MB_SECTOR_SIZE}, + [FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT, + STM_16MB_SECTOR_SIZE} +}; + +/* Mapping of generic opcodes to STM serial flash opcodes */ +enum { + SPI_WRITE_ENABLE, + SPI_WRITE_DISABLE, + SPI_RD_STATUS, + SPI_WR_STATUS, + SPI_RD_DATA, + SPI_FAST_RD_DATA, + SPI_PAGE_PROGRAM, + SPI_SECTOR_ERASE, + SPI_BULK_ERASE, + SPI_DEEP_PWRDOWN, + SPI_RD_SIG, +}; + +struct opcodes { + __u16 code; + __s8 tx_cnt; + __s8 rx_cnt; +}; + +static const struct opcodes stm_opcodes[] = { + [SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0}, + [SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0}, + [SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1}, + [SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0}, + [SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4}, + [SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0}, + [SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0}, + [SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0}, + [SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0}, + [SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0}, + [SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1}, +}; + +/* Driver private data structure */ +struct spiflash_priv { + struct mtd_info mtd; + void __iomem *readaddr; /* memory mapped data for read */ + void __iomem *mmraddr; /* memory mapped register space */ + struct mutex lock; /* serialize registers access */ +}; + +#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd) + +enum { + FL_READY, + FL_READING, + FL_ERASING, + FL_WRITING +}; + +/*****************************************************************************/ + +static u32 +spiflash_read_reg(struct spiflash_priv *priv, int reg) +{ + return ioread32(priv->mmraddr + reg); +} + +static void +spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data) +{ + iowrite32(data, priv->mmraddr + reg); +} + +static u32 +spiflash_wait_busy(struct spiflash_priv *priv) +{ + u32 reg; + + busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) & + SPI_CTL_BUSY, 0); + return reg; +} + +static u32 +spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr) +{ + const struct opcodes *op; + u32 reg, mask; + + op = &stm_opcodes[opcode]; + reg = spiflash_wait_busy(priv); + spiflash_write_reg(priv, SPI_FLASH_OPCODE, + ((u32)op->code) | (addr << 8)); + + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4); + + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + spiflash_wait_busy(priv); + + if (!op->rx_cnt) + return 0; + + reg = spiflash_read_reg(priv, SPI_FLASH_DATA); + + switch (op->rx_cnt) { + case 1: + mask = 0x000000ff; + break; + case 2: + mask = 0x0000ffff; + break; + case 3: + mask = 0x00ffffff; + break; + default: + mask = 0xffffffff; + break; + } + reg &= mask; + + return reg; +} + +/* + * Probe SPI flash device + * Function returns 0 for failure. + * and flashconfig_tbl array index for success. + */ +static int +spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv) +{ + u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0); + int flash_size; + + switch (sig) { + case STM_8MBIT_SIGNATURE: + flash_size = FLASH_1MB; + break; + case STM_16MBIT_SIGNATURE: + flash_size = FLASH_2MB; + break; + case STM_32MBIT_SIGNATURE: + flash_size = FLASH_4MB; + break; + case STM_64MBIT_SIGNATURE: + flash_size = FLASH_8MB; + break; + case STM_128MBIT_SIGNATURE: + flash_size = FLASH_16MB; + break; + default: + dev_warn(&pdev->dev, "read of flash device signature failed!\n"); + return 0; + } + + return flash_size; +} + +static void +spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout) +{ + busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) & + SPI_STATUS_WIP, timeout); +} + +static int +spiflash_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + const struct opcodes *op; + u32 temp, reg; + + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + + mutex_lock(&priv->lock); + + spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); + reg = spiflash_wait_busy(priv); + + op = &stm_opcodes[SPI_SECTOR_ERASE]; + temp = ((u32)instr->addr << 8) | (u32)(op->code); + spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp); + + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= op->tx_cnt | SPI_CTL_START; + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + + spiflash_wait_complete(priv, 20); + + mutex_unlock(&priv->lock); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +static int +spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, + u_char *buf) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + + if (!len) + return 0; + + if (from + len > mtd->size) + return -EINVAL; + + *retlen = len; + + mutex_lock(&priv->lock); + + memcpy_fromio(buf, priv->readaddr + from, len); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int +spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u8 *buf) +{ + struct spiflash_priv *priv = to_spiflash(mtd); + u32 opcode, bytes_left; + + *retlen = 0; + + if (!len) + return 0; + + if (to + len > mtd->size) + return -EINVAL; + + bytes_left = len; + + do { + u32 read_len, reg, page_offset, spi_data = 0; + + read_len = min(bytes_left, sizeof(u32)); + + /* 32-bit writes cannot span across a page boundary + * (256 bytes). This types of writes require two page + * program operations to handle it correctly. The STM part + * will write the overflow data to the beginning of the + * current page as opposed to the subsequent page. + */ + page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len; + + if (page_offset > STM_PAGE_SIZE) + read_len -= (page_offset - STM_PAGE_SIZE); + + mutex_lock(&priv->lock); + + spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0); + spi_data = 0; + switch (read_len) { + case 4: + spi_data |= buf[3] << 24; + /* fall through */ + case 3: + spi_data |= buf[2] << 16; + /* fall through */ + case 2: + spi_data |= buf[1] << 8; + /* fall through */ + case 1: + spi_data |= buf[0] & 0xff; + break; + default: + break; + } + + spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data); + opcode = stm_opcodes[SPI_PAGE_PROGRAM].code | + (to & 0x00ffffff) << 8; + spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode); + + reg = spiflash_read_reg(priv, SPI_FLASH_CTL); + reg &= ~SPI_CTL_TX_RX_CNT_MASK; + reg |= (read_len + 4) | SPI_CTL_START; + spiflash_write_reg(priv, SPI_FLASH_CTL, reg); + + spiflash_wait_complete(priv, 1); + + mutex_unlock(&priv->lock); + + bytes_left -= read_len; + to += read_len; + buf += read_len; + + *retlen += read_len; + } while (bytes_left != 0); + + return 0; +} + +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS +static const char * const part_probe_types[] = { + "cmdlinepart", "RedBoot", "MyLoader", NULL +}; +#endif + +static int +spiflash_probe(struct platform_device *pdev) +{ + struct spiflash_priv *priv; + struct mtd_info *mtd; + struct resource *res; + int index; + int result = 0; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->lock); + mtd = &priv->mtd; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->mmraddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->mmraddr)) { + dev_warn(&pdev->dev, "failed to map flash MMR\n"); + return PTR_ERR(priv->mmraddr); + } + + index = spiflash_probe_chip(pdev, priv); + if (!index) { + dev_warn(&pdev->dev, "found no flash device\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->readaddr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->readaddr)) { + dev_warn(&pdev->dev, "failed to map flash read mem\n"); + return PTR_ERR(priv->readaddr); + } + + platform_set_drvdata(pdev, priv); + mtd->name = "spiflash"; + mtd->type = MTD_NORFLASH; + mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE); + mtd->size = flashconfig_tbl[index].byte_cnt; + mtd->erasesize = flashconfig_tbl[index].sector_size; + mtd->writesize = 1; + mtd->numeraseregions = 0; + mtd->eraseregions = NULL; + mtd->_erase = spiflash_erase; + mtd->_read = spiflash_read; + mtd->_write = spiflash_write; + mtd->owner = THIS_MODULE; + + dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10); + +#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS + /* parse redboot partitions */ + + result = mtd_device_parse_register(mtd, part_probe_types, + NULL, NULL, 0); +#endif + + return result; +} + +static int +spiflash_remove(struct platform_device *pdev) +{ + struct spiflash_priv *priv = platform_get_drvdata(pdev); + + mtd_device_unregister(&priv->mtd); + + return 0; +} + +static struct platform_driver spiflash_driver = { + .driver.name = DRIVER_NAME, + .probe = spiflash_probe, + .remove = spiflash_remove, +}; + +module_platform_driver(spiflash_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("OpenWrt.org"); +MODULE_AUTHOR("Atheros Communications Inc"); +MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC"); +MODULE_ALIAS("platform:" DRIVER_NAME); + diff --git a/drivers/mtd/devices/ar2315_spiflash.h b/drivers/mtd/devices/ar2315_spiflash.h new file mode 100644 index 0000000..17b0903 --- /dev/null +++ b/drivers/mtd/devices/ar2315_spiflash.h @@ -0,0 +1,106 @@ +/* + * Atheros AR2315 SPI Flash Memory support header file. + * + * Copyright (c) 2005, Atheros Communications Inc. + * Copyright (C) 2006 FON Technology, SL. + * Copyright (C) 2006 Imre Kaloz + * Copyright (C) 2006-2009 Felix Fietkau + * + * This code is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __AR2315_SPIFLASH_H +#define __AR2315_SPIFLASH_H + +#define STM_PAGE_SIZE 256 + +#define SFI_WRITE_BUFFER_SIZE 4 +#define SFI_FLASH_ADDR_MASK 0x00ffffff + +#define STM_8MBIT_SIGNATURE 0x13 +#define STM_M25P80_BYTE_COUNT 1048576 +#define STM_M25P80_SECTOR_COUNT 16 +#define STM_M25P80_SECTOR_SIZE 0x10000 + +#define STM_16MBIT_SIGNATURE 0x14 +#define STM_M25P16_BYTE_COUNT 2097152 +#define STM_M25P16_SECTOR_COUNT 32 +#define STM_M25P16_SECTOR_SIZE 0x10000 + +#define STM_32MBIT_SIGNATURE 0x15 +#define STM_M25P32_BYTE_COUNT 4194304 +#define STM_M25P32_SECTOR_COUNT 64 +#define STM_M25P32_SECTOR_SIZE 0x10000 + +#define STM_64MBIT_SIGNATURE 0x16 +#define STM_M25P64_BYTE_COUNT 8388608 +#define STM_M25P64_SECTOR_COUNT 128 +#define STM_M25P64_SECTOR_SIZE 0x10000 + +#define STM_128MBIT_SIGNATURE 0x17 +#define STM_M25P128_BYTE_COUNT 16777216 +#define STM_M25P128_SECTOR_COUNT 256 +#define STM_M25P128_SECTOR_SIZE 0x10000 + +#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT +#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT +#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE +#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT +#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT +#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE +#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT +#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT +#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE +#define STM_8MB_BYTE_COUNT STM_M25P64_BYTE_COUNT +#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT +#define STM_8MB_SECTOR_SIZE STM_M25P64_SECTOR_SIZE +#define STM_16MB_BYTE_COUNT STM_M25P128_BYTE_COUNT +#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT +#define STM_16MB_SECTOR_SIZE STM_M25P128_SECTOR_SIZE + +/* + * ST Microelectronics Opcodes for Serial Flash + */ + +#define STM_OP_WR_ENABLE 0x06 /* Write Enable */ +#define STM_OP_WR_DISABLE 0x04 /* Write Disable */ +#define STM_OP_RD_STATUS 0x05 /* Read Status */ +#define STM_OP_WR_STATUS 0x01 /* Write Status */ +#define STM_OP_RD_DATA 0x03 /* Read Data */ +#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */ +#define STM_OP_PAGE_PGRM 0x02 /* Page Program */ +#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */ +#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */ +#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */ +#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */ + +#define STM_STATUS_WIP 0x01 /* Write-In-Progress */ +#define STM_STATUS_WEL 0x02 /* Write Enable Latch */ +#define STM_STATUS_BP0 0x04 /* Block Protect 0 */ +#define STM_STATUS_BP1 0x08 /* Block Protect 1 */ +#define STM_STATUS_BP2 0x10 /* Block Protect 2 */ +#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */ + +/* + * SPI Flash Interface Registers + */ + +#define SPI_FLASH_CTL 0x00 +#define SPI_FLASH_OPCODE 0x04 +#define SPI_FLASH_DATA 0x08 + +#define SPI_CTL_START 0x00000100 +#define SPI_CTL_BUSY 0x00010000 +#define SPI_CTL_TXCNT_MASK 0x0000000f +#define SPI_CTL_RXCNT_MASK 0x000000f0 +#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff +#define SPI_CTL_SIZE_MASK 0x00060000 + +#define SPI_CTL_CLK_SEL_MASK 0x03000000 +#define SPI_OPCODE_MASK 0x000000ff + +#define SPI_STATUS_WIP STM_STATUS_WIP + +#endif -- 1.8.5.5 From fabf at skynet.be Sun Sep 28 12:26:32 2014 From: fabf at skynet.be (Fabian Frederick) Date: Sun, 28 Sep 2014 21:26:32 +0200 Subject: [PATCH V2 linux-next] jffs2: fix sparse warning: unexpected unlock Message-ID: <1411932392-7751-1-git-send-email-fabf@skynet.be> fs/jffs2/summary.c:846:5: warning: context imbalance in 'jffs2_sum_write_sumnode' - unexpected unlock Suggested-by: Brian Norris Suggested-by: Josh Triplett Signed-off-by: Fabian Frederick --- V2: use __must_hold instead of __releases / __acquires (suggested by Brian Norris and Josh Triplett) fs/jffs2/summary.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index c522d09..bc53854 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -844,6 +844,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock /* Write out summary information - called from jffs2_do_reserve_space */ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) + __must_hold(&c->erase_completion_block) { int datasize, infosize, padsize; struct jffs2_eraseblock *jeb; -- 1.9.1 From zajec5 at gmail.com Sun Sep 28 13:29:42 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Sun, 28 Sep 2014 22:29:42 +0200 Subject: [PATCH V2] mtd: spi-nor: add Kconfig option to disable 4K sectors In-Reply-To: <20140928002813.GP7362@norris-Latitude-E6410> References: <1408220271-21455-1-git-send-email-zajec5@gmail.com> <1408267646-6643-1-git-send-email-zajec5@gmail.com> <20140928002813.GP7362@norris-Latitude-E6410> Message-ID: On 28 September 2014 02:28, Brian Norris wrote: > On Sun, Aug 17, 2014 at 11:27:26AM +0200, Rafa? Mi?ecki wrote: >> Current situation with 4K sectors is quite messy. First of all, some >> MTD "users" don't work with such small size. An example may be UBIFS >> which requires 15 KiB erase blocks as a minimum. In theory spi-nor >> should provide multiple erase regions and MTD "users" should use the >> one they need. Unforunately that is not implemented. >> >> In the result our flashes database in spi-nor is hackish. For some >> flashes we pretend they don't support 4K sectors just because some >> distribution uses UBIFS on it. This ofc leads to conflicts, like >> Samsung using w25q128 with 4K sectors vs. OpenWrt requiring it to >> pretend it's 64 KiB blocks only. >> >> My idea (plan?) for fixing this situation: >> 1) Use real hw info (this requires a way for disabling 4K for now) >> 2) Provide detailed info about erase regions >> 3) Make UBIFS work with devices that support 4K sectors >> >> Signed-off-by: Rafa? Mi?ecki >> --- >> V2: Add extra info about performance in Kconfig. Thanks Kevin. >> Fix typo s/users/uses/ in commit message. > > Pushed to l2-mtd.git. Thanks! Ooops, for some reason the whole diff is part of the commit message :| http://git.infradead.org/l2-mtd.git/commitdiff/f83cd098095c0e2967e15914f3f9521bb122bc0a > Now we should probably try to handle (1), at least, so that the data > table holds fully accurate info about the flash. I agree, will try to collect real info and submit a patch! -- Rafa? From zajec5 at gmail.com Sun Sep 28 13:36:54 2014 From: zajec5 at gmail.com (=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?=) Date: Sun, 28 Sep 2014 22:36:54 +0200 Subject: [PATCH V3] mtd: move support for struct flash_platform_data into m25p80 In-Reply-To: <1408194788-10434-1-git-send-email-zajec5@gmail.com> References: <1408194788-10434-1-git-send-email-zajec5@gmail.com> Message-ID: <1411936614-28886-1-git-send-email-zajec5@gmail.com> This "type" seems to be an extra hint for m25p80 about the flash. Some archs register flash_platform_data with "name" set to "m25p80" and then with a real flash name set in "type". It seems to be a trick specific to the m25p80 so let's move it out of spi-nor. Btw switch to the spi_nor_match_id instead of iterating spi_nor_ids. Signed-off-by: Rafa? Mi?ecki --- V2: Comment usage of data->type Set mtd.name in m25p80 V3: Fix "respect" spelling in the comment Brian: do you think this comment about "name" and "type" is clear enough now? If so, could you pick this patch, please? --- drivers/mtd/devices/m25p80.c | 22 ++++++++++++++++++++-- drivers/mtd/spi-nor/spi-nor.c | 28 +--------------------------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ed7e0a1b..dcda628 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi) { struct mtd_part_parser_data ppdata; struct flash_platform_data *data; + const struct spi_device_id *id = NULL; struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; int ret; + data = dev_get_platdata(&spi->dev); + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; @@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi) mode = SPI_NOR_QUAD; else if (spi->mode & SPI_RX_DUAL) mode = SPI_NOR_DUAL; - ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); + + if (data && data->name) + flash->mtd.name = data->name; + + /* For some (historical?) reason many platforms provide two different + * names in flash_platform_data: "name" and "type". Quite often name is + * set to "m25p80" and then "type" provides a real chip name. + * If that's the case, respect "type" and ignore a "name". + */ + if (data && data->type) + id = spi_nor_match_id(data->type); + + /* If we didn't get name from platform, simply use "modalias". */ + if (!id) + id = spi_get_device_id(spi); + + ret = spi_nor_scan(nor, id, mode); if (ret) return ret; - data = dev_get_platdata(&spi->dev); ppdata.of_node = spi->dev.of_node; return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 11459f6..ae16aa2 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -915,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode) { struct flash_info *info; - struct flash_platform_data *data; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; struct device_node *np = dev->of_node; @@ -926,28 +925,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (ret) return ret; - /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. If we don't have - * a chip ID, try the JEDEC id commands; they'll work for most - * newer chips, even if we don't recognize the particular chip. - */ - data = dev_get_platdata(dev); - if (data && data->type) { - const struct spi_device_id *plat_id; - - for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { - plat_id = &spi_nor_ids[i]; - if (strcmp(data->type, plat_id->name)) - continue; - break; - } - - if (i < ARRAY_SIZE(spi_nor_ids) - 1) - id = plat_id; - else - dev_warn(dev, "unrecognized id %s\n", data->type); - } - info = (void *)id->driver_data; if (info->jedec_id) { @@ -985,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, write_sr(nor, 0); } - if (data && data->name) - mtd->name = data->name; - else + if (!mtd->name) mtd->name = dev_name(dev); - mtd->type = MTD_NORFLASH; mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; -- 1.8.4.5 From computersforpeace at gmail.com Sun Sep 28 14:17:00 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sun, 28 Sep 2014 14:17:00 -0700 Subject: [PATCH V2] mtd: spi-nor: add Kconfig option to disable 4K sectors In-Reply-To: References: <1408220271-21455-1-git-send-email-zajec5@gmail.com> <1408267646-6643-1-git-send-email-zajec5@gmail.com> <20140928002813.GP7362@norris-Latitude-E6410> Message-ID: <20140928211700.GA3248@norris-Latitude-E6410> On Sun, Sep 28, 2014 at 10:29:42PM +0200, Rafa? Mi?ecki wrote: > On 28 September 2014 02:28, Brian Norris wrote: > > Pushed to l2-mtd.git. Thanks! > > Ooops, for some reason the whole diff is part of the commit message :| > http://git.infradead.org/l2-mtd.git/commitdiff/f83cd098095c0e2967e15914f3f9521bb122bc0a Oops indeed. Not sure how I did that. Fixed now, thanks for reporting. Brian From computersforpeace at gmail.com Sun Sep 28 15:03:00 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sun, 28 Sep 2014 15:03:00 -0700 Subject: [PATCH 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification In-Reply-To: <1410714795.3040.45.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714795.3040.45.camel@decadent.org.uk> Message-ID: <20140928220300.GB3248@norris-Latitude-E6410> On Sun, Sep 14, 2014 at 06:13:15PM +0100, Ben Hutchings wrote: > On Sun, 2014-09-14 at 18:10 +0100, Ben Hutchings wrote: > > The first patch in the series restores the module aliases to m25p80, but > > it does so by duplicating the list of names. This should be suitable > > for stable, but it isn't viable in the longer term. > > > > The following patches change the spi-nor interface so that this > > duplication is no longer necessary. This includes removing > > spi_nor::read_id, but it could be re-added after this with a different > > interface, e.g. returning a flash_info structure (which would need to be > > defined in spi_nor.h). > > Note that these patch are: > - Based on your 'testing' branch Which testing branch? These two are the only official repos for MTD: git git://git.infradead.org/linux-mtd.git git git://git.infradead.org/l2-mtd.git > - Untested by me, aside from compiling and checking that m25p80 has the > expected module aliases Brian From computersforpeace at gmail.com Sun Sep 28 15:21:50 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sun, 28 Sep 2014 15:21:50 -0700 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <1410714670.3040.39.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> Message-ID: <20140928222150.GC3248@norris-Latitude-E6410> + Rafal Rafal has been looking at the same area of code. I'd really like to get this patch into 3.18 if possible, so the more eyes the better. On Sun, Sep 14, 2014 at 06:11:10PM +0100, Ben Hutchings wrote: > m25p80's device ID table is now spi_nor_ids, defined in spi-nor. The > MODULE_DEVICE_TABLE() macro doesn't work with extern definitions, but > its use was also removed at the same time. Now if m25p80 is built as > a module it doesn't get the necessary aliases to be loaded > automatically. > > A clean solution to this will involve defining the list of device > IDs in spi-nor.h and removing struct spi_device_id from the spi-nor > API, but this is quite a large change. > > As a quick fix suitable for stable, copy the device IDs back into > m25p80. > > Fixes: 03e296f613af ("mtd: m25p80: use the SPI nor framework") > Cc: stable # 3.16 > Signed-off-by: Ben Hutchings > --- > drivers/mtd/devices/m25p80.c | 58 +++++++++++++++++++++++++++++++++++++++++-- > drivers/mtd/spi-nor/spi-nor.c | 5 ++-- > include/linux/mtd/spi-nor.h | 3 +-- > 3 files changed, 59 insertions(+), 7 deletions(-) > > diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c > index ed7e0a1b..3f0fe86 100644 > --- a/drivers/mtd/devices/m25p80.c > +++ b/drivers/mtd/devices/m25p80.c > @@ -196,6 +196,7 @@ static int m25p_probe(struct spi_device *spi) > struct m25p *flash; > struct spi_nor *nor; > enum read_mode mode = SPI_NOR_NORMAL; > + const struct spi_device_id *id; > int ret; > > flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); > @@ -223,7 +224,10 @@ static int m25p_probe(struct spi_device *spi) > mode = SPI_NOR_QUAD; > else if (spi->mode & SPI_RX_DUAL) > mode = SPI_NOR_DUAL; > - ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); > + id = spi_nor_match_id(spi_get_device_id(spi)->name); > + if (WARN_ON(!id)) > + return -ENODEV; I'm not confident this logic is sound. And even if it is sound, does it belong in a patch for stable? You might take a look at Rafal's patch here: http://lists.infradead.org/pipermail/linux-mtd/2014-September/055596.html some of the matching logic is actually done via platform data, and I don't think this check for spi_nor_match_id() will catch it. (Honestly, some of this name-matching / ID-matching stuff confuses me; there is at least one too many ways to choose a flash device for this driver.) > + ret = spi_nor_scan(nor, id, mode); > if (ret) > return ret; > > @@ -245,12 +249,62 @@ static int m25p_remove(struct spi_device *spi) > } > > > +/* > + * XXX This needs to be kept in sync with spi_nor_ids. We can't share > + * it with spi-nor, because if this is built as a module then modpost > + * won't be able to read it and add appropriate aliases. > + */ > +static const struct spi_device_id m25p_ids[] = { > + {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, > + {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, > + {"at26df321"}, {"at45db081d"}, > + {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, > + {"en25q64"}, {"en25qh128"}, {"en25qh256"}, > + {"f25l32pa"}, > + {"mr25h256"}, {"mr25h10"}, > + {"gd25q32"}, {"gd25q64"}, > + {"160s33b"}, {"320s33b"}, {"640s33b"}, > + {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, > + {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, > + {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, > + {"mx66l1g55g"}, > + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, > + {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, > + {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, > + {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, > + {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, > + {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, > + {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, > + {"s25fl016k"}, {"s25fl064k"}, > + {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, > + {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, > + {"sst25wf040"}, > + {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, > + {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, > + {"m25p128"}, {"n25q032"}, > + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, > + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, > + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, > + {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, > + {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, > + {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, > + {"m25px64"}, > + {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, > + {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, > + {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, > + {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, > + {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, > + { }, > +}; > +MODULE_DEVICE_TABLE(spi, m25p_ids); > + > + > static struct spi_driver m25p80_driver = { > .driver = { > .name = "m25p80", > .owner = THIS_MODULE, > }, > - .id_table = spi_nor_ids, > + .id_table = m25p_ids, > .probe = m25p_probe, > .remove = m25p_remove, > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index 03e0ab8..6b1bda2 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -473,7 +473,7 @@ struct flash_info { > * more nor chips. This current list focusses on newer chips, which > * have been converging on command sets which including JEDEC ID. > */ > -const struct spi_device_id spi_nor_ids[] = { > +static const struct spi_device_id spi_nor_ids[] = { > /* Atmel -- some are (confusingly) marketed as "DataFlash" */ > { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, > { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, > @@ -637,7 +637,6 @@ const struct spi_device_id spi_nor_ids[] = { > { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, > { }, > }; > -EXPORT_SYMBOL_GPL(spi_nor_ids); > > static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) > { > @@ -1136,7 +1135,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > } > EXPORT_SYMBOL_GPL(spi_nor_scan); > > -const struct spi_device_id *spi_nor_match_id(char *name) > +const struct spi_device_id *spi_nor_match_id(const char *name) > { > const struct spi_device_id *id = spi_nor_ids; > > diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h > index 9e6294f..5ec84cc 100644 > --- a/include/linux/mtd/spi-nor.h > +++ b/include/linux/mtd/spi-nor.h > @@ -201,7 +201,6 @@ struct spi_nor { > */ > int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > enum read_mode mode); > -extern const struct spi_device_id spi_nor_ids[]; > > /** > * spi_nor_match_id() - find the spi_device_id by the name > @@ -213,6 +212,6 @@ extern const struct spi_device_id spi_nor_ids[]; > * Return: returns the right spi_device_id pointer on success, > * and returns NULL on failure. > */ > -const struct spi_device_id *spi_nor_match_id(char *name); > +const struct spi_device_id *spi_nor_match_id(const char *name); > > #endif > > But aside from that, I think this patch is OK. Brian From marex at denx.de Sun Sep 28 15:43:43 2014 From: marex at denx.de (Marek Vasut) Date: Mon, 29 Sep 2014 00:43:43 +0200 Subject: [PATCH 1/1 v2] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: References: <201409261046.07132.marex@denx.de> Message-ID: <201409290043.43750.marex@denx.de> On Sunday, September 28, 2014 at 03:59:42 AM, bpqw wrote: > For Micron spi norflash,you can enable > Quad spi transfer by clear EVCR(Enhanced > Volatile Configuration Register) Quad I/O > protocol bit. OK, this information is nice and all, but what does this patch do? I can't learn this information from the commit message as it is, can I ? And , the purpose of the commit message is exactly to summarize the change the patch implements. > Signed-off-by: bean huo > --- > v1-v2:modified to that capture wait_till_ready() > return value,if error,directly return its > the value. > > drivers/mtd/spi-nor/spi-nor.c | 46 > +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | > 6 ++++++ > 2 files changed, 52 insertions(+) > > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index b5ad6be..0c3b4fd 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -878,6 +878,45 @@ static int spansion_quad_enable(struct spi_nor *nor) > return 0; > } > > +static int micron_quad_enable(struct spi_nor *nor) > +{ > + int ret, val; > + > + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); > + if (ret < 0) { > + dev_err(nor->dev, "error %d reading EVCR\n", ret); > + return -EINVAL; > + } > + > + write_enable(nor); > + > + /* set EVCR ,enable quad I/O */ > + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; > + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); > + if (ret < 0) { > + dev_err(nor->dev, > + "error while writing EVCR register\n"); > + return -EINVAL; Why not just "return ret;" ? [...] From computersforpeace at gmail.com Sun Sep 28 16:17:14 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Sun, 28 Sep 2014 16:17:14 -0700 Subject: [PATCH V3] mtd: move support for struct flash_platform_data into m25p80 In-Reply-To: <1411936614-28886-1-git-send-email-zajec5@gmail.com> References: <1408194788-10434-1-git-send-email-zajec5@gmail.com> <1411936614-28886-1-git-send-email-zajec5@gmail.com> Message-ID: <20140928231714.GD3248@norris-Latitude-E6410> Hi Rafal, On Sun, Sep 28, 2014 at 10:36:54PM +0200, Rafa? Mi?ecki wrote: > This "type" seems to be an extra hint for m25p80 about the flash. Some > archs register flash_platform_data with "name" set to "m25p80" and then > with a real flash name set in "type". It seems to be a trick specific > to the m25p80 so let's move it out of spi-nor. > Btw switch to the spi_nor_match_id instead of iterating spi_nor_ids. > > Signed-off-by: Rafa? Mi?ecki > --- > V2: Comment usage of data->type > Set mtd.name in m25p80 > V3: Fix "respect" spelling in the comment > > Brian: do you think this comment about "name" and "type" is clear > enough now? If so, could you pick this patch, please? I think the comments and patch look good now. Unfortunately, I've delayed this a bit long, and in the meantime, we have another issue cropping up here that may cause conflicts: http://lists.infradead.org/pipermail/linux-mtd/2014-September/055323.html But anyway, I think his patch set is not quite ready, and this patch may get us in a better position to resolve his, so: Applied to l2-mtd.git. Ben, please base your work on l2-mtd.git/master. If we need to get your patch #1 into stable, then we can mark this patch as a dependency, I think. Brian > --- > drivers/mtd/devices/m25p80.c | 22 ++++++++++++++++++++-- > drivers/mtd/spi-nor/spi-nor.c | 28 +--------------------------- > 2 files changed, 21 insertions(+), 29 deletions(-) > > diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c > index ed7e0a1b..dcda628 100644 > --- a/drivers/mtd/devices/m25p80.c > +++ b/drivers/mtd/devices/m25p80.c > @@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi) > { > struct mtd_part_parser_data ppdata; > struct flash_platform_data *data; > + const struct spi_device_id *id = NULL; > struct m25p *flash; > struct spi_nor *nor; > enum read_mode mode = SPI_NOR_NORMAL; > int ret; > > + data = dev_get_platdata(&spi->dev); > + > flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); > if (!flash) > return -ENOMEM; > @@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi) > mode = SPI_NOR_QUAD; > else if (spi->mode & SPI_RX_DUAL) > mode = SPI_NOR_DUAL; > - ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); > + > + if (data && data->name) > + flash->mtd.name = data->name; > + > + /* For some (historical?) reason many platforms provide two different > + * names in flash_platform_data: "name" and "type". Quite often name is > + * set to "m25p80" and then "type" provides a real chip name. > + * If that's the case, respect "type" and ignore a "name". > + */ > + if (data && data->type) > + id = spi_nor_match_id(data->type); > + > + /* If we didn't get name from platform, simply use "modalias". */ > + if (!id) > + id = spi_get_device_id(spi); > + > + ret = spi_nor_scan(nor, id, mode); > if (ret) > return ret; > > - data = dev_get_platdata(&spi->dev); > ppdata.of_node = spi->dev.of_node; > > return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, > diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c > index 11459f6..ae16aa2 100644 > --- a/drivers/mtd/spi-nor/spi-nor.c > +++ b/drivers/mtd/spi-nor/spi-nor.c > @@ -915,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > enum read_mode mode) > { > struct flash_info *info; > - struct flash_platform_data *data; > struct device *dev = nor->dev; > struct mtd_info *mtd = nor->mtd; > struct device_node *np = dev->of_node; > @@ -926,28 +925,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > if (ret) > return ret; > > - /* Platform data helps sort out which chip type we have, as > - * well as how this board partitions it. If we don't have > - * a chip ID, try the JEDEC id commands; they'll work for most > - * newer chips, even if we don't recognize the particular chip. > - */ > - data = dev_get_platdata(dev); > - if (data && data->type) { > - const struct spi_device_id *plat_id; > - > - for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { > - plat_id = &spi_nor_ids[i]; > - if (strcmp(data->type, plat_id->name)) > - continue; > - break; > - } > - > - if (i < ARRAY_SIZE(spi_nor_ids) - 1) > - id = plat_id; > - else > - dev_warn(dev, "unrecognized id %s\n", data->type); > - } > - > info = (void *)id->driver_data; > > if (info->jedec_id) { > @@ -985,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, > write_sr(nor, 0); > } > > - if (data && data->name) > - mtd->name = data->name; > - else > + if (!mtd->name) > mtd->name = dev_name(dev); > - > mtd->type = MTD_NORFLASH; > mtd->writesize = 1; > mtd->flags = MTD_CAP_NORFLASH; From josh at joshtriplett.org Sun Sep 28 17:02:44 2014 From: josh at joshtriplett.org (Josh Triplett) Date: Sun, 28 Sep 2014 17:02:44 -0700 Subject: [PATCH V2 linux-next] jffs2: fix sparse warning: unexpected unlock In-Reply-To: <1411932392-7751-1-git-send-email-fabf@skynet.be> References: <1411932392-7751-1-git-send-email-fabf@skynet.be> Message-ID: <20140929000243.GA1353@thin> On Sun, Sep 28, 2014 at 09:26:32PM +0200, Fabian Frederick wrote: > fs/jffs2/summary.c:846:5: warning: context imbalance in 'jffs2_sum_write_sumnode' - unexpected unlock > > Suggested-by: Brian Norris > Suggested-by: Josh Triplett > Signed-off-by: Fabian Frederick Reviewed-by: Josh Triplett > V2: use __must_hold instead of __releases / __acquires > (suggested by Brian Norris and Josh Triplett) > > fs/jffs2/summary.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c > index c522d09..bc53854 100644 > --- a/fs/jffs2/summary.c > +++ b/fs/jffs2/summary.c > @@ -844,6 +844,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock > /* Write out summary information - called from jffs2_do_reserve_space */ > > int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) > + __must_hold(&c->erase_completion_block) > { > int datasize, infosize, padsize; > struct jffs2_eraseblock *jeb; > -- > 1.9.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-sparse" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html From bpqw at micron.com Sun Sep 28 17:30:04 2014 From: bpqw at micron.com (bpqw) Date: Mon, 29 Sep 2014 00:30:04 +0000 Subject: [PATCH 1/1 v2] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: <201409290043.43750.marex@denx.de> References: <201409261046.07132.marex@denx.de> <201409290043.43750.marex@denx.de> Message-ID: >> For Micron spi norflash,you can enable Quad spi transfer by clear >> EVCR(Enhanced Volatile Configuration Register) Quad I/O protocol bit. > >OK, this information is nice and all, but what does this patch do? I can't learn this information from the commit message as it is, can I ? >And , the purpose of the commit message is exactly to summarize the change the patch implements. you don't understand what purpose of this patch! just as subject and commit message described, it is for enable Micron Quad spi transfer mode.do you read the spi-nor.c file? please pay attention to the set_quad_mode() function.by the way,I can add more commit message for it,but I think it is redundant,don't need. >> +static int micron_quad_enable(struct spi_nor *nor) { >> + int ret, val; >> + >> + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); >> + if (ret < 0) { >> + dev_err(nor->dev, "error %d reading EVCR\n", ret); >> + return -EINVAL; >> + } >> + >> + write_enable(nor); >> + >> + /* set EVCR ,enable quad I/O */ >> + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; >> + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); >> + if (ret < 0) { >> + dev_err(nor->dev, >> + "error while writing EVCR register\n"); >> + return -EINVAL; >Why not just "return ret;" ? >[...] Ok,this is good,I will modify it in the next patch version.thanks. From Iwo.Mergler at netcommwireless.com Sun Sep 28 18:22:11 2014 From: Iwo.Mergler at netcommwireless.com (Iwo Mergler) Date: Mon, 29 Sep 2014 11:22:11 +1000 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: <20140911143616.3ebb025a@bbrezillon> References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain>, <20140911143616.3ebb025a@bbrezillon> Message-ID: On Thu, 11 Sep 2014 22:36:16 +1000 Boris BREZILLON wrote: > > Well, I don't know about freescale specific tools, but at least I have > an example with mtd_nandbiterrs module. > This module is assuming it can write only the data part of a NAND page > without modifying the OOB area (see [1]), which in GPMI controller > case is impossible because raw write function store the data as if > there were no specific scheme, while there is one: > (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). > Hi Boris, just as an aside, only the incremental bit errors test in nandbiterrs positively requires raw data write. The overwrite test (re-write the same page data repeatedly without erase), only uses raw access because I was lazy. A normal ECC write would do just as well. Best regards, Iwo ______________________________________________________________________ This communication contains information which may be confidential or privileged. The information is intended solely for the use of the individual or entity named above. If you are not the intended recipient, be aware that any disclosure, copying, distribution or use of the contents of this information is prohibited. If you have received this communication in error, please notify me by telephone immediately. ______________________________________________________________________ From wang.bo116 at zte.com.cn Sun Sep 28 18:38:43 2014 From: wang.bo116 at zte.com.cn (wang.bo116 at zte.com.cn) Date: Mon, 29 Sep 2014 09:38:43 +0800 Subject: JFFS2 when rename a directory there maybe occur hard link between directories Message-ID: Hi?everyone Our kernel version is 2.6.21.7, and we update the jffs2 part to version 3.16.3, our machine has 256MB nor flash, and we use 236MB for jffs2.(CONFIG_JFFS2_SUMMARY = y) We do the test like this. 1. create some directories under root, like /SW1, /SW2, 2. create directory under root, named old, the dirent is /old 3. mv(rename) /SW1 /SW2 under /old then now is /old/SW1 /old/SW2 , then do some other things but don't touch /old/SW1 /old/SW2 4. mv(rename) /old/SW1 /old/SW2 under root, so there is /SW1 /SW2, and the /old is empty 5. delete(remove) /old 6. reboot Now, after the machine rebooted, we found /SW1 and /old/SW1 become hardlink, but /old/SW1 shouldn't exist. So we catched some logs. ---------------------------------------------------------------- ino = 0, name = SW1, version = 6, pino = 71, ofs = 0x056803e4 ino = 0, name = SW2, version = 7, pino = 71, ofs = 0x0568043c ino = 2, name = SW1, version = 2, pino = 71, ofs = 0x0e6186e8 ino = 3, name = SW2, version = 3, pino = 71, ofs = 0x0e618740 ino = 0, name = old, version = 298, pino = 1, ofs = 0x0e6185c4 ino = 71, name = old, version = 299, pino = 1, ofs = 0x0e6186bc ----------------------------------------------------------------- from the log, we can see the old(ino 71) has deleted ,and SW1 SW2 seem good, they all have their deletion dirent, everything's ok. Then,we reboot the machine and also catched some logs. ----------------------------------------------------------------- ino = 2, name = SW1, version = 2, pino = 71, ofs = 0x0e6186e8 ino = 3, name = SW2, version = 3, pino = 71, ofs = 0x0e618740 child dir "SW1" (ino #2) of dir ino #71 appears to be a hard link child dir "SW2" (ino #3) of dir ino #71 appears to be a hard link ----------------------------------------------------------------- /old/SW1 and /old/SW2 's deletion dirent has gone, and /SW1 <-> /old/SW1 /SW2 <->/old/SW2 become hard link. We found, after reboot , during mount JFFS2, in jffs2_build_remove_unlinked_inode static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds) { ... while (raw != (void *)ic) { struct jffs2_raw_node_ref *next = raw->next_in_ino; dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw)); jffs2_mark_node_obsolete(c, raw); raw = next; } ... } Because /old/SW1 and /old/SW1 deletion dirent still exist in the flash, during scan, could create its parent's inode cache. /old has deleted,then should do jffs2_build_remove_unlinked_inode, and make every under /old to obsolete, include /old/SW1's deletion dirent.If the deletion dirent's eraseblock is totally dirty, then will erase it.So, the obsolete /old/SW1 is still in flash. /old/SW1 is obsoleted but just record in ram, if we reboot before the obsoleted /old/SW1 erased, after reboot, there will be a hard link between /old/SW1 and /SW1. Then, /old/SW1 and /SW1 share inode,but in jffs2_build_remove_unlinked_inode will make /old/SW1's inode obsolete.So, if we want to enter /SW1, we'll found /SW1 has none valid nodes and got -EIO. /SW1 dirent can not access. Thanks! Best Regards From zajec5 at gmail.com Sun Sep 28 23:36:46 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Mon, 29 Sep 2014 08:36:46 +0200 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <20140928222150.GC3248@norris-Latitude-E6410> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> Message-ID: On 29 September 2014 00:21, Brian Norris wrote: > + Rafal > > Rafal has been looking at the same area of code. I'd really like to get > this patch into 3.18 if possible, so the more eyes the better. Thanks Brian. I took me a while to follow this issue, too bad I wasn't subscribed to the ML earlier. Let me try to sum it up. 1) The main urgent issue: broken auto-loading Tracked in the thread: http://www.spinics.net/lists/linux-spi/msg01726.html Problem: m25p80.c references spi_nor_ids (from external file) Short-term solution: duplicate IDs in the m25p80.c Ben: just like Brian, I think the patch like this one ( [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 ) is the way to go. However few comments: a) I don't see why you modify m25p_probe in it. b) I don't think the described clean solution (you described it in the commit message): > A clean solution to this will involve defining the list of device > IDs in spi-nor.h and removing struct spi_device_id from the spi-nor > API, but this is quite a large change. is the correct one. I think there should be a single string to trigger m25p80 load and the rest should be handled using JEDEC, with some workarounds for incompatible devices only. One thing I wonder about is sense of pushing this patch to the Linus's tree. Do you think we could prepare a real fix for Linus and leave this patch for stable@ only? I'm far from being an expert on such things, just asking. 2) On going cleanups It seems there are at least 2 ppl (me, Ben) working on some cleanups independently. a) There is (l2-mtd pushed) patch moving flash_platform_data into m25p80: https://patchwork.ozlabs.org/patch/394219/ b) Removing spi_nor::read_id https://patchwork.ozlabs.org/patch/389073/ Ben: I think this one has a NACK from me, because I'm going to use custom read_id in the bcm53xxspiflash driver. See following thread for bcm53xxspiflash description: http://comments.gmane.org/gmane.linux.drivers.mtd/54578 Initial commit (it uses read_id): https://patchwork.ozlabs.org/patch/381902/ c) Obsoleting spi_device_id It seems we both were working on the same thing, me slightly slower however ;) https://patchwork.ozlabs.org/patch/377917/ https://patchwork.ozlabs.org/patch/389074/ https://patchwork.ozlabs.org/patch/389075/ I still have to review calmly your changes, but they need to be rebased anyway. d) Cleaning m25p80 https://patchwork.ozlabs.org/patch/389076/ Ben: As said before, I think we should do smarter in the m25p80. We should get rid of all that duplicated strings. From josh.wu at atmel.com Mon Sep 29 01:36:03 2014 From: josh.wu at atmel.com (Josh Wu) Date: Mon, 29 Sep 2014 16:36:03 +0800 Subject: [PATCH] MAINTAINERS: add atmel nand driver maintainer entry Message-ID: <1411979763-1449-1-git-send-email-josh.wu@atmel.com> This patch adds an entry in MAINTAINERS file for ATMEL nand driver. Signed-off-by: Josh Wu --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3705430..1bdf3bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1698,6 +1698,12 @@ M: Nicolas Ferre S: Supported F: drivers/net/ethernet/cadence/ +ATMEL NAND DRIVER +M: Josh Wu +L: linux-mtd at lists.infradead.org +S: Supported +F: drivers/mtd/nand/atmel_nand* + ATMEL SPI DRIVER M: Nicolas Ferre S: Supported -- 1.9.1 From zajec5 at gmail.com Mon Sep 29 01:37:20 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Mon, 29 Sep 2014 10:37:20 +0200 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <20140928222150.GC3248@norris-Latitude-E6410> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> Message-ID: On 29 September 2014 00:21, Brian Norris wrote: > (Honestly, some of this name-matching / ID-matching stuff confuses me; > there is at least one too many ways to choose a flash device for this > driver.) It's not that complex once you track it. It's just ugly to tracks because of different structs, function calls and code locations. 1) All m25p80 users (arch code, SPI drivers, etc.) register struct spi_board_info that contains "modalias". It it used to match a driver to load. In most (?) cases modalias is set to "m25p80" 2) Some m25p80 users decided to put a flash device name (e.g. "at25fs010", "mx25l2005a", "m25p05", "w25x10") as modalias of the struct spi_board_info. I think they are affected by the recent m25p80 change to use spi-not framework. 3) Other m25p80 users provide flash device name (e.g. "at25fs010", "mx25l2005a", "m25p05", "w25x10") using platform_data in the struct spi_board_info. It points to the struct flash_platform_data with "name" and "type" properties. It seems to me that "name" is never used. My idea for fixing this: 1) Always use "m25p80" modalias (for m25p80 compatible hw). This will make m25p80 driver work without this huge id_table 2) Do not use "name" nor "type" in the struct flash_platform_data if the flash supports JEDEC 3) If the flash is m25p80 compatible, but doesn't support JEDEC, let's use "type" to let m25p80 work. From nicolas.ferre at atmel.com Mon Sep 29 01:38:28 2014 From: nicolas.ferre at atmel.com (Nicolas Ferre) Date: Mon, 29 Sep 2014 10:38:28 +0200 Subject: [PATCH] MAINTAINERS: add atmel nand driver maintainer entry In-Reply-To: <1411979763-1449-1-git-send-email-josh.wu@atmel.com> References: <1411979763-1449-1-git-send-email-josh.wu@atmel.com> Message-ID: <54291A84.5080109@atmel.com> On 29/09/2014 10:36, Josh Wu : > This patch adds an entry in MAINTAINERS file for ATMEL nand driver. > > Signed-off-by: Josh Wu Acked-by: Nicolas Ferre > --- > MAINTAINERS | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/MAINTAINERS b/MAINTAINERS > index 3705430..1bdf3bf 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -1698,6 +1698,12 @@ M: Nicolas Ferre > S: Supported > F: drivers/net/ethernet/cadence/ > > +ATMEL NAND DRIVER > +M: Josh Wu > +L: linux-mtd at lists.infradead.org > +S: Supported > +F: drivers/mtd/nand/atmel_nand* > + > ATMEL SPI DRIVER > M: Nicolas Ferre > S: Supported > -- Nicolas Ferre From alexander.stein at systec-electronic.com Mon Sep 29 02:43:15 2014 From: alexander.stein at systec-electronic.com (Alexander Stein) Date: Mon, 29 Sep 2014 11:43:15 +0200 Subject: [PATCH 1/1 RFC] mtd: spi-nor: Fix ID for Spansion s70fl01gs Message-ID: <1411983795-6444-1-git-send-email-alexander.stein@systec-electronic.com> The Device ID is the same as with s25fl512s as stated in datasheet: 6. Identification (RDID) The Read Identification (RDID) command outputs the one-byte manufacturer identification, followed by the two-byte device identification and the bytes for the Common Flash Interface (CFI) tables. Each die of the FL01GS dual die stack will have identical identification data as the FL512S die, with the exception of the CFI data at byte 27h, as shown in Table 6.1. If DT is configured with 's70fl01gs' I get the following warnings (on a 3.12 kernel, but that shouldn't matter): m25p80 spi32766.0: found s25fl512s, expected s70fl01gs m25p80 spi32766.1: found s25fl512s, expected s70fl01gs Signed-off-by: Alexander Stein --- I am aware that there is now an ID conflict. But this is due that the s70fl01gs simply uses two separate chips. How to handle that? drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..0c34968 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -551,7 +551,7 @@ const struct spi_device_id spi_nor_ids[] = { { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s70fl01gs", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, -- 1.8.5.5 From zajec5 at gmail.com Mon Sep 29 02:47:53 2014 From: zajec5 at gmail.com (=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?=) Date: Mon, 29 Sep 2014 11:47:53 +0200 Subject: [PATCH 1/2] mtd: m25p80: get rid of spi_get_device_id Message-ID: <1411984074-3850-1-git-send-email-zajec5@gmail.com> This simplifies the way we use spi_nor framework and will allow us to drop spi_nor_match_id. Signed-off-by: Rafa? Mi?ecki --- drivers/mtd/devices/m25p80.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dcda628..822209d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -197,6 +197,7 @@ static int m25p_probe(struct spi_device *spi) struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; + char *flash_name = NULL; int ret; data = dev_get_platdata(&spi->dev); @@ -236,12 +237,11 @@ static int m25p_probe(struct spi_device *spi) * If that's the case, respect "type" and ignore a "name". */ if (data && data->type) - id = spi_nor_match_id(data->type); - - /* If we didn't get name from platform, simply use "modalias". */ - if (!id) - id = spi_get_device_id(spi); + flash_name = data->type; + else + flash_name = spi->modalias; + id = spi_nor_match_id(flash_name); ret = spi_nor_scan(nor, id, mode); if (ret) return ret; -- 1.8.4.5 From zajec5 at gmail.com Mon Sep 29 02:47:54 2014 From: zajec5 at gmail.com (=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?=) Date: Mon, 29 Sep 2014 11:47:54 +0200 Subject: [PATCH 2/2] mtd: spi-nor: make spi_nor_scan() take a chip type name, not spi_device_id In-Reply-To: <1411984074-3850-1-git-send-email-zajec5@gmail.com> References: <1411984074-3850-1-git-send-email-zajec5@gmail.com> Message-ID: <1411984074-3850-2-git-send-email-zajec5@gmail.com> From: Ben Hutchings Drivers currently call spi_nor_match_id() and then spi_nor_scan(). This adds a dependency on struct spi_device_id which we want to avoid. Make spi_nor_scan() do it for them. Signed-off-by: Ben Hutchings Signed-off-by: Rafa? Mi?ecki --- drivers/mtd/devices/m25p80.c | 4 +--- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +------ drivers/mtd/spi-nor/spi-nor.c | 13 +++++++++---- include/linux/mtd/spi-nor.h | 20 +++----------------- 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 822209d..bd5e4c6 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -193,7 +193,6 @@ static int m25p_probe(struct spi_device *spi) { struct mtd_part_parser_data ppdata; struct flash_platform_data *data; - const struct spi_device_id *id = NULL; struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; @@ -241,8 +240,7 @@ static int m25p_probe(struct spi_device *spi) else flash_name = spi->modalias; - id = spi_nor_match_id(flash_name); - ret = spi_nor_scan(nor, id, mode); + ret = spi_nor_scan(nor, flash_name, mode); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 8d659a2..d5269a2 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -881,7 +881,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { - const struct spi_device_id *id; char modalias[40]; /* skip the holes */ @@ -909,10 +908,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) goto map_failed; - id = spi_nor_match_id(modalias); - if (!id) - goto map_failed; - ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) @@ -921,7 +916,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); - ret = spi_nor_scan(nor, id, SPI_NOR_QUAD); + ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) goto map_failed; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index ae16aa2..5c8e399 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,6 +28,8 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) +static const struct spi_device_id *spi_nor_match_id(const char *name); + /* * Read the status register, returning its value in the location * Return the status register value. @@ -911,9 +913,9 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode) +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { + const struct spi_device_id *id = NULL; struct flash_info *info; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; @@ -925,6 +927,10 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (ret) return ret; + id = spi_nor_match_id(name); + if (!id) + return -ENOENT; + info = (void *)id->driver_data; if (info->jedec_id) { @@ -1113,7 +1119,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(char *name) +static const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; @@ -1124,7 +1130,6 @@ const struct spi_device_id *spi_nor_match_id(char *name) } return NULL; } -EXPORT_SYMBOL_GPL(spi_nor_match_id); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..a5a7a08 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -187,32 +187,18 @@ struct spi_nor { /** * spi_nor_scan() - scan the SPI NOR * @nor: the spi_nor structure - * @id: the spi_device_id provided by the driver + * @name: the chip type name * @mode: the read mode supported by the driver * * The drivers can use this fuction to scan the SPI NOR. * In the scanning, it will try to get all the necessary information to * fill the mtd_info{} and the spi_nor{}. * - * The board may assigns a spi_device_id with @id which be used to compared with - * the spi_device_id detected by the scanning. + * The chip type name can be provided through the @name parameter. * * Return: 0 for success, others for failure. */ -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode); +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); extern const struct spi_device_id spi_nor_ids[]; -/** - * spi_nor_match_id() - find the spi_device_id by the name - * @name: the name of the spi_device_id - * - * The drivers use this function to find the spi_device_id - * specified by the @name. - * - * Return: returns the right spi_device_id pointer on success, - * and returns NULL on failure. - */ -const struct spi_device_id *spi_nor_match_id(char *name); - #endif -- 1.8.4.5 From zajec5 at gmail.com Mon Sep 29 02:53:14 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Mon, 29 Sep 2014 11:53:14 +0200 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> Message-ID: On 29 September 2014 08:36, Rafa? Mi?ecki wrote: > 1) The main urgent issue: broken auto-loading > Tracked in the thread: http://www.spinics.net/lists/linux-spi/msg01726.html > Problem: m25p80.c references spi_nor_ids (from external file) > Short-term solution: duplicate IDs in the m25p80.c > > Ben: just like Brian, I think the patch like this one ( > [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 > ) is the way to go. However few comments: I started wondering... would this be possible to fix all m25p80 users instead? Make them always specify modalias as "m25p80" and then provide platform_data if needed? Has anyone checked in how many places we use "wrong" (or should I say "weird") modaliases? I guess some would need to grep kernel for all possible names. From zajec5 at gmail.com Mon Sep 29 03:25:05 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Mon, 29 Sep 2014 12:25:05 +0200 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> Message-ID: On 29 September 2014 11:53, Rafa? Mi?ecki wrote: > On 29 September 2014 08:36, Rafa? Mi?ecki wrote: >> 1) The main urgent issue: broken auto-loading >> Tracked in the thread: http://www.spinics.net/lists/linux-spi/msg01726.html >> Problem: m25p80.c references spi_nor_ids (from external file) >> Short-term solution: duplicate IDs in the m25p80.c >> >> Ben: just like Brian, I think the patch like this one ( >> [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 >> ) is the way to go. However few comments: > > I started wondering... would this be possible to fix all m25p80 users > instead? Make them always specify modalias as "m25p80" and then > provide platform_data if needed? > > Has anyone checked in how many places we use "wrong" (or should I say > "weird") modaliases? I guess some would need to grep kernel for all > possible names. I did some (e)grepping, it seems we have: 1) Only 6 references (modalias) in arch/mips/ath79/ 2) About 57 references (compatible) in arch/arm/boot/dts/ 3) About 32 references (compatible) in arch/powerpc/boot/dts/ However it seems there is no way to provide platform_data in Device Tree files. So we have to support compatible (modalias) for now I guess. The list (if someone would like to check) of used names in archs: m25p128 m25p16 m25p32 m25p40 m25p64 mx25l12805d mx25l1606e mx25l25635e mx25l4005a mx25l6405d mx66l51235l n25q128a11 n25q128a13 n25q512a s25fl008k s25fl256s1 s25fl512s s25sl064a s25sl12801 sst25vf016b sst25vf032b sst25vf040b sst25wf040 w25q128 w25q256 w25q32 w25q32dw w25q80bl w25x80 -- Rafa? From kiran.padwal21 at gmail.com Mon Sep 29 03:50:29 2014 From: kiran.padwal21 at gmail.com (Kiran Padwal) Date: Mon, 29 Sep 2014 16:20:29 +0530 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> Message-ID: <54293975.9040402@gmail.com> Hi Tanya, On Sunday 28 September 2014 12:06 PM, Tanya Brokhman wrote: > If there is more then one UBI device mounted, there is no way to > distinguish between messages from different UBI devices. > Add device number to all ubi layer message types. > > > Signed-off-by: Tanya Brokhman > > --- > drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- > drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- > drivers/mtd/ubi/cdev.c | 37 +++++----- > drivers/mtd/ubi/debug.c | 9 +-- > drivers/mtd/ubi/eba.c | 54 +++++++------- > drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ > drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- > drivers/mtd/ubi/kapi.c | 6 +- > drivers/mtd/ubi/misc.c | 6 +- > drivers/mtd/ubi/ubi.h | 13 ++-- > drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- > drivers/mtd/ubi/vtbl.c | 54 ++++++++------ > drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- > 13 files changed, 521 insertions(+), 374 deletions(-) Compilation breaks while I try to compile with this patch. May be you need to update remaining ubi layer messages also. Thanks, --Kiran From richard at nod.at Mon Sep 29 05:01:05 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 29 Sep 2014 14:01:05 +0200 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <54293975.9040402@gmail.com> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <54293975.9040402@gmail.com> Message-ID: <54294A01.8070505@nod.at> Am 29.09.2014 12:50, schrieb Kiran Padwal: > Hi Tanya, > > On Sunday 28 September 2014 12:06 PM, Tanya Brokhman wrote: >> If there is more then one UBI device mounted, there is no way to >> distinguish between messages from different UBI devices. >> Add device number to all ubi layer message types. >> >> >> Signed-off-by: Tanya Brokhman >> >> --- >> drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- >> drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- >> drivers/mtd/ubi/cdev.c | 37 +++++----- >> drivers/mtd/ubi/debug.c | 9 +-- >> drivers/mtd/ubi/eba.c | 54 +++++++------- >> drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ >> drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- >> drivers/mtd/ubi/kapi.c | 6 +- >> drivers/mtd/ubi/misc.c | 6 +- >> drivers/mtd/ubi/ubi.h | 13 ++-- >> drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- >> drivers/mtd/ubi/vtbl.c | 54 ++++++++------ >> drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- >> 13 files changed, 521 insertions(+), 374 deletions(-) > > Compilation breaks while I try to compile with this patch. > May be you need to update remaining ubi layer messages also. Please always share the errors you face. Maybe you have a different config. Thanks, //richard From zajec5 at gmail.com Mon Sep 29 05:30:53 2014 From: zajec5 at gmail.com (=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?=) Date: Mon, 29 Sep 2014 14:30:53 +0200 Subject: [PATCH] ARM: don't set unused name in struct flash_platform_data Message-ID: <1411993853-6309-1-git-send-email-zajec5@gmail.com> Loading correct SPI driver (m25p80) is handled using modalias from the struct spi_board_info. There is no point of setting name in the platform_data, m25p80 ignores it anyway. Signed-off-by: Rafa? Mi?ecki --- arch/arm/mach-davinci/board-da830-evm.c | 1 - arch/arm/mach-davinci/board-da850-evm.c | 1 - arch/arm/mach-davinci/board-mityomapl138.c | 1 - arch/arm/mach-shmobile/board-bockw.c | 1 - arch/arm/mach-shmobile/board-koelsch.c | 1 - arch/arm/mach-shmobile/board-lager.c | 1 - arch/arm/mach-w90x900/dev.c | 1 - 7 files changed, 7 deletions(-) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 5623131..263004a 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -567,7 +567,6 @@ static struct mtd_partition da830evm_spiflash_part[] = { }; static struct flash_platform_data da830evm_spiflash_data = { - .name = "m25p80", .parts = da830evm_spiflash_part, .nr_parts = ARRAY_SIZE(da830evm_spiflash_part), .type = "w25x32", diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 234c5bb..721ff2b 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -104,7 +104,6 @@ static struct mtd_partition da850evm_spiflash_part[] = { }; static struct flash_platform_data da850evm_spiflash_data = { - .name = "m25p80", .parts = da850evm_spiflash_part, .nr_parts = ARRAY_SIZE(da850evm_spiflash_part), .type = "m25p64", diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 96fc00a..3c93b65 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -350,7 +350,6 @@ static struct mtd_partition spi_flash_partitions[] = { }; static struct flash_platform_data mityomapl138_spi_flash_data = { - .name = "m25p80", .parts = spi_flash_partitions, .nr_parts = ARRAY_SIZE(spi_flash_partitions), .type = "m24p64", diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index 8a83eb3..e25af56 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -266,7 +266,6 @@ static struct mtd_partition m25p80_spi_flash_partitions[] = { }; static struct flash_platform_data spi_flash_data = { - .name = "m25p80", .type = "s25fl008k", .parts = m25p80_spi_flash_partitions, .nr_parts = ARRAY_SIZE(m25p80_spi_flash_partitions), diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index b7d5bc7..a494a00 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -207,7 +207,6 @@ static struct mtd_partition spi_flash_part[] = { }; static const struct flash_platform_data spi_flash_data = { - .name = "m25p80", .parts = spi_flash_part, .nr_parts = ARRAY_SIZE(spi_flash_part), .type = "s25fl512s", diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index e1d8215..3575731 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -315,7 +315,6 @@ static struct mtd_partition spi_flash_part[] = { }; static const struct flash_platform_data spi_flash_data = { - .name = "m25p80", .parts = spi_flash_part, .nr_parts = ARRAY_SIZE(spi_flash_part), .type = "s25fl512s", diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c index e65a80a..9745a73 100644 --- a/arch/arm/mach-w90x900/dev.c +++ b/arch/arm/mach-w90x900/dev.c @@ -249,7 +249,6 @@ static struct mtd_partition nuc900_spi_flash_partitions[] = { }; static struct flash_platform_data nuc900_spi_flash_data = { - .name = "m25p80", .parts = nuc900_spi_flash_partitions, .nr_parts = ARRAY_SIZE(nuc900_spi_flash_partitions), .type = "w25x16", -- 1.8.4.5 From kiran.padwal at smartplayin.com Mon Sep 29 05:32:37 2014 From: kiran.padwal at smartplayin.com (Kiran Padwal) Date: Mon, 29 Sep 2014 18:02:37 +0530 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <54294A01.8070505@nod.at> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <54293975.9040402@gmail.com> <54294A01.8070505@nod.at> Message-ID: <54295165.4030201@smartplayin.com> On Monday 29 September 2014 05:31 PM, Richard Weinberger wrote: > Am 29.09.2014 12:50, schrieb Kiran Padwal: >> Hi Tanya, >> >> On Sunday 28 September 2014 12:06 PM, Tanya Brokhman wrote: >>> If there is more then one UBI device mounted, there is no way to >>> distinguish between messages from different UBI devices. >>> Add device number to all ubi layer message types. >>> >>> >>> Signed-off-by: Tanya Brokhman >>> >>> --- >>> drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- >>> drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- >>> drivers/mtd/ubi/cdev.c | 37 +++++----- >>> drivers/mtd/ubi/debug.c | 9 +-- >>> drivers/mtd/ubi/eba.c | 54 +++++++------- >>> drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ >>> drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- >>> drivers/mtd/ubi/kapi.c | 6 +- >>> drivers/mtd/ubi/misc.c | 6 +- >>> drivers/mtd/ubi/ubi.h | 13 ++-- >>> drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- >>> drivers/mtd/ubi/vtbl.c | 54 ++++++++------ >>> drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- >>> 13 files changed, 521 insertions(+), 374 deletions(-) >> >> Compilation breaks while I try to compile with this patch. >> May be you need to update remaining ubi layer messages also. > > Please always share the errors you face. > Maybe you have a different config. Sure, I will take care of this next time. Macros have been changed but some instances of older macros still remained, which caused many errors like, drivers/mtd/ubi/build.c: In function ?ubi_init?: drivers/mtd/ubi/build.c:1322:49: error: expected ?)? before ?err? ubi_err("block: cannot initialize, error %d", err); ^ > > Thanks, > //richard > -- > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > From richard at nod.at Mon Sep 29 05:37:08 2014 From: richard at nod.at (Richard Weinberger) Date: Mon, 29 Sep 2014 14:37:08 +0200 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <54295165.4030201@smartplayin.com> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <54293975.9040402@gmail.com> <54294A01.8070505@nod.at> <54295165.4030201@smartplayin.com> Message-ID: <54295274.4020805@nod.at> Am 29.09.2014 14:32, schrieb Kiran Padwal: > On Monday 29 September 2014 05:31 PM, Richard Weinberger wrote: >> Am 29.09.2014 12:50, schrieb Kiran Padwal: >>> Hi Tanya, >>> >>> On Sunday 28 September 2014 12:06 PM, Tanya Brokhman wrote: >>>> If there is more then one UBI device mounted, there is no way to >>>> distinguish between messages from different UBI devices. >>>> Add device number to all ubi layer message types. >>>> >>>> >>>> Signed-off-by: Tanya Brokhman >>>> >>>> --- >>>> drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- >>>> drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- >>>> drivers/mtd/ubi/cdev.c | 37 +++++----- >>>> drivers/mtd/ubi/debug.c | 9 +-- >>>> drivers/mtd/ubi/eba.c | 54 +++++++------- >>>> drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ >>>> drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- >>>> drivers/mtd/ubi/kapi.c | 6 +- >>>> drivers/mtd/ubi/misc.c | 6 +- >>>> drivers/mtd/ubi/ubi.h | 13 ++-- >>>> drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- >>>> drivers/mtd/ubi/vtbl.c | 54 ++++++++------ >>>> drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- >>>> 13 files changed, 521 insertions(+), 374 deletions(-) >>> >>> Compilation breaks while I try to compile with this patch. >>> May be you need to update remaining ubi layer messages also. >> >> Please always share the errors you face. >> Maybe you have a different config. > > Sure, I will take care of this next time. > > Macros have been changed but some instances of older macros still remained, which caused many errors like, > > drivers/mtd/ubi/build.c: In function ?ubi_init?: > drivers/mtd/ubi/build.c:1322:49: error: expected ?)? before ?err? > ubi_err("block: cannot initialize, error %d", err); Ohh. :( Tanya, did you test your patch? Thanks, //richard From zajec5 at gmail.com Mon Sep 29 06:59:59 2014 From: zajec5 at gmail.com (=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?=) Date: Mon, 29 Sep 2014 15:59:59 +0200 Subject: [PATCH] blackfin: don't set unused name in struct flash_platform_data Message-ID: <1411999199-7390-1-git-send-email-zajec5@gmail.com> Loading correct SPI driver (m25p80) is handled using modalias from the struct spi_board_info. There is no point of setting name in this platform_data, m25p80 ignores it anyway. Signed-off-by: Rafa? Mi?ecki --- arch/blackfin/mach-bf518/boards/ezbrd.c | 1 - arch/blackfin/mach-bf518/boards/tcm-bf518.c | 1 - arch/blackfin/mach-bf527/boards/ad7160eval.c | 1 - arch/blackfin/mach-bf527/boards/cm_bf527.c | 1 - arch/blackfin/mach-bf527/boards/ezbrd.c | 1 - arch/blackfin/mach-bf527/boards/ezkit.c | 1 - arch/blackfin/mach-bf527/boards/tll6527m.c | 1 - arch/blackfin/mach-bf533/boards/H8606.c | 1 - arch/blackfin/mach-bf533/boards/blackstamp.c | 1 - arch/blackfin/mach-bf533/boards/cm_bf533.c | 1 - arch/blackfin/mach-bf533/boards/ezkit.c | 1 - arch/blackfin/mach-bf533/boards/stamp.c | 1 - arch/blackfin/mach-bf537/boards/cm_bf537e.c | 1 - arch/blackfin/mach-bf537/boards/cm_bf537u.c | 1 - arch/blackfin/mach-bf537/boards/minotaur.c | 1 - arch/blackfin/mach-bf537/boards/pnav10.c | 1 - arch/blackfin/mach-bf537/boards/stamp.c | 1 - arch/blackfin/mach-bf537/boards/tcm_bf537.c | 1 - arch/blackfin/mach-bf538/boards/ezkit.c | 1 - arch/blackfin/mach-bf548/boards/cm_bf548.c | 1 - arch/blackfin/mach-bf548/boards/ezkit.c | 1 - arch/blackfin/mach-bf561/boards/cm_bf561.c | 1 - arch/blackfin/mach-bf609/boards/ezkit.c | 1 - 23 files changed, 23 deletions(-) diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c index d022112..e12e883 100644 --- a/arch/blackfin/mach-bf518/boards/ezbrd.c +++ b/arch/blackfin/mach-bf518/boards/ezbrd.c @@ -180,7 +180,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf518/boards/tcm-bf518.c b/arch/blackfin/mach-bf518/boards/tcm-bf518.c index 240d5cb..c304134 100644 --- a/arch/blackfin/mach-bf518/boards/tcm-bf518.c +++ b/arch/blackfin/mach-bf518/boards/tcm-bf518.c @@ -128,7 +128,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf527/boards/ad7160eval.c b/arch/blackfin/mach-bf527/boards/ad7160eval.c index 00b3eb4..98ad4f9 100644 --- a/arch/blackfin/mach-bf527/boards/ad7160eval.c +++ b/arch/blackfin/mach-bf527/boards/ad7160eval.c @@ -256,7 +256,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c index 4e4f8b6..b24ceda 100644 --- a/arch/blackfin/mach-bf527/boards/cm_bf527.c +++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c @@ -345,7 +345,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c index 0674fdc..f92c038 100644 --- a/arch/blackfin/mach-bf527/boards/ezbrd.c +++ b/arch/blackfin/mach-bf527/boards/ezbrd.c @@ -244,7 +244,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "sst25wf040", diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c index e7ca793..439cb78 100644 --- a/arch/blackfin/mach-bf527/boards/ezkit.c +++ b/arch/blackfin/mach-bf527/boards/ezkit.c @@ -442,7 +442,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf527/boards/tll6527m.c b/arch/blackfin/mach-bf527/boards/tll6527m.c index 22f876c..7ed6547 100644 --- a/arch/blackfin/mach-bf527/boards/tll6527m.c +++ b/arch/blackfin/mach-bf527/boards/tll6527m.c @@ -304,7 +304,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c index 01300f4..0c8ad43 100644 --- a/arch/blackfin/mach-bf533/boards/H8606.c +++ b/arch/blackfin/mach-bf533/boards/H8606.c @@ -151,7 +151,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf533/boards/blackstamp.c b/arch/blackfin/mach-bf533/boards/blackstamp.c index 0ccf0cf..179155f 100644 --- a/arch/blackfin/mach-bf533/boards/blackstamp.c +++ b/arch/blackfin/mach-bf533/boards/blackstamp.c @@ -94,7 +94,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c index 4ef2fb0..4bf4a89 100644 --- a/arch/blackfin/mach-bf533/boards/cm_bf533.c +++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c @@ -50,7 +50,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c index 3625e9e..5d2f7dd 100644 --- a/arch/blackfin/mach-bf533/boards/ezkit.c +++ b/arch/blackfin/mach-bf533/boards/ezkit.c @@ -201,7 +201,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c index 6ec3a79..8254213 100644 --- a/arch/blackfin/mach-bf533/boards/stamp.c +++ b/arch/blackfin/mach-bf533/boards/stamp.c @@ -167,7 +167,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/arch/blackfin/mach-bf537/boards/cm_bf537e.c index 1e7290e..da69165 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537e.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537e.c @@ -55,7 +55,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/arch/blackfin/mach-bf537/boards/cm_bf537u.c index c7495dc..de05f7d 100644 --- a/arch/blackfin/mach-bf537/boards/cm_bf537u.c +++ b/arch/blackfin/mach-bf537/boards/cm_bf537u.c @@ -55,7 +55,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c index dd7bda0..b2c9938 100644 --- a/arch/blackfin/mach-bf537/boards/minotaur.c +++ b/arch/blackfin/mach-bf537/boards/minotaur.c @@ -149,7 +149,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c index 06a50dd..74d86d1 100644 --- a/arch/blackfin/mach-bf537/boards/pnav10.c +++ b/arch/blackfin/mach-bf537/boards/pnav10.c @@ -175,7 +175,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index d5a4be8..b55355d 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -529,7 +529,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), /* .type = "m25p64", */ diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c index 6b988ad..bf5ec13 100644 --- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c +++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c @@ -55,7 +55,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf538/boards/ezkit.c b/arch/blackfin/mach-bf538/boards/ezkit.c index f4b5274..e09714c 100644 --- a/arch/blackfin/mach-bf538/boards/ezkit.c +++ b/arch/blackfin/mach-bf538/boards/ezkit.c @@ -508,7 +508,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c index 35fcdf8..af5b4a1 100644 --- a/arch/blackfin/mach-bf548/boards/cm_bf548.c +++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c @@ -875,7 +875,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c index a19c151..77ed055 100644 --- a/arch/blackfin/mach-bf548/boards/ezkit.c +++ b/arch/blackfin/mach-bf548/boards/ezkit.c @@ -1061,7 +1061,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p16", diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c index e862f78..89d3990 100644 --- a/arch/blackfin/mach-bf561/boards/cm_bf561.c +++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c @@ -52,7 +52,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "m25p64", diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 2d547b2..c600027 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -758,7 +758,6 @@ static struct mtd_partition bfin_spi_flash_partitions[] = { }; static struct flash_platform_data bfin_spi_flash_data = { - .name = "m25p80", .parts = bfin_spi_flash_partitions, .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions), .type = "w25q32", -- 1.8.4.5 From richard at nod.at Mon Sep 29 15:20:45 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:20:45 +0200 Subject: [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL shutdown In-Reply-To: <1412029248-22454-1-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> Message-ID: <1412029248-22454-2-git-send-email-richard@nod.at> ...otherwise the deferred work might run after datastructures got freed and corrupt memory. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f491713..dc01b1f 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -2029,6 +2029,9 @@ static void protection_queue_destroy(struct ubi_device *ubi) void ubi_wl_close(struct ubi_device *ubi) { dbg_wl("close the WL sub-system"); +#ifdef CONFIG_MTD_UBI_FASTMAP + flush_work(&ubi->fm_work); +#endif cancel_pending(ubi); protection_queue_destroy(ubi); tree_destroy(&ubi->used); -- 2.1.0 From richard at nod.at Mon Sep 29 15:20:44 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:20:44 +0200 Subject: UBI: Fastmap fixes - round one Message-ID: <1412029248-22454-1-git-send-email-richard@nod.at> This is the first set of fastmap fixes for v3.18. I have more in my local queue but these depend on non-trivial fastmap changes I made. As soon they have been fully tested I'll submitt them too. Thanks, //richard [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL [PATCH 2/4] UBI: Fastmap: Calc fastmap size correctly [PATCH 3/4] UBI: Fastmap: Care about the protection queue [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is From richard at nod.at Mon Sep 29 15:20:47 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:20:47 +0200 Subject: [PATCH 3/4] UBI: Fastmap: Care about the protection queue In-Reply-To: <1412029248-22454-1-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> Message-ID: <1412029248-22454-4-git-send-email-richard@nod.at> Fastmap can miss a PEB if it is in the protection queue and not jet in the used tree. Treat every protected PEB as used. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 2b0d8d6..2853a69 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -1195,6 +1195,19 @@ static int ubi_write_fastmap(struct ubi_device *ubi, fm_pos += sizeof(*fec); ubi_assert(fm_pos <= ubi->fm_size); } + + for (i = 0; i < UBI_PROT_QUEUE_LEN; i++) { + list_for_each_entry(wl_e, &ubi->pq[i], u.list) { + fec = (struct ubi_fm_ec *)(fm_raw + fm_pos); + + fec->pnum = cpu_to_be32(wl_e->pnum); + fec->ec = cpu_to_be32(wl_e->ec); + + used_peb_count++; + fm_pos += sizeof(*fec); + ubi_assert(fm_pos <= ubi->fm_size); + } + } fmh->used_peb_count = cpu_to_be32(used_peb_count); for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) { -- 2.1.0 From richard at nod.at Mon Sep 29 15:20:46 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:20:46 +0200 Subject: [PATCH 2/4] UBI: Fastmap: Calc fastmap size correctly In-Reply-To: <1412029248-22454-1-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> Message-ID: <1412029248-22454-3-git-send-email-richard@nod.at> We need to add fm_sb too. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 0431b46..2b0d8d6 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -24,7 +24,8 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi) { size_t size; - size = sizeof(struct ubi_fm_hdr) + \ + size = sizeof(struct ubi_fm_sb) + \ + sizeof(struct ubi_fm_hdr) + \ sizeof(struct ubi_fm_scan_pool) + \ sizeof(struct ubi_fm_scan_pool) + \ (ubi->peb_count * sizeof(struct ubi_fm_ec)) + \ -- 2.1.0 From richard at nod.at Mon Sep 29 15:20:48 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:20:48 +0200 Subject: [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is scheduled In-Reply-To: <1412029248-22454-1-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> Message-ID: <1412029248-22454-5-git-send-email-richard@nod.at> If the WL pool runs out of PEBs we schedule a fastmap write to refill it was soon as possible. Ensure that only one at a time is scheduled otherwise we might end in a fastmap write storm was writing the fastmap can schedule another write if bitflips were detected. Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/ubi.h | 2 ++ drivers/mtd/ubi/wl.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..529dfb0 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -426,6 +426,7 @@ struct ubi_debug_info { * @fm_size: fastmap size in bytes * @fm_sem: allows ubi_update_fastmap() to block EBA table changes * @fm_work: fastmap work queue + * @fm_work_scheduled: non-zero if fastmap work was scheduled * * @used: RB-tree of used physical eraseblocks * @erroneous: RB-tree of erroneous used physical eraseblocks @@ -531,6 +532,7 @@ struct ubi_device { void *fm_buf; size_t fm_size; struct work_struct fm_work; + int fm_work_scheduled; /* Wear-leveling sub-system's stuff */ struct rb_root used; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index dc01b1f..4c02a6e 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -149,6 +149,9 @@ static void update_fastmap_work_fn(struct work_struct *wrk) { struct ubi_device *ubi = container_of(wrk, struct ubi_device, fm_work); ubi_update_fastmap(ubi); + spin_lock(&ubi->wl_lock); + ubi->fm_work_scheduled = 0; + spin_unlock(&ubi->wl_lock); } /** @@ -657,7 +660,10 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) /* We cannot update the fastmap here because this * function is called in atomic context. * Let's fail here and refill/update it as soon as possible. */ - schedule_work(&ubi->fm_work); + if (!ubi->fm_work_scheduled) { + ubi->fm_work_scheduled = 1; + schedule_work(&ubi->fm_work); + } return NULL; } else { pnum = pool->pebs[pool->used++]; -- 2.1.0 From richard at nod.at Mon Sep 29 15:22:56 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 00:22:56 +0200 Subject: [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() In-Reply-To: <1411728032.23429.63.camel@sauron.fi.intel.com> References: <1411375536-20067-1-git-send-email-richard@nod.at> <1411375536-20067-3-git-send-email-richard@nod.at> <1411728032.23429.63.camel@sauron.fi.intel.com> Message-ID: <5429DBC0.1010801@nod.at> Am 26.09.2014 12:40, schrieb Artem Bityutskiy: > On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote: >> If sync_erase() fails with EINTR, ENOMEM, EAGAIN or >> EBUSY erase_worker() re-schedules the failed work. >> This will lead to a deadlock because erase_worker() is called >> with work_sem held in read mode. And schedule_erase() will take >> this lock again. >> >> Signed-off-by: Richard Weinberger > > Did you manage to test it? > > Why no -stable this time? Not that important, or just something > theoretical and you never actually hit this bug? It is something theoretical, I was only able to trigger it by injecting ENOMEM by hand. Thanks, //richard From richard.weinberger at gmail.com Mon Sep 29 15:24:17 2014 From: richard.weinberger at gmail.com (Richard Weinberger) Date: Tue, 30 Sep 2014 00:24:17 +0200 Subject: Two lame typo fixes In-Reply-To: <1410874236-3125-1-git-send-email-richard@nod.at> References: <1410874236-3125-1-git-send-email-richard@nod.at> Message-ID: On Tue, Sep 16, 2014 at 3:30 PM, Richard Weinberger wrote: > ...found them while browsing. > > Thanks, > //richard > > [PATCH 1/2] UBI: Fix trivial typo in __schedule_ubi_work > [PATCH 2/2] UBIFS: Fix trivial typo in power_cut_emulated() ping? -- Thanks, //richard From joe at perches.com Mon Sep 29 16:08:20 2014 From: joe at perches.com (Joe Perches) Date: Mon, 29 Sep 2014 16:08:20 -0700 Subject: [PATCH 0/7] seq_printf cleanups In-Reply-To: <20140929124246.3e39dac8@gandalf.local.home> References: <20140929124246.3e39dac8@gandalf.local.home> Message-ID: seq_printf should return void. Add a public bool seq_is_full function that can be used to shortcut unnecesary seq_printf/seq_puts calls when the seq buffer is full. Start removing the misuses of the seq_printf/seq_puts return value. Patchset brought forward from an unreplied to set of changes from back in December 2013. https://lkml.org/lkml/2013/12/11/713 Renamed seq_is_buf_full to seq_is_full. Joe Perches (7): seq_file: Rename static bool seq_overflow to public bool seq_is_full netfilter: Convert print_tuple functions to return void dlm: Use seq_is_full - remove seq_printf returns dlm: Use seq_puts, remove unnecessary trailing spaces fs: Convert show_fdinfo functions to void debugfs: Fix misuse of seq_printf return value docg3: Fix mixuse of seq_printf return value Documentation/filesystems/seq_file.txt | 28 +-- Documentation/filesystems/vfs.txt | 2 +- drivers/mtd/devices/docg3.c | 112 ++++++------ drivers/net/tun.c | 4 +- fs/debugfs/file.c | 14 +- fs/dlm/debug_fs.c | 260 +++++++++++++-------------- fs/eventfd.c | 15 +- fs/eventpoll.c | 19 +- fs/notify/fdinfo.c | 76 ++++---- fs/notify/fdinfo.h | 4 +- fs/proc/fd.c | 2 +- fs/seq_file.c | 28 +-- fs/signalfd.c | 10 +- fs/timerfd.c | 27 +-- include/linux/fs.h | 2 +- include/linux/seq_file.h | 8 + include/net/netfilter/nf_conntrack_core.h | 2 +- include/net/netfilter/nf_conntrack_l3proto.h | 4 +- include/net/netfilter/nf_conntrack_l4proto.h | 4 +- net/netfilter/nf_conntrack_l3proto_generic.c | 5 +- net/netfilter/nf_conntrack_proto_dccp.c | 10 +- net/netfilter/nf_conntrack_proto_generic.c | 5 +- net/netfilter/nf_conntrack_proto_gre.c | 10 +- net/netfilter/nf_conntrack_proto_sctp.c | 10 +- net/netfilter/nf_conntrack_proto_tcp.c | 10 +- net/netfilter/nf_conntrack_proto_udp.c | 10 +- net/netfilter/nf_conntrack_proto_udplite.c | 10 +- net/netfilter/nf_conntrack_standalone.c | 15 +- 28 files changed, 333 insertions(+), 373 deletions(-) -- 1.8.1.2.459.gbcd45b4.dirty From joe at perches.com Mon Sep 29 16:08:27 2014 From: joe at perches.com (Joe Perches) Date: Mon, 29 Sep 2014 16:08:27 -0700 Subject: [PATCH 7/7] docg3: Fix miuse of seq_printf return value In-Reply-To: References: <20140929124246.3e39dac8@gandalf.local.home> Message-ID: seq_printf doesn't return a useful value, so remove these misuses. Signed-off-by: Joe Perches --- drivers/mtd/devices/docg3.c | 112 ++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 60 deletions(-) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 21cc4b6..68ff83c 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1655,22 +1655,21 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; - int pos = 0; u8 fctrl; mutex_lock(&docg3->cascade->lock); fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); mutex_unlock(&docg3->cascade->lock); - pos += seq_printf(s, - "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", - fctrl, - fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", - fctrl & DOC_CTRL_CE ? "active" : "inactive", - fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", - fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", - fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready"); - return pos; + seq_printf(s, "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", + fctrl, + fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", + fctrl & DOC_CTRL_CE ? "active" : "inactive", + fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", + fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", + fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready"); + + return 0; } DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show); @@ -1678,58 +1677,56 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; - int pos = 0, pctrl, mode; + int pctrl, mode; mutex_lock(&docg3->cascade->lock); pctrl = doc_register_readb(docg3, DOC_ASICMODE); mode = pctrl & 0x03; mutex_unlock(&docg3->cascade->lock); - pos += seq_printf(s, - "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", - pctrl, - pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, - pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, - pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, - pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, - pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, - mode >> 1, mode & 0x1); + seq_printf(s, + "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", + pctrl, + pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, + pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, + pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, + mode >> 1, mode & 0x1); switch (mode) { case DOC_ASICMODE_RESET: - pos += seq_puts(s, "reset"); + seq_puts(s, "reset"); break; case DOC_ASICMODE_NORMAL: - pos += seq_puts(s, "normal"); + seq_puts(s, "normal"); break; case DOC_ASICMODE_POWERDOWN: - pos += seq_puts(s, "powerdown"); + seq_puts(s, "powerdown"); break; } - pos += seq_puts(s, ")\n"); - return pos; + seq_puts(s, ")\n"); + return 0; } DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); static int dbg_device_id_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; - int pos = 0; int id; mutex_lock(&docg3->cascade->lock); id = doc_register_readb(docg3, DOC_DEVICESELECT); mutex_unlock(&docg3->cascade->lock); - pos += seq_printf(s, "DeviceId = %d\n", id); - return pos; + seq_printf(s, "DeviceId = %d\n", id); + return 0; } DEBUGFS_RO_ATTR(device_id, dbg_device_id_show); static int dbg_protection_show(struct seq_file *s, void *p) { struct docg3 *docg3 = (struct docg3 *)s->private; - int pos = 0; int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; mutex_lock(&docg3->cascade->lock); @@ -1742,45 +1739,40 @@ static int dbg_protection_show(struct seq_file *s, void *p) dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); mutex_unlock(&docg3->cascade->lock); - pos += seq_printf(s, "Protection = 0x%02x (", - protect); + seq_printf(s, "Protection = 0x%02x (", protect); if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) - pos += seq_puts(s, "FOUNDRY_OTP_LOCK,"); + seq_puts(s, "FOUNDRY_OTP_LOCK,"); if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) - pos += seq_puts(s, "CUSTOMER_OTP_LOCK,"); + seq_puts(s, "CUSTOMER_OTP_LOCK,"); if (protect & DOC_PROTECT_LOCK_INPUT) - pos += seq_puts(s, "LOCK_INPUT,"); + seq_puts(s, "LOCK_INPUT,"); if (protect & DOC_PROTECT_STICKY_LOCK) - pos += seq_puts(s, "STICKY_LOCK,"); + seq_puts(s, "STICKY_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ENABLED) - pos += seq_puts(s, "PROTECTION ON,"); + seq_puts(s, "PROTECTION ON,"); if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) - pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,"); + seq_puts(s, "IPL_DOWNLOAD_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ERROR) - pos += seq_puts(s, "PROTECT_ERR,"); + seq_puts(s, "PROTECT_ERR,"); else - pos += seq_puts(s, "NO_PROTECT_ERR"); - pos += seq_puts(s, ")\n"); - - pos += seq_printf(s, "DPS0 = 0x%02x : " - "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " - "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", - dps0, dps0_low, dps0_high, - !!(dps0 & DOC_DPS_OTP_PROTECTED), - !!(dps0 & DOC_DPS_READ_PROTECTED), - !!(dps0 & DOC_DPS_WRITE_PROTECTED), - !!(dps0 & DOC_DPS_HW_LOCK_ENABLED), - !!(dps0 & DOC_DPS_KEY_OK)); - pos += seq_printf(s, "DPS1 = 0x%02x : " - "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " - "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", - dps1, dps1_low, dps1_high, - !!(dps1 & DOC_DPS_OTP_PROTECTED), - !!(dps1 & DOC_DPS_READ_PROTECTED), - !!(dps1 & DOC_DPS_WRITE_PROTECTED), - !!(dps1 & DOC_DPS_HW_LOCK_ENABLED), - !!(dps1 & DOC_DPS_KEY_OK)); - return pos; + seq_puts(s, "NO_PROTECT_ERR"); + seq_puts(s, ")\n"); + + seq_printf(s, "DPS0 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps0, dps0_low, dps0_high, + !!(dps0 & DOC_DPS_OTP_PROTECTED), + !!(dps0 & DOC_DPS_READ_PROTECTED), + !!(dps0 & DOC_DPS_WRITE_PROTECTED), + !!(dps0 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps0 & DOC_DPS_KEY_OK)); + seq_printf(s, "DPS1 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps1, dps1_low, dps1_high, + !!(dps1 & DOC_DPS_OTP_PROTECTED), + !!(dps1 & DOC_DPS_READ_PROTECTED), + !!(dps1 & DOC_DPS_WRITE_PROTECTED), + !!(dps1 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps1 & DOC_DPS_KEY_OK)); + return 0; } DEBUGFS_RO_ATTR(protection, dbg_protection_show); -- 1.8.1.2.459.gbcd45b4.dirty From ben at decadent.org.uk Mon Sep 29 18:47:53 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 02:47:53 +0100 Subject: [PATCH 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification In-Reply-To: <20140928220300.GB3248@norris-Latitude-E6410> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714795.3040.45.camel@decadent.org.uk> <20140928220300.GB3248@norris-Latitude-E6410> Message-ID: <1412041673.9388.75.camel@decadent.org.uk> On Sun, 2014-09-28 at 15:03 -0700, Brian Norris wrote: > On Sun, Sep 14, 2014 at 06:13:15PM +0100, Ben Hutchings wrote: > > On Sun, 2014-09-14 at 18:10 +0100, Ben Hutchings wrote: > > > The first patch in the series restores the module aliases to m25p80, but > > > it does so by duplicating the list of names. This should be suitable > > > for stable, but it isn't viable in the longer term. > > > > > > The following patches change the spi-nor interface so that this > > > duplication is no longer necessary. This includes removing > > > spi_nor::read_id, but it could be re-added after this with a different > > > interface, e.g. returning a flash_info structure (which would need to be > > > defined in spi_nor.h). > > > > Note that these patch are: > > - Based on your 'testing' branch > > Which testing branch? These two are the only official > repos for MTD: > > git git://git.infradead.org/linux-mtd.git > git git://git.infradead.org/l2-mtd.git You had a testing branch in git://git.infradead.org/users/norris/linux-mtd.git, and that included commit af249c3a0ca8 ('mtd: spi-nor: remove duplicated w25q128 entry') which this patch series depended on. Ben. > > - Untested by me, aside from compiling and checking that m25p80 has the > > expected module aliases > > Brian -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 18:50:40 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 02:50:40 +0100 Subject: [PATCH 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: References: <1410714624.3040.38.camel@decadent.org.uk> <1410714708.3040.43.camel@decadent.org.uk> <1410793627.3040.61.camel@decadent.org.uk> Message-ID: <1412041840.9388.77.camel@decadent.org.uk> On Wed, 2014-09-17 at 10:23 +0200, Geert Uytterhoeven wrote: > Hi Ben, > > On Mon, Sep 15, 2014 at 5:07 PM, Ben Hutchings wrote: > >> > > >> > +#define __SPI_NOR_ENUM_TYPES(c_id, str_and_c_id) \ > >> > + c_id(at25fs010) c_id(at25fs040) c_id(at25df041a) \ > >> > + c_id(at25df321a) c_id(at25df641) c_id(at26f004) \ > >> > >> Can't you just have the IDs in a header file only, and let the header file > >> generate either a struct flash_info or a struct spi_device_id table, using > >> a macro defined by the file that includes it? > > > > How would we match up the rest of the struct flash_info to the name? > > Ah, you use the enums to match the names to the rest of the flash_info. > But you can do it in one-shot, can't you? [...] I know, but I didn't want to expose the data in a header file. As other people consider that a lesser evil than this rather complex approach, I'll do it the simple way. Ben. -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:07:38 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:07:38 +0100 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> Message-ID: <1412042858.9388.79.camel@decadent.org.uk> On Mon, 2014-09-29 at 08:36 +0200, Rafa? Mi?ecki wrote: > On 29 September 2014 00:21, Brian Norris wrote: > > + Rafal > > > > Rafal has been looking at the same area of code. I'd really like to get > > this patch into 3.18 if possible, so the more eyes the better. > > Thanks Brian. > > I took me a while to follow this issue, too bad I wasn't subscribed to > the ML earlier. Let me try to sum it up. > > > > 1) The main urgent issue: broken auto-loading > Tracked in the thread: http://www.spinics.net/lists/linux-spi/msg01726.html > Problem: m25p80.c references spi_nor_ids (from external file) > Short-term solution: duplicate IDs in the m25p80.c > > Ben: just like Brian, I think the patch like this one ( > [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 > ) is the way to go. However few comments: > > a) I don't see why you modify m25p_probe in it. Because spi_nor_scan() requires a struct spi_device_id with the driver_data field pointing to a struct flash_info. > b) I don't think the described clean solution (you described it in the > commit message): > > A clean solution to this will involve defining the list of device > > IDs in spi-nor.h and removing struct spi_device_id from the spi-nor > > API, but this is quite a large change. > is the correct one. I think there should be a single string to trigger > m25p80 load and the rest should be handled using JEDEC, with some > workarounds for incompatible devices only. That certainly makes sense for Linux-specific platform data, but I don't think it works for Device Tree "compatible" strings (see ). [...] > b) Removing spi_nor::read_id > https://patchwork.ozlabs.org/patch/389073/ > Ben: I think this one has a NACK from me, because I'm going to use > custom read_id in the bcm53xxspiflash driver. > See following thread for bcm53xxspiflash description: > http://comments.gmane.org/gmane.linux.drivers.mtd/54578 > Initial commit (it uses read_id): https://patchwork.ozlabs.org/patch/381902/ [...] But it has to use spi_nor_match_id() because of the driver_data requirement. This just illustrates that the read_id operation doesn't make sense as currently defined. I accept that there will be a need for a read_id operation, but I think it should fill in a struct flash_info rather than requiring every chip to be described and named in spi-nor.c. Ben. -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:13:42 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:13:42 +0100 Subject: [PATCH v2 0/5] m25p80,spi-nor: Fix module aliases for m25p80; clean up chip identification Message-ID: <1412043222.9388.81.camel@decadent.org.uk> The first patch in the series restores the module aliases to m25p80, but it does so by duplicating the list of names. This should be suitable for stable, but it isn't viable in the longer term. The following patches change the spi-nor interface so that this duplication is no longer necessary. This includes removing spi_nor::read_id, but it could be re-added after this with a different interface, e.g. returning a flash_info structure (which would need to be defined in spi_nor.h). v2: Rebase onto l2-mtd/master. Put all the flash information into spi-nor.h rather than using an elaborate set of macros to validate names in spi-nor.c. These patches are still untested by me, aside from compiling and checking that m25p80 has the expected module aliases. Ben. Ben Hutchings (5): m25p80,spi-nor: Fix module aliases for m25p80 spi-nor: Remove spi_nor::read_id operation spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id spi-nor: Replace struct spi_device_id with struct flash_info m25p80,spi-nor: Share the list of supported chip type names again drivers/mtd/devices/m25p80.c | 21 +++- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +- drivers/mtd/spi-nor/spi-nor.c | 251 +++++++------------------------------- include/linux/mtd/spi-nor.h | 191 ++++++++++++++++++++++++++--- 4 files changed, 232 insertions(+), 238 deletions(-) -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:15:04 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:15:04 +0100 Subject: [PATCH v2 2/5] spi-nor: Remove spi_nor::read_id operation In-Reply-To: <1412043222.9388.81.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> Message-ID: <1412043304.9388.83.camel@decadent.org.uk> There is currently no useful way to override the default implementation of this operation. The returned struct spi_device_id must have a pointer to struct flash_info in its private data, but this structure is defined inside spi-nor. Signed-off-by: Ben Hutchings --- drivers/mtd/spi-nor/spi-nor.c | 4 +--- include/linux/mtd/spi-nor.h | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 53783ed..c2f0573 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -902,8 +902,6 @@ static int spi_nor_check(struct spi_nor *nor) return -EINVAL; } - if (!nor->read_id) - nor->read_id = spi_nor_read_id; if (!nor->wait_till_ready) nor->wait_till_ready = spi_nor_wait_till_ready; @@ -929,7 +927,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (info->jedec_id) { const struct spi_device_id *jid; - jid = nor->read_id(nor); + jid = spi_nor_read_id(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 5ec84cc..66af67a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -139,8 +139,6 @@ enum spi_nor_ops { * @write_xfer: [OPTIONAL] the writefundamental primitive * @read_reg: [DRIVER-SPECIFIC] read out the register * @write_reg: [DRIVER-SPECIFIC] write data to the register - * @read_id: [REPLACEABLE] read out the ID data, and find - * the proper spi_device_id * @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready * @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR @@ -172,7 +170,6 @@ struct spi_nor { int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len, int write_enable); - const struct spi_device_id *(*read_id)(struct spi_nor *nor); int (*wait_till_ready)(struct spi_nor *nor); int (*read)(struct spi_nor *nor, loff_t from, -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:14:55 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:14:55 +0100 Subject: [PATCH v2 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <1412043222.9388.81.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> Message-ID: <1412043295.9388.82.camel@decadent.org.uk> m25p80's device ID table is now spi_nor_ids, defined in spi-nor. The MODULE_DEVICE_TABLE() macro doesn't work with extern definitions, but its use was also removed at the same time. Now if m25p80 is built as a module it doesn't get the necessary aliases to be loaded automatically. A clean solution to this will involve defining the list of device IDs in spi-nor.h and removing struct spi_device_id from the spi-nor API, but this is quite a large change. As a quick fix suitable for stable, copy the device IDs back into m25p80. Fixes: 03e296f613af ("mtd: m25p80: use the SPI nor framework") Cc: stable # 3.16.x: 32f1b7c8352f: mtd: move support for struct flash_platform_data into m25p80 Cc: stable # 3.16.x Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 59 ++++++++++++++++++++++++++++++++++++++++--- drivers/mtd/spi-nor/spi-nor.c | 5 ++-- include/linux/mtd/spi-nor.h | 3 +-- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index dcda628..204bec1 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -239,8 +239,11 @@ static int m25p_probe(struct spi_device *spi) id = spi_nor_match_id(data->type); /* If we didn't get name from platform, simply use "modalias". */ - if (!id) - id = spi_get_device_id(spi); + if (!id) { + id = spi_nor_match_id(spi_get_device_id(spi)->name); + if (WARN_ON(!id)) + return -ENODEV; + } ret = spi_nor_scan(nor, id, mode); if (ret) @@ -263,12 +266,62 @@ static int m25p_remove(struct spi_device *spi) } +/* + * XXX This needs to be kept in sync with spi_nor_ids. We can't share + * it with spi-nor, because if this is built as a module then modpost + * won't be able to read it and add appropriate aliases. + */ +static const struct spi_device_id m25p_ids[] = { + {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, + {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, + {"at26df321"}, {"at45db081d"}, + {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, + {"en25q64"}, {"en25qh128"}, {"en25qh256"}, + {"f25l32pa"}, + {"mr25h256"}, {"mr25h10"}, + {"gd25q32"}, {"gd25q64"}, + {"160s33b"}, {"320s33b"}, {"640s33b"}, + {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, + {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, + {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, + {"mx66l1g55g"}, + {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, + {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, + {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, + {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, + {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, + {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, + {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, + {"s25fl016k"}, {"s25fl064k"}, + {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, + {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, + {"sst25wf040"}, + {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, + {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, + {"m25p128"}, {"n25q032"}, + {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, + {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, + {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, + {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, + {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, + {"m25px64"}, + {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, + {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, + {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, + {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, + {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, + { }, +}; +MODULE_DEVICE_TABLE(spi, m25p_ids); + + static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .owner = THIS_MODULE, }, - .id_table = spi_nor_ids, + .id_table = m25p_ids, .probe = m25p_probe, .remove = m25p_remove, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index ae16aa2..53783ed 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -473,7 +473,7 @@ struct flash_info { * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ -const struct spi_device_id spi_nor_ids[] = { +static const struct spi_device_id spi_nor_ids[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, @@ -637,7 +637,6 @@ const struct spi_device_id spi_nor_ids[] = { { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { }, }; -EXPORT_SYMBOL_GPL(spi_nor_ids); static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) { @@ -1113,7 +1112,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(char *name) +const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..5ec84cc 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -201,7 +201,6 @@ struct spi_nor { */ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode); -extern const struct spi_device_id spi_nor_ids[]; /** * spi_nor_match_id() - find the spi_device_id by the name @@ -213,6 +212,6 @@ extern const struct spi_device_id spi_nor_ids[]; * Return: returns the right spi_device_id pointer on success, * and returns NULL on failure. */ -const struct spi_device_id *spi_nor_match_id(char *name); +const struct spi_device_id *spi_nor_match_id(const char *name); #endif -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:15:17 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:15:17 +0100 Subject: [PATCH v2 3/5] spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id In-Reply-To: <1412043222.9388.81.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> Message-ID: <1412043317.9388.84.camel@decadent.org.uk> Drivers currently call spi_nor_match_id() and then spi_nor_scan(). This adds a dependency on struct spi_device_id which we want to avoid. Make spi_nor_scan() do it for them. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 13 +++++-------- drivers/mtd/spi-nor/fsl-quadspi.c | 7 +------ drivers/mtd/spi-nor/spi-nor.c | 13 +++++++++---- include/linux/mtd/spi-nor.h | 20 ++------------------ 4 files changed, 17 insertions(+), 36 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 204bec1..d9578b9 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -193,7 +193,7 @@ static int m25p_probe(struct spi_device *spi) { struct mtd_part_parser_data ppdata; struct flash_platform_data *data; - const struct spi_device_id *id = NULL; + const char *name = NULL; struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; @@ -236,16 +236,13 @@ static int m25p_probe(struct spi_device *spi) * If that's the case, respect "type" and ignore a "name". */ if (data && data->type) - id = spi_nor_match_id(data->type); + name = data->type; /* If we didn't get name from platform, simply use "modalias". */ - if (!id) { - id = spi_nor_match_id(spi_get_device_id(spi)->name); - if (WARN_ON(!id)) - return -ENODEV; - } + if (!name) + name = spi_get_device_id(spi)->name; - ret = spi_nor_scan(nor, id, mode); + ret = spi_nor_scan(nor, name, mode); if (ret) return ret; diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 8d659a2..d5269a2 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -881,7 +881,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { - const struct spi_device_id *id; char modalias[40]; /* skip the holes */ @@ -909,10 +908,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) goto map_failed; - id = spi_nor_match_id(modalias); - if (!id) - goto map_failed; - ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) @@ -921,7 +916,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); - ret = spi_nor_scan(nor, id, SPI_NOR_QUAD); + ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) goto map_failed; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index c2f0573..171c665 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,6 +28,8 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) +static const struct spi_device_id *spi_nor_match_id(const char *name); + /* * Read the status register, returning its value in the location * Return the status register value. @@ -908,9 +910,9 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode) +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { + const struct spi_device_id *id = NULL; struct flash_info *info; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; @@ -922,6 +924,10 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (ret) return ret; + id = spi_nor_match_id(name); + if (!id) + return -ENODEV; + info = (void *)id->driver_data; if (info->jedec_id) { @@ -1110,7 +1116,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } EXPORT_SYMBOL_GPL(spi_nor_scan); -const struct spi_device_id *spi_nor_match_id(const char *name) +static const struct spi_device_id *spi_nor_match_id(const char *name) { const struct spi_device_id *id = spi_nor_ids; @@ -1121,7 +1127,6 @@ const struct spi_device_id *spi_nor_match_id(const char *name) } return NULL; } -EXPORT_SYMBOL_GPL(spi_nor_match_id); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 66af67a..c48ad49 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -184,31 +184,15 @@ struct spi_nor { /** * spi_nor_scan() - scan the SPI NOR * @nor: the spi_nor structure - * @id: the spi_device_id provided by the driver + * @name: the chip type name * @mode: the read mode supported by the driver * * The drivers can use this fuction to scan the SPI NOR. * In the scanning, it will try to get all the necessary information to * fill the mtd_info{} and the spi_nor{}. * - * The board may assigns a spi_device_id with @id which be used to compared with - * the spi_device_id detected by the scanning. - * * Return: 0 for success, others for failure. */ -int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, - enum read_mode mode); - -/** - * spi_nor_match_id() - find the spi_device_id by the name - * @name: the name of the spi_device_id - * - * The drivers use this function to find the spi_device_id - * specified by the @name. - * - * Return: returns the right spi_device_id pointer on success, - * and returns NULL on failure. - */ -const struct spi_device_id *spi_nor_match_id(const char *name); +int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); #endif -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:15:29 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:15:29 +0100 Subject: [PATCH v2 4/5] spi-nor: Replace struct spi_device_id with struct flash_info In-Reply-To: <1412043222.9388.81.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> Message-ID: <1412043329.9388.85.camel@decadent.org.uk> spi-nor does not depend on the SPI layer, so its use of struct spi_device_id adds an unnecessary indirection. Add the chip type name to struct flash_info and remove the wrapping struct spi_device_id. It also doesn't need a terminating zero entry in the array any more, so remove that. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 2 +- drivers/mtd/spi-nor/spi-nor.c | 340 +++++++++++++++++++++--------------------- 2 files changed, 170 insertions(+), 172 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d9578b9..79bc27a 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -264,7 +264,7 @@ static int m25p_remove(struct spi_device *spi) /* - * XXX This needs to be kept in sync with spi_nor_ids. We can't share + * XXX This needs to be kept in sync with spi_nor_info. We can't share * it with spi-nor, because if this is built as a module then modpost * won't be able to read it and add appropriate aliases. */ diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 171c665..2449ee5 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -28,8 +28,6 @@ #define JEDEC_MFR(_jedec_id) ((_jedec_id) >> 16) -static const struct spi_device_id *spi_nor_match_id(const char *name); - /* * Read the status register, returning its value in the location * Return the status register value. @@ -425,6 +423,8 @@ err: } struct flash_info { + const char name[SPI_NAME_SIZE]; + /* JEDEC id zero means "no ID" (most older chips); otherwise it has * a high byte of zero plus three data bytes: the manufacturer id, * then a two byte device id. @@ -452,201 +452,215 @@ struct flash_info { #define USE_FSR 0x80 /* use flag status register */ }; -#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ +#define INFO(_name, _jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ + { \ + .name = (_name), \ .jedec_id = (_jedec_id), \ .ext_id = (_ext_id), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ .flags = (_flags), \ - }) + } -#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ +#define CAT25_INFO(_name, _sector_size, _n_sectors, _page_size, \ + _addr_width, _flags) \ + { \ + .name = (_name), \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ .addr_width = (_addr_width), \ .flags = (_flags), \ - }) + } /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. */ -static const struct spi_device_id spi_nor_ids[] = { +static const struct flash_info spi_nor_info[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, - { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, + INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), + INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), - { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, - { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, - { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, + INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K), + INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K), + INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K), - { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, - { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, - { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K), + INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K), + INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K), + INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K), - { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, + INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K), /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, - { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, - { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, + INFO("en25f32", 0x1c3116, 0, 64 * 1024, 64, SECT_4K), + INFO("en25p32", 0x1c2016, 0, 64 * 1024, 64, 0), + INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0), + INFO("en25p64", 0x1c2017, 0, 64 * 1024, 128, 0), + INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K), + INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0), + INFO("en25qh256", 0x1c7019, 0, 64 * 1024, 512, 0), /* ESMT */ - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + INFO("f25l32pa", 0x8c2016, 0, 64 * 1024, 64, SECT_4K), /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + CAT25_INFO("mr25h256", 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("mr25h10", 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), /* GigaDevice */ - { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, - { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, + INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, SECT_4K), + INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, SECT_4K), /* Intel/Numonyx -- xxxs33b */ - { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, - { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, - { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, + INFO("160s33b", 0x898911, 0, 64 * 1024, 32, 0), + INFO("320s33b", 0x898912, 0, 64 * 1024, 64, 0), + INFO("640s33b", 0x898913, 0, 64 * 1024, 128, 0), /* Macronix */ - { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, - { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, - { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, - { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, - { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, - { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, - { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, - { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, + INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K), + INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K), + INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0), + INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K), + INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, 0), + INFO("mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, SECT_4K), + INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, 0), + INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0), + INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0), + INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, 0), + INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0), + INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), + INFO("mx66l1g55g", 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), /* Micron */ - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, - { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, - { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, - { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, - { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, - { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) }, - { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) }, + INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, 0), + INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, 0), + INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, 0), + INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K), + INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), + INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), + INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), /* PMC */ - { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, - { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, - { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, + INFO("pm25lv512", 0, 0, 32 * 1024, 2, SECT_4K_PMC), + INFO("pm25lv010", 0, 0, 32 * 1024, 4, SECT_4K_PMC), + INFO("pm25lq032", 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). */ - { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, - { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, - { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, - { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, - { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, - { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, - { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, - { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64, 0) }, - { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128, 0) }, - { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) }, - { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, 0), + INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 0), + INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s25fl512s", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), + INFO("s70fl01gs", 0x010221, 0x4d00, 256 * 1024, 256, 0), + INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0), + INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0), + INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, 0), + INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, 0), + INFO("s25sl004a", 0x010212, 0, 64 * 1024, 8, 0), + INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0), + INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0), + INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0), + INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0), + INFO("s25fl008k", 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO("s25fl016k", 0xef4015, 0, 64 * 1024, 32, SECT_4K), + INFO("s25fl064k", 0xef4017, 0, 64 * 1024, 128, SECT_4K), /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, - { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) }, - { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) }, - { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) }, - { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, - { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, - { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, - { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, + INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), + INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), + INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), + INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), + INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K), + INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), + INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), + INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), + INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), /* ST Microelectronics -- newer production may have feature updates */ - { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, - { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, - { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, - { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, - { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, - { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, - { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, - { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, - { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, - { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, - - { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, - { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, - { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, - { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, - { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, - { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, - { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, - { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, - { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, - - { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, - { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, - { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, - - { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, - { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, - { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, - - { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, - { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, - { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, - { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, + INFO("m25p05", 0x202010, 0, 32 * 1024, 2, 0), + INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0), + INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0), + INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0), + INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0), + INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0), + INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0), + INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0), + INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0), + INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, 0), + + INFO("m25p05-nonjedec", 0, 0, 32 * 1024, 2, 0), + INFO("m25p10-nonjedec", 0, 0, 32 * 1024, 4, 0), + INFO("m25p20-nonjedec", 0, 0, 64 * 1024, 4, 0), + INFO("m25p40-nonjedec", 0, 0, 64 * 1024, 8, 0), + INFO("m25p80-nonjedec", 0, 0, 64 * 1024, 16, 0), + INFO("m25p16-nonjedec", 0, 0, 64 * 1024, 32, 0), + INFO("m25p32-nonjedec", 0, 0, 64 * 1024, 64, 0), + INFO("m25p64-nonjedec", 0, 0, 64 * 1024, 128, 0), + INFO("m25p128-nonjedec", 0, 0, 256 * 1024, 64, 0), + + INFO("m45pe10", 0x204011, 0, 64 * 1024, 2, 0), + INFO("m45pe80", 0x204014, 0, 64 * 1024, 16, 0), + INFO("m45pe16", 0x204015, 0, 64 * 1024, 32, 0), + + INFO("m25pe20", 0x208012, 0, 64 * 1024, 4, 0), + INFO("m25pe80", 0x208014, 0, 64 * 1024, 16, 0), + INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K), + + INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K), + INFO("m25px32", 0x207116, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px32-s0", 0x207316, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px32-s1", 0x206316, 0, 64 * 1024, 64, SECT_4K), + INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0), /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, - { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, - { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, - { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, - { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, - { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) }, + INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K), + INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K), + INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K), + INFO("w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K), + INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, SECT_4K), + INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K), + INFO("w25q64", 0xef4017, 0, 64 * 1024, 128, SECT_4K), + INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K), + INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K), + INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K), /* Catalyst / On Semiconductor -- non-JEDEC */ - { "cat25c11", CAT25_INFO( 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c03", CAT25_INFO( 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, - { }, + CAT25_INFO("cat25c11", 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c03", 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c09", 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25c17", 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + CAT25_INFO("cat25128", 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), }; -static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) +static const struct flash_info *spi_nor_info_by_name(const char *name) +{ + const struct flash_info *info; + int i; + + for (i = 0; i < ARRAY_SIZE(spi_nor_info); i++) { + info = &spi_nor_info[i]; + if (!strcmp(name, info->name)) + return info; + } + return NULL; +} + +static const struct flash_info *spi_nor_info_probe(struct spi_nor *nor) { int tmp; u8 id[5]; u32 jedec; u16 ext_jedec; - struct flash_info *info; + const struct flash_info *info; tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, 5); if (tmp < 0) { @@ -661,11 +675,11 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) ext_jedec = id[3] << 8 | id[4]; - for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { - info = (void *)spi_nor_ids[tmp].driver_data; + for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_info); tmp++) { + info = &spi_nor_info[tmp]; if (info->jedec_id == jedec) { if (info->ext_id == 0 || info->ext_id == ext_jedec) - return &spi_nor_ids[tmp]; + return info; } } dev_err(nor->dev, "unrecognized JEDEC id %06x\n", jedec); @@ -912,8 +926,7 @@ static int spi_nor_check(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { - const struct spi_device_id *id = NULL; - struct flash_info *info; + const struct flash_info *info = NULL; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; struct device_node *np = dev->of_node; @@ -924,19 +937,17 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) if (ret) return ret; - id = spi_nor_match_id(name); - if (!id) + info = spi_nor_info_by_name(name); + if (!info) return -ENODEV; - info = (void *)id->driver_data; - if (info->jedec_id) { - const struct spi_device_id *jid; + const struct flash_info *jinfo; - jid = spi_nor_read_id(nor); - if (IS_ERR(jid)) { - return PTR_ERR(jid); - } else if (jid != id) { + jinfo = spi_nor_info_probe(nor); + if (IS_ERR(jinfo)) { + return PTR_ERR(jinfo); + } else if (jinfo != info) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let @@ -945,9 +956,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", - jid->name, id->name); - id = jid; - info = (void *)jid->driver_data; + jinfo->name, info->name); + info = jinfo; } } @@ -1093,7 +1103,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) nor->read_dummy = spi_nor_read_dummy_cycles(nor); - dev_info(dev, "%s (%lld Kbytes)\n", id->name, + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); dev_dbg(dev, @@ -1116,18 +1126,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) } EXPORT_SYMBOL_GPL(spi_nor_scan); -static const struct spi_device_id *spi_nor_match_id(const char *name) -{ - const struct spi_device_id *id = spi_nor_ids; - - while (id->name[0]) { - if (!strcmp(name, id->name)) - return id; - id++; - } - return NULL; -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Huang Shijie "); MODULE_AUTHOR("Mike Lavender"); -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Mon Sep 29 19:15:52 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 03:15:52 +0100 Subject: [PATCH v2 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: <1412043222.9388.81.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> Message-ID: <1412043352.9388.86.camel@decadent.org.uk> Move the list of chip type information to a macro in spi-nor.h, but leave the definitions of INFO and CAT25_INFO in spi-nor. In m25p80, define the INFO and CAT25_INFO macros to initialise a struct spi_device_id with the name, ignoring the remaining parameters. Signed-off-by: Ben Hutchings --- drivers/mtd/devices/m25p80.c | 47 +----------- drivers/mtd/spi-nor/spi-nor.c | 165 +--------------------------------------- include/linux/mtd/spi-nor.h | 173 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 208 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 79bc27a..d13ac07 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -263,51 +263,10 @@ static int m25p_remove(struct spi_device *spi) } -/* - * XXX This needs to be kept in sync with spi_nor_info. We can't share - * it with spi-nor, because if this is built as a module then modpost - * won't be able to read it and add appropriate aliases. - */ static const struct spi_device_id m25p_ids[] = { - {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, - {"at25df641"}, {"at26f004"}, {"at26df081a"}, {"at26df161a"}, - {"at26df321"}, {"at45db081d"}, - {"en25f32"}, {"en25p32"}, {"en25q32b"}, {"en25p64"}, - {"en25q64"}, {"en25qh128"}, {"en25qh256"}, - {"f25l32pa"}, - {"mr25h256"}, {"mr25h10"}, - {"gd25q32"}, {"gd25q64"}, - {"160s33b"}, {"320s33b"}, {"640s33b"}, - {"mx25l2005a"}, {"mx25l4005a"}, {"mx25l8005"}, {"mx25l1606e"}, - {"mx25l3205d"}, {"mx25l3255e"}, {"mx25l6405d"}, {"mx25l12805d"}, - {"mx25l12855e"},{"mx25l25635e"},{"mx25l25655e"},{"mx66l51235l"}, - {"mx66l1g55g"}, - {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q256a"}, - {"n25q512a"}, {"n25q512ax3"}, {"n25q00"}, - {"pm25lv512"}, {"pm25lv010"}, {"pm25lq032"}, - {"s25sl032p"}, {"s25sl064p"}, {"s25fl256s0"}, {"s25fl256s1"}, - {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, - {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, - {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, - {"s25fl016k"}, {"s25fl064k"}, - {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, - {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, - {"sst25wf040"}, - {"m25p05"}, {"m25p10"}, {"m25p20"}, {"m25p40"}, - {"m25p80"}, {"m25p16"}, {"m25p32"}, {"m25p64"}, - {"m25p128"}, {"n25q032"}, - {"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"}, - {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, - {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, - {"m45pe10"}, {"m45pe80"}, {"m45pe16"}, - {"m25pe20"}, {"m25pe80"}, {"m25pe16"}, - {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, - {"m25px64"}, - {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, - {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, - {"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, - {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, - {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, +#define INFO(name, ...) { name } +#define CAT25_INFO(name, ...) { name } + SPI_NOR_INFO { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2449ee5..d98c6e0 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -474,171 +474,8 @@ struct flash_info { .flags = (_flags), \ } -/* NOTE: double check command sets and memory organization when you add - * more nor chips. This current list focusses on newer chips, which - * have been converging on command sets which including JEDEC ID. - */ static const struct flash_info spi_nor_info[] = { - /* Atmel -- some are (confusingly) marketed as "DataFlash" */ - INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), - INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), - - INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K), - INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K), - INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K), - - INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K), - INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K), - INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K), - INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K), - - INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K), - - /* EON -- en25xxx */ - INFO("en25f32", 0x1c3116, 0, 64 * 1024, 64, SECT_4K), - INFO("en25p32", 0x1c2016, 0, 64 * 1024, 64, 0), - INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0), - INFO("en25p64", 0x1c2017, 0, 64 * 1024, 128, 0), - INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K), - INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0), - INFO("en25qh256", 0x1c7019, 0, 64 * 1024, 512, 0), - - /* ESMT */ - INFO("f25l32pa", 0x8c2016, 0, 64 * 1024, 64, SECT_4K), - - /* Everspin */ - CAT25_INFO("mr25h256", 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("mr25h10", 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - - /* GigaDevice */ - INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, SECT_4K), - INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, SECT_4K), - - /* Intel/Numonyx -- xxxs33b */ - INFO("160s33b", 0x898911, 0, 64 * 1024, 32, 0), - INFO("320s33b", 0x898912, 0, 64 * 1024, 64, 0), - INFO("640s33b", 0x898913, 0, 64 * 1024, 128, 0), - - /* Macronix */ - INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K), - INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K), - INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0), - INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K), - INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, 0), - INFO("mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, SECT_4K), - INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, 0), - INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0), - INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0), - INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, 0), - INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0), - INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), - INFO("mx66l1g55g", 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), - - /* Micron */ - INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, 0), - INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, 0), - INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, 0), - INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K), - INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), - INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), - INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), - - /* PMC */ - INFO("pm25lv512", 0, 0, 32 * 1024, 2, SECT_4K_PMC), - INFO("pm25lv010", 0, 0, 32 * 1024, 4, SECT_4K_PMC), - INFO("pm25lq032", 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), - - /* Spansion -- single (large) sector size only, at least - * for the chips listed here (without boot sectors). - */ - INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, 0), - INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 0), - INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s25fl512s", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), - INFO("s70fl01gs", 0x010221, 0x4d00, 256 * 1024, 256, 0), - INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0), - INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0), - INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, 0), - INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, 0), - INFO("s25sl004a", 0x010212, 0, 64 * 1024, 8, 0), - INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0), - INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0), - INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0), - INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0), - INFO("s25fl008k", 0xef4014, 0, 64 * 1024, 16, SECT_4K), - INFO("s25fl016k", 0xef4015, 0, 64 * 1024, 32, SECT_4K), - INFO("s25fl064k", 0xef4017, 0, 64 * 1024, 128, SECT_4K), - - /* SST -- large erase sizes are "overlays", "sectors" are 4K */ - INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), - INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), - INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), - INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), - INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K), - INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), - INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), - INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), - INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), - - /* ST Microelectronics -- newer production may have feature updates */ - INFO("m25p05", 0x202010, 0, 32 * 1024, 2, 0), - INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0), - INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0), - INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0), - INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0), - INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0), - INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0), - INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0), - INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0), - INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, 0), - - INFO("m25p05-nonjedec", 0, 0, 32 * 1024, 2, 0), - INFO("m25p10-nonjedec", 0, 0, 32 * 1024, 4, 0), - INFO("m25p20-nonjedec", 0, 0, 64 * 1024, 4, 0), - INFO("m25p40-nonjedec", 0, 0, 64 * 1024, 8, 0), - INFO("m25p80-nonjedec", 0, 0, 64 * 1024, 16, 0), - INFO("m25p16-nonjedec", 0, 0, 64 * 1024, 32, 0), - INFO("m25p32-nonjedec", 0, 0, 64 * 1024, 64, 0), - INFO("m25p64-nonjedec", 0, 0, 64 * 1024, 128, 0), - INFO("m25p128-nonjedec", 0, 0, 256 * 1024, 64, 0), - - INFO("m45pe10", 0x204011, 0, 64 * 1024, 2, 0), - INFO("m45pe80", 0x204014, 0, 64 * 1024, 16, 0), - INFO("m45pe16", 0x204015, 0, 64 * 1024, 32, 0), - - INFO("m25pe20", 0x208012, 0, 64 * 1024, 4, 0), - INFO("m25pe80", 0x208014, 0, 64 * 1024, 16, 0), - INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K), - - INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K), - INFO("m25px32", 0x207116, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px32-s0", 0x207316, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px32-s1", 0x206316, 0, 64 * 1024, 64, SECT_4K), - INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0), - - /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ - INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K), - INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K), - INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K), - INFO("w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K), - INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, SECT_4K), - INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K), - INFO("w25q64", 0xef4017, 0, 64 * 1024, 128, SECT_4K), - INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K), - INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K), - INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K), - - /* Catalyst / On Semiconductor -- non-JEDEC */ - CAT25_INFO("cat25c11", 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c03", 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c09", 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25c17", 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), - CAT25_INFO("cat25128", 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), + SPI_NOR_INFO }; static const struct flash_info *spi_nor_info_by_name(const char *name) diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index c48ad49..8cc7281 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -195,4 +195,177 @@ struct spi_nor { */ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode); +/* NOTE: double check command sets and memory organization when you add + * more nor chips. This current list focusses on newer chips, which + * have been converging on command sets which including JEDEC ID. + * + * Caller must define the macros: + * INFO(name, jedec_id, ext_id, sector_size, n_sectors, flags) + * CAT25_INFO(name, sector_size, n_sectors, page_size, addr_width, flags) + */ +#define SPI_NOR_INFO \ + /* Atmel -- some are (confusingly) marketed as "DataFlash" */ \ + INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECT_4K), \ + INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECT_4K), \ + \ + INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECT_4K), \ + INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECT_4K), \ + INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECT_4K), \ + \ + INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECT_4K), \ + INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECT_4K), \ + INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECT_4K), \ + INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECT_4K), \ + \ + INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECT_4K), \ + \ + /* EON -- en25xxx */ \ + INFO("en25f32", 0x1c3116, 0, 64 * 1024, 64, SECT_4K), \ + INFO("en25p32", 0x1c2016, 0, 64 * 1024, 64, 0), \ + INFO("en25q32b", 0x1c3016, 0, 64 * 1024, 64, 0), \ + INFO("en25p64", 0x1c2017, 0, 64 * 1024, 128, 0), \ + INFO("en25q64", 0x1c3017, 0, 64 * 1024, 128, SECT_4K), \ + INFO("en25qh128", 0x1c7018, 0, 64 * 1024, 256, 0), \ + INFO("en25qh256", 0x1c7019, 0, 64 * 1024, 512, 0), \ + \ + /* ESMT */ \ + INFO("f25l32pa", 0x8c2016, 0, 64 * 1024, 64, SECT_4K), \ + \ + /* Everspin */ \ + CAT25_INFO("mr25h256", 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + CAT25_INFO("mr25h10", 128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + \ + /* GigaDevice */ \ + INFO("gd25q32", 0xc84016, 0, 64 * 1024, 64, SECT_4K), \ + INFO("gd25q64", 0xc84017, 0, 64 * 1024, 128, SECT_4K), \ + \ + /* Intel/Numonyx -- xxxs33b */ \ + INFO("160s33b", 0x898911, 0, 64 * 1024, 32, 0), \ + INFO("320s33b", 0x898912, 0, 64 * 1024, 64, 0), \ + INFO("640s33b", 0x898913, 0, 64 * 1024, 128, 0), \ + \ + /* Macronix */ \ + INFO("mx25l2005a", 0xc22012, 0, 64 * 1024, 4, SECT_4K), \ + INFO("mx25l4005a", 0xc22013, 0, 64 * 1024, 8, SECT_4K), \ + INFO("mx25l8005", 0xc22014, 0, 64 * 1024, 16, 0), \ + INFO("mx25l1606e", 0xc22015, 0, 64 * 1024, 32, SECT_4K), \ + INFO("mx25l3205d", 0xc22016, 0, 64 * 1024, 64, 0), \ + INFO("mx25l3255e", 0xc29e16, 0, 64 * 1024, 64, SECT_4K), \ + INFO("mx25l6405d", 0xc22017, 0, 64 * 1024, 128, 0), \ + INFO("mx25l12805d", 0xc22018, 0, 64 * 1024, 256, 0), \ + INFO("mx25l12855e", 0xc22618, 0, 64 * 1024, 256, 0), \ + INFO("mx25l25635e", 0xc22019, 0, 64 * 1024, 512, 0), \ + INFO("mx25l25655e", 0xc22619, 0, 64 * 1024, 512, 0), \ + INFO("mx66l51235l", 0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ), \ + INFO("mx66l1g55g", 0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ), \ + \ + /* Micron */ \ + INFO("n25q064", 0x20ba17, 0, 64 * 1024, 128, 0), \ + INFO("n25q128a11", 0x20bb18, 0, 64 * 1024, 256, 0), \ + INFO("n25q128a13", 0x20ba18, 0, 64 * 1024, 256, 0), \ + INFO("n25q256a", 0x20ba19, 0, 64 * 1024, 512, SECT_4K), \ + INFO("n25q512a", 0x20bb20, 0, 64 * 1024, 1024, SECT_4K), \ + INFO("n25q512ax3", 0x20ba20, 0, 64 * 1024, 1024, USE_FSR), \ + INFO("n25q00", 0x20ba21, 0, 64 * 1024, 2048, USE_FSR), \ + \ + /* PMC */ \ + INFO("pm25lv512", 0, 0, 32 * 1024, 2, SECT_4K_PMC), \ + INFO("pm25lv010", 0, 0, 32 * 1024, 4, SECT_4K_PMC), \ + INFO("pm25lq032", 0x7f9d46, 0, 64 * 1024, 64, SECT_4K), \ + \ + /* Spansion -- single (large), sector size only, at least \ + * for the chips listed here (without boot sectors),. \ + */ \ + INFO("s25sl032p", 0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), \ + INFO("s25sl064p", 0x010216, 0x4d00, 64 * 1024, 128, 0), \ + INFO("s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, 0), \ + INFO("s25fl256s1", 0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), \ + INFO("s25fl512s", 0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ), \ + INFO("s70fl01gs", 0x010221, 0x4d00, 256 * 1024, 256, 0), \ + INFO("s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, 0), \ + INFO("s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, 0), \ + INFO("s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, 0), \ + INFO("s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, 0), \ + INFO("s25sl004a", 0x010212, 0, 64 * 1024, 8, 0), \ + INFO("s25sl008a", 0x010213, 0, 64 * 1024, 16, 0), \ + INFO("s25sl016a", 0x010214, 0, 64 * 1024, 32, 0), \ + INFO("s25sl032a", 0x010215, 0, 64 * 1024, 64, 0), \ + INFO("s25sl064a", 0x010216, 0, 64 * 1024, 128, 0), \ + INFO("s25fl008k", 0xef4014, 0, 64 * 1024, 16, SECT_4K), \ + INFO("s25fl016k", 0xef4015, 0, 64 * 1024, 32, SECT_4K), \ + INFO("s25fl064k", 0xef4017, 0, 64 * 1024, 128, SECT_4K), \ + \ + /* SST -- large erase sizes are "overlays", "sectors" are 4K */ \ + INFO("sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), \ + INFO("sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE), \ + INFO("sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE), \ + INFO("sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE), \ + INFO("sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, SECT_4K), \ + INFO("sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE), \ + INFO("sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE), \ + INFO("sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE), \ + INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE), \ + \ + /* ST Microelectronics -- newer production may have feature updates */ \ + INFO("m25p05", 0x202010, 0, 32 * 1024, 2, 0), \ + INFO("m25p10", 0x202011, 0, 32 * 1024, 4, 0), \ + INFO("m25p20", 0x202012, 0, 64 * 1024, 4, 0), \ + INFO("m25p40", 0x202013, 0, 64 * 1024, 8, 0), \ + INFO("m25p80", 0x202014, 0, 64 * 1024, 16, 0), \ + INFO("m25p16", 0x202015, 0, 64 * 1024, 32, 0), \ + INFO("m25p32", 0x202016, 0, 64 * 1024, 64, 0), \ + INFO("m25p64", 0x202017, 0, 64 * 1024, 128, 0), \ + INFO("m25p128", 0x202018, 0, 256 * 1024, 64, 0), \ + INFO("n25q032", 0x20ba16, 0, 64 * 1024, 64, 0), \ + \ + INFO("m25p05-nonjedec", 0, 0, 32 * 1024, 2, 0), \ + INFO("m25p10-nonjedec", 0, 0, 32 * 1024, 4, 0), \ + INFO("m25p20-nonjedec", 0, 0, 64 * 1024, 4, 0), \ + INFO("m25p40-nonjedec", 0, 0, 64 * 1024, 8, 0), \ + INFO("m25p80-nonjedec", 0, 0, 64 * 1024, 16, 0), \ + INFO("m25p16-nonjedec", 0, 0, 64 * 1024, 32, 0), \ + INFO("m25p32-nonjedec", 0, 0, 64 * 1024, 64, 0), \ + INFO("m25p64-nonjedec", 0, 0, 64 * 1024, 128, 0), \ + INFO("m25p128-nonjedec", 0, 0, 256 * 1024, 64, 0), \ + \ + INFO("m45pe10", 0x204011, 0, 64 * 1024, 2, 0), \ + INFO("m45pe80", 0x204014, 0, 64 * 1024, 16, 0), \ + INFO("m45pe16", 0x204015, 0, 64 * 1024, 32, 0), \ + \ + INFO("m25pe20", 0x208012, 0, 64 * 1024, 4, 0), \ + INFO("m25pe80", 0x208014, 0, 64 * 1024, 16, 0), \ + INFO("m25pe16", 0x208015, 0, 64 * 1024, 32, SECT_4K), \ + \ + INFO("m25px16", 0x207115, 0, 64 * 1024, 32, SECT_4K), \ + INFO("m25px32", 0x207116, 0, 64 * 1024, 64, SECT_4K), \ + INFO("m25px32-s0", 0x207316, 0, 64 * 1024, 64, SECT_4K), \ + INFO("m25px32-s1", 0x206316, 0, 64 * 1024, 64, SECT_4K), \ + INFO("m25px64", 0x207117, 0, 64 * 1024, 128, 0), \ + \ + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ \ + INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECT_4K), \ + INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECT_4K), \ + INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECT_4K), \ + INFO("w25x80", 0xef3014, 0, 64 * 1024, 16, SECT_4K), \ + INFO("w25x16", 0xef3015, 0, 64 * 1024, 32, SECT_4K), \ + INFO("w25x32", 0xef3016, 0, 64 * 1024, 64, SECT_4K), \ + INFO("w25q32", 0xef4016, 0, 64 * 1024, 64, SECT_4K), \ + INFO("w25q32dw", 0xef6016, 0, 64 * 1024, 64, SECT_4K), \ + INFO("w25x64", 0xef3017, 0, 64 * 1024, 128, SECT_4K), \ + INFO("w25q64", 0xef4017, 0, 64 * 1024, 128, SECT_4K), \ + INFO("w25q80", 0xef5014, 0, 64 * 1024, 16, SECT_4K), \ + INFO("w25q80bl", 0xef4014, 0, 64 * 1024, 16, SECT_4K), \ + INFO("w25q128", 0xef4018, 0, 64 * 1024, 256, SECT_4K), \ + INFO("w25q256", 0xef4019, 0, 64 * 1024, 512, SECT_4K), \ + \ + /* Catalyst / On Semiconductor -- non-JEDEC */ \ + CAT25_INFO("cat25c11", 16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + CAT25_INFO("cat25c03", 32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + CAT25_INFO("cat25c09", 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + CAT25_INFO("cat25c17", 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + CAT25_INFO("cat25128", 2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR), \ + \ + /* end SPI_NOR_INFO */ + + #endif -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From horms at verge.net.au Mon Sep 29 19:21:07 2014 From: horms at verge.net.au (Simon Horman) Date: Tue, 30 Sep 2014 11:21:07 +0900 Subject: [PATCH] ARM: don't set unused name in struct flash_platform_data In-Reply-To: <1411993853-6309-1-git-send-email-zajec5@gmail.com> References: <1411993853-6309-1-git-send-email-zajec5@gmail.com> Message-ID: <20140930022107.GG10373@verge.net.au> On Mon, Sep 29, 2014 at 02:30:53PM +0200, Rafa? Mi?ecki wrote: > Loading correct SPI driver (m25p80) is handled using modalias from the > struct spi_board_info. There is no point of setting name in the > platform_data, m25p80 ignores it anyway. > > Signed-off-by: Rafa? Mi?ecki > --- > arch/arm/mach-davinci/board-da830-evm.c | 1 - > arch/arm/mach-davinci/board-da850-evm.c | 1 - > arch/arm/mach-davinci/board-mityomapl138.c | 1 - > arch/arm/mach-shmobile/board-bockw.c | 1 - > arch/arm/mach-shmobile/board-koelsch.c | 1 - > arch/arm/mach-shmobile/board-lager.c | 1 - > arch/arm/mach-w90x900/dev.c | 1 - > 7 files changed, 7 deletions(-) Hi, I am happy to queue up the mach-shmobile portion of this change if you break it out into a separate patch, one per board. > > diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c > index 5623131..263004a 100644 > --- a/arch/arm/mach-davinci/board-da830-evm.c > +++ b/arch/arm/mach-davinci/board-da830-evm.c > @@ -567,7 +567,6 @@ static struct mtd_partition da830evm_spiflash_part[] = { > }; > > static struct flash_platform_data da830evm_spiflash_data = { > - .name = "m25p80", > .parts = da830evm_spiflash_part, > .nr_parts = ARRAY_SIZE(da830evm_spiflash_part), > .type = "w25x32", > diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c > index 234c5bb..721ff2b 100644 > --- a/arch/arm/mach-davinci/board-da850-evm.c > +++ b/arch/arm/mach-davinci/board-da850-evm.c > @@ -104,7 +104,6 @@ static struct mtd_partition da850evm_spiflash_part[] = { > }; > > static struct flash_platform_data da850evm_spiflash_data = { > - .name = "m25p80", > .parts = da850evm_spiflash_part, > .nr_parts = ARRAY_SIZE(da850evm_spiflash_part), > .type = "m25p64", > diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c > index 96fc00a..3c93b65 100644 > --- a/arch/arm/mach-davinci/board-mityomapl138.c > +++ b/arch/arm/mach-davinci/board-mityomapl138.c > @@ -350,7 +350,6 @@ static struct mtd_partition spi_flash_partitions[] = { > }; > > static struct flash_platform_data mityomapl138_spi_flash_data = { > - .name = "m25p80", > .parts = spi_flash_partitions, > .nr_parts = ARRAY_SIZE(spi_flash_partitions), > .type = "m24p64", > diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c > index 8a83eb3..e25af56 100644 > --- a/arch/arm/mach-shmobile/board-bockw.c > +++ b/arch/arm/mach-shmobile/board-bockw.c > @@ -266,7 +266,6 @@ static struct mtd_partition m25p80_spi_flash_partitions[] = { > }; > > static struct flash_platform_data spi_flash_data = { > - .name = "m25p80", > .type = "s25fl008k", > .parts = m25p80_spi_flash_partitions, > .nr_parts = ARRAY_SIZE(m25p80_spi_flash_partitions), > diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c > index b7d5bc7..a494a00 100644 > --- a/arch/arm/mach-shmobile/board-koelsch.c > +++ b/arch/arm/mach-shmobile/board-koelsch.c > @@ -207,7 +207,6 @@ static struct mtd_partition spi_flash_part[] = { > }; > > static const struct flash_platform_data spi_flash_data = { > - .name = "m25p80", > .parts = spi_flash_part, > .nr_parts = ARRAY_SIZE(spi_flash_part), > .type = "s25fl512s", > diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c > index e1d8215..3575731 100644 > --- a/arch/arm/mach-shmobile/board-lager.c > +++ b/arch/arm/mach-shmobile/board-lager.c > @@ -315,7 +315,6 @@ static struct mtd_partition spi_flash_part[] = { > }; > > static const struct flash_platform_data spi_flash_data = { > - .name = "m25p80", > .parts = spi_flash_part, > .nr_parts = ARRAY_SIZE(spi_flash_part), > .type = "s25fl512s", > diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c > index e65a80a..9745a73 100644 > --- a/arch/arm/mach-w90x900/dev.c > +++ b/arch/arm/mach-w90x900/dev.c > @@ -249,7 +249,6 @@ static struct mtd_partition nuc900_spi_flash_partitions[] = { > }; > > static struct flash_platform_data nuc900_spi_flash_data = { > - .name = "m25p80", > .parts = nuc900_spi_flash_partitions, > .nr_parts = ARRAY_SIZE(nuc900_spi_flash_partitions), > .type = "w25x16", > -- > 1.8.4.5 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-sh" in > the body of a message to majordomo at vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > From beanhuo at micron.com Mon Sep 29 19:47:39 2014 From: beanhuo at micron.com (=?iso-2022-jp?B?QmVhbiBIdW8gGyRCcDlJTElMGyhCIChiZWFuaHVvKQ==?=) Date: Tue, 30 Sep 2014 02:47:39 +0000 Subject: [PATCH 1/1 v3] driver:mtd:spi-nor: Add Micron quad I/O support References: <201409251211.57183.marex@denx.de> <201409261046.07132.marex@denx.de> Message-ID: For Micron spi norflash,enables or disables quad I/O protocol ,which controled by EVCR(Enhanced Volatile Configuration Register) Quad I/O protocol bit 7.When EVCR bit 7 is reset to 0, the spi norflash will operate in quad I/O following the next WRITE ENHANCED VOLATILE CONFIGURATION command. Signed-off-by: bean huo --- v1-v2:modified to that capture wait_till_ready() return value,if error,directly return its the value. v2-v3:directly use the reurning error value of read_reg and write_reg,instead of -EINVAL. drivers/mtd/spi-nor/spi-nor.c | 46 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 6 ++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..486b167 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -878,6 +878,45 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int micron_quad_enable(struct spi_nor *nor) +{ + int ret, val; + + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + + write_enable(nor); + + /* set EVCR ,enable quad I/O */ + nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; + ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); + if (ret < 0) { + dev_err(nor->dev, + "error while writing EVCR register\n"); + return ret; + } + + ret = wait_till_ready(nor); + if (ret) + return ret; + + /* read EVCR and check it */ + ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading EVCR\n", ret); + return ret; + } + if (val & EVCR_QUAD_EN_MICRON) { + dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); + return -EINVAL; + } + + return 0; +} + static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) { int status; @@ -890,6 +929,13 @@ static int set_quad_mode(struct spi_nor *nor, u32 jedec_id) return -EINVAL; } return status; + case CFI_MFR_ST: + status = micron_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Micron quad-read not enabled\n"); + return -EINVAL; + } + return status; default: status = spansion_quad_enable(nor); if (status) { diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 9e6294f..d71b659 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -56,6 +56,10 @@ /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ +/* Used for Micron flashes only. */ +#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ +#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ + /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ @@ -67,6 +71,8 @@ #define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ +#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */ + /* Flag Status Register bits */ #define FSR_READY 0x80 -- 1.7.9.5 From marex at denx.de Mon Sep 29 11:57:31 2014 From: marex at denx.de (Marek Vasut) Date: Mon, 29 Sep 2014 20:57:31 +0200 Subject: [PATCH 1/1 v2] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: References: <201409290043.43750.marex@denx.de> Message-ID: <201409292057.31274.marex@denx.de> On Monday, September 29, 2014 at 02:30:04 AM, bpqw wrote: > >> For Micron spi norflash,you can enable Quad spi transfer by clear > >> EVCR(Enhanced Volatile Configuration Register) Quad I/O protocol bit. > > > >OK, this information is nice and all, but what does this patch do? I can't > >learn this information from the commit message as it is, can I ? And , > >the purpose of the commit message is exactly to summarize the change the > >patch implements. > > you don't understand what purpose of this patch! Well, I dare to say, reacting to feedback like you just did won't make you many allies around here. > just as subject and commit > message described, it is for enable Micron Quad spi transfer mode. I understand the subject part. The commit message, on the other hand, just states that it is possible to frob with a certain register to achieve a certain effect ; the commit message does not state what this patch does or how is the patch useful. Does this patch enable the bit or does it disable the bit ? I cannot tell without looking into the code , I really have no clue just by reading the subject and the commit message. > do you > read the spi-nor.c file? No, I didn't even look at the code. > please pay attention to the set_quad_mode() > function. No, what set_quad_mode_function() are you talking about ... > by the way,I can add more commit message for it,but I think it is > redundant,don't need. The commit message shall state what the patch does in the first place, what the hardware can do is ortogonal to that. The commit message can be as short as: The hardware supports 4-bit I/O when bit FOO is set in register BAR. This patch adds function that sets bit FOO in register BAR to enable 4-bit I/O if condition BAZ and QUUX are met. Then I do not even have to look at the code if I want to just get the high-level overview of what the patch does. If I want to know the details, I will look into the code. Do you know what I'm getting at ? [...] Best regards, Marek Vasut From computersforpeace at gmail.com Mon Sep 29 20:55:58 2014 From: computersforpeace at gmail.com (Brian Norris) Date: Mon, 29 Sep 2014 20:55:58 -0700 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <1412042858.9388.79.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> <1412042858.9388.79.camel@decadent.org.uk> Message-ID: <20140930035558.GA8687@brian-ubuntu> On Tue, Sep 30, 2014 at 03:07:38AM +0100, Ben Hutchings wrote: > On Mon, 2014-09-29 at 08:36 +0200, Rafa? Mi?ecki wrote: > > b) I don't think the described clean solution (you described it in the > > commit message): > > > A clean solution to this will involve defining the list of device > > > IDs in spi-nor.h and removing struct spi_device_id from the spi-nor > > > API, but this is quite a large change. > > is the correct one. I think there should be a single string to trigger > > m25p80 load and the rest should be handled using JEDEC, with some > > workarounds for incompatible devices only. > > That certainly makes sense for Linux-specific platform data, but I don't > think it works for Device Tree "compatible" strings (see > ). I think it might work. Your quote from that thread: "I think that a DT node is always supposed to include a compatible string for the specific device. It could also include a generic compatible string for SPI NOR chips, but the *only* thing a driver can do with that is to use the JEDEC ID command. It can't even generically read a single byte, since addresses may be either 3 or 4 bytes long! So I think that if a generic compatible string is defined, the DT binding must also define the properties that spi-nor currently reads out of its static table." For every current entry (except the "*-nonjedec" entries; I don't think we should be supporting any more entries like this, and I'd like to kill the existing ones if possible), we can do just that; read out the JEDEC ID and go from there. (Rafal is also looking at non-JEDEC RDID commands, but that would just require a different type of binding.) In fact, for most of these entries, we'll read out the ID and override the match provided by the driver anyway. See: int spi_nor_scan(...) { ... [Note: almost all 'info' entries provide a non-zero jedec_id field] if (info->jedec_id) { const struct spi_device_id *jid; jid = nor->read_id(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let * mtd apply them anyway, since some partitions may be * marked read-only, and we don't want to lose that * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", jid->name, id->name); id = jid; info = (void *)jid->driver_data; } } ... } I think this chunk might be reworked (or at least, modify the comments) to note how we primarily expect to override the input ID. We might even drop the dev_warn() eventually, and make it more informative instead. > [...] > > b) Removing spi_nor::read_id > > https://patchwork.ozlabs.org/patch/389073/ > > Ben: I think this one has a NACK from me, because I'm going to use > > custom read_id in the bcm53xxspiflash driver. > > See following thread for bcm53xxspiflash description: > > http://comments.gmane.org/gmane.linux.drivers.mtd/54578 > > Initial commit (it uses read_id): https://patchwork.ozlabs.org/patch/381902/ > [...] > > But it has to use spi_nor_match_id() because of the driver_data > requirement. This just illustrates that the read_id operation doesn't > make sense as currently defined. Right. I think it may turn out better to drop it and force a redesign for the next user. > I accept that there will be a need for a read_id operation, but I think > it should fill in a struct flash_info rather than requiring every chip > to be described and named in spi-nor.c. Maybe struct flash_info, but this still leaks more spi-nor.c internal info into drivers. Perhaps Rafal's use case could be served by a select-able 'READ ID' opcode, with his flash_info structs still stored in spi_nor_ids[] -- or possibly as a separate ID table within spi-nor.c. But either way, I agree the current read_id() hook is not satisfactory. Brian From hujianyang at huawei.com Mon Sep 29 21:08:30 2014 From: hujianyang at huawei.com (hujianyang) Date: Tue, 30 Sep 2014 12:08:30 +0800 Subject: [PATCH v4 2/4] ubi-utils: ubidump: add libdump In-Reply-To: <542A2C57.3090401@huawei.com> References: <542A2C57.3090401@huawei.com> Message-ID: <542A2CBE.1050304@huawei.com> This is a preparatory patch for ubidump, an utility to print on-media format of UBIFS partitions. This patch includes the library functions used by ubidump. These functions are taken from linux kernel. Some of them are modified to work well in userspace. Signed-off-by: hujianyang --- ubi-utils/include/libdump.h | 78 ++++++++ ubi-utils/libdump.c | 440 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 518 insertions(+), 0 deletions(-) create mode 100644 ubi-utils/include/libdump.h create mode 100644 ubi-utils/libdump.c diff --git a/ubi-utils/include/libdump.h b/ubi-utils/include/libdump.h new file mode 100644 index 0000000..fe0286b --- /dev/null +++ b/ubi-utils/include/libdump.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * The *scan* part of code was taken from the kernel UBIFS implementation, and + * some "glub" definations needed by libdump.c was copied from mkfs.ubifs/defs.h + */ + +#ifndef __LIBDUMP_H__ +#define __LIBDUMP_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + +#define min_t(t,x,y) ({ \ + typeof((x)) _x = (x); \ + typeof((y)) _y = (y); \ + (_x < _y) ? _x : _y; \ +}) + +/* + * ubidump - dump ubi/ubifs information + * @lnum: logical eraseblock number + * @buf: buffer to dump + * @leb_size: size of buffer/logical eraseblock size + * @info: print NODEs detailed info + * + * This function dump ubi/ubifs information on the buffer. + */ +int ubi_dump(int lnum, void *buf, int leb_size, int info); + +/* Taken from kernel UBIFS implementation */ + +/* + * 'ubifs_scan_a_node()' return values. + * + * SCANNED_GARBAGE: scanned garbage + * SCANNED_EMPTY_SPACE: scanned empty space + * SCANNED_A_NODE: scanned a valid node + * SCANNED_A_CORRUPT_NODE: scanned a corrupted node + * SCANNED_A_BAD_PAD_NODE: scanned a padding node with invalid pad length + * + * Greater than zero means: 'scanned that number of padding bytes' + */ +enum { + SCANNED_GARBAGE = 0, + SCANNED_EMPTY_SPACE = -1, + SCANNED_A_NODE = -2, + SCANNED_A_CORRUPT_NODE = -3, + SCANNED_A_BAD_PAD_NODE = -4, +}; + +#ifdef __cplusplus +} +#endif + +#endif /*!__LIBDUMP_H__ */ diff --git a/ubi-utils/libdump.c b/ubi-utils/libdump.c new file mode 100644 index 0000000..6bb92e0 --- /dev/null +++ b/ubi-utils/libdump.c @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Great deal of the code was taken from kernel UBIFS implementation including + * fs/ubifs/scan.c and fs/ubifs/dump.c. There is a little difference in + * ubifs_scan(). The struct *ubifs_scan_leb* which contains the list of scanned + * NODEs was dropped because we can deal with each NODE directly. We don't need + * *corrupt* part of code either. In addition, a new parameter is added to + * indicate if ubifs_dump_node() is needed for a scanned NODE. + * + * Besides, ubifs_dump_node() can't dump all kinds of NODEs because some of + * them contain user data and useless for debugging. + */ + +#define PROGRAM_NAME "libdump" + +#include +#include +#include +#include +#include "common.h" + +static const char *get_key_fmt(int fmt) +{ + switch (fmt) { + case UBIFS_SIMPLE_KEY_FMT: + return "simple"; + default: + return "unknown/invalid format"; + } +} + +static const char *get_key_hash(int hash) +{ + switch (hash) { + case UBIFS_KEY_HASH_R5: + return "R5"; + case UBIFS_KEY_HASH_TEST: + return "test"; + default: + return "unknown/invalid name hash"; + } +} + +static const char *node_ntype(int type) +{ + switch (type) { + case UBIFS_PAD_NODE: + return "padding node"; + case UBIFS_SB_NODE: + return "superblock node"; + case UBIFS_MST_NODE: + return "master node"; + case UBIFS_REF_NODE: + return "reference node"; + case UBIFS_INO_NODE: + return "inode node"; + case UBIFS_DENT_NODE: + return "direntry node"; + case UBIFS_XENT_NODE: + return "xentry node"; + case UBIFS_DATA_NODE: + return "data node"; + case UBIFS_TRUN_NODE: + return "truncate node"; + case UBIFS_IDX_NODE: + return "indexing node"; + case UBIFS_CS_NODE: + return "commit start node"; + case UBIFS_ORPH_NODE: + return "orphan node"; + default: + return "unknown node"; + } +} + +static const char *node_gtype(int type) +{ + switch (type) { + case UBIFS_NO_NODE_GROUP: + return "no node group"; + case UBIFS_IN_NODE_GROUP: + return "in node group"; + case UBIFS_LAST_OF_NODE_GROUP: + return "last of node group"; + default: + return "unknown"; + } +} + +static void dump_ch(const struct ubifs_ch *ch) +{ + printf("\tmagic %#x\n", le32_to_cpu(ch->magic)); + printf("\tcrc %#x\n", le32_to_cpu(ch->crc)); + printf("\tnode_type %d (%s)\n", ch->node_type, + node_ntype(ch->node_type)); + printf("\tgroup_type %d (%s)\n", ch->group_type, + node_gtype(ch->group_type)); + printf("\tsqnum %llu\n", + (unsigned long long)le64_to_cpu(ch->sqnum)); + printf("\tlen %u\n", le32_to_cpu(ch->len)); +} + +/* + * This function is copied from linux kernel fs/ubifs/debug.c but + * just enable the dumping of PAD_NODE, SB_NODE, MST_NODE, REF_NODE + * and CS_NODE. + * + * One can add more functions by taking the code from kernel and + * put the on-media format to include/mtd/ubifs-media.h + */ +static void ubifs_dump_node(const void *node) +{ + const struct ubifs_ch *ch = node; + + if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { + printf("Not a node, first %zu bytes:\n", UBIFS_CH_SZ); + return; + } + + dump_ch(node); + + switch (ch->node_type) { + case UBIFS_PAD_NODE: + { + const struct ubifs_pad_node *pad = node; + + printf("\tpad_len %u\n", le32_to_cpu(pad->pad_len)); + break; + } + case UBIFS_SB_NODE: + { + const struct ubifs_sb_node *sup = node; + unsigned int sup_flags = le32_to_cpu(sup->flags); + + printf("\tkey_hash %d (%s)\n", + (int)sup->key_hash, get_key_hash(sup->key_hash)); + printf("\tkey_fmt %d (%s)\n", + (int)sup->key_fmt, get_key_fmt(sup->key_fmt)); + printf("\tflags %#x\n", sup_flags); + printf("\t big_lpt %u\n", + !!(sup_flags & UBIFS_FLG_BIGLPT)); + printf("\t space_fixup %u\n", + !!(sup_flags & UBIFS_FLG_SPACE_FIXUP)); + printf("\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size)); + printf("\tleb_size %u\n", le32_to_cpu(sup->leb_size)); + printf("\tleb_cnt %u\n", le32_to_cpu(sup->leb_cnt)); + printf("\tmax_leb_cnt %u\n", le32_to_cpu(sup->max_leb_cnt)); + printf("\tmax_bud_bytes %llu\n", + (unsigned long long)le64_to_cpu(sup->max_bud_bytes)); + printf("\tlog_lebs %u\n", le32_to_cpu(sup->log_lebs)); + printf("\tlpt_lebs %u\n", le32_to_cpu(sup->lpt_lebs)); + printf("\torph_lebs %u\n", le32_to_cpu(sup->orph_lebs)); + printf("\tjhead_cnt %u\n", le32_to_cpu(sup->jhead_cnt)); + printf("\tfanout %u\n", le32_to_cpu(sup->fanout)); + printf("\tlsave_cnt %u\n", le32_to_cpu(sup->lsave_cnt)); + printf("\tdefault_compr %u\n", + (int)le16_to_cpu(sup->default_compr)); + printf("\trp_size %llu\n", + (unsigned long long)le64_to_cpu(sup->rp_size)); + printf("\trp_uid %u\n", le32_to_cpu(sup->rp_uid)); + printf("\trp_gid %u\n", le32_to_cpu(sup->rp_gid)); + printf("\tfmt_version %u\n", le32_to_cpu(sup->fmt_version)); + printf("\ttime_gran %u\n", le32_to_cpu(sup->time_gran)); + printf("\tUUID %pUB\n", sup->uuid); + break; + } + case UBIFS_MST_NODE: + { + const struct ubifs_mst_node *mst = node; + + printf("\thighest_inum %llu\n", + (unsigned long long)le64_to_cpu(mst->highest_inum)); + printf("\tcommit number %llu\n", + (unsigned long long)le64_to_cpu(mst->cmt_no)); + printf("\tflags %#x\n", le32_to_cpu(mst->flags)); + printf("\tlog_lnum %u\n", le32_to_cpu(mst->log_lnum)); + printf("\troot_lnum %u\n", le32_to_cpu(mst->root_lnum)); + printf("\troot_offs %u\n", le32_to_cpu(mst->root_offs)); + printf("\troot_len %u\n", le32_to_cpu(mst->root_len)); + printf("\tgc_lnum %u\n", le32_to_cpu(mst->gc_lnum)); + printf("\tihead_lnum %u\n", le32_to_cpu(mst->ihead_lnum)); + printf("\tihead_offs %u\n", le32_to_cpu(mst->ihead_offs)); + printf("\tindex_size %llu\n", + (unsigned long long)le64_to_cpu(mst->index_size)); + printf("\tlpt_lnum %u\n", le32_to_cpu(mst->lpt_lnum)); + printf("\tlpt_offs %u\n", le32_to_cpu(mst->lpt_offs)); + printf("\tnhead_lnum %u\n", le32_to_cpu(mst->nhead_lnum)); + printf("\tnhead_offs %u\n", le32_to_cpu(mst->nhead_offs)); + printf("\tltab_lnum %u\n", le32_to_cpu(mst->ltab_lnum)); + printf("\tltab_offs %u\n", le32_to_cpu(mst->ltab_offs)); + printf("\tlsave_lnum %u\n", le32_to_cpu(mst->lsave_lnum)); + printf("\tlsave_offs %u\n", le32_to_cpu(mst->lsave_offs)); + printf("\tlscan_lnum %u\n", le32_to_cpu(mst->lscan_lnum)); + printf("\tleb_cnt %u\n", le32_to_cpu(mst->leb_cnt)); + printf("\tempty_lebs %u\n", le32_to_cpu(mst->empty_lebs)); + printf("\tidx_lebs %u\n", le32_to_cpu(mst->idx_lebs)); + printf("\ttotal_free %llu\n", + (unsigned long long)le64_to_cpu(mst->total_free)); + printf("\ttotal_dirty %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dirty)); + printf("\ttotal_used %llu\n", + (unsigned long long)le64_to_cpu(mst->total_used)); + printf("\ttotal_dead %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dead)); + printf("\ttotal_dark %llu\n", + (unsigned long long)le64_to_cpu(mst->total_dark)); + break; + } + case UBIFS_REF_NODE: + { + const struct ubifs_ref_node *ref = node; + + printf("\tlnum %u\n", le32_to_cpu(ref->lnum)); + printf("\toffs %u\n", le32_to_cpu(ref->offs)); + printf("\tjhead %u\n", le32_to_cpu(ref->jhead)); + break; + } + case UBIFS_CS_NODE: + break; + case UBIFS_INO_NODE: + case UBIFS_DENT_NODE: + case UBIFS_XENT_NODE: + case UBIFS_DATA_NODE: + case UBIFS_TRUN_NODE: + case UBIFS_IDX_NODE: + case UBIFS_ORPH_NODE: + printf("cannot dump node, type not support\n"); + default: + printf("node type %d was not recognized\n", + (int)ch->node_type); + } +} + +/** + * scan_padding_bytes - scan for padding bytes. + * @buf: buffer to scan + * @len: length of buffer + * + * This function returns the number of padding bytes on success and + * %SCANNED_GARBAGE on failure. + */ +static int scan_padding_bytes(void *buf, int len) +{ + int pad_len = 0, max_pad_len = min_t(int, UBIFS_PAD_NODE_SZ, len); + uint8_t *p = buf; + + printf("not a node\n"); + + while (pad_len < max_pad_len && *p++ == UBIFS_PADDING_BYTE) + pad_len += 1; + + if (!pad_len || (pad_len & 7)) + return SCANNED_GARBAGE; + + printf("%d padding bytes\n", pad_len); + + return pad_len; +} + +/** + * ubifs_scan_a_node - scan for a node or padding. + * @buf: buffer to scan + * @size: logical eraseblock size + * @len: length of buffer + * @lnum: logical eraseblock number + * @offs: offset within the logical eraseblock + * + * This function returns a scanning code to indicate what was scanned. + */ +static int ubifs_scan_a_node(void *buf, int leb_size, int len, int lnum, int offs) +{ + struct ubifs_ch *ch = buf; + uint32_t magic; + + magic = le32_to_cpu(ch->magic); + + if (magic == 0xFFFFFFFF) { + printf("hit empty space at LEB %d:%d\n", lnum, offs); + return SCANNED_EMPTY_SPACE; + } + + if (magic != UBIFS_NODE_MAGIC) + return scan_padding_bytes(buf, len); + + if (len < UBIFS_CH_SZ) + return SCANNED_GARBAGE; + + printf("scanning %s at LEB %d:%d\n", + node_ntype(ch->node_type), lnum, offs); + + /* No ubifs_check_nodei() perform here */ + + if (ch->node_type == UBIFS_PAD_NODE) { + struct ubifs_pad_node *pad = buf; + int pad_len = le32_to_cpu(pad->pad_len); + int node_len = le32_to_cpu(ch->len); + + /* Validate the padding node */ + if (pad_len < 0 || + offs + node_len + pad_len > leb_size) { + printf("bad pad node at LEB %d:%d\n", lnum, offs); + ubifs_dump_node(pad); + return SCANNED_A_BAD_PAD_NODE; + } + + /* Make the node pads to 8-byte boundary */ + if ((node_len + pad_len) & 7) { + printf("bad padding length %d - %d\n", + offs, offs + node_len + pad_len); + return SCANNED_A_BAD_PAD_NODE; + } + + printf("%d bytes padded at LEB %d:%d, offset now %d\n", pad_len, + lnum, offs, ALIGN(offs + node_len + pad_len, 8)); + + return node_len + pad_len; + } + + return SCANNED_A_NODE; +} + +/** + * ubifs_scan - scan a logical eraseblock. + * @lnum: logical eraseblock number + * @sbuf: scan buffer + * @size: size of @buf in bytes + * @offs: offset to start at (usually zero) + * @info: print NODEs detailed info + * + * This function scans LEB number @lnum and prints complete information about + * its contents. If @info is non-zero, this function will print dump messages + * of each scanned NODE. + * + * Note, it's a simplified version of ubifs_scan() in kernel fs/ubifs/scan.c. + * The struct *ubifs_scan_leb* is removed, we directly deal with each scanned + * NODE. The *corrupt* part of code is removed either because this function + * just print the contents of an LEB without checking its correctness. Beside, + * a new parameter @info is added for the dumping of NODEs. + */ +static void ubifs_scan(int lnum, void *sbuf, int leb_size, int offs, int info) +{ + void *buf = sbuf + offs; + int err, len = leb_size - offs; + + printf("scan LEB %d:%d\n", lnum, offs); + + while (len >= 8) { + struct ubifs_ch *ch = buf; + int node_len, ret; + + printf("look at LEB %d:%d (%d bytes left)\n", + lnum, offs, len); + + ret = ubifs_scan_a_node(buf, leb_size, len, lnum, offs); + if (ret > 0) { + /* Padding bytes or a valid padding node */ + offs += ret; + buf += ret; + len -= ret; + continue; + } + + if (ret == SCANNED_EMPTY_SPACE) + /* Empty space is checked later */ + break; + + switch (ret) { + case SCANNED_GARBAGE: + printf("garbage\n"); + goto corrupted; + case SCANNED_A_NODE: + if (info) + ubifs_dump_node(buf); + break; + case SCANNED_A_CORRUPT_NODE: + case SCANNED_A_BAD_PAD_NODE: + printf("bad node\n"); + goto corrupted; + default: + printf("unknown\n"); + err = -EINVAL; + goto error; + } + + node_len = ALIGN(le32_to_cpu(ch->len), 8); + offs += node_len; + buf += node_len; + len -= node_len; + } + + for (; len > 4; offs += 4, buf = buf + 4, len -= 4) + if (*(uint32_t *)buf != 0xffffffff) + break; + for (; len; offs++, buf++, len--) + if (*(uint8_t *)buf != 0xff) { + printf("corrupt empty space at LEB %d:%d\n", + lnum, offs); + goto corrupted; + } + + printf("stop scanning LEB %d at offset %d\n", lnum, offs); + return; + +corrupted: + printf("corruption at LEB %d:%d\n", lnum, offs); + err = -EUCLEAN; +error: + printf("LEB %d scanning failed, error %d\n", lnum, err); +} + +/** + * ubidump - dump ubi/ubifs information + * @lnum: logical eraseblock number + * @buf: buffer to dump + * @leb_size: size of buffer/logical eraseblock size + * @info: print NODEs detailed info + * + * This function dump ubi/ubifs information on the buffer. + */ +int ubi_dump(int lnum, void *buf, int leb_size, int info) +{ + ubifs_scan(lnum, buf, leb_size, 0, info); + return 0; +} -- 1.6.0.2 From hujianyang at huawei.com Mon Sep 29 21:06:47 2014 From: hujianyang at huawei.com (hujianyang) Date: Tue, 30 Sep 2014 12:06:47 +0800 Subject: [PATCH v4 1/4] ubi-utils: ubidump: add ubifs-media Message-ID: <542A2C57.3090401@huawei.com> This is a preparatory patch for ubidump, an utility to print on-media format of UBIFS partitions. This patch contains only one file named ubifs-media.h which is entirely taken from linux kernel. This file descibes the on-flash format of UBIFS objects and helps us to analyse the data on the media. Note, the start up commit of this file is not a completely copy from fs/ubifs/ubifs-media.h in kernel. Only the code which is used by ubidump is now presented here. Signed-off-by: hujianyang --- include/mtd/ubifs-media.h | 298 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 298 insertions(+), 0 deletions(-) create mode 100644 include/mtd/ubifs-media.h diff --git a/include/mtd/ubifs-media.h b/include/mtd/ubifs-media.h new file mode 100644 index 0000000..d59dfa6 --- /dev/null +++ b/include/mtd/ubifs-media.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + */ + +/* + * This file defines the layout of UBI headers and all the other UBIFS + * on-flash data structures. + */ + +/* + * Note, the entire code of this file was taken from linux kernel + * driver/mtd/ubi/ubi-media.h. But not all of the code in kernel was + * copied here because this file is *now* only used by ubidump, only + * the code which is needed by libdump.c is presented. + */ + +#ifndef __UBIFS_MEDIA_H__ +#define __UBIFS_MEDIA_H__ + +#include + +/* UBIFS node magic number (must not have the padding byte first or last) */ +#define UBIFS_NODE_MAGIC 0x06101831 + +/* UBIFS padding byte pattern (must not be first or last byte of node magic) */ +#define UBIFS_PADDING_BYTE 0xCE + +/* Node sizes (N.B. these are guaranteed to be multiples of 8) */ +#define UBIFS_CH_SZ sizeof(struct ubifs_ch) +#define UBIFS_PAD_NODE_SZ sizeof(struct ubifs_pad_node) + +/* + * UBIFS node types. + * + * UBIFS_INO_NODE: inode node + * UBIFS_DATA_NODE: data node + * UBIFS_DENT_NODE: directory entry node + * UBIFS_XENT_NODE: extended attribute node + * UBIFS_TRUN_NODE: truncation node + * UBIFS_PAD_NODE: padding node + * UBIFS_SB_NODE: superblock node + * UBIFS_MST_NODE: master node + * UBIFS_REF_NODE: LEB reference node + * UBIFS_IDX_NODE: index node + * UBIFS_CS_NODE: commit start node + * UBIFS_ORPH_NODE: orphan node + * UBIFS_NODE_TYPES_CNT: count of supported node types + * + * Note, we index arrays by these numbers, so keep them low and contiguous. + * Node type constants for inodes, direntries and so on have to be the same as + * corresponding key type constants. + */ +enum { + UBIFS_INO_NODE, + UBIFS_DATA_NODE, + UBIFS_DENT_NODE, + UBIFS_XENT_NODE, + UBIFS_TRUN_NODE, + UBIFS_PAD_NODE, + UBIFS_SB_NODE, + UBIFS_MST_NODE, + UBIFS_REF_NODE, + UBIFS_IDX_NODE, + UBIFS_CS_NODE, + UBIFS_ORPH_NODE, + UBIFS_NODE_TYPES_CNT, +}; + +/* + * Supported key hash functions. + * + * UBIFS_KEY_HASH_R5: R5 hash + * UBIFS_KEY_HASH_TEST: test hash which just returns first 4 bytes of the name + */ +enum { + UBIFS_KEY_HASH_R5, + UBIFS_KEY_HASH_TEST, +}; + +/* + * Supported key formats. + * + * UBIFS_SIMPLE_KEY_FMT: simple key format + */ +enum { + UBIFS_SIMPLE_KEY_FMT, +}; + +/* + * Node group type (used by recovery to recover whole group or none). + * + * UBIFS_NO_NODE_GROUP: this node is not part of a group + * UBIFS_IN_NODE_GROUP: this node is a part of a group + * UBIFS_LAST_OF_NODE_GROUP: this node is the last in a group + */ +enum { + UBIFS_NO_NODE_GROUP = 0, + UBIFS_IN_NODE_GROUP, + UBIFS_LAST_OF_NODE_GROUP, +}; + +/* + * Superblock flags. + * + * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set + * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed + */ +enum { + UBIFS_FLG_BIGLPT = 0x02, + UBIFS_FLG_SPACE_FIXUP = 0x04, +}; + +/** + * struct ubifs_ch - common header node. + * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) + * @crc: CRC-32 checksum of the node header + * @sqnum: sequence number + * @len: full node length + * @node_type: node type + * @group_type: node group type + * @padding: reserved for future, zeroes + * + * Every UBIFS node starts with this common part. If the node has a key, the + * key always goes next. + */ +struct ubifs_ch { + __le32 magic; + __le32 crc; + __le64 sqnum; + __le32 len; + __u8 node_type; + __u8 group_type; + __u8 padding[2]; +} __attribute__ ((packed)); + +/** + * struct ubifs_pad_node - padding node. + * @ch: common header + * @pad_len: how many bytes after this node are unused (because padded) + * @padding: reserved for future, zeroes + */ +struct ubifs_pad_node { + struct ubifs_ch ch; + __le32 pad_len; +} __attribute__ ((packed)); + +/** + * struct ubifs_sb_node - superblock node. + * @ch: common header + * @padding: reserved for future, zeroes + * @key_hash: type of hash function used in keys + * @key_fmt: format of the key + * @flags: file-system flags (%UBIFS_FLG_BIGLPT, etc) + * @min_io_size: minimal input/output unit size + * @leb_size: logical eraseblock size in bytes + * @leb_cnt: count of LEBs used by file-system + * @max_leb_cnt: maximum count of LEBs used by file-system + * @max_bud_bytes: maximum amount of data stored in buds + * @log_lebs: log size in logical eraseblocks + * @lpt_lebs: number of LEBs used for lprops table + * @orph_lebs: number of LEBs used for recording orphans + * @jhead_cnt: count of journal heads + * @fanout: tree fanout (max. number of links per indexing node) + * @lsave_cnt: number of LEB numbers in LPT's save table + * @fmt_version: UBIFS on-flash format version + * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) + * @padding1: reserved for future, zeroes + * @rp_uid: reserve pool UID + * @rp_gid: reserve pool GID + * @rp_size: size of the reserved pool in bytes + * @padding2: reserved for future, zeroes + * @time_gran: time granularity in nanoseconds + * @uuid: UUID generated when the file system image was created + * @ro_compat_version: UBIFS R/O compatibility version + */ +struct ubifs_sb_node { + struct ubifs_ch ch; + __u8 padding[2]; + __u8 key_hash; + __u8 key_fmt; + __le32 flags; + __le32 min_io_size; + __le32 leb_size; + __le32 leb_cnt; + __le32 max_leb_cnt; + __le64 max_bud_bytes; + __le32 log_lebs; + __le32 lpt_lebs; + __le32 orph_lebs; + __le32 jhead_cnt; + __le32 fanout; + __le32 lsave_cnt; + __le32 fmt_version; + __le16 default_compr; + __u8 padding1[2]; + __le32 rp_uid; + __le32 rp_gid; + __le64 rp_size; + __le32 time_gran; + __u8 uuid[16]; + __le32 ro_compat_version; + __u8 padding2[3968]; +} __attribute__ ((packed)); + +/** + * struct ubifs_mst_node - master node. + * @ch: common header + * @highest_inum: highest inode number in the committed index + * @cmt_no: commit number + * @flags: various flags (%UBIFS_MST_DIRTY, etc) + * @log_lnum: start of the log + * @root_lnum: LEB number of the root indexing node + * @root_offs: offset within @root_lnum + * @root_len: root indexing node length + * @gc_lnum: LEB reserved for garbage collection (%-1 value means the LEB was + * not reserved and should be reserved on mount) + * @ihead_lnum: LEB number of index head + * @ihead_offs: offset of index head + * @index_size: size of index on flash + * @total_free: total free space in bytes + * @total_dirty: total dirty space in bytes + * @total_used: total used space in bytes (includes only data LEBs) + * @total_dead: total dead space in bytes (includes only data LEBs) + * @total_dark: total dark space in bytes (includes only data LEBs) + * @lpt_lnum: LEB number of LPT root nnode + * @lpt_offs: offset of LPT root nnode + * @nhead_lnum: LEB number of LPT head + * @nhead_offs: offset of LPT head + * @ltab_lnum: LEB number of LPT's own lprops table + * @ltab_offs: offset of LPT's own lprops table + * @lsave_lnum: LEB number of LPT's save table (big model only) + * @lsave_offs: offset of LPT's save table (big model only) + * @lscan_lnum: LEB number of last LPT scan + * @empty_lebs: number of empty logical eraseblocks + * @idx_lebs: number of indexing logical eraseblocks + * @leb_cnt: count of LEBs used by file-system + * @padding: reserved for future, zeroes + */ +struct ubifs_mst_node { + struct ubifs_ch ch; + __le64 highest_inum; + __le64 cmt_no; + __le32 flags; + __le32 log_lnum; + __le32 root_lnum; + __le32 root_offs; + __le32 root_len; + __le32 gc_lnum; + __le32 ihead_lnum; + __le32 ihead_offs; + __le64 index_size; + __le64 total_free; + __le64 total_dirty; + __le64 total_used; + __le64 total_dead; + __le64 total_dark; + __le32 lpt_lnum; + __le32 lpt_offs; + __le32 nhead_lnum; + __le32 nhead_offs; + __le32 ltab_lnum; + __le32 ltab_offs; + __le32 lsave_lnum; + __le32 lsave_offs; + __le32 lscan_lnum; + __le32 empty_lebs; + __le32 idx_lebs; + __le32 leb_cnt; + __u8 padding[344]; +} __attribute__ ((packed)); + +/** + * struct ubifs_ref_node - logical eraseblock reference node. + * @ch: common header + * @lnum: the referred logical eraseblock number + * @offs: start offset in the referred LEB + * @jhead: journal head number + * @padding: reserved for future, zeroes + */ +struct ubifs_ref_node { + struct ubifs_ch ch; + __le32 lnum; + __le32 offs; + __le32 jhead; + __u8 padding[28]; +} __attribute__ ((packed)); + +#endif /*!__UBIFS_MEDIA_H__ */ -- 1.6.0.2 From hujianyang at huawei.com Mon Sep 29 21:09:43 2014 From: hujianyang at huawei.com (hujianyang) Date: Tue, 30 Sep 2014 12:09:43 +0800 Subject: [PATCH v4 3/4] ubi-utils: ubidump: introduce ubidump In-Reply-To: <542A2C57.3090401@huawei.com> References: <542A2C57.3090401@huawei.com> Message-ID: <542A2D07.7070408@huawei.com> This patch introude a new utility named ubidump. This utiltiy can dump a specific leb to userspace(maybe a arrange of lebs in the future). We don't have an useful tool to get data from a specified logical erase block and to describe what it contains in userspace before. I suppose if this utility could help us overcome these problems and give us a new way to analyse the behaviour of UBI/UBIFS without changing kernel. Artem (dedekind1 at gmail.com) and Bill (bpringlemeir at nbsps.com) also contribute a lot to this utility. I appreciate their help very much. Only the UBIFS level dumping is supported now, we've discussed and tried many ways to realize UBI level dumping but didn't reach an agreement. I'll keep working on it. I think this work is just the beginning of enriching UBI/UBIFS debugging. Changes in v4: - rewrite the header and copyright of each file. - add comments for modified files and functions. v1: http://lists.infradead.org/pipermail/linux-mtd/2014-July/054541.html v2: http://lists.infradead.org/pipermail/linux-mtd/2014-July/054831.html v3: http://lists.infradead.org/pipermail/linux-mtd/2014-September/055463.html Signed-off-by: hujianyang --- ubi-utils/ubidump.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 223 insertions(+), 0 deletions(-) create mode 100644 ubi-utils/ubidump.c diff --git a/ubi-utils/ubidump.c b/ubi-utils/ubidump.c new file mode 100644 index 0000000..40834dd --- /dev/null +++ b/ubi-utils/ubidump.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2008 Nokia Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * An utility to dump UBI/UBIFS format data in eraseblock + * + * Author: Hu Jianyang + */ + +#define PROGRAM_NAME "ubidump" + +#include +#include +#include + +#include +#include +#include +#include "common.h" +#include "ubiutils-common.h" + +/* The variables below are set by command line arguments */ +struct args { + const char *vol; + int lnum; + int info:1; +}; + +static struct args args = +{ + .vol = NULL, + .lnum = -1, + .info = 0, +}; + +static const char doc[] = PROGRAM_NAME " version " VERSION + " - an utility to dump UBI/UBIFS format data in eraseblock"; + +static const char optionsstr[] = +"-h, --help print help message\n" +"-l, --lnum logic eraseblock num to dump\n" +"-i, --info show explicit information about ubifs-level\n" +"-V, --version print program version"; + +static const char usage[] = +"Usage: " PROGRAM_NAME " [-l ] [-i]\n" +"\t\t\t[--help] [--version]\n\n" +"Example 1: " PROGRAM_NAME " /dev/ubi0_1 --lnum 2 - dump leb 2 in volume 1\n" +"Example 2: " PROGRAM_NAME " /dev/ubi0_0 -l 1234 -i - dump leb 1234 with explicit info\n"; + +static const struct option long_options[] = { + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = "lnum", .has_arg = 1, .flag = NULL, .val = 'l' }, + { .name = "info", .has_arg = 0, .flag = NULL, .val = 'i' }, + { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' }, + { NULL, 0, NULL, 0} +}; + +static int parse_opt(int argc, char * const argv[]) +{ + while (1) { + int key, error = 0; + + key = getopt_long(argc, argv, "h?il:", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'l': + args.lnum = simple_strtoul(optarg, &error); + if (error || args.lnum < 0) + return errmsg("bad lnum: \"%s\"", optarg); + break; + + case 'i': + args.info = 1; + break; + + case 'h': + case '?': + printf("%s\n\n", doc); + printf("%s\n\n", usage); + printf("%s\n", optionsstr); + exit(EXIT_SUCCESS); + + case 'V': + common_print_version(); + exit(EXIT_SUCCESS); + + case ':': + return errmsg("parameter is missing"); + + default: + fprintf(stderr, "Use -h for help\n"); + return -1; + } + } + if (optind == argc) + return errmsg("UBI device name was not specified (use -h for help)"); + else if (optind != argc - 1) + return errmsg("more then one UBI device specified (use -h for help)"); + + args.vol = argv[optind]; + + if (args.lnum < 0) + return errmsg("lnum was not specified (use -h for help)"); + + return 0; +} + +static int dump_eraseblock(int fd, struct ubi_vol_info *vol_info) +{ + int ret, leb_size, lnum; + off_t offs; + char *buf; + + leb_size = vol_info->leb_size; + lnum = args.lnum; + + ret = ubi_is_mapped(fd, lnum); + if (ret == 0) { + errmsg("lnum %d is not mapped", lnum); + goto out; + } else if (ret < 0) { + sys_errmsg("ubi_is_mapped() failed"); + goto out; + } + + buf = malloc(leb_size); + if (!buf) + return errmsg("cannot allocate %d bytes of memory", + leb_size); + offs = lnum * leb_size; + + ret = pread(fd, buf, leb_size, offs); + if (ret != leb_size) { + errmsg("cannot read %d bytes at lnum %d, read %d", + leb_size, lnum, ret); + goto out_free; + } + + ret = ubi_dump(lnum, buf, leb_size, args.info); + +out_free: + free(buf); +out: + return ret; +} + +int main(int argc, char * const argv[]) +{ + int err, fd; + libubi_t libubi; + struct ubi_vol_info vol_info; + + err = parse_opt(argc, argv); + if (err) + return -1; + + libubi = libubi_open(); + if (!libubi) { + if (errno == 0) + errmsg("UBI is not present in the system"); + else + sys_errmsg("cannot open libubi"); + goto out_libubi; + } + + err = ubi_probe_node(libubi, args.vol); + if (err == 1) { + errmsg("\"%s\" is an UBI device node, not an UBI volume node", + args.vol); + goto out_libubi; + } else if (err < 0) { + if (errno == ENODEV) + errmsg("\"%s\" is not an UBI volume node", args.vol); + else + sys_errmsg("error while probing \"%s\"", args.vol); + goto out_libubi; + } + + err = ubi_get_vol_info(libubi, args.vol, &vol_info); + if (err) { + sys_errmsg("cannot get information about UBI volume \"%s\"", + args.vol); + goto out_libubi; + } + + fd = open(args.vol, O_RDONLY); + if (fd == -1) { + sys_errmsg("cannot open UBI volume \"%s\"", args.vol); + goto out_libubi; + } + + err = dump_eraseblock(fd, &vol_info); + if (err) + goto out_fd; + + close(fd); + libubi_close(libubi); + return 0; + +out_fd: + close(fd); +out_libubi: + libubi_close(libubi); + return -1; +} -- 1.6.0.2 From hujianyang at huawei.com Mon Sep 29 21:10:43 2014 From: hujianyang at huawei.com (hujianyang) Date: Tue, 30 Sep 2014 12:10:43 +0800 Subject: [PATCH v4 4/4] ubi-utils: ubidump: compile enable In-Reply-To: <542A2C57.3090401@huawei.com> References: <542A2C57.3090401@huawei.com> Message-ID: <542A2D43.3060107@huawei.com> This patch is the last part of ubidump. We enable the compile of this new utility by it. Signed-off-by: hujianyang --- Makefile | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index eade234..9dc9645 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ MTD_BINS = \ sumtool jffs2reader UBI_BINS = \ ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ - ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock + ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock \ + ubidump BINS = $(MTD_BINS) BINS += mkfs.ubifs/mkfs.ubifs @@ -115,10 +116,12 @@ obj-libiniparser.a = libiniparser.o dictionary.o obj-libscan.a = libscan.o obj-libubi.a = libubi.o obj-libubigen.a = libubigen.o +obj-libdump.a = libdump.o obj-mtdinfo = libubigen.a obj-ubinize = libubigen.a libiniparser.a obj-ubiformat = libubigen.a libscan.a +obj-ubidump = libdump.a -$(foreach v,libubi.a libubigen.a libiniparser.a libscan.a,$(eval $(call _mkdep,ubi-utils/,$(v)))) +$(foreach v,libubi.a libubigen.a libiniparser.a libscan.a libdump.a,$(eval $(call _mkdep,ubi-utils/,$(v)))) $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-common.o))) -- 1.6.0.2 From zajec5 at gmail.com Mon Sep 29 22:14:15 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Tue, 30 Sep 2014 07:14:15 +0200 Subject: [PATCH v2 3/5] spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id In-Reply-To: <1412043317.9388.84.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> <1412043317.9388.84.camel@decadent.org.uk> Message-ID: On 30 September 2014 04:15, Ben Hutchings wrote: > @@ -236,16 +236,13 @@ static int m25p_probe(struct spi_device *spi) > * If that's the case, respect "type" and ignore a "name". > */ > if (data && data->type) > - id = spi_nor_match_id(data->type); > + name = data->type; > > /* If we didn't get name from platform, simply use "modalias". */ > - if (!id) { > - id = spi_nor_match_id(spi_get_device_id(spi)->name); > - if (WARN_ON(!id)) > - return -ENODEV; > - } > + if (!name) > + name = spi_get_device_id(spi)->name; Huh? Iterating the whole id_table, checking the entries (looking for one with name equal to the spi->modalias) and then... getting that name? Did it hurt to use the patch I've sent mtd: m25p80: get rid of spi_get_device_id https://patchwork.ozlabs.org/patch/394328/ From zajec5 at gmail.com Mon Sep 29 22:09:38 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Tue, 30 Sep 2014 07:09:38 +0200 Subject: [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 In-Reply-To: <1412042858.9388.79.camel@decadent.org.uk> References: <1410714624.3040.38.camel@decadent.org.uk> <1410714670.3040.39.camel@decadent.org.uk> <20140928222150.GC3248@norris-Latitude-E6410> <1412042858.9388.79.camel@decadent.org.uk> Message-ID: On 30 September 2014 04:07, Ben Hutchings wrote: > On Mon, 2014-09-29 at 08:36 +0200, Rafa? Mi?ecki wrote: >> On 29 September 2014 00:21, Brian Norris wrote: >> > + Rafal >> > >> > Rafal has been looking at the same area of code. I'd really like to get >> > this patch into 3.18 if possible, so the more eyes the better. >> >> Thanks Brian. >> >> I took me a while to follow this issue, too bad I wasn't subscribed to >> the ML earlier. Let me try to sum it up. >> >> >> >> 1) The main urgent issue: broken auto-loading >> Tracked in the thread: http://www.spinics.net/lists/linux-spi/msg01726.html >> Problem: m25p80.c references spi_nor_ids (from external file) >> Short-term solution: duplicate IDs in the m25p80.c >> >> Ben: just like Brian, I think the patch like this one ( >> [PATCH 1/5] m25p80,spi-nor: Fix module aliases for m25p80 >> ) is the way to go. However few comments: >> >> a) I don't see why you modify m25p_probe in it. > > Because spi_nor_scan() requires a struct spi_device_id with the > driver_data field pointing to a struct flash_info. More friendly explanation: because spi_get_device_id uses driver's id_table (that was now changes to pure strings). I see the point. >> b) I don't think the described clean solution (you described it in the >> commit message): >> > A clean solution to this will involve defining the list of device >> > IDs in spi-nor.h and removing struct spi_device_id from the spi-nor >> > API, but this is quite a large change. >> is the correct one. I think there should be a single string to trigger >> m25p80 load and the rest should be handled using JEDEC, with some >> workarounds for incompatible devices only. > > That certainly makes sense for Linux-specific platform data, but I don't > think it works for Device Tree "compatible" strings (see > ). We could simply follow the way Linux-specific platform data works. We could always use compatible = "m25p80"; and then for some rare cases (where JEDEC fails) add something like model = "at25df321a"; >> b) Removing spi_nor::read_id >> https://patchwork.ozlabs.org/patch/389073/ >> Ben: I think this one has a NACK from me, because I'm going to use >> custom read_id in the bcm53xxspiflash driver. >> See following thread for bcm53xxspiflash description: >> http://comments.gmane.org/gmane.linux.drivers.mtd/54578 >> Initial commit (it uses read_id): https://patchwork.ozlabs.org/patch/381902/ > [...] > > But it has to use spi_nor_match_id() because of the driver_data > requirement. This just illustrates that the read_id operation doesn't > make sense as currently defined. I agree, however there is already a patch in progress handling that: https://patchwork.ozlabs.org/patch/377917/ > I accept that there will be a need for a read_id operation, but I think > it should fill in a struct flash_info rather than requiring every chip > to be described and named in spi-nor.c. Flashes not supporting JEDEC are usually some weird versions of normal flashes with JEDEC support. So I think we could still have them in the spi-nor database and let users provide the name instead of filling the whole struct flash_info. -- Rafa? From dedekind1 at gmail.com Mon Sep 29 23:26:06 2014 From: dedekind1 at gmail.com (Artem Bityutskiy) Date: Tue, 30 Sep 2014 09:26:06 +0300 Subject: [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL shutdown In-Reply-To: <1412029248-22454-2-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-2-git-send-email-richard@nod.at> Message-ID: <1412058366.23429.77.camel@sauron.fi.intel.com> On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: > ...otherwise the deferred work might run after datastructures > got freed and corrupt memory. How can this happend? The background thread is stopped by this time already, so what are the other possibilities? And why is this fastmap-only? -- Best Regards, Artem Bityutskiy From artem.bityutskiy at intel.com Mon Sep 29 23:31:50 2014 From: artem.bityutskiy at intel.com (Bityutskiy, Artem) Date: Tue, 30 Sep 2014 06:31:50 +0000 Subject: Two lame typo fixes In-Reply-To: References: <1410874236-3125-1-git-send-email-richard@nod.at> Message-ID: <1412058710.3904.0.camel@sauron.fi.intel.com> On Tue, 2014-09-30 at 00:24 +0200, Richard Weinberger wrote: > On Tue, Sep 16, 2014 at 3:30 PM, Richard Weinberger wrote: > > ...found them while browsing. > > > > Thanks, > > //richard > > > > [PATCH 1/2] UBI: Fix trivial typo in __schedule_ubi_work > > [PATCH 2/2] UBIFS: Fix trivial typo in power_cut_emulated() > > ping? Pushed both, thanks! -- Best Regards, Artem Bityutskiy --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. From artem.bityutskiy at intel.com Mon Sep 29 23:41:19 2014 From: artem.bityutskiy at intel.com (Bityutskiy, Artem) Date: Tue, 30 Sep 2014 06:41:19 +0000 Subject: [RFC] UBI bitrot checking In-Reply-To: <1411509976-12636-1-git-send-email-richard@nod.at> References: <1411509976-12636-1-git-send-email-richard@nod.at> Message-ID: <1412059278.3904.8.camel@sauron.fi.intel.com> On Wed, 2014-09-24 at 00:06 +0200, Richard Weinberger wrote: > This is a very initial draft for one possibility of bitrot checking in UBI. > The basic idea is to have a worker function which reads a complete PEB and > schedules scrubbing if bit flips are detected. > Currently this check is triggered by accessing any UBI debugfs file (yes, I'm lazy!). > We have to agree on an interface first. > Do we want a debugfs file? Another ioctl()? > Automatic in-kernel schedules? > Of course this interface has to return EBUSY if currently a check is running... > > The current implementation has one limitation, it can only check PEBs which are used. > As of now ubi_wl_scrub_peb() works only for used PEBs but I think we could change that. Most probably we do want to give user-space some kind of control. At the very least: 1. Whether the unflipper (or bitunrotter?) is triggered or not at all 2. When is it triggered 3. Whether the unflipper finished the job or not 4. For #3, it is preferrable that user-space has a possibility to wait for an event, rather than poll. Should be easy to do with sysfs. And no, not debugfs, this is not a debugging feature. Sysfs or, less preferrably, IMO, ioctl. Then, question - do we want user-space to have more control over the unflipper, e.g., pause it and resume? E.g., if we are talking a critical path, like a phone call on a phone, user-space may pause the unflipper to make sure the phone UI latency stays within certain limits. We need to consider various usage scenarios and make sure the interface is suitable. And we do not have to implement all the features, just make sure we can add them in the future if needed. -- Best Regards, Artem Bityutskiy --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. From artem.bityutskiy at intel.com Mon Sep 29 23:45:24 2014 From: artem.bityutskiy at intel.com (Bityutskiy, Artem) Date: Tue, 30 Sep 2014 06:45:24 +0000 Subject: [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is scheduled In-Reply-To: <1412029248-22454-5-git-send-email-richard@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-5-git-send-email-richard@nod.at> Message-ID: <1412059523.3904.11.camel@sauron.fi.intel.com> On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: > + spin_lock(&ubi->wl_lock); > + ubi->fm_work_scheduled = 0; > + spin_unlock(&ubi->wl_lock); Andrew Morton once said me that if I am protecting an integer change like this with a spinlock, I have a problem in my locking design. He was right for my particular case. Integer is changes atomic. The only other thing spinlock adds are the barriers. -- Best Regards, Artem Bityutskiy --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. From richard at nod.at Mon Sep 29 23:58:18 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 08:58:18 +0200 Subject: [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL shutdown In-Reply-To: <1412058366.23429.77.camel@sauron.fi.intel.com> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-2-git-send-email-richard@nod.at> <1412058366.23429.77.camel@sauron.fi.intel.com> Message-ID: <542A548A.7040308@nod.at> Am 30.09.2014 08:26, schrieb Artem Bityutskiy: > On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: >> ...otherwise the deferred work might run after datastructures >> got freed and corrupt memory. > > How can this happend? The background thread is stopped by this time > already, so what are the other possibilities? And why is this > fastmap-only? This has nothing do to with the background thread. Fastmap has a work queue. If one fastmap work has been scheuled we have to wait for it. Thanks, //richard From richard at nod.at Mon Sep 29 23:59:48 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 08:59:48 +0200 Subject: [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is scheduled In-Reply-To: <1412059523.3904.11.camel@sauron.fi.intel.com> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-5-git-send-email-richard@nod.at> <1412059523.3904.11.camel@sauron.fi.intel.com> Message-ID: <542A54E4.2060407@nod.at> Am 30.09.2014 08:45, schrieb Bityutskiy, Artem: > On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: >> + spin_lock(&ubi->wl_lock); >> + ubi->fm_work_scheduled = 0; >> + spin_unlock(&ubi->wl_lock); > > Andrew Morton once said me that if I am protecting an integer change > like this with a spinlock, I have a problem in my locking design. He was > right for my particular case. > > Integer is changes atomic. The only other thing spinlock adds are the > barriers. I've added the spinlock to have a barrier in any case. Thanks, //richard From geert at linux-m68k.org Tue Sep 30 00:22:44 2014 From: geert at linux-m68k.org (Geert Uytterhoeven) Date: Tue, 30 Sep 2014 09:22:44 +0200 Subject: [PATCH v2 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: <1412043352.9388.86.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> <1412043352.9388.86.camel@decadent.org.uk> Message-ID: Hi Ben, On Tue, Sep 30, 2014 at 4:15 AM, Ben Hutchings wrote: > Move the list of chip type information to a macro in spi-nor.h, but > leave the definitions of INFO and CAT25_INFO in spi-nor. > > In m25p80, define the INFO and CAT25_INFO macros to initialise a > struct spi_device_id with the name, ignoring the remaining parameters. > > Signed-off-by: Ben Hutchings Thanks! I didn't have an in-depth look, but this looks much better, and has less opportunities for getting out-of-sync. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds From tlinder at codeaurora.org Tue Sep 30 00:30:00 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Tue, 30 Sep 2014 10:30:00 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <54295274.4020805@nod.at> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <54293975.9040402@gmail.com> <54294A01.8070505@nod.at> <54295165.4030201@smartplayin.com> <54295274.4020805@nod.at> Message-ID: <542A5BF8.3030103@codeaurora.org> On 9/29/2014 3:37 PM, Richard Weinberger wrote: > Am 29.09.2014 14:32, schrieb Kiran Padwal: >> On Monday 29 September 2014 05:31 PM, Richard Weinberger wrote: >>> Am 29.09.2014 12:50, schrieb Kiran Padwal: >>>> Hi Tanya, >>>> >>>> On Sunday 28 September 2014 12:06 PM, Tanya Brokhman wrote: >>>>> If there is more then one UBI device mounted, there is no way to >>>>> distinguish between messages from different UBI devices. >>>>> Add device number to all ubi layer message types. >>>>> >>>>> >>>>> Signed-off-by: Tanya Brokhman >>>>> >>>>> --- >>>>> drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- >>>>> drivers/mtd/ubi/build.c | 130 ++++++++++++++++++++-------------- >>>>> drivers/mtd/ubi/cdev.c | 37 +++++----- >>>>> drivers/mtd/ubi/debug.c | 9 +-- >>>>> drivers/mtd/ubi/eba.c | 54 +++++++------- >>>>> drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ >>>>> drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- >>>>> drivers/mtd/ubi/kapi.c | 6 +- >>>>> drivers/mtd/ubi/misc.c | 6 +- >>>>> drivers/mtd/ubi/ubi.h | 13 ++-- >>>>> drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- >>>>> drivers/mtd/ubi/vtbl.c | 54 ++++++++------ >>>>> drivers/mtd/ubi/wl.c | 87 +++++++++++++++-------- >>>>> 13 files changed, 521 insertions(+), 374 deletions(-) >>>> >>>> Compilation breaks while I try to compile with this patch. >>>> May be you need to update remaining ubi layer messages also. >>> >>> Please always share the errors you face. >>> Maybe you have a different config. >> >> Sure, I will take care of this next time. >> >> Macros have been changed but some instances of older macros still remained, which caused many errors like, >> >> drivers/mtd/ubi/build.c: In function ?ubi_init?: >> drivers/mtd/ubi/build.c:1322:49: error: expected ?)? before ?err? >> ubi_err("block: cannot initialize, error %d", err); > > Ohh. :( > Tanya, did you test your patch? > Of course I did. I used nandsimulator on a virtual machine to test all patches. Perhaps my error was testing them all together (with read-disturb) and this got lost somehow. It's very strange you got compilation errors. I'm sorry for the inconvenience. Will look into this today and upload a new version ASAP. (with all previous comments addressed as well) > Thanks, > //richard > > ______________________________________________________ > Linux MTD discussion mailing list > http://lists.infradead.org/mailman/listinfo/linux-mtd/ > -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From artem.bityutskiy at intel.com Tue Sep 30 00:39:23 2014 From: artem.bityutskiy at intel.com (Bityutskiy, Artem) Date: Tue, 30 Sep 2014 07:39:23 +0000 Subject: [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is scheduled In-Reply-To: <542A54E4.2060407@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-5-git-send-email-richard@nod.at> <1412059523.3904.11.camel@sauron.fi.intel.com> <542A54E4.2060407@nod.at> Message-ID: <1412062762.2379.2.camel@sauron.fi.intel.com> On Tue, 2014-09-30 at 08:59 +0200, Richard Weinberger wrote: > Am 30.09.2014 08:45, schrieb Bityutskiy, Artem: > > On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: > >> + spin_lock(&ubi->wl_lock); > >> + ubi->fm_work_scheduled = 0; > >> + spin_unlock(&ubi->wl_lock); > > > > Andrew Morton once said me that if I am protecting an integer change > > like this with a spinlock, I have a problem in my locking design. He was > > right for my particular case. > > > > Integer is changes atomic. The only other thing spinlock adds are the > > barriers. > > I've added the spinlock to have a barrier in any case. Examples of any? -- Best Regards, Artem Bityutskiy --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. From richard at nod.at Tue Sep 30 00:44:36 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 09:44:36 +0200 Subject: [PATCH 4/4] UBI: Fastmap: Ensure that only one fastmap work is scheduled In-Reply-To: <1412062762.2379.2.camel@sauron.fi.intel.com> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-5-git-send-email-richard@nod.at> <1412059523.3904.11.camel@sauron.fi.intel.com> <542A54E4.2060407@nod.at> <1412062762.2379.2.camel@sauron.fi.intel.com> Message-ID: <542A5F64.5000302@nod.at> Am 30.09.2014 09:39, schrieb Bityutskiy, Artem: > On Tue, 2014-09-30 at 08:59 +0200, Richard Weinberger wrote: >> Am 30.09.2014 08:45, schrieb Bityutskiy, Artem: >>> On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: >>>> + spin_lock(&ubi->wl_lock); >>>> + ubi->fm_work_scheduled = 0; >>>> + spin_unlock(&ubi->wl_lock); >>> >>> Andrew Morton once said me that if I am protecting an integer change >>> like this with a spinlock, I have a problem in my locking design. He was >>> right for my particular case. >>> >>> Integer is changes atomic. The only other thing spinlock adds are the >>> barriers. >> >> I've added the spinlock to have a barrier in any case. > > Examples of any? You mean a case where the compiler would reorder code and the barrier is needed? I don't have one, but I'm not that creative as a modern C compiler. If you say that no barrier is needed I'll trust you. :-) Thanks, //richard From artem.bityutskiy at intel.com Tue Sep 30 00:53:40 2014 From: artem.bityutskiy at intel.com (Bityutskiy, Artem) Date: Tue, 30 Sep 2014 07:53:40 +0000 Subject: [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL shutdown In-Reply-To: <542A548A.7040308@nod.at> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-2-git-send-email-richard@nod.at> <1412058366.23429.77.camel@sauron.fi.intel.com> <542A548A.7040308@nod.at> Message-ID: <1412063620.2379.12.camel@sauron.fi.intel.com> On Tue, 2014-09-30 at 08:58 +0200, Richard Weinberger wrote: > Am 30.09.2014 08:26, schrieb Artem Bityutskiy: > > On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: > >> ...otherwise the deferred work might run after datastructures > >> got freed and corrupt memory. > > > > How can this happend? The background thread is stopped by this time > > already, so what are the other possibilities? And why is this > > fastmap-only? > > This has nothing do to with the background thread. > Fastmap has a work queue. If one fastmap work has been > scheuled we have to wait for it. I expected a bit more explanation. But OK, here is what I think. UBI consists of subsystems. Subsystems try to be more or less independent, whenever possible. They expose interface functions for other subsystems. Of course the split is not ideal, but we do our best. * wl.c does wear-levelling. * wl.c does not do fastmap. * fastmap.c does fastmap. * I am unhappy seeing yet another ifdef to wl.c * I am unhappy seeing wl.c calling 'flush_work(&ubi->fm_work)', because fastmap.c should deal with 'fm_work'. Or said differently, wl.c is not a fastmap queue baby-sitter. fastmap.c is. Most UB subsystems have the init and close function. May be adding one for fastmap would help? Then you could flush whatever from 'ubi_wl_close()' ? Historically the work queue was implemented in wl.c because wl.c was the only user of it. If this layout is not good enough, we should probably extend it, may be separate work queue management out of wl.c. But populating wl.c with macros and little "take care of this fatmap bit" stuff is a not going to lead to better code structure. -- Best Regards, Artem Bityutskiy --------------------------------------------------------------------- Intel Finland Oy Registered Address: PL 281, 00181 Helsinki Business Identity Code: 0357606 - 4 Domiciled in Helsinki This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. From zajec5 at gmail.com Tue Sep 30 01:02:25 2014 From: zajec5 at gmail.com (=?UTF-8?B?UmFmYcWCIE1pxYJlY2tp?=) Date: Tue, 30 Sep 2014 10:02:25 +0200 Subject: [PATCH v2 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: <1412043352.9388.86.camel@decadent.org.uk> References: <1412043222.9388.81.camel@decadent.org.uk> <1412043352.9388.86.camel@decadent.org.uk> Message-ID: On 30 September 2014 04:15, Ben Hutchings wrote: > Move the list of chip type information to a macro in spi-nor.h, but > leave the definitions of INFO and CAT25_INFO in spi-nor. > > In m25p80, define the INFO and CAT25_INFO macros to initialise a > struct spi_device_id with the name, ignoring the remaining parameters. Anyone would consider my idea proposed in 1/5 thread? We could simply follow the way Linux-specific platform data works. We could always use compatible = "m25p80"; and then for some rare cases (where JEDEC fails) add something like model = "at25df321a"; Using above way we could use a one single "compatible" in m25p80.c and avoid this messy share of id_table. From tlinder at codeaurora.org Tue Sep 30 01:02:23 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Tue, 30 Sep 2014 11:02:23 +0300 Subject: [PATCH] mtd: ubi: Extend UBI layer debug/messaging capabilities In-Reply-To: <1411905665.11836.15.camel@karhu> References: <1411886185-7838-1-git-send-email-tlinder@codeaurora.org> <1411905665.11836.15.camel@karhu> Message-ID: <542A638F.6090703@codeaurora.org> On 9/28/2014 3:01 PM, Artem Bityutskiy wrote: > On Sun, 2014-09-28 at 09:36 +0300, Tanya Brokhman wrote: >> If there is more then one UBI device mounted, there is no way to >> distinguish between messages from different UBI devices. >> Add device number to all ubi layer message types. > > Hi, the goal looks legit to me, but the patch is so large that I do not > think that I can really review it in this form. > > a) A patch which changes the macros (ubi_err(), etc) If I divide the patches like this, patch (a) wont compile > b) A set of patches which do not change messages at all, but add the > 'ubi' parameter to the places where it is missing. > c) A patch which changes the messages. I think patches (b)+(C) can be combined into one patch. Don't you agree? I changed ~2 or 3 messages that were printing ubi number by themselves. No need for a separate patch for this. Don't you agree? > > So a) will be the most important patch for the reviewer. b) - more or > less mechanical changes of a similar kind. c) - the same. > > Also, if you add a parameter to 'ubi_err()' and the other printing > wrappers, add 'ubi' there, not 'ubi_num'. This will allow to prefix > messages with vary different things, not just the device number in the > future. So the calls would look like > > ubi_err(ubi, "inconsistent used_ebs"); > > Once this is done, the series should be more reviewable. The next thing > I'd check is whether we really need to change all the messages, or most > of them, or we actually need to change only a small part of them. In the > former case, it is OK to do what you do, I guess. In the latter case we > probably better off with introducing a separate set of printing macros > and leave the existing ones as they are. Large portion of the messages needs updating. I think perhaps I'll overcome the messages during init (when I don't' have the ubi yet) in a different manner and add "ubi" not "ubi_num" parameter to the macros, as you suggested > > Thanks! > -- Employee of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation From boris.brezillon at free-electrons.com Tue Sep 30 01:04:15 2014 From: boris.brezillon at free-electrons.com (Boris Brezillon) Date: Tue, 30 Sep 2014 10:04:15 +0200 Subject: [PATCH] mtd: nand: gpmi: add proper raw access support In-Reply-To: References: <1410339339-25561-1-git-send-email-boris.brezillon@free-electrons.com> <20140911120928.GA1585@localhost.localdomain> <20140911143616.3ebb025a@bbrezillon> Message-ID: <20140930100415.4834971d@bbrezillon> Hi Iwo, On Mon, 29 Sep 2014 11:22:11 +1000 Iwo Mergler wrote: > On Thu, 11 Sep 2014 22:36:16 +1000 > Boris BREZILLON wrote: > > > > Well, I don't know about freescale specific tools, but at least I have > > an example with mtd_nandbiterrs module. > > This module is assuming it can write only the data part of a NAND page > > without modifying the OOB area (see [1]), which in GPMI controller > > case is impossible because raw write function store the data as if > > there were no specific scheme, while there is one: > > (metadata + n x (data_chunk + ECC bytes) + remaining_bytes). > > > > Hi Boris, > > > just as an aside, only the incremental bit errors test in nandbiterrs > positively requires raw data write. > > The overwrite test (re-write the same page data repeatedly without > erase), only uses raw access because I was lazy. A normal ECC write > would do just as well. Okay. Anyway, the test I'm really interested in is the incremental bit errors test :-). BTW, any reason you chose to implement this test/testsuite as a module ? From my understanding (and tell me if I'm wrong) we could do the same from user-space. Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From boris.brezillon at free-electrons.com Tue Sep 30 01:07:20 2014 From: boris.brezillon at free-electrons.com (Boris Brezillon) Date: Tue, 30 Sep 2014 10:07:20 +0200 Subject: [PATCH v3 0/3] mtd: nand: gpmi: add proper raw access support In-Reply-To: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> References: <1411481256-29141-1-git-send-email-boris.brezillon@free-electrons.com> Message-ID: <20140930100720.45625804@bbrezillon> Hi, On Tue, 23 Sep 2014 16:07:33 +0200 Boris BREZILLON wrote: > Hello Huang, Brian, > > This is just a new proposal to support raw accesses in a more standard way > in the GPMI driver. > This series has been tested on an imx28 board. > > Any suggestions are welcome. Brian, any chance you could take a look at this series and give your opinion and/or suggest a new approach ? Huang, did you have time to think about a better way to implement these raw access functions ? Best Regards, Boris -- Boris Brezillon, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com From richard at nod.at Tue Sep 30 01:07:23 2014 From: richard at nod.at (Richard Weinberger) Date: Tue, 30 Sep 2014 10:07:23 +0200 Subject: [PATCH 1/4] UBI: Ensure that all fastmap work is done upon WL shutdown In-Reply-To: <1412063620.2379.12.camel@sauron.fi.intel.com> References: <1412029248-22454-1-git-send-email-richard@nod.at> <1412029248-22454-2-git-send-email-richard@nod.at> <1412058366.23429.77.camel@sauron.fi.intel.com> <542A548A.7040308@nod.at> <1412063620.2379.12.camel@sauron.fi.intel.com> Message-ID: <542A64BB.7060904@nod.at> Am 30.09.2014 09:53, schrieb Bityutskiy, Artem: > On Tue, 2014-09-30 at 08:58 +0200, Richard Weinberger wrote: >> Am 30.09.2014 08:26, schrieb Artem Bityutskiy: >>> On Tue, 2014-09-30 at 00:20 +0200, Richard Weinberger wrote: >>>> ...otherwise the deferred work might run after datastructures >>>> got freed and corrupt memory. >>> >>> How can this happend? The background thread is stopped by this time >>> already, so what are the other possibilities? And why is this >>> fastmap-only? >> >> This has nothing do to with the background thread. >> Fastmap has a work queue. If one fastmap work has been >> scheuled we have to wait for it. > > I expected a bit more explanation. But OK, here is what I think. > > UBI consists of subsystems. Subsystems try to be more or less > independent, whenever possible. They expose interface functions for > other subsystems. Of course the split is not ideal, but we do our best. > > * wl.c does wear-levelling. > * wl.c does not do fastmap. > * fastmap.c does fastmap. > * I am unhappy seeing yet another ifdef to wl.c I can warp it. > * I am unhappy seeing wl.c calling 'flush_work(&ubi->fm_work)', because > fastmap.c should deal with 'fm_work'. Or said differently, wl.c is not a > fastmap queue baby-sitter. fastmap.c is. But wl.c has to trigger the deferred fastmap work as only wl.c detects when it is needed. I you want I can implement a ubi_fastmap_shutdown() in fastmap.c which calls flush_work(). But I did it in wl.c to have it balanced. wl.c triggers and stops the fastmap work. > Most UB subsystems have the init and close function. May be adding one > for fastmap would help? Then you could flush whatever from > 'ubi_wl_close()' ? > > Historically the work queue was implemented in wl.c because wl.c was the > only user of it. What work queue are you talking about? The fastmap work queue was added by me and has nothing to do with the UBI background worker thread. > If this layout is not good enough, we should probably extend it, may be > separate work queue management out of wl.c. One thing I can think of is getting completely rid of the UBI background thread and convert it to a work queue. But I'm not sure if this would make things easier for fastmap. > But populating wl.c with macros and little "take care of this fatmap > bit" stuff is a not going to lead to better code structure. s/fatmap/fastmap. A Freudian slip? ;) I spent already a full week on refactoring that code. My goal was making ubi_update_fastmap() callable from within the wear_leveling_worker() to get rid of the fastmap work queue completely. After one week the new code was more complicated and ugly than the current one. :-\ Some background info: Fastmap needs to create a snapshot of the UBI state. This is why you cannot call it within an UBI work. As UBI works can run in parallel. The fastmap creation does many things which can sleep. Most stuff in the wear_leveling_worker() happens in atmoic context. Thanks, //richard From steve at baconbits.demon.co.uk Tue Sep 30 04:00:49 2014 From: steve at baconbits.demon.co.uk (steve) Date: Tue, 30 Sep 2014 12:00:49 +0100 (BST) Subject: UBI: Question about error checking in ubi_eba_write_leb() Message-ID: This is my first post to this mailing list, I think this is the right place for my question. I think the error checking in ubi_eba_write_leb() may be wrong and may cause incorrect behaviour when extra checking is enabled in debugfs, here's the scenario I have a problem with: ubi_eba_write_leb() calls ubi_io_write_data() -> ubi_io_write() -> ubi_dbg_check_all_ff() ubi_dbg_check_all_ff() will perform an mtd_read() which can fail with EBADMSG (if there is a failure to correct using ECC as in my case). This error code will bubble back up to ubi_eba_write_leb(), but recover_peb() will only be called if the error code was EIO. The question is should recover_peb() be called in this case as well? Thanks for any help with this, Steve From ben at decadent.org.uk Tue Sep 30 04:36:03 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 12:36:03 +0100 Subject: [PATCH v2 5/5] m25p80,spi-nor: Share the list of supported chip type names again In-Reply-To: References: <1412043222.9388.81.camel@decadent.org.uk> <1412043352.9388.86.camel@decadent.org.uk> Message-ID: <1412076963.9388.96.camel@decadent.org.uk> On Tue, 2014-09-30 at 10:02 +0200, Rafa? Mi?ecki wrote: > On 30 September 2014 04:15, Ben Hutchings wrote: > > Move the list of chip type information to a macro in spi-nor.h, but > > leave the definitions of INFO and CAT25_INFO in spi-nor. > > > > In m25p80, define the INFO and CAT25_INFO macros to initialise a > > struct spi_device_id with the name, ignoring the remaining parameters. > > Anyone would consider my idea proposed in 1/5 thread? > > We could simply follow the way Linux-specific platform data works. We > could always use > compatible = "m25p80"; > and then for some rare cases (where JEDEC fails) add something like > model = "at25df321a"; > > Using above way we could use a one single "compatible" in m25p80.c and > avoid this messy share of id_table. You *cannot* define a DT compatible string by reference to out-of-band information about all the chips that has to be updated for each new chip. That is not 'compatible'. Ben. -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From ben at decadent.org.uk Tue Sep 30 04:38:08 2014 From: ben at decadent.org.uk (Ben Hutchings) Date: Tue, 30 Sep 2014 12:38:08 +0100 Subject: [PATCH v2 3/5] spi-nor: Make spi_nor_scan() take a chip type name, not an spi_device_id In-Reply-To: References: <1412043222.9388.81.camel@decadent.org.uk> <1412043317.9388.84.camel@decadent.org.uk> Message-ID: <1412077088.9388.98.camel@decadent.org.uk> On Tue, 2014-09-30 at 07:14 +0200, Rafa? Mi?ecki wrote: > On 30 September 2014 04:15, Ben Hutchings wrote: > > @@ -236,16 +236,13 @@ static int m25p_probe(struct spi_device *spi) > > * If that's the case, respect "type" and ignore a "name". > > */ > > if (data && data->type) > > - id = spi_nor_match_id(data->type); > > + name = data->type; > > > > /* If we didn't get name from platform, simply use "modalias". */ > > - if (!id) { > > - id = spi_nor_match_id(spi_get_device_id(spi)->name); > > - if (WARN_ON(!id)) > > - return -ENODEV; > > - } > > + if (!name) > > + name = spi_get_device_id(spi)->name; > > Huh? Iterating the whole id_table, checking the entries (looking for > one with name equal to the spi->modalias) and then... getting that > name? Ah, I didn't realise what spi_get_device_id() was doing. > Did it hurt to use the patch I've sent > mtd: m25p80: get rid of spi_get_device_id > https://patchwork.ozlabs.org/patch/394328/ It would make sense to insert that before this. Ben. -- Ben Hutchings The two most common things in the universe are hydrogen and stupidity. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 811 bytes Desc: This is a digitally signed message part URL: From arnd at arndb.de Tue Sep 30 05:04:17 2014 From: arnd at arndb.de (Arnd Bergmann) Date: Tue, 30 Sep 2014 14:04:17 +0200 Subject: [PATCH] nand: omap2: fix building with CONFIG_MTD_NAND_OMAP_BCH=m Message-ID: <1811108.CcWEs0vKNL@wuerfel> If the OMAP nand driver is built-in but the BCH driver is a module, we get a link-time error: drivers/built-in.o: In function `omap_elm_correct_data': :(.text+0x174e88): undefined reference to `elm_decode_bch_error_page' drivers/built-in.o: In function `omap_nand_probe': :(.text+0x175b48): undefined reference to `elm_config' There are two possible ways to deal with this, either prevent that configuration in Kconfig or make sure we don't reference the ELM driver in this case. This patch picks the second approach, which makes it possible to use the ELM driver in other modules while still having the OMAP NAND driver built-in. Signed-off-by: Arnd Bergmann Fixes: 93af53b8633c ("nand: omap2: Remove horrible ifdefs to fix module probe") diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index b8686c00f15f..cbca66ce7c10 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,7 +42,7 @@ struct elm_errorvec { int error_loc[16]; }; -#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) +#if defined(CONFIG_MTD_NAND_OMAP_BCH) || (defined(CONFIG_MTD_NAND_OMAP_BCH_MODULE) && defined(MODULE)) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, From marex at denx.de Tue Sep 30 06:38:40 2014 From: marex at denx.de (Marek Vasut) Date: Tue, 30 Sep 2014 15:38:40 +0200 Subject: [PATCH 1/1 v3] driver:mtd:spi-nor: Add Micron quad I/O support In-Reply-To: References: <201409261046.07132.marex@denx.de> Message-ID: <201409301538.40466.marex@denx.de> On Tuesday, September 30, 2014 at 04:47:39 AM, Bean Huo ??? (beanhuo) wrote: > For Micron spi norflash,enables or disables quad I/O > protocol ,which controled by EVCR(Enhanced > Volatile Configuration Register) Quad I/O > protocol bit 7.When EVCR bit 7 is reset to 0, > the spi norflash will operate in quad I/O following > the next WRITE ENHANCED VOLATILE CONFIGURATION > command. You only do one WRITE ENHANCED VOLATILE CONFIGURATION command in the patch, so this text doesn't add up. Try something like this: -->8-- This patch adds code which enables Quad I/O mode on Micron SPI NOR flashes. For Micron SPI NOR flash, enabling or disabling quad I/O protocol is controled by EVCR (Enhanced Volatile Configuration Register), Quad I/O protocol bit 7. When EVCR bit 7 is reset to 0, the SPI NOR flash will operate in quad I/O mode. --8<-- What do you think ? Brian, am I bitching too much about pointless things ? Please stop me if you think I do. [...] Best regards, Marek Vasut From tlinder at codeaurora.org Tue Sep 30 08:13:18 2014 From: tlinder at codeaurora.org (Tanya Brokhman) Date: Tue, 30 Sep 2014 18:13:18 +0300 Subject: [PATCH v2] mtd: ubi: Extend UBI layer debug/messaging capabilities Message-ID: <1412089998-18978-1-git-send-email-tlinder@codeaurora.org> If there is more then one UBI device mounted, there is no way to distinguish between messages from different UBI devices. Add device number to all ubi layer message types. Signed-off-by: Tanya Brokhman --- Changes from V1: - Compilation error fixed - macros were updated to receive the ubi structure as parameter and not just ubi_number - Places in code, where ubi-messaging macros were used, but ubi struct is not present yet (init phase), were updated to just use pr_err or similar Note for reviewers: The updated macros are all in ubi.h. All other file changes are just technical changes for compilation (usage of the defined macros) drivers/mtd/ubi/attach.c | 138 ++++++++++++++++++++---------------- drivers/mtd/ubi/block.c | 6 +- drivers/mtd/ubi/build.c | 128 +++++++++++++++++++-------------- drivers/mtd/ubi/cdev.c | 37 +++++----- drivers/mtd/ubi/debug.c | 9 +-- drivers/mtd/ubi/eba.c | 54 +++++++------- drivers/mtd/ubi/fastmap.c | 108 ++++++++++++++++------------ drivers/mtd/ubi/io.c | 177 +++++++++++++++++++++++++++------------------- drivers/mtd/ubi/kapi.c | 6 +- drivers/mtd/ubi/misc.c | 6 +- drivers/mtd/ubi/ubi.h | 13 ++-- drivers/mtd/ubi/vmt.c | 76 +++++++++++--------- drivers/mtd/ubi/vtbl.c | 54 ++++++++------ drivers/mtd/ubi/wl.c | 89 ++++++++++++++--------- 14 files changed, 521 insertions(+), 380 deletions(-) diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 6f27d9a..739e9a6 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -176,6 +176,7 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) /** * validate_vid_hdr - check volume identifier header. + * @ubi: UBI device description object * @vid_hdr: the volume identifier header to check * @av: information about the volume this logical eraseblock belongs to * @pnum: physical eraseblock number the VID header came from @@ -188,7 +189,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec) * information in the VID header is consistent to the information in other VID * headers of the same volume. */ -static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, +static int validate_vid_hdr(const struct ubi_device *ubi, + const struct ubi_vid_hdr *vid_hdr, const struct ubi_ainf_volume *av, int pnum) { int vol_type = vid_hdr->vol_type; @@ -206,7 +208,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, */ if (vol_id != av->vol_id) { - ubi_err("inconsistent vol_id"); + ubi_err(ubi, "inconsistent vol_id"); goto bad; } @@ -216,17 +218,17 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, av_vol_type = UBI_VID_DYNAMIC; if (vol_type != av_vol_type) { - ubi_err("inconsistent vol_type"); + ubi_err(ubi, "inconsistent vol_type"); goto bad; } if (used_ebs != av->used_ebs) { - ubi_err("inconsistent used_ebs"); + ubi_err(ubi, "inconsistent used_ebs"); goto bad; } if (data_pad != av->data_pad) { - ubi_err("inconsistent data_pad"); + ubi_err(ubi, "inconsistent data_pad"); goto bad; } } @@ -234,7 +236,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, return 0; bad: - ubi_err("inconsistent VID header at PEB %d", pnum); + ubi_err(ubi, "inconsistent VID header at PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); ubi_dump_av(av); return -EINVAL; @@ -336,7 +338,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, * support these images anymore. Well, those images still work, * but only if no unclean reboots happened. */ - ubi_err("unsupported on-flash UBI format"); + ubi_err(ubi, "unsupported on-flash UBI format"); return -EINVAL; } @@ -377,7 +379,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb, if (err == UBI_IO_BITFLIPS) bitflips = 1; else { - ubi_err("VID of PEB %d header is bad, but it was OK earlier, err %d", + ubi_err(ubi, "VID of PEB %d header is bad, but it was OK earlier, err %d", pnum, err); if (err > 0) err = -EIO; @@ -507,7 +509,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * logical eraseblocks because there was an unclean reboot. */ if (aeb->sqnum == sqnum && sqnum != 0) { - ubi_err("two LEBs with same sequence number %llu", + ubi_err(ubi, "two LEBs with same sequence number %llu", sqnum); ubi_dump_aeb(aeb, 0); ubi_dump_vid_hdr(vid_hdr); @@ -527,7 +529,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * This logical eraseblock is newer than the one * found earlier. */ - err = validate_vid_hdr(vid_hdr, av, pnum); + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); if (err) return err; @@ -565,7 +567,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum, * attaching information. */ - err = validate_vid_hdr(vid_hdr, av, pnum); + err = validate_vid_hdr(ubi, vid_hdr, av, pnum); if (err) return err; @@ -668,7 +670,8 @@ static int early_erase_peb(struct ubi_device *ubi, * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ - ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); + ubi_err(ubi, + "erase counter overflow at PEB %d, EC %d", pnum, ec); return -EINVAL; } @@ -736,7 +739,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, return aeb; } - ubi_err("no free eraseblocks"); + ubi_err(ubi, "no free eraseblocks"); return ERR_PTR(-ENOSPC); } @@ -785,9 +788,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size)) goto out_unlock; - ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF", + ubi_err(ubi, "PEB %d contains corrupted VID header, and the data does not contain all 0xFF", pnum); - ubi_err("this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); + ubi_err(ubi, "this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection"); ubi_dump_vid_hdr(vid_hdr); pr_err("hexdump of PEB %d offset %d, length %d", pnum, ubi->leb_start, ubi->leb_size); @@ -859,7 +862,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, bitflips = 1; break; default: - ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err); + ubi_err(ubi, + "'ubi_io_read_ec_hdr()' returned unknown code %d", err); return -EINVAL; } @@ -868,7 +872,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, /* Make sure UBI version is OK */ if (ech->version != UBI_VERSION) { - ubi_err("this UBI version is %d, image version is %d", + ubi_err(ubi, "this UBI version is %d, image version is %d", UBI_VERSION, (int)ech->version); return -EINVAL; } @@ -882,7 +886,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, * flash. Upgrade UBI and use 64-bit erase counters * internally. */ - ubi_err("erase counter overflow, max is %d", + ubi_err(ubi, "erase counter overflow, max is %d", UBI_MAX_ERASECOUNTER); ubi_dump_ec_hdr(ech); return -EINVAL; @@ -903,7 +907,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, if (!ubi->image_seq) ubi->image_seq = image_seq; if (image_seq && ubi->image_seq != image_seq) { - ubi_err("bad image sequence number %d in PEB %d, expected %d", + ubi_err(ubi, "bad image sequence number %d in PEB %d, expected %d", image_seq, pnum, ubi->image_seq); ubi_dump_ec_hdr(ech); return -EINVAL; @@ -981,7 +985,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return err; goto adjust_mean_ec; default: - ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d", + ubi_err(ubi, "'ubi_io_read_vid_hdr()' returned unknown code %d", err); return -EINVAL; } @@ -999,7 +1003,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, case UBI_COMPAT_DELETE: if (vol_id != UBI_FM_SB_VOLUME_ID && vol_id != UBI_FM_DATA_VOLUME_ID) { - ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it", + ubi_msg(ubi, + "\"delete\" compatible internal volume %d:%d found, will remove it", vol_id, lnum); } err = add_to_list(ai, pnum, vol_id, lnum, @@ -1009,13 +1014,15 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; case UBI_COMPAT_RO: - ubi_msg("read-only compatible internal volume %d:%d found, switch to read-only mode", + ubi_msg(ubi, + "read-only compatible internal volume %d:%d found, switch to read-only mode", vol_id, lnum); ubi->ro_mode = 1; break; case UBI_COMPAT_PRESERVE: - ubi_msg("\"preserve\" compatible internal volume %d:%d found", + ubi_msg(ubi, + "\"preserve\" compatible internal volume %d:%d found", vol_id, lnum); err = add_to_list(ai, pnum, vol_id, lnum, ec, 0, &ai->alien); @@ -1024,14 +1031,14 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, return 0; case UBI_COMPAT_REJECT: - ubi_err("incompatible internal volume %d:%d found", + ubi_err(ubi, "incompatible internal volume %d:%d found", vol_id, lnum); return -EINVAL; } } if (ec_err) - ubi_warn("valid VID header but corrupted EC header at PEB %d", + ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d", pnum); err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips); if (err) @@ -1075,7 +1082,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) * with the flash HW or driver. */ if (ai->corr_peb_count) { - ubi_err("%d PEBs are corrupted and preserved", + ubi_err(ubi, "%d PEBs are corrupted and preserved", ai->corr_peb_count); pr_err("Corrupted PEBs are:"); list_for_each_entry(aeb, &ai->corr, u.list) @@ -1087,7 +1094,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) * otherwise, only print a warning. */ if (ai->corr_peb_count >= max_corr) { - ubi_err("too many corrupted PEBs, refusing"); + ubi_err(ubi, "too many corrupted PEBs, refusing"); return -EINVAL; } } @@ -1110,11 +1117,11 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai) */ if (ai->maybe_bad_peb_count <= 2) { ai->is_empty = 1; - ubi_msg("empty MTD device detected"); + ubi_msg(ubi, "empty MTD device detected"); get_random_bytes(&ubi->image_seq, sizeof(ubi->image_seq)); } else { - ubi_err("MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); + ubi_err(ubi, "MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it"); return -EINVAL; } @@ -1248,7 +1255,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, goto out_vidh; } - ubi_msg("scanning is finished"); + ubi_msg(ubi, "scanning is finished"); /* Calculate mean erase counter */ if (ai->ec_count) @@ -1515,37 +1522,37 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) vols_found += 1; if (ai->is_empty) { - ubi_err("bad is_empty flag"); + ubi_err(ubi, "bad is_empty flag"); goto bad_av; } if (av->vol_id < 0 || av->highest_lnum < 0 || av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 || av->data_pad < 0 || av->last_data_size < 0) { - ubi_err("negative values"); + ubi_err(ubi, "negative values"); goto bad_av; } if (av->vol_id >= UBI_MAX_VOLUMES && av->vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("bad vol_id"); + ubi_err(ubi, "bad vol_id"); goto bad_av; } if (av->vol_id > ai->highest_vol_id) { - ubi_err("highest_vol_id is %d, but vol_id %d is there", + ubi_err(ubi, "highest_vol_id is %d, but vol_id %d is there", ai->highest_vol_id, av->vol_id); goto out; } if (av->vol_type != UBI_DYNAMIC_VOLUME && av->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); + ubi_err(ubi, "bad vol_type"); goto bad_av; } if (av->data_pad > ubi->leb_size / 2) { - ubi_err("bad data_pad"); + ubi_err(ubi, "bad data_pad"); goto bad_av; } @@ -1557,48 +1564,48 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) leb_count += 1; if (aeb->pnum < 0 || aeb->ec < 0) { - ubi_err("negative values"); + ubi_err(ubi, "negative values"); goto bad_aeb; } if (aeb->ec < ai->min_ec) { - ubi_err("bad ai->min_ec (%d), %d found", + ubi_err(ubi, "bad ai->min_ec (%d), %d found", ai->min_ec, aeb->ec); goto bad_aeb; } if (aeb->ec > ai->max_ec) { - ubi_err("bad ai->max_ec (%d), %d found", + ubi_err(ubi, "bad ai->max_ec (%d), %d found", ai->max_ec, aeb->ec); goto bad_aeb; } if (aeb->pnum >= ubi->peb_count) { - ubi_err("too high PEB number %d, total PEBs %d", + ubi_err(ubi, "too high PEB number %d, total PEBs %d", aeb->pnum, ubi->peb_count); goto bad_aeb; } if (av->vol_type == UBI_STATIC_VOLUME) { if (aeb->lnum >= av->used_ebs) { - ubi_err("bad lnum or used_ebs"); + ubi_err(ubi, "bad lnum or used_ebs"); goto bad_aeb; } } else { if (av->used_ebs != 0) { - ubi_err("non-zero used_ebs"); + ubi_err(ubi, "non-zero used_ebs"); goto bad_aeb; } } if (aeb->lnum > av->highest_lnum) { - ubi_err("incorrect highest_lnum or lnum"); + ubi_err(ubi, "incorrect highest_lnum or lnum"); goto bad_aeb; } } if (av->leb_count != leb_count) { - ubi_err("bad leb_count, %d objects in the tree", + ubi_err(ubi, "bad leb_count, %d objects in the tree", leb_count); goto bad_av; } @@ -1609,13 +1616,13 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) aeb = last_aeb; if (aeb->lnum != av->highest_lnum) { - ubi_err("bad highest_lnum"); + ubi_err(ubi, "bad highest_lnum"); goto bad_aeb; } } if (vols_found != ai->vols_found) { - ubi_err("bad ai->vols_found %d, should be %d", + ubi_err(ubi, "bad ai->vols_found %d, should be %d", ai->vols_found, vols_found); goto out; } @@ -1632,7 +1639,8 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("VID header is not OK (%d)", err); + ubi_err(ubi, + "VID header is not OK (%d)", err); if (err > 0) err = -EIO; return err; @@ -1641,37 +1649,42 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; if (av->vol_type != vol_type) { - ubi_err("bad vol_type"); + ubi_err(ubi, "bad vol_type"); goto bad_vid_hdr; } if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) { - ubi_err("bad sqnum %llu", aeb->sqnum); + ubi_err(ubi, + "bad sqnum %llu", aeb->sqnum); goto bad_vid_hdr; } if (av->vol_id != be32_to_cpu(vidh->vol_id)) { - ubi_err("bad vol_id %d", av->vol_id); + ubi_err(ubi, + "bad vol_id %d", av->vol_id); goto bad_vid_hdr; } if (av->compat != vidh->compat) { - ubi_err("bad compat %d", vidh->compat); + ubi_err(ubi, + "bad compat %d", vidh->compat); goto bad_vid_hdr; } if (aeb->lnum != be32_to_cpu(vidh->lnum)) { - ubi_err("bad lnum %d", aeb->lnum); + ubi_err(ubi, "bad lnum %d", aeb->lnum); goto bad_vid_hdr; } if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) { - ubi_err("bad used_ebs %d", av->used_ebs); + ubi_err(ubi, + "bad used_ebs %d", av->used_ebs); goto bad_vid_hdr; } if (av->data_pad != be32_to_cpu(vidh->data_pad)) { - ubi_err("bad data_pad %d", av->data_pad); + ubi_err(ubi, + "bad data_pad %d", av->data_pad); goto bad_vid_hdr; } } @@ -1680,12 +1693,14 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) continue; if (av->highest_lnum != be32_to_cpu(vidh->lnum)) { - ubi_err("bad highest_lnum %d", av->highest_lnum); + ubi_err(ubi, + "bad highest_lnum %d", av->highest_lnum); goto bad_vid_hdr; } if (av->last_data_size != be32_to_cpu(vidh->data_size)) { - ubi_err("bad last_data_size %d", av->last_data_size); + ubi_err(ubi, + "bad last_data_size %d", av->last_data_size); goto bad_vid_hdr; } } @@ -1726,7 +1741,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) err = 0; for (pnum = 0; pnum < ubi->peb_count; pnum++) if (!buf[pnum]) { - ubi_err("PEB %d is not referred", pnum); + ubi_err(ubi, "PEB %d is not referred", pnum); err = 1; } @@ -1736,18 +1751,21 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai) return 0; bad_aeb: - ubi_err("bad attaching information about LEB %d", aeb->lnum); + ubi_err(ubi, "bad attaching information about LEB %d", + aeb->lnum); ubi_dump_aeb(aeb, 0); ubi_dump_av(av); goto out; bad_av: - ubi_err("bad attaching information about volume %d", av->vol_id); + ubi_err(ubi, "bad attaching information about volume %d", + av->vol_id); ubi_dump_av(av); goto out; bad_vid_hdr: - ubi_err("bad attaching information about volume %d", av->vol_id); + ubi_err(ubi, "bad attaching information about volume %d", + av->vol_id); ubi_dump_av(av); ubi_dump_vid_hdr(vidh); diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 33c6495..08c570f 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -111,7 +111,7 @@ static int __init ubiblock_set_param(const char *val, len = strnlen(val, UBIBLOCK_PARAM_LEN); if (len == 0) { - ubi_warn("block: empty 'block=' parameter - ignored\n"); + ubi_warn(ubi, "block: empty 'block=' parameter - ignored\n"); return 0; } @@ -505,7 +505,7 @@ static int ubiblock_resize(struct ubi_volume_info *vi) u64 disk_capacity = ((u64)vi->size * vi->usable_leb_size) >> 9; if ((sector_t)disk_capacity != disk_capacity) { - ubi_warn("%s: the volume is too big, cannot resize (%d LEBs)", + ubi_warn(ubi, "%s: the volume is too big, cannot resize (%d LEBs)", dev->gd->disk_name, vi->size); return -EFBIG; } @@ -523,7 +523,7 @@ static int ubiblock_resize(struct ubi_volume_info *vi) mutex_lock(&dev->dev_mutex); set_capacity(dev->gd, disk_capacity); - ubi_msg("%s resized to %d LEBs", dev->gd->disk_name, vi->size); + ubi_msg(ubi, "%s resized to %d LEBs", dev->gd->disk_name, vi->size); mutex_unlock(&dev->dev_mutex); mutex_unlock(&devices_mutex); return 0; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 6e30a3c..c20440e 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -166,7 +166,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol, int ntype) case UBI_VOLUME_RESIZED: case UBI_VOLUME_RENAMED: if (ubi_update_fastmap(ubi)) { - ubi_err("Unable to update fastmap!"); + ubi_err(ubi, "Unable to update fastmap!"); ubi_ro_mode(ubi); } } @@ -517,7 +517,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) */ err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); if (err) { - ubi_err("cannot register UBI character devices"); + ubi_err(ubi, "cannot register UBI character devices"); return err; } @@ -528,7 +528,7 @@ static int uif_init(struct ubi_device *ubi, int *ref) err = cdev_add(&ubi->cdev, dev, 1); if (err) { - ubi_err("cannot add character device"); + ubi_err(ubi, "cannot add character device"); goto out_unreg; } @@ -540,7 +540,8 @@ static int uif_init(struct ubi_device *ubi, int *ref) if (ubi->volumes[i]) { err = ubi_add_volume(ubi, ubi->volumes[i]); if (err) { - ubi_err("cannot add volume %d", i); + ubi_err(ubi, + "cannot add volume %d", i); goto out_volumes; } } @@ -556,7 +557,8 @@ out_sysfs: cdev_del(&ubi->cdev); out_unreg: unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); - ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); + ubi_err(ubi, "cannot initialize UBI %s, error %d", + ubi->ubi_name, err); return err; } @@ -650,7 +652,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * guess we should just pick the largest region. But this is * not implemented. */ - ubi_err("multiple regions, not implemented"); + ubi_err(ubi, "multiple regions, not implemented"); return -EINVAL; } @@ -685,7 +687,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * which allows us to avoid costly division operations. */ if (!is_power_of_2(ubi->min_io_size)) { - ubi_err("min. I/O unit (%d) is not power of 2", + ubi_err(ubi, "min. I/O unit (%d) is not power of 2", ubi->min_io_size); return -EINVAL; } @@ -702,7 +704,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) if (ubi->max_write_size < ubi->min_io_size || ubi->max_write_size % ubi->min_io_size || !is_power_of_2(ubi->max_write_size)) { - ubi_err("bad write buffer size %d for %d min. I/O unit", + ubi_err(ubi, "bad write buffer size %d for %d min. I/O unit", ubi->max_write_size, ubi->min_io_size); return -EINVAL; } @@ -739,7 +741,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) /* The shift must be aligned to 32-bit boundary */ if (ubi->vid_hdr_shift % 4) { - ubi_err("unaligned VID header shift %d", + ubi_err(ubi, "unaligned VID header shift %d", ubi->vid_hdr_shift); return -EINVAL; } @@ -749,7 +751,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || ubi->leb_start & (ubi->min_io_size - 1)) { - ubi_err("bad VID header (%d) or data offsets (%d)", + ubi_err(ubi, "bad VID header (%d) or data offsets (%d)", ubi->vid_hdr_offset, ubi->leb_start); return -EINVAL; } @@ -769,14 +771,15 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) * read-only mode. */ if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { - ubi_warn("EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); + ubi_warn(ubi, "EC and VID headers are in the same minimal I/O unit, switch to read-only mode"); ubi->ro_mode = 1; } ubi->leb_size = ubi->peb_size - ubi->leb_start; if (!(ubi->mtd->flags & MTD_WRITEABLE)) { - ubi_msg("MTD device %d is write-protected, attach in read-only mode", + ubi_msg(ubi, + "MTD device %d is write-protected, attach in read-only mode", ubi->mtd->index); ubi->ro_mode = 1; } @@ -809,7 +812,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id) int err, old_reserved_pebs = vol->reserved_pebs; if (ubi->ro_mode) { - ubi_warn("skip auto-resize because of R/O mode"); + ubi_warn(ubi, "skip auto-resize because of R/O mode"); return 0; } @@ -830,20 +833,23 @@ static int autoresize(struct ubi_device *ubi, int vol_id) vtbl_rec = ubi->vtbl[vol_id]; err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); if (err) - ubi_err("cannot clean auto-resize flag for volume %d", + ubi_err(ubi, + "cannot clean auto-resize flag for volume %d", vol_id); } else { desc.vol = vol; err = ubi_resize_volume(&desc, old_reserved_pebs + ubi->avail_pebs); if (err) - ubi_err("cannot auto-resize volume %d", vol_id); + ubi_err(ubi, "cannot auto-resize volume %d", + vol_id); } if (err) return err; - ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + ubi_msg(ubi, "volume %d (\"%s\") re-sized from %d to %d LEBs", + vol_id, vol->name, old_reserved_pebs, vol->reserved_pebs); return 0; } @@ -885,7 +891,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, for (i = 0; i < UBI_MAX_DEVICES; i++) { ubi = ubi_devices[i]; if (ubi && mtd->index == ubi->mtd->index) { - ubi_err("mtd%d is already attached to ubi%d", + ubi_err(ubi, + "mtd%d is already attached to ubi%d", mtd->index, i); return -EEXIST; } @@ -900,7 +907,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, * no sense to attach emulated MTD devices, so we prohibit this. */ if (mtd->type == MTD_UBIVOLUME) { - ubi_err("refuse attaching mtd%d - it is already emulated on top of UBI", + ubi_err(ubi, "refuse attaching mtd%d - it is already emulated on top of UBI", mtd->index); return -EINVAL; } @@ -911,7 +918,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, if (!ubi_devices[ubi_num]) break; if (ubi_num == UBI_MAX_DEVICES) { - ubi_err("only %d UBI devices may be created", + ubi_err(ubi, + "only %d UBI devices may be created", UBI_MAX_DEVICES); return -ENFILE; } @@ -921,7 +929,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, /* Make sure ubi_num is not busy */ if (ubi_devices[ubi_num]) { - ubi_err("ubi%d already exists", ubi_num); + ubi_err(ubi, "ubi%d already exists", ubi_num); return -EEXIST; } } @@ -953,13 +961,15 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) <= UBI_FM_MAX_START) { - ubi_err("More than %i PEBs are needed for fastmap, sorry.", + ubi_err(ubi, "More than %i PEBs are needed for fastmap, sorry.", UBI_FM_MAX_START); ubi->fm_disabled = 1; } - ubi_msg("default fastmap pool size: %d", ubi->fm_pool.max_size); - ubi_msg("default fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); + ubi_msg(ubi, "default fastmap pool size: %d", + ubi->fm_pool.max_size); + ubi_msg(ubi, "default fastmap WL pool size: %d", + ubi->fm_wl_pool.max_size); #else ubi->fm_disabled = 1; #endif @@ -970,7 +980,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, mutex_init(&ubi->fm_mutex); init_rwsem(&ubi->fm_sem); - ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); + ubi_msg(ubi, "attaching mtd%d to ubi%d", mtd->index, ubi_num); err = io_init(ubi, max_beb_per1024); if (err) @@ -989,7 +999,8 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, #endif err = ubi_attach(ubi, 0); if (err) { - ubi_err("failed to attach mtd%d, error %d", mtd->index, err); + ubi_err(ubi, "failed to attach mtd%d, error %d", + mtd->index, err); goto out_free; } @@ -1010,28 +1021,32 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name); if (IS_ERR(ubi->bgt_thread)) { err = PTR_ERR(ubi->bgt_thread); - ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, + ubi_err(ubi, "cannot spawn \"%s\", error %d", + ubi->bgt_name, err); goto out_debugfs; } - ubi_msg("attached mtd%d (name \"%s\", size %llu MiB) to ubi%d", - mtd->index, mtd->name, ubi->flash_size >> 20, ubi_num); - ubi_msg("PEB size: %d bytes (%d KiB), LEB size: %d bytes", + ubi_msg(ubi, "attached mtd%d (name \"%s\", size %llu MiB)", + mtd->index, mtd->name, ubi->flash_size >> 20); + ubi_msg(ubi, "PEB size: %d bytes (%d KiB), LEB size: %d bytes", ubi->peb_size, ubi->peb_size >> 10, ubi->leb_size); - ubi_msg("min./max. I/O unit sizes: %d/%d, sub-page size %d", + ubi_msg(ubi, "min./max. I/O unit sizes: %d/%d, sub-page size %d", ubi->min_io_size, ubi->max_write_size, ubi->hdrs_min_io_size); - ubi_msg("VID header offset: %d (aligned %d), data offset: %d", + ubi_msg(ubi, "VID header offset: %d (aligned %d), data offset: %d", ubi->vid_hdr_offset, ubi->vid_hdr_aloffset, ubi->leb_start); - ubi_msg("good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", + ubi_msg(ubi, "good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d", ubi->good_peb_count, ubi->bad_peb_count, ubi->corr_peb_count); - ubi_msg("user volume: %d, internal volumes: %d, max. volumes count: %d", + ubi_msg(ubi, + "user volume: %d, internal volumes: %d, max. volumes count: %d", ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT, ubi->vtbl_slots); - ubi_msg("max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", + ubi_msg(ubi, + "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u", ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD, ubi->image_seq); - ubi_msg("available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", + ubi_msg(ubi, + "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d", ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs); /* @@ -1100,7 +1115,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) return -EBUSY; } /* This may only happen if there is a bug */ - ubi_err("%s reference count %d, destroy anyway", + ubi_err(ubi, "%s reference count %d, destroy anyway", ubi->ubi_name, ubi->ref_count); } ubi_devices[ubi_num] = NULL; @@ -1108,7 +1123,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) ubi_assert(ubi_num == ubi->ubi_num); ubi_notify_all(ubi, UBI_VOLUME_REMOVED, NULL); - ubi_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); + ubi_msg(ubi, "detaching mtd%d", ubi->mtd->index); #ifdef CONFIG_MTD_UBI_FASTMAP /* If we don't write a new fastmap at detach time we lose all * EC updates that have been made since the last written fastmap. */ @@ -1136,7 +1151,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) put_mtd_device(ubi->mtd); vfree(ubi->peb_buf); vfree(ubi->fm_buf); - ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); + ubi_msg(ubi, "mtd%d is detached", ubi->mtd->index); put_device(&ubi->dev); return 0; } @@ -1218,7 +1233,8 @@ static int __init ubi_init(void) BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); if (mtd_devs > UBI_MAX_DEVICES) { - ubi_err("too many MTD devices, maximum is %d", UBI_MAX_DEVICES); + pr_err("UBI error: too many MTD devices, maximum is %d", + UBI_MAX_DEVICES); return -EINVAL; } @@ -1226,19 +1242,19 @@ static int __init ubi_init(void) ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); if (IS_ERR(ubi_class)) { err = PTR_ERR(ubi_class); - ubi_err("cannot create UBI class"); + pr_err("UBI error: cannot create UBI class"); goto out; } err = class_create_file(ubi_class, &ubi_version); if (err) { - ubi_err("cannot create sysfs file"); + pr_err("UBI error: cannot create sysfs file"); goto out_class; } err = misc_register(&ubi_ctrl_cdev); if (err) { - ubi_err("cannot register device"); + pr_err("UBI error: cannot register device"); goto out_version; } @@ -1265,7 +1281,8 @@ static int __init ubi_init(void) mtd = open_mtd_device(p->name); if (IS_ERR(mtd)) { err = PTR_ERR(mtd); - ubi_err("cannot open mtd %s, error %d", p->name, err); + pr_err("UBI error: cannot open mtd %s, error %d", + p->name, err); /* See comment below re-ubi_is_module(). */ if (ubi_is_module()) goto out_detach; @@ -1277,7 +1294,8 @@ static int __init ubi_init(void) p->vid_hdr_offs, p->max_beb_per1024); mutex_unlock(&ubi_devices_mutex); if (err < 0) { - ubi_err("cannot attach mtd%d", mtd->index); + pr_err("UBI error: cannot attach mtd%d", + mtd->index); put_mtd_device(mtd); /* @@ -1300,7 +1318,7 @@ static int __init ubi_init(void) err = ubiblock_init(); if (err) { - ubi_err("block: cannot initialize, error %d", err); + pr_err("UBI error: block: cannot initialize, error %d", err); /* See comment above re-ubi_is_module(). */ if (ubi_is_module()) @@ -1326,7 +1344,7 @@ out_version: out_class: class_destroy(ubi_class); out: - ubi_err("cannot initialize UBI, error %d", err); + pr_err("UBI error: cannot initialize UBI, error %d", err); return err; } late_initcall(ubi_init); @@ -1365,7 +1383,7 @@ static int __init bytes_str_to_int(const char *str) result = simple_strtoul(str, &endp, 0); if (str == endp || result >= INT_MAX) { - ubi_err("incorrect bytes count: \"%s\"\n", str); + pr_err("UBI error: incorrect bytes count: \"%s\"\n", str); return -EINVAL; } @@ -1381,7 +1399,7 @@ static int __init bytes_str_to_int(const char *str) case '\0': break; default: - ubi_err("incorrect bytes count: \"%s\"\n", str); + pr_err("UBI error: incorrect bytes count: \"%s\"\n", str); return -EINVAL; } @@ -1408,20 +1426,20 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) return -EINVAL; if (mtd_devs == UBI_MAX_DEVICES) { - ubi_err("too many parameters, max. is %d\n", + pr_err("UBI error: too many parameters, max. is %d\n", UBI_MAX_DEVICES); return -EINVAL; } len = strnlen(val, MTD_PARAM_LEN_MAX); if (len == MTD_PARAM_LEN_MAX) { - ubi_err("parameter \"%s\" is too long, max. is %d\n", + pr_err("UBI error: parameter \"%s\" is too long, max. is %d\n", val, MTD_PARAM_LEN_MAX); return -EINVAL; } if (len == 0) { - pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n"); + pr_err("UBI warning: empty 'mtd=' parameter - ignored\n"); return 0; } @@ -1435,7 +1453,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) tokens[i] = strsep(&pbuf, ","); if (pbuf) { - ubi_err("too many arguments at \"%s\"\n", val); + pr_err("UBI error: too many arguments at \"%s\"\n", + val); return -EINVAL; } @@ -1455,7 +1474,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) int err = kstrtoint(token, 10, &p->max_beb_per1024); if (err) { - ubi_err("bad value for max_beb_per1024 parameter: %s", + pr_err("UBI error: bad value for max_beb_per1024 parameter: %s", token); return -EINVAL; } @@ -1466,7 +1485,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) int err = kstrtoint(token, 10, &p->ubi_num); if (err) { - ubi_err("bad value for ubi_num parameter: %s", token); + pr_err("UBI error: bad value for ubi_num parameter: %s", + token); return -EINVAL; } } else diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 7646220..aafef1e 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -48,13 +48,14 @@ /** * get_exclusive - get exclusive access to an UBI volume. + * @ubi: UBI device description object * @desc: volume descriptor * * This function changes UBI volume open mode to "exclusive". Returns previous * mode value (positive integer) in case of success and a negative error code * in case of failure. */ -static int get_exclusive(struct ubi_volume_desc *desc) +static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc) { int users, err; struct ubi_volume *vol = desc->vol; @@ -63,7 +64,8 @@ static int get_exclusive(struct ubi_volume_desc *desc) users = vol->readers + vol->writers + vol->exclusive; ubi_assert(users > 0); if (users > 1) { - ubi_err("%d users for volume %d", users, vol->vol_id); + ubi_err(ubi, "%d users for volume %d", + users, vol->vol_id); err = -EBUSY; } else { vol->readers = vol->writers = 0; @@ -134,7 +136,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file) vol->ubi->ubi_num, vol->vol_id, desc->mode); if (vol->updating) { - ubi_warn("update of volume %d not finished, volume is damaged", + ubi_warn(vol->ubi, "update of volume %d not finished, volume is damaged", vol->vol_id); ubi_assert(!vol->changing_leb); vol->updating = 0; @@ -158,7 +160,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin) if (vol->updating) { /* Update is in progress, seeking is prohibited */ - ubi_err("updating"); + ubi_err(vol->ubi, "updating"); return -EBUSY; } @@ -193,11 +195,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, count, *offp, vol->vol_id); if (vol->updating) { - ubi_err("updating"); + ubi_err(vol->ubi, "updating"); return -EBUSY; } if (vol->upd_marker) { - ubi_err("damaged volume, update marker is set"); + ubi_err(vol->ubi, "damaged volume, update marker is set"); return -EBADF; } if (*offp == vol->used_bytes || count == 0) @@ -277,7 +279,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, lnum = div_u64_rem(*offp, vol->usable_leb_size, &off); if (off & (ubi->min_io_size - 1)) { - ubi_err("unaligned position"); + ubi_err(ubi, "unaligned position"); return -EINVAL; } @@ -286,7 +288,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, /* We can write only in fractions of the minimum I/O unit */ if (count & (ubi->min_io_size - 1)) { - ubi_err("unaligned write length"); + ubi_err(ubi, "unaligned write length"); return -EINVAL; } @@ -348,7 +350,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, err = ubi_more_leb_change_data(ubi, vol, buf, count); if (err < 0) { - ubi_err("cannot accept more %zd bytes of data, error %d", + ubi_err(ubi, "cannot accept more %zd bytes of data, error %d", count, err); return err; } @@ -370,7 +372,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, return err; if (err) { - ubi_warn("volume %d on UBI device %d is corrupted", + ubi_warn(ubi, "volume %d on UBI device %d is corrupted", vol->vol_id, ubi->ubi_num); vol->corrupted = 1; } @@ -420,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, break; } - err = get_exclusive(desc); + err = get_exclusive(ubi, desc); if (err < 0) break; @@ -454,7 +456,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd, req.bytes < 0 || req.lnum >= vol->usable_leb_size) break; - err = get_exclusive(desc); + err = get_exclusive(ubi, desc); if (err < 0) break; @@ -640,7 +642,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi, return 0; bad: - ubi_err("bad volume creation request"); + ubi_err(ubi, "bad volume creation request"); ubi_dump_mkvol_req(req); return err; } @@ -706,12 +708,12 @@ static int rename_volumes(struct ubi_device *ubi, for (i = 0; i < req->count - 1; i++) { for (n = i + 1; n < req->count; n++) { if (req->ents[i].vol_id == req->ents[n].vol_id) { - ubi_err("duplicated volume id %d", + ubi_err(ubi, "duplicated volume id %d", req->ents[i].vol_id); return -EINVAL; } if (!strcmp(req->ents[i].name, req->ents[n].name)) { - ubi_err("duplicated volume name \"%s\"", + ubi_err(ubi, "duplicated volume name \"%s\"", req->ents[i].name); return -EINVAL; } @@ -734,7 +736,8 @@ static int rename_volumes(struct ubi_device *ubi, re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE); if (IS_ERR(re->desc)) { err = PTR_ERR(re->desc); - ubi_err("cannot open volume %d, error %d", vol_id, err); + ubi_err(ubi, + "cannot open volume %d, error %d", vol_id, err); kfree(re); goto out_free; } @@ -793,7 +796,7 @@ static int rename_volumes(struct ubi_device *ubi, continue; /* The volume exists but busy, or an error occurred */ - ubi_err("cannot open volume \"%s\", error %d", + ubi_err(ubi, "cannot open volume \"%s\", error %d", re->new_name, err); goto out_free; } diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index 63cb1d7..9c5c89e 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -43,12 +43,13 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) return; err = mtd_read(ubi->mtd, addr, len, &read, buf); if (err && err != -EUCLEAN) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi, + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", err, len, pnum, offset, read); goto out; } - ubi_msg("dumping %d bytes of data from PEB %d, offset %d", + ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d", len, pnum, offset); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); out: @@ -238,7 +239,7 @@ int ubi_debugfs_init(void) if (IS_ERR_OR_NULL(dfs_rootdir)) { int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); - ubi_err("cannot create \"ubi\" debugfs directory, error %d\n", + pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n", err); return err; } @@ -433,7 +434,7 @@ out_remove: debugfs_remove_recursive(d->dfs_dir); out: err = dent ? PTR_ERR(dent) : -ENODEV; - ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n", + ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n", fname, err); return err; } diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 0e11671d..04c7b36 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -422,7 +422,7 @@ retry: */ if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_BAD_HDR) { - ubi_warn("corrupted VID header at PEB %d, LEB %d:%d", + ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d", pnum, vol_id, lnum); err = -EBADMSG; } else @@ -449,7 +449,7 @@ retry: goto out_unlock; scrub = 1; if (!check) { - ubi_msg("force data checking"); + ubi_msg(ubi, "force data checking"); check = 1; goto retry; } @@ -460,7 +460,7 @@ retry: if (check) { uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len); if (crc1 != crc) { - ubi_warn("CRC error: calculated %#08x, must be %#08x", + ubi_warn(ubi, "CRC error: calculated %#08x, must be %#08x", crc1, crc); err = -EBADMSG; goto out_unlock; @@ -514,7 +514,8 @@ retry: return new_pnum; } - ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); + ubi_msg(ubi, "recover PEB %d, move data to PEB %d", + pnum, new_pnum); err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); if (err && err != UBI_IO_BITFLIPS) { @@ -555,7 +556,7 @@ retry: up_read(&ubi->fm_sem); ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1); - ubi_msg("data was successfully recovered"); + ubi_msg(ubi, "data was successfully recovered"); return 0; out_unlock: @@ -570,13 +571,13 @@ write_error: * Bad luck? This physical eraseblock is bad too? Crud. Let's try to * get another one. */ - ubi_warn("failed to write to PEB %d", new_pnum); + ubi_warn(ubi, "failed to write to PEB %d", new_pnum); ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1); if (++tries > UBI_IO_RETRIES) { ubi_free_vid_hdr(ubi, vid_hdr); return err; } - ubi_msg("try again"); + ubi_msg(ubi, "try again"); goto retry; } @@ -614,7 +615,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { - ubi_warn("failed to write data to PEB %d", pnum); + ubi_warn(ubi, + "failed to write data to PEB %d", pnum); if (err == -EIO && ubi->bad_allowed) err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); @@ -655,7 +657,7 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } @@ -663,7 +665,7 @@ retry: if (len) { err = ubi_io_write_data(ubi, buf, pnum, offset, len); if (err) { - ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", + ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); goto write_error; } @@ -699,7 +701,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi, "try another PEB"); goto retry; } @@ -776,14 +778,14 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", + ubi_warn(ubi, "failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } @@ -819,7 +821,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi, "try another PEB"); goto retry; } @@ -894,14 +896,14 @@ retry: err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); if (err) { - ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d", vol_id, lnum, pnum); goto write_error; } err = ubi_io_write_data(ubi, buf, pnum, 0, len); if (err) { - ubi_warn("failed to write %d bytes of data to PEB %d", + ubi_warn(ubi, "failed to write %d bytes of data to PEB %d", len, pnum); goto write_error; } @@ -941,7 +943,7 @@ write_error: } vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi)); - ubi_msg("try another PEB"); + ubi_msg(ubi, "try another PEB"); goto retry; } @@ -1064,7 +1066,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, dbg_wl("read %d bytes of data", aldata_size); err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size); if (err && err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data from PEB %d", + ubi_warn(ubi, "error %d while reading data from PEB %d", err, from); err = MOVE_SOURCE_RD_ERR; goto out_unlock_buf; @@ -1114,7 +1116,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading VID header back from PEB %d", + ubi_warn(ubi, "error %d while reading VID header back from PEB %d", err, to); if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; @@ -1141,7 +1143,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size); if (err) { if (err != UBI_IO_BITFLIPS) { - ubi_warn("error %d while reading data back from PEB %d", + ubi_warn(ubi, "error %d while reading data back from PEB %d", err, to); if (is_error_sane(err)) err = MOVE_TARGET_RD_ERR; @@ -1153,7 +1155,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, cond_resched(); if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) { - ubi_warn("read data back from PEB %d and it is different", + ubi_warn(ubi, "read data back from PEB %d and it is different", to); err = -EINVAL; goto out_unlock_buf; @@ -1206,10 +1208,10 @@ static void print_rsvd_warning(struct ubi_device *ubi, return; } - ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", + ubi_warn(ubi, "cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d", ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); if (ubi->corr_peb_count) - ubi_warn("%d PEBs are corrupted and not used", + ubi_warn(ubi, "%d PEBs are corrupted and not used", ubi->corr_peb_count); } @@ -1287,7 +1289,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, fm_eba[i][j] == UBI_LEB_UNMAPPED) continue; - ubi_err("LEB:%i:%i is PEB:%i instead of %i!", + ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!", vol->vol_id, i, fm_eba[i][j], scan_eba[i][j]); ubi_assert(0); @@ -1367,10 +1369,10 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai) } if (ubi->avail_pebs < EBA_RESERVED_PEBS) { - ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi_err(ubi, "no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, EBA_RESERVED_PEBS); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, "%d PEBs are corrupted and not used", ubi->corr_peb_count); err = -ENOSPC; goto out_free; diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index 0431b46..38e5a11 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -329,7 +329,7 @@ static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai, if (found) av = tmp_av; else { - ubi_err("orphaned volume in fastmap pool!"); + ubi_err(ubi, "orphaned volume in fastmap pool!"); return UBI_BAD_FASTMAP; } @@ -412,14 +412,14 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, pnum = be32_to_cpu(pebs[i]); if (ubi_io_is_bad(ubi, pnum)) { - ubi_err("bad PEB in fastmap pool!"); + ubi_err(ubi, "bad PEB in fastmap pool!"); ret = UBI_BAD_FASTMAP; goto out; } err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("unable to read EC header! PEB:%i err:%i", + ubi_err(ubi, "unable to read EC header! PEB:%i err:%i", pnum, err); ret = err > 0 ? UBI_BAD_FASTMAP : err; goto out; @@ -433,7 +433,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, image_seq = be32_to_cpu(ech->image_seq); if (image_seq && (image_seq != ubi->image_seq)) { - ubi_err("bad image seq: 0x%x, expected: 0x%x", + ubi_err(ubi, "bad image seq: 0x%x, expected: 0x%x", be32_to_cpu(ech->image_seq), ubi->image_seq); ret = UBI_BAD_FASTMAP; goto out; @@ -491,7 +491,7 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } } else { /* We are paranoid and fall back to scanning mode */ - ubi_err("fastmap pool PEBs contains damaged PEBs!"); + ubi_err(ubi, "fastmap pool PEBs contains damaged PEBs!"); ret = err > 0 ? UBI_BAD_FASTMAP : err; goto out; } @@ -586,7 +586,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fmhdr->magic) != UBI_FM_HDR_MAGIC) { - ubi_err("bad fastmap header magic: 0x%x, expected: 0x%x", + ubi_err(ubi, "bad fastmap header magic: 0x%x, expected: 0x%x", be32_to_cpu(fmhdr->magic), UBI_FM_HDR_MAGIC); goto fail_bad; } @@ -596,7 +596,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; if (be32_to_cpu(fmpl1->magic) != UBI_FM_POOL_MAGIC) { - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", + ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x", be32_to_cpu(fmpl1->magic), UBI_FM_POOL_MAGIC); goto fail_bad; } @@ -606,7 +606,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, if (fm_pos >= fm_size) goto fail_bad; if (be32_to_cpu(fmpl2->magic) != UBI_FM_POOL_MAGIC) { - ubi_err("bad fastmap pool magic: 0x%x, expected: 0x%x", + ubi_err(ubi, "bad fastmap pool magic: 0x%x, expected: 0x%x", be32_to_cpu(fmpl2->magic), UBI_FM_POOL_MAGIC); goto fail_bad; } @@ -617,25 +617,27 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, fm->max_wl_pool_size = be16_to_cpu(fmpl2->max_size); if (pool_size > UBI_FM_MAX_POOL_SIZE || pool_size < 0) { - ubi_err("bad pool size: %i", pool_size); + ubi_err(ubi, "bad pool size: %i", pool_size); goto fail_bad; } if (wl_pool_size > UBI_FM_MAX_POOL_SIZE || wl_pool_size < 0) { - ubi_err("bad WL pool size: %i", wl_pool_size); + ubi_err(ubi, "bad WL pool size: %i", wl_pool_size); goto fail_bad; } if (fm->max_pool_size > UBI_FM_MAX_POOL_SIZE || fm->max_pool_size < 0) { - ubi_err("bad maximal pool size: %i", fm->max_pool_size); + ubi_err(ubi, "bad maximal pool size: %i", + fm->max_pool_size); goto fail_bad; } if (fm->max_wl_pool_size > UBI_FM_MAX_POOL_SIZE || fm->max_wl_pool_size < 0) { - ubi_err("bad maximal WL pool size: %i", fm->max_wl_pool_size); + ubi_err(ubi, "bad maximal WL pool size: %i", + fm->max_wl_pool_size); goto fail_bad; } @@ -694,8 +696,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fmvhdr->magic) != UBI_FM_VHDR_MAGIC) { - ubi_err("bad fastmap vol header magic: 0x%x, " \ - "expected: 0x%x", + ubi_err(ubi, + "bad fastmap vol header magic: 0x%x, expected: 0x%x", be32_to_cpu(fmvhdr->magic), UBI_FM_VHDR_MAGIC); goto fail_bad; } @@ -720,7 +722,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, goto fail_bad; if (be32_to_cpu(fm_eba->magic) != UBI_FM_EBA_MAGIC) { - ubi_err("bad fastmap EBA header magic: 0x%x, " \ + ubi_err(ubi, "bad fastmap EBA header magic: 0x%x, " "expected: 0x%x", be32_to_cpu(fm_eba->magic), UBI_FM_EBA_MAGIC); goto fail_bad; @@ -786,7 +788,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, int err; if (ubi_io_is_bad(ubi, tmp_aeb->pnum)) { - ubi_err("bad PEB in fastmap EBA orphan list"); + ubi_err(ubi, "bad PEB in fastmap EBA orphan list"); ret = UBI_BAD_FASTMAP; kfree(ech); goto fail; @@ -794,8 +796,9 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, err = ubi_io_read_ec_hdr(ubi, tmp_aeb->pnum, ech, 0); if (err && err != UBI_IO_BITFLIPS) { - ubi_err("unable to read EC header! PEB:%i " \ - "err:%i", tmp_aeb->pnum, err); + ubi_err(ubi, + "unable to read EC header! PEB:%i err:%i", + tmp_aeb->pnum, err); ret = err > 0 ? UBI_BAD_FASTMAP : err; kfree(ech); @@ -906,14 +909,14 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, fm->to_be_tortured[0] = 1; if (be32_to_cpu(fmsb->magic) != UBI_FM_SB_MAGIC) { - ubi_err("bad super block magic: 0x%x, expected: 0x%x", + ubi_err(ubi, "bad super block magic: 0x%x, expected: 0x%x", be32_to_cpu(fmsb->magic), UBI_FM_SB_MAGIC); ret = UBI_BAD_FASTMAP; goto free_fm_sb; } if (fmsb->version != UBI_FM_FMT_VERSION) { - ubi_err("bad fastmap version: %i, expected: %i", + ubi_err(ubi, "bad fastmap version: %i, expected: %i", fmsb->version, UBI_FM_FMT_VERSION); ret = UBI_BAD_FASTMAP; goto free_fm_sb; @@ -921,14 +924,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, used_blocks = be32_to_cpu(fmsb->used_blocks); if (used_blocks > UBI_FM_MAX_BLOCKS || used_blocks < 1) { - ubi_err("number of fastmap blocks is invalid: %i", used_blocks); + ubi_err(ubi, + "number of fastmap blocks is invalid: %i", used_blocks); ret = UBI_BAD_FASTMAP; goto free_fm_sb; } fm_size = ubi->leb_size * used_blocks; if (fm_size != ubi->fm_size) { - ubi_err("bad fastmap size: %zi, expected: %zi", fm_size, + ubi_err(ubi, + "bad fastmap size: %zi, expected: %zi", fm_size, ubi->fm_size); ret = UBI_BAD_FASTMAP; goto free_fm_sb; @@ -958,7 +963,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i EC (PEB: %i)", + ubi_err(ubi, + "unable to read fastmap block# %i EC (PEB: %i)", i, pnum); if (ret > 0) ret = UBI_BAD_FASTMAP; @@ -975,7 +981,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, * we shouldn't fail if image_seq == 0. */ if (image_seq && (image_seq != ubi->image_seq)) { - ubi_err("wrong image seq:%d instead of %d", + ubi_err(ubi, + "wrong image seq:%d instead of %d", be32_to_cpu(ech->image_seq), ubi->image_seq); ret = UBI_BAD_FASTMAP; goto free_hdr; @@ -983,14 +990,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i (PEB: %i)", + ubi_err(ubi, + "unable to read fastmap block# %i (PEB: %i)", i, pnum); goto free_hdr; } if (i == 0) { if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { - ubi_err("bad fastmap anchor vol_id: 0x%x," \ + ubi_err(ubi, + "bad fastmap anchor vol_id: 0x%x," " expected: 0x%x", be32_to_cpu(vh->vol_id), UBI_FM_SB_VOLUME_ID); @@ -999,7 +1008,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, } } else { if (be32_to_cpu(vh->vol_id) != UBI_FM_DATA_VOLUME_ID) { - ubi_err("bad fastmap data vol_id: 0x%x," \ + ubi_err(ubi, + "bad fastmap data vol_id: 0x%x," " expected: 0x%x", be32_to_cpu(vh->vol_id), UBI_FM_DATA_VOLUME_ID); @@ -1014,7 +1024,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ret = ubi_io_read(ubi, ubi->fm_buf + (ubi->leb_size * i), pnum, ubi->leb_start, ubi->leb_size); if (ret && ret != UBI_IO_BITFLIPS) { - ubi_err("unable to read fastmap block# %i (PEB: %i, " \ + ubi_err(ubi, + "unable to read fastmap block# %i (PEB: %i, " "err: %i)", i, pnum, ret); goto free_hdr; } @@ -1028,8 +1039,9 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, fmsb2->data_crc = 0; crc = crc32(UBI_CRC32_INIT, ubi->fm_buf, fm_size); if (crc != tmp_crc) { - ubi_err("fastmap data CRC is invalid"); - ubi_err("CRC should be: 0x%x, calc: 0x%x", tmp_crc, crc); + ubi_err(ubi, "fastmap data CRC is invalid"); + ubi_err(ubi, "CRC should be: 0x%x, calc: 0x%x", + tmp_crc, crc); ret = UBI_BAD_FASTMAP; goto free_hdr; } @@ -1065,9 +1077,10 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, ubi->fm = fm; ubi->fm_pool.max_size = ubi->fm->max_pool_size; ubi->fm_wl_pool.max_size = ubi->fm->max_wl_pool_size; - ubi_msg("attached by fastmap"); - ubi_msg("fastmap pool size: %d", ubi->fm_pool.max_size); - ubi_msg("fastmap WL pool size: %d", ubi->fm_wl_pool.max_size); + ubi_msg(ubi, "attached by fastmap"); + ubi_msg(ubi, "fastmap pool size: %d", ubi->fm_pool.max_size); + ubi_msg(ubi, "fastmap WL pool size: %d", + ubi->fm_wl_pool.max_size); ubi->fm_disabled = 0; ubi_free_vid_hdr(ubi, vh); @@ -1075,7 +1088,8 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, out: mutex_unlock(&ubi->fm_mutex); if (ret == UBI_BAD_FASTMAP) - ubi_err("Attach by fastmap failed, doing a full scan!"); + ubi_err(ubi, + "Attach by fastmap failed, doing a full scan!"); return ret; free_hdr: @@ -1271,7 +1285,7 @@ static int ubi_write_fastmap(struct ubi_device *ubi, dbg_bld("writing fastmap SB to PEB %i", new_fm->e[0]->pnum); ret = ubi_io_write_vid_hdr(ubi, new_fm->e[0]->pnum, avhdr); if (ret) { - ubi_err("unable to write vid_hdr to fastmap SB!"); + ubi_err(ubi, "unable to write vid_hdr to fastmap SB!"); goto out_kfree; } @@ -1291,7 +1305,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, new_fm->e[i]->pnum, be64_to_cpu(dvhdr->sqnum)); ret = ubi_io_write_vid_hdr(ubi, new_fm->e[i]->pnum, dvhdr); if (ret) { - ubi_err("unable to write vid_hdr to PEB %i!", + ubi_err(ubi, + "unable to write vid_hdr to PEB %i!", new_fm->e[i]->pnum); goto out_kfree; } @@ -1301,7 +1316,8 @@ static int ubi_write_fastmap(struct ubi_device *ubi, ret = ubi_io_write(ubi, fm_raw + (i * ubi->leb_size), new_fm->e[i]->pnum, ubi->leb_start, ubi->leb_size); if (ret) { - ubi_err("unable to write fastmap to PEB %i!", + ubi_err(ubi, + "unable to write fastmap to PEB %i!", new_fm->e[i]->pnum); goto out_kfree; } @@ -1448,7 +1464,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) ubi->fm = NULL; if (new_fm->used_blocks > UBI_FM_MAX_BLOCKS) { - ubi_err("fastmap too large"); + ubi_err(ubi, "fastmap too large"); ret = -ENOSPC; goto err; } @@ -1460,7 +1476,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) if (!tmp_e && !old_fm) { int j; - ubi_err("could not get any free erase block"); + ubi_err(ubi, + "could not get any free erase block"); for (j = 1; j < i; j++) ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); @@ -1476,7 +1493,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) ubi_wl_put_fm_peb(ubi, new_fm->e[j], j, 0); - ubi_err("could not erase old fastmap PEB"); + ubi_err(ubi, + "could not erase old fastmap PEB"); goto err; } @@ -1502,7 +1520,8 @@ int ubi_update_fastmap(struct ubi_device *ubi) ret = erase_block(ubi, old_fm->e[0]->pnum); if (ret < 0) { int i; - ubi_err("could not erase old anchor PEB"); + ubi_err(ubi, + "could not erase old anchor PEB"); for (i = 1; i < new_fm->used_blocks; i++) ubi_wl_put_fm_peb(ubi, new_fm->e[i], @@ -1523,7 +1542,7 @@ int ubi_update_fastmap(struct ubi_device *ubi) } else { if (!tmp_e) { int i; - ubi_err("could not find any anchor PEB"); + ubi_err(ubi, "could not find any anchor PEB"); for (i = 1; i < new_fm->used_blocks; i++) ubi_wl_put_fm_peb(ubi, new_fm->e[i], i, 0); @@ -1553,13 +1572,14 @@ out_unlock: err: kfree(new_fm); - ubi_warn("Unable to write new fastmap, err=%i", ret); + ubi_warn(ubi, "Unable to write new fastmap, err=%i", ret); ret = 0; if (old_fm) { ret = invalidate_fastmap(ubi, old_fm); if (ret < 0) - ubi_err("Unable to invalidiate current fastmap!"); + ubi_err(ubi, + "Unable to invalidiate current fastmap!"); else if (ret) ret = 0; } diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index d361349..98dba8b 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -177,19 +177,22 @@ retry: * enabled. A corresponding message will be printed * later, when it is has been scrubbed. */ - ubi_msg("fixable bit-flip detected at PEB %d", pnum); + ubi_msg(ubi, + "fixable bit-flip detected at PEB %d", pnum); ubi_assert(len == read); return UBI_IO_BITFLIPS; } if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", + ubi_warn(ubi, + "error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry", err, errstr, len, pnum, offset, read); yield(); goto retry; } - ubi_err("error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi, + "error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes", err, errstr, len, pnum, offset, read); dump_stack(); @@ -246,7 +249,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi, "read-only mode"); return -EROFS; } @@ -273,7 +276,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, } if (ubi_dbg_is_write_failure(ubi)) { - ubi_err("cannot write %d bytes to PEB %d:%d (emulated)", + ubi_err(ubi, + "cannot write %d bytes to PEB %d:%d (emulated)", len, pnum, offset); dump_stack(); return -EIO; @@ -282,7 +286,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, addr = (loff_t)pnum * ubi->peb_size + offset; err = mtd_write(ubi->mtd, addr, len, &written, buf); if (err) { - ubi_err("error %d while writing %d bytes to PEB %d:%d, written %zd bytes", + ubi_err(ubi, + "error %d while writing %d bytes to PEB %d:%d, written %zd bytes", err, len, pnum, offset, written); dump_stack(); ubi_dump_flash(ubi, pnum, offset, len); @@ -338,7 +343,7 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) ubi_assert(pnum >= 0 && pnum < ubi->peb_count); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi, "read-only mode"); return -EROFS; } @@ -355,12 +360,14 @@ retry: err = mtd_erase(ubi->mtd, &ei); if (err) { if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error %d while erasing PEB %d, retry", + ubi_warn(ubi, + "error %d while erasing PEB %d, retry", err, pnum); yield(); goto retry; } - ubi_err("cannot erase PEB %d, error %d", pnum, err); + ubi_err(ubi, + "cannot erase PEB %d, error %d", pnum, err); dump_stack(); return err; } @@ -368,17 +375,18 @@ retry: err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || ei.state == MTD_ERASE_FAILED); if (err) { - ubi_err("interrupted PEB %d erasure", pnum); + ubi_err(ubi, "interrupted PEB %d erasure", pnum); return -EINTR; } if (ei.state == MTD_ERASE_FAILED) { if (retries++ < UBI_IO_RETRIES) { - ubi_warn("error while erasing PEB %d, retry", pnum); + ubi_warn(ubi, + "error while erasing PEB %d, retry", pnum); yield(); goto retry; } - ubi_err("cannot erase PEB %d", pnum); + ubi_err(ubi, "cannot erase PEB %d", pnum); dump_stack(); return -EIO; } @@ -388,7 +396,7 @@ retry: return err; if (ubi_dbg_is_erase_failure(ubi)) { - ubi_err("cannot erase PEB %d (emulated)", pnum); + ubi_err(ubi, "cannot erase PEB %d (emulated)", pnum); return -EIO; } @@ -411,7 +419,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) { int err, i, patt_count; - ubi_msg("run torture test for PEB %d", pnum); + ubi_msg(ubi, "run torture test for PEB %d", pnum); patt_count = ARRAY_SIZE(patterns); ubi_assert(patt_count > 0); @@ -428,7 +436,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size); if (err == 0) { - ubi_err("erased PEB %d, but a non-0xFF byte found", + ubi_err(ubi, + "erased PEB %d, but a non-0xFF byte found", pnum); err = -EIO; goto out; @@ -448,7 +457,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) err = ubi_check_pattern(ubi->peb_buf, patterns[i], ubi->peb_size); if (err == 0) { - ubi_err("pattern %x checking failed for PEB %d", + ubi_err(ubi, + "pattern %x checking failed for PEB %d", patterns[i], pnum); err = -EIO; goto out; @@ -456,7 +466,8 @@ static int torture_peb(struct ubi_device *ubi, int pnum) } err = patt_count; - ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum); + ubi_msg(ubi, + "PEB %d passed torture test, do not mark it as bad", pnum); out: mutex_unlock(&ubi->buf_mutex); @@ -466,7 +477,8 @@ out: * has not passed because it happened on a freshly erased * physical eraseblock which means something is wrong with it. */ - ubi_err("read problems on freshly erased PEB %d, must be bad", + ubi_err(ubi, + "read problems on freshly erased PEB %d, must be bad", pnum); err = -EIO; } @@ -542,7 +554,8 @@ error: * it. Supposedly the flash media or the driver is screwed up, so * return an error. */ - ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err); + ubi_err(ubi, + "cannot invalidate PEB %d, write returned %d", pnum, err); ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); return -EIO; } @@ -574,7 +587,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) return err; if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi, "read-only mode"); return -EROFS; } @@ -616,7 +629,8 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size); if (ret < 0) - ubi_err("error %d while checking if PEB %d is bad", + ubi_err(ubi, + "error %d while checking if PEB %d is bad", ret, pnum); else if (ret) dbg_io("PEB %d is bad", pnum); @@ -642,7 +656,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) ubi_assert(pnum >= 0 && pnum < ubi->peb_count); if (ubi->ro_mode) { - ubi_err("read-only mode"); + ubi_err(ubi, "read-only mode"); return -EROFS; } @@ -651,7 +665,8 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size); if (err) - ubi_err("cannot mark PEB %d bad, error %d", pnum, err); + ubi_err(ubi, + "cannot mark PEB %d bad, error %d", pnum, err); return err; } @@ -674,32 +689,33 @@ static int validate_ec_hdr(const struct ubi_device *ubi, leb_start = be32_to_cpu(ec_hdr->data_offset); if (ec_hdr->version != UBI_VERSION) { - ubi_err("node with incompatible UBI version found: this UBI version is %d, image version is %d", + ubi_err(ubi, + "node with incompatible UBI version found: this UBI version is %d, image version is %d", UBI_VERSION, (int)ec_hdr->version); goto bad; } if (vid_hdr_offset != ubi->vid_hdr_offset) { - ubi_err("bad VID header offset %d, expected %d", + ubi_err(ubi, "bad VID header offset %d, expected %d", vid_hdr_offset, ubi->vid_hdr_offset); goto bad; } if (leb_start != ubi->leb_start) { - ubi_err("bad data offset %d, expected %d", + ubi_err(ubi, "bad data offset %d, expected %d", leb_start, ubi->leb_start); goto bad; } if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) { - ubi_err("bad erase counter %lld", ec); + ubi_err(ubi, "bad erase counter %lld", ec); goto bad; } return 0; bad: - ubi_err("bad EC header"); + ubi_err(ubi, "bad EC header"); ubi_dump_ec_hdr(ec_hdr); dump_stack(); return 1; @@ -765,7 +781,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { /* The physical eraseblock is supposedly empty */ if (verbose) - ubi_warn("no EC header found at PEB %d, only 0xFF bytes", + ubi_warn(ubi, + "no EC header found at PEB %d, only 0xFF bytes", pnum); dbg_bld("no EC header found at PEB %d, only 0xFF bytes", pnum); @@ -780,7 +797,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, * 0xFF bytes. Report that the header is corrupted. */ if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", + ubi_warn(ubi, + "bad magic number at PEB %d: %08x instead of %08x", pnum, magic, UBI_EC_HDR_MAGIC); ubi_dump_ec_hdr(ec_hdr); } @@ -794,7 +812,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, if (hdr_crc != crc) { if (verbose) { - ubi_warn("bad EC header CRC at PEB %d, calculated %#08x, read %#08x", + ubi_warn(ubi, + "bad EC header CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); ubi_dump_ec_hdr(ec_hdr); } @@ -810,7 +829,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, /* And of course validate what has just been read from the media */ err = validate_ec_hdr(ubi, ec_hdr); if (err) { - ubi_err("validation failed for PEB %d", pnum); + ubi_err(ubi, "validation failed for PEB %d", pnum); return -EINVAL; } @@ -884,40 +903,40 @@ static int validate_vid_hdr(const struct ubi_device *ubi, int usable_leb_size = ubi->leb_size - data_pad; if (copy_flag != 0 && copy_flag != 1) { - ubi_err("bad copy_flag"); + ubi_err(ubi, "bad copy_flag"); goto bad; } if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 || data_pad < 0) { - ubi_err("negative values"); + ubi_err(ubi, "negative values"); goto bad; } if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("bad vol_id"); + ubi_err(ubi, "bad vol_id"); goto bad; } if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) { - ubi_err("bad compat"); + ubi_err(ubi, "bad compat"); goto bad; } if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE && compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE && compat != UBI_COMPAT_REJECT) { - ubi_err("bad compat"); + ubi_err(ubi, "bad compat"); goto bad; } if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { - ubi_err("bad vol_type"); + ubi_err(ubi, "bad vol_type"); goto bad; } if (data_pad >= ubi->leb_size / 2) { - ubi_err("bad data_pad"); + ubi_err(ubi, "bad data_pad"); goto bad; } @@ -929,45 +948,46 @@ static int validate_vid_hdr(const struct ubi_device *ubi, * mapped logical eraseblocks. */ if (used_ebs == 0) { - ubi_err("zero used_ebs"); + ubi_err(ubi, "zero used_ebs"); goto bad; } if (data_size == 0) { - ubi_err("zero data_size"); + ubi_err(ubi, "zero data_size"); goto bad; } if (lnum < used_ebs - 1) { if (data_size != usable_leb_size) { - ubi_err("bad data_size"); + ubi_err(ubi, "bad data_size"); goto bad; } } else if (lnum == used_ebs - 1) { if (data_size == 0) { - ubi_err("bad data_size at last LEB"); + ubi_err(ubi, + "bad data_size at last LEB"); goto bad; } } else { - ubi_err("too high lnum"); + ubi_err(ubi, "too high lnum"); goto bad; } } else { if (copy_flag == 0) { if (data_crc != 0) { - ubi_err("non-zero data CRC"); + ubi_err(ubi, "non-zero data CRC"); goto bad; } if (data_size != 0) { - ubi_err("non-zero data_size"); + ubi_err(ubi, "non-zero data_size"); goto bad; } } else { if (data_size == 0) { - ubi_err("zero data_size of copy"); + ubi_err(ubi, "zero data_size of copy"); goto bad; } } if (used_ebs != 0) { - ubi_err("bad used_ebs"); + ubi_err(ubi, "bad used_ebs"); goto bad; } } @@ -975,7 +995,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, return 0; bad: - ubi_err("bad VID header"); + ubi_err(ubi, "bad VID header"); ubi_dump_vid_hdr(vid_hdr); dump_stack(); return 1; @@ -1020,7 +1040,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { if (verbose) - ubi_warn("no VID header found at PEB %d, only 0xFF bytes", + ubi_warn(ubi, + "no VID header found at PEB %d, only 0xFF bytes", pnum); dbg_bld("no VID header found at PEB %d, only 0xFF bytes", pnum); @@ -1031,7 +1052,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, } if (verbose) { - ubi_warn("bad magic number at PEB %d: %08x instead of %08x", + ubi_warn(ubi, + "bad magic number at PEB %d: %08x instead of %08x", pnum, magic, UBI_VID_HDR_MAGIC); ubi_dump_vid_hdr(vid_hdr); } @@ -1045,7 +1067,8 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, if (hdr_crc != crc) { if (verbose) { - ubi_warn("bad CRC at PEB %d, calculated %#08x, read %#08x", + ubi_warn(ubi, + "bad CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); ubi_dump_vid_hdr(vid_hdr); } @@ -1059,7 +1082,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, err = validate_vid_hdr(ubi, vid_hdr); if (err) { - ubi_err("validation failed for PEB %d", pnum); + ubi_err(ubi, "validation failed for PEB %d", pnum); return -EINVAL; } @@ -1129,7 +1152,7 @@ static int self_check_not_bad(const struct ubi_device *ubi, int pnum) if (!err) return err; - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "self-check failed for PEB %d", pnum); dump_stack(); return err > 0 ? -EINVAL : err; } @@ -1154,14 +1177,14 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum, magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - ubi_err("bad magic %#08x, must be %#08x", + ubi_err(ubi, "bad magic %#08x, must be %#08x", magic, UBI_EC_HDR_MAGIC); goto fail; } err = validate_ec_hdr(ubi, ec_hdr); if (err) { - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "self-check failed for PEB %d", pnum); goto fail; } @@ -1201,8 +1224,9 @@ static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); if (hdr_crc != crc) { - ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "bad CRC, calculated %#08x, read %#08x", + crc, hdr_crc); + ubi_err(ubi, "self-check failed for PEB %d", pnum); ubi_dump_ec_hdr(ec_hdr); dump_stack(); err = -EINVAL; @@ -1236,21 +1260,22 @@ static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum, magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", + ubi_err(ubi, + "bad VID header magic %#08x at PEB %d, must be %#08x", magic, pnum, UBI_VID_HDR_MAGIC); goto fail; } err = validate_vid_hdr(ubi, vid_hdr); if (err) { - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "self-check failed for PEB %d", pnum); goto fail; } return err; fail: - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "self-check failed for PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); dump_stack(); return -EINVAL; @@ -1288,9 +1313,10 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); if (hdr_crc != crc) { - ubi_err("bad VID header CRC at PEB %d, calculated %#08x, read %#08x", + ubi_err(ubi, + "bad VID header CRC at PEB %d, calculated %#08x, read %#08x", pnum, crc, hdr_crc); - ubi_err("self-check failed for PEB %d", pnum); + ubi_err(ubi, "self-check failed for PEB %d", pnum); ubi_dump_vid_hdr(vid_hdr); dump_stack(); err = -EINVAL; @@ -1329,7 +1355,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf1) { - ubi_err("cannot allocate memory to check writes"); + ubi_err(ubi, "cannot allocate memory to check writes"); return 0; } @@ -1345,15 +1371,17 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum, if (c == c1) continue; - ubi_err("self-check failed for PEB %d:%d, len %d", + ubi_err(ubi, "self-check failed for PEB %d:%d, len %d", pnum, offset, len); - ubi_msg("data differ at position %d", i); + ubi_msg(ubi, "data differ at position %d", i); dump_len = max_t(int, 128, len - i); - ubi_msg("hex dump of the original buffer from %d to %d", + ubi_msg(ubi, + "hex dump of the original buffer from %d to %d", i, i + dump_len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf + i, dump_len, 1); - ubi_msg("hex dump of the read buffer from %d to %d", + ubi_msg(ubi, + "hex dump of the read buffer from %d to %d", i, i + dump_len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf1 + i, dump_len, 1); @@ -1393,20 +1421,22 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf) { - ubi_err("cannot allocate memory to check for 0xFFs"); + ubi_err(ubi, "cannot allocate memory to check for 0xFFs"); return 0; } err = mtd_read(ubi->mtd, addr, len, &read, buf); if (err && !mtd_is_bitflip(err)) { - ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", + ubi_err(ubi, + "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", err, len, pnum, offset, read); goto error; } err = ubi_check_pattern(buf, 0xFF, len); if (err == 0) { - ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", + ubi_err(ubi, + "flash region at PEB %d:%d, length %d does not contain all 0xFF bytes", pnum, offset, len); goto fail; } @@ -1415,8 +1445,9 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) return 0; fail: - ubi_err("self-check failed for PEB %d", pnum); - ubi_msg("hex dump of the %d-%d region", offset, offset + len); + ubi_err(ubi, "self-check failed for PEB %d", pnum); + ubi_msg(ubi, "hex dump of the %d-%d region", + offset, offset + len); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); err = -EINVAL; error: diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 3aac1ac..f3bab66 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -204,7 +204,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) return ERR_PTR(err); } if (err == 1) { - ubi_warn("volume %d on UBI device %d is corrupted", + ubi_warn(ubi, "volume %d on UBI device %d is corrupted", vol_id, ubi->ubi_num); vol->corrupted = 1; } @@ -221,7 +221,7 @@ out_free: kfree(desc); out_put_ubi: ubi_put_device(ubi); - ubi_err("cannot open device %d, volume %d, error %d", + ubi_err(ubi, "cannot open device %d, volume %d, error %d", ubi_num, vol_id, err); return ERR_PTR(err); } @@ -411,7 +411,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { - ubi_warn("mark volume %d as corrupted", vol_id); + ubi_warn(ubi, "mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index f913d70..4c2fccb 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -111,7 +111,8 @@ void ubi_update_reserved(struct ubi_device *ubi) ubi->avail_pebs -= need; ubi->rsvd_pebs += need; ubi->beb_rsvd_pebs += need; - ubi_msg("reserved more %d PEBs for bad PEB handling", need); + ubi_msg(ubi, + "reserved more %d PEBs for bad PEB handling", need); } /** @@ -128,7 +129,8 @@ void ubi_calculate_reserved(struct ubi_device *ubi) ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count; if (ubi->beb_rsvd_level < 0) { ubi->beb_rsvd_level = 0; - ubi_warn("number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", + ubi_warn(ubi, + "number of bad PEBs (%d) is above the expected limit (%d), not reserving any PEBs for bad PEB handling, will use available PEBs (if any)", ubi->bad_peb_count, ubi->bad_peb_limit); } } diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 7bf4163..00f8835 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -50,13 +50,14 @@ #define UBI_NAME_STR "ubi" /* Normal UBI messages */ -#define ubi_msg(fmt, ...) pr_notice("UBI: " fmt "\n", ##__VA_ARGS__) +#define ubi_msg(ubi, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", \ + ubi->ubi_num, __func__, ##__VA_ARGS__) /* UBI warning messages */ -#define ubi_warn(fmt, ...) pr_warn("UBI warning: %s: " fmt "\n", \ - __func__, ##__VA_ARGS__) +#define ubi_warn(ubi, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \ + ubi->ubi_num, __func__, ##__VA_ARGS__) /* UBI error messages */ -#define ubi_err(fmt, ...) pr_err("UBI error: %s: " fmt "\n", \ - __func__, ##__VA_ARGS__) +#define ubi_err(ubi, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \ + ubi->ubi_num, __func__, ##__VA_ARGS__) /* Background thread name pattern */ #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd" @@ -985,7 +986,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi) { if (!ubi->ro_mode) { ubi->ro_mode = 1; - ubi_warn("switch to read-only mode"); + ubi_warn(ubi, "switch to read-only mode"); dump_stack(); } } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 8330703..84b0f77 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -223,7 +223,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) } if (vol_id == UBI_VOL_NUM_AUTO) { - ubi_err("out of volume IDs"); + ubi_err(ubi, "out of volume IDs"); err = -ENFILE; goto out_unlock; } @@ -237,7 +237,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Ensure that this volume does not exist */ err = -EEXIST; if (ubi->volumes[vol_id]) { - ubi_err("volume %d already exists", vol_id); + ubi_err(ubi, "volume %d already exists", vol_id); goto out_unlock; } @@ -246,7 +246,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) if (ubi->volumes[i] && ubi->volumes[i]->name_len == req->name_len && !strcmp(ubi->volumes[i]->name, req->name)) { - ubi_err("volume \"%s\" exists (ID %d)", req->name, i); + ubi_err(ubi, "volume \"%s\" exists (ID %d)", + req->name, i); goto out_unlock; } @@ -257,9 +258,11 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) /* Reserve physical eraseblocks */ if (vol->reserved_pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs, only %d available", ubi->avail_pebs); + ubi_err(ubi, "not enough PEBs, only %d available", + ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); err = -ENOSPC; goto out_unlock; @@ -314,7 +317,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); err = cdev_add(&vol->cdev, dev, 1); if (err) { - ubi_err("cannot add character device"); + ubi_err(ubi, "cannot add character device"); goto out_mapping; } @@ -326,7 +329,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); err = device_register(&vol->dev); if (err) { - ubi_err("cannot register device"); + ubi_err(ubi, "cannot register device"); goto out_cdev; } @@ -386,7 +389,7 @@ out_unlock: kfree(vol); else put_device(&vol->dev); - ubi_err("cannot create volume %d, error %d", vol_id, err); + ubi_err(ubi, "cannot create volume %d, error %d", vol_id, err); return err; } @@ -454,7 +457,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) return err; out_err: - ubi_err("cannot remove volume %d, error %d", vol_id, err); + ubi_err(ubi, "cannot remove volume %d, error %d", vol_id, err); spin_lock(&ubi->volumes_lock); ubi->volumes[vol_id] = vol; out_unlock: @@ -487,7 +490,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (vol->vol_type == UBI_STATIC_VOLUME && reserved_pebs < vol->used_ebs) { - ubi_err("too small size %d, %d LEBs contain data", + ubi_err(ubi, "too small size %d, %d LEBs contain data", reserved_pebs, vol->used_ebs); return -EINVAL; } @@ -516,10 +519,12 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) if (pebs > 0) { spin_lock(&ubi->volumes_lock); if (pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs: requested %d, available %d", + ubi_err(ubi, + "not enough PEBs: requested %d, available %d", pebs, ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); spin_unlock(&ubi->volumes_lock); err = -ENOSPC; @@ -643,7 +648,8 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); err = cdev_add(&vol->cdev, dev, 1); if (err) { - ubi_err("cannot add character device for volume %d, error %d", + ubi_err(ubi, + "cannot add character device for volume %d, error %d", vol_id, err); return err; } @@ -710,7 +716,8 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (!vol) { if (reserved_pebs) { - ubi_err("no volume info, but volume exists"); + ubi_err(ubi, + "no volume info, but volume exists"); goto fail; } spin_unlock(&ubi->volumes_lock); @@ -719,90 +726,93 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || vol->name_len < 0) { - ubi_err("negative values"); + ubi_err(ubi, "negative values"); goto fail; } if (vol->alignment > ubi->leb_size || vol->alignment == 0) { - ubi_err("bad alignment"); + ubi_err(ubi, "bad alignment"); goto fail; } n = vol->alignment & (ubi->min_io_size - 1); if (vol->alignment != 1 && n) { - ubi_err("alignment is not multiple of min I/O unit"); + ubi_err(ubi, + "alignment is not multiple of min I/O unit"); goto fail; } n = ubi->leb_size % vol->alignment; if (vol->data_pad != n) { - ubi_err("bad data_pad, has to be %lld", n); + ubi_err(ubi, "bad data_pad, has to be %lld", n); goto fail; } if (vol->vol_type != UBI_DYNAMIC_VOLUME && vol->vol_type != UBI_STATIC_VOLUME) { - ubi_err("bad vol_type"); + ubi_err(ubi, "bad vol_type"); goto fail; } if (vol->upd_marker && vol->corrupted) { - ubi_err("update marker and corrupted simultaneously"); + ubi_err(ubi, + "update marker and corrupted simultaneously"); goto fail; } if (vol->reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs"); + ubi_err(ubi, "too large reserved_pebs"); goto fail; } n = ubi->leb_size - vol->data_pad; if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { - ubi_err("bad usable_leb_size, has to be %lld", n); + ubi_err(ubi, "bad usable_leb_size, has to be %lld", n); goto fail; } if (vol->name_len > UBI_VOL_NAME_MAX) { - ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); + ubi_err(ubi, "too long volume name, max is %d", + UBI_VOL_NAME_MAX); goto fail; } n = strnlen(vol->name, vol->name_len + 1); if (n != vol->name_len) { - ubi_err("bad name_len %lld", n); + ubi_err(ubi, "bad name_len %lld", n); goto fail; } n = (long long)vol->used_ebs * vol->usable_leb_size; if (vol->vol_type == UBI_DYNAMIC_VOLUME) { if (vol->corrupted) { - ubi_err("corrupted dynamic volume"); + ubi_err(ubi, "corrupted dynamic volume"); goto fail; } if (vol->used_ebs != vol->reserved_pebs) { - ubi_err("bad used_ebs"); + ubi_err(ubi, "bad used_ebs"); goto fail; } if (vol->last_eb_bytes != vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); + ubi_err(ubi, "bad last_eb_bytes"); goto fail; } if (vol->used_bytes != n) { - ubi_err("bad used_bytes"); + ubi_err(ubi, "bad used_bytes"); goto fail; } } else { if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { - ubi_err("bad used_ebs"); + ubi_err(ubi, "bad used_ebs"); goto fail; } if (vol->last_eb_bytes < 0 || vol->last_eb_bytes > vol->usable_leb_size) { - ubi_err("bad last_eb_bytes"); + ubi_err(ubi, "bad last_eb_bytes"); goto fail; } if (vol->used_bytes < 0 || vol->used_bytes > n || vol->used_bytes < n - vol->usable_leb_size) { - ubi_err("bad used_bytes"); + ubi_err(ubi, "bad used_bytes"); goto fail; } } @@ -820,7 +830,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) if (alignment != vol->alignment || data_pad != vol->data_pad || upd_marker != vol->upd_marker || vol_type != vol->vol_type || name_len != vol->name_len || strncmp(name, vol->name, name_len)) { - ubi_err("volume info is different"); + ubi_err(ubi, "volume info is different"); goto fail; } @@ -828,7 +838,7 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) return 0; fail: - ubi_err("self-check failed for volume %d", vol_id); + ubi_err(ubi, "self-check failed for volume %d", vol_id); if (vol) ubi_dump_vol_info(vol); ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 07cac5f..8068641 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -190,7 +190,7 @@ static int vtbl_check(const struct ubi_device *ubi, crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); if (be32_to_cpu(vtbl[i].crc) != crc) { - ubi_err("bad CRC at record %u: %#08x, not %#08x", + ubi_err(ubi, "bad CRC at record %u: %#08x, not %#08x", i, crc, be32_to_cpu(vtbl[i].crc)); ubi_dump_vtbl_record(&vtbl[i], i); return 1; @@ -224,7 +224,7 @@ static int vtbl_check(const struct ubi_device *ubi, n = ubi->leb_size % alignment; if (data_pad != n) { - ubi_err("bad data_pad, has to be %d", n); + ubi_err(ubi, "bad data_pad, has to be %d", n); err = 6; goto bad; } @@ -240,7 +240,7 @@ static int vtbl_check(const struct ubi_device *ubi, } if (reserved_pebs > ubi->good_peb_count) { - ubi_err("too large reserved_pebs %d, good PEBs %d", + ubi_err(ubi, "too large reserved_pebs %d, good PEBs %d", reserved_pebs, ubi->good_peb_count); err = 9; goto bad; @@ -270,7 +270,8 @@ static int vtbl_check(const struct ubi_device *ubi, if (len1 > 0 && len1 == len2 && !strncmp(vtbl[i].name, vtbl[n].name, len1)) { - ubi_err("volumes %d and %d have the same name \"%s\"", + ubi_err(ubi, + "volumes %d and %d have the same name \"%s\"", i, n, vtbl[i].name); ubi_dump_vtbl_record(&vtbl[i], i); ubi_dump_vtbl_record(&vtbl[n], n); @@ -282,7 +283,8 @@ static int vtbl_check(const struct ubi_device *ubi, return 0; bad: - ubi_err("volume table check failed: record %d, error %d", i, err); + ubi_err(ubi, + "volume table check failed: record %d, error %d", i, err); ubi_dump_vtbl_record(&vtbl[i], i); return -EINVAL; } @@ -446,11 +448,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); if (leb_corrupted[1]) { - ubi_warn("volume table copy #2 is corrupted"); + ubi_warn(ubi, "volume table copy #2 is corrupted"); err = create_vtbl(ubi, ai, 1, leb[0]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi, "volume table was restored"); } /* Both LEB 1 and LEB 2 are OK and consistent */ @@ -465,15 +467,15 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, } if (leb_corrupted[1]) { /* Both LEB 0 and LEB 1 are corrupted */ - ubi_err("both volume tables are corrupted"); + ubi_err(ubi, "both volume tables are corrupted"); goto out_free; } - ubi_warn("volume table copy #1 is corrupted"); + ubi_warn(ubi, "volume table copy #1 is corrupted"); err = create_vtbl(ubi, ai, 0, leb[1]); if (err) goto out_free; - ubi_msg("volume table was restored"); + ubi_msg(ubi, "volume table was restored"); vfree(leb[0]); return leb[1]; @@ -562,7 +564,7 @@ static int init_volumes(struct ubi_device *ubi, if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { - ubi_err("more than one auto-resize volume (%d and %d)", + ubi_err(ubi, "more than one auto-resize volume (%d and %d)", ubi->autoresize_vol_id, i); kfree(vol); return -EINVAL; @@ -608,7 +610,7 @@ static int init_volumes(struct ubi_device *ubi, * We found a static volume which misses several * eraseblocks. Treat it as corrupted. */ - ubi_warn("static volume %d misses %d LEBs - corrupted", + ubi_warn(ubi, "static volume %d misses %d LEBs - corrupted", av->vol_id, av->used_ebs - av->leb_count); vol->corrupted = 1; continue; @@ -646,10 +648,10 @@ static int init_volumes(struct ubi_device *ubi, vol->ubi = ubi; if (reserved_pebs > ubi->avail_pebs) { - ubi_err("not enough PEBs, required %d, available %d", + ubi_err(ubi, "not enough PEBs, required %d, available %d", reserved_pebs, ubi->avail_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, "%d PEBs are corrupted and not used", ubi->corr_peb_count); } ubi->rsvd_pebs += reserved_pebs; @@ -660,13 +662,14 @@ static int init_volumes(struct ubi_device *ubi, /** * check_av - check volume attaching information. + * @ubi: UBI device description object * @vol: UBI volume description object * @av: volume attaching information * * This function returns zero if the volume attaching information is consistent * to the data read from the volume tabla, and %-EINVAL if not. */ -static int check_av(const struct ubi_volume *vol, +static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol, const struct ubi_ainf_volume *av) { int err; @@ -694,7 +697,7 @@ static int check_av(const struct ubi_volume *vol, return 0; bad: - ubi_err("bad attaching information, error %d", err); + ubi_err(ubi, "bad attaching information, error %d", err); ubi_dump_av(av); ubi_dump_vol_info(vol); return -EINVAL; @@ -718,14 +721,16 @@ static int check_attaching_info(const struct ubi_device *ubi, struct ubi_volume *vol; if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { - ubi_err("found %d volumes while attaching, maximum is %d + %d", + ubi_err(ubi, + "found %d volumes while attaching, maximum is %d + %d", ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); return -EINVAL; } if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && ai->highest_vol_id < UBI_INTERNAL_VOL_START) { - ubi_err("too large volume ID %d found", ai->highest_vol_id); + ubi_err(ubi, "too large volume ID %d found", + ai->highest_vol_id); return -EINVAL; } @@ -753,10 +758,11 @@ static int check_attaching_info(const struct ubi_device *ubi, * reboot while the volume was being removed. Discard * these eraseblocks. */ - ubi_msg("finish volume %d removal", av->vol_id); + ubi_msg(ubi, "finish volume %d removal", + av->vol_id); ubi_remove_av(ai, av); } else if (av) { - err = check_av(vol, av); + err = check_av(ubi, vol, av); if (err) return err; } @@ -807,13 +813,15 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai) if (IS_ERR(ubi->vtbl)) return PTR_ERR(ubi->vtbl); } else { - ubi_err("the layout volume was not found"); + ubi_err(ubi, + "the layout volume was not found"); return -EINVAL; } } else { if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) { /* This must not happen with proper UBI images */ - ubi_err("too many LEBs (%d) in layout volume", + ubi_err(ubi, + "too many LEBs (%d) in layout volume", av->leb_count); return -EINVAL; } @@ -862,7 +870,7 @@ static void self_vtbl_check(const struct ubi_device *ubi) return; if (vtbl_check(ubi, ubi->vtbl)) { - ubi_err("self-check failed"); + ubi_err(ubi, "self-check failed"); BUG(); } } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 20f4917..bbc7dff 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -253,7 +253,7 @@ static int do_work(struct ubi_device *ubi) */ err = wrk->func(ubi, wrk, 0); if (err) - ubi_err("work failed with error code %d", err); + ubi_err(ubi, "work failed with error code %d", err); up_read(&ubi->work_sem); return err; @@ -470,8 +470,12 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) { struct ubi_wl_entry *e = NULL; - if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) + if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) { + ubi_warn(ubi, + "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d", + anchor, ubi->free_count, ubi->beb_rsvd_pebs); goto out; + } if (anchor) e = find_anchor_wl_entry(&ubi->free); @@ -507,7 +511,7 @@ static int __wl_get_peb(struct ubi_device *ubi) retry: if (!ubi->free.rb_node) { if (ubi->works_count == 0) { - ubi_err("no free eraseblocks"); + ubi_err(ubi, "no free eraseblocks"); ubi_assert(list_empty(&ubi->works)); return -ENOSPC; } @@ -520,7 +524,7 @@ retry: e = find_mean_wl_entry(ubi, &ubi->free); if (!e) { - ubi_err("no free eraseblocks"); + ubi_err(ubi, "no free eraseblocks"); return -ENOSPC; } @@ -692,7 +696,8 @@ int ubi_wl_get_peb(struct ubi_device *ubi) err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, ubi->peb_size - ubi->vid_hdr_aloffset); if (err) { - ubi_err("new PEB %d does not contain all 0xFF bytes", peb); + ubi_err(ubi, + "new PEB %d does not contain all 0xFF bytes", peb); return err; } @@ -760,7 +765,8 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, * Erase counter overflow. Upgrade UBI and use 64-bit * erase counters internally. */ - ubi_err("erase counter overflow at PEB %d, EC %llu", + ubi_err(ubi, + "erase counter overflow at PEB %d, EC %llu", e->pnum, ec); err = -EINVAL; goto out_free; @@ -1136,7 +1142,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, goto out_not_moved; } - ubi_err("error %d while reading VID header from PEB %d", + ubi_err(ubi, + "error %d while reading VID header from PEB %d", err, e1->pnum); goto out_error; } @@ -1180,7 +1187,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, * UBI from trying to move it over and over again. */ if (ubi->erroneous_peb_count > ubi->max_erroneous) { - ubi_err("too many erroneous eraseblocks (%d)", + ubi_err(ubi, + "too many erroneous eraseblocks (%d)", ubi->erroneous_peb_count); goto out_error; } @@ -1196,7 +1204,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, /* The PEB has been successfully moved */ if (scrubbing) - ubi_msg("scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", + ubi_msg(ubi, + "scrubbed PEB %d (LEB %d:%d), data moved to PEB %d", e1->pnum, vol_id, lnum, e2->pnum); ubi_free_vid_hdr(ubi, vid_hdr); @@ -1273,10 +1282,11 @@ out_not_moved: out_error: if (vol_id != -1) - ubi_err("error %d while moving PEB %d to PEB %d", + ubi_err(ubi, "error %d while moving PEB %d to PEB %d", err, e1->pnum, e2->pnum); else - ubi_err("error %d while moving PEB %d (LEB %d:%d) to PEB %d", + ubi_err(ubi, + "error %d while moving PEB %d (LEB %d:%d) to PEB %d", err, e1->pnum, vol_id, lnum, e2->pnum); spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; @@ -1456,7 +1466,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, return err; } - ubi_err("failed to erase PEB %d, error %d", pnum, err); + ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err); kfree(wl_wrk); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || @@ -1484,7 +1494,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, /* It is %-EIO, the PEB went bad */ if (!ubi->bad_allowed) { - ubi_err("bad physical eraseblock %d detected", pnum); + ubi_err(ubi, "bad physical eraseblock %d detected", + pnum); goto out_ro; } @@ -1492,7 +1503,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, if (ubi->beb_rsvd_pebs == 0) { if (ubi->avail_pebs == 0) { spin_unlock(&ubi->volumes_lock); - ubi_err("no reserved/available physical eraseblocks"); + ubi_err(ubi, + "no reserved/available physical eraseblocks"); goto out_ro; } ubi->avail_pebs -= 1; @@ -1500,7 +1512,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, } spin_unlock(&ubi->volumes_lock); - ubi_msg("mark PEB %d as bad", pnum); + ubi_msg(ubi, "mark PEB %d as bad", pnum); err = ubi_io_mark_bad(ubi, pnum); if (err) goto out_ro; @@ -1521,11 +1533,13 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ubi->good_peb_count -= 1; ubi_calculate_reserved(ubi); if (available_consumed) - ubi_warn("no PEBs in the reserved pool, used an available PEB"); + ubi_warn(ubi, + "no PEBs in the reserved pool, used an available PEB"); else if (ubi->beb_rsvd_pebs) - ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs); + ubi_msg(ubi, "%d PEBs left in the reserve", + ubi->beb_rsvd_pebs); else - ubi_warn("last PEB from the reserve was used"); + ubi_warn(ubi, "last PEB from the reserve was used"); spin_unlock(&ubi->volumes_lock); return err; @@ -1611,7 +1625,7 @@ retry: } else { err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); return err; @@ -1644,7 +1658,7 @@ int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) { struct ubi_wl_entry *e; - ubi_msg("schedule PEB %d for scrubbing", pnum); + ubi_msg(ubi, "schedule PEB %d for scrubbing", pnum); retry: spin_lock(&ubi->wl_lock); @@ -1676,7 +1690,7 @@ retry: err = prot_queue_del(ubi, e->pnum); if (err) { - ubi_err("PEB %d not found", pnum); + ubi_err(ubi, "PEB %d not found", pnum); ubi_ro_mode(ubi); spin_unlock(&ubi->wl_lock); return err; @@ -1796,15 +1810,19 @@ int ubi_thread(void *u) int failures = 0; struct ubi_device *ubi = u; - ubi_msg("background thread \"%s\" started, PID %d", + ubi_msg(ubi, "background thread \"%s\" started, PID %d", ubi->bgt_name, task_pid_nr(current)); set_freezable(); for (;;) { int err; - if (kthread_should_stop()) + if (kthread_should_stop()) { + ubi_msg(ubi, + "background thread \"%s\" should stop, PID %d", + ubi->bgt_name, task_pid_nr(current)); break; + } if (try_to_freeze()) continue; @@ -1821,14 +1839,16 @@ int ubi_thread(void *u) err = do_work(ubi); if (err) { - ubi_err("%s: work failed with error code %d", + ubi_err(ubi, + "%s: work failed with error code %d", ubi->bgt_name, err); if (failures++ > WL_MAX_FAILURES) { /* * Too many failures, disable the thread and * switch to read-only mode. */ - ubi_msg("%s: %d consecutive failures", + ubi_msg(ubi, + "%s: %d consecutive failures", ubi->bgt_name, WL_MAX_FAILURES); ubi_ro_mode(ubi); ubi->thread_enabled = 0; @@ -1979,10 +1999,12 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) #endif if (ubi->avail_pebs < reserved_pebs) { - ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi_err(ubi, + "no enough physical eraseblocks (%d, need %d)", ubi->avail_pebs, reserved_pebs); if (ubi->corr_peb_count) - ubi_err("%d PEBs are corrupted and not used", + ubi_err(ubi, + "%d PEBs are corrupted and not used", ubi->corr_peb_count); goto out_free; } @@ -2028,7 +2050,7 @@ static void protection_queue_destroy(struct ubi_device *ubi) */ void ubi_wl_close(struct ubi_device *ubi) { - dbg_wl("close the WL sub-system"); + ubi_msg(ubi, "close the WL sub-system"); cancel_pending(ubi); protection_queue_destroy(ubi); tree_destroy(&ubi->used); @@ -2070,8 +2092,9 @@ static int self_check_ec(struct ubi_device *ubi, int pnum, int ec) read_ec = be64_to_cpu(ec_hdr->ec); if (ec != read_ec && read_ec - ec > 1) { - ubi_err("self-check failed for PEB %d", pnum); - ubi_err("read EC is %lld, should be %d", read_ec, ec); + ubi_err(ubi, "self-check failed for PEB %d", pnum); + ubi_err(ubi, "read EC is %lld, should be %d", + read_ec, ec); dump_stack(); err = 1; } else @@ -2100,7 +2123,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, if (in_wl_tree(e, root)) return 0; - ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ", + ubi_err(ubi, + "self-check failed for PEB %d, EC %d, RB-tree %p ", e->pnum, e->ec, root); dump_stack(); return -EINVAL; @@ -2128,7 +2152,8 @@ static int self_check_in_pq(const struct ubi_device *ubi, if (p == e) return 0; - ubi_err("self-check failed for PEB %d, EC %d, Protect queue", + ubi_err(ubi, + "self-check failed for PEB %d, EC %d, Protect queue", e->pnum, e->ec); dump_stack(); return -EINVAL; -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation