Skip to content

Commit dfcee1e

Browse files
rosatomjhuth
authored andcommitted
s390x/pci: add support for guests that request direct mapping
When receiving a guest mpcifc(4) or mpcifc(6) instruction without the T bit set, treat this as a request to perform direct mapping instead of address translation. In order to facilitate this, pin the entirety of guest memory into the host iommu. Pinning for the direct mapping case is handled via vfio and its memory listener. Additionally, ram discard settings are inherited from vfio: coordinated discards (e.g. virtio-mem) are allowed while uncoordinated discards (e.g. virtio-balloon) are disabled. Subsequent guest DMA operations are all expected to be of the format guest_phys+sdma, allowing them to be used as lookup into the host iommu table. Signed-off-by: Matthew Rosato <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Message-ID: <[email protected]> Signed-off-by: Thomas Huth <[email protected]>
1 parent 9cbff6f commit dfcee1e

File tree

5 files changed

+75
-8
lines changed

5 files changed

+75
-8
lines changed

hw/s390x/s390-pci-bus.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "hw/s390x/s390-pci-inst.h"
1919
#include "hw/s390x/s390-pci-kvm.h"
2020
#include "hw/s390x/s390-pci-vfio.h"
21+
#include "hw/s390x/s390-virtio-ccw.h"
22+
#include "hw/boards.h"
2123
#include "hw/pci/pci_bus.h"
2224
#include "hw/qdev-properties.h"
2325
#include "hw/pci/pci_bridge.h"
@@ -724,12 +726,42 @@ void s390_pci_iommu_enable(S390PCIIOMMU *iommu)
724726
g_free(name);
725727
}
726728

729+
void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu)
730+
{
731+
MachineState *ms = MACHINE(qdev_get_machine());
732+
S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms);
733+
734+
/*
735+
* For direct-mapping we must map the entire guest address space. Rather
736+
* than using an iommu, create a memory region alias that maps GPA X to
737+
* IOVA X + SDMA. VFIO will handle pinning via its memory listener.
738+
*/
739+
g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x",
740+
iommu->pbdev->uid);
741+
742+
iommu->dm_mr = g_malloc0(sizeof(*iommu->dm_mr));
743+
memory_region_init_alias(iommu->dm_mr, OBJECT(&iommu->mr), name,
744+
get_system_memory(), 0,
745+
s390_get_memory_limit(s390ms));
746+
iommu->enabled = true;
747+
memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma,
748+
iommu->dm_mr);
749+
}
750+
727751
void s390_pci_iommu_disable(S390PCIIOMMU *iommu)
728752
{
729753
iommu->enabled = false;
730754
g_hash_table_remove_all(iommu->iotlb);
731-
memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&iommu->iommu_mr));
732-
object_unparent(OBJECT(&iommu->iommu_mr));
755+
if (iommu->dm_mr) {
756+
memory_region_del_subregion(&iommu->mr, iommu->dm_mr);
757+
object_unparent(OBJECT(iommu->dm_mr));
758+
g_free(iommu->dm_mr);
759+
iommu->dm_mr = NULL;
760+
} else {
761+
memory_region_del_subregion(&iommu->mr,
762+
MEMORY_REGION(&iommu->iommu_mr));
763+
object_unparent(OBJECT(&iommu->iommu_mr));
764+
}
733765
}
734766

735767
static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
@@ -1145,6 +1177,7 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
11451177
/* Always intercept emulated devices */
11461178
pbdev->interp = false;
11471179
pbdev->forwarding_assist = false;
1180+
pbdev->rtr_avail = false;
11481181
}
11491182

11501183
if (s390_pci_msix_init(pbdev) && !pbdev->interp) {
@@ -1510,6 +1543,8 @@ static const Property s390_pci_device_properties[] = {
15101543
DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true),
15111544
DEFINE_PROP_BOOL("forwarding-assist", S390PCIBusDevice, forwarding_assist,
15121545
true),
1546+
DEFINE_PROP_BOOL("relaxed-translation", S390PCIBusDevice, rtr_avail,
1547+
true),
15131548
};
15141549

