Example #1
0
/*
 * removes a virtio device if a hot remove event has been
 * requested by the host.
 */
static int _vop_remove_device(struct mic_device_desc __iomem *d,
                              unsigned int offset, struct vop_device *vpdev)
{
    struct mic_device_ctrl __iomem *dc
        = (void __iomem *)d + _vop_aligned_desc_size(d);
    struct _vop_vdev *vdev = (struct _vop_vdev *)readq(&dc->vdev);
    u8 status;
    int ret = -1;

    if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) {
        dev_dbg(&vpdev->dev,
                "%s %d config_change %d type %d vdev %p\n",
                __func__, __LINE__,
                ioread8(&dc->config_change), ioread8(&d->type), vdev);
        status = ioread8(&d->status);
        reinit_completion(&vdev->reset_done);
        unregister_virtio_device(&vdev->vdev);
        vpdev->hw_ops->free_irq(vpdev, vdev->virtio_cookie, vdev);
        iowrite8(-1, &dc->h2c_vdev_db);
        if (status & VIRTIO_CONFIG_S_DRIVER_OK)
            wait_for_completion(&vdev->reset_done);
        kfree(vdev);
        iowrite8(1, &dc->guest_ack);
        dev_dbg(&vpdev->dev, "%s %d guest_ack %d\n",
                __func__, __LINE__, ioread8(&dc->guest_ack));
        iowrite8(-1, &d->type);
        ret = 0;
    }
    return ret;
}
Example #2
0
/*
 * adds a new device and register it with virtio
 * appropriate drivers are loaded by the device model
 */
static int _vop_add_device(struct mic_device_desc __iomem *d,
			   unsigned int offset, struct vop_device *vpdev,
			   int dnode)
{
	struct _vop_vdev *vdev, *reg_dev = NULL;
	int ret;
	u8 type = ioread8(&d->type);

	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
	if (!vdev)
		return -ENOMEM;

	vdev->vpdev = vpdev;
	vdev->vdev.dev.parent = &vpdev->dev;
	vdev->vdev.dev.release = vop_virtio_release_dev;
	vdev->vdev.id.device = type;
	vdev->vdev.config = &vop_vq_config_ops;
	vdev->desc = d;
	vdev->dc = (void __iomem *)d + _vop_aligned_desc_size(d);
	vdev->dnode = dnode;
	vdev->vdev.priv = (void *)(unsigned long)dnode;
	init_completion(&vdev->reset_done);

	vdev->h2c_vdev_db = vpdev->hw_ops->next_db(vpdev);
	vdev->virtio_cookie = vpdev->hw_ops->request_irq(vpdev,
			vop_virtio_intr_handler, "virtio intr",
			vdev, vdev->h2c_vdev_db);
	if (IS_ERR(vdev->virtio_cookie)) {
		ret = PTR_ERR(vdev->virtio_cookie);
		goto kfree;
	}
	iowrite8((u8)vdev->h2c_vdev_db, &vdev->dc->h2c_vdev_db);
	vdev->c2h_vdev_db = ioread8(&vdev->dc->c2h_vdev_db);

	ret = register_virtio_device(&vdev->vdev);
	reg_dev = vdev;
	if (ret) {
		dev_err(_vop_dev(vdev),
			"Failed to register vop device %u type %u\n",
			offset, type);
		goto free_irq;
	}
	writeq((unsigned long)vdev, &vdev->dc->vdev);
	dev_dbg(_vop_dev(vdev), "%s: registered vop device %u type %u vdev %p\n",
		__func__, offset, type, vdev);

	return 0;

free_irq:
	vpdev->hw_ops->free_irq(vpdev, vdev->virtio_cookie, vdev);
kfree:
	if (reg_dev)
		put_device(&vdev->vdev.dev);
	else
		kfree(vdev);
	return ret;
}
Example #3
0
static void _vop_scan_devices(void __iomem *dp, struct vop_device *vpdev,
                              bool remove, int dnode)
{
    s8 type;
    unsigned int i;
    struct mic_device_desc __iomem *d;
    struct mic_device_ctrl __iomem *dc;
    struct device *dev;
    int ret;

    for (i = sizeof(struct mic_bootparam);
            i < MIC_DP_SIZE; i += _vop_total_desc_size(d)) {
        d = dp + i;
        dc = (void __iomem *)d + _vop_aligned_desc_size(d);
        /*
         * This read barrier is paired with the corresponding write
         * barrier on the host which is inserted before adding or
         * removing a virtio device descriptor, by updating the type.
         */
        rmb();
        type = ioread8(&d->type);

        /* end of list */
        if (type == 0)
            break;

        if (type == -1)
            continue;

        /* device already exists */
        dev = device_find_child(&vpdev->dev, (void __force *)d,
                                vop_match_desc);
        if (dev) {
            if (remove)
                iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE,
                         &dc->config_change);
            put_device(dev);
            _vop_handle_config_change(d, i, vpdev);
            ret = _vop_remove_device(d, i, vpdev);
            if (remove) {
                iowrite8(0, &dc->config_change);
                iowrite8(0, &dc->guest_ack);
            }
            continue;
        }

        /* new device */
        dev_dbg(&vpdev->dev, "%s %d Adding new virtio device %p\n",
                __func__, __LINE__, d);
        if (!remove)
            _vop_add_device(d, i, vpdev, dnode);
    }
}
Example #4
0
static void _vop_handle_config_change(struct mic_device_desc __iomem *d,
                                      unsigned int offset,
                                      struct vop_device *vpdev)
{
    struct mic_device_ctrl __iomem *dc
        = (void __iomem *)d + _vop_aligned_desc_size(d);
    struct _vop_vdev *vdev = (struct _vop_vdev *)readq(&dc->vdev);

    if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED)
        return;

    dev_dbg(&vpdev->dev, "%s %d\n", __func__, __LINE__);
    virtio_config_changed(&vdev->vdev);
    iowrite8(1, &dc->guest_ack);
}
Example #5
0
static inline unsigned
_vop_total_desc_size(struct mic_device_desc __iomem *desc)
{
    return _vop_aligned_desc_size(desc) + sizeof(struct mic_device_ctrl);
}