if (err)
pr_debug("Error writing multi-queue-max-queues\n");
+ /* Multi-queue mapping support: This is an optional feature. */
+ err = xenbus_printf(XBT_NIL, dev->nodename,
+ "feature-multi-queue-mapping", "%d", 1);
+ if (err)
+ pr_debug("Error writing feature-multi-queue-mapping\n");
+
script = xenbus_read(XBT_NIL, dev->nodename, "script", NULL);
if (IS_ERR(script)) {
err = PTR_ERR(script);
}
}
-static int xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
+static int xen_register_credit_watch(struct xenbus_device *dev, struct xenvif *vif)
{
int err = 0;
char *node;
return err;
}
-static void xen_unregister_watchers(struct xenvif *vif)
+static void xen_unregister_credit_watch(struct xenvif *vif)
{
if (vif->credit_watch.node) {
unregister_xenbus_watch(&vif->credit_watch);
}
}
+static void xen_net_read_multi_queue_mapping(struct xenvif *vif)
+{
+ struct xenbus_device *dev = xenvif_to_xenbus_device(vif);
+ char *str, *token;
+ unsigned int *mapping;
+ unsigned int n, i;
+
+ str = xenbus_read(XBT_NIL, dev->otherend, "multi-queue-mapping", NULL);
+ if (IS_ERR(str)) {
+ pr_info("%s: no mapping table\n", dev->nodename);
+ goto fail1;
+ }
+
+ mapping = kcalloc(ARRAY_SIZE(vif->queue_mapping), sizeof(unsigned int),
+ GFP_KERNEL);
+ if (mapping == NULL) {
+ pr_err("%s: failed to allocate mapping table\n",
+ dev->nodename);
+ goto fail2;
+ }
+
+ n = 0;
+ while ((token = strsep(&str, ",")) != NULL) {
+ int rc;
+
+ if (n >= ARRAY_SIZE(vif->queue_mapping)) {
+ pr_err("%s: mapping table too big\n",
+ dev->nodename);
+ goto fail3;
+ }
+
+ rc = kstrtouint(token, 0, &mapping[n]);
+ if (rc < 0 || mapping[n] > vif->num_queues) {
+ pr_err("%s: invalid mapping table value (%s at index %u)\n",
+ dev->nodename, token, n);
+ goto fail3;
+ }
+
+ n++;
+ }
+
+ if (n == 0 || (n & (n - 1)) != 0) {
+ pr_err("%s: invalid mapping table size (%u)\n",
+ dev->nodename, n);
+ goto fail3;
+ }
+
+ i = ARRAY_SIZE(vif->queue_mapping);
+ while (i-- > 0)
+ vif->queue_mapping[i] = mapping[i & (n - 1)];
+
+ pr_info("%s: set mapping table\n", dev->nodename);
+
+ kfree(mapping);
+ kfree(str);
+ return;
+
+fail3:
+ kfree(mapping);
+fail2:
+ kfree(str);
+fail1:
+ vif->queue_mapping[0] = -1;
+}
+
+
+static void xen_mq_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenvif *vif = container_of(watch, struct xenvif, mq_watch);
+
+ xen_net_read_multi_queue_mapping(vif);
+}
+
+static int xen_register_mq_watch(struct xenbus_device *dev, struct xenvif *vif)
+{
+ int err = 0;
+ char *node;
+ unsigned maxlen = strlen(dev->otherend) + sizeof("/multi-queue-mapping");
+
+ if (vif->mq_watch.node)
+ return -EADDRINUSE;
+
+ node = kmalloc(maxlen, GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+ snprintf(node, maxlen, "%s/multi-queue-mapping", dev->otherend);
+ vif->mq_watch.node = node;
+ vif->mq_watch.callback = xen_mq_changed;
+ err = register_xenbus_watch(&vif->mq_watch);
+ if (err) {
+ pr_err("Failed to set watcher %s\n", vif->mq_watch.node);
+ kfree(node);
+ vif->mq_watch.node = NULL;
+ vif->mq_watch.callback = NULL;
+ }
+ return err;
+}
+
+static void xen_unregister_mq_watch(struct xenvif *vif)
+{
+ if (vif->mq_watch.node) {
+ unregister_xenbus_watch(&vif->mq_watch);
+ kfree(vif->mq_watch.node);
+ vif->mq_watch.node = NULL;
+ }
+}
+
+static void xen_register_watchers(struct xenbus_device *dev, struct xenvif *vif)
+{
+ xen_register_credit_watch(dev, vif);
+ xen_register_mq_watch(dev, vif);
+}
+
+static void xen_unregister_watchers(struct xenvif *vif)
+{
+ xen_unregister_mq_watch(vif);
+ xen_unregister_credit_watch(vif);
+}
+
static void unregister_hotplug_status_watch(struct backend_info *be)
{
if (be->have_hotplug_status_watch) {
return;
}
+ /* Use the number of queues requested by the frontend */
+ be->vif->queues = vzalloc(requested_num_queues *
+ sizeof(struct xenvif_queue));
+ be->vif->num_queues = requested_num_queues;
+ be->vif->stalled_queues = requested_num_queues;
+
err = xen_net_read_mac(dev, be->vif->fe_dev_addr);
if (err) {
xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
xen_register_watchers(dev, be->vif);
read_xenbus_vif_flags(be);
- /* Use the number of queues requested by the frontend */
- be->vif->queues = vzalloc(requested_num_queues *
- sizeof(struct xenvif_queue));
- be->vif->num_queues = requested_num_queues;
- be->vif->stalled_queues = requested_num_queues;
-
for (queue_index = 0; queue_index < requested_num_queues; ++queue_index) {
queue = &be->vif->queues[queue_index];
queue->vif = be->vif;