s390x updates:
- clang compilation fixes - fixes in zpci hotplug code - handle unimplemented diag 308 subcodes correctly - add common fmb in zpci -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAlxBwuYSHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vjqsQAKm4JODzShFicwwTF9uzFrvK3fE91GX2 Xr2gIgNL5o8B0D2JXhF5CtK8FsZQVd7DHn3w/wDJYX80Z2fhM8x/RrRKraC/MYmb DHQMbeCX3jss/HMkbC401v1P8ocEqdvxbEIh4PSilnomXoXmgS5zGq6EjMgKoRJY +mLMoUKHEewHqxpeDt+Y5RWrNtVeMHbFrhC2N/qHMmHv0/dySsGYis8IvYJ9WK0O NCuVwNkUgjZ25la69niPYRIuhYiF/kSHVtQ3myAGHqFynN7EmZuJZfpQ+hjIs1T4 ow6Zcol9bswjVrla3t8vnUR7BjZRClFinLEka3w4Bpy7KCIDvYbrub4dRX8DQhbW xj36fgrS/B+Hfd6mpCwj+w3MX8bQWqNhMSbESmQnM5I4r+xyJkg4otR2pgNwHEWN 3Xgo7LVwNm2atJCagbPwWIHdpN8G8DJ7yAdKToDUow0uD0Q3Zw/Bucqc1XH2rgk/ T8+deSdxNxLvuwI/ZsfwX4KNpZMDbVVfc6VSl/JapxtV3RITqquctVO6WIzZ6Qgh bh1rYd6t5b42IlFkc1zxVHiYn81eCayWN6RdtXp7KGM3Srb8wPLatuaUzZ9+R0zo Yt/I2ODV1Cw0MmvUivmH2dmh7fgKYh43zADQXvjEWJKaaL2BplM8HKrQa7d4YA8n xMTfZqvGqVcP =0S0e -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20190118' into staging s390x updates: - clang compilation fixes - fixes in zpci hotplug code - handle unimplemented diag 308 subcodes correctly - add common fmb in zpci # gpg: Signature made Fri 18 Jan 2019 12:13:26 GMT # gpg: using RSA key DECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # gpg: aka "Cornelia Huck <cohuck@kernel.org>" # gpg: aka "Cornelia Huck <cohuck@redhat.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck/tags/s390x-20190118: s390x/pci: add common function measurement block s390x/pci: Ignore the unplug call if we already have a release_timer s390x/pci: Always delete and free the release_timer s390x/pci: Move some hotplug checks to the pre_plug handler s390x/pci: Use hotplug_dev instead of looking up the host bridge s390x/pci: Set the iommu region size mpcifc request s390x/pci: Send correct event on hotplug configure: Only build the s390-ccw bios if the compiler supports -march=z900 s390x: Return specification exception for unimplemented diag 308 subcodes pc-bios/s390-ccw: Use proper register names for Clang s390: avoid potential null dereference in s390_pcihost_unplug() Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
a8d2b06856
|
@ -5892,8 +5892,12 @@ if test "$cpu" = "ppc64" -a "$targetos" != "Darwin" ; then
|
||||||
roms="$roms spapr-rtas"
|
roms="$roms spapr-rtas"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
|
||||||
if test "$cpu" = "s390x" ; then
|
if test "$cpu" = "s390x" ; then
|
||||||
roms="$roms s390-ccw"
|
write_c_skeleton
|
||||||
|
if compile_prog "-march=z900" ""; then
|
||||||
|
roms="$roms s390-ccw"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Probe for the need for relocating the user-only binary.
|
# Probe for the need for relocating the user-only binary.
|
||||||
|
|
|
@ -660,7 +660,7 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
|
||||||
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
|
char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid);
|
||||||
memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
|
memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr),
|
||||||
TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
|
TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr),
|
||||||
name, iommu->pal + 1);
|
name, iommu->pal - iommu->pba + 1);
|
||||||
iommu->enabled = true;
|
iommu->enabled = true;
|
||||||
memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
|
memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr));
|
||||||
g_free(name);
|
g_free(name);
|
||||||
|
@ -818,27 +818,42 @@ static bool s390_pci_alloc_idx(S390pciState *s, S390PCIBusDevice *pbdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
pbdev->idx = idx;
|
pbdev->idx = idx;
|
||||||
s->next_idx = (idx + 1) & FH_MASK_INDEX;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
static void s390_pcihost_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
PCIDevice *pdev = NULL;
|
S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
|
||||||
S390PCIBusDevice *pbdev = NULL;
|
|
||||||
S390pciState *s = s390_get_phb();
|
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||||
BusState *bus;
|
|
||||||
PCIBridge *pb = PCI_BRIDGE(dev);
|
|
||||||
PCIDevice *pdev = PCI_DEVICE(dev);
|
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||||
|
|
||||||
if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
|
if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
|
||||||
error_setg(errp, "multifunction not supported in s390");
|
error_setg(errp, "multifunction not supported in s390");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
|
||||||
|
S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev);
|
||||||
|
|
||||||
|
if (!s390_pci_alloc_idx(s, pbdev)) {
|
||||||
|
error_setg(errp, "no slot for plugging zpci device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
|
||||||
|
PCIDevice *pdev = NULL;
|
||||||
|
S390PCIBusDevice *pbdev = NULL;
|
||||||
|
|
||||||
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
|
||||||
|
BusState *bus;
|
||||||
|
PCIBridge *pb = PCI_BRIDGE(dev);
|
||||||
|
PCIDevice *pdev = PCI_DEVICE(dev);
|
||||||
|
|
||||||
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
|
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
|
||||||
pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
|
pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
|
||||||
|
@ -859,11 +874,6 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
||||||
pdev = PCI_DEVICE(dev);
|
pdev = PCI_DEVICE(dev);
|
||||||
|
|
||||||
if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
|
|
||||||
error_setg(errp, "multifunction not supported in s390");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev->id) {
|
if (!dev->id) {
|
||||||
/* In the case the PCI device does not define an id */
|
/* In the case the PCI device does not define an id */
|
||||||
/* we generate one based on the PCI address */
|
/* we generate one based on the PCI address */
|
||||||
|
@ -899,19 +909,19 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->hotplugged) {
|
if (dev->hotplugged) {
|
||||||
s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY,
|
s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED ,
|
||||||
pbdev->fh, pbdev->fid);
|
pbdev->fh, pbdev->fid);
|
||||||
}
|
}
|
||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
|
||||||
pbdev = S390_PCI_DEVICE(dev);
|
pbdev = S390_PCI_DEVICE(dev);
|
||||||
|
|
||||||
if (!s390_pci_alloc_idx(s, pbdev)) {
|
/* the allocated idx is actually getting used */
|
||||||
error_setg(errp, "no slot for plugging zpci device");
|
s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX;
|
||||||
return;
|
|
||||||
}
|
|
||||||
pbdev->fh = pbdev->idx;
|
pbdev->fh = pbdev->idx;
|
||||||
QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link);
|
QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link);
|
||||||
g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
|
g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,11 +945,11 @@ static void s390_pcihost_timer_cb(void *opaque)
|
||||||
static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
|
||||||
PCIDevice *pci_dev = NULL;
|
PCIDevice *pci_dev = NULL;
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
int32_t devfn;
|
int32_t devfn;
|
||||||
S390PCIBusDevice *pbdev = NULL;
|
S390PCIBusDevice *pbdev = NULL;
|
||||||
S390pciState *s = s390_get_phb();
|
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
|
||||||
error_setg(errp, "PCI bridge hot unplug currently not supported");
|
error_setg(errp, "PCI bridge hot unplug currently not supported");
|
||||||
|
@ -956,6 +966,8 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_S390_PCI_DEVICE)) {
|
||||||
pbdev = S390_PCI_DEVICE(dev);
|
pbdev = S390_PCI_DEVICE(dev);
|
||||||
pci_dev = pbdev->pdev;
|
pci_dev = pbdev->pdev;
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pbdev->state) {
|
switch (pbdev->state) {
|
||||||
|
@ -964,6 +976,9 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
case ZPCI_FS_STANDBY:
|
case ZPCI_FS_STANDBY:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (pbdev->release_timer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST,
|
s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST,
|
||||||
pbdev->fh, pbdev->fid);
|
pbdev->fh, pbdev->fid);
|
||||||
pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||||
|
@ -974,7 +989,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pbdev->release_timer && timer_pending(pbdev->release_timer)) {
|
if (pbdev->release_timer) {
|
||||||
timer_del(pbdev->release_timer);
|
timer_del(pbdev->release_timer);
|
||||||
timer_free(pbdev->release_timer);
|
timer_free(pbdev->release_timer);
|
||||||
pbdev->release_timer = NULL;
|
pbdev->release_timer = NULL;
|
||||||
|
@ -985,6 +1000,7 @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
bus = pci_get_bus(pci_dev);
|
bus = pci_get_bus(pci_dev);
|
||||||
devfn = pci_dev->devfn;
|
devfn = pci_dev->devfn;
|
||||||
object_unparent(OBJECT(pci_dev));
|
object_unparent(OBJECT(pci_dev));
|
||||||
|
fmb_timer_free(pbdev);
|
||||||
s390_pci_msix_free(pbdev);
|
s390_pci_msix_free(pbdev);
|
||||||
s390_pci_iommu_free(s, bus, devfn);
|
s390_pci_iommu_free(s, bus, devfn);
|
||||||
pbdev->pdev = NULL;
|
pbdev->pdev = NULL;
|
||||||
|
@ -1041,6 +1057,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
|
||||||
|
|
||||||
dc->reset = s390_pcihost_reset;
|
dc->reset = s390_pcihost_reset;
|
||||||
dc->realize = s390_pcihost_realize;
|
dc->realize = s390_pcihost_realize;
|
||||||
|
hc->pre_plug = s390_pcihost_pre_plug;
|
||||||
hc->plug = s390_pcihost_plug;
|
hc->plug = s390_pcihost_plug;
|
||||||
hc->unplug = s390_pcihost_unplug;
|
hc->unplug = s390_pcihost_unplug;
|
||||||
msi_nonbroken = true;
|
msi_nonbroken = true;
|
||||||
|
@ -1132,6 +1149,7 @@ static void s390_pci_device_realize(DeviceState *dev, Error **errp)
|
||||||
}
|
}
|
||||||
|
|
||||||
zpci->state = ZPCI_FS_RESERVED;
|
zpci->state = ZPCI_FS_RESERVED;
|
||||||
|
zpci->fmb.format = ZPCI_FMB_FORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390_pci_device_reset(DeviceState *dev)
|
static void s390_pci_device_reset(DeviceState *dev)
|
||||||
|
@ -1156,7 +1174,7 @@ static void s390_pci_device_reset(DeviceState *dev)
|
||||||
pci_dereg_ioat(pbdev->iommu);
|
pci_dereg_ioat(pbdev->iommu);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbdev->fmb_addr = 0;
|
fmb_timer_free(pbdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name,
|
static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name,
|
||||||
|
|
|
@ -285,6 +285,33 @@ typedef struct S390PCIIOMMUTable {
|
||||||
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
|
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
|
||||||
} S390PCIIOMMUTable;
|
} S390PCIIOMMUTable;
|
||||||
|
|
||||||
|
/* Function Measurement Block */
|
||||||
|
#define DEFAULT_MUI 4000
|
||||||
|
#define UPDATE_U_BIT 0x1ULL
|
||||||
|
#define FMBK_MASK 0xfULL
|
||||||
|
|
||||||
|
typedef struct ZpciFmbFmt0 {
|
||||||
|
uint64_t dma_rbytes;
|
||||||
|
uint64_t dma_wbytes;
|
||||||
|
} ZpciFmbFmt0;
|
||||||
|
|
||||||
|
#define ZPCI_FMB_CNT_LD 0
|
||||||
|
#define ZPCI_FMB_CNT_ST 1
|
||||||
|
#define ZPCI_FMB_CNT_STB 2
|
||||||
|
#define ZPCI_FMB_CNT_RPCIT 3
|
||||||
|
#define ZPCI_FMB_CNT_MAX 4
|
||||||
|
|
||||||
|
#define ZPCI_FMB_FORMAT 0
|
||||||
|
|
||||||
|
typedef struct ZpciFmb {
|
||||||
|
uint32_t format;
|
||||||
|
uint32_t sample;
|
||||||
|
uint64_t last_update;
|
||||||
|
uint64_t counter[ZPCI_FMB_CNT_MAX];
|
||||||
|
ZpciFmbFmt0 fmt0;
|
||||||
|
} ZpciFmb;
|
||||||
|
QEMU_BUILD_BUG_MSG(offsetof(ZpciFmb, fmt0) != 48, "padding in ZpciFmb");
|
||||||
|
|
||||||
struct S390PCIBusDevice {
|
struct S390PCIBusDevice {
|
||||||
DeviceState qdev;
|
DeviceState qdev;
|
||||||
PCIDevice *pdev;
|
PCIDevice *pdev;
|
||||||
|
@ -296,6 +323,8 @@ struct S390PCIBusDevice {
|
||||||
uint32_t fid;
|
uint32_t fid;
|
||||||
bool fid_defined;
|
bool fid_defined;
|
||||||
uint64_t fmb_addr;
|
uint64_t fmb_addr;
|
||||||
|
ZpciFmb fmb;
|
||||||
|
QEMUTimer *fmb_timer;
|
||||||
uint8_t isc;
|
uint8_t isc;
|
||||||
uint16_t noi;
|
uint16_t noi;
|
||||||
uint16_t maxstbl;
|
uint16_t maxstbl;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "exec/memory-internal.h"
|
#include "exec/memory-internal.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/hw_accel.h"
|
#include "sysemu/hw_accel.h"
|
||||||
|
#include "hw/s390x/tod.h"
|
||||||
|
|
||||||
#ifndef DEBUG_S390PCI_INST
|
#ifndef DEBUG_S390PCI_INST
|
||||||
#define DEBUG_S390PCI_INST 0
|
#define DEBUG_S390PCI_INST 0
|
||||||
|
@ -293,7 +294,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
|
||||||
resgrp->fr = 1;
|
resgrp->fr = 1;
|
||||||
stq_p(&resgrp->dasm, 0);
|
stq_p(&resgrp->dasm, 0);
|
||||||
stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
|
stq_p(&resgrp->msia, ZPCI_MSI_ADDR);
|
||||||
stw_p(&resgrp->mui, 0);
|
stw_p(&resgrp->mui, DEFAULT_MUI);
|
||||||
stw_p(&resgrp->i, 128);
|
stw_p(&resgrp->i, 128);
|
||||||
stw_p(&resgrp->maxstbl, 128);
|
stw_p(&resgrp->maxstbl, 128);
|
||||||
resgrp->version = 0;
|
resgrp->version = 0;
|
||||||
|
@ -456,6 +457,8 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbdev->fmb.counter[ZPCI_FMB_CNT_LD]++;
|
||||||
|
|
||||||
env->regs[r1] = data;
|
env->regs[r1] = data;
|
||||||
setcc(cpu, ZPCI_PCI_LS_OK);
|
setcc(cpu, ZPCI_PCI_LS_OK);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -561,6 +564,8 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbdev->fmb.counter[ZPCI_FMB_CNT_ST]++;
|
||||||
|
|
||||||
setcc(cpu, ZPCI_PCI_LS_OK);
|
setcc(cpu, ZPCI_PCI_LS_OK);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -681,6 +686,7 @@ err:
|
||||||
s390_set_status_code(env, r1, ZPCI_PCI_ST_FUNC_IN_ERR);
|
s390_set_status_code(env, r1, ZPCI_PCI_ST_FUNC_IN_ERR);
|
||||||
s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, start, 0);
|
s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, start, 0);
|
||||||
} else {
|
} else {
|
||||||
|
pbdev->fmb.counter[ZPCI_FMB_CNT_RPCIT]++;
|
||||||
setcc(cpu, ZPCI_PCI_LS_OK);
|
setcc(cpu, ZPCI_PCI_LS_OK);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -783,6 +789,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbdev->fmb.counter[ZPCI_FMB_CNT_STB]++;
|
||||||
|
|
||||||
setcc(cpu, ZPCI_PCI_LS_OK);
|
setcc(cpu, ZPCI_PCI_LS_OK);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -889,6 +897,99 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu)
|
||||||
iommu->g_iota = 0;
|
iommu->g_iota = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fmb_timer_free(S390PCIBusDevice *pbdev)
|
||||||
|
{
|
||||||
|
if (pbdev->fmb_timer) {
|
||||||
|
timer_del(pbdev->fmb_timer);
|
||||||
|
timer_free(pbdev->fmb_timer);
|
||||||
|
pbdev->fmb_timer = NULL;
|
||||||
|
}
|
||||||
|
pbdev->fmb_addr = 0;
|
||||||
|
memset(&pbdev->fmb, 0, sizeof(ZpciFmb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
MemTxResult ret;
|
||||||
|
uint64_t dst = pbdev->fmb_addr + offset;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 8:
|
||||||
|
address_space_stq_be(&address_space_memory, dst, val,
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
&ret);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
address_space_stl_be(&address_space_memory, dst, val,
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
&ret);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
address_space_stw_be(&address_space_memory, dst, val,
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
&ret);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
address_space_stb(&address_space_memory, dst, val,
|
||||||
|
MEMTXATTRS_UNSPECIFIED,
|
||||||
|
&ret);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = MEMTX_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret != MEMTX_OK) {
|
||||||
|
s390_pci_generate_error_event(ERR_EVENT_FMBA, pbdev->fh, pbdev->fid,
|
||||||
|
pbdev->fmb_addr, 0);
|
||||||
|
fmb_timer_free(pbdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fmb_update(void *opaque)
|
||||||
|
{
|
||||||
|
S390PCIBusDevice *pbdev = opaque;
|
||||||
|
int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Update U bit */
|
||||||
|
pbdev->fmb.last_update *= 2;
|
||||||
|
pbdev->fmb.last_update |= UPDATE_U_BIT;
|
||||||
|
if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update),
|
||||||
|
pbdev->fmb.last_update,
|
||||||
|
sizeof(pbdev->fmb.last_update))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update FMB sample count */
|
||||||
|
if (fmb_do_update(pbdev, offsetof(ZpciFmb, sample),
|
||||||
|
pbdev->fmb.sample++,
|
||||||
|
sizeof(pbdev->fmb.sample))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update FMB counters */
|
||||||
|
for (i = 0; i < ZPCI_FMB_CNT_MAX; i++) {
|
||||||
|
if (fmb_do_update(pbdev, offsetof(ZpciFmb, counter[i]),
|
||||||
|
pbdev->fmb.counter[i],
|
||||||
|
sizeof(pbdev->fmb.counter[0]))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear U bit and update the time */
|
||||||
|
pbdev->fmb.last_update = time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||||
|
pbdev->fmb.last_update *= 2;
|
||||||
|
if (fmb_do_update(pbdev, offsetof(ZpciFmb, last_update),
|
||||||
|
pbdev->fmb.last_update,
|
||||||
|
sizeof(pbdev->fmb.last_update))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timer_mod(pbdev->fmb_timer, t + DEFAULT_MUI);
|
||||||
|
}
|
||||||
|
|
||||||
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
||||||
uintptr_t ra)
|
uintptr_t ra)
|
||||||
{
|
{
|
||||||
|
@ -1018,9 +1119,35 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
||||||
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
|
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ZPCI_MOD_FC_SET_MEASURE:
|
case ZPCI_MOD_FC_SET_MEASURE: {
|
||||||
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
|
uint64_t fmb_addr = ldq_p(&fib.fmb_addr);
|
||||||
|
|
||||||
|
if (fmb_addr & FMBK_MASK) {
|
||||||
|
cc = ZPCI_PCI_LS_ERR;
|
||||||
|
s390_pci_generate_error_event(ERR_EVENT_FMBPRO, pbdev->fh,
|
||||||
|
pbdev->fid, fmb_addr, 0);
|
||||||
|
fmb_timer_free(pbdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fmb_addr) {
|
||||||
|
/* Stop updating FMB. */
|
||||||
|
fmb_timer_free(pbdev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pbdev->fmb_timer) {
|
||||||
|
pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
||||||
|
fmb_update, pbdev);
|
||||||
|
} else if (timer_pending(pbdev->fmb_timer)) {
|
||||||
|
/* Remove pending timer to update FMB address. */
|
||||||
|
timer_del(pbdev->fmb_timer);
|
||||||
|
}
|
||||||
|
pbdev->fmb_addr = fmb_addr;
|
||||||
|
timer_mod(pbdev->fmb_timer,
|
||||||
|
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra);
|
s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra);
|
||||||
cc = ZPCI_PCI_LS_ERR;
|
cc = ZPCI_PCI_LS_ERR;
|
||||||
|
|
|
@ -303,6 +303,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
||||||
uintptr_t ra);
|
uintptr_t ra);
|
||||||
int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
|
||||||
uintptr_t ra);
|
uintptr_t ra);
|
||||||
|
void fmb_timer_free(S390PCIBusDevice *pbdev);
|
||||||
|
|
||||||
#define ZPCI_IO_BAR_MIN 0
|
#define ZPCI_IO_BAR_MIN 0
|
||||||
#define ZPCI_IO_BAR_MAX 5
|
#define ZPCI_IO_BAR_MAX 5
|
||||||
|
|
|
@ -59,9 +59,9 @@ disabled_wait:
|
||||||
.globl consume_sclp_int
|
.globl consume_sclp_int
|
||||||
consume_sclp_int:
|
consume_sclp_int:
|
||||||
/* enable service interrupts in cr0 */
|
/* enable service interrupts in cr0 */
|
||||||
stctg 0,0,0(15)
|
stctg %c0,%c0,0(%r15)
|
||||||
oi 6(15), 0x2
|
oi 6(%r15),0x2
|
||||||
lctlg 0,0,0(15)
|
lctlg %c0,%c0,0(%r15)
|
||||||
/* prepare external call handler */
|
/* prepare external call handler */
|
||||||
larl %r1, external_new_code
|
larl %r1, external_new_code
|
||||||
stg %r1, 0x1b8
|
stg %r1, 0x1b8
|
||||||
|
@ -73,10 +73,10 @@ consume_sclp_int:
|
||||||
|
|
||||||
external_new_code:
|
external_new_code:
|
||||||
/* disable service interrupts in cr0 */
|
/* disable service interrupts in cr0 */
|
||||||
stctg 0,0,0(15)
|
stctg %c0,%c0,0(%r15)
|
||||||
ni 6(15), 0xfd
|
ni 6(%r15),0xfd
|
||||||
lctlg 0,0,0(15)
|
lctlg %c0,%c0,0(%r15)
|
||||||
br 14
|
br %r14
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
disabled_wait_psw:
|
disabled_wait_psw:
|
||||||
|
|
|
@ -130,7 +130,7 @@ out:
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
|
s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue