diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /net/dsa | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'net/dsa')
| -rw-r--r-- | net/dsa/dsa.c | 101 | ||||
| -rw-r--r-- | net/dsa/dsa_priv.h | 8 | ||||
| -rw-r--r-- | net/dsa/slave.c | 397 | ||||
| -rw-r--r-- | net/dsa/tag_brcm.c | 15 | ||||
| -rw-r--r-- | net/dsa/tag_dsa.c | 12 | ||||
| -rw-r--r-- | net/dsa/tag_edsa.c | 12 | ||||
| -rw-r--r-- | net/dsa/tag_trailer.c | 12 | 
7 files changed, 433 insertions, 124 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 392e29a0227d..76e3800765f8 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -176,6 +176,41 @@ __ATTRIBUTE_GROUPS(dsa_hwmon);  #endif /* CONFIG_NET_DSA_HWMON */  /* basic switch operations **************************************************/ +static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master) +{ +	struct dsa_chip_data *cd = ds->pd; +	struct device_node *port_dn; +	struct phy_device *phydev; +	int ret, port, mode; + +	for (port = 0; port < DSA_MAX_PORTS; port++) { +		if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) +			continue; + +		port_dn = cd->port_dn[port]; +		if (of_phy_is_fixed_link(port_dn)) { +			ret = of_phy_register_fixed_link(port_dn); +			if (ret) { +				netdev_err(master, +					   "failed to register fixed PHY\n"); +				return ret; +			} +			phydev = of_phy_find_device(port_dn); + +			mode = of_get_phy_mode(port_dn); +			if (mode < 0) +				mode = PHY_INTERFACE_MODE_NA; +			phydev->interface = mode; + +			genphy_config_init(phydev); +			genphy_read_status(phydev); +			if (ds->drv->adjust_link) +				ds->drv->adjust_link(ds, port, phydev); +		} +	} +	return 0; +} +  static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)  {  	struct dsa_switch_driver *drv = ds->drv; @@ -297,6 +332,14 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent)  		}  	} +	/* Perform configuration of the CPU and DSA ports */ +	ret = dsa_cpu_dsa_setup(ds, dst->master_netdev); +	if (ret < 0) { +		netdev_err(dst->master_netdev, "[%d] : can't configure CPU and DSA ports\n", +			   index); +		ret = 0; +	} +  #ifdef CONFIG_NET_DSA_HWMON  	/* If the switch provides a temperature sensor,  	 * register with hardware monitoring subsystem. @@ -554,6 +597,31 @@ static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,  	return 0;  } +static int dsa_of_probe_links(struct dsa_platform_data *pd, +			      struct dsa_chip_data *cd, +			      int chip_index, int port_index, +			      struct device_node *port, +			      const char *port_name) +{ +	struct device_node *link; +	int link_index; +	int ret; + +	for (link_index = 0;; link_index++) { +		link = of_parse_phandle(port, "link", link_index); +		if (!link) +			break; + +		if (!strcmp(port_name, "dsa") && pd->nr_chips > 1) { +			ret = dsa_of_setup_routing_table(pd, cd, chip_index, +							 port_index, link); +			if (ret) +				return ret; +		} +	} +	return 0; +} +  static void dsa_of_free_platform_data(struct dsa_platform_data *pd)  {  	int i; @@ -573,8 +641,8 @@ static void dsa_of_free_platform_data(struct dsa_platform_data *pd)  static int dsa_of_probe(struct device *dev)  {  	struct device_node *np = dev->of_node; -	struct device_node *child, *mdio, *ethernet, *port, *link; -	struct mii_bus *mdio_bus; +	struct device_node *child, *mdio, *ethernet, *port; +	struct mii_bus *mdio_bus, *mdio_bus_switch;  	struct net_device *ethernet_dev;  	struct dsa_platform_data *pd;  	struct dsa_chip_data *cd; @@ -630,18 +698,30 @@ static int dsa_of_probe(struct device *dev)  			continue;  		cd->sw_addr = be32_to_cpup(sw_addr); -		if (cd->sw_addr > PHY_MAX_ADDR) +		if (cd->sw_addr >= PHY_MAX_ADDR)  			continue;  		if (!of_property_read_u32(child, "eeprom-length", &eeprom_len))  			cd->eeprom_len = eeprom_len; +		mdio = of_parse_phandle(child, "mii-bus", 0); +		if (mdio) { +			mdio_bus_switch = of_mdio_find_bus(mdio); +			if (!mdio_bus_switch) { +				ret = -EPROBE_DEFER; +				goto out_free_chip; +			} +			cd->host_dev = &mdio_bus_switch->dev; +		} +  		for_each_available_child_of_node(child, port) {  			port_reg = of_get_property(port, "reg", NULL);  			if (!port_reg)  				continue;  			port_index = be32_to_cpup(port_reg); +			if (port_index >= DSA_MAX_PORTS) +				break;  			port_name = of_get_property(port, "label", NULL);  			if (!port_name) @@ -656,18 +736,11 @@ static int dsa_of_probe(struct device *dev)  				goto out_free_chip;  			} -			link = of_parse_phandle(port, "link", 0); - -			if (!strcmp(port_name, "dsa") && link && -					pd->nr_chips > 1) { -				ret = dsa_of_setup_routing_table(pd, cd, -						chip_index, port_index, link); -				if (ret) -					goto out_free_chip; -			} +			ret = dsa_of_probe_links(pd, cd, chip_index, +						 port_index, port, port_name); +			if (ret) +				goto out_free_chip; -			if (port_index == DSA_MAX_PORTS) -				break;  		}  	} diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index d5f1f9b862ea..311796c809af 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -13,9 +13,10 @@  #include <linux/phy.h>  #include <linux/netdevice.h> +#include <linux/netpoll.h>  struct dsa_device_ops { -	netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev); +	struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);  	int (*rcv)(struct sk_buff *skb, struct net_device *dev,  		   struct packet_type *pt, struct net_device *orig_dev);  }; @@ -26,7 +27,7 @@ struct dsa_slave_priv {  	 * switch port.  	 */  	struct net_device	*dev; -	netdev_tx_t		(*xmit)(struct sk_buff *skb, +	struct sk_buff *	(*xmit)(struct sk_buff *skb,  					struct net_device *dev);  	/* @@ -47,6 +48,9 @@ struct dsa_slave_priv {  	int			old_duplex;  	struct net_device	*bridge_dev; +#ifdef CONFIG_NET_POLL_CONTROLLER +	struct netpoll		*netpoll; +#endif  };  /* dsa.c */ diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0917123790ea..cce97385f743 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -18,6 +18,7 @@  #include <net/rtnetlink.h>  #include <net/switchdev.h>  #include <linux/if_bridge.h> +#include <linux/netpoll.h>  #include "dsa_priv.h"  /* slave mii_bus handling ***************************************************/ @@ -199,103 +200,212 @@ out:  	return 0;  } -static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], -			     struct net_device *dev, -			     const unsigned char *addr, u16 vid, u16 nlm_flags) +static int dsa_bridge_check_vlan_range(struct dsa_switch *ds, +				       const struct net_device *bridge, +				       u16 vid_begin, u16 vid_end)  { +	struct dsa_slave_priv *p; +	struct net_device *dev, *vlan_br; +	DECLARE_BITMAP(members, DSA_MAX_PORTS); +	DECLARE_BITMAP(untagged, DSA_MAX_PORTS); +	u16 vid; +	int member, err; + +	if (!ds->drv->vlan_getnext || !vid_begin) +		return -EOPNOTSUPP; + +	vid = vid_begin - 1; + +	do { +		err = ds->drv->vlan_getnext(ds, &vid, members, untagged); +		if (err) +			break; + +		if (vid > vid_end) +			break; + +		member = find_first_bit(members, DSA_MAX_PORTS); +		if (member == DSA_MAX_PORTS) +			continue; + +		dev = ds->ports[member]; +		p = netdev_priv(dev); +		vlan_br = p->bridge_dev; +		if (vlan_br == bridge) +			continue; + +		netdev_dbg(vlan_br, "hardware VLAN %d already in use\n", vid); +		return -EOPNOTSUPP; +	} while (vid < vid_end); + +	return err == -ENOENT ? 0 : err; +} + +static int dsa_slave_port_vlan_add(struct net_device *dev, +				   struct switchdev_obj *obj) +{ +	struct switchdev_obj_vlan *vlan = &obj->u.vlan;  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	int ret = -EOPNOTSUPP; +	u16 vid; +	int err; -	if (ds->drv->fdb_add) -		ret = ds->drv->fdb_add(ds, p->port, addr, vid); +	switch (obj->trans) { +	case SWITCHDEV_TRANS_PREPARE: +		if (!ds->drv->port_vlan_add || !ds->drv->port_pvid_set) +			return -EOPNOTSUPP; -	return ret; +		/* If the requested port doesn't belong to the same bridge as +		 * the VLAN members, fallback to software VLAN (hopefully). +		 */ +		err = dsa_bridge_check_vlan_range(ds, p->bridge_dev, +						  vlan->vid_begin, +						  vlan->vid_end); +		if (err) +			return err; +		break; +	case SWITCHDEV_TRANS_COMMIT: +		for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { +			err = ds->drv->port_vlan_add(ds, p->port, vid, +						     vlan->flags & +						     BRIDGE_VLAN_INFO_UNTAGGED); +			if (!err && vlan->flags & BRIDGE_VLAN_INFO_PVID) +				err = ds->drv->port_pvid_set(ds, p->port, vid); +			if (err) +				return err; +		} +		break; +	default: +		return -EOPNOTSUPP; +	} + +	return 0;  } -static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], -			     struct net_device *dev, -			     const unsigned char *addr, u16 vid) +static int dsa_slave_port_vlan_del(struct net_device *dev, +				   struct switchdev_obj *obj)  { +	struct switchdev_obj_vlan *vlan = &obj->u.vlan;  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	int ret = -EOPNOTSUPP; +	u16 vid; +	int err; -	if (ds->drv->fdb_del) -		ret = ds->drv->fdb_del(ds, p->port, addr, vid); +	if (!ds->drv->port_vlan_del) +		return -EOPNOTSUPP; -	return ret; +	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { +		err = ds->drv->port_vlan_del(ds, p->port, vid); +		if (err) +			return err; +	} + +	return 0;  } -static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb, -			       const unsigned char *addr, u16 vid, -			       bool is_static, -			       u32 portid, u32 seq, int type, -			       unsigned int flags) +static int dsa_slave_port_vlan_dump(struct net_device *dev, +				    struct switchdev_obj *obj)  { -	struct nlmsghdr *nlh; -	struct ndmsg *ndm; +	struct switchdev_obj_vlan *vlan = &obj->u.vlan; +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; +	DECLARE_BITMAP(members, DSA_MAX_PORTS); +	DECLARE_BITMAP(untagged, DSA_MAX_PORTS); +	u16 pvid, vid = 0; +	int err; -	nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); -	if (!nlh) -		return -EMSGSIZE; +	if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get) +		return -EOPNOTSUPP; -	ndm = nlmsg_data(nlh); -	ndm->ndm_family	 = AF_BRIDGE; -	ndm->ndm_pad1    = 0; -	ndm->ndm_pad2    = 0; -	ndm->ndm_flags	 = NTF_EXT_LEARNED; -	ndm->ndm_type	 = 0; -	ndm->ndm_ifindex = dev->ifindex; -	ndm->ndm_state   = is_static ? NUD_NOARP : NUD_REACHABLE; +	err = ds->drv->port_pvid_get(ds, p->port, &pvid); +	if (err) +		return err; -	if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) -		goto nla_put_failure; +	for (;;) { +		err = ds->drv->vlan_getnext(ds, &vid, members, untagged); +		if (err) +			break; -	if (vid && nla_put_u16(skb, NDA_VLAN, vid)) -		goto nla_put_failure; +		if (!test_bit(p->port, members)) +			continue; -	nlmsg_end(skb, nlh); -	return 0; +		memset(vlan, 0, sizeof(*vlan)); +		vlan->vid_begin = vlan->vid_end = vid; + +		if (vid == pvid) +			vlan->flags |= BRIDGE_VLAN_INFO_PVID; + +		if (test_bit(p->port, untagged)) +			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; + +		err = obj->cb(dev, obj); +		if (err) +			break; +	} + +	return err == -ENOENT ? 0 : err; +} -nla_put_failure: -	nlmsg_cancel(skb, nlh); -	return -EMSGSIZE; +static int dsa_slave_port_fdb_add(struct net_device *dev, +				  struct switchdev_obj *obj) +{ +	struct switchdev_obj_fdb *fdb = &obj->u.fdb; +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; +	int ret = -EOPNOTSUPP; + +	if (obj->trans == SWITCHDEV_TRANS_PREPARE) +		ret = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; +	else if (obj->trans == SWITCHDEV_TRANS_COMMIT) +		ret = ds->drv->port_fdb_add(ds, p->port, fdb->addr, fdb->vid); + +	return ret;  } -/* Dump information about entries, in response to GETNEIGH */ -static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, -			      struct net_device *dev, -			      struct net_device *filter_dev, int idx) +static int dsa_slave_port_fdb_del(struct net_device *dev, +				  struct switchdev_obj *obj) +{ +	struct switchdev_obj_fdb *fdb = &obj->u.fdb; +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; +	int ret = -EOPNOTSUPP; + +	if (ds->drv->port_fdb_del) +		ret = ds->drv->port_fdb_del(ds, p->port, fdb->addr, fdb->vid); + +	return ret; +} + +static int dsa_slave_port_fdb_dump(struct net_device *dev, +				   struct switchdev_obj *obj)  {  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent;  	unsigned char addr[ETH_ALEN] = { 0 }; +	u16 vid = 0;  	int ret; -	if (!ds->drv->fdb_getnext) +	if (!ds->drv->port_fdb_getnext)  		return -EOPNOTSUPP; -	for (; ; idx++) { +	for (;;) {  		bool is_static; -		ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static); +		ret = ds->drv->port_fdb_getnext(ds, p->port, addr, &vid, +						&is_static);  		if (ret < 0)  			break; -		if (idx < cb->args[0]) -			continue; +		obj->u.fdb.addr = addr; +		obj->u.fdb.vid = vid; +		obj->u.fdb.ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; -		ret = dsa_slave_fill_info(dev, skb, addr, 0, -					  is_static, -					  NETLINK_CB(cb->skb).portid, -					  cb->nlh->nlmsg_seq, -					  RTM_NEWNEIGH, NLM_F_MULTI); +		ret = obj->cb(dev, obj);  		if (ret < 0)  			break;  	} -	return idx; +	return ret == -ENOENT ? 0 : ret;  }  static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -363,6 +473,71 @@ static int dsa_slave_port_attr_set(struct net_device *dev,  	return ret;  } +static int dsa_slave_port_obj_add(struct net_device *dev, +				  struct switchdev_obj *obj) +{ +	int err; + +	/* For the prepare phase, ensure the full set of changes is feasable in +	 * one go in order to signal a failure properly. If an operation is not +	 * supported, return -EOPNOTSUPP. +	 */ + +	switch (obj->id) { +	case SWITCHDEV_OBJ_PORT_FDB: +		err = dsa_slave_port_fdb_add(dev, obj); +		break; +	case SWITCHDEV_OBJ_PORT_VLAN: +		err = dsa_slave_port_vlan_add(dev, obj); +		break; +	default: +		err = -EOPNOTSUPP; +		break; +	} + +	return err; +} + +static int dsa_slave_port_obj_del(struct net_device *dev, +				  struct switchdev_obj *obj) +{ +	int err; + +	switch (obj->id) { +	case SWITCHDEV_OBJ_PORT_FDB: +		err = dsa_slave_port_fdb_del(dev, obj); +		break; +	case SWITCHDEV_OBJ_PORT_VLAN: +		err = dsa_slave_port_vlan_del(dev, obj); +		break; +	default: +		err = -EOPNOTSUPP; +		break; +	} + +	return err; +} + +static int dsa_slave_port_obj_dump(struct net_device *dev, +				   struct switchdev_obj *obj) +{ +	int err; + +	switch (obj->id) { +	case SWITCHDEV_OBJ_PORT_FDB: +		err = dsa_slave_port_fdb_dump(dev, obj); +		break; +	case SWITCHDEV_OBJ_PORT_VLAN: +		err = dsa_slave_port_vlan_dump(dev, obj); +		break; +	default: +		err = -EOPNOTSUPP; +		break; +	} + +	return err; +} +  static int dsa_slave_bridge_port_join(struct net_device *dev,  				      struct net_device *br)  { @@ -418,24 +593,53 @@ static int dsa_slave_port_attr_get(struct net_device *dev,  	return 0;  } -static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) +static inline netdev_tx_t dsa_netpoll_send_skb(struct dsa_slave_priv *p, +					       struct sk_buff *skb)  { -	struct dsa_slave_priv *p = netdev_priv(dev); - -	return p->xmit(skb, dev); +#ifdef CONFIG_NET_POLL_CONTROLLER +	if (p->netpoll) +		netpoll_send_skb(p->netpoll, skb); +#else +	BUG(); +#endif +	return NETDEV_TX_OK;  } -static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb, -					struct net_device *dev) +static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev); +	struct sk_buff *nskb; + +	dev->stats.tx_packets++; +	dev->stats.tx_bytes += skb->len; + +	/* Transmit function may have to reallocate the original SKB */ +	nskb = p->xmit(skb, dev); +	if (!nskb) +		return NETDEV_TX_OK; -	skb->dev = p->parent->dst->master_netdev; -	dev_queue_xmit(skb); +	/* SKB for netpoll still need to be mangled with the protocol-specific +	 * tag to be successfully transmitted +	 */ +	if (unlikely(netpoll_tx_running(dev))) +		return dsa_netpoll_send_skb(p, nskb); + +	/* Queue the SKB for transmission on the parent interface, but +	 * do not modify its EtherType +	 */ +	nskb->dev = p->parent->dst->master_netdev; +	dev_queue_xmit(nskb);  	return NETDEV_TX_OK;  } +static struct sk_buff *dsa_slave_notag_xmit(struct sk_buff *skb, +					    struct net_device *dev) +{ +	/* Just return the original SKB */ +	return skb; +} +  /* ethtool operations *******************************************************/  static int @@ -665,6 +869,49 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)  	return ret;  } +#ifdef CONFIG_NET_POLL_CONTROLLER +static int dsa_slave_netpoll_setup(struct net_device *dev, +				   struct netpoll_info *ni) +{ +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; +	struct net_device *master = ds->dst->master_netdev; +	struct netpoll *netpoll; +	int err = 0; + +	netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL); +	if (!netpoll) +		return -ENOMEM; + +	err = __netpoll_setup(netpoll, master); +	if (err) { +		kfree(netpoll); +		goto out; +	} + +	p->netpoll = netpoll; +out: +	return err; +} + +static void dsa_slave_netpoll_cleanup(struct net_device *dev) +{ +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct netpoll *netpoll = p->netpoll; + +	if (!netpoll) +		return; + +	p->netpoll = NULL; + +	__netpoll_free_async(netpoll); +} + +static void dsa_slave_poll_controller(struct net_device *dev) +{ +} +#endif +  static const struct ethtool_ops dsa_slave_ethtool_ops = {  	.get_settings		= dsa_slave_get_settings,  	.set_settings		= dsa_slave_set_settings, @@ -692,16 +939,27 @@ static const struct net_device_ops dsa_slave_netdev_ops = {  	.ndo_change_rx_flags	= dsa_slave_change_rx_flags,  	.ndo_set_rx_mode	= dsa_slave_set_rx_mode,  	.ndo_set_mac_address	= dsa_slave_set_mac_address, -	.ndo_fdb_add		= dsa_slave_fdb_add, -	.ndo_fdb_del		= dsa_slave_fdb_del, -	.ndo_fdb_dump		= dsa_slave_fdb_dump, +	.ndo_fdb_add		= switchdev_port_fdb_add, +	.ndo_fdb_del		= switchdev_port_fdb_del, +	.ndo_fdb_dump		= switchdev_port_fdb_dump,  	.ndo_do_ioctl		= dsa_slave_ioctl,  	.ndo_get_iflink		= dsa_slave_get_iflink, +#ifdef CONFIG_NET_POLL_CONTROLLER +	.ndo_netpoll_setup	= dsa_slave_netpoll_setup, +	.ndo_netpoll_cleanup	= dsa_slave_netpoll_cleanup, +	.ndo_poll_controller	= dsa_slave_poll_controller, +#endif +	.ndo_bridge_getlink	= switchdev_port_bridge_getlink, +	.ndo_bridge_setlink	= switchdev_port_bridge_setlink, +	.ndo_bridge_dellink	= switchdev_port_bridge_dellink,  };  static const struct switchdev_ops dsa_slave_switchdev_ops = {  	.switchdev_port_attr_get	= dsa_slave_port_attr_get,  	.switchdev_port_attr_set	= dsa_slave_port_attr_set, +	.switchdev_port_obj_add		= dsa_slave_port_obj_add, +	.switchdev_port_obj_del		= dsa_slave_port_obj_del, +	.switchdev_port_obj_dump	= dsa_slave_port_obj_dump,  };  static void dsa_slave_adjust_link(struct net_device *dev) @@ -756,7 +1014,8 @@ static int dsa_slave_phy_connect(struct dsa_slave_priv *p,  		return -ENODEV;  	/* Use already configured phy mode */ -	p->phy_interface = p->phy->interface; +	if (p->phy_interface == PHY_INTERFACE_MODE_NA) +		p->phy_interface = p->phy->interface;  	phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,  			   p->phy_interface); @@ -888,7 +1147,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,  	slave_dev->features = master->vlan_features;  	slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;  	eth_hw_addr_inherit(slave_dev, master); -	slave_dev->tx_queue_len = 0; +	slave_dev->priv_flags |= IFF_NO_QUEUE;  	slave_dev->netdev_ops = &dsa_slave_netdev_ops;  	slave_dev->switchdev_ops = &dsa_slave_switchdev_ops; diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index 83d3572cdb20..e2aadb73111d 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -58,14 +58,11 @@  #define BRCM_EG_TC_MASK		0x7  #define BRCM_EG_PID_MASK	0x1f -static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev) +static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev);  	u8 *brcm_tag; -	dev->stats.tx_packets++; -	dev->stats.tx_bytes += skb->len; -  	if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)  		goto out_free; @@ -87,17 +84,11 @@ static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)  		brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;  	brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK; -	/* Queue the SKB for transmission on the parent interface, but -	 * do not modify its EtherType -	 */ -	skb->dev = p->parent->dst->master_netdev; -	dev_queue_xmit(skb); - -	return NETDEV_TX_OK; +	return skb;  out_free:  	kfree_skb(skb); -	return NETDEV_TX_OK; +	return NULL;  }  static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 2dab27063273..aa780e4ac0bd 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -15,14 +15,11 @@  #define DSA_HLEN	4 -static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev) +static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev);  	u8 *dsa_header; -	dev->stats.tx_packets++; -	dev->stats.tx_bytes += skb->len; -  	/*  	 * Convert the outermost 802.1q tag to a DSA tag for tagged  	 * packets, or insert a DSA tag between the addresses and @@ -63,14 +60,11 @@ static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)  		dsa_header[3] = 0x00;  	} -	skb->dev = p->parent->dst->master_netdev; -	dev_queue_xmit(skb); - -	return NETDEV_TX_OK; +	return skb;  out_free:  	kfree_skb(skb); -	return NETDEV_TX_OK; +	return NULL;  }  static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 9aeda596f7ec..2288c8098c42 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c @@ -16,14 +16,11 @@  #define DSA_HLEN	4  #define EDSA_HLEN	8 -static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) +static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev);  	u8 *edsa_header; -	dev->stats.tx_packets++; -	dev->stats.tx_bytes += skb->len; -  	/*  	 * Convert the outermost 802.1q tag to a DSA tag and prepend  	 * a DSA ethertype field is the packet is tagged, or insert @@ -76,14 +73,11 @@ static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)  		edsa_header[7] = 0x00;  	} -	skb->dev = p->parent->dst->master_netdev; -	dev_queue_xmit(skb); - -	return NETDEV_TX_OK; +	return skb;  out_free:  	kfree_skb(skb); -	return NETDEV_TX_OK; +	return NULL;  }  static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index e268f9db8893..d25efc93d8f1 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -13,16 +13,13 @@  #include <linux/slab.h>  #include "dsa_priv.h" -static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev) +static struct sk_buff *trailer_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct sk_buff *nskb;  	int padlen;  	u8 *trailer; -	dev->stats.tx_packets++; -	dev->stats.tx_bytes += skb->len; -  	/*  	 * We have to make sure that the trailer ends up as the very  	 * last 4 bytes of the packet.  This means that we have to pad @@ -36,7 +33,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)  	nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC);  	if (nskb == NULL) {  		kfree_skb(skb); -		return NETDEV_TX_OK; +		return NULL;  	}  	skb_reserve(nskb, NET_IP_ALIGN); @@ -57,10 +54,7 @@ static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)  	trailer[2] = 0x10;  	trailer[3] = 0x00; -	nskb->dev = p->parent->dst->master_netdev; -	dev_queue_xmit(nskb); - -	return NETDEV_TX_OK; +	return nskb;  }  static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,  |