From patchwork Thu May 19 06:58:15 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tadashi Abe X-Patchwork-Id: 96318 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1D98B1007D5 for ; Thu, 19 May 2011 17:00:03 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by bombadil.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QMxBj-00043I-7F; Thu, 19 May 2011 06:58:27 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QMxBh-0001J4-JK; Thu, 19 May 2011 06:58:25 +0000 Received: from mail-pz0-f49.google.com ([209.85.210.49]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QMxBd-0001Il-6A for linux-mtd@lists.infradead.org; Thu, 19 May 2011 06:58:22 +0000 Received: by pzk28 with SMTP id 28so1240799pzk.36 for ; Wed, 18 May 2011 23:58:19 -0700 (PDT) Received: by 10.142.150.32 with SMTP id x32mr1690156wfd.287.1305788299529; Wed, 18 May 2011 23:58:19 -0700 (PDT) Received: from [10.200.16.51] (sw.montavista.co.jp [202.232.97.131]) by mx.google.com with ESMTPS id w14sm2068044wfh.8.2011.05.18.23.58.17 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 18 May 2011 23:58:18 -0700 (PDT) Message-ID: <4DD4BF87.6030107@mvista.com> Date: Thu, 19 May 2011 15:58:15 +0900 From: Tadashi Abe User-Agent: Mozilla/5.0 (X11; U; Linux i686; ja; rv:1.9.2.17) Gecko/20110414 Thunderbird/3.1.10 MIME-Version: 1.0 To: linux-mtd@lists.infradead.org, dwmw2@infradead.org Subject: mtd: fix hang-up in cfi erase and read contention X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110519_025821_432352_71A5951B X-CRM114-Status: GOOD ( 16.59 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.210.49 listed in list.dnswl.org] 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain Cc: Tadashi Abe X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org cfi erase command hangs up when erase and read contention occurs. If read runs at the same address as erase operation, read issues Erase-Suspend via get_chip() and the erase goes into sleep in wait queue. But in this case, read operation exits by time-out without waking it up. I think the other variants (0001, 0020 and lpddr) have the same problem too. Tested and verified the patch only on CFI-0002 flash, though. Signed-off-by: Tadashi Abe Acked-by: Joakim Tjernlund --- drivers/mtd/chips/cfi_cmdset_0001.c | 9 +++------ drivers/mtd/chips/cfi_cmdset_0002.c | 4 +--- drivers/mtd/chips/cfi_cmdset_0020.c | 1 + drivers/mtd/lpddr/lpddr_cmds.c | 7 +------ 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 09cb7c8..121be02 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -812,12 +812,9 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long break; if (time_after(jiffies, timeo)) { - /* Urgh. Resume and pretend we weren't here. */ - map_write(map, CMD(0xd0), adr); - /* Make sure we're in 'read status' mode if it had finished */ - map_write(map, CMD(0x70), adr); - chip->state = FL_ERASING; - chip->oldstate = FL_READY; + /* Urgh. Resume and pretend we weren't here. + * Make sure we're in 'read status' mode if it had finished */ + put_chip(map, chip, adr); printk(KERN_ERR "%s: Chip not ready after erase " "suspended: status = 0x%lx\n", map->name, status.x[0]); return -EIO; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 0b49266..e97e697 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -710,9 +710,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr * there was an error (so leave the erase * routine to recover from it) or we trying to * use the erase-in-progress sector. */ - map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); - chip->state = FL_ERASING; - chip->oldstate = FL_READY; + put_chip(map, chip, adr); printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); return -EIO; } diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index ed56ad3..179814a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -296,6 +296,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof /* make sure we're in 'read status' mode */ map_write(map, CMD(0x70), cmd_addr); chip->state = FL_ERASING; + wake_up(&chip->wq); mutex_unlock(&chip->mutex); printk(KERN_ERR "Chip not ready after erase " "suspended: status = 0x%lx\n", status.x[0]); diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 1267992..16dcd1c 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -313,12 +313,7 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode) if (ret) { /* Oops. something got wrong. */ /* Resume and pretend we weren't here. */ - map_write(map, CMD(LPDDR_RESUME), - map->pfow_base + PFOW_COMMAND_CODE); - map_write(map, CMD(LPDDR_START_EXECUTION), - map->pfow_base + PFOW_COMMAND_EXECUTE); - chip->state = FL_ERASING; - chip->oldstate = FL_READY; + put_chip(map, chip); printk(KERN_ERR "%s: suspend operation failed." "State may be wrong \n", map->name); return -EIO;