diff options
Diffstat (limited to 'net/dsa/slave.c')
| -rw-r--r-- | net/dsa/slave.c | 222 | 
1 files changed, 149 insertions, 73 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index fc9196745225..6b1282c006b1 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -28,7 +28,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)  	struct dsa_switch *ds = bus->priv;  	if (ds->phys_mii_mask & (1 << addr)) -		return ds->drv->phy_read(ds, addr, reg); +		return ds->ops->phy_read(ds, addr, reg);  	return 0xffff;  } @@ -38,7 +38,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)  	struct dsa_switch *ds = bus->priv;  	if (ds->phys_mii_mask & (1 << addr)) -		return ds->drv->phy_write(ds, addr, reg, val); +		return ds->ops->phy_write(ds, addr, reg, val);  	return 0;  } @@ -69,6 +69,30 @@ static inline bool dsa_port_is_bridged(struct dsa_slave_priv *p)  	return !!p->bridge_dev;  } +static void dsa_port_set_stp_state(struct dsa_switch *ds, int port, u8 state) +{ +	struct dsa_port *dp = &ds->ports[port]; + +	if (ds->ops->port_stp_state_set) +		ds->ops->port_stp_state_set(ds, port, state); + +	if (ds->ops->port_fast_age) { +		/* Fast age FDB entries or flush appropriate forwarding database +		 * for the given port, if we are moving it from Learning or +		 * Forwarding state, to Disabled or Blocking or Listening state. +		 */ + +		if ((dp->stp_state == BR_STATE_LEARNING || +		     dp->stp_state == BR_STATE_FORWARDING) && +		    (state == BR_STATE_DISABLED || +		     state == BR_STATE_BLOCKING || +		     state == BR_STATE_LISTENING)) +			ds->ops->port_fast_age(ds, port); +	} + +	dp->stp_state = state; +} +  static int dsa_slave_open(struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev); @@ -98,14 +122,13 @@ static int dsa_slave_open(struct net_device *dev)  			goto clear_allmulti;  	} -	if (ds->drv->port_enable) { -		err = ds->drv->port_enable(ds, p->port, p->phy); +	if (ds->ops->port_enable) { +		err = ds->ops->port_enable(ds, p->port, p->phy);  		if (err)  			goto clear_promisc;  	} -	if (ds->drv->port_stp_state_set) -		ds->drv->port_stp_state_set(ds, p->port, stp_state); +	dsa_port_set_stp_state(ds, p->port, stp_state);  	if (p->phy)  		phy_start(p->phy); @@ -144,11 +167,10 @@ static int dsa_slave_close(struct net_device *dev)  	if (!ether_addr_equal(dev->dev_addr, master->dev_addr))  		dev_uc_del(master, dev->dev_addr); -	if (ds->drv->port_disable) -		ds->drv->port_disable(ds, p->port, p->phy); +	if (ds->ops->port_disable) +		ds->ops->port_disable(ds, p->port, p->phy); -	if (ds->drv->port_stp_state_set) -		ds->drv->port_stp_state_set(ds, p->port, BR_STATE_DISABLED); +	dsa_port_set_stp_state(ds, p->port, BR_STATE_DISABLED);  	return 0;  } @@ -209,13 +231,13 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,  	struct dsa_switch *ds = p->parent;  	if (switchdev_trans_ph_prepare(trans)) { -		if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add) +		if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)  			return -EOPNOTSUPP; -		return ds->drv->port_vlan_prepare(ds, p->port, vlan, trans); +		return ds->ops->port_vlan_prepare(ds, p->port, vlan, trans);  	} -	ds->drv->port_vlan_add(ds, p->port, vlan, trans); +	ds->ops->port_vlan_add(ds, p->port, vlan, trans);  	return 0;  } @@ -226,10 +248,10 @@ static int dsa_slave_port_vlan_del(struct net_device *dev,  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (!ds->drv->port_vlan_del) +	if (!ds->ops->port_vlan_del)  		return -EOPNOTSUPP; -	return ds->drv->port_vlan_del(ds, p->port, vlan); +	return ds->ops->port_vlan_del(ds, p->port, vlan);  }  static int dsa_slave_port_vlan_dump(struct net_device *dev, @@ -239,8 +261,8 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->port_vlan_dump) -		return ds->drv->port_vlan_dump(ds, p->port, vlan, cb); +	if (ds->ops->port_vlan_dump) +		return ds->ops->port_vlan_dump(ds, p->port, vlan, cb);  	return -EOPNOTSUPP;  } @@ -253,13 +275,13 @@ static int dsa_slave_port_fdb_add(struct net_device *dev,  	struct dsa_switch *ds = p->parent;  	if (switchdev_trans_ph_prepare(trans)) { -		if (!ds->drv->port_fdb_prepare || !ds->drv->port_fdb_add) +		if (!ds->ops->port_fdb_prepare || !ds->ops->port_fdb_add)  			return -EOPNOTSUPP; -		return ds->drv->port_fdb_prepare(ds, p->port, fdb, trans); +		return ds->ops->port_fdb_prepare(ds, p->port, fdb, trans);  	} -	ds->drv->port_fdb_add(ds, p->port, fdb, trans); +	ds->ops->port_fdb_add(ds, p->port, fdb, trans);  	return 0;  } @@ -271,8 +293,8 @@ static int dsa_slave_port_fdb_del(struct net_device *dev,  	struct dsa_switch *ds = p->parent;  	int ret = -EOPNOTSUPP; -	if (ds->drv->port_fdb_del) -		ret = ds->drv->port_fdb_del(ds, p->port, fdb); +	if (ds->ops->port_fdb_del) +		ret = ds->ops->port_fdb_del(ds, p->port, fdb);  	return ret;  } @@ -284,8 +306,52 @@ static int dsa_slave_port_fdb_dump(struct net_device *dev,  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->port_fdb_dump) -		return ds->drv->port_fdb_dump(ds, p->port, fdb, cb); +	if (ds->ops->port_fdb_dump) +		return ds->ops->port_fdb_dump(ds, p->port, fdb, cb); + +	return -EOPNOTSUPP; +} + +static int dsa_slave_port_mdb_add(struct net_device *dev, +				  const struct switchdev_obj_port_mdb *mdb, +				  struct switchdev_trans *trans) +{ +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; + +	if (switchdev_trans_ph_prepare(trans)) { +		if (!ds->ops->port_mdb_prepare || !ds->ops->port_mdb_add) +			return -EOPNOTSUPP; + +		return ds->ops->port_mdb_prepare(ds, p->port, mdb, trans); +	} + +	ds->ops->port_mdb_add(ds, p->port, mdb, trans); + +	return 0; +} + +static int dsa_slave_port_mdb_del(struct net_device *dev, +				  const struct switchdev_obj_port_mdb *mdb) +{ +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; + +	if (ds->ops->port_mdb_del) +		return ds->ops->port_mdb_del(ds, p->port, mdb); + +	return -EOPNOTSUPP; +} + +static int dsa_slave_port_mdb_dump(struct net_device *dev, +				   struct switchdev_obj_port_mdb *mdb, +				   switchdev_obj_dump_cb_t *cb) +{ +	struct dsa_slave_priv *p = netdev_priv(dev); +	struct dsa_switch *ds = p->parent; + +	if (ds->ops->port_mdb_dump) +		return ds->ops->port_mdb_dump(ds, p->port, mdb, cb);  	return -EOPNOTSUPP;  } @@ -308,9 +374,9 @@ static int dsa_slave_stp_state_set(struct net_device *dev,  	struct dsa_switch *ds = p->parent;  	if (switchdev_trans_ph_prepare(trans)) -		return ds->drv->port_stp_state_set ? 0 : -EOPNOTSUPP; +		return ds->ops->port_stp_state_set ? 0 : -EOPNOTSUPP; -	ds->drv->port_stp_state_set(ds, p->port, attr->u.stp_state); +	dsa_port_set_stp_state(ds, p->port, attr->u.stp_state);  	return 0;  } @@ -326,8 +392,8 @@ static int dsa_slave_vlan_filtering(struct net_device *dev,  	if (switchdev_trans_ph_prepare(trans))  		return 0; -	if (ds->drv->port_vlan_filtering) -		return ds->drv->port_vlan_filtering(ds, p->port, +	if (ds->ops->port_vlan_filtering) +		return ds->ops->port_vlan_filtering(ds, p->port,  						    attr->u.vlan_filtering);  	return 0; @@ -365,8 +431,8 @@ static int dsa_slave_ageing_time(struct net_device *dev,  	ds->ports[p->port].ageing_time = ageing_time;  	ageing_time = dsa_fastest_ageing_time(ds, ageing_time); -	if (ds->drv->set_ageing_time) -		return ds->drv->set_ageing_time(ds, ageing_time); +	if (ds->ops->set_ageing_time) +		return ds->ops->set_ageing_time(ds, ageing_time);  	return 0;  } @@ -412,6 +478,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev,  					     SWITCHDEV_OBJ_PORT_FDB(obj),  					     trans);  		break; +	case SWITCHDEV_OBJ_ID_PORT_MDB: +		err = dsa_slave_port_mdb_add(dev, SWITCHDEV_OBJ_PORT_MDB(obj), +					     trans); +		break;  	case SWITCHDEV_OBJ_ID_PORT_VLAN:  		err = dsa_slave_port_vlan_add(dev,  					      SWITCHDEV_OBJ_PORT_VLAN(obj), @@ -435,6 +505,9 @@ static int dsa_slave_port_obj_del(struct net_device *dev,  		err = dsa_slave_port_fdb_del(dev,  					     SWITCHDEV_OBJ_PORT_FDB(obj));  		break; +	case SWITCHDEV_OBJ_ID_PORT_MDB: +		err = dsa_slave_port_mdb_del(dev, SWITCHDEV_OBJ_PORT_MDB(obj)); +		break;  	case SWITCHDEV_OBJ_ID_PORT_VLAN:  		err = dsa_slave_port_vlan_del(dev,  					      SWITCHDEV_OBJ_PORT_VLAN(obj)); @@ -459,6 +532,10 @@ static int dsa_slave_port_obj_dump(struct net_device *dev,  					      SWITCHDEV_OBJ_PORT_FDB(obj),  					      cb);  		break; +	case SWITCHDEV_OBJ_ID_PORT_MDB: +		err = dsa_slave_port_mdb_dump(dev, SWITCHDEV_OBJ_PORT_MDB(obj), +					      cb); +		break;  	case SWITCHDEV_OBJ_ID_PORT_VLAN:  		err = dsa_slave_port_vlan_dump(dev,  					       SWITCHDEV_OBJ_PORT_VLAN(obj), @@ -481,8 +558,8 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,  	p->bridge_dev = br; -	if (ds->drv->port_bridge_join) -		ret = ds->drv->port_bridge_join(ds, p->port, br); +	if (ds->ops->port_bridge_join) +		ret = ds->ops->port_bridge_join(ds, p->port, br);  	return ret == -EOPNOTSUPP ? 0 : ret;  } @@ -493,16 +570,15 @@ static void dsa_slave_bridge_port_leave(struct net_device *dev)  	struct dsa_switch *ds = p->parent; -	if (ds->drv->port_bridge_leave) -		ds->drv->port_bridge_leave(ds, p->port); +	if (ds->ops->port_bridge_leave) +		ds->ops->port_bridge_leave(ds, p->port);  	p->bridge_dev = NULL;  	/* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer,  	 * so allow it to be in BR_STATE_FORWARDING to be kept functional  	 */ -	if (ds->drv->port_stp_state_set) -		ds->drv->port_stp_state_set(ds, p->port, BR_STATE_FORWARDING); +	dsa_port_set_stp_state(ds, p->port, BR_STATE_FORWARDING);  }  static int dsa_slave_port_attr_get(struct net_device *dev, @@ -605,8 +681,8 @@ static int dsa_slave_get_regs_len(struct net_device *dev)  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->get_regs_len) -		return ds->drv->get_regs_len(ds, p->port); +	if (ds->ops->get_regs_len) +		return ds->ops->get_regs_len(ds, p->port);  	return -EOPNOTSUPP;  } @@ -617,8 +693,8 @@ dsa_slave_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->get_regs) -		ds->drv->get_regs(ds, p->port, regs, _p); +	if (ds->ops->get_regs) +		ds->ops->get_regs(ds, p->port, regs, _p);  }  static int dsa_slave_nway_reset(struct net_device *dev) @@ -651,8 +727,8 @@ static int dsa_slave_get_eeprom_len(struct net_device *dev)  	if (ds->cd && ds->cd->eeprom_len)  		return ds->cd->eeprom_len; -	if (ds->drv->get_eeprom_len) -		return ds->drv->get_eeprom_len(ds); +	if (ds->ops->get_eeprom_len) +		return ds->ops->get_eeprom_len(ds);  	return 0;  } @@ -663,8 +739,8 @@ static int dsa_slave_get_eeprom(struct net_device *dev,  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->get_eeprom) -		return ds->drv->get_eeprom(ds, eeprom, data); +	if (ds->ops->get_eeprom) +		return ds->ops->get_eeprom(ds, eeprom, data);  	return -EOPNOTSUPP;  } @@ -675,8 +751,8 @@ static int dsa_slave_set_eeprom(struct net_device *dev,  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->set_eeprom) -		return ds->drv->set_eeprom(ds, eeprom, data); +	if (ds->ops->set_eeprom) +		return ds->ops->set_eeprom(ds, eeprom, data);  	return -EOPNOTSUPP;  } @@ -694,8 +770,8 @@ static void dsa_slave_get_strings(struct net_device *dev,  		strncpy(data + len, "tx_bytes", len);  		strncpy(data + 2 * len, "rx_packets", len);  		strncpy(data + 3 * len, "rx_bytes", len); -		if (ds->drv->get_strings != NULL) -			ds->drv->get_strings(ds, p->port, data + 4 * len); +		if (ds->ops->get_strings) +			ds->ops->get_strings(ds, p->port, data + 4 * len);  	}  } @@ -714,8 +790,8 @@ static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev,  		dst->master_ethtool_ops.get_ethtool_stats(dev, stats, data);  	} -	if (ds->drv->get_ethtool_stats) -		ds->drv->get_ethtool_stats(ds, cpu_port, data + count); +	if (ds->ops->get_ethtool_stats) +		ds->ops->get_ethtool_stats(ds, cpu_port, data + count);  }  static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset) @@ -727,8 +803,8 @@ static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset)  	if (dst->master_ethtool_ops.get_sset_count)  		count += dst->master_ethtool_ops.get_sset_count(dev, sset); -	if (sset == ETH_SS_STATS && ds->drv->get_sset_count) -		count += ds->drv->get_sset_count(ds); +	if (sset == ETH_SS_STATS && ds->ops->get_sset_count) +		count += ds->ops->get_sset_count(ds);  	return count;  } @@ -755,14 +831,14 @@ static void dsa_cpu_port_get_strings(struct net_device *dev,  		dst->master_ethtool_ops.get_strings(dev, stringset, data);  	} -	if (stringset == ETH_SS_STATS && ds->drv->get_strings) { +	if (stringset == ETH_SS_STATS && ds->ops->get_strings) {  		ndata = data + mcount * len;  		/* This function copies ETH_GSTRINGS_LEN bytes, we will mangle  		 * the output after to prepend our CPU port prefix we  		 * constructed earlier  		 */ -		ds->drv->get_strings(ds, cpu_port, ndata); -		count = ds->drv->get_sset_count(ds); +		ds->ops->get_strings(ds, cpu_port, ndata); +		count = ds->ops->get_sset_count(ds);  		for (i = 0; i < count; i++) {  			memmove(ndata + (i * len + sizeof(pfx)),  				ndata + i * len, len - sizeof(pfx)); @@ -782,8 +858,8 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,  	data[1] = dev->stats.tx_bytes;  	data[2] = dev->stats.rx_packets;  	data[3] = dev->stats.rx_bytes; -	if (ds->drv->get_ethtool_stats != NULL) -		ds->drv->get_ethtool_stats(ds, p->port, data + 4); +	if (ds->ops->get_ethtool_stats) +		ds->ops->get_ethtool_stats(ds, p->port, data + 4);  }  static int dsa_slave_get_sset_count(struct net_device *dev, int sset) @@ -795,8 +871,8 @@ static int dsa_slave_get_sset_count(struct net_device *dev, int sset)  		int count;  		count = 4; -		if (ds->drv->get_sset_count != NULL) -			count += ds->drv->get_sset_count(ds); +		if (ds->ops->get_sset_count) +			count += ds->ops->get_sset_count(ds);  		return count;  	} @@ -809,8 +885,8 @@ static void dsa_slave_get_wol(struct net_device *dev, struct ethtool_wolinfo *w)  	struct dsa_slave_priv *p = netdev_priv(dev);  	struct dsa_switch *ds = p->parent; -	if (ds->drv->get_wol) -		ds->drv->get_wol(ds, p->port, w); +	if (ds->ops->get_wol) +		ds->ops->get_wol(ds, p->port, w);  }  static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) @@ -819,8 +895,8 @@ static int dsa_slave_set_wol(struct net_device *dev, struct ethtool_wolinfo *w)  	struct dsa_switch *ds = p->parent;  	int ret = -EOPNOTSUPP; -	if (ds->drv->set_wol) -		ret = ds->drv->set_wol(ds, p->port, w); +	if (ds->ops->set_wol) +		ret = ds->ops->set_wol(ds, p->port, w);  	return ret;  } @@ -831,10 +907,10 @@ static int dsa_slave_set_eee(struct net_device *dev, struct ethtool_eee *e)  	struct dsa_switch *ds = p->parent;  	int ret; -	if (!ds->drv->set_eee) +	if (!ds->ops->set_eee)  		return -EOPNOTSUPP; -	ret = ds->drv->set_eee(ds, p->port, p->phy, e); +	ret = ds->ops->set_eee(ds, p->port, p->phy, e);  	if (ret)  		return ret; @@ -850,10 +926,10 @@ static int dsa_slave_get_eee(struct net_device *dev, struct ethtool_eee *e)  	struct dsa_switch *ds = p->parent;  	int ret; -	if (!ds->drv->get_eee) +	if (!ds->ops->get_eee)  		return -EOPNOTSUPP; -	ret = ds->drv->get_eee(ds, p->port, e); +	ret = ds->ops->get_eee(ds, p->port, e);  	if (ret)  		return ret; @@ -988,8 +1064,8 @@ static void dsa_slave_adjust_link(struct net_device *dev)  		p->old_pause = p->phy->pause;  	} -	if (ds->drv->adjust_link && status_changed) -		ds->drv->adjust_link(ds, p->port, p->phy); +	if (ds->ops->adjust_link && status_changed) +		ds->ops->adjust_link(ds, p->port, p->phy);  	if (status_changed)  		phy_print_status(p->phy); @@ -1004,8 +1080,8 @@ static int dsa_slave_fixed_link_update(struct net_device *dev,  	if (dev) {  		p = netdev_priv(dev);  		ds = p->parent; -		if (ds->drv->fixed_link_update) -			ds->drv->fixed_link_update(ds, p->port, status); +		if (ds->ops->fixed_link_update) +			ds->ops->fixed_link_update(ds, p->port, status);  	}  	return 0; @@ -1062,8 +1138,8 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p,  		phy_dn = port_dn;  	} -	if (ds->drv->get_phy_flags) -		phy_flags = ds->drv->get_phy_flags(ds, p->port); +	if (ds->ops->get_phy_flags) +		phy_flags = ds->ops->get_phy_flags(ds, p->port);  	if (phy_dn) {  		int phy_id = of_mdio_parse_addr(&slave_dev->dev, phy_dn);  |