[PATCH 1/2] mtd: rawnand: brcmnand: fallback to detected ecc-strengh, ecc-step-size

2024-02-25 Thread Mark Tomlinson
[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

2024-02-25 Thread Mark Tomlinson
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

2021-09-27 Thread Mark Tomlinson
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

2021-09-20 Thread Mark Tomlinson
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

2016-06-13 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson

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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-30 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2015-06-28 Thread Mark Tomlinson
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

2014-12-01 Thread Mark Tomlinson
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

2014-12-01 Thread Mark Tomlinson
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

2010-05-19 Thread mark tomlinson

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

2010-05-18 Thread mark tomlinson

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().

2010-05-17 Thread Mark Tomlinson
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

2010-05-17 Thread Mark Tomlinson
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