Re: [RFC 3/3] mmc: Context support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 18 May 2012 18:56, Subhash Jadavani <subhashj@xxxxxxxxxxxxxx> wrote:
> Hi Sougata,
>
> Please find few comments inline below.
>

Many thanks for your time and comments,


> Regards,
> Subhash
>
>> -----Original Message-----
>> From: linux-mmc-owner@xxxxxxxxxxxxxxx [mailto:linux-mmc-
>> owner@xxxxxxxxxxxxxxx] On Behalf Of Saugata Das
>> Sent: Wednesday, May 16, 2012 9:01 PM
>> To: linux-ext4@xxxxxxxxxxxxxxx; linux-fsdevel@xxxxxxxxxxxxxxx; linux-
>> mmc@xxxxxxxxxxxxxxx
>> Cc: arnd.bergmann@xxxxxxxxxx; venkat@xxxxxxxxxx; saugata.das@xxxxxxxxxx
>> Subject: [RFC 3/3] mmc: Context support
>>
>> From: Saugata Das <saugata.das@xxxxxxxxxx>
>>
>> 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 <saugata.das@xxxxxxxxxx>
>> ---
>>  drivers/mmc/card/block.c |   35 +++++++++++++++++++++-
>>  drivers/mmc/core/core.c  |   72
>> ++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/mmc/core/mmc.c   |   28 ++++++++++++++++++
>>  include/linux/mmc/card.h |    4 ++
>>  include/linux/mmc/core.h |    4 ++
>>  include/linux/mmc/host.h |    1 +
>>  include/linux/mmc/mmc.h  |    3 ++
>>  7 files changed, 145 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index
>> dabec55..914f942 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);
>
> This is called unconditionally. Shouldn't we check if context is really
> enabled or not and host have asked (by defining MMC_CAP2_CONTEXT) for it or
> not.

I think the best approach will be to set max_context_id to 0 in
mmc_read_ext_csd, if MMC_CAP2_CONTEXT is not enabled. Then, we do not
have to add a check for MMC_CAP2_CONTEXT, wherever we want to use the
context.

>
> Also shouln't this mmc_flush_contexts() be called after the
> __blk_end_request_all() in this same function?
>

I do not think so. This is in line with how mmc_flush_cache is done
today, i.e. we complete the closing/flushing all pending operations on
the device before  __blk_end_request_all.


>> +     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))) {
>
> card->ext_csd.max_context_id can be non-zero even if host has not enabled
> MMC_CAP2_CONTEXT cap.  So you should add proper check here before tagging
> the context id.
>

I will set max_context_id to 0 in mmc_read_ext_csd if MMC_CAP2_CONTEXT
is not set as mentioned above.

>> +             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,23 @@ 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) ?
>> +                             req->context % card-
>> >ext_csd.max_context_id : 0;
>> +                     /*
>> +                      * 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 */
>
> Use multiline comments format.

Ok

>
>> +                     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..728145a 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -2262,6 +2262,78 @@ int mmc_cache_ctrl(struct mmc_host *host, u8
>> enable)  }  EXPORT_SYMBOL(mmc_cache_ctrl);
>>
>> +/*
>> + * Synchronize a context by first closing the context and then
>> + * opening it
>> + */
>> +int mmc_sync_context(struct mmc_card *card, int context_id) {
>> +     int err = 0;
>> +
>> +     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +             EXT_CSD_CONTEXT_CONF + context_id,
>> +             0x0, card->ext_csd.generic_cmd6_time);
>> +
>> +     if (err)
>> +             return err;
>> +
>> +     err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +             EXT_CSD_CONTEXT_CONF + context_id,
>
> Value of context_id passed to this function can range from 1 to 15. If it's
> 15 then (EXT_CSD_CONTEXT_CONF + context_id) would be 52 which is beyond the
> CONTEXT_CONF [51:37].
> So basically the index value passed to mmc_switch() should be
> (EXT_CSD_CONTEXT_CONF + context_id - 1).
>

In mmc_blk_issue_rq,  we do a "req->context %
card->ext_csd.max_context_id", which will set the context_cfg_id
between 0 and 14. We use this context_cfg_id for the mmc_sync_context.
It should fall within the range.

But in the call from mmc_flush_contexts, I should set the loop i from
0 to (max_context_id-1).

