aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/card
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r--drivers/mmc/card/mmc_test.c225
-rw-r--r--drivers/mmc/card/queue.c97
2 files changed, 252 insertions, 70 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index d6b9b486417c..a067fe436301 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -21,13 +21,17 @@
21#define RESULT_UNSUP_HOST 2 21#define RESULT_UNSUP_HOST 2
22#define RESULT_UNSUP_CARD 3 22#define RESULT_UNSUP_CARD 3
23 23
24#define BUFFER_SIZE (PAGE_SIZE * 4) 24#define BUFFER_ORDER 2
25#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
25 26
26struct mmc_test_card { 27struct mmc_test_card {
27 struct mmc_card *card; 28 struct mmc_card *card;
28 29
29 u8 scratch[BUFFER_SIZE]; 30 u8 scratch[BUFFER_SIZE];
30 u8 *buffer; 31 u8 *buffer;
32#ifdef CONFIG_HIGHMEM
33 struct page *highmem;
34#endif
31}; 35};
32 36
33/*******************************************************************/ 37/*******************************************************************/
@@ -384,14 +388,16 @@ static int mmc_test_transfer(struct mmc_test_card *test,
384 int ret, i; 388 int ret, i;
385 unsigned long flags; 389 unsigned long flags;
386 390
391 BUG_ON(blocks * blksz > BUFFER_SIZE);
392
387 if (write) { 393 if (write) {
388 for (i = 0;i < blocks * blksz;i++) 394 for (i = 0;i < blocks * blksz;i++)
389 test->scratch[i] = i; 395 test->scratch[i] = i;
390 } else { 396 } else {
391 memset(test->scratch, 0, BUFFER_SIZE); 397 memset(test->scratch, 0, blocks * blksz);
392 } 398 }
393 local_irq_save(flags); 399 local_irq_save(flags);
394 sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); 400 sg_copy_from_buffer(sg, sg_len, test->scratch, blocks * blksz);
395 local_irq_restore(flags); 401 local_irq_restore(flags);
396 402
397 ret = mmc_test_set_blksize(test, blksz); 403 ret = mmc_test_set_blksize(test, blksz);
@@ -438,7 +444,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
438 } 444 }
439 } else { 445 } else {
440 local_irq_save(flags); 446 local_irq_save(flags);
441 sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE); 447 sg_copy_to_buffer(sg, sg_len, test->scratch, blocks * blksz);
442 local_irq_restore(flags); 448 local_irq_restore(flags);
443 for (i = 0;i < blocks * blksz;i++) { 449 for (i = 0;i < blocks * blksz;i++) {
444 if (test->scratch[i] != (u8)i) 450 if (test->scratch[i] != (u8)i)
@@ -799,6 +805,157 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
799 return 0; 805 return 0;
800} 806}
801 807
808static int mmc_test_bigsg_write(struct mmc_test_card *test)
809{
810 int ret;
811 unsigned int size;
812 struct scatterlist sg;
813
814 if (test->card->host->max_blk_count == 1)
815 return RESULT_UNSUP_HOST;
816
817 size = PAGE_SIZE * 2;
818 size = min(size, test->card->host->max_req_size);
819 size = min(size, test->card->host->max_seg_size);
820 size = min(size, test->card->host->max_blk_count * 512);
821
822 memset(test->buffer, 0, BUFFER_SIZE);
823
824 if (size < 1024)
825 return RESULT_UNSUP_HOST;
826
827 sg_init_table(&sg, 1);
828 sg_init_one(&sg, test->buffer, BUFFER_SIZE);
829
830 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
831 if (ret)
832 return ret;
833
834 return 0;
835}
836
837static int mmc_test_bigsg_read(struct mmc_test_card *test)
838{
839 int ret, i;
840 unsigned int size;
841 struct scatterlist sg;
842
843 if (test->card->host->max_blk_count == 1)
844 return RESULT_UNSUP_HOST;
845
846 size = PAGE_SIZE * 2;
847 size = min(size, test->card->host->max_req_size);
848 size = min(size, test->card->host->max_seg_size);
849 size = min(size, test->card->host->max_blk_count * 512);
850
851 if (size < 1024)
852 return RESULT_UNSUP_HOST;
853
854 memset(test->buffer, 0xCD, BUFFER_SIZE);
855
856 sg_init_table(&sg, 1);
857 sg_init_one(&sg, test->buffer, BUFFER_SIZE);
858 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
859 if (ret)
860 return ret;
861
862 /* mmc_test_transfer() doesn't check for read overflows */
863 for (i = size;i < BUFFER_SIZE;i++) {
864 if (test->buffer[i] != 0xCD)
865 return RESULT_FAIL;
866 }
867
868 return 0;
869}
870
871#ifdef CONFIG_HIGHMEM
872
873static int mmc_test_write_high(struct mmc_test_card *test)
874{
875 int ret;
876 struct scatterlist sg;
877
878 sg_init_table(&sg, 1);
879 sg_set_page(&sg, test->highmem, 512, 0);
880
881 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
882 if (ret)
883 return ret;
884
885 return 0;
886}
887
888static int mmc_test_read_high(struct mmc_test_card *test)
889{
890 int ret;
891 struct scatterlist sg;
892
893 sg_init_table(&sg, 1);
894 sg_set_page(&sg, test->highmem, 512, 0);
895
896 ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
897 if (ret)
898 return ret;
899
900 return 0;
901}
902
903static int mmc_test_multi_write_high(struct mmc_test_card *test)
904{
905 int ret;
906 unsigned int size;
907 struct scatterlist sg;
908
909 if (test->card->host->max_blk_count == 1)
910 return RESULT_UNSUP_HOST;
911
912 size = PAGE_SIZE * 2;
913 size = min(size, test->card->host->max_req_size);
914 size = min(size, test->card->host->max_seg_size);
915 size = min(size, test->card->host->max_blk_count * 512);
916
917 if (size < 1024)
918 return RESULT_UNSUP_HOST;
919
920 sg_init_table(&sg, 1);
921 sg_set_page(&sg, test->highmem, size, 0);
922
923 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
924 if (ret)
925 return ret;
926
927 return 0;
928}
929
930static int mmc_test_multi_read_high(struct mmc_test_card *test)
931{
932 int ret;
933 unsigned int size;
934 struct scatterlist sg;
935
936 if (test->card->host->max_blk_count == 1)
937 return RESULT_UNSUP_HOST;
938
939 size = PAGE_SIZE * 2;
940 size = min(size, test->card->host->max_req_size);
941 size = min(size, test->card->host->max_seg_size);
942 size = min(size, test->card->host->max_blk_count * 512);
943
944 if (size < 1024)
945 return RESULT_UNSUP_HOST;
946
947 sg_init_table(&sg, 1);
948 sg_set_page(&sg, test->highmem, size, 0);
949
950 ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
951 if (ret)
952 return ret;
953
954 return 0;
955}
956
957#endif /* CONFIG_HIGHMEM */
958
802static const struct mmc_test_case mmc_test_cases[] = { 959static const struct mmc_test_case mmc_test_cases[] = {
803 { 960 {
804 .name = "Basic write (no data verification)", 961 .name = "Basic write (no data verification)",
@@ -913,6 +1070,53 @@ static const struct mmc_test_case mmc_test_cases[] = {
913 .name = "Correct xfer_size at read (midway failure)", 1070 .name = "Correct xfer_size at read (midway failure)",
914 .run = mmc_test_multi_xfersize_read, 1071 .run = mmc_test_multi_xfersize_read,
915 }, 1072 },
1073
1074 {
1075 .name = "Over-sized SG list write",
1076 .prepare = mmc_test_prepare_write,
1077 .run = mmc_test_bigsg_write,
1078 .cleanup = mmc_test_cleanup,
1079 },
1080
1081 {
1082 .name = "Over-sized SG list read",
1083 .prepare = mmc_test_prepare_read,
1084 .run = mmc_test_bigsg_read,
1085 .cleanup = mmc_test_cleanup,
1086 },
1087
1088#ifdef CONFIG_HIGHMEM
1089
1090 {
1091 .name = "Highmem write",
1092 .prepare = mmc_test_prepare_write,
1093 .run = mmc_test_write_high,
1094 .cleanup = mmc_test_cleanup,
1095 },
1096
1097 {
1098 .name = "Highmem read",
1099 .prepare = mmc_test_prepare_read,
1100 .run = mmc_test_read_high,
1101 .cleanup = mmc_test_cleanup,
1102 },
1103
1104 {
1105 .name = "Multi-block highmem write",
1106 .prepare = mmc_test_prepare_write,
1107 .run = mmc_test_multi_write_high,
1108 .cleanup = mmc_test_cleanup,
1109 },
1110
1111 {
1112 .name = "Multi-block highmem read",
1113 .prepare = mmc_test_prepare_read,
1114 .run = mmc_test_multi_read_high,
1115 .cleanup = mmc_test_cleanup,
1116 },
1117
1118#endif /* CONFIG_HIGHMEM */
1119
916}; 1120};
917 1121
918static struct mutex mmc_test_lock; 1122static struct mutex mmc_test_lock;
@@ -1014,12 +1218,23 @@ static ssize_t mmc_test_store(struct device *dev,
1014 test->card = card; 1218 test->card = card;
1015 1219
1016 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); 1220 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
1221#ifdef CONFIG_HIGHMEM
1222 test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
1223#endif
1224
1225#ifdef CONFIG_HIGHMEM
1226 if (test->buffer && test->highmem) {
1227#else
1017 if (test->buffer) { 1228 if (test->buffer) {
1229#endif
1018 mutex_lock(&mmc_test_lock); 1230 mutex_lock(&mmc_test_lock);
1019 mmc_test_run(test, testcase); 1231 mmc_test_run(test, testcase);
1020 mutex_unlock(&mmc_test_lock); 1232 mutex_unlock(&mmc_test_lock);
1021 } 1233 }
1022 1234
1235#ifdef CONFIG_HIGHMEM
1236 __free_pages(test->highmem, BUFFER_ORDER);
1237#endif
1023 kfree(test->buffer); 1238 kfree(test->buffer);
1024 kfree(test); 1239 kfree(test);
1025 1240
@@ -1041,6 +1256,8 @@ static int mmc_test_probe(struct mmc_card *card)
1041 if (ret) 1256 if (ret)
1042 return ret; 1257 return ret;
1043 1258
1259 dev_info(&card->dev, "Card claimed for testing.\n");
1260
1044 return 0; 1261 return 0;
1045} 1262}
1046 1263
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 7731ddefdc1b..3dee97e7d165 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -148,7 +148,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
148 printk(KERN_WARNING "%s: unable to allocate " 148 printk(KERN_WARNING "%s: unable to allocate "
149 "bounce buffer\n", mmc_card_name(card)); 149 "bounce buffer\n", mmc_card_name(card));
150 } else { 150 } else {
151 blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); 151 blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
152 blk_queue_max_sectors(mq->queue, bouncesz / 512); 152 blk_queue_max_sectors(mq->queue, bouncesz / 512);
153 blk_queue_max_phys_segments(mq->queue, bouncesz / 512); 153 blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
154 blk_queue_max_hw_segments(mq->queue, bouncesz / 512); 154 blk_queue_max_hw_segments(mq->queue, bouncesz / 512);
@@ -290,55 +290,15 @@ void mmc_queue_resume(struct mmc_queue *mq)
290 } 290 }
291} 291}
292 292
293static void copy_sg(struct scatterlist *dst, unsigned int dst_len, 293/*
294 struct scatterlist *src, unsigned int src_len) 294 * Prepare the sg list(s) to be handed of to the host driver
295{ 295 */
296 unsigned int chunk;
297 char *dst_buf, *src_buf;
298 unsigned int dst_size, src_size;
299
300 dst_buf = NULL;
301 src_buf = NULL;
302 dst_size = 0;
303 src_size = 0;
304
305 while (src_len) {
306 BUG_ON(dst_len == 0);
307
308 if (dst_size == 0) {
309 dst_buf = sg_virt(dst);
310 dst_size = dst->length;
311 }
312
313 if (src_size == 0) {
314 src_buf = sg_virt(src);
315 src_size = src->length;
316 }
317
318 chunk = min(dst_size, src_size);
319
320 memcpy(dst_buf, src_buf, chunk);
321
322 dst_buf += chunk;
323 src_buf += chunk;
324 dst_size -= chunk;
325 src_size -= chunk;
326
327 if (dst_size == 0) {
328 dst++;
329 dst_len--;
330 }
331
332 if (src_size == 0) {
333 src++;
334 src_len--;
335 }
336 }
337}
338
339unsigned int mmc_queue_map_sg(struct mmc_queue *mq) 296unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
340{ 297{
341 unsigned int sg_len; 298 unsigned int sg_len;
299 size_t buflen;
300 struct scatterlist *sg;
301 int i;
342 302
343 if (!mq->bounce_buf) 303 if (!mq->bounce_buf)
344 return blk_rq_map_sg(mq->queue, mq->req, mq->sg); 304 return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
@@ -349,47 +309,52 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
349 309
350 mq->bounce_sg_len = sg_len; 310 mq->bounce_sg_len = sg_len;
351 311
352 /* 312 buflen = 0;
353 * Shortcut in the event we only get a single entry. 313 for_each_sg(mq->bounce_sg, sg, sg_len, i)
354 */ 314 buflen += sg->length;
355 if (sg_len == 1) {
356 memcpy(mq->sg, mq->bounce_sg, sizeof(struct scatterlist));
357 return 1;
358 }
359 315
360 sg_init_one(mq->sg, mq->bounce_buf, 0); 316 sg_init_one(mq->sg, mq->bounce_buf, buflen);
361
362 while (sg_len) {
363 mq->sg[0].length += mq->bounce_sg[sg_len - 1].length;
364 sg_len--;
365 }
366 317
367 return 1; 318 return 1;
368} 319}
369 320
321/*
322 * If writing, bounce the data to the buffer before the request
323 * is sent to the host driver
324 */
370void mmc_queue_bounce_pre(struct mmc_queue *mq) 325void mmc_queue_bounce_pre(struct mmc_queue *mq)
371{ 326{
327 unsigned long flags;
328
372 if (!mq->bounce_buf) 329 if (!mq->bounce_buf)
373 return; 330 return;
374 331
375 if (mq->bounce_sg_len == 1)
376 return;
377 if (rq_data_dir(mq->req) != WRITE) 332 if (rq_data_dir(mq->req) != WRITE)
378 return; 333 return;
379 334
380 copy_sg(mq->sg, 1, mq->bounce_sg, mq->bounce_sg_len); 335 local_irq_save(flags);
336 sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
337 mq->bounce_buf, mq->sg[0].length);
338 local_irq_restore(flags);
381} 339}
382 340
341/*
342 * If reading, bounce the data from the buffer after the request
343 * has been handled by the host driver
344 */
383void mmc_queue_bounce_post(struct mmc_queue *mq) 345void mmc_queue_bounce_post(struct mmc_queue *mq)
384{ 346{
347 unsigned long flags;
348
385 if (!mq->bounce_buf) 349 if (!mq->bounce_buf)
386 return; 350 return;
387 351
388 if (mq->bounce_sg_len == 1)
389 return;
390 if (rq_data_dir(mq->req) != READ) 352 if (rq_data_dir(mq->req) != READ)
391 return; 353 return;
392 354
393 copy_sg(mq->bounce_sg, mq->bounce_sg_len, mq->sg, 1); 355 local_irq_save(flags);
356 sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
357 mq->bounce_buf, mq->sg[0].length);
358 local_irq_restore(flags);
394} 359}
395 360