/* Notify all virtqueues on an interrupt. */ static irqreturn_t vm_interrupt(int irq, void *opaque) { struct virtio_mmio_device *vm_dev = opaque; struct virtio_mmio_vq_info *info; struct virtio_driver *vdrv = container_of(vm_dev->vdev.dev.driver, struct virtio_driver, driver); unsigned long status; unsigned long flags; irqreturn_t ret = IRQ_NONE; /* Read and acknowledge interrupts */ status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); if (unlikely(status & VIRTIO_MMIO_INT_CONFIG) && vdrv && vdrv->config_changed) { vdrv->config_changed(&vm_dev->vdev); ret = IRQ_HANDLED; } if (likely(status & VIRTIO_MMIO_INT_VRING)) { spin_lock_irqsave(&vm_dev->lock, flags); list_for_each_entry(info, &vm_dev->virtqueues, node) ret |= vring_interrupt(irq, info->vq); spin_unlock_irqrestore(&vm_dev->lock, flags); } return ret; }
static irqreturn_t mic_virtio_intr_handler(int irq, void *data) { struct mic_vdev *mvdev = data; struct virtqueue *vq; mic_ack_interrupt(mvdev->mdev); list_for_each_entry(vq, &mvdev->vdev.vqs, list) vring_interrupt(0, vq); return IRQ_HANDLED; }
static irqreturn_t vop_virtio_intr_handler(int irq, void *data) { struct _vop_vdev *vdev = data; struct vop_device *vpdev = vdev->vpdev; struct virtqueue *vq; vpdev->hw_ops->ack_interrupt(vpdev, vdev->h2c_vdev_db); list_for_each_entry(vq, &vdev->vdev.vqs, list) vring_interrupt(0, vq); return IRQ_HANDLED; }
static void handle_event(struct work_struct *work) { struct virtqueue *vq; flush_cache_all(); outer_flush_range(zynq_rpmsg_p->mem_start, zynq_rpmsg_p->mem_end); vq = zynq_rpmsg_p->vrings[0].vq; if (vring_interrupt(0, vq) == IRQ_NONE) dev_dbg(&zynq_rpmsg_platform->dev, "no message found in vqid 0\n"); }
/* * we emulate the request_irq behaviour on top of s390 extints */ static void kvm_extint_handler(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct virtqueue *vq; u32 param; if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) return; kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(param64 & ~1UL); /* We use ext_params to decide what this interrupt means */ param = param32 & VIRTIO_PARAM_MASK; switch (param) { case VIRTIO_PARAM_CONFIG_CHANGED: { struct virtio_driver *drv; drv = container_of(vq->vdev->dev.driver, struct virtio_driver, driver); if (drv->config_changed) drv->config_changed(vq->vdev); break; } case VIRTIO_PARAM_DEV_ADD: schedule_work(&hotplug_work); break; case VIRTIO_PARAM_VRING_INTERRUPT: default: vring_interrupt(0, vq); break; } }