diff options
| author | Pierre Ossman <drzeus@drzeus.cx> | 2008-07-04 12:17:13 -0400 |
|---|---|---|
| committer | Pierre Ossman <drzeus@drzeus.cx> | 2008-07-23 08:42:08 -0400 |
| commit | 2661081f5ab9cb25359d27f88707a018cf4e68e9 (patch) | |
| tree | 5bbdd138b1432a76de4328bbd718aa6253c76928 | |
| parent | 907b2cd6dbbdfd6a4be7908f57b1498dfabc880e (diff) | |
mmc_test: highmem tests
Add a couple of tests to make sure the host driver handles highmem
memory pages properly. Unfortunately there is no way to guarantee an
allocation below 4 GB in i386, so it might give you addresses that
are out of reach for the hardware (OTOH, so will any other highmem
allocation in the kernel).
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 138 |
1 files changed, 137 insertions, 1 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index d6b9b486417c..6fc13d4c634a 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 | ||
| 26 | struct mmc_test_card { | 27 | struct 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 | /*******************************************************************/ |
| @@ -799,6 +803,94 @@ static int mmc_test_multi_xfersize_read(struct mmc_test_card *test) | |||
| 799 | return 0; | 803 | return 0; |
| 800 | } | 804 | } |
| 801 | 805 | ||
| 806 | #ifdef CONFIG_HIGHMEM | ||
| 807 | |||
| 808 | static int mmc_test_write_high(struct mmc_test_card *test) | ||
| 809 | { | ||
| 810 | int ret; | ||
| 811 | struct scatterlist sg; | ||
| 812 | |||
| 813 | sg_init_table(&sg, 1); | ||
| 814 | sg_set_page(&sg, test->highmem, 512, 0); | ||
| 815 | |||
| 816 | ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1); | ||
| 817 | if (ret) | ||
| 818 | return ret; | ||
| 819 | |||
| 820 | return 0; | ||
| 821 | } | ||
| 822 | |||
| 823 | static int mmc_test_read_high(struct mmc_test_card *test) | ||
| 824 | { | ||
| 825 | int ret; | ||
| 826 | struct scatterlist sg; | ||
| 827 | |||
| 828 | sg_init_table(&sg, 1); | ||
| 829 | sg_set_page(&sg, test->highmem, 512, 0); | ||
| 830 | |||
| 831 | ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0); | ||
| 832 | if (ret) | ||
| 833 | return ret; | ||
| 834 | |||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | |||
| 838 | static int mmc_test_multi_write_high(struct mmc_test_card *test) | ||
| 839 | { | ||
| 840 | int ret; | ||
| 841 | unsigned int size; | ||
| 842 | struct scatterlist sg; | ||
| 843 | |||
| 844 | if (test->card->host->max_blk_count == 1) | ||
| 845 | return RESULT_UNSUP_HOST; | ||
| 846 | |||
| 847 | size = PAGE_SIZE * 2; | ||
| 848 | size = min(size, test->card->host->max_req_size); | ||
| 849 | size = min(size, test->card->host->max_seg_size); | ||
| 850 | size = min(size, test->card->host->max_blk_count * 512); | ||
| 851 | |||
| 852 | if (size < 1024) | ||
| 853 | return RESULT_UNSUP_HOST; | ||
| 854 | |||
| 855 | sg_init_table(&sg, 1); | ||
| 856 | sg_set_page(&sg, test->highmem, size, 0); | ||
| 857 | |||
| 858 | ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1); | ||
| 859 | if (ret) | ||
| 860 | return ret; | ||
| 861 | |||
| 862 | return 0; | ||
| 863 | } | ||
| 864 | |||
| 865 | static int mmc_test_multi_read_high(struct mmc_test_card *test) | ||
| 866 | { | ||
| 867 | int ret; | ||
| 868 | unsigned int size; | ||
| 869 | struct scatterlist sg; | ||
| 870 | |||
| 871 | if (test->card->host->max_blk_count == 1) | ||
| 872 | return RESULT_UNSUP_HOST; | ||
| 873 | |||
| 874 | size = PAGE_SIZE * 2; | ||
| 875 | size = min(size, test->card->host->max_req_size); | ||
| 876 | size = min(size, test->card->host->max_seg_size); | ||
| 877 | size = min(size, test->card->host->max_blk_count * 512); | ||
| 878 | |||
| 879 | if (size < 1024) | ||
| 880 | return RESULT_UNSUP_HOST; | ||
| 881 | |||
| 882 | sg_init_table(&sg, 1); | ||
| 883 | sg_set_page(&sg, test->highmem, size, 0); | ||
| 884 | |||
| 885 | ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0); | ||
| 886 | if (ret) | ||
| 887 | return ret; | ||
| 888 | |||
| 889 | return 0; | ||
| 890 | } | ||
| 891 | |||
| 892 | #endif /* CONFIG_HIGHMEM */ | ||
| 893 | |||
| 802 | static const struct mmc_test_case mmc_test_cases[] = { | 894 | static const struct mmc_test_case mmc_test_cases[] = { |
| 803 | { | 895 | { |
| 804 | .name = "Basic write (no data verification)", | 896 | .name = "Basic write (no data verification)", |
| @@ -913,6 +1005,39 @@ static const struct mmc_test_case mmc_test_cases[] = { | |||
| 913 | .name = "Correct xfer_size at read (midway failure)", | 1005 | .name = "Correct xfer_size at read (midway failure)", |
| 914 | .run = mmc_test_multi_xfersize_read, | 1006 | .run = mmc_test_multi_xfersize_read, |
| 915 | }, | 1007 | }, |
| 1008 | |||
| 1009 | #ifdef CONFIG_HIGHMEM | ||
| 1010 | |||
| 1011 | { | ||
| 1012 | .name = "Highmem write", | ||
| 1013 | .prepare = mmc_test_prepare_write, | ||
| 1014 | .run = mmc_test_write_high, | ||
| 1015 | .cleanup = mmc_test_cleanup, | ||
| 1016 | }, | ||
| 1017 | |||
| 1018 | { | ||
| 1019 | .name = "Highmem read", | ||
| 1020 | .prepare = mmc_test_prepare_read, | ||
| 1021 | .run = mmc_test_read_high, | ||
| 1022 | .cleanup = mmc_test_cleanup, | ||
| 1023 | }, | ||
| 1024 | |||
| 1025 | { | ||
| 1026 | .name = "Multi-block highmem write", | ||
| 1027 | .prepare = mmc_test_prepare_write, | ||
| 1028 | .run = mmc_test_multi_write_high, | ||
| 1029 | .cleanup = mmc_test_cleanup, | ||
| 1030 | }, | ||
| 1031 | |||
| 1032 | { | ||
| 1033 | .name = "Multi-block highmem read", | ||
| 1034 | .prepare = mmc_test_prepare_read, | ||
| 1035 | .run = mmc_test_multi_read_high, | ||
| 1036 | .cleanup = mmc_test_cleanup, | ||
| 1037 | }, | ||
| 1038 | |||
| 1039 | #endif /* CONFIG_HIGHMEM */ | ||
| 1040 | |||
| 916 | }; | 1041 | }; |
| 917 | 1042 | ||
| 918 | static struct mutex mmc_test_lock; | 1043 | static struct mutex mmc_test_lock; |
| @@ -1014,12 +1139,23 @@ static ssize_t mmc_test_store(struct device *dev, | |||
| 1014 | test->card = card; | 1139 | test->card = card; |
| 1015 | 1140 | ||
| 1016 | test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); | 1141 | test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); |
| 1142 | #ifdef CONFIG_HIGHMEM | ||
| 1143 | test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER); | ||
| 1144 | #endif | ||
| 1145 | |||
| 1146 | #ifdef CONFIG_HIGHMEM | ||
| 1147 | if (test->buffer && test->highmem) { | ||
| 1148 | #else | ||
| 1017 | if (test->buffer) { | 1149 | if (test->buffer) { |
| 1150 | #endif | ||
| 1018 | mutex_lock(&mmc_test_lock); | 1151 | mutex_lock(&mmc_test_lock); |
| 1019 | mmc_test_run(test, testcase); | 1152 | mmc_test_run(test, testcase); |
| 1020 | mutex_unlock(&mmc_test_lock); | 1153 | mutex_unlock(&mmc_test_lock); |
| 1021 | } | 1154 | } |
| 1022 | 1155 | ||
| 1156 | #ifdef CONFIG_HIGHMEM | ||
| 1157 | __free_pages(test->highmem, BUFFER_ORDER); | ||
| 1158 | #endif | ||
| 1023 | kfree(test->buffer); | 1159 | kfree(test->buffer); |
| 1024 | kfree(test); | 1160 | kfree(test); |
| 1025 | 1161 | ||
