From patchwork Fri Apr 13 14:27:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 152317 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A17E6B7014 for ; Sat, 14 Apr 2012 00:28:28 +1000 (EST) Received: from localhost ([::1]:57382 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SIhUA-0004Rm-06 for incoming@patchwork.ozlabs.org; Fri, 13 Apr 2012 10:28:26 -0400 Received: from eggs.gnu.org ([208.118.235.92]:56161) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SIhTx-0004Qa-7Z for qemu-devel@nongnu.org; Fri, 13 Apr 2012 10:28:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SIhTp-0006ys-VL for qemu-devel@nongnu.org; Fri, 13 Apr 2012 10:28:12 -0400 Received: from e06smtp10.uk.ibm.com ([195.75.94.106]:52123) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SIhTp-0006ya-MP for qemu-devel@nongnu.org; Fri, 13 Apr 2012 10:28:05 -0400 Received: from /spool/local by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 13 Apr 2012 15:28:01 +0100 Received: from d06nrmr1707.portsmouth.uk.ibm.com (9.149.39.225) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 13 Apr 2012 15:28:00 +0100 Received: from d06av12.portsmouth.uk.ibm.com (d06av12.portsmouth.uk.ibm.com [9.149.37.247]) by d06nrmr1707.portsmouth.uk.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q3DERx1P2302000 for ; Fri, 13 Apr 2012 15:27:59 +0100 Received: from d06av12.portsmouth.uk.ibm.com (loopback [127.0.0.1]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q3DERwkH005860 for ; Fri, 13 Apr 2012 08:27:59 -0600 Received: from localhost (dyn-9-174-219-44.manchester-maybrook.uk.ibm.com [9.174.219.44]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q3DERwwI005839; Fri, 13 Apr 2012 08:27:58 -0600 From: Stefan Hajnoczi To: Date: Fri, 13 Apr 2012 15:27:50 +0100 Message-Id: <1334327272-31278-2-git-send-email-stefanha@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1334327272-31278-1-git-send-email-stefanha@linux.vnet.ibm.com> References: <1334327272-31278-1-git-send-email-stefanha@linux.vnet.ibm.com> x-cbid: 12041314-4966-0000-0000-000002046F56 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 195.75.94.106 Cc: Paolo Bonzini , Anthony Liguori , Stefan Hajnoczi , dmitry.fleytman@ravellosystems.com Subject: [Qemu-devel] [RFC PATCH 1/3] tests: add libpci qtest library X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds a common PCI bus driver library which works for i386/x86-64 targets. Tests can use the library to probe for PCI devices, map BARs, and access configuration space. Signed-off-by: Stefan Hajnoczi --- tests/libpci.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/libpci.h | 41 ++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 tests/libpci.c create mode 100644 tests/libpci.h diff --git a/tests/libpci.c b/tests/libpci.c new file mode 100644 index 0000000..24d4d8b --- /dev/null +++ b/tests/libpci.c @@ -0,0 +1,106 @@ +/* + * QTest PCI library + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include +#include "bswap.h" +#include "libqtest.h" +#include "libpci.h" + +enum { + /* PCI controller I/O ports */ + PCI_CONFIG_ADDR = 0xcf8, + PCI_CONFIG_DATA = 0xcfc, +}; + +static void pci_config_setup(PciDevice *dev, unsigned int offset) +{ + outl(PCI_CONFIG_ADDR, 0x80000000 | (dev->devfn << 8) | (offset & ~3)); +} + +uint8_t pci_config_readb(PciDevice *dev, unsigned int offset) +{ + pci_config_setup(dev, offset); + return inb(PCI_CONFIG_DATA + (offset & 3)); +} + +void pci_config_writeb(PciDevice *dev, unsigned int offset, uint8_t b) +{ + pci_config_setup(dev, offset); + outb(PCI_CONFIG_DATA + (offset & 3), b); +} + +uint16_t pci_config_readw(PciDevice *dev, unsigned int offset) +{ + pci_config_setup(dev, offset); + return inw(PCI_CONFIG_DATA + (offset & 2)); +} + +void pci_config_writew(PciDevice *dev, unsigned int offset, uint16_t w) +{ + pci_config_setup(dev, offset); + outw(PCI_CONFIG_DATA + (offset & 2), w); +} + +uint32_t pci_config_readl(PciDevice *dev, unsigned int offset) +{ + pci_config_setup(dev, offset); + return inl(PCI_CONFIG_DATA); +} + +void pci_config_writel(PciDevice *dev, unsigned int offset, uint32_t l) +{ + pci_config_setup(dev, offset); + outl(PCI_CONFIG_DATA, l); +} + +/* Initialize a PciDevice if a device is present on the bus */ +bool pci_probe(PciDevice *dev, unsigned int slot, unsigned int func) +{ + uint16_t vendor; + + dev->devfn = (slot << 3) | func; + vendor = pci_config_readw(dev, PCI_VENDOR_ID); + if (vendor == 0xffff || vendor == 0x0) { + return false; + } + return true; +} + +/* Map an I/O BAR to a specific address */ +void pci_map_bar_io(PciDevice *dev, unsigned int bar, uint16_t addr) +{ + uint32_t old_bar; + + old_bar = pci_config_readl(dev, bar); + g_assert_cmphex(old_bar & PCI_BASE_ADDRESS_SPACE, ==, + PCI_BASE_ADDRESS_SPACE_IO); + + /* Address must be valid */ + g_assert_cmphex(addr & ~PCI_BASE_ADDRESS_IO_MASK, ==, 0); + + pci_config_writel(dev, bar, addr); + + /* BAR must have accepted address */ + old_bar = pci_config_readl(dev, bar); + g_assert_cmphex(old_bar & PCI_BASE_ADDRESS_IO_MASK, ==, addr); +} + +/* Enable memory and I/O decoding so BARs can be accessed */ +void pci_enable(PciDevice *dev) +{ + uint16_t cmd; + + cmd = pci_config_readw(dev, PCI_COMMAND); + pci_config_writew(dev, PCI_COMMAND, + cmd | PCI_COMMAND_IO | PCI_COMMAND_MEMORY); +} diff --git a/tests/libpci.h b/tests/libpci.h new file mode 100644 index 0000000..1b3103d --- /dev/null +++ b/tests/libpci.h @@ -0,0 +1,41 @@ +/* + * QTest PCI library + * + * Copyright IBM, Corp. 2012 + * + * Authors: + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef LIBPCI_H +#define LIBPCI_H + +#include +#include "hw/pci_regs.h" + +/* A PCI Device + * + * Set up a PciDevice instance with pci_probe(). The device can then be used + * for configuration space access and other operations. + */ +typedef struct { + uint8_t devfn; +} PciDevice; + +bool pci_probe(PciDevice *dev, unsigned int slot, unsigned int func); +void pci_map_bar_io(PciDevice *dev, unsigned int bar, uint16_t addr); +void pci_enable(PciDevice *dev); + +/* Configuration space access */ +uint8_t pci_config_readb(PciDevice *dev, unsigned int offset); +void pci_config_writeb(PciDevice *dev, unsigned int offset, uint8_t b); +uint16_t pci_config_readw(PciDevice *dev, unsigned int offset); +void pci_config_writew(PciDevice *dev, unsigned int offset, uint16_t w); +uint32_t pci_config_readl(PciDevice *dev, unsigned int offset); +void pci_config_writel(PciDevice *dev, unsigned int offset, uint32_t l); + +#endif /* LIBPCI_H */