#define WPRINTK(fmt, args...) \
printk(KERN_WARNING "xen_net: " fmt, ##args)
+struct backend_info;
+
typedef struct netif_st {
/* Unique identifier for this interface. */
domid_t domid;
atomic_t refcnt;
struct net_device *dev;
struct net_device_stats stats;
+ struct backend_info *be;
unsigned int carrier;
struct xenbus_device *dev;
netif_t *netif;
enum xenbus_state frontend_state;
+ struct xenbus_watch csum_offload_watch;
+ int have_csum_offload:1;
+ int have_csum_offload_watch:1;
/* State relating to the netback accelerator */
void *netback_accel_priv;
struct net_device_stats *netif_be_get_stats(struct net_device *dev);
irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+void netif_set_tx_csum(struct backend_info *, u32);
+
static inline int netbk_can_queue(struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
return ethtool_op_set_tso(dev, data);
}
+static int netbk_set_tx_csum(struct net_device *dev, u32 data)
+{
+ netif_t *netif = netdev_priv(dev);
+ netif_set_tx_csum(netif->be, data);
+ return ethtool_op_set_tx_csum(dev, data);
+}
+
static struct ethtool_ops network_ethtool_ops =
{
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_tx_csum = netbk_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = netbk_set_sg,
.get_tso = ethtool_op_get_tso,
static int connect_rings(struct backend_info *);
static void connect(struct backend_info *);
static void backend_create_netif(struct backend_info *be);
+static int register_csum_offload_watch(struct backend_info *be);
+static void unregister_csum_offload_watch(struct backend_info *be);
static int netback_remove(struct xenbus_device *dev)
{
netback_remove_accelerators(be, dev);
+ unregister_csum_offload_watch(be);
if (be->netif) {
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
netif_disconnect(be->netif);
be->dev = dev;
dev->dev.driver_data = be;
+ be->have_csum_offload = 1;
+
sg = 1;
if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
sg = 0;
xenbus_dev_fatal(dev, err, "creating interface");
return;
}
+ be->netif->be = be;
kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
}
struct backend_info *be = dev->dev.driver_data;
if (be->netif) {
+ unregister_csum_offload_watch(be);
netif_disconnect(be->netif);
be->netif = NULL;
}
netif_wake_queue(be->netif->dev);
}
+static void feature_csum_offload_changed(struct xenbus_watch *watch,
+ const char **vec,
+ unsigned int vec_size)
+{
+ int val;
+ struct backend_info *be = container_of(watch,
+ struct backend_info,
+ csum_offload_watch);
+
+ if (xenbus_scanf(XBT_NIL, be->dev->otherend, "feature-no-csum-offload",
+ "%d", &val) < 0)
+ val = 0;
+
+ if (val) {
+ be->netif->features &= ~NETIF_F_IP_CSUM;
+ be->netif->dev->features &= ~NETIF_F_IP_CSUM;
+ } else {
+ be->netif->features |= NETIF_F_IP_CSUM;
+ be->netif->dev->features |= NETIF_F_IP_CSUM;
+ }
+}
+static int register_csum_offload_watch(struct backend_info *be)
+{
+ struct xenbus_device *dev = be->dev;
+ int err;
+
+ if (!be->have_csum_offload || be->have_csum_offload_watch)
+ return 0;
+
+ err = xenbus_watch_path2(dev, dev->otherend, "feature-no-csum-offload",
+ &be->csum_offload_watch,
+ feature_csum_offload_changed);
+ if (err) {
+ xenbus_dev_fatal(dev, err,
+ "watching %s/feature-no-csum-offload",
+ dev->otherend);
+ return err;
+ }
+ be->have_csum_offload_watch = 1;
+ return 0;
+
+}
+
+static void unregister_csum_offload_watch(struct backend_info *be)
+{
+ if (be->have_csum_offload_watch) {
+ unregister_xenbus_watch(&be->csum_offload_watch);
+ kfree(be->csum_offload_watch.node);
+ }
+ be->have_csum_offload_watch = 0;
+}
+
+void netif_set_tx_csum(struct backend_info *be, u32 data)
+{
+ be->have_csum_offload = data;
+ if (data)
+ register_csum_offload_watch(be);
+ else
+ unregister_csum_offload_watch(be);
+}
static int connect_rings(struct backend_info *be)
{
be->netif->dev->features |= NETIF_F_TSO;
}
- if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
- "%d", &val) < 0)
- val = 0;
- if (val) {
- be->netif->features &= ~NETIF_F_IP_CSUM;
- be->netif->dev->features &= ~NETIF_F_IP_CSUM;
- }
+ unregister_csum_offload_watch(be);
+ err = register_csum_offload_watch(be);
+ if (err)
+ return err;
/* Map the shared frame, irq etc. */
err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);