diff options
Diffstat (limited to 'tests/libqos')
-rw-r--r-- | tests/libqos/arm-imx25-pdk-machine.c | 92 | ||||
-rw-r--r-- | tests/libqos/arm-n800-machine.c | 92 | ||||
-rw-r--r-- | tests/libqos/i2c-imx.c | 40 | ||||
-rw-r--r-- | tests/libqos/i2c-omap.c | 70 | ||||
-rw-r--r-- | tests/libqos/i2c.c | 74 | ||||
-rw-r--r-- | tests/libqos/i2c.h | 63 | ||||
-rw-r--r-- | tests/libqos/qgraph.c | 12 | ||||
-rw-r--r-- | tests/libqos/qgraph.h | 15 |
8 files changed, 394 insertions, 64 deletions
diff --git a/tests/libqos/arm-imx25-pdk-machine.c b/tests/libqos/arm-imx25-pdk-machine.c new file mode 100644 index 0000000000..25066fb8a9 --- /dev/null +++ b/tests/libqos/arm-imx25-pdk-machine.c @@ -0,0 +1,92 @@ +/* + * libqos driver framework + * + * Copyright (c) 2019 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/malloc.h" +#include "libqos/qgraph.h" +#include "libqos/i2c.h" + +#define ARM_PAGE_SIZE 4096 +#define IMX25_PDK_RAM_START 0x80000000 +#define IMX25_PDK_RAM_END 0x88000000 + +typedef struct QIMX25PDKMachine QIMX25PDKMachine; + +struct QIMX25PDKMachine { + QOSGraphObject obj; + QGuestAllocator alloc; + IMXI2C i2c_1; +}; + +static void *imx25_pdk_get_driver(void *object, const char *interface) +{ + QIMX25PDKMachine *machine = object; + if (!g_strcmp0(interface, "memory")) { + return &machine->alloc; + } + + fprintf(stderr, "%s not present in arm/imx25_pdk\n", interface); + g_assert_not_reached(); +} + +static QOSGraphObject *imx25_pdk_get_device(void *obj, const char *device) +{ + QIMX25PDKMachine *machine = obj; + if (!g_strcmp0(device, "imx.i2c")) { + return &machine->i2c_1.obj; + } + + fprintf(stderr, "%s not present in arm/imx25_pdk\n", device); + g_assert_not_reached(); +} + +static void imx25_pdk_destructor(QOSGraphObject *obj) +{ + QIMX25PDKMachine *machine = (QIMX25PDKMachine *) obj; + alloc_destroy(&machine->alloc); +} + +static void *qos_create_machine_arm_imx25_pdk(QTestState *qts) +{ + QIMX25PDKMachine *machine = g_new0(QIMX25PDKMachine, 1); + + alloc_init(&machine->alloc, 0, + IMX25_PDK_RAM_START, + IMX25_PDK_RAM_END, + ARM_PAGE_SIZE); + machine->obj.get_device = imx25_pdk_get_device; + machine->obj.get_driver = imx25_pdk_get_driver; + machine->obj.destructor = imx25_pdk_destructor; + + imx_i2c_init(&machine->i2c_1, qts, 0x43f80000); + return &machine->obj; +} + +static void imx25_pdk_register_nodes(void) +{ + QOSGraphEdgeOptions edge = { + .extra_device_opts = "bus=i2c-bus.0" + }; + qos_node_create_machine("arm/imx25-pdk", qos_create_machine_arm_imx25_pdk); + qos_node_contains("arm/imx25-pdk", "imx.i2c", &edge, NULL); +} + +libqos_init(imx25_pdk_register_nodes); diff --git a/tests/libqos/arm-n800-machine.c b/tests/libqos/arm-n800-machine.c new file mode 100644 index 0000000000..87279bdb26 --- /dev/null +++ b/tests/libqos/arm-n800-machine.c @@ -0,0 +1,92 @@ +/* + * libqos driver framework + * + * Copyright (c) 2019 Red Hat, Inc. + * + * Author: Paolo Bonzini <pbonzini@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/malloc.h" +#include "libqos/qgraph.h" +#include "libqos/i2c.h" + +#define ARM_PAGE_SIZE 4096 +#define N800_RAM_START 0x80000000 +#define N800_RAM_END 0x88000000 + +typedef struct QN800Machine QN800Machine; + +struct QN800Machine { + QOSGraphObject obj; + QGuestAllocator alloc; + OMAPI2C i2c_1; +}; + +static void *n800_get_driver(void *object, const char *interface) +{ + QN800Machine *machine = object; + if (!g_strcmp0(interface, "memory")) { + return &machine->alloc; + } + + fprintf(stderr, "%s not present in arm/n800\n", interface); + g_assert_not_reached(); +} + +static QOSGraphObject *n800_get_device(void *obj, const char *device) +{ + QN800Machine *machine = obj; + if (!g_strcmp0(device, "omap_i2c")) { + return &machine->i2c_1.obj; + } + + fprintf(stderr, "%s not present in arm/n800\n", device); + g_assert_not_reached(); +} + +static void n800_destructor(QOSGraphObject *obj) +{ + QN800Machine *machine = (QN800Machine *) obj; + alloc_destroy(&machine->alloc); +} + +static void *qos_create_machine_arm_n800(QTestState *qts) +{ + QN800Machine *machine = g_new0(QN800Machine, 1); + + alloc_init(&machine->alloc, 0, + N800_RAM_START, + N800_RAM_END, + ARM_PAGE_SIZE); + machine->obj.get_device = n800_get_device; + machine->obj.get_driver = n800_get_driver; + machine->obj.destructor = n800_destructor; + + omap_i2c_init(&machine->i2c_1, qts, 0x48070000); + return &machine->obj; +} + +static void n800_register_nodes(void) +{ + QOSGraphEdgeOptions edge = { + .extra_device_opts = "bus=i2c-bus.0" + }; + qos_node_create_machine("arm/n800", qos_create_machine_arm_n800); + qos_node_contains("arm/n800", "omap_i2c", &edge, NULL); +} + +libqos_init(n800_register_nodes); diff --git a/tests/libqos/i2c-imx.c b/tests/libqos/i2c-imx.c index 0945f2ecdc..f33ece55a3 100644 --- a/tests/libqos/i2c-imx.c +++ b/tests/libqos/i2c-imx.c @@ -30,13 +30,6 @@ enum IMXI2CDirection { IMX_I2C_WRITE, }; -typedef struct IMXI2C { - I2CAdapter parent; - - uint64_t addr; -} IMXI2C; - - static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, enum IMXI2CDirection direction) { @@ -47,7 +40,7 @@ static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr, const uint8_t *buf, uint16_t len) { - IMXI2C *s = (IMXI2C *)i2c; + IMXI2C *s = container_of(i2c, IMXI2C, parent); uint8_t data; uint8_t status; uint16_t size = 0; @@ -107,7 +100,7 @@ static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr, static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr, uint8_t *buf, uint16_t len) { - IMXI2C *s = (IMXI2C *)i2c; + IMXI2C *s = container_of(i2c, IMXI2C, parent); uint8_t data; uint8_t status; uint16_t size = 0; @@ -193,16 +186,31 @@ static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr, g_assert((status & I2SR_IBB) == 0); } -I2CAdapter *imx_i2c_create(QTestState *qts, uint64_t addr) +static void *imx_i2c_get_driver(void *obj, const char *interface) { - IMXI2C *s = g_malloc0(sizeof(*s)); - I2CAdapter *i2c = (I2CAdapter *)s; + IMXI2C *s = obj; + if (!g_strcmp0(interface, "i2c-bus")) { + return &s->parent; + } + fprintf(stderr, "%s not present in imx-i2c\n", interface); + g_assert_not_reached(); +} +void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr) +{ s->addr = addr; - i2c->send = imx_i2c_send; - i2c->recv = imx_i2c_recv; - i2c->qts = qts; + s->obj.get_driver = imx_i2c_get_driver; - return i2c; + s->parent.send = imx_i2c_send; + s->parent.recv = imx_i2c_recv; + s->parent.qts = qts; } + +static void imx_i2c_register_nodes(void) +{ + qos_node_create_driver("imx.i2c", NULL); + qos_node_produces("imx.i2c", "i2c-bus"); +} + +libqos_init(imx_i2c_register_nodes); diff --git a/tests/libqos/i2c-omap.c b/tests/libqos/i2c-omap.c index 1ef6e7b200..9ae8214fa8 100644 --- a/tests/libqos/i2c-omap.c +++ b/tests/libqos/i2c-omap.c @@ -40,12 +40,6 @@ enum OMAPI2CCONBits { OMAP_I2C_CON_I2C_EN = 1 << 15, }; -typedef struct OMAPI2C { - I2CAdapter parent; - - uint64_t addr; -} OMAPI2C; - static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) { @@ -59,7 +53,7 @@ static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr) static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr, const uint8_t *buf, uint16_t len) { - OMAPI2C *s = (OMAPI2C *)i2c; + OMAPI2C *s = container_of(i2c, OMAPI2C, parent); uint16_t data; omap_i2c_set_slave_addr(s, addr); @@ -103,8 +97,9 @@ static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr, static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, uint8_t *buf, uint16_t len) { - OMAPI2C *s = (OMAPI2C *)i2c; + OMAPI2C *s = container_of(i2c, OMAPI2C, parent); uint16_t data, stat; + uint16_t orig_len = len; omap_i2c_set_slave_addr(s, addr); @@ -116,16 +111,24 @@ static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, OMAP_I2C_CON_STT | OMAP_I2C_CON_STP; qtest_writew(i2c->qts, s->addr + OMAP_I2C_CON, data); - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON); - g_assert((data & OMAP_I2C_CON_STP) == 0); data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_NACK) == 0); - data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT); - g_assert_cmpuint(data, ==, len); - while (len > 0) { + data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CON); + if (len <= 4) { + g_assert((data & OMAP_I2C_CON_STP) == 0); + + data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT); + g_assert_cmpuint(data, ==, orig_len); + } else { + g_assert((data & OMAP_I2C_CON_STP) != 0); + + data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_CNT); + g_assert_cmpuint(data, ==, len - 4); + } + data = qtest_readw(i2c->qts, s->addr + OMAP_I2C_STAT); g_assert((data & OMAP_I2C_STAT_RRDY) != 0); g_assert((data & OMAP_I2C_STAT_ROVR) == 0); @@ -152,21 +155,42 @@ static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr, g_assert((data & OMAP_I2C_CON_STP) == 0); } -I2CAdapter *omap_i2c_create(QTestState *qts, uint64_t addr) +static void *omap_i2c_get_driver(void *obj, const char *interface) +{ + OMAPI2C *s = obj; + if (!g_strcmp0(interface, "i2c-bus")) { + return &s->parent; + } + fprintf(stderr, "%s not present in omap_i2c\n", interface); + g_assert_not_reached(); +} + +static void omap_i2c_start_hw(QOSGraphObject *object) { - OMAPI2C *s = g_malloc0(sizeof(*s)); - I2CAdapter *i2c = (I2CAdapter *)s; + OMAPI2C *s = (OMAPI2C *) object; uint16_t data; + /* verify the mmio address by looking for a known signature */ + data = qtest_readw(s->parent.qts, s->addr + OMAP_I2C_REV); + g_assert_cmphex(data, ==, 0x34); +} + +void omap_i2c_init(OMAPI2C *s, QTestState *qts, uint64_t addr) +{ s->addr = addr; - i2c->send = omap_i2c_send; - i2c->recv = omap_i2c_recv; - i2c->qts = qts; + s->obj.get_driver = omap_i2c_get_driver; + s->obj.start_hw = omap_i2c_start_hw; - /* verify the mmio address by looking for a known signature */ - data = qtest_readw(qts, addr + OMAP_I2C_REV); - g_assert_cmphex(data, ==, 0x34); + s->parent.send = omap_i2c_send; + s->parent.recv = omap_i2c_recv; + s->parent.qts = qts; +} - return i2c; +static void omap_i2c_register_nodes(void) +{ + qos_node_create_driver("omap_i2c", NULL); + qos_node_produces("omap_i2c", "i2c-bus"); } + +libqos_init(omap_i2c_register_nodes); diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c index 23bc2a3eb2..156114e745 100644 --- a/tests/libqos/i2c.c +++ b/tests/libqos/i2c.c @@ -10,14 +10,76 @@ #include "libqos/i2c.h" #include "libqtest.h" -void i2c_send(I2CAdapter *i2c, uint8_t addr, - const uint8_t *buf, uint16_t len) +void i2c_send(QI2CDevice *i2cdev, const uint8_t *buf, uint16_t len) { - i2c->send(i2c, addr, buf, len); + i2cdev->bus->send(i2cdev->bus, i2cdev->addr, buf, len); } -void i2c_recv(I2CAdapter *i2c, uint8_t addr, - uint8_t *buf, uint16_t len) +void i2c_recv(QI2CDevice *i2cdev, uint8_t *buf, uint16_t len) { - i2c->recv(i2c, addr, buf, len); + i2cdev->bus->recv(i2cdev->bus, i2cdev->addr, buf, len); +} + +void i2c_read_block(QI2CDevice *i2cdev, uint8_t reg, + uint8_t *buf, uint16_t len) +{ + i2c_send(i2cdev, ®, 1); + i2c_recv(i2cdev, buf, len); +} + +void i2c_write_block(QI2CDevice *i2cdev, uint8_t reg, + const uint8_t *buf, uint16_t len) +{ + uint8_t *cmd = g_malloc(len + 1); + cmd[0] = reg; + memcpy(&cmd[1], buf, len); + i2c_send(i2cdev, cmd, len + 1); + g_free(cmd); +} + +uint8_t i2c_get8(QI2CDevice *i2cdev, uint8_t reg) +{ + uint8_t resp[1]; + i2c_read_block(i2cdev, reg, resp, sizeof(resp)); + return resp[0]; +} + +uint16_t i2c_get16(QI2CDevice *i2cdev, uint8_t reg) +{ + uint8_t resp[2]; + i2c_read_block(i2cdev, reg, resp, sizeof(resp)); + return (resp[0] << 8) | resp[1]; +} + +void i2c_set8(QI2CDevice *i2cdev, uint8_t reg, uint8_t value) +{ + i2c_write_block(i2cdev, reg, &value, 1); +} + +void i2c_set16(QI2CDevice *i2cdev, uint8_t reg, uint16_t value) +{ + uint8_t data[2]; + + data[0] = value >> 8; + data[1] = value & 255; + i2c_write_block(i2cdev, reg, data, sizeof(data)); +} + +void *i2c_device_create(void *i2c_bus, QGuestAllocator *alloc, void *addr) +{ + QI2CDevice *i2cdev = g_new0(QI2CDevice, 1); + + i2cdev->bus = i2c_bus; + if (addr) { + i2cdev->addr = ((QI2CAddress *)addr)->addr; + } + return &i2cdev->obj; +} + +void add_qi2c_address(QOSGraphEdgeOptions *opts, QI2CAddress *addr) +{ + g_assert(addr); + + opts->arg = addr; + opts->size_arg = sizeof(QI2CAddress); } diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h index cc01358a9f..945b65b34c 100644 --- a/tests/libqos/i2c.h +++ b/tests/libqos/i2c.h @@ -10,6 +10,7 @@ #define LIBQOS_I2C_H #include "libqtest.h" +#include "libqos/qgraph.h" typedef struct I2CAdapter I2CAdapter; struct I2CAdapter { @@ -21,17 +22,61 @@ struct I2CAdapter { QTestState *qts; }; -#define OMAP2_I2C_1_BASE 0x48070000 +typedef struct QI2CAddress QI2CAddress; +struct QI2CAddress { + uint8_t addr; +}; + +typedef struct QI2CDevice QI2CDevice; +struct QI2CDevice { + /* + * For now, all devices are simple enough that there is no need for + * them to define their own constructor and get_driver functions. + * Therefore, QOSGraphObject is included directly in QI2CDevice; + * the tests expect to get a QI2CDevice rather than doing something + * like obj->get_driver("i2c-device"). + * + * In fact there is no i2c-device interface even, because there are + * no generic I2C tests). + */ + QOSGraphObject obj; + I2CAdapter *bus; + uint8_t addr; +}; + +void *i2c_device_create(void *i2c_bus, QGuestAllocator *alloc, void *addr); +void add_qi2c_address(QOSGraphEdgeOptions *opts, QI2CAddress *addr); + +void i2c_send(QI2CDevice *dev, const uint8_t *buf, uint16_t len); +void i2c_recv(QI2CDevice *dev, uint8_t *buf, uint16_t len); + +void i2c_read_block(QI2CDevice *dev, uint8_t reg, + uint8_t *buf, uint16_t len); +void i2c_write_block(QI2CDevice *dev, uint8_t reg, + const uint8_t *buf, uint16_t len); +uint8_t i2c_get8(QI2CDevice *dev, uint8_t reg); +uint16_t i2c_get16(QI2CDevice *dev, uint8_t reg); +void i2c_set8(QI2CDevice *dev, uint8_t reg, uint8_t value); +void i2c_set16(QI2CDevice *dev, uint8_t reg, uint16_t value); + +/* i2c-omap.c */ +typedef struct OMAPI2C { + QOSGraphObject obj; + I2CAdapter parent; + + uint64_t addr; +} OMAPI2C; + +void omap_i2c_init(OMAPI2C *s, QTestState *qts, uint64_t addr); -void i2c_send(I2CAdapter *i2c, uint8_t addr, - const uint8_t *buf, uint16_t len); -void i2c_recv(I2CAdapter *i2c, uint8_t addr, - uint8_t *buf, uint16_t len); +/* i2c-imx.c */ +typedef struct IMXI2C { + QOSGraphObject obj; + I2CAdapter parent; -/* libi2c-omap.c */ -I2CAdapter *omap_i2c_create(QTestState *qts, uint64_t addr); + uint64_t addr; +} IMXI2C; -/* libi2c-imx.c */ -I2CAdapter *imx_i2c_create(QTestState *qts, uint64_t addr); +void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr); #endif diff --git a/tests/libqos/qgraph.c b/tests/libqos/qgraph.c index b149caaaa9..7a7ae2a19e 100644 --- a/tests/libqos/qgraph.c +++ b/tests/libqos/qgraph.c @@ -632,15 +632,19 @@ void qos_node_create_driver(const char *name, QOSCreateDriverFunc function) } void qos_node_contains(const char *container, const char *contained, - ...) + QOSGraphEdgeOptions *opts, ...) { va_list va; - va_start(va, contained); - QOSGraphEdgeOptions *opts; + if (opts == NULL) { + add_edge(container, contained, QEDGE_CONTAINS, NULL); + return; + } + + va_start(va, opts); do { - opts = va_arg(va, QOSGraphEdgeOptions *); add_edge(container, contained, QEDGE_CONTAINS, opts); + opts = va_arg(va, QOSGraphEdgeOptions *); } while (opts != NULL); va_end(va); diff --git a/tests/libqos/qgraph.h b/tests/libqos/qgraph.h index e799095b30..3a25dda4b2 100644 --- a/tests/libqos/qgraph.h +++ b/tests/libqos/qgraph.h @@ -453,14 +453,16 @@ void qos_node_create_machine_args(const char *name, void qos_node_create_driver(const char *name, QOSCreateDriverFunc function); /** - * qos_node_contains(): creates an edge of type QEDGE_CONTAINS and - * adds it to the edge list mapped to @container in the + * qos_node_contains(): creates one or more edges of type QEDGE_CONTAINS + * and adds them to the edge list mapped to @container in the * edge hash table. * - * This edge will have @container as source and @contained as destination. + * The edges will have @container as source and @contained as destination. * - * It also has the possibility to add optional NULL-terminated - * @opts parameters (see %QOSGraphEdgeOptions) + * If @opts is NULL, a single edge will be added with no options. + * If @opts is non-NULL, the arguments after @contained represent a + * NULL-terminated list of %QOSGraphEdgeOptions structs, and an + * edge will be added for each of them. * * This function can be useful when there are multiple devices * with the same node name contained in a machine/other node @@ -480,7 +482,8 @@ void qos_node_create_driver(const char *name, QOSCreateDriverFunc function); * For contains, op1.arg and op1.size_arg represent the arg to pass * to @contained constructor to properly initialize it. */ -void qos_node_contains(const char *container, const char *contained, ...); +void qos_node_contains(const char *container, const char *contained, + QOSGraphEdgeOptions *opts, ...); /** * qos_node_produces(): creates an edge of type QEDGE_PRODUCES and |