Răsfoiți Sursa

HACK: drivers: net: cpsw: add support for switch ioctl

Add support for add/delete multicast and vlan using switch ioctl

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 ani în urmă
părinte
comite
213d551772
1 a modificat fișierele cu 73 adăugiri și 0 ștergeri
  1. 73 0
      drivers/net/ethernet/ti/cpsw.c

+ 73 - 0
drivers/net/ethernet/ti/cpsw.c

@@ -37,6 +37,7 @@
 #include <linux/if_vlan.h>
 #include <linux/if_vlan.h>
 #include <linux/kmemleak.h>
 #include <linux/kmemleak.h>
 #include <linux/sys_soc.h>
 #include <linux/sys_soc.h>
+#include <linux/net_switch_config.h>
 
 
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/consumer.h>
 #include <net/pkt_cls.h>
 #include <net/pkt_cls.h>
@@ -2211,6 +2212,76 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
 }
 }
 #endif /*CONFIG_TI_CPTS*/
 #endif /*CONFIG_TI_CPTS*/
 
 
+static int cpsw_switch_config_ioctl(struct net_device *ndev,
+				    struct ifreq *ifrq, int cmd)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+	struct cpsw_common *cpsw = priv->cpsw;
+	struct net_switch_config config;
+	int ret = -EINVAL;
+
+	if (cpsw->data.dual_emac) {
+		dev_err(priv->dev, "CPSW not in switch mode\n");
+		return -ENOTSUPP;
+	}
+
+	/* Only SIOCSWITCHCONFIG is used as cmd argument and hence, there is no
+	 * switch statement required.
+	 * Function calls are based on switch_config.cmd
+	 */
+
+	if (copy_from_user(&config, (ifrq->ifr_data), sizeof(config)))
+		return -EFAULT;
+
+	if (config.vid > 4095) {
+		dev_err(priv->dev, "Invalid VLAN id Arguments for cmd %d\n",
+			config.cmd);
+		return ret;
+	}
+
+	switch (config.cmd) {
+	case CONFIG_SWITCH_ADD_MULTICAST:
+		if ((config.port > 0) && (config.port <= 7) &&
+		    is_multicast_ether_addr(config.addr)) {
+			ret = cpsw_ale_add_mcast(cpsw->ale, config.addr,
+						 config.port, ALE_VLAN,
+						 config.vid, 0);
+		} else {
+			dev_err(priv->dev, "Invalid Arguments for cmd %d\n",
+				config.cmd);
+		}
+		break;
+	case CONFIG_SWITCH_DEL_MULTICAST:
+		if (is_multicast_ether_addr(config.addr)) {
+			ret = cpsw_ale_del_mcast(cpsw->ale, config.addr,
+						 0, ALE_VLAN, config.vid);
+		} else {
+			dev_err(priv->dev, "Invalid Arguments for cmd %d\n",
+				config.cmd);
+		}
+		break;
+	case CONFIG_SWITCH_ADD_VLAN:
+		if ((config.port > 0) && (config.port <= 7)) {
+			ret = cpsw_ale_add_vlan(cpsw->ale, config.vid,
+						config.port,
+						config.untag_port,
+						config.reg_multi,
+						config.unreg_multi);
+		} else {
+			dev_err(priv->dev, "Invalid Arguments for cmd %d\n",
+				config.cmd);
+		}
+		break;
+	case CONFIG_SWITCH_DEL_VLAN:
+		ret = cpsw_ale_del_vlan(cpsw->ale, config.vid, 0);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
 static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
 {
 	struct cpsw_priv *priv = netdev_priv(dev);
 	struct cpsw_priv *priv = netdev_priv(dev);
@@ -2225,6 +2296,8 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 		return cpsw_hwtstamp_set(dev, req);
 		return cpsw_hwtstamp_set(dev, req);
 	case SIOCGHWTSTAMP:
 	case SIOCGHWTSTAMP:
 		return cpsw_hwtstamp_get(dev, req);
 		return cpsw_hwtstamp_get(dev, req);
+	case SIOCSWITCHCONFIG:
+		return cpsw_switch_config_ioctl(dev, req, cmd);
 	}
 	}
 
 
 	if (!cpsw->slaves[slave_no].phy)
 	if (!cpsw->slaves[slave_no].phy)