diff options
Diffstat (limited to 'drivers/net/xen-netback')
| -rw-r--r-- | drivers/net/xen-netback/common.h | 4 | ||||
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 3 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 39 | ||||
| -rw-r--r-- | drivers/net/xen-netback/xenbus.c | 95 |
4 files changed, 103 insertions, 38 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 589fa256256b..8a495b318b6f 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -238,6 +238,8 @@ struct xenvif { unsigned int num_queues; /* active queues, resource allocated */ unsigned int stalled_queues; + struct xenbus_watch credit_watch; + spinlock_t lock; #ifdef CONFIG_DEBUG_FS @@ -260,6 +262,8 @@ static inline struct xenbus_device *xenvif_to_xenbus_device(struct xenvif *vif) return to_xenbus_device(vif->dev->dev.parent); } +void xenvif_tx_credit_callback(unsigned long data); + struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, unsigned int handle); diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 3aa8648080c8..1a83e190fc15 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -437,7 +437,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, * stolen by an Ethernet bridge for STP purposes. * (FE:FF:FF:FF:FF:FF) */ - memset(dev->dev_addr, 0xFF, ETH_ALEN); + eth_broadcast_addr(dev->dev_addr); dev->dev_addr[0] &= ~0x01; netif_carrier_off(dev); @@ -463,6 +463,7 @@ int xenvif_init_queue(struct xenvif_queue *queue) queue->credit_bytes = queue->remaining_credit = ~0UL; queue->credit_usec = 0UL; init_timer(&queue->credit_timeout); + queue->credit_timeout.function = xenvif_tx_credit_callback; queue->credit_window_start = get_jiffies_64(); queue->rx_queue_max = XENVIF_RX_QUEUE_BYTES; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 997cf0901ac2..7d50711476fe 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -44,15 +44,15 @@ #include <xen/xen.h> #include <xen/events.h> #include <xen/interface/memory.h> +#include <xen/page.h> #include <asm/xen/hypercall.h> -#include <asm/xen/page.h> /* Provide an option to disable split event channels at load time as * event channels are limited resource. Split event channels are * enabled by default. */ -bool separate_tx_rx_irq = 1; +bool separate_tx_rx_irq = true; module_param(separate_tx_rx_irq, bool, 0644); /* The time that packets can stay on the guest Rx internal queue @@ -515,14 +515,9 @@ static void xenvif_rx_action(struct xenvif_queue *queue) while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX) && (skb = xenvif_rx_dequeue(queue)) != NULL) { - RING_IDX old_req_cons; - RING_IDX ring_slots_used; - queue->last_rx_time = jiffies; - old_req_cons = queue->rx.req_cons; XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue); - ring_slots_used = queue->rx.req_cons - old_req_cons; __skb_queue_tail(&rxq, skb); } @@ -642,7 +637,7 @@ static void tx_add_credit(struct xenvif_queue *queue) queue->remaining_credit = min(max_credit, max_burst); } -static void tx_credit_callback(unsigned long data) +void xenvif_tx_credit_callback(unsigned long data) { struct xenvif_queue *queue = (struct xenvif_queue *)data; tx_add_credit(queue); @@ -753,7 +748,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue, slots++; if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) { - netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %x, size: %u\n", + netdev_err(queue->vif->dev, "Cross page boundary, txp->offset: %u, size: %u\n", txp->offset, txp->size); xenvif_fatal_tx_err(queue->vif); return -EINVAL; @@ -879,7 +874,7 @@ static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, if (unlikely(queue->grant_tx_handle[pending_idx] != NETBACK_INVALID_HANDLE)) { netdev_err(queue->vif->dev, - "Trying to overwrite active handle! pending_idx: %x\n", + "Trying to overwrite active handle! pending_idx: 0x%x\n", pending_idx); BUG(); } @@ -892,7 +887,7 @@ static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, if (unlikely(queue->grant_tx_handle[pending_idx] == NETBACK_INVALID_HANDLE)) { netdev_err(queue->vif->dev, - "Trying to unmap invalid handle! pending_idx: %x\n", + "Trying to unmap invalid handle! pending_idx: 0x%x\n", pending_idx); BUG(); } @@ -1165,8 +1160,6 @@ static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size) if (size > queue->remaining_credit) { queue->credit_timeout.data = (unsigned long)queue; - queue->credit_timeout.function = - tx_credit_callback; mod_timer(&queue->credit_timeout, next_credit); queue->credit_window_start = next_credit; @@ -1250,9 +1243,9 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, /* No crossing a page as the payload mustn't fragment. */ if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) { netdev_err(queue->vif->dev, - "txreq.offset: %x, size: %u, end: %lu\n", + "txreq.offset: %u, size: %u, end: %lu\n", txreq.offset, txreq.size, - (txreq.offset&~PAGE_MASK) + txreq.size); + (unsigned long)(txreq.offset&~PAGE_MASK) + txreq.size); xenvif_fatal_tx_err(queue->vif); break; } @@ -1573,13 +1566,13 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue) smp_rmb(); while (dc != dp) { - BUG_ON(gop - queue->tx_unmap_ops > MAX_PENDING_REQS); + BUG_ON(gop - queue->tx_unmap_ops >= MAX_PENDING_REQS); pending_idx = queue->dealloc_ring[pending_index(dc++)]; - pending_idx_release[gop-queue->tx_unmap_ops] = + pending_idx_release[gop - queue->tx_unmap_ops] = pending_idx; - queue->pages_to_unmap[gop-queue->tx_unmap_ops] = + queue->pages_to_unmap[gop - queue->tx_unmap_ops] = queue->mmap_pages[pending_idx]; gnttab_set_unmap_op(gop, idx_to_kaddr(queue, pending_idx), @@ -1600,12 +1593,12 @@ static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue) queue->pages_to_unmap, gop - queue->tx_unmap_ops); if (ret) { - netdev_err(queue->vif->dev, "Unmap fail: nr_ops %tx ret %d\n", + netdev_err(queue->vif->dev, "Unmap fail: nr_ops %tu ret %d\n", gop - queue->tx_unmap_ops, ret); for (i = 0; i < gop - queue->tx_unmap_ops; ++i) { if (gop[i].status != GNTST_okay) netdev_err(queue->vif->dev, - " host_addr: %llx handle: %x status: %d\n", + " host_addr: 0x%llx handle: 0x%x status: %d\n", gop[i].host_addr, gop[i].handle, gop[i].status); @@ -1738,7 +1731,7 @@ void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx) &queue->mmap_pages[pending_idx], 1); if (ret) { netdev_err(queue->vif->dev, - "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: %x status: %d\n", + "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: 0x%x status: %d\n", ret, pending_idx, tx_unmap_op.host_addr, @@ -1782,7 +1775,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, int err = -ENOMEM; err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), - tx_ring_ref, &addr); + &tx_ring_ref, 1, &addr); if (err) goto err; @@ -1790,7 +1783,7 @@ int xenvif_map_frontend_rings(struct xenvif_queue *queue, BACK_RING_INIT(&queue->tx, txs, PAGE_SIZE); err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), - rx_ring_ref, &addr); + &rx_ring_ref, 1, &addr); if (err) goto err; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 794204e34fba..ec383b0f5443 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,62 @@ 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"); + + if (vif->credit_watch.node) + return -EADDRINUSE; + + 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 +773,8 @@ static void connect(struct backend_info *be) } xen_net_read_rate(dev, &credit_bytes, &credit_usec); + xen_unregister_watchers(be->vif); + xen_register_watchers(dev, be->vif); read_xenbus_vif_flags(be); /* Use the number of queues requested by the frontend */ @@ -736,6 +802,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; |