15151550
static const VMStateDescription s390_pci_device_vmstate = {

hw/s390x/s390-pci-inst.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "exec/memory.h"
1717
#include "qemu/error-report.h"
1818
#include "system/hw_accel.h"
19+
#include "hw/boards.h"
1920
#include "hw/pci/pci_device.h"
2021
#include "hw/s390x/s390-pci-inst.h"
2122
#include "hw/s390x/s390-pci-bus.h"
@@ -1008,17 +1009,25 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib,
10081009
}
10091010

10101011
/* currently we only support designation type 1 with translation */
1011-
if (!(dt == ZPCI_IOTA_RTTO && t)) {
1012+
if (t && dt != ZPCI_IOTA_RTTO) {
10121013
error_report("unsupported ioat dt %d t %d", dt, t);
10131014
s390_program_interrupt(env, PGM_OPERAND, ra);
10141015
return -EINVAL;
1016+
} else if (!t && !pbdev->rtr_avail) {
1017+
error_report("relaxed translation not allowed");
1018+
s390_program_interrupt(env, PGM_OPERAND, ra);
1019+
return -EINVAL;
10151020
}
10161021

10171022
iommu->pba = pba;
10181023
iommu->pal = pal;
10191024
iommu->g_iota = g_iota;
10201025

1021-
s390_pci_iommu_enable(iommu);
1026+
if (t) {
1027+
s390_pci_iommu_enable(iommu);
1028+
} else {
1029+
s390_pci_iommu_direct_map_enable(iommu);
1030+
}
10221031

10231032
return 0;
10241033
}

hw/s390x/s390-pci-vfio.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,28 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev,
131131
/* Store function type separately for type-specific behavior */
132132
pbdev->pft = cap->pft;
133133

134+
/*
135+
* If the device is a passthrough ISM device, disallow relaxed
136+
* translation.
137+
*/
138+
if (pbdev->pft == ZPCI_PFT_ISM) {
139+
pbdev->rtr_avail = false;
140+
}
141+
134142
/*
135143
* If appropriate, reduce the size of the supported DMA aperture reported
136-
* to the guest based upon the vfio DMA limit.
144+
* to the guest based upon the vfio DMA limit. This is applicable for
145+
* devices that are guaranteed to not use relaxed translation. If the
146+
* device is capable of relaxed translation then we must advertise the
147+
* full aperture. In this case, if translation is used then we will
148+
* rely on the vfio DMA limit counting and use RPCIT CC1 / status 16
149+
* to request that the guest free DMA mappings as necessary.
137150
*/
138-
vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS;
139-
if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) {
140-
pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1;
151+
if (!pbdev->rtr_avail) {
152+
vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS;
153+
if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) {
154+
pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1;
155+
}
141156
}
142157
}
143158

hw/s390x/s390-virtio-ccw.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,8 +936,13 @@ static void ccw_machine_9_2_instance_options(MachineState *machine)
936936

937937
static void ccw_machine_9_2_class_options(MachineClass *mc)
938938
{
939+
static GlobalProperty compat[] = {
940+
{ TYPE_S390_PCI_DEVICE, "relaxed-translation", "off", },
941+
};
942+
939943
ccw_machine_10_0_class_options(mc);
940944
compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len);
945+
compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
941946
}
942947
DEFINE_CCW_MACHINE(9, 2);
943948

include/hw/s390x/s390-pci-bus.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ struct S390PCIIOMMU {
277277
AddressSpace as;
278278
MemoryRegion mr;
279279
IOMMUMemoryRegion iommu_mr;
280+
MemoryRegion *dm_mr;
280281
bool enabled;
281282
uint64_t g_iota;
282283
uint64_t pba;
@@ -362,6 +363,7 @@ struct S390PCIBusDevice {
362363
bool interp;
363364
bool forwarding_assist;
364365
bool aif;
366+
bool rtr_avail;
365367
QTAILQ_ENTRY(S390PCIBusDevice) link;
366368
};
367369

@@ -389,6 +391,7 @@ int pci_chsc_sei_nt2_have_event(void);
389391
void s390_pci_sclp_configure(SCCB *sccb);
390392
void s390_pci_sclp_deconfigure(SCCB *sccb);
391393
void s390_pci_iommu_enable(S390PCIIOMMU *iommu);
394+
void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu);
392395
void s390_pci_iommu_disable(S390PCIIOMMU *iommu);
393396
void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid,
394397
uint64_t faddr, uint32_t e);

0 commit comments

Comments
 (0)