diff options
-rw-r--r-- | drivers/s390/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/kvm/Makefile | 9 | ||||
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 338 | ||||
-rw-r--r-- | include/asm-s390/kvm_para.h | 124 | ||||
-rw-r--r-- | include/asm-s390/kvm_virtio.h | 53 |
5 files changed, 523 insertions, 3 deletions
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 5a888704a8d0..4f4e7cf105d4 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | 5 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w |
6 | 6 | ||
7 | obj-y += s390mach.o sysinfo.o s390_rdev.o | 7 | obj-y += s390mach.o sysinfo.o s390_rdev.o |
8 | obj-y += cio/ block/ char/ crypto/ net/ scsi/ | 8 | obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/ |
9 | 9 | ||
10 | drivers-y += drivers/s390/built-in.o | 10 | drivers-y += drivers/s390/built-in.o |
11 | 11 | ||
diff --git a/drivers/s390/kvm/Makefile b/drivers/s390/kvm/Makefile new file mode 100644 index 000000000000..4a5ec39f9ca6 --- /dev/null +++ b/drivers/s390/kvm/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for kvm guest drivers on s390 | ||
2 | # | ||
3 | # Copyright IBM Corp. 2008 | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License (version 2 only) | ||
7 | # as published by the Free Software Foundation. | ||
8 | |||
9 | obj-$(CONFIG_VIRTIO) += kvm_virtio.o | ||
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c new file mode 100644 index 000000000000..bbef3764fbf8 --- /dev/null +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * kvm_virtio.c - virtio for kvm on s390 | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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): Christian Borntraeger <borntraeger@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/bootmem.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/virtio.h> | ||
17 | #include <linux/virtio_config.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/virtio_ring.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/kvm_para.h> | ||
22 | #include <asm/kvm_virtio.h> | ||
23 | #include <asm/setup.h> | ||
24 | #include <asm/s390_ext.h> | ||
25 | |||
26 | #define VIRTIO_SUBCODE_64 0x0D00 | ||
27 | |||
28 | /* | ||
29 | * The pointer to our (page) of device descriptions. | ||
30 | */ | ||
31 | static void *kvm_devices; | ||
32 | |||
33 | /* | ||
34 | * Unique numbering for kvm devices. | ||
35 | */ | ||
36 | static unsigned int dev_index; | ||
37 | |||
38 | struct kvm_device { | ||
39 | struct virtio_device vdev; | ||
40 | struct kvm_device_desc *desc; | ||
41 | }; | ||
42 | |||
43 | #define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev) | ||
44 | |||
45 | /* | ||
46 | * memory layout: | ||
47 | * - kvm_device_descriptor | ||
48 | * struct kvm_device_desc | ||
49 | * - configuration | ||
50 | * struct kvm_vqconfig | ||
51 | * - feature bits | ||
52 | * - config space | ||
53 | */ | ||
54 | static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc) | ||
55 | { | ||
56 | return (struct kvm_vqconfig *)(desc + 1); | ||
57 | } | ||
58 | |||
59 | static u8 *kvm_vq_features(const struct kvm_device_desc *desc) | ||
60 | { | ||
61 | return (u8 *)(kvm_vq_config(desc) + desc->num_vq); | ||
62 | } | ||
63 | |||
64 | static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc) | ||
65 | { | ||
66 | return kvm_vq_features(desc) + desc->feature_len * 2; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * The total size of the config page used by this device (incl. desc) | ||
71 | */ | ||
72 | static unsigned desc_size(const struct kvm_device_desc *desc) | ||
73 | { | ||
74 | return sizeof(*desc) | ||
75 | + desc->num_vq * sizeof(struct kvm_vqconfig) | ||
76 | + desc->feature_len * 2 | ||
77 | + desc->config_len; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * This tests (and acknowleges) a feature bit. | ||
82 | */ | ||
83 | static bool kvm_feature(struct virtio_device *vdev, unsigned fbit) | ||
84 | { | ||
85 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
86 | u8 *features; | ||
87 | |||
88 | if (fbit / 8 > desc->feature_len) | ||
89 | return false; | ||
90 | |||
91 | features = kvm_vq_features(desc); | ||
92 | if (!(features[fbit / 8] & (1 << (fbit % 8)))) | ||
93 | return false; | ||
94 | |||
95 | /* | ||
96 | * We set the matching bit in the other half of the bitmap to tell the | ||
97 | * Host we want to use this feature. | ||
98 | */ | ||
99 | features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); | ||
100 | return true; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Reading and writing elements in config space | ||
105 | */ | ||
106 | static void kvm_get(struct virtio_device *vdev, unsigned int offset, | ||
107 | void *buf, unsigned len) | ||
108 | { | ||
109 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
110 | |||
111 | BUG_ON(offset + len > desc->config_len); | ||
112 | memcpy(buf, kvm_vq_configspace(desc) + offset, len); | ||
113 | } | ||
114 | |||
115 | static void kvm_set(struct virtio_device *vdev, unsigned int offset, | ||
116 | const void *buf, unsigned len) | ||
117 | { | ||
118 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
119 | |||
120 | BUG_ON(offset + len > desc->config_len); | ||
121 | memcpy(kvm_vq_configspace(desc) + offset, buf, len); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * The operations to get and set the status word just access | ||
126 | * the status field of the device descriptor. set_status will also | ||
127 | * make a hypercall to the host, to tell about status changes | ||
128 | */ | ||
129 | static u8 kvm_get_status(struct virtio_device *vdev) | ||
130 | { | ||
131 | return to_kvmdev(vdev)->desc->status; | ||
132 | } | ||
133 | |||
134 | static void kvm_set_status(struct virtio_device *vdev, u8 status) | ||
135 | { | ||
136 | BUG_ON(!status); | ||
137 | to_kvmdev(vdev)->desc->status = status; | ||
138 | kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS, | ||
139 | (unsigned long) to_kvmdev(vdev)->desc); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the | ||
144 | * descriptor address. The Host will zero the status and all the | ||
145 | * features. | ||
146 | */ | ||
147 | static void kvm_reset(struct virtio_device *vdev) | ||
148 | { | ||
149 | kvm_hypercall1(KVM_S390_VIRTIO_RESET, | ||
150 | (unsigned long) to_kvmdev(vdev)->desc); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * When the virtio_ring code wants to notify the Host, it calls us here and we | ||
155 | * make a hypercall. We hand the address of the virtqueue so the Host | ||
156 | * knows which virtqueue we're talking about. | ||
157 | */ | ||
158 | static void kvm_notify(struct virtqueue *vq) | ||
159 | { | ||
160 | struct kvm_vqconfig *config = vq->priv; | ||
161 | |||
162 | kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * This routine finds the first virtqueue described in the configuration of | ||
167 | * this device and sets it up. | ||
168 | */ | ||
169 | static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, | ||
170 | unsigned index, | ||
171 | void (*callback)(struct virtqueue *vq)) | ||
172 | { | ||
173 | struct kvm_device *kdev = to_kvmdev(vdev); | ||
174 | struct kvm_vqconfig *config; | ||
175 | struct virtqueue *vq; | ||
176 | int err; | ||
177 | |||
178 | if (index >= kdev->desc->num_vq) | ||
179 | return ERR_PTR(-ENOENT); | ||
180 | |||
181 | config = kvm_vq_config(kdev->desc)+index; | ||
182 | |||
183 | if (add_shared_memory(config->address, | ||
184 | vring_size(config->num, PAGE_SIZE))) { | ||
185 | err = -ENOMEM; | ||
186 | goto out; | ||
187 | } | ||
188 | |||
189 | vq = vring_new_virtqueue(config->num, vdev, (void *) config->address, | ||
190 | kvm_notify, callback); | ||
191 | if (!vq) { | ||
192 | err = -ENOMEM; | ||
193 | goto unmap; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * register a callback token | ||
198 | * The host will sent this via the external interrupt parameter | ||
199 | */ | ||
200 | config->token = (u64) vq; | ||
201 | |||
202 | vq->priv = config; | ||
203 | return vq; | ||
204 | unmap: | ||
205 | remove_shared_memory(config->address, vring_size(config->num, | ||
206 | PAGE_SIZE)); | ||
207 | out: | ||
208 | return ERR_PTR(err); | ||
209 | } | ||
210 | |||
211 | static void kvm_del_vq(struct virtqueue *vq) | ||
212 | { | ||
213 | struct kvm_vqconfig *config = vq->priv; | ||
214 | |||
215 | vring_del_virtqueue(vq); | ||
216 | remove_shared_memory(config->address, | ||
217 | vring_size(config->num, PAGE_SIZE)); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * The config ops structure as defined by virtio config | ||
222 | */ | ||
223 | static struct virtio_config_ops kvm_vq_configspace_ops = { | ||
224 | .feature = kvm_feature, | ||
225 | .get = kvm_get, | ||
226 | .set = kvm_set, | ||
227 | .get_status = kvm_get_status, | ||
228 | .set_status = kvm_set_status, | ||
229 | .reset = kvm_reset, | ||
230 | .find_vq = kvm_find_vq, | ||
231 | .del_vq = kvm_del_vq, | ||
232 | }; | ||
233 | |||
234 | /* | ||
235 | * The root device for the kvm virtio devices. | ||
236 | * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. | ||
237 | */ | ||
238 | static struct device kvm_root = { | ||
239 | .parent = NULL, | ||
240 | .bus_id = "kvm_s390", | ||
241 | }; | ||
242 | |||
243 | /* | ||
244 | * adds a new device and register it with virtio | ||
245 | * appropriate drivers are loaded by the device model | ||
246 | */ | ||
247 | static void add_kvm_device(struct kvm_device_desc *d) | ||
248 | { | ||
249 | struct kvm_device *kdev; | ||
250 | |||
251 | kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); | ||
252 | if (!kdev) { | ||
253 | printk(KERN_EMERG "Cannot allocate kvm dev %u\n", | ||
254 | dev_index++); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | kdev->vdev.dev.parent = &kvm_root; | ||
259 | kdev->vdev.index = dev_index++; | ||
260 | kdev->vdev.id.device = d->type; | ||
261 | kdev->vdev.config = &kvm_vq_configspace_ops; | ||
262 | kdev->desc = d; | ||
263 | |||
264 | if (register_virtio_device(&kdev->vdev) != 0) { | ||
265 | printk(KERN_ERR "Failed to register kvm device %u\n", | ||
266 | kdev->vdev.index); | ||
267 | kfree(kdev); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * scan_devices() simply iterates through the device page. | ||
273 | * The type 0 is reserved to mean "end of devices". | ||
274 | */ | ||
275 | static void scan_devices(void) | ||
276 | { | ||
277 | unsigned int i; | ||
278 | struct kvm_device_desc *d; | ||
279 | |||
280 | for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { | ||
281 | d = kvm_devices + i; | ||
282 | |||
283 | if (d->type == 0) | ||
284 | break; | ||
285 | |||
286 | add_kvm_device(d); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * we emulate the request_irq behaviour on top of s390 extints | ||
292 | */ | ||
293 | static void kvm_extint_handler(u16 code) | ||
294 | { | ||
295 | void *data = (void *) *(long *) __LC_PFAULT_INTPARM; | ||
296 | u16 subcode = S390_lowcore.cpu_addr; | ||
297 | |||
298 | if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) | ||
299 | return; | ||
300 | |||
301 | vring_interrupt(0, data); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Init function for virtio | ||
306 | * devices are in a single page above top of "normal" mem | ||
307 | */ | ||
308 | static int __init kvm_devices_init(void) | ||
309 | { | ||
310 | int rc; | ||
311 | |||
312 | if (!MACHINE_IS_KVM) | ||
313 | return -ENODEV; | ||
314 | |||
315 | rc = device_register(&kvm_root); | ||
316 | if (rc) { | ||
317 | printk(KERN_ERR "Could not register kvm_s390 root device"); | ||
318 | return rc; | ||
319 | } | ||
320 | |||
321 | if (add_shared_memory((max_pfn) << PAGE_SHIFT, PAGE_SIZE)) { | ||
322 | device_unregister(&kvm_root); | ||
323 | return -ENOMEM; | ||
324 | } | ||
325 | |||
326 | kvm_devices = (void *) (max_pfn << PAGE_SHIFT); | ||
327 | |||
328 | ctl_set_bit(0, 9); | ||
329 | register_external_interrupt(0x2603, kvm_extint_handler); | ||
330 | |||
331 | scan_devices(); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | * We do this after core stuff, but before the drivers. | ||
337 | */ | ||
338 | postcore_initcall(kvm_devices_init); | ||
diff --git a/include/asm-s390/kvm_para.h b/include/asm-s390/kvm_para.h index e9bd3fbe878c..2c503796b619 100644 --- a/include/asm-s390/kvm_para.h +++ b/include/asm-s390/kvm_para.h | |||
@@ -14,14 +14,134 @@ | |||
14 | #define __S390_KVM_PARA_H | 14 | #define __S390_KVM_PARA_H |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * No hypercalls for KVM on s390 | 17 | * Hypercalls for KVM on s390. The calling convention is similar to the |
18 | * s390 ABI, so we use R2-R6 for parameters 1-5. In addition we use R1 | ||
19 | * as hypercall number and R7 as parameter 6. The return value is | ||
20 | * written to R2. We use the diagnose instruction as hypercall. To avoid | ||
21 | * conflicts with existing diagnoses for LPAR and z/VM, we do not use | ||
22 | * the instruction encoded number, but specify the number in R1 and | ||
23 | * use 0x500 as KVM hypercall | ||
24 | * | ||
25 | * Copyright IBM Corp. 2007,2008 | ||
26 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
27 | * | ||
28 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
18 | */ | 29 | */ |
19 | 30 | ||
31 | static inline long kvm_hypercall0(unsigned long nr) | ||
32 | { | ||
33 | register unsigned long __nr asm("1") = nr; | ||
34 | register long __rc asm("2"); | ||
35 | |||
36 | asm volatile ("diag 2,4,0x500\n" | ||
37 | : "=d" (__rc) : "d" (__nr): "memory", "cc"); | ||
38 | return __rc; | ||
39 | } | ||
40 | |||
41 | static inline long kvm_hypercall1(unsigned long nr, unsigned long p1) | ||
42 | { | ||
43 | register unsigned long __nr asm("1") = nr; | ||
44 | register unsigned long __p1 asm("2") = p1; | ||
45 | register long __rc asm("2"); | ||
46 | |||
47 | asm volatile ("diag 2,4,0x500\n" | ||
48 | : "=d" (__rc) : "d" (__nr), "0" (__p1) : "memory", "cc"); | ||
49 | return __rc; | ||
50 | } | ||
51 | |||
52 | static inline long kvm_hypercall2(unsigned long nr, unsigned long p1, | ||
53 | unsigned long p2) | ||
54 | { | ||
55 | register unsigned long __nr asm("1") = nr; | ||
56 | register unsigned long __p1 asm("2") = p1; | ||
57 | register unsigned long __p2 asm("3") = p2; | ||
58 | register long __rc asm("2"); | ||
59 | |||
60 | asm volatile ("diag 2,4,0x500\n" | ||
61 | : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2) | ||
62 | : "memory", "cc"); | ||
63 | return __rc; | ||
64 | } | ||
65 | |||
66 | static inline long kvm_hypercall3(unsigned long nr, unsigned long p1, | ||
67 | unsigned long p2, unsigned long p3) | ||
68 | { | ||
69 | register unsigned long __nr asm("1") = nr; | ||
70 | register unsigned long __p1 asm("2") = p1; | ||
71 | register unsigned long __p2 asm("3") = p2; | ||
72 | register unsigned long __p3 asm("4") = p3; | ||
73 | register long __rc asm("2"); | ||
74 | |||
75 | asm volatile ("diag 2,4,0x500\n" | ||
76 | : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2), | ||
77 | "d" (__p3) : "memory", "cc"); | ||
78 | return __rc; | ||
79 | } | ||
80 | |||
81 | |||
82 | static inline long kvm_hypercall4(unsigned long nr, unsigned long p1, | ||
83 | unsigned long p2, unsigned long p3, | ||
84 | unsigned long p4) | ||
85 | { | ||
86 | register unsigned long __nr asm("1") = nr; | ||
87 | register unsigned long __p1 asm("2") = p1; | ||
88 | register unsigned long __p2 asm("3") = p2; | ||
89 | register unsigned long __p3 asm("4") = p3; | ||
90 | register unsigned long __p4 asm("5") = p4; | ||
91 | register long __rc asm("2"); | ||
92 | |||
93 | asm volatile ("diag 2,4,0x500\n" | ||
94 | : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2), | ||
95 | "d" (__p3), "d" (__p4) : "memory", "cc"); | ||
96 | return __rc; | ||
97 | } | ||
98 | |||
99 | static inline long kvm_hypercall5(unsigned long nr, unsigned long p1, | ||
100 | unsigned long p2, unsigned long p3, | ||
101 | unsigned long p4, unsigned long p5) | ||
102 | { | ||
103 | register unsigned long __nr asm("1") = nr; | ||
104 | register unsigned long __p1 asm("2") = p1; | ||
105 | register unsigned long __p2 asm("3") = p2; | ||
106 | register unsigned long __p3 asm("4") = p3; | ||
107 | register unsigned long __p4 asm("5") = p4; | ||
108 | register unsigned long __p5 asm("6") = p5; | ||
109 | register long __rc asm("2"); | ||
110 | |||
111 | asm volatile ("diag 2,4,0x500\n" | ||
112 | : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2), | ||
113 | "d" (__p3), "d" (__p4), "d" (__p5) : "memory", "cc"); | ||
114 | return __rc; | ||
115 | } | ||
116 | |||
117 | static inline long kvm_hypercall6(unsigned long nr, unsigned long p1, | ||
118 | unsigned long p2, unsigned long p3, | ||
119 | unsigned long p4, unsigned long p5, | ||
120 | unsigned long p6) | ||
121 | { | ||
122 | register unsigned long __nr asm("1") = nr; | ||
123 | register unsigned long __p1 asm("2") = p1; | ||
124 | register unsigned long __p2 asm("3") = p2; | ||
125 | register unsigned long __p3 asm("4") = p3; | ||
126 | register unsigned long __p4 asm("5") = p4; | ||
127 | register unsigned long __p5 asm("6") = p5; | ||
128 | register unsigned long __p6 asm("7") = p6; | ||
129 | register long __rc asm("2"); | ||
130 | |||
131 | asm volatile ("diag 2,4,0x500\n" | ||
132 | : "=d" (__rc) : "d" (__nr), "0" (__p1), "d" (__p2), | ||
133 | "d" (__p3), "d" (__p4), "d" (__p5), "d" (__p6) | ||
134 | : "memory", "cc"); | ||
135 | return __rc; | ||
136 | } | ||
137 | |||
138 | /* kvm on s390 is always paravirtualization enabled */ | ||
20 | static inline int kvm_para_available(void) | 139 | static inline int kvm_para_available(void) |
21 | { | 140 | { |
22 | return 0; | 141 | return 1; |
23 | } | 142 | } |
24 | 143 | ||
144 | /* No feature bits are currently assigned for kvm on s390 */ | ||
25 | static inline unsigned int kvm_arch_para_features(void) | 145 | static inline unsigned int kvm_arch_para_features(void) |
26 | { | 146 | { |
27 | return 0; | 147 | return 0; |
diff --git a/include/asm-s390/kvm_virtio.h b/include/asm-s390/kvm_virtio.h new file mode 100644 index 000000000000..5c871a990c29 --- /dev/null +++ b/include/asm-s390/kvm_virtio.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * kvm_virtio.h - definition for virtio for kvm on s390 | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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): Christian Borntraeger <borntraeger@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #ifndef __KVM_S390_VIRTIO_H | ||
14 | #define __KVM_S390_VIRTIO_H | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | |||
18 | struct kvm_device_desc { | ||
19 | /* The device type: console, network, disk etc. Type 0 terminates. */ | ||
20 | __u8 type; | ||
21 | /* The number of virtqueues (first in config array) */ | ||
22 | __u8 num_vq; | ||
23 | /* | ||
24 | * The number of bytes of feature bits. Multiply by 2: one for host | ||
25 | * features and one for guest acknowledgements. | ||
26 | */ | ||
27 | __u8 feature_len; | ||
28 | /* The number of bytes of the config array after virtqueues. */ | ||
29 | __u8 config_len; | ||
30 | /* A status byte, written by the Guest. */ | ||
31 | __u8 status; | ||
32 | __u8 config[0]; | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * This is how we expect the device configuration field for a virtqueue | ||
37 | * to be laid out in config space. | ||
38 | */ | ||
39 | struct kvm_vqconfig { | ||
40 | /* The token returned with an interrupt. Set by the guest */ | ||
41 | __u64 token; | ||
42 | /* The address of the virtio ring */ | ||
43 | __u64 address; | ||
44 | /* The number of entries in the virtio_ring */ | ||
45 | __u16 num; | ||
46 | |||
47 | }; | ||
48 | |||
49 | #define KVM_S390_VIRTIO_NOTIFY 0 | ||
50 | #define KVM_S390_VIRTIO_RESET 1 | ||
51 | #define KVM_S390_VIRTIO_SET_STATUS 2 | ||
52 | |||
53 | #endif | ||