From patchwork Thu Oct 28 17:17:51 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 71955 Return-Path: X-Original-To: wd@gemini.denx.de Delivered-To: wd@gemini.denx.de Received: from diddl.denx.de (diddl.denx.de [10.0.0.6]) by gemini.denx.de (Postfix) with ESMTP id F2D04152452 for ; Thu, 28 Oct 2010 19:19:13 +0200 (CEST) Received: from diddl.denx.de (localhost.localdomain [127.0.0.1]) by diddl.denx.de (Postfix) with ESMTP id DC66F3364F8D for ; Thu, 28 Oct 2010 19:19:13 +0200 (CEST) Received: from pop.mnet-online.de by diddl.denx.de with POP3 (fetchmail-6.3.17) for (single-drop); Thu, 28 Oct 2010 19:19:13 +0200 (CEST) Received: from murder ([192.168.8.180]) by backend2 (Cyrus v2.2.12) with LMTPA; Thu, 28 Oct 2010 19:18:13 +0200 X-Sieve: CMU Sieve 2.2 Received: from mail.m-online.net (localhost [127.0.0.1]) by frontend1.mail.m-online.net (Cyrus v2.2.12) with LMTPA; Thu, 28 Oct 2010 19:18:13 +0200 Received: from scanner-2.m-online.net (scanner-2.mail.m-online.net [192.168.8.166]) by mail.m-online.net (Postfix) with ESMTP id 4ABD81C0014C; Thu, 28 Oct 2010 19:18:13 +0200 (CEST) Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by mxin-2.m-online.net (Postfix) with ESMTP id DD45946AF3D; Thu, 28 Oct 2010 19:18:10 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 34D3D280A0; Thu, 28 Oct 2010 19:18:08 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5q2XDnhB0rfD; Thu, 28 Oct 2010 19:18:07 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 38A37280A2; Thu, 28 Oct 2010 19:18:02 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 147E02809B for ; Thu, 28 Oct 2010 19:18:00 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id V15WLJmvcwy0 for ; Thu, 28 Oct 2010 19:17:58 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-iw0-f172.google.com (mail-iw0-f172.google.com [209.85.214.172]) by theia.denx.de (Postfix) with ESMTP id 0668A2805F for ; Thu, 28 Oct 2010 19:17:56 +0200 (CEST) Received: by iwn40 with SMTP id 40so2504364iwn.3 for ; Thu, 28 Oct 2010 10:17:56 -0700 (PDT) Received: by 10.231.152.3 with SMTP id e3mr10407273ibw.157.1288286275806; Thu, 28 Oct 2010 10:17:55 -0700 (PDT) Received: from [192.168.0.210] (static-74-41-60-154.dsl1.pco.ca.frontiernet.net [74.41.60.154]) by mx.google.com with ESMTPS id l3sm932569yha.28.2010.10.28.10.17.53 (version=SSLv3 cipher=RC4-MD5); Thu, 28 Oct 2010 10:17:54 -0700 (PDT) From: Steve Sakoman To: Alagu Sankar , "u-boot@lists.denx.de" Date: Thu, 28 Oct 2010 10:17:51 -0700 Message-ID: <1288286271.2342.259.camel@quadra> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 Cc: Andy Fleming , John Rigby Subject: [U-Boot] [PATCH RFC] mmc: Add multi-block read support to the generic mmc driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de X-Virus-Scanned: by amavisd-new at m-online.net From: Alagu Sankar This patch adds multi-block read support for the generic MMC driver. Large reads are broken into chunks of 65535 blocks to ensure that the code works with controllers having a 16 bit block counter. This patch results in a significant performance improvement. Time to read a 45 MB file went from 36 seconds to 9 seconds on Overo Signed-off-by: Steve Sakoman Tested-by: Steve Sakoman --- This is based on Alagu's original patch, but heavily modified to reflect recent changes in the driver and to remove the CONFIG option as requested in the earlier discussion of the patch: http://www.mail-archive.com/u-boot@lists.denx.de/msg32319.html It also incorporates feedback on my previously submitted RFC multi-block read patch. I am leaving authorship with Alagu since he did the original work, but will leave it up to him to add his "Signed-off-by" --- diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 00fe867..6805b33 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -154,110 +154,78 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) return blkcnt; } -int mmc_read_block(struct mmc *mmc, void *dst, uint blocknum) +int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt) { struct mmc_cmd cmd; struct mmc_data data; - cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; + if (blkcnt > 1) + cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; + else + cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; if (mmc->high_capacity) - cmd.cmdarg = blocknum; + cmd.cmdarg = start; else - cmd.cmdarg = blocknum * mmc->read_bl_len; + cmd.cmdarg = start * mmc->read_bl_len; cmd.resp_type = MMC_RSP_R1; cmd.flags = 0; data.dest = dst; - data.blocks = 1; + data.blocks = blkcnt; data.blocksize = mmc->read_bl_len; data.flags = MMC_DATA_READ; - return mmc_send_cmd(mmc, &cmd, &data); -} - -int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size) -{ - char *buffer; - int i; - int blklen = mmc->read_bl_len; - int startblock = lldiv(src, mmc->read_bl_len); - int endblock = lldiv(src + size - 1, mmc->read_bl_len); - int err = 0; - - /* Make a buffer big enough to hold all the blocks we might read */ - buffer = malloc(blklen); - - if (!buffer) { - printf("Could not allocate buffer for MMC read!\n"); - return -1; - } - - /* We always do full block reads from the card */ - err = mmc_set_blocklen(mmc, mmc->read_bl_len); - - if (err) - goto free_buffer; - - for (i = startblock; i <= endblock; i++) { - int segment_size; - int offset; - - err = mmc_read_block(mmc, buffer, i); - - if (err) - goto free_buffer; - - /* - * The first block may not be aligned, so we - * copy from the desired point in the block - */ - offset = (src & (blklen - 1)); - segment_size = MIN(blklen - offset, size); - - memcpy(dst, buffer + offset, segment_size); + if (mmc_send_cmd(mmc, &cmd, &data)) + return 0; - dst += segment_size; - src += segment_size; - size -= segment_size; + if (blkcnt > 1) { + cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_RSP_R1b; + cmd.flags = 0; + if (mmc_send_cmd(mmc, &cmd, NULL)) { + printf("mmc fail to send stop cmd\n"); + return 0; + } } -free_buffer: - free(buffer); - - return err; + return blkcnt; } static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) { - int err; - int i; - struct mmc *mmc = find_mmc_device(dev_num); + lbaint_t cur, blocks_todo = blkcnt; + + if (blkcnt == 0) + return 0; + struct mmc *mmc = find_mmc_device(dev_num); if (!mmc) return 0; if ((start + blkcnt) > mmc->block_dev.lba) { - printf("MMC: block number 0x%lx exceeds max(0x%lx)", + printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", start + blkcnt, mmc->block_dev.lba); return 0; } - /* We always do full block reads from the card */ - err = mmc_set_blocklen(mmc, mmc->read_bl_len); - if (err) { + if (mmc_set_blocklen(mmc, mmc->read_bl_len)) return 0; - } - for (i = start; i < start + blkcnt; i++, dst += mmc->read_bl_len) { - err = mmc_read_block(mmc, dst, i); - - if (err) { - printf("block read failed: %d\n", err); - return i - start; - } - } + do { + /* + * The 65535 constraint comes from some hardware has + * only 16 bit width block number counter + */ + cur = (blocks_todo > 65535) ? 65535 : blocks_todo; + if(mmc_read_blocks(mmc, dst, start, cur) != cur) + return 0; + blocks_todo -= cur; + start += cur; + dst += cur * mmc->read_bl_len; + } while (blocks_todo > 0); return blkcnt; }