qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Cornelia Huck <cornelia.huck@de.ibm.com>
To: peter.maydell@linaro.org
Cc: borntraeger@de.ibm.com, agraf@suse.de, jfrei@linux.vnet.ibm.com,
	qemu-devel@nongnu.org, Yi Min Zhao <zyimin@linux.vnet.ibm.com>,
	Cornelia Huck <cornelia.huck@de.ibm.com>
Subject: [Qemu-devel] [PULL 17/25] s390x/pci: introduce S390PCIBusDevice qdev
Date: Mon, 11 Jul 2016 10:09:04 +0200	[thread overview]
Message-ID: <20160711080912.13947-18-cornelia.huck@de.ibm.com> (raw)
In-Reply-To: <20160711080912.13947-1-cornelia.huck@de.ibm.com>

From: Yi Min Zhao <zyimin@linux.vnet.ibm.com>

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 <zyimin@linux.vnet.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
---
 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;
-- 
2.9.0

  parent reply	other threads:[~2016-07-11  8:09 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-11  8:08 [Qemu-devel] [PULL 00/25] s390x patches for 2.7 Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 01/25] pc-bios/s390-ccw: Pass selected SCSI device to IPL Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 02/25] pc-bios/s390-ccw.img: rebuild image Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 03/25] s390x/ipl: Support IPL from selected SCSI device Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 04/25] s390x/ipl: fix reboots for migration from different bios Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 05/25] s390x/css: factor out some generic code from virtio_ccw_device_realize() Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 06/25] s390x/css: use define for "virtual-css-bridge" literal Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 07/25] s390x/css: Factor out virtual css bridge and bus Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 08/25] s390x/css: Unplug handler of virtual css bridge Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 09/25] s390x/pci: fix failures of dma map/unmap Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 10/25] s390x/pci: acceleration for getting S390pciState Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 11/25] s390x/pci: write fid in CLP_QUERY_PCI_FN Cornelia Huck
2016-07-11  8:08 ` [Qemu-devel] [PULL 12/25] s390x/pci: unify FH_ macros Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 13/25] s390x/pci: refactor s390_pci_find_dev_by_fh Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 14/25] s390x/pci: enforce zPCI state checking Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 15/25] s390x/pci: introduce S390PCIBus Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 16/25] s390x/pci: introduce S390PCIIOMMU Cornelia Huck
2016-07-11  8:09 ` Cornelia Huck [this message]
2016-07-11  8:09 ` [Qemu-devel] [PULL 18/25] s390x/pci: enable uid-checking Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 19/25] s390x/pci: enable zpci hot-plug/hot-unplug Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 20/25] s390x/pci: add checkings in CLP_SET_PCI_FN Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 21/25] s390x/pci: refactor s390_pci_find_dev_by_idx Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 22/25] s390x/pci: refactor list_pci Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 23/25] s390x/pci: fix stpcifc_service_call Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 24/25] s390x/pci: replace fid with idx in msg data of msix Cornelia Huck
2016-07-11  8:09 ` [Qemu-devel] [PULL 25/25] s390x/pci: make hot-unplug handler smoother Cornelia Huck
2016-07-12  8:48 ` [Qemu-devel] [PULL 00/25] s390x patches for 2.7 Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160711080912.13947-18-cornelia.huck@de.ibm.com \
    --to=cornelia.huck@de.ibm.com \
    --cc=agraf@suse.de \
    --cc=borntraeger@de.ibm.com \
    --cc=jfrei@linux.vnet.ibm.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=zyimin@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).