From patchwork Mon Jul 11 08:09:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cornelia Huck X-Patchwork-Id: 9222993 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 C0F9660572 for ; Mon, 11 Jul 2016 08:20:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AE78A27569 for ; Mon, 11 Jul 2016 08:20:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A1EC727AC2; Mon, 11 Jul 2016 08:20:02 +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 6327427569 for ; Mon, 11 Jul 2016 08:20:01 +0000 (UTC) Received: from localhost ([::1]:58708 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMWRc-0004qJ-9A for patchwork-qemu-devel@patchwork.kernel.org; Mon, 11 Jul 2016 04:20:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36281) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMWHS-0001XF-Nm for qemu-devel@nongnu.org; Mon, 11 Jul 2016 04:09:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bMWHO-00006e-4G for qemu-devel@nongnu.org; Mon, 11 Jul 2016 04:09:29 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:18682 helo=mx0a-001b2d01.pphosted.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bMWHN-00006X-V7 for qemu-devel@nongnu.org; Mon, 11 Jul 2016 04:09:26 -0400 Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id u6B88foO065197 for ; Mon, 11 Jul 2016 04:09:25 -0400 Received: from e06smtp07.uk.ibm.com (e06smtp07.uk.ibm.com [195.75.94.103]) by mx0b-001b2d01.pphosted.com with ESMTP id 243edc7sy1-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 11 Jul 2016 04:09:25 -0400 Received: from localhost by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 11 Jul 2016 09:09:23 +0100 Received: from d06dlp03.portsmouth.uk.ibm.com (9.149.20.15) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 11 Jul 2016 09:09:22 +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 b06cxnps3074.portsmouth.uk.ibm.com (d06relay09.portsmouth.uk.ibm.com [9.149.109.194]) by d06dlp03.portsmouth.uk.ibm.com (Postfix) with ESMTP id 2A4A91B08074 for ; Mon, 11 Jul 2016 09:10:42 +0100 (BST) Received: from d06av05.portsmouth.uk.ibm.com (d06av05.portsmouth.uk.ibm.com [9.149.37.229]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id u6B89LxE55443604 for ; Mon, 11 Jul 2016 08:09:21 GMT Received: from d06av05.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id u6B89Kbd020883 for ; Mon, 11 Jul 2016 02:09:20 -0600 Received: from gondolin.boeblingen.de.ibm.com (dyn-9-152-224-202.boeblingen.de.ibm.com [9.152.224.202]) by d06av05.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id u6B89Eac020066 (version=TLSv1/SSLv3 cipher=AES256-SHA256 bits=256 verify=NO); Mon, 11 Jul 2016 02:09:19 -0600 From: Cornelia Huck To: peter.maydell@linaro.org Date: Mon, 11 Jul 2016 10:09:04 +0200 X-Mailer: git-send-email 2.9.0 In-Reply-To: <20160711080912.13947-1-cornelia.huck@de.ibm.com> References: <20160711080912.13947-1-cornelia.huck@de.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16071108-0028-0000-0000-000001E852E4 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16071108-0029-0000-0000-00001F83D6BA Message-Id: <20160711080912.13947-18-cornelia.huck@de.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-07-11_04:, , 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-1607110089 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 148.163.158.5 Subject: [Qemu-devel] [PULL 17/25] 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: Yi Min Zhao , agraf@suse.de, qemu-devel@nongnu.org, borntraeger@de.ibm.com, jfrei@linux.vnet.ibm.com, Cornelia Huck 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;