We use a test device, "PONG" to transfer chunks of data of different size and alignment and compare a checksum calculated before the sending with the VIRTIO device checksum response. Signed-off-by: Pierre Morel <pmorel@xxxxxxxxxxxxx> --- s390x/virtio_pong.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/s390x/virtio_pong.c b/s390x/virtio_pong.c index 1e050a4d..94d6acdc 100644 --- a/s390x/virtio_pong.c +++ b/s390x/virtio_pong.c @@ -39,6 +39,112 @@ static struct virtio_ccw_device *vcdev; static struct virtqueue *out_vq; static struct virtqueue *in_vq; +static bool virtio_read(struct virtqueue *q, char **buf, unsigned int *len) +{ + int ret; + char *p; + + ret = virtqueue_add_inbuf(q, *buf, *len); + if (ret < 0) + return false; + + disable_io_irq(); + virtqueue_kick(q); + wait_for_interrupt(PSW_MASK_IO); + + do { + p = virtqueue_get_buf(q, len); + } while (!p); + + *buf = (void *)p; + + return true; +} + +static bool virtio_write(struct virtqueue *q, char *buf, unsigned int len) +{ + int ret; + + ret = virtqueue_add_outbuf(q, buf, len); + if (ret < 0) + return false; + + virtqueue_kick(q); + while (!virtqueue_get_buf(q, &len)) + ; + + return true; +} + +static unsigned int simple_checksum(char *buf, unsigned int len) +{ + unsigned int sum = 0; + + while (len--) { + sum += *buf * *buf + 7 * *buf + 3; + buf++; + } + + return sum; +} + +static void pong_write(char *buf, unsigned int len) +{ + unsigned int cksum; + unsigned int cksum_ret; + char *ret_ptr = (char *)&cksum_ret; + + cksum = simple_checksum(buf, len); + report(virtio_write(out_vq, buf, len), "Sending data: %08x", cksum); + + len = sizeof(cksum_ret); + report(virtio_read(in_vq, &ret_ptr, &len), + "Receiving checksum: %08x", cksum_ret); + + report(cksum == cksum_ret, "Verifying checksum"); +} + +static struct { + const char *name; + int size; + int offset; +} chunks[] = { + { "Small buffer", 3, 0 }, + { "Page aligned", 4096, 0 }, + { "Large page aligned", 0x00100000, 0 }, + { "Page unaligned", 4096, 0x107 }, + { "Random data", 5119, 0x107 }, + { NULL, 0, 0 } +}; + +static void test_pong_data(void) +{ + char *buf; + char *p; + int len; + int i; + + if (vcdev->state != VCDEV_INIT) { + report_skip("Device non initialized"); + return; + } + + for (i = 0; chunks[i].name; i++) { + report_prefix_push(chunks[i].name); + + len = chunks[i].size + chunks[i].offset; + buf = alloc_io_mem(len, 0); + + p = buf + chunks[i].offset; + memset(p, 0xA5, chunks[i].size); + pong_write(p, chunks[i].size); + + free_io_mem(buf, len); + + report_prefix_pop(); + } +} + static void test_find_vqs(void) { struct virtio_device *vdev = &vcdev->vdev; @@ -186,6 +292,7 @@ static struct { { "CCW Bus", test_virtio_ccw_bus }, { "CCW Device", test_virtio_device_init }, { "Queues setup", test_find_vqs }, + { "Data transfer", test_pong_data }, { NULL, NULL } }; -- 2.25.1