Browse Source

HACK: drivers: net: cpsw: switch-config: set/get port state

Add support for configuring port states handling of the packet switching
to the slave port like disabling packet forwarding/learning.

Note: Using this interface a user can disable all the slave ports which
      will bring down the Ethernet interface.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Mugunthan V N 7 years ago
parent
commit
d292523bbb
2 changed files with 55 additions and 1 deletions
  1. 45 1
      drivers/net/ethernet/ti/cpsw.c
  2. 10 0
      include/uapi/linux/net_switch_config.h

+ 45 - 1
drivers/net/ethernet/ti/cpsw.c

@@ -471,6 +471,7 @@ struct cpsw_priv {
 	int				rx_ts_enabled;
 	u32 emac_port;
 	struct cpsw_common *cpsw;
+	u8				port_state[3];
 };
 
 struct cpsw_stats {
@@ -1148,7 +1149,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave,
 
 		/* enable forwarding */
 		cpsw_ale_control_set(cpsw->ale, slave_port,
-				     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
+				     ALE_PORT_STATE,
+				     priv->port_state[slave_port]);
 
 		if (phy->speed == 1000)
 			mac_control |= BIT(7);	/* GIGABITEN	*/
@@ -1481,6 +1483,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	slave->mac_control = 0;	/* no link yet */
 
 	slave_port = cpsw_get_slave_port(slave->slave_num);
+	priv->port_state[slave_port] = ALE_PORT_STATE_FORWARD;
 
 	if (cpsw->data.dual_emac)
 		cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port);
@@ -2212,6 +2215,30 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
 }
 #endif /*CONFIG_TI_CPTS*/
 
+static int cpsw_set_port_state(struct cpsw_priv *priv, int port,
+			       int port_state)
+{
+	switch (port_state) {
+	case PORT_STATE_DISABLED:
+		priv->port_state[port] = ALE_PORT_STATE_DISABLE;
+		break;
+	case PORT_STATE_BLOCKED:
+		priv->port_state[port] = ALE_PORT_STATE_BLOCK;
+		break;
+	case PORT_STATE_LEARN:
+		priv->port_state[port] = ALE_PORT_STATE_LEARN;
+		break;
+	case PORT_STATE_FORWARD:
+		priv->port_state[port] = ALE_PORT_STATE_FORWARD;
+		break;
+	default:
+		dev_err(priv->dev, "Switch config: Invalid port state\n");
+		return -EINVAL;
+	}
+	return cpsw_ale_control_set(priv->cpsw->ale, port, ALE_PORT_STATE,
+			priv->port_state[port]);
+}
+
 static int cpsw_switch_config_ioctl(struct net_device *ndev,
 				    struct ifreq *ifrq, int cmd)
 {
@@ -2335,6 +2362,23 @@ static int cpsw_switch_config_ioctl(struct net_device *ndev,
 			dev_err(priv->dev, "Invalid Unknown VLAN Arguments\n");
 		}
 		break;
+	case CONFIG_SWITCH_GET_PORT_STATE:
+		if (config.port == 1 || config.port == 2) {
+			config.port_state = priv->port_state[config.port];
+			ret = copy_to_user(ifrq->ifr_data, &config,
+					   sizeof(config));
+		} else {
+			dev_err(priv->dev, "Invalid Port number\n");
+		}
+		break;
+	case CONFIG_SWITCH_SET_PORT_STATE:
+		if (config.port == 1 || config.port == 2) {
+			ret = cpsw_set_port_state(priv, config.port,
+						  config.port_state);
+		} else {
+			dev_err(priv->dev, "Invalid Port number\n");
+		}
+		break;
 
 	default:
 		ret = -EOPNOTSUPP;

+ 10 - 0
include/uapi/linux/net_switch_config.h

@@ -19,6 +19,15 @@ enum {
 	CONFIG_SWITCH_SET_PORT_CONFIG,
 	CONFIG_SWITCH_GET_PORT_CONFIG,
 	CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO,
+	CONFIG_SWITCH_GET_PORT_STATE,
+	CONFIG_SWITCH_SET_PORT_STATE,
+};
+
+enum {
+	PORT_STATE_DISABLED = 0,
+	PORT_STATE_BLOCKED,
+	PORT_STATE_LEARN,
+	PORT_STATE_FORWARD,
 };
 
 /*
@@ -39,6 +48,7 @@ struct net_switch_config {
 	unsigned char	unknown_vlan_untag;
 	unsigned int	unknown_vlan_unreg_multi;
 	unsigned int	unknown_vlan_reg_multi;
+	unsigned int	port_state;
 
 	unsigned int ret_type;   /* Return  Success/Failure */
 };