aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2013-07-15 07:36:01 -0400
committerCornelia Huck <cornelia.huck@de.ibm.com>2014-03-21 08:42:49 -0400
commit841b91c584b6d1e2a2cb508bd2d0236cd37e1750 (patch)
tree0a2f1b2cfa471cefa22bc9c12628361ed2c0ac4c /arch/s390/kvm
parentd938dc55225a7212e7f31c5a8571da304cc3de16 (diff)
KVM: s390: adapter interrupt sources
Add a new interface to register/deregister sources of adapter interrupts identified by an unique id via the flic. Adapters may also be maskable and carry a list of pinned pages. These adapters will be used by irq routing later. Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r--arch/s390/kvm/interrupt.c173
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--arch/s390/kvm/kvm-s390.h2
3 files changed, 175 insertions, 1 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 79d2e4fa9f9c..7ecef5a18e25 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * handling kvm guest interrupts 2 * handling kvm guest interrupts
3 * 3 *
4 * Copyright IBM Corp. 2008 4 * Copyright IBM Corp. 2008,2014
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License (version 2 only) 7 * it under the terms of the GNU General Public License (version 2 only)
@@ -1054,6 +1054,171 @@ static int enqueue_floating_irq(struct kvm_device *dev,
1054 return r; 1054 return r;
1055} 1055}
1056 1056
1057static struct s390_io_adapter *get_io_adapter(struct kvm *kvm, unsigned int id)
1058{
1059 if (id >= MAX_S390_IO_ADAPTERS)
1060 return NULL;
1061 return kvm->arch.adapters[id];
1062}
1063
1064static int register_io_adapter(struct kvm_device *dev,
1065 struct kvm_device_attr *attr)
1066{
1067 struct s390_io_adapter *adapter;
1068 struct kvm_s390_io_adapter adapter_info;
1069
1070 if (copy_from_user(&adapter_info,
1071 (void __user *)attr->addr, sizeof(adapter_info)))
1072 return -EFAULT;
1073
1074 if ((adapter_info.id >= MAX_S390_IO_ADAPTERS) ||
1075 (dev->kvm->arch.adapters[adapter_info.id] != NULL))
1076 return -EINVAL;
1077
1078 adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
1079 if (!adapter)
1080 return -ENOMEM;
1081
1082 INIT_LIST_HEAD(&adapter->maps);
1083 init_rwsem(&adapter->maps_lock);
1084 atomic_set(&adapter->nr_maps, 0);
1085 adapter->id = adapter_info.id;
1086 adapter->isc = adapter_info.isc;
1087 adapter->maskable = adapter_info.maskable;
1088 adapter->masked = false;
1089 adapter->swap = adapter_info.swap;
1090 dev->kvm->arch.adapters[adapter->id] = adapter;
1091
1092 return 0;
1093}
1094
1095int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked)
1096{
1097 int ret;
1098 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1099
1100 if (!adapter || !adapter->maskable)
1101 return -EINVAL;
1102 ret = adapter->masked;
1103 adapter->masked = masked;
1104 return ret;
1105}
1106
1107static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
1108{
1109 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1110 struct s390_map_info *map;
1111 int ret;
1112
1113 if (!adapter || !addr)
1114 return -EINVAL;
1115
1116 map = kzalloc(sizeof(*map), GFP_KERNEL);
1117 if (!map) {
1118 ret = -ENOMEM;
1119 goto out;
1120 }
1121 INIT_LIST_HEAD(&map->list);
1122 map->guest_addr = addr;
1123 map->addr = gmap_translate(addr, kvm->arch.gmap);
1124 if (map->addr == -EFAULT) {
1125 ret = -EFAULT;
1126 goto out;
1127 }
1128 ret = get_user_pages_fast(map->addr, 1, 1, &map->page);
1129 if (ret < 0)
1130 goto out;
1131 BUG_ON(ret != 1);
1132 down_write(&adapter->maps_lock);
1133 if (atomic_inc_return(&adapter->nr_maps) < MAX_S390_ADAPTER_MAPS) {
1134 list_add_tail(&map->list, &adapter->maps);
1135 ret = 0;
1136 } else {
1137 put_page(map->page);
1138 ret = -EINVAL;
1139 }
1140 up_write(&adapter->maps_lock);
1141out:
1142 if (ret)
1143 kfree(map);
1144 return ret;
1145}
1146
1147static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
1148{
1149 struct s390_io_adapter *adapter = get_io_adapter(kvm, id);
1150 struct s390_map_info *map, *tmp;
1151 int found = 0;
1152
1153 if (!adapter || !addr)
1154 return -EINVAL;
1155
1156 down_write(&adapter->maps_lock);
1157 list_for_each_entry_safe(map, tmp, &adapter->maps, list) {
1158 if (map->guest_addr == addr) {
1159 found = 1;
1160 atomic_dec(&adapter->nr_maps);
1161 list_del(&map->list);
1162 put_page(map->page);
1163 kfree(map);
1164 break;
1165 }
1166 }
1167 up_write(&adapter->maps_lock);
1168
1169 return found ? 0 : -EINVAL;
1170}
1171
1172void kvm_s390_destroy_adapters(struct kvm *kvm)
1173{
1174 int i;
1175 struct s390_map_info *map, *tmp;
1176
1177 for (i = 0; i < MAX_S390_IO_ADAPTERS; i++) {
1178 if (!kvm->arch.adapters[i])
1179 continue;
1180 list_for_each_entry_safe(map, tmp,
1181 &kvm->arch.adapters[i]->maps, list) {
1182 list_del(&map->list);
1183 put_page(map->page);
1184 kfree(map);
1185 }
1186 kfree(kvm->arch.adapters[i]);
1187 }
1188}
1189
1190static int modify_io_adapter(struct kvm_device *dev,
1191 struct kvm_device_attr *attr)
1192{
1193 struct kvm_s390_io_adapter_req req;
1194 struct s390_io_adapter *adapter;
1195 int ret;
1196
1197 if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req)))
1198 return -EFAULT;
1199
1200 adapter = get_io_adapter(dev->kvm, req.id);
1201 if (!adapter)
1202 return -EINVAL;
1203 switch (req.type) {
1204 case KVM_S390_IO_ADAPTER_MASK:
1205 ret = kvm_s390_mask_adapter(dev->kvm, req.id, req.mask);
1206 if (ret > 0)
1207 ret = 0;
1208 break;
1209 case KVM_S390_IO_ADAPTER_MAP:
1210 ret = kvm_s390_adapter_map(dev->kvm, req.id, req.addr);
1211 break;
1212 case KVM_S390_IO_ADAPTER_UNMAP:
1213 ret = kvm_s390_adapter_unmap(dev->kvm, req.id, req.addr);
1214 break;
1215 default:
1216 ret = -EINVAL;
1217 }
1218
1219 return ret;
1220}
1221
1057static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) 1222static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1058{ 1223{
1059 int r = 0; 1224 int r = 0;
@@ -1082,6 +1247,12 @@ static int flic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
1082 kvm_for_each_vcpu(i, vcpu, dev->kvm) 1247 kvm_for_each_vcpu(i, vcpu, dev->kvm)
1083 kvm_clear_async_pf_completion_queue(vcpu); 1248 kvm_clear_async_pf_completion_queue(vcpu);
1084 break; 1249 break;
1250 case KVM_DEV_FLIC_ADAPTER_REGISTER:
1251 r = register_io_adapter(dev, attr);
1252 break;
1253 case KVM_DEV_FLIC_ADAPTER_MODIFY:
1254 r = modify_io_adapter(dev, attr);
1255 break;
1085 default: 1256 default:
1086 r = -EINVAL; 1257 r = -EINVAL;
1087 } 1258 }
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 9f1e99f12d4f..2e6fbb0b4f68 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -343,6 +343,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
343 debug_unregister(kvm->arch.dbf); 343 debug_unregister(kvm->arch.dbf);
344 if (!kvm_is_ucontrol(kvm)) 344 if (!kvm_is_ucontrol(kvm))
345 gmap_free(kvm->arch.gmap); 345 gmap_free(kvm->arch.gmap);
346 kvm_s390_destroy_adapters(kvm);
346} 347}
347 348
348/* Section: vcpu related */ 349/* Section: vcpu related */
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index ed4750a5bc3c..5502cc951868 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -136,6 +136,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
136int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); 136int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
137struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, 137struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
138 u64 cr6, u64 schid); 138 u64 cr6, u64 schid);
139int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
139 140
140/* implemented in priv.c */ 141/* implemented in priv.c */
141int kvm_s390_handle_b2(struct kvm_vcpu *vcpu); 142int kvm_s390_handle_b2(struct kvm_vcpu *vcpu);
@@ -162,5 +163,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
162/* implemented in interrupt.c */ 163/* implemented in interrupt.c */
163int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); 164int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
164int psw_extint_disabled(struct kvm_vcpu *vcpu); 165int psw_extint_disabled(struct kvm_vcpu *vcpu);
166void kvm_s390_destroy_adapters(struct kvm *kvm);
165 167
166#endif 168#endif