Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-11 Thread Subhash Jadavani


Thanks Maya. Looks good to me.
Reviewed-by: subha...@codeaurora.org

Regards,
Subhash

On 10/5/2012 3:58 AM, Maya Erez wrote:

Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle,
and in case of an incoming request the BKOPS operation will be
interrupted.

When the mmcqd thread is idle, a delayed work is created to check the
need for BKOPS. The time to start the delayed work is calculated based
on the host controller suspend timeout, in case it was set. If not, a
default time is used.
If BKOPS are required in level 1, which is non-blocking, there will be
polling of the card status to wait for the BKOPS completion and prevent
suspend that will interrupt the BKOPS.
If the card raised an exception, the need for urgent BKOPS (level 2/3)
will be checked immediately and if needed, the BKOPS will be performed
without waiting for the next idle time.

Signed-off-by: Maya Erez 
Signed-off-by: Jaehoon Chung 
---
This patch is based on the periodic BKOPS implementation in version 8 of "support 
BKOPS feature for eMMC" patch.
The patch was modified to answer the following issues:
- In order to prevent a race condition between going into suspend and starting 
BKOPS,
   the suspend timeout of the host controller is taking into accound in 
determination of the start time
   of the delayed work
- Since mmc_start_bkops is called from two contexts now, mmc_claim_host was 
moved to the beginning of the function
- Also, the check of doing_bkops should be protected when determing if an HPI 
is needed due to the same reason.
- Starting and canceling the delayed work in each idle caused degradation of 
iozone performance. Therefore,
   the delayed work is not started on each idle. The amount of sectors changed 
(written or discard) from the last
   delayed work is the trigger for starting the delayed BKOPS work.
---
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768..ed040d5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
  
+	if (card->ext_csd.bkops_en)

+   card->bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
struct request *rqc)
if (!rqc && !mq->mqrq_prev->req)
return 0;
  
+	if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))

+   card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
+
do {
if (rqc) {
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a97..e96f5cf 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
+   struct mmc_card *card = mq->card;
  
  	current->flags |= PF_MEMALLOC;
  
@@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)

spin_unlock_irq(q->queue_lock);
  
  		if (req || mq->mqrq_prev->req) {

+   /*
+* If this is the first request, BKOPs might be in
+* progress and needs to be stopped before issuing the
+* request
+*/
+   if (card->ext_csd.bkops_en &&
+   card->bkops_info.started_delayed_bkops) {
+   card->bkops_info.started_delayed_bkops = false;
+   mmc_stop_bkops(card);
+   }
+
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
} else {
@@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_RUNNING);
break;
}
+   mmc_start_delayed_bkops(card);
up(>thread_sem);
   

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-11 Thread Subhash Jadavani


Thanks Maya. Looks good to me.
Reviewed-by: subha...@codeaurora.org

Regards,
Subhash

On 10/5/2012 3:58 AM, Maya Erez wrote:

Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle,
and in case of an incoming request the BKOPS operation will be
interrupted.

When the mmcqd thread is idle, a delayed work is created to check the
need for BKOPS. The time to start the delayed work is calculated based
on the host controller suspend timeout, in case it was set. If not, a
default time is used.
If BKOPS are required in level 1, which is non-blocking, there will be
polling of the card status to wait for the BKOPS completion and prevent
suspend that will interrupt the BKOPS.
If the card raised an exception, the need for urgent BKOPS (level 2/3)
will be checked immediately and if needed, the BKOPS will be performed
without waiting for the next idle time.

Signed-off-by: Maya Erez me...@codeaurora.org
Signed-off-by: Jaehoon Chung jh80.ch...@samsung.com
---
This patch is based on the periodic BKOPS implementation in version 8 of support 
BKOPS feature for eMMC patch.
The patch was modified to answer the following issues:
- In order to prevent a race condition between going into suspend and starting 
BKOPS,
   the suspend timeout of the host controller is taking into accound in 
determination of the start time
   of the delayed work
- Since mmc_start_bkops is called from two contexts now, mmc_claim_host was 
moved to the beginning of the function
- Also, the check of doing_bkops should be protected when determing if an HPI 
is needed due to the same reason.
- Starting and canceling the delayed work in each idle caused degradation of 
iozone performance. Therefore,
   the delayed work is not started on each idle. The amount of sectors changed 
(written or discard) from the last
   delayed work is the trigger for starting the delayed BKOPS work.
---
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768..ed040d5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
  
+	if (card-ext_csd.bkops_en)

+   card-bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
struct request *rqc)
if (!rqc  !mq-mqrq_prev-req)
return 0;
  
+	if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))

+   card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
+
do {
if (rqc) {
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a97..e96f5cf 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
struct mmc_queue *mq = d;
struct request_queue *q = mq-queue;
+   struct mmc_card *card = mq-card;
  
  	current-flags |= PF_MEMALLOC;
  
@@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)

spin_unlock_irq(q-queue_lock);
  
  		if (req || mq-mqrq_prev-req) {

+   /*
+* If this is the first request, BKOPs might be in
+* progress and needs to be stopped before issuing the
+* request
+*/
+   if (card-ext_csd.bkops_en 
+   card-bkops_info.started_delayed_bkops) {
+   card-bkops_info.started_delayed_bkops = false;
+   mmc_stop_bkops(card);
+   }
+
set_current_state(TASK_RUNNING);
mq-issue_fn(mq, req);
} else {
@@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_RUNNING);
break;
}
+   mmc_start_delayed_bkops(card);
up(mq-thread_sem);
 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-07 Thread Jaehoon Chung
Hi Maya, 

I tested with dw-mmc controller.
It's look good to me.

Tested-by: Jaehoon Chung 

