Message ID | 1600121324-31337-4-git-send-email-fnu.vikram@xilinx.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Introduce Xilinx ZynqMP CAN controller | expand |
Hi Vikram, On 9/15/20 12:08 AM, Vikram Garhwal wrote: > The QTests perform five tests on the Xilinx ZynqMP CAN controller: > Tests the CAN controller in loopback, sleep and snoop mode. > Tests filtering of incoming CAN messages. > > Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> > Signed-off-by: Vikram Garhwal <fnu.vikram@xilinx.com> > --- > tests/qtest/meson.build | 1 + > tests/qtest/xlnx-can-test.c | 359 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 360 insertions(+) > create mode 100644 tests/qtest/xlnx-can-test.c > > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > index 874b5be..945f86c 100644 > --- a/tests/qtest/meson.build > +++ b/tests/qtest/meson.build > @@ -148,6 +148,7 @@ qtests_aarch64 = \ > (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ > ['numa-test', > 'boot-serial-test', > + 'xlnx-can-test', > 'migration-test'] > > qtests_s390x = \ > diff --git a/tests/qtest/xlnx-can-test.c b/tests/qtest/xlnx-can-test.c > new file mode 100644 > index 0000000..d04189f > --- /dev/null > +++ b/tests/qtest/xlnx-can-test.c > @@ -0,0 +1,359 @@ > +/* > + * QTests for the Xilinx ZynqMP CAN controller. > + * > + * Copyright (c) 2020 Xilinx Inc. > + * > + * Written-by: Vikram Garhwal<fnu.vikram@xilinx.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#include "qemu/osdep.h" > +#include "libqos/libqtest.h" > + > +/* Base address. */ > +#define CAN0_BASE_ADDR 0xFF060000 > +#define CAN1_BASE_ADDR 0xFF070000 > + > +/* Register addresses. */ > +#define R_SRR_OFFSET 0x00 > +#define R_MSR_OFFSET 0x04 > +#define R_SR_OFFSET 0x18 > +#define R_ISR_OFFSET 0x1C > +#define R_ICR_OFFSET 0x24 > +#define R_TXID_OFFSET 0x30 > +#define R_TXDLC_OFFSET 0x34 > +#define R_TXDATA1_OFFSET 0x38 > +#define R_TXDATA2_OFFSET 0x3C > +#define R_RXID_OFFSET 0x50 > +#define R_RXDLC_OFFSET 0x54 > +#define R_RXDATA1_OFFSET 0x58 > +#define R_RXDATA2_OFFSET 0x5C > +#define R_AFR 0x60 > +#define R_AFMR1 0x64 > +#define R_AFIR1 0x68 > +#define R_AFMR2 0x6C > +#define R_AFIR2 0x70 > +#define R_AFMR3 0x74 > +#define R_AFIR3 0x78 > +#define R_AFMR4 0x7C > +#define R_AFIR4 0x80 > + > +/* CAN modes. */ > +#define CONFIG_MODE 0x00 > +#define NORMAL_MODE 0x00 > +#define LOOPBACK_MODE 0x02 > +#define SNOOP_MODE 0x04 > +#define SLEEP_MODE 0x01 > +#define ENABLE_CAN (1 << 1) > +#define STATUS_NORMAL_MODE (1 << 3) > +#define STATUS_LOOPBACK_MODE (1 << 1) > +#define STATUS_SNOOP_MODE (1 << 12) > +#define STATUS_SLEEP_MODE (1 << 2) > +#define ISR_TXOK (1 << 1) > +#define ISR_RXOK (1 << 4) > + > +static void match_rx_tx_data(uint32_t *buf_tx, uint32_t *buf_rx, > + uint8_t can_timestamp) Both buf_tx/buf_rx should be const. > +{ > + uint16_t size = 0; > + uint8_t len = 4; > + > + while (size < len) { > + if (R_RXID_OFFSET + 4 * size == R_RXDLC_OFFSET) { > + g_assert_cmpint(buf_rx[size], ==, buf_tx[size] + can_timestamp); > + } else { > + g_assert_cmpint(buf_rx[size], ==, buf_tx[size]); > + } > + > + size++; > + } > +} > + > +static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx) > +{ > + uint32_t int_status; > + > + /* Read the interrupt on CAN rx. */ > + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK; > + > + g_assert_cmpint(int_status, ==, ISR_RXOK); > + > + /* Read the RX register data for CAN. */ > + buf_rx[0] = qtest_readl(qts, can_base_addr + R_RXID_OFFSET); > + buf_rx[1] = qtest_readl(qts, can_base_addr + R_RXDLC_OFFSET); > + buf_rx[2] = qtest_readl(qts, can_base_addr + R_RXDATA1_OFFSET); > + buf_rx[3] = qtest_readl(qts, can_base_addr + R_RXDATA2_OFFSET); > + > + /* Clear the RX interrupt. */ > + qtest_writel(qts, CAN1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK); > +} > + > +static void send_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_tx) > +{ buf_tx should be const. > + uint32_t int_status; > + > + /* Write the TX register data for CAN. */ > + qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]); > + qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]); > + qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]); > + qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]); > + > + /* Read the interrupt on CAN for tx. */ > + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK; > + > + g_assert_cmpint(int_status, ==, ISR_TXOK); > + > + /* Clear the interrupt for tx. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK); > +} > + > +/* > + * This test will be transferring data from CAN0 and CAN1 through canbus. CAN0 > + * initiate the data transfer to can-bus, CAN1 receives the data. Test compares > + * the data sent from CAN0 with received on CAN1. > + */ > +static void test_can_bus(void) > +{ > + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; buf_tx should be const (similarly in the followng tests). Can probably be cleaned on top of this patch, so: Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > + uint32_t status = 0; > + uint8_t can_timestamp = 1; > + > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > + " -object can-bus,id=canbus0" > + " -machine xlnx-zcu102.canbus0=canbus0" > + " -machine xlnx-zcu102.canbus1=canbus0" > + ); > + > + /* Configure the CAN0 and CAN1. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + > + /* Check here if CAN0 and CAN1 are in normal mode. */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > + > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > + > + qtest_quit(qts); > +} > + > +/* > + * This test is performing loopback mode on CAN0 and CAN1. Data sent from TX of > + * each CAN0 and CAN1 are compared with RX register data for respective CAN. > + */ > +static void test_can_loopback(void) > +{ > + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > + uint32_t status = 0; > + > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > + " -object can-bus,id=canbus0" > + " -machine xlnx-zcu102.canbus0=canbus0" > + " -machine xlnx-zcu102.canbus1=canbus0" > + ); > + > + /* Configure the CAN0 in loopback mode. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + > + /* Check here if CAN0 is set in loopback mode. */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + > + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); > + > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > + match_rx_tx_data(buf_tx, buf_rx, 0); > + > + /* Configure the CAN1 in loopback mode. */ > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + > + /* Check here if CAN1 is set in loopback mode. */ > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > + > + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); > + > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > + match_rx_tx_data(buf_tx, buf_rx, 0); > + > + qtest_quit(qts); > +} > + > +/* > + * Enable filters for CAN1. This will filter incoming messages with ID. In this > + * test message will pass through filter 2. > + */ > +static void test_can_filter(void) > +{ > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > + uint32_t status = 0; > + uint8_t can_timestamp = 1; > + > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > + " -object can-bus,id=canbus0" > + " -machine xlnx-zcu102.canbus0=canbus0" > + " -machine xlnx-zcu102.canbus1=canbus0" > + ); > + > + /* Configure the CAN0 and CAN1. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + > + /* Check here if CAN0 and CAN1 are in normal mode. */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + /* Set filter for CAN1 for incoming messages. */ > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0x0); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR1, 0xF7); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR1, 0x121F); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR2, 0x5431); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR2, 0x14); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR3, 0x1234); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR3, 0x5431); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR4, 0xFFF); > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR4, 0x1234); > + > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0xF); > + > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > + > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > + > + qtest_quit(qts); > +} > + > +/* Testing sleep mode on CAN0 while CAN1 is in normal mode. */ > +static void test_can_sleepmode(void) > +{ > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > + uint32_t status = 0; > + uint8_t can_timestamp = 1; > + > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > + " -object can-bus,id=canbus0" > + " -machine xlnx-zcu102.canbus0=canbus0" > + " -machine xlnx-zcu102.canbus1=canbus0" > + ); > + > + /* Configure the CAN0. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SLEEP_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + > + /* Check here if CAN0 is in SLEEP mode and CAN1 in normal mode. */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_SLEEP_MODE); > + > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > + > + /* > + * Once CAN1 sends data on can-bus. CAN0 should exit sleep mode. > + * Check the CAN0 status now. It should exit the sleep mode and receive the > + * incoming data. > + */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > + > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > + > + qtest_quit(qts); > +} > + > +/* Testing Snoop mode on CAN0 while CAN1 is in normal mode. */ > +static void test_can_snoopmode(void) > +{ > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > + uint32_t status = 0; > + uint8_t can_timestamp = 1; > + > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > + " -object can-bus,id=canbus0" > + " -machine xlnx-zcu102.canbus0=canbus0" > + " -machine xlnx-zcu102.canbus1=canbus0" > + ); > + > + /* Configure the CAN0. */ > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SNOOP_MODE); > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > + > + /* Check here if CAN0 is in SNOOP mode and CAN1 in normal mode. */ > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_SNOOP_MODE); > + > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > + > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > + > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > + > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > + > + qtest_quit(qts); > +} > + > +int main(int argc, char **argv) > +{ > + g_test_init(&argc, &argv, NULL); > + > + qtest_add_func("/net/can/can_bus", test_can_bus); > + qtest_add_func("/net/can/can_loopback", test_can_loopback); > + qtest_add_func("/net/can/can_filter", test_can_filter); > + qtest_add_func("/net/can/can_test_snoopmode", test_can_snoopmode); > + qtest_add_func("/net/can/can_test_sleepmode", test_can_sleepmode); > + > + return g_test_run(); > +} >
Hi Philippe, Thanks for reviewing this one. I will address the comments in next version and add reviewed-by tags. On Fri, Oct 02, 2020 at 03:49:31PM +0200, Philippe Mathieu-Daudé wrote: > Hi Vikram, > > On 9/15/20 12:08 AM, Vikram Garhwal wrote: > > The QTests perform five tests on the Xilinx ZynqMP CAN controller: > > Tests the CAN controller in loopback, sleep and snoop mode. > > Tests filtering of incoming CAN messages. > > > > Reviewed-by: Francisco Iglesias <francisco.iglesias@xilinx.com> > > Signed-off-by: Vikram Garhwal <fnu.vikram@xilinx.com> > > --- > > tests/qtest/meson.build | 1 + > > tests/qtest/xlnx-can-test.c | 359 ++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 360 insertions(+) > > create mode 100644 tests/qtest/xlnx-can-test.c > > > > diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build > > index 874b5be..945f86c 100644 > > --- a/tests/qtest/meson.build > > +++ b/tests/qtest/meson.build > > @@ -148,6 +148,7 @@ qtests_aarch64 = \ > > (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ > > ['numa-test', > > 'boot-serial-test', > > + 'xlnx-can-test', > > 'migration-test'] > > > > qtests_s390x = \ > > diff --git a/tests/qtest/xlnx-can-test.c b/tests/qtest/xlnx-can-test.c > > new file mode 100644 > > index 0000000..d04189f > > --- /dev/null > > +++ b/tests/qtest/xlnx-can-test.c > > @@ -0,0 +1,359 @@ > > +/* > > + * QTests for the Xilinx ZynqMP CAN controller. > > + * > > + * Copyright (c) 2020 Xilinx Inc. > > + * > > + * Written-by: Vikram Garhwal<fnu.vikram@xilinx.com> > > + * > > + * Permission is hereby granted, free of charge, to any person obtaining a copy > > + * of this software and associated documentation files (the "Software"), to deal > > + * in the Software without restriction, including without limitation the rights > > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > > + * copies of the Software, and to permit persons to whom the Software is > > + * furnished to do so, subject to the following conditions: > > + * > > + * The above copyright notice and this permission notice shall be included in > > + * all copies or substantial portions of the Software. > > + * > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > > + * THE SOFTWARE. > > + */ > > + > > +#include "qemu/osdep.h" > > +#include "libqos/libqtest.h" > > + > > +/* Base address. */ > > +#define CAN0_BASE_ADDR 0xFF060000 > > +#define CAN1_BASE_ADDR 0xFF070000 > > + > > +/* Register addresses. */ > > +#define R_SRR_OFFSET 0x00 > > +#define R_MSR_OFFSET 0x04 > > +#define R_SR_OFFSET 0x18 > > +#define R_ISR_OFFSET 0x1C > > +#define R_ICR_OFFSET 0x24 > > +#define R_TXID_OFFSET 0x30 > > +#define R_TXDLC_OFFSET 0x34 > > +#define R_TXDATA1_OFFSET 0x38 > > +#define R_TXDATA2_OFFSET 0x3C > > +#define R_RXID_OFFSET 0x50 > > +#define R_RXDLC_OFFSET 0x54 > > +#define R_RXDATA1_OFFSET 0x58 > > +#define R_RXDATA2_OFFSET 0x5C > > +#define R_AFR 0x60 > > +#define R_AFMR1 0x64 > > +#define R_AFIR1 0x68 > > +#define R_AFMR2 0x6C > > +#define R_AFIR2 0x70 > > +#define R_AFMR3 0x74 > > +#define R_AFIR3 0x78 > > +#define R_AFMR4 0x7C > > +#define R_AFIR4 0x80 > > + > > +/* CAN modes. */ > > +#define CONFIG_MODE 0x00 > > +#define NORMAL_MODE 0x00 > > +#define LOOPBACK_MODE 0x02 > > +#define SNOOP_MODE 0x04 > > +#define SLEEP_MODE 0x01 > > +#define ENABLE_CAN (1 << 1) > > +#define STATUS_NORMAL_MODE (1 << 3) > > +#define STATUS_LOOPBACK_MODE (1 << 1) > > +#define STATUS_SNOOP_MODE (1 << 12) > > +#define STATUS_SLEEP_MODE (1 << 2) > > +#define ISR_TXOK (1 << 1) > > +#define ISR_RXOK (1 << 4) > > + > > +static void match_rx_tx_data(uint32_t *buf_tx, uint32_t *buf_rx, > > + uint8_t can_timestamp) > > Both buf_tx/buf_rx should be const. > > > +{ > > + uint16_t size = 0; > > + uint8_t len = 4; > > + > > + while (size < len) { > > + if (R_RXID_OFFSET + 4 * size == R_RXDLC_OFFSET) { > > + g_assert_cmpint(buf_rx[size], ==, buf_tx[size] + can_timestamp); > > + } else { > > + g_assert_cmpint(buf_rx[size], ==, buf_tx[size]); > > + } > > + > > + size++; > > + } > > +} > > + > > +static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx) > > +{ > > + uint32_t int_status; > > + > > + /* Read the interrupt on CAN rx. */ > > + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK; > > + > > + g_assert_cmpint(int_status, ==, ISR_RXOK); > > + > > + /* Read the RX register data for CAN. */ > > + buf_rx[0] = qtest_readl(qts, can_base_addr + R_RXID_OFFSET); > > + buf_rx[1] = qtest_readl(qts, can_base_addr + R_RXDLC_OFFSET); > > + buf_rx[2] = qtest_readl(qts, can_base_addr + R_RXDATA1_OFFSET); > > + buf_rx[3] = qtest_readl(qts, can_base_addr + R_RXDATA2_OFFSET); > > + > > + /* Clear the RX interrupt. */ > > + qtest_writel(qts, CAN1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK); > > +} > > + > > +static void send_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_tx) > > +{ > > buf_tx should be const. > > > + uint32_t int_status; > > + > > + /* Write the TX register data for CAN. */ > > + qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]); > > + qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]); > > + qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]); > > + qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]); > > + > > + /* Read the interrupt on CAN for tx. */ > > + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK; > > + > > + g_assert_cmpint(int_status, ==, ISR_TXOK); > > + > > + /* Clear the interrupt for tx. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK); > > +} > > + > > +/* > > + * This test will be transferring data from CAN0 and CAN1 through canbus. CAN0 > > + * initiate the data transfer to can-bus, CAN1 receives the data. Test compares > > + * the data sent from CAN0 with received on CAN1. > > + */ > > +static void test_can_bus(void) > > +{ > > + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; > > buf_tx should be const (similarly in the followng tests). > > Can probably be cleaned on top of this patch, so: > Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> > > > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > > + uint32_t status = 0; > > + uint8_t can_timestamp = 1; > > + > > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > > + " -object can-bus,id=canbus0" > > + " -machine xlnx-zcu102.canbus0=canbus0" > > + " -machine xlnx-zcu102.canbus1=canbus0" > > + ); > > + > > + /* Configure the CAN0 and CAN1. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + > > + /* Check here if CAN0 and CAN1 are in normal mode. */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > > + > > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > > + > > + qtest_quit(qts); > > +} > > + > > +/* > > + * This test is performing loopback mode on CAN0 and CAN1. Data sent from TX of > > + * each CAN0 and CAN1 are compared with RX register data for respective CAN. > > + */ > > +static void test_can_loopback(void) > > +{ > > + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; > > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > > + uint32_t status = 0; > > + > > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > > + " -object can-bus,id=canbus0" > > + " -machine xlnx-zcu102.canbus0=canbus0" > > + " -machine xlnx-zcu102.canbus1=canbus0" > > + ); > > + > > + /* Configure the CAN0 in loopback mode. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + > > + /* Check here if CAN0 is set in loopback mode. */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + > > + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); > > + > > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > > + match_rx_tx_data(buf_tx, buf_rx, 0); > > + > > + /* Configure the CAN1 in loopback mode. */ > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + > > + /* Check here if CAN1 is set in loopback mode. */ > > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > > + > > + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); > > + > > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > > + match_rx_tx_data(buf_tx, buf_rx, 0); > > + > > + qtest_quit(qts); > > +} > > + > > +/* > > + * Enable filters for CAN1. This will filter incoming messages with ID. In this > > + * test message will pass through filter 2. > > + */ > > +static void test_can_filter(void) > > +{ > > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > > + uint32_t status = 0; > > + uint8_t can_timestamp = 1; > > + > > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > > + " -object can-bus,id=canbus0" > > + " -machine xlnx-zcu102.canbus0=canbus0" > > + " -machine xlnx-zcu102.canbus1=canbus0" > > + ); > > + > > + /* Configure the CAN0 and CAN1. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + > > + /* Check here if CAN0 and CAN1 are in normal mode. */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + /* Set filter for CAN1 for incoming messages. */ > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0x0); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR1, 0xF7); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR1, 0x121F); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR2, 0x5431); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR2, 0x14); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR3, 0x1234); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR3, 0x5431); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR4, 0xFFF); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR4, 0x1234); > > + > > + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0xF); > > + > > + send_data(qts, CAN0_BASE_ADDR, buf_tx); > > + > > + read_data(qts, CAN1_BASE_ADDR, buf_rx); > > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > > + > > + qtest_quit(qts); > > +} > > + > > +/* Testing sleep mode on CAN0 while CAN1 is in normal mode. */ > > +static void test_can_sleepmode(void) > > +{ > > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > > + uint32_t status = 0; > > + uint8_t can_timestamp = 1; > > + > > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > > + " -object can-bus,id=canbus0" > > + " -machine xlnx-zcu102.canbus0=canbus0" > > + " -machine xlnx-zcu102.canbus1=canbus0" > > + ); > > + > > + /* Configure the CAN0. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SLEEP_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + > > + /* Check here if CAN0 is in SLEEP mode and CAN1 in normal mode. */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_SLEEP_MODE); > > + > > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > > + > > + /* > > + * Once CAN1 sends data on can-bus. CAN0 should exit sleep mode. > > + * Check the CAN0 status now. It should exit the sleep mode and receive the > > + * incoming data. > > + */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > > + > > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > > + > > + qtest_quit(qts); > > +} > > + > > +/* Testing Snoop mode on CAN0 while CAN1 is in normal mode. */ > > +static void test_can_snoopmode(void) > > +{ > > + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; > > + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; > > + uint32_t status = 0; > > + uint8_t can_timestamp = 1; > > + > > + QTestState *qts = qtest_init("-machine xlnx-zcu102" > > + " -object can-bus,id=canbus0" > > + " -machine xlnx-zcu102.canbus0=canbus0" > > + " -machine xlnx-zcu102.canbus1=canbus0" > > + ); > > + > > + /* Configure the CAN0. */ > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SNOOP_MODE); > > + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + > > + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); > > + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); > > + > > + /* Check here if CAN0 is in SNOOP mode and CAN1 in normal mode. */ > > + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_SNOOP_MODE); > > + > > + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); > > + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); > > + > > + send_data(qts, CAN1_BASE_ADDR, buf_tx); > > + > > + read_data(qts, CAN0_BASE_ADDR, buf_rx); > > + > > + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); > > + > > + qtest_quit(qts); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + g_test_init(&argc, &argv, NULL); > > + > > + qtest_add_func("/net/can/can_bus", test_can_bus); > > + qtest_add_func("/net/can/can_loopback", test_can_loopback); > > + qtest_add_func("/net/can/can_filter", test_can_filter); > > + qtest_add_func("/net/can/can_test_snoopmode", test_can_snoopmode); > > + qtest_add_func("/net/can/can_test_sleepmode", test_can_sleepmode); > > + > > + return g_test_run(); > > +} > > >
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 874b5be..945f86c 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -148,6 +148,7 @@ qtests_aarch64 = \ (config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? ['tpm-tis-device-swtpm-test'] : []) + \ ['numa-test', 'boot-serial-test', + 'xlnx-can-test', 'migration-test'] qtests_s390x = \ diff --git a/tests/qtest/xlnx-can-test.c b/tests/qtest/xlnx-can-test.c new file mode 100644 index 0000000..d04189f --- /dev/null +++ b/tests/qtest/xlnx-can-test.c @@ -0,0 +1,359 @@ +/* + * QTests for the Xilinx ZynqMP CAN controller. + * + * Copyright (c) 2020 Xilinx Inc. + * + * Written-by: Vikram Garhwal<fnu.vikram@xilinx.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "libqos/libqtest.h" + +/* Base address. */ +#define CAN0_BASE_ADDR 0xFF060000 +#define CAN1_BASE_ADDR 0xFF070000 + +/* Register addresses. */ +#define R_SRR_OFFSET 0x00 +#define R_MSR_OFFSET 0x04 +#define R_SR_OFFSET 0x18 +#define R_ISR_OFFSET 0x1C +#define R_ICR_OFFSET 0x24 +#define R_TXID_OFFSET 0x30 +#define R_TXDLC_OFFSET 0x34 +#define R_TXDATA1_OFFSET 0x38 +#define R_TXDATA2_OFFSET 0x3C +#define R_RXID_OFFSET 0x50 +#define R_RXDLC_OFFSET 0x54 +#define R_RXDATA1_OFFSET 0x58 +#define R_RXDATA2_OFFSET 0x5C +#define R_AFR 0x60 +#define R_AFMR1 0x64 +#define R_AFIR1 0x68 +#define R_AFMR2 0x6C +#define R_AFIR2 0x70 +#define R_AFMR3 0x74 +#define R_AFIR3 0x78 +#define R_AFMR4 0x7C +#define R_AFIR4 0x80 + +/* CAN modes. */ +#define CONFIG_MODE 0x00 +#define NORMAL_MODE 0x00 +#define LOOPBACK_MODE 0x02 +#define SNOOP_MODE 0x04 +#define SLEEP_MODE 0x01 +#define ENABLE_CAN (1 << 1) +#define STATUS_NORMAL_MODE (1 << 3) +#define STATUS_LOOPBACK_MODE (1 << 1) +#define STATUS_SNOOP_MODE (1 << 12) +#define STATUS_SLEEP_MODE (1 << 2) +#define ISR_TXOK (1 << 1) +#define ISR_RXOK (1 << 4) + +static void match_rx_tx_data(uint32_t *buf_tx, uint32_t *buf_rx, + uint8_t can_timestamp) +{ + uint16_t size = 0; + uint8_t len = 4; + + while (size < len) { + if (R_RXID_OFFSET + 4 * size == R_RXDLC_OFFSET) { + g_assert_cmpint(buf_rx[size], ==, buf_tx[size] + can_timestamp); + } else { + g_assert_cmpint(buf_rx[size], ==, buf_tx[size]); + } + + size++; + } +} + +static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx) +{ + uint32_t int_status; + + /* Read the interrupt on CAN rx. */ + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK; + + g_assert_cmpint(int_status, ==, ISR_RXOK); + + /* Read the RX register data for CAN. */ + buf_rx[0] = qtest_readl(qts, can_base_addr + R_RXID_OFFSET); + buf_rx[1] = qtest_readl(qts, can_base_addr + R_RXDLC_OFFSET); + buf_rx[2] = qtest_readl(qts, can_base_addr + R_RXDATA1_OFFSET); + buf_rx[3] = qtest_readl(qts, can_base_addr + R_RXDATA2_OFFSET); + + /* Clear the RX interrupt. */ + qtest_writel(qts, CAN1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK); +} + +static void send_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_tx) +{ + uint32_t int_status; + + /* Write the TX register data for CAN. */ + qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]); + qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]); + qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]); + qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]); + + /* Read the interrupt on CAN for tx. */ + int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK; + + g_assert_cmpint(int_status, ==, ISR_TXOK); + + /* Clear the interrupt for tx. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK); +} + +/* + * This test will be transferring data from CAN0 and CAN1 through canbus. CAN0 + * initiate the data transfer to can-bus, CAN1 receives the data. Test compares + * the data sent from CAN0 with received on CAN1. + */ +static void test_can_bus(void) +{ + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint32_t status = 0; + uint8_t can_timestamp = 1; + + QTestState *qts = qtest_init("-machine xlnx-zcu102" + " -object can-bus,id=canbus0" + " -machine xlnx-zcu102.canbus0=canbus0" + " -machine xlnx-zcu102.canbus1=canbus0" + ); + + /* Configure the CAN0 and CAN1. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + + /* Check here if CAN0 and CAN1 are in normal mode. */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + send_data(qts, CAN0_BASE_ADDR, buf_tx); + + read_data(qts, CAN1_BASE_ADDR, buf_rx); + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); + + qtest_quit(qts); +} + +/* + * This test is performing loopback mode on CAN0 and CAN1. Data sent from TX of + * each CAN0 and CAN1 are compared with RX register data for respective CAN. + */ +static void test_can_loopback(void) +{ + uint32_t buf_tx[4] = { 0xFF, 0x80000000, 0x12345678, 0x87654321 }; + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint32_t status = 0; + + QTestState *qts = qtest_init("-machine xlnx-zcu102" + " -object can-bus,id=canbus0" + " -machine xlnx-zcu102.canbus0=canbus0" + " -machine xlnx-zcu102.canbus1=canbus0" + ); + + /* Configure the CAN0 in loopback mode. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + + /* Check here if CAN0 is set in loopback mode. */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); + + send_data(qts, CAN0_BASE_ADDR, buf_tx); + read_data(qts, CAN0_BASE_ADDR, buf_rx); + match_rx_tx_data(buf_tx, buf_rx, 0); + + /* Configure the CAN1 in loopback mode. */ + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, LOOPBACK_MODE); + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + + /* Check here if CAN1 is set in loopback mode. */ + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); + + g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE); + + send_data(qts, CAN1_BASE_ADDR, buf_tx); + read_data(qts, CAN1_BASE_ADDR, buf_rx); + match_rx_tx_data(buf_tx, buf_rx, 0); + + qtest_quit(qts); +} + +/* + * Enable filters for CAN1. This will filter incoming messages with ID. In this + * test message will pass through filter 2. + */ +static void test_can_filter(void) +{ + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint32_t status = 0; + uint8_t can_timestamp = 1; + + QTestState *qts = qtest_init("-machine xlnx-zcu102" + " -object can-bus,id=canbus0" + " -machine xlnx-zcu102.canbus0=canbus0" + " -machine xlnx-zcu102.canbus1=canbus0" + ); + + /* Configure the CAN0 and CAN1. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + + /* Check here if CAN0 and CAN1 are in normal mode. */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + /* Set filter for CAN1 for incoming messages. */ + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0x0); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR1, 0xF7); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR1, 0x121F); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR2, 0x5431); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR2, 0x14); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR3, 0x1234); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR3, 0x5431); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFMR4, 0xFFF); + qtest_writel(qts, CAN1_BASE_ADDR + R_AFIR4, 0x1234); + + qtest_writel(qts, CAN1_BASE_ADDR + R_AFR, 0xF); + + send_data(qts, CAN0_BASE_ADDR, buf_tx); + + read_data(qts, CAN1_BASE_ADDR, buf_rx); + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); + + qtest_quit(qts); +} + +/* Testing sleep mode on CAN0 while CAN1 is in normal mode. */ +static void test_can_sleepmode(void) +{ + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint32_t status = 0; + uint8_t can_timestamp = 1; + + QTestState *qts = qtest_init("-machine xlnx-zcu102" + " -object can-bus,id=canbus0" + " -machine xlnx-zcu102.canbus0=canbus0" + " -machine xlnx-zcu102.canbus1=canbus0" + ); + + /* Configure the CAN0. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SLEEP_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + + /* Check here if CAN0 is in SLEEP mode and CAN1 in normal mode. */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_SLEEP_MODE); + + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + send_data(qts, CAN1_BASE_ADDR, buf_tx); + + /* + * Once CAN1 sends data on can-bus. CAN0 should exit sleep mode. + * Check the CAN0 status now. It should exit the sleep mode and receive the + * incoming data. + */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + read_data(qts, CAN0_BASE_ADDR, buf_rx); + + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); + + qtest_quit(qts); +} + +/* Testing Snoop mode on CAN0 while CAN1 is in normal mode. */ +static void test_can_snoopmode(void) +{ + uint32_t buf_tx[4] = { 0x14, 0x80000000, 0x12345678, 0x87654321 }; + uint32_t buf_rx[4] = { 0x00, 0x00, 0x00, 0x00 }; + uint32_t status = 0; + uint8_t can_timestamp = 1; + + QTestState *qts = qtest_init("-machine xlnx-zcu102" + " -object can-bus,id=canbus0" + " -machine xlnx-zcu102.canbus0=canbus0" + " -machine xlnx-zcu102.canbus1=canbus0" + ); + + /* Configure the CAN0. */ + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, CONFIG_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_MSR_OFFSET, SNOOP_MODE); + qtest_writel(qts, CAN0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + + qtest_writel(qts, CAN1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CAN); + qtest_writel(qts, CAN1_BASE_ADDR + R_MSR_OFFSET, NORMAL_MODE); + + /* Check here if CAN0 is in SNOOP mode and CAN1 in normal mode. */ + status = qtest_readl(qts, CAN0_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_SNOOP_MODE); + + status = qtest_readl(qts, CAN1_BASE_ADDR + R_SR_OFFSET); + g_assert_cmpint(status, ==, STATUS_NORMAL_MODE); + + send_data(qts, CAN1_BASE_ADDR, buf_tx); + + read_data(qts, CAN0_BASE_ADDR, buf_rx); + + match_rx_tx_data(buf_tx, buf_rx, can_timestamp); + + qtest_quit(qts); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/net/can/can_bus", test_can_bus); + qtest_add_func("/net/can/can_loopback", test_can_loopback); + qtest_add_func("/net/can/can_filter", test_can_filter); + qtest_add_func("/net/can/can_test_snoopmode", test_can_snoopmode); + qtest_add_func("/net/can/can_test_sleepmode", test_can_sleepmode); + + return g_test_run(); +}