Merge remote-tracking branches 'spi/topic/spidev', 'spi/topic/spidev-test', 'spi...
[sfrench/cifs-2.6.git] / drivers / spi / spi-loopback-test.c
index 50e620f4e8fe2ae29c655358e38d771c464ec01d..f4875f177df04fe3ae9c8f334b534b3119ba6672 100644 (file)
 
 #include <linux/delay.h>
 #include <linux/kernel.h>
+#include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/printk.h>
+#include <linux/vmalloc.h>
 #include <linux/spi/spi.h>
 
 #include "spi-test.h"
@@ -55,6 +57,18 @@ module_param(run_only_test, int, 0);
 MODULE_PARM_DESC(run_only_test,
                 "only run the test with this number (0-based !)");
 
+/* use vmalloc'ed buffers */
+int use_vmalloc;
+module_param(use_vmalloc, int, 0644);
+MODULE_PARM_DESC(use_vmalloc,
+                "use vmalloc'ed buffers instead of kmalloc'ed");
+
+/* check rx ranges */
+int check_ranges = 1;
+module_param(check_ranges, int, 0644);
+MODULE_PARM_DESC(check_ranges,
+                "checks rx_buffer pattern are valid");
+
 /* the actual tests to execute */
 static struct spi_test spi_tests[] = {
        {
@@ -63,9 +77,9 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_rx_align = ITERATE_ALIGN,
+               .transfer_count = 1,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                                .rx_buf = RX(0),
                        },
@@ -77,9 +91,9 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_rx_align = ITERATE_ALIGN,
+               .transfer_count = 1,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(PAGE_SIZE - 4),
                                .rx_buf = RX(PAGE_SIZE - 4),
                        },
@@ -90,9 +104,9 @@ static struct spi_test spi_tests[] = {
                .fill_option    = FILL_COUNT_8,
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
+               .transfer_count = 1,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                        },
                },
@@ -102,9 +116,9 @@ static struct spi_test spi_tests[] = {
                .fill_option    = FILL_COUNT_8,
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_rx_align = ITERATE_ALIGN,
+               .transfer_count = 1,
                .transfers              = {
                        {
-                               .len = 1,
                                .rx_buf = RX(0),
                        },
                },
@@ -115,13 +129,12 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(0) | BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                        },
                        {
-                               .len = 1,
                                /* this is why we cant use ITERATE_MAX_LEN */
                                .tx_buf = TX(SPI_TEST_MAX_SIZE_HALF),
                        },
@@ -132,10 +145,10 @@ static struct spi_test spi_tests[] = {
                .fill_option    = FILL_COUNT_8,
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
-               .iterate_transfer_mask = BIT(1),
+               .iterate_transfer_mask = BIT(0),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(64),
                        },
                        {
@@ -149,14 +162,14 @@ static struct spi_test spi_tests[] = {
                .fill_option    = FILL_COUNT_8,
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
-               .iterate_transfer_mask = BIT(0),
+               .iterate_transfer_mask = BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
                                .len = 16,
                                .tx_buf = TX(0),
                        },
                        {
-                               .len = 1,
                                .tx_buf = TX(64),
                        },
                },
@@ -167,13 +180,12 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(0) | BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                        },
                        {
-                               .len = 1,
                                .rx_buf = RX(0),
                        },
                },
@@ -184,9 +196,9 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(0),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                        },
                        {
@@ -201,13 +213,13 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
                                .len = 1,
                                .tx_buf = TX(0),
                        },
                        {
-                               .len = 1,
                                .rx_buf = RX(0),
                        },
                },
@@ -218,14 +230,13 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(0) | BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                .tx_buf = TX(0),
                                .rx_buf = RX(0),
                        },
                        {
-                               .len = 1,
                                /* making sure we align without overwrite
                                 * the reason we can not use ITERATE_MAX_LEN
                                 */
@@ -240,9 +251,9 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(0),
+               .transfer_count = 2,
                .transfers              = {
                        {
-                               .len = 1,
                                /* making sure we align without overwrite */
                                .tx_buf = TX(1024),
                                .rx_buf = RX(1024),
@@ -261,6 +272,7 @@ static struct spi_test spi_tests[] = {
                .iterate_len    = { ITERATE_MAX_LEN },
                .iterate_tx_align = ITERATE_ALIGN,
                .iterate_transfer_mask = BIT(1),
+               .transfer_count = 2,
                .transfers              = {
                        {
                                .len = 1,
@@ -268,13 +280,31 @@ static struct spi_test spi_tests[] = {
                                .rx_buf = RX(0),
                        },
                        {
-                               .len = 1,
                                /* making sure we align without overwrite */
                                .tx_buf = TX(1024),
                                .rx_buf = RX(1024),
                        },
                },
        },
+       {
+               .description    = "two tx+rx transfers - delay after transfer",
+               .fill_option    = FILL_COUNT_8,
+               .iterate_len    = { ITERATE_MAX_LEN },
+               .iterate_transfer_mask = BIT(0) | BIT(1),
+               .transfer_count = 2,
+               .transfers              = {
+                       {
+                               .tx_buf = TX(0),
+                               .rx_buf = RX(0),
+                               .delay_usecs = 1000,
+                       },
+                       {
+                               .tx_buf = TX(0),
+                               .rx_buf = RX(0),
+                               .delay_usecs = 1000,
+                       },
+               },
+       },
 
        { /* end of tests sequence */ }
 };
@@ -482,6 +512,36 @@ static int spi_check_rx_ranges(struct spi_device *spi,
        return ret;
 }
 
+static int spi_test_check_elapsed_time(struct spi_device *spi,
+                                      struct spi_test *test)
+{
+       int i;
+       unsigned long long estimated_time = 0;
+       unsigned long long delay_usecs = 0;
+
+       for (i = 0; i < test->transfer_count; i++) {
+               struct spi_transfer *xfer = test->transfers + i;
+               unsigned long long nbits = (unsigned long long)BITS_PER_BYTE *
+                                          xfer->len;
+
+               delay_usecs += xfer->delay_usecs;
+               if (!xfer->speed_hz)
+                       continue;
+               estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz);
+       }
+
+       estimated_time += delay_usecs * NSEC_PER_USEC;
+       if (test->elapsed_time < estimated_time) {
+               dev_err(&spi->dev,
+                       "elapsed time %lld ns is shorter than minimum estimated time %lld ns\n",
+                       test->elapsed_time, estimated_time);
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int spi_test_check_loopback_result(struct spi_device *spi,
                                          struct spi_message *msg,
                                          void *tx, void *rx)
@@ -492,9 +552,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
        int ret;
 
        /* checks rx_buffer pattern are valid with loopback or without */
-       ret = spi_check_rx_ranges(spi, msg, rx);
-       if (ret)
-               return ret;
+       if (check_ranges) {
+               ret = spi_check_rx_ranges(spi, msg, rx);
+               if (ret)
+                       return ret;
+       }
 
        /* if we run without loopback, then return now */
        if (!loopback)
@@ -503,11 +565,11 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
        /* if applicable to transfer check that rx_buf is equal to tx_buf */
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                /* if there is no rx, then no check is needed */
-               if (!xfer->rx_buf)
+               if (!xfer->len || !xfer->rx_buf)
                        continue;
                /* so depending on tx_buf we need to handle things */
                if (xfer->tx_buf) {
-                       for (i = 1; i < xfer->len; i++) {
+                       for (i = 0; i < xfer->len; i++) {
                                txb = ((u8 *)xfer->tx_buf)[i];
                                rxb = ((u8 *)xfer->rx_buf)[i];
                                if (txb != rxb)
@@ -745,15 +807,6 @@ static int spi_test_run_iter(struct spi_device *spi,
        /* copy the test template to test */
        memcpy(&test, testtemplate, sizeof(test));
 
-       /* set up test->transfers to the correct count */
-       if (!test.transfer_count) {
-               for (i = 0;
-                   (i < SPI_TEST_MAX_TRANSFERS) && test.transfers[i].len;
-                   i++) {
-                       test.transfer_count++;
-               }
-       }
-
        /* if iterate_transfer_mask is not set,
         * then set it to first transfer only
         */
@@ -799,8 +852,7 @@ static int spi_test_run_iter(struct spi_device *spi,
                /* only when bit in transfer mask is set */
                if (!(test.iterate_transfer_mask & BIT(i)))
                        continue;
-               if (len)
-                       test.transfers[i].len = len;
+               test.transfers[i].len = len;
                if (test.transfers[i].tx_buf)
                        test.transfers[i].tx_buf += tx_off;
                if (test.transfers[i].tx_buf)
@@ -830,12 +882,16 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
 
        /* only if we do not simulate */
        if (!simulate_only) {
+               ktime_t start;
+
                /* dump the complete message before and after the transfer */
                if (dump_messages == 3)
                        spi_test_dump_message(spi, msg, true);
 
+               start = ktime_get();
                /* run spi message */
                ret = spi_sync(spi, msg);
+               test->elapsed_time = ktime_to_ns(ktime_sub(ktime_get(), start));
                if (ret == -ETIMEDOUT) {
                        dev_info(&spi->dev,
                                 "spi-message timed out - reruning...\n");
@@ -861,6 +917,10 @@ int spi_test_execute_msg(struct spi_device *spi, struct spi_test *test,
 
                /* run rx-buffer tests */
                ret = spi_test_check_loopback_result(spi, msg, tx, rx);
+               if (ret)
+                       goto exit;
+
+               ret = spi_test_check_elapsed_time(spi, test);
        }
 
        /* if requested or on error dump message (including data) */
@@ -910,15 +970,6 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
        /* iterate over all the iterable values using macros
         * (to make it a bit more readable...
         */
-#define FOR_EACH_ITERATE(var, defaultvalue)                            \
-       for (idx_##var = -1, var = defaultvalue;                        \
-            ((idx_##var < 0) ||                                        \
-                    (                                                  \
-                            (idx_##var < SPI_TEST_MAX_ITERATE) &&      \
-                            (var = test->iterate_##var[idx_##var])     \
-                    )                                                  \
-            );                                                         \
-            idx_##var++)
 #define FOR_EACH_ALIGNMENT(var)                                                \
        for (var = 0;                                                   \
            var < (test->iterate_##var ?                                \
@@ -928,7 +979,8 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
                        1);                                             \
            var++)
 
-       FOR_EACH_ITERATE(len, 0) {
+       for (idx_len = 0; idx_len < SPI_TEST_MAX_ITERATE &&
+            (len = test->iterate_len[idx_len]) != -1; idx_len++) {
                FOR_EACH_ALIGNMENT(tx_align) {
                        FOR_EACH_ALIGNMENT(rx_align) {
                                /* and run the iteration */
@@ -965,13 +1017,19 @@ int spi_test_run_tests(struct spi_device *spi,
        /* allocate rx/tx buffers of 128kB size without devm
         * in the hope that is on a page boundary
         */
-       rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
+       if (use_vmalloc)
+               rx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
+       else
+               rx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
        if (!rx) {
                ret = -ENOMEM;
                goto out;
        }
 
-       tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
+       if (use_vmalloc)
+               tx = vmalloc(SPI_TEST_MAX_SIZE_PLUS);
+       else
+               tx = kzalloc(SPI_TEST_MAX_SIZE_PLUS, GFP_KERNEL);
        if (!tx) {
                ret = -ENOMEM;
                goto out;
@@ -999,8 +1057,8 @@ int spi_test_run_tests(struct spi_device *spi,
        }
 
 out:
-       kfree(rx);
-       kfree(tx);
+       kvfree(rx);
+       kvfree(tx);
        return ret;
 }
 EXPORT_SYMBOL_GPL(spi_test_run_tests);