summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/s390x/css.c12
-rw-r--r--hw/s390x/s390-pci-bus.c48
-rw-r--r--hw/s390x/s390-pci-bus.h4
-rw-r--r--hw/s390x/s390-pci-inst.c6
-rw-r--r--pc-bios/s390-ccw.imgbin26440 -> 26392 bytes
-rw-r--r--pc-bios/s390-ccw/virtio.c3
-rw-r--r--target-s390x/kvm.c13
7 files changed, 52 insertions, 34 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index b0e81efc27..0f2580d644 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -775,7 +775,7 @@ int css_do_xsch(SubchDev *sch)
     PMCW *p = &sch->curr_status.pmcw;
     int ret;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         ret = -ENODEV;
         goto out;
     }
@@ -815,7 +815,7 @@ int css_do_csch(SubchDev *sch)
     PMCW *p = &sch->curr_status.pmcw;
     int ret;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         ret = -ENODEV;
         goto out;
     }
@@ -837,7 +837,7 @@ int css_do_hsch(SubchDev *sch)
     PMCW *p = &sch->curr_status.pmcw;
     int ret;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         ret = -ENODEV;
         goto out;
     }
@@ -913,7 +913,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb)
     PMCW *p = &sch->curr_status.pmcw;
     int ret;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         ret = -ENODEV;
         goto out;
     }
@@ -990,7 +990,7 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
     uint16_t stctl;
     IRB irb;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         return 3;
     }
 
@@ -1196,7 +1196,7 @@ int css_do_rsch(SubchDev *sch)
     PMCW *p = &sch->curr_status.pmcw;
     int ret;
 
-    if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
+    if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
         ret = -ENODEV;
         goto out;
     }
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index ac8f06d9e7..b7f8bca1fd 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -383,7 +383,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
     uint64_t pte;
     uint32_t flags;
     S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr);
-    S390pciState *s;
     IOMMUTLBEntry ret = {
         .target_as = &address_space_memory,
         .iova = 0,
@@ -405,19 +404,6 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
 
     DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
 
-    s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent);
-    /* s390 does not have an APIC mapped to main storage so we use
-     * a separate AddressSpace only for msix notifications
-     */
-    if (addr == ZPCI_MSI_ADDR) {
-        ret.target_as = &s->msix_notify_as;
-        ret.iova = addr;
-        ret.translated_addr = addr;
-        ret.addr_mask = 0xfff;
-        ret.perm = IOMMU_RW;
-        return ret;
-    }
-
     if (addr < pbdev->pba || addr > pbdev->pal) {
         return ret;
     }
@@ -476,7 +462,7 @@ static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
 static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
                                 unsigned int size)
 {
-    S390PCIBusDevice *pbdev;
+    S390PCIBusDevice *pbdev = opaque;
     uint32_t io_int_word;
     uint32_t idx = data >> ZPCI_MSI_VEC_BITS;
     uint32_t vec = data & ZPCI_MSI_VEC_MASK;
@@ -486,7 +472,6 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
 
     DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec);
 
-    pbdev = s390_pci_find_dev_by_idx(idx);
     if (!pbdev) {
         e |= (vec << ERR_EVENT_MVN_OFFSET);
         s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e);
@@ -548,10 +533,6 @@ static void s390_pcihost_init_as(S390pciState *s)
 
         s->iommu[i] = iommu;
     }
-
-    memory_region_init_io(&s->msix_notify_mr, OBJECT(s),
-                          &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX);
-    address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci");
 }
 
 static int s390_pcihost_init(SysBusDevice *dev)
@@ -581,7 +562,7 @@ static int s390_pcihost_init(SysBusDevice *dev)
     return 0;
 }
 
-static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
+static int s390_pci_setup_msix(S390PCIBusDevice *pbdev)
 {
     uint8_t pos;
     uint16_t ctrl;
@@ -609,6 +590,26 @@ static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev)
     return 0;
 }
 
