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:43:00 -0400
commit84223598778ba08041f4297fda485df83414d57e (patch)
treebd93b83a13cc5cd1f6781bf681161fb3982548c5 /arch/s390/kvm
parent841b91c584b6d1e2a2cb508bd2d0236cd37e1750 (diff)
KVM: s390: irq routing for adapter interrupts.
Introduce a new interrupt class for s390 adapter interrupts and enable irqfds for s390. This is depending on a new s390 specific vm capability, KVM_CAP_S390_IRQCHIP, that needs to be enabled by userspace. 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/Kconfig2
-rw-r--r--arch/s390/kvm/Makefile2
-rw-r--r--arch/s390/kvm/interrupt.c121
-rw-r--r--arch/s390/kvm/irq.h22
-rw-r--r--arch/s390/kvm/kvm-s390.c17
5 files changed, 163 insertions, 1 deletions
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index c8bacbcd2e5b..10d529ac9821 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -25,6 +25,8 @@ config KVM
25 select HAVE_KVM_EVENTFD 25 select HAVE_KVM_EVENTFD
26 select KVM_ASYNC_PF 26 select KVM_ASYNC_PF
27 select KVM_ASYNC_PF_SYNC 27 select KVM_ASYNC_PF_SYNC
28 select HAVE_KVM_IRQCHIP
29 select HAVE_KVM_IRQ_ROUTING
28 ---help--- 30 ---help---
29 Support hosting paravirtualized guest machines using the SIE 31 Support hosting paravirtualized guest machines using the SIE
30 virtualization capability on the mainframe. This should work 32 virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index a47d2c355f68..d3adb37e93a4 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -7,7 +7,7 @@
7# as published by the Free Software Foundation. 7# as published by the Free Software Foundation.
8 8
9KVM := ../../../virt/kvm 9KVM := ../../../virt/kvm
10common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o 10common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqchip.o
11 11
12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm 12ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
13 13
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 7ecef5a18e25..2e2814eceb85 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -13,6 +13,7 @@
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/kvm_host.h> 14#include <linux/kvm_host.h>
15#include <linux/hrtimer.h> 15#include <linux/hrtimer.h>
16#include <linux/mmu_context.h>
16#include <linux/signal.h> 17#include <linux/signal.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
18#include <asm/asm-offsets.h> 19#include <asm/asm-offsets.h>
@@ -1284,3 +1285,123 @@ struct kvm_device_ops kvm_flic_ops = {
1284 .create = flic_create, 1285 .create = flic_create,
1285 .destroy = flic_destroy, 1286 .destroy = flic_destroy,
1286}; 1287};
1288
1289static unsigned long get_ind_bit(__u64 addr, unsigned long bit_nr, bool swap)
1290{
1291 unsigned long bit;
1292
1293 bit = bit_nr + (addr % PAGE_SIZE) * 8;
1294
1295 return swap ? (bit ^ (BITS_PER_LONG - 1)) : bit;
1296}
1297
1298static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
1299 u64 addr)
1300{
1301 struct s390_map_info *map;
1302
1303 if (!adapter)
1304 return NULL;
1305
1306 list_for_each_entry(map, &adapter->maps, list) {
1307 if (map->guest_addr == addr)
1308 return map;
1309 }
1310 return NULL;
1311}
1312
1313static int adapter_indicators_set(struct kvm *kvm,
1314 struct s390_io_adapter *adapter,
1315 struct kvm_s390_adapter_int *adapter_int)
1316{
1317 unsigned long bit;
1318 int summary_set, idx;
1319 struct s390_map_info *info;
1320 void *map;
1321
1322 info = get_map_info(adapter, adapter_int->ind_addr);
1323 if (!info)
1324 return -1;
1325 map = page_address(info->page);
1326 bit = get_ind_bit(info->addr, adapter_int->ind_offset, adapter->swap);
1327 set_bit(bit, map);
1328 idx = srcu_read_lock(&kvm->srcu);
1329 mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
1330 set_page_dirty_lock(info->page);
1331 info = get_map_info(adapter, adapter_int->summary_addr);
1332 if (!info) {
1333 srcu_read_unlock(&kvm->srcu, idx);
1334 return -1;
1335 }
1336 map = page_address(info->page);
1337 bit = get_ind_bit(info->addr, adapter_int->summary_offset,
1338 adapter->swap);
1339 summary_set = test_and_set_bit(bit, map);
1340 mark_page_dirty(kvm, info->guest_addr >> PAGE_SHIFT);
1341 set_page_dirty_lock(info->page);
1342 srcu_read_unlock(&kvm->srcu, idx);
1343 return summary_set ? 0 : 1;
1344}
1345
1346/*
1347 * < 0 - not injected due to error
1348 * = 0 - coalesced, summary indicator already active
1349 * > 0 - injected interrupt
1350 */
1351static int set_adapter_int(struct kvm_kernel_irq_routing_entry *e,
1352 struct kvm *kvm, int irq_source_id, int level,
1353 bool line_status)
1354{
1355 int ret;
1356 struct s390_io_adapter *adapter;
1357
1358 /* We're only interested in the 0->1 transition. */
1359 if (!level)
1360 return 0;
1361 adapter = get_io_adapter(kvm, e->adapter.adapter_id);
1362 if (!adapter)
1363 return -1;
1364 down_read(&adapter->maps_lock);
1365 ret = adapter_indicators_set(kvm, adapter, &e->adapter);
1366 up_read(&adapter->maps_lock);
1367 if ((ret > 0) && !adapter->masked) {
1368 struct kvm_s390_interrupt s390int = {
1369 .type = KVM_S390_INT_IO(1, 0, 0, 0),
1370 .parm = 0,
1371 .parm64 = (adapter->isc << 27) | 0x80000000,
1372 };
1373 ret = kvm_s390_inject_vm(kvm, &s390int);
1374 if (ret == 0)
1375 ret = 1;
1376 }
1377 return ret;
1378}
1379
1380int kvm_set_routing_entry(struct kvm_irq_routing_table *rt,
1381 struct kvm_kernel_irq_routing_entry *e,
1382 const struct kvm_irq_routing_entry *ue)
1383{
1384 int ret;
1385
1386 switch (ue->type) {
1387 case KVM_IRQ_ROUTING_S390_ADAPTER:
1388 e->set = set_adapter_int;
1389 e->adapter.summary_addr = ue->u.adapter.summary_addr;
1390 e->adapter.ind_addr = ue->u.adapter.ind_addr;
1391 e->adapter.summary_offset = ue->u.adapter.summary_offset;
1392 e->adapter.ind_offset = ue->u.adapter.ind_offset;
1393 e->adapter.adapter_id = ue->u.adapter.adapter_id;
1394 ret = 0;
1395 break;
1396 default:
1397 ret = -EINVAL;
1398 }
1399
1400 return ret;
1401}
1402
1403int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
1404 int irq_source_id, int level, bool line_status)
1405{
1406 return -EINVAL;
1407}
diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
new file mode 100644
index 000000000000..d98e4159643d
--- /dev/null
+++ b/arch/s390/kvm/irq.h
@@ -0,0 +1,22 @@
1/*
2 * s390 irqchip routines
3 *
4 * Copyright IBM Corp. 2014
5 *
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)
8 * as published by the Free Software Foundation.
9 *
10 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
11 */
12#ifndef __KVM_IRQ_H
13#define __KVM_IRQ_H
14
15#include <linux/kvm_host.h>
16
17static inline int irqchip_in_kernel(struct kvm *kvm)
18{
19 return 1;
20}
21
22#endif
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 2e6fbb0b4f68..ce5b659ec531 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -196,6 +196,10 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
196 return -EINVAL; 196 return -EINVAL;
197 197
198 switch (cap->cap) { 198 switch (cap->cap) {
199 case KVM_CAP_S390_IRQCHIP:
200 kvm->arch.use_irqchip = 1;
201 r = 0;
202 break;
199 default: 203 default:
200 r = -EINVAL; 204 r = -EINVAL;
201 break; 205 break;
@@ -228,6 +232,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
228 r = kvm_vm_ioctl_enable_cap(kvm, &cap); 232 r = kvm_vm_ioctl_enable_cap(kvm, &cap);
229 break; 233 break;
230 } 234 }
235 case KVM_CREATE_IRQCHIP: {
236 struct kvm_irq_routing_entry routing;
237
238 r = -EINVAL;
239 if (kvm->arch.use_irqchip) {
240 /* Set up dummy routing. */
241 memset(&routing, 0, sizeof(routing));
242 kvm_set_irq_routing(kvm, &routing, 0, 0);
243 r = 0;
244 }
245 break;
246 }
231 default: 247 default:
232 r = -ENOTTY; 248 r = -ENOTTY;
233 } 249 }
@@ -284,6 +300,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
284 } 300 }
285 301
286 kvm->arch.css_support = 0; 302 kvm->arch.css_support = 0;
303 kvm->arch.use_irqchip = 0;
287 304
288 return 0; 305 return 0;
289out_nogmap: 306out_nogmap: