Skip to content

Commit

Permalink
xen-netback: add control ring boilerplate
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paul Durrant authored and David S. Miller committed May 16, 2016
1 parent 1ca4673 commit 4e15ee2
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 30 deletions.
28 changes: 20 additions & 8 deletions drivers/net/xen-netback/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ struct xenvif {
struct dentry *xenvif_dbg_root;
#endif

struct xen_netif_ctrl_back_ring ctrl;
struct task_struct *ctrl_task;
wait_queue_head_t ctrl_wq;
unsigned int ctrl_irq;

/* Miscellaneous private stuff. */
struct net_device *dev;
};
Expand All @@ -285,10 +290,15 @@ struct xenvif *xenvif_alloc(struct device *parent,
int xenvif_init_queue(struct xenvif_queue *queue);
void xenvif_deinit_queue(struct xenvif_queue *queue);

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);
void xenvif_disconnect(struct xenvif *vif);
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);
void xenvif_disconnect_data(struct xenvif *vif);
int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,
unsigned int evtchn);
void xenvif_disconnect_ctrl(struct xenvif *vif);
void xenvif_free(struct xenvif *vif);

int xenvif_xenbus_init(void);
Expand All @@ -300,10 +310,10 @@ int xenvif_queue_stopped(struct xenvif_queue *queue);
void xenvif_wake_queue(struct xenvif_queue *queue);

/* (Un)Map communication rings. */
void xenvif_unmap_frontend_rings(struct xenvif_queue *queue);
int xenvif_map_frontend_rings(struct xenvif_queue *queue,
grant_ref_t tx_ring_ref,
grant_ref_t rx_ring_ref);
void xenvif_unmap_frontend_data_rings(struct xenvif_queue *queue);
int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
grant_ref_t tx_ring_ref,
grant_ref_t rx_ring_ref);

/* Check for SKBs from frontend and schedule backend processing */
void xenvif_napi_schedule_or_enable_events(struct xenvif_queue *queue);
Expand All @@ -318,6 +328,8 @@ void xenvif_kick_thread(struct xenvif_queue *queue);

int xenvif_dealloc_kthread(void *data);

int xenvif_ctrl_kthread(void *data);

void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);

void xenvif_carrier_on(struct xenvif *vif);
Expand Down
101 changes: 94 additions & 7 deletions drivers/net/xen-netback/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -614,7 +681,7 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
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);
Expand All @@ -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;
Expand Down Expand Up @@ -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().
Expand Down
99 changes: 94 additions & 5 deletions drivers/net/xen-netback/netback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1926,7 +1926,7 @@ static inline bool tx_dealloc_work_todo(struct xenvif_queue *queue)
return queue->dealloc_cons != queue->dealloc_prod;
}

void xenvif_unmap_frontend_rings(struct xenvif_queue *queue)
void xenvif_unmap_frontend_data_rings(struct xenvif_queue *queue)
{
if (queue->tx.sring)
xenbus_unmap_ring_vfree(xenvif_to_xenbus_device(queue->vif),
Expand All @@ -1936,9 +1936,9 @@ void xenvif_unmap_frontend_rings(struct xenvif_queue *queue)
queue->rx.sring);
}

int xenvif_map_frontend_rings(struct xenvif_queue *queue,
grant_ref_t tx_ring_ref,
grant_ref_t rx_ring_ref)
int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
grant_ref_t tx_ring_ref,
grant_ref_t rx_ring_ref)
{
void *addr;
struct xen_netif_tx_sring *txs;
Expand All @@ -1965,7 +1965,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue,
return 0;

err:
xenvif_unmap_frontend_rings(queue);
xenvif_unmap_frontend_data_rings(queue);
return err;
}

Expand Down Expand Up @@ -2164,6 +2164,95 @@ int xenvif_dealloc_kthread(void *data)
return 0;
}

static void make_ctrl_response(struct xenvif *vif,
const struct xen_netif_ctrl_request *req,
u32 status, u32 data)
{
RING_IDX idx = vif->ctrl.rsp_prod_pvt;
struct xen_netif_ctrl_response rsp = {
.id = req->id,
.type = req->type,
.status = status,
.data = data,
};

*RING_GET_RESPONSE(&vif->ctrl, idx) = rsp;
vif->ctrl.rsp_prod_pvt = ++idx;
}

static void push_ctrl_response(struct xenvif *vif)
{
int notify;

RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->ctrl, notify);
if (notify)
notify_remote_via_irq(vif->ctrl_irq);
}

static void process_ctrl_request(struct xenvif *vif,
const struct xen_netif_ctrl_request *req)
{
make_ctrl_response(vif, req, XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED,
0);
push_ctrl_response(vif);
}

static void xenvif_ctrl_action(struct xenvif *vif)
{
for (;;) {
RING_IDX req_prod, req_cons;

req_prod = vif->ctrl.sring->req_prod;
req_cons = vif->ctrl.req_cons;

/* Make sure we can see requests before we process them. */
rmb();

if (req_cons == req_prod)
break;

while (req_cons != req_prod) {
struct xen_netif_ctrl_request req;

RING_COPY_REQUEST(&vif->ctrl, req_cons, &req);
req_cons++;

process_ctrl_request(vif, &req);
}

vif->ctrl.req_cons = req_cons;
vif->ctrl.sring->req_event = req_cons + 1;
}
}

static bool xenvif_ctrl_work_todo(struct xenvif *vif)
{
if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->ctrl)))
return 1;

return 0;
}

int xenvif_ctrl_kthread(void *data)
{
struct xenvif *vif = data;

for (;;) {
wait_event_interruptible(vif->ctrl_wq,
xenvif_ctrl_work_todo(vif) ||
kthread_should_stop());
if (kthread_should_stop())
break;

while (xenvif_ctrl_work_todo(vif))
xenvif_ctrl_action(vif);

cond_resched();
}

return 0;
}

static int __init netback_init(void)
{
int rc = 0;
Expand Down
Loading

0 comments on commit 4e15ee2

Please sign in to comment.