+static void s390_pci_msix_init(S390PCIBusDevice *pbdev)
+{
+    char *name;
+
+    name = g_strdup_printf("msix-s390-%04x", pbdev->uid);
+
+    memory_region_init_io(&pbdev->msix_notify_mr, OBJECT(pbdev),
+                          &s390_msi_ctrl_ops, pbdev, name, PAGE_SIZE);
+    memory_region_add_subregion(&pbdev->iommu->mr, ZPCI_MSI_ADDR,
+                                &pbdev->msix_notify_mr);
+
+    g_free(name);
+}
+
+static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
+{
+    memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr);
+    object_unparent(OBJECT(&pbdev->msix_notify_mr));
+}
+
 static S390PCIBusDevice *s390_pci_device_new(const char *target)
 {
     DeviceState *dev = NULL;
@@ -662,7 +663,9 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
         pbdev->pdev = pdev;
         pbdev->iommu = s->iommu[PCI_SLOT(pdev->devfn)];
         pbdev->state = ZPCI_FS_STANDBY;
-        s390_pcihost_setup_msix(pbdev);
+
+        s390_pci_msix_init(pbdev);
+        s390_pci_setup_msix(pbdev);
 
         if (dev->hotplugged) {
             s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
@@ -749,6 +752,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
     s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
                                  pbdev->fh, pbdev->fid);
     object_unparent(OBJECT(pci_dev));
+    s390_pci_msix_free(pbdev);
     pbdev->pdev = NULL;
     pbdev->state = ZPCI_FS_RESERVED;
 out:
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 4f564e02f2..7f2701301e 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -82,6 +82,7 @@
 #define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL
 
 #define PAGE_SHIFT      12
+#define PAGE_SIZE       (1 << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
 #define PAGE_DEFAULT_ACC        0
 #define PAGE_DEFAULT_KEY        (PAGE_DEFAULT_ACC << 4)
@@ -283,6 +284,7 @@ typedef struct S390PCIBusDevice {
     AdapterRoutes routes;
     S390PCIIOMMU *iommu;
     MemoryRegion iommu_mr;
+    MemoryRegion msix_notify_mr;
     IndAddr *summary_ind;
     IndAddr *indicator;
     QEMUTimer *release_timer;
@@ -297,8 +299,6 @@ typedef struct S390pciState {
     S390PCIBus *bus;
     S390PCIBusDevice *pbdev[PCI_SLOT_MAX];
     S390PCIIOMMU *iommu[PCI_SLOT_MAX];
-    AddressSpace msix_notify_as;
-    MemoryRegion msix_notify_mr;
     QTAILQ_HEAD(, SeiContainer) pending_sei;
 } S390pciState;
 
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index f069b110b4..80a51049ca 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -315,6 +315,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
     S390PCIBusDevice *pbdev;
     uint64_t offset;
     uint64_t data;
+    MemoryRegion *mr;
     uint8_t len;
     uint32_t fh;
     uint8_t pcias;
@@ -363,7 +364,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
             program_interrupt(env, PGM_OPERAND, 4);
             return 0;
         }
-        MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory;
+        mr = pbdev->pdev->io_regions[pcias].memory;
         memory_region_dispatch_read(mr, offset, &data, len,
                                     MEMTXATTRS_UNSPECIFIED);
     } else if (pcias == 15) {
@@ -442,6 +443,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
     CPUS390XState *env = &cpu->env;
     uint64_t offset, data;
     S390PCIBusDevice *pbdev;
+    MemoryRegion *mr;
     uint8_t len;
     uint32_t fh;
     uint8_t pcias;
@@ -491,7 +493,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
             program_interrupt(env, PGM_OPERAND, 4);
             return 0;
         }
-        MemoryRegion *mr;
+
         if (trap_msix(pbdev, offset, pcias)) {
             offset = offset - pbdev->msix.table_offset;
             mr = &pbdev->pdev->msix_table_mmio;
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 089f6ba5e9..cf05bf0be2 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differdiff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 1d34e8c1aa..b333734955 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -97,7 +97,8 @@ static int run_ccw(VDev *vdev, int cmd, void *ptr, int len)
 
     /* start command processing */
     stsch_err(vdev->schid, &schib);
-    schib.scsw.ctrl = SCSW_FCTL_START_FUNC;
+    /* enable the subchannel for IPL device */
+    schib.pmcw.ena = 1;
     msch(vdev->schid, &schib);
 
     /* start subchannel command */
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index fd929e8351..7f745726bd 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -132,6 +132,8 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
 
+static QemuMutex qemu_sigp_mutex;
+
 static int cap_sync_regs;
 static int cap_async_pf;
 static int cap_mem_op;
@@ -287,6 +289,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
         }
     }
 
+    qemu_mutex_init(&qemu_sigp_mutex);
+
     return 0;
 }
 
@@ -1776,6 +1780,11 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
     status_reg = &env->regs[r1];
     param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
 
+    if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
+        ret = SIGP_CC_BUSY;
+        goto out;
+    }
+
     switch (order) {
     case SIGP_SET_ARCH:
         ret = sigp_set_architecture(cpu, param, status_reg);
@@ -1785,7 +1794,9 @@ static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
         dst_cpu = s390_cpu_addr2state(env->regs[r3]);
         ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
     }
+    qemu_mutex_unlock(&qemu_sigp_mutex);
 
+out:
     trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
                             dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
 
@@ -1990,7 +2001,7 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
         strcpy((char *)sysib.ext_names[0], "KVMguest");
     }
     /* Insert UUID */
-    memcpy(sysib.vm[0].uuid, qemu_uuid, sizeof(sysib.vm[0].uuid));
+    memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
 
     s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
 }