[PATCH 1/2] mtd: rawnand: brcmnand: fallback to detected ecc-strengh, ecc-step-size
[Ported to U-Boot from the Linux kernel, commit 78933218f5c, original author Kamal Dasu ] The following description is from that patch: If both nand-ecc-strength and nand-ecc-step-size are not specified in device tree node for NAND, raw NAND layer does detect ECC information by reading ONFI extended parameter page for parts using ONFI >= 2.1. In case of non-ONFI NAND parts there could be a nand_id table entry with ECC information. If there is valid device tree entry for nand-ecc-strength and nand-ecc-step-size fields it still shall override the detected values. Signed-off-by: Mark Tomlinson Cc: Dario Binacchi Cc: Michael Trimarchi --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index efbf9a3120a..3e5ae93dda2 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2336,6 +2336,17 @@ static int brcmnand_setup_dev(struct brcmnand_host *host) return -EINVAL; } + if (chip->ecc.mode != NAND_ECC_NONE && + (!chip->ecc.size || !chip->ecc.strength)) { + if (chip->ecc_step_ds && chip->ecc_strength_ds) { + /* use detected parameters */ + chip->ecc.size = chip->ecc_step_ds; + chip->ecc.strength = chip->ecc_strength_ds; + dev_info(ctrl->dev, "Using ECC step-size %d, strength %d\n", +chip->ecc.size, chip->ecc.strength); + } + } + switch (chip->ecc.size) { case 512: if (chip->ecc.algo == NAND_ECC_HAMMING) -- 2.43.2
[PATCH 2/2] mtd: rawnand: brcmnand: Allow soc-specific callbacks to work
Set soc->ctrl so that the prepare_data_bus callback is used if it has been specified by the soc. Signed-off-by: Mark Tomlinson Cc: Dario Binacchi Cc: Michael Trimarchi --- drivers/mtd/nand/raw/brcmnand/brcmnand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 3e5ae93dda2..193471c2fb4 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -2851,6 +2851,8 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc) ctrl->irq, ret); goto err; } +#else + ctrl->soc = soc; #endif /* __UBOOT__ */ #ifndef __UBOOT__ -- 2.43.2
[PATCH v2] rtc: ds1307: Handle oscillator-stop bit correctly
The DS1307 driver was originally based on the DS1337 driver. However, the functionality of the clock set/get functions has diverged. In the original DS1337 driver, the set/get functions did the following: 1) Setting the clock ensured the oscillator was enabled. 2) Getting the clock checked and reset the oscillator-stop flag. The DS1307 does not have an oscillator-stop flag, but the driver tried (incorrectly) to emulate this by ensuring the oscillator was running. It really makes no sense to start a stopped clock without setting it. This patch makes the DS1307 driver behave like the original DS1337 driver again. For the DS1307 itself, this is just a removal of code, since there is no oscillator-fail bit to check or reset, and the clock is started when it is set. Since the DS1307 driver can now also be used for the DS1337 and DS1340 which do have this bit, add code to handle the oscillator-stop bit in the same was the original DS1337 driver did -- i.e. report that the oscillator had stopped and clear the flag. This means that setting the date using the date command (which does both a get and a set) will now clear the oscillator-stop flag in addition to setting and starting the clock. The old-style (non-DM) code has not been updated and will be removed in a future patch. Note that this older code does not support the DS1337, as there is a separate driver for this. Also note that the original (DM) code used the wrong control-register address for the DS1337. Signed-off-by: Mark Tomlinson --- Note that this patch is based on 'next' rather than 'master' as it is dependent on a patch which has not yet made it to master. Changes for v2: - Fix spelling mistake in commit. - Remove changes to old non-DM code. drivers/rtc/ds1307.c | 72 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be97c9d93..1963565c5e 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -41,6 +41,12 @@ enum ds_type { #define RTC_YR_REG_ADDR0x06 #define RTC_CTL_REG_ADDR 0x07 +#define DS1337_CTL_REG_ADDR0x0e +#define DS1337_STAT_REG_ADDR 0x0f +#define DS1340_STAT_REG_ADDR 0x09 + +#define RTC_STAT_BIT_OSF 0x80 + #define RTC_SEC_BIT_CH 0x80/* Clock Halt (in Register 0) */ /* DS1307-specific bits */ @@ -248,6 +254,11 @@ static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) if (ret < 0) return ret; + if (type == ds_1337) { + /* Ensure oscillator is enabled */ + dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, 0); + } + return 0; } @@ -257,62 +268,19 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) uchar buf[7]; enum ds_type type = dev_get_driver_data(dev); -read_rtc: ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); if (ret < 0) return ret; - if (type == ds_1307) { - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, -buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == ds_1337) { - if (buf[RTC_CTL_REG_ADDR] & DS1337_CTL_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_CTL_REG_ADDR] &= ~DS1337_CTL_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, -buf[RTC_CTL_REG_ADDR]); - return -1; - } - } else if (type == ds_1340) { - if (buf[RTC_SEC_REG_ADDR] & DS1340_SEC_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_SEC_REG_ADDR] &= ~DS1340_SEC_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, -buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == m41t11) { - /* clock halted? turn it on, so clock can tick. */ - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, -MCP7941X_BIT_ST); - dm_i2c_reg_write(dev, RTC_SEC_REG
[PATCH] rtc: ds1307: Handle oscillator-stop bit correctly
The DS1307 driver was originally based on the DS1337 driver. However, the functionality of the clock set/get functions has diverged. In the original DS1337 driver, the set/get functions did the following: 1) Setting the clock ensured the oscillator was enabled. 2) Getting the clock checked and reset the oscillator-stop flag. The DS1307 does not have and oscillator-stop flag, but the driver tried (incorrectly) to emulate this by ensuring the oscillator was running. It really makes no sense to start a stopped clock without setting it. This patch makes the DS1307 driver behave like the original DS1337 driver again. For the DS1307 itself, this is just a removal of code, since there is no oscillator-fail bit to check or reset, and the clock is started when it is set. Since the DS1307 driver can now also be used for the DS1337 and DS1340 which do have this bit, add code to handle the oscillator-stop bit in the same was the original DS1337 driver did -- i.e. report that the oscillator had stopped and clear the flag. This means that setting the date using the date command (which does both a get and a set) will now clear the oscillator-stop flag in addition to setting and starting the clock. The old-style (non-DM) code has also been updated. Note that this does not support the DS1337, as there is a separate driver for this. Also note that the original (DM) code used the wrong control-register address for the DS1337. Signed-off-by: Mark Tomlinson --- Note that this patch is based on 'next' rather than 'master' as it is dependent on a patch which has not yet made it to master. drivers/rtc/ds1307.c | 106 --- 1 file changed, 29 insertions(+), 77 deletions(-) diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be97c9d93..7fe4f590c5 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -41,6 +41,12 @@ enum ds_type { #define RTC_YR_REG_ADDR0x06 #define RTC_CTL_REG_ADDR 0x07 +#define DS1337_CTL_REG_ADDR0x0e +#define DS1337_STAT_REG_ADDR 0x0f +#define DS1340_STAT_REG_ADDR 0x09 + +#define RTC_STAT_BIT_OSF 0x80 + #define RTC_SEC_BIT_CH 0x80/* Clock Halt (in Register 0) */ /* DS1307-specific bits */ @@ -92,10 +98,10 @@ int rtc_get (struct rtc_time *tmp) { int rel = 0; uchar sec, min, hour, mday, wday, mon, year; - -#ifdef CONFIG_RTC_MCP79411 -read_rtc: +#ifdef CONFIG_RTC_DS1340 + uchar status; #endif + sec = rtc_read (RTC_SEC_REG_ADDR); min = rtc_read (RTC_MIN_REG_ADDR); hour = rtc_read (RTC_HR_REG_ADDR); @@ -108,32 +114,16 @@ read_rtc: "hr: %02x min: %02x sec: %02x\n", year, mon, mday, wday, hour, min, sec); -#ifdef CONFIG_RTC_DS1307 - if (sec & RTC_SEC_BIT_CH) { - printf ("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ - rtc_write (RTC_SEC_REG_ADDR, - rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH); +#ifdef CONFIG_RTC_DS1340 + status = rtc_read (DS1340_STAT_REG_ADDR); + if (status & RTC_STAT_BIT_OSF) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + rtc_write (DS1340_STAT_REG_ADDR, status & ~RTC_STAT_BIT_OSF); rel = -1; } #endif -#ifdef CONFIG_RTC_MCP79411 - /* make sure that the backup battery is enabled */ - if (!(wday & MCP7941X_BIT_VBATEN)) { - rtc_write(RTC_DAY_REG_ADDR, - wday | MCP7941X_BIT_VBATEN); - } - - /* clock halted? turn it on, so clock can tick. */ - if (!(sec & MCP7941X_BIT_ST)) { - rtc_write(RTC_SEC_REG_ADDR, MCP7941X_BIT_ST); - printf("Started RTC\n"); - goto read_rtc; - } -#endif - - tmp->tm_sec = bcd2bin (sec & 0x7F); tmp->tm_min = bcd2bin (min & 0x7F); tmp->tm_hour = bcd2bin (hour & 0x3F); @@ -248,6 +238,11 @@ static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) if (ret < 0) return ret; + if (type == ds_1337) { + /* Ensure oscillator is enabled */ + dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, 0); + } + return 0; } @@ -257,62 +252,19 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) uchar buf[7]; enum ds_type type = dev_get_driver_data(dev); -read_rtc: ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); if (ret < 0) return ret; - if (type == ds_1307) { - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ -
[U-Boot] [PATCH] net: smsc95xx: Use correct get_unaligned functions
The __get_unaligned_le* functions may not be declared on all platforms. Instead, get_unaligned_le* should be used. On many platforms both of these are the same function. Change-Id: If28222615e85a6f34f3fde42eb21c6f56a2cb988 Reviewed-by: Chris Packham--- drivers/usb/eth/smsc95xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index 08eaed5..7d9abfd 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -391,8 +391,8 @@ static int smsc95xx_write_hwaddr_common(struct usb_device *udev, struct smsc95xx_private *priv, unsigned char *enetaddr) { - u32 addr_lo = __get_unaligned_le32([0]); - u32 addr_hi = __get_unaligned_le16([4]); + u32 addr_lo = get_unaligned_le32([0]); + u32 addr_hi = get_unaligned_le16([4]); int ret; /* set hardware address */ -- 2.8.4 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 8/8] JFFS2: Use merge sort when parsing filesystem
When building the file system the existing code does an insertion into a linked list. It attempts to speed this up by keeping a pointer to where the last entry was inserted but it's still slow. Now the nodes are just inserted into the list without searching through for the correct place. This unsorted list is then sorted once using mergesort after all the entries have been added to the list. This speeds up the scanning of the flash file system considerably. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Changed copyright notice to use SPDX-Licence-Identifier. - Added URL to original mergesort code. - Removed #ifdef, using Makefile change instead. fs/jffs2/Makefile| 1 + fs/jffs2/jffs2_1pass.c | 47 +++ fs/jffs2/jffs2_private.h | 4 fs/jffs2/mergesort.c | 52 4 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 fs/jffs2/mergesort.c diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 4cb0600..3625d74 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -10,4 +10,5 @@ obj-y += compr_rtime.o obj-y += compr_rubin.o obj-y += compr_zlib.o obj-y += jffs2_1pass.o +obj-$(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) += mergesort.o obj-y += mini_inflate.o diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 4325792..64f5542 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -545,49 +545,19 @@ static struct b_node * insert_node(struct b_list *list, u32 offset) { struct b_node *new; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - struct b_node *b, *prev; -#endif if (!(new = add_node(list))) { putstr(add_node failed!\r\n); return NULL; } new-offset = offset; + new-next = NULL; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - if (list-listTail != NULL list-listCompare(new, list-listTail)) - prev = list-listTail; - else if (list-listLast != NULL list-listCompare(new, list-listLast)) - prev = list-listLast; + if (list-listTail != NULL) + list-listTail-next = new; else - prev = NULL; - - for (b = (prev ? prev-next : list-listHead); -b != NULL list-listCompare(new, b); -prev = b, b = b-next) { - list-listLoops++; - } - if (b != NULL) - list-listLast = prev; - - if (b != NULL) { - new-next = b; - if (prev != NULL) - prev-next = new; - else - list-listHead = new; - } else -#endif - { - new-next = (struct b_node *) NULL; - if (list-listTail != NULL) { - list-listTail-next = new; - list-listTail = new; - } else { - list-listTail = list-listHead = new; - } - } + list-listHead = new; + list-listTail = new; return new; } @@ -1800,6 +1770,13 @@ jffs2_1pass_build_lists(struct part_info * part) } free(buf); +#if defined(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) + /* +* Sort the lists. +*/ + sort_list(pL-frag); + sort_list(pL-dir); +#endif putstr(\b\b done.\r\n); /* close off the dots */ /* We don't care if malloc failed - then each read operation will diff --git a/fs/jffs2/jffs2_private.h b/fs/jffs2/jffs2_private.h index 658b325..06b6ca2 100644 --- a/fs/jffs2/jffs2_private.h +++ b/fs/jffs2/jffs2_private.h @@ -98,4 +98,8 @@ data_crc(struct jffs2_raw_inode *node) } } +#if defined(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) +/* External merge sort. */ +int sort_list(struct b_list *list); +#endif #endif /* jffs2_private.h */ diff --git a/fs/jffs2/mergesort.c b/fs/jffs2/mergesort.c new file mode 100644 index 000..6e633a1 --- /dev/null +++ b/fs/jffs2/mergesort.c @@ -0,0 +1,52 @@ +/* + * This file is copyright 2001 Simon Tatham. + * Rewritten from original source 2006 by Dan Merillat for use in u-boot. + * + * Original code can be found at: + * http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + * + * SPDX-License-Identifier:MIT + */ + +#include common.h +#include jffs2_private.h + +int sort_list(struct b_list *list) +{ + struct b_node *p, *q, *e, **tail; + int k, psize, qsize; + + if (!list-listHead) + return 0; + + for (k = 1; k list-listCount; k *= 2) { + tail = list-listHead; + for (p = q = list-listHead; p; p = q) { + /* step 'k' places from p; */ + for (psize = 0; q psize k; psize++) + q = q-next; + qsize = k; + + /* two lists, merge them
[U-Boot] [PATCH v2 3/8] JFFS2: Only list each directory entry once
If multiple versions of a file exist, only the most recent version should be used. The scheme to write 0 for the inode in older versions did not work, since this would have required writing to flash. The only time this caused an issue was listing a directory, where older versions of the file would still be seen. Since the directory entries are sorted, just look at the next entry in the list, and if it's the same move to that entry instead. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Fixed some missing calls to put_fl_mem(). fs/jffs2/jffs2_1pass.c | 38 +- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index aaeb522..346f3a1 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -845,7 +845,6 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) jDir = (struct jffs2_raw_dirent *) get_node_mem(b-offset, pL-readbuf); if ((pino == jDir-pino) (len == jDir-nsize) - (jDir-ino) /* 0 for unlink */ (!strncmp((char *)jDir-name, name, len))) {/* a match */ if (jDir-version version) { put_fl_mem(jDir, pL-readbuf); @@ -966,13 +965,43 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) for (b = pL-dir.listHead; b; b = b-next) { jDir = (struct jffs2_raw_dirent *) get_node_mem(b-offset, pL-readbuf); - if ((pino == jDir-pino) (jDir-ino)) { /* ino=0 - unlink */ + if (pino == jDir-pino) { u32 i_version = 0; struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode, *i = NULL; - struct b_node *b2 = pL-frag.listHead; + struct b_node *b2; - while (b2) { +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS + /* Check for more recent versions of this file */ + int match; + do { + struct b_node *next = b-next; + struct jffs2_raw_dirent *jDirNext; + if (!next) + break; + jDirNext = (struct jffs2_raw_dirent *) + get_node_mem(next-offset, NULL); + match = jDirNext-pino == jDir-pino + jDirNext-nsize == jDir-nsize + strncmp((char *)jDirNext-name, + (char *)jDir-name, + jDir-nsize) == 0; + if (match) { + /* Use next. It is more recent */ + b = next; + /* Update buffer with the new info */ + *jDir = *jDirNext; + } + put_fl_mem(jDirNext, NULL); + } while (match); +#endif + if (jDir-ino == 0) { + /* Deleted file */ + put_fl_mem(jDir, pL-readbuf); + continue; + } + + for (b2 = pL-frag.listHead; b2; b2 = b2-next) { jNode = (struct jffs2_raw_inode *) get_fl_mem(b2-offset, sizeof(ojNode), ojNode); if (jNode-ino == jDir-ino jNode-version = i_version) { @@ -988,7 +1017,6 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) sizeof(*i), NULL); } - b2 = b2-next; } dump_inode(pL, jDir, i); -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 6/8] JFFS2: Change scansize to match linux kernel
The scan code is similar to the linux kernel, but the kernel defines a much smaller size to scan through before deciding a sector is blank. Assuming that what is in the kernel is OK, make these two match. On its own, this change makes no difference to scanning of any sectors which have a clean marker at the beginning, since the entire sector is not blank. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: None fs/jffs2/jffs2_1pass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index f488537..c55d472 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1480,7 +1480,7 @@ dump_dirents(struct b_lists *pL) } #endif -#define DEFAULT_EMPTY_SCAN_SIZE4096 +#define DEFAULT_EMPTY_SCAN_SIZE256 static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 4/8] JFFS2: Improve speed reading flash files
jffs2_1pass_read_inode() would read the entire data for each node in the filesystem, regardless of whether it was part of the file to be loaded or not. By only reading the header data for an inode, and then reading the data only when it is found to be part of the file to be loaded, much copying of data is saved. jffs2_1pass_list_inodes() read each inode for every file in the directory into a buffer. By using NULL as a buffer pointer, NOR flash simply returns a pointer, and therefore avoids a memory copy. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Change comment style fs/jffs2/jffs2_1pass.c | 27 +-- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 346f3a1..e58e7d2 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -735,8 +735,13 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif for (b = pL-frag.listHead; b != NULL; b = b-next) { - jNode = (struct jffs2_raw_inode *) get_node_mem(b-offset, - pL-readbuf); + /* +* Copy just the node and not the data at this point, +* since we don't yet know if we need this data. +*/ + jNode = (struct jffs2_raw_inode *)get_fl_mem(b-offset, + sizeof(struct jffs2_raw_inode), + pL-readbuf); if (inode == jNode-ino) { #if 0 putLabeledWord(\r\n\r\nread_inode: totlen = , jNode-totlen); @@ -760,7 +765,15 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif if(dest) { - src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode); + /* +* Now that the inode has been checked, +* read the entire inode, including data. +*/ + put_fl_mem(jNode, pL-readbuf); + jNode = (struct jffs2_raw_inode *) + get_node_mem(b-offset, pL-readbuf); + src = ((uchar *)jNode) + + sizeof(struct jffs2_raw_inode); /* ignore data behind latest known EOF */ if (jNode-offset totalSize) { put_fl_mem(jNode, pL-readbuf); @@ -967,7 +980,6 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) pL-readbuf); if (pino == jDir-pino) { u32 i_version = 0; - struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode, *i = NULL; struct b_node *b2; @@ -1003,8 +1015,10 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) for (b2 = pL-frag.listHead; b2; b2 = b2-next) { jNode = (struct jffs2_raw_inode *) - get_fl_mem(b2-offset, sizeof(ojNode), ojNode); - if (jNode-ino == jDir-ino jNode-version = i_version) { + get_fl_mem(b2-offset, sizeof(*jNode), + NULL); + if (jNode-ino == jDir-ino + jNode-version = i_version) { i_version = jNode-version; if (i) put_fl_mem(i, NULL); @@ -1017,6 +1031,7 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) sizeof(*i), NULL); } + put_fl_mem(jNode, NULL); } dump_inode(pL, jDir, i); -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 0/8] JFFS2 fixes and performance improvements
In reply to comments from Wolfgang Denk and Heiko Schocher: My aim was to optimize U-Boot's loading of a JFFS2 file, since we needed to boot much more quickly on one of our devices than we currently were. We had discussed the possibility of abandoning JFFS2 entirely, but chose to see how quickly JFFS2 could be made to work. We also knew that Linux would mount this file system much quicker than u-boot did, so knew that at least some speed improvement was possible. The improvments was from three sources: (1) searching U-Boot mailing list archives, (2) looking at the linux kernel, and (3) our own measurements and improvements. For example, the merge sort (before my modifications) can be found here: http://lists.denx.de/pipermail/u-boot/2007-January/018777.html Two of the patches were inspired from the Linux kernel: Changing scansize, and recognising the CLEANMARKER. While trying to synchronize U-Boot code with Linux sounds like a good idea, I think this wouldn't be the right way to go, since Linux needs to also build lists of blocks which are empty, and a list of blocks that still need to be erased. Stripping this out is more work than just enhancing what U-Boot currently has. === Original cover message follows === These patches fix bugs and improve performance of JFFS2. Some of these improvements can already be found in old mailing lists, but for some reason they have not made their way into the u-boot source. I have the feeling that any one of these patches didn't show enough performance gain to warrant adding it to the source. I am hopeful that together, all these patches can be seen to make a big difference. One of these patches (Only list each directory entry once) is a bug fix, all the rest are for performance. Although performance is not high on the priority list for a bootloader, the length of time it was taking to scan a JFFS2 filesystem was painfully slow. The code for mergesort was found in an abandoned u-boot patch, although I have refactored the code somewhat. The original author is still shown at the top of that file. The timings below are with jffs2_summary_support turned off. With these improvements, summary support was no longer useful - most of our time is now spent loading the actual release. Even without this feature turned on, the code will still load from a filesystem that has summary nodes. Due to not having other resources, I also have not done anything for NAND flash. At least some of these changes will be directly applicable to NAND as well as NOR. My own testing is on a system with a 1GHz PowerPC, and 256MB of NOR Flash. The flash accesses are slow compared with processing power and RAM, so minimising the number of flash accesses makes a huge difference. Here are the timing comparisons for three JFFS2 operations on this system: 1) Scanning the file system 2) Getting a director listing of the top level, and 3) Loading a 30MB file. Times are in seconds, and the contribution from each patch has been measured: ScanListLoadTotal Original: 266.017.323.4 306.7 Speed up comparison: 52.317.323.493.0 List dir entries once: 52.311.023.486.7 Improve read speed: 52.3 0.8 5.458.5 Optimize building lists: 31.9 0.8 5.438.1 Change scansize: 30.8 0.8 5.437.0 Use cleanmarker: 16.0 0.8 5.422.2 Use mergesort:2.0 0.8 5.4 8.2 Note that List dir entries once is not a speed improvement as such, but because old versions of a file and deleted files are no longer scanned, there is an improvement on this filesystem (the flash is approx half full). Also, change scansize appears to do very little in this benchmark list. But without it, the use cleanmarker would not show as much improvement. Changes in v2: - Fix comment style - Remove extra {} pair. - Changed comment style. - Fixed some missing calls to put_fl_mem(). - Change comment style - Change comment style - Changed comment style - Changed copyright notice to use SPDX-Licence-Identifier. - Added URL to original mergesort code. - Removed #ifdef, using Makefile change instead. Mark Tomlinson (8): JFFS2: Return early when file read not necessary JFFS2: Speed up and fix comparison functions JFFS2: Only list each directory entry once JFFS2: Improve speed reading flash files JFFS2: Optimize building lists during scan JFFS2: Change scansize to match linux kernel JFFS2: Use CLEANMARKER to reduce scanning time JFFS2: Use merge sort when parsing filesystem fs/jffs2/Makefile| 1 + fs/jffs2/jffs2_1pass.c | 257 ++- fs/jffs2/jffs2_private.h | 4 + fs/jffs2/mergesort.c | 52 ++ 4 files changed, 223 insertions(+), 91 deletions(-) create mode 100644 fs/jffs2/mergesort.c -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http
[U-Boot] [PATCH v2 7/8] JFFS2: Use CLEANMARKER to reduce scanning time
If a sector has a CLEANMARKER at the beginning, it indicates that the entire sector has been erased. Therefore, if this is found, we can skip the entire block. This was not being done before this patch. The code now does the same as the kernel does when encountering a CLEANMARKER. It still checks that the next few words are , and if so, the block is assumed to be empty, and so is skipped. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Changed comment style fs/jffs2/jffs2_1pass.c | 25 + 1 file changed, 25 insertions(+) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index c55d472..4325792 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1528,6 +1528,8 @@ jffs2_1pass_build_lists(struct part_info * part) uint32_t sumlen; int ret; #endif + /* Indicates a sector with a CLEANMARKER was found */ + int clean_sector = 0; /* Set buf_size to maximum length */ buf_size = DEFAULT_EMPTY_SCAN_SIZE; @@ -1652,6 +1654,14 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += 4; } /* Ran off end. */ + /* +* If this sector had a clean marker at the +* beginning, and immediately following this +* have been a bunch of FF bytes, treat the +* entire sector as empty. +*/ + if (clean_sector) + break; /* See how much more there is to read in this * eraseblock... @@ -1673,6 +1683,11 @@ jffs2_1pass_build_lists(struct part_info * part) buf_ofs = ofs; goto more_empty; } + /* +* Found something not erased in the sector, so reset +* the 'clean_sector' flag. +*/ + clean_sector = 0; if (node-magic != JFFS2_MAGIC_BITMASK || !hdr_crc(node)) { ofs += 4; @@ -1754,6 +1769,16 @@ jffs2_1pass_build_lists(struct part_info * part) %d != %zu\n, node-totlen, sizeof(struct jffs2_unknown_node)); + if ((node-totlen == +sizeof(struct jffs2_unknown_node)) + (ofs == sector_ofs)) { + /* +* Found a CLEANMARKER at the beginning +* of the sector. It's in the correct +* place with correct size and CRC. +*/ + clean_sector = 1; + } break; case JFFS2_NODETYPE_PADDING: if (node-totlen sizeof(struct jffs2_unknown_node)) -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 2/8] JFFS2: Speed up and fix comparison functions
Copying complete nodes from flash can be slow if the flash is slow to read. By only reading the data needed, the sorting operation can be made much faster. The directory entry comparison function also had a two bugs. First, it did not ensure the name was copied, so the name comparison may have been faulty (although it would have worked with NOR flash). Second, setting the ino to zero to ignore the entry did not work, since this was either writing to a temporary buffer, or (for NOR flash) directly to flash. Either way, the change was not remembered. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Changed comment style. fs/jffs2/jffs2_1pass.c | 87 +++--- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 2e569ff..aaeb522 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -598,14 +598,18 @@ insert_node(struct b_list *list, u32 offset) */ static int compare_inodes(struct b_node *new, struct b_node *old) { - struct jffs2_raw_inode ojNew; - struct jffs2_raw_inode ojOld; - struct jffs2_raw_inode *jNew = - (struct jffs2_raw_inode *)get_fl_mem(new-offset, sizeof(ojNew), ojNew); - struct jffs2_raw_inode *jOld = - (struct jffs2_raw_inode *)get_fl_mem(old-offset, sizeof(ojOld), ojOld); - - return jNew-version jOld-version; + /* +* Only read in the version info from flash, not the entire inode. +* This can make a big difference to speed if flash is slow. +*/ + u32 new_version; + u32 old_version; + get_fl_mem(new-offset + offsetof(struct jffs2_raw_inode, version), + sizeof(new_version), new_version); + get_fl_mem(old-offset + offsetof(struct jffs2_raw_inode, version), + sizeof(old_version), old_version); + + return new_version old_version; } /* Sort directory entries so all entries in the same directory @@ -615,42 +619,45 @@ static int compare_inodes(struct b_node *new, struct b_node *old) */ static int compare_dirents(struct b_node *new, struct b_node *old) { - struct jffs2_raw_dirent ojNew; - struct jffs2_raw_dirent ojOld; - struct jffs2_raw_dirent *jNew = - (struct jffs2_raw_dirent *)get_fl_mem(new-offset, sizeof(ojNew), ojNew); - struct jffs2_raw_dirent *jOld = - (struct jffs2_raw_dirent *)get_fl_mem(old-offset, sizeof(ojOld), ojOld); - int cmp; - - /* ascending sort by pino */ - if (jNew-pino != jOld-pino) - return jNew-pino jOld-pino; - - /* pino is the same, so use ascending sort by nsize, so -* we don't do strncmp unless we really must. -*/ - if (jNew-nsize != jOld-nsize) - return jNew-nsize jOld-nsize; - - /* length is also the same, so use ascending sort by name -*/ - cmp = strncmp((char *)jNew-name, (char *)jOld-name, jNew-nsize); - if (cmp != 0) - return cmp 0; - - /* we have duplicate names in this directory, so use ascending -* sort by version + /* +* Using NULL as the buffer for NOR flash prevents the entire node +* being read. This makes most comparisons much quicker as only one +* or two entries from the node will be used most of the time. */ - if (jNew-version jOld-version) { - /* since jNew is newer, we know jOld is not valid, so -* mark it with inode 0 and it will not be used + struct jffs2_raw_dirent *jNew = get_node_mem(new-offset, NULL); + struct jffs2_raw_dirent *jOld = get_node_mem(old-offset, NULL); + int cmp; + int ret; + + if (jNew-pino != jOld-pino) { + /* ascending sort by pino */ + ret = jNew-pino jOld-pino; + } else if (jNew-nsize != jOld-nsize) { + /* +* pino is the same, so use ascending sort by nsize, +* so we don't do strncmp unless we really must. */ - jOld-ino = 0; - return 1; + ret = jNew-nsize jOld-nsize; + } else { + /* +* length is also the same, so use ascending sort by name +*/ + cmp = strncmp((char *)jNew-name, (char *)jOld-name, + jNew-nsize); + if (cmp != 0) { + ret = cmp 0; + } else { + /* +* we have duplicate names in this directory, +* so use ascending sort by version +*/ + ret = jNew-version jOld-version; + } } + put_fl_mem(jNew, NULL); + put_fl_mem(jOld, NULL); - return 0; + return ret; } #endif -- 1.9.1
[U-Boot] [PATCH v2 5/8] JFFS2: Optimize building lists during scan
If the flash is slow, reading less from the flash into buffers makes the process faster. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Change comment style fs/jffs2/jffs2_1pass.c | 25 + 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index e58e7d2..f488537 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1501,7 +1501,7 @@ jffs2_1pass_build_lists(struct part_info * part) u32 counterF = 0; u32 counterN = 0; u32 max_totlen = 0; - u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE; + u32 buf_size; char *buf; nr_sectors = lldiv(part-size, part-sector_size); @@ -1513,7 +1513,7 @@ jffs2_1pass_build_lists(struct part_info * part) /* if we are building a list we need to refresh the cache. */ jffs_init_1pass_list(part); pL = (struct b_lists *)part-jffs2_priv; - buf = malloc(buf_size); + buf = malloc(DEFAULT_EMPTY_SCAN_SIZE); puts (Scanning JFFS2 FS: ); /* start at the beginning of the partition */ @@ -1529,6 +1529,8 @@ jffs2_1pass_build_lists(struct part_info * part) int ret; #endif + /* Set buf_size to maximum length */ + buf_size = DEFAULT_EMPTY_SCAN_SIZE; WATCHDOG_RESET(); #ifdef CONFIG_JFFS2_SUMMARY @@ -1603,6 +1605,11 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += sector_ofs; prevofs = ofs - 1; + /* +* Set buf_size down to the minimum size required. +* This prevents reading in chunks of flash data unnecessarily. +*/ + buf_size = sizeof(union jffs2_node_union); scan_more: while (ofs sector_ofs + part-sector_size) { @@ -1683,13 +1690,18 @@ jffs2_1pass_build_lists(struct part_info * part) case JFFS2_NODETYPE_INODE: if (buf_ofs + buf_len ofs + sizeof(struct jffs2_raw_inode)) { + buf_len = min_t(uint32_t, + sizeof(struct jffs2_raw_inode), + sector_ofs + + part-sector_size - + ofs); get_fl_mem((u32)part-offset + ofs, buf_len, buf); buf_ofs = ofs; node = (void *)buf; } - if (!inode_crc((struct jffs2_raw_inode *) node)) - break; + if (!inode_crc((struct jffs2_raw_inode *)node)) + break; if (insert_node(pL-frag, (u32) part-offset + ofs) == NULL) { @@ -1706,6 +1718,11 @@ jffs2_1pass_build_lists(struct part_info * part) ((struct jffs2_raw_dirent *) node)-nsize) { + buf_len = min_t(uint32_t, + node-totlen, + sector_ofs + + part-sector_size - + ofs); get_fl_mem((u32)part-offset + ofs, buf_len, buf); buf_ofs = ofs; -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH v2 1/8] JFFS2: Return early when file read not necessary
If a destination is not provided, jffs2_1pass_read_inode() only returns the length of the file. In this case, avoid reading all the data nodes, and return as soon as the length of the file is known. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- Changes in v2: - Fix comment style - Remove extra {} pair. fs/jffs2/jffs2_1pass.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index b1d6470..2e569ff 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -719,6 +719,12 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) } put_fl_mem(jNode, pL-readbuf); } + /* +* If no destination is provided, we are done. +* Just return the total size. +*/ + if (!dest) + return totalSize; #endif for (b = pL-frag.listHead; b != NULL; b = b-next) { -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 8/8] JFFS2: Use merge sort when parsing filesystem
When building the file system the existing code does an insertion into a linked list. It attempts to speed this up by keeping a pointer to where the last entry was inserted but it's still slow. Now the nodes are just inserted into the list without searching through for the correct place. This unsorted list is then sorted once using mergesort after all the entries have been added to the list. This speeds up the scanning of the flash file system considerably. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/Makefile| 1 + fs/jffs2/jffs2_1pass.c | 47 fs/jffs2/jffs2_private.h | 4 +++ fs/jffs2/mergesort.c | 70 4 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 fs/jffs2/mergesort.c diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 4cb0600..90524ba 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -10,4 +10,5 @@ obj-y += compr_rtime.o obj-y += compr_rubin.o obj-y += compr_zlib.o obj-y += jffs2_1pass.o +obj-y += mergesort.o obj-y += mini_inflate.o diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 26a748f..a456650 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -125,7 +125,6 @@ #include jffs2_private.h - #defineNODE_CHUNK 1024/* size of memory allocation chunk in b_nodes */ #defineSPIN_BLKSIZE18 /* spin after having scanned 1BLKSIZE bytes */ @@ -545,49 +544,19 @@ static struct b_node * insert_node(struct b_list *list, u32 offset) { struct b_node *new; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - struct b_node *b, *prev; -#endif if (!(new = add_node(list))) { putstr(add_node failed!\r\n); return NULL; } new-offset = offset; + new-next = NULL; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - if (list-listTail != NULL list-listCompare(new, list-listTail)) - prev = list-listTail; - else if (list-listLast != NULL list-listCompare(new, list-listLast)) - prev = list-listLast; + if (list-listTail != NULL) + list-listTail-next = new; else - prev = NULL; - - for (b = (prev ? prev-next : list-listHead); -b != NULL list-listCompare(new, b); -prev = b, b = b-next) { - list-listLoops++; - } - if (b != NULL) - list-listLast = prev; - - if (b != NULL) { - new-next = b; - if (prev != NULL) - prev-next = new; - else - list-listHead = new; - } else -#endif - { - new-next = (struct b_node *) NULL; - if (list-listTail != NULL) { - list-listTail-next = new; - list-listTail = new; - } else { - list-listTail = list-listHead = new; - } - } + list-listHead = new; + list-listTail = new; return new; } @@ -1788,6 +1757,12 @@ jffs2_1pass_build_lists(struct part_info * part) } free(buf); +#if defined(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) + /* Sort the lists. +*/ + sort_list(pL-frag); + sort_list(pL-dir); +#endif putstr(\b\b done.\r\n); /* close off the dots */ /* We don't care if malloc failed - then each read operation will diff --git a/fs/jffs2/jffs2_private.h b/fs/jffs2/jffs2_private.h index 658b325..06b6ca2 100644 --- a/fs/jffs2/jffs2_private.h +++ b/fs/jffs2/jffs2_private.h @@ -98,4 +98,8 @@ data_crc(struct jffs2_raw_inode *node) } } +#if defined(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) +/* External merge sort. */ +int sort_list(struct b_list *list); +#endif #endif /* jffs2_private.h */ diff --git a/fs/jffs2/mergesort.c b/fs/jffs2/mergesort.c new file mode 100644 index 000..10ecc8d --- /dev/null +++ b/fs/jffs2/mergesort.c @@ -0,0 +1,70 @@ +/* + * This file is copyright 2001 Simon Tatham. + * Rewritten from original source 2006 by Dan Merillat for use in u-boot. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the Software), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS
[U-Boot] [PATCH 3/8] JFFS2: Only list each directory entry once
If multiple versions of a file exist, only the most recent version should be used. The scheme to write 0 for the inode in older versions did not work, since this would have required writing to flash. The only time this caused an issue was listing a directory, where older versions of the file would still be seen. Since the directory entries are sorted, just look at the next entry in the list, and if it's the same move to that entry instead. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 37 - 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 079bb73..1f6eea7 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -840,7 +840,6 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) jDir = (struct jffs2_raw_dirent *) get_node_mem(b-offset, pL-readbuf); if ((pino == jDir-pino) (len == jDir-nsize) - (jDir-ino) /* 0 for unlink */ (!strncmp((char *)jDir-name, name, len))) {/* a match */ if (jDir-version version) { put_fl_mem(jDir, pL-readbuf); @@ -961,13 +960,42 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) for (b = pL-dir.listHead; b; b = b-next) { jDir = (struct jffs2_raw_dirent *) get_node_mem(b-offset, pL-readbuf); - if ((pino == jDir-pino) (jDir-ino)) { /* ino=0 - unlink */ + if (pino == jDir-pino) { u32 i_version = 0; struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode, *i = NULL; - struct b_node *b2 = pL-frag.listHead; + struct b_node *b2; - while (b2) { +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS + /* Check for more recent versions of this file */ + int match; + do { + struct b_node *next = b-next; + struct jffs2_raw_dirent *jDirNext; + if (!next) + break; + jDirNext = (struct jffs2_raw_dirent *) + get_node_mem(next-offset, NULL); + match = jDirNext-pino == jDir-pino + jDirNext-nsize == jDir-nsize + strncmp((char *)jDirNext-name, + (char *)jDir-name, + jDir-nsize) == 0; + if (match) { + /* Use next. It is more recent */ + b = next; + /* Update buffer with the new info */ + *jDir = *jDirNext; + put_fl_mem(jDirNext, NULL); + } + } while (match); +#endif + if (jDir-ino == 0) { + /* Deleted file */ + continue; + } + + for (b2 = pL-frag.listHead; b2; b2 = b2-next) { jNode = (struct jffs2_raw_inode *) get_fl_mem(b2-offset, sizeof(ojNode), ojNode); if (jNode-ino == jDir-ino jNode-version = i_version) { @@ -983,7 +1011,6 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) sizeof(*i), NULL); } - b2 = b2-next; } dump_inode(pL, jDir, i); -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 7/8] JFFS2: Use CLEANMARKER to reduce scanning time
If a sector has a CLEANMARKER at the beginning, it indicates that the entire sector has been erased. Therefore, if this is found, we can skip the entire block. This was not being done before this patch. The code now does the same as the kernel does when encountering a CLEANMARKER. It still checks that the next few words are , and if so, the block is assumed to be empty, and so is skipped. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index d78fb06..26a748f 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1520,6 +1520,8 @@ jffs2_1pass_build_lists(struct part_info * part) uint32_t sumlen; int ret; #endif + /* Indicates a sector with a CLEANMARKER was found */ + int clean_sector = 0; /* Set buf_size to maximum length */ buf_size = DEFAULT_EMPTY_SCAN_SIZE; @@ -1643,6 +1645,13 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += 4; } /* Ran off end. */ + /* If this sector had a clean marker at the +* beginning, and immediately following this +* have been a bunch of FF bytes, treat the +* entire sector as empty. +*/ + if (clean_sector) + break; /* See how much more there is to read in this * eraseblock... @@ -1664,6 +1673,10 @@ jffs2_1pass_build_lists(struct part_info * part) buf_ofs = ofs; goto more_empty; } + /* Found something not erased in the sector, so reset +* the 'clean_sector' flag. +*/ + clean_sector = 0; if (node-magic != JFFS2_MAGIC_BITMASK || !hdr_crc(node)) { ofs += 4; @@ -1745,6 +1758,15 @@ jffs2_1pass_build_lists(struct part_info * part) %d != %zu\n, node-totlen, sizeof(struct jffs2_unknown_node)); + if ((node-totlen == +sizeof(struct jffs2_unknown_node)) + (ofs == sector_ofs)) { + /* Found a CLEANMARKER at the beginning +* of the sector. It's in the correct +* place with correct size and CRC. +*/ + clean_sector = 1; + } break; case JFFS2_NODETYPE_PADDING: if (node-totlen sizeof(struct jffs2_unknown_node)) -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 4/8] JFFS2: Improve speed reading flash files
jffs2_1pass_read_inode() would read the entire data for each node in the filesystem, regardless of whether it was part of the file to be loaded or not. By only reading the header data for an inode, and then reading the data only when it is found to be part of the file to be loaded, much copying of data is saved. jffs2_1pass_list_inodes() read each inode for every file in the directory into a buffer. By using NULL as a buffer pointer, NOR flash simply returns a pointer, and therefore avoids a memory copy. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 25 +++-- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 1f6eea7..80210be 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -730,8 +730,12 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif for (b = pL-frag.listHead; b != NULL; b = b-next) { - jNode = (struct jffs2_raw_inode *) get_node_mem(b-offset, - pL-readbuf); + /* Copy just the node and not the data at this point, +* since we don't yet know if we need this data. +*/ + jNode = (struct jffs2_raw_inode *)get_fl_mem(b-offset, + sizeof(struct jffs2_raw_inode), + pL-readbuf); if (inode == jNode-ino) { #if 0 putLabeledWord(\r\n\r\nread_inode: totlen = , jNode-totlen); @@ -755,7 +759,14 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif if(dest) { - src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode); + /* Now that the inode has been checked, +* read the entire inode, including data. +*/ + put_fl_mem(jNode, pL-readbuf); + jNode = (struct jffs2_raw_inode *) + get_node_mem(b-offset, pL-readbuf); + src = ((uchar *)jNode) + + sizeof(struct jffs2_raw_inode); /* ignore data behind latest known EOF */ if (jNode-offset totalSize) { put_fl_mem(jNode, pL-readbuf); @@ -962,7 +973,6 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) pL-readbuf); if (pino == jDir-pino) { u32 i_version = 0; - struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode, *i = NULL; struct b_node *b2; @@ -997,8 +1007,10 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) for (b2 = pL-frag.listHead; b2; b2 = b2-next) { jNode = (struct jffs2_raw_inode *) - get_fl_mem(b2-offset, sizeof(ojNode), ojNode); - if (jNode-ino == jDir-ino jNode-version = i_version) { + get_fl_mem(b2-offset, sizeof(*jNode), + NULL); + if (jNode-ino == jDir-ino + jNode-version = i_version) { i_version = jNode-version; if (i) put_fl_mem(i, NULL); @@ -1011,6 +1023,7 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) sizeof(*i), NULL); } + put_fl_mem(jNode, NULL); } dump_inode(pL, jDir, i); -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 5/8] JFFS2: Optimize building lists during scan
If the flash is slow, reading less from the flash into buffers makes the process faster. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 24 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 80210be..10bd7be 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1493,7 +1493,7 @@ jffs2_1pass_build_lists(struct part_info * part) u32 counterF = 0; u32 counterN = 0; u32 max_totlen = 0; - u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE; + u32 buf_size; char *buf; nr_sectors = lldiv(part-size, part-sector_size); @@ -1505,7 +1505,7 @@ jffs2_1pass_build_lists(struct part_info * part) /* if we are building a list we need to refresh the cache. */ jffs_init_1pass_list(part); pL = (struct b_lists *)part-jffs2_priv; - buf = malloc(buf_size); + buf = malloc(DEFAULT_EMPTY_SCAN_SIZE); puts (Scanning JFFS2 FS: ); /* start at the beginning of the partition */ @@ -1521,6 +1521,8 @@ jffs2_1pass_build_lists(struct part_info * part) int ret; #endif + /* Set buf_size to maximum length */ + buf_size = DEFAULT_EMPTY_SCAN_SIZE; WATCHDOG_RESET(); #ifdef CONFIG_JFFS2_SUMMARY @@ -1595,6 +1597,10 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += sector_ofs; prevofs = ofs - 1; + /* Set buf_size down to the minimum size required. +* This prevents reading in chunks of flash data unnecessarily. +*/ + buf_size = sizeof(union jffs2_node_union); scan_more: while (ofs sector_ofs + part-sector_size) { @@ -1675,13 +1681,18 @@ jffs2_1pass_build_lists(struct part_info * part) case JFFS2_NODETYPE_INODE: if (buf_ofs + buf_len ofs + sizeof(struct jffs2_raw_inode)) { + buf_len = min_t(uint32_t, + sizeof(struct jffs2_raw_inode), + sector_ofs + + part-sector_size - + ofs); get_fl_mem((u32)part-offset + ofs, buf_len, buf); buf_ofs = ofs; node = (void *)buf; } - if (!inode_crc((struct jffs2_raw_inode *) node)) - break; + if (!inode_crc((struct jffs2_raw_inode *)node)) + break; if (insert_node(pL-frag, (u32) part-offset + ofs) == NULL) { @@ -1698,6 +1709,11 @@ jffs2_1pass_build_lists(struct part_info * part) ((struct jffs2_raw_dirent *) node)-nsize) { + buf_len = min_t(uint32_t, + node-totlen, + sector_ofs + + part-sector_size - + ofs); get_fl_mem((u32)part-offset + ofs, buf_len, buf); buf_ofs = ofs; -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/8] JFFS2: Return early when file read not necessary
If a destination is not provided, jffs2_1pass_read_inode() only returns the length of the file. In this case, avoid reading all the data nodes, and return as soon as the length of the file is known. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index b1d6470..2335db1 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -719,6 +719,12 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) } put_fl_mem(jNode, pL-readbuf); } + /* If no destination is provided, we are done. +* Just return the total size. +*/ + if (!dest) { + return totalSize; + } #endif for (b = pL-frag.listHead; b != NULL; b = b-next) { -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/8] JFFS2 fixes and performance improvements
These patches fix bugs and improve performance of JFFS2. Some of these improvements can already be found in old mailing lists, but for some reason they have not made their way into the u-boot source. I have the feeling that any one of these patches didn't show enough performance gain to warrant adding it to the source. I am hopeful that together, all these patches can be seen to make a big difference. One of these patches (Only list each directory entry once) is a bug fix, all the rest are for performance. Although performance is not high on the priority list for a bootloader, the length of time it was taking to scan a JFFS2 filesystem was painfully slow. The code for mergesort was found in an abandoned u-boot patch, although I have refactored the code somewhat. The original author is still shown at the top of that file. The timings below are with jffs2_summary_support turned off. With these improvements, summary support was no longer useful - most of our time is now spent loading the actual release. Even without this feature turned on, the code will still load from a filesystem that has summary nodes. Due to not having other resources, I also have not done anything for NAND flash. At least some of these changes will be directly applicable to NAND as well as NOR. My own testing is on a system with a 1GHz PowerPC, and 256MB of NOR Flash. The flash accesses are slow compared with processing power and RAM, so minimising the number of flash accesses makes a huge difference. Here are the timing comparisons for three JFFS2 operations on this system: 1) Scanning the file system 2) Getting a director listing of the top level, and 3) Loading a 30MB file. Times are in seconds, and the contribution from each patch has been measured: ScanListLoadTotal Original: 266.017.323.4 306.7 Speed up comparison: 52.317.323.493.0 List dir entries once: 52.311.023.486.7 Improve read speed: 52.3 0.8 5.458.5 Optimize building lists: 31.9 0.8 5.438.1 Change scansize: 30.8 0.8 5.437.0 Use cleanmarker: 16.0 0.8 5.422.2 Use mergesort:2.0 0.8 5.4 8.2 Note that List dir entries once is not a speed improvement as such, but because old versions of a file and deleted files are no longer scanned, there is an improvement on this filesystem (the flash is approx half full). Also, change scansize appears to do very little in this benchmark list. But without it, the use cleanmarker would not show as much improvement. Mark Tomlinson (8): JFFS2: Return early when file read not necessary JFFS2: Speed up and fix comparison functions JFFS2: Only list each directory entry once JFFS2: Improve speed reading flash files JFFS2: Optimize building lists during scan JFFS2: Change scansize to match linux kernel JFFS2: Use CLEANMARKER to reduce scanning time JFFS2: Use merge sort when parsing filesystem fs/jffs2/Makefile| 1 + fs/jffs2/jffs2_1pass.c | 245 +-- fs/jffs2/jffs2_private.h | 4 + fs/jffs2/mergesort.c | 70 ++ 4 files changed, 228 insertions(+), 92 deletions(-) create mode 100644 fs/jffs2/mergesort.c -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 6/8] JFFS2: Change scansize to match linux kernel
The scan code is similar to the linux kernel, but the kernel defines a much smaller size to scan through before deciding a sector is blank. Assuming that what is in the kernel is OK, make these two match. On its own, this change makes no difference to scanning of any sectors which have a clean marker at the beginning, since the entire sector is not blank. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 10bd7be..d78fb06 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -1472,7 +1472,7 @@ dump_dirents(struct b_lists *pL) } #endif -#define DEFAULT_EMPTY_SCAN_SIZE4096 +#define DEFAULT_EMPTY_SCAN_SIZE256 static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/8] JFFS2: Speed up and fix comparison functions
Copying complete nodes from flash can be slow if the flash is slow to read. By only reading the data needed, the sorting operation can be made much faster. The directory entry comparison function also had a two bugs. First, it did not ensure the name was copied, so the name comparison may have been faulty (although it would have worked with NOR flash). Second, setting the ino to zero to ignore the entry did not work, since this was either writing to a temporary buffer, or (for NOR flash) directly to flash. Either way, the change was not remembered. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- fs/jffs2/jffs2_1pass.c | 82 ++ 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 2335db1..079bb73 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -598,14 +598,17 @@ insert_node(struct b_list *list, u32 offset) */ static int compare_inodes(struct b_node *new, struct b_node *old) { - struct jffs2_raw_inode ojNew; - struct jffs2_raw_inode ojOld; - struct jffs2_raw_inode *jNew = - (struct jffs2_raw_inode *)get_fl_mem(new-offset, sizeof(ojNew), ojNew); - struct jffs2_raw_inode *jOld = - (struct jffs2_raw_inode *)get_fl_mem(old-offset, sizeof(ojOld), ojOld); - - return jNew-version jOld-version; + /* Only read in the version info from flash, not the entire inode. +* This can make a big difference to speed if flash is slow. +*/ + u32 new_version; + u32 old_version; + get_fl_mem(new-offset + offsetof(struct jffs2_raw_inode, version), + sizeof(new_version), new_version); + get_fl_mem(old-offset + offsetof(struct jffs2_raw_inode, version), + sizeof(old_version), old_version); + + return new_version old_version; } /* Sort directory entries so all entries in the same directory @@ -615,42 +618,41 @@ static int compare_inodes(struct b_node *new, struct b_node *old) */ static int compare_dirents(struct b_node *new, struct b_node *old) { - struct jffs2_raw_dirent ojNew; - struct jffs2_raw_dirent ojOld; - struct jffs2_raw_dirent *jNew = - (struct jffs2_raw_dirent *)get_fl_mem(new-offset, sizeof(ojNew), ojNew); - struct jffs2_raw_dirent *jOld = - (struct jffs2_raw_dirent *)get_fl_mem(old-offset, sizeof(ojOld), ojOld); - int cmp; - - /* ascending sort by pino */ - if (jNew-pino != jOld-pino) - return jNew-pino jOld-pino; - - /* pino is the same, so use ascending sort by nsize, so -* we don't do strncmp unless we really must. -*/ - if (jNew-nsize != jOld-nsize) - return jNew-nsize jOld-nsize; - - /* length is also the same, so use ascending sort by name -*/ - cmp = strncmp((char *)jNew-name, (char *)jOld-name, jNew-nsize); - if (cmp != 0) - return cmp 0; - - /* we have duplicate names in this directory, so use ascending -* sort by version + /* Using NULL as the buffer for NOR flash prevents the entire node +* being read. This makes most comparisons much quicker as only one +* or two entries from the node will be used most of the time. */ - if (jNew-version jOld-version) { - /* since jNew is newer, we know jOld is not valid, so -* mark it with inode 0 and it will not be used + struct jffs2_raw_dirent *jNew = get_node_mem(new-offset, NULL); + struct jffs2_raw_dirent *jOld = get_node_mem(old-offset, NULL); + int cmp; + int ret; + + if (jNew-pino != jOld-pino) { + /* ascending sort by pino */ + ret = jNew-pino jOld-pino; + } else if (jNew-nsize != jOld-nsize) { + /* pino is the same, so use ascending sort by nsize, so +* we don't do strncmp unless we really must. */ - jOld-ino = 0; - return 1; + ret = jNew-nsize jOld-nsize; + } else { + /* length is also the same, so use ascending sort by name +*/ + cmp = strncmp((char *)jNew-name, (char *)jOld-name, + jNew-nsize); + if (cmp != 0) { + ret = cmp 0; + } else { + /* we have duplicate names in this directory, +* so use ascending sort by version +*/ + ret = jNew-version jOld-version; + } } + put_fl_mem(jNew, NULL); + put_fl_mem(jOld, NULL); - return 0; + return ret; } #endif -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u
[U-Boot] [PATCH 1/2] i2c: Fix deselection of muxes
Due to an uninitialised variable, when muxes were deselected, any value could be written to the mux control register. On the PCA9548, this could result in multiple channels being selected, thus enabling multiple pull-up resistors, and much bus capacitance. The fix is simply to initialise the written value to zero. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- drivers/i2c/i2c_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/i2c_core.c b/drivers/i2c/i2c_core.c index d34b749..4539667 100644 --- a/drivers/i2c/i2c_core.c +++ b/drivers/i2c/i2c_core.c @@ -178,7 +178,7 @@ static int i2c_mux_disconnet_all(void) { struct i2c_bus_hose *i2c_bus_tmp = i2c_bus[I2C_BUS]; int i; - uint8_t buf; + uint8_t buf = 0; if (I2C_ADAP-init_done == 0) return 0; -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 2/2] i2c: Correct spelling error
diconnect and disconnet should both be disconnect. Signed-off-by: Mark Tomlinson mark.tomlin...@alliedtelesis.co.nz --- drivers/i2c/i2c_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c_core.c b/drivers/i2c/i2c_core.c index 4539667..41cc3b8 100644 --- a/drivers/i2c/i2c_core.c +++ b/drivers/i2c/i2c_core.c @@ -174,7 +174,7 @@ static int i2c_mux_set_all(void) return 0; } -static int i2c_mux_disconnet_all(void) +static int i2c_mux_disconnect_all(void) { struct i2c_bus_hose *i2c_bus_tmp = i2c_bus[I2C_BUS]; int i; @@ -197,7 +197,7 @@ static int i2c_mux_disconnet_all(void) ret = I2C_ADAP-write(I2C_ADAP, chip, 0, 0, buf, 1); if (ret != 0) { - printf(i2c: mux diconnect error\n); + printf(i2c: mux disconnect error\n); return ret; } } while (i 0); @@ -293,7 +293,7 @@ int i2c_set_bus_num(unsigned int bus) } #ifndef CONFIG_SYS_I2C_DIRECT_BUS - i2c_mux_disconnet_all(); + i2c_mux_disconnect_all(); #endif gd-cur_i2c_bus = bus; -- 1.9.1 ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH 0/1] Fix hang trying to protect flash sectors
Sorry, no. The flash chips are 0xf800-0xf9ff (32MB). (Actually we have twice this area reserved for 64MB flash in the future). The flash chip from 0xf800 is also mirrored at 0xfff0 at boot time. I don't know if you consider this a hardware bug to not have all the flash at the very top of memory, but that is the way our product has been designed. Here's a memory map of the high memory area: f800-fbff 64M Flash fe00-fe0f1M Battery-backed RAM ff00-ff00 64K On-board logic ff70-ff7f1M CCSR fff0-1M Flash (mirror of f800). So we have CONFIG_SYS_FLASH_BASE pointing to the entire Flash, and CONFIG_SYS_MONITOR_BASE pointing to the mirrored section which contains u-boot. The auto protect was already there; nothing new. See CONFIG_SYS_FLASH_AUTOPROTECT_LIST in cfi_flash.c. Stefan Roese s...@denx.de 5/19/2010 9:44 PM Mark, On Tuesday 18 May 2010 22:10:51 mark tomlinson wrote: Yes we do have 2 flash chips. Here's the mapping: #define CONFIG_SYS_FLASH_BASE 0xf800 /* 2 chips*16M */ Hmmm. 2 * 16MByte, thats 32MByte == 0x200. So you should have one chip at base address 0xff00 and one at 0xfe00. Why 0xf800? #define CONFIG_SYS_MONITOR_BASE TEXT_BASE /* start of monitor */ and in our config.mk file: TEXT_BASE = 0xfff4 This is the same flash chip as that at 0xf800, but remapped at reset by a CPLD to the high memory area too. This seems wrong. See my comments above. The conditional code in cfi_flash.c: #if (CONFIG_SYS_MONITOR_BASE = CONFIG_SYS_FLASH_BASE) \ (!defined(CONFIG_MONITOR_IS_IN_RAM)) is therefore included since 0xfff4 is greater than 0xf800, but flash_get_info(0xfff4) returns NULL (as expected). I don't see why flash_get_info(0xfff4) should return NULL. It should return the pointer to the 16MB FLASH chip starting at 0xff00. I understand that not passing NULL to flash_protect() would be a better idea, and there's nothing wrong with doing both. Agreed in general. But we have to keep the code compact. And unnecessary checks do increase the code size (at least a small bit). I was going to fix it in cfi_flash.c, but noticed that many other areas of code (in different flash.c files) do the same thing. In our own build, I have just removed the code that tries to protect the monitor area, and will use an auto-protect area instead to do the same job. auto-protect area? Please explain what you mean with this? Perhaps this is an interesting feature for mainline as well. Cheers, Stefan -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: off...@denx.de NOTICE: This message contains privileged and confidential information intended only for the use of the addressee named above. If you are not the intended recipient of this message you are hereby notified that you must not disseminate, copy or take any action in reliance on it. If you have received this message in error please notify Allied Telesis Labs Ltd immediately. Any views expressed in this message are those of the individual sender, except where the sender has the authority to issue and specifically states them to be the views of Allied Telesis Labs. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Re: [U-Boot] [PATCH 0/1] Fix hang trying to protect flash sectors
Yes we do have 2 flash chips. Here's the mapping: #define CONFIG_SYS_FLASH_BASE 0xf800 /* 2 chips*16M */ #define CONFIG_SYS_MONITOR_BASE TEXT_BASE /* start of monitor */ and in our config.mk file: TEXT_BASE = 0xfff4 This is the same flash chip as that at 0xf800, but remapped at reset by a CPLD to the high memory area too. The conditional code in cfi_flash.c: #if (CONFIG_SYS_MONITOR_BASE = CONFIG_SYS_FLASH_BASE) \ (!defined(CONFIG_MONITOR_IS_IN_RAM)) is therefore included since 0xfff4 is greater than 0xf800, but flash_get_info(0xfff4) returns NULL (as expected). I understand that not passing NULL to flash_protect() would be a better idea, and there's nothing wrong with doing both. I was going to fix it in cfi_flash.c, but noticed that many other areas of code (in different flash.c files) do the same thing. In our own build, I have just removed the code that tries to protect the monitor area, and will use an auto-protect area instead to do the same job. - Mark Stefan Roese s...@denx.de 5/18/2010 8:20 PM Hi Mark, On Tuesday 18 May 2010 07:26:34 Mark Tomlinson wrote: Our hardware has part of the flash mapped in two address ranges. The CONFIG_SYS_MONITOR_BASE is in the upper 'boot' area, whereas the CONFIG_SYS_FLASH_BANKS_LIST has the full flash available at a lower address. Just to be sure: You have 2 FLASH chips? Mapped at which addresses? And where does CONFIG_SYS_MONITOR_BASE point to? This all works fine until the code in cfi_flash.c:flash_init(), which uses flash_get_info() to find the flash_info_t associated with the monitor and environment. These are not in the probed flash range, so flash_get_info() returns NULL. You mean that flash_get_info(CONFIG_SYS_MONITOR_BASE) returns NULL? Please explain again, why is this the case? This is not checked and is passed directly to flash_protect(). Since flash_protect() was not checking for this NULL pointer either, random memory would be clobbered causing the device to lock up. This patch changes flash_protect() to check for the NULL, and the error goes unreported. I would prefer to fix the real problem, that flash_get_info() returns NULL, instead. Cheers, Stefan -- DENX Software Engineering GmbH, MD: Wolfgang Denk Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: off...@denx.de NOTICE: This message contains privileged and confidential information intended only for the use of the addressee named above. If you are not the intended recipient of this message you are hereby notified that you must not disseminate, copy or take any action in reliance on it. If you have received this message in error please notify Allied Telesis Labs Ltd immediately. Any views expressed in this message are those of the individual sender, except where the sender has the authority to issue and specifically states them to be the views of Allied Telesis Labs. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 1/1] flash: Check info pointer in flash_protect().
Some calls to flash_protect() do not check that info is not NULL. This change prevents this from causing random memory to be stomped on. --- common/flash.c | 10 +++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/common/flash.c b/common/flash.c index eb4b2f5..dc376ee 100644 --- a/common/flash.c +++ b/common/flash.c @@ -43,15 +43,19 @@ extern flash_info_t flash_info[]; /* info for FLASH chips */ void flash_protect (int flag, ulong from, ulong to, flash_info_t *info) { - ulong b_end = info-start[0] + info-size - 1; /* bank end address */ - short s_end = info-sector_count - 1; /* index of last sector */ + ulong b_end;/* bank end address */ + short s_end;/* index of last sector */ int i; /* Do nothing if input data is bad. */ - if (info-sector_count == 0 || info-size == 0 || to from) { + if (!info || info-sector_count == 0 || info-size == 0 || + to from) { return; } + b_end = info-start[0] + info-size - 1; + s_end = info-sector_count - 1; + debug (flash_protect %s: from 0x%08lX to 0x%08lX\n, (flag FLAG_PROTECT_SET) ? ON : (flag FLAG_PROTECT_CLEAR) ? OFF : ???, -- 1.6.3 NOTICE: This message contains privileged and confidential information intended only for the use of the addressee named above. If you are not the intended recipient of this message you are hereby notified that you must not disseminate, copy or take any action in reliance on it. If you have received this message in error please notify Allied Telesis Labs Ltd immediately. Any views expressed in this message are those of the individual sender, except where the sender has the authority to issue and specifically states them to be the views of Allied Telesis Labs. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
[U-Boot] [PATCH 0/1] Fix hang trying to protect flash sectors
Our hardware has part of the flash mapped in two address ranges. The CONFIG_SYS_MONITOR_BASE is in the upper 'boot' area, whereas the CONFIG_SYS_FLASH_BANKS_LIST has the full flash available at a lower address. This all works fine until the code in cfi_flash.c:flash_init(), which uses flash_get_info() to find the flash_info_t associated with the monitor and environment. These are not in the probed flash range, so flash_get_info() returns NULL. This is not checked and is passed directly to flash_protect(). Since flash_protect() was not checking for this NULL pointer either, random memory would be clobbered causing the device to lock up. This patch changes flash_protect() to check for the NULL, and the error goes unreported. Mark Tomlinson (1): flash: Check info pointer in flash_protect(). common/flash.c | 10 +++--- 1 files changed, 7 insertions(+), 3 deletions(-) NOTICE: This message contains privileged and confidential information intended only for the use of the addressee named above. If you are not the intended recipient of this message you are hereby notified that you must not disseminate, copy or take any action in reliance on it. If you have received this message in error please notify Allied Telesis Labs Ltd immediately. Any views expressed in this message are those of the individual sender, except where the sender has the authority to issue and specifically states them to be the views of Allied Telesis Labs. ___ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot