From patchwork Wed Aug 17 12:07:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Gordeev X-Patchwork-Id: 9285761 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2A13F6086A for ; Wed, 17 Aug 2016 12:08:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 24C3A29089 for ; Wed, 17 Aug 2016 12:08:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 19B0229097; Wed, 17 Aug 2016 12:08:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 76EB329089 for ; Wed, 17 Aug 2016 12:08:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751839AbcHQMIJ (ORCPT ); Wed, 17 Aug 2016 08:08:09 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56570 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753660AbcHQMIB (ORCPT ); Wed, 17 Aug 2016 08:08:01 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CF7E3C000414 for ; Wed, 17 Aug 2016 12:08:00 +0000 (UTC) Received: from dhcp-27-118.brq.redhat.com (dhcp-27-122.brq.redhat.com [10.34.27.122]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u7HC7i9u028577; Wed, 17 Aug 2016 08:07:59 -0400 From: Alexander Gordeev To: kvm@vger.kernel.org Cc: Alexander Gordeev , Thomas Huth , Andrew Jones Subject: [kvm-unit-tests PATCH v7 12/13] pci: Add pci-testdev PCI bus test device Date: Wed, 17 Aug 2016 14:07:13 +0200 Message-Id: <15b9e7ffcf6f978c58e44e45502331949d61d19f.1471434672.git.agordeev@redhat.com> In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 17 Aug 2016 12:08:00 +0000 (UTC) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Cc: Thomas Huth Cc: Andrew Jones Signed-off-by: Alexander Gordeev Reviewed-by: Andrew Jones --- lib/pci-testdev.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pci.h | 7 ++ 2 files changed, 199 insertions(+) create mode 100644 lib/pci-testdev.c diff --git a/lib/pci-testdev.c b/lib/pci-testdev.c new file mode 100644 index 000000000000..ad482d3291c7 --- /dev/null +++ b/lib/pci-testdev.c @@ -0,0 +1,192 @@ +/* + * QEMU "pci-testdev" PCI test device + * + * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "pci.h" +#include "asm/io.h" + +struct pci_testdev_ops { + u8 (*io_readb)(const volatile void *addr); + u16 (*io_readw)(const volatile void *addr); + u32 (*io_readl)(const volatile void *addr); + void (*io_writeb)(u8 value, volatile void *addr); + void (*io_writew)(u16 value, volatile void *addr); + void (*io_writel)(u32 value, volatile void *addr); +}; + +static u8 pio_readb(const volatile void *addr) +{ + return inb((unsigned long)addr); +} + +static u16 pio_readw(const volatile void *addr) +{ + return inw((unsigned long)addr); +} + +static u32 pio_readl(const volatile void *addr) +{ + return inl((unsigned long)addr); +} + +static void pio_writeb(u8 value, volatile void *addr) +{ + outb(value, (unsigned long)addr); +} + +static void pio_writew(u16 value, volatile void *addr) +{ + outw(value, (unsigned long)addr); +} + +static void pio_writel(u32 value, volatile void *addr) +{ + outl(value, (unsigned long)addr); +} + +static struct pci_testdev_ops pci_testdev_io_ops = { + .io_readb = pio_readb, + .io_readw = pio_readw, + .io_readl = pio_readl, + .io_writeb = pio_writeb, + .io_writew = pio_writew, + .io_writel = pio_writel +}; + +static u8 mmio_readb(const volatile void *addr) +{ + return *(const volatile u8 __force *)addr; +} + +static u16 mmio_readw(const volatile void *addr) +{ + return *(const volatile u16 __force *)addr; +} + +static u32 mmio_readl(const volatile void *addr) +{ + return *(const volatile u32 __force *)addr; +} + +static void mmio_writeb(u8 value, volatile void *addr) +{ + *(volatile u8 __force *)addr = value; +} + +static void mmio_writew(u16 value, volatile void *addr) +{ + *(volatile u16 __force *)addr = value; +} + +static void mmio_writel(u32 value, volatile void *addr) +{ + *(volatile u32 __force *)addr = value; +} + +static struct pci_testdev_ops pci_testdev_mem_ops = { + .io_readb = mmio_readb, + .io_readw = mmio_readw, + .io_readl = mmio_readl, + .io_writeb = mmio_writeb, + .io_writew = mmio_writew, + .io_writel = mmio_writel +}; + +static bool pci_testdev_one(struct pci_test_dev_hdr *test, + int test_nr, + struct pci_testdev_ops *ops) +{ + u8 width; + u32 count, sig, off; + const int nr_writes = 16; + int i; + + ops->io_writeb(test_nr, &test->test); + count = ops->io_readl(&test->count); + if (count != 0) + return false; + + width = ops->io_readb(&test->width); + if (width != 1 && width != 2 && width != 4) + return false; + + sig = ops->io_readl(&test->data); + off = ops->io_readl(&test->offset); + + for (i = 0; i < nr_writes; i++) { + switch (width) { + case 1: ops->io_writeb(sig, (void *)test + off); break; + case 2: ops->io_writew(sig, (void *)test + off); break; + case 4: ops->io_writel(sig, (void *)test + off); break; + } + } + + count = ops->io_readl(&test->count); + if (!count) + return true; + + return (int)count == nr_writes; +} + +void pci_testdev_print(struct pci_test_dev_hdr *test, + struct pci_testdev_ops *ops) +{ + bool io = (ops == &pci_testdev_io_ops); + int i; + + printf("pci-testdev %3s: ", io ? "io" : "mem"); + for (i = 0;; ++i) { + char c = ops->io_readb(&test->name[i]); + if (!c) + break; + printf("%c", c); + } + printf("\n"); +} + +static int pci_testdev_all(struct pci_test_dev_hdr *test, + struct pci_testdev_ops *ops) +{ + int i; + + for (i = 0;; i++) { + if (!pci_testdev_one(test, i, ops)) + break; + pci_testdev_print(test, ops); + } + + return i; +} + +int pci_testdev(void) +{ + phys_addr_t addr; + void __iomem *mem, *io; + pcidevaddr_t dev; + int nr_tests = 0; + bool ret; + + dev = pci_find_dev(PCI_VENDOR_ID_REDHAT, PCI_DEVICE_ID_REDHAT_TEST); + if (dev == PCIDEVADDR_INVALID) { + printf("'pci-testdev' device is not found, " + "check QEMU '-device pci-testdev' parameter\n"); + return -1; + } + + ret = pci_bar_is_valid(dev, 0) && pci_bar_is_valid(dev, 1); + assert(ret); + + addr = pci_bar_get_addr(dev, 0); + mem = ioremap(addr, PAGE_SIZE); + + addr = pci_bar_get_addr(dev, 1); + io = (void *)(unsigned long)addr; + + nr_tests += pci_testdev_all(mem, &pci_testdev_mem_ops); + nr_tests += pci_testdev_all(io, &pci_testdev_io_ops); + + return nr_tests; +} diff --git a/lib/pci.h b/lib/pci.h index 7acbbdf2eb16..40e11a892783 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -41,6 +41,8 @@ extern bool pci_bar_is64(pcidevaddr_t dev, int bar_num); extern bool pci_bar_is_memory(pcidevaddr_t dev, int bar_num); extern bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num); +int pci_testdev(void); + /* * pci-testdev is a driver for the pci-testdev qemu pci device. The * device enables testing mmio and portio exits, and measuring their @@ -49,7 +51,12 @@ extern bool pci_bar_is_valid(pcidevaddr_t dev, int bar_num); #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_TEST 0x0005 +/* + * pci-testdev supports at least three types of tests (via mmio and + * portio BARs): no-eventfd, wildcard-eventfd and datamatch-eventfd + */ #define PCI_TESTDEV_NUM_BARS 2 +#define PCI_TESTDEV_NUM_TESTS 3 struct pci_test_dev_hdr { uint8_t test;