From patchwork Thu Jun 13 08:03:39 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 2714421 Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 76C32C1459 for ; Thu, 13 Jun 2013 08:03:51 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 71E592019D for ; Thu, 13 Jun 2013 08:03:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C878520197 for ; Thu, 13 Jun 2013 08:03:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755531Ab3FMIDn (ORCPT ); Thu, 13 Jun 2013 04:03:43 -0400 Received: from relmlor2.renesas.com ([210.160.252.172]:46019 "EHLO relmlor2.renesas.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755530Ab3FMIDl (ORCPT ); Thu, 13 Jun 2013 04:03:41 -0400 Received: from relmlir3.idc.renesas.com ([10.200.68.153]) by relmlor2.idc.renesas.com ( SJSMS) with ESMTP id <0MOB00C2DNQ4F1D0@relmlor2.idc.renesas.com>; Thu, 13 Jun 2013 17:03:40 +0900 (JST) Received: from relmlac3.idc.renesas.com ([10.200.69.23]) by relmlir3.idc.renesas.com ( SJSMS) with ESMTP id <0MOB0012DNQ3A890@relmlir3.idc.renesas.com>; Thu, 13 Jun 2013 17:03:39 +0900 (JST) Received: by relmlac3.idc.renesas.com (Postfix, from userid 0) id E6972180A0; Thu, 13 Jun 2013 17:03:39 +0900 (JST) Received: from relmlac3.idc.renesas.com (localhost [127.0.0.1]) by relmlac3.idc.renesas.com (Postfix) with ESMTP id DF43F1809C; Thu, 13 Jun 2013 17:03:39 +0900 (JST) Received: from relmlii2.idc.renesas.com [10.200.68.66] by relmlac3.idc.renesas.com with ESMTP id TAS29932; Thu, 13 Jun 2013 17:03:39 +0900 X-IronPort-AV: E=Sophos; i="4.87,857,1363100400"; d="scan'208"; a="130610458" Received: from unknown (HELO [10.161.41.141]) ([10.161.41.141]) by relmlii2.idc.renesas.com with ESMTP; Thu, 13 Jun 2013 17:03:39 +0900 Message-id: <51B97CDB.7010207@renesas.com> Date: Thu, 13 Jun 2013 17:03:39 +0900 From: "Shimoda, Yoshihiro" User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20130509 Thunderbird/17.0.6 MIME-version: 1.0 To: cjb@laptop.org Cc: linux-mmc@vger.kernel.org, SH-Linux , Guennadi Liakhovetski Subject: [PATCH] mmc: sh_mmcif: add SET_BLOCK_COUNT support Content-type: text/plain; charset=ISO-8859-1 Content-transfer-encoding: 7bit Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds SET_BLOCK_COUNT(CMD23) support to sh_mmcif driver. If we add MMC_CAP_CMD23 to ".caps" of sh_mmcif_plat_data, the mmc core driver will use CMD23. Then, the sh_mmcif driver can use Reliable Write feature. Signed-off-by: Yoshihiro Shimoda --- This patch is based on the latest mmc-next branch of mmc.git. drivers/mmc/host/sh_mmcif.c | 83 +++++++++++++++++++++++++++++++++++++++++- 1 files changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 8ef5efa..14d4c81 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -244,6 +244,7 @@ struct sh_mmcif_host { bool power; bool card_present; struct mutex thread_lock; + struct completion sbc_complete; /* DMA support */ struct dma_chan *chan_rx; @@ -802,7 +803,11 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, tmp |= CMD_SET_DWEN; /* CMLTE/CMD12EN */ if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { - tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; + /* If SBC, we don't use CMD12(STOP) */ + if (mrq->sbc) + tmp |= CMD_SET_CMLTE; + else + tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, data->blocks << 16); } @@ -903,6 +908,43 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, host->wait_for = MMCIF_WAIT_FOR_STOP; } +static bool sh_mmcif_send_sbc(struct sh_mmcif_host *host, + struct mmc_request *mrq) +{ + struct mmc_request req_orig = *mrq; + long time; + + /* Switch the commands around */ + mrq->cmd = mrq->sbc; + mrq->sbc = NULL; + mrq->data = NULL; + mrq->stop = NULL; + + /* Send SBC Cmd */ + sh_mmcif_start_cmd(host, mrq); + + /* Normal completion time is less than 1us */ + time = wait_for_completion_interruptible_timeout(&host->sbc_complete, + host->timeout); + + /* Restore */ + mrq->cmd = req_orig.cmd; + mrq->sbc = req_orig.sbc; + mrq->data = req_orig.data; + mrq->stop = req_orig.stop; + + if (mrq->sbc->error || host->sd_error || time <= 0) { + dev_dbg(&host->pd->dev, "%s(): failed!\n", __func__); + host->state = STATE_IDLE; + if (!time) + mrq->sbc->error = -ETIMEDOUT; + mmc_request_done(host->mmc, mrq); + return true; + } + + return false; +} + static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct sh_mmcif_host *host = mmc_priv(mmc); @@ -938,6 +980,11 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; + if (mrq->sbc) { + if (sh_mmcif_send_sbc(host, mrq)) + return; + } + sh_mmcif_start_cmd(host, mrq); } @@ -1074,6 +1121,9 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) sh_mmcif_get_response(host, cmd); + if (cmd->opcode == MMC_SET_BLOCK_COUNT) + complete(&host->sbc_complete); + if (!data) return false; @@ -1212,13 +1262,35 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) return IRQ_HANDLED; } + if (mrq->sbc && (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) && + (host->wait_for != MMCIF_WAIT_FOR_WRITE_END)) { + /* Wait for end of data phase */ + host->wait_for = MMCIF_WAIT_FOR_WRITE_END; + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); + schedule_delayed_work(&host->timeout_work, host->timeout); + mutex_unlock(&host->thread_lock); + return IRQ_HANDLED; + } + + if (mrq->sbc && (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) && + (host->wait_for != MMCIF_WAIT_FOR_READ_END)) { + /* Wait for end of data phase */ + host->wait_for = MMCIF_WAIT_FOR_READ_END; + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); + schedule_delayed_work(&host->timeout_work, host->timeout); + mutex_unlock(&host->thread_lock); + return IRQ_HANDLED; + } + if (host->wait_for != MMCIF_WAIT_FOR_STOP) { struct mmc_data *data = mrq->data; if (!mrq->cmd->error && data && !data->error) data->bytes_xfered = data->blocks * data->blksz; - if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { + /* If SBC, we don't use CMD12(STOP) */ + if (mrq->stop && !mrq->cmd->error && (!data || !data->error) && + !mrq->sbc) { sh_mmcif_stop_cmd(host, mrq); if (!mrq->stop->error) { schedule_delayed_work(&host->timeout_work, host->timeout); @@ -1228,6 +1300,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) } } + if ((mrq->cmd->opcode == MMC_SET_BLOCK_COUNT) && !mrq->cmd->error) { + schedule_delayed_work(&host->timeout_work, host->timeout); + mutex_unlock(&host->thread_lock); + return IRQ_HANDLED; + } + host->wait_for = MMCIF_WAIT_FOR_REQUEST; host->state = STATE_IDLE; host->mrq = NULL; @@ -1379,6 +1457,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->pd = pdev; spin_lock_init(&host->lock); + init_completion(&host->sbc_complete); mmc->ops = &sh_mmcif_ops; sh_mmcif_init_ocr(host);