May be, it is good idea to call the parameter context_id as
context_cfg_id within mmc_sync_context to avoid confusion.

>> +             0x3, card->ext_csd.generic_cmd6_time);
>> +
>> +     return err;
>> +}
>> +EXPORT_SYMBOL(mmc_sync_context);
>> +
>> +int mmc_flush_contexts(struct mmc_card *card) {
>> +     int i;
>
> One line space after the declaration missing.
>

Ok

>> +     for (i = 1; i <= card->ext_csd.max_context_id; i++) {
>> +             int err = mmc_sync_context(card, i);
>> +             if (err)
>> +                     return err;
>
> Shouldn't we try to flush other contexts even if flush for other context
> fails?
>

Ok. Will do. But this function will still return an error.

>> +     }
>> +     return 0;
>> +}
>> +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_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                     EXT_CSD_CONTEXT_CONF + i,
>> +                                     0x3, card-
>> >ext_csd.generic_cmd6_time);
>
> I would suggest a separate function which takes the context index,
> activation mode, large unit context as it's arguments and writes the
> activation mode in appropriate context configuration offset. So in future if
> we want to add enable other contexts, we can use the same function.
>
> Also, let's have macro for 0x03 to indicate what it really means (read/write
> context).
>

Ok

>> +             if (err) {
>> +                     pr_warning("%s: Activating of context %d failed
>> [%x]\n",
>> +                                mmc_hostname(card->host), i, err);
>> +                     break;
>> +             }
>> +     }
>> +
>> +     if (!err)
>> +             return 0;
>> +
>> +     /*
>> +      * Close the opened contexts
>> +      */
>
> Why should we close the already opened contexts? Rather we can still use the
> opened contexts. Right?
>

Ok. We can set max_context_id to (1 + the context id we could
successfully opened).


>> +     for (i = i-1; i >= 0; i--) {
>> +             int err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                                     EXT_CSD_CONTEXT_CONF + i,
>> +                                     0x0, card-
>> >ext_csd.generic_cmd6_time);
>> +             if (err)
>> +                     pr_warning("%s: Closing of context %d failed
>> [%x]\n",
>> +                                mmc_hostname(card->host), i, err);
>> +     }
>> +
>> +     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..84bec43 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -533,6 +533,20 @@ static int mmc_read_ext_csd(struct mmc_card *card,
>> u8 *ext_csd)
>>               } else {
>>                       card->ext_csd.data_tag_unit_size = 0;
>>               }
>> +
>> +             /* LU size in 512 byt sectors */
>
> Typo here. s/byt/byte
>
>> +             card->ext_csd.lu_size =
>> +                     (ext_csd[EXT_CSD_LARGE_UNIT_SIZE_M1] + 1) *
>> 0x800;
>
> In this patch you are not using the large unit context anywhere then better
> not to read the large unit size as part of this patch. Let it be completely
> handled separately when someone adds the large unit context in future.
>

Ok

>> +
>> +             card->ext_csd.max_context_id =
>> +                     ext_csd[EXT_CSD_CONTEXT_CAPABILITIES] & 0x0f;
>
> This is what spec says: " The mandatory minimum value for this field is 5
> plus the default ID #0 (MAX_CONTEXT_ID shall be 5 or higher) ". Can you add
> check for this? And if card violates this, we at least should print a
> warning.
>

Ok

>> +
>> +             if (card->ext_csd.max_context_id >
>> MAX_MMC_CONTEXT_ID) {
>
> Is this check required? You are already &ing with 0x0f which means the
> max_context_id will never be more than MAX_MMC_CONTEXT_ID (which is 15).
>
>> +                     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 +1281,20 @@ 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;
>> +                     }
>> +             }
>> +     }
>> +
>>       if (!oldcard)
>>               host->card = card;
>>
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index
>> 629b823..adf2c84 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -74,6 +74,8 @@ 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            lu_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 +186,8 @@ struct sdio_func_tuple;
>>  #define MMC_NUM_PHY_PARTITION        6
>>  #define MAX_MMC_PART_NAME_LEN        20
>>
>> +#define MAX_MMC_CONTEXT_ID           15
>> +
>>  /*
>>   * 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..8f8d958 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,8 @@ 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_LARGE_UNIT_SIZE_M1   495     /* RO */
>> +#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 */
>> --
>> 1.7.4.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the
>> body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at
>> http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux