/* * This routine finds the first virtqueue described in the configuration of * this device and sets it up. */ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, unsigned index, void (*callback)(struct virtqueue *vq)) { struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_vqconfig *config; struct virtqueue *vq; int err; if (index >= kdev->desc->num_vq) return ERR_PTR(-ENOENT); config = kvm_vq_config(kdev->desc)+index; err = vmem_add_mapping(config->address, vring_size(config->num, KVM_S390_VIRTIO_RING_ALIGN)); if (err) goto out; vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, vdev, (void *) config->address, kvm_notify, callback); if (!vq) { err = -ENOMEM; goto unmap; } /* * register a callback token * The host will sent this via the external interrupt parameter */ config->token = (u64) vq; vq->priv = config; return vq; unmap: vmem_remove_mapping(config->address, vring_size(config->num, KVM_S390_VIRTIO_RING_ALIGN)); out: return ERR_PTR(err); }
static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], const char *names[]) { struct kvm_device *kdev = to_kvmdev(vdev); int i; /* We must have this many virtqueues. */ if (nvqs > kdev->desc->num_vq) return -ENOENT; for (i = 0; i < nvqs; ++i) { vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i]); if (IS_ERR(vqs[i])) goto error; } return 0; error: kvm_del_vqs(vdev); return PTR_ERR(vqs[i]); }
/* * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the * descriptor address. The Host will zero the status and all the * features. */ static void kvm_reset(struct virtio_device *vdev) { kvm_hypercall1(KVM_S390_VIRTIO_RESET, (unsigned long) to_kvmdev(vdev)->desc); }
/* * The operations to get and set the status word just access * the status field of the device descriptor. set_status will also * make a hypercall to the host, to tell about status changes */ static u8 kvm_get_status(struct virtio_device *vdev) { return to_kvmdev(vdev)->desc->status; }
/* * This routine finds the first virtqueue described in the configuration of * this device and sets it up. */ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, unsigned index, void (*callback)(struct virtqueue *vq), const char *name) { struct kvm_device *kdev = to_kvmdev(vdev); struct kvm_vqinfo *vqi; struct kvm_vqconfig *config; struct virtqueue *vq; long irq; int err = -EINVAL; if (index >= kdev->desc->num_vq) return ERR_PTR(-ENOENT); vqi = kzalloc(sizeof(*vqi), GFP_KERNEL); if (!vqi) return ERR_PTR(-ENOMEM); config = kvm_vq_config(kdev->desc)+index; vqi->config = config; vqi->pages = generic_remap_prot(config->pa, vring_size(config->num, KVM_TILE_VIRTIO_RING_ALIGN), 0, io_prot()); if (!vqi->pages) { err = -ENOMEM; goto out; } vq = vring_new_virtqueue(config->num, KVM_TILE_VIRTIO_RING_ALIGN, vdev, 0, vqi->pages, kvm_notify, callback, name); if (!vq) { err = -ENOMEM; goto unmap; } /* * Trigger the IPI interrupt in SW way. * TODO: We do not need to create one irq for each vq. A bit wasteful. */ irq = create_irq(); if (irq < 0) { err = -ENXIO; goto del_virtqueue; } tile_irq_activate(irq, TILE_IRQ_SW_CLEAR); if (request_irq(irq, vring_interrupt, 0, dev_name(&vdev->dev), vq)) { err = -ENXIO; destroy_irq(irq); goto del_virtqueue; } config->irq = irq; vq->priv = vqi; return vq; del_virtqueue: vring_del_virtqueue(vq); unmap: vunmap(vqi->pages); out: return ERR_PTR(err); }
/* * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the * descriptor address. The Host will zero the status and all the * features. */ static void kvm_reset(struct virtio_device *vdev) { hcall_virtio(KVM_VIRTIO_RESET, to_kvmdev(vdev)->desc_pa); }
static void kvm_set_status(struct virtio_device *vdev, u8 status) { BUG_ON(!status); to_kvmdev(vdev)->desc->status = status; hcall_virtio(KVM_VIRTIO_SET_STATUS, to_kvmdev(vdev)->desc_pa); }