xen-netback: create a debugfs node for hash information
[cascardo/linux.git] / drivers / net / xen-netback / xenbus.c
index bd182cd..bacf6e0 100644 (file)
@@ -38,7 +38,8 @@ struct backend_info {
        const char *hotplug_script;
 };
 
-static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
+static int connect_data_rings(struct backend_info *be,
+                             struct xenvif_queue *queue);
 static void connect(struct backend_info *be);
 static int read_xenbus_vif_flags(struct backend_info *be);
 static int backend_create_xenvif(struct backend_info *be);
@@ -164,7 +165,7 @@ xenvif_write_io_ring(struct file *filp, const char __user *buf, size_t count,
        return count;
 }
 
-static int xenvif_dump_open(struct inode *inode, struct file *filp)
+static int xenvif_io_ring_open(struct inode *inode, struct file *filp)
 {
        int ret;
        void *queue = NULL;
@@ -178,13 +179,35 @@ static int xenvif_dump_open(struct inode *inode, struct file *filp)
 
 static const struct file_operations xenvif_dbg_io_ring_ops_fops = {
        .owner = THIS_MODULE,
-       .open = xenvif_dump_open,
+       .open = xenvif_io_ring_open,
        .read = seq_read,
        .llseek = seq_lseek,
        .release = single_release,
        .write = xenvif_write_io_ring,
 };
 
+static int xenvif_read_ctrl(struct seq_file *m, void *v)
+{
+       struct xenvif *vif = m->private;
+
+       xenvif_dump_hash_info(vif, m);
+
+       return 0;
+}
+
+static int xenvif_ctrl_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, xenvif_read_ctrl, inode->i_private);
+}
+
+static const struct file_operations xenvif_dbg_ctrl_ops_fops = {
+       .owner = THIS_MODULE,
+       .open = xenvif_ctrl_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
 static void xenvif_debugfs_addif(struct xenvif *vif)
 {
        struct dentry *pfile;
@@ -209,6 +232,17 @@ static void xenvif_debugfs_addif(struct xenvif *vif)
                                pr_warn("Creation of io_ring file returned %ld!\n",
                                        PTR_ERR(pfile));
                }
+
+               if (vif->ctrl_task) {
+                       pfile = debugfs_create_file("ctrl",
+                                                   S_IRUSR,
+                                                   vif->xenvif_dbg_root,
+                                                   vif,
+                                                   &xenvif_dbg_ctrl_ops_fops);
+                       if (IS_ERR_OR_NULL(pfile))
+                               pr_warn("Creation of ctrl file returned %ld!\n",
+                                       PTR_ERR(pfile));
+               }
        } else
                netdev_warn(vif->dev,
                            "Creation of vif debugfs dir returned %ld!\n",
@@ -367,6 +401,12 @@ static int netback_probe(struct xenbus_device *dev,
        if (err)
                pr_debug("Error writing multi-queue-max-queues\n");
 
+       err = xenbus_printf(XBT_NIL, dev->nodename,
+                           "feature-ctrl-ring",
+                           "%u", true);
+       if (err)
+               pr_debug("Error writing feature-ctrl-ring\n");
+
        script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
        if (IS_ERR(script)) {
                err = PTR_ERR(script);
@@ -457,7 +497,8 @@ static void backend_disconnect(struct backend_info *be)
 #ifdef CONFIG_DEBUG_FS
                xenvif_debugfs_delif(be->vif);
 #endif /* CONFIG_DEBUG_FS */
-               xenvif_disconnect(be->vif);
+               xenvif_disconnect_data(be->vif);
+               xenvif_disconnect_ctrl(be->vif);
        }
 }
 
@@ -825,6 +866,48 @@ static void hotplug_status_changed(struct xenbus_watch *watch,
        kfree(str);
 }
 
+static int connect_ctrl_ring(struct backend_info *be)
+{
+       struct xenbus_device *dev = be->dev;
+       struct xenvif *vif = be->vif;
+       unsigned int val;
+       grant_ref_t ring_ref;
+       unsigned int evtchn;
+       int err;
+
+       err = xenbus_gather(XBT_NIL, dev->otherend,
+                           "ctrl-ring-ref", "%u", &val, NULL);
+       if (err)
+               goto done; /* The frontend does not have a control ring */
+
+       ring_ref = val;
+
+       err = xenbus_gather(XBT_NIL, dev->otherend,
+                           "event-channel-ctrl", "%u", &val, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "reading %s/event-channel-ctrl",
+                                dev->otherend);
+               goto fail;
+       }
+
+       evtchn = val;
+
+       err = xenvif_connect_ctrl(vif, ring_ref, evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "mapping shared-frame %u port %u",
+                                ring_ref, evtchn);
+               goto fail;
+       }
+
+done:
+       return 0;
+
+fail:
+       return err;
+}
+
 static void connect(struct backend_info *be)
 {
        int err;
@@ -861,6 +944,12 @@ static void connect(struct backend_info *be)
        xen_register_watchers(dev, be->vif);
        read_xenbus_vif_flags(be);
 
+       err = connect_ctrl_ring(be);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "connecting control ring");
+               return;
+       }
+
        /* Use the number of queues requested by the frontend */
        be->vif->queues = vzalloc(requested_num_queues *
                                  sizeof(struct xenvif_queue));
@@ -896,11 +985,12 @@ static void connect(struct backend_info *be)
                queue->remaining_credit = credit_bytes;
                queue->credit_usec = credit_usec;
 
-               err = connect_rings(be, queue);
+               err = connect_data_rings(be, queue);
                if (err) {
-                       /* connect_rings() cleans up after itself on failure,
-                        * but we need to clean up after xenvif_init_queue() here,
-                        * and also clean up any previously initialised queues.
+                       /* connect_data_rings() cleans up after itself on
+                        * failure, but we need to clean up after
+                        * xenvif_init_queue() here, and also clean up any
+                        * previously initialised queues.
                         */
                        xenvif_deinit_queue(queue);
                        be->vif->num_queues = queue_index;
@@ -935,15 +1025,17 @@ static void connect(struct backend_info *be)
 
 err:
        if (be->vif->num_queues > 0)
-               xenvif_disconnect(be->vif); /* Clean up existing queues */
+               xenvif_disconnect_data(be->vif); /* Clean up existing queues */
        vfree(be->vif->queues);
        be->vif->queues = NULL;
        be->vif->num_queues = 0;
+       xenvif_disconnect_ctrl(be->vif);
        return;
 }
 
 
-static int connect_rings(struct backend_info *be, struct xenvif_queue *queue)
+static int connect_data_rings(struct backend_info *be,
+                             struct xenvif_queue *queue)
 {
        struct xenbus_device *dev = be->dev;
        unsigned int num_queues = queue->vif->num_queues;
@@ -1007,8 +1099,8 @@ static int connect_rings(struct backend_info *be, struct xenvif_queue *queue)
        }
 
        /* Map the shared frame, irq etc. */
-       err = xenvif_connect(queue, tx_ring_ref, rx_ring_ref,
-                            tx_evtchn, rx_evtchn);
+       err = xenvif_connect_data(queue, tx_ring_ref, rx_ring_ref,
+                                 tx_evtchn, rx_evtchn);
        if (err) {
                xenbus_dev_fatal(dev, err,
                                 "mapping shared-frames %lu/%lu port tx %u rx %u",