From patchwork Mon Jun 6 11:53:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amitkumar Karwar X-Patchwork-Id: 9157951 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B832860572 for ; Mon, 6 Jun 2016 11:53:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A93C6281AA for ; Mon, 6 Jun 2016 11:53:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9CD43281BE; Mon, 6 Jun 2016 11:53:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF56B27D45 for ; Mon, 6 Jun 2016 11:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751291AbcFFLxy (ORCPT ); Mon, 6 Jun 2016 07:53:54 -0400 Received: from mx0b-0016f401.pphosted.com ([67.231.156.173]:50012 "EHLO mx0b-0016f401.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751228AbcFFLxw (ORCPT ); Mon, 6 Jun 2016 07:53:52 -0400 Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.17/8.16.0.17) with SMTP id u56Bq8Bg005068; Mon, 6 Jun 2016 04:53:50 -0700 Received: from sc-exch03.marvell.com ([199.233.58.183]) by mx0b-0016f401.pphosted.com with ESMTP id 23bxgfxef2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Mon, 06 Jun 2016 04:53:50 -0700 Received: from SC-EXCH01.marvell.com (10.93.176.81) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server (TLS) id 15.0.1104.5; Mon, 6 Jun 2016 04:53:48 -0700 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH01.marvell.com (10.93.176.81) with Microsoft SMTP Server id 15.0.1104.5 via Frontend Transport; Mon, 6 Jun 2016 04:53:48 -0700 Received: from pe-lt101 (unknown [10.31.130.199]) by maili.marvell.com (Postfix) with ESMTP id 89DFE3F703F; Mon, 6 Jun 2016 04:53:48 -0700 (PDT) Received: from pe-lt101 (pe-lt077 [127.0.0.1]) by pe-lt101 (8.14.4/8.14.4) with ESMTP id u56BrN12032252; Mon, 6 Jun 2016 04:53:24 -0700 Received: (from root@localhost) by pe-lt101 (8.14.4/8.14.4/Submit) id u56BrNwf032251; Mon, 6 Jun 2016 04:53:23 -0700 From: Amitkumar Karwar To: CC: Nishant Sarmukadam , Wei-Ning Huang , , Cathy Luo , Xinming Hu , Amitkumar Karwar Subject: [PATCH v3 2/2] mmc: sdio support external scatter gather list Date: Mon, 6 Jun 2016 04:53:09 -0700 Message-ID: <1465213989-32218-2-git-send-email-akarwar@marvell.com> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1465213989-32218-1-git-send-email-akarwar@marvell.com> References: <1465213989-32218-1-git-send-email-akarwar@marvell.com> MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-06-06_05:, , signatures=0 X-Proofpoint-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=4 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1606060142 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Xinming Hu Currently sdio device drivers need to prepare a big continuous physical memory for large data transfer. mmc stack will construct scatter/gather buffer list to make use of ADMA2. According to the sdio host controller specification version 4.00 chapter 1.13.2, sdio device drivers have the ability to construct scatter/gather DMA buffer list. In this way, they do not need to allocate big memory. This patch refactors current sdio command 53 wrapper mmc_io_rw_extended, so that it can accept external scatter/gather buffer list from its caller, such as the sdio device driver. This patch is very useful on some embedded systems where large memory allocation fails sometimes. It gives 10 to 15% better throughput performance compared to a case in which small single data transfers are done. Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar --- drivers/mmc/core/sdio_io.c | 22 ++++++++++++++++-- drivers/mmc/core/sdio_ops.c | 53 +++++++++++++++++++++++++++++++++++++++---- drivers/mmc/core/sdio_ops.h | 3 ++- include/linux/mmc/sdio_func.h | 6 +++++ 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index a546c89..8505c4d 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -322,7 +322,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, size = blocks * func->cur_blksize; ret = mmc_io_rw_extended(func->card, write, - func->num, addr, incr_addr, buf, + func->num, addr, incr_addr, false, buf, blocks, func->cur_blksize); if (ret) return ret; @@ -340,7 +340,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, /* Indicate byte mode by setting "blocks" = 0 */ ret = mmc_io_rw_extended(func->card, write, func->num, addr, - incr_addr, buf, 0, size); + incr_addr, false, buf, 0, size); if (ret) return ret; @@ -504,6 +504,24 @@ int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, } EXPORT_SYMBOL_GPL(sdio_writesb); +int sdio_readsb_sg_enh(struct sdio_func *func, unsigned int addr, + struct sg_table *dst) +{ + return mmc_io_rw_extended(func->card, 0, func->num, + addr, 0, true, + dst, 0, func->cur_blksize); +} +EXPORT_SYMBOL_GPL(sdio_readsb_sg_enh); + +int sdio_writesb_sg_enh(struct sdio_func *func, unsigned int addr, + struct sg_table *src) +{ + return mmc_io_rw_extended(func->card, 1, func->num, + addr, 0, true, + src, 0, func->cur_blksize); +} +EXPORT_SYMBOL_GPL(sdio_writesb_sg_enh); + /** * sdio_readw - read a 16 bit integer from a SDIO function * @func: SDIO function to access diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 34f6e80..c44f65e 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -118,16 +118,39 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); } +/** + * mmc_io_rw_extended - wrapper for sdio command 53 read/write operation + * @card: destination device for read/write + * @write: zero indcate read, non-zero indicate write. + * @fn: SDIO function to access + * @addr: address of (single byte) FIFO + * @incr_addr: set to 1 indicate read or write multiple bytes + of data to/from an IO register address that + increment by 1 after each operation. + * @sg_enhance: if set true, the caller of this function will + prepare scatter gather dma buffer list. + * @buf: buffer that contains the data to write. if sg_enhance + is set, it point to SG dma buffer list. + * @blocks: number of blocks of data transfer. + if set zero, indicate byte mode + if set non-zero, indicate block mode + if sg_enhance is set, this parameter will not be used. + * @blksz: block size for block mode data transfer. + * + */ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) + unsigned int addr, int incr_addr, bool sg_enhance, + void *buf, unsigned int blocks, unsigned int blksz) { struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; struct scatterlist sg, *sg_ptr; struct sg_table sgtable; + struct sg_table *sgtable_external; unsigned int nents, left_size, i; unsigned int seg_size = card->host->max_seg_size; + unsigned int sg_blocks = 0; BUG_ON(!card); BUG_ON(fn > 7); @@ -145,16 +168,35 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= fn << 28; cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + data.blksz = blksz; + + if (sg_enhance) { + sgtable_external = buf; + + for_each_sg(sgtable_external->sgl, sg_ptr, + sgtable_external->nents, i) { + if (sg_ptr->length > card->host->max_seg_size) + return -EINVAL; + sg_blocks += DIV_ROUND_UP(sg_ptr->length, blksz); + } + + cmd.arg |= 0x08000000 | sg_blocks; + data.blocks = sg_blocks; + data.sg = sgtable_external->sgl; + data.sg_len = sgtable_external->nents; + goto mmc_data_req; + } + if (blocks == 0) cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ - cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; - data.blksz = blksz; /* Code in host drivers/fwk assumes that "blocks" always is >=1 */ data.blocks = blocks ? blocks : 1; - data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; left_size = data.blksz * data.blocks; nents = (left_size - 1) / seg_size + 1; @@ -178,11 +220,12 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, sg_init_one(&sg, buf, left_size); } +mmc_data_req: mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); - if (nents > 1) + if (!sg_enhance && nents > 1) sg_free_table(&sgtable); if (cmd.error) diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index 5660c7f..a8b8e0c 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -18,7 +18,8 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, - unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); + unsigned int addr, int incr_addr, bool sg_enhance, + void *buf, unsigned int blocks, unsigned int blksz); int sdio_reset(struct mmc_host *host); static inline bool mmc_is_io_op(u32 opcode) diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index b2b91df..ba8f392 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -14,6 +14,7 @@ #include #include +#include #include @@ -136,6 +137,11 @@ extern int sdio_memcpy_fromio(struct sdio_func *func, void *dst, extern int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count); +int sdio_readsb_sg_enh(struct sdio_func *func, unsigned int addr, + struct sg_table *dst); +int sdio_writesb_sg_enh(struct sdio_func *func, unsigned int addr, + struct sg_table *src); + extern void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret); extern void sdio_writew(struct sdio_func *func, u16 b,