Signed-off-by: Andy Shevchenko <[email protected]>
---
 drivers/mmc/card/mmc_test.c |  116 ++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 114 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 5423ac9..3cfef37 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -16,6 +16,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/swap.h>
+#include <linux/list.h>
 
 #define RESULT_OK              0
 #define RESULT_FAIL            1
@@ -66,6 +67,28 @@ struct mmc_test_area {
 };
 
 /**
+ * struct mmc_test_transfer_result - container of the transfer results for
+ * performance tests.
+ */
+struct mmc_test_transfer_result {
+       struct list_head link;
+       unsigned int count;
+       unsigned int sectors;
+       struct timespec ts;
+       unsigned int rate;
+};
+
+/**
+ * struct mmc_test_general_result - container of the results for tests.
+ */
+struct mmc_test_general_result {
+       struct list_head link;
+       int testcase;
+       int result;
+       struct list_head transfer;
+};
+
+/**
  * struct mmc_test_card - test information.
  * @card: card under test
  * @scratch: transfer buffer
@@ -81,7 +104,8 @@ struct mmc_test_card {
 #ifdef CONFIG_HIGHMEM
        struct page     *highmem;
 #endif
-       struct mmc_test_area area;
+       struct mmc_test_area    area;
+       struct list_head        *result;
 };
 
 /*******************************************************************/
@@ -420,6 +444,10 @@ static void mmc_test_print_rate(struct mmc_test_card 
*test, uint64_t bytes,
 {
        unsigned int rate, sectors = bytes >> 9;
        struct timespec ts;
+       struct mmc_test_transfer_result *transfer;
+       struct mmc_test_general_result *result =
+               list_entry(test->result->prev, struct mmc_test_general_result,
+                       link);
 
        ts = timespec_sub(*ts2, *ts1);
 
@@ -430,6 +458,15 @@ static void mmc_test_print_rate(struct mmc_test_card 
*test, uint64_t bytes,
                         mmc_hostname(test->card->host), sectors, sectors >> 1,
                         (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
                         (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+
+       transfer = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+
+       transfer->count = 0;
+       transfer->sectors = sectors;
+       memcpy(&transfer->ts, &ts, sizeof(struct timespec));
+       transfer->rate = rate;
+
+       list_add_tail(&transfer->link, &result->transfer);
 }
 
 /*
@@ -442,6 +479,10 @@ static void mmc_test_print_avg_rate(struct mmc_test_card 
*test, uint64_t bytes,
        unsigned int rate, sectors = bytes >> 9;
        uint64_t tot = bytes * count;
        struct timespec ts;
+       struct mmc_test_transfer_result *transfer;
+       struct mmc_test_general_result *result =
+               list_entry(test->result->prev, struct mmc_test_general_result,
+                       link);
 
        ts = timespec_sub(*ts2, *ts1);
 
@@ -453,6 +494,15 @@ static void mmc_test_print_avg_rate(struct mmc_test_card 
*test, uint64_t bytes,
                         sectors >> 1, (sectors == 1 ? ".5" : ""),
                         (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
                         rate / 1000, rate / 1024);
+
+       transfer = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+
+       transfer->count = count;
+       transfer->sectors = sectors;
+       memcpy(&transfer->ts, &ts, sizeof(struct timespec));
+       transfer->rate = rate;
+
+       list_add_tail(&transfer->link, &result->transfer);
 }
 
 /*
@@ -1847,6 +1897,8 @@ static void mmc_test_run(struct mmc_test_card *test, long 
testcase)
        mmc_claim_host(test->card->host);
 
        for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+               struct mmc_test_general_result *result;
+
                if (testcase && ((i + 1) != testcase))
                        continue;
 
@@ -1865,6 +1917,11 @@ static void mmc_test_run(struct mmc_test_card *test, 
long testcase)
                        }
                }
 
+               result = kzalloc(sizeof(struct mmc_test_general_result),
+                       GFP_KERNEL);
+               INIT_LIST_HEAD(&result->transfer);
+               list_add_tail(&result->link, test->result);
+
                ret = mmc_test_cases[i].run(test);
                switch (ret) {
                case RESULT_OK:
@@ -1890,6 +1947,10 @@ static void mmc_test_run(struct mmc_test_card *test, 
long testcase)
                                mmc_hostname(test->card->host), ret);
                }
 
+               /* Save the result */
+               result->testcase = i;
+               result->result = ret;
+
                if (mmc_test_cases[i].cleanup) {
                        ret = mmc_test_cases[i].cleanup(test);
                        if (ret) {
@@ -1907,13 +1968,57 @@ static void mmc_test_run(struct mmc_test_card *test, 
long testcase)
                mmc_hostname(test->card->host));
 }
 
+static struct list_head mmc_test_result;
+
+static void mmc_test_result_free(struct list_head *result)
+{
+       struct mmc_test_general_result *gr, *grs;
+
+       list_for_each_entry_safe(gr, grs, result, link) {
+               struct mmc_test_transfer_result *tr, *trs;
+
+               list_for_each_entry_safe(tr, trs, &gr->transfer, link)
+                       kfree(tr);
+               kfree(gr);
+       }
+}
+
 static ssize_t mmc_test_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
+       struct mmc_test_general_result *result;
+       char *p = buf;
+       size_t len = PAGE_SIZE;
+
        mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry(result, &mmc_test_result, link) {
+               struct mmc_test_transfer_result *transfer;
+               int ret;
+
+               ret = snprintf(p, len, "Test %d: %d\n", result->testcase + 1,
+                       result->result);
+               if (ret < 0)
+                       return ret;
+               p += ret;
+               len -= ret;
+
+               list_for_each_entry(transfer, &result->transfer, link) {
+                       ret = snprintf(p, len, "%u %d %lu.%09lu %u\n",
+                               transfer->count, transfer->sectors,
+                               (unsigned long)transfer->ts.tv_sec,
+                               (unsigned long)transfer->ts.tv_nsec,
+                               transfer->rate);
+                       if (ret < 0)
+                               return ret;
+                       p += ret;
+                       len -= ret;
+               }
+       }
+
        mutex_unlock(&mmc_test_lock);
 
-       return 0;
+       return PAGE_SIZE - len;
 }
 
 static ssize_t mmc_test_store(struct device *dev,
@@ -1932,6 +2037,10 @@ static ssize_t mmc_test_store(struct device *dev,
 
        test->card = card;
 
+       mmc_test_result_free(&mmc_test_result);
+       INIT_LIST_HEAD(&mmc_test_result);
+       test->result = &mmc_test_result;
+
        test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
 #ifdef CONFIG_HIGHMEM
        test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
@@ -1969,6 +2078,8 @@ static int mmc_test_probe(struct mmc_card *card)
        if (ret)
                return ret;
 
+       INIT_LIST_HEAD(&mmc_test_result);
+
        dev_info(&card->dev, "Card claimed for testing.\n");
 
        return 0;
@@ -1976,6 +2087,7 @@ static int mmc_test_probe(struct mmc_card *card)
 
 static void mmc_test_remove(struct mmc_card *card)
 {
+       mmc_test_result_free(&mmc_test_result);
        device_remove_file(&card->dev, &dev_attr_test);
 }
 
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to