From patchwork Fri Aug 30 15:14:05 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seungwon Jeon X-Patchwork-Id: 2852124 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 32C2A9F2F4 for ; Fri, 30 Aug 2013 15:14:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DE3C120182 for ; Fri, 30 Aug 2013 15:14:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 736F420488 for ; Fri, 30 Aug 2013 15:14:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756576Ab3H3POI (ORCPT ); Fri, 30 Aug 2013 11:14:08 -0400 Received: from mailout4.samsung.com ([203.254.224.34]:20297 "EHLO mailout4.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756321Ab3H3POH (ORCPT ); Fri, 30 Aug 2013 11:14:07 -0400 Received: from epcpsbgr3.samsung.com (u143.gpu120.samsung.co.kr [203.254.230.143]) by mailout4.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MSC00EXBNNI0GD0@mailout4.samsung.com> for linux-mmc@vger.kernel.org; Sat, 31 Aug 2013 00:14:06 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [203.254.230.47]) by epcpsbgr3.samsung.com (EPCPMTA) with SMTP id A3.17.22755.EB6B0225; Sat, 31 Aug 2013 00:14:06 +0900 (KST) X-AuditID: cbfee68f-b7f656d0000058e3-5b-5220b6bed408 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 7D.61.09055.EB6B0225; Sat, 31 Aug 2013 00:14:06 +0900 (KST) Received: from DOTGIHJUN01 ([12.23.118.161]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MSC00DRWNNIPC00@mmp2.samsung.com>; Sat, 31 Aug 2013 00:14:06 +0900 (KST) From: Seungwon Jeon To: linux-mmc@vger.kernel.org Cc: 'Chris Ball' , 'Jaehoon Chung' References: In-reply-to: Subject: [PATCH 18/22] mmc: dw_mmc: guarantee stop-abort cmd in data errors Date: Sat, 31 Aug 2013 00:14:05 +0900 Message-id: <001501cea593$917ce4e0$b476aea0$%jun@samsung.com> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-transfer-encoding: 7bit X-Mailer: Microsoft Office Outlook 12.0 Thread-index: Ac03z3aCvVFr8FaITt2vKVQKst76fw3OcIrwS9fJ1BAByUIdcA== Content-language: ko X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrIIsWRmVeSWpSXmKPExsVy+t8zfd192xSCDB5OFrLY/nojm8WNX22s Fkf+9zM6MHscurKW0aNvyypGj8+b5AKYo7hsUlJzMstSi/TtErgy3k36zVbwwrBiyoPzTA2M S9S7GDk5JARMJB7s+MwMYYtJXLi3nq2LkYtDSGAZo8Tv2RsZYYr6vl2DSkxnlDh/6B4rhPOH UeLdXogqNgEtib9v3oCNEhGQlfj55wIbiM0s4C3xav4aoBoOoAZuidXNQSBhTgEeiXV/OsHK hYFKmvaeAbNZBFQlnq7ezARi8wrYSvQ9vMMGYQtK/Jh8jwVkDLOAusSUKbkQ0+UlNq95ywwS lgAKP/qrC3GAk8TZpoOMECUiEvtevGMEuVhCYBe7xP3H65ggVglIfJt8iAWiV1Zi0wFoOEhK HFxxg2UCo8QsJItnISyehWTxLCQbFjCyrGIUTS1ILihOSi8y1itOzC0uzUvXS87P3cQIib7+ HYx3D1gfYkwG2j6RWUo0OR8YvXkl8YbGZkYWpiamxkbmlmakCSuJ86q1WAcKCaQnlqRmp6YW pBbFF5XmpBYfYmTi4JRqYNz1tE/yrjXPzScTA/Xuis+9ab7mcNxiP48JvUbL+LouS8T3ZBr7 s37bct729L51xttn/an+fCa2PG7LBO5cB83p3Gfbj86LtVmnkHZ6YU9E4Q8fvsZW/l/bpG6u eLLv/gXBsu1efmV9SpI85yIMN4TVhvh8mlJ1X/p3z8LJ4WfCT5mquvFmv1ZiKc5INNRiLipO BABHuyLe1AIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprHKsWRmVeSWpSXmKPExsVy+t9jQd192xSCDH6d4bXY/nojm8WNX22s Fkf+9zM6MHscurKW0aNvyypGj8+b5AKYoxoYbTJSE1NSixRS85LzUzLz0m2VvIPjneNNzQwM dQ0tLcyVFPISc1NtlVx8AnTdMnOANikplCXmlAKFAhKLi5X07TBNCA1x07WAaYzQ9Q0Jgusx MkADCesYM95N+s1W8MKwYsqD80wNjEvUuxg5OSQETCT6vl1jg7DFJC7cWw9kc3EICUxnlDh/ 6B4rhPOHUeLd3o2MIFVsAloSf9+8YQaxRQRkJX7+uQDWzSzgLfFq/hqgGg6gBm6J1c1BIGFO AR6JdX86wcqFgUqa9p4Bs1kEVCWert7MBGLzCthK9D28wwZhC0r8mHyPBWQMs4C6xJQpuRDT 5SU2r3nLDBKWAAo/+qsLcYCTxNmmg4wQJSIS+168Y5zAKDQLyaBZCINmIRk0C0nHAkaWVYyi qQXJBcVJ6bmGesWJucWleel6yfm5mxjBsf1MagfjygaLQ4wCHIxKPLwJSxWChFgTy4orcw8x SnAwK4nwflwMFOJNSaysSi3Kjy8qzUktPsSYDPTmRGYp0eR8YNrJK4k3NDYxM7I0MrMwMjE3 J01YSZz3QKt1oJBAemJJanZqakFqEcwWJg5OqQbG3e+2b5t5/seZ2g96b3dd2PzjXOySf0ny xUt15m0+7TJNyvAJc8Zx6cvxjFn7ZlxYXjP3w2TTTAO7cnXHOwvmCbs63fztvfrkgzc3L3jF HlUscD7SzpT02uxCj3GIVSnXpc0Ca5bVHBFg/rpC3DZgqt/jKVwL1p6s666fI7OhvndpW3nj VFmzUCWW4oxEQy3mouJEAPMHN0MxAwAA DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Spam-Status: No, score=-9.0 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 In error cases, DTO interrupt may or may not be generated depending on remained data. Stop/Abort command ensures DTO generation for that situation. Currently if 'stop' field of data is empty, there is no stop/abort command. So, it could hang waiting DTO. This change rein- forces these cases. Signed-off-by: Seungwon Jeon Tested-by: Alim Akhtar --- drivers/mmc/host/dw_mmc.c | 84 +++++++++++++++++++++++++++++++++---------- include/linux/mmc/dw_mmc.h | 2 + 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index abe4d21..b724827 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -246,10 +247,15 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) cmdr = cmd->opcode; - if (cmdr == MMC_STOP_TRANSMISSION) + if (cmd->opcode == MMC_STOP_TRANSMISSION || + cmd->opcode == MMC_GO_IDLE_STATE || + cmd->opcode == MMC_GO_INACTIVE_STATE || + (cmd->opcode == SD_IO_RW_DIRECT && + ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) cmdr |= SDMMC_CMD_STOP; else - cmdr |= SDMMC_CMD_PRV_DAT_WAIT; + if (cmd->opcode != MMC_SEND_STATUS && cmd->data) + cmdr |= SDMMC_CMD_PRV_DAT_WAIT; if (cmd->flags & MMC_RSP_PRESENT) { /* We expect a response, so set this bit */ @@ -276,6 +282,40 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) return cmdr; } +static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd) +{ + struct mmc_command *stop; + u32 cmdr; + + if (!cmd->data) + return 0; + + stop = &host->stop_abort; + cmdr = cmd->opcode; + memset(stop, 0, sizeof(struct mmc_command)); + + if (cmdr == MMC_READ_SINGLE_BLOCK || + cmdr == MMC_READ_MULTIPLE_BLOCK || + cmdr == MMC_WRITE_BLOCK || + cmdr == MMC_WRITE_MULTIPLE_BLOCK) { + stop->opcode = MMC_STOP_TRANSMISSION; + stop->arg = 0; + stop->flags = MMC_RSP_R1B | MMC_CMD_AC; + } else if (cmdr == SD_IO_RW_EXTENDED) { + stop->opcode = SD_IO_RW_DIRECT; + stop->arg |= (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) | + ((cmd->arg >> 28) & 0x7); + stop->flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; + } else { + return 0; + } + + cmdr = stop->opcode | SDMMC_CMD_STOP | + SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP; + + return cmdr; +} + static void dw_mci_start_command(struct dw_mci *host, struct mmc_command *cmd, u32 cmd_flags) { @@ -290,9 +330,10 @@ static void dw_mci_start_command(struct dw_mci *host, mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START); } -static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) +static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data) { - dw_mci_start_command(host, data->stop, host->stop_cmdr); + struct mmc_command *stop = data->stop ? data->stop : &host->stop_abort; + dw_mci_start_command(host, stop, host->stop_cmdr); } /* DMA interface functions */ @@ -828,6 +869,8 @@ static void __dw_mci_start_request(struct dw_mci *host, if (mrq->stop) host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); + else + host->stop_cmdr = dw_mci_prep_stop_abort(host, cmd); } static void dw_mci_start_request(struct dw_mci *host, @@ -1190,13 +1233,9 @@ static void dw_mci_tasklet_func(unsigned long priv) if (cmd->data && cmd->error) { dw_mci_stop_dma(host); - if (data->stop) { - send_stop_cmd(host, data); - state = STATE_SENDING_STOP; - break; - } else { - host->data = NULL; - } + send_stop_abort(host, data); + state = STATE_SENDING_STOP; + break; } if (!host->mrq->data || cmd->error) { @@ -1211,8 +1250,7 @@ static void dw_mci_tasklet_func(unsigned long priv) if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { dw_mci_stop_dma(host); - if (data->stop) - send_stop_cmd(host, data); + send_stop_abort(host, data); state = STATE_DATA_ERROR; break; } @@ -1272,7 +1310,7 @@ static void dw_mci_tasklet_func(unsigned long priv) data->error = 0; } - if (!data->stop) { + if (!data->stop && !data->error) { dw_mci_request_end(host, host->mrq); goto unlock; } @@ -1284,8 +1322,10 @@ static void dw_mci_tasklet_func(unsigned long priv) } prev_state = state = STATE_SENDING_STOP; - if (!data->error) - send_stop_cmd(host, data); + if (data->stop && !data->error) { + /* stop command for open-ended transfer*/ + send_stop_abort(host, data); + } /* fall through */ case STATE_SENDING_STOP: @@ -1304,7 +1344,12 @@ static void dw_mci_tasklet_func(unsigned long priv) host->cmd = NULL; host->data = NULL; - dw_mci_command_complete(host, host->mrq->stop); + + if (host->mrq->stop) + dw_mci_command_complete(host, host->mrq->stop); + else + host->cmd_status = 0; + dw_mci_request_end(host, host->mrq); goto unlock; @@ -1888,11 +1933,10 @@ static void dw_mci_work_routine_card(struct work_struct *work) case STATE_DATA_ERROR: if (mrq->data->error == -EINPROGRESS) mrq->data->error = -ENOMEDIUM; - if (!mrq->stop) - break; /* fall through */ case STATE_SENDING_STOP: - mrq->stop->error = -ENOMEDIUM; + if (mrq->stop) + mrq->stop->error = -ENOMEDIUM; break; } diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index a829f7e..6ce7d2c 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -15,6 +15,7 @@ #define LINUX_MMC_DW_MMC_H #include +#include #define MAX_MCI_SLOTS 2 @@ -129,6 +130,7 @@ struct dw_mci { struct mmc_request *mrq; struct mmc_command *cmd; struct mmc_data *data; + struct mmc_command stop_abort; unsigned int prev_blksz; unsigned char timing; struct workqueue_struct *card_workqueue;