Re: [PATCH v2] mmc: support BKOPS feature for eMMC

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

 



On Fri, Nov 11, 2011 at 7:24 AM, Jae hoon Chung <jh80.chung@xxxxxxxxx> wrote:
> Hi per.
>
> 2011/11/8 Per Forlin <per.lkml@xxxxxxxxx>:
>> Hi Jaehoon,
>>
>> On Tue, Nov 8, 2011 at 1:43 PM, Jae hoon Chung <jh80.chung@xxxxxxxxx> wrote:
>>> Hi Per.
>>>
>>> 2011/11/5 Per Forlin <per.lkml@xxxxxxxxx>:
>>>> Hi Jaehoon,
>>>>
>>>> On Wed, Nov 2, 2011 at 11:28 AM, Jaehoon Chung <jh80.chung@xxxxxxxxxxx> wrote:
>>>>> Enable eMMC background operations (BKOPS) feature.
>>>>>
>>>>> If URGENT_BKOPS is set after a response, note that BKOPS
>>>>> are required. After all I/O requests are finished, run
>>>>> BKOPS if required. Should read/write operations be requested
>>>>> during BKOPS, first issue HPI to interrupt the ongoing BKOPS
>>>>> and then service the request.
>>>>>
>>>>> If you want to enable this feature, set MMC_CAP2_BKOPS.
>>>>>
>>>>> Signed-off-by: Jaehoon Chung <jh80.chung@xxxxxxxxxxx>
>>>>> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
>>>>> CC: Hanumath Prasad <hanumath.prasad@xxxxxxxxxxxxxx>
>>>>>
>>>>> ---
>>>>> Changelog V2:
>>>>>        - Use EXCEPTION_STATUS instead of URGENT_BKOPS
>>>>>        - Add function to check Exception_status(for eMMC4.5)
>>>>>        - remove unnecessary code.
>>>>>
>>>>>  drivers/mmc/card/block.c   |    9 +++++
>>>>>  drivers/mmc/card/queue.c   |    4 ++
>>>>>  drivers/mmc/core/core.c    |   87 ++++++++++++++++++++++++++++++++++++++++++++
>>>>>  drivers/mmc/core/mmc.c     |    9 ++++-
>>>>>  drivers/mmc/core/mmc_ops.c |    4 ++
>>>>>  include/linux/mmc/card.h   |   12 ++++++
>>>>>  include/linux/mmc/core.h   |    3 ++
>>>>>  include/linux/mmc/host.h   |    1 +
>>>>>  include/linux/mmc/mmc.h    |   14 +++++++
>>>>>  9 files changed, 142 insertions(+), 1 deletions(-)
>>>>>
>>>>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
>>>>> index a1cb21f..fbfb405 100644
>>>>> --- a/drivers/mmc/card/block.c
>>>>> +++ b/drivers/mmc/card/block.c
>>>>> @@ -1192,6 +1192,15 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
>>>>>                case MMC_BLK_SUCCESS:
>>>>>                case MMC_BLK_PARTIAL:
>>>>>                        /*
>>>>> +                        * Check BKOPS urgency from each R1 response
>>>>> +                        */
>>>>> +                       if (mmc_card_mmc(card) &&
>>>>> +                               (brq->cmd.resp[0] & R1_EXCEPTION_EVENT)) {
>>>>> +                               if (mmc_is_exception_event(card,
>>>>> +                                               EXT_CSD_URGENT_BKOPS))
>>>>> +                                       mmc_card_set_need_bkops(card);
>>>>> +                       }
>>>>> +                       /*
>>>>>                         * A block was successfully transferred.
>>>>>                         */
>>>>>                        mmc_blk_reset_success(md, type);
>>>>> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
>>>>> index dcad59c..20bb4a5 100644
>>>>> --- a/drivers/mmc/card/queue.c
>>>>> +++ b/drivers/mmc/card/queue.c
>>>>> @@ -61,6 +61,9 @@ static int mmc_queue_thread(void *d)
>>>>>                spin_unlock_irq(q->queue_lock);
>>>>>
>>>>>                if (req || mq->mqrq_prev->req) {
>>>>> +                       if (mmc_card_doing_bkops(mq->card))
>>>>> +                               mmc_interrupt_bkops(mq->card);
>>>>> +
>>>>>                        set_current_state(TASK_RUNNING);
>>>>>                        mq->issue_fn(mq, req);
>>>>>                } else {
>>>>> @@ -68,6 +71,7 @@ static int mmc_queue_thread(void *d)
>>>>>                                set_current_state(TASK_RUNNING);
>>>>>                                break;
>>>>>                        }
>>>>> +                       mmc_start_bkops(mq->card);
>>>>>                        up(&mq->thread_sem);
>>>>>                        schedule();
>>>>>                        down(&mq->thread_sem);
>>>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>>>> index 5278ffb..41ea923 100644
>>>>> --- a/drivers/mmc/core/core.c
>>>>> +++ b/drivers/mmc/core/core.c
>>>>> @@ -238,6 +238,50 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
>>>>>        host->ops->request(host, mrq);
>>>>>  }
>>>>>
>>>>> +/**
>>>>> + *     mmc_start_bkops - start BKOPS for supported cards
>>>>> + *     @card: MMC card to start BKOPS
>>>>> + *
>>>>> + *     Start background operations whenever requested.
>>>>> + *     when the urgent BKOPS bit is set in a R1 command response
>>>>> + *     then background operations should be started immediately.
>>>>> +*/
>>>>> +void mmc_start_bkops(struct mmc_card *card)
>>>>> +{
>>>>> +       int err;
>>>>> +       unsigned long flags;
>>>>> +
>>>>
>>>>> +       card->host->caps2 |= MMC_CAP2_BKOPS;
>>>> I guess this should be set by the host driver?
>>> You're right...it's my mistake...i will remove this..
>>>>
>>>>> +       if ((!card || !card->ext_csd.bkops_en) &&
>>>>> +                       !(card->host->caps2 & MMC_CAP2_BKOPS))
>>>> I don't really understand this. If card is NULL it will seg-fault.
>>>>
>>>> Do you mean:
>>>> if (!card)
>>>>  return
>>>>
>>>> if (!card->ext_csd.bkops_en ||
>>>>   !(card->host->caps2 & MMC_CAP2_BKOPS))
>>>>    return
>>>>
>>>> Do you really need to check card != NULL? Consider BUG_ON
>>> Maybe if (!card && !card->ext_csd.bkops_en) is correctly...i think...
>> If card is NULL it will seg-fault.
>> Did you mean: if (card && !card->ext_csd.bkops_en)
>>
>> I would suggest.
>> # return if card is NULL
>> if (!card)
>>  return
>>
>> # if card is set, check the values.
>> if (!card->ext_csd.bkops_en ||
>>   !(card->host->caps2 & MMC_CAP2_BKOPS))
>>   return
>>
> You're right...i will use BUGON()...and modify for ext_bkops_en checking
>>
>>>>
>>>>> +               return;
>>>>> +
>>>>> +       /*
>>>>> +        * If card is already doing bkops or need for
>>>>> +        * bkops flag is not set, then do nothing just
>>>>> +        * return
>>>>> +        */
>>>>> +       if (mmc_card_doing_bkops(card)
>>>>> +                       || !mmc_card_need_bkops(card))
>>>>> +               return;
>>>>> +
>>>>> +       mmc_claim_host(card->host);
>>>>> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>>> +                       EXT_CSD_BKOPS_START, 1, 0);
>>>>> +       if (err) {
>>>>> +               pr_warning("error %d starting bkops\n", err);
>>>>> +               mmc_card_clr_need_bkops(card);
>>>>> +               goto out;
>>>>> +       }
>>>>> +       spin_lock_irqsave(&card->host->lock, flags);
>>>>> +       mmc_card_clr_need_bkops(card);
>>>>> +       mmc_card_set_doing_bkops(card);
>>>>> +       spin_unlock_irqrestore(&card->host->lock, flags);
>>>>> +out:
>>>>> +       mmc_release_host(card->host);
>>>>> +}
>>>>> +EXPORT_SYMBOL(mmc_start_bkops);
>>>>> +
>>>>>  static void mmc_wait_done(struct mmc_request *mrq)
>>>>>  {
>>>>>        complete(&mrq->completion);
>>>>> @@ -466,6 +510,49 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
>>>>>  EXPORT_SYMBOL(mmc_wait_for_cmd);
>>>>>
>>>>>  /**
>>>>> + *     mmc_interrupt_bkops - interrupt ongoing BKOPS
>>>>> + *     @card: MMC card to check BKOPS
>>>>> + *
>>>>> + *     Send HPI command to interrupt ongoing background operations,
>>>>> + *     to allow rapid servicing of foreground operations,e.g. read/
>>>>> + *     writes. Wait until the card comes out of the programming state
>>>>> + *     to avoid errors in servicing read/write requests.
>>>>> + */
>>>>> +int mmc_interrupt_bkops(struct mmc_card *card)
>>>>> +{
>>>>> +       int err = 0;
>>>>> +       unsigned long flags;
>>>>> +
>>>>> +       BUG_ON(!card);
>>>>> +
>>>>> +       err = mmc_interrupt_hpi(card);
>>>>> +
>>>>> +       spin_lock_irqsave(&card->host->lock, flags);
>>>>> +       mmc_card_clr_doing_bkops(card);
>>>>> +       spin_unlock_irqrestore(&card->host->lock, flags);
>>>>> +
>>>>> +       return err;
>>>>> +}
>>>>> +EXPORT_SYMBOL(mmc_interrupt_bkops);
>>>>> +
>>>>> +int mmc_is_exception_event(struct mmc_card *card, unsigned int value)
>>>>> +{
>>>>> +       int err;
>>>>> +       u8 ext_csd[512];
>>>>> +
>>>>> +       /* In eMMC 4.41, R1_EXCEPTION_EVENT is URGENT_BKOPS */
>>>>> +       if (card->ext_csd.rev == 5)
>>>>> +               return 1;
>>>>> +
>>>>> +       err = mmc_send_ext_csd(card, ext_csd);
>>>>> +       if (err)
>>>>> +               return err;
>>>>> +
>>>>> +       return (ext_csd[EXT_CSD_EXCEPTION_STATUS] & value) ? 1 : 0;
>>>>> +}
>>>>> +EXPORT_SYMBOL(mmc_is_exception_event);
>>>>> +
>>>>> +/**
>>>>>  *     mmc_set_data_timeout - set the timeout for a data command
>>>>>  *     @data: data phase for command
>>>>>  *     @card: the MMC card associated with the data transfer
>>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>>> index 3627044..af40fbb 100644
>>>>> --- a/drivers/mmc/core/mmc.c
>>>>> +++ b/drivers/mmc/core/mmc.c
>>>>> @@ -448,6 +448,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>>>>        }
>>>>>
>>>>>        if (card->ext_csd.rev >= 5) {
>>>>> +               /* check whether the eMMC card support BKOPS */
>>>>> +               if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
>>>>> +                       card->ext_csd.bkops = 1;
>>>>> +                       card->ext_csd.bkops_en = 1;
>>>> What if the card has not enabled bkops? This bit could be unset.
>>>> card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
>>> When card is supported the bkops, bkops_en bit is set by default...
>>>
>> How do you know if the bkops_en is really enabled in th ext_csd?
>> It could be unset in the ext_csd, right?
>
> In emmc4.5 spec, if card is supported the bkops, bkops_en is set by default.
If bkops_en is set by default it should be in the the ext_csd too, right?
It should be safer to trust the value of ext_csd[EXT_CSD_BKOPS_EN] in
this case I think.

Regards,
Per
--
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