diff options
Diffstat (limited to 'drivers/iommu/virtio-iommu.c')
-rw-r--r-- | drivers/iommu/virtio-iommu.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c index 433f4d2ee956..80a740df0737 100644 --- a/drivers/iommu/virtio-iommu.c +++ b/drivers/iommu/virtio-iommu.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * Virtio driver for the paravirtualized IOMMU | 3 | * Virtio driver for the paravirtualized IOMMU |
4 | * | 4 | * |
5 | * Copyright (C) 2018 Arm Limited | 5 | * Copyright (C) 2019 Arm Limited |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -47,7 +47,10 @@ struct viommu_dev { | |||
47 | /* Device configuration */ | 47 | /* Device configuration */ |
48 | struct iommu_domain_geometry geometry; | 48 | struct iommu_domain_geometry geometry; |
49 | u64 pgsize_bitmap; | 49 | u64 pgsize_bitmap; |
50 | u8 domain_bits; | 50 | u32 first_domain; |
51 | u32 last_domain; | ||
52 | /* Supported MAP flags */ | ||
53 | u32 map_flags; | ||
51 | u32 probe_size; | 54 | u32 probe_size; |
52 | }; | 55 | }; |
53 | 56 | ||
@@ -62,6 +65,7 @@ struct viommu_domain { | |||
62 | struct viommu_dev *viommu; | 65 | struct viommu_dev *viommu; |
63 | struct mutex mutex; /* protects viommu pointer */ | 66 | struct mutex mutex; /* protects viommu pointer */ |
64 | unsigned int id; | 67 | unsigned int id; |
68 | u32 map_flags; | ||
65 | 69 | ||
66 | spinlock_t mappings_lock; | 70 | spinlock_t mappings_lock; |
67 | struct rb_root_cached mappings; | 71 | struct rb_root_cached mappings; |
@@ -113,6 +117,8 @@ static int viommu_get_req_errno(void *buf, size_t len) | |||
113 | return -ENOENT; | 117 | return -ENOENT; |
114 | case VIRTIO_IOMMU_S_FAULT: | 118 | case VIRTIO_IOMMU_S_FAULT: |
115 | return -EFAULT; | 119 | return -EFAULT; |
120 | case VIRTIO_IOMMU_S_NOMEM: | ||
121 | return -ENOMEM; | ||
116 | case VIRTIO_IOMMU_S_IOERR: | 122 | case VIRTIO_IOMMU_S_IOERR: |
117 | case VIRTIO_IOMMU_S_DEVERR: | 123 | case VIRTIO_IOMMU_S_DEVERR: |
118 | default: | 124 | default: |
@@ -607,15 +613,15 @@ static int viommu_domain_finalise(struct viommu_dev *viommu, | |||
607 | { | 613 | { |
608 | int ret; | 614 | int ret; |
609 | struct viommu_domain *vdomain = to_viommu_domain(domain); | 615 | struct viommu_domain *vdomain = to_viommu_domain(domain); |
610 | unsigned int max_domain = viommu->domain_bits > 31 ? ~0 : | ||
611 | (1U << viommu->domain_bits) - 1; | ||
612 | 616 | ||
613 | vdomain->viommu = viommu; | 617 | vdomain->viommu = viommu; |
618 | vdomain->map_flags = viommu->map_flags; | ||
614 | 619 | ||
615 | domain->pgsize_bitmap = viommu->pgsize_bitmap; | 620 | domain->pgsize_bitmap = viommu->pgsize_bitmap; |
616 | domain->geometry = viommu->geometry; | 621 | domain->geometry = viommu->geometry; |
617 | 622 | ||
618 | ret = ida_alloc_max(&viommu->domain_ids, max_domain, GFP_KERNEL); | 623 | ret = ida_alloc_range(&viommu->domain_ids, viommu->first_domain, |
624 | viommu->last_domain, GFP_KERNEL); | ||
619 | if (ret >= 0) | 625 | if (ret >= 0) |
620 | vdomain->id = (unsigned int)ret; | 626 | vdomain->id = (unsigned int)ret; |
621 | 627 | ||
@@ -710,7 +716,7 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova, | |||
710 | phys_addr_t paddr, size_t size, int prot) | 716 | phys_addr_t paddr, size_t size, int prot) |
711 | { | 717 | { |
712 | int ret; | 718 | int ret; |
713 | int flags; | 719 | u32 flags; |
714 | struct virtio_iommu_req_map map; | 720 | struct virtio_iommu_req_map map; |
715 | struct viommu_domain *vdomain = to_viommu_domain(domain); | 721 | struct viommu_domain *vdomain = to_viommu_domain(domain); |
716 | 722 | ||
@@ -718,6 +724,9 @@ static int viommu_map(struct iommu_domain *domain, unsigned long iova, | |||
718 | (prot & IOMMU_WRITE ? VIRTIO_IOMMU_MAP_F_WRITE : 0) | | 724 | (prot & IOMMU_WRITE ? VIRTIO_IOMMU_MAP_F_WRITE : 0) | |
719 | (prot & IOMMU_MMIO ? VIRTIO_IOMMU_MAP_F_MMIO : 0); | 725 | (prot & IOMMU_MMIO ? VIRTIO_IOMMU_MAP_F_MMIO : 0); |
720 | 726 | ||
727 | if (flags & ~vdomain->map_flags) | ||
728 | return -EINVAL; | ||
729 | |||
721 | ret = viommu_add_mapping(vdomain, iova, paddr, size, flags); | 730 | ret = viommu_add_mapping(vdomain, iova, paddr, size, flags); |
722 | if (ret) | 731 | if (ret) |
723 | return ret; | 732 | return ret; |
@@ -1027,7 +1036,8 @@ static int viommu_probe(struct virtio_device *vdev) | |||
1027 | goto err_free_vqs; | 1036 | goto err_free_vqs; |
1028 | } | 1037 | } |
1029 | 1038 | ||
1030 | viommu->domain_bits = 32; | 1039 | viommu->map_flags = VIRTIO_IOMMU_MAP_F_READ | VIRTIO_IOMMU_MAP_F_WRITE; |
1040 | viommu->last_domain = ~0U; | ||
1031 | 1041 | ||
1032 | /* Optional features */ | 1042 | /* Optional features */ |
1033 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE, | 1043 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_INPUT_RANGE, |
@@ -1038,9 +1048,13 @@ static int viommu_probe(struct virtio_device *vdev) | |||
1038 | struct virtio_iommu_config, input_range.end, | 1048 | struct virtio_iommu_config, input_range.end, |
1039 | &input_end); | 1049 | &input_end); |
1040 | 1050 | ||
1041 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_DOMAIN_BITS, | 1051 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_DOMAIN_RANGE, |
1042 | struct virtio_iommu_config, domain_bits, | 1052 | struct virtio_iommu_config, domain_range.start, |
1043 | &viommu->domain_bits); | 1053 | &viommu->first_domain); |
1054 | |||
1055 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_DOMAIN_RANGE, | ||
1056 | struct virtio_iommu_config, domain_range.end, | ||
1057 | &viommu->last_domain); | ||
1044 | 1058 | ||
1045 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_PROBE, | 1059 | virtio_cread_feature(vdev, VIRTIO_IOMMU_F_PROBE, |
1046 | struct virtio_iommu_config, probe_size, | 1060 | struct virtio_iommu_config, probe_size, |
@@ -1052,6 +1066,9 @@ static int viommu_probe(struct virtio_device *vdev) | |||
1052 | .force_aperture = true, | 1066 | .force_aperture = true, |
1053 | }; | 1067 | }; |
1054 | 1068 | ||
1069 | if (virtio_has_feature(vdev, VIRTIO_IOMMU_F_MMIO)) | ||
1070 | viommu->map_flags |= VIRTIO_IOMMU_MAP_F_MMIO; | ||
1071 | |||
1055 | viommu_ops.pgsize_bitmap = viommu->pgsize_bitmap; | 1072 | viommu_ops.pgsize_bitmap = viommu->pgsize_bitmap; |
1056 | 1073 | ||
1057 | virtio_device_ready(vdev); | 1074 | virtio_device_ready(vdev); |
@@ -1130,9 +1147,10 @@ static void viommu_config_changed(struct virtio_device *vdev) | |||
1130 | 1147 | ||
1131 | static unsigned int features[] = { | 1148 | static unsigned int features[] = { |
1132 | VIRTIO_IOMMU_F_MAP_UNMAP, | 1149 | VIRTIO_IOMMU_F_MAP_UNMAP, |
1133 | VIRTIO_IOMMU_F_DOMAIN_BITS, | ||
1134 | VIRTIO_IOMMU_F_INPUT_RANGE, | 1150 | VIRTIO_IOMMU_F_INPUT_RANGE, |
1151 | VIRTIO_IOMMU_F_DOMAIN_RANGE, | ||
1135 | VIRTIO_IOMMU_F_PROBE, | 1152 | VIRTIO_IOMMU_F_PROBE, |
1153 | VIRTIO_IOMMU_F_MMIO, | ||
1136 | }; | 1154 | }; |
1137 | 1155 | ||
1138 | static struct virtio_device_id id_table[] = { | 1156 | static struct virtio_device_id id_table[] = { |