From patchwork Thu Feb 14 05:08:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 1041823 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.b="Sl44kAwc"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 440PbH3rvhz9s7h for ; Thu, 14 Feb 2019 16:10:03 +1100 (AEDT) Received: from localhost ([127.0.0.1]:40262 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gu9Hd-0003vu-FG for incoming@patchwork.ozlabs.org; Thu, 14 Feb 2019 00:10:01 -0500 Received: from eggs.gnu.org ([209.51.188.92]:53175) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gu9GS-0003Ml-7j for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gu9GH-0003yw-Fx for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:41 -0500 Received: from ozlabs.org ([2401:3900:2:1::2]:40167) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gu9GE-0003nR-TP for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:35 -0500 Received: by ozlabs.org (Postfix, from userid 1007) id 440PY829Tqz9sML; Thu, 14 Feb 2019 16:08:12 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1550120892; bh=8lQS0aeklgFws270207wBViG5/Jc9NypH3zB5m1hSTE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Sl44kAwcC29bs76sVmIa5yuWbsIefhbem7ADYZwvXa13gopgoDnoBad2rO5hefzIN /mXQ4TDeyeSNLT2W5030N512oFLg5/hyjHw4hA7LLckWY2w8q9waStnPulvjRivvTl aVU2SMBRcfQn9a7ruf/YQU4tTb3jkBzKWV8JpXvs= From: David Gibson To: mst@redhat.com, qemu-devel@nongnu.org Date: Thu, 14 Feb 2019 16:08:07 +1100 Message-Id: <20190214050808.16653-2-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190214050808.16653-1-david@gibson.dropbear.id.au> References: <20190214050808.16653-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2401:3900:2:1::2 Subject: [Qemu-devel] [PATCH 1/2] pci: Simplify pci_bus_is_root() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Marcel Apfelbaum , Peter Xu , mdroth@linux.vnet.ibm.com, David Gibson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" pci_bus_is_root() currently relies on a method in the PCIBusClass. But it's always known if a PCI bus is a root bus when we create it, so using a dynamic method is overkill. This replaces it with an IS_ROOT bit in a new flags field, which is set on root buses and otherwise clear. As a bonus this removes the special is_root logic from pci_expander_bridge, since it already creates its bus as a root bus. Signed-off-by: David Gibson Reviewed-by: Marcel Apfelbaum Reviewed-by: Peter Xu --- hw/pci-bridge/pci_expander_bridge.c | 6 ------ hw/pci/pci.c | 14 ++------------ hw/virtio/virtio-pci.c | 1 + include/hw/pci/pci.h | 1 - include/hw/pci/pci_bus.h | 11 +++++++++++ 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index e62de4218f..ca66bc721a 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -66,11 +66,6 @@ static int pxb_bus_num(PCIBus *bus) return pxb->bus_nr; } -static bool pxb_is_root(PCIBus *bus) -{ - return true; /* by definition */ -} - static uint16_t pxb_bus_numa_node(PCIBus *bus) { PXBDev *pxb = convert_to_pxb(bus->parent_dev); @@ -83,7 +78,6 @@ static void pxb_bus_class_init(ObjectClass *class, void *data) PCIBusClass *pbc = PCI_BUS_CLASS(class); pbc->bus_num = pxb_bus_num; - pbc->is_root = pxb_is_root; pbc->numa_node = pxb_bus_numa_node; } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index c9fc2fbe19..f6d8b337db 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -129,14 +129,9 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp) vmstate_unregister(NULL, &vmstate_pcibus, bus); } -static bool pcibus_is_root(PCIBus *bus) -{ - return !bus->parent_dev; -} - static int pcibus_num(PCIBus *bus) { - if (pcibus_is_root(bus)) { + if (pci_bus_is_root(bus)) { return 0; /* pci host bridge */ } return bus->parent_dev->config[PCI_SECONDARY_BUS]; @@ -159,7 +154,6 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->unrealize = pci_bus_unrealize; k->reset = pcibus_reset; - pbc->is_root = pcibus_is_root; pbc->bus_num = pcibus_num; pbc->numa_node = pcibus_numa_node; } @@ -379,6 +373,7 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent, bus->slot_reserved_mask = 0x0; bus->address_space_mem = address_space_mem; bus->address_space_io = address_space_io; + bus->flags |= PCI_BUS_IS_ROOT; /* host bridge */ QLIST_INIT(&bus->child); @@ -396,11 +391,6 @@ bool pci_bus_is_express(PCIBus *bus) return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } -bool pci_bus_is_root(PCIBus *bus) -{ - return PCI_BUS_GET_CLASS(bus)->is_root(bus); -} - void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index e978bfe760..a3e43ebe31 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -20,6 +20,7 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/virtio/virtio.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/pci/msi.h" diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index d87f5f93e9..1273deb740 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -395,7 +395,6 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); #define TYPE_PCIE_BUS "PCIE" bool pci_bus_is_express(PCIBus *bus); -bool pci_bus_is_root(PCIBus *bus); void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index dfb75752cb..3a4d599da3 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -20,8 +20,14 @@ typedef struct PCIBusClass { uint16_t (*numa_node)(PCIBus *bus); } PCIBusClass; +enum PCIBusFlags { + /* This bus is the root of a PCI domain */ + PCI_BUS_IS_ROOT = 0x0001, +}; + struct PCIBus { BusState qbus; + enum PCIBusFlags flags; PCIIOMMUFunc iommu_fn; void *iommu_opaque; uint8_t devfn_min; @@ -46,4 +52,9 @@ struct PCIBus { Notifier machine_done; }; +static inline bool pci_bus_is_root(PCIBus *bus) +{ + return !!(bus->flags & PCI_BUS_IS_ROOT); +} + #endif /* QEMU_PCI_BUS_H */ From patchwork Thu Feb 14 05:08:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Gibson X-Patchwork-Id: 1041822 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.b="hP6uqLkM"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 440PZm3ZJJz9s7h for ; Thu, 14 Feb 2019 16:09:35 +1100 (AEDT) Received: from localhost ([127.0.0.1]:40259 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gu9HA-0003O6-IL for incoming@patchwork.ozlabs.org; Thu, 14 Feb 2019 00:09:32 -0500 Received: from eggs.gnu.org ([209.51.188.92]:53159) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gu9GR-0003Mj-7q for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gu9GG-0003yE-9I for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:39 -0500 Received: from ozlabs.org ([2401:3900:2:1::2]:49457) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gu9GE-0003nP-Q8 for qemu-devel@nongnu.org; Thu, 14 Feb 2019 00:08:35 -0500 Received: by ozlabs.org (Postfix, from userid 1007) id 440PY842F9z9sMx; Thu, 14 Feb 2019 16:08:12 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gibson.dropbear.id.au; s=201602; t=1550120892; bh=3HWxPI75kzr4tp9AcOYTReJAPFCgy4u+DQBd29H+Kzg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hP6uqLkMED0l9jYlZOJwUI1XI3W5+XhJ7hv0ILc38t6Yhka+uCRF/cE0ehyt+01/h B07E2ZD5x8ngtJMXkc2NRpB+B7c8nLzHKjNBEeyOVfr2V6EGavjByqbTg50lMDMmkx 9VOtxLW0JJqfGfJt9LElmujp0oduyS3wSc8tJMd8= From: David Gibson To: mst@redhat.com, qemu-devel@nongnu.org Date: Thu, 14 Feb 2019 16:08:08 +1100 Message-Id: <20190214050808.16653-3-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190214050808.16653-1-david@gibson.dropbear.id.au> References: <20190214050808.16653-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2401:3900:2:1::2 Subject: [Qemu-devel] [PATCH 2/2] pcie: Don't allow extended config space access via conventional PCI bridges X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mdroth@linux.vnet.ibm.com, David Gibson Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" In hardware it's possible, if odd, to have a configuration like: PCIe host bridge \- PCIe to PCI bridge \- PCI to PCIe bridge \- PCIe device The PCIe extended configuration space on the device won't be accessible to the host, because the cycles can't traverse the conventional PCI bus on the way there. However, if we attempt to model that configuration under qemu, extended config access on the device *will* work, because pci_config_size() depends only on whether the device itself is PCIe capable. This patch fixes that modelling error by adding a flag to each PCI/PCIe bus instance indicating whether extended config space accesses are possible on it. It will always be false for conventional PCI buses, for PCIe buses it will be true if and only if the parent bus also has the flag set. AIUI earlier attempts to correct this have been rejected, because they involved expensively traversing the whole bus hierarchy on each config access. This approach avoids that by computing the value as the bus hierarchy is constructed, meaning we only need a single bit check when we actually attempt the config access. Signed-off-by: David Gibson --- hw/pci/pci.c | 32 ++++++++++++++++++++++++++++++++ include/hw/pci/pci.h | 4 +++- include/hw/pci/pci_bus.h | 2 ++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index f6d8b337db..f2d9dff9ee 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -120,6 +120,25 @@ static void pci_bus_realize(BusState *qbus, Error **errp) vmstate_register(NULL, -1, &vmstate_pcibus, bus); } +static void pcie_bus_realize(BusState *qbus, Error **errp) +{ + PCIBus *bus = PCI_BUS(qbus); + + pci_bus_realize(qbus, errp); + + /* a PCI-E bus can supported extended config space if it's the + * root bus, or if the bus/bridge above it does as well */ + if (pci_bus_is_root(bus)) { + bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; + } else { + PCIBus *parent_bus = pci_get_bus(bus->parent_dev); + + if (pci_bus_extended_config_space(parent_bus)) { + bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE; + } + } +} + static void pci_bus_unrealize(BusState *qbus, Error **errp) { PCIBus *bus = PCI_BUS(qbus); @@ -166,6 +185,13 @@ static const TypeInfo pci_bus_info = { .class_init = pci_bus_class_init, }; +static void pcie_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->realize = pcie_bus_realize; +} + static const TypeInfo pcie_interface_info = { .name = INTERFACE_PCIE_DEVICE, .parent = TYPE_INTERFACE, @@ -174,6 +200,7 @@ static const TypeInfo pcie_interface_info = { static const TypeInfo conventional_pci_interface_info = { .name = INTERFACE_CONVENTIONAL_PCI_DEVICE, .parent = TYPE_INTERFACE, + .class_init = pcie_bus_class_init, }; static const TypeInfo pcie_bus_info = { @@ -391,6 +418,11 @@ bool pci_bus_is_express(PCIBus *bus) return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); } +bool pci_bus_extended_config_space(PCIBus *bus) +{ + return !!(bus->flags & PCI_BUS_EXTENDED_CONFIG_SPACE); +} + void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 1273deb740..919e8a6f5f 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -395,6 +395,7 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin); #define TYPE_PCIE_BUS "PCIE" bool pci_bus_is_express(PCIBus *bus); +bool pci_bus_extended_config_space(PCIBus *bus); void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, @@ -754,7 +755,8 @@ static inline int pci_is_express_downstream_port(const PCIDevice *d) static inline uint32_t pci_config_size(const PCIDevice *d) { - return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; + return (pci_is_express(d) && pci_bus_extended_config_space(pci_get_bus(d))) + ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE; } static inline uint16_t pci_get_bdf(PCIDevice *dev) diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h index 3a4d599da3..8b1e849c34 100644 --- a/include/hw/pci/pci_bus.h +++ b/include/hw/pci/pci_bus.h @@ -23,6 +23,8 @@ typedef struct PCIBusClass { enum PCIBusFlags { /* This bus is the root of a PCI domain */ PCI_BUS_IS_ROOT = 0x0001, + /* PCIe extended configuration space is accessible on this bus */ + PCI_BUS_EXTENDED_CONFIG_SPACE = 0x0002, }; struct PCIBus {