Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d4cdf47 authored by Benjamin LaHaise's avatar Benjamin LaHaise Committed by David S. Miller
Browse files

vlan: add 802.1q netpoll support



Add netpoll support to 802.1q vlan devices.  Based on the netpoll support
in the bridging code.  Tested on a forced_eth device with netconsole.

Signed-off-by: default avatarBenjamin LaHaise <bcrl@kvack.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8af2a218
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ struct vlan_pcpu_stats {
	u32			tx_dropped;
};

struct netpoll;

/**
 *	struct vlan_dev_priv - VLAN private device data
 *	@nr_ingress_mappings: number of ingress priority mappings
@@ -68,6 +70,9 @@ struct vlan_dev_priv {

	struct proc_dir_entry			*dent;
	struct vlan_pcpu_stats __percpu		*vlan_pcpu_stats;
#ifdef CONFIG_NET_POLL_CONTROLLER
	struct netpoll				*netpoll;
#endif
};

static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
+59 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include "vlan.h"
#include "vlanproc.h"
#include <linux/if_vlan.h>
#include <linux/netpoll.h>

/*
 *	Rebuild the Ethernet MAC header. This is called after an ARP
@@ -158,6 +159,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,

	skb_set_dev(skb, vlan_dev_priv(dev)->real_dev);
	len = skb->len;
	if (netpoll_tx_running(dev))
		return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev);
	ret = dev_queue_xmit(skb);

	if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
@@ -660,6 +663,57 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
	return stats;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
void vlan_dev_poll_controller(struct net_device *dev)
{
	return;
}

int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
{
	struct vlan_dev_priv *info = vlan_dev_priv(dev);
	struct net_device *real_dev = info->real_dev;
	struct netpoll *netpoll;
	int err = 0;

	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
	err = -ENOMEM;
	if (!netpoll)
		goto out;

	netpoll->dev = real_dev;
	strlcpy(netpoll->dev_name, real_dev->name, IFNAMSIZ);

	err = __netpoll_setup(netpoll);
	if (err) {
		kfree(netpoll);
		goto out;
	}

	info->netpoll = netpoll;

out:
	return err;
}

void vlan_dev_netpoll_cleanup(struct net_device *dev)
{
	struct vlan_dev_priv *info = vlan_dev_priv(dev);
	struct netpoll *netpoll = info->netpoll;

	if (!netpoll)
		return;

	info->netpoll = NULL;

        /* Wait for transmitting packets to finish before freeing. */
        synchronize_rcu_bh();

        __netpoll_cleanup(netpoll);
        kfree(netpoll);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */

static const struct ethtool_ops vlan_ethtool_ops = {
	.get_settings	        = vlan_ethtool_get_settings,
	.get_drvinfo	        = vlan_ethtool_get_drvinfo,
@@ -687,6 +741,11 @@ static const struct net_device_ops vlan_netdev_ops = {
	.ndo_fcoe_disable	= vlan_dev_fcoe_disable,
	.ndo_fcoe_get_wwn	= vlan_dev_fcoe_get_wwn,
	.ndo_fcoe_ddp_target	= vlan_dev_fcoe_ddp_target,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= vlan_dev_poll_controller,
	.ndo_netpoll_setup	= vlan_dev_netpoll_setup,
	.ndo_netpoll_cleanup	= vlan_dev_netpoll_cleanup,
#endif
	.ndo_fix_features	= vlan_dev_fix_features,
};