diff options
Diffstat (limited to 'target/linux')
| -rw-r--r-- | target/linux/generic/files/drivers/net/phy/ar8216.c | 310 | ||||
| -rw-r--r-- | target/linux/generic/files/drivers/net/phy/ar8216.h | 8 | 
2 files changed, 318 insertions, 0 deletions
| diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index a07dd7848..b6df6425a 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -120,6 +120,12 @@ struct ar8xxx_priv {  	u8 vlan_table[AR8X16_MAX_VLANS];  	u8 vlan_tagged;  	u16 pvid[AR8X16_MAX_PORTS]; + +	/* mirroring */ +	bool mirror_rx; +	bool mirror_tx; +	int source_port; +	int monitor_port;  };  #define MIB_DESC(_s , _o, _n)	\ @@ -1457,6 +1463,98 @@ ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)  	return 0;  } +static void +ar8327_set_mirror_regs(struct ar8xxx_priv *priv) +{ +	int port; +  +	/* reset all mirror registers */ +	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, +		   AR8327_FWD_CTRL0_MIRROR_PORT, +		   (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); +	for (port = 0; port < AR8327_NUM_PORTS; port++) { +		ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(port), +			   AR8327_PORT_LOOKUP_ING_MIRROR_EN, +			   0); + +		ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(port), +			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, +			   0); +	} + +	/* now enable mirroring if necessary */ +	if (priv->source_port >= AR8327_NUM_PORTS || +	    priv->monitor_port >= AR8327_NUM_PORTS || +	    priv->source_port == priv->monitor_port) { +		return; +	} + +	ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, +		   AR8327_FWD_CTRL0_MIRROR_PORT, +		   (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); + +	if (priv->mirror_rx) +		ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), +			   AR8327_PORT_LOOKUP_ING_MIRROR_EN, +			   AR8327_PORT_LOOKUP_ING_MIRROR_EN); + +	if (priv->mirror_tx) +		ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), +			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN, +			   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); +} + +static void +ar8216_set_mirror_regs(struct ar8xxx_priv *priv) +{ +	int port; + +	/* reset all mirror registers */ +	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, +		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT, +		   (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); +	for (port = 0; port < AR8216_NUM_PORTS; port++) { +		ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), +			   AR8216_PORT_CTRL_MIRROR_RX, +			   0); + +		ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), +			   AR8216_PORT_CTRL_MIRROR_TX, +			   0); +	} + +	/* now enable mirroring if necessary */ +	if (priv->source_port >= AR8216_NUM_PORTS || +	    priv->monitor_port >= AR8216_NUM_PORTS || +	    priv->source_port == priv->monitor_port) { +		return; +	} + +	ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, +		   AR8216_GLOBAL_CPUPORT_MIRROR_PORT, +		   (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); + +	if (priv->mirror_rx) +		ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port), +			   AR8216_PORT_CTRL_MIRROR_RX, +			   AR8216_PORT_CTRL_MIRROR_RX); + +	if (priv->mirror_tx) +		ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port), +			   AR8216_PORT_CTRL_MIRROR_TX, +			   AR8216_PORT_CTRL_MIRROR_TX); +} + +static void +ar8xxx_set_mirror_regs(struct ar8xxx_priv *priv) +{ +	if (chip_is_ar8327(priv)) { +		ar8327_set_mirror_regs(priv); +	} else { +		ar8216_set_mirror_regs(priv); +	} +} +  static int  ar8xxx_sw_hw_apply(struct switch_dev *dev)  { @@ -1520,6 +1618,9 @@ ar8xxx_sw_hw_apply(struct switch_dev *dev)  		priv->chip->setup_port(priv, i, egress, ingress, portmask[i],  				       pvid);  	} +	 +	ar8xxx_set_mirror_regs(priv); +	  	mutex_unlock(&priv->reg_mutex);  	return 0;  } @@ -1541,7 +1642,13 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)  	for (i = 0; i < dev->ports; i++)  		priv->chip->init_port(priv, i); +	priv->mirror_rx = false; +	priv->mirror_tx = false; +	priv->source_port = 0; +	priv->monitor_port = 0; +	  	priv->chip->init_globals(priv); +  	mutex_unlock(&priv->reg_mutex);  	return ar8xxx_sw_hw_apply(dev); @@ -1576,6 +1683,106 @@ unlock:  }  static int +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, +			       const struct switch_attr *attr, +			       struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	 +	mutex_lock(&priv->reg_mutex); +	priv->mirror_rx = !!val->value.i; +	ar8xxx_set_mirror_regs(priv); +	mutex_unlock(&priv->reg_mutex); + +	return 0; +} + +static int +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, +			       const struct switch_attr *attr, +			       struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	val->value.i = priv->mirror_rx; +	return 0; +} + +static int +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, +			       const struct switch_attr *attr, +			       struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + +	mutex_lock(&priv->reg_mutex); +	priv->mirror_tx = !!val->value.i; +	ar8xxx_set_mirror_regs(priv); +	mutex_unlock(&priv->reg_mutex); + +	return 0; +} + +static int +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, +			       const struct switch_attr *attr, +			       struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	val->value.i = priv->mirror_tx; +	return 0; +} + +static int +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, +				  const struct switch_attr *attr, +				  struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	 +	mutex_lock(&priv->reg_mutex); +	priv->monitor_port = val->value.i; +	ar8xxx_set_mirror_regs(priv); +	mutex_unlock(&priv->reg_mutex); + +	return 0; +} + +static int +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, +				  const struct switch_attr *attr, +				  struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	val->value.i = priv->monitor_port; +	return 0; +} + +static int +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, +				 const struct switch_attr *attr, +				 struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	 +	mutex_lock(&priv->reg_mutex); +	priv->source_port = val->value.i; +	ar8xxx_set_mirror_regs(priv); +	mutex_unlock(&priv->reg_mutex); + +	return 0; +} + +static int +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, +				 const struct switch_attr *attr, +				 struct switch_val *val) +{ +	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); +	val->value.i = priv->source_port; +	return 0; +} + +static int  ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,  			     const struct switch_attr *attr,  			     struct switch_val *val) @@ -1668,7 +1875,87 @@ static struct switch_attr ar8xxx_sw_attr_globals[] = {  		.description = "Reset all MIB counters",  		.set = ar8xxx_sw_set_reset_mibs,  	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "enable_mirror_rx", +		.description = "Enable mirroring of RX packets", +		.set = ar8xxx_sw_set_mirror_rx_enable, +		.get = ar8xxx_sw_get_mirror_rx_enable, +		.max = 1 +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "enable_mirror_tx", +		.description = "Enable mirroring of TX packets", +		.set = ar8xxx_sw_set_mirror_tx_enable, +		.get = ar8xxx_sw_get_mirror_tx_enable, +		.max = 1 +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "mirror_monitor_port", +		.description = "Mirror monitor port", +		.set = ar8xxx_sw_set_mirror_monitor_port, +		.get = ar8xxx_sw_get_mirror_monitor_port, +		.max = AR8216_NUM_PORTS - 1  +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "mirror_source_port", +		.description = "Mirror source port", +		.set = ar8xxx_sw_set_mirror_source_port, +		.get = ar8xxx_sw_get_mirror_source_port, +		.max = AR8216_NUM_PORTS - 1 + 	}, +}; +static struct switch_attr ar8327_sw_attr_globals[] = { +	{ +		.type = SWITCH_TYPE_INT, +		.name = "enable_vlan", +		.description = "Enable VLAN mode", +		.set = ar8xxx_sw_set_vlan, +		.get = ar8xxx_sw_get_vlan, +		.max = 1 +	}, +	{ +		.type = SWITCH_TYPE_NOVAL, +		.name = "reset_mibs", +		.description = "Reset all MIB counters", +		.set = ar8xxx_sw_set_reset_mibs, +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "enable_mirror_rx", +		.description = "Enable mirroring of RX packets", +		.set = ar8xxx_sw_set_mirror_rx_enable, +		.get = ar8xxx_sw_get_mirror_rx_enable, +		.max = 1 +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "enable_mirror_tx", +		.description = "Enable mirroring of TX packets", +		.set = ar8xxx_sw_set_mirror_tx_enable, +		.get = ar8xxx_sw_get_mirror_tx_enable, +		.max = 1 +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "mirror_monitor_port", +		.description = "Mirror monitor port", +		.set = ar8xxx_sw_set_mirror_monitor_port, +		.get = ar8xxx_sw_get_mirror_monitor_port, +		.max = AR8327_NUM_PORTS - 1  +	}, +	{ +		.type = SWITCH_TYPE_INT, +		.name = "mirror_source_port", +		.description = "Mirror source port", +		.set = ar8xxx_sw_set_mirror_source_port, +		.get = ar8xxx_sw_get_mirror_source_port, +		.max = AR8327_NUM_PORTS - 1 + 	},  };  static struct switch_attr ar8xxx_sw_attr_port[] = { @@ -1720,6 +2007,28 @@ static const struct switch_dev_ops ar8xxx_sw_ops = {  	.get_port_link = ar8xxx_sw_get_port_link,  }; +static const struct switch_dev_ops ar8327_sw_ops = { +	.attr_global = { +		.attr = ar8327_sw_attr_globals, +		.n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), +	}, +	.attr_port = { +		.attr = ar8xxx_sw_attr_port, +		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), +	}, +	.attr_vlan = { +		.attr = ar8xxx_sw_attr_vlan, +		.n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), +	}, +	.get_port_pvid = ar8xxx_sw_get_pvid, +	.set_port_pvid = ar8xxx_sw_set_pvid, +	.get_vlan_ports = ar8xxx_sw_get_ports, +	.set_vlan_ports = ar8xxx_sw_set_ports, +	.apply_config = ar8xxx_sw_hw_apply, +	.reset_switch = ar8xxx_sw_reset_switch, +	.get_port_link = ar8xxx_sw_get_port_link, +}; +  static int  ar8xxx_id_chip(struct ar8xxx_priv *priv)  { @@ -1900,6 +2209,7 @@ ar8xxx_probe_switch(struct ar8xxx_priv *priv)  		swdev->name = "Atheros AR8327";  		swdev->vlans = AR8X16_MAX_VLANS;  		swdev->ports = AR8327_NUM_PORTS; +		swdev->ops = &ar8327_sw_ops;  	} else {  		swdev->name = "Atheros AR8216";  		swdev->vlans = AR8216_NUM_VLANS; diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h index 95d9a96e7..086d58fba 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -105,6 +105,10 @@  #define   AR8216_MIB_FUNC_CAPTURE	0x3  #define   AR8236_MIB_EN			BIT(30) +#define AR8216_REG_GLOBAL_CPUPORT		0x0078 +#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT	BITS(4, 4) +#define   AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S	4 +  #define AR8216_PORT_OFFSET(_i)		(0x0100 * (_i + 1))  #define AR8216_REG_PORT_STATUS(_i)	(AR8216_PORT_OFFSET(_i) + 0x0000)  #define   AR8216_PORT_STATUS_SPEED	BITS(0,2) @@ -433,9 +437,13 @@  #define   AR8327_PORT_LOOKUP_STATE		BITS(16, 3)  #define   AR8327_PORT_LOOKUP_STATE_S		16  #define   AR8327_PORT_LOOKUP_LEARN		BIT(20) +#define   AR8327_PORT_LOOKUP_ING_MIRROR_EN	BIT(25)  #define AR8327_REG_PORT_PRIO(_i)		(0x664 + (_i) * 0xc) +#define AR8327_REG_PORT_HOL_CTRL1(_i)		(0x974 + (_i) * 0x8) +#define   AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN	BIT(16) +  #define AR8327_REG_PORT_STATS_BASE(_i)		(0x1000 + (_i) * 0x100)  /* port speed */ | 
