[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH] pci-testdev: enhance to support new testcases
From: |
Michael S. Tsirkin |
Subject: |
Re: [Qemu-devel] [PATCH] pci-testdev: enhance to support new testcases |
Date: |
Thu, 22 Sep 2016 21:23:05 +0300 |
On Thu, Sep 22, 2016 at 02:15:08PM +0800, Peter Xu wrote:
> pci-testdev is used mostly in kvm-unit-test for some eventfd tests.
> However I see it a good framework for other tests as well (e.g., the
> IOMMU unit test in the future). So enhanced it to support more
> testcases.
>
> The original memory handlers and protocol are strict and not easy to
> change (we need to keep the old behavior of pci-testdev).
> So I added a
> new parameter for the device, and memory ops will be dynamically handled
> depending on what testcase it is configured. To specify a new test case
> for pci-testdev, we use:
>
> -device pci-testdev,testcase=XXX
>
> The default will be "eventfd", which is the original behavior for
> pci-testdev. In the future, we can just add new testcase for pci-testdev
> to achieve different goals.
Instead of a parameter, how about creating a subregion
of the BAR and adding new tests at an offset?
All you need for compatibility is add a 0-filled
entry after existing tests.
>
> Signed-off-by: Peter Xu <address@hidden>
> ---
>
> This is kind-of a RFC since I am not sure whether this is a good way.
> I did run the default kvm-unit-test cases on x86 to make sure it
> didn't break anything. In case this is not good, I didn't write any
> further test cases (e.g., emulate device DMAR/IR operations) yet. If
> we like the idea, I can move on.
>
> Please kindly review. Thanks.
>
> hw/misc/pci-testdev.c | 80
> ++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 76 insertions(+), 4 deletions(-)
>
> diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c
> index 7d59902..b25d673 100644
> --- a/hw/misc/pci-testdev.c
> +++ b/hw/misc/pci-testdev.c
> @@ -22,6 +22,19 @@
> #include "hw/pci/pci.h"
> #include "qemu/event_notifier.h"
> #include "sysemu/kvm.h"
> +#include "qemu/error-report.h"
> +
> +/* Type: 0 for MMIO write, 1 for PIO write. */
> +typedef void (*pci_testdev_write_op)(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size, int type);
> +typedef uint64_t (*pci_testdev_read_op)(void *opaque, hwaddr addr,
> + unsigned size);
> +
> +struct testcase {
> + const char *name;
> + pci_testdev_write_op write_op;
> + pci_testdev_read_op read_op;
> +};
>
> typedef struct PCITestDevHdr {
> uint8_t test;
> @@ -85,6 +98,8 @@ typedef struct PCITestDevState {
> MemoryRegion portio;
> IOTest *tests;
> int current;
> + char *testcase_name;
> + struct testcase *testcase;
> } PCITestDevState;
>
> #define TYPE_PCI_TEST_DEV "pci-testdev"
> @@ -200,22 +215,58 @@ pci_testdev_read(void *opaque, hwaddr addr, unsigned
> size)
> return buf[addr];
> }
>
> +/*
> + * To add a new test, we need to implement both write_op and read_op,
> + * and add a new "struct testcase" into the global pci_testcases[].
> + */
> +struct testcase pci_testcases[] = {
> + {"eventfd", pci_testdev_write, pci_testdev_read},
> + {NULL, NULL, NULL},
> +};
> +
> +#define FOREACH_TEST_CASE(n) for (n = &pci_testcases[0]; n->name; n++)
> +
> +static struct testcase *
> +pci_testdev_find_testcase(char *name)
> +{
> + struct testcase *test;
> +
> + FOREACH_TEST_CASE(test) {
> + if (!strcmp(test->name, name)) {
> + return test;
> + }
> + }
> + return NULL;
> +}
> +
> +static uint64_t
> +pci_testdev_common_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + PCITestDevState *d = opaque;
> + pci_testdev_read_op read_op = d->testcase->read_op;
> + return read_op(opaque, addr, size);
> +}
> +
> static void
> pci_testdev_mmio_write(void *opaque, hwaddr addr, uint64_t val,
> unsigned size)
> {
> - pci_testdev_write(opaque, addr, val, size, 0);
> + PCITestDevState *d = opaque;
> + pci_testdev_write_op write_op = d->testcase->write_op;
> + write_op(opaque, addr, val, size, 0);
> }
>
> static void
> pci_testdev_pio_write(void *opaque, hwaddr addr, uint64_t val,
> unsigned size)
> {
> - pci_testdev_write(opaque, addr, val, size, 1);
> + PCITestDevState *d = opaque;
> + pci_testdev_write_op write_op = d->testcase->write_op;
> + write_op(opaque, addr, val, size, 1);
> }
>
> static const MemoryRegionOps pci_testdev_mmio_ops = {
> - .read = pci_testdev_read,
> + .read = pci_testdev_common_read,
> .write = pci_testdev_mmio_write,
> .endianness = DEVICE_LITTLE_ENDIAN,
> .impl = {
> @@ -225,7 +276,7 @@ static const MemoryRegionOps pci_testdev_mmio_ops = {
> };
>
> static const MemoryRegionOps pci_testdev_pio_ops = {
> - .read = pci_testdev_read,
> + .read = pci_testdev_common_read,
> .write = pci_testdev_pio_write,
> .endianness = DEVICE_LITTLE_ENDIAN,
> .impl = {
> @@ -281,6 +332,21 @@ static void pci_testdev_realize(PCIDevice *pci_dev,
> Error **errp)
> assert(r >= 0);
> test->hasnotifier = true;
> }
> +
> + if (!d->testcase_name) {
> + d->testcase_name = (char *)"eventfd";
> + }
> +
> + d->testcase = pci_testdev_find_testcase(d->testcase_name);
> + if (!d->testcase) {
> + struct testcase *test;
> + error_report("Invalid test case. Currently support: {");
> + FOREACH_TEST_CASE(test) {
> + error_report("\t\"%s\", ", test->name);
> + }
> + error_report("}");
> + exit(1);
> + }
> }
>
> static void
> @@ -305,6 +371,11 @@ static void qdev_pci_testdev_reset(DeviceState *dev)
> pci_testdev_reset(d);
> }
>
> +static Property pci_testdev_properties[] = {
> + DEFINE_PROP_STRING("testcase", PCITestDevState, testcase_name),
> + DEFINE_PROP_END_OF_LIST(),
> +};
> +
> static void pci_testdev_class_init(ObjectClass *klass, void *data)
> {
> DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -319,6 +390,7 @@ static void pci_testdev_class_init(ObjectClass *klass,
> void *data)
> dc->desc = "PCI Test Device";
> set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> dc->reset = qdev_pci_testdev_reset;
> + dc->props = pci_testdev_properties;
> }
>
> static const TypeInfo pci_testdev_info = {
> --
> 2.7.4