On 11/07/2012 01:28 PM, me...@codeaurora.org wrote:
> Hi Jaehoon,
> 
> Any update on this patch review and testing?
> 
> Thanks,
> Maya
> On Mon, October 15, 2012 11:53 pm, Jaehoon Chung wrote:
>> Hi Maya,
>>
>> I'm testing with your patch..but i need to have the more time for testing.
>> In now, it looks good to me. Thank you for working the idle bkops.
>>
>> Best Regards,
>> Jaehoon Chung
>>
>>> ---
>>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
>>> index 172a768..ed040d5 100644
>>> --- a/drivers/mmc/card/block.c
>>> +++ b/drivers/mmc/card/block.c
>>> @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
>>> *mq, struct request *req)
>>> from = blk_rq_pos(req);
>>> nr = blk_rq_sectors(req);
>>>
>>> +   if (card->ext_csd.bkops_en)
>>> +   card->bkops_info.sectors_changed += blk_rq_sectors(req);
>> using nr?
>>> +
>>> if (mmc_can_discard(card))
>>> arg = MMC_DISCARD_ARG;
>>> else if (mmc_can_trim(card))
>>> @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue
>>> *mq, struct request *rqc)
>>> if (!rqc && !mq->mqrq_prev->req)
>>> return 0;
>>>
>>> +   if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
>>> +   card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
>> Fix the indent.
>>> +
>>> do {
>>> if (rqc) {
>>> /*
>>> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
>>> index e360a97..e96f5cf 100644
>>> --- a/drivers/mmc/card/queue.c
>>> +++ b/drivers/mmc/card/queue.c
>>> @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
>>>  {
>>> struct mmc_queue *mq = d;
>>> struct request_queue *q = mq->queue;
>>> +   struct mmc_card *card = mq->card;
>>>
>>> current->flags |= PF_MEMALLOC;
>>>
>>> @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
>>> spin_unlock_irq(q->queue_lock);
>>>
>>> if (req || mq->mqrq_prev->req) {
>>> +   /*
>>> +* If this is the first request, BKOPs might be in
>>> +* progress and needs to be stopped before issuing the
>>> +* request
>>> +*/
>>> +   if (card->ext_csd.bkops_en &&
>>> +   card->bkops_info.started_delayed_bkops) {
>>> +   card->bkops_info.started_delayed_bkops = false;
>>> +   mmc_stop_bkops(card);
>> if mmc_stop_bkops is failed..?
>>> +   }
>>> +
>>> set_current_state(TASK_RUNNING);
>>> mq->issue_fn(mq, req);
>>> } else {
>>> @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
>>> set_current_state(TASK_RUNNING);
>>> break;
>>> }
>>> +   mmc_start_delayed_bkops(card);
>>> up(>thread_sem);
>>> schedule();
>>> down(>thread_sem);
>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>> index 6612163..fd8783d 100644
>>> --- a/drivers/mmc/core/core.c
>>> +++ b/drivers/mmc/core/core.c
>>> @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct
>>> mmc_request *mrq)
>>>  }
>>>
>>>  /**
>>> + * mmc_start_delayed_bkops() - Start a delayed work to check for
>>> + *  the need of non urgent BKOPS
>>> + *
>>> + * @card: MMC card to start BKOPS on
>>> + */
>>> +void mmc_start_delayed_bkops(struct mmc_card *card)
>>> +{
>>> +   if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
>>> +   return;
>>> +
>>> +   if (card->bkops_info.sectors_changed <
>>> +   BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
>>> +   return;
>>> +
>>> +   pr_debug("%s: %s: queueing delayed_bkops_work\n",
>>> +mmc_hostname(card->host), __func__);
>>> +
>>> +   card->bkops_info.sectors_changed = 0;
>>> +
>>> +   /*
>>> +* cancel_delayed_bkops_work will prevent a race condition between
>>> +* fetching a request by the mmcqd and the delayed work, in case
>>> +* it was removed from the queue work but not started yet
>>> +*/
>>> +   card->bkops_info.cancel_delayed_work = false;
>>> +   card->bkops_info.started_delayed_bkops = true;
>>> +   queue_delayed_work(system_nrt_wq, >bkops_info.dw,
>>> +  msecs_to_jiffies(
>>> +  card->bkops_info.delay_ms));
>>> +}
>>> +EXPORT_SYMBOL(mmc_start_delayed_bkops);
>>> +
>>> +/**
>>>   * mmc_start_bkops - start BKOPS for supported cards
>>>   * @card: MMC card to start BKOPS
>>> - * @form_exception: A flag to indicate if this function was
>>> + * @from_exception: A flag to indicate if this function was
>>>   *  called due to an exception raised by the card
>>>   *
>>>   * Start background operations whenever 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-07 Thread Jaehoon Chung
Hi Maya, 

I tested with dw-mmc controller.
It's look good to me.

Tested-by: Jaehoon Chung jh80.ch...@samsung.com

On 11/07/2012 01:28 PM, me...@codeaurora.org wrote:
 Hi Jaehoon,
 
 Any update on this patch review and testing?
 
 Thanks,
 Maya
 On Mon, October 15, 2012 11:53 pm, Jaehoon Chung wrote:
 Hi Maya,

 I'm testing with your patch..but i need to have the more time for testing.
 In now, it looks good to me. Thank you for working the idle bkops.

 Best Regards,
 Jaehoon Chung

 ---
 diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
 index 172a768..ed040d5 100644
 --- a/drivers/mmc/card/block.c
 +++ b/drivers/mmc/card/block.c
 @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
 *mq, struct request *req)
 from = blk_rq_pos(req);
 nr = blk_rq_sectors(req);

 +   if (card-ext_csd.bkops_en)
 +   card-bkops_info.sectors_changed += blk_rq_sectors(req);
 using nr?
 +
 if (mmc_can_discard(card))
 arg = MMC_DISCARD_ARG;
 else if (mmc_can_trim(card))
 @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue
 *mq, struct request *rqc)
 if (!rqc  !mq-mqrq_prev-req)
 return 0;

 +   if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))
 +   card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
 Fix the indent.
 +
 do {
 if (rqc) {
 /*
 diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
 index e360a97..e96f5cf 100644
 --- a/drivers/mmc/card/queue.c
 +++ b/drivers/mmc/card/queue.c
 @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
 struct mmc_queue *mq = d;
 struct request_queue *q = mq-queue;
 +   struct mmc_card *card = mq-card;

 current-flags |= PF_MEMALLOC;

 @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
 spin_unlock_irq(q-queue_lock);

 if (req || mq-mqrq_prev-req) {
 +   /*
 +* If this is the first request, BKOPs might be in
 +* progress and needs to be stopped before issuing the
 +* request
 +*/
 +   if (card-ext_csd.bkops_en 
 +   card-bkops_info.started_delayed_bkops) {
 +   card-bkops_info.started_delayed_bkops = false;
 +   mmc_stop_bkops(card);
 if mmc_stop_bkops is failed..?
 +   }
 +
 set_current_state(TASK_RUNNING);
 mq-issue_fn(mq, req);
 } else {
 @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
 set_current_state(TASK_RUNNING);
 break;
 }
 +   mmc_start_delayed_bkops(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 6612163..fd8783d 100644
 --- a/drivers/mmc/core/core.c
 +++ b/drivers/mmc/core/core.c
 @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct
 mmc_request *mrq)
  }

  /**
 + * mmc_start_delayed_bkops() - Start a delayed work to check for
 + *  the need of non urgent BKOPS
 + *
 + * @card: MMC card to start BKOPS on
 + */
 +void mmc_start_delayed_bkops(struct mmc_card *card)
 +{
 +   if (!card || !card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 +   return;
 +
 +   if (card-bkops_info.sectors_changed 
 +   BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
 +   return;
 +
 +   pr_debug(%s: %s: queueing delayed_bkops_work\n,
 +mmc_hostname(card-host), __func__);
 +
 +   card-bkops_info.sectors_changed = 0;
 +
 +   /*
 +* cancel_delayed_bkops_work will prevent a race condition between
 +* fetching a request by the mmcqd and the delayed work, in case
 +* it was removed from the queue work but not started yet
 +*/
 +   card-bkops_info.cancel_delayed_work = false;
 +   card-bkops_info.started_delayed_bkops = true;
 +   queue_delayed_work(system_nrt_wq, card-bkops_info.dw,
 +  msecs_to_jiffies(
 +  card-bkops_info.delay_ms));
 +}
 +EXPORT_SYMBOL(mmc_start_delayed_bkops);
 +
 +/**
   * mmc_start_bkops - start BKOPS for supported cards
   * @card: MMC card to start BKOPS
 - * @form_exception: A flag to indicate if this function was
 + * @from_exception: A flag to indicate if this function was
   *  called due to an exception raised by the card
   *
   * Start background operations whenever requested.
 @@ -269,25 +302,47 @@ void mmc_start_bkops(struct mmc_card *card, bool
 from_exception)
 bool use_busy_signal;

 BUG_ON(!card);
 -
 -   if (!card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 +   if (!card-ext_csd.bkops_en)
 return;

 +   mmc_claim_host(card-host);
 +
 +   if ((card-bkops_info.cancel_delayed_work)  !from_exception) {
 +

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-06 Thread merez
Hi Jaehoon,

Any update on this patch review and testing?

Thanks,
Maya
On Mon, October 15, 2012 11:53 pm, Jaehoon Chung wrote:
> Hi Maya,
>
> I'm testing with your patch..but i need to have the more time for testing.
> In now, it looks good to me. Thank you for working the idle bkops.
>
> Best Regards,
> Jaehoon Chung
>
>> ---
>> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
>> index 172a768..ed040d5 100644
>> --- a/drivers/mmc/card/block.c
>> +++ b/drivers/mmc/card/block.c
>> @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
>> *mq, struct request *req)
>>  from = blk_rq_pos(req);
>>  nr = blk_rq_sectors(req);
>>
>> +if (card->ext_csd.bkops_en)
>> +card->bkops_info.sectors_changed += blk_rq_sectors(req);
> using nr?
>> +
>>  if (mmc_can_discard(card))
>>  arg = MMC_DISCARD_ARG;
>>  else if (mmc_can_trim(card))
>> @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue
>> *mq, struct request *rqc)
>>  if (!rqc && !mq->mqrq_prev->req)
>>  return 0;
>>
>> +if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
>> +card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
> Fix the indent.
>> +
>>  do {
>>  if (rqc) {
>>  /*
>> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
>> index e360a97..e96f5cf 100644
>> --- a/drivers/mmc/card/queue.c
>> +++ b/drivers/mmc/card/queue.c
>> @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
>>  {
>>  struct mmc_queue *mq = d;
>>  struct request_queue *q = mq->queue;
>> +struct mmc_card *card = mq->card;
>>
>>  current->flags |= PF_MEMALLOC;
>>
>> @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
>>  spin_unlock_irq(q->queue_lock);
>>
>>  if (req || mq->mqrq_prev->req) {
>> +/*
>> + * If this is the first request, BKOPs might be in
>> + * progress and needs to be stopped before issuing the
>> + * request
>> + */
>> +if (card->ext_csd.bkops_en &&
>> +card->bkops_info.started_delayed_bkops) {
>> +card->bkops_info.started_delayed_bkops = false;
>> +mmc_stop_bkops(card);
> if mmc_stop_bkops is failed..?
>> +}
>> +
>>  set_current_state(TASK_RUNNING);
>>  mq->issue_fn(mq, req);
>>  } else {
>> @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
>>  set_current_state(TASK_RUNNING);
>>  break;
>>  }
>> +mmc_start_delayed_bkops(card);
>>  up(>thread_sem);
>>  schedule();
>>  down(>thread_sem);
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 6612163..fd8783d 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct
>> mmc_request *mrq)
>>  }
>>
>>  /**
>> + * mmc_start_delayed_bkops() - Start a delayed work to check for
>> + *  the need of non urgent BKOPS
>> + *
>> + * @card: MMC card to start BKOPS on
>> + */
>> +void mmc_start_delayed_bkops(struct mmc_card *card)
>> +{
>> +if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
>> +return;
>> +
>> +if (card->bkops_info.sectors_changed <
>> +BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
>> +return;
>> +
>> +pr_debug("%s: %s: queueing delayed_bkops_work\n",
>> + mmc_hostname(card->host), __func__);
>> +
>> +card->bkops_info.sectors_changed = 0;
>> +
>> +/*
>> + * cancel_delayed_bkops_work will prevent a race condition between
>> + * fetching a request by the mmcqd and the delayed work, in case
>> + * it was removed from the queue work but not started yet
>> + */
>> +card->bkops_info.cancel_delayed_work = false;
>> +card->bkops_info.started_delayed_bkops = true;
>> +queue_delayed_work(system_nrt_wq, >bkops_info.dw,
>> +   msecs_to_jiffies(
>> +   card->bkops_info.delay_ms));
>> +}
>> +EXPORT_SYMBOL(mmc_start_delayed_bkops);
>> +
>> +/**
>>   *  mmc_start_bkops - start BKOPS for supported cards
>>   *  @card: MMC card to start BKOPS
>> - *  @form_exception: A flag to indicate if this function was
>> + *  @from_exception: A flag to indicate if this function was
>>   *   called due to an exception raised by the card
>>   *
>>   *  Start background operations whenever requested.
>> @@ -269,25 +302,47 @@ void mmc_start_bkops(struct mmc_card *card, bool
>> from_exception)
>>  bool use_busy_signal;
>>
>>  BUG_ON(!card);
>> -
>> -if (!card->ext_csd.bkops_en || 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-11-06 Thread merez
Hi Jaehoon,

Any update on this patch review and testing?

Thanks,
Maya
On Mon, October 15, 2012 11:53 pm, Jaehoon Chung wrote:
 Hi Maya,

 I'm testing with your patch..but i need to have the more time for testing.
 In now, it looks good to me. Thank you for working the idle bkops.

 Best Regards,
 Jaehoon Chung

 ---
 diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
 index 172a768..ed040d5 100644
 --- a/drivers/mmc/card/block.c
 +++ b/drivers/mmc/card/block.c
 @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
 *mq, struct request *req)
  from = blk_rq_pos(req);
  nr = blk_rq_sectors(req);

 +if (card-ext_csd.bkops_en)
 +card-bkops_info.sectors_changed += blk_rq_sectors(req);
 using nr?
 +
  if (mmc_can_discard(card))
  arg = MMC_DISCARD_ARG;
  else if (mmc_can_trim(card))
 @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue
 *mq, struct request *rqc)
  if (!rqc  !mq-mqrq_prev-req)
  return 0;

 +if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))
 +card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
 Fix the indent.
 +
  do {
  if (rqc) {
  /*
 diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
 index e360a97..e96f5cf 100644
 --- a/drivers/mmc/card/queue.c
 +++ b/drivers/mmc/card/queue.c
 @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
  struct mmc_queue *mq = d;
  struct request_queue *q = mq-queue;
 +struct mmc_card *card = mq-card;

  current-flags |= PF_MEMALLOC;

 @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
  spin_unlock_irq(q-queue_lock);

  if (req || mq-mqrq_prev-req) {
 +/*
 + * If this is the first request, BKOPs might be in
 + * progress and needs to be stopped before issuing the
 + * request
 + */
 +if (card-ext_csd.bkops_en 
 +card-bkops_info.started_delayed_bkops) {
 +card-bkops_info.started_delayed_bkops = false;
 +mmc_stop_bkops(card);
 if mmc_stop_bkops is failed..?
 +}
 +
  set_current_state(TASK_RUNNING);
  mq-issue_fn(mq, req);
  } else {
 @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
  set_current_state(TASK_RUNNING);
  break;
  }
 +mmc_start_delayed_bkops(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 6612163..fd8783d 100644
 --- a/drivers/mmc/core/core.c
 +++ b/drivers/mmc/core/core.c
 @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct
 mmc_request *mrq)
  }

  /**
 + * mmc_start_delayed_bkops() - Start a delayed work to check for
 + *  the need of non urgent BKOPS
 + *
 + * @card: MMC card to start BKOPS on
 + */
 +void mmc_start_delayed_bkops(struct mmc_card *card)
 +{
 +if (!card || !card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 +return;
 +
 +if (card-bkops_info.sectors_changed 
 +BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
 +return;
 +
 +pr_debug(%s: %s: queueing delayed_bkops_work\n,
 + mmc_hostname(card-host), __func__);
 +
 +card-bkops_info.sectors_changed = 0;
 +
 +/*
 + * cancel_delayed_bkops_work will prevent a race condition between
 + * fetching a request by the mmcqd and the delayed work, in case
 + * it was removed from the queue work but not started yet
 + */
 +card-bkops_info.cancel_delayed_work = false;
 +card-bkops_info.started_delayed_bkops = true;
 +queue_delayed_work(system_nrt_wq, card-bkops_info.dw,
 +   msecs_to_jiffies(
 +   card-bkops_info.delay_ms));
 +}
 +EXPORT_SYMBOL(mmc_start_delayed_bkops);
 +
 +/**
   *  mmc_start_bkops - start BKOPS for supported cards
   *  @card: MMC card to start BKOPS
 - *  @form_exception: A flag to indicate if this function was
 + *  @from_exception: A flag to indicate if this function was
   *   called due to an exception raised by the card
   *
   *  Start background operations whenever requested.
 @@ -269,25 +302,47 @@ void mmc_start_bkops(struct mmc_card *card, bool
 from_exception)
  bool use_busy_signal;

  BUG_ON(!card);
 -
 -if (!card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 +if (!card-ext_csd.bkops_en)
  return;

 +mmc_claim_host(card-host);
 +
 +if ((card-bkops_info.cancel_delayed_work)  !from_exception) {
 +pr_debug(%s: %s: cancel_delayed_work was set, exit\n,
 + 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-16 Thread Jaehoon Chung
Hi Maya,

I'm testing with your patch..but i need to have the more time for testing.
In now, it looks good to me. Thank you for working the idle bkops.

Best Regards,
Jaehoon Chung

> ---
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 172a768..ed040d5 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
> struct request *req)
>   from = blk_rq_pos(req);
>   nr = blk_rq_sectors(req);
>  
> + if (card->ext_csd.bkops_en)
> + card->bkops_info.sectors_changed += blk_rq_sectors(req);
using nr?
> +
>   if (mmc_can_discard(card))
>   arg = MMC_DISCARD_ARG;
>   else if (mmc_can_trim(card))
> @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
> struct request *rqc)
>   if (!rqc && !mq->mqrq_prev->req)
>   return 0;
>  
> + if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
> + card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
Fix the indent.
> +
>   do {
>   if (rqc) {
>   /*
> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
> index e360a97..e96f5cf 100644
> --- a/drivers/mmc/card/queue.c
> +++ b/drivers/mmc/card/queue.c
> @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
>  {
>   struct mmc_queue *mq = d;
>   struct request_queue *q = mq->queue;
> + struct mmc_card *card = mq->card;
>  
>   current->flags |= PF_MEMALLOC;
>  
> @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
>   spin_unlock_irq(q->queue_lock);
>  
>   if (req || mq->mqrq_prev->req) {
> + /*
> +  * If this is the first request, BKOPs might be in
> +  * progress and needs to be stopped before issuing the
> +  * request
> +  */
> + if (card->ext_csd.bkops_en &&
> + card->bkops_info.started_delayed_bkops) {
> + card->bkops_info.started_delayed_bkops = false;
> + mmc_stop_bkops(card);
if mmc_stop_bkops is failed..?
> + }
> +
>   set_current_state(TASK_RUNNING);
>   mq->issue_fn(mq, req);
>   } else {
> @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
>   set_current_state(TASK_RUNNING);
>   break;
>   }
> + mmc_start_delayed_bkops(card);
>   up(>thread_sem);
>   schedule();
>   down(>thread_sem);
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 6612163..fd8783d 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct 
> mmc_request *mrq)
>  }
>  
>  /**
> + * mmc_start_delayed_bkops() - Start a delayed work to check for
> + *  the need of non urgent BKOPS
> + *
> + * @card: MMC card to start BKOPS on
> + */
> +void mmc_start_delayed_bkops(struct mmc_card *card)
> +{
> + if (!card || !card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
> + return;
> +
> + if (card->bkops_info.sectors_changed <
> + BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
> + return;
> +
> + pr_debug("%s: %s: queueing delayed_bkops_work\n",
> +  mmc_hostname(card->host), __func__);
> +
> + card->bkops_info.sectors_changed = 0;
> +
> + /*
> +  * cancel_delayed_bkops_work will prevent a race condition between
> +  * fetching a request by the mmcqd and the delayed work, in case
> +  * it was removed from the queue work but not started yet
> +  */
> + card->bkops_info.cancel_delayed_work = false;
> + card->bkops_info.started_delayed_bkops = true;
> + queue_delayed_work(system_nrt_wq, >bkops_info.dw,
> +msecs_to_jiffies(
> +card->bkops_info.delay_ms));
> +}
> +EXPORT_SYMBOL(mmc_start_delayed_bkops);
> +
> +/**
>   *   mmc_start_bkops - start BKOPS for supported cards
>   *   @card: MMC card to start BKOPS
> - *   @form_exception: A flag to indicate if this function was
> + *   @from_exception: A flag to indicate if this function was
>   *called due to an exception raised by the card
>   *
>   *   Start background operations whenever requested.
> @@ -269,25 +302,47 @@ void mmc_start_bkops(struct mmc_card *card, bool 
> from_exception)
>   bool use_busy_signal;
>  
>   BUG_ON(!card);
> -
> - if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
> + if (!card->ext_csd.bkops_en)
>   return;
>  
> + mmc_claim_host(card->host);
> +
> + if ((card->bkops_info.cancel_delayed_work) && 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-16 Thread Jaehoon Chung
Hi Maya,

I'm testing with your patch..but i need to have the more time for testing.
In now, it looks good to me. Thank you for working the idle bkops.

Best Regards,
Jaehoon Chung

 ---
 diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
 index 172a768..ed040d5 100644
 --- a/drivers/mmc/card/block.c
 +++ b/drivers/mmc/card/block.c
 @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
 struct request *req)
   from = blk_rq_pos(req);
   nr = blk_rq_sectors(req);
  
 + if (card-ext_csd.bkops_en)
 + card-bkops_info.sectors_changed += blk_rq_sectors(req);
using nr?
 +
   if (mmc_can_discard(card))
   arg = MMC_DISCARD_ARG;
   else if (mmc_can_trim(card))
 @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
 struct request *rqc)
   if (!rqc  !mq-mqrq_prev-req)
   return 0;
  
 + if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))
 + card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
Fix the indent.
 +
   do {
   if (rqc) {
   /*
 diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
 index e360a97..e96f5cf 100644
 --- a/drivers/mmc/card/queue.c
 +++ b/drivers/mmc/card/queue.c
 @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
   struct mmc_queue *mq = d;
   struct request_queue *q = mq-queue;
 + struct mmc_card *card = mq-card;
  
   current-flags |= PF_MEMALLOC;
  
 @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
   spin_unlock_irq(q-queue_lock);
  
   if (req || mq-mqrq_prev-req) {
 + /*
 +  * If this is the first request, BKOPs might be in
 +  * progress and needs to be stopped before issuing the
 +  * request
 +  */
 + if (card-ext_csd.bkops_en 
 + card-bkops_info.started_delayed_bkops) {
 + card-bkops_info.started_delayed_bkops = false;
 + mmc_stop_bkops(card);
if mmc_stop_bkops is failed..?
 + }
 +
   set_current_state(TASK_RUNNING);
   mq-issue_fn(mq, req);
   } else {
 @@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
   set_current_state(TASK_RUNNING);
   break;
   }
 + mmc_start_delayed_bkops(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 6612163..fd8783d 100644
 --- a/drivers/mmc/core/core.c
 +++ b/drivers/mmc/core/core.c
 @@ -253,9 +253,42 @@ mmc_start_request(struct mmc_host *host, struct 
 mmc_request *mrq)
  }
  
  /**
 + * mmc_start_delayed_bkops() - Start a delayed work to check for
 + *  the need of non urgent BKOPS
 + *
 + * @card: MMC card to start BKOPS on
 + */
 +void mmc_start_delayed_bkops(struct mmc_card *card)
 +{
 + if (!card || !card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 + return;
 +
 + if (card-bkops_info.sectors_changed 
 + BKOPS_MIN_SECTORS_TO_QUEUE_DELAYED_WORK)
 + return;
 +
 + pr_debug(%s: %s: queueing delayed_bkops_work\n,
 +  mmc_hostname(card-host), __func__);
 +
 + card-bkops_info.sectors_changed = 0;
 +
 + /*
 +  * cancel_delayed_bkops_work will prevent a race condition between
 +  * fetching a request by the mmcqd and the delayed work, in case
 +  * it was removed from the queue work but not started yet
 +  */
 + card-bkops_info.cancel_delayed_work = false;
 + card-bkops_info.started_delayed_bkops = true;
 + queue_delayed_work(system_nrt_wq, card-bkops_info.dw,
 +msecs_to_jiffies(
 +card-bkops_info.delay_ms));
 +}
 +EXPORT_SYMBOL(mmc_start_delayed_bkops);
 +
 +/**
   *   mmc_start_bkops - start BKOPS for supported cards
   *   @card: MMC card to start BKOPS
 - *   @form_exception: A flag to indicate if this function was
 + *   @from_exception: A flag to indicate if this function was
   *called due to an exception raised by the card
   *
   *   Start background operations whenever requested.
 @@ -269,25 +302,47 @@ void mmc_start_bkops(struct mmc_card *card, bool 
 from_exception)
   bool use_busy_signal;
  
   BUG_ON(!card);
 -
 - if (!card-ext_csd.bkops_en || mmc_card_doing_bkops(card))
 + if (!card-ext_csd.bkops_en)
   return;
  
 + mmc_claim_host(card-host);
 +
 + if ((card-bkops_info.cancel_delayed_work)  !from_exception) {
 + pr_debug(%s: %s: cancel_delayed_work was set, exit\n,
 +  mmc_hostname(card-host), __func__);
 + 

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-08 Thread merez
Hi Chris and all,

According to the eMMC4.5 standard, a host that enables the BKOPS_EN bit
must also check the BKOPS status periodically:
"Host shall check the status periodically and start background operations
as needed, so that the device has enough time for its maintenance
operations, to help reduce the latencies during foreground operations. If
the status is at level 3 ("critical"), some operations may extend beyond
their original timeouts due to maintenance operations which cannot be
delayed anymore. The host should give the device enough time for
background operations to avoid getting to this level in the first place."

As mentioned in the standard quotation above, it is not recommended to
handle only BKOPS of level 3 since it can lead to foreground operations
timeout.

I would appreciate if you could review this change to add the periodic
BKOPS on top of handling BKOPS level 3 that was already mainlined.

Thnaks,
Maya
On Thu, October 4, 2012 3:28 pm, Maya Erez wrote:
> Devices have various maintenance operations need to perform internally.
> In order to reduce latencies during time critical operations like read
> and write, it is better to execute maintenance operations in other
> times - when the host is not being serviced. Such operations are called
> Background operations (BKOPS).
> The device notifies the status of the BKOPS need by updating BKOPS_STATUS
> (EXT_CSD byte [246]).
>
> According to the standard a host that supports BKOPS shall check the
> status periodically and start background operations as needed, so that
> the device has enough time for its maintenance operations.
>
> This patch adds support for this periodic check of the BKOPS status.
> Since foreground operations are of higher priority than background
> operations the host will check the need for BKOPS when it is idle,
> and in case of an incoming request the BKOPS operation will be
> interrupted.
>
> When the mmcqd thread is idle, a delayed work is created to check the
> need for BKOPS. The time to start the delayed work is calculated based
> on the host controller suspend timeout, in case it was set. If not, a
> default time is used.
> If BKOPS are required in level 1, which is non-blocking, there will be
> polling of the card status to wait for the BKOPS completion and prevent
> suspend that will interrupt the BKOPS.
> If the card raised an exception, the need for urgent BKOPS (level 2/3)
> will be checked immediately and if needed, the BKOPS will be performed
> without waiting for the next idle time.
>
> Signed-off-by: Maya Erez 
> Signed-off-by: Jaehoon Chung 
> ---
> This patch is based on the periodic BKOPS implementation in version 8 of
> "support BKOPS feature for eMMC" patch.
> The patch was modified to answer the following issues:
> - In order to prevent a race condition between going into suspend and
> starting BKOPS,
>   the suspend timeout of the host controller is taking into accound in
> determination of the start time
>   of the delayed work
> - Since mmc_start_bkops is called from two contexts now, mmc_claim_host
> was moved to the beginning of the function
> - Also, the check of doing_bkops should be protected when determing if an
> HPI is needed due to the same reason.
> - Starting and canceling the delayed work in each idle caused degradation
> of iozone performance. Therefore,
>   the delayed work is not started on each idle. The amount of sectors
> changed (written or discard) from the last
>   delayed work is the trigger for starting the delayed BKOPS work.
> ---
> diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
> index 172a768..ed040d5 100644
> --- a/drivers/mmc/card/block.c
> +++ b/drivers/mmc/card/block.c
> @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
> *mq, struct request *req)
>   from = blk_rq_pos(req);
>   nr = blk_rq_sectors(req);
>
> + if (card->ext_csd.bkops_en)
> + card->bkops_info.sectors_changed += blk_rq_sectors(req);
> +
>   if (mmc_can_discard(card))
>   arg = MMC_DISCARD_ARG;
>   else if (mmc_can_trim(card))
> @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq,
> struct request *rqc)
>   if (!rqc && !mq->mqrq_prev->req)
>   return 0;
>
> + if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
> + card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
> +
>   do {
>   if (rqc) {
>   /*
> diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
> index e360a97..e96f5cf 100644
> --- a/drivers/mmc/card/queue.c
> +++ b/drivers/mmc/card/queue.c
> @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
>  {
>   struct mmc_queue *mq = d;
>   struct request_queue *q = mq->queue;
> + struct mmc_card *card = mq->card;
>
>   current->flags |= PF_MEMALLOC;
>
> @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
>   spin_unlock_irq(q->queue_lock);
>
>  

Re: [PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-08 Thread merez
Hi Chris and all,

According to the eMMC4.5 standard, a host that enables the BKOPS_EN bit
must also check the BKOPS status periodically:
Host shall check the status periodically and start background operations
as needed, so that the device has enough time for its maintenance
operations, to help reduce the latencies during foreground operations. If
the status is at level 3 (critical), some operations may extend beyond
their original timeouts due to maintenance operations which cannot be
delayed anymore. The host should give the device enough time for
background operations to avoid getting to this level in the first place.

As mentioned in the standard quotation above, it is not recommended to
handle only BKOPS of level 3 since it can lead to foreground operations
timeout.

I would appreciate if you could review this change to add the periodic
BKOPS on top of handling BKOPS level 3 that was already mainlined.

Thnaks,
Maya
On Thu, October 4, 2012 3:28 pm, Maya Erez wrote:
 Devices have various maintenance operations need to perform internally.
 In order to reduce latencies during time critical operations like read
 and write, it is better to execute maintenance operations in other
 times - when the host is not being serviced. Such operations are called
 Background operations (BKOPS).
 The device notifies the status of the BKOPS need by updating BKOPS_STATUS
 (EXT_CSD byte [246]).

 According to the standard a host that supports BKOPS shall check the
 status periodically and start background operations as needed, so that
 the device has enough time for its maintenance operations.

 This patch adds support for this periodic check of the BKOPS status.
 Since foreground operations are of higher priority than background
 operations the host will check the need for BKOPS when it is idle,
 and in case of an incoming request the BKOPS operation will be
 interrupted.

 When the mmcqd thread is idle, a delayed work is created to check the
 need for BKOPS. The time to start the delayed work is calculated based
 on the host controller suspend timeout, in case it was set. If not, a
 default time is used.
 If BKOPS are required in level 1, which is non-blocking, there will be
 polling of the card status to wait for the BKOPS completion and prevent
 suspend that will interrupt the BKOPS.
 If the card raised an exception, the need for urgent BKOPS (level 2/3)
 will be checked immediately and if needed, the BKOPS will be performed
 without waiting for the next idle time.

 Signed-off-by: Maya Erez me...@codeaurora.org
 Signed-off-by: Jaehoon Chung jh80.ch...@samsung.com
 ---
 This patch is based on the periodic BKOPS implementation in version 8 of
 support BKOPS feature for eMMC patch.
 The patch was modified to answer the following issues:
 - In order to prevent a race condition between going into suspend and
 starting BKOPS,
   the suspend timeout of the host controller is taking into accound in
 determination of the start time
   of the delayed work
 - Since mmc_start_bkops is called from two contexts now, mmc_claim_host
 was moved to the beginning of the function
 - Also, the check of doing_bkops should be protected when determing if an
 HPI is needed due to the same reason.
 - Starting and canceling the delayed work in each idle caused degradation
 of iozone performance. Therefore,
   the delayed work is not started on each idle. The amount of sectors
 changed (written or discard) from the last
   delayed work is the trigger for starting the delayed BKOPS work.
 ---
 diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
 index 172a768..ed040d5 100644
 --- a/drivers/mmc/card/block.c
 +++ b/drivers/mmc/card/block.c
 @@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue
 *mq, struct request *req)
   from = blk_rq_pos(req);
   nr = blk_rq_sectors(req);

 + if (card-ext_csd.bkops_en)
 + card-bkops_info.sectors_changed += blk_rq_sectors(req);
 +
   if (mmc_can_discard(card))
   arg = MMC_DISCARD_ARG;
   else if (mmc_can_trim(card))
 @@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq,
 struct request *rqc)
   if (!rqc  !mq-mqrq_prev-req)
   return 0;

 + if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))
 + card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
 +
   do {
   if (rqc) {
   /*
 diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
 index e360a97..e96f5cf 100644
 --- a/drivers/mmc/card/queue.c
 +++ b/drivers/mmc/card/queue.c
 @@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
  {
   struct mmc_queue *mq = d;
   struct request_queue *q = mq-queue;
 + struct mmc_card *card = mq-card;

   current-flags |= PF_MEMALLOC;

 @@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
   spin_unlock_irq(q-queue_lock);

   if (req || mq-mqrq_prev-req) {
 + /*
 +

[PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-04 Thread Maya Erez
Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle,
and in case of an incoming request the BKOPS operation will be
interrupted.

When the mmcqd thread is idle, a delayed work is created to check the
need for BKOPS. The time to start the delayed work is calculated based
on the host controller suspend timeout, in case it was set. If not, a
default time is used.
If BKOPS are required in level 1, which is non-blocking, there will be
polling of the card status to wait for the BKOPS completion and prevent
suspend that will interrupt the BKOPS.
If the card raised an exception, the need for urgent BKOPS (level 2/3)
will be checked immediately and if needed, the BKOPS will be performed
without waiting for the next idle time.

Signed-off-by: Maya Erez 
Signed-off-by: Jaehoon Chung 
---
This patch is based on the periodic BKOPS implementation in version 8 of 
"support BKOPS feature for eMMC" patch.
The patch was modified to answer the following issues:
- In order to prevent a race condition between going into suspend and starting 
BKOPS, 
  the suspend timeout of the host controller is taking into accound in 
determination of the start time 
  of the delayed work
- Since mmc_start_bkops is called from two contexts now, mmc_claim_host was 
moved to the beginning of the function
- Also, the check of doing_bkops should be protected when determing if an HPI 
is needed due to the same reason.
- Starting and canceling the delayed work in each idle caused degradation of 
iozone performance. Therefore,
  the delayed work is not started on each idle. The amount of sectors changed 
(written or discard) from the last 
  delayed work is the trigger for starting the delayed BKOPS work.
---
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768..ed040d5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
 
+   if (card->ext_csd.bkops_en)
+   card->bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
struct request *rqc)
if (!rqc && !mq->mqrq_prev->req)
return 0;
 
+   if (rqc && (card->ext_csd.bkops_en) && (rq_data_dir(rqc) == WRITE))
+   card->bkops_info.sectors_changed += blk_rq_sectors(rqc);
+
do {
if (rqc) {
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a97..e96f5cf 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
 {
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
+   struct mmc_card *card = mq->card;
 
current->flags |= PF_MEMALLOC;
 
@@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
spin_unlock_irq(q->queue_lock);
 
if (req || mq->mqrq_prev->req) {
+   /*
+* If this is the first request, BKOPs might be in
+* progress and needs to be stopped before issuing the
+* request
+*/
+   if (card->ext_csd.bkops_en &&
+   card->bkops_info.started_delayed_bkops) {
+   card->bkops_info.started_delayed_bkops = false;
+   mmc_stop_bkops(card);
+   }
+
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
} else {
@@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_RUNNING);
break;
}
+   mmc_start_delayed_bkops(card);
up(>thread_sem);
schedule();
down(>thread_sem);
diff --git a/drivers/mmc/core/core.c 

[PATCH v2] mmc: core: Add support for idle time BKOPS

2012-10-04 Thread Maya Erez
Devices have various maintenance operations need to perform internally.
In order to reduce latencies during time critical operations like read
and write, it is better to execute maintenance operations in other
times - when the host is not being serviced. Such operations are called
Background operations (BKOPS).
The device notifies the status of the BKOPS need by updating BKOPS_STATUS
(EXT_CSD byte [246]).

According to the standard a host that supports BKOPS shall check the
status periodically and start background operations as needed, so that
the device has enough time for its maintenance operations.

This patch adds support for this periodic check of the BKOPS status.
Since foreground operations are of higher priority than background
operations the host will check the need for BKOPS when it is idle,
and in case of an incoming request the BKOPS operation will be
interrupted.

When the mmcqd thread is idle, a delayed work is created to check the
need for BKOPS. The time to start the delayed work is calculated based
on the host controller suspend timeout, in case it was set. If not, a
default time is used.
If BKOPS are required in level 1, which is non-blocking, there will be
polling of the card status to wait for the BKOPS completion and prevent
suspend that will interrupt the BKOPS.
If the card raised an exception, the need for urgent BKOPS (level 2/3)
will be checked immediately and if needed, the BKOPS will be performed
without waiting for the next idle time.

