summaryrefslogtreecommitdiffstats
path: root/drivers/net/xen-netback/xenbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/xen-netback/xenbus.c')
-rw-r--r--drivers/net/xen-netback/xenbus.c91
1 files changed, 77 insertions, 14 deletions
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 794204e34fba..968787abf78d 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -34,6 +34,8 @@ struct backend_info {
enum xenbus_state frontend_state;
struct xenbus_watch hotplug_status_watch;
u8 have_hotplug_status_watch:1;
+
+ const char *hotplug_script;
};
static int connect_rings(struct backend_info *be, struct xenvif_queue *queue);
@@ -41,6 +43,7 @@ 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);
static void unregister_hotplug_status_watch(struct backend_info *be);
+static void xen_unregister_watchers(struct xenvif *vif);
static void set_backend_state(struct backend_info *be,
enum xenbus_state state);
@@ -232,10 +235,12 @@ static int netback_remove(struct xenbus_device *dev)
unregister_hotplug_status_watch(be);
if (be->vif) {
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
+ xen_unregister_watchers(be->vif);
xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
xenvif_free(be->vif);
be->vif = NULL;
}
+ kfree(be->hotplug_script);
kfree(be);
dev_set_drvdata(&dev->dev, NULL);
return 0;
@@ -253,6 +258,7 @@ static int netback_probe(struct xenbus_device *dev,
struct xenbus_transaction xbt;
int err;
int sg;
+ const char *script;
struct backend_info *be = kzalloc(sizeof(struct backend_info),
GFP_KERNEL);
if (!be) {
@@ -345,6 +351,15 @@ static int netback_probe(struct xenbus_device *dev,
if (err)
pr_debug("Error writing multi-queue-max-queues\n");
+ script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
+ if (IS_ERR(script)) {
+ err = PTR_ERR(script);
+ xenbus_dev_fatal(dev, err, "reading script");
+ goto fail;
+ }
+
+ be->hotplug_script = script;
+
err = xenbus_switch_state(dev, XenbusStateInitWait);
if (err)
goto fail;
@@ -377,22 +392,14 @@ static int netback_uevent(struct xenbus_device *xdev,
struct kobj_uevent_env *env)
{
struct backend_info *be = dev_get_drvdata(&xdev->dev);
- char *val;
- val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
- if (IS_ERR(val)) {
- int err = PTR_ERR(val);
- xenbus_dev_fatal(xdev, err, "reading script");
- return err;
- } else {
- if (add_uevent_var(env, "script=%s", val)) {
- kfree(val);
- return -ENOMEM;
- }
- kfree(val);
- }
+ if (!be)
+ return 0;
- if (!be || !be->vif)
+ if (add_uevent_var(env, "script=%s", be->hotplug_script))
+ return -ENOMEM;
+
+ if (!be->vif)
return 0;
return add_uevent_var(env, "vif=%s", be->vif->dev->name);
@@ -430,6 +437,7 @@ static int backend_create_xenvif(struct backend_info *be)
static void backend_disconnect(struct backend_info *be)
{
if (be->vif) {
+ xen_unregister_watchers(be->vif);
#ifdef CONFIG_DEBUG_FS
xenvif_debugfs_delif(be->vif);
#endif /* CONFIG_DEBUG_FS */
@@ -645,6 +653,59 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
return 0;
}
+static void xen_net_rate_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenvif *vif = container_of(watch, struct xenvif, credit_watch);
+ struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
+ unsigned long credit_bytes;
+ unsigned long credit_usec;
+ unsigned int queue_index;
+
+ xen_net_read_rate(dev, &credit_bytes, &credit_usec);
+ for (queue_index = 0; queue_index < vif->num_queues; queue_index++) {
+ struct xenvif_queue *queue = &vif->queues[queue_index];
+
+ queue->credit_bytes = credit_bytes;
+ queue->credit_usec = credit_usec;
+ if (!mod_timer_pending(&queue->credit_timeout, jiffies) &&
+ queue->remaining_credit > queue->credit_bytes) {
+ queue->remaining_credit = queue->credit_bytes;
+ }
+ }
+}
+
+static int xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
+{
+ int err = 0;
+ char *node;
+ unsigned maxlen = strlen(dev->nodename) + sizeof("/rate");
+
+ node = kmalloc(maxlen, GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+ snprintf(node, maxlen, "%s/rate", dev->nodename);
+ vif->credit_watch.node = node;
+ vif->credit_watch.callback = xen_net_rate_changed;
+ err = register_xenbus_watch(&vif->credit_watch);
+ if (err) {
+ pr_err("Failed to set watcher %s\n", vif->credit_watch.node);
+ kfree(node);
+ vif->credit_watch.node = NULL;
+ vif->credit_watch.callback = NULL;
+ }
+ return err;
+}
+
+static void xen_unregister_watchers(struct xenvif *vif)
+{
+ if (vif->credit_watch.node) {
+ unregister_xenbus_watch(&vif->credit_watch);
+ kfree(vif->credit_watch.node);
+ vif->credit_watch.node = NULL;
+ }
+}
+
static void unregister_hotplug_status_watch(struct backend_info *be)
{
if (be->have_hotplug_status_watch) {
@@ -709,6 +770,7 @@ static void connect(struct backend_info *be)
}
xen_net_read_rate(dev, &credit_bytes, &credit_usec);
+ xen_register_watchers(dev, be->vif);
read_xenbus_vif_flags(be);
/* Use the number of queues requested by the frontend */
@@ -736,6 +798,7 @@ static void connect(struct backend_info *be)
goto err;
}
+ queue->credit_bytes = credit_bytes;
queue->remaining_credit = credit_bytes;
queue->credit_usec = credit_usec;
OpenPOWER on IntegriCloud