From patchwork Mon Jun 11 10:46:02 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Saugata Das X-Patchwork-Id: 9187 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id B579623E4F for ; Mon, 11 Jun 2012 10:46:39 +0000 (UTC) Received: from mail-gg0-f180.google.com (mail-gg0-f180.google.com [209.85.161.180]) by fiordland.canonical.com (Postfix) with ESMTP id 6CBB0A1817F for ; Mon, 11 Jun 2012 10:46:39 +0000 (UTC) Received: by ggnf1 with SMTP id f1so2566366ggn.11 for ; Mon, 11 Jun 2012 03:46:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:x-gm-message-state; bh=4b8Y2eh7W9PcoFpN31B6aN8jOt/xFJpDRgxflfKOLUQ=; b=g2c1f/LtbluaAdvrl3jy220NYdoUiJNE8OhiK7B1Jh3xXvBzQbRLHFrwKV5+6Tr7lK DCLOPQ+Jcm/5Q30ipt59NtNm+9jwBVbILNBdRcoG51P8parDdyc4n8jaWpCW7YUwrXT0 xM/tW9nvvR8oo2ky6Ua6pUL+2HV8MtVKC4c80LzRBNaOF6i5mnT76Xqk+TEHWoXaaY7s b4rYoE9MdbpmAYh49OecoxQTSNdVjPM+wuvzrvyJFSp74uCXlMtIzwj4jIOACK8n6L8U 5Sfa5Sxx21MQoibO9Qlksxj2FUmGF1bbmRagNeUDSMlWJqjkBcC5vxNIDm8FIxKMbzo+ PVUg== Received: by 10.50.203.39 with SMTP id kn7mr5853628igc.53.1339411598729; Mon, 11 Jun 2012 03:46:38 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp100705ibb; Mon, 11 Jun 2012 03:46:37 -0700 (PDT) Received: by 10.14.97.134 with SMTP id t6mr5750738eef.121.1339411597488; Mon, 11 Jun 2012 03:46:37 -0700 (PDT) Received: from eu1sys200aog120.obsmtp.com (eu1sys200aog120.obsmtp.com. [207.126.144.149]) by mx.google.com with SMTP id v42si7335736eef.8.2012.06.11.03.46.35 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 11 Jun 2012 03:46:37 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.149 is neither permitted nor denied by best guess record for domain of saugata.das@stericsson.com) client-ip=207.126.144.149; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.149 is neither permitted nor denied by best guess record for domain of saugata.das@stericsson.com) smtp.mail=saugata.das@stericsson.com Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob120.postini.com ([207.126.147.11]) with SMTP ID DSNKT9XMiqx0kTHw0JmAbUSHicQ2xZzCOagL@postini.com; Mon, 11 Jun 2012 10:46:37 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id EF315101; Mon, 11 Jun 2012 10:46:33 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A49EC2802; Mon, 11 Jun 2012 10:46:33 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id 41E6624C07D; Mon, 11 Jun 2012 12:46:27 +0200 (CEST) Received: from localhost (10.201.54.119) by exdcvycastm022.EQ1STM.local (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Mon, 11 Jun 2012 12:46:32 +0200 From: Saugata Das To: , , Cc: , , Saugata Das Subject: [PATCH 3/3] mmc: Context support Date: Mon, 11 Jun 2012 16:16:02 +0530 Message-ID: <1339411562-17100-3-git-send-email-saugata.das@stericsson.com> X-Mailer: git-send-email 1.7.4.3 In-Reply-To: <1339411562-17100-1-git-send-email-saugata.das@stericsson.com> References: <1339411562-17100-1-git-send-email-saugata.das@stericsson.com> MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmyN/sB21zU4j/4WNTw4kjDXj5SDq1hfNrU/WZjes0gXta5JIrToEFHxUCUJdUQsoBrQs07 From: Saugata Das This patch implements the context ID support at MMC layer. From file system (ext4), the context is passed in the request structure. At MMC layer the context is retrieved from the request structure and then used in the CMD23 argument. Since number of MMC contexts is limited, multiple file system contexts are mapped to single MMC contexts. When the REQ_SYNC or REQ_FLUSH flag is set, the context is flushed or sync'ed, in which the context is closed so that the data blocks are safely written out to non-volatile memory and then the context is opened again. Signed-off-by: Saugata Das --- drivers/mmc/card/block.c | 37 ++++++++++++++++++++++++++- drivers/mmc/core/core.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/mmc.c | 25 +++++++++++++++++++ include/linux/mmc/card.h | 6 ++++ include/linux/mmc/core.h | 4 +++ include/linux/mmc/host.h | 1 + include/linux/mmc/mmc.h | 2 + 7 files changed, 134 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dabec55..4760d5a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -958,6 +958,15 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) struct mmc_card *card = md->queue.card; int ret = 0; + /* + * The flush command is a synchronization point from file system. + * The contexts are flushed here to ensure that the data written + * in the open contexts are saved reliably in non-volatile media + */ + ret = mmc_flush_contexts(card); + if (ret) + ret = -EIO; + ret = mmc_flush_cache(card); if (ret) ret = -EIO; @@ -1207,11 +1216,16 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, */ if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) && (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) || - do_data_tag)) { + do_data_tag || (card->ext_csd.max_context_id > 0))) { + int context_id = (req->context && + card->ext_csd.max_context_id) ? + (req->context % card->ext_csd.max_context_id + 1) : + 0; brq->sbc.opcode = MMC_SET_BLOCK_COUNT; brq->sbc.arg = brq->data.blocks | (do_rel_wr ? (1 << 31) : 0) | - (do_data_tag ? (1 << 29) : 0); + (do_data_tag ? (1 << 29) : 0) | + (!do_data_tag ? (context_id << 25) : 0); brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; brq->mrq.sbc = &brq->sbc; } @@ -1440,6 +1454,25 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) mmc_blk_issue_rw_rq(mq, NULL); ret = mmc_blk_issue_flush(mq, req); } else { + if (req && (req->cmd_flags & REQ_SYNC) && + req->context && card->ext_csd.max_context_id) { + int context_cfg_id = + req->context % card->ext_csd.max_context_id; + /* + * The SYNC command is a synchronization point from + * file system. The relevent context is sync'ed here + * to ensure that the data written in the open context + * are saved reliably in non-volatile media + */ + if (card->host->areq) + mmc_blk_issue_rw_rq(mq, NULL); + mmc_sync_context(card, context_cfg_id); + /* + * This write will go without context to ensure + * that it is reliably written + */ + req->context = 0; + } ret = mmc_blk_issue_rw_rq(mq, req); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ba821fe..54857f9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2262,6 +2262,67 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable) } EXPORT_SYMBOL(mmc_cache_ctrl); +static inline int mmc_set_context_conf(struct mmc_card *card, + int context_cfg_id, int context_act_dir) +{ + return mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_CONTEXT_CONF + context_cfg_id, + context_act_dir, card->ext_csd.generic_cmd6_time); +} + +/* + * Synchronize a context by first closing the context and then + * opening it + */ +int mmc_sync_context(struct mmc_card *card, int context_cfg_id) +{ + int err = 0; + + err = mmc_set_context_conf(card, context_cfg_id, MMC_CONTEXT_CLOSE); + if (err) + return err; + + err = mmc_set_context_conf(card, context_cfg_id, MMC_CONTEXT_ACT_RW); + return err; +} +EXPORT_SYMBOL(mmc_sync_context); + +int mmc_flush_contexts(struct mmc_card *card) +{ + int i, err = 0; + + for (i = 0; i < card->ext_csd.max_context_id; i++) { + int err1 = mmc_sync_context(card, i); + err = (err1 && !err) ? err1 : err; + } + return err; +} +EXPORT_SYMBOL(mmc_flush_contexts); + +/* + * Initialize all the MMC contexts in read-write and non-LU mode + */ +int mmc_init_context(struct mmc_card *card) +{ + int i, err = 0; + + for (i = 0; i < card->ext_csd.max_context_id; i++) { + err = mmc_set_context_conf(card, i, MMC_CONTEXT_ACT_RW); + if (err) { + pr_warning("%s: Activating of context %d failed [%x]\n", + mmc_hostname(card->host), i, err); + break; + } + } + + if (!err) + return 0; + + card->ext_csd.max_context_id = i; + return err; +} +EXPORT_SYMBOL(mmc_init_context); + #ifdef CONFIG_PM /** diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 54df5ad..77476a3 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -533,6 +533,16 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } else { card->ext_csd.data_tag_unit_size = 0; } + + card->ext_csd.max_context_id = + ext_csd[EXT_CSD_CONTEXT_CAPABILITIES] & 0x0f; + + if (card->ext_csd.max_context_id < VALID_MAX_MMC_CONTEXT_ID) { + pr_warning("%s: card has invalid number of contexts [%d]\n", + mmc_hostname(card->host), + card->ext_csd.max_context_id); + card->ext_csd.max_context_id = 0; + } } out: @@ -1267,6 +1277,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } } + if (host->caps2 & MMC_CAP2_CONTEXT) { + if (card->ext_csd.max_context_id > 0) { + err = mmc_init_context(card); + if (err && err != -EBADMSG) + goto free_card; + if (err) { + pr_warning("%s: failed to activate context (%x)\n", + mmc_hostname(card->host), err); + card->ext_csd.max_context_id = 0; + err = 0; + } + } + } else + card->ext_csd.max_context_id = 0; + if (!oldcard) host->card = card; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 629b823..3d60849 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -74,6 +74,7 @@ struct mmc_ext_csd { unsigned int hpi_cmd; /* cmd used as HPI */ unsigned int data_sector_size; /* 512 bytes or 4KB */ unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ + unsigned int max_context_id; unsigned int boot_ro_lock; /* ro lock support */ bool boot_ro_lockable; u8 raw_partition_support; /* 160 */ @@ -184,6 +185,11 @@ struct sdio_func_tuple; #define MMC_NUM_PHY_PARTITION 6 #define MAX_MMC_PART_NAME_LEN 20 +#define MAX_MMC_CONTEXT_ID 15 +#define VALID_MAX_MMC_CONTEXT_ID 5 +#define MMC_CONTEXT_CLOSE 0 +#define MMC_CONTEXT_ACT_RW 3 + /* * MMC Physical partitions */ diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 1b431c7..a4e6bc9 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -179,6 +179,10 @@ extern int mmc_try_claim_host(struct mmc_host *host); extern int mmc_flush_cache(struct mmc_card *); +extern int mmc_sync_context(struct mmc_card *card, int context_id); +extern int mmc_flush_contexts(struct mmc_card *card); +extern int mmc_init_context(struct mmc_card *card); + extern int mmc_detect_card_removed(struct mmc_host *host); /** diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0707d22..688348f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -233,6 +233,7 @@ struct mmc_host { #define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */ #define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */ #define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */ +#define MMC_CAP2_CONTEXT (1<<7) /* Context ID supported */ #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ MMC_CAP2_HS200_1_2V_SDR) #define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index b822a2c..96d73aa 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -274,6 +274,7 @@ struct _mmc_csd { #define EXT_CSD_FLUSH_CACHE 32 /* W */ #define EXT_CSD_CACHE_CTRL 33 /* R/W */ #define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_CONTEXT_CONF 37 /* R/W */ #define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ #define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ #define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ @@ -316,6 +317,7 @@ struct _mmc_csd { #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ +#define EXT_CSD_CONTEXT_CAPABILITIES 496 /* RO */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ #define EXT_CSD_HPI_FEATURES 503 /* RO */