diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:31:39 -0700 |
commit | d25e436c4b68db2895185b24ad1f22499c2f87b0 (patch) | |
tree | dd66245410513f09d2439ef0b34cf1d131696bed /drivers/spi/spi-loopback-test.c | |
parent | a90f0e9ebb88ba7b0efea4e7d9defc0c2b96f712 (diff) | |
parent | 282ec0ea65dab88fda51b5b9b649958ae42f4ac0 (diff) | |
download | talos-op-linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.tar.gz talos-op-linux-d25e436c4b68db2895185b24ad1f22499c2f87b0.zip |
Merge tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"There's quite a lot of small driver specific fixes and enhancements in
this release but the main activity has been around the loopback and
spidev test drivers which is good to see as it should hopefully help
improve the quality of all the drivers as people start to make use of
the new code:
- Additional tests in the loopback test driver for vmalloc()
compatibility and around delays together with fixes for existing
tests.
- Support for testing continuous data transfer for use in soak
testing.
- Device property support for board info platforms.
- Support for registering empty sets of devices via board info
(useful when writing code to enumerate hardware automatically)"
* tag 'spi-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (52 commits)
spi: cadence: Allow for GPIO pins to be used as chipselects
spi-imx: Implements handling of the SPI_READY mode flag.
spi: tegra: fix spelling mistake: "trasfer" -> "transfer"
spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble
spi: Add can_dma like interface for spi_flash_read
spi: dw: Disable clock after unregistering the host
spi: double time out tolerance
spi: atmel: add deepest PM support to SAMA5D2
spi: atmel: factorize reusable code for SPI controller init
spi: orion: add LSB support
spi: pl022: don't use uninitialized variable
spi: loopback-test: fix spelling mistake: "minimam" -> "minimum"
spi: dynamycally allocated message initialization
spi: spi-ti-qspi: Remove unused dma_dev variable
spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer
spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call
spi: spidev_test: add option to continuously transfer data
spi: loopback-test: fix potential integer overflow on multiple
spi: sun6i: update max transfer size reported
spi: pl022: Document property values
...
Diffstat (limited to 'drivers/spi/spi-loopback-test.c')
-rw-r--r-- | drivers/spi/spi-loopback-test.c | 154 |
1 files changed, 106 insertions, 48 deletions
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index 50e620f4e8fe..f4875f177df0 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -20,11 +20,13 @@ #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); |