From patchwork Fri Jun 24 13:28:58 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cornelia Huck X-Patchwork-Id: 9197557 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9164160754 for ; Fri, 24 Jun 2016 13:59:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7FFD3284AB for ; Fri, 24 Jun 2016 13:59:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 74A91284B2; Fri, 24 Jun 2016 13:59:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2D452284AB for ; Fri, 24 Jun 2016 13:59:11 +0000 (UTC) Received: from localhost ([::1]:43721 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGRdW-00033U-CL for patchwork-qemu-devel@patchwork.kernel.org; Fri, 24 Jun 2016 09:59:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49899) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGRAn-0002xA-3D for qemu-devel@nongnu.org; Fri, 24 Jun 2016 09:29:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bGRAf-0000dG-1i for qemu-devel@nongnu.org; Fri, 24 Jun 2016 09:29:27 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:3361) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGRAe-0000d1-Ok for qemu-devel@nongnu.org; Fri, 24 Jun 2016 09:29:20 -0400 Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u5ODSwEo081555 for ; Fri, 24 Jun 2016 09:29:20 -0400 Received: from e06smtp08.uk.ibm.com (e06smtp08.uk.ibm.com [195.75.94.104]) by mx0a-001b2d01.pphosted.com with ESMTP id 23rq9m3hfx-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Fri, 24 Jun 2016 09:29:20 -0400 Received: from localhost by e06smtp08.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 24 Jun 2016 14:29:15 +0100 Received: from d06dlp03.portsmouth.uk.ibm.com (9.149.20.15) by e06smtp08.uk.ibm.com (192.168.101.138) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 24 Jun 2016 14:29:13 +0100 X-IBM-Helo: d06dlp03.portsmouth.uk.ibm.com X-IBM-MailFrom: cornelia.huck@de.ibm.com X-IBM-RcptTo: qemu-devel@nongnu.org Received: from b06cxnps4075.portsmouth.uk.ibm.com (d06relay12.portsmouth.uk.ibm.com [9.149.109.197]) by d06dlp03.portsmouth.uk.ibm.com (Postfix) with ESMTP id 353981B0805F for ; Fri, 24 Jun 2016 14:30:25 +0100 (BST) Received: from d06av10.portsmouth.uk.ibm.com (d06av10.portsmouth.uk.ibm.com [9.149.37.251]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u5ODTClL48169170 for ; Fri, 24 Jun 2016 13:29:12 GMT Received: from d06av10.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av10.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u5OCTERp018243 for ; Fri, 24 Jun 2016 06:29:14 -0600 Received: from gondolin.boeblingen.de.ibm.com (dyn-9-152-224-202.boeblingen.de.ibm.com [9.152.224.202]) by d06av10.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u5OCTBMp018033 (version=TLSv1/SSLv3 cipher=AES256-SHA256 bits=256 verify=NO); Fri, 24 Jun 2016 06:29:14 -0600 From: Cornelia Huck To: qemu-devel@nongnu.org Date: Fri, 24 Jun 2016 15:28:58 +0200 X-Mailer: git-send-email 2.9.0 In-Reply-To: <20160624132906.14446-1-cornelia.huck@de.ibm.com> References: <20160624132906.14446-1-cornelia.huck@de.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16062413-0032-0000-0000-000001DEB926 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16062413-0033-0000-0000-00001B82F2CC Message-Id: <20160624132906.14446-10-cornelia.huck@de.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-06-24_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=3 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000 definitions=main-1606240147 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 148.163.156.1 Subject: [Qemu-devel] [PATCH 09/17] s390x/pci: introduce S390PCIBusDevice qdev X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Cornelia Huck , zyimin@linux.vnet.ibm.com, mst@redhat.com, agraf@suse.de, borntraeger@de.ibm.com, jfrei@linux.vnet.ibm.com, marcel@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Yi Min Zhao To support definitions of s390 pci attributes in Qemu cmdline, we have to make current S390PCIBusDevice struct inherit DeviceState and add three properties for it. Currently we only support definitions of uid and fid. 'uid' is optionally defined by users, identifies a zpci device and must be defined with a 16-bit and non-zero unique value. 'fid' ranges from 0x0 to 0xFFFFFFFF. For fid property, we introduce a new PropertyInfo by the name of s390_pci_fid_propinfo with our special setter and getter. As 'fid' is optional, introduce 'fid_defined' to track whether the user specified a fid. 'target' field is to direct qemu to find the corresponding generic PCI device. It is equal to the 'id' value of one of generic pci devices. If the user doesn't specify 'id' parameter for a generic pci device, its 'id' value will be generated automatically and use this value as 'target' to create an associated zpci device. If the user did not specify 'uid' or 'fid', values are generated automatically. 'target' is required. In addition, if a pci device has no associated zpci device, the code will generate a zpci device automatically for it. Signed-off-by: Yi Min Zhao Reviewed-by: Pierre Morel Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-bus.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++-- hw/s390x/s390-pci-bus.h | 12 ++- 2 files changed, 261 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index af3263f..8e0f707 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -12,6 +12,8 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/visitor.h" #include "qemu-common.h" #include "cpu.h" #include "s390-pci-bus.h" @@ -96,8 +98,8 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) S390pciState *s = s390_get_phb(); for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - if ((pbdev->fh != 0) && (pbdev->fid == fid)) { + pbdev = s->pbdev[i]; + if (pbdev && pbdev->fid == fid) { return pbdev; } } @@ -185,6 +187,50 @@ static uint32_t s390_pci_get_pfh(PCIDevice *pdev) return PCI_SLOT(pdev->devfn) | FH_SHM_VFIO; } +static S390PCIBusDevice *s390_pci_find_dev_by_uid(uint16_t uid) +{ + int i; + S390PCIBusDevice *pbdev; + S390pciState *s = s390_get_phb(); + + for (i = 0; i < PCI_SLOT_MAX; i++) { + pbdev = s->pbdev[i]; + if (!pbdev) { + continue; + } + + if (pbdev->uid == uid) { + return pbdev; + } + } + + return NULL; +} + +static S390PCIBusDevice *s390_pci_find_dev_by_target(const char *target) +{ + int i; + S390PCIBusDevice *pbdev; + S390pciState *s = s390_get_phb(); + + if (!target) { + return NULL; + } + + for (i = 0; i < PCI_SLOT_MAX; i++) { + pbdev = s->pbdev[i]; + if (!pbdev) { + continue; + } + + if (!strcmp(pbdev->target, target)) { + return pbdev; + } + } + + return NULL; +} + S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) { S390PCIBusDevice *pbdev; @@ -193,7 +239,10 @@ S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) S390pciState *s = s390_get_phb(); for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; + pbdev = s->pbdev[i]; + if (!pbdev) { + continue; + } if (pbdev->state == ZPCI_FS_RESERVED) { continue; @@ -213,8 +262,8 @@ S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh) S390pciState *s = s390_get_phb(); S390PCIBusDevice *pbdev; - pbdev = &s->pbdev[fh & FH_MASK_INDEX]; - if (pbdev->fh != 0 && pbdev->fh == fh) { + pbdev = s->pbdev[fh & FH_MASK_INDEX]; + if (pbdev && pbdev->fh == fh) { return pbdev; } @@ -564,6 +613,22 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) return 0; } +static S390PCIBusDevice *s390_pci_device_new(const char *target) +{ + DeviceState *dev = NULL; + S390pciState *s = s390_get_phb(); + + dev = qdev_try_create(BUS(s->bus), TYPE_S390_PCI_DEVICE); + if (!dev) { + return NULL; + } + + qdev_prop_set_string(dev, "target", target); + qdev_init_nofail(dev); + + return S390_PCI_DEVICE(dev); +} + static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -572,8 +637,24 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) ->qbus.parent); - pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; + if (!dev->id) { + /* In the case the PCI device does not define an id */ + /* we generate one based on the PCI address */ + dev->id = g_strdup_printf("auto_%02x:%02x.%01x", + pci_bus_num(pci_dev->bus), + PCI_SLOT(pci_dev->devfn), + PCI_FUNC(pci_dev->devfn)); + } + + pbdev = s390_pci_find_dev_by_target(dev->id); + if (!pbdev) { + pbdev = s390_pci_device_new(dev->id); + if (!pbdev) { + error_setg(errp, "create zpci device failed"); + } + } + s->pbdev[PCI_SLOT(pci_dev->devfn)] = pbdev; pbdev->fid = s390_pci_get_pfid(pci_dev); pbdev->pdev = pci_dev; pbdev->state = ZPCI_FS_DISABLED; @@ -596,7 +677,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, PCIDevice *pci_dev = PCI_DEVICE(dev); S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) ->qbus.parent); - S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; + S390PCIBusDevice *pbdev = s->pbdev[PCI_SLOT(pci_dev->devfn)]; switch (pbdev->state) { case ZPCI_FS_RESERVED: @@ -648,10 +729,172 @@ static const TypeInfo s390_pcibus_info = { .instance_size = sizeof(S390PCIBus), }; +static uint16_t s390_pci_generate_uid(void) +{ + uint16_t uid = 0; + + do { + uid++; + if (!s390_pci_find_dev_by_uid(uid)) { + return uid; + } + } while (uid < ZPCI_MAX_UID); + + return UID_UNDEFINED; +} + +static uint32_t s390_pci_generate_fid(Error **errp) +{ + uint32_t fid = 0; + + while (fid <= ZPCI_MAX_FID) { + if (!s390_pci_find_dev_by_fid(fid)) { + return fid; + } + + if (fid == ZPCI_MAX_FID) { + break; + } + + fid++; + } + + error_setg(errp, "no free fid could be found"); + return 0; +} + +static void s390_pci_device_realize(DeviceState *dev, Error **errp) +{ + S390PCIBusDevice *zpci = S390_PCI_DEVICE(dev); + + if (!zpci->target) { + error_setg(errp, "target must be defined"); + return; + } + + if (s390_pci_find_dev_by_target(zpci->target)) { + error_setg(errp, "target %s already has an associated zpci device", + zpci->target); + return; + } + + if (zpci->uid == UID_UNDEFINED) { + zpci->uid = s390_pci_generate_uid(); + if (!zpci->uid) { + error_setg(errp, "no free uid could be found"); + return; + } + } else if (s390_pci_find_dev_by_uid(zpci->uid)) { + error_setg(errp, "uid %u already in use", zpci->uid); + return; + } + + if (!zpci->fid_defined) { + Error *local_error = NULL; + + zpci->fid = s390_pci_generate_fid(&local_error); + if (local_error) { + error_propagate(errp, local_error); + return; + } + } else if (s390_pci_find_dev_by_fid(zpci->fid)) { + error_setg(errp, "fid %u already in use", zpci->fid); + return; + } + + zpci->state = ZPCI_FS_RESERVED; +} + +static void s390_pci_device_reset(DeviceState *dev) +{ + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); + + switch (pbdev->state) { + case ZPCI_FS_RESERVED: + return; + case ZPCI_FS_STANDBY: + break; + default: + pbdev->fh &= ~FH_MASK_ENABLE; + pbdev->state = ZPCI_FS_DISABLED; + break; + } + + if (pbdev->summary_ind) { + pci_dereg_irqs(pbdev); + } + if (pbdev->iommu_enabled) { + pci_dereg_ioat(pbdev); + } + + pbdev->fmb_addr = 0; +} + +static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(DEVICE(obj), prop); + + visit_type_uint32(v, name, ptr, errp); +} + +static void s390_pci_set_fid(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + S390PCIBusDevice *zpci = S390_PCI_DEVICE(obj); + Property *prop = opaque; + uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_uint32(v, name, ptr, errp); + zpci->fid_defined = true; +} + +static PropertyInfo s390_pci_fid_propinfo = { + .name = "zpci_fid", + .get = s390_pci_get_fid, + .set = s390_pci_set_fid, +}; + +#define DEFINE_PROP_S390_PCI_FID(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, s390_pci_fid_propinfo, uint32_t) + +static Property s390_pci_device_properties[] = { + DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED), + DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid), + DEFINE_PROP_STRING("target", S390PCIBusDevice, target), + DEFINE_PROP_END_OF_LIST(), +}; + +static void s390_pci_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "zpci device"; + dc->reset = s390_pci_device_reset; + dc->bus_type = TYPE_S390_PCI_BUS; + dc->realize = s390_pci_device_realize; + dc->props = s390_pci_device_properties; +} + +static const TypeInfo s390_pci_device_info = { + .name = TYPE_S390_PCI_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(S390PCIBusDevice), + .class_init = s390_pci_device_class_init, +}; + static void s390_pci_register_types(void) { type_register_static(&s390_pcihost_info); type_register_static(&s390_pcibus_info); + type_register_static(&s390_pci_device_info); } type_init(s390_pci_register_types) diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index ea1efcc..658bda5 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -22,6 +22,7 @@ #define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost" #define TYPE_S390_PCI_BUS "s390-pcibus" +#define TYPE_S390_PCI_DEVICE "zpci" #define FH_MASK_ENABLE 0x80000000 #define FH_MASK_INSTANCE 0x7f000000 #define FH_MASK_SHM 0x00ff0000 @@ -29,11 +30,16 @@ #define FH_SHM_VFIO 0x00010000 #define FH_SHM_EMUL 0x00020000 #define S390_PCIPT_ADAPTER 2 +#define ZPCI_MAX_FID 0xffffffff +#define ZPCI_MAX_UID 0xffff +#define UID_UNDEFINED 0 #define S390_PCI_HOST_BRIDGE(obj) \ OBJECT_CHECK(S390pciState, (obj), TYPE_S390_PCI_HOST_BRIDGE) #define S390_PCI_BUS(obj) \ OBJECT_CHECK(S390PCIBus, (obj), TYPE_S390_PCI_BUS) +#define S390_PCI_DEVICE(obj) \ + OBJECT_CHECK(S390PCIBusDevice, (obj), TYPE_S390_PCI_DEVICE) #define HP_EVENT_TO_CONFIGURED 0x0301 #define HP_EVENT_RESERVED_TO_STANDBY 0x0302 @@ -254,11 +260,15 @@ typedef struct S390PCIIOMMU { } S390PCIIOMMU; typedef struct S390PCIBusDevice { + DeviceState qdev; PCIDevice *pdev; ZpciState state; bool iommu_enabled; + char *target; + uint16_t uid; uint32_t fh; uint32_t fid; + bool fid_defined; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -281,7 +291,7 @@ typedef struct S390PCIBus { typedef struct S390pciState { PCIHostState parent_obj; S390PCIBus *bus; - S390PCIBusDevice pbdev[PCI_SLOT_MAX]; + S390PCIBusDevice *pbdev[PCI_SLOT_MAX]; S390PCIIOMMU *iommu[PCI_SLOT_MAX]; AddressSpace msix_notify_as; MemoryRegion msix_notify_mr;