[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 1/1] s390x/pci: add common fmb
From: |
Yi Min Zhao |
Subject: |
[Qemu-devel] [RFC PATCH 1/1] s390x/pci: add common fmb |
Date: |
Fri, 27 Apr 2018 18:02:44 +0800 |
Common function measurement block is used to report counters of
successfully issued pcilg/stg/stb and rpcit instructions. This patch
introduces a new struct ZpciFmb and schedules a timer callback to
copy fmb to the guest memory at a interval time which is set to
4000ms by default. While attemping to update fmb failed, an event
error would be generated. After pcilg/stg/stb and rpcit interception
handlers issue successfully, increase the related counter.
Signed-off-by: Yi Min Zhao <address@hidden>
---
hw/s390x/s390-pci-bus.c | 3 ++-
hw/s390x/s390-pci-bus.h | 16 +++++++++++++
hw/s390x/s390-pci-inst.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-
hw/s390x/s390-pci-inst.h | 1 +
4 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 10da87458e..62e121dcf6 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -967,6 +967,7 @@ static void s390_pcihost_hot_unplug(HotplugHandler
*hotplug_dev,
bus = pci_get_bus(pci_dev);
devfn = pci_dev->devfn;
object_unparent(OBJECT(pci_dev));
+ s390_pci_fmb_free(pbdev);
s390_pci_msix_free(pbdev);
s390_pci_iommu_free(s, bus, devfn);
pbdev->pdev = NULL;
@@ -1139,7 +1140,7 @@ static void s390_pci_device_reset(DeviceState *dev)
pci_dereg_ioat(pbdev->iommu);
}
- pbdev->fmb_addr = 0;
+ s390_pci_fmb_free(pbdev);
}
static void s390_pci_get_fid(Object *obj, Visitor *v, const char *name,
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 1f7f9b5814..c280dfaacc 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -286,6 +286,20 @@ typedef struct S390PCIIOMMUTable {
S390PCIIOMMU *iommu[PCI_SLOT_MAX];
} S390PCIIOMMUTable;
+/* Function Measurement Block */
+#define DEFAULT_MUI 4000
+#define UPDATE_TIME_MASK (~0x1ULL)
+typedef struct ZpciFmb {
+ uint32_t format : 8;
+ uint32_t fmt_ind : 24;
+ uint32_t sample;
+ uint64_t last_update;
+ uint64_t ld_ops;
+ uint64_t st_ops;
+ uint64_t stb_ops;
+ uint64_t rpcit_ops;
+} QEMU_PACKED ZpciFmb;
+
struct S390PCIBusDevice {
DeviceState qdev;
PCIDevice *pdev;
@@ -297,6 +311,8 @@ struct S390PCIBusDevice {
uint32_t fid;
bool fid_defined;
uint64_t fmb_addr;
+ ZpciFmb fmb;
+ QEMUTimer *fmb_timer;
uint8_t isc;
uint16_t noi;
uint16_t maxstbl;
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 3fcc330fe3..3b64ed0960 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -14,6 +14,7 @@
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "cpu.h"
+#include "internal.h"
#include "s390-pci-inst.h"
#include "s390-pci-bus.h"
#include "exec/memory-internal.h"
@@ -295,7 +296,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
resgrp->fr = 1;
stq_p(&resgrp->dasm, 0);
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->maxstbl, 128);
resgrp->version = 0;
@@ -460,6 +461,10 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t
r2, uintptr_t ra)
return 0;
}
+ if (pbdev->fmb_addr) {
+ pbdev->fmb.ld_ops++;
+ }
+
env->regs[r1] = data;
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
@@ -567,6 +572,10 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t
r2, uintptr_t ra)
return 0;
}
+ if (pbdev->fmb_addr) {
+ pbdev->fmb.st_ops++;
+ }
+
setcc(cpu, ZPCI_PCI_LS_OK);
return 0;
}
@@ -689,6 +698,9 @@ 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);
} else {
+ if (pbdev->fmb_addr) {
+ pbdev->fmb.rpcit_ops++;
+ }
setcc(cpu, ZPCI_PCI_LS_OK);
}
return 0;
@@ -740,6 +752,8 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t
r3, uint64_t gaddr,
break;
}
+ atomic_inc(&pbdev->fmb.stb_ops);
+
if (pcias > ZPCI_IO_BAR_MAX) {
DPRINTF("pcistb invalid space\n");
setcc(cpu, ZPCI_PCI_LS_ERR);
@@ -896,6 +910,42 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu)
iommu->g_iota = 0;
}
+void s390_pci_fmb_free(S390PCIBusDevice *pbdev)
+{
+ if (!pbdev) {
+ return;
+ }
+
+ 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 void fmb_update(void *opaque)
+{
+ S390PCIBusDevice *pbdev = opaque;
+ MemTxResult ret;
+
+ pbdev->fmb.sample++;
+ pbdev->fmb.last_update = time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL))
+ & UPDATE_TIME_MASK;
+ ret = address_space_write(&address_space_memory, pbdev->fmb_addr,
+ MEMTXATTRS_UNSPECIFIED, (uint8_t *)&pbdev->fmb,
+ sizeof(ZpciFmb));
+ if (ret) {
+ s390_pci_generate_error_event(ERR_EVENT_FMBA, pbdev->fh, pbdev->fid,
+ pbdev->fmb_addr, 0);
+ s390_pci_fmb_free(pbdev);
+ } else {
+ timer_mod(pbdev->fmb_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI);
+ }
+}
+
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra)
{
@@ -1027,6 +1077,14 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1,
uint64_t fiba, uint8_t ar,
break;
case ZPCI_MOD_FC_SET_MEASURE:
pbdev->fmb_addr = ldq_p(&fib.fmb_addr);
+ if (!pbdev->fmb_addr) {
+ s390_pci_fmb_free(pbdev);
+ } else {
+ pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ fmb_update, pbdev);
+ timer_mod(pbdev->fmb_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI);
+ }
break;
default:
s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra);
diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h
index 91c3d61f2a..579fc55255 100644
--- a/hw/s390x/s390-pci-inst.h
+++ b/hw/s390x/s390-pci-inst.h
@@ -303,6 +303,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t
fiba, uint8_t ar,
uintptr_t ra);
int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
uintptr_t ra);
+void s390_pci_fmb_free(S390PCIBusDevice *pbdev);
#define ZPCI_IO_BAR_MIN 0
#define ZPCI_IO_BAR_MAX 5
--
2.15.1 (Apple Git-101)