| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 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 |  | 
| Heiko Carstens | 052ff46 | 2011-01-05 12:47:28 +0100 | [diff] [blame] | 13 | #include <linux/kernel_stat.h> | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 14 | #include <linux/init.h> | 
 | 15 | #include <linux/bootmem.h> | 
 | 16 | #include <linux/err.h> | 
 | 17 | #include <linux/virtio.h> | 
 | 18 | #include <linux/virtio_config.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 19 | #include <linux/slab.h> | 
| Christian Borntraeger | faeba83 | 2008-06-20 15:24:18 +0200 | [diff] [blame] | 20 | #include <linux/virtio_console.h> | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 21 | #include <linux/interrupt.h> | 
 | 22 | #include <linux/virtio_ring.h> | 
| Heiko Carstens | 3a4c5d5 | 2011-07-30 09:25:15 +0200 | [diff] [blame] | 23 | #include <linux/export.h> | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 24 | #include <linux/pfn.h> | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 25 | #include <asm/io.h> | 
 | 26 | #include <asm/kvm_para.h> | 
 | 27 | #include <asm/kvm_virtio.h> | 
 | 28 | #include <asm/setup.h> | 
| Heiko Carstens | 052ff46 | 2011-01-05 12:47:28 +0100 | [diff] [blame] | 29 | #include <asm/irq.h> | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 30 |  | 
 | 31 | #define VIRTIO_SUBCODE_64 0x0D00 | 
 | 32 |  | 
 | 33 | /* | 
 | 34 |  * The pointer to our (page) of device descriptions. | 
 | 35 |  */ | 
 | 36 | static void *kvm_devices; | 
| Martin Schwidefsky | c4736d9 | 2011-10-30 15:17:11 +0100 | [diff] [blame] | 37 | static struct work_struct hotplug_work; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 38 |  | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 39 | struct kvm_device { | 
 | 40 | 	struct virtio_device vdev; | 
 | 41 | 	struct kvm_device_desc *desc; | 
 | 42 | }; | 
 | 43 |  | 
 | 44 | #define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev) | 
 | 45 |  | 
 | 46 | /* | 
 | 47 |  * memory layout: | 
 | 48 |  * - kvm_device_descriptor | 
 | 49 |  *        struct kvm_device_desc | 
 | 50 |  * - configuration | 
 | 51 |  *        struct kvm_vqconfig | 
 | 52 |  * - feature bits | 
 | 53 |  * - config space | 
 | 54 |  */ | 
 | 55 | static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc) | 
 | 56 | { | 
 | 57 | 	return (struct kvm_vqconfig *)(desc + 1); | 
 | 58 | } | 
 | 59 |  | 
 | 60 | static u8 *kvm_vq_features(const struct kvm_device_desc *desc) | 
 | 61 | { | 
 | 62 | 	return (u8 *)(kvm_vq_config(desc) + desc->num_vq); | 
 | 63 | } | 
 | 64 |  | 
 | 65 | static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc) | 
 | 66 | { | 
 | 67 | 	return kvm_vq_features(desc) + desc->feature_len * 2; | 
 | 68 | } | 
 | 69 |  | 
 | 70 | /* | 
 | 71 |  * The total size of the config page used by this device (incl. desc) | 
 | 72 |  */ | 
 | 73 | static unsigned desc_size(const struct kvm_device_desc *desc) | 
 | 74 | { | 
 | 75 | 	return sizeof(*desc) | 
 | 76 | 		+ desc->num_vq * sizeof(struct kvm_vqconfig) | 
 | 77 | 		+ desc->feature_len * 2 | 
 | 78 | 		+ desc->config_len; | 
 | 79 | } | 
 | 80 |  | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 81 | /* This gets the device's feature bits. */ | 
 | 82 | static u32 kvm_get_features(struct virtio_device *vdev) | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 83 | { | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 84 | 	unsigned int i; | 
 | 85 | 	u32 features = 0; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 86 | 	struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 87 | 	u8 *in_features = kvm_vq_features(desc); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 88 |  | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 89 | 	for (i = 0; i < min(desc->feature_len * 8, 32); i++) | 
 | 90 | 		if (in_features[i / 8] & (1 << (i % 8))) | 
 | 91 | 			features |= (1 << i); | 
 | 92 | 	return features; | 
 | 93 | } | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 94 |  | 
| Rusty Russell | c624896 | 2008-07-25 12:06:07 -0500 | [diff] [blame] | 95 | static void kvm_finalize_features(struct virtio_device *vdev) | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 96 | { | 
| Rusty Russell | c624896 | 2008-07-25 12:06:07 -0500 | [diff] [blame] | 97 | 	unsigned int i, bits; | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 98 | 	struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | 
 | 99 | 	/* Second half of bitmap is features we accept. */ | 
 | 100 | 	u8 *out_features = kvm_vq_features(desc) + desc->feature_len; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 101 |  | 
| Rusty Russell | e34f872 | 2008-07-25 12:06:13 -0500 | [diff] [blame] | 102 | 	/* Give virtio_ring a chance to accept features. */ | 
 | 103 | 	vring_transport_features(vdev); | 
 | 104 |  | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 105 | 	memset(out_features, 0, desc->feature_len); | 
| Rusty Russell | c624896 | 2008-07-25 12:06:07 -0500 | [diff] [blame] | 106 | 	bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8; | 
 | 107 | 	for (i = 0; i < bits; i++) { | 
 | 108 | 		if (test_bit(i, vdev->features)) | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 109 | 			out_features[i / 8] |= (1 << (i % 8)); | 
 | 110 | 	} | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 111 | } | 
 | 112 |  | 
 | 113 | /* | 
 | 114 |  * Reading and writing elements in config space | 
 | 115 |  */ | 
 | 116 | static void kvm_get(struct virtio_device *vdev, unsigned int offset, | 
 | 117 | 		   void *buf, unsigned len) | 
 | 118 | { | 
 | 119 | 	struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | 
 | 120 |  | 
 | 121 | 	BUG_ON(offset + len > desc->config_len); | 
 | 122 | 	memcpy(buf, kvm_vq_configspace(desc) + offset, len); | 
 | 123 | } | 
 | 124 |  | 
 | 125 | static void kvm_set(struct virtio_device *vdev, unsigned int offset, | 
 | 126 | 		   const void *buf, unsigned len) | 
 | 127 | { | 
 | 128 | 	struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | 
 | 129 |  | 
 | 130 | 	BUG_ON(offset + len > desc->config_len); | 
 | 131 | 	memcpy(kvm_vq_configspace(desc) + offset, buf, len); | 
 | 132 | } | 
 | 133 |  | 
 | 134 | /* | 
 | 135 |  * The operations to get and set the status word just access | 
 | 136 |  * the status field of the device descriptor. set_status will also | 
 | 137 |  * make a hypercall to the host, to tell about status changes | 
 | 138 |  */ | 
 | 139 | static u8 kvm_get_status(struct virtio_device *vdev) | 
 | 140 | { | 
 | 141 | 	return to_kvmdev(vdev)->desc->status; | 
 | 142 | } | 
 | 143 |  | 
 | 144 | static void kvm_set_status(struct virtio_device *vdev, u8 status) | 
 | 145 | { | 
 | 146 | 	BUG_ON(!status); | 
 | 147 | 	to_kvmdev(vdev)->desc->status = status; | 
 | 148 | 	kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS, | 
 | 149 | 		       (unsigned long) to_kvmdev(vdev)->desc); | 
 | 150 | } | 
 | 151 |  | 
 | 152 | /* | 
 | 153 |  * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the | 
 | 154 |  * descriptor address. The Host will zero the status and all the | 
 | 155 |  * features. | 
 | 156 |  */ | 
 | 157 | static void kvm_reset(struct virtio_device *vdev) | 
 | 158 | { | 
 | 159 | 	kvm_hypercall1(KVM_S390_VIRTIO_RESET, | 
 | 160 | 		       (unsigned long) to_kvmdev(vdev)->desc); | 
 | 161 | } | 
 | 162 |  | 
 | 163 | /* | 
 | 164 |  * When the virtio_ring code wants to notify the Host, it calls us here and we | 
 | 165 |  * make a hypercall.  We hand the address  of the virtqueue so the Host | 
 | 166 |  * knows which virtqueue we're talking about. | 
 | 167 |  */ | 
 | 168 | static void kvm_notify(struct virtqueue *vq) | 
 | 169 | { | 
 | 170 | 	struct kvm_vqconfig *config = vq->priv; | 
 | 171 |  | 
 | 172 | 	kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); | 
 | 173 | } | 
 | 174 |  | 
 | 175 | /* | 
 | 176 |  * This routine finds the first virtqueue described in the configuration of | 
 | 177 |  * this device and sets it up. | 
 | 178 |  */ | 
 | 179 | static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, | 
| Rusty Russell | 9499f5e | 2009-06-12 22:16:35 -0600 | [diff] [blame] | 180 | 				     unsigned index, | 
 | 181 | 				     void (*callback)(struct virtqueue *vq), | 
 | 182 | 				     const char *name) | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 183 | { | 
 | 184 | 	struct kvm_device *kdev = to_kvmdev(vdev); | 
 | 185 | 	struct kvm_vqconfig *config; | 
 | 186 | 	struct virtqueue *vq; | 
 | 187 | 	int err; | 
 | 188 |  | 
 | 189 | 	if (index >= kdev->desc->num_vq) | 
 | 190 | 		return ERR_PTR(-ENOENT); | 
 | 191 |  | 
 | 192 | 	config = kvm_vq_config(kdev->desc)+index; | 
 | 193 |  | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 194 | 	err = vmem_add_mapping(config->address, | 
| Rusty Russell | db40598 | 2008-12-30 09:26:02 -0600 | [diff] [blame] | 195 | 			       vring_size(config->num, | 
 | 196 | 					  KVM_S390_VIRTIO_RING_ALIGN)); | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 197 | 	if (err) | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 198 | 		goto out; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 199 |  | 
| Rusty Russell | 87c7d57 | 2008-12-30 09:26:03 -0600 | [diff] [blame] | 200 | 	vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, | 
| Rusty Russell | 7b21e34 | 2012-01-12 15:44:42 +1030 | [diff] [blame] | 201 | 				 vdev, true, (void *) config->address, | 
| Rusty Russell | 9499f5e | 2009-06-12 22:16:35 -0600 | [diff] [blame] | 202 | 				 kvm_notify, callback, name); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 203 | 	if (!vq) { | 
 | 204 | 		err = -ENOMEM; | 
 | 205 | 		goto unmap; | 
 | 206 | 	} | 
 | 207 |  | 
 | 208 | 	/* | 
 | 209 | 	 * register a callback token | 
 | 210 | 	 * The host will sent this via the external interrupt parameter | 
 | 211 | 	 */ | 
 | 212 | 	config->token = (u64) vq; | 
 | 213 |  | 
 | 214 | 	vq->priv = config; | 
 | 215 | 	return vq; | 
 | 216 | unmap: | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 217 | 	vmem_remove_mapping(config->address, | 
| Rusty Russell | db40598 | 2008-12-30 09:26:02 -0600 | [diff] [blame] | 218 | 			    vring_size(config->num, | 
 | 219 | 				       KVM_S390_VIRTIO_RING_ALIGN)); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 220 | out: | 
 | 221 | 	return ERR_PTR(err); | 
 | 222 | } | 
 | 223 |  | 
 | 224 | static void kvm_del_vq(struct virtqueue *vq) | 
 | 225 | { | 
 | 226 | 	struct kvm_vqconfig *config = vq->priv; | 
 | 227 |  | 
 | 228 | 	vring_del_virtqueue(vq); | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 229 | 	vmem_remove_mapping(config->address, | 
| Rusty Russell | db40598 | 2008-12-30 09:26:02 -0600 | [diff] [blame] | 230 | 			    vring_size(config->num, | 
 | 231 | 				       KVM_S390_VIRTIO_RING_ALIGN)); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 232 | } | 
 | 233 |  | 
| Michael S. Tsirkin | d2a7ddd | 2009-06-12 22:16:36 -0600 | [diff] [blame] | 234 | static void kvm_del_vqs(struct virtio_device *vdev) | 
 | 235 | { | 
 | 236 | 	struct virtqueue *vq, *n; | 
 | 237 |  | 
 | 238 | 	list_for_each_entry_safe(vq, n, &vdev->vqs, list) | 
 | 239 | 		kvm_del_vq(vq); | 
 | 240 | } | 
 | 241 |  | 
 | 242 | static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, | 
 | 243 | 			struct virtqueue *vqs[], | 
 | 244 | 			vq_callback_t *callbacks[], | 
 | 245 | 			const char *names[]) | 
 | 246 | { | 
 | 247 | 	struct kvm_device *kdev = to_kvmdev(vdev); | 
 | 248 | 	int i; | 
 | 249 |  | 
 | 250 | 	/* We must have this many virtqueues. */ | 
 | 251 | 	if (nvqs > kdev->desc->num_vq) | 
 | 252 | 		return -ENOENT; | 
 | 253 |  | 
 | 254 | 	for (i = 0; i < nvqs; ++i) { | 
 | 255 | 		vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); | 
 | 256 | 		if (IS_ERR(vqs[i])) | 
 | 257 | 			goto error; | 
 | 258 | 	} | 
 | 259 | 	return 0; | 
 | 260 |  | 
 | 261 | error: | 
 | 262 | 	kvm_del_vqs(vdev); | 
 | 263 | 	return PTR_ERR(vqs[i]); | 
 | 264 | } | 
 | 265 |  | 
| Rick Jones | 6684604 | 2011-11-14 14:17:08 +0000 | [diff] [blame] | 266 | static const char *kvm_bus_name(struct virtio_device *vdev) | 
 | 267 | { | 
 | 268 | 	return ""; | 
 | 269 | } | 
 | 270 |  | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 271 | /* | 
 | 272 |  * The config ops structure as defined by virtio config | 
 | 273 |  */ | 
 | 274 | static struct virtio_config_ops kvm_vq_configspace_ops = { | 
| Heiko Carstens | 5ca9fd5 | 2008-05-06 17:38:30 +0300 | [diff] [blame] | 275 | 	.get_features = kvm_get_features, | 
| Rusty Russell | c624896 | 2008-07-25 12:06:07 -0500 | [diff] [blame] | 276 | 	.finalize_features = kvm_finalize_features, | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 277 | 	.get = kvm_get, | 
 | 278 | 	.set = kvm_set, | 
 | 279 | 	.get_status = kvm_get_status, | 
 | 280 | 	.set_status = kvm_set_status, | 
 | 281 | 	.reset = kvm_reset, | 
| Michael S. Tsirkin | d2a7ddd | 2009-06-12 22:16:36 -0600 | [diff] [blame] | 282 | 	.find_vqs = kvm_find_vqs, | 
 | 283 | 	.del_vqs = kvm_del_vqs, | 
| Rick Jones | 6684604 | 2011-11-14 14:17:08 +0000 | [diff] [blame] | 284 | 	.bus_name = kvm_bus_name, | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 285 | }; | 
 | 286 |  | 
 | 287 | /* | 
 | 288 |  * The root device for the kvm virtio devices. | 
 | 289 |  * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. | 
 | 290 |  */ | 
| Cornelia Huck | 37f1c01 | 2008-10-10 21:33:12 +0200 | [diff] [blame] | 291 | static struct device *kvm_root; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 292 |  | 
 | 293 | /* | 
 | 294 |  * adds a new device and register it with virtio | 
 | 295 |  * appropriate drivers are loaded by the device model | 
 | 296 |  */ | 
| Rusty Russell | b769f57 | 2008-05-30 15:09:42 -0500 | [diff] [blame] | 297 | static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset) | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 298 | { | 
 | 299 | 	struct kvm_device *kdev; | 
 | 300 |  | 
 | 301 | 	kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); | 
 | 302 | 	if (!kdev) { | 
| Rusty Russell | b769f57 | 2008-05-30 15:09:42 -0500 | [diff] [blame] | 303 | 		printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n", | 
 | 304 | 		       offset, d->type); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 305 | 		return; | 
 | 306 | 	} | 
 | 307 |  | 
| Cornelia Huck | 37f1c01 | 2008-10-10 21:33:12 +0200 | [diff] [blame] | 308 | 	kdev->vdev.dev.parent = kvm_root; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 309 | 	kdev->vdev.id.device = d->type; | 
 | 310 | 	kdev->vdev.config = &kvm_vq_configspace_ops; | 
 | 311 | 	kdev->desc = d; | 
 | 312 |  | 
 | 313 | 	if (register_virtio_device(&kdev->vdev) != 0) { | 
| Rusty Russell | b769f57 | 2008-05-30 15:09:42 -0500 | [diff] [blame] | 314 | 		printk(KERN_ERR "Failed to register kvm device %u type %u\n", | 
 | 315 | 		       offset, d->type); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 316 | 		kfree(kdev); | 
 | 317 | 	} | 
 | 318 | } | 
 | 319 |  | 
 | 320 | /* | 
 | 321 |  * scan_devices() simply iterates through the device page. | 
 | 322 |  * The type 0 is reserved to mean "end of devices". | 
 | 323 |  */ | 
 | 324 | static void scan_devices(void) | 
 | 325 | { | 
 | 326 | 	unsigned int i; | 
 | 327 | 	struct kvm_device_desc *d; | 
 | 328 |  | 
 | 329 | 	for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { | 
 | 330 | 		d = kvm_devices + i; | 
 | 331 |  | 
 | 332 | 		if (d->type == 0) | 
 | 333 | 			break; | 
 | 334 |  | 
| Rusty Russell | b769f57 | 2008-05-30 15:09:42 -0500 | [diff] [blame] | 335 | 		add_kvm_device(d, i); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 336 | 	} | 
 | 337 | } | 
 | 338 |  | 
 | 339 | /* | 
| Alexander Graf | cefa33e | 2010-08-24 15:48:51 +0200 | [diff] [blame] | 340 |  * match for a kvm device with a specific desc pointer | 
 | 341 |  */ | 
 | 342 | static int match_desc(struct device *dev, void *data) | 
 | 343 | { | 
| Martin Schwidefsky | 7bf4074 | 2011-10-30 15:17:17 +0100 | [diff] [blame] | 344 | 	struct virtio_device *vdev = dev_to_virtio(dev); | 
 | 345 | 	struct kvm_device *kdev = to_kvmdev(vdev); | 
| Alexander Graf | cefa33e | 2010-08-24 15:48:51 +0200 | [diff] [blame] | 346 |  | 
| Martin Schwidefsky | 7bf4074 | 2011-10-30 15:17:17 +0100 | [diff] [blame] | 347 | 	return kdev->desc == data; | 
| Alexander Graf | cefa33e | 2010-08-24 15:48:51 +0200 | [diff] [blame] | 348 | } | 
 | 349 |  | 
 | 350 | /* | 
 | 351 |  * hotplug_device tries to find changes in the device page. | 
 | 352 |  */ | 
 | 353 | static void hotplug_devices(struct work_struct *dummy) | 
 | 354 | { | 
 | 355 | 	unsigned int i; | 
 | 356 | 	struct kvm_device_desc *d; | 
 | 357 | 	struct device *dev; | 
 | 358 |  | 
 | 359 | 	for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { | 
 | 360 | 		d = kvm_devices + i; | 
 | 361 |  | 
 | 362 | 		/* end of list */ | 
 | 363 | 		if (d->type == 0) | 
 | 364 | 			break; | 
 | 365 |  | 
 | 366 | 		/* device already exists */ | 
 | 367 | 		dev = device_find_child(kvm_root, d, match_desc); | 
 | 368 | 		if (dev) { | 
 | 369 | 			/* XXX check for hotplug remove */ | 
 | 370 | 			put_device(dev); | 
 | 371 | 			continue; | 
 | 372 | 		} | 
 | 373 |  | 
 | 374 | 		/* new device */ | 
 | 375 | 		printk(KERN_INFO "Adding new virtio device %p\n", d); | 
 | 376 | 		add_kvm_device(d, i); | 
 | 377 | 	} | 
 | 378 | } | 
 | 379 |  | 
 | 380 | /* | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 381 |  * we emulate the request_irq behaviour on top of s390 extints | 
 | 382 |  */ | 