Signed-off-by: Maya Erez me...@codeaurora.org
Signed-off-by: Jaehoon Chung jh80.ch...@samsung.com
---
This patch is based on the periodic BKOPS implementation in version 8 of 
support BKOPS feature for eMMC patch.
The patch was modified to answer the following issues:
- In order to prevent a race condition between going into suspend and starting 
BKOPS, 
  the suspend timeout of the host controller is taking into accound in 
determination of the start time 
  of the delayed work
- Since mmc_start_bkops is called from two contexts now, mmc_claim_host was 
moved to the beginning of the function
- Also, the check of doing_bkops should be protected when determing if an HPI 
is needed due to the same reason.
- Starting and canceling the delayed work in each idle caused degradation of 
iozone performance. Therefore,
  the delayed work is not started on each idle. The amount of sectors changed 
(written or discard) from the last 
  delayed work is the trigger for starting the delayed BKOPS work.
---
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768..ed040d5 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -827,6 +827,9 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, 
struct request *req)
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
 
+   if (card-ext_csd.bkops_en)
+   card-bkops_info.sectors_changed += blk_rq_sectors(req);
+
if (mmc_can_discard(card))
arg = MMC_DISCARD_ARG;
else if (mmc_can_trim(card))
@@ -1268,6 +1271,9 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, 
struct request *rqc)
if (!rqc  !mq-mqrq_prev-req)
return 0;
 
