Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.27-rc5 363 lines 8.7 kB view raw
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/virtio_console.h> 19#include <linux/interrupt.h> 20#include <linux/virtio_ring.h> 21#include <linux/pfn.h> 22#include <asm/io.h> 23#include <asm/kvm_para.h> 24#include <asm/kvm_virtio.h> 25#include <asm/setup.h> 26#include <asm/s390_ext.h> 27 28#define VIRTIO_SUBCODE_64 0x0D00 29 30/* 31 * The pointer to our (page) of device descriptions. 32 */ 33static void *kvm_devices; 34 35struct kvm_device { 36 struct virtio_device vdev; 37 struct kvm_device_desc *desc; 38}; 39 40#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev) 41 42/* 43 * memory layout: 44 * - kvm_device_descriptor 45 * struct kvm_device_desc 46 * - configuration 47 * struct kvm_vqconfig 48 * - feature bits 49 * - config space 50 */ 51static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc) 52{ 53 return (struct kvm_vqconfig *)(desc + 1); 54} 55 56static u8 *kvm_vq_features(const struct kvm_device_desc *desc) 57{ 58 return (u8 *)(kvm_vq_config(desc) + desc->num_vq); 59} 60 61static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc) 62{ 63 return kvm_vq_features(desc) + desc->feature_len * 2; 64} 65 66/* 67 * The total size of the config page used by this device (incl. desc) 68 */ 69static unsigned desc_size(const struct kvm_device_desc *desc) 70{ 71 return sizeof(*desc) 72 + desc->num_vq * sizeof(struct kvm_vqconfig) 73 + desc->feature_len * 2 74 + desc->config_len; 75} 76 77/* This gets the device's feature bits. */ 78static u32 kvm_get_features(struct virtio_device *vdev) 79{ 80 unsigned int i; 81 u32 features = 0; 82 struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; 83 u8 *in_features = kvm_vq_features(desc); 84 85 for (i = 0; i < min(desc->feature_len * 8, 32); i++) 86 if (in_features[i / 8] & (1 << (i % 8))) 87 features |= (1 << i); 88 return features; 89} 90 91static void kvm_finalize_features(struct virtio_device *vdev) 92{ 93 unsigned int i, bits; 94 struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; 95 /* Second half of bitmap is features we accept. */ 96 u8 *out_features = kvm_vq_features(desc) + desc->feature_len; 97 98 /* Give virtio_ring a chance to accept features. */ 99 vring_transport_features(vdev); 100 101 memset(out_features, 0, desc->feature_len); 102 bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8; 103 for (i = 0; i < bits; i++) { 104 if (test_bit(i, vdev->features)) 105 out_features[i / 8] |= (1 << (i % 8)); 106 } 107} 108 109/* 110 * Reading and writing elements in config space 111 */ 112static void kvm_get(struct virtio_device *vdev, unsigned int offset, 113 void *buf, unsigned len) 114{ 115 struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; 116 117 BUG_ON(offset + len > desc->config_len); 118 memcpy(buf, kvm_vq_configspace(desc) + offset, len); 119} 120 121static void kvm_set(struct virtio_device *vdev, unsigned int offset, 122 const void *buf, unsigned len) 123{ 124 struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; 125 126 BUG_ON(offset + len > desc->config_len); 127 memcpy(kvm_vq_configspace(desc) + offset, buf, len); 128} 129 130/* 131 * The operations to get and set the status word just access 132 * the status field of the device descriptor. set_status will also 133 * make a hypercall to the host, to tell about status changes 134 */ 135static u8 kvm_get_status(struct virtio_device *vdev) 136{ 137 return to_kvmdev(vdev)->desc->status; 138} 139 140static void kvm_set_status(struct virtio_device *vdev, u8 status) 141{ 142 BUG_ON(!status); 143 to_kvmdev(vdev)->desc->status = status; 144 kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS, 145 (unsigned long) to_kvmdev(vdev)->desc); 146} 147 148/* 149 * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the 150 * descriptor address. The Host will zero the status and all the 151 * features. 152 */ 153static void kvm_reset(struct virtio_device *vdev) 154{ 155 kvm_hypercall1(KVM_S390_VIRTIO_RESET, 156 (unsigned long) to_kvmdev(vdev)->desc); 157} 158 159/* 160 * When the virtio_ring code wants to notify the Host, it calls us here and we 161 * make a hypercall. We hand the address of the virtqueue so the Host 162 * knows which virtqueue we're talking about. 163 */ 164static void kvm_notify(struct virtqueue *vq) 165{ 166 struct kvm_vqconfig *config = vq->priv; 167 168 kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); 169} 170 171/* 172 * This routine finds the first virtqueue described in the configuration of 173 * this device and sets it up. 174 */ 175static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, 176 unsigned index, 177 void (*callback)(struct virtqueue *vq)) 178{ 179 struct kvm_device *kdev = to_kvmdev(vdev); 180 struct kvm_vqconfig *config; 181 struct virtqueue *vq; 182 int err; 183 184 if (index >= kdev->desc->num_vq) 185 return ERR_PTR(-ENOENT); 186 187 config = kvm_vq_config(kdev->desc)+index; 188 189 err = vmem_add_mapping(config->address, 190 vring_size(config->num, PAGE_SIZE)); 191 if (err) 192 goto out; 193 194 vq = vring_new_virtqueue(config->num, vdev, (void *) config->address, 195 kvm_notify, callback); 196 if (!vq) { 197 err = -ENOMEM; 198 goto unmap; 199 } 200 201 /* 202 * register a callback token 203 * The host will sent this via the external interrupt parameter 204 */ 205 config->token = (u64) vq; 206 207 vq->priv = config; 208 return vq; 209unmap: 210 vmem_remove_mapping(config->address, 211 vring_size(config->num, PAGE_SIZE)); 212out: 213 return ERR_PTR(err); 214} 215 216static void kvm_del_vq(struct virtqueue *vq) 217{ 218 struct kvm_vqconfig *config = vq->priv; 219 220 vring_del_virtqueue(vq); 221 vmem_remove_mapping(config->address, 222 vring_size(config->num, PAGE_SIZE)); 223} 224 225/* 226 * The config ops structure as defined by virtio config 227 */ 228static struct virtio_config_ops kvm_vq_configspace_ops = { 229 .get_features = kvm_get_features, 230 .finalize_features = kvm_finalize_features, 231 .get = kvm_get, 232 .set = kvm_set, 233 .get_status = kvm_get_status, 234 .set_status = kvm_set_status, 235 .reset = kvm_reset, 236 .find_vq = kvm_find_vq, 237 .del_vq = kvm_del_vq, 238}; 239 240/* 241 * The root device for the kvm virtio devices. 242 * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. 243 */ 244static struct device kvm_root = { 245 .parent = NULL, 246 .bus_id = "kvm_s390", 247}; 248 249/* 250 * adds a new device and register it with virtio 251 * appropriate drivers are loaded by the device model 252 */ 253static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset) 254{ 255 struct kvm_device *kdev; 256 257 kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); 258 if (!kdev) { 259 printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n", 260 offset, d->type); 261 return; 262 } 263 264 kdev->vdev.dev.parent = &kvm_root; 265 kdev->vdev.id.device = d->type; 266 kdev->vdev.config = &kvm_vq_configspace_ops; 267 kdev->desc = d; 268 269 if (register_virtio_device(&kdev->vdev) != 0) { 270 printk(KERN_ERR "Failed to register kvm device %u type %u\n", 271 offset, d->type); 272 kfree(kdev); 273 } 274} 275 276/* 277 * scan_devices() simply iterates through the device page. 278 * The type 0 is reserved to mean "end of devices". 279 */ 280static void scan_devices(void) 281{ 282 unsigned int i; 283 struct kvm_device_desc *d; 284 285 for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { 286 d = kvm_devices + i; 287 288 if (d->type == 0) 289 break; 290 291 add_kvm_device(d, i); 292 } 293} 294 295/* 296 * we emulate the request_irq behaviour on top of s390 extints 297 */ 298static void kvm_extint_handler(u16 code) 299{ 300 void *data = (void *) *(long *) __LC_PFAULT_INTPARM; 301 u16 subcode = S390_lowcore.cpu_addr; 302 303 if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) 304 return; 305 306 vring_interrupt(0, data); 307} 308 309/* 310 * Init function for virtio 311 * devices are in a single page above top of "normal" mem 312 */ 313static int __init kvm_devices_init(void) 314{ 315 int rc; 316 317 if (!MACHINE_IS_KVM) 318 return -ENODEV; 319 320 rc = device_register(&kvm_root); 321 if (rc) { 322 printk(KERN_ERR "Could not register kvm_s390 root device"); 323 return rc; 324 } 325 326 rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE); 327 if (rc) { 328 device_unregister(&kvm_root); 329 return rc; 330 } 331 332 kvm_devices = (void *) PFN_PHYS(max_pfn); 333 334 ctl_set_bit(0, 9); 335 register_external_interrupt(0x2603, kvm_extint_handler); 336 337 scan_devices(); 338 return 0; 339} 340 341/* code for early console output with virtio_console */ 342static __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 355void __init s390_virtio_console_init(void) 356{ 357 virtio_cons_early_init(early_put_chars); 358} 359 360/* 361 * We do this after core stuff, but before the drivers. 362 */ 363postcore_initcall(kvm_devices_init);