| Martin Schwidefsky | f6649a7 | 2010-10-25 16:10:38 +0200 | [diff] [blame] | 383 | static void kvm_extint_handler(unsigned int ext_int_code, | 
 | 384 | 			       unsigned int param32, unsigned long param64) | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 385 | { | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 386 | 	struct virtqueue *vq; | 
 | 387 | 	u16 subcode; | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 388 | 	u32 param; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 389 |  | 
| Martin Schwidefsky | f6649a7 | 2010-10-25 16:10:38 +0200 | [diff] [blame] | 390 | 	subcode = ext_int_code >> 16; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 391 | 	if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) | 
 | 392 | 		return; | 
| Heiko Carstens | a985183 | 2011-04-29 10:42:19 +0200 | [diff] [blame] | 393 | 	kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 394 |  | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 395 | 	/* The LSB might be overloaded, we have to mask it */ | 
| Martin Schwidefsky | f6649a7 | 2010-10-25 16:10:38 +0200 | [diff] [blame] | 396 | 	vq = (struct virtqueue *)(param64 & ~1UL); | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 397 |  | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 398 | 	/* We use ext_params to decide what this interrupt means */ | 
| Martin Schwidefsky | f6649a7 | 2010-10-25 16:10:38 +0200 | [diff] [blame] | 399 | 	param = param32 & VIRTIO_PARAM_MASK; | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 400 |  | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 401 | 	switch (param) { | 
 | 402 | 	case VIRTIO_PARAM_CONFIG_CHANGED: | 
 | 403 | 	{ | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 404 | 		struct virtio_driver *drv; | 
 | 405 | 		drv = container_of(vq->vdev->dev.driver, | 
 | 406 | 				   struct virtio_driver, driver); | 
 | 407 | 		if (drv->config_changed) | 
 | 408 | 			drv->config_changed(vq->vdev); | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 409 |  | 
 | 410 | 		break; | 
 | 411 | 	} | 
| Alexander Graf | cefa33e | 2010-08-24 15:48:51 +0200 | [diff] [blame] | 412 | 	case VIRTIO_PARAM_DEV_ADD: | 
 | 413 | 		schedule_work(&hotplug_work); | 
 | 414 | 		break; | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 415 | 	case VIRTIO_PARAM_VRING_INTERRUPT: | 
 | 416 | 	default: | 
| Christian Borntraeger | be3c583 | 2008-11-18 22:44:13 +0100 | [diff] [blame] | 417 | 		vring_interrupt(0, vq); | 
| Alexander Graf | fc678d6 | 2010-08-24 15:48:50 +0200 | [diff] [blame] | 418 | 		break; | 
 | 419 | 	} | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 420 | } | 
 | 421 |  | 
 | 422 | /* | 
 | 423 |  * Init function for virtio | 
 | 424 |  * devices are in a single page above top of "normal" mem | 
 | 425 |  */ | 
 | 426 | static int __init kvm_devices_init(void) | 
 | 427 | { | 
 | 428 | 	int rc; | 
 | 429 |  | 
 | 430 | 	if (!MACHINE_IS_KVM) | 
 | 431 | 		return -ENODEV; | 
 | 432 |  | 
| Mark McLoughlin | 035da16 | 2008-12-15 12:58:29 +0000 | [diff] [blame] | 433 | 	kvm_root = root_device_register("kvm_s390"); | 
| Cornelia Huck | 37f1c01 | 2008-10-10 21:33:12 +0200 | [diff] [blame] | 434 | 	if (IS_ERR(kvm_root)) { | 
 | 435 | 		rc = PTR_ERR(kvm_root); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 436 | 		printk(KERN_ERR "Could not register kvm_s390 root device"); | 
 | 437 | 		return rc; | 
 | 438 | 	} | 
 | 439 |  | 
| Christian Borntraeger | cc835f78 | 2008-11-14 18:18:02 +0100 | [diff] [blame] | 440 | 	rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 441 | 	if (rc) { | 
| Mark McLoughlin | 035da16 | 2008-12-15 12:58:29 +0000 | [diff] [blame] | 442 | 		root_device_unregister(kvm_root); | 
| Heiko Carstens | 17f3458 | 2008-04-30 13:38:47 +0200 | [diff] [blame] | 443 | 		return rc; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 444 | 	} | 
 | 445 |  | 
| Christian Borntraeger | cc835f78 | 2008-11-14 18:18:02 +0100 | [diff] [blame] | 446 | 	kvm_devices = (void *) real_memory_size; | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 447 |  | 
| Alexander Graf | cefa33e | 2010-08-24 15:48:51 +0200 | [diff] [blame] | 448 | 	INIT_WORK(&hotplug_work, hotplug_devices); | 
 | 449 |  | 
| Heiko Carstens | df7997a | 2011-05-26 09:48:23 +0200 | [diff] [blame] | 450 | 	service_subclass_irq_register(); | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 451 | 	register_external_interrupt(0x2603, kvm_extint_handler); | 
 | 452 |  | 
 | 453 | 	scan_devices(); | 
 | 454 | 	return 0; | 
 | 455 | } | 
 | 456 |  | 
