From patchwork Wed Aug 21 13:51:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Seungwon Jeon X-Patchwork-Id: 2847752 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 DEC159F271 for ; Wed, 21 Aug 2013 13:51:13 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 88FAA204F4 for ; Wed, 21 Aug 2013 13:51:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 09DEE204CD for ; Wed, 21 Aug 2013 13:51:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751608Ab3HUNvH (ORCPT ); Wed, 21 Aug 2013 09:51:07 -0400 Received: from mailout2.samsung.com ([203.254.224.25]:54871 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751628Ab3HUNvF (ORCPT ); Wed, 21 Aug 2013 09:51:05 -0400 Received: from epcpsbgr3.samsung.com (u143.gpu120.samsung.co.kr [203.254.230.143]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MRV00FYHVT078H0@mailout2.samsung.com> for linux-mmc@vger.kernel.org; Wed, 21 Aug 2013 22:51:04 +0900 (KST) Received: from epcpsbgm2.samsung.com ( [203.254.230.50]) by epcpsbgr3.samsung.com (EPCPMTA) with SMTP id EE.DD.03969.7C5C4125; Wed, 21 Aug 2013 22:51:03 +0900 (KST) X-AuditID: cbfee68f-b7f436d000000f81-e2-5214c5c74657 Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id EB.C1.31505.7C5C4125; Wed, 21 Aug 2013 22:51:03 +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 <0MRV000ZWVT3Y940@mmp2.samsung.com>; Wed, 21 Aug 2013 22:51:03 +0900 (KST) From: Seungwon Jeon To: linux-mmc@vger.kernel.org Cc: 'Chris Ball' , 'Jaehoon Chung' , 'Alim Akhtar' References: In-reply-to: Subject: [PATCH 10/14] mmc: dw_mmc: guarantee stop-abort cmd in data errors Date: Wed, 21 Aug 2013 22:51:03 +0900 Message-id: <002f01ce9e75$7a1ac4e0$6e504ea0$%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: Ac03z3aCvVFr8FaITt2vKVQKst76fw3OcIrwS9fJ1BA= Content-language: ko X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrCIsWRmVeSWpSXmKPExsVy+t8zI93jR0WCDLZ/sLB4MG8bm8X21xvZ LG78amO1OPK/n9GBxePQlbWMHn1bVjF6fN4kF8AcxWWTkpqTWZZapG+XwJWx7e9O9oJthhUL zzWxNTB+V+ti5OSQEDCR+HRkKiuELSZx4d56ti5GLg4hgWWMEh//bWHuYuQAK/r9AqxGSGA6 o8S6F9YQNX8YJT5v3MkEkmAT0JL4++YNM4gtIiAr8fPPBTYQm1mgTOLtnftgc4QEuCVWNweB hDkFeCTW/ekEKxcW8Ja4OX0j2BgWAVWJF//fsIPYvAK2Es/7D0DZghI/Jt9jARnDLKAuMWVK LsR0eYnNa95CXaku8eivLsQBVhKHlx9hhSgRkdj34h0jyMUSAsfYJdb9OM8CsUpA4tvkQywQ vbISmw4wQ0JBUuLgihssExglZiFZPAth8Swki2ch2bCAkWUVo2hqQXJBcVJ6kbFecWJucWle ul5yfu4mRkgM9u9gvHvA+hBjMtD2icxSosn5wBjOK4k3NDYzsjA1MTU2Mrc0I01YSZxXrcU6 UEggPbEkNTs1tSC1KL6oNCe1+BAjEwenVANjhZPUVEvuhJ1bd7+5kb/9ku1uA6b4ki67J5KL 71efr591Tddsx4+fLzyWOScl3Ntb+9/8warMi39ORoSHfn58V/208vo7t/vXB4QsnZl2PIdz qVf8xy1cXev/rn1fohjVb/kts+ji7L930+bG6thdCOvY/lVa7/tJy76bbJGK0/u7Lm+qvNFs qMRSnJFoqMVcVJwIAKnk6KLXAgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrIKsWRmVeSWpSXmKPExsVy+t9jQd3jR0WCDO7eM7R4MG8bm8X21xvZ LG78amO1OPK/n9GBxePQlbWMHn1bVjF6fN4kF8Ac1cBok5GamJJapJCal5yfkpmXbqvkHRzv HG9qZmCoa2hpYa6kkJeYm2qr5OIToOuWmQO0TkmhLDGnFCgUkFhcrKRvh2lCaIibrgVMY4Su b0gQXI+RARpIWMeYse3vTvaCbYYVC881sTUwflfrYuTgkBAwkfj9grWLkRPIFJO4cG89G4gt JDCdUWLdC+suRi4g+w+jxOeNO5lAEmwCWhJ/37xhBrFFBGQlfv65ANbALFAm8fbOfWaQmUIC 3BKrm4NAwpwCPBLr/nSClQsLeEvcnL4RbAyLgKrEi/9v2EFsXgFbief9B6BsQYkfk++xgIxh FlCXmDIlF2K6vMTmNW+ZIS5Wl3j0VxfiACuJw8uPsEKUiEjse/GOcQKj0Cwkg2YhDJqFZNAs JB0LGFlWMYqmFiQXFCel5xrpFSfmFpfmpesl5+duYgRH+DPpHYyrGiwOMQpwMCrx8F7YKRIk xJpYVlyZe4hRgoNZSYT3836gEG9KYmVValF+fFFpTmrxIcZkoDcnMkuJJucDk09eSbyhsYmZ kaWRmYWRibk5acJK4rwHW60DhQTSE0tSs1NTC1KLYLYwcXBKNTBueDAh9WPBF/vj257NNFs/ lTN3p+DJAlGess7Nv2+zzFPhEGBLTZX4vjIs6ZeP1dy1LhPyX/1btTA4+5r1Mo0O4Tvbl11W mTRJ9vBXhfXuPYFF0nNa5+zYMDNO7i1nVpxzy+2eK5cfiXsVO27WWlZu4nO2lqV8xkHxVYYP zi/X5g5YyqsbIzRPiaU4I9FQi7moOBEArLWroTQDAAA= 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.7 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 --- 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 9c3205e..88d5f51 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 */ @@ -818,6 +859,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, @@ -1182,13 +1225,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) { @@ -1203,8 +1242,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; } @@ -1264,7 +1302,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; } @@ -1276,8 +1314,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: @@ -1296,7 +1336,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; @@ -1881,11 +1926,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;