+   if (rqc  (card-ext_csd.bkops_en)  (rq_data_dir(rqc) == WRITE))
+   card-bkops_info.sectors_changed += blk_rq_sectors(rqc);
+
do {
if (rqc) {
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a97..e96f5cf 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -51,6 +51,7 @@ static int mmc_queue_thread(void *d)
 {
struct mmc_queue *mq = d;
struct request_queue *q = mq-queue;
+   struct mmc_card *card = mq-card;
 
current-flags |= PF_MEMALLOC;
 
@@ -66,6 +67,17 @@ static int mmc_queue_thread(void *d)
spin_unlock_irq(q-queue_lock);
 
if (req || mq-mqrq_prev-req) {
+   /*
+* If this is the first request, BKOPs might be in
+* progress and needs to be stopped before issuing the
+* request
+*/
+   if (card-ext_csd.bkops_en 
+   card-bkops_info.started_delayed_bkops) {
+   card-bkops_info.started_delayed_bkops = false;
+   mmc_stop_bkops(card);
+   }
+
set_current_state(TASK_RUNNING);
mq-issue_fn(mq, req);
} else {
@@ -73,6 +85,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_RUNNING);
break;
}
+   mmc_start_delayed_bkops(card);
up(mq-thread_sem);
schedule();
down(mq-thread_sem);
diff --git