diff options
author | Richard Weinberger <richard@nod.at> | 2018-02-08 09:29:52 +0300 |
---|---|---|
committer | Heiko Schocher <hs@denx.de> | 2018-02-19 10:22:58 +0300 |
commit | f82290afc84716a16a8e300d5d17702858ba84ea (patch) | |
tree | a29f2e01e2a019d4e489b18b4188b5cf91d80d10 /drivers/mtd | |
parent | 02b0895c215e252cff50d9edf53a972d2bbbfd30 (diff) | |
download | u-boot-f82290afc84716a16a8e300d5d17702858ba84ea.tar.xz |
mtd: ubi: Fix worker handling
Fixes a bug found on thuban boards, which were for 2 years in
a long-term test with varying temperatures. They showed
problems in u-boot when attaching the ubi partition:
U-Boot# run flash_self_test
Booting from nand
set A...
UBI: attaching mtd1 to ubi0
UBI: scanning is finished
data abort
pc : [<87f97c3c>] lr : [<87f97c28>]
reloc pc : [<8012cc3c>] lr : [<8012cc28>]
sp : 85f686e8 ip : 00000020 fp : 000001f7
r10: 8605ce40 r9 : 85f68ef8 r8 : 0001f000
r7 : 00000001 r6 : 00000006 r5 : 0001f000 r4 : 85f6ecc0
r3 : 00000000 r2 : 44e35000 r1 : 87fcbcd4 r0 : 87fc755b
Flags: nZCv IRQs off FIQs on Mode SVC_32
Resetting CPU ...
Reason is, that accidentially the U-Boot implementation
from __schedule_ubi_work() did not check the flag
ubi->thread_enabled and started with wearleveling work,
but ubi did not have setup all structures at this point
and crashes.
Solve this problem by splitting work scheduling and processing.
Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/ubi/build.c | 10 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/wl.c | 53 |
3 files changed, 40 insertions, 25 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index baf4e2d25b..d81bd434ac 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1060,15 +1060,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, #ifndef __UBOOT__ wake_up_process(ubi->bgt_thread); #else - /* - * U-Boot special: We have no bgt_thread in U-Boot! - * So just call do_work() here directly. - */ - err = do_work(ubi); - if (err) { - ubi_err(ubi, "%s: work failed with error code %d", - ubi->bgt_name, err); - } + ubi_do_worker(ubi); #endif spin_unlock(&ubi->wl_lock); diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 540f721e1b..3337201fb0 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -1119,6 +1119,6 @@ static inline int idx2vol_id(const struct ubi_device *ubi, int idx) } #ifdef __UBOOT__ -int do_work(struct ubi_device *ubi); +void ubi_do_worker(struct ubi_device *ubi); #endif #endif /* !__UBI_UBI_H__ */ diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index e823ca56f2..0de2a4a5f8 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -191,11 +191,7 @@ static void wl_entry_destroy(struct ubi_device *ubi, struct ubi_wl_entry *e) * This function returns zero in case of success and a negative error code in * case of failure. */ -#ifndef __UBOOT__ static int do_work(struct ubi_device *ubi) -#else -int do_work(struct ubi_device *ubi) -#endif { int err; struct ubi_work *wrk; @@ -528,6 +524,33 @@ repeat: spin_unlock(&ubi->wl_lock); } +#ifdef __UBOOT__ +void ubi_do_worker(struct ubi_device *ubi) +{ + int err; + + if (list_empty(&ubi->works) || ubi->ro_mode || + !ubi->thread_enabled || ubi_dbg_is_bgt_disabled(ubi)) + return; + + spin_lock(&ubi->wl_lock); + while (!list_empty(&ubi->works)) { + /* + * call do_work, which executes exactly one work form the queue, + * including removeing it from the work queue. + */ + spin_unlock(&ubi->wl_lock); + err = do_work(ubi); + spin_lock(&ubi->wl_lock); + if (err) { + ubi_err(ubi, "%s: work failed with error code %d", + ubi->bgt_name, err); + } + } + spin_unlock(&ubi->wl_lock); +} +#endif + /** * __schedule_ubi_work - schedule a work. * @ubi: UBI device description object @@ -545,17 +568,6 @@ static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) #ifndef __UBOOT__ if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled(ubi)) wake_up_process(ubi->bgt_thread); -#else - int err; - /* - * U-Boot special: We have no bgt_thread in U-Boot! - * So just call do_work() here directly. - */ - err = do_work(ubi); - if (err) { - ubi_err(ubi, "%s: work failed with error code %d", - ubi->bgt_name, err); - } #endif spin_unlock(&ubi->wl_lock); } @@ -610,6 +622,10 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, wl_wrk->torture = torture; schedule_ubi_work(ubi, wl_wrk); + +#ifdef __UBOOT__ + ubi_do_worker(ubi); +#endif return 0; } @@ -1011,8 +1027,15 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested) wrk->func = &wear_leveling_worker; if (nested) __schedule_ubi_work(ubi, wrk); +#ifndef __UBOOT__ else schedule_ubi_work(ubi, wrk); +#else + else { + schedule_ubi_work(ubi, wrk); + ubi_do_worker(ubi); + } +#endif return err; out_cancel: |