diff options
Diffstat (limited to 'drivers/s390/kvm/kvm_virtio.c')
-rw-r--r-- | drivers/s390/kvm/kvm_virtio.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 5ab34340919b..79954bd6bfa5 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/virtio.h> | 16 | #include <linux/virtio.h> |
17 | #include <linux/virtio_config.h> | 17 | #include <linux/virtio_config.h> |
18 | #include <linux/virtio_console.h> | ||
18 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
19 | #include <linux/virtio_ring.h> | 20 | #include <linux/virtio_ring.h> |
20 | #include <linux/pfn.h> | 21 | #include <linux/pfn.h> |
@@ -87,16 +88,20 @@ static u32 kvm_get_features(struct virtio_device *vdev) | |||
87 | return features; | 88 | return features; |
88 | } | 89 | } |
89 | 90 | ||
90 | static void kvm_set_features(struct virtio_device *vdev, u32 features) | 91 | static void kvm_finalize_features(struct virtio_device *vdev) |
91 | { | 92 | { |
92 | unsigned int i; | 93 | unsigned int i, bits; |
93 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | 94 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; |
94 | /* Second half of bitmap is features we accept. */ | 95 | /* Second half of bitmap is features we accept. */ |
95 | u8 *out_features = kvm_vq_features(desc) + desc->feature_len; | 96 | u8 *out_features = kvm_vq_features(desc) + desc->feature_len; |
96 | 97 | ||
98 | /* Give virtio_ring a chance to accept features. */ | ||
99 | vring_transport_features(vdev); | ||
100 | |||
97 | memset(out_features, 0, desc->feature_len); | 101 | memset(out_features, 0, desc->feature_len); |
98 | for (i = 0; i < min(desc->feature_len * 8, 32); i++) { | 102 | bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8; |
99 | if (features & (1 << i)) | 103 | for (i = 0; i < bits; i++) { |
104 | if (test_bit(i, vdev->features)) | ||
100 | out_features[i / 8] |= (1 << (i % 8)); | 105 | out_features[i / 8] |= (1 << (i % 8)); |
101 | } | 106 | } |
102 | } | 107 | } |
@@ -222,7 +227,7 @@ static void kvm_del_vq(struct virtqueue *vq) | |||
222 | */ | 227 | */ |
223 | static struct virtio_config_ops kvm_vq_configspace_ops = { | 228 | static struct virtio_config_ops kvm_vq_configspace_ops = { |
224 | .get_features = kvm_get_features, | 229 | .get_features = kvm_get_features, |
225 | .set_features = kvm_set_features, | 230 | .finalize_features = kvm_finalize_features, |
226 | .get = kvm_get, | 231 | .get = kvm_get, |
227 | .set = kvm_set, | 232 | .set = kvm_set, |
228 | .get_status = kvm_get_status, | 233 | .get_status = kvm_get_status, |
@@ -333,6 +338,25 @@ static int __init kvm_devices_init(void) | |||
333 | return 0; | 338 | return 0; |
334 | } | 339 | } |
335 | 340 | ||
341 | /* code for early console output with virtio_console */ | ||
342 | static __init int early_put_chars(u32 vtermno, const char *buf, int count) | ||
343 | { | ||
344 | char scratch[17]; | ||
345 | unsigned int len = count; | ||
346 | |||
347 | if (len > sizeof(scratch) - 1) | ||
348 | len = sizeof(scratch) - 1; | ||
349 | scratch[len] = '\0'; | ||
350 | memcpy(scratch, buf, len); | ||
351 | kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch)); | ||
352 | return len; | ||
353 | } | ||
354 | |||
355 | void s390_virtio_console_init(void) | ||
356 | { | ||
357 | virtio_cons_early_init(early_put_chars); | ||
358 | } | ||
359 | |||
336 | /* | 360 | /* |
337 | * We do this after core stuff, but before the drivers. | 361 | * We do this after core stuff, but before the drivers. |
338 | */ | 362 | */ |