Merge branch 'stable/drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
[pandora-kernel.git] / drivers / mmc / card / queue.c
index c07322c..45fb362 100644 (file)
@@ -52,14 +52,18 @@ static int mmc_queue_thread(void *d)
        down(&mq->thread_sem);
        do {
                struct request *req = NULL;
+               struct mmc_queue_req *tmp;
 
                spin_lock_irq(q->queue_lock);
                set_current_state(TASK_INTERRUPTIBLE);
                req = blk_fetch_request(q);
-               mq->req = req;
+               mq->mqrq_cur->req = req;
                spin_unlock_irq(q->queue_lock);
 
-               if (!req) {
+               if (req || mq->mqrq_prev->req) {
+                       set_current_state(TASK_RUNNING);
+                       mq->issue_fn(mq, req);
+               } else {
                        if (kthread_should_stop()) {
                                set_current_state(TASK_RUNNING);
                                break;
@@ -67,11 +71,14 @@ static int mmc_queue_thread(void *d)
                        up(&mq->thread_sem);
                        schedule();
                        down(&mq->thread_sem);
-                       continue;
                }
-               set_current_state(TASK_RUNNING);
 
-               mq->issue_fn(mq, req);
+               /* Current request becomes previous request and vice versa. */
+               mq->mqrq_prev->brq.mrq.data = NULL;
+               mq->mqrq_prev->req = NULL;
+               tmp = mq->mqrq_prev;
+               mq->mqrq_prev = mq->mqrq_cur;
+               mq->mqrq_cur = tmp;
        } while (1);
        up(&mq->thread_sem);
 
@@ -97,23 +104,63 @@ static void mmc_request(struct request_queue *q)
                return;
        }
 
-       if (!mq->req)
+       if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
                wake_up_process(mq->thread);
 }
 
+struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
+{
+       struct scatterlist *sg;
+
+       sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
+       if (!sg)
+               *err = -ENOMEM;
+       else {
+               *err = 0;
+               sg_init_table(sg, sg_len);
+       }
+
+       return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+                                   struct mmc_card *card)
+{
+       unsigned max_discard;
+
+       max_discard = mmc_calc_max_discard(card);
+       if (!max_discard)
+               return;
+
+       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+       q->limits.max_discard_sectors = max_discard;
+       if (card->erased_byte == 0)
+               q->limits.discard_zeroes_data = 1;
+       q->limits.discard_granularity = card->pref_erase << 9;
+       /* granularity must not be greater than max. discard */
+       if (card->pref_erase > max_discard)
+               q->limits.discard_granularity = 0;
+       if (mmc_can_secure_erase_trim(card))
+               queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
+}
+
 /**
  * mmc_init_queue - initialise a queue structure.
  * @mq: mmc queue
  * @card: mmc card to attach this queue
  * @lock: queue lock
+ * @subname: partition subname
  *
  * Initialise a MMC card request queue.
  */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+                  spinlock_t *lock, const char *subname)
 {
        struct mmc_host *host = card->host;
        u64 limit = BLK_BOUNCE_HIGH;
        int ret;
+       struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
+       struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
        if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
                limit = *mmc_dev(host)->dma_mask;
@@ -123,26 +170,16 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        if (!mq->queue)
                return -ENOMEM;
 
+       memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
+       memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
+       mq->mqrq_cur = mqrq_cur;
+       mq->mqrq_prev = mqrq_prev;
        mq->queue->queuedata = mq;
-       mq->req = NULL;
 
        blk_queue_prep_rq(mq->queue, mmc_prep_request);
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
-       if (mmc_can_erase(card)) {
-               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
-               mq->queue->limits.max_discard_sectors = UINT_MAX;
-               if (card->erased_byte == 0)
-                       mq->queue->limits.discard_zeroes_data = 1;
-               if (!mmc_can_trim(card) && is_power_of_2(card->erase_size)) {
-                       mq->queue->limits.discard_granularity =
-                                                       card->erase_size << 9;
-                       mq->queue->limits.discard_alignment =
-                                                       card->erase_size << 9;
-               }
-               if (mmc_can_secure_erase_trim(card))
-                       queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
-                                               mq->queue);
-       }
+       if (mmc_can_erase(card))
+               mmc_queue_setup_discard(mq->queue, card);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
        if (host->max_segs == 1) {
@@ -158,59 +195,70 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                        bouncesz = host->max_blk_count * 512;
 
                if (bouncesz > 512) {
-                       mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-                       if (!mq->bounce_buf) {
+                       mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+                       if (!mqrq_cur->bounce_buf) {
+                               printk(KERN_WARNING "%s: unable to "
+                                       "allocate bounce cur buffer\n",
+                                       mmc_card_name(card));
+                       }
+                       mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+                       if (!mqrq_prev->bounce_buf) {
                                printk(KERN_WARNING "%s: unable to "
-                                       "allocate bounce buffer\n",
+                                       "allocate bounce prev buffer\n",
                                        mmc_card_name(card));
+                               kfree(mqrq_cur->bounce_buf);
+                               mqrq_cur->bounce_buf = NULL;
                        }
                }
 
-               if (mq->bounce_buf) {
+               if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
                        blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
                        blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
                        blk_queue_max_segments(mq->queue, bouncesz / 512);
                        blk_queue_max_segment_size(mq->queue, bouncesz);
 
-                       mq->sg = kmalloc(sizeof(struct scatterlist),
-                               GFP_KERNEL);
-                       if (!mq->sg) {
-                               ret = -ENOMEM;
+                       mqrq_cur->sg = mmc_alloc_sg(1, &ret);
+                       if (ret)
                                goto cleanup_queue;
-                       }
-                       sg_init_table(mq->sg, 1);
 
-                       mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
-                               bouncesz / 512, GFP_KERNEL);
-                       if (!mq->bounce_sg) {
-                               ret = -ENOMEM;
+                       mqrq_cur->bounce_sg =
+                               mmc_alloc_sg(bouncesz / 512, &ret);
+                       if (ret)
+                               goto cleanup_queue;
+
+                       mqrq_prev->sg = mmc_alloc_sg(1, &ret);
+                       if (ret)
+                               goto cleanup_queue;
+
+                       mqrq_prev->bounce_sg =
+                               mmc_alloc_sg(bouncesz / 512, &ret);
+                       if (ret)
                                goto cleanup_queue;
-                       }
-                       sg_init_table(mq->bounce_sg, bouncesz / 512);
                }
        }
 #endif
 
-       if (!mq->bounce_buf) {
+       if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
                blk_queue_bounce_limit(mq->queue, limit);
                blk_queue_max_hw_sectors(mq->queue,
                        min(host->max_blk_count, host->max_req_size / 512));
                blk_queue_max_segments(mq->queue, host->max_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
-               mq->sg = kmalloc(sizeof(struct scatterlist) *
-                       host->max_segs, GFP_KERNEL);
-               if (!mq->sg) {
-                       ret = -ENOMEM;
+               mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
+               if (ret)
+                       goto cleanup_queue;
+
+
+               mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
+               if (ret)
                        goto cleanup_queue;
-               }
-               sg_init_table(mq->sg, host->max_segs);
        }
 
        sema_init(&mq->thread_sem, 1);
 
-       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d",
-               host->index);
+       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
+               host->index, subname ? subname : "");
 
        if (IS_ERR(mq->thread)) {
                ret = PTR_ERR(mq->thread);
@@ -219,16 +267,22 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
        return 0;
  free_bounce_sg:
-       if (mq->bounce_sg)
-               kfree(mq->bounce_sg);
-       mq->bounce_sg = NULL;
+       kfree(mqrq_cur->bounce_sg);
+       mqrq_cur->bounce_sg = NULL;
+       kfree(mqrq_prev->bounce_sg);
+       mqrq_prev->bounce_sg = NULL;
+
  cleanup_queue:
-       if (mq->sg)
-               kfree(mq->sg);
-       mq->sg = NULL;
-       if (mq->bounce_buf)
-               kfree(mq->bounce_buf);
-       mq->bounce_buf = NULL;
+       kfree(mqrq_cur->sg);
+       mqrq_cur->sg = NULL;
+       kfree(mqrq_cur->bounce_buf);
+       mqrq_cur->bounce_buf = NULL;
+
+       kfree(mqrq_prev->sg);
+       mqrq_prev->sg = NULL;
+       kfree(mqrq_prev->bounce_buf);
+       mqrq_prev->bounce_buf = NULL;
+
        blk_cleanup_queue(mq->queue);
        return ret;
 }
@@ -237,6 +291,8 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
 {
        struct request_queue *q = mq->queue;
        unsigned long flags;
+       struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
+       struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
 
        /* Make sure the queue isn't suspended, as that will deadlock */
        mmc_queue_resume(mq);
@@ -250,16 +306,23 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
        blk_start_queue(q);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
-       if (mq->bounce_sg)
-               kfree(mq->bounce_sg);
-       mq->bounce_sg = NULL;
+       kfree(mqrq_cur->bounce_sg);
+       mqrq_cur->bounce_sg = NULL;
 
-       kfree(mq->sg);
-       mq->sg = NULL;
+       kfree(mqrq_cur->sg);
+       mqrq_cur->sg = NULL;
 
-       if (mq->bounce_buf)
-               kfree(mq->bounce_buf);
-       mq->bounce_buf = NULL;
+       kfree(mqrq_cur->bounce_buf);
+       mqrq_cur->bounce_buf = NULL;
+
+       kfree(mqrq_prev->bounce_sg);
+       mqrq_prev->bounce_sg = NULL;
+
+       kfree(mqrq_prev->sg);
+       mqrq_prev->sg = NULL;
+
+       kfree(mqrq_prev->bounce_buf);
+       mqrq_prev->bounce_buf = NULL;
 
        mq->card = NULL;
 }
@@ -312,27 +375,27 @@ void mmc_queue_resume(struct mmc_queue *mq)
 /*
  * Prepare the sg list(s) to be handed of to the host driver
  */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
 {
        unsigned int sg_len;
        size_t buflen;
        struct scatterlist *sg;
        int i;
 
-       if (!mq->bounce_buf)
-               return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
+       if (!mqrq->bounce_buf)
+               return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
 
-       BUG_ON(!mq->bounce_sg);
+       BUG_ON(!mqrq->bounce_sg);
 
-       sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
+       sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
 
-       mq->bounce_sg_len = sg_len;
+       mqrq->bounce_sg_len = sg_len;
 
        buflen = 0;
-       for_each_sg(mq->bounce_sg, sg, sg_len, i)
+       for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
                buflen += sg->length;
 
-       sg_init_one(mq->sg, mq->bounce_buf, buflen);
+       sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
 
        return 1;
 }
@@ -341,31 +404,30 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
  * If writing, bounce the data to the buffer before the request
  * is sent to the host driver
  */
-void mmc_queue_bounce_pre(struct mmc_queue *mq)
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
 {
-       if (!mq->bounce_buf)
+       if (!mqrq->bounce_buf)
                return;
 
-       if (rq_data_dir(mq->req) != WRITE)
+       if (rq_data_dir(mqrq->req) != WRITE)
                return;
 
-       sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
-               mq->bounce_buf, mq->sg[0].length);
+       sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+               mqrq->bounce_buf, mqrq->sg[0].length);
 }
 
 /*
  * If reading, bounce the data from the buffer after the request
  * has been handled by the host driver
  */
-void mmc_queue_bounce_post(struct mmc_queue *mq)
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
 {
-       if (!mq->bounce_buf)
+       if (!mqrq->bounce_buf)
                return;
 
-       if (rq_data_dir(mq->req) != READ)
+       if (rq_data_dir(mqrq->req) != READ)
                return;
 
-       sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
-               mq->bounce_buf, mq->sg[0].length);
+       sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+               mqrq->bounce_buf, mqrq->sg[0].length);
 }
-