[linux-next] LinuxNextTracking branch, master, updated. next-20160113

batman at open-mesh.org batman at open-mesh.org
Thu Jan 14 00:16:00 CET 2016


The following commit has been merged in the master branch:
commit 9d367eddf363553c7668ba92c3b9d187ec4f71f7
Merge: b6a0e72ad3cffabaf30b856deb58fbe64a0f36a8 03d84a5f83a67e692af00a3d3901e7820e3e84d5
Author: David S. Miller <davem at davemloft.net>
Date:   Mon Jan 11 23:55:43 2016 -0500

    Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
    
    Conflicts:
    	drivers/net/bonding/bond_main.c
    	drivers/net/ethernet/mellanox/mlxsw/spectrum.h
    	drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
    
    The bond_main.c and mellanox switch conflicts were cases of
    overlapping changes.
    
    Signed-off-by: David S. Miller <davem at davemloft.net>

diff --combined drivers/net/bonding/bond_main.c
index cab99fd,f1692e4..56b5605
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@@ -830,8 -830,7 +830,8 @@@ void bond_change_active_slave(struct bo
  			}
  
  			new_active->delay = 0;
 -			bond_set_slave_link_state(new_active, BOND_LINK_UP);
 +			bond_set_slave_link_state(new_active, BOND_LINK_UP,
 +						  BOND_SLAVE_NOTIFY_NOW);
  
  			if (BOND_MODE(bond) == BOND_MODE_8023AD)
  				bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
@@@ -1067,12 -1066,12 +1067,12 @@@ static netdev_features_t bond_fix_featu
  	return features;
  }
  
 -#define BOND_VLAN_FEATURES	(NETIF_F_ALL_CSUM | NETIF_F_SG | \
 +#define BOND_VLAN_FEATURES	(NETIF_F_HW_CSUM | NETIF_F_SG | \
  				 NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
  				 NETIF_F_HIGHDMA | NETIF_F_LRO)
  
 -#define BOND_ENC_FEATURES	(NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\
 -				 NETIF_F_ALL_TSO)
 +#define BOND_ENC_FEATURES	(NETIF_F_HW_CSUM | NETIF_F_SG | \
 +				 NETIF_F_RXCSUM | NETIF_F_ALL_TSO)
  
  static void bond_compute_features(struct bonding *bond)
  {
@@@ -1199,43 -1198,25 +1199,42 @@@ static rx_handler_result_t bond_handle_
  	return ret;
  }
  
 -static int bond_master_upper_dev_link(struct net_device *bond_dev,
 -				      struct net_device *slave_dev,
 -				      struct slave *slave)
 +static enum netdev_lag_tx_type bond_lag_tx_type(struct bonding *bond)
  {
 +	switch (BOND_MODE(bond)) {
 +	case BOND_MODE_ROUNDROBIN:
 +		return NETDEV_LAG_TX_TYPE_ROUNDROBIN;
 +	case BOND_MODE_ACTIVEBACKUP:
 +		return NETDEV_LAG_TX_TYPE_ACTIVEBACKUP;
 +	case BOND_MODE_BROADCAST:
 +		return NETDEV_LAG_TX_TYPE_BROADCAST;
 +	case BOND_MODE_XOR:
 +	case BOND_MODE_8023AD:
 +		return NETDEV_LAG_TX_TYPE_HASH;
 +	default:
 +		return NETDEV_LAG_TX_TYPE_UNKNOWN;
 +	}
 +}
 +
 +static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave)
 +{
 +	struct netdev_lag_upper_info lag_upper_info;
  	int err;
  
 -	err = netdev_master_upper_dev_link_private(slave_dev, bond_dev, slave);
 +	lag_upper_info.tx_type = bond_lag_tx_type(bond);
 +	err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave,
 +					   &lag_upper_info);
  	if (err)
  		return err;
- 	slave->dev->flags |= IFF_SLAVE;
 -	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL);
 +	rtmsg_ifinfo(RTM_NEWLINK, slave->dev, IFF_SLAVE, GFP_KERNEL);
  	return 0;
  }
  
 -static void bond_upper_dev_unlink(struct net_device *bond_dev,
 -				  struct net_device *slave_dev)
 +static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave)
  {
 -	netdev_upper_dev_unlink(slave_dev, bond_dev);
 -	slave_dev->flags &= ~IFF_SLAVE;
 -	rtmsg_ifinfo(RTM_NEWLINK, slave_dev, IFF_SLAVE, GFP_KERNEL);
 +	netdev_upper_dev_unlink(slave->dev, bond->dev);
 +	slave->dev->flags &= ~IFF_SLAVE;
 +	rtmsg_ifinfo(RTM_NEWLINK, slave->dev, IFF_SLAVE, GFP_KERNEL);
  }
  
  static struct slave *bond_alloc_slave(struct bonding *bond)
@@@ -1317,16 -1298,6 +1316,16 @@@ void bond_queue_slave_event(struct slav
  	queue_delayed_work(slave->bond->wq, &nnw->work, 0);
  }
  
 +void bond_lower_state_changed(struct slave *slave)
 +{
 +	struct netdev_lag_lower_state_info info;
 +
 +	info.link_up = slave->link == BOND_LINK_UP ||
 +		       slave->link == BOND_LINK_FAIL;
 +	info.tx_enabled = bond_is_active_slave(slave);
 +	netdev_lower_state_changed(slave->dev, &info);
 +}
 +
  /* enslave device <slave> to bond device <master> */
  int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
  {
@@@ -1379,7 -1350,7 +1378,7 @@@
  	 * the current ifenslave will set the interface down prior to
  	 * enslaving it; the old ifenslave will not.
  	 */
 -	if ((slave_dev->flags & IFF_UP)) {
 +	if (slave_dev->flags & IFF_UP) {
  		netdev_err(bond_dev, "%s is up - this may be due to an out of date ifenslave\n",
  			   slave_dev->name);
  		res = -EPERM;
@@@ -1493,6 -1464,9 +1492,9 @@@
  		}
  	}
  
+ 	/* set slave flag before open to prevent IPv6 addrconf */
+ 	slave_dev->flags |= IFF_SLAVE;
+ 
  	/* open the slave since the application closed it */
  	res = dev_open(slave_dev);
  	if (res) {
@@@ -1591,26 -1565,21 +1593,26 @@@
  		if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
  			if (bond->params.updelay) {
  				bond_set_slave_link_state(new_slave,
 -							  BOND_LINK_BACK);
 +							  BOND_LINK_BACK,
 +							  BOND_SLAVE_NOTIFY_NOW);
  				new_slave->delay = bond->params.updelay;
  			} else {
  				bond_set_slave_link_state(new_slave,
 -							  BOND_LINK_UP);
 +							  BOND_LINK_UP,
 +							  BOND_SLAVE_NOTIFY_NOW);
  			}
  		} else {
 -			bond_set_slave_link_state(new_slave, BOND_LINK_DOWN);
 +			bond_set_slave_link_state(new_slave, BOND_LINK_DOWN,
 +						  BOND_SLAVE_NOTIFY_NOW);
  		}
  	} else if (bond->params.arp_interval) {
  		bond_set_slave_link_state(new_slave,
  					  (netif_carrier_ok(slave_dev) ?
 -					  BOND_LINK_UP : BOND_LINK_DOWN));
 +					  BOND_LINK_UP : BOND_LINK_DOWN),
 +					  BOND_SLAVE_NOTIFY_NOW);
  	} else {
 -		bond_set_slave_link_state(new_slave, BOND_LINK_UP);
 +		bond_set_slave_link_state(new_slave, BOND_LINK_UP,
 +					  BOND_SLAVE_NOTIFY_NOW);
  	}
  
  	if (new_slave->link != BOND_LINK_DOWN)
@@@ -1695,7 -1664,7 +1697,7 @@@
  		goto err_detach;
  	}
  
 -	res = bond_master_upper_dev_link(bond_dev, slave_dev, new_slave);
 +	res = bond_master_upper_dev_link(bond, new_slave);
  	if (res) {
  		netdev_dbg(bond_dev, "Error %d calling bond_master_upper_dev_link\n", res);
  		goto err_unregister;
@@@ -1731,7 -1700,7 +1733,7 @@@
  
  /* Undo stages on error */
  err_upper_unlink:
 -	bond_upper_dev_unlink(bond_dev, slave_dev);
 +	bond_upper_dev_unlink(bond, new_slave);
  
  err_unregister:
  	netdev_rx_handler_unregister(slave_dev);
@@@ -1758,6 -1727,7 +1760,7 @@@ err_close
  	dev_close(slave_dev);
  
  err_restore_mac:
+ 	slave_dev->flags &= ~IFF_SLAVE;
  	if (!bond->params.fail_over_mac ||
  	    BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
  		/* XXX TODO - fom follow mode needs to change master's
@@@ -1832,14 -1802,12 +1835,14 @@@ static int __bond_release_one(struct ne
  		return -EINVAL;
  	}
  
 +	bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW);
 +
  	bond_sysfs_slave_del(slave);
  
  	/* recompute stats just before removing the slave */
  	bond_get_stats(bond->dev, &bond->bond_stats);
  
 -	bond_upper_dev_unlink(bond_dev, slave_dev);
 +	bond_upper_dev_unlink(bond, slave);
  	/* unregister rx_handler early so bond_handle_frame wouldn't be called
  	 * for this slave anymore.
  	 */
@@@ -2031,8 -1999,7 +2034,8 @@@ static int bond_miimon_inspect(struct b
  			if (link_state)
  				continue;
  
 -			bond_set_slave_link_state(slave, BOND_LINK_FAIL);
 +			bond_set_slave_link_state(slave, BOND_LINK_FAIL,
 +						  BOND_SLAVE_NOTIFY_LATER);
  			slave->delay = bond->params.downdelay;
  			if (slave->delay) {
  				netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
@@@ -2047,8 -2014,7 +2050,8 @@@
  		case BOND_LINK_FAIL:
  			if (link_state) {
  				/* recovered before downdelay expired */
 -				bond_set_slave_link_state(slave, BOND_LINK_UP);
 +				bond_set_slave_link_state(slave, BOND_LINK_UP,
 +							  BOND_SLAVE_NOTIFY_LATER);
  				slave->last_link_up = jiffies;
  				netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
  					    (bond->params.downdelay - slave->delay) *
@@@ -2070,8 -2036,7 +2073,8 @@@
  			if (!link_state)
  				continue;
  
 -			bond_set_slave_link_state(slave, BOND_LINK_BACK);
 +			bond_set_slave_link_state(slave, BOND_LINK_BACK,
 +						  BOND_SLAVE_NOTIFY_LATER);
  			slave->delay = bond->params.updelay;
  
  			if (slave->delay) {
@@@ -2085,8 -2050,7 +2088,8 @@@
  		case BOND_LINK_BACK:
  			if (!link_state) {
  				bond_set_slave_link_state(slave,
 -							  BOND_LINK_DOWN);
 +							  BOND_LINK_DOWN,
 +							  BOND_SLAVE_NOTIFY_LATER);
  				netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
  					    (bond->params.updelay - slave->delay) *
  					    bond->params.miimon,
@@@ -2124,8 -2088,7 +2127,8 @@@ static void bond_miimon_commit(struct b
  			continue;
  
  		case BOND_LINK_UP:
 -			bond_set_slave_link_state(slave, BOND_LINK_UP);
 +			bond_set_slave_link_state(slave, BOND_LINK_UP,
 +						  BOND_SLAVE_NOTIFY_NOW);
  			slave->last_link_up = jiffies;
  
  			primary = rtnl_dereference(bond->primary_slave);
@@@ -2165,8 -2128,7 +2168,8 @@@
  			if (slave->link_failure_count < UINT_MAX)
  				slave->link_failure_count++;
  
 -			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
 +			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
 +						  BOND_SLAVE_NOTIFY_NOW);
  
  			if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
  			    BOND_MODE(bond) == BOND_MODE_8023AD)
@@@ -2749,8 -2711,7 +2752,8 @@@ static void bond_ab_arp_commit(struct b
  				struct slave *current_arp_slave;
  
  				current_arp_slave = rtnl_dereference(bond->current_arp_slave);
 -				bond_set_slave_link_state(slave, BOND_LINK_UP);
 +				bond_set_slave_link_state(slave, BOND_LINK_UP,
 +							  BOND_SLAVE_NOTIFY_NOW);
  				if (current_arp_slave) {
  					bond_set_slave_inactive_flags(
  						current_arp_slave,
@@@ -2773,8 -2734,7 +2776,8 @@@
  			if (slave->link_failure_count < UINT_MAX)
  				slave->link_failure_count++;
  
 -			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
 +			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
 +						  BOND_SLAVE_NOTIFY_NOW);
  			bond_set_slave_inactive_flags(slave,
  						      BOND_SLAVE_NOTIFY_NOW);
  
@@@ -2853,8 -2813,7 +2856,8 @@@ static bool bond_ab_arp_probe(struct bo
  		 * up when it is actually down
  		 */
  		if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
 -			bond_set_slave_link_state(slave, BOND_LINK_DOWN);
 +			bond_set_slave_link_state(slave, BOND_LINK_DOWN,
 +						  BOND_SLAVE_NOTIFY_LATER);
  			if (slave->link_failure_count < UINT_MAX)
  				slave->link_failure_count++;
  
@@@ -2874,8 -2833,7 +2877,8 @@@
  	if (!new_slave)
  		goto check_state;
  
 -	bond_set_slave_link_state(new_slave, BOND_LINK_BACK);
 +	bond_set_slave_link_state(new_slave, BOND_LINK_BACK,
 +				  BOND_SLAVE_NOTIFY_LATER);
  	bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
  	bond_arp_send_all(bond, new_slave);
  	new_slave->last_link_up = jiffies;
@@@ -2883,7 -2841,7 +2886,7 @@@
  
  check_state:
  	bond_for_each_slave_rcu(bond, slave, iter) {
 -		if (slave->should_notify) {
 +		if (slave->should_notify || slave->should_notify_link) {
  			should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
  			break;
  		}
@@@ -2938,10 -2896,8 +2941,10 @@@ re_arm
  		if (should_notify_peers)
  			call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
  						 bond->dev);
 -		if (should_notify_rtnl)
 +		if (should_notify_rtnl) {
  			bond_slave_state_notify(bond);
 +			bond_slave_link_notify(bond);
 +		}
  
  		rtnl_unlock();
  	}
@@@ -4182,6 -4138,7 +4185,6 @@@ void bond_setup(struct net_device *bond
  				NETIF_F_HW_VLAN_CTAG_RX |
  				NETIF_F_HW_VLAN_CTAG_FILTER;
  
 -	bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
  	bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
  	bond_dev->features |= bond_dev->hw_features;
  }
diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 199f91a,69281ca..a23dc61
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@@ -41,73 -41,16 +41,73 @@@
  #include <linux/netdevice.h>
  #include <linux/bitops.h>
  #include <linux/if_vlan.h>
 +#include <linux/list.h>
  #include <net/switchdev.h>
  
 +#include "port.h"
  #include "core.h"
  
  #define MLXSW_SP_VFID_BASE VLAN_N_VID
 +#define MLXSW_SP_VFID_PORT_MAX 512	/* Non-bridged VLAN interfaces */
 +#define MLXSW_SP_VFID_BR_MAX 8192	/* Bridged VLAN interfaces */
 +#define MLXSW_SP_VFID_MAX (MLXSW_SP_VFID_PORT_MAX + MLXSW_SP_VFID_BR_MAX)
 +
 +#define MLXSW_SP_LAG_MAX 64
 +#define MLXSW_SP_PORT_PER_LAG_MAX 16
 +
 +#define MLXSW_SP_MID_MAX 7000
  
  struct mlxsw_sp_port;
  
 +struct mlxsw_sp_upper {
 +	struct net_device *dev;
 +	unsigned int ref_count;
 +};
 +
 +struct mlxsw_sp_vfid {
 +	struct list_head list;
 +	u16 nr_vports;
 +	u16 vfid;	/* Starting at 0 */
 +	struct net_device *br_dev;
 +	u16 vid;
 +};
 +
 +struct mlxsw_sp_mid {
 +	struct list_head list;
 +	unsigned char addr[ETH_ALEN];
 +	u16 vid;
 +	u16 mid;
 +	unsigned int ref_count;
 +};
 +
 +static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid)
 +{
 +	return MLXSW_SP_VFID_BASE + vfid;
 +}
 +
 +static inline u16 mlxsw_sp_fid_to_vfid(u16 fid)
 +{
 +	return fid - MLXSW_SP_VFID_BASE;
 +}
 +
 +static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
 +{
 +	return fid >= MLXSW_SP_VFID_BASE;
 +}
 +
  struct mlxsw_sp {
 -	unsigned long active_vfids[BITS_TO_LONGS(VLAN_N_VID)];
 +	struct {
 +		struct list_head list;
 +		unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_PORT_MAX)];
 +	} port_vfids;
 +	struct {
 +		struct list_head list;
 +		unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_BR_MAX)];
 +	} br_vfids;
 +	struct {
 +		struct list_head list;
 +		unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_MID_MAX)];
 +	} br_mids;
  	unsigned long active_fids[BITS_TO_LONGS(VLAN_N_VID)];
  	struct mlxsw_sp_port **ports;
  	struct mlxsw_core *core;
@@@ -120,16 -63,13 +120,17 @@@
  	} fdb_notify;
  #define MLXSW_SP_DEFAULT_AGEING_TIME 300
  	u32 ageing_time;
+ 	struct mutex fdb_lock;	/* Make sure FDB sessions are atomic. */
 -	struct {
 -		struct net_device *dev;
 -		unsigned int ref_count;
 -	} master_bridge;
 +	struct mlxsw_sp_upper master_bridge;
 +	struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX];
  };
  
 +static inline struct mlxsw_sp_upper *
 +mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
 +{
 +	return &mlxsw_sp->lags[lag_id];
 +}
 +
  struct mlxsw_sp_port_pcpu_stats {
  	u64			rx_packets;
  	u64			rx_bytes;
@@@ -148,87 -88,15 +149,87 @@@ struct mlxsw_sp_port 
  	u8 learning:1,
  	   learning_sync:1,
  	   uc_flood:1,
 -	   bridged:1;
 +	   bridged:1,
 +	   lagged:1;
  	u16 pvid;
 +	u16 lag_id;
 +	struct {
 +		struct list_head list;
 +		struct mlxsw_sp_vfid *vfid;
 +		u16 vid;
 +	} vport;
  	/* 802.1Q bridge VLANs */
 -	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 +	unsigned long *active_vlans;
 +	unsigned long *untagged_vlans;
  	/* VLAN interfaces */
 -	unsigned long active_vfids[BITS_TO_LONGS(VLAN_N_VID)];
 -	u16 nr_vfids;
 +	struct list_head vports_list;
  };
  
 +static inline struct mlxsw_sp_port *
 +mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_port;
 +	u8 local_port;
 +
 +	local_port = mlxsw_core_lag_mapping_get(mlxsw_sp->core,
 +						lag_id, port_index);
 +	mlxsw_sp_port = mlxsw_sp->ports[local_port];
 +	return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL;
 +}
 +
 +static inline bool
 +mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port)
 +{
 +	return mlxsw_sp_port->vport.vfid;
 +}
 +
 +static inline struct net_device *
 +mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 +{
 +	return mlxsw_sp_vport->vport.vfid->br_dev;
 +}
 +
 +static inline u16
 +mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 +{
 +	return mlxsw_sp_vport->vport.vid;
 +}
 +
 +static inline u16
 +mlxsw_sp_vport_vfid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
 +{
 +	return mlxsw_sp_vport->vport.vfid->vfid;
 +}
 +
 +static inline struct mlxsw_sp_port *
 +mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_vport;
 +
 +	list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
 +			    vport.list) {
 +		if (mlxsw_sp_vport_vid_get(mlxsw_sp_vport) == vid)
 +			return mlxsw_sp_vport;
 +	}
 +
 +	return NULL;
 +}
 +
 +static inline struct mlxsw_sp_port *
 +mlxsw_sp_port_vport_find_by_vfid(const struct mlxsw_sp_port *mlxsw_sp_port,
 +				 u16 vfid)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_vport;
 +
 +	list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
 +			    vport.list) {
 +		if (mlxsw_sp_vport_vfid_get(mlxsw_sp_vport) == vfid)
 +			return mlxsw_sp_vport;
 +	}
 +
 +	return NULL;
 +}
 +
  enum mlxsw_sp_flood_table {
  	MLXSW_SP_FLOOD_TABLE_UC,
  	MLXSW_SP_FLOOD_TABLE_BM,
@@@ -251,7 -119,5 +252,7 @@@ int mlxsw_sp_port_add_vid(struct net_de
  			  u16 vid);
  int mlxsw_sp_port_kill_vid(struct net_device *dev,
  			   __be16 __always_unused proto, u16 vid);
 +int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
 +			     bool set, bool only_uc);
  
  #endif
diff --combined drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 4cdc18e,80e2660..ffe894e
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@@ -51,50 -51,12 +51,50 @@@
  #include "core.h"
  #include "reg.h"
  
 +static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port,
 +					u16 vid)
 +{
 +	u16 fid = vid;
 +
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		u16 vfid = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
 +
 +		fid = mlxsw_sp_vfid_to_fid(vfid);
 +	}
 +
 +	if (!fid)
 +		fid = mlxsw_sp_port->pvid;
 +
 +	return fid;
 +}
 +
 +static struct mlxsw_sp_port *
 +mlxsw_sp_port_orig_get(struct net_device *dev,
 +		       struct mlxsw_sp_port *mlxsw_sp_port)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_vport;
 +	u16 vid;
 +
 +	if (!is_vlan_dev(dev))
 +		return mlxsw_sp_port;
 +
 +	vid = vlan_dev_vlan_id(dev);
 +	mlxsw_sp_vport = mlxsw_sp_port_vport_find(mlxsw_sp_port, vid);
 +	WARN_ON(!mlxsw_sp_vport);
 +
 +	return mlxsw_sp_vport;
 +}
 +
  static int mlxsw_sp_port_attr_get(struct net_device *dev,
  				  struct switchdev_attr *attr)
  {
  	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  
 +	mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port);
 +	if (!mlxsw_sp_port)
 +		return -EINVAL;
 +
  	switch (attr->id) {
  	case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
  		attr->u.ppid.id_len = sizeof(mlxsw_sp->base_mac);
@@@ -143,14 -105,8 +143,14 @@@ static int mlxsw_sp_port_stp_state_set(
  	if (!spms_pl)
  		return -ENOMEM;
  	mlxsw_reg_spms_pack(spms_pl, mlxsw_sp_port->local_port);
 -	for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID)
 +
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
  		mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
 +	} else {
 +		for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID)
 +			mlxsw_reg_spms_vid_pack(spms_pl, vid, spms_state);
 +	}
  
  	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spms), spms_pl);
  	kfree(spms_pl);
@@@ -168,38 -124,22 +168,38 @@@ static int mlxsw_sp_port_attr_stp_state
  	return mlxsw_sp_port_stp_state_set(mlxsw_sp_port, state);
  }
  
 +static bool mlxsw_sp_vfid_is_vport_br(u16 vfid)
 +{
 +	return vfid >= MLXSW_SP_VFID_PORT_MAX;
 +}
 +
  static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
 -				     u16 fid_begin, u16 fid_end, bool set,
 +				     u16 idx_begin, u16 idx_end, bool set,
  				     bool only_uc)
  {
  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 -	u16 range = fid_end - fid_begin + 1;
 +	u16 local_port = mlxsw_sp_port->local_port;
 +	enum mlxsw_flood_table_type table_type;
 +	u16 range = idx_end - idx_begin + 1;
  	char *sftr_pl;
  	int err;
  
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID;
 +		if (mlxsw_sp_vfid_is_vport_br(idx_begin))
 +			local_port = mlxsw_sp_port->local_port;
 +		else
 +			local_port = MLXSW_PORT_CPU_PORT;
 +	} else {
 +		table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST;
 +	}
 +
  	sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
  	if (!sftr_pl)
  		return -ENOMEM;
  
 -	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, fid_begin,
 -			    MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
 -			    mlxsw_sp_port->local_port, set);
 +	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
 +			    table_type, range, local_port, set);
  	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
  	if (err)
  		goto buffer_out;
@@@ -210,8 -150,9 +210,8 @@@
  	if (only_uc)
  		goto buffer_out;
  
 -	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, fid_begin,
 -			    MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, range,
 -			    mlxsw_sp_port->local_port, set);
 +	mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, idx_begin,
 +			    table_type, range, local_port, set);
  	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
  
  buffer_out:
@@@ -226,13 -167,6 +226,13 @@@ static int mlxsw_sp_port_uc_flood_set(s
  	u16 vid, last_visited_vid;
  	int err;
  
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		u16 vfid = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
 +
 +		return  __mlxsw_sp_port_flood_set(mlxsw_sp_port, vfid, vfid,
 +						  set, true);
 +	}
 +
  	for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) {
  		err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid, vid, set,
  						true);
@@@ -251,16 -185,6 +251,16 @@@ err_port_flood_set
  	return err;
  }
  
 +int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
 +			     bool set, bool only_uc)
 +{
 +	/* In case of vFIDs, index into the flooding table is relative to
 +	 * the start of the vFIDs range.
 +	 */
 +	return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set,
 +					 only_uc);
 +}
 +
  static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
  					   struct switchdev_trans *trans,
  					   unsigned long brport_flags)
@@@ -269,9 -193,6 +269,9 @@@
  	bool set;
  	int err;
  
 +	if (!mlxsw_sp_port->bridged)
 +		return -EINVAL;
 +
  	if (switchdev_trans_ph_prepare(trans))
  		return 0;
  
@@@ -316,22 -237,6 +316,22 @@@ static int mlxsw_sp_port_attr_br_ageing
  	return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
  }
  
 +static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
 +					  struct switchdev_trans *trans,
 +					  struct net_device *orig_dev,
 +					  bool vlan_enabled)
 +{
 +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +
 +	/* SWITCHDEV_TRANS_PREPARE phase */
 +	if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) {
 +		netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n");
 +		return -EINVAL;
 +	}
 +
 +	return 0;
 +}
 +
  static int mlxsw_sp_port_attr_set(struct net_device *dev,
  				  const struct switchdev_attr *attr,
  				  struct switchdev_trans *trans)
@@@ -339,10 -244,6 +339,10 @@@
  	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  	int err = 0;
  
 +	mlxsw_sp_port = mlxsw_sp_port_orig_get(attr->orig_dev, mlxsw_sp_port);
 +	if (!mlxsw_sp_port)
 +		return -EINVAL;
 +
  	switch (attr->id) {
  	case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
  		err = mlxsw_sp_port_attr_stp_state_set(mlxsw_sp_port, trans,
@@@ -356,11 -257,6 +356,11 @@@
  		err = mlxsw_sp_port_attr_br_ageing_set(mlxsw_sp_port, trans,
  						       attr->u.ageing_time);
  		break;
 +	case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
 +		err = mlxsw_sp_port_attr_br_vlan_set(mlxsw_sp_port, trans,
 +						     attr->orig_dev,
 +						     attr->u.vlan_filtering);
 +		break;
  	default:
  		err = -EOPNOTSUPP;
  		break;
@@@ -408,7 -304,7 +408,7 @@@ static int mlxsw_sp_port_fid_map(struc
  {
  	enum mlxsw_reg_svfa_mt mt;
  
 -	if (mlxsw_sp_port->nr_vfids)
 +	if (!list_empty(&mlxsw_sp_port->vports_list))
  		mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
  	else
  		mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
@@@ -420,7 -316,7 +420,7 @@@ static int mlxsw_sp_port_fid_unmap(stru
  {
  	enum mlxsw_reg_svfa_mt mt;
  
 -	if (!mlxsw_sp_port->nr_vfids)
 +	if (list_empty(&mlxsw_sp_port->vports_list))
  		return 0;
  
  	mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
@@@ -446,35 -342,14 +446,35 @@@ err_port_add_vid
  	return err;
  }
  
 +static int __mlxsw_sp_port_vlans_set(struct mlxsw_sp_port *mlxsw_sp_port,
 +				     u16 vid_begin, u16 vid_end, bool is_member,
 +				     bool untagged)
 +{
 +	u16 vid, vid_e;
 +	int err;
 +
 +	for (vid = vid_begin; vid <= vid_end;
 +	     vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {
 +		vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),
 +			    vid_end);
 +
 +		err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e,
 +					     is_member, untagged);
 +		if (err)
 +			return err;
 +	}
 +
 +	return 0;
 +}
 +
  static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
  				     u16 vid_begin, u16 vid_end,
  				     bool flag_untagged, bool flag_pvid)
  {
  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
  	struct net_device *dev = mlxsw_sp_port->dev;
 +	u16 vid, last_visited_vid, old_pvid;
  	enum mlxsw_reg_svfa_mt mt;
 -	u16 vid, vid_e;
  	int err;
  
  	/* In case this is invoked with BRIDGE_FLAGS_SELF and port is
@@@ -502,18 -377,15 +502,18 @@@
  			if (err) {
  				netdev_err(dev, "Failed to create FID=VID=%d mapping\n",
  					   vid);
 -				return err;
 +				goto err_port_vid_to_fid_set;
  			}
  		}
 +	}
  
 -		/* Set FID mapping according to port's mode */
 +	/* Set FID mapping according to port's mode */
 +	for (vid = vid_begin; vid <= vid_end; vid++) {
  		err = mlxsw_sp_port_fid_map(mlxsw_sp_port, vid);
  		if (err) {
  			netdev_err(dev, "Failed to map FID=%d", vid);
 -			return err;
 +			last_visited_vid = --vid;
 +			goto err_port_fid_map;
  		}
  	}
  
@@@ -521,133 -393,83 +521,133 @@@
  					true, false);
  	if (err) {
  		netdev_err(dev, "Failed to configure flooding\n");
 -		return err;
 +		goto err_port_flood_set;
  	}
  
 -	for (vid = vid_begin; vid <= vid_end;
 -	     vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {
 -		vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),
 -			    vid_end);
 -
 -		err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e, true,
 -					     flag_untagged);
 -		if (err) {
 -			netdev_err(mlxsw_sp_port->dev, "Unable to add VIDs %d-%d\n",
 -				   vid, vid_e);
 -			return err;
 -		}
 +	err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end,
 +					true, flag_untagged);
 +	if (err) {
 +		netdev_err(dev, "Unable to add VIDs %d-%d\n", vid_begin,
 +			   vid_end);
 +		goto err_port_vlans_set;
  	}
  
 -	vid = vid_begin;
 -	if (flag_pvid && mlxsw_sp_port->pvid != vid) {
 -		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid);
 +	old_pvid = mlxsw_sp_port->pvid;
 +	if (flag_pvid && old_pvid != vid_begin) {
 +		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid_begin);
  		if (err) {
 -			netdev_err(mlxsw_sp_port->dev, "Unable to add PVID %d\n",
 -				   vid);
 -			return err;
 +			netdev_err(dev, "Unable to add PVID %d\n", vid_begin);
 +			goto err_port_pvid_set;
  		}
 -		mlxsw_sp_port->pvid = vid;
 +		mlxsw_sp_port->pvid = vid_begin;
  	}
  
  	/* Changing activity bits only if HW operation succeded */
 -	for (vid = vid_begin; vid <= vid_end; vid++)
 +	for (vid = vid_begin; vid <= vid_end; vid++) {
  		set_bit(vid, mlxsw_sp_port->active_vlans);
 +		if (flag_untagged)
 +			set_bit(vid, mlxsw_sp_port->untagged_vlans);
 +		else
 +			clear_bit(vid, mlxsw_sp_port->untagged_vlans);
 +	}
  
 -	return mlxsw_sp_port_stp_state_set(mlxsw_sp_port,
 -					   mlxsw_sp_port->stp_state);
 +	/* STP state change must be done after we set active VLANs */
 +	err = mlxsw_sp_port_stp_state_set(mlxsw_sp_port,
 +					  mlxsw_sp_port->stp_state);
 +	if (err) {
 +		netdev_err(dev, "Failed to set STP state\n");
 +		goto err_port_stp_state_set;
 +	}
 +
 +	return 0;
 +
 +err_port_vid_to_fid_set:
 +	mlxsw_sp_fid_destroy(mlxsw_sp, vid);
 +	return err;
 +
 +err_port_stp_state_set:
 +	for (vid = vid_begin; vid <= vid_end; vid++)
 +		clear_bit(vid, mlxsw_sp_port->active_vlans);
 +	if (old_pvid != mlxsw_sp_port->pvid)
 +		mlxsw_sp_port_pvid_set(mlxsw_sp_port, old_pvid);
 +err_port_pvid_set:
 +	__mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end, false,
 +				  false);
 +err_port_vlans_set:
 +	__mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end, false,
 +				  false);
 +err_port_flood_set:
 +	last_visited_vid = vid_end;
 +err_port_fid_map:
 +	for (vid = last_visited_vid; vid >= vid_begin; vid--)
 +		mlxsw_sp_port_fid_unmap(mlxsw_sp_port, vid);
 +	return err;
  }
  
  static int mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
  				   const struct switchdev_obj_port_vlan *vlan,
  				   struct switchdev_trans *trans)
  {
 -	bool untagged_flag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
 -	bool pvid_flag = vlan->flags & BRIDGE_VLAN_INFO_PVID;
 +	bool flag_untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
 +	bool flag_pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
  
  	if (switchdev_trans_ph_prepare(trans))
  		return 0;
  
  	return __mlxsw_sp_port_vlans_add(mlxsw_sp_port,
  					 vlan->vid_begin, vlan->vid_end,
 -					 untagged_flag, pvid_flag);
 +					 flag_untagged, flag_pvid);
 +}
 +
 +static enum mlxsw_reg_sfd_rec_policy mlxsw_sp_sfd_rec_policy(bool dynamic)
 +{
 +	return dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
 +			 MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY;
 +}
 +
 +static enum mlxsw_reg_sfd_op mlxsw_sp_sfd_op(bool adding)
 +{
 +	return adding ? MLXSW_REG_SFD_OP_WRITE_EDIT :
 +			MLXSW_REG_SFD_OP_WRITE_REMOVE;
  }
  
 -static int mlxsw_sp_port_fdb_op(struct mlxsw_sp_port *mlxsw_sp_port,
 -				const char *mac, u16 vid, bool adding,
 -				bool dynamic)
 +static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
 +				   const char *mac, u16 fid, bool adding,
 +				   bool dynamic)
  {
 -	enum mlxsw_reg_sfd_rec_policy policy;
 -	enum mlxsw_reg_sfd_op op;
  	char *sfd_pl;
  	int err;
  
 -	if (!vid)
 -		vid = mlxsw_sp_port->pvid;
 +	sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
 +	if (!sfd_pl)
 +		return -ENOMEM;
 +
 +	mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
 +	mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
 +			      mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
 +			      local_port);
 +	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
 +	kfree(sfd_pl);
 +
 +	return err;
 +}
 +
 +static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
 +				       const char *mac, u16 fid, u16 lag_vid,
 +				       bool adding, bool dynamic)
 +{
 +	char *sfd_pl;
 +	int err;
  
  	sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
  	if (!sfd_pl)
  		return -ENOMEM;
  
 -	policy = dynamic ? MLXSW_REG_SFD_REC_POLICY_DYNAMIC_ENTRY_INGRESS :
 -			   MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY;
 -	op = adding ? MLXSW_REG_SFD_OP_WRITE_EDIT :
 -		      MLXSW_REG_SFD_OP_WRITE_REMOVE;
 -	mlxsw_reg_sfd_pack(sfd_pl, op, 0);
 -	mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy,
 -			      mac, vid, MLXSW_REG_SFD_REC_ACTION_NOP,
 -			      mlxsw_sp_port->local_port);
 -	err = mlxsw_reg_write(mlxsw_sp_port->mlxsw_sp->core, MLXSW_REG(sfd),
 -			      sfd_pl);
 +	mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
 +	mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
 +				  mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
 +				  lag_vid, lag_id);
 +	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
  	kfree(sfd_pl);
  
  	return err;
@@@ -658,162 -480,11 +658,162 @@@ mlxsw_sp_port_fdb_static_add(struct mlx
  			     const struct switchdev_obj_port_fdb *fdb,
  			     struct switchdev_trans *trans)
  {
 +	u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid);
 +	u16 lag_vid = 0;
 +
 +	if (switchdev_trans_ph_prepare(trans))
 +		return 0;
 +
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
 +	}
 +
 +	if (!mlxsw_sp_port->lagged)
 +		return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp,
 +					       mlxsw_sp_port->local_port,
 +					       fdb->addr, fid, true, false);
 +	else
 +		return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp,
 +						   mlxsw_sp_port->lag_id,
 +						   fdb->addr, fid, lag_vid,
 +						   true, false);
 +}
 +
 +static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
 +				u16 fid, u16 mid, bool adding)
 +{
 +	char *sfd_pl;
 +	int err;
 +
 +	sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
 +	if (!sfd_pl)
 +		return -ENOMEM;
 +
 +	mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
 +	mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
 +			      MLXSW_REG_SFD_REC_ACTION_NOP, mid);
 +	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
 +	kfree(sfd_pl);
 +	return err;
 +}
 +
 +static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 mid,
 +				  bool add, bool clear_all_ports)
 +{
 +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +	char *smid_pl;
 +	int err, i;
 +
 +	smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL);
 +	if (!smid_pl)
 +		return -ENOMEM;
 +
 +	mlxsw_reg_smid_pack(smid_pl, mid, mlxsw_sp_port->local_port, add);
 +	if (clear_all_ports) {
 +		for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++)
 +			if (mlxsw_sp->ports[i])
 +				mlxsw_reg_smid_port_mask_set(smid_pl, i, 1);
 +	}
 +	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid), smid_pl);
 +	kfree(smid_pl);
 +	return err;
 +}
 +
 +static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp,
 +					      const unsigned char *addr,
 +					      u16 vid)
 +{
 +	struct mlxsw_sp_mid *mid;
 +
 +	list_for_each_entry(mid, &mlxsw_sp->br_mids.list, list) {
 +		if (ether_addr_equal(mid->addr, addr) && mid->vid == vid)
 +			return mid;
 +	}
 +	return NULL;
 +}
 +
 +static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
 +						const unsigned char *addr,
 +						u16 vid)
 +{
 +	struct mlxsw_sp_mid *mid;
 +	u16 mid_idx;
 +
 +	mid_idx = find_first_zero_bit(mlxsw_sp->br_mids.mapped,
 +				      MLXSW_SP_MID_MAX);
 +	if (mid_idx == MLXSW_SP_MID_MAX)
 +		return NULL;
 +
 +	mid = kzalloc(sizeof(*mid), GFP_KERNEL);
 +	if (!mid)
 +		return NULL;
 +
 +	set_bit(mid_idx, mlxsw_sp->br_mids.mapped);
 +	ether_addr_copy(mid->addr, addr);
 +	mid->vid = vid;
 +	mid->mid = mid_idx;
 +	mid->ref_count = 0;
 +	list_add_tail(&mid->list, &mlxsw_sp->br_mids.list);
 +
 +	return mid;
 +}
 +
 +static int __mlxsw_sp_mc_dec_ref(struct mlxsw_sp *mlxsw_sp,
 +				 struct mlxsw_sp_mid *mid)
 +{
 +	if (--mid->ref_count == 0) {
 +		list_del(&mid->list);
 +		clear_bit(mid->mid, mlxsw_sp->br_mids.mapped);
 +		kfree(mid);
 +		return 1;
 +	}
 +	return 0;
 +}
 +
 +static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
 +				 const struct switchdev_obj_port_mdb *mdb,
 +				 struct switchdev_trans *trans)
 +{
 +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +	struct net_device *dev = mlxsw_sp_port->dev;
 +	struct mlxsw_sp_mid *mid;
 +	u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid);
 +	int err = 0;
 +
  	if (switchdev_trans_ph_prepare(trans))
  		return 0;
  
 -	return mlxsw_sp_port_fdb_op(mlxsw_sp_port, fdb->addr, fdb->vid,
 -				    true, false);
 +	mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, mdb->vid);
 +	if (!mid) {
 +		mid = __mlxsw_sp_mc_alloc(mlxsw_sp, mdb->addr, mdb->vid);
 +		if (!mid) {
 +			netdev_err(dev, "Unable to allocate MC group\n");
 +			return -ENOMEM;
 +		}
 +	}
 +	mid->ref_count++;
 +
 +	err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, true,
 +				     mid->ref_count == 1);
 +	if (err) {
 +		netdev_err(dev, "Unable to set SMID\n");
 +		goto err_out;
 +	}
 +
 +	if (mid->ref_count == 1) {
 +		err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid->mid,
 +					   true);
 +		if (err) {
 +			netdev_err(dev, "Unable to set MC SFD\n");
 +			goto err_out;
 +		}
 +	}
 +
 +	return 0;
 +
 +err_out:
 +	__mlxsw_sp_mc_dec_ref(mlxsw_sp, mid);
 +	return err;
  }
  
  static int mlxsw_sp_port_obj_add(struct net_device *dev,
@@@ -823,15 -494,8 +823,15 @@@
  	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  	int err = 0;
  
 +	mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port);
 +	if (!mlxsw_sp_port)
 +		return -EINVAL;
 +
  	switch (obj->id) {
  	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 +		if (mlxsw_sp_port_is_vport(mlxsw_sp_port))
 +			return 0;
 +
  		err = mlxsw_sp_port_vlans_add(mlxsw_sp_port,
  					      SWITCHDEV_OBJ_PORT_VLAN(obj),
  					      trans);
@@@ -841,11 -505,6 +841,11 @@@
  						   SWITCHDEV_OBJ_PORT_FDB(obj),
  						   trans);
  		break;
 +	case SWITCHDEV_OBJ_ID_PORT_MDB:
 +		err = mlxsw_sp_port_mdb_add(mlxsw_sp_port,
 +					    SWITCHDEV_OBJ_PORT_MDB(obj),
 +					    trans);
 +		break;
  	default:
  		err = -EOPNOTSUPP;
  		break;
@@@ -873,7 -532,7 +873,7 @@@ static int __mlxsw_sp_port_vlans_del(st
  				     u16 vid_begin, u16 vid_end, bool init)
  {
  	struct net_device *dev = mlxsw_sp_port->dev;
 -	u16 vid, vid_e;
 +	u16 vid, pvid;
  	int err;
  
  	/* In case this is invoked with BRIDGE_FLAGS_SELF and port is
@@@ -883,23 -542,30 +883,23 @@@
  	if (!init && !mlxsw_sp_port->bridged)
  		return mlxsw_sp_port_kill_vids(dev, vid_begin, vid_end);
  
 -	for (vid = vid_begin; vid <= vid_end;
 -	     vid += MLXSW_REG_SPVM_REC_MAX_COUNT) {
 -		vid_e = min((u16) (vid + MLXSW_REG_SPVM_REC_MAX_COUNT - 1),
 -			    vid_end);
 -		err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, vid, vid_e, false,
 -					     false);
 -		if (err) {
 -			netdev_err(mlxsw_sp_port->dev, "Unable to del VIDs %d-%d\n",
 -				   vid, vid_e);
 -			return err;
 -		}
 +	err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end,
 +					false, false);
 +	if (err) {
 +		netdev_err(dev, "Unable to del VIDs %d-%d\n", vid_begin,
 +			   vid_end);
 +		return err;
  	}
  
 -	if ((mlxsw_sp_port->pvid >= vid_begin) &&
 -	    (mlxsw_sp_port->pvid <= vid_end)) {
 +	pvid = mlxsw_sp_port->pvid;
 +	if (pvid >= vid_begin && pvid <= vid_end && pvid != 1) {
  		/* Default VLAN is always 1 */
 -		mlxsw_sp_port->pvid = 1;
 -		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port,
 -					     mlxsw_sp_port->pvid);
 +		err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
  		if (err) {
 -			netdev_err(mlxsw_sp_port->dev, "Unable to del PVID %d\n",
 -				   vid);
 +			netdev_err(dev, "Unable to del PVID %d\n", pvid);
  			return err;
  		}
 +		mlxsw_sp_port->pvid = 1;
  	}
  
  	if (init)
