From patchwork Tue Mar 10 13:03:34 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Blaschka X-Patchwork-Id: 448521 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id E40EA1401AF for ; Wed, 11 Mar 2015 00:05:59 +1100 (AEDT) Received: from localhost ([::1]:48738 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YVJrC-00042o-3O for incoming@patchwork.ozlabs.org; Tue, 10 Mar 2015 09:05:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50180) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YVJpB-0001iY-WF for qemu-devel@nongnu.org; Tue, 10 Mar 2015 09:03:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YVJp5-0007Ma-AR for qemu-devel@nongnu.org; Tue, 10 Mar 2015 09:03:53 -0400 Received: from e06smtp12.uk.ibm.com ([195.75.94.108]:37926) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YVJp5-0007M8-1Y for qemu-devel@nongnu.org; Tue, 10 Mar 2015 09:03:47 -0400 Received: from /spool/local by e06smtp12.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 10 Mar 2015 13:03:45 -0000 Received: from d06dlp02.portsmouth.uk.ibm.com (9.149.20.14) by e06smtp12.uk.ibm.com (192.168.101.142) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 10 Mar 2015 13:03:42 -0000 Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by d06dlp02.portsmouth.uk.ibm.com (Postfix) with ESMTP id 63AE5219005C for ; Tue, 10 Mar 2015 13:03:33 +0000 (GMT) Received: from d06av12.portsmouth.uk.ibm.com (d06av12.portsmouth.uk.ibm.com [9.149.37.247]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t2AD3gMp63766772 for ; Tue, 10 Mar 2015 13:03:42 GMT Received: from d06av12.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t2AD3e73023076 for ; Tue, 10 Mar 2015 07:03:41 -0600 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av12.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t2AD3aGf022746; Tue, 10 Mar 2015 07:03:38 -0600 From: Frank Blaschka To: qemu-devel@nongnu.org, cornelia.huck@de.ibm.com, borntraeger@de.ibm.com, agraf@suse.de, mst@redhat.com Date: Tue, 10 Mar 2015 14:03:34 +0100 Message-Id: <1425992614-8938-3-git-send-email-blaschka@linux.vnet.ibm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1425992614-8938-1-git-send-email-blaschka@linux.vnet.ibm.com> References: <1425992614-8938-1-git-send-email-blaschka@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15031013-0009-0000-0000-0000036C1E68 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.75.94.108 Cc: MIHAJLOV@de.ibm.com, Frank Blaschka , fiuczy@linux.vnet.ibm.com Subject: [Qemu-devel] [PATCH 2/2 RFC] s390x/pci: rework pci infrastructure modeling X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch changes the modeling of the s390 qemu pci infrastructure to better match the actual pci architecture defined by the real hardware. A pci host bridge like device (s390-pcihost) models the abstract view of the bare pci function. It provides s390 specific configuration attributes (fid and uid) for the attached pci device. The host bridge restrict the pci bus to just hold one single pci device. Also we have to make the s390 pci host bridge hot plugable. This is done by implementing a s390 specific bus to attach this new host bridge like devices. Sample qemu configuration: -device s390-pcihost,fid=16,uid=2216 -device e1000,bus=pci.0 -device s390-pcihost,fid=17,uid=2217,id=mydev -device ne2k_pci,bus=mydev.0,addr=0 A pci device references the corresponding host bridge via pci bus name (as usual). The pci device must be attached to slot 0 of the bus. The fid and uid must be unique for the qemu instance. The design allows to define (static and hotplug) multiple host bridges and support a large number of pci devices. Signed-off-by: Frank Blaschka --- hw/s390x/s390-pci-bus.c | 174 ++++++++++++++++++++++++++------------------- hw/s390x/s390-pci-bus.h | 24 ++++++- hw/s390x/s390-pci-inst.c | 2 +- hw/s390x/s390-virtio-ccw.c | 4 +- 4 files changed, 128 insertions(+), 76 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index dc455a2..6ad80d9 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -32,12 +32,8 @@ int chsc_sei_nt2_get_event(void *res) PciCcdfErr *eccdf; int rc = 1; SeiContainer *sei_cont; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return rc; - } + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); sei_cont = QTAILQ_FIRST(&s->pending_sei); if (sei_cont) { @@ -71,31 +67,23 @@ int chsc_sei_nt2_get_event(void *res) int chsc_sei_nt2_have_event(void) { - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return 0; - } + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); return !QTAILQ_EMPTY(&s->pending_sei); } S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) { - S390PCIBusDevice *pbdev; - int i; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); + BusChild *kid; + S390pciState *state; + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); - if (!s) { - return NULL; - } - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - if ((pbdev->fh != 0) && (pbdev->fid == fid)) { - return pbdev; + QTAILQ_FOREACH(kid, &s->sbus.qbus.children, sibling) { + state = (S390pciState *)kid->child; + if ((state->pbdev[0].fh != 0) && (state->pbdev[0].fid == fid)) { + return &state->pbdev[0]; } } @@ -125,37 +113,23 @@ void s390_pci_sclp_configure(int configure, SCCB *sccb) return; } -static uint32_t s390_pci_get_pfid(PCIDevice *pdev) -{ - return PCI_SLOT(pdev->devfn); -} - -static uint32_t s390_pci_get_pfh(PCIDevice *pdev) -{ - return PCI_SLOT(pdev->devfn) | FH_VIRT; -} - S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) { - S390PCIBusDevice *pbdev; - int i; + BusChild *kid; int j = 0; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return NULL; - } + S390pciState *state; + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; + QTAILQ_FOREACH(kid, &s->sbus.qbus.children, sibling) { + state = (S390pciState *)kid->child; - if (pbdev->fh == 0) { + if (state->pbdev[0].fh == 0) { continue; } if (j == idx) { - return pbdev; + return &state->pbdev[0]; } j++; } @@ -165,19 +139,19 @@ S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh) { - S390PCIBusDevice *pbdev; - int i; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); + BusChild *kid; + S390pciState *state; + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); - if (!s || !fh) { + if (!fh) { return NULL; } - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - if (pbdev->fh == fh) { - return pbdev; + QTAILQ_FOREACH(kid, &s->sbus.qbus.children, sibling) { + state = (S390pciState *)kid->child; + if (state->pbdev[0].fh == fh) { + return &state->pbdev[0]; } } @@ -188,12 +162,8 @@ static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e) { SeiContainer *sei_cont; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return; - } + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); sei_cont = g_malloc0(sizeof(SeiContainer)); sei_cont->fh = fh; @@ -461,15 +431,29 @@ static void s390_pcihost_init_as(S390pciState *s) address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci"); } -static int s390_pcihost_init(SysBusDevice *dev) +static void s390_pcihost_realize(DeviceState *dev, Error **errp) { PCIBus *b; BusState *bus; - PCIHostState *phb = PCI_HOST_BRIDGE(dev); S390pciState *s = S390_PCI_HOST_BRIDGE(dev); + S390pciState *state; + BusChild *kid; + PCIFacility *fac = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); DPRINTF("host_init\n"); + QTAILQ_FOREACH(kid, &fac->sbus.qbus.children, sibling) { + state = (S390pciState *)kid->child; + if (state == s) { + continue; + } + if (state->fid == s->fid || state->uid == s->uid) { + error_setg(errp, "s390-pcihost needs unique fid and uid"); + return; + } + } + b = pci_register_bus(DEVICE(dev), NULL, s390_pci_set_irq, s390_pci_map_irq, NULL, get_system_memory(), get_system_io(), 0, 64, @@ -479,9 +463,6 @@ static int s390_pcihost_init(SysBusDevice *dev) bus = BUS(b); qbus_set_hotplug_handler(bus, DEVICE(dev), NULL); - phb->bus = b; - QTAILQ_INIT(&s->pending_sei); - return 0; } static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) @@ -520,12 +501,18 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) ->qbus.parent); + if (PCI_SLOT(pci_dev->devfn) != 0) { + error_setg(errp, "s390-pcihost only slot 0 allowed."); + return; + } + pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - pbdev->fid = s390_pci_get_pfid(pci_dev); + pbdev->fid = s->fid; + pbdev->uid = s->uid; pbdev->pdev = pci_dev; pbdev->configured = true; - pbdev->fh = s390_pci_get_pfh(pci_dev); + pbdev->fh = s->fid | FH_VIRT; s390_pcihost_setup_msix(pbdev); @@ -560,14 +547,20 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, object_unparent(OBJECT(pci_dev)); } +static Property s390_pcihost_properties[] = { + DEFINE_PROP_UINT32("fid", S390pciState, fid, 0), + DEFINE_PROP_UINT32("uid", S390pciState, uid, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void s390_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - dc->cannot_instantiate_with_device_add_yet = true; - k->init = s390_pcihost_init; + dc->props = s390_pcihost_properties; + dc->bus_type = TYPE_PCI_FACILITY_BUS; + dc->realize = s390_pcihost_realize; hc->plug = s390_pcihost_hot_plug; hc->unplug = s390_pcihost_hot_unplug; msi_supported = true; @@ -575,7 +568,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data) static const TypeInfo s390_pcihost_info = { .name = TYPE_S390_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, + .parent = TYPE_DEVICE, .instance_size = sizeof(S390pciState), .class_init = s390_pcihost_class_init, .interfaces = (InterfaceInfo[]) { @@ -584,9 +577,46 @@ static const TypeInfo s390_pcihost_info = { } }; +static const TypeInfo pci_facility_bus_info = { + .name = TYPE_PCI_FACILITY_BUS, + .parent = TYPE_BUS, +}; + +static void pci_facility_realize(DeviceState *qdev, Error **errp) +{ + PCIFacility *facility = PCI_FACILITY(qdev); + + qbus_create_inplace(&facility->sbus, sizeof(facility->sbus), + TYPE_PCI_FACILITY_BUS, qdev, NULL); + + qbus_set_hotplug_handler(&facility->sbus.qbus, qdev, NULL); + QTAILQ_INIT(&facility->pending_sei); +} + +static void pci_facility_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pci_facility_realize; +} + +static const TypeInfo pci_facility_info = { + .name = TYPE_PCI_FACILITY, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PCIFacility), + .class_init = pci_facility_class_init, + .class_size = sizeof(PCIFacilityClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } +}; + static void s390_pci_register_types(void) { type_register_static(&s390_pcihost_info); + type_register_static(&pci_facility_info); + type_register_static(&pci_facility_bus_info); } type_init(s390_pci_register_types) diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 464a92e..78a5c83 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -220,6 +220,7 @@ typedef struct S390PCIBusDevice { bool lgstg_blocked; uint32_t fh; uint32_t fid; + uint32_t uid; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -238,7 +239,8 @@ typedef struct S390pciState { S390PCIBusDevice pbdev[PCI_SLOT_MAX]; AddressSpace msix_notify_as; MemoryRegion msix_notify_mr; - QTAILQ_HEAD(, SeiContainer) pending_sei; + uint32_t fid; + uint32_t uid; } S390pciState; int chsc_sei_nt2_get_event(void *res); @@ -248,4 +250,24 @@ S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid); +#define TYPE_PCI_FACILITY "pci-facility" +#define TYPE_PCI_FACILITY_BUS "pci-facility-bus" + +#define PCI_FACILITY(obj) \ + OBJECT_CHECK(PCIFacility, (obj), TYPE_PCI_FACILITY) + +typedef struct PCIFacilityBus { + BusState qbus; +} PCIFacilityBus; + +typedef struct PCIFacility { + SysBusDevice parent_obj; + PCIFacilityBus sbus; + QTAILQ_HEAD(, SeiContainer) pending_sei; +} PCIFacility; + +typedef struct PCIFacilityClass { + DeviceClass parent_class; + int (*init)(PCIFacility *pf); +} PCIFacilityClass; #endif diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 08d8aa6..d138b28 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -254,7 +254,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) stq_p(&resquery->edma, ZPCI_EDMA_ADDR); stw_p(&resquery->pchid, 0); stw_p(&resquery->ug, 1); - stl_p(&resquery->uid, pbdev->fid); + stl_p(&resquery->uid, pbdev->uid); stw_p(&resquery->hdr.rsp, CLP_RC_OK); break; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 8f0ae59..358b192 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -129,8 +129,8 @@ static void ccw_init(MachineState *machine) machine->initrd_filename, "s390-ccw.img", true); s390_flic_init(); - dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); - object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, + dev = qdev_create(NULL, TYPE_PCI_FACILITY); + object_property_add_child(qdev_get_machine(), TYPE_PCI_FACILITY, OBJECT(dev), NULL); qdev_init_nofail(dev);