diff options
Diffstat (limited to 'arch/um/drivers/virtio_uml.c')
| -rw-r--r-- | arch/um/drivers/virtio_uml.c | 54 | 
1 files changed, 51 insertions, 3 deletions
| diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index d51e445df797..ba562d68dc04 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -21,6 +21,7 @@   * Based on Virtio MMIO driver by Pawel Moll, copyright 2011-2014, ARM Ltd.   */  #include <linux/module.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/virtio.h> @@ -49,6 +50,7 @@ struct virtio_uml_platform_data {  struct virtio_uml_device {  	struct virtio_device vdev;  	struct platform_device *pdev; +	struct virtio_uml_platform_data *pdata;  	spinlock_t sock_lock;  	int sock, req_fd, irq; @@ -149,7 +151,7 @@ static int vhost_user_recv(struct virtio_uml_device *vu_dev,  	if (rc == -ECONNRESET && vu_dev->registered) {  		struct virtio_uml_platform_data *pdata; -		pdata = vu_dev->pdev->dev.platform_data; +		pdata = vu_dev->pdata;  		virtio_break_device(&vu_dev->vdev);  		schedule_work(&pdata->conn_broken_wk); @@ -1090,6 +1092,8 @@ static void virtio_uml_release_dev(struct device *d)  			container_of(d, struct virtio_device, dev);  	struct virtio_uml_device *vu_dev = to_virtio_uml_device(vdev); +	time_travel_propagate_time(); +  	/* might not have been opened due to not negotiating the feature */  	if (vu_dev->req_fd >= 0) {  		um_free_irq(vu_dev->irq, vu_dev); @@ -1113,21 +1117,63 @@ void virtio_uml_set_no_vq_suspend(struct virtio_device *vdev,  		 no_vq_suspend ? "dis" : "en");  } +static void vu_of_conn_broken(struct work_struct *wk) +{ +	/* +	 * We can't remove the device from the devicetree so the only thing we +	 * can do is warn. +	 */ +	WARN_ON(1); +} +  /* Platform device */ +static struct virtio_uml_platform_data * +virtio_uml_create_pdata(struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct virtio_uml_platform_data *pdata; +	int ret; + +	if (!np) +		return ERR_PTR(-EINVAL); + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return ERR_PTR(-ENOMEM); + +	INIT_WORK(&pdata->conn_broken_wk, vu_of_conn_broken); +	pdata->pdev = pdev; + +	ret = of_property_read_string(np, "socket-path", &pdata->socket_path); +	if (ret) +		return ERR_PTR(ret); + +	ret = of_property_read_u32(np, "virtio-device-id", +				   &pdata->virtio_device_id); +	if (ret) +		return ERR_PTR(ret); + +	return pdata; +} +  static int virtio_uml_probe(struct platform_device *pdev)  {  	struct virtio_uml_platform_data *pdata = pdev->dev.platform_data;  	struct virtio_uml_device *vu_dev;  	int rc; -	if (!pdata) -		return -EINVAL; +	if (!pdata) { +		pdata = virtio_uml_create_pdata(pdev); +		if (IS_ERR(pdata)) +			return PTR_ERR(pdata); +	}  	vu_dev = kzalloc(sizeof(*vu_dev), GFP_KERNEL);  	if (!vu_dev)  		return -ENOMEM; +	vu_dev->pdata = pdata;  	vu_dev->vdev.dev.parent = &pdev->dev;  	vu_dev->vdev.dev.release = virtio_uml_release_dev;  	vu_dev->vdev.config = &virtio_uml_config_ops; @@ -1136,6 +1182,8 @@ static int virtio_uml_probe(struct platform_device *pdev)  	vu_dev->pdev = pdev;  	vu_dev->req_fd = -1; +	time_travel_propagate_time(); +  	do {  		rc = os_connect_socket(pdata->socket_path);  	} while (rc == -EINTR); |