@@@ -940,54 -606,8 +940,54 @@@ static in
  mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port,
  			     const struct switchdev_obj_port_fdb *fdb)
  {
 -	return mlxsw_sp_port_fdb_op(mlxsw_sp_port, fdb->addr, fdb->vid,
 -				    false, false);
 +	u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, fdb->vid);
 +	u16 lag_vid = 0;
 +
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		lag_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
 +	}
 +
 +	if (!mlxsw_sp_port->lagged)
 +		return mlxsw_sp_port_fdb_uc_op(mlxsw_sp_port->mlxsw_sp,
 +					       mlxsw_sp_port->local_port,
 +					       fdb->addr, fid,
 +					       false, false);
 +	else
 +		return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp_port->mlxsw_sp,
 +						   mlxsw_sp_port->lag_id,
 +						   fdb->addr, fid, lag_vid,
 +						   false, false);
 +}
 +
 +static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
 +				 const struct switchdev_obj_port_mdb *mdb)
 +{
 +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +	struct net_device *dev = mlxsw_sp_port->dev;
 +	struct mlxsw_sp_mid *mid;
 +	u16 fid = mlxsw_sp_port_vid_to_fid_get(mlxsw_sp_port, mdb->vid);
 +	u16 mid_idx;
 +	int err = 0;
 +
 +	mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, mdb->vid);
 +	if (!mid) {
 +		netdev_err(dev, "Unable to remove port from MC DB\n");
 +		return -EINVAL;
 +	}
 +
 +	err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false, false);
 +	if (err)
 +		netdev_err(dev, "Unable to remove port from SMID\n");
 +
 +	mid_idx = mid->mid;
 +	if (__mlxsw_sp_mc_dec_ref(mlxsw_sp, mid)) {
 +		err = mlxsw_sp_port_mdb_op(mlxsw_sp, mdb->addr, fid, mid_idx,
 +					   false);
 +		if (err)
 +			netdev_err(dev, "Unable to remove MC SFD\n");
 +	}
 +
 +	return err;
  }
  
  static int mlxsw_sp_port_obj_del(struct net_device *dev,
@@@ -996,15 -616,8 +996,15 @@@
  	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  	int err = 0;
  
 +	mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port);
 +	if (!mlxsw_sp_port)
 +		return -EINVAL;
 +
  	switch (obj->id) {
  	case SWITCHDEV_OBJ_ID_PORT_VLAN:
 +		if (mlxsw_sp_port_is_vport(mlxsw_sp_port))
 +			return 0;
 +
  		err = mlxsw_sp_port_vlans_del(mlxsw_sp_port,
  					      SWITCHDEV_OBJ_PORT_VLAN(obj));
  		break;
@@@ -1012,9 -625,6 +1012,9 @@@
  		err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port,
  						   SWITCHDEV_OBJ_PORT_FDB(obj));
  		break;
 +	case SWITCHDEV_OBJ_ID_PORT_MDB:
 +		err = mlxsw_sp_port_mdb_del(mlxsw_sp_port,
 +					    SWITCHDEV_OBJ_PORT_MDB(obj));
  	default:
  		err = -EOPNOTSUPP;
  		break;
@@@ -1023,31 -633,14 +1023,31 @@@
  	return err;
  }
  
 +static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp,
 +						   u16 lag_id)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_port;
 +	int i;
 +
 +	for (i = 0; i < MLXSW_SP_PORT_PER_LAG_MAX; i++) {
 +		mlxsw_sp_port = mlxsw_sp_port_lagged_get(mlxsw_sp, lag_id, i);
 +		if (mlxsw_sp_port)
 +			return mlxsw_sp_port;
 +	}
 +	return NULL;
 +}
 +
  static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,
  				  struct switchdev_obj_port_fdb *fdb,
  				  switchdev_obj_dump_cb_t *cb)
  {
 +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 +	u16 vport_vid = 0, vport_fid = 0;
  	char *sfd_pl;
  	char mac[ETH_ALEN];
 -	u16 vid;
 +	u16 fid;
  	u8 local_port;
 +	u16 lag_id;
  	u8 num_rec;
  	int stored_err = 0;
  	int i;
@@@ -1057,18 -650,12 +1057,19 @@@
  	if (!sfd_pl)
  		return -ENOMEM;
  
+ 	mutex_lock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		u16 tmp;
 +
 +		tmp = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
 +		vport_fid = mlxsw_sp_vfid_to_fid(tmp);
 +		vport_vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
 +	}
 +
  	mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0);
  	do {
  		mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT);
 -		err = mlxsw_reg_query(mlxsw_sp_port->mlxsw_sp->core,
 -				      MLXSW_REG(sfd), sfd_pl);
 +		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
  		if (err)
  			goto out;
  
@@@ -1083,45 -670,22 +1084,46 @@@
  		for (i = 0; i < num_rec; i++) {
  			switch (mlxsw_reg_sfd_rec_type_get(sfd_pl, i)) {
  			case MLXSW_REG_SFD_REC_TYPE_UNICAST:
 -				mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, &vid,
 +				mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, &fid,
  							&local_port);
  				if (local_port == mlxsw_sp_port->local_port) {
 +					if (vport_fid && vport_fid != fid)
 +						continue;
 +					else if (vport_fid)
 +						fdb->vid = vport_vid;
 +					else
 +						fdb->vid = fid;
 +					ether_addr_copy(fdb->addr, mac);
 +					fdb->ndm_state = NUD_REACHABLE;
 +					err = cb(&fdb->obj);
 +					if (err)
 +						stored_err = err;
 +				}
 +				break;
 +			case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG:
 +				mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i,
 +							    mac, &fid, &lag_id);
 +				if (mlxsw_sp_port ==
 +				    mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id)) {
 +					if (vport_fid && vport_fid != fid)
 +						continue;
 +					else if (vport_fid)
 +						fdb->vid = vport_vid;
 +					else
 +						fdb->vid = fid;
  					ether_addr_copy(fdb->addr, mac);
  					fdb->ndm_state = NUD_REACHABLE;
 -					fdb->vid = vid;
  					err = cb(&fdb->obj);
  					if (err)
  						stored_err = err;
  				}
 +				break;
  			}
  		}
  	} while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT);
  
  out:
+ 	mutex_unlock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);
  	kfree(sfd_pl);
  	return stored_err ? stored_err : err;
  }
@@@ -1133,19 -697,10 +1135,19 @@@ static int mlxsw_sp_port_vlan_dump(stru
  	u16 vid;
  	int err = 0;
  
 +	if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
 +		vlan->flags = 0;
 +		vlan->vid_begin = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
 +		vlan->vid_end = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
 +		return cb(&vlan->obj);
 +	}
 +
  	for_each_set_bit(vid, mlxsw_sp_port->active_vlans, VLAN_N_VID) {
  		vlan->flags = 0;
  		if (vid == mlxsw_sp_port->pvid)
  			vlan->flags |= BRIDGE_VLAN_INFO_PVID;
 +		if (test_bit(vid, mlxsw_sp_port->untagged_vlans))
 +			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
  		vlan->vid_begin = vid;
  		vlan->vid_end = vid;
  		err = cb(&vlan->obj);
@@@ -1162,10 -717,6 +1164,10 @@@ static int mlxsw_sp_port_obj_dump(struc
  	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
  	int err = 0;
  
 +	mlxsw_sp_port = mlxsw_sp_port_orig_get(obj->orig_dev, mlxsw_sp_port);
 +	if (!mlxsw_sp_port)
 +		return -EINVAL;
 +
  	switch (obj->id) {
  	case SWITCHDEV_OBJ_ID_PORT_VLAN:
  		err = mlxsw_sp_port_vlan_dump(mlxsw_sp_port,
@@@ -1191,21 -742,6 +1193,21 @@@ static const struct switchdev_ops mlxsw
  	.switchdev_port_obj_dump	= mlxsw_sp_port_obj_dump,
  };
  
 +static void mlxsw_sp_fdb_call_notifiers(bool learning, bool learning_sync,
 +					bool adding, char *mac, u16 vid,
 +					struct net_device *dev)
 +{
 +	struct switchdev_notifier_fdb_info info;
 +	unsigned long notifier_type;
 +
 +	if (learning && learning_sync) {
 +		info.addr = mac;
 +		info.vid = vid;
 +		notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL;
 +		call_switchdev_notifiers(notifier_type, dev, &info.info);
 +	}
 +}
 +
  static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
  					    char *sfn_pl, int rec_index,
  					    bool adding)
@@@ -1213,119 -749,34 +1215,119 @@@
  	struct mlxsw_sp_port *mlxsw_sp_port;
  	char mac[ETH_ALEN];
  	u8 local_port;
 -	u16 vid;
 +	u16 vid, fid;
 +	bool do_notification = true;
  	int err;
  
 -	mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &vid, &local_port);
 +	mlxsw_reg_sfn_mac_unpack(sfn_pl, rec_index, mac, &fid, &local_port);
  	mlxsw_sp_port = mlxsw_sp->ports[local_port];
  	if (!mlxsw_sp_port) {
  		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Incorrect local port in FDB notification\n");
 -		return;
 +		goto just_remove;
 +	}
 +
 +	if (mlxsw_sp_fid_is_vfid(fid)) {
 +		u16 vfid = mlxsw_sp_fid_to_vfid(fid);
 +		struct mlxsw_sp_port *mlxsw_sp_vport;
 +
 +		mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
 +								  vfid);
 +		if (!mlxsw_sp_vport) {
 +			netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
 +			goto just_remove;
 +		}
 +		vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
 +		/* Override the physical port with the vPort. */
 +		mlxsw_sp_port = mlxsw_sp_vport;
 +	} else {
 +		vid = fid;
  	}
  
 -	err = mlxsw_sp_port_fdb_op(mlxsw_sp_port, mac, vid,
 -				   adding && mlxsw_sp_port->learning, true);
 +	adding = adding && mlxsw_sp_port->learning;
 +
 +do_fdb_op:
 +	err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
 +				      adding, true);
  	if (err) {
  		if (net_ratelimit())
  			netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
  		return;
  	}
  
 -	if (mlxsw_sp_port->learning && mlxsw_sp_port->learning_sync) {
 -		struct switchdev_notifier_fdb_info info;
 -		unsigned long notifier_type;
 +	if (!do_notification)
 +		return;
 +	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning,
 +				    mlxsw_sp_port->learning_sync,
 +				    adding, mac, vid, mlxsw_sp_port->dev);
 +	return;
 +
 +just_remove:
 +	adding = false;
 +	do_notification = false;
 +	goto do_fdb_op;
 +}
  
 -		info.addr = mac;
 -		info.vid = vid;
 -		notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL;
 -		call_switchdev_notifiers(notifier_type, mlxsw_sp_port->dev,
 -					 &info.info);
 +static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
 +						char *sfn_pl, int rec_index,
 +						bool adding)
 +{
 +	struct mlxsw_sp_port *mlxsw_sp_port;
 +	char mac[ETH_ALEN];
 +	u16 lag_vid = 0;
 +	u16 lag_id;
 +	u16 vid, fid;
 +	bool do_notification = true;
 +	int err;
 +
 +	mlxsw_reg_sfn_mac_lag_unpack(sfn_pl, rec_index, mac, &fid, &lag_id);
 +	mlxsw_sp_port = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id);
 +	if (!mlxsw_sp_port) {
 +		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Cannot find port representor for LAG\n");
 +		goto just_remove;
  	}
 +
 +	if (mlxsw_sp_fid_is_vfid(fid)) {
 +		u16 vfid = mlxsw_sp_fid_to_vfid(fid);
 +		struct mlxsw_sp_port *mlxsw_sp_vport;
 +
 +		mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
 +								  vfid);
 +		if (!mlxsw_sp_vport) {
 +			netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
 +			goto just_remove;
 +		}
 +
 +		vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport);
 +		lag_vid = vid;
 +		/* Override the physical port with the vPort. */
 +		mlxsw_sp_port = mlxsw_sp_vport;
 +	} else {
 +		vid = fid;
 +	}
 +
 +	adding = adding && mlxsw_sp_port->learning;
 +
 +do_fdb_op:
 +	err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
 +					  adding, true);
 +	if (err) {
 +		if (net_ratelimit())
 +			netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
 +		return;
 +	}
 +
 +	if (!do_notification)
 +		return;
 +	mlxsw_sp_fdb_call_notifiers(mlxsw_sp_port->learning,
 +				    mlxsw_sp_port->learning_sync,
 +				    adding, mac, vid,
 +				    mlxsw_sp_lag_get(mlxsw_sp, lag_id)->dev);
 +	return;
 +
 +just_remove:
 +	adding = false;
 +	do_notification = false;
 +	goto do_fdb_op;
  }
  
  static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
@@@ -1340,14 -791,6 +1342,14 @@@
  		mlxsw_sp_fdb_notify_mac_process(mlxsw_sp, sfn_pl,
  						rec_index, false);
  		break;
 +	case MLXSW_REG_SFN_REC_TYPE_LEARNED_MAC_LAG:
 +		mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
 +						    rec_index, true);
 +		break;
 +	case MLXSW_REG_SFN_REC_TYPE_AGED_OUT_MAC_LAG:
 +		mlxsw_sp_fdb_notify_mac_lag_process(mlxsw_sp, sfn_pl,
 +						    rec_index, false);
 +		break;
  	}
  }
  
@@@ -1371,6 -814,7 +1373,7 @@@ static void mlxsw_sp_fdb_notify_work(st
  
  	mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work);
  
+ 	mutex_lock(&mlxsw_sp->fdb_lock);
  	do {
  		mlxsw_reg_sfn_pack(sfn_pl);
  		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
@@@ -1383,6 -827,7 +1386,7 @@@
  			mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
  
  	} while (num_rec);
+ 	mutex_unlock(&mlxsw_sp->fdb_lock);
  
  	kfree(sfn_pl);
  	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
@@@ -1397,6 -842,7 +1401,7 @@@ static int mlxsw_sp_fdb_init(struct mlx
  		dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
  		return err;
  	}
+ 	mutex_init(&mlxsw_sp->fdb_lock);
  	INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
  	mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
  	mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
@@@ -1436,8 -882,7 +1441,8 @@@ int mlxsw_sp_port_vlan_init(struct mlxs
  	 * with VID 1.
  	 */
  	mlxsw_sp_port->pvid = 1;
 -	err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID, true);
 +	err = __mlxsw_sp_port_vlans_del(mlxsw_sp_port, 0, VLAN_N_VID - 1,
 +					true);
  	if (err) {
  		netdev_err(dev, "Unable to init VLANs\n");
  		return err;
diff --combined drivers/net/ethernet/renesas/ravb_main.c
index 9e20f37,fef4fa12..ac43ed9
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@@ -32,8 -32,6 +32,8 @@@
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  
 +#include <asm/div64.h>
 +
  #include "ravb.h"
  
  #define RAVB_DEF_MSG_ENABLE \
@@@ -115,15 -113,12 +115,15 @@@ static void ravb_read_mac_address(struc
  	if (mac) {
  		ether_addr_copy(ndev->dev_addr, mac);
  	} else {
 -		ndev->dev_addr[0] = (ravb_read(ndev, MAHR) >> 24);
 -		ndev->dev_addr[1] = (ravb_read(ndev, MAHR) >> 16) & 0xFF;
 -		ndev->dev_addr[2] = (ravb_read(ndev, MAHR) >> 8) & 0xFF;
 -		ndev->dev_addr[3] = (ravb_read(ndev, MAHR) >> 0) & 0xFF;
 -		ndev->dev_addr[4] = (ravb_read(ndev, MALR) >> 8) & 0xFF;
 -		ndev->dev_addr[5] = (ravb_read(ndev, MALR) >> 0) & 0xFF;
 +		u32 mahr = ravb_read(ndev, MAHR);
 +		u32 malr = ravb_read(ndev, MALR);
 +
 +		ndev->dev_addr[0] = (mahr >> 24) & 0xFF;
 +		ndev->dev_addr[1] = (mahr >> 16) & 0xFF;
 +		ndev->dev_addr[2] = (mahr >>  8) & 0xFF;
 +		ndev->dev_addr[3] = (mahr >>  0) & 0xFF;
 +		ndev->dev_addr[4] = (malr >>  8) & 0xFF;
 +		ndev->dev_addr[5] = (malr >>  0) & 0xFF;
  	}
  }
  
@@@ -343,16 -338,13 +343,13 @@@ error
  static void ravb_emac_init(struct net_device *ndev)
  {
  	struct ravb_private *priv = netdev_priv(ndev);
- 	u32 ecmr;
  
  	/* Receive frame limit set register */
  	ravb_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, RFLR);
  
  	/* PAUSE prohibition */
- 	ecmr =  ravb_read(ndev, ECMR);
- 	ecmr &= ECMR_DM;
- 	ecmr |= ECMR_ZPF | (priv->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
- 	ravb_write(ndev, ecmr, ECMR);
+ 	ravb_write(ndev, ECMR_ZPF | (priv->duplex ? ECMR_DM : 0) |
+ 		   ECMR_TE | ECMR_RE, ECMR);
  
  	ravb_set_rate(ndev);
  
@@@ -410,11 -402,9 +407,11 @@@ static int ravb_dmac_init(struct net_de
  	/* Timestamp enable */
  	ravb_write(ndev, TCCR_TFEN, TCCR);
  
 -	/* Interrupt enable: */
 +	/* Interrupt init: */
  	/* Frame receive */
  	ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
 +	/* Disable FIFO full warning */
 +	ravb_write(ndev, 0, RIC1);
  	/* Receive FIFO full error, descriptor empty */
  	ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
  	/* Frame transmitted, timestamp FIFO updated */
@@@ -882,7 -872,6 +879,7 @@@ static int ravb_phy_init(struct net_dev
  	struct ravb_private *priv = netdev_priv(ndev);
  	struct phy_device *phydev;
  	struct device_node *pn;
 +	int err;
  
  	priv->link = 0;
  	priv->speed = 0;
@@@ -890,17 -879,6 +887,17 @@@
  
  	/* Try connecting to PHY */
  	pn = of_parse_phandle(np, "phy-handle", 0);
 +	if (!pn) {
 +		/* In the case of a fixed PHY, the DT node associated
 +		 * to the PHY is the Ethernet MAC DT node.
 +		 */
 +		if (of_phy_is_fixed_link(np)) {
 +			err = of_phy_register_fixed_link(np);
 +			if (err)
 +				return err;
 +		}
 +		pn = of_node_get(np);
 +	}
  	phydev = of_phy_connect(ndev, pn, ravb_adjust_link, 0,
  				priv->phy_interface);
  	if (!phydev) {
@@@ -927,7 -905,8 +924,7 @@@
  	/* 10BASE is not supported */
  	phydev->supported &= ~PHY_10BT_FEATURES;
  
 -	netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
 -		    phydev->addr, phydev->irq, phydev->drv->name);
 +	phy_attached_info(phydev);
  
  	priv->phydev = phydev;
  
@@@ -1250,8 -1229,7 +1247,8 @@@ static int ravb_open(struct net_device 
  	ravb_emac_init(ndev);
  
  	/* Initialise PTP Clock driver */
 -	ravb_ptp_init(ndev, priv->pdev);
 +	if (priv->chip_id == RCAR_GEN2)
 +		ravb_ptp_init(ndev, priv->pdev);
  
  	netif_tx_start_all_queues(ndev);
  
@@@ -1264,8 -1242,7 +1261,8 @@@
  
  out_ptp_stop:
  	/* Stop PTP Clock driver */
 -	ravb_ptp_stop(ndev);
 +	if (priv->chip_id == RCAR_GEN2)
 +		ravb_ptp_stop(ndev);
  out_free_irq2:
  	if (priv->chip_id == RCAR_GEN3)
  		free_irq(priv->emac_irq, ndev);
@@@ -1494,12 -1471,12 +1491,12 @@@ static int ravb_close(struct net_devic
  
  	/* Disable interrupts by clearing the interrupt masks. */
  	ravb_write(ndev, 0, RIC0);
 -	ravb_write(ndev, 0, RIC1);
  	ravb_write(ndev, 0, RIC2);
  	ravb_write(ndev, 0, TIC);
  
  	/* Stop PTP Clock driver */
 -	ravb_ptp_stop(ndev);
 +	if (priv->chip_id == RCAR_GEN2)
 +		ravb_ptp_stop(ndev);
  
  	/* Set the config mode to stop the AVB-DMAC's processes */
  	if (ravb_stop_dma(ndev) < 0)
@@@ -1679,45 -1656,11 +1676,45 @@@ static int ravb_mdio_release(struct rav
  static const struct of_device_id ravb_match_table[] = {
  	{ .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 },
  	{ .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 },
 +	{ .compatible = "renesas,etheravb-rcar-gen2", .data = (void *)RCAR_GEN2 },
  	{ .compatible = "renesas,etheravb-r8a7795", .data = (void *)RCAR_GEN3 },
 +	{ .compatible = "renesas,etheravb-rcar-gen3", .data = (void *)RCAR_GEN3 },
  	{ }
  };
  MODULE_DEVICE_TABLE(of, ravb_match_table);
  
 +static int ravb_set_gti(struct net_device *ndev)
 +{
 +
 +	struct device *dev = ndev->dev.parent;
 +	struct device_node *np = dev->of_node;
 +	unsigned long rate;
 +	struct clk *clk;
 +	uint64_t inc;
 +
 +	clk = of_clk_get(np, 0);
 +	if (IS_ERR(clk)) {
 +		dev_err(dev, "could not get clock\n");
 +		return PTR_ERR(clk);
 +	}
 +
 +	rate = clk_get_rate(clk);
 +	clk_put(clk);
 +
 +	inc = 1000000000ULL << 20;
 +	do_div(inc, rate);
 +
 +	if (inc < GTI_TIV_MIN || inc > GTI_TIV_MAX) {
 +		dev_err(dev, "gti.tiv increment 0x%llx is outside the range 0x%x - 0x%x\n",
 +			inc, GTI_TIV_MIN, GTI_TIV_MAX);
 +		return -EINVAL;
 +	}
 +
 +	ravb_write(ndev, inc, GTI);
 +
 +	return 0;
 +}
 +
  static int ravb_probe(struct platform_device *pdev)
  {
  	struct device_node *np = pdev->dev.of_node;
@@@ -1806,25 -1749,15 +1803,25 @@@
  	ndev->ethtool_ops = &ravb_ethtool_ops;
  
  	/* Set AVB config mode */
 -	ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) | CCC_OPC_CONFIG,
 -		   CCC);
 +	if (chip_id == RCAR_GEN2) {
 +		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) |
 +			   CCC_OPC_CONFIG, CCC);
 +		/* Set CSEL value */
 +		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) |
 +			   CCC_CSEL_HPB, CCC);
 +	} else {
 +		ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_OPC) |
 +			   CCC_OPC_CONFIG | CCC_GAC | CCC_CSEL_HPB, CCC);
 +	}
  
  	/* Set CSEL value */
  	ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB,
  		   CCC);
  
  	/* Set GTI value */
 -	ravb_write(ndev, ((1000 << 20) / 130) & GTI_TIV, GTI);
 +	error = ravb_set_gti(ndev);
 +	if (error)
 +		goto out_release;
  
  	/* Request GTI loading */
  	ravb_write(ndev, ravb_read(ndev, GCCR) | GCCR_LTI, GCCR);
@@@ -1847,10 -1780,6 +1844,10 @@@
  	/* Initialise HW timestamp list */
  	INIT_LIST_HEAD(&priv->ts_skb_list);
  
 +	/* Initialise PTP Clock driver */
 +	if (chip_id != RCAR_GEN2)
 +		ravb_ptp_init(ndev, pdev);
 +
  	/* Debug message level */
  	priv->msg_enable = RAVB_DEF_MSG_ENABLE;
  
@@@ -1892,10 -1821,6 +1889,10 @@@ out_napi_del
  out_dma_free:
  	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
  			  priv->desc_bat_dma);
 +
 +	/* Stop PTP Clock driver */
 +	if (chip_id != RCAR_GEN2)
 +		ravb_ptp_stop(ndev);
  out_release:
  	if (ndev)
  		free_netdev(ndev);
@@@ -1910,10 -1835,6 +1907,10 @@@ static int ravb_remove(struct platform_
  	struct net_device *ndev = platform_get_drvdata(pdev);
  	struct ravb_private *priv = netdev_priv(ndev);
  
 +	/* Stop PTP Clock driver */
 +	if (priv->chip_id != RCAR_GEN2)
 +		ravb_ptp_stop(ndev);
 +
  	dma_free_coherent(ndev->dev.parent, priv->desc_bat_size, priv->desc_bat,
  			  priv->desc_bat_dma);
  	/* Set reset mode */
diff --combined drivers/net/ethernet/renesas/sh_eth.c
index c5ec57ce,9c1e290..dfa9e59
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@@ -473,109 -473,6 +473,109 @@@ static void sh_eth_set_duplex(struct ne
  		sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
  }
  
 +static void sh_eth_chip_reset(struct net_device *ndev)
 +{
 +	struct sh_eth_private *mdp = netdev_priv(ndev);
 +
 +	/* reset device */
 +	sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
 +	mdelay(1);
 +}
 +
 +static void sh_eth_set_rate_gether(struct net_device *ndev)
 +{
 +	struct sh_eth_private *mdp = netdev_priv(ndev);
 +
 +	switch (mdp->speed) {
 +	case 10: /* 10BASE */
 +		sh_eth_write(ndev, GECMR_10, GECMR);
 +		break;
 +	case 100:/* 100BASE */
 +		sh_eth_write(ndev, GECMR_100, GECMR);
 +		break;
 +	case 1000: /* 1000BASE */
 +		sh_eth_write(ndev, GECMR_1000, GECMR);
 +		break;
 +	default:
 +		break;
 +	}
 +}
 +
 +#ifdef CONFIG_OF
 +/* R7S72100 */
 +static struct sh_eth_cpu_data r7s72100_data = {
 +	.chip_reset	= sh_eth_chip_reset,
 +	.set_duplex	= sh_eth_set_duplex,
 +
 +	.register_type	= SH_ETH_REG_FAST_RZ,
 +
 +	.ecsr_value	= ECSR_ICD,
 +	.ecsipr_value	= ECSIPR_ICDIP,
 +	.eesipr_value	= 0xff7f009f,
 +
 +	.tx_check	= EESR_TC1 | EESR_FTC,
 +	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
 +			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
 +			  EESR_TDE | EESR_ECI,
 +	.fdr_value	= 0x0000070f,
 +
 +	.no_psr		= 1,
 +	.apr		= 1,
 +	.mpr		= 1,
 +	.tpauser	= 1,
 +	.hw_swap	= 1,
 +	.rpadir		= 1,
 +	.rpadir_value   = 2 << 16,
 +	.no_trimd	= 1,
 +	.no_ade		= 1,
 +	.hw_crc		= 1,
 +	.tsu		= 1,
 +	.shift_rd0	= 1,
 +};
 +
 +static void sh_eth_chip_reset_r8a7740(struct net_device *ndev)
 +{
 +	struct sh_eth_private *mdp = netdev_priv(ndev);
 +
 +	/* reset device */
 +	sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
 +	mdelay(1);
 +
 +	sh_eth_select_mii(ndev);
 +}
 +
 +/* R8A7740 */
 +static struct sh_eth_cpu_data r8a7740_data = {
 +	.chip_reset	= sh_eth_chip_reset_r8a7740,
 +	.set_duplex	= sh_eth_set_duplex,
 +	.set_rate	= sh_eth_set_rate_gether,
 +
 +	.register_type	= SH_ETH_REG_GIGABIT,
 +
 +	.ecsr_value	= ECSR_ICD | ECSR_MPD,
 +	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
 +	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
 +
 +	.tx_check	= EESR_TC1 | EESR_FTC,
 +	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
 +			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
 +			  EESR_TDE | EESR_ECI,
 +	.fdr_value	= 0x0000070f,
 +
 +	.apr		= 1,
 +	.mpr		= 1,
 +	.tpauser	= 1,
 +	.bculr		= 1,
 +	.hw_swap	= 1,
 +	.rpadir		= 1,
 +	.rpadir_value   = 2 << 16,
 +	.no_trimd	= 1,
 +	.no_ade		= 1,
 +	.tsu		= 1,
 +	.select_mii	= 1,
 +	.shift_rd0	= 1,
 +};
 +
  /* There is CPU dependent code */
  static void sh_eth_set_rate_r8a777x(struct net_device *ndev)
  {
@@@ -641,7 -538,6 +641,7 @@@ static struct sh_eth_cpu_data r8a779x_d
  	.hw_swap	= 1,
  	.rmiimode	= 1,
  };
 +#endif /* CONFIG_OF */
  
  static void sh_eth_set_rate_sh7724(struct net_device *ndev)
  {
@@@ -799,6 -695,34 +799,6 @@@ static struct sh_eth_cpu_data sh7757_da
  	.tsu		= 1,
  };
  
 -static void sh_eth_chip_reset(struct net_device *ndev)
 -{
 -	struct sh_eth_private *mdp = netdev_priv(ndev);
 -
 -	/* reset device */
 -	sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
 -	mdelay(1);
 -}
 -
 -static void sh_eth_set_rate_gether(struct net_device *ndev)
 -{
 -	struct sh_eth_private *mdp = netdev_priv(ndev);
 -
 -	switch (mdp->speed) {
 -	case 10: /* 10BASE */
 -		sh_eth_write(ndev, GECMR_10, GECMR);
 -		break;
 -	case 100:/* 100BASE */
 -		sh_eth_write(ndev, GECMR_100, GECMR);
 -		break;
 -	case 1000: /* 1000BASE */
 -		sh_eth_write(ndev, GECMR_1000, GECMR);
 -		break;
 -	default:
 -		break;
 -	}
 -}
 -
  /* SH7734 */
  static struct sh_eth_cpu_data sh7734_data = {
  	.chip_reset	= sh_eth_chip_reset,
@@@ -856,6 -780,80 +856,6 @@@ static struct sh_eth_cpu_data sh7763_da
  	.irq_flags	= IRQF_SHARED,
  };
  
 -static void sh_eth_chip_reset_r8a7740(struct net_device *ndev)
 -{
 -	struct sh_eth_private *mdp = netdev_priv(ndev);
 -
 -	/* reset device */
 -	sh_eth_tsu_write(mdp, ARSTR_ARSTR, ARSTR);
 -	mdelay(1);
 -
 -	sh_eth_select_mii(ndev);
 -}
 -
 -/* R8A7740 */
 -static struct sh_eth_cpu_data r8a7740_data = {
 -	.chip_reset	= sh_eth_chip_reset_r8a7740,
 -	.set_duplex	= sh_eth_set_duplex,
 -	.set_rate	= sh_eth_set_rate_gether,
 -
 -	.register_type	= SH_ETH_REG_GIGABIT,
 -
 -	.ecsr_value	= ECSR_ICD | ECSR_MPD,
 -	.ecsipr_value	= ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
 -	.eesipr_value	= DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
 -
 -	.tx_check	= EESR_TC1 | EESR_FTC,
 -	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
 -			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
 -			  EESR_TDE | EESR_ECI,
 -	.fdr_value	= 0x0000070f,
 -
 -	.apr		= 1,
 -	.mpr		= 1,
 -	.tpauser	= 1,
 -	.bculr		= 1,
 -	.hw_swap	= 1,
 -	.rpadir		= 1,
 -	.rpadir_value   = 2 << 16,
 -	.no_trimd	= 1,
 -	.no_ade		= 1,
 -	.tsu		= 1,
 -	.select_mii	= 1,
 -	.shift_rd0	= 1,
 -};
 -
 -/* R7S72100 */
 -static struct sh_eth_cpu_data r7s72100_data = {
 -	.chip_reset	= sh_eth_chip_reset,
 -	.set_duplex	= sh_eth_set_duplex,
 -
 -	.register_type	= SH_ETH_REG_FAST_RZ,
 -
 -	.ecsr_value	= ECSR_ICD,
 -	.ecsipr_value	= ECSIPR_ICDIP,
 -	.eesipr_value	= 0xff7f009f,
 -
 -	.tx_check	= EESR_TC1 | EESR_FTC,
 -	.eesr_err_check	= EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
 -			  EESR_RFE | EESR_RDE | EESR_RFRMER | EESR_TFE |
 -			  EESR_TDE | EESR_ECI,
 -	.fdr_value	= 0x0000070f,
 -
 -	.no_psr		= 1,
 -	.apr		= 1,
 -	.mpr		= 1,
 -	.tpauser	= 1,
 -	.hw_swap	= 1,
 -	.rpadir		= 1,
 -	.rpadir_value   = 2 << 16,
 -	.no_trimd	= 1,
 -	.no_ade		= 1,
 -	.hw_crc		= 1,
 -	.tsu		= 1,
 -	.shift_rd0	= 1,
 -};
 -
  static struct sh_eth_cpu_data sh7619_data = {
  	.register_type	= SH_ETH_REG_FAST_SH3_SH2,
  
@@@ -967,6 -965,30 +967,6 @@@ static void sh_eth_set_receive_align(st
  		skb_reserve(skb, SH_ETH_RX_ALIGN - reserve);
  }
  
 -
 -/* CPU <-> EDMAC endian convert */
 -static inline __u32 cpu_to_edmac(struct sh_eth_private *mdp, u32 x)
 -{
 -	switch (mdp->edmac_endian) {
 -	case EDMAC_LITTLE_ENDIAN:
 -		return cpu_to_le32(x);
 -	case EDMAC_BIG_ENDIAN:
 -		return cpu_to_be32(x);
 -	}
 -	return x;
 -}
 -
 -static inline __u32 edmac_to_cpu(struct sh_eth_private *mdp, u32 x)
 -{
 -	switch (mdp->edmac_endian) {
 -	case EDMAC_LITTLE_ENDIAN:
 -		return le32_to_cpu(x);
 -	case EDMAC_BIG_ENDIAN:
 -		return be32_to_cpu(x);
 -	}
 -	return x;
 -}
 -
  /* Program the hardware MAC address from dev->dev_addr. */
  static void update_mac_address(struct net_device *ndev)
  {
@@@ -989,15 -1011,12 +989,15 @@@ static void read_mac_address(struct net
  	if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
  		memcpy(ndev->dev_addr, mac, ETH_ALEN);
  	} else {
 -		ndev->dev_addr[0] = (sh_eth_read(ndev, MAHR) >> 24);
 -		ndev->dev_addr[1] = (sh_eth_read(ndev, MAHR) >> 16) & 0xFF;
 -		ndev->dev_addr[2] = (sh_eth_read(ndev, MAHR) >> 8) & 0xFF;
 -		ndev->dev_addr[3] = (sh_eth_read(ndev, MAHR) & 0xFF);
 -		ndev->dev_addr[4] = (sh_eth_read(ndev, MALR) >> 8) & 0xFF;
 -		ndev->dev_addr[5] = (sh_eth_read(ndev, MALR) & 0xFF);
 +		u32 mahr = sh_eth_read(ndev, MAHR);
 +		u32 malr = sh_eth_read(ndev, MALR);
 +
 +		ndev->dev_addr[0] = (mahr >> 24) & 0xFF;
 +		ndev->dev_addr[1] = (mahr >> 16) & 0xFF;
 +		ndev->dev_addr[2] = (mahr >>  8) & 0xFF;
 +		ndev->dev_addr[3] = (mahr >>  0) & 0xFF;
 +		ndev->dev_addr[4] = (malr >>  8) & 0xFF;
 +		ndev->dev_addr[5] = (malr >>  0) & 0xFF;
  	}
  }
  
@@@ -1013,34 -1032,56 +1013,34 @@@ struct bb_info 
  	void (*set_gate)(void *addr);
  	struct mdiobb_ctrl ctrl;
  	void *addr;
 -	u32 mmd_msk;/* MMD */
 -	u32 mdo_msk;
 -	u32 mdi_msk;
 -	u32 mdc_msk;
  };
  
 -/* PHY bit set */
 -static void bb_set(void *addr, u32 msk)
 +static void sh_mdio_ctrl(struct mdiobb_ctrl *ctrl, u32 mask, int set)
  {
 -	iowrite32(ioread32(addr) | msk, addr);
 -}
 +	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 +	u32 pir;
  
 -/* PHY bit clear */
 -static void bb_clr(void *addr, u32 msk)
 -{
 -	iowrite32((ioread32(addr) & ~msk), addr);
 -}
 +	if (bitbang->set_gate)
 +		bitbang->set_gate(bitbang->addr);
  
 -/* PHY bit read */
 -static int bb_read(void *addr, u32 msk)
 -{
 -	return (ioread32(addr) & msk) != 0;
 +	pir = ioread32(bitbang->addr);
 +	if (set)
 +		pir |=  mask;
 +	else
 +		pir &= ~mask;
 +	iowrite32(pir, bitbang->addr);
  }
  
  /* Data I/O pin control */
  static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
  {
 -	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 -
 -	if (bitbang->set_gate)
 -		bitbang->set_gate(bitbang->addr);
 -
 -	if (bit)
 -		bb_set(bitbang->addr, bitbang->mmd_msk);
 -	else
 -		bb_clr(bitbang->addr, bitbang->mmd_msk);
 +	sh_mdio_ctrl(ctrl, PIR_MMD, bit);
  }
  
  /* Set bit data*/
  static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
  {
 -	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 -
 -	if (bitbang->set_gate)
 -		bitbang->set_gate(bitbang->addr);
 -
 -	if (bit)
 -		bb_set(bitbang->addr, bitbang->mdo_msk);
 -	else
 -		bb_clr(bitbang->addr, bitbang->mdo_msk);
 +	sh_mdio_ctrl(ctrl, PIR_MDO, bit);
  }
  
  /* Get bit data*/
@@@ -1051,13 -1092,21 +1051,13 @@@ static int sh_get_mdio(struct mdiobb_ct
  	if (bitbang->set_gate)
  		bitbang->set_gate(bitbang->addr);
  
 -	return bb_read(bitbang->addr, bitbang->mdi_msk);
 +	return (ioread32(bitbang->addr) & PIR_MDI) != 0;
  }
  
  /* MDC pin control */
  static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
  {
 -	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 -
 -	if (bitbang->set_gate)
 -		bitbang->set_gate(bitbang->addr);
 -
 -	if (bit)
 -		bb_set(bitbang->addr, bitbang->mdc_msk);
 -	else
 -		bb_clr(bitbang->addr, bitbang->mdc_msk);
 +	sh_mdio_ctrl(ctrl, PIR_MDC, bit);
  }
  
  /* mdio bus control struct */
@@@ -1140,7 -1189,7 +1140,7 @@@ static void sh_eth_ring_format(struct n
  		rxdesc = &mdp->rx_ring[i];
  		/* The size of the buffer is a multiple of 32 bytes. */
  		buf_len = ALIGN(mdp->rx_buf_sz, 32);
 -		rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 +		rxdesc->len = cpu_to_le32(buf_len << 16);
  		dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
  					  DMA_FROM_DEVICE);
  		if (dma_mapping_error(&ndev->dev, dma_addr)) {
@@@ -1148,8 -1197,8 +1148,8 @@@
  			break;
  		}
  		mdp->rx_skbuff[i] = skb;
 -		rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
 -		rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 +		rxdesc->addr = cpu_to_le32(dma_addr);
 +		rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP);
  
  		/* Rx descriptor address set */
  		if (i == 0) {
@@@ -1163,7 -1212,7 +1163,7 @@@
  	mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
  
  	/* Mark the last entry as wrapping the ring. */
 -	rxdesc->status |= cpu_to_edmac(mdp, RD_RDLE);
 +	rxdesc->status |= cpu_to_le32(RD_RDLE);
  
  	memset(mdp->tx_ring, 0, tx_ringsize);
  
@@@ -1171,8 -1220,8 +1171,8 @@@
  	for (i = 0; i < mdp->num_tx_ring; i++) {
  		mdp->tx_skbuff[i] = NULL;
  		txdesc = &mdp->tx_ring[i];
 -		txdesc->status = cpu_to_edmac(mdp, TD_TFP);
 -		txdesc->len = cpu_to_edmac(mdp, 0);
 +		txdesc->status = cpu_to_le32(TD_TFP);
 +		txdesc->len = cpu_to_le32(0);
  		if (i == 0) {
  			/* Tx descriptor address set */
  			sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
@@@ -1182,7 -1231,7 +1182,7 @@@
  		}
  	}
  
 -	txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
 +	txdesc->status |= cpu_to_le32(TD_TDLE);
  }
  
  /* Get skb and descriptor buffer */
@@@ -1240,7 -1289,6 +1240,6 @@@ static int sh_eth_dev_init(struct net_d
  {
  	int ret = 0;
  	struct sh_eth_private *mdp = netdev_priv(ndev);
- 	u32 val;
  
  	/* Soft Reset */
  	ret = sh_eth_reset(ndev);
@@@ -1293,10 -1341,8 +1292,8 @@@
  	}
  
  	/* PAUSE Prohibition */
- 	val = (sh_eth_read(ndev, ECMR) & ECMR_DM) |
- 		ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
- 
- 	sh_eth_write(ndev, val, ECMR);
+ 	sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) |
+ 		     ECMR_TE | ECMR_RE, ECMR);
  
  	if (mdp->cd->set_rate)
  		mdp->cd->set_rate(ndev);
@@@ -1338,7 -1384,7 +1335,7 @@@ static void sh_eth_dev_exit(struct net_
  	 * packet boundary if it's currently running
  	 */
  	for (i = 0; i < mdp->num_tx_ring; i++)
 -		mdp->tx_ring[i].status &= ~cpu_to_edmac(mdp, TD_TACT);
 +		mdp->tx_ring[i].status &= ~cpu_to_le32(TD_TACT);
  
  	/* Disable TX FIFO egress to MAC */
  	sh_eth_rcv_snd_disable(ndev);
@@@ -1370,28 -1416,29 +1367,28 @@@ static int sh_eth_txfree(struct net_dev
  	for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) {
  		entry = mdp->dirty_tx % mdp->num_tx_ring;
  		txdesc = &mdp->tx_ring[entry];
 -		if (txdesc->status & cpu_to_edmac(mdp, TD_TACT))
 +		if (txdesc->status & cpu_to_le32(TD_TACT))
  			break;
  		/* TACT bit must be checked before all the following reads */
  		dma_rmb();
  		netif_info(mdp, tx_done, ndev,
  			   "tx entry %d status 0x%08x\n",
 -			   entry, edmac_to_cpu(mdp, txdesc->status));
 +			   entry, le32_to_cpu(txdesc->status));
  		/* Free the original skb. */
  		if (mdp->tx_skbuff[entry]) {
 -			dma_unmap_single(&ndev->dev,
 -					 edmac_to_cpu(mdp, txdesc->addr),
 -					 edmac_to_cpu(mdp, txdesc->len) >> 16,
 +			dma_unmap_single(&ndev->dev, le32_to_cpu(txdesc->addr),
 +					 le32_to_cpu(txdesc->len) >> 16,
  					 DMA_TO_DEVICE);
  			dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
  			mdp->tx_skbuff[entry] = NULL;
  			free_num++;
  		}
 -		txdesc->status = cpu_to_edmac(mdp, TD_TFP);
 +		txdesc->status = cpu_to_le32(TD_TFP);
  		if (entry >= mdp->num_tx_ring - 1)
 -			txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
 +			txdesc->status |= cpu_to_le32(TD_TDLE);
  
  		ndev->stats.tx_packets++;
 -		ndev->stats.tx_bytes += edmac_to_cpu(mdp, txdesc->len) >> 16;
 +		ndev->stats.tx_bytes += le32_to_cpu(txdesc->len) >> 16;
  	}
  	return free_num;
  }
@@@ -1415,11 -1462,11 +1412,11 @@@ static int sh_eth_rx(struct net_device 
  	boguscnt = min(boguscnt, *quota);
  	limit = boguscnt;
  	rxdesc = &mdp->rx_ring[entry];
 -	while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) {
 +	while (!(rxdesc->status & cpu_to_le32(RD_RACT))) {
  		/* RACT bit must be checked before all the following reads */
  		dma_rmb();
 -		desc_status = edmac_to_cpu(mdp, rxdesc->status);
 -		pkt_len = edmac_to_cpu(mdp, rxdesc->len) & RD_RFL;
 +		desc_status = le32_to_cpu(rxdesc->status);
 +		pkt_len = le32_to_cpu(rxdesc->len) & RD_RFL;
  
  		if (--boguscnt < 0)
  			break;
@@@ -1457,7 -1504,7 +1454,7 @@@
  			if (desc_status & RD_RFS10)
  				ndev->stats.rx_over_errors++;
  		} else	if (skb) {
 -			dma_addr = edmac_to_cpu(mdp, rxdesc->addr);
 +			dma_addr = le32_to_cpu(rxdesc->addr);
  			if (!mdp->cd->hw_swap)
  				sh_eth_soft_swap(
  					phys_to_virt(ALIGN(dma_addr, 4)),
@@@ -1486,7 -1533,7 +1483,7 @@@
  		rxdesc = &mdp->rx_ring[entry];
  		/* The size of the buffer is 32 byte boundary. */
  		buf_len = ALIGN(mdp->rx_buf_sz, 32);
 -		rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
 +		rxdesc->len = cpu_to_le32(buf_len << 16);
  
  		if (mdp->rx_skbuff[entry] == NULL) {
  			skb = netdev_alloc_skb(ndev, skbuff_size);
@@@ -1502,14 -1549,15 +1499,14 @@@
  			mdp->rx_skbuff[entry] = skb;
  
  			skb_checksum_none_assert(skb);
 -			rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
 +			rxdesc->addr = cpu_to_le32(dma_addr);
  		}
  		dma_wmb(); /* RACT bit must be set after all the above writes */
  		if (entry >= mdp->num_rx_ring - 1)
  			rxdesc->status |=
 -				cpu_to_edmac(mdp, RD_RACT | RD_RFP | RD_RDLE);
 +				cpu_to_le32(RD_RACT | RD_RFP | RD_RDLE);
  		else
 -			rxdesc->status |=
 -				cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 +			rxdesc->status |= cpu_to_le32(RD_RACT | RD_RFP);
  	}
  
  	/* Restart Rx engine if stopped. */
@@@ -1826,7 -1874,8 +1823,7 @@@ static int sh_eth_phy_init(struct net_d
  		return PTR_ERR(phydev);
  	}
  
 -	netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
 -		    phydev->addr, phydev->irq, phydev->drv->name);
 +	phy_attached_info(phydev);
  
  	mdp->phydev = phydev;
  
@@@ -2308,8 -2357,8 +2305,8 @@@ static void sh_eth_tx_timeout(struct ne
  	/* Free all the skbuffs in the Rx queue. */
  	for (i = 0; i < mdp->num_rx_ring; i++) {
  		rxdesc = &mdp->rx_ring[i];
 -		rxdesc->status = cpu_to_edmac(mdp, 0);
 -		rxdesc->addr = cpu_to_edmac(mdp, 0xBADF00D0);
 +		rxdesc->status = cpu_to_le32(0);
 +		rxdesc->addr = cpu_to_le32(0xBADF00D0);
  		dev_kfree_skb(mdp->rx_skbuff[i]);
  		mdp->rx_skbuff[i] = NULL;
  	}
@@@ -2357,14 -2406,14 +2354,14 @@@ static int sh_eth_start_xmit(struct sk_
  		kfree_skb(skb);
  		return NETDEV_TX_OK;
  	}
 -	txdesc->addr = cpu_to_edmac(mdp, dma_addr);
 -	txdesc->len  = cpu_to_edmac(mdp, skb->len << 16);
 +	txdesc->addr = cpu_to_le32(dma_addr);
 +	txdesc->len  = cpu_to_le32(skb->len << 16);
  
  	dma_wmb(); /* TACT bit must be set after all the above writes */
  	if (entry >= mdp->num_tx_ring - 1)
 -		txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
 +		txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE);
  	else
 -		txdesc->status |= cpu_to_edmac(mdp, TD_TACT);
 +		txdesc->status |= cpu_to_le32(TD_TACT);
  
  	mdp->cur_tx++;
  
@@@ -2859,7 -2908,7 +2856,7 @@@ static int sh_mdio_release(struct sh_et
  static int sh_mdio_init(struct sh_eth_private *mdp,
  			struct sh_eth_plat_data *pd)
  {
 -	int ret, i;
 +	int ret;
  	struct bb_info *bitbang;
  	struct platform_device *pdev = mdp->pdev;
  	struct device *dev = &mdp->pdev->dev;
@@@ -2872,6 -2921,10 +2869,6 @@@
  	/* bitbang init */
  	bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
  	bitbang->set_gate = pd->set_mdio_gate;
 -	bitbang->mdi_msk = PIR_MDI;
 -	bitbang->mdo_msk = PIR_MDO;
 -	bitbang->mmd_msk = PIR_MMD;
 -	bitbang->mdc_msk = PIR_MDC;
  	bitbang->ctrl.ops = &bb_ops;
  
  	/* MII controller setting */
@@@ -2885,10 -2938,20 +2882,10 @@@
  	snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
  		 pdev->name, pdev->id);
  
 -	/* PHY IRQ */
 -	mdp->mii_bus->irq = devm_kmalloc_array(dev, PHY_MAX_ADDR, sizeof(int),
 -					       GFP_KERNEL);
 -	if (!mdp->mii_bus->irq) {
 -		ret = -ENOMEM;
 -		goto out_free_bus;
 -	}
 -
  	/* register MDIO bus */
  	if (dev->of_node) {
  		ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
  	} else {
 -		for (i = 0; i < PHY_MAX_ADDR; i++)
 -			mdp->mii_bus->irq[i] = PHY_POLL;
  		if (pd->phy_irq > 0)
  			mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
  
@@@ -3060,6 -3123,8 +3057,6 @@@ static int sh_eth_drv_probe(struct plat
  	/* get PHY ID */
  	mdp->phy_id = pd->phy;
  	mdp->phy_interface = pd->phy_interface;
 -	/* EDMAC endian */
 -	mdp->edmac_endian = pd->edmac_endian;
  	mdp->no_ether_link = pd->no_ether_link;
  	mdp->ether_link_active_low = pd->ether_link_active_low;
  
@@@ -3239,6 -3304,13 +3236,6 @@@ static struct platform_device_id sh_eth
  	{ "sh7757-ether", (kernel_ulong_t)&sh7757_data },
  	{ "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
  	{ "sh7763-gether", (kernel_ulong_t)&sh7763_data },
 -	{ "r7s72100-ether", (kernel_ulong_t)&r7s72100_data },
 -	{ "r8a7740-gether", (kernel_ulong_t)&r8a7740_data },
 -	{ "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
 -	{ "r8a7790-ether", (kernel_ulong_t)&r8a779x_data },
 -	{ "r8a7791-ether", (kernel_ulong_t)&r8a779x_data },
 -	{ "r8a7793-ether", (kernel_ulong_t)&r8a779x_data },
 -	{ "r8a7794-ether", (kernel_ulong_t)&r8a779x_data },
  	{ }
  };
  MODULE_DEVICE_TABLE(platform, sh_eth_id_table);
diff --combined drivers/net/geneve.c
index 24b077a,db96b0c..7456569
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@@ -71,14 -71,8 +71,14 @@@ struct geneve_dev 
  	__be16		   dst_port;
  	bool		   collect_md;
  	struct gro_cells   gro_cells;
 +	u32		   flags;
  };
  
 +/* Geneve device flags */
 +#define GENEVE_F_UDP_CSUM		BIT(0)
 +#define GENEVE_F_UDP_ZERO_CSUM6_TX	BIT(1)
 +#define GENEVE_F_UDP_ZERO_CSUM6_RX	BIT(2)
 +
  struct geneve_sock {
  	bool			collect_md;
  	struct list_head	list;
@@@ -87,7 -81,6 +87,7 @@@
  	int			refcnt;
  	struct udp_offload	udp_offloads;
  	struct hlist_head	vni_list[VNI_HASH_SIZE];
 +	u32			flags;
  };
  
  static inline __u32 geneve_net_vni_hash(u8 vni[3])
@@@ -350,7 -343,7 +350,7 @@@ error
  }
  
  static struct socket *geneve_create_sock(struct net *net, bool ipv6,
 -					 __be16 port)
 +					 __be16 port, u32 flags)
  {
  	struct socket *sock;
  	struct udp_port_cfg udp_conf;
@@@ -361,8 -354,6 +361,8 @@@
  	if (ipv6) {
  		udp_conf.family = AF_INET6;
  		udp_conf.ipv6_v6only = 1;
 +		udp_conf.use_udp6_rx_checksums =
 +		    !(flags & GENEVE_F_UDP_ZERO_CSUM6_RX);
  	} else {
  		udp_conf.family = AF_INET;
  		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
@@@ -380,27 -371,16 +380,27 @@@
  
  static void geneve_notify_add_rx_port(struct geneve_sock *gs)
  {
 +	struct net_device *dev;
  	struct sock *sk = gs->sock->sk;
 +	struct net *net = sock_net(sk);
  	sa_family_t sa_family = sk->sk_family;
 +	__be16 port = inet_sk(sk)->inet_sport;
  	int err;
  
  	if (sa_family == AF_INET) {
- 		err = udp_add_offload(&gs->udp_offloads);
+ 		err = udp_add_offload(sock_net(sk), &gs->udp_offloads);
  		if (err)
  			pr_warn("geneve: udp_add_offload failed with status %d\n",
  				err);
  	}
 +
 +	rcu_read_lock();
 +	for_each_netdev_rcu(net, dev) {
 +		if (dev->netdev_ops->ndo_add_geneve_port)
 +			dev->netdev_ops->ndo_add_geneve_port(dev, sa_family,
 +							     port);
 +	}
 +	rcu_read_unlock();
  }
  
  static int geneve_hlen(struct genevehdr *gh)
@@@ -500,7 -480,7 +500,7 @@@ static int geneve_gro_complete(struct s
  
  /* Create new listen socket if needed */
  static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port,
 -						bool ipv6)
 +						bool ipv6, u32 flags)
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
  	struct geneve_sock *gs;
@@@ -512,7 -492,7 +512,7 @@@
  	if (!gs)
  		return ERR_PTR(-ENOMEM);
  
 -	sock = geneve_create_sock(net, ipv6, port);
 +	sock = geneve_create_sock(net, ipv6, port, flags);
  	if (IS_ERR(sock)) {
  		kfree(gs);
  		return ERR_CAST(sock);
@@@ -541,20 -521,8 +541,20 @@@
  
  static void geneve_notify_del_rx_port(struct geneve_sock *gs)
  {
 +	struct net_device *dev;
  	struct sock *sk = gs->sock->sk;
 +	struct net *net = sock_net(sk);
  	sa_family_t sa_family = sk->sk_family;
 +	__be16 port = inet_sk(sk)->inet_sport;
 +
 +	rcu_read_lock();
 +	for_each_netdev_rcu(net, dev) {
 +		if (dev->netdev_ops->ndo_del_geneve_port)
 +			dev->netdev_ops->ndo_del_geneve_port(dev, sa_family,
 +							     port);
 +	}
 +
 +	rcu_read_unlock();
  
  	if (sa_family == AF_INET)
  		udp_del_offload(&gs->udp_offloads);
@@@ -607,13 -575,12 +607,13 @@@ static int geneve_sock_add(struct genev
  		goto out;
  	}
  
 -	gs = geneve_socket_create(net, geneve->dst_port, ipv6);
 +	gs = geneve_socket_create(net, geneve->dst_port, ipv6, geneve->flags);
  	if (IS_ERR(gs))
  		return PTR_ERR(gs);
  
  out:
  	gs->collect_md = geneve->collect_md;
 +	gs->flags = geneve->flags;
  #if IS_ENABLED(CONFIG_IPV6)
  	if (ipv6)
  		geneve->sock6 = gs;
@@@ -675,12 -642,11 +675,12 @@@ static void geneve_build_header(struct 
  
  static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb,
  			    __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
 -			    bool csum, bool xnet)
 +			    u32 flags, bool xnet)
  {
  	struct genevehdr *gnvh;
  	int min_headroom;
  	int err;
 +	bool udp_sum = !!(flags & GENEVE_F_UDP_CSUM);
  
  	skb_scrub_packet(skb, xnet);
  
@@@ -692,7 -658,7 +692,7 @@@
  		goto free_rt;
  	}
  
 -	skb = udp_tunnel_handle_offloads(skb, csum);
 +	skb = udp_tunnel_handle_offloads(skb, udp_sum);
  	if (IS_ERR(skb)) {
  		err = PTR_ERR(skb);
  		goto free_rt;
@@@ -712,12 -678,11 +712,12 @@@ free_rt
  #if IS_ENABLED(CONFIG_IPV6)
  static int geneve6_build_skb(struct dst_entry *dst, struct sk_buff *skb,
  			     __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt,
 -			     bool csum, bool xnet)
 +			     u32 flags, bool xnet)
  {
  	struct genevehdr *gnvh;
  	int min_headroom;
  	int err;
 +	bool udp_sum = !(flags & GENEVE_F_UDP_ZERO_CSUM6_TX);
  
  	skb_scrub_packet(skb, xnet);
  
@@@ -729,7 -694,7 +729,7 @@@
  		goto free_dst;
  	}
  
 -	skb = udp_tunnel_handle_offloads(skb, csum);
 +	skb = udp_tunnel_handle_offloads(skb, udp_sum);
  	if (IS_ERR(skb)) {
  		err = PTR_ERR(skb);
  		goto free_dst;
@@@ -859,9 -824,9 +859,9 @@@ static netdev_tx_t geneve_xmit_skb(stru
  	struct flowi4 fl4;
  	__u8 tos, ttl;
  	__be16 sport;
 -	bool udp_csum;
  	__be16 df;
  	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
 +	u32 flags = geneve->flags;
  
  	if (geneve->collect_md) {
  		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
@@@ -892,13 -857,9 +892,13 @@@
  		if (key->tun_flags & TUNNEL_GENEVE_OPT)
  			opts = ip_tunnel_info_opts(info);
  
 -		udp_csum = !!(key->tun_flags & TUNNEL_CSUM);
 +		if (key->tun_flags & TUNNEL_CSUM)
 +			flags |= GENEVE_F_UDP_CSUM;
 +		else
 +			flags &= ~GENEVE_F_UDP_CSUM;
 +
  		err = geneve_build_skb(rt, skb, key->tun_flags, vni,
 -				       info->options_len, opts, udp_csum, xnet);
 +				       info->options_len, opts, flags, xnet);
  		if (unlikely(err))
  			goto err;
  
@@@ -906,8 -867,9 +906,8 @@@
  		ttl = key->ttl;
  		df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
  	} else {
 -		udp_csum = false;
  		err = geneve_build_skb(rt, skb, 0, geneve->vni,
 -				       0, NULL, udp_csum, xnet);
 +				       0, NULL, flags, xnet);
  		if (unlikely(err))
  			goto err;
  
@@@ -918,11 -880,12 +918,11 @@@
  		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
  		df = 0;
  	}
 -	err = udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
 -				  tos, ttl, df, sport, geneve->dst_port,
 -				  !net_eq(geneve->net, dev_net(geneve->dev)),
 -				  !udp_csum);
 +	udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
 +			    tos, ttl, df, sport, geneve->dst_port,
 +			    !net_eq(geneve->net, dev_net(geneve->dev)),
 +			    !(flags & GENEVE_F_UDP_CSUM));
  
 -	iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
  	return NETDEV_TX_OK;
  
  tx_error:
@@@ -949,8 -912,8 +949,8 @@@ static netdev_tx_t geneve6_xmit_skb(str
  	struct flowi6 fl6;
  	__u8 prio, ttl;
  	__be16 sport;
 -	bool udp_csum;
  	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
 +	u32 flags = geneve->flags;
  
  	if (geneve->collect_md) {
  		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
@@@ -979,22 -942,19 +979,22 @@@
  		if (key->tun_flags & TUNNEL_GENEVE_OPT)
  			opts = ip_tunnel_info_opts(info);
  
 -		udp_csum = !!(key->tun_flags & TUNNEL_CSUM);
 +		if (key->tun_flags & TUNNEL_CSUM)
 +			flags |= GENEVE_F_UDP_CSUM;
 +		else
 +			flags &= ~GENEVE_F_UDP_CSUM;
 +
  		err = geneve6_build_skb(dst, skb, key->tun_flags, vni,
  					info->options_len, opts,
 -					udp_csum, xnet);
 +					flags, xnet);
  		if (unlikely(err))
  			goto err;
  
  		prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
  		ttl = key->ttl;
  	} else {
 -		udp_csum = false;
  		err = geneve6_build_skb(dst, skb, 0, geneve->vni,
 -					0, NULL, udp_csum, xnet);
 +					0, NULL, flags, xnet);
  		if (unlikely(err))
  			goto err;
  
@@@ -1004,10 -964,9 +1004,10 @@@
  			ttl = 1;
  		ttl = ttl ? : ip6_dst_hoplimit(dst);
  	}
 -	err = udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
 -				   &fl6.saddr, &fl6.daddr, prio, ttl,
 -				   sport, geneve->dst_port, !udp_csum);
 +	udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
 +			     &fl6.saddr, &fl6.daddr, prio, ttl,
 +			     sport, geneve->dst_port,
 +			     !!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX));
  	return NETDEV_TX_OK;
  
  tx_error:
@@@ -1106,30 -1065,6 +1106,30 @@@ static struct device_type geneve_type 
  	.name = "geneve",
  };
  
 +/* Calls the ndo_add_geneve_port of the caller in order to
 + * supply the listening GENEVE udp ports. Callers are expected
 + * to implement the ndo_add_geneve_port.
 + */
 +void geneve_get_rx_port(struct net_device *dev)
 +{
 +	struct net *net = dev_net(dev);
 +	struct geneve_net *gn = net_generic(net, geneve_net_id);
 +	struct geneve_sock *gs;
 +	sa_family_t sa_family;
 +	struct sock *sk;
 +	__be16 port;
 +
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(gs, &gn->sock_list, list) {
 +		sk = gs->sock->sk;
 +		sa_family = sk->sk_family;
 +		port = inet_sk(sk)->inet_sport;
 +		dev->netdev_ops->ndo_add_geneve_port(dev, sa_family, port);
 +	}
 +	rcu_read_unlock();
 +}
 +EXPORT_SYMBOL_GPL(geneve_get_rx_port);
 +
  /* Initialize the device structure. */
  static void geneve_setup(struct net_device *dev)
  {
@@@ -1162,9 -1097,6 +1162,9 @@@ static const struct nla_policy geneve_p
  	[IFLA_GENEVE_TOS]		= { .type = NLA_U8 },
  	[IFLA_GENEVE_PORT]		= { .type = NLA_U16 },
  	[IFLA_GENEVE_COLLECT_METADATA]	= { .type = NLA_FLAG },
 +	[IFLA_GENEVE_UDP_CSUM]		= { .type = NLA_U8 },
 +	[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]	= { .type = NLA_U8 },
 +	[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]	= { .type = NLA_U8 },
  };
  
  static int geneve_validate(struct nlattr *tb[], struct nlattr *data[])
@@@ -1218,7 -1150,7 +1218,7 @@@ static struct geneve_dev *geneve_find_d
  static int geneve_configure(struct net *net, struct net_device *dev,
  			    union geneve_addr *remote,
  			    __u32 vni, __u8 ttl, __u8 tos, __be16 dst_port,
 -			    bool metadata)
 +			    bool metadata, u32 flags)
  {
  	struct geneve_net *gn = net_generic(net, geneve_net_id);
  	struct geneve_dev *t, *geneve = netdev_priv(dev);
@@@ -1249,7 -1181,6 +1249,7 @@@
  	geneve->tos = tos;
  	geneve->dst_port = dst_port;
  	geneve->collect_md = metadata;
 +	geneve->flags = flags;
  
  	t = geneve_find_dev(gn, dst_port, remote, geneve->vni,
  			    &tun_on_same_port, &tun_collect_md);
@@@ -1288,7 -1219,6 +1288,7 @@@ static int geneve_newlink(struct net *n
  	bool metadata = false;
  	union geneve_addr remote = geneve_remote_unspec;
  	__u32 vni = 0;
 +	u32 flags = 0;
  
  	if (data[IFLA_GENEVE_REMOTE] && data[IFLA_GENEVE_REMOTE6])
  		return -EINVAL;
@@@ -1329,20 -1259,8 +1329,20 @@@
  	if (data[IFLA_GENEVE_COLLECT_METADATA])
  		metadata = true;
  
 +	if (data[IFLA_GENEVE_UDP_CSUM] &&
 +	    nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
 +		flags |= GENEVE_F_UDP_CSUM;
 +
 +	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] &&
 +	    nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
 +		flags |= GENEVE_F_UDP_ZERO_CSUM6_TX;
 +
 +	if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX] &&
 +	    nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
 +		flags |= GENEVE_F_UDP_ZERO_CSUM6_RX;
 +
  	return geneve_configure(net, dev, &remote, vni, ttl, tos, dst_port,
 -				metadata);
 +				metadata, flags);
  }
  
  static void geneve_dellink(struct net_device *dev, struct list_head *head)
@@@ -1361,9 -1279,6 +1361,9 @@@ static size_t geneve_get_size(const str
  		nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
  		nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
  		nla_total_size(0) +	 /* IFLA_GENEVE_COLLECT_METADATA */
 +		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
 +		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_TX */
 +		nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_ZERO_CSUM6_RX */
  		0;
  }
  
@@@ -1400,14 -1315,6 +1400,14 @@@ static int geneve_fill_info(struct sk_b
  			goto nla_put_failure;
  	}
  
 +	if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
 +		       !!(geneve->flags & GENEVE_F_UDP_CSUM)) ||
 +	    nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
 +		       !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_TX)) ||
 +	    nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
 +		       !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_RX)))
 +		goto nla_put_failure;
 +
  	return 0;
  
  nla_put_failure:
@@@ -1441,7 -1348,7 +1441,7 @@@ struct net_device *geneve_dev_create_fb
  		return dev;
  
  	err = geneve_configure(net, dev, &geneve_remote_unspec,
 -			       0, 0, 0, htons(dst_port), true);
 +			       0, 0, 0, htons(dst_port), true, 0);
  	if (err) {
  		free_netdev(dev);
  		return ERR_PTR(err);
diff --combined drivers/net/phy/micrel.c
index 0dbc649,7a56799..03833db
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@@ -73,17 -73,6 +73,17 @@@
  
  #define PS_TO_REG				200
  
 +struct kszphy_hw_stat {
 +	const char *string;
 +	u8 reg;
 +	u8 bits;
 +};
 +
 +static struct kszphy_hw_stat kszphy_hw_stats[] = {
 +	{ "phy_receive_errors", 21, 16},
 +	{ "phy_idle_errors", 10, 8 },
 +};
 +
  struct kszphy_type {
  	u32 led_mode_reg;
  	u16 interrupt_level_mask;
@@@ -97,7 -86,6 +97,7 @@@ struct kszphy_priv 
  	int led_mode;
  	bool rmii_ref_clk_sel;
  	bool rmii_ref_clk_sel_val;
 +	u64 stats[ARRAY_SIZE(kszphy_hw_stats)];
  };
  
  static const struct kszphy_type ksz8021_type = {
@@@ -224,7 -212,7 +224,7 @@@ static int kszphy_setup_led(struct phy_
  	rc = phy_write(phydev, reg, temp);
  out:
  	if (rc < 0)
 -		dev_err(&phydev->dev, "failed to set led mode\n");
 +		phydev_err(phydev, "failed to set led mode\n");
  
  	return rc;
  }
@@@ -243,7 -231,7 +243,7 @@@ static int kszphy_broadcast_disable(str
  	ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
  out:
  	if (ret)
 -		dev_err(&phydev->dev, "failed to disable broadcast address\n");
 +		phydev_err(phydev, "failed to disable broadcast address\n");
  
  	return ret;
  }
@@@ -263,7 -251,7 +263,7 @@@ static int kszphy_nand_tree_disable(str
  			ret & ~KSZPHY_OMSO_NAND_TREE_ON);
  out:
  	if (ret)
 -		dev_err(&phydev->dev, "failed to disable NAND tree mode\n");
 +		phydev_err(phydev, "failed to disable NAND tree mode\n");
  
  	return ret;
  }
@@@ -288,8 -276,7 +288,8 @@@ static int kszphy_config_init(struct ph
  	if (priv->rmii_ref_clk_sel) {
  		ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
  		if (ret) {
 -			dev_err(&phydev->dev, "failed to set rmii reference clock\n");
 +			phydev_err(phydev,
 +				   "failed to set rmii reference clock\n");
  			return ret;
  		}
  	}
@@@ -350,7 -337,7 +350,7 @@@ static int ksz9021_load_values_from_of(
  
  static int ksz9021_config_init(struct phy_device *phydev)
  {
 -	const struct device *dev = &phydev->dev;
 +	const struct device *dev = &phydev->mdio.dev;
  	const struct device_node *of_node = dev->of_node;
  	const struct device *dev_walker;
  
@@@ -358,7 -345,7 +358,7 @@@
  	 * properties in the MAC node. Walk up the tree of devices to
  	 * find a device with an OF node.
  	 */
 -	dev_walker = &phydev->dev;
 +	dev_walker = &phydev->mdio.dev;
  	do {
  		of_node = dev_walker->of_node;
  		dev_walker = dev_walker->parent;
@@@ -471,7 -458,7 +471,7 @@@ static int ksz9031_center_flp_timing(st
  
  static int ksz9031_config_init(struct phy_device *phydev)
  {
 -	const struct device *dev = &phydev->dev;
 +	const struct device *dev = &phydev->mdio.dev;
  	const struct device_node *of_node = dev->of_node;
  	static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
  	static const char *rx_data_skews[4] = {
@@@ -483,9 -470,17 +483,17 @@@
  		"txd2-skew-ps", "txd3-skew-ps"
  	};
  	static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
+ 	const struct device *dev_walker;
  
- 	if (!of_node && dev->parent->of_node)
- 		of_node = dev->parent->of_node;
+ 	/* The Micrel driver has a deprecated option to place phy OF
+ 	 * properties in the MAC node. Walk up the tree of devices to
+ 	 * find a device with an OF node.
+ 	 */
 -	dev_walker = &phydev->dev;
++	dev_walker = &phydev->mdio.dev;
+ 	do {
+ 		of_node = dev_walker->of_node;
+ 		dev_walker = dev_walker->parent;
+ 	} while (!of_node && dev_walker);
  
  	if (of_node) {
  		ksz9031_of_load_skew_values(phydev, of_node,
@@@ -582,60 -577,15 +590,60 @@@ ksz9021_wr_mmd_phyreg(struct phy_devic
  {
  }
  
 +static int kszphy_get_sset_count(struct phy_device *phydev)
 +{
 +	return ARRAY_SIZE(kszphy_hw_stats);
 +}
 +
 +static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
 +{
 +	int i;
 +
 +	for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
 +		memcpy(data + i * ETH_GSTRING_LEN,
 +		       kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
 +	}
 +}
 +
 +#ifndef UINT64_MAX
 +#define UINT64_MAX              (u64)(~((u64)0))
 +#endif
 +static u64 kszphy_get_stat(struct phy_device *phydev, int i)
 +{
 +	struct kszphy_hw_stat stat = kszphy_hw_stats[i];
 +	struct kszphy_priv *priv = phydev->priv;
 +	u64 val;
 +
 +	val = phy_read(phydev, stat.reg);
 +	if (val < 0) {
 +		val = UINT64_MAX;
 +	} else {
 +		val = val & ((1 << stat.bits) - 1);
 +		priv->stats[i] += val;
 +		val = priv->stats[i];
 +	}
 +
 +	return val;
 +}
 +
 +static void kszphy_get_stats(struct phy_device *phydev,
 +			     struct ethtool_stats *stats, u64 *data)
 +{
 +	int i;
 +
 +	for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
 +		data[i] = kszphy_get_stat(phydev, i);
 +}
 +
  static int kszphy_probe(struct phy_device *phydev)
  {
  	const struct kszphy_type *type = phydev->drv->driver_data;
 -	const struct device_node *np = phydev->dev.of_node;
 +	const struct device_node *np = phydev->mdio.dev.of_node;
  	struct kszphy_priv *priv;
  	struct clk *clk;
  	int ret;
  
 -	priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL);
 +	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
  	if (!priv)
  		return -ENOMEM;
  
@@@ -650,15 -600,15 +658,15 @@@
  			priv->led_mode = -1;
  
  		if (priv->led_mode > 3) {
 -			dev_err(&phydev->dev, "invalid led mode: 0x%02x\n",
 -					priv->led_mode);
 +			phydev_err(phydev, "invalid led mode: 0x%02x\n",
 +				   priv->led_mode);
  			priv->led_mode = -1;
  		}
  	} else {
  		priv->led_mode = -1;
  	}
  
 -	clk = devm_clk_get(&phydev->dev, "rmii-ref");
 +	clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
  	/* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
  	if (!IS_ERR_OR_NULL(clk)) {
  		unsigned long rate = clk_get_rate(clk);
@@@ -673,8 -623,7 +681,8 @@@
  		} else if (rate > 49500000 && rate < 50500000) {
  			priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz;
  		} else {
 -			dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate);
 +			phydev_err(phydev, "Clock rate out of range: %ld\n",
 +				   rate);
  			return -EINVAL;
  		}
  	}
@@@ -701,11 -650,9 +709,11 @@@ static struct phy_driver ksphy_driver[
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8021,
  	.phy_id_mask	= 0x00ffffff,
@@@ -720,11 -667,9 +728,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8031,
  	.phy_id_mask	= 0x00ffffff,
@@@ -739,11 -684,9 +747,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8041,
  	.phy_id_mask	= 0x00fffff0,
@@@ -758,11 -701,9 +766,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8041RNLI,
  	.phy_id_mask	= 0x00fffff0,
@@@ -777,11 -718,9 +785,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8051,
  	.phy_id_mask	= 0x00fffff0,
@@@ -796,11 -735,9 +804,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8001,
  	.name		= "Micrel KSZ8001 or KS8721",
@@@ -814,11 -751,9 +822,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8081,
  	.name		= "Micrel KSZ8081 or KSZ8091",
@@@ -832,11 -767,9 +840,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ8061,
  	.name		= "Micrel KSZ8061",
@@@ -848,11 -781,9 +856,11 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE,},
  }, {
  	.phy_id		= PHY_ID_KSZ9021,
  	.phy_id_mask	= 0x000ffffe,
@@@ -865,13 -796,11 +873,13 @@@
  	.read_status	= genphy_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
  	.read_mmd_indirect = ksz9021_rd_mmd_phyreg,
  	.write_mmd_indirect = ksz9021_wr_mmd_phyreg,
 -	.driver		= { .owner = THIS_MODULE, },
  }, {
  	.phy_id		= PHY_ID_KSZ9031,
  	.phy_id_mask	= 0x00fffff0,
@@@ -884,11 -813,9 +892,11 @@@
  	.read_status	= ksz9031_read_status,
  	.ack_interrupt	= kszphy_ack_interrupt,
  	.config_intr	= kszphy_config_intr,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE, },
  }, {
  	.phy_id		= PHY_ID_KSZ8873MLL,
  	.phy_id_mask	= 0x00fffff0,
@@@ -898,11 -825,9 +906,11 @@@
  	.config_init	= kszphy_config_init,
  	.config_aneg	= ksz8873mll_config_aneg,
  	.read_status	= ksz8873mll_read_status,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE, },
  }, {
  	.phy_id		= PHY_ID_KSZ886X,
  	.phy_id_mask	= 0x00fffff0,
@@@ -912,11 -837,9 +920,11 @@@
  	.config_init	= kszphy_config_init,
  	.config_aneg	= genphy_config_aneg,
  	.read_status	= genphy_read_status,
 +	.get_sset_count = kszphy_get_sset_count,
 +	.get_strings	= kszphy_get_strings,
 +	.get_stats	= kszphy_get_stats,
  	.suspend	= genphy_suspend,
  	.resume		= genphy_resume,
 -	.driver		= { .owner = THIS_MODULE, },
  } };
  
  module_phy_driver(ksphy_driver);
diff --combined drivers/net/usb/lan78xx.c
index 1662b7b,d54f536..2ed5333
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@@ -603,6 -603,59 +603,59 @@@ static int lan78xx_read_raw_otp(struct 
  	return 0;
  }
  
+ static int lan78xx_write_raw_otp(struct lan78xx_net *dev, u32 offset,
+ 				 u32 length, u8 *data)
+ {
+ 	int i;
+ 	int ret;
+ 	u32 buf;
+ 	unsigned long timeout;
+ 
+ 	ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+ 
+ 	if (buf & OTP_PWR_DN_PWRDN_N_) {
+ 		/* clear it and wait to be cleared */
+ 		ret = lan78xx_write_reg(dev, OTP_PWR_DN, 0);
+ 
+ 		timeout = jiffies + HZ;
+ 		do {
+ 			udelay(1);
+ 			ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf);
+ 			if (time_after(jiffies, timeout)) {
+ 				netdev_warn(dev->net,
+ 					    "timeout on OTP_PWR_DN completion");
+ 				return -EIO;
+ 			}
+ 		} while (buf & OTP_PWR_DN_PWRDN_N_);
+ 	}
+ 
+ 	/* set to BYTE program mode */
+ 	ret = lan78xx_write_reg(dev, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
+ 
+ 	for (i = 0; i < length; i++) {
+ 		ret = lan78xx_write_reg(dev, OTP_ADDR1,
+ 					((offset + i) >> 8) & OTP_ADDR1_15_11);
+ 		ret = lan78xx_write_reg(dev, OTP_ADDR2,
+ 					((offset + i) & OTP_ADDR2_10_3));
+ 		ret = lan78xx_write_reg(dev, OTP_PRGM_DATA, data[i]);
+ 		ret = lan78xx_write_reg(dev, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
+ 		ret = lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_);
+ 
+ 		timeout = jiffies + HZ;
+ 		do {
+ 			udelay(1);
+ 			ret = lan78xx_read_reg(dev, OTP_STATUS, &buf);
+ 			if (time_after(jiffies, timeout)) {
+ 				netdev_warn(dev->net,
+ 					    "Timeout on OTP_STATUS completion");
+ 				return -EIO;
+ 			}
+ 		} while (buf & OTP_STATUS_BUSY_);
+ 	}
+ 
+ 	return 0;
+ }
+ 
  static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset,
  			    u32 length, u8 *data)
  {
@@@ -969,7 -1022,7 +1022,7 @@@ static int lan78xx_ethtool_set_eeprom(s
  		 (ee->offset == 0) &&
  		 (ee->len == 512) &&
  		 (data[0] == OTP_INDICATOR_1))
- 		return lan78xx_write_raw_eeprom(dev, ee->offset, ee->len, data);
+ 		return lan78xx_write_raw_otp(dev, ee->offset, ee->len, data);
  
  	return -EINVAL;
  }
@@@ -1458,6 -1511,12 +1511,6 @@@ static int lan78xx_mdio_init(struct lan
  	snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
  		 dev->udev->bus->busnum, dev->udev->devnum);
  
 -	dev->mdiobus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
 -	if (!dev->mdiobus->irq) {
 -		ret = -ENOMEM;
 -		goto exit1;
 -	}
 -
  	/* handle our own interrupt */
  	for (i = 0; i < PHY_MAX_ADDR; i++)
  		dev->mdiobus->irq[i] = PHY_IGNORE_INTERRUPT;
@@@ -1473,11 -1532,13 +1526,11 @@@
  	ret = mdiobus_register(dev->mdiobus);
  	if (ret) {
  		netdev_err(dev->net, "can't register MDIO bus\n");
 -		goto exit2;
 +		goto exit1;
  	}
  
  	netdev_dbg(dev->net, "registered mdiobus bus %s\n", dev->mdiobus->id);
  	return 0;
 -exit2:
 -	kfree(dev->mdiobus->irq);
  exit1:
  	mdiobus_free(dev->mdiobus);
  	return ret;
@@@ -1486,6 -1547,7 +1539,6 @@@
  static void lan78xx_remove_mdio(struct lan78xx_net *dev)
  {
  	mdiobus_unregister(dev->mdiobus);
 -	kfree(dev->mdiobus->irq);
  	mdiobus_free(dev->mdiobus);
  }
  
diff --combined drivers/net/usb/qmi_wwan.c
index 3341d8a,772b9d0..23e9880
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@@ -14,9 -14,7 +14,9 @@@
  #include <linux/netdevice.h>
  #include <linux/ethtool.h>
  #include <linux/etherdevice.h>
 +#include <linux/if_arp.h>
  #include <linux/mii.h>
 +#include <linux/rtnetlink.h>
  #include <linux/usb.h>
  #include <linux/usb/cdc.h>
  #include <linux/usb/usbnet.h>
@@@ -50,100 -48,11 +50,100 @@@
  struct qmi_wwan_state {
  	struct usb_driver *subdriver;
  	atomic_t pmcount;
 -	unsigned long unused;
 +	unsigned long flags;
  	struct usb_interface *control;
  	struct usb_interface *data;
  };
  
 +enum qmi_wwan_flags {
 +	QMI_WWAN_FLAG_RAWIP = 1 << 0,
 +};
 +
 +static void qmi_wwan_netdev_setup(struct net_device *net)
 +{
 +	struct usbnet *dev = netdev_priv(net);
 +	struct qmi_wwan_state *info = (void *)&dev->data;
 +
 +	if (info->flags & QMI_WWAN_FLAG_RAWIP) {
 +		net->header_ops      = NULL;  /* No header */
 +		net->type            = ARPHRD_NONE;
 +		net->hard_header_len = 0;
 +		net->addr_len        = 0;
 +		net->flags           = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
 +		netdev_dbg(net, "mode: raw IP\n");
 +	} else if (!net->header_ops) { /* don't bother if already set */
 +		ether_setup(net);
 +		netdev_dbg(net, "mode: Ethernet\n");
 +	}
 +
 +	/* recalculate buffers after changing hard_header_len */
 +	usbnet_change_mtu(net, net->mtu);
 +}
 +
 +static ssize_t raw_ip_show(struct device *d, struct device_attribute *attr, char *buf)
 +{
 +	struct usbnet *dev = netdev_priv(to_net_dev(d));
 +	struct qmi_wwan_state *info = (void *)&dev->data;
 +
 +	return sprintf(buf, "%c\n", info->flags & QMI_WWAN_FLAG_RAWIP ? 'Y' : 'N');
 +}
 +
 +static ssize_t raw_ip_store(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
 +{
 +	struct usbnet *dev = netdev_priv(to_net_dev(d));
 +	struct qmi_wwan_state *info = (void *)&dev->data;
 +	bool enable;
 +	int ret;
 +
 +	if (strtobool(buf, &enable))
 +		return -EINVAL;
 +
 +	/* no change? */
 +	if (enable == (info->flags & QMI_WWAN_FLAG_RAWIP))
 +		return len;
 +
 +	if (!rtnl_trylock())
 +		return restart_syscall();
 +
 +	/* we don't want to modify a running netdev */
 +	if (netif_running(dev->net)) {
 +		netdev_err(dev->net, "Cannot change a running device\n");
 +		ret = -EBUSY;
 +		goto err;
 +	}
 +
 +	/* let other drivers deny the change */
 +	ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev->net);
 +	ret = notifier_to_errno(ret);
 +	if (ret) {
 +		netdev_err(dev->net, "Type change was refused\n");
 +		goto err;
 +	}
 +
 +	if (enable)
 +		info->flags |= QMI_WWAN_FLAG_RAWIP;
 +	else
 +		info->flags &= ~QMI_WWAN_FLAG_RAWIP;
 +	qmi_wwan_netdev_setup(dev->net);
 +	call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev->net);
 +	ret = len;
 +err:
 +	rtnl_unlock();
 +	return ret;
 +}
 +
 +static DEVICE_ATTR_RW(raw_ip);
 +
 +static struct attribute *qmi_wwan_sysfs_attrs[] = {
 +	&dev_attr_raw_ip.attr,
 +	NULL,
 +};
 +
 +static struct attribute_group qmi_wwan_sysfs_attr_group = {
 +	.name = "qmi",
 +	.attrs = qmi_wwan_sysfs_attrs,
 +};
 +
  /* default ethernet address used by the modem */
  static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
  
@@@ -171,8 -80,6 +171,8 @@@ static const u8 buggy_fw_addr[ETH_ALEN
   */
  static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
  {
 +	struct qmi_wwan_state *info = (void *)&dev->data;
 +	bool rawip = info->flags & QMI_WWAN_FLAG_RAWIP;
  	__be16 proto;
  
  	/* This check is no longer done by usbnet */
@@@ -187,25 -94,15 +187,25 @@@
  		proto = htons(ETH_P_IPV6);
  		break;
  	case 0x00:
 +		if (rawip)
 +			return 0;
  		if (is_multicast_ether_addr(skb->data))
  			return 1;
  		/* possibly bogus destination - rewrite just in case */
  		skb_reset_mac_header(skb);
  		goto fix_dest;
  	default:
 +		if (rawip)
 +			return 0;
  		/* pass along other packets without modifications */
  		return 1;
  	}
 +	if (rawip) {
 +		skb->dev = dev->net; /* normally set by eth_type_trans */
 +		skb->protocol = proto;
 +		return 1;
 +	}
 +
  	if (skb_headroom(skb) < ETH_HLEN)
  		return 0;
  	skb_push(skb, ETH_HLEN);
@@@ -326,20 -223,6 +326,20 @@@ err
  	return rv;
  }
  
 +/* Send CDC SetControlLineState request, setting or clearing the DTR.
 + * "Required for Autoconnect and 9x30 to wake up" according to the
 + * GobiNet driver. The requirement has been verified on an MDM9230
 + * based Sierra Wireless MC7455
 + */
 +static int qmi_wwan_change_dtr(struct usbnet *dev, bool on)
 +{
 +	u8 intf = dev->intf->cur_altsetting->desc.bInterfaceNumber;
 +
 +	return usbnet_write_cmd(dev, USB_CDC_REQ_SET_CONTROL_LINE_STATE,
 +				USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 +				on ? 0x01 : 0x00, intf, NULL, 0);
 +}
 +
  static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
  {
  	int status = -1;
@@@ -374,10 -257,7 +374,10 @@@
  				"bogus CDC Union: master=%u, slave=%u\n",
  				cdc_union->bMasterInterface0,
  				cdc_union->bSlaveInterface0);
 -			goto err;
 +
 +			/* ignore and continue... */
 +			cdc_union = NULL;
 +			info->data = intf;
  		}
  	}
  
@@@ -400,24 -280,6 +400,24 @@@
  		usb_driver_release_interface(driver, info->data);
  	}
  
 +	/* disabling remote wakeup on MDM9x30 devices has the same
 +	 * effect as clearing DTR. The device will not respond to QMI
 +	 * requests until we set DTR again.  This is similar to a
 +	 * QMI_CTL SYNC request, clearing a lot of firmware state
 +	 * including the client ID allocations.
 +	 *
 +	 * Our usage model allows a session to span multiple
 +	 * open/close events, so we must prevent the firmware from
 +	 * clearing out state the clients might need.
 +	 *
 +	 * MDM9x30 is the first QMI chipset with USB3 support. Abuse
 +	 * this fact to enable the quirk.
 +	 */
 +	if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
 +		qmi_wwan_manage_power(dev, 1);
 +		qmi_wwan_change_dtr(dev, true);
 +	}
 +
  	/* Never use the same address on both ends of the link, even if the
  	 * buggy firmware told us to. Or, if device is assigned the well-known
  	 * buggy firmware MAC address, replace it with a random address,
@@@ -432,7 -294,6 +432,7 @@@
  		dev->net->dev_addr[0] &= 0xbf;	/* clear "IP" bit */
  	}
  	dev->net->netdev_ops = &qmi_wwan_netdev_ops;
 +	dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group;
  err:
  	return status;
  }
