From patchwork Thu Feb 26 11:59:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Blaschka X-Patchwork-Id: 443888 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 23D981400D5 for ; Thu, 26 Feb 2015 23:00:55 +1100 (AEDT) Received: from localhost ([::1]:58565 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YQx7b-0002QI-E5 for incoming@patchwork.ozlabs.org; Thu, 26 Feb 2015 07:00:51 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39968) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YQx6w-0001Ox-6z for qemu-devel@nongnu.org; Thu, 26 Feb 2015 07:00:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YQx6n-0000jP-2i for qemu-devel@nongnu.org; Thu, 26 Feb 2015 07:00:10 -0500 Received: from e06smtp11.uk.ibm.com ([195.75.94.107]:38299) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YQx6m-0000j5-MO for qemu-devel@nongnu.org; Thu, 26 Feb 2015 07:00:01 -0500 Received: from /spool/local by e06smtp11.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 26 Feb 2015 11:59:58 -0000 Received: from d06dlp03.portsmouth.uk.ibm.com (9.149.20.15) by e06smtp11.uk.ibm.com (192.168.101.141) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 26 Feb 2015 11:59:56 -0000 Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by d06dlp03.portsmouth.uk.ibm.com (Postfix) with ESMTP id D946F1B08069 for ; Thu, 26 Feb 2015 12:00:11 +0000 (GMT) Received: from d06av04.portsmouth.uk.ibm.com (d06av04.portsmouth.uk.ibm.com [9.149.37.216]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t1QBxu7e12124528 for ; Thu, 26 Feb 2015 11:59:56 GMT Received: from d06av04.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av04.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t1QBxsQA027916 for ; Thu, 26 Feb 2015 04:59:55 -0700 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av04.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t1QBxp2l027845; Thu, 26 Feb 2015 04:59:52 -0700 From: Frank Blaschka To: qemu-devel@nongnu.org, cornelia.huck@de.ibm.com, borntraeger@de.ibm.com, agraf@suse.de Date: Thu, 26 Feb 2015 12:59:48 +0100 Message-Id: <1424951988-40477-2-git-send-email-blaschka@linux.vnet.ibm.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1424951988-40477-1-git-send-email-blaschka@linux.vnet.ibm.com> References: <1424951988-40477-1-git-send-email-blaschka@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15022611-0041-0000-0000-000003829928 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.75.94.107 Cc: Frank Blaschka Subject: [Qemu-devel] [PATCH RFC 1/1] s390x/pci: Extend pci representation by new zpci device 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 extends the current s390 pci implementation to provide more flexibility in configuration of s390 specific device handling. For this we had to introduce a new facility (and bus) to hold devices representing information actually provided by s390 firmware and I/O configuration. On s390 the physical structure of the pci system (bridge, bus, slot) in not shown to the OS. For this the pci bridge and bus created in qemu can also not be shown to the guest. The new zpci device class represents this abstract view on the bare pci function and allows to provide s390 specific configuration attributes for it. Sample qemu configuration: -device e1000,id=zpci1 -device ne2k_pci,id=zpci2 -device zpci,fid=2,uid=1248,pci_id=zpci1 -device zpci,fid=17,uid=2244,pci_id=zpci2 A zpci device references the corresponding PCI device via device id. The new design allows to define multiple host bridges and support more pci devices. Signed-off-by: Frank Blaschka --- hw/s390x/s390-pci-bus.c | 253 ++++++++++++++++++++++++++++++++------------- hw/s390x/s390-pci-bus.h | 38 ++++++- hw/s390x/s390-pci-inst.c | 2 +- hw/s390x/s390-virtio-ccw.c | 8 +- 4 files changed, 227 insertions(+), 74 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index dc455a2..0bb448c 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; + ZPci *zpci; + 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) { + zpci = (ZPci *)kid->child; + if (zpci->pbdev->fid == fid) { + return zpci->pbdev; } } @@ -137,25 +125,16 @@ static uint32_t s390_pci_get_pfh(PCIDevice *pdev) S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) { - S390PCIBusDevice *pbdev; - int i; int j = 0; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return NULL; - } - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - - if (pbdev->fh == 0) { - continue; - } + BusChild *kid; + ZPci *zpci; + PCIFacility *s = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); + QTAILQ_FOREACH(kid, &s->sbus.qbus.children, sibling) { + zpci = (ZPci *)kid->child; if (j == idx) { - return pbdev; + return zpci->pbdev; } j++; } @@ -165,19 +144,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; + ZPci *zpci; + 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) { + zpci = (ZPci *)kid->child; + if (zpci->pbdev->fh == fh) { + return zpci->pbdev; } } @@ -188,12 +167,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; @@ -480,7 +455,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; } @@ -529,12 +503,6 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, s390_pcihost_setup_msix(pbdev); - if (dev->hotplugged) { - s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, - pbdev->fh, pbdev->fid); - s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED, - pbdev->fh, pbdev->fid); - } return; } @@ -546,14 +514,11 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, ->qbus.parent); S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - if (pbdev->configured) { - pbdev->configured = false; - s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES, - pbdev->fh, pbdev->fid); + if (pbdev->in_use) { + error_setg(errp, "device in use by zpci device"); + return; } - s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, - pbdev->fh, pbdev->fid); pbdev->fh = 0; pbdev->fid = 0; pbdev->pdev = NULL; @@ -563,10 +528,8 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, 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; hc->plug = s390_pcihost_hot_plug; hc->unplug = s390_pcihost_hot_unplug; @@ -584,9 +547,159 @@ static const TypeInfo s390_pcihost_info = { } }; +static const TypeInfo pci_facility_bus_info = { + .name = TYPE_PCI_FACILITY_BUS, + .parent = TYPE_BUS, +}; + +static int init_pci_facility(PCIFacility *facility) +{ + DeviceState *sdev = DEVICE(facility); + + qbus_create_inplace(&facility->sbus, sizeof(facility->sbus), + TYPE_PCI_FACILITY_BUS, sdev, NULL); + + qbus_set_hotplug_handler(&facility->sbus.qbus, sdev, NULL); + QTAILQ_INIT(&facility->pending_sei); + return 0; +} + +static void pci_facility_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ZPci *zpci = ZPCI(dev); + + if (dev->hotplugged) { + s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, + zpci->pbdev->fh, zpci->pbdev->fid); + s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED, + zpci->pbdev->fh, zpci->pbdev->fid); + } +} + +static void pci_facility_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + ZPci *zpci = ZPCI(dev); + + if (zpci->pbdev->configured) { + zpci->pbdev->configured = false; + s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES, + zpci->pbdev->fh, zpci->pbdev->fid); + } + + s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, + zpci->pbdev->fh, zpci->pbdev->fid); + + object_unparent(OBJECT(dev)); +} + +static void init_pci_facility_class(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(sbdc); + PCIFacilityClass *k = PCI_FACILITY_CLASS(dc); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + + k->init = init_pci_facility; + hc->plug = pci_facility_plug; + hc->unplug = pci_facility_unplug; +} + +static const TypeInfo pci_facility_info = { + .name = TYPE_PCI_FACILITY, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PCIFacility), + .class_init = init_pci_facility_class, + .class_size = sizeof(PCIFacilityClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + } +}; + +static void zpci_realize(DeviceState *qdev, Error **errp) +{ + ZPci *zpci = ZPCI(qdev); + ZPci *tmp; + PCIDevice *dev; + int ret; + S390pciState *s; + BusChild *kid; + PCIFacility *f = PCI_FACILITY( + object_resolve_path(TYPE_PCI_FACILITY, NULL)); + + if (!zpci->pci_id || !zpci->fid || !zpci->uid) { + error_setg(errp, "zpci needs valid fid, uid and pci_id"); + return; + } + + ret = pci_qdev_find_device(zpci->pci_id, &dev); + if (ret < 0) { + error_setg(errp, "zpci device not found"); + return; + } + + QTAILQ_FOREACH(kid, &f->sbus.qbus.children, sibling) { + tmp = (ZPci *)kid->child; + if (tmp == zpci) { + continue; + } + + if (tmp->fid == zpci->fid || tmp->uid == zpci->uid || + !strcmp(tmp->pci_id, zpci->pci_id)) { + error_setg(errp, "zpci needs unique fid, uid and pci_id"); + return; + } + } + + s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(dev) + ->qbus.parent); + + zpci->pbdev = &s->pbdev[PCI_SLOT(dev->devfn)]; + zpci->pbdev->fid = zpci->fid; + zpci->pbdev->uid = zpci->uid; + zpci->pbdev->fh = zpci->fid | FH_VIRT; + zpci->pbdev->in_use = true; +} + +static void zpci_unrealize(DeviceState *qdev, Error **errp) +{ + ZPci *zpci = ZPCI(qdev); + + zpci->pbdev->in_use = false; +} + +static Property zpci_properties[] = { + DEFINE_PROP_UINT32("fid", ZPci, fid, 0), + DEFINE_PROP_UINT32("uid", ZPci, uid, 0), + DEFINE_PROP_STRING("pci_id", ZPci, pci_id), + DEFINE_PROP_END_OF_LIST(), +}; + +static void zpci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->bus_type = TYPE_PCI_FACILITY_BUS; + dc->realize = zpci_realize; + dc->unrealize = zpci_unrealize; + dc->props = zpci_properties; +} + +static const TypeInfo zpci_type_info = { + .name = TYPE_ZPCI, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ZPci), + .class_init = zpci_class_init, +}; + 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_register_static(&zpci_type_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..f7f506c 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -215,11 +215,13 @@ typedef struct S390MsixInfo { typedef struct S390PCIBusDevice { PCIDevice *pdev; + bool in_use; bool configured; bool error_state; bool lgstg_blocked; uint32_t fh; uint32_t fid; + uint32_t uid; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -238,7 +240,6 @@ typedef struct S390pciState { S390PCIBusDevice pbdev[PCI_SLOT_MAX]; AddressSpace msix_notify_as; MemoryRegion msix_notify_mr; - QTAILQ_HEAD(, SeiContainer) pending_sei; } S390pciState; int chsc_sei_nt2_get_event(void *res); @@ -248,4 +249,39 @@ 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 TYPE_ZPCI "zpci" + +#define PCI_FACILITY(obj) \ + OBJECT_CHECK(PCIFacility, (obj), TYPE_PCI_FACILITY) + +#define PCI_FACILITY_CLASS(klass) \ + OBJECT_CLASS_CHECK(PCIFacilityClass, (klass), TYPE_PCI_FACILITY) + +#define ZPCI(obj) \ + OBJECT_CHECK(ZPci, (obj), TYPE_ZPCI) + +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; + +typedef struct ZPci { + DeviceState qdev; + uint32_t fid; + uint32_t uid; + char *pci_id; + S390PCIBusDevice *pbdev; +} ZPci; #endif diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 9e5bc5b..401a156 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -246,7 +246,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 71bafe0..12d4900 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -129,11 +129,14 @@ static void ccw_init(MachineState *machine) machine->initrd_filename, "s390-ccw.img"); 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); + dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); + qdev_init_nofail(dev); + /* register hypercalls */ virtio_ccw_register_hcalls(); @@ -190,6 +193,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_sdcard = 1; mc->use_sclp = 1; mc->max_cpus = 255; + mc->has_dynamic_sysbus = 1; nc->nmi_monitor_handler = s390_nmi; }