diff options
| author | Paul Durrant <Paul.Durrant@citrix.com> | 2016-05-13 11:37:26 +0300 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-05-16 20:35:56 +0300 | 
| commit | 4e15ee2cb46fed730fe6f0195a86d44e5aeef129 (patch) | |
| tree | 852b76177b94ed322cc38f54bcce7cc052abea65 /drivers/net/xen-netback/interface.c | |
| parent | 1ca467343240be738c8e61edd4b421ca9ebe2d77 (diff) | |
| download | linux-4e15ee2cb46fed730fe6f0195a86d44e5aeef129.tar.xz | |
xen-netback: add control ring boilerplate
My recent patch to include/xen/interface/io/netif.h defines a new shared
ring (in addition to the rx and tx rings) for passing control messages
from a VM frontend driver to a backend driver.
This patch adds the necessary code to xen-netback to map this new shared
ring, should it be created by a frontend, but does not add implementations
for any of the defined protocol messages. These are added in a subsequent
patch for clarity.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback/interface.c')
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 101 | 
1 files changed, 94 insertions, 7 deletions
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index f5231a2dd2ac..78a10d2af101 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -128,6 +128,15 @@ irqreturn_t xenvif_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } +irqreturn_t xenvif_ctrl_interrupt(int irq, void *dev_id) +{ +	struct xenvif *vif = dev_id; + +	wake_up(&vif->ctrl_wq); + +	return IRQ_HANDLED; +} +  int xenvif_queue_stopped(struct xenvif_queue *queue)  {  	struct net_device *dev = queue->vif->dev; @@ -527,9 +536,66 @@ void xenvif_carrier_on(struct xenvif *vif)  	rtnl_unlock();  } -int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref, -		   unsigned long rx_ring_ref, unsigned int tx_evtchn, -		   unsigned int rx_evtchn) +int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref, +			unsigned int evtchn) +{ +	struct net_device *dev = vif->dev; +	void *addr; +	struct xen_netif_ctrl_sring *shared; +	struct task_struct *task; +	int err = -ENOMEM; + +	err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), +				     &ring_ref, 1, &addr); +	if (err) +		goto err; + +	shared = (struct xen_netif_ctrl_sring *)addr; +	BACK_RING_INIT(&vif->ctrl, shared, XEN_PAGE_SIZE); + +	init_waitqueue_head(&vif->ctrl_wq); + +	err = bind_interdomain_evtchn_to_irqhandler(vif->domid, evtchn, +						    xenvif_ctrl_interrupt, +						    0, dev->name, vif); +	if (err < 0) +		goto err_unmap; + +	vif->ctrl_irq = err; + +	task = kthread_create(xenvif_ctrl_kthread, (void *)vif, +			      "%s-control", dev->name); +	if (IS_ERR(task)) { +		pr_warn("Could not allocate kthread for %s\n", dev->name); +		err = PTR_ERR(task); +		goto err_deinit; +	} + +	get_task_struct(task); +	vif->ctrl_task = task; + +	wake_up_process(vif->ctrl_task); + +	return 0; + +err_deinit: +	unbind_from_irqhandler(vif->ctrl_irq, vif); +	vif->ctrl_irq = 0; + +err_unmap: +	xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif), +				vif->ctrl.sring); +	vif->ctrl.sring = NULL; + +err: +	return err; +} + +int xenvif_connect_data(struct xenvif_queue *queue, +			unsigned long tx_ring_ref, +			unsigned long rx_ring_ref, +			unsigned int tx_evtchn, +			unsigned int rx_evtchn)  {  	struct task_struct *task;  	int err = -ENOMEM; @@ -538,7 +604,8 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,  	BUG_ON(queue->task);  	BUG_ON(queue->dealloc_task); -	err = xenvif_map_frontend_rings(queue, tx_ring_ref, rx_ring_ref); +	err = xenvif_map_frontend_data_rings(queue, tx_ring_ref, +					     rx_ring_ref);  	if (err < 0)  		goto err; @@ -614,7 +681,7 @@ err_tx_unbind:  	unbind_from_irqhandler(queue->tx_irq, queue);  	queue->tx_irq = 0;  err_unmap: -	xenvif_unmap_frontend_rings(queue); +	xenvif_unmap_frontend_data_rings(queue);  	netif_napi_del(&queue->napi);  err:  	module_put(THIS_MODULE); @@ -634,7 +701,7 @@ void xenvif_carrier_off(struct xenvif *vif)  	rtnl_unlock();  } -void xenvif_disconnect(struct xenvif *vif) +void xenvif_disconnect_data(struct xenvif *vif)  {  	struct xenvif_queue *queue = NULL;  	unsigned int num_queues = vif->num_queues; @@ -668,12 +735,32 @@ void xenvif_disconnect(struct xenvif *vif)  			queue->tx_irq = 0;  		} -		xenvif_unmap_frontend_rings(queue); +		xenvif_unmap_frontend_data_rings(queue);  	}  	xenvif_mcast_addr_list_free(vif);  } +void xenvif_disconnect_ctrl(struct xenvif *vif) +{ +	if (vif->ctrl_task) { +		kthread_stop(vif->ctrl_task); +		put_task_struct(vif->ctrl_task); +		vif->ctrl_task = NULL; +	} + +	if (vif->ctrl_irq) { +		unbind_from_irqhandler(vif->ctrl_irq, vif); +		vif->ctrl_irq = 0; +	} + +	if (vif->ctrl.sring) { +		xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(vif), +					vif->ctrl.sring); +		vif->ctrl.sring = NULL; +	} +} +  /* Reverse the relevant parts of xenvif_init_queue().   * Used for queue teardown from xenvif_free(), and on the   * error handling paths in xenbus.c:connect().  | 