@@@ -446,12 -307,6 +446,12 @@@ static void qmi_wwan_unbind(struct usbn
  	if (info->subdriver && info->subdriver->disconnect)
  		info->subdriver->disconnect(info->control);
  
 +	/* disable MDM9x30 quirk */
 +	if (le16_to_cpu(dev->udev->descriptor.bcdUSB) >= 0x0201) {
 +		qmi_wwan_change_dtr(dev, false);
 +		qmi_wwan_manage_power(dev, 0);
 +	}
 +
  	/* allow user to unbind using either control or data */
  	if (intf == info->control)
  		other = info->data;
@@@ -860,6 -715,8 +860,6 @@@ static const struct usb_device_id produ
  	{QMI_FIXED_INTF(0x1199, 0x9056, 8)},	/* Sierra Wireless Modem */
  	{QMI_FIXED_INTF(0x1199, 0x9057, 8)},
  	{QMI_FIXED_INTF(0x1199, 0x9061, 8)},	/* Sierra Wireless Modem */
 -	{QMI_FIXED_INTF(0x1199, 0x9070, 8)},	/* Sierra Wireless MC74xx/EM74xx */
 -	{QMI_FIXED_INTF(0x1199, 0x9070, 10)},	/* Sierra Wireless MC74xx/EM74xx */
  	{QMI_FIXED_INTF(0x1199, 0x9071, 8)},	/* Sierra Wireless MC74xx/EM74xx */
  	{QMI_FIXED_INTF(0x1199, 0x9071, 10)},	/* Sierra Wireless MC74xx/EM74xx */
  	{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},	/* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
@@@ -886,6 -743,7 +886,7 @@@
  	{QMI_FIXED_INTF(0x413c, 0x81b1, 8)},	/* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
  	{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},	/* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
  	{QMI_FIXED_INTF(0x22de, 0x9061, 3)},	/* WeTelecom WPD-600N */
+ 	{QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},	/* SIMCom 7230E */
  
  	/* 4. Gobi 1000 devices */
  	{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},	/* Acer Gobi Modem Device */
diff --combined drivers/net/usb/r8152.c
index 230c73c,ef9aab6..d1f78c2
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@@ -25,12 -25,13 +25,13 @@@
  #include <uapi/linux/mdio.h>
  #include <linux/mdio.h>
  #include <linux/usb/cdc.h>
+ #include <linux/suspend.h>
  
  /* Information for net-next */
  #define NETNEXT_VERSION		"08"
  
  /* Information for net */
- #define NET_VERSION		"2"
+ #define NET_VERSION		"3"
  
  #define DRIVER_VERSION		"v1." NETNEXT_VERSION "." NET_VERSION
  #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd at realtek.com>"
@@@ -604,6 -605,9 +605,9 @@@ struct r8152 
  	struct delayed_work schedule;
  	struct mii_if_info mii;
  	struct mutex control;	/* use for hw setting */
+ #ifdef CONFIG_PM_SLEEP
+ 	struct notifier_block pm_notifier;
+ #endif
  
  	struct rtl_ops {
  		void (*init)(struct r8152 *);
@@@ -1938,6 -1942,7 +1942,6 @@@ static void _rtl8152_set_rx_mode(struc
  	__le32 tmp[2];
  	u32 ocp_data;
  
 -	clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
  	netif_stop_queue(netdev);
  	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
  	ocp_data &= ~RCR_ACPT_ALL;
@@@ -1985,7 -1990,7 +1989,7 @@@ rtl8152_features_check(struct sk_buff *
  	int offset = skb_transport_offset(skb);
  
  	if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset)
 -		features &= ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
 +		features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
  	else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
  		features &= ~NETIF_F_GSO_MASK;
  
@@@ -2423,6 -2428,8 +2427,6 @@@ static void rtl_phy_reset(struct r8152 
  	u16 data;
  	int i;
  
 -	clear_bit(PHY_RESET, &tp->flags);
 -
  	data = r8152_mdio_read(tp, MII_BMCR);
  
  	/* don't reset again before the previous one complete */
@@@ -2452,23 -2459,23 +2456,23 @@@ static void r8153_teredo_off(struct r81
  	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
  }
  
 -static void r8152b_disable_aldps(struct r8152 *tp)
 -{
 -	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
 -	msleep(20);
 -}
 -
 -static inline void r8152b_enable_aldps(struct r8152 *tp)
 +static void r8152_aldps_en(struct r8152 *tp, bool enable)
  {
 -	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
 -					    LINKENA | DIS_SDSAVE);
 +	if (enable) {
 +		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
 +						    LINKENA | DIS_SDSAVE);
 +	} else {
 +		ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA |
 +						    DIS_SDSAVE);
 +		msleep(20);
 +	}
  }
  
  static void rtl8152_disable(struct r8152 *tp)
  {
 -	r8152b_disable_aldps(tp);
 +	r8152_aldps_en(tp, false);
  	rtl_disable(tp);
 -	r8152b_enable_aldps(tp);
 +	r8152_aldps_en(tp, true);
  }
  
  static void r8152b_hw_phy_cfg(struct r8152 *tp)
@@@ -2780,26 -2787,30 +2784,26 @@@ static void r8153_enter_oob(struct r815
  	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
  }
  
 -static void r8153_disable_aldps(struct r8152 *tp)
 +static void r8153_aldps_en(struct r8152 *tp, bool enable)
  {
  	u16 data;
  
  	data = ocp_reg_read(tp, OCP_POWER_CFG);
 -	data &= ~EN_ALDPS;
 -	ocp_reg_write(tp, OCP_POWER_CFG, data);
 -	msleep(20);
 -}
 -
 -static void r8153_enable_aldps(struct r8152 *tp)
 -{
 -	u16 data;
 -
 -	data = ocp_reg_read(tp, OCP_POWER_CFG);
 -	data |= EN_ALDPS;
 -	ocp_reg_write(tp, OCP_POWER_CFG, data);
 +	if (enable) {
 +		data |= EN_ALDPS;
 +		ocp_reg_write(tp, OCP_POWER_CFG, data);
 +	} else {
 +		data &= ~EN_ALDPS;
 +		ocp_reg_write(tp, OCP_POWER_CFG, data);
 +		msleep(20);
 +	}
  }
  
  static void rtl8153_disable(struct r8152 *tp)
  {
 -	r8153_disable_aldps(tp);
 +	r8153_aldps_en(tp, false);
  	rtl_disable(tp);
 -	r8153_enable_aldps(tp);
 +	r8153_aldps_en(tp, true);
  	usb_enable_lpm(tp->udev);
  }
  
@@@ -2877,9 -2888,10 +2881,9 @@@ static int rtl8152_set_speed(struct r81
  	r8152_mdio_write(tp, MII_ADVERTISE, anar);
  	r8152_mdio_write(tp, MII_BMCR, bmcr);
  
 -	if (test_bit(PHY_RESET, &tp->flags)) {
 +	if (test_and_clear_bit(PHY_RESET, &tp->flags)) {
  		int i;
  
 -		clear_bit(PHY_RESET, &tp->flags);
  		for (i = 0; i < 50; i++) {
  			msleep(20);
  			if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
@@@ -2888,6 -2900,7 +2892,6 @@@
  	}
  
  out:
 -
  	return ret;
  }
  
@@@ -2896,9 -2909,9 +2900,9 @@@ static void rtl8152_up(struct r8152 *tp
  	if (test_bit(RTL8152_UNPLUG, &tp->flags))
  		return;
  
 -	r8152b_disable_aldps(tp);
 +	r8152_aldps_en(tp, false);
  	r8152b_exit_oob(tp);
 -	r8152b_enable_aldps(tp);
 +	r8152_aldps_en(tp, true);
  }
  
  static void rtl8152_down(struct r8152 *tp)
@@@ -2909,9 -2922,9 +2913,9 @@@
  	}
  
  	r8152_power_cut_en(tp, false);
 -	r8152b_disable_aldps(tp);
 +	r8152_aldps_en(tp, false);
  	r8152b_enter_oob(tp);
 -	r8152b_enable_aldps(tp);
 +	r8152_aldps_en(tp, true);
  }
  
  static void rtl8153_up(struct r8152 *tp)
@@@ -2920,9 -2933,9 +2924,9 @@@
  		return;
  
  	r8153_u1u2en(tp, false);
 -	r8153_disable_aldps(tp);
 +	r8153_aldps_en(tp, false);
  	r8153_first_init(tp);
 -	r8153_enable_aldps(tp);
 +	r8153_aldps_en(tp, true);
  	r8153_u2p3en(tp, true);
  	r8153_u1u2en(tp, true);
  	usb_enable_lpm(tp->udev);
@@@ -2938,9 -2951,9 +2942,9 @@@ static void rtl8153_down(struct r8152 *
  	r8153_u1u2en(tp, false);
  	r8153_u2p3en(tp, false);
  	r8153_power_cut_en(tp, false);
 -	r8153_disable_aldps(tp);
 +	r8153_aldps_en(tp, false);
  	r8153_enter_oob(tp);
 -	r8153_enable_aldps(tp);
 +	r8153_aldps_en(tp, true);
  }
  
  static bool rtl8152_in_nway(struct r8152 *tp)
@@@ -2974,6 -2987,7 +2978,6 @@@ static void set_carrier(struct r8152 *t
  	struct net_device *netdev = tp->netdev;
  	u8 speed;
  
 -	clear_bit(RTL8152_LINK_CHG, &tp->flags);
  	speed = rtl8152_get_speed(tp);
  
  	if (speed & LINK_STATUS) {
@@@ -3016,18 -3030,20 +3020,18 @@@ static void rtl_work_func_t(struct work
  		goto out1;
  	}
  
 -	if (test_bit(RTL8152_LINK_CHG, &tp->flags))
 +	if (test_and_clear_bit(RTL8152_LINK_CHG, &tp->flags))
  		set_carrier(tp);
  
 -	if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
 +	if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags))
  		_rtl8152_set_rx_mode(tp->netdev);
  
  	/* don't schedule napi before linking */
 -	if (test_bit(SCHEDULE_NAPI, &tp->flags) &&
 -	    netif_carrier_ok(tp->netdev)) {
 -		clear_bit(SCHEDULE_NAPI, &tp->flags);
 +	if (test_and_clear_bit(SCHEDULE_NAPI, &tp->flags) &&
 +	    netif_carrier_ok(tp->netdev))
  		napi_schedule(&tp->napi);
 -	}
  
 -	if (test_bit(PHY_RESET, &tp->flags))
 +	if (test_and_clear_bit(PHY_RESET, &tp->flags))
  		rtl_phy_reset(tp);
  
  	mutex_unlock(&tp->control);
@@@ -3036,6 -3052,33 +3040,33 @@@ out1
  	usb_autopm_put_interface(tp->intf);
  }
  
+ #ifdef CONFIG_PM_SLEEP
+ static int rtl_notifier(struct notifier_block *nb, unsigned long action,
+ 			void *data)
+ {
+ 	struct r8152 *tp = container_of(nb, struct r8152, pm_notifier);
+ 
+ 	switch (action) {
+ 	case PM_HIBERNATION_PREPARE:
+ 	case PM_SUSPEND_PREPARE:
+ 		usb_autopm_get_interface(tp->intf);
+ 		break;
+ 
+ 	case PM_POST_HIBERNATION:
+ 	case PM_POST_SUSPEND:
+ 		usb_autopm_put_interface(tp->intf);
+ 		break;
+ 
+ 	case PM_POST_RESTORE:
+ 	case PM_RESTORE_PREPARE:
+ 	default:
+ 		break;
+ 	}
+ 
+ 	return NOTIFY_DONE;
+ }
+ #endif
+ 
  static int rtl8152_open(struct net_device *netdev)
  {
  	struct r8152 *tp = netdev_priv(netdev);
@@@ -3078,6 -3121,10 +3109,10 @@@
  	mutex_unlock(&tp->control);
  
  	usb_autopm_put_interface(tp->intf);
+ #ifdef CONFIG_PM_SLEEP
+ 	tp->pm_notifier.notifier_call = rtl_notifier;
+ 	register_pm_notifier(&tp->pm_notifier);
+ #endif
  
  out:
  	return res;
@@@ -3088,6 -3135,9 +3123,9 @@@ static int rtl8152_close(struct net_dev
  	struct r8152 *tp = netdev_priv(netdev);
  	int res = 0;
  
+ #ifdef CONFIG_PM_SLEEP
+ 	unregister_pm_notifier(&tp->pm_notifier);
+ #endif
  	napi_disable(&tp->napi);
  	clear_bit(WORK_ENABLE, &tp->flags);
  	usb_kill_urb(tp->intr_urb);
@@@ -3226,7 -3276,7 +3264,7 @@@ static void r8152b_init(struct r8152 *t
  	if (test_bit(RTL8152_UNPLUG, &tp->flags))
  		return;
  
 -	r8152b_disable_aldps(tp);
 +	r8152_aldps_en(tp, false);
  
  	if (tp->version == RTL_VER_01) {
  		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
@@@ -3248,7 -3298,7 +3286,7 @@@
  	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
  
  	r8152b_enable_eee(tp);
 -	r8152b_enable_aldps(tp);
 +	r8152_aldps_en(tp, true);
  	r8152b_enable_fc(tp);
  	rtl_tally_reset(tp);
  
@@@ -3266,7 -3316,7 +3304,7 @@@ static void r8153_init(struct r8152 *tp
  	if (test_bit(RTL8152_UNPLUG, &tp->flags))
  		return;
  
 -	r8153_disable_aldps(tp);
 +	r8153_aldps_en(tp, false);
  	r8153_u1u2en(tp, false);
  
  	for (i = 0; i < 500; i++) {
@@@ -3355,7 -3405,7 +3393,7 @@@
  		       EEE_SPDWN_EN);
  
  	r8153_enable_eee(tp);
 -	r8153_enable_aldps(tp);
 +	r8153_aldps_en(tp, true);
  	r8152b_enable_fc(tp);
  	rtl_tally_reset(tp);
  	r8153_u2p3en(tp, true);
diff --combined drivers/net/vxlan.c
index fecf7b6,e1e147f..2d88c79
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@@ -621,7 -621,7 +621,7 @@@ static void vxlan_notify_add_rx_port(st
  	int err;
  
  	if (sa_family == AF_INET) {
- 		err = udp_add_offload(&vs->udp_offloads);
+ 		err = udp_add_offload(net, &vs->udp_offloads);
  		if (err)
  			pr_warn("vxlan: udp_add_offload failed with status %d\n", err);
  	}
@@@ -1841,10 -1841,9 +1841,10 @@@ static int vxlan_xmit_skb(struct rtabl
  
  	skb_set_inner_protocol(skb, htons(ETH_P_TEB));
  
 -	return udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos,
 -				   ttl, df, src_port, dst_port, xnet,
 -				   !(vxflags & VXLAN_F_UDP_CSUM));
 +	udp_tunnel_xmit_skb(rt, sk, skb, src, dst, tos, ttl, df,
 +			    src_port, dst_port, xnet,
 +			    !(vxflags & VXLAN_F_UDP_CSUM));
 +	return 0;
  }
  
  #if IS_ENABLED(CONFIG_IPV6)
@@@ -2057,6 -2056,8 +2057,6 @@@ static void vxlan_xmit_one(struct sk_bu
  			skb = NULL;
  			goto rt_tx_error;
  		}
 -
 -		iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
  #if IS_ENABLED(CONFIG_IPV6)
  	} else {
  		struct dst_entry *ndst;
@@@ -2750,7 -2751,7 +2750,7 @@@ static int vxlan_dev_configure(struct n
  			       struct vxlan_config *conf)
  {
  	struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
- 	struct vxlan_dev *vxlan = netdev_priv(dev);
+ 	struct vxlan_dev *vxlan = netdev_priv(dev), *tmp;
  	struct vxlan_rdst *dst = &vxlan->default_dst;
  	unsigned short needed_headroom = ETH_HLEN;
  	int err;
@@@ -2816,9 -2817,15 +2816,15 @@@
  	if (!vxlan->cfg.age_interval)
  		vxlan->cfg.age_interval = FDB_AGE_DEFAULT;
  
- 	if (vxlan_find_vni(src_net, conf->vni, use_ipv6 ? AF_INET6 : AF_INET,
- 			   vxlan->cfg.dst_port, vxlan->flags))
+ 	list_for_each_entry(tmp, &vn->vxlan_list, next) {
+ 		if (tmp->cfg.vni == conf->vni &&
+ 		    (tmp->default_dst.remote_ip.sa.sa_family == AF_INET6 ||
+ 		     tmp->cfg.saddr.sa.sa_family == AF_INET6) == use_ipv6 &&
+ 		    tmp->cfg.dst_port == vxlan->cfg.dst_port &&
+ 		    (tmp->flags & VXLAN_F_RCV_FLAGS) ==
+ 		    (vxlan->flags & VXLAN_F_RCV_FLAGS))
  		return -EEXIST;
+ 	}
  
  	dev->ethtool_ops = &vxlan_ethtool_ops;
  
diff --combined net/batman-adv/bat_iv_ogm.c
index 2467024,aa94b4e..df625de
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@@ -185,7 -185,8 +185,8 @@@ unlock
  static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
  				     int max_if_num, int del_if_num)
  {
- 	int chunk_size,  ret = -ENOMEM, if_offset;
+ 	int ret = -ENOMEM;
+ 	size_t chunk_size, if_offset;
  	void *data_ptr = NULL;
  
  	spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
@@@ -203,8 -204,9 +204,9 @@@
  	memcpy(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
  
  	/* copy second part */
+ 	if_offset = (del_if_num + 1) * chunk_size;
  	memcpy((char *)data_ptr + del_if_num * chunk_size,
- 	       orig_node->bat_iv.bcast_own + ((del_if_num + 1) * chunk_size),
+ 	       (uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
  	       (max_if_num - del_if_num) * chunk_size);
  
  free_bcast_own:
@@@ -361,6 -363,7 +363,6 @@@ batadv_iv_ogm_primary_iface_set(struct 
  	unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
  
  	batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
 -	batadv_ogm_packet->flags = BATADV_PRIMARIES_FIRST_HOP;
  	batadv_ogm_packet->ttl = BATADV_TTL;
  }
  
@@@ -841,6 -844,8 +843,6 @@@ static void batadv_iv_ogm_forward(struc
  		   "Forwarding packet: tq: %i, ttl: %i\n",
  		   batadv_ogm_packet->tq, batadv_ogm_packet->ttl);
  
 -	/* switch of primaries first hop flag when forwarding */
 -	batadv_ogm_packet->flags &= ~BATADV_PRIMARIES_FIRST_HOP;
  	if (is_single_hop_neigh)
  		batadv_ogm_packet->flags |= BATADV_DIRECTLINK;
  	else
@@@ -1376,7 -1381,6 +1378,7 @@@ batadv_iv_ogm_process_per_outif(const s
  				struct batadv_hard_iface *if_outgoing)
  {
  	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 +	struct batadv_hardif_neigh_node *hardif_neigh = NULL;
  	struct batadv_neigh_node *router = NULL;
  	struct batadv_neigh_node *router_router = NULL;
  	struct batadv_orig_node *orig_neigh_node;
@@@ -1421,13 -1425,6 +1423,13 @@@
  		goto out;
  	}
  
 +	if (is_single_hop_neigh) {
 +		hardif_neigh = batadv_hardif_neigh_get(if_incoming,
 +						       ethhdr->h_source);
 +		if (hardif_neigh)
 +			hardif_neigh->last_seen = jiffies;
 +	}
 +
  	router = batadv_orig_router_get(orig_node, if_outgoing);
  	if (router) {
  		router_router = batadv_orig_router_get(router->orig_node,
@@@ -1562,8 -1559,6 +1564,8 @@@ out
  		batadv_neigh_node_free_ref(router_router);
  	if (orig_neigh_router)
  		batadv_neigh_node_free_ref(orig_neigh_router);
 +	if (hardif_neigh)
 +		batadv_hardif_neigh_free_ref(hardif_neigh);
  
  	kfree_skb(skb_priv);
  }
@@@ -1869,58 -1864,6 +1871,58 @@@ next
  }
  
  /**
 + * batadv_iv_hardif_neigh_print - print a single hop neighbour node
 + * @seq: neighbour table seq_file struct
 + * @hardif_neigh: hardif neighbour information
 + */
 +static void
 +batadv_iv_hardif_neigh_print(struct seq_file *seq,
 +			     struct batadv_hardif_neigh_node *hardif_neigh)
 +{
 +	int last_secs, last_msecs;
 +
 +	last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
 +	last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
 +
 +	seq_printf(seq, "   %10s   %pM %4i.%03is\n",
 +		   hardif_neigh->if_incoming->net_dev->name,
 +		   hardif_neigh->addr, last_secs, last_msecs);
 +}
 +
 +/**
 + * batadv_iv_ogm_neigh_print - print the single hop neighbour list
 + * @bat_priv: the bat priv with all the soft interface information
 + * @seq: neighbour table seq_file struct
 + */
 +static void batadv_iv_neigh_print(struct batadv_priv *bat_priv,
 +				  struct seq_file *seq)
 +{
 +	struct net_device *net_dev = (struct net_device *)seq->private;
 +	struct batadv_hardif_neigh_node *hardif_neigh;
 +	struct batadv_hard_iface *hard_iface;
 +	int batman_count = 0;
 +
 +	seq_printf(seq, "   %10s        %-13s %s\n",
 +		   "IF", "Neighbor", "last-seen");
 +
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
 +		if (hard_iface->soft_iface != net_dev)
 +			continue;
 +
 +		hlist_for_each_entry_rcu(hardif_neigh,
 +					 &hard_iface->neigh_list, list) {
 +			batadv_iv_hardif_neigh_print(seq, hardif_neigh);
 +			batman_count++;
 +		}
 +	}
 +	rcu_read_unlock();
 +
 +	if (batman_count == 0)
 +		seq_puts(seq, "No batman nodes in range ...\n");
 +}
 +
 +/**
   * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
   * @neigh1: the first neighbor object of the comparison
   * @if_outgoing1: outgoing interface for the first neighbor
@@@ -1961,8 -1904,8 +1963,8 @@@ out
  }
  
  /**
 - * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
 - *  neigh2 from the metric prospective
 + * batadv_iv_ogm_neigh_is_sob - check if neigh1 is similarly good or better
 + *  than neigh2 from the metric prospective
   * @neigh1: the first neighbor object of the comparison
   * @if_outgoing1: outgoing interface for the first neighbor
   * @neigh2: the second neighbor object of the comparison
@@@ -1972,7 -1915,7 +1974,7 @@@
   * the metric via neigh2, false otherwise.
   */
  static bool
 -batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
 +batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
  			   struct batadv_hard_iface *if_outgoing1,
  			   struct batadv_neigh_node *neigh2,
  			   struct batadv_hard_iface *if_outgoing2)
@@@ -2012,8 -1955,7 +2014,8 @@@ static struct batadv_algo_ops batadv_ba
  	.bat_ogm_schedule = batadv_iv_ogm_schedule,
  	.bat_ogm_emit = batadv_iv_ogm_emit,
  	.bat_neigh_cmp = batadv_iv_ogm_neigh_cmp,
 -	.bat_neigh_is_equiv_or_better = batadv_iv_ogm_neigh_is_eob,
 +	.bat_neigh_is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
 +	.bat_neigh_print = batadv_iv_neigh_print,
  	.bat_orig_print = batadv_iv_ogm_orig_print,
  	.bat_orig_free = batadv_iv_ogm_orig_free,
  	.bat_orig_add_if = batadv_iv_ogm_orig_add_if,
diff --combined net/core/pktgen.c
index 2be1444,4da4d51..1474cfd
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@@ -2787,7 -2787,9 +2787,9 @@@ static struct sk_buff *pktgen_alloc_skb
  	} else {
  		 skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
  	}
- 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
+ 
+ 	if (likely(skb))
+ 		skb_reserve(skb, LL_RESERVED_SPACE(dev));
  
  	return skb;
  }
@@@ -2898,7 -2900,7 +2900,7 @@@ static struct sk_buff *fill_packet_ipv4
  
  	if (!(pkt_dev->flags & F_UDPCSUM)) {
  		skb->ip_summed = CHECKSUM_NONE;
 -	} else if (odev->features & NETIF_F_V4_CSUM) {
 +	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)) {
  		skb->ip_summed = CHECKSUM_PARTIAL;
  		skb->csum = 0;
  		udp4_hwcsum(skb, iph->saddr, iph->daddr);
@@@ -3032,7 -3034,7 +3034,7 @@@ static struct sk_buff *fill_packet_ipv6
  
  	if (!(pkt_dev->flags & F_UDPCSUM)) {
  		skb->ip_summed = CHECKSUM_NONE;
 -	} else if (odev->features & NETIF_F_V6_CSUM) {
 +	} else if (odev->features & (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM)) {
  		skb->ip_summed = CHECKSUM_PARTIAL;
  		skb->csum_start = skb_transport_header(skb) - skb->head;
  		skb->csum_offset = offsetof(struct udphdr, check);
diff --combined net/ipv4/ip_output.c
index 568e2bc,36ac9f3..512a447
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@@ -76,6 -76,7 +76,6 @@@
  #include <linux/igmp.h>
  #include <linux/netfilter_ipv4.h>
  #include <linux/netfilter_bridge.h>
 -#include <linux/mroute.h>
  #include <linux/netlink.h>
  #include <linux/tcp.h>
  
@@@ -911,7 -912,7 +911,7 @@@ static int __ip_append_data(struct soc
  	 */
  	if (transhdrlen &&
  	    length + fragheaderlen <= mtu &&
 -	    rt->dst.dev->features & NETIF_F_V4_CSUM &&
 +	    rt->dst.dev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM) &&
  	    !(flags & MSG_MORE) &&
  	    !exthdrlen)
  		csummode = CHECKSUM_PARTIAL;
@@@ -920,7 -921,7 +920,7 @@@
  	if (((length > mtu) || (skb && skb_is_gso(skb))) &&
  	    (sk->sk_protocol == IPPROTO_UDP) &&
  	    (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len &&
- 	    (sk->sk_type == SOCK_DGRAM)) {
+ 	    (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) {
  		err = ip_ufo_append_data(sk, queue, getfrag, from, length,
  					 hh_len, fragheaderlen, transhdrlen,
  					 maxfraglen, flags);
diff --combined net/ipv4/udp_offload.c
index 1300426,5d396b9..4c519c1
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@@ -21,6 -21,7 +21,7 @@@ static struct udp_offload_priv __rcu *u
  
  struct udp_offload_priv {
  	struct udp_offload	*offload;
+ 	possible_net_t	net;
  	struct rcu_head		rcu;
  	struct udp_offload_priv __rcu *next;
  };
@@@ -60,9 -61,8 +61,9 @@@ static struct sk_buff *__skb_udp_tunnel
  
  	/* Try to offload checksum if possible */
  	offload_csum = !!(need_csum &&
 -			  (skb->dev->features &
 -			   (is_ipv6 ? NETIF_F_V6_CSUM : NETIF_F_V4_CSUM)));
 +			  ((skb->dev->features & NETIF_F_HW_CSUM) ||
 +			   (skb->dev->features & (is_ipv6 ?
 +			    NETIF_F_IPV6_CSUM : NETIF_F_IP_CSUM))));
  
  	/* segment inner packet. */
  	enc_features = skb->dev->hw_enc_features & features;
@@@ -242,13 -242,14 +243,14 @@@ out
  	return segs;
  }
  
- int udp_add_offload(struct udp_offload *uo)
+ int udp_add_offload(struct net *net, struct udp_offload *uo)
  {
  	struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
  
  	if (!new_offload)
  		return -ENOMEM;
  
+ 	write_pnet(&new_offload->net, net);
  	new_offload->offload = uo;
  
  	spin_lock(&udp_offload_lock);
@@@ -312,7 -313,8 +314,8 @@@ struct sk_buff **udp_gro_receive(struc
  	rcu_read_lock();
  	uo_priv = rcu_dereference(udp_offload_base);
  	for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
- 		if (uo_priv->offload->port == uh->dest &&
+ 		if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
+ 		    uo_priv->offload->port == uh->dest &&
  		    uo_priv->offload->callbacks.gro_receive)
  			goto unflush;
  	}
@@@ -390,7 -392,8 +393,8 @@@ int udp_gro_complete(struct sk_buff *sk
  
  	uo_priv = rcu_dereference(udp_offload_base);
  	for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
- 		if (uo_priv->offload->port == uh->dest &&
+ 		if (net_eq(read_pnet(&uo_priv->net), dev_net(skb->dev)) &&
+ 		    uo_priv->offload->port == uh->dest &&
  		    uo_priv->offload->callbacks.gro_complete)
  			break;
  	}
diff --combined net/ipv6/ip6_output.c
index 2f74845,6473889..23de98f
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@@ -1322,7 -1322,7 +1322,7 @@@ emsgsize
  	    headersize == sizeof(struct ipv6hdr) &&
  	    length < mtu - headersize &&
  	    !(flags & MSG_MORE) &&
 -	    rt->dst.dev->features & NETIF_F_V6_CSUM)
 +	    rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
  		csummode = CHECKSUM_PARTIAL;
  
  	if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
@@@ -1353,7 -1353,7 +1353,7 @@@
  	     (skb && skb_is_gso(skb))) &&
  	    (sk->sk_protocol == IPPROTO_UDP) &&
  	    (rt->dst.dev->features & NETIF_F_UFO) &&
- 	    (sk->sk_type == SOCK_DGRAM)) {
+ 	    (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) {
  		err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
  					  hh_len, fragheaderlen,
  					  transhdrlen, mtu, flags, fl6);
diff --combined net/ipv6/tcp_ipv6.c
index 9ecb012,bd100b4..db9f1c3
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@@ -462,8 -462,10 +462,10 @@@ static int tcp_v6_send_synack(const str
  		if (np->repflow && ireq->pktopts)
  			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
  
+ 		rcu_read_lock();
  		err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
  			       np->tclass);
+ 		rcu_read_unlock();
  		err = net_xmit_eval(err);
  	}
  
@@@ -854,9 -856,7 +856,9 @@@ static void tcp_v6_send_reset(const str
  
  #ifdef CONFIG_TCP_MD5SIG
  	hash_location = tcp_parse_md5sig_option(th);
 -	if (!sk && hash_location) {
 +	if (sk && sk_fullsock(sk)) {
 +		key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr);
 +	} else if (hash_location) {
  		/*
  		 * active side is lost. Try to find listening socket through
  		 * source port, and then find md5 key through listening socket.
@@@ -879,6 -879,8 +881,6 @@@
  		genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb);
  		if (genhash || memcmp(hash_location, newhash, 16) != 0)
  			goto release_sk1;
 -	} else {
 -		key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL;
  	}
  #endif
  
@@@ -1135,7 -1137,7 +1137,7 @@@ static struct sock *tcp_v6_syn_recv_soc
  		 */
  		tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr,
  			       AF_INET6, key->key, key->keylen,
 -			       sk_gfp_atomic(sk, GFP_ATOMIC));
 +			       sk_gfp_mask(sk, GFP_ATOMIC));
  	}
  #endif
  
@@@ -1151,7 -1153,7 +1153,7 @@@
  		/* Clone pktoptions received with SYN, if we own the req */
  		if (ireq->pktopts) {
  			newnp->pktoptions = skb_clone(ireq->pktopts,
 -						      sk_gfp_atomic(sk, GFP_ATOMIC));
 +						      sk_gfp_mask(sk, GFP_ATOMIC));
  			consume_skb(ireq->pktopts);
  			ireq->pktopts = NULL;
  			if (newnp->pktoptions)
@@@ -1217,7 -1219,7 +1219,7 @@@ static int tcp_v6_do_rcv(struct sock *s
  					       --ANK (980728)
  	 */
  	if (np->rxopt.all)
 -		opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
 +		opt_skb = skb_clone(skb, sk_gfp_mask(sk, GFP_ATOMIC));
  
  	if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
  		struct dst_entry *dst = sk->sk_rx_dst;
@@@ -1516,9 -1518,7 +1518,9 @@@ do_time_wait
  		break;
  	case TCP_TW_RST:
  		tcp_v6_restore_cb(skb);
 -		goto no_tcp_socket;
 +		tcp_v6_send_reset(sk, skb);
 +		inet_twsk_deschedule_put(inet_twsk(sk));
 +		goto discard_it;
  	case TCP_TW_SUCCESS:
  		;
  	}
@@@ -1891,7 -1891,6 +1893,7 @@@ struct proto tcpv6_prot = 
  	.proto_cgroup		= tcp_proto_cgroup,
  #endif
  	.clear_sk		= tcp_v6_clear_sk,
 +	.diag_destroy		= tcp_abort,
  };
  
  static const struct inet6_protocol tcpv6_protocol = {
diff --combined net/sctp/sm_sideeffect.c
index 4f170ad,be23d5c..2e21384
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@@ -63,7 -63,7 +63,7 @@@ static int sctp_cmd_interpreter(sctp_ev
  static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
  			     sctp_state_t state,
  			     struct sctp_endpoint *ep,
- 			     struct sctp_association *asoc,
+ 			     struct sctp_association **asoc,
  			     void *event_arg,
  			     sctp_disposition_t status,
  			     sctp_cmd_seq_t *commands,
@@@ -477,8 -477,6 +477,8 @@@ static void sctp_do_8_2_transport_strik
  					 struct sctp_transport *transport,
  					 int is_hb)
  {
 +	struct net *net = sock_net(asoc->base.sk);
 +
  	/* The check for association's overall error counter exceeding the
  	 * threshold is done in the state function.
  	 */
@@@ -505,8 -503,7 +505,8 @@@
  	 * is SCTP_ACTIVE, then mark this transport as Partially Failed,
  	 * see SCTP Quick Failover Draft, section 5.1
  	 */
 -	if ((transport->state == SCTP_ACTIVE) &&
 +	if (net->sctp.pf_enable &&
 +	   (transport->state == SCTP_ACTIVE) &&
  	   (asoc->pf_retrans < transport->pathmaxrxt) &&
  	   (transport->error_count > asoc->pf_retrans)) {
  
@@@ -866,6 -863,7 +866,6 @@@ static void sctp_cmd_delete_tcb(sctp_cm
  	    (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))
  		return;
  
 -	sctp_unhash_established(asoc);
  	sctp_association_free(asoc);
  }
  
@@@ -1125,7 -1123,7 +1125,7 @@@ int sctp_do_sm(struct net *net, sctp_ev
  	debug_post_sfn();
  
  	error = sctp_side_effects(event_type, subtype, state,
- 				  ep, asoc, event_arg, status,
+ 				  ep, &asoc, event_arg, status,
  				  &commands, gfp);
  	debug_post_sfx();
  
@@@ -1138,7 -1136,7 +1138,7 @@@
  static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
  			     sctp_state_t state,
  			     struct sctp_endpoint *ep,
- 			     struct sctp_association *asoc,
+ 			     struct sctp_association **asoc,
  			     void *event_arg,
  			     sctp_disposition_t status,
  			     sctp_cmd_seq_t *commands,
@@@ -1153,7 -1151,7 +1153,7 @@@
  	 * disposition SCTP_DISPOSITION_CONSUME.
  	 */
  	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
- 					       ep, asoc,
+ 					       ep, *asoc,
  					       event_arg, status,
  					       commands, gfp)))
  		goto bail;
@@@ -1176,11 -1174,12 +1176,12 @@@
  		break;
  
  	case SCTP_DISPOSITION_DELETE_TCB:
+ 	case SCTP_DISPOSITION_ABORT:
  		/* This should now be a command. */
+ 		*asoc = NULL;
  		break;
  
  	case SCTP_DISPOSITION_CONSUME:
- 	case SCTP_DISPOSITION_ABORT:
  		/*
  		 * We should no longer have much work to do here as the
  		 * real work has been done as explicit commands above.
@@@ -1268,6 -1267,7 +1269,6 @@@ static int sctp_cmd_interpreter(sctp_ev
  			asoc = cmd->obj.asoc;
  			BUG_ON(asoc->peer.primary_path == NULL);
  			sctp_endpoint_add_asoc(ep, asoc);
 -			sctp_hash_established(asoc);
  			break;
  
  		case SCTP_CMD_UPDATE_ASSOC:
diff --combined net/sctp/sysctl.c
index ccbfc93,3e0fc51..daf8554
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@@ -308,13 -308,6 +308,13 @@@ static struct ctl_table sctp_net_table[
  		.extra1		= &max_autoclose_min,
  		.extra2		= &max_autoclose_max,
  	},
 +	{
 +		.procname	= "pf_enable",
 +		.data		= &init_net.sctp.pf_enable,
 +		.maxlen		= sizeof(int),
 +		.mode		= 0644,
 +		.proc_handler	= proc_dointvec,
 +	},
  
  	{ /* sentinel */ }
  };
@@@ -327,7 -320,7 +327,7 @@@ static int proc_sctp_do_hmac_alg(struc
  	struct ctl_table tbl;
  	bool changed = false;
  	char *none = "none";
- 	char tmp[8];
+ 	char tmp[8] = {0};
  	int ret;
  
  	memset(&tbl, 0, sizeof(struct ctl_table));
diff --combined net/unix/af_unix.c
index e6d3556,e3f85bc..c5bf5ef
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@@ -451,7 -451,7 +451,7 @@@ static void unix_write_space(struct soc
  	rcu_read_lock();
  	if (unix_writable(sk)) {
  		wq = rcu_dereference(sk->sk_wq);
 -		if (wq_has_sleeper(wq))
 +		if (skwq_has_sleeper(wq))
  			wake_up_interruptible_sync_poll(&wq->wait,
  				POLLOUT | POLLWRNORM | POLLWRBAND);
  		sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
@@@ -1513,6 -1513,21 +1513,21 @@@ static void unix_destruct_scm(struct sk
  	sock_wfree(skb);
  }
  
+ /*
+  * The "user->unix_inflight" variable is protected by the garbage
+  * collection lock, and we just read it locklessly here. If you go
+  * over the limit, there might be a tiny race in actually noticing
+  * it across threads. Tough.
+  */
+ static inline bool too_many_unix_fds(struct task_struct *p)
+ {
+ 	struct user_struct *user = current_user();
+ 
+ 	if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
+ 		return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
+ 	return false;
+ }
+ 
  #define MAX_RECURSION_LEVEL 4
  
  static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
@@@ -1521,6 -1536,9 +1536,9 @@@
  	unsigned char max_level = 0;
  	int unix_sock_count = 0;
  
+ 	if (too_many_unix_fds(current))
+ 		return -ETOOMANYREFS;
+ 
  	for (i = scm->fp->count - 1; i >= 0; i--) {
  		struct sock *sk = unix_get_socket(scm->fp->fp[i]);
  
@@@ -1542,10 -1560,8 +1560,8 @@@
  	if (!UNIXCB(skb).fp)
  		return -ENOMEM;
  
- 	if (unix_sock_count) {
- 		for (i = scm->fp->count - 1; i >= 0; i--)
- 			unix_inflight(scm->fp->fp[i]);
- 	}
+ 	for (i = scm->fp->count - 1; i >= 0; i--)
+ 		unix_inflight(scm->fp->fp[i]);
  	return max_level;
  }
  
@@@ -2092,8 -2108,8 +2108,8 @@@ static int unix_dgram_recvmsg(struct so
  	struct scm_cookie scm;
  	struct sock *sk = sock->sk;
  	struct unix_sock *u = unix_sk(sk);
 -	int noblock = flags & MSG_DONTWAIT;
 -	struct sk_buff *skb;
 +	struct sk_buff *skb, *last;
 +	long timeo;
  	int err;
  	int peeked, skip;
  
@@@ -2101,38 -2117,30 +2117,38 @@@
  	if (flags&MSG_OOB)
  		goto out;
  
 -	err = mutex_lock_interruptible(&u->readlock);
 -	if (unlikely(err)) {
 -		/* recvmsg() in non blocking mode is supposed to return -EAGAIN
 -		 * sk_rcvtimeo is not honored by mutex_lock_interruptible()
 -		 */
 -		err = noblock ? -EAGAIN : -ERESTARTSYS;
 -		goto out;
 -	}
 +	timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
  
 -	skip = sk_peek_offset(sk, flags);
 +	do {
 +		mutex_lock(&u->readlock);
  
 -	skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
 -	if (!skb) {
 +		skip = sk_peek_offset(sk, flags);
 +		skb = __skb_try_recv_datagram(sk, flags, &peeked, &skip, &err,
 +					      &last);
 +		if (skb)
 +			break;
 +
 +		mutex_unlock(&u->readlock);
 +
 +		if (err != -EAGAIN)
 +			break;
 +	} while (timeo &&
 +		 !__skb_wait_for_more_packets(sk, &err, &timeo, last));
 +
 +	if (!skb) { /* implies readlock unlocked */
  		unix_state_lock(sk);
  		/* Signal EOF on disconnected non-blocking SEQPACKET socket. */
  		if (sk->sk_type == SOCK_SEQPACKET && err == -EAGAIN &&
  		    (sk->sk_shutdown & RCV_SHUTDOWN))
  			err = 0;
  		unix_state_unlock(sk);
 -		goto out_unlock;
 +		goto out;
  	}
  
 -	wake_up_interruptible_sync_poll(&u->peer_wait,
 -					POLLOUT | POLLWRNORM | POLLWRBAND);
 +	if (wq_has_sleeper(&u->peer_wait))
 +		wake_up_interruptible_sync_poll(&u->peer_wait,
 +						POLLOUT | POLLWRNORM |
 +						POLLWRBAND);
  
  	if (msg->msg_name)
  		unix_copy_addr(msg, skb->sk);
@@@ -2184,6 -2192,7 +2200,6 @@@
  
  out_free:
  	skb_free_datagram(sk, skb);
 -out_unlock:
  	mutex_unlock(&u->readlock);
  out:
  	return err;

-- 
LinuxNextTracking


More information about the linux-merge mailing list