aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x/s390-pci-inst.c
diff options
context:
space:
mode:
authorYi Min Zhao <zyimin@cn.ibm.com>2015-01-19 15:15:56 +0800
committerCornelia Huck <cornelia.huck@de.ibm.com>2015-02-03 13:42:40 +0100
commit4e99a0f7ae2a8392fd306c357148763ac4f820f9 (patch)
treea378247188eaafe81317dcda0e8897ecc7a8b483 /hw/s390x/s390-pci-inst.c
parent5b324bbafc4fe367bd9c5bfa6cff071081fb8b0e (diff)
s390x/pci: fix dma notifications in rpcit instruction
The virtual I/O address range passed to rpcit instruction might not map to consecutive physical guest pages. For this we have to translate and create mapping notifications for each vioa page separately. Signed-off-by: Yi Min Zhao <zyimin@cn.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'hw/s390x/s390-pci-inst.c')
-rw-r--r--hw/s390x/s390-pci-inst.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index c2691841fd..9e5bc5b899 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -487,7 +487,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
CPUS390XState *env = &cpu->env;
uint32_t fh;
S390PCIBusDevice *pbdev;
- ram_addr_t size;
+ hwaddr start, end;
IOMMUTLBEntry entry;
MemoryRegion *mr;
@@ -504,7 +504,8 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
}
fh = env->regs[r1] >> 32;
- size = env->regs[r2 + 1];
+ start = env->regs[r2];
+ end = start + env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(fh);
@@ -515,15 +516,18 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2)
}
mr = pci_device_iommu_address_space(pbdev->pdev)->root;
- entry = mr->iommu_ops->translate(mr, env->regs[r2], 0);
+ while (start < end) {
+ entry = mr->iommu_ops->translate(mr, start, 0);
- if (!entry.translated_addr) {
- setcc(cpu, ZPCI_PCI_LS_ERR);
- goto out;
+ if (!entry.translated_addr) {
+ setcc(cpu, ZPCI_PCI_LS_ERR);
+ goto out;
+ }
+
+ memory_region_notify_iommu(mr, entry);
+ start += entry.addr_mask + 1;
}
- entry.addr_mask = size - 1;
- memory_region_notify_iommu(mr, entry);
setcc(cpu, ZPCI_PCI_LS_OK);
out:
return 0;