]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/card/mmc_test.c
Merge branch 'core/softlockup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-omap-h63xx.git] / drivers / mmc / card / mmc_test.c
index d6b9b486417cc702acb18bba2fd413baedf592d9..a067fe436301d2853bcc50be9f8a7d09d79fbfe0 100644 (file)
 #define RESULT_UNSUP_HOST      2
 #define RESULT_UNSUP_CARD      3
 
-#define BUFFER_SIZE    (PAGE_SIZE * 4)
+#define BUFFER_ORDER           2
+#define BUFFER_SIZE            (PAGE_SIZE << BUFFER_ORDER)
 
 struct mmc_test_card {
        struct mmc_card *card;
 
        u8              scratch[BUFFER_SIZE];
        u8              *buffer;
+#ifdef CONFIG_HIGHMEM
+       struct page     *highmem;
+#endif
 };
 
 /*******************************************************************/
@@ -384,14 +388,16 @@ static int mmc_test_transfer(struct mmc_test_card *test,
        int ret, i;
        unsigned long flags;
 
+       BUG_ON(blocks * blksz > BUFFER_SIZE);
+
        if (write) {
                for (i = 0;i < blocks * blksz;i++)
                        test->scratch[i] = i;
        } else {
-               memset(test->scratch, 0, BUFFER_SIZE);
+               memset(test->scratch, 0, blocks * blksz);
        }
        local_irq_save(flags);
-       sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
+       sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz);
        local_irq_restore(flags);
 
        ret = mmc_test_set_blksize(test, blksz);
@@ -438,7 +444,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
                }
        } else {
                local_irq_save(flags);
-               sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
+               sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz);
                local_irq_restore(flags);
                for (i = 0;i < blocks * blksz;i++) {
                        if (test->scratch[i] != (u8)i)
@@ -799,6 +805,157 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
        return 0;
 }
 
+static int mmc_test_bigsg_write(struct mmc_test_card *test)
+{
+       int ret;
+       unsigned int size;
+       struct scatterlist sg;
+
+       if (test->card->host->max_blk_count == 1)
+               return RESULT_UNSUP_HOST;
+
+       size = PAGE_SIZE * 2;
+       size = min(size, test->card->host->max_req_size);
+       size = min(size, test->card->host->max_seg_size);
+       size = min(size, test->card->host->max_blk_count * 512);
+
+       memset(test->buffer, 0, BUFFER_SIZE);
+
+       if (size < 1024)
+               return RESULT_UNSUP_HOST;
+
+       sg_init_table(&sg, 1);
+       sg_init_one(&sg, test->buffer, BUFFER_SIZE);
+
+       ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mmc_test_bigsg_read(struct mmc_test_card *test)
+{
+       int ret, i;
+       unsigned int size;
+       struct scatterlist sg;
+
+       if (test->card->host->max_blk_count == 1)
+               return RESULT_UNSUP_HOST;
+
+       size = PAGE_SIZE * 2;
+       size = min(size, test->card->host->max_req_size);
+       size = min(size, test->card->host->max_seg_size);
+       size = min(size, test->card->host->max_blk_count * 512);
+
+       if (size < 1024)
+               return RESULT_UNSUP_HOST;
+
+       memset(test->buffer, 0xCD, BUFFER_SIZE);
+
+       sg_init_table(&sg, 1);
+       sg_init_one(&sg, test->buffer, BUFFER_SIZE);
+       ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+       if (ret)
+               return ret;
+
+       /* mmc_test_transfer() doesn't check for read overflows */
+       for (i = size;i < BUFFER_SIZE;i++) {
+               if (test->buffer[i] != 0xCD)
+                       return RESULT_FAIL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_HIGHMEM
+
+static int mmc_test_write_high(struct mmc_test_card *test)
+{
+       int ret;
+       struct scatterlist sg;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, test->highmem, 512, 0);
+
+       ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mmc_test_read_high(struct mmc_test_card *test)
+{
+       int ret;
+       struct scatterlist sg;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, test->highmem, 512, 0);
+
+       ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mmc_test_multi_write_high(struct mmc_test_card *test)
+{
+       int ret;
+       unsigned int size;
+       struct scatterlist sg;
+
+       if (test->card->host->max_blk_count == 1)
+               return RESULT_UNSUP_HOST;
+
+       size = PAGE_SIZE * 2;
+       size = min(size, test->card->host->max_req_size);
+       size = min(size, test->card->host->max_seg_size);
+       size = min(size, test->card->host->max_blk_count * 512);
+
+       if (size < 1024)
+               return RESULT_UNSUP_HOST;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, test->highmem, size, 0);
+
+       ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int mmc_test_multi_read_high(struct mmc_test_card *test)
+{
+       int ret;
+       unsigned int size;
+       struct scatterlist sg;
+
+       if (test->card->host->max_blk_count == 1)
+               return RESULT_UNSUP_HOST;
+
+       size = PAGE_SIZE * 2;
+       size = min(size, test->card->host->max_req_size);
+       size = min(size, test->card->host->max_seg_size);
+       size = min(size, test->card->host->max_blk_count * 512);
+
+       if (size < 1024)
+               return RESULT_UNSUP_HOST;
+
+       sg_init_table(&sg, 1);
+       sg_set_page(&sg, test->highmem, size, 0);
+
+       ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+#endif /* CONFIG_HIGHMEM */
+
 static const struct mmc_test_case mmc_test_cases[] = {
        {
                .name = "Basic write (no data verification)",
@@ -913,6 +1070,53 @@ static const struct mmc_test_case mmc_test_cases[] = {
                .name = "Correct xfer_size at read (midway failure)",
                .run = mmc_test_multi_xfersize_read,
        },
+
+       {
+               .name = "Over-sized SG list write",
+               .prepare = mmc_test_prepare_write,
+               .run = mmc_test_bigsg_write,
+               .cleanup = mmc_test_cleanup,
+       },
+
+       {
+               .name = "Over-sized SG list read",
+               .prepare = mmc_test_prepare_read,
+               .run = mmc_test_bigsg_read,
+               .cleanup = mmc_test_cleanup,
+       },
+
+#ifdef CONFIG_HIGHMEM
+
+       {
+               .name = "Highmem write",
+               .prepare = mmc_test_prepare_write,
+               .run = mmc_test_write_high,
+               .cleanup = mmc_test_cleanup,
+       },
+
+       {
+               .name = "Highmem read",
+               .prepare = mmc_test_prepare_read,
+               .run = mmc_test_read_high,
+               .cleanup = mmc_test_cleanup,
+       },
+
+       {
+               .name = "Multi-block highmem write",
+               .prepare = mmc_test_prepare_write,
+               .run = mmc_test_multi_write_high,
+               .cleanup = mmc_test_cleanup,
+       },
+
+       {
+               .name = "Multi-block highmem read",
+               .prepare = mmc_test_prepare_read,
+               .run = mmc_test_multi_read_high,
+               .cleanup = mmc_test_cleanup,
+       },
+
+#endif /* CONFIG_HIGHMEM */
+
 };
 
 static struct mutex mmc_test_lock;
@@ -1014,12 +1218,23 @@ static ssize_t mmc_test_store(struct device *dev,
        test->card = card;
 
        test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+#ifdef CONFIG_HIGHMEM
+       test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
+#endif
+
+#ifdef CONFIG_HIGHMEM
+       if (test->buffer && test->highmem) {
+#else
        if (test->buffer) {
+#endif
                mutex_lock(&mmc_test_lock);
                mmc_test_run(test, testcase);
                mutex_unlock(&mmc_test_lock);
        }
 
+#ifdef CONFIG_HIGHMEM
+       __free_pages(test->highmem, BUFFER_ORDER);
+#endif
        kfree(test->buffer);
        kfree(test);
 
@@ -1041,6 +1256,8 @@ static int mmc_test_probe(struct mmc_card *card)
        if (ret)
                return ret;
 
+       dev_info(&card->dev, "Card claimed for testing.\n");
+
        return 0;
 }