* [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge @ 2015-01-21 16:18 Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() Alexander Graf ` (3 more replies) 0 siblings, 4 replies; 24+ messages in thread From: Alexander Graf @ 2015-01-21 16:18 UTC (permalink / raw) To: qemu-devel Cc: Peter Maydell, ard.biesheuvel, rob.herring, mst, claudio.fontana, stuart.yoder, a.rigo Linux implements a nice binding to describe a "generic" PCI Express host bridge using only device tree. This patch set adds enough emulation logic to expose the parts that are "generic" as a simple sysbus device and maps it into ARM's virt machine. With this patch set, we can finally spawn PCI devices on ARM VMs. I was able to have a fully DRM enabled virtual machine with VGA, e1000 and XHCI (for keyboard and mouse) up and working. It's only a small step for QEMU, but a big step for ARM VM's usability. v1 -> v2: - Add documentation links - Remove mmio_window_size - Add define for pci range types - Use 4 PCI INTX IRQ lines Alexander Graf (4): pci: Split pcie_host_mmcfg_map() pci: Add generic PCIe host bridge arm: Add PCIe host bridge in virt machine pci: Move PCI VGA to pci.mak default-configs/alpha-softmmu.mak | 2 - default-configs/arm-softmmu.mak | 2 + default-configs/i386-softmmu.mak | 2 - default-configs/mips-softmmu.mak | 2 - default-configs/mips64-softmmu.mak | 2 - default-configs/mips64el-softmmu.mak | 2 - default-configs/mipsel-softmmu.mak | 2 - default-configs/pci.mak | 2 + default-configs/ppc-softmmu.mak | 2 - default-configs/ppc64-softmmu.mak | 2 - default-configs/ppcemb-softmmu.mak | 2 - default-configs/sparc64-softmmu.mak | 2 - default-configs/x86_64-softmmu.mak | 2 - hw/arm/virt.c | 112 +++++++++++++++++++++++-- hw/pci-host/Makefile.objs | 1 + hw/pci-host/gpex.c | 153 +++++++++++++++++++++++++++++++++++ hw/pci/pcie_host.c | 9 ++- include/hw/pci-host/gpex.h | 54 +++++++++++++ include/hw/pci/pcie_host.h | 1 + include/sysemu/device_tree.h | 9 +++ 20 files changed, 336 insertions(+), 29 deletions(-) create mode 100644 hw/pci-host/gpex.c create mode 100644 include/hw/pci-host/gpex.h -- 1.7.12.4 ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() 2015-01-21 16:18 [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge Alexander Graf @ 2015-01-21 16:18 ` Alexander Graf 2015-01-27 13:55 ` Peter Maydell 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge Alexander Graf ` (2 subsequent siblings) 3 siblings, 1 reply; 24+ messages in thread From: Alexander Graf @ 2015-01-21 16:18 UTC (permalink / raw) To: qemu-devel Cc: Peter Maydell, ard.biesheuvel, rob.herring, mst, claudio.fontana, stuart.yoder, a.rigo The mmcfg space is a memory region that allows access to PCI config space in the PCIe world. To maintain abstraction layers, I would like to expose the mmcfg space as a sysbus mmio region rather than have it mapped straight into the system's memory address space though. So this patch splits the initialization of the mmcfg space from the actual mapping, allowing us to only have an mmfg memory region without the map. Signed-off-by: Alexander Graf <agraf@suse.de> Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> --- hw/pci/pcie_host.c | 9 +++++++-- include/hw/pci/pcie_host.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index 3db038f..dfb4a2b 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -98,8 +98,7 @@ void pcie_host_mmcfg_unmap(PCIExpressHost *e) } } -void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, - uint32_t size) +void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size) { assert(!(size & (size - 1))); /* power of 2 */ assert(size >= PCIE_MMCFG_SIZE_MIN); @@ -107,6 +106,12 @@ void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, e->size = size; memory_region_init_io(&e->mmio, OBJECT(e), &pcie_mmcfg_ops, e, "pcie-mmcfg", e->size); +} + +void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, + uint32_t size) +{ + pcie_host_mmcfg_init(e, size); e->base_addr = addr; memory_region_add_subregion(get_system_memory(), e->base_addr, &e->mmio); } diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index ff44ef6..4d23c80 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -50,6 +50,7 @@ struct PCIExpressHost { }; void pcie_host_mmcfg_unmap(PCIExpressHost *e); +void pcie_host_mmcfg_init(PCIExpressHost *e, uint32_t size); void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size); void pcie_host_mmcfg_update(PCIExpressHost *e, int enable, -- 1.7.12.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() Alexander Graf @ 2015-01-27 13:55 ` Peter Maydell 2015-01-27 14:24 ` Michael S. Tsirkin 0 siblings, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-27 13:55 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: > The mmcfg space is a memory region that allows access to PCI config space > in the PCIe world. To maintain abstraction layers, I would like to expose > the mmcfg space as a sysbus mmio region rather than have it mapped straight > into the system's memory address space though. > > So this patch splits the initialization of the mmcfg space from the actual > mapping, allowing us to only have an mmfg memory region without the map. > > Signed-off-by: Alexander Graf <agraf@suse.de> > Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> ...as far as it goes, but: Really the pcie_host_mmcfg_map/unmap/update() function is just totally misguided. This functionality should be pushed upwards into hw/pci-host/q35.c which can handle its own mapping of the MMIO region into the system address space at the appropriate location/size. In particular, at the moment q35.c will leak a bunch of stuff every time the guest unmaps and remaps the mmcfg space, because we call memory_region_init_io() over and over again on the same MMIO object (which isn't valid). Any time you see a device with its own base address in its device struct it's a red flag that the design's probably wrong... The size of the MMCFG region should probably be a device property. Then the subclass realize could just rely on the baseclass realize to always create the mmio region, rather than having to explicitly call a function to get it to do the right thing. thanks -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() 2015-01-27 13:55 ` Peter Maydell @ 2015-01-27 14:24 ` Michael S. Tsirkin 2015-01-27 14:40 ` Paolo Bonzini 0 siblings, 1 reply; 24+ messages in thread From: Michael S. Tsirkin @ 2015-01-27 14:24 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Ard Biesheuvel, QEMU Developers, Claudio Fontana, Alvise Rigo, Stuart Yoder, Alexander Graf, pbonzini On Tue, Jan 27, 2015 at 01:55:32PM +0000, Peter Maydell wrote: > On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: > > The mmcfg space is a memory region that allows access to PCI config space > > in the PCIe world. To maintain abstraction layers, I would like to expose > > the mmcfg space as a sysbus mmio region rather than have it mapped straight > > into the system's memory address space though. > > > > So this patch splits the initialization of the mmcfg space from the actual > > mapping, allowing us to only have an mmfg memory region without the map. > > > > Signed-off-by: Alexander Graf <agraf@suse.de> > > Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> > > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> > > Reviewed-by: Peter Maydell <peter.maydell@linaro.org> > ...as far as it goes, but: > > Really the pcie_host_mmcfg_map/unmap/update() function is just totally > misguided. This functionality should be pushed upwards into > hw/pci-host/q35.c which can handle its own mapping of the MMIO region > into the system address space at the appropriate location/size. > > In particular, at the moment q35.c will leak a bunch of stuff > every time the guest unmaps and remaps the mmcfg space, because > we call memory_region_init_io() over and over again on the same > MMIO object (which isn't valid). I used to be fine before the QOM conversion I think? Take a look at this one (and previous patch): commit 469b046ead0671932ff3af8d6f95045b19b186ef Author: Paolo Bonzini <pbonzini@redhat.com> Date: Wed Jun 11 12:50:43 2014 +0200 memory: remove memory_region_destroy The function is empty after the previous patch, so remove it. Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > > Any time you see a device with its own base address in its > device struct it's a red flag that the design's probably wrong... I suspect this is not the only device that leaks memory now. Paolo? > The size of the MMCFG region should probably be a device property. > Then the subclass realize could just rely on the baseclass realize > to always create the mmio region, rather than having to explicitly > call a function to get it to do the right thing. > > thanks > -- PMM -- MST ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() 2015-01-27 14:24 ` Michael S. Tsirkin @ 2015-01-27 14:40 ` Paolo Bonzini 0 siblings, 0 replies; 24+ messages in thread From: Paolo Bonzini @ 2015-01-27 14:40 UTC (permalink / raw) To: Michael S. Tsirkin, Peter Maydell Cc: Rob Herring, Ard Biesheuvel, QEMU Developers, Claudio Fontana, Alvise Rigo, Stuart Yoder, Alexander Graf On 27/01/2015 15:24, Michael S. Tsirkin wrote: > I suspect this is not the only device that leaks memory now. > Paolo? It should be, this is a bug. Commit d8d95814609e89e5438a3318a647ec322fc4ff16 missed this place due to a rebase error. (I can tell it's a rebase error because I have the fixed patch in a private branch). Paolo Author: Paolo Bonzini <pbonzini@redhat.com> Date: Wed Jun 11 12:42:01 2014 +0200 memory: convert memory_region_destroy to object_unparent Explicitly call object_unparent in the few places where we will re-create the memory region. If the memory region is simply being destroyed as part of device teardown, let QOM handle it. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-21 16:18 [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() Alexander Graf @ 2015-01-21 16:18 ` Alexander Graf 2015-01-22 16:32 ` B02008 2015-01-27 15:31 ` Peter Maydell 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 4/4] pci: Move PCI VGA to pci.mak Alexander Graf 3 siblings, 2 replies; 24+ messages in thread From: Alexander Graf @ 2015-01-21 16:18 UTC (permalink / raw) To: qemu-devel Cc: Peter Maydell, ard.biesheuvel, rob.herring, mst, claudio.fontana, stuart.yoder, a.rigo With simple exposure of MMFG, ioport window, mmio window and an IRQ line we can successfully create a workable PCIe host bridge that can be mapped anywhere and only needs to get described to the OS using whatever means it likes. This patch implements such a "generic" host bridge. It only supports a single legacy IRQ line so far. MSIs need to be handled external to the host bridge. This device is particularly useful for the "pci-host-ecam-generic" driver in Linux. Signed-off-by: Alexander Graf <agraf@suse.de> Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> --- v1 -> v2: - Add documentation links - Remove mmio_window_size - Expose 4 INTX IRQs --- hw/pci-host/Makefile.objs | 1 + hw/pci-host/gpex.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/pci-host/gpex.h | 54 ++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 hw/pci-host/gpex.c create mode 100644 include/hw/pci-host/gpex.h diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index bb65f9c..45f1f0e 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -15,3 +15,4 @@ common-obj-$(CONFIG_PCI_APB) += apb.o common-obj-$(CONFIG_FULONG) += bonito.o common-obj-$(CONFIG_PCI_PIIX) += piix.o common-obj-$(CONFIG_PCI_Q35) += q35.o +common-obj-$(CONFIG_PCI_GENERIC) += gpex.o diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c new file mode 100644 index 0000000..11aaf5b --- /dev/null +++ b/hw/pci-host/gpex.c @@ -0,0 +1,153 @@ +/* + * QEMU Generic PCI Express Bridge Emulation + * + * Copyright (C) 2015 Alexander Graf <agraf@suse.de> + * + * Code loosely based on q35.c. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Check out these documents for more information on the device: + * + * http://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt + * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf + */ +#include "hw/hw.h" +#include "hw/pci-host/gpex.h" + +/**************************************************************************** + * GPEX host + */ + +static void gpex_set_irq(void *opaque, int irq_num, int level) +{ + GPEXHost *s = opaque; + + qemu_set_irq(s->irq[irq_num], level); +} + +static void gpex_host_realize(DeviceState *dev, Error **errp) +{ + PCIHostState *pci = PCI_HOST_BRIDGE(dev); + GPEXHost *s = GPEX_HOST(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); + int i; + + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MIN); + memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX); + memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024); + + sysbus_init_mmio(sbd, &pex->mmio); + sysbus_init_mmio(sbd, &s->io_mmio); + sysbus_init_mmio(sbd, &s->io_ioport); + for (i = 0; i < 4; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + + pci->bus = pci_register_bus(dev, "pcie.0", gpex_set_irq, + pci_swizzle_map_irq_fn, s, &s->io_mmio, + &s->io_ioport, 0, 4, TYPE_PCIE_BUS); + + qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus)); + qdev_init_nofail(DEVICE(&s->gpex_root)); +} + +static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, + PCIBus *rootbus) +{ + return "0000:00"; +} + +static void gpex_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); + + hc->root_bus_path = gpex_host_root_bus_path; + dc->realize = gpex_host_realize; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->fw_name = "pci"; +} + +static void gpex_host_initfn(Object *obj) +{ + GPEXHost *s = GPEX_HOST(obj); + + object_initialize(&s->gpex_root, sizeof(s->gpex_root), TYPE_GPEX_ROOT_DEVICE); + object_property_add_child(OBJECT(s), "gpex_root", OBJECT(&s->gpex_root), NULL); + qdev_prop_set_uint32(DEVICE(&s->gpex_root), "addr", PCI_DEVFN(0, 0)); + qdev_prop_set_bit(DEVICE(&s->gpex_root), "multifunction", false); +} + +static const TypeInfo gpex_host_info = { + .name = TYPE_GPEX_HOST, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(GPEXHost), + .instance_init = gpex_host_initfn, + .class_init = gpex_host_class_init, +}; + +/**************************************************************************** + * GPEX Root D0:F0 + */ + +static const VMStateDescription vmstate_gpex_root = { + .name = "gpex_root", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState), + VMSTATE_END_OF_LIST() + } +}; + +static void gpex_root_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->desc = "Host bridge"; + dc->vmsd = &vmstate_gpex_root; + k->vendor_id = PCI_VENDOR_ID_REDHAT; + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; + k->revision = 0; + k->class_id = PCI_CLASS_BRIDGE_HOST; + /* + * PCI-facing part of the host bridge, not usable without the + * host-facing part, which can't be device_add'ed, yet. + */ + dc->cannot_instantiate_with_device_add_yet = true; +} + +static const TypeInfo gpex_root_info = { + .name = TYPE_GPEX_ROOT_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(GPEXRootState), + .class_init = gpex_root_class_init, +}; + +static void gpex_register(void) +{ + type_register_static(&gpex_root_info); + type_register_static(&gpex_host_info); +} + +type_init(gpex_register); diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h new file mode 100644 index 0000000..b465667 --- /dev/null +++ b/include/hw/pci-host/gpex.h @@ -0,0 +1,54 @@ +/* + * gpex.h + * + * Copyright (C) 2015 Alexander Graf <agraf@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HW_GPEX_H +#define HW_GPEX_H + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pcie_host.h" + +#define TYPE_GPEX_HOST "gpex-pcihost" +#define GPEX_HOST(obj) \ + OBJECT_CHECK(GPEXHost, (obj), TYPE_GPEX_HOST) + +#define TYPE_GPEX_ROOT_DEVICE "gpex-root" +#define MCH_PCI_DEVICE(obj) \ + OBJECT_CHECK(GPEXRootState, (obj), TYPE_GPEX_ROOT_DEVICE) + +typedef struct GPEXRootState { + /*< private >*/ + PCIDevice parent_obj; + /*< public >*/ +} GPEXRootState; + +typedef struct GPEXHost { + /*< private >*/ + PCIExpressHost parent_obj; + /*< public >*/ + + GPEXRootState gpex_root; + + MemoryRegion io_ioport; + MemoryRegion io_mmio; + qemu_irq irq[4]; +} GPEXHost; + +#endif /* HW_GPEX_H */ -- 1.7.12.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge Alexander Graf @ 2015-01-22 16:32 ` B02008 2015-01-27 15:31 ` Peter Maydell 1 sibling, 0 replies; 24+ messages in thread From: B02008 @ 2015-01-22 16:32 UTC (permalink / raw) To: Alexander Graf, qemu-devel Cc: Peter Maydell, mst, ard.biesheuvel, claudio.fontana, stuart.yoder, a.rigo, rob.herring Looks that you forgot the "single legacy IRQ line" comment from v1. -Mike On 01/21/2015 06:18 PM, Alexander Graf wrote: > With simple exposure of MMFG, ioport window, mmio window and an IRQ line we > can successfully create a workable PCIe host bridge that can be mapped anywhere > and only needs to get described to the OS using whatever means it likes. > > This patch implements such a "generic" host bridge. It only supports a single > legacy IRQ line so far. MSIs need to be handled external to the host bridge. > > This device is particularly useful for the "pci-host-ecam-generic" driver in > Linux. > > Signed-off-by: Alexander Graf <agraf@suse.de> > Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> > > --- > > v1 -> v2: > > - Add documentation links > - Remove mmio_window_size > - Expose 4 INTX IRQs > --- > hw/pci-host/Makefile.objs | 1 + > hw/pci-host/gpex.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ > include/hw/pci-host/gpex.h | 54 ++++++++++++++++ > 3 files changed, 208 insertions(+) > create mode 100644 hw/pci-host/gpex.c > create mode 100644 include/hw/pci-host/gpex.h > > diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs > index bb65f9c..45f1f0e 100644 > --- a/hw/pci-host/Makefile.objs > +++ b/hw/pci-host/Makefile.objs > @@ -15,3 +15,4 @@ common-obj-$(CONFIG_PCI_APB) += apb.o > common-obj-$(CONFIG_FULONG) += bonito.o > common-obj-$(CONFIG_PCI_PIIX) += piix.o > common-obj-$(CONFIG_PCI_Q35) += q35.o > +common-obj-$(CONFIG_PCI_GENERIC) += gpex.o > diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c > new file mode 100644 > index 0000000..11aaf5b > --- /dev/null > +++ b/hw/pci-host/gpex.c > @@ -0,0 +1,153 @@ > +/* > + * QEMU Generic PCI Express Bridge Emulation > + * > + * Copyright (C) 2015 Alexander Graf <agraf@suse.de> > + * > + * Code loosely based on q35.c. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + * > + * Check out these documents for more information on the device: > + * > + * http://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt > + * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf > + */ > +#include "hw/hw.h" > +#include "hw/pci-host/gpex.h" > + > +/**************************************************************************** > + * GPEX host > + */ > + > +static void gpex_set_irq(void *opaque, int irq_num, int level) > +{ > + GPEXHost *s = opaque; > + > + qemu_set_irq(s->irq[irq_num], level); > +} > + > +static void gpex_host_realize(DeviceState *dev, Error **errp) > +{ > + PCIHostState *pci = PCI_HOST_BRIDGE(dev); > + GPEXHost *s = GPEX_HOST(dev); > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > + PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); > + int i; > + > + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MIN); > + memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX); > + memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024); > + > + sysbus_init_mmio(sbd, &pex->mmio); > + sysbus_init_mmio(sbd, &s->io_mmio); > + sysbus_init_mmio(sbd, &s->io_ioport); > + for (i = 0; i < 4; i++) { > + sysbus_init_irq(sbd, &s->irq[i]); > + } > + > + pci->bus = pci_register_bus(dev, "pcie.0", gpex_set_irq, > + pci_swizzle_map_irq_fn, s, &s->io_mmio, > + &s->io_ioport, 0, 4, TYPE_PCIE_BUS); > + > + qdev_set_parent_bus(DEVICE(&s->gpex_root), BUS(pci->bus)); > + qdev_init_nofail(DEVICE(&s->gpex_root)); > +} > + > +static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, > + PCIBus *rootbus) > +{ > + return "0000:00"; > +} > + > +static void gpex_host_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); > + > + hc->root_bus_path = gpex_host_root_bus_path; > + dc->realize = gpex_host_realize; > + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); > + dc->fw_name = "pci"; > +} > + > +static void gpex_host_initfn(Object *obj) > +{ > + GPEXHost *s = GPEX_HOST(obj); > + > + object_initialize(&s->gpex_root, sizeof(s->gpex_root), TYPE_GPEX_ROOT_DEVICE); > + object_property_add_child(OBJECT(s), "gpex_root", OBJECT(&s->gpex_root), NULL); > + qdev_prop_set_uint32(DEVICE(&s->gpex_root), "addr", PCI_DEVFN(0, 0)); > + qdev_prop_set_bit(DEVICE(&s->gpex_root), "multifunction", false); > +} > + > +static const TypeInfo gpex_host_info = { > + .name = TYPE_GPEX_HOST, > + .parent = TYPE_PCIE_HOST_BRIDGE, > + .instance_size = sizeof(GPEXHost), > + .instance_init = gpex_host_initfn, > + .class_init = gpex_host_class_init, > +}; > + > +/**************************************************************************** > + * GPEX Root D0:F0 > + */ > + > +static const VMStateDescription vmstate_gpex_root = { > + .name = "gpex_root", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void gpex_root_class_init(ObjectClass *klass, void *data) > +{ > + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); > + dc->desc = "Host bridge"; > + dc->vmsd = &vmstate_gpex_root; > + k->vendor_id = PCI_VENDOR_ID_REDHAT; > + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; > + k->revision = 0; > + k->class_id = PCI_CLASS_BRIDGE_HOST; > + /* > + * PCI-facing part of the host bridge, not usable without the > + * host-facing part, which can't be device_add'ed, yet. > + */ > + dc->cannot_instantiate_with_device_add_yet = true; > +} > + > +static const TypeInfo gpex_root_info = { > + .name = TYPE_GPEX_ROOT_DEVICE, > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(GPEXRootState), > + .class_init = gpex_root_class_init, > +}; > + > +static void gpex_register(void) > +{ > + type_register_static(&gpex_root_info); > + type_register_static(&gpex_host_info); > +} > + > +type_init(gpex_register); > diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h > new file mode 100644 > index 0000000..b465667 > --- /dev/null > +++ b/include/hw/pci-host/gpex.h > @@ -0,0 +1,54 @@ > +/* > + * gpex.h > + * > + * Copyright (C) 2015 Alexander Graf <agraf@suse.de> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see <http://www.gnu.org/licenses/> > + */ > + > +#ifndef HW_GPEX_H > +#define HW_GPEX_H > + > +#include "hw/hw.h" > +#include "hw/sysbus.h" > +#include "hw/pci/pci.h" > +#include "hw/pci/pcie_host.h" > + > +#define TYPE_GPEX_HOST "gpex-pcihost" > +#define GPEX_HOST(obj) \ > + OBJECT_CHECK(GPEXHost, (obj), TYPE_GPEX_HOST) > + > +#define TYPE_GPEX_ROOT_DEVICE "gpex-root" > +#define MCH_PCI_DEVICE(obj) \ > + OBJECT_CHECK(GPEXRootState, (obj), TYPE_GPEX_ROOT_DEVICE) > + > +typedef struct GPEXRootState { > + /*< private >*/ > + PCIDevice parent_obj; > + /*< public >*/ > +} GPEXRootState; > + > +typedef struct GPEXHost { > + /*< private >*/ > + PCIExpressHost parent_obj; > + /*< public >*/ > + > + GPEXRootState gpex_root; > + > + MemoryRegion io_ioport; > + MemoryRegion io_mmio; > + qemu_irq irq[4]; > +} GPEXHost; > + > +#endif /* HW_GPEX_H */ > ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge Alexander Graf 2015-01-22 16:32 ` B02008 @ 2015-01-27 15:31 ` Peter Maydell 2015-01-29 13:59 ` Alexander Graf 1 sibling, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-27 15:31 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: > With simple exposure of MMFG, ioport window, mmio window and an IRQ line we Four :-) > can successfully create a workable PCIe host bridge that can be mapped anywhere > and only needs to get described to the OS using whatever means it likes. > > This patch implements such a "generic" host bridge. It only supports a single > legacy IRQ line so far. MSIs need to be handled external to the host bridge. > > This device is particularly useful for the "pci-host-ecam-generic" driver in > Linux. > > Signed-off-by: Alexander Graf <agraf@suse.de> > Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> Checkpatch complains about a few over-80-chars lines; the URL is an unavoidable one but could you fold the others, please? > +static void gpex_host_realize(DeviceState *dev, Error **errp) > +{ > + PCIHostState *pci = PCI_HOST_BRIDGE(dev); > + GPEXHost *s = GPEX_HOST(dev); > + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); > + PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); > + int i; > + > + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MIN); So this gives us 1MB of ECAM (config) space. That means we can't specify a target bus, so we're restricted to the 31 devices directly attached to the root complex. Among other things, this will mean we can't do PCIe hotplug. I think we should make this at least a bit bigger, even if we don't go up to the full 256MB. Probably the best thing for the gpex device itself is to make the config space be the spec maximum (PCIE_MMCFG_SIZE_MAX) and let the user map only a portion of that into their address space if they want. Ideally we should just do that in the base class, and get the q35 subclass to do the right thing with aliases to handle the dynamic resizing it wants. Then we wouldn't need to track "size of cfg region" in the baseclass either. > + memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX); > + memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024); > + > + sysbus_init_mmio(sbd, &pex->mmio); > + sysbus_init_mmio(sbd, &s->io_mmio); > + sysbus_init_mmio(sbd, &s->io_ioport); > + for (i = 0; i < 4; i++) { Can we at least have a constant rather than hardcoded 4s ? (qdev property for number-of-irqs if you're really feeling enthusiastic...) > + > +/**************************************************************************** > + * GPEX Root D0:F0 > + */ What does "D0:F0" mean here? > + > +static const VMStateDescription vmstate_gpex_root = { > + .name = "gpex_root", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void gpex_root_class_init(ObjectClass *klass, void *data) > +{ > + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); > + dc->desc = "Host bridge"; We can be a bit less terse: "QEMU generic PCIe host bridge". > + dc->vmsd = &vmstate_gpex_root; > + k->vendor_id = PCI_VENDOR_ID_REDHAT; > + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; Pretty sure we shouldn't be reusing the PCI bridge IDs for a host bridge. We should allocate ourselves another device ID in the range... > + k->revision = 0; > + k->class_id = PCI_CLASS_BRIDGE_HOST; > + /* > + * PCI-facing part of the host bridge, not usable without the > + * host-facing part, which can't be device_add'ed, yet. > + */ > + dc->cannot_instantiate_with_device_add_yet = true; > +} > + > +static const TypeInfo gpex_root_info = { > + .name = TYPE_GPEX_ROOT_DEVICE, > + .parent = TYPE_PCI_DEVICE, > + .instance_size = sizeof(GPEXRootState), > + .class_init = gpex_root_class_init, > +}; > + > +static void gpex_register(void) > +{ > + type_register_static(&gpex_root_info); > + type_register_static(&gpex_host_info); > +} > + > +type_init(gpex_register); We seem to prefer no trailing ';' on type_init by a ratio of more than 10:1. > diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h > new file mode 100644 > index 0000000..b465667 > --- /dev/null > +++ b/include/hw/pci-host/gpex.h > @@ -0,0 +1,54 @@ > +/* > + * gpex.h Would be nice to say "QEMU Generic PCI Express Bridge Emulation" here (like the .c file's header does). thanks -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-27 15:31 ` Peter Maydell @ 2015-01-29 13:59 ` Alexander Graf 2015-01-29 14:25 ` Peter Maydell 0 siblings, 1 reply; 24+ messages in thread From: Alexander Graf @ 2015-01-29 13:59 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 27.01.15 16:31, Peter Maydell wrote: > On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: >> With simple exposure of MMFG, ioport window, mmio window and an IRQ line we > > Four :-) > >> can successfully create a workable PCIe host bridge that can be mapped anywhere >> and only needs to get described to the OS using whatever means it likes. >> >> This patch implements such a "generic" host bridge. It only supports a single >> legacy IRQ line so far. MSIs need to be handled external to the host bridge. >> >> This device is particularly useful for the "pci-host-ecam-generic" driver in >> Linux. >> >> Signed-off-by: Alexander Graf <agraf@suse.de> >> Reviewed-by: Claudio Fontana <claudio.fontana@huawei.com> >> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> > > Checkpatch complains about a few over-80-chars lines; > the URL is an unavoidable one but could you fold the others, > please? Sure > >> +static void gpex_host_realize(DeviceState *dev, Error **errp) >> +{ >> + PCIHostState *pci = PCI_HOST_BRIDGE(dev); >> + GPEXHost *s = GPEX_HOST(dev); >> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); >> + PCIExpressHost *pex = PCIE_HOST_BRIDGE(dev); >> + int i; >> + >> + pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MIN); > > So this gives us 1MB of ECAM (config) space. That means > we can't specify a target bus, so we're restricted to > the 31 devices directly attached to the root complex. > Among other things, this will mean we can't do PCIe > hotplug. I think we should make this at least a bit bigger, > even if we don't go up to the full 256MB. > > Probably the best thing for the gpex device itself is > to make the config space be the spec maximum (PCIE_MMCFG_SIZE_MAX) > and let the user map only a portion of that into their > address space if they want. Sounds like a good plan. Will do. > > Ideally we should just do that in the base class, and > get the q35 subclass to do the right thing with aliases > to handle the dynamic resizing it wants. Then we wouldn't > need to track "size of cfg region" in the baseclass either. > >> + memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX); >> + memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024); >> + >> + sysbus_init_mmio(sbd, &pex->mmio); >> + sysbus_init_mmio(sbd, &s->io_mmio); >> + sysbus_init_mmio(sbd, &s->io_ioport); >> + for (i = 0; i < 4; i++) { > > Can we at least have a constant rather than hardcoded 4s ? > (qdev property for number-of-irqs if you're really feeling > enthusiastic...) Sure. > >> + >> +/**************************************************************************** >> + * GPEX Root D0:F0 >> + */ > > What does "D0:F0" mean here? Device 0 Function 0. It's pretty common PCI speech ;). > >> + >> +static const VMStateDescription vmstate_gpex_root = { >> + .name = "gpex_root", >> + .version_id = 1, >> + .minimum_version_id = 1, >> + .fields = (VMStateField[]) { >> + VMSTATE_PCI_DEVICE(parent_obj, GPEXRootState), >> + VMSTATE_END_OF_LIST() >> + } >> +}; >> + >> +static void gpex_root_class_init(ObjectClass *klass, void *data) >> +{ >> + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); >> + DeviceClass *dc = DEVICE_CLASS(klass); >> + >> + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); >> + dc->desc = "Host bridge"; > > We can be a bit less terse: "QEMU generic PCIe host bridge". > >> + dc->vmsd = &vmstate_gpex_root; >> + k->vendor_id = PCI_VENDOR_ID_REDHAT; >> + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; > > Pretty sure we shouldn't be reusing the PCI bridge IDs > for a host bridge. We should allocate ourselves another > device ID in the range... Ah, right, I forgot about that. Unfortunately I can't reserve PCI IDs in the Red Hat PCI range. Michael, what's the process here? > >> + k->revision = 0; >> + k->class_id = PCI_CLASS_BRIDGE_HOST; >> + /* >> + * PCI-facing part of the host bridge, not usable without the >> + * host-facing part, which can't be device_add'ed, yet. >> + */ >> + dc->cannot_instantiate_with_device_add_yet = true; >> +} >> + >> +static const TypeInfo gpex_root_info = { >> + .name = TYPE_GPEX_ROOT_DEVICE, >> + .parent = TYPE_PCI_DEVICE, >> + .instance_size = sizeof(GPEXRootState), >> + .class_init = gpex_root_class_init, >> +}; >> + >> +static void gpex_register(void) >> +{ >> + type_register_static(&gpex_root_info); >> + type_register_static(&gpex_host_info); >> +} >> + >> +type_init(gpex_register); > > We seem to prefer no trailing ';' on type_init by a ratio > of more than 10:1. Ok > >> diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h >> new file mode 100644 >> index 0000000..b465667 >> --- /dev/null >> +++ b/include/hw/pci-host/gpex.h >> @@ -0,0 +1,54 @@ >> +/* >> + * gpex.h > > Would be nice to say "QEMU Generic PCI Express Bridge Emulation" here > (like the .c file's header does). Ok Alex ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-29 13:59 ` Alexander Graf @ 2015-01-29 14:25 ` Peter Maydell 2015-01-30 10:25 ` Paolo Bonzini 0 siblings, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-29 14:25 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder, Paolo Bonzini On 29 January 2015 at 13:59, Alexander Graf <agraf@suse.de> wrote: > On 27.01.15 16:31, Peter Maydell wrote: >> On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: >>> + dc->vmsd = &vmstate_gpex_root; >>> + k->vendor_id = PCI_VENDOR_ID_REDHAT; >>> + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; >> >> Pretty sure we shouldn't be reusing the PCI bridge IDs >> for a host bridge. We should allocate ourselves another >> device ID in the range... > > Ah, right, I forgot about that. Unfortunately I can't reserve PCI IDs in > the Red Hat PCI range. > > Michael, what's the process here? Last time this came up I think Paolo said the official registration was getting a patch into QEMU master that added a line to the list in pci.h :-) [ie QEMU is the master source for these IDs] -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge 2015-01-29 14:25 ` Peter Maydell @ 2015-01-30 10:25 ` Paolo Bonzini 0 siblings, 0 replies; 24+ messages in thread From: Paolo Bonzini @ 2015-01-30 10:25 UTC (permalink / raw) To: Peter Maydell, Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 29/01/2015 15:25, Peter Maydell wrote: > > Ah, right, I forgot about that. Unfortunately I can't reserve PCI IDs in > > the Red Hat PCI range. > > > > Michael, what's the process here? > > Last time this came up I think Paolo said the official registration > was getting a patch into QEMU master that added a line to the > list in pci.h :-) [ie QEMU is the master source for these IDs] Yeah, rocker was the first case of someone not a QEMU developer needing an id. So let's make QEMU the master source. Paolo ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-21 16:18 [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge Alexander Graf @ 2015-01-21 16:18 ` Alexander Graf 2015-01-22 15:28 ` Claudio Fontana 2015-01-27 16:52 ` Peter Maydell 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 4/4] pci: Move PCI VGA to pci.mak Alexander Graf 3 siblings, 2 replies; 24+ messages in thread From: Alexander Graf @ 2015-01-21 16:18 UTC (permalink / raw) To: qemu-devel Cc: Peter Maydell, ard.biesheuvel, rob.herring, mst, claudio.fontana, stuart.yoder, a.rigo Now that we have a working "generic" PCIe host bridge driver, we can plug it into ARMs virt machine to always have PCIe available to normal ARM VMs. I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 into an AArch64 VM with this and they all lived happily ever after. Signed-off-by: Alexander Graf <agraf@suse.de> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> --- Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM systems. If you want to use it with AArch64 guests, please apply the following patch or wait until upstream cleaned up the code properly: http://csgraf.de/agraf/pci/pci-3.19.patch v1 -> v2: - Add define for pci range types - Remove mmio_window_size - Use 4 PCI INTX IRQ lines --- default-configs/arm-softmmu.mak | 2 + hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- include/sysemu/device_tree.h | 9 ++++ 3 files changed, 118 insertions(+), 5 deletions(-) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index f3513fa..7671ee2 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y CONFIG_VERSATILE_PCI=y CONFIG_VERSATILE_I2C=y +CONFIG_PCI_GENERIC=y + CONFIG_SDHCI=y CONFIG_INTEGRATOR_DEBUG=y diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 2353440..a727b4e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -42,6 +42,7 @@ #include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" +#include "hw/pci-host/gpex.h" #define NUM_VIRTIO_TRANSPORTS 32 @@ -69,6 +70,7 @@ enum { VIRT_MMIO, VIRT_RTC, VIRT_FW_CFG, + VIRT_PCIE, }; typedef struct MemMapEntry { @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ - /* 0x10000000 .. 0x40000000 reserved for PCI */ + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, }; static const int a15irqmap[] = { [VIRT_UART] = 1, [VIRT_RTC] = 2, + [VIRT_PCIE] = 3, /* ... to 6 */ [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ }; @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) } } -static void fdt_add_gic_node(const VirtBoardInfo *vbi) +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) { uint32_t gic_phandle; @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) 2, vbi->memmap[VIRT_GIC_CPU].base, 2, vbi->memmap[VIRT_GIC_CPU].size); qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); + + return gic_phandle; } -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) { /* We create a standalone GIC v2 */ DeviceState *gicdev; @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) pic[i] = qdev_get_gpio_in(gicdev, i); } - fdt_add_gic_node(vbi); + return fdt_add_gic_node(vbi); } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) g_free(nodename); } +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, + int first_irq, const char *nodename) +{ + int devfn, pin; + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; + uint32_t *irq_map = full_irq_map; + + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { + for (pin = 0; pin < 4; pin++) { + int irq_type = GIC_FDT_IRQ_TYPE_SPI; + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; + int i; + + uint32_t map[] = { + devfn << 8, 0, 0, /* devfn */ + pin + 1, /* PCI pin */ + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ + + /* Convert map to big endian */ + for (i = 0; i < 8; i++) { + irq_map[i] = cpu_to_be32(map[i]); + } + irq_map += 8; + } + } + + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", + full_irq_map, sizeof(full_irq_map)); +} + +static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, + uint32_t gic_phandle) +{ + hwaddr base = vbi->memmap[VIRT_PCIE].base; + hwaddr size = vbi->memmap[VIRT_PCIE].size; + hwaddr size_ioport = 64 * 1024; + hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN; + hwaddr size_mmio = size - size_ecam - size_ioport; + hwaddr base_mmio = base; + hwaddr base_ioport = base_mmio + size_mmio; + hwaddr base_ecam = base_ioport + size_ioport; + int irq = vbi->irqmap[VIRT_PCIE]; + MemoryRegion *mmio_alias; + MemoryRegion *mmio_reg; + DeviceState *dev; + char *nodename; + int i; + + dev = qdev_create(NULL, TYPE_GPEX_HOST); + qdev_init_nofail(dev); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base_ecam); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport); + + /* Map the MMIO window at the same spot in bus and cpu layouts */ + mmio_alias = g_new0(MemoryRegion, 1); + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", + mmio_reg, base_mmio, size_mmio); + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); + + for (i = 0; i < 4; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); + } + + nodename = g_strdup_printf("/pcie@%" PRIx64, base); + qemu_fdt_add_subnode(vbi->fdt, nodename); + qemu_fdt_setprop_string(vbi->fdt, nodename, + "compatible", "pci-host-ecam-generic"); + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); + qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, 1); + + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", + 2, base_ecam, 2, size_ecam); + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", + 1, FDT_PCI_RANGE_IOPORT, 2, 0, + 2, base_ioport, 2, size_ioport, + + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, + 2, base_mmio, 2, size_mmio); + + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); + create_pcie_irq_map(vbi, gic_phandle, irq, nodename); + + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", + 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ + 0x7 /* PCI irq */); + + g_free(nodename); +} + static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) { const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; @@ -573,6 +672,7 @@ static void machvirt_init(MachineState *machine) MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; VirtBoardInfo *vbi; + uint32_t gic_phandle; if (!cpu_model) { cpu_model = "cortex-a15"; @@ -634,12 +734,14 @@ static void machvirt_init(MachineState *machine) create_flash(vbi); - create_gic(vbi, pic); + gic_phandle = create_gic(vbi, pic); create_uart(vbi, pic); create_rtc(vbi, pic); + create_pcie(vbi, pic, gic_phandle); + /* Create mmio transports, so the user can create virtio backends * (which will be automatically plugged in to the transports). If * no backend is created the transport will just sit harmlessly idle. diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index 899f05c..979169b 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -110,4 +110,13 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, qdt_tmp); \ }) +#define FDT_PCI_RANGE_RELOCATABLE 0x80000000 +#define FDT_PCI_RANGE_PREFETCHABLE 0x40000000 +#define FDT_PCI_RANGE_ALIASED 0x20000000 +#define FDT_PCI_RANGE_TYPE 0x03000000 +#define FDT_PCI_RANGE_MMIO_64BIT 0x03000000 +#define FDT_PCI_RANGE_MMIO 0x02000000 +#define FDT_PCI_RANGE_IOPORT 0x01000000 +#define FDT_PCI_RANGE_CONFIG 0x00000000 + #endif /* __DEVICE_TREE_H__ */ -- 1.7.12.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine Alexander Graf @ 2015-01-22 15:28 ` Claudio Fontana 2015-01-22 15:52 ` Alexander Graf 2015-01-27 16:52 ` Peter Maydell 1 sibling, 1 reply; 24+ messages in thread From: Claudio Fontana @ 2015-01-22 15:28 UTC (permalink / raw) To: Alexander Graf, qemu-devel Cc: Peter Maydell, ard.biesheuvel, mst, rob.herring, stuart.yoder, a.rigo Hi Alexander, thank you for the respin. I retested with the new mappings on OSv for AArch64, and they show up ok in the guest. Just a couple minor comments below, otherwise I think this is good. On 21.01.2015 17:18, Alexander Graf wrote: > Now that we have a working "generic" PCIe host bridge driver, we can plug > it into ARMs virt machine to always have PCIe available to normal ARM VMs. > > I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 > into an AArch64 VM with this and they all lived happily ever after. > > Signed-off-by: Alexander Graf <agraf@suse.de> > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> > > --- > > Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM > systems. If you want to use it with AArch64 guests, please apply the following > patch or wait until upstream cleaned up the code properly: > > http://csgraf.de/agraf/pci/pci-3.19.patch > > v1 -> v2: > > - Add define for pci range types > - Remove mmio_window_size > - Use 4 PCI INTX IRQ lines > --- > default-configs/arm-softmmu.mak | 2 + > hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- > include/sysemu/device_tree.h | 9 ++++ > 3 files changed, 118 insertions(+), 5 deletions(-) > > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak > index f3513fa..7671ee2 100644 > --- a/default-configs/arm-softmmu.mak > +++ b/default-configs/arm-softmmu.mak > @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y > CONFIG_VERSATILE_PCI=y > CONFIG_VERSATILE_I2C=y > > +CONFIG_PCI_GENERIC=y > + > CONFIG_SDHCI=y > CONFIG_INTEGRATOR_DEBUG=y > > diff --git a/hw/arm/virt.c b/hw/arm/virt.c > index 2353440..a727b4e 100644 > --- a/hw/arm/virt.c > +++ b/hw/arm/virt.c > @@ -42,6 +42,7 @@ > #include "exec/address-spaces.h" > #include "qemu/bitops.h" > #include "qemu/error-report.h" > +#include "hw/pci-host/gpex.h" > > #define NUM_VIRTIO_TRANSPORTS 32 > > @@ -69,6 +70,7 @@ enum { > VIRT_MMIO, > VIRT_RTC, > VIRT_FW_CFG, > + VIRT_PCIE, > }; > > typedef struct MemMapEntry { > @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { > [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, > [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, > /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ > - /* 0x10000000 .. 0x40000000 reserved for PCI */ > + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, > [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, > }; > > static const int a15irqmap[] = { > [VIRT_UART] = 1, > [VIRT_RTC] = 2, > + [VIRT_PCIE] = 3, /* ... to 6 */ > [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ > }; > > @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) > } > } > > -static void fdt_add_gic_node(const VirtBoardInfo *vbi) > +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) > { > uint32_t gic_phandle; > > @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) > 2, vbi->memmap[VIRT_GIC_CPU].base, > 2, vbi->memmap[VIRT_GIC_CPU].size); > qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); > + > + return gic_phandle; > } > > -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > { > /* We create a standalone GIC v2 */ > DeviceState *gicdev; > @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > pic[i] = qdev_get_gpio_in(gicdev, i); > } > > - fdt_add_gic_node(vbi); > + return fdt_add_gic_node(vbi); > } > > static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) > @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) > g_free(nodename); > } > > +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, > + int first_irq, const char *nodename) > +{ > + int devfn, pin; > + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; > + uint32_t *irq_map = full_irq_map; > + > + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { devfn += 0x8 (spaces) > + for (pin = 0; pin < 4; pin++) { > + int irq_type = GIC_FDT_IRQ_TYPE_SPI; > + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); > + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; > + int i; > + > + uint32_t map[] = { > + devfn << 8, 0, 0, /* devfn */ > + pin + 1, /* PCI pin */ > + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ > + > + /* Convert map to big endian */ > + for (i = 0; i < 8; i++) { > + irq_map[i] = cpu_to_be32(map[i]); > + } > + irq_map += 8; > + } > + } > + > + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", > + full_irq_map, sizeof(full_irq_map)); > +} I raise again (? or maybe for the first time) the suggestion to add a comment like: /* see the openfirmware specs at * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf */ and optionally also a reference to the linux host-generic-pci bindings: /* see the linux Documentation about device tree bindings at: * https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt */ Peter mentioned that the documentation there is not perfect, but at least it's a starting point for the reader to understand what's going on. > + > +static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, > + uint32_t gic_phandle) > +{ > + hwaddr base = vbi->memmap[VIRT_PCIE].base; > + hwaddr size = vbi->memmap[VIRT_PCIE].size; > + hwaddr size_ioport = 64 * 1024; > + hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN; > + hwaddr size_mmio = size - size_ecam - size_ioport; > + hwaddr base_mmio = base; > + hwaddr base_ioport = base_mmio + size_mmio; > + hwaddr base_ecam = base_ioport + size_ioport; > + int irq = vbi->irqmap[VIRT_PCIE]; > + MemoryRegion *mmio_alias; > + MemoryRegion *mmio_reg; > + DeviceState *dev; > + char *nodename; > + int i; > + > + dev = qdev_create(NULL, TYPE_GPEX_HOST); > + qdev_init_nofail(dev); > + > + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base_ecam); > + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport); > + > + /* Map the MMIO window at the same spot in bus and cpu layouts */ > + mmio_alias = g_new0(MemoryRegion, 1); > + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); > + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", > + mmio_reg, base_mmio, size_mmio); > + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); > + > + for (i = 0; i < 4; i++) { > + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); > + } > + > + nodename = g_strdup_printf("/pcie@%" PRIx64, base); > + qemu_fdt_add_subnode(vbi->fdt, nodename); > + qemu_fdt_setprop_string(vbi->fdt, nodename, > + "compatible", "pci-host-ecam-generic"); > + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); > + qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, 1); > + > + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", > + 2, base_ecam, 2, size_ecam); > + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", > + 1, FDT_PCI_RANGE_IOPORT, 2, 0, > + 2, base_ioport, 2, size_ioport, > + > + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, > + 2, base_mmio, 2, size_mmio); > + > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); > + create_pcie_irq_map(vbi, gic_phandle, irq, nodename); > + > + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", > + 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ > + 0x7 /* PCI irq */); > + > + g_free(nodename); > +} > + > static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) > { > const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; > @@ -573,6 +672,7 @@ static void machvirt_init(MachineState *machine) > MemoryRegion *ram = g_new(MemoryRegion, 1); > const char *cpu_model = machine->cpu_model; > VirtBoardInfo *vbi; > + uint32_t gic_phandle; > > if (!cpu_model) { > cpu_model = "cortex-a15"; > @@ -634,12 +734,14 @@ static void machvirt_init(MachineState *machine) > > create_flash(vbi); > > - create_gic(vbi, pic); > + gic_phandle = create_gic(vbi, pic); > > create_uart(vbi, pic); > > create_rtc(vbi, pic); > > + create_pcie(vbi, pic, gic_phandle); > + > /* Create mmio transports, so the user can create virtio backends > * (which will be automatically plugged in to the transports). If > * no backend is created the transport will just sit harmlessly idle. > diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h > index 899f05c..979169b 100644 > --- a/include/sysemu/device_tree.h > +++ b/include/sysemu/device_tree.h > @@ -110,4 +110,13 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, > qdt_tmp); \ > }) > > +#define FDT_PCI_RANGE_RELOCATABLE 0x80000000 > +#define FDT_PCI_RANGE_PREFETCHABLE 0x40000000 > +#define FDT_PCI_RANGE_ALIASED 0x20000000 > +#define FDT_PCI_RANGE_TYPE 0x03000000 > +#define FDT_PCI_RANGE_MMIO_64BIT 0x03000000 > +#define FDT_PCI_RANGE_MMIO 0x02000000 > +#define FDT_PCI_RANGE_IOPORT 0x01000000 > +#define FDT_PCI_RANGE_CONFIG 0x00000000 > + > #endif /* __DEVICE_TREE_H__ */ > I appreciate those defines. Thank you, Claudio ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-22 15:28 ` Claudio Fontana @ 2015-01-22 15:52 ` Alexander Graf 2015-01-27 9:24 ` Claudio Fontana 0 siblings, 1 reply; 24+ messages in thread From: Alexander Graf @ 2015-01-22 15:52 UTC (permalink / raw) To: Claudio Fontana, qemu-devel Cc: Peter Maydell, ard.biesheuvel, mst, rob.herring, stuart.yoder, a.rigo On 22.01.15 16:28, Claudio Fontana wrote: > Hi Alexander, > > thank you for the respin. I retested with the new mappings on OSv for AArch64, > and they show up ok in the guest. > > Just a couple minor comments below, otherwise I think this is good. > > On 21.01.2015 17:18, Alexander Graf wrote: >> Now that we have a working "generic" PCIe host bridge driver, we can plug >> it into ARMs virt machine to always have PCIe available to normal ARM VMs. >> >> I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 >> into an AArch64 VM with this and they all lived happily ever after. >> >> Signed-off-by: Alexander Graf <agraf@suse.de> >> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> >> >> --- >> >> Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM >> systems. If you want to use it with AArch64 guests, please apply the following >> patch or wait until upstream cleaned up the code properly: >> >> http://csgraf.de/agraf/pci/pci-3.19.patch >> >> v1 -> v2: >> >> - Add define for pci range types >> - Remove mmio_window_size >> - Use 4 PCI INTX IRQ lines >> --- >> default-configs/arm-softmmu.mak | 2 + >> hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- >> include/sysemu/device_tree.h | 9 ++++ >> 3 files changed, 118 insertions(+), 5 deletions(-) >> >> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak >> index f3513fa..7671ee2 100644 >> --- a/default-configs/arm-softmmu.mak >> +++ b/default-configs/arm-softmmu.mak >> @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y >> CONFIG_VERSATILE_PCI=y >> CONFIG_VERSATILE_I2C=y >> >> +CONFIG_PCI_GENERIC=y >> + >> CONFIG_SDHCI=y >> CONFIG_INTEGRATOR_DEBUG=y >> >> diff --git a/hw/arm/virt.c b/hw/arm/virt.c >> index 2353440..a727b4e 100644 >> --- a/hw/arm/virt.c >> +++ b/hw/arm/virt.c >> @@ -42,6 +42,7 @@ >> #include "exec/address-spaces.h" >> #include "qemu/bitops.h" >> #include "qemu/error-report.h" >> +#include "hw/pci-host/gpex.h" >> >> #define NUM_VIRTIO_TRANSPORTS 32 >> >> @@ -69,6 +70,7 @@ enum { >> VIRT_MMIO, >> VIRT_RTC, >> VIRT_FW_CFG, >> + VIRT_PCIE, >> }; >> >> typedef struct MemMapEntry { >> @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { >> [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, >> [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, >> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ >> - /* 0x10000000 .. 0x40000000 reserved for PCI */ >> + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, >> [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, >> }; >> >> static const int a15irqmap[] = { >> [VIRT_UART] = 1, >> [VIRT_RTC] = 2, >> + [VIRT_PCIE] = 3, /* ... to 6 */ >> [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ >> }; >> >> @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) >> } >> } >> >> -static void fdt_add_gic_node(const VirtBoardInfo *vbi) >> +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) >> { >> uint32_t gic_phandle; >> >> @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) >> 2, vbi->memmap[VIRT_GIC_CPU].base, >> 2, vbi->memmap[VIRT_GIC_CPU].size); >> qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); >> + >> + return gic_phandle; >> } >> >> -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> { >> /* We create a standalone GIC v2 */ >> DeviceState *gicdev; >> @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> pic[i] = qdev_get_gpio_in(gicdev, i); >> } >> >> - fdt_add_gic_node(vbi); >> + return fdt_add_gic_node(vbi); >> } >> >> static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) >> @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) >> g_free(nodename); >> } >> >> +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, >> + int first_irq, const char *nodename) >> +{ >> + int devfn, pin; >> + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; >> + uint32_t *irq_map = full_irq_map; >> + >> + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { > > devfn += 0x8 (spaces) Yeah, I had it like that and it looked uglier. I guess it's a matter of personal preference? > >> + for (pin = 0; pin < 4; pin++) { >> + int irq_type = GIC_FDT_IRQ_TYPE_SPI; >> + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); >> + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; >> + int i; >> + >> + uint32_t map[] = { >> + devfn << 8, 0, 0, /* devfn */ >> + pin + 1, /* PCI pin */ >> + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ >> + >> + /* Convert map to big endian */ >> + for (i = 0; i < 8; i++) { >> + irq_map[i] = cpu_to_be32(map[i]); >> + } >> + irq_map += 8; >> + } >> + } >> + >> + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", >> + full_irq_map, sizeof(full_irq_map)); >> +} > > I raise again (? or maybe for the first time) the suggestion to add a comment like: > > /* see the openfirmware specs at > * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf > */ > > and optionally also a reference to the linux host-generic-pci bindings: > > /* see the linux Documentation about device tree bindings at: > * https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt > */ I added those links to the big description comment at the top of this file. Alex ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-22 15:52 ` Alexander Graf @ 2015-01-27 9:24 ` Claudio Fontana 2015-01-27 10:09 ` Peter Maydell 0 siblings, 1 reply; 24+ messages in thread From: Claudio Fontana @ 2015-01-27 9:24 UTC (permalink / raw) To: Alexander Graf, qemu-devel Cc: Peter Maydell, ard.biesheuvel, mst, rob.herring, stuart.yoder, a.rigo On 22.01.2015 16:52, Alexander Graf wrote: > > > On 22.01.15 16:28, Claudio Fontana wrote: >> Hi Alexander, >> >> thank you for the respin. I retested with the new mappings on OSv for AArch64, >> and they show up ok in the guest. >> >> Just a couple minor comments below, otherwise I think this is good. >> >> On 21.01.2015 17:18, Alexander Graf wrote: >>> Now that we have a working "generic" PCIe host bridge driver, we can plug >>> it into ARMs virt machine to always have PCIe available to normal ARM VMs. >>> >>> I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 >>> into an AArch64 VM with this and they all lived happily ever after. >>> >>> Signed-off-by: Alexander Graf <agraf@suse.de> >>> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> >>> >>> --- >>> >>> Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM >>> systems. If you want to use it with AArch64 guests, please apply the following >>> patch or wait until upstream cleaned up the code properly: >>> >>> http://csgraf.de/agraf/pci/pci-3.19.patch >>> >>> v1 -> v2: >>> >>> - Add define for pci range types >>> - Remove mmio_window_size >>> - Use 4 PCI INTX IRQ lines >>> --- >>> default-configs/arm-softmmu.mak | 2 + >>> hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- >>> include/sysemu/device_tree.h | 9 ++++ >>> 3 files changed, 118 insertions(+), 5 deletions(-) >>> >>> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak >>> index f3513fa..7671ee2 100644 >>> --- a/default-configs/arm-softmmu.mak >>> +++ b/default-configs/arm-softmmu.mak >>> @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y >>> CONFIG_VERSATILE_PCI=y >>> CONFIG_VERSATILE_I2C=y >>> >>> +CONFIG_PCI_GENERIC=y >>> + >>> CONFIG_SDHCI=y >>> CONFIG_INTEGRATOR_DEBUG=y >>> >>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c >>> index 2353440..a727b4e 100644 >>> --- a/hw/arm/virt.c >>> +++ b/hw/arm/virt.c >>> @@ -42,6 +42,7 @@ >>> #include "exec/address-spaces.h" >>> #include "qemu/bitops.h" >>> #include "qemu/error-report.h" >>> +#include "hw/pci-host/gpex.h" >>> >>> #define NUM_VIRTIO_TRANSPORTS 32 >>> >>> @@ -69,6 +70,7 @@ enum { >>> VIRT_MMIO, >>> VIRT_RTC, >>> VIRT_FW_CFG, >>> + VIRT_PCIE, >>> }; >>> >>> typedef struct MemMapEntry { >>> @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { >>> [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, >>> [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, >>> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ >>> - /* 0x10000000 .. 0x40000000 reserved for PCI */ >>> + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, >>> [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, >>> }; >>> >>> static const int a15irqmap[] = { >>> [VIRT_UART] = 1, >>> [VIRT_RTC] = 2, >>> + [VIRT_PCIE] = 3, /* ... to 6 */ >>> [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ >>> }; >>> >>> @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) >>> } >>> } >>> >>> -static void fdt_add_gic_node(const VirtBoardInfo *vbi) >>> +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) >>> { >>> uint32_t gic_phandle; >>> >>> @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) >>> 2, vbi->memmap[VIRT_GIC_CPU].base, >>> 2, vbi->memmap[VIRT_GIC_CPU].size); >>> qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); >>> + >>> + return gic_phandle; >>> } >>> >>> -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >>> +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >>> { >>> /* We create a standalone GIC v2 */ >>> DeviceState *gicdev; >>> @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >>> pic[i] = qdev_get_gpio_in(gicdev, i); >>> } >>> >>> - fdt_add_gic_node(vbi); >>> + return fdt_add_gic_node(vbi); >>> } >>> >>> static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) >>> @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) >>> g_free(nodename); >>> } >>> >>> +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, >>> + int first_irq, const char *nodename) >>> +{ >>> + int devfn, pin; >>> + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; >>> + uint32_t *irq_map = full_irq_map; >>> + >>> + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { >> >> devfn += 0x8 (spaces) > > Yeah, I had it like that and it looked uglier. I guess it's a matter of > personal preference? You don't have coding standards for this ? > >> >>> + for (pin = 0; pin < 4; pin++) { >>> + int irq_type = GIC_FDT_IRQ_TYPE_SPI; >>> + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); >>> + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; >>> + int i; >>> + >>> + uint32_t map[] = { >>> + devfn << 8, 0, 0, /* devfn */ >>> + pin + 1, /* PCI pin */ >>> + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ >>> + >>> + /* Convert map to big endian */ >>> + for (i = 0; i < 8; i++) { >>> + irq_map[i] = cpu_to_be32(map[i]); >>> + } >>> + irq_map += 8; >>> + } >>> + } >>> + >>> + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", >>> + full_irq_map, sizeof(full_irq_map)); >>> +} >> >> I raise again (? or maybe for the first time) the suggestion to add a comment like: >> >> /* see the openfirmware specs at >> * http://www.firmware.org/1275/practice/imap/imap0_9d.pdf >> */ >> >> and optionally also a reference to the linux host-generic-pci bindings: >> >> /* see the linux Documentation about device tree bindings at: >> * https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/host-generic-pci.txt >> */ > > I added those links to the big description comment at the top of this file. > It is not on top of this file unfortunately. You put the description comment in an unrelated .h file: the pointers to the docs belong here I think. Ciao, Claudio ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-27 9:24 ` Claudio Fontana @ 2015-01-27 10:09 ` Peter Maydell 2015-01-27 14:37 ` Claudio Fontana 0 siblings, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-27 10:09 UTC (permalink / raw) To: Claudio Fontana Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Alvise Rigo, Stuart Yoder, Alexander Graf On 27 January 2015 at 09:24, Claudio Fontana <claudio.fontana@huawei.com> wrote: > On 22.01.2015 16:52, Alexander Graf wrote: >> On 22.01.15 16:28, Claudio Fontana wrote: >>> Alex wrote; >>>> + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { >>> >>> devfn += 0x8 (spaces) >> >> Yeah, I had it like that and it looked uglier. I guess it's a matter of >> personal preference? > > You don't have coding standards for this ? Not formal ones, but (a) I think += should have spaces aronud it and (b) I'm a bit surprised if checkpatch doesn't catch this (it certainly attempts to...) -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-27 10:09 ` Peter Maydell @ 2015-01-27 14:37 ` Claudio Fontana 0 siblings, 0 replies; 24+ messages in thread From: Claudio Fontana @ 2015-01-27 14:37 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Alvise Rigo, Stuart Yoder, Alexander Graf On 27.01.2015 11:09, Peter Maydell wrote: > On 27 January 2015 at 09:24, Claudio Fontana <claudio.fontana@huawei.com> wrote: >> On 22.01.2015 16:52, Alexander Graf wrote: >>> On 22.01.15 16:28, Claudio Fontana wrote: >>>> Alex wrote; >>>>> + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { >>>> >>>> devfn += 0x8 (spaces) >>> >>> Yeah, I had it like that and it looked uglier. I guess it's a matter of >>> personal preference? >> >> You don't have coding standards for this ? > > Not formal ones, but (a) I think += should have spaces aronud > it and (b) I'm a bit surprised if checkpatch doesn't catch > this (it certainly attempts to...) > > -- PMM It does: ERROR: spaces required around that '+=' (ctx:VxV) #167: FILE: hw/arm/virt.c:571: + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { ^ Claudio ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine Alexander Graf 2015-01-22 15:28 ` Claudio Fontana @ 2015-01-27 16:52 ` Peter Maydell 2015-01-29 14:31 ` Alexander Graf 1 sibling, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-27 16:52 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: > Now that we have a working "generic" PCIe host bridge driver, we can plug > it into ARMs virt machine to always have PCIe available to normal ARM VMs. "ARM's". > > I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 > into an AArch64 VM with this and they all lived happily ever after. > > Signed-off-by: Alexander Graf <agraf@suse.de> > Tested-by: Claudio Fontana <claudio.fontana@huawei.com> > > --- > > Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM > systems. If you want to use it with AArch64 guests, please apply the following > patch or wait until upstream cleaned up the code properly: > > http://csgraf.de/agraf/pci/pci-3.19.patch > > v1 -> v2: > > - Add define for pci range types > - Remove mmio_window_size > - Use 4 PCI INTX IRQ lines > --- > default-configs/arm-softmmu.mak | 2 + > hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- > include/sysemu/device_tree.h | 9 ++++ > 3 files changed, 118 insertions(+), 5 deletions(-) > > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak > index f3513fa..7671ee2 100644 > --- a/default-configs/arm-softmmu.mak > +++ b/default-configs/arm-softmmu.mak > @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y > CONFIG_VERSATILE_PCI=y > CONFIG_VERSATILE_I2C=y > > +CONFIG_PCI_GENERIC=y > + > CONFIG_SDHCI=y > CONFIG_INTEGRATOR_DEBUG=y > > diff --git a/hw/arm/virt.c b/hw/arm/virt.c > index 2353440..a727b4e 100644 > --- a/hw/arm/virt.c > +++ b/hw/arm/virt.c > @@ -42,6 +42,7 @@ > #include "exec/address-spaces.h" > #include "qemu/bitops.h" > #include "qemu/error-report.h" > +#include "hw/pci-host/gpex.h" > > #define NUM_VIRTIO_TRANSPORTS 32 > > @@ -69,6 +70,7 @@ enum { > VIRT_MMIO, > VIRT_RTC, > VIRT_FW_CFG, > + VIRT_PCIE, > }; > > typedef struct MemMapEntry { > @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { > [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, > [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, > /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ > - /* 0x10000000 .. 0x40000000 reserved for PCI */ > + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, Might be nice to have a comment about how this is split up between MMIO, IO and config space. > [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, > }; > > static const int a15irqmap[] = { > [VIRT_UART] = 1, > [VIRT_RTC] = 2, > + [VIRT_PCIE] = 3, /* ... to 6 */ > [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ > }; > > @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) > } > } > > -static void fdt_add_gic_node(const VirtBoardInfo *vbi) > +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) > { > uint32_t gic_phandle; > > @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) > 2, vbi->memmap[VIRT_GIC_CPU].base, > 2, vbi->memmap[VIRT_GIC_CPU].size); > qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); > + > + return gic_phandle; > } > > -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > { > /* We create a standalone GIC v2 */ > DeviceState *gicdev; > @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) > pic[i] = qdev_get_gpio_in(gicdev, i); > } > > - fdt_add_gic_node(vbi); > + return fdt_add_gic_node(vbi); > } > > static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) > @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) > g_free(nodename); > } > > +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, > + int first_irq, const char *nodename) > +{ > + int devfn, pin; > + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; > + uint32_t *irq_map = full_irq_map; > + > + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { > + for (pin = 0; pin < 4; pin++) { > + int irq_type = GIC_FDT_IRQ_TYPE_SPI; > + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); > + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; > + int i; > + > + uint32_t map[] = { > + devfn << 8, 0, 0, /* devfn */ > + pin + 1, /* PCI pin */ > + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ > + > + /* Convert map to big endian */ > + for (i = 0; i < 8; i++) { > + irq_map[i] = cpu_to_be32(map[i]); > + } > + irq_map += 8; > + } > + } > + > + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", > + full_irq_map, sizeof(full_irq_map)); > +} > + > +static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, > + uint32_t gic_phandle) > +{ > + hwaddr base = vbi->memmap[VIRT_PCIE].base; > + hwaddr size = vbi->memmap[VIRT_PCIE].size; > + hwaddr size_ioport = 64 * 1024; > + hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN; See remarks in previous patch about wanting more than the minimum ECAM space. > + hwaddr size_mmio = size - size_ecam - size_ioport; > + hwaddr base_mmio = base; > + hwaddr base_ioport = base_mmio + size_mmio; > + hwaddr base_ecam = base_ioport + size_ioport; PCIe spec says the ECAM window has to be aligned to its size (ie if it's 1MB in size it has to be 1MB aligned, if it's 256MB aligned it has to be 256MB aligned). I think this is dumb, but it's what the spec says... > + int irq = vbi->irqmap[VIRT_PCIE]; > + MemoryRegion *mmio_alias; > + MemoryRegion *mmio_reg; > + DeviceState *dev; > + char *nodename; > + int i; > + > + dev = qdev_create(NULL, TYPE_GPEX_HOST); > + qdev_init_nofail(dev); > + > + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base_ecam); > + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport); > + > + /* Map the MMIO window at the same spot in bus and cpu layouts */ > + mmio_alias = g_new0(MemoryRegion, 1); > + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); > + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", > + mmio_reg, base_mmio, size_mmio); > + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); The comment claims to be mapping the MMIO window twice (in the system memory space and in the PCI mmio address space) but the code only seems to be mapping something into system memory space? > + > + for (i = 0; i < 4; i++) { > + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); > + } > + > + nodename = g_strdup_printf("/pcie@%" PRIx64, base); > + qemu_fdt_add_subnode(vbi->fdt, nodename); > + qemu_fdt_setprop_string(vbi->fdt, nodename, > + "compatible", "pci-host-ecam-generic"); > + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); > + qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, 1); > + > + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", > + 2, base_ecam, 2, size_ecam); > + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", > + 1, FDT_PCI_RANGE_IOPORT, 2, 0, > + 2, base_ioport, 2, size_ioport, > + > + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, > + 2, base_mmio, 2, size_mmio); > + > + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); > + create_pcie_irq_map(vbi, gic_phandle, irq, nodename); > + > + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", > + 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ > + 0x7 /* PCI irq */); I think at least the interrupt-map-mask and maybe also the #interrupt-cells setprop calls should go inside the create_pcie_irq_map() function. In particular the interrupt-map and interrupt-map-mask are meaningless unless interpreted together so they should go in the same function. > + > + g_free(nodename); > +} > + > static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) > { > const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; > @@ -573,6 +672,7 @@ static void machvirt_init(MachineState *machine) > MemoryRegion *ram = g_new(MemoryRegion, 1); > const char *cpu_model = machine->cpu_model; > VirtBoardInfo *vbi; > + uint32_t gic_phandle; > > if (!cpu_model) { > cpu_model = "cortex-a15"; > @@ -634,12 +734,14 @@ static void machvirt_init(MachineState *machine) > > create_flash(vbi); > > - create_gic(vbi, pic); > + gic_phandle = create_gic(vbi, pic); > > create_uart(vbi, pic); > > create_rtc(vbi, pic); > > + create_pcie(vbi, pic, gic_phandle); > + > /* Create mmio transports, so the user can create virtio backends > * (which will be automatically plugged in to the transports). If > * no backend is created the transport will just sit harmlessly idle. > diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h > index 899f05c..979169b 100644 > --- a/include/sysemu/device_tree.h > +++ b/include/sysemu/device_tree.h > @@ -110,4 +110,13 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, > qdt_tmp); \ > }) > > +#define FDT_PCI_RANGE_RELOCATABLE 0x80000000 > +#define FDT_PCI_RANGE_PREFETCHABLE 0x40000000 > +#define FDT_PCI_RANGE_ALIASED 0x20000000 > +#define FDT_PCI_RANGE_TYPE 0x03000000 > +#define FDT_PCI_RANGE_MMIO_64BIT 0x03000000 I had to go dig up the spec to figure out that it wasn't an error that these two had the same values. Calling the first _TYPE_MASK might help? > +#define FDT_PCI_RANGE_MMIO 0x02000000 > +#define FDT_PCI_RANGE_IOPORT 0x01000000 > +#define FDT_PCI_RANGE_CONFIG 0x00000000 thanks -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-27 16:52 ` Peter Maydell @ 2015-01-29 14:31 ` Alexander Graf 2015-01-29 14:34 ` Peter Maydell 0 siblings, 1 reply; 24+ messages in thread From: Alexander Graf @ 2015-01-29 14:31 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 27.01.15 17:52, Peter Maydell wrote: > On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: >> Now that we have a working "generic" PCIe host bridge driver, we can plug >> it into ARMs virt machine to always have PCIe available to normal ARM VMs. > > "ARM's". > >> >> I've successfully managed to expose a Bochs VGA device, XHCI and an e1000 >> into an AArch64 VM with this and they all lived happily ever after. >> >> Signed-off-by: Alexander Graf <agraf@suse.de> >> Tested-by: Claudio Fontana <claudio.fontana@huawei.com> >> >> --- >> >> Linux 3.19 only supports the generic PCIe host bridge driver for 32bit ARM >> systems. If you want to use it with AArch64 guests, please apply the following >> patch or wait until upstream cleaned up the code properly: >> >> http://csgraf.de/agraf/pci/pci-3.19.patch >> >> v1 -> v2: >> >> - Add define for pci range types >> - Remove mmio_window_size >> - Use 4 PCI INTX IRQ lines >> --- >> default-configs/arm-softmmu.mak | 2 + >> hw/arm/virt.c | 112 ++++++++++++++++++++++++++++++++++++++-- >> include/sysemu/device_tree.h | 9 ++++ >> 3 files changed, 118 insertions(+), 5 deletions(-) >> >> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak >> index f3513fa..7671ee2 100644 >> --- a/default-configs/arm-softmmu.mak >> +++ b/default-configs/arm-softmmu.mak >> @@ -82,6 +82,8 @@ CONFIG_ZYNQ=y >> CONFIG_VERSATILE_PCI=y >> CONFIG_VERSATILE_I2C=y >> >> +CONFIG_PCI_GENERIC=y >> + >> CONFIG_SDHCI=y >> CONFIG_INTEGRATOR_DEBUG=y >> >> diff --git a/hw/arm/virt.c b/hw/arm/virt.c >> index 2353440..a727b4e 100644 >> --- a/hw/arm/virt.c >> +++ b/hw/arm/virt.c >> @@ -42,6 +42,7 @@ >> #include "exec/address-spaces.h" >> #include "qemu/bitops.h" >> #include "qemu/error-report.h" >> +#include "hw/pci-host/gpex.h" >> >> #define NUM_VIRTIO_TRANSPORTS 32 >> >> @@ -69,6 +70,7 @@ enum { >> VIRT_MMIO, >> VIRT_RTC, >> VIRT_FW_CFG, >> + VIRT_PCIE, >> }; >> >> typedef struct MemMapEntry { >> @@ -129,13 +131,14 @@ static const MemMapEntry a15memmap[] = { >> [VIRT_FW_CFG] = { 0x09020000, 0x0000000a }, >> [VIRT_MMIO] = { 0x0a000000, 0x00000200 }, >> /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ >> - /* 0x10000000 .. 0x40000000 reserved for PCI */ >> + [VIRT_PCIE] = { 0x10000000, 0x30000000 }, > > Might be nice to have a comment about how this is split up between > MMIO, IO and config space. I'd prefer to keep the details of that in the allocation code so that we don't potentially have 2 places that diverge eventually. But I'll document the allocation code a bit nicer and add a small overview split here. > >> [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 }, >> }; >> >> static const int a15irqmap[] = { >> [VIRT_UART] = 1, >> [VIRT_RTC] = 2, >> + [VIRT_PCIE] = 3, /* ... to 6 */ >> [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ >> }; >> >> @@ -312,7 +315,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) >> } >> } >> >> -static void fdt_add_gic_node(const VirtBoardInfo *vbi) >> +static uint32_t fdt_add_gic_node(const VirtBoardInfo *vbi) >> { >> uint32_t gic_phandle; >> >> @@ -331,9 +334,11 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi) >> 2, vbi->memmap[VIRT_GIC_CPU].base, >> 2, vbi->memmap[VIRT_GIC_CPU].size); >> qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle); >> + >> + return gic_phandle; >> } >> >> -static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> +static uint32_t create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> { >> /* We create a standalone GIC v2 */ >> DeviceState *gicdev; >> @@ -380,7 +385,7 @@ static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic) >> pic[i] = qdev_get_gpio_in(gicdev, i); >> } >> >> - fdt_add_gic_node(vbi); >> + return fdt_add_gic_node(vbi); >> } >> >> static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) >> @@ -556,6 +561,100 @@ static void create_fw_cfg(const VirtBoardInfo *vbi) >> g_free(nodename); >> } >> >> +static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, >> + int first_irq, const char *nodename) >> +{ >> + int devfn, pin; >> + uint32_t full_irq_map[4 * 4 * 8] = { 0 }; >> + uint32_t *irq_map = full_irq_map; >> + >> + for (devfn = 0; devfn <= 0x18; devfn+=0x8) { >> + for (pin = 0; pin < 4; pin++) { >> + int irq_type = GIC_FDT_IRQ_TYPE_SPI; >> + int irq_nr = first_irq + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); >> + int irq_level = GIC_FDT_IRQ_FLAGS_LEVEL_HI; >> + int i; >> + >> + uint32_t map[] = { >> + devfn << 8, 0, 0, /* devfn */ >> + pin + 1, /* PCI pin */ >> + gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ >> + >> + /* Convert map to big endian */ >> + for (i = 0; i < 8; i++) { >> + irq_map[i] = cpu_to_be32(map[i]); >> + } >> + irq_map += 8; >> + } >> + } >> + >> + qemu_fdt_setprop(vbi->fdt, nodename, "interrupt-map", >> + full_irq_map, sizeof(full_irq_map)); >> +} >> + >> +static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic, >> + uint32_t gic_phandle) >> +{ >> + hwaddr base = vbi->memmap[VIRT_PCIE].base; >> + hwaddr size = vbi->memmap[VIRT_PCIE].size; >> + hwaddr size_ioport = 64 * 1024; >> + hwaddr size_ecam = PCIE_MMCFG_SIZE_MIN; > > See remarks in previous patch about wanting more than the minimum > ECAM space. > >> + hwaddr size_mmio = size - size_ecam - size_ioport; >> + hwaddr base_mmio = base; >> + hwaddr base_ioport = base_mmio + size_mmio; >> + hwaddr base_ecam = base_ioport + size_ioport; > > PCIe spec says the ECAM window has to be aligned to its size > (ie if it's 1MB in size it has to be 1MB aligned, if it's > 256MB aligned it has to be 256MB aligned). I think this is > dumb, but it's what the spec says... No problem, fortunately we have a good number of nice macros for this ;) > >> + int irq = vbi->irqmap[VIRT_PCIE]; >> + MemoryRegion *mmio_alias; >> + MemoryRegion *mmio_reg; >> + DeviceState *dev; >> + char *nodename; >> + int i; >> + >> + dev = qdev_create(NULL, TYPE_GPEX_HOST); >> + qdev_init_nofail(dev); >> + >> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base_ecam); >> + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_ioport); >> + >> + /* Map the MMIO window at the same spot in bus and cpu layouts */ >> + mmio_alias = g_new0(MemoryRegion, 1); >> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); >> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", >> + mmio_reg, base_mmio, size_mmio); >> + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); > > The comment claims to be mapping the MMIO window twice (in the > system memory space and in the PCI mmio address space) but the > code only seems to be mapping something into system memory space? The comment claims to map it at the same spot. It means the offset in system memory is the same offset as the one in the mmio window that gets exported by the PHB. The PHB exports a UINT64_MAX MMIO region as id 1. This is basically a full window into the PCI address space. What we do here is to map a 1:1 window between CPU address space and PCI address space. > >> + >> + for (i = 0; i < 4; i++) { >> + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); >> + } >> + >> + nodename = g_strdup_printf("/pcie@%" PRIx64, base); >> + qemu_fdt_add_subnode(vbi->fdt, nodename); >> + qemu_fdt_setprop_string(vbi->fdt, nodename, >> + "compatible", "pci-host-ecam-generic"); >> + qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "pci"); >> + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#address-cells", 3); >> + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); >> + qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, 1); >> + >> + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", >> + 2, base_ecam, 2, size_ecam); >> + qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "ranges", >> + 1, FDT_PCI_RANGE_IOPORT, 2, 0, >> + 2, base_ioport, 2, size_ioport, >> + >> + 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, >> + 2, base_mmio, 2, size_mmio); >> + >> + qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1); >> + create_pcie_irq_map(vbi, gic_phandle, irq, nodename); >> + >> + qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupt-map-mask", >> + 0x1800, 0, 0, /* devfn (PCI_SLOT(3)) */ >> + 0x7 /* PCI irq */); > > I think at least the interrupt-map-mask and maybe also the > #interrupt-cells setprop calls should go inside the > create_pcie_irq_map() function. In particular the interrupt-map > and interrupt-map-mask are meaningless unless interpreted together > so they should go in the same function. Sure, works for me. > >> + >> + g_free(nodename); >> +} >> + >> static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) >> { >> const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; >> @@ -573,6 +672,7 @@ static void machvirt_init(MachineState *machine) >> MemoryRegion *ram = g_new(MemoryRegion, 1); >> const char *cpu_model = machine->cpu_model; >> VirtBoardInfo *vbi; >> + uint32_t gic_phandle; >> >> if (!cpu_model) { >> cpu_model = "cortex-a15"; >> @@ -634,12 +734,14 @@ static void machvirt_init(MachineState *machine) >> >> create_flash(vbi); >> >> - create_gic(vbi, pic); >> + gic_phandle = create_gic(vbi, pic); >> >> create_uart(vbi, pic); >> >> create_rtc(vbi, pic); >> >> + create_pcie(vbi, pic, gic_phandle); >> + >> /* Create mmio transports, so the user can create virtio backends >> * (which will be automatically plugged in to the transports). If >> * no backend is created the transport will just sit harmlessly idle. >> diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h >> index 899f05c..979169b 100644 >> --- a/include/sysemu/device_tree.h >> +++ b/include/sysemu/device_tree.h >> @@ -110,4 +110,13 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt, >> qdt_tmp); \ >> }) >> >> +#define FDT_PCI_RANGE_RELOCATABLE 0x80000000 >> +#define FDT_PCI_RANGE_PREFETCHABLE 0x40000000 >> +#define FDT_PCI_RANGE_ALIASED 0x20000000 >> +#define FDT_PCI_RANGE_TYPE 0x03000000 >> +#define FDT_PCI_RANGE_MMIO_64BIT 0x03000000 > > I had to go dig up the spec to figure out that it wasn't an error that > these two had the same values. Calling the first _TYPE_MASK might help? Probably :) Alex ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-29 14:31 ` Alexander Graf @ 2015-01-29 14:34 ` Peter Maydell 2015-01-29 14:37 ` Alexander Graf 0 siblings, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-29 14:34 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 29 January 2015 at 14:31, Alexander Graf <agraf@suse.de> wrote: > > > On 27.01.15 17:52, Peter Maydell wrote: >> On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: >>> + /* Map the MMIO window at the same spot in bus and cpu layouts */ >>> + mmio_alias = g_new0(MemoryRegion, 1); >>> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); >>> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", >>> + mmio_reg, base_mmio, size_mmio); >>> + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); >> >> The comment claims to be mapping the MMIO window twice (in the >> system memory space and in the PCI mmio address space) but the >> code only seems to be mapping something into system memory space? > > The comment claims to map it at the same spot. It means the offset in > system memory is the same offset as the one in the mmio window that gets > exported by the PHB. > > The PHB exports a UINT64_MAX MMIO region as id 1. This is basically a > full window into the PCI address space. What we do here is to map a 1:1 > window between CPU address space and PCI address space. I kind of see, but isn't this just a window from CPU address space into PCI address space, not vice-versa? DMA by PCI devices bus-mastering into system memory must be being set up elsewhere, I think. -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-29 14:34 ` Peter Maydell @ 2015-01-29 14:37 ` Alexander Graf 2015-01-29 14:45 ` Peter Maydell 0 siblings, 1 reply; 24+ messages in thread From: Alexander Graf @ 2015-01-29 14:37 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 29.01.15 15:34, Peter Maydell wrote: > On 29 January 2015 at 14:31, Alexander Graf <agraf@suse.de> wrote: >> >> >> On 27.01.15 17:52, Peter Maydell wrote: >>> On 21 January 2015 at 16:18, Alexander Graf <agraf@suse.de> wrote: >>>> + /* Map the MMIO window at the same spot in bus and cpu layouts */ >>>> + mmio_alias = g_new0(MemoryRegion, 1); >>>> + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); >>>> + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", >>>> + mmio_reg, base_mmio, size_mmio); >>>> + memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias); >>> >>> The comment claims to be mapping the MMIO window twice (in the >>> system memory space and in the PCI mmio address space) but the >>> code only seems to be mapping something into system memory space? >> >> The comment claims to map it at the same spot. It means the offset in >> system memory is the same offset as the one in the mmio window that gets >> exported by the PHB. >> >> The PHB exports a UINT64_MAX MMIO region as id 1. This is basically a >> full window into the PCI address space. What we do here is to map a 1:1 >> window between CPU address space and PCI address space. > > I kind of see, but isn't this just a window from CPU address > space into PCI address space, not vice-versa? Yup, exactly. But PCI devices need to map themselves somewhere into the PCI address space. So if I configure a BAR to live at 0x10000000, it should also show up at 0x10000000 when accessed from the CPU. That's what the mapping above is about. > DMA by PCI devices bus-mastering into system memory must be > being set up elsewhere, I think. Yes, that's a different mechanism that's not implemented yet for GPEX :). On ARM this would happen via SMMU emulation. Alex ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-29 14:37 ` Alexander Graf @ 2015-01-29 14:45 ` Peter Maydell 2015-01-29 14:49 ` Alexander Graf 0 siblings, 1 reply; 24+ messages in thread From: Peter Maydell @ 2015-01-29 14:45 UTC (permalink / raw) To: Alexander Graf Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 29 January 2015 at 14:37, Alexander Graf <agraf@suse.de> wrote: > On 29.01.15 15:34, Peter Maydell wrote: >> I kind of see, but isn't this just a window from CPU address >> space into PCI address space, not vice-versa? > > Yup, exactly. But PCI devices need to map themselves somewhere into the > PCI address space. So if I configure a BAR to live at 0x10000000, it > should also show up at 0x10000000 when accessed from the CPU. That's > what the mapping above is about. No, it doesn't have to. It's a choice to make the mapping be such that the system address for a BAR matches the address in PCI memory space, not a requirement. I agree it's a sensible choice, though. But as I say, this code is setting up one mapping (the system address -> PCI space mapping), not two. >> DMA by PCI devices bus-mastering into system memory must be >> being set up elsewhere, I think. > > Yes, that's a different mechanism that's not implemented yet for GPEX > :). We can't not implement DMA, it would break lots of the usual PCI devices people want to use. In fact I thought the PCI core code implemented a default of "DMA by PCI devices goes to the system address space" if you didn't specifically set up something else by calling pci_setup_iommu(). This is definitely how it works for plain PCI host bridges, are PCIe bridges different? > On ARM this would happen via SMMU emulation. There's no requirement for a PCI host controller to be sat behind an SMMU -- that's a system design choice. We don't need to implement the SMMU yet (or perhaps ever?); we definitely need to support PCI DMA. -- PMM ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine 2015-01-29 14:45 ` Peter Maydell @ 2015-01-29 14:49 ` Alexander Graf 0 siblings, 0 replies; 24+ messages in thread From: Alexander Graf @ 2015-01-29 14:49 UTC (permalink / raw) To: Peter Maydell Cc: Rob Herring, Michael S. Tsirkin, QEMU Developers, Ard Biesheuvel, Claudio Fontana, Alvise Rigo, Stuart Yoder On 29.01.15 15:45, Peter Maydell wrote: > On 29 January 2015 at 14:37, Alexander Graf <agraf@suse.de> wrote: >> On 29.01.15 15:34, Peter Maydell wrote: >>> I kind of see, but isn't this just a window from CPU address >>> space into PCI address space, not vice-versa? >> >> Yup, exactly. But PCI devices need to map themselves somewhere into the >> PCI address space. So if I configure a BAR to live at 0x10000000, it >> should also show up at 0x10000000 when accessed from the CPU. That's >> what the mapping above is about. > > No, it doesn't have to. It's a choice to make the mapping > be such that the system address for a BAR matches the address > in PCI memory space, not a requirement. I agree it's a > sensible choice, though. > > But as I say, this code is setting up one mapping (the > system address -> PCI space mapping), not two. Yes, the other one is done implicitly by the OS based on what device tree tells it to do. If we map it at 0, our good old if (BAR == 0) break; friend hits us again though - and any other arbitrary offset is as good as a 1:1 map. > >>> DMA by PCI devices bus-mastering into system memory must be >>> being set up elsewhere, I think. >> >> Yes, that's a different mechanism that's not implemented yet for GPEX >> :). > > We can't not implement DMA, it would break lots of the usual > PCI devices people want to use. In fact I thought the PCI > core code implemented a default of "DMA by PCI devices goes > to the system address space" if you didn't specifically > set up something else by calling pci_setup_iommu(). This is > definitely how it works for plain PCI host bridges, are > PCIe bridges different? Nono, this is exactly the way it works. The thing that's not implemented is the SMMU to make that dynamic. >> On ARM this would happen via SMMU emulation. > > There's no requirement for a PCI host controller to be > sat behind an SMMU -- that's a system design choice. We > don't need to implement the SMMU yet (or perhaps ever?); The main benefit of implementing a guest SMMU is that you don't have to pin all guest memory at all times. Apart from that and the usual security aid it only makes things slower ;). > we definitely need to support PCI DMA. We do. Alex ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] [PATCH v2 4/4] pci: Move PCI VGA to pci.mak 2015-01-21 16:18 [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge Alexander Graf ` (2 preceding siblings ...) 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine Alexander Graf @ 2015-01-21 16:18 ` Alexander Graf 3 siblings, 0 replies; 24+ messages in thread From: Alexander Graf @ 2015-01-21 16:18 UTC (permalink / raw) To: qemu-devel Cc: Peter Maydell, ard.biesheuvel, rob.herring, mst, claudio.fontana, stuart.yoder, a.rigo Every platform that supports PCI can also spawn the Bochs VGA PCI adapter. Move it to pci.mak to enable it for everyone. Signed-off-by: Alexander Graf <agraf@suse.de> --- default-configs/alpha-softmmu.mak | 2 -- default-configs/i386-softmmu.mak | 2 -- default-configs/mips-softmmu.mak | 2 -- default-configs/mips64-softmmu.mak | 2 -- default-configs/mips64el-softmmu.mak | 2 -- default-configs/mipsel-softmmu.mak | 2 -- default-configs/pci.mak | 2 ++ default-configs/ppc-softmmu.mak | 2 -- default-configs/ppc64-softmmu.mak | 2 -- default-configs/ppcemb-softmmu.mak | 2 -- default-configs/sparc64-softmmu.mak | 2 -- default-configs/x86_64-softmmu.mak | 2 -- 12 files changed, 2 insertions(+), 22 deletions(-) diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak index bc07600..7f6161e 100644 --- a/default-configs/alpha-softmmu.mak +++ b/default-configs/alpha-softmmu.mak @@ -5,8 +5,6 @@ include usb.mak CONFIG_SERIAL=y CONFIG_I8254=y CONFIG_PCKBD=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_VGA_CIRRUS=y CONFIG_IDE_CORE=y CONFIG_IDE_QDEV=y diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 8e08841..bd99af9 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -3,9 +3,7 @@ include pci.mak include sound.mak include usb.mak -CONFIG_VGA=y CONFIG_QXL=$(CONFIG_SPICE) -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak index 2a80b04..cce2c81 100644 --- a/default-configs/mips-softmmu.mak +++ b/default-configs/mips-softmmu.mak @@ -4,8 +4,6 @@ include pci.mak include sound.mak include usb.mak CONFIG_ESP=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_ISA_MM=y CONFIG_VGA_CIRRUS=y diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak index f1f933b..7a88a08 100644 --- a/default-configs/mips64-softmmu.mak +++ b/default-configs/mips64-softmmu.mak @@ -4,8 +4,6 @@ include pci.mak include sound.mak include usb.mak CONFIG_ESP=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_ISA_MM=y CONFIG_VGA_CIRRUS=y diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak index 317b151..095de43 100644 --- a/default-configs/mips64el-softmmu.mak +++ b/default-configs/mips64el-softmmu.mak @@ -4,8 +4,6 @@ include pci.mak include sound.mak include usb.mak CONFIG_ESP=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_ISA_MM=y CONFIG_VGA_CIRRUS=y diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak index 7708185..0e25108 100644 --- a/default-configs/mipsel-softmmu.mak +++ b/default-configs/mipsel-softmmu.mak @@ -4,8 +4,6 @@ include pci.mak include sound.mak include usb.mak CONFIG_ESP=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_ISA_MM=y CONFIG_VGA_CIRRUS=y diff --git a/default-configs/pci.mak b/default-configs/pci.mak index a186c39..89986f1 100644 --- a/default-configs/pci.mak +++ b/default-configs/pci.mak @@ -32,3 +32,5 @@ CONFIG_PCI_TESTDEV=y CONFIG_NVME_PCI=y CONFIG_SD=y CONFIG_SDHCI=y +CONFIG_VGA=y +CONFIG_VGA_PCI=y diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak index d725b23..aebfab9 100644 --- a/default-configs/ppc-softmmu.mak +++ b/default-configs/ppc-softmmu.mak @@ -6,8 +6,6 @@ include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index bd30d69..f195a87 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -6,8 +6,6 @@ include usb.mak CONFIG_ISA_MMIO=y CONFIG_ESCC=y CONFIG_M48T59=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index e032761..a1b3d5f 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -4,8 +4,6 @@ include pci.mak include sound.mak include usb.mak CONFIG_M48T59=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_SERIAL=y CONFIG_I8257=y CONFIG_OPENPIC=y diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak index 299c97b..123bb99 100644 --- a/default-configs/sparc64-softmmu.mak +++ b/default-configs/sparc64-softmmu.mak @@ -5,8 +5,6 @@ include usb.mak CONFIG_ISA_MMIO=y CONFIG_M48T59=y CONFIG_PTIMER=y -CONFIG_VGA=y -CONFIG_VGA_PCI=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_PCKBD=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 66557ac..e7c2734 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -3,9 +3,7 @@ include pci.mak include sound.mak include usb.mak -CONFIG_VGA=y CONFIG_QXL=$(CONFIG_SPICE) -CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y -- 1.7.12.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
end of thread, other threads:[~2015-01-30 10:25 UTC | newest] Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-01-21 16:18 [Qemu-devel] [PATCH v2 0/4] ARM: Add support for a generic PCI Express host bridge Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 1/4] pci: Split pcie_host_mmcfg_map() Alexander Graf 2015-01-27 13:55 ` Peter Maydell 2015-01-27 14:24 ` Michael S. Tsirkin 2015-01-27 14:40 ` Paolo Bonzini 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 2/4] pci: Add generic PCIe host bridge Alexander Graf 2015-01-22 16:32 ` B02008 2015-01-27 15:31 ` Peter Maydell 2015-01-29 13:59 ` Alexander Graf 2015-01-29 14:25 ` Peter Maydell 2015-01-30 10:25 ` Paolo Bonzini 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 3/4] arm: Add PCIe host bridge in virt machine Alexander Graf 2015-01-22 15:28 ` Claudio Fontana 2015-01-22 15:52 ` Alexander Graf 2015-01-27 9:24 ` Claudio Fontana 2015-01-27 10:09 ` Peter Maydell 2015-01-27 14:37 ` Claudio Fontana 2015-01-27 16:52 ` Peter Maydell 2015-01-29 14:31 ` Alexander Graf 2015-01-29 14:34 ` Peter Maydell 2015-01-29 14:37 ` Alexander Graf 2015-01-29 14:45 ` Peter Maydell 2015-01-29 14:49 ` Alexander Graf 2015-01-21 16:18 ` [Qemu-devel] [PATCH v2 4/4] pci: Move PCI VGA to pci.mak Alexander Graf
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.