From patchwork Thu Aug 29 15:14:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Hoyler, Gernot" X-Patchwork-Id: 270822 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A89E92C0079 for ; Thu, 29 Aug 2013 23:11:04 +1000 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VF1zu-00011q-Js; Thu, 29 Aug 2013 13:10:50 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VF1zs-0002ga-JT; Thu, 29 Aug 2013 13:10:48 +0000 Received: from usausmgw01.spansion.com ([12.110.209.161]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VF1zp-0002fz-EV for linux-mtd@lists.infradead.org; Thu, 29 Aug 2013 13:10:46 +0000 Received: from biz-exht101.spansion.com ([10.248.30.7]) by usausmgw01.Spansion.com with ESMTP; 29 Aug 2013 06:10:22 -0700 Received: from muc-cse-01.spansion.com (10.244.1.191) by BIZ-EXHT101.spansion.com (10.248.30.13) with Microsoft SMTP Server id 14.2.342.3; Thu, 29 Aug 2013 08:10:22 -0500 From: Gernot Hoyler Organization: Spansion To: Subject: [PATCH 1/2] mtd: cfi_cmdset_0002: write buffer cleanup Date: Thu, 29 Aug 2013 17:14:30 +0200 User-Agent: KMail/1.11.2 (Linux/2.6.31-65nm; KDE/4.2.2; i686; ; ) MIME-Version: 1.0 Content-Disposition: inline Message-ID: <201308291714.31393.Gernot.Hoyler@spansion.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130829_091045_555865_B7D48EC5 X-CRM114-Status: GOOD ( 20.85 ) X-Spam-Score: -4.4 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.5 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This patch cleans up the write buffer programing code for today's and next generation flash devices. It removes classic word programing and uses 100% write buffer programing instead. Word programing is not recommended any more for today's devices. In addition, the patch increases the timeout value for write buffer program operations from 1 ms to 20 ms. Due to the larger write buffer size of today's devices, the maximum program time has become longer too and can now be more than 1 ms (e.g. Spansion S29GL-S). Signed-off-by: Gernot Hoyler --- drivers/mtd/chips/cfi_cmdset_0002.c | 75 +++++++++++++++-------------------- 1 files changed, 32 insertions(+), 43 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 89b9d68..b8f7b87 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1458,21 +1458,18 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, } -/* - * FIXME: interleaved mode not tested, and probably not supported! - */ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const u_char *buf, int len) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; - /* see comments in do_write_oneword() regarding uWriteTimeo. */ - unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; + /* see comments in do_write_oneword() regarding uWriteTimeout, 20ms */ + unsigned long uWriteTimeout = (HZ / 50) + 1; int ret = -EIO; unsigned long cmd_adr; - int z, words; - map_word datum; + int z, words, prolog, epilog, buflen = len; + map_word datum, pdat, edat; adr += chip->start; cmd_adr = adr; @@ -1493,6 +1490,21 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, cmd_adr); + /* If start is not bus-aligned, prepend old contents of flash */ + prolog = (adr & (map_bankwidth(map)-1)); + if (prolog) { + adr -= prolog; + cmd_adr -= prolog; + len += prolog; + pdat = map_read(map, adr); + } + /* If end is not bus-aligned, append old contents of flash */ + epilog = ((adr + len) & (map_bankwidth(map)-1)); + if (epilog) { + len += map_bankwidth(map)-epilog; + edat = map_read(map, adr + len - map_bankwidth(map)); + } + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); @@ -1506,8 +1518,19 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(words - 1), cmd_adr); /* Write data */ z = 0; + if (prolog) { + datum = map_word_load_partial(map, pdat, buf, prolog, + min_t(int, buflen, map_bankwidth(map) - prolog)); + map_write(map, datum, adr); + + z += map_bankwidth(map); + buf += map_bankwidth(map) - prolog; + } while(z < words * map_bankwidth(map)) { - datum = map_word_load(map, buf); + if (epilog && z >= (words-1) * map_bankwidth(map)) + datum = map_word_load_partial(map, edat, buf, 0, epilog); + else + datum = map_word_load(map, buf); map_write(map, datum, adr + z); z += map_bankwidth(map); @@ -1598,36 +1621,12 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, chipnum = to >> cfi->chipshift; ofs = to - (chipnum << cfi->chipshift); - /* If it's not bus-aligned, do the first word write */ - if (ofs & (map_bankwidth(map)-1)) { - size_t local_len = (-ofs)&(map_bankwidth(map)-1); - if (local_len > len) - local_len = len; - ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<chipshift), - local_len, retlen, buf); - if (ret) - return ret; - ofs += local_len; - buf += local_len; - len -= local_len; - - if (ofs >> cfi->chipshift) { - chipnum ++; - ofs = 0; - if (chipnum == cfi->numchips) - return 0; - } - } - - /* Write buffer is worth it only if more than one word to write... */ - while (len >= map_bankwidth(map) * 2) { + while (len) { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) size = len; - if (size % map_bankwidth(map)) - size -= size % map_bankwidth(map); ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size); @@ -1647,16 +1646,6 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, } } - if (len) { - size_t retlen_dregs = 0; - - ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<chipshift), - len, &retlen_dregs, buf); - - *retlen += retlen_dregs; - return ret; - } - return 0; }