summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-loopback-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-loopback-test.c')
-rw-r--r--drivers/spi/spi-loopback-test.c119
1 files changed, 78 insertions, 41 deletions
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index 4e7843ec8aac..f4875f177df0 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -20,6 +20,7 @@
#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>
@@ -76,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),
},
@@ -90,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),
},
@@ -103,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),
},
},
@@ -115,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),
},
},
@@ -128,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),
},
@@ -145,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),
},
{
@@ -162,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),
},
},
@@ -180,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),
},
},
@@ -197,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),
},
{
@@ -214,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),
},
},
@@ -231,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
*/
@@ -253,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),
@@ -274,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,
@@ -281,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 */ }
};
@@ -495,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)
@@ -518,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)
@@ -760,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
*/
@@ -814,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)
@@ -845,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");
@@ -876,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) */
@@ -925,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 ? \
@@ -943,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 */