From 172a31bf87bf299130a68320f08aa492c34ea3e0 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 21 Apr 2015 13:57:20 -0500 Subject: test: dm: eth: Skip timeouts on ping tests Indicate to the emulated sandbox Ethernet driver when we expect a timeout and tell it to leap forward. Signed-off-by: Joe Hershberger Acked-by: Simon Glass --- test/dm/eth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/dm/eth.c b/test/dm/eth.c index 4891f3ad34f..196eba85a2b 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -135,6 +135,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) sandbox_eth_disable_response(1, true); setenv("ethact", "eth@10004000"); setenv("netretry", "yes"); + sandbox_eth_skip_timeout(); ut_assertok(net_loop(PING)); ut_asserteq_str("eth@10002000", getenv("ethact")); @@ -144,6 +145,7 @@ static int dm_test_net_retry(struct dm_test_state *dms) */ setenv("ethact", "eth@10004000"); setenv("netretry", "no"); + sandbox_eth_skip_timeout(); ut_asserteq(-ETIMEDOUT, net_loop(PING)); ut_asserteq_str("eth@10004000", getenv("ethact")); -- cgit v1.3.1 From 182bf92d19cf007c2d6b9a264107d6996ae9014f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 20 Apr 2015 12:37:15 -0600 Subject: dm: i2c: Add an explicit test mode to the sandbox I2C driver At present this driver has a few test features. They are needed for running the driver model unit tests but are confusing and unnecessary if using sandbox at the command line. Add a flag to enable the test mode, and don't enable it by default. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/test.h | 10 ++++++++++ drivers/i2c/sandbox_i2c.c | 34 +++++++++++++++++++++++----------- include/i2c.h | 1 + test/dm/i2c.c | 8 ++++++++ 4 files changed, 42 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 296589c2826..06e73012680 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -17,6 +17,16 @@ #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL +/** + * sandbox_i2c_set_test_mode() - set test mode for running unit tests + * + * See sandbox_i2c_xfer() for the behaviour changes. + * + * @bus: sandbox I2C bus to adjust + * @test_mode: true to select test mode, false to run normally + */ +void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode); + enum sandbox_i2c_eeprom_test_mode { SIE_TEST_MODE_NONE, /* Permits read/write of only one byte per I2C transaction */ diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c index 621caecf044..dd1c7e59e4b 100644 --- a/drivers/i2c/sandbox_i2c.c +++ b/drivers/i2c/sandbox_i2c.c @@ -18,8 +18,8 @@ DECLARE_GLOBAL_DATA_PTR; -struct dm_sandbox_i2c_emul_priv { - struct udevice *emul; +struct sandbox_i2c_priv { + bool test_mode; }; static int get_emul(struct udevice *dev, struct udevice **devp, @@ -47,17 +47,25 @@ static int get_emul(struct udevice *dev, struct udevice **devp, return 0; } +void sandbox_i2c_set_test_mode(struct udevice *bus, bool test_mode) +{ + struct sandbox_i2c_priv *priv = dev_get_priv(bus); + + priv->test_mode = test_mode; +} + static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) { struct dm_i2c_bus *i2c = dev_get_uclass_priv(bus); + struct sandbox_i2c_priv *priv = dev_get_priv(bus); struct dm_i2c_ops *ops; struct udevice *emul, *dev; bool is_read; int ret; /* Special test code to return success but with no emulation */ - if (msg->addr == SANDBOX_I2C_TEST_ADDR) + if (priv->test_mode && msg->addr == SANDBOX_I2C_TEST_ADDR) return 0; ret = i2c_get_chip(bus, msg->addr, 1, &dev); @@ -68,15 +76,18 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, if (ret) return ret; - /* - * For testing, don't allow writing above 100KHz for writes and - * 400KHz for reads - */ - is_read = nmsgs > 1; - if (i2c->speed_hz > (is_read ? 400000 : 100000)) { - debug("%s: Max speed exceeded\n", __func__); - return -EINVAL; + if (priv->test_mode) { + /* + * For testing, don't allow writing above 100KHz for writes and + * 400KHz for reads. + */ + is_read = nmsgs > 1; + if (i2c->speed_hz > (is_read ? 400000 : 100000)) { + debug("%s: Max speed exceeded\n", __func__); + return -EINVAL; + } } + return ops->xfer(emul, msg, nmsgs); } @@ -94,4 +105,5 @@ U_BOOT_DRIVER(i2c_sandbox) = { .id = UCLASS_I2C, .of_match = sandbox_i2c_ids, .ops = &sandbox_i2c_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_i2c_priv), }; diff --git a/include/i2c.h b/include/i2c.h index d794057f4b9..1e259861b78 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -54,6 +54,7 @@ struct dm_i2c_chip { uint flags; #ifdef CONFIG_SANDBOX struct udevice *emul; + bool test_mode; #endif }; diff --git a/test/dm/i2c.c b/test/dm/i2c.c index 541b73b8037..c5939a165e9 100644 --- a/test/dm/i2c.c +++ b/test/dm/i2c.c @@ -66,6 +66,9 @@ static int dm_test_i2c_speed(struct dm_test_state *dms) uint8_t buf[5]; ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + + /* Use test mode so we create the required errors for invalid speeds */ + sandbox_i2c_set_test_mode(bus, true); ut_assertok(i2c_get_chip(bus, chip, 1, &dev)); ut_assertok(dm_i2c_set_bus_speed(bus, 100000)); ut_assertok(dm_i2c_read(dev, 0, buf, 5)); @@ -73,6 +76,7 @@ static int dm_test_i2c_speed(struct dm_test_state *dms) ut_asserteq(400000, dm_i2c_get_bus_speed(bus)); ut_assertok(dm_i2c_read(dev, 0, buf, 5)); ut_asserteq(-EINVAL, dm_i2c_write(dev, 0, buf, 5)); + sandbox_i2c_set_test_mode(bus, false); return 0; } @@ -100,7 +104,11 @@ static int dm_test_i2c_probe_empty(struct dm_test_state *dms) struct udevice *bus, *dev; ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus)); + + /* Use test mode so that this chip address will always probe */ + sandbox_i2c_set_test_mode(bus, true); ut_assertok(dm_i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev)); + sandbox_i2c_set_test_mode(bus, false); return 0; } -- cgit v1.3.1 From fbe07ba0f8486d8c77d686caec1f840aecb01424 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 20 Apr 2015 12:37:30 -0600 Subject: dm: test: dts: Sort the aliases in the test device tree file Sort these aliases to avoid confusion as to what is present. Signed-off-by: Simon Glass Reviewed-by: Joe Hershberger --- test/dm/test.dts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/test/dm/test.dts b/test/dm/test.dts index d0c40be6b0a..dd6d0acc27d 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -8,18 +8,18 @@ aliases { console = &uart0; + eth0 = "/eth@10002000"; + eth5 = ð_5; i2c0 = "/i2c@0"; - spi0 = "/spi@0"; pci0 = &pci; - testfdt6 = "/e-test"; + spi0 = "/spi@0"; testbus3 = "/some-bus"; testfdt0 = "/some-bus/c-test@0"; testfdt1 = "/some-bus/c-test@1"; testfdt3 = "/b-test"; testfdt5 = "/some-bus/c-test@5"; + testfdt6 = "/e-test"; testfdt8 = "/a-test"; - eth0 = "/eth@10002000"; - eth5 = ð_5; usb0 = &usb_0; usb1 = &usb_1; usb2 = &usb_2; -- cgit v1.3.1 From 4772511475ce9221a040142eb808fa963024598f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 20 Apr 2015 12:37:31 -0600 Subject: dm: rtc: Add tests for real-time clocks Add some simple tests to verify that the RTC uclass works correctly in U-Boot. Signed-off-by: Simon Glass --- test/dm/Makefile | 1 + test/dm/rtc.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 18 ++++++ 3 files changed, 194 insertions(+) create mode 100644 test/dm/rtc.c (limited to 'test') diff --git a/test/dm/Makefile b/test/dm/Makefile index fd9e29f201c..a0cc2c6de5f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_DM_ETH) += eth.o obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_DM_PCI) += pci.o +obj-$(CONFIG_DM_RTC) += rtc.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_DM_USB) += usb.o diff --git a/test/dm/rtc.c b/test/dm/rtc.c new file mode 100644 index 00000000000..9397cf72a73 --- /dev/null +++ b/test/dm/rtc.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Simple RTC sanity check */ +static int dm_test_rtc_base(struct dm_test_state *dms) +{ + struct udevice *dev; + + ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_RTC, 2, &dev)); + ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev)); + ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev)); + + return 0; +} +DM_TEST(dm_test_rtc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +static void show_time(const char *msg, struct rtc_time *time) +{ + printf("%s: %02d/%02d/%04d %02d:%02d:%02d\n", msg, + time->tm_mday, time->tm_mon, time->tm_year, + time->tm_hour, time->tm_min, time->tm_sec); +} + +static int cmp_times(struct rtc_time *expect, struct rtc_time *time, bool show) +{ + bool same; + + same = expect->tm_sec == time->tm_sec; + same &= expect->tm_min == time->tm_min; + same &= expect->tm_hour == time->tm_hour; + same &= expect->tm_mday == time->tm_mday; + same &= expect->tm_mon == time->tm_mon; + same &= expect->tm_year == time->tm_year; + if (!same && show) { + show_time("expected", expect); + show_time("actual", time); + } + + return same ? 0 : -EINVAL; +} + +/* Set and get the time */ +static int dm_test_rtc_set_get(struct dm_test_state *dms) +{ + struct rtc_time now, time, cmp; + struct udevice *dev, *emul; + long offset, old_offset, old_base_time; + + ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev)); + ut_assertok(dm_rtc_get(dev, &now)); + + ut_assertok(device_find_first_child(dev, &emul)); + ut_assert(emul != NULL); + + /* Tell the RTC to go into manual mode */ + old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0); + old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1); + + memset(&time, '\0', sizeof(time)); + time.tm_mday = 25; + time.tm_mon = 8; + time.tm_year = 2004; + time.tm_sec = 0; + time.tm_min = 18; + time.tm_hour = 18; + ut_assertok(dm_rtc_set(dev, &time)); + + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev, &cmp)); + ut_assertok(cmp_times(&time, &cmp, true)); + + /* Increment by 1 second */ + offset = sandbox_i2c_rtc_set_offset(emul, false, 0); + sandbox_i2c_rtc_set_offset(emul, false, offset + 1); + + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev, &cmp)); + ut_asserteq(1, cmp.tm_sec); + + /* Check against original offset */ + sandbox_i2c_rtc_set_offset(emul, false, old_offset); + ut_assertok(dm_rtc_get(dev, &cmp)); + ut_assertok(cmp_times(&now, &cmp, true)); + + /* Back to the original offset */ + sandbox_i2c_rtc_set_offset(emul, false, 0); + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev, &cmp)); + ut_assertok(cmp_times(&now, &cmp, true)); + + /* Increment the base time by 1 emul */ + sandbox_i2c_rtc_get_set_base_time(emul, old_base_time + 1); + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev, &cmp)); + if (now.tm_sec == 59) { + ut_asserteq(0, cmp.tm_sec); + } else { + ut_asserteq(now.tm_sec + 1, cmp.tm_sec); + } + + old_offset = sandbox_i2c_rtc_set_offset(emul, true, 0); + + return 0; +} +DM_TEST(dm_test_rtc_set_get, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Reset the time */ +static int dm_test_rtc_reset(struct dm_test_state *dms) +{ + struct rtc_time now; + struct udevice *dev, *emul; + long old_base_time, base_time; + + ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev)); + ut_assertok(dm_rtc_get(dev, &now)); + + ut_assertok(device_find_first_child(dev, &emul)); + ut_assert(emul != NULL); + + old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, 0); + + ut_asserteq(0, sandbox_i2c_rtc_get_set_base_time(emul, -1)); + + /* Resetting the RTC should put he base time back to normal */ + ut_assertok(dm_rtc_reset(dev)); + base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1); + ut_asserteq(old_base_time, base_time); + + return 0; +} +DM_TEST(dm_test_rtc_reset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Check that two RTC devices can be used independently */ +static int dm_test_rtc_dual(struct dm_test_state *dms) +{ + struct rtc_time now1, now2, cmp; + struct udevice *dev1, *dev2; + struct udevice *emul1, *emul2; + long offset; + + ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev1)); + ut_assertok(dm_rtc_get(dev1, &now1)); + ut_assertok(uclass_get_device(UCLASS_RTC, 1, &dev2)); + ut_assertok(dm_rtc_get(dev2, &now2)); + + ut_assertok(device_find_first_child(dev1, &emul1)); + ut_assert(emul1 != NULL); + ut_assertok(device_find_first_child(dev2, &emul2)); + ut_assert(emul2 != NULL); + + offset = sandbox_i2c_rtc_set_offset(emul1, false, -1); + sandbox_i2c_rtc_set_offset(emul2, false, offset + 1); + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev2, &cmp)); + ut_asserteq(-EINVAL, cmp_times(&now1, &cmp, false)); + + memset(&cmp, '\0', sizeof(cmp)); + ut_assertok(dm_rtc_get(dev1, &cmp)); + ut_assertok(cmp_times(&now1, &cmp, true)); + + return 0; +} +DM_TEST(dm_test_rtc_dual, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); diff --git a/test/dm/test.dts b/test/dm/test.dts index dd6d0acc27d..008584865c0 100644 --- a/test/dm/test.dts +++ b/test/dm/test.dts @@ -20,6 +20,8 @@ testfdt5 = "/some-bus/c-test@5"; testfdt6 = "/e-test"; testfdt8 = "/a-test"; + rtc0 = &rtc_0; + rtc1 = &rtc_1; usb0 = &usb_0; usb1 = &usb_1; usb2 = &usb_2; @@ -139,6 +141,22 @@ sandbox,size = <256>; }; }; + + rtc_0: rtc@43 { + reg = <0x43>; + compatible = "sandbox-rtc"; + emul { + compatible = "sandbox,i2c-rtc"; + }; + }; + + rtc_1: rtc@61 { + reg = <0x61>; + compatible = "sandbox-rtc"; + emul { + compatible = "sandbox,i2c-rtc"; + }; + }; }; pci: pci-controller { -- cgit v1.3.1 From 8271f5d4c3a0ce8282025217509c18220a0f552b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 2 May 2015 09:25:02 -0600 Subject: test: Add a simple time test Sometimes the time functions are incorrect due to bad time support on a board. Add a unit test which tries to detect this. Signed-off-by: Simon Glass --- test/Kconfig | 8 ++++ test/Makefile | 1 + test/time_ut.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 test/time_ut.c (limited to 'test') diff --git a/test/Kconfig b/test/Kconfig index 1fb1716a4ad..3270c84213b 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -1 +1,9 @@ +config CMD_UT_TIME + bool "Unit tests for time functions" + help + Enables the 'ut_time' command which tests that the time functions + work correctly. The test is fairly simple and will not catch all + problems. But if you are having problems with udelay() and the like, + this is a good place to start. + source "test/dm/Kconfig" diff --git a/test/Makefile b/test/Makefile index 9c95805c44e..08330e020c5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SANDBOX) += command_ut.o obj-$(CONFIG_SANDBOX) += compression.o +obj-$(CONFIG_CMD_UT_TIME) += time_ut.o diff --git a/test/time_ut.c b/test/time_ut.c new file mode 100644 index 00000000000..6b52245d7ff --- /dev/null +++ b/test/time_ut.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +static int test_get_timer(void) +{ + ulong base, start, next, diff; + int iter; + + base = get_timer(0); + start = get_timer(0); + for (iter = 0; iter < 10; iter++) { + do { + next = get_timer(0); + } while (start == next); + + if (start + 1 != next) { + printf("%s: iter=%d, start=%lu, next=%lu, expected a difference of 1\n", + __func__, iter, start, next); + return -EINVAL; + } + start++; + } + + /* + * Check that get_timer(base) matches our elapsed time, allowing that + * an extra millisecond may have passed. + */ + diff = get_timer(base); + if (diff != iter && diff != iter + 1) { + printf("%s: expected get_timer(base) to match elapsed time: diff=%lu, expected=%d\n", + __func__, diff, iter); + return -EINVAL; + } + + return 0; +} + +static int test_timer_get_us(void) +{ + ulong prev, next, min = 1000000; + long delta; + int iter; + + /* Find the minimum delta we can measure, in microseconds */ + prev = timer_get_us(); + for (iter = 0; iter < 100; ) { + next = timer_get_us(); + if (next != prev) { + delta = next - prev; + if (delta < 0) { + printf("%s: timer_get_us() went backwards from %lu to %lu\n", + __func__, prev, next); + return -EINVAL; + } else if (delta != 0) { + if (delta < min) + min = delta; + prev = next; + iter++; + } + } + } + + if (min != 1) { + printf("%s: Minimum microsecond delta should be 1 but is %lu\n", + __func__, min); + return -EINVAL; + } + + return 0; +} + +static int test_time_comparison(void) +{ + ulong start_us, end_us, delta_us; + long error; + ulong start; + + start = get_timer(0); + start_us = timer_get_us(); + while (get_timer(start) < 1000) + ; + end_us = timer_get_us(); + delta_us = end_us - start_us; + error = delta_us - 1000000; + printf("%s: Microsecond time for 1 second: %lu, error = %ld\n", + __func__, delta_us, error); + if (abs(error) > 1000) + return -EINVAL; + + return 0; +} + +static int test_udelay(void) +{ + long error; + ulong start, delta; + int iter; + + start = get_timer(0); + for (iter = 0; iter < 1000; iter++) + udelay(1000); + delta = get_timer(start); + error = delta - 1000; + printf("%s: Delay time for 1000 udelay(1000): %lu ms, error = %ld\n", + __func__, delta, error); + if (abs(error) > 100) + return -EINVAL; + + return 0; +} + +static int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = 0; + + ret |= test_get_timer(); + ret |= test_timer_get_us(); + ret |= test_time_comparison(); + ret |= test_udelay(); + + printf("Test %s\n", ret ? "failed" : "passed"); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + ut_time, 1, 1, do_ut_time, + "Very basic test of time functions", + "" +); -- cgit v1.3.1