| Christian Borntraeger | faeba83 | 2008-06-20 15:24:18 +0200 | [diff] [blame] | 457 | /* code for early console output with virtio_console */ | 
 | 458 | static __init int early_put_chars(u32 vtermno, const char *buf, int count) | 
 | 459 | { | 
 | 460 | 	char scratch[17]; | 
 | 461 | 	unsigned int len = count; | 
 | 462 |  | 
 | 463 | 	if (len > sizeof(scratch) - 1) | 
 | 464 | 		len = sizeof(scratch) - 1; | 
 | 465 | 	scratch[len] = '\0'; | 
 | 466 | 	memcpy(scratch, buf, len); | 
 | 467 | 	kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch)); | 
 | 468 | 	return len; | 
 | 469 | } | 
 | 470 |  | 
| Hendrik Brueckner | c4de0c1 | 2009-09-11 10:28:56 +0200 | [diff] [blame] | 471 | static int __init s390_virtio_console_init(void) | 
| Christian Borntraeger | faeba83 | 2008-06-20 15:24:18 +0200 | [diff] [blame] | 472 | { | 
| Hendrik Brueckner | c4de0c1 | 2009-09-11 10:28:56 +0200 | [diff] [blame] | 473 | 	if (!MACHINE_IS_KVM) | 
 | 474 | 		return -ENODEV; | 
 | 475 | 	return virtio_cons_early_init(early_put_chars); | 
| Christian Borntraeger | faeba83 | 2008-06-20 15:24:18 +0200 | [diff] [blame] | 476 | } | 
| Hendrik Brueckner | c4de0c1 | 2009-09-11 10:28:56 +0200 | [diff] [blame] | 477 | console_initcall(s390_virtio_console_init); | 
 | 478 |  | 
| Christian Borntraeger | faeba83 | 2008-06-20 15:24:18 +0200 | [diff] [blame] | 479 |  | 
| Christian Borntraeger | e976a2b | 2008-03-25 18:47:46 +0100 | [diff] [blame] | 480 | /* | 
 | 481 |  * We do this after core stuff, but before the drivers. | 
 | 482 |  */ | 
 | 483 | postcore_initcall(kvm_devices_init); |