aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorAndy Shevchenko <andy.shevchenko@gmail.com>2010-09-01 02:26:47 -0400
committerChris Ball <cjb@laptop.org>2010-10-23 09:11:13 -0400
commit3183aa1534de4e98ffb0527d4f2be7ac9f019a4e (patch)
treeb38ce66b22f1b6385ad2387278a259a46a0dccd4 /drivers/mmc
parent5c25aee5364550d7fa6314886370e76cda18d7e2 (diff)
mmc_test: collect data and show it via sysfs by demand
Make it possible to get test results via sysfs. It helps to do tests non-interactively. We have the file created under sysfs already and can use it to show test results. Prior to this patch, the "test" file under each card's sysfs node was write-only, and results were obtained by looking at dmesg. This patch improves programmatic access to the test results, making them available by reading back from the same "test" file: [root@host mmc0:e624]# echo 6 > test [root@host mmc0:e624]# cat test Test 6: 2 [cjb@laptop.org: changelog improvements] Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com> Cc: Chris Ball <cjb@laptop.org> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/card/mmc_test.c171
1 files changed, 169 insertions, 2 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 2888fdccd7ad..0c8b5685d4b7 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -17,6 +17,7 @@
17 17
18#include <linux/scatterlist.h> 18#include <linux/scatterlist.h>
19#include <linux/swap.h> /* For nr_free_buffer_pages() */ 19#include <linux/swap.h> /* For nr_free_buffer_pages() */
20#include <linux/list.h>
20 21
21#define RESULT_OK 0 22#define RESULT_OK 0
22#define RESULT_FAIL 1 23#define RESULT_FAIL 1
@@ -77,12 +78,45 @@ struct mmc_test_area {
77}; 78};
78 79
79/** 80/**
81 * struct mmc_test_transfer_result - transfer results for performance tests.
82 * @link: double-linked list
83 * @count: amount of group of sectors to check
84 * @sectors: amount of sectors to check in one group
85 * @ts: time values of transfer
86 * @rate: calculated transfer rate
87 */
88struct mmc_test_transfer_result {
89 struct list_head link;
90 unsigned int count;
91 unsigned int sectors;
92 struct timespec ts;
93 unsigned int rate;
94};
95
96/**
97 * struct mmc_test_general_result - results for tests.
98 * @link: double-linked list
99 * @card: card under test
100 * @testcase: number of test case
101 * @result: result of test run
102 * @tr_lst: transfer measurements if any as mmc_test_transfer_result
103 */
104struct mmc_test_general_result {
105 struct list_head link;
106 struct mmc_card *card;
107 int testcase;
108 int result;
109 struct list_head tr_lst;
110};
111
112/**
80 * struct mmc_test_card - test information. 113 * struct mmc_test_card - test information.
81 * @card: card under test 114 * @card: card under test
82 * @scratch: transfer buffer 115 * @scratch: transfer buffer
83 * @buffer: transfer buffer 116 * @buffer: transfer buffer
84 * @highmem: buffer for highmem tests 117 * @highmem: buffer for highmem tests
85 * @area: information for performance tests 118 * @area: information for performance tests
119 * @gr: pointer to results of current testcase
86 */ 120 */
87struct mmc_test_card { 121struct mmc_test_card {
88 struct mmc_card *card; 122 struct mmc_card *card;
@@ -92,7 +126,8 @@ struct mmc_test_card {
92#ifdef CONFIG_HIGHMEM 126#ifdef CONFIG_HIGHMEM
93 struct page *highmem; 127 struct page *highmem;
94#endif 128#endif
95 struct mmc_test_area area; 129 struct mmc_test_area area;
130 struct mmc_test_general_result *gr;
96}; 131};
97 132
98/*******************************************************************/ 133/*******************************************************************/
@@ -449,6 +484,30 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
449} 484}
450 485
451/* 486/*
487 * Save transfer results for future usage
488 */
489static void mmc_test_save_transfer_result(struct mmc_test_card *test,
490 unsigned int count, unsigned int sectors, struct timespec ts,
491 unsigned int rate)
492{
493 struct mmc_test_transfer_result *tr;
494
495 if (!test->gr)
496 return;
497
498 tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
499 if (!tr)
500 return;
501
502 tr->count = count;
503 tr->sectors = sectors;
504 tr->ts = ts;
505 tr->rate = rate;
506
507 list_add_tail(&tr->link, &test->gr->tr_lst);
508}
509
510/*
452 * Print the transfer rate. 511 * Print the transfer rate.
453 */ 512 */
454static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, 513static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
@@ -466,6 +525,8 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
466 mmc_hostname(test->card->host), sectors, sectors >> 1, 525 mmc_hostname(test->card->host), sectors, sectors >> 1,
467 (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec, 526 (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
468 (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024); 527 (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
528
529 mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
469} 530}
470 531
471/* 532/*
@@ -489,6 +550,8 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
489 sectors >> 1, (sectors == 1 ? ".5" : ""), 550 sectors >> 1, (sectors == 1 ? ".5" : ""),
490 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, 551 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
491 rate / 1000, rate / 1024); 552 rate / 1000, rate / 1024);
553
554 mmc_test_save_transfer_result(test, count, sectors, ts, rate);
492} 555}
493 556
494/* 557/*
@@ -1940,6 +2003,8 @@ static const struct mmc_test_case mmc_test_cases[] = {
1940 2003
1941static DEFINE_MUTEX(mmc_test_lock); 2004static DEFINE_MUTEX(mmc_test_lock);
1942 2005
2006static LIST_HEAD(mmc_test_result);
2007
1943static void mmc_test_run(struct mmc_test_card *test, int testcase) 2008static void mmc_test_run(struct mmc_test_card *test, int testcase)
1944{ 2009{
1945 int i, ret; 2010 int i, ret;
@@ -1950,6 +2015,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
1950 mmc_claim_host(test->card->host); 2015 mmc_claim_host(test->card->host);
1951 2016
1952 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) { 2017 for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
2018 struct mmc_test_general_result *gr;
2019
1953 if (testcase && ((i + 1) != testcase)) 2020 if (testcase && ((i + 1) != testcase))
1954 continue; 2021 continue;
1955 2022
@@ -1968,6 +2035,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
1968 } 2035 }
1969 } 2036 }
1970 2037
2038 gr = kzalloc(sizeof(struct mmc_test_general_result),
2039 GFP_KERNEL);
2040 if (gr) {
2041 INIT_LIST_HEAD(&gr->tr_lst);
2042
2043 /* Assign data what we know already */
2044 gr->card = test->card;
2045 gr->testcase = i;
2046
2047 /* Append container to global one */
2048 list_add_tail(&gr->link, &mmc_test_result);
2049
2050 /*
2051 * Save the pointer to created container in our private
2052 * structure.
2053 */
2054 test->gr = gr;
2055 }
2056
1971 ret = mmc_test_cases[i].run(test); 2057 ret = mmc_test_cases[i].run(test);
1972 switch (ret) { 2058 switch (ret) {
1973 case RESULT_OK: 2059 case RESULT_OK:
@@ -1993,6 +2079,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
1993 mmc_hostname(test->card->host), ret); 2079 mmc_hostname(test->card->host), ret);
1994 } 2080 }
1995 2081
2082 /* Save the result */
2083 if (gr)
2084 gr->result = ret;
2085
1996 if (mmc_test_cases[i].cleanup) { 2086 if (mmc_test_cases[i].cleanup) {
1997 ret = mmc_test_cases[i].cleanup(test); 2087 ret = mmc_test_cases[i].cleanup(test);
1998 if (ret) { 2088 if (ret) {
@@ -2010,13 +2100,80 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
2010 mmc_hostname(test->card->host)); 2100 mmc_hostname(test->card->host));
2011} 2101}
2012 2102
2103static void mmc_test_free_result(struct mmc_card *card)
2104{
2105 struct mmc_test_general_result *gr, *grs;
2106
2107 mutex_lock(&mmc_test_lock);
2108
2109 list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
2110 struct mmc_test_transfer_result *tr, *trs;
2111
2112 if (card && gr->card != card)
2113 continue;
2114
2115 list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
2116 list_del(&tr->link);
2117 kfree(tr);
2118 }
2119
2120 list_del(&gr->link);
2121 kfree(gr);
2122 }
2123
2124 mutex_unlock(&mmc_test_lock);
2125}
2126
2013static ssize_t mmc_test_show(struct device *dev, 2127static ssize_t mmc_test_show(struct device *dev,
2014 struct device_attribute *attr, char *buf) 2128 struct device_attribute *attr, char *buf)
2015{ 2129{
2130 struct mmc_card *card = mmc_dev_to_card(dev);
2131 struct mmc_test_general_result *gr;
2132 char *p = buf;
2133 size_t len = PAGE_SIZE;
2134 int ret;
2135
2016 mutex_lock(&mmc_test_lock); 2136 mutex_lock(&mmc_test_lock);
2137
2138 list_for_each_entry(gr, &mmc_test_result, link) {
2139 struct mmc_test_transfer_result *tr;
2140
2141 if (gr->card != card)
2142 continue;
2143
2144 ret = snprintf(p, len, "Test %d: %d\n", gr->testcase + 1,
2145 gr->result);
2146 if (ret < 0)
2147 goto err;
2148 if (ret >= len) {
2149 ret = -ENOBUFS;
2150 goto err;
2151 }
2152 p += ret;
2153 len -= ret;
2154
2155 list_for_each_entry(tr, &gr->tr_lst, link) {
2156 ret = snprintf(p, len, "%u %d %lu.%09lu %u\n",
2157 tr->count, tr->sectors,
2158 (unsigned long)tr->ts.tv_sec,
2159 (unsigned long)tr->ts.tv_nsec,
2160 tr->rate);
2161 if (ret < 0)
2162 goto err;
2163 if (ret >= len) {
2164 ret = -ENOBUFS;
2165 goto err;
2166 }
2167 p += ret;
2168 len -= ret;
2169 }
2170 }
2171
2172 ret = PAGE_SIZE - len;
2173err:
2017 mutex_unlock(&mmc_test_lock); 2174 mutex_unlock(&mmc_test_lock);
2018 2175
2019 return 0; 2176 return ret;
2020} 2177}
2021 2178
2022static ssize_t mmc_test_store(struct device *dev, 2179static ssize_t mmc_test_store(struct device *dev,
@@ -2033,6 +2190,12 @@ static ssize_t mmc_test_store(struct device *dev,
2033 if (!test) 2190 if (!test)
2034 return -ENOMEM; 2191 return -ENOMEM;
2035 2192
2193 /*
2194 * Remove all test cases associated with given card. Thus we have only
2195 * actual data of the last run.
2196 */
2197 mmc_test_free_result(card);
2198
2036 test->card = card; 2199 test->card = card;
2037 2200
2038 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL); 2201 test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
@@ -2079,6 +2242,7 @@ static int mmc_test_probe(struct mmc_card *card)
2079 2242
2080static void mmc_test_remove(struct mmc_card *card) 2243static void mmc_test_remove(struct mmc_card *card)
2081{ 2244{
2245 mmc_test_free_result(card);
2082 device_remove_file(&card->dev, &dev_attr_test); 2246 device_remove_file(&card->dev, &dev_attr_test);
2083} 2247}
2084 2248
@@ -2097,6 +2261,9 @@ static int __init mmc_test_init(void)
2097 2261
2098static void __exit mmc_test_exit(void) 2262static void __exit mmc_test_exit(void)
2099{ 2263{
2264 /* Clear stalled data if card is still plugged */
2265 mmc_test_free_result(NULL);
2266
2100 mmc_unregister_driver(&mmc_driver); 2267 mmc_unregister_driver(&mmc_driver);
2101} 2268}
2102 2269