Browse Source

HACK: drivers: net: cpsw: switch-config: get/set phy status support

Support for get/set individual switch port phy link status

Use ethtool_cmd interface for switch-config.
This also enables using the same userspace application with older as
well as newer kernels.

Since CPSW switch config code exposes an interface very similar to
ethtool, we need some helper functions to convert from legacy userspace
interface to the new one. Make some helper functions from ethtool code
available for other drivers.

TODO: The complete switch config private IOCTL interface needs to be
      converted to an upstream-friendly solution.

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
c75d92d941

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

@@ -2275,6 +2275,45 @@ static int cpsw_switch_config_ioctl(struct net_device *ndev,
 	case CONFIG_SWITCH_DEL_VLAN:
 	case CONFIG_SWITCH_DEL_VLAN:
 		ret = cpsw_ale_del_vlan(cpsw->ale, config.vid, 0);
 		ret = cpsw_ale_del_vlan(cpsw->ale, config.vid, 0);
 		break;
 		break;
+	case CONFIG_SWITCH_SET_PORT_CONFIG:
+	{
+		struct phy_device *phy = NULL;
+		struct ethtool_link_ksettings cmd;
+
+		if ((config.port == 1) || (config.port == 2))
+			phy = cpsw->slaves[config.port - 1].phy;
+
+		if (!phy) {
+			dev_err(priv->dev, "Phy not Found\n");
+			break;
+		}
+
+		convert_legacy_settings_to_link_ksettings(&cmd, &config.ecmd);
+		cmd.base.phy_address = phy->mdio.addr;
+		ret = phy_ethtool_ksettings_set(phy, &cmd);
+		break;
+	}
+	case CONFIG_SWITCH_GET_PORT_CONFIG:
+	{
+		struct phy_device *phy = NULL;
+		struct ethtool_link_ksettings cmd;
+
+		if ((config.port == 1) || (config.port == 2))
+			phy = cpsw->slaves[config.port - 1].phy;
+
+		if (!phy) {
+			dev_err(priv->dev, "Phy not Found\n");
+			break;
+		}
+
+		cmd.base.phy_address = phy->mdio.addr;
+		phy_ethtool_ksettings_get(phy, &cmd);
+		convert_link_ksettings_to_legacy_settings(&config.ecmd, &cmd);
+
+		ret = copy_to_user(ifrq->ifr_data, &config, sizeof(config));
+		break;
+	}
+
 	default:
 	default:
 		ret = -EOPNOTSUPP;
 		ret = -EOPNOTSUPP;
 	}
 	}

+ 8 - 0
include/linux/ethtool.h

@@ -181,6 +181,14 @@ void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst,
 bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
 bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
 				     const unsigned long *src);
 				     const unsigned long *src);
 
 
+bool convert_legacy_settings_to_link_ksettings(
+	struct ethtool_link_ksettings *link_ksettings,
+	const struct ethtool_cmd *legacy_settings);
+
+bool convert_link_ksettings_to_legacy_settings(
+	struct ethtool_cmd *legacy_settings,
+	const struct ethtool_link_ksettings *link_ksettings);
+
 /**
 /**
  * struct ethtool_ops - optional netdev operations
  * struct ethtool_ops - optional netdev operations
  * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
  * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings

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

@@ -16,6 +16,8 @@ enum {
 	CONFIG_SWITCH_DEL_MULTICAST,
 	CONFIG_SWITCH_DEL_MULTICAST,
 	CONFIG_SWITCH_ADD_VLAN,
 	CONFIG_SWITCH_ADD_VLAN,
 	CONFIG_SWITCH_DEL_VLAN,
 	CONFIG_SWITCH_DEL_VLAN,
+	CONFIG_SWITCH_SET_PORT_CONFIG,
+	CONFIG_SWITCH_GET_PORT_CONFIG,
 };
 };
 
 
 /*
 /*
@@ -31,6 +33,7 @@ struct net_switch_config {
 	unsigned char	untag_port;	/* Untag ports */
 	unsigned char	untag_port;	/* Untag ports */
 	unsigned char	addr[6];
 	unsigned char	addr[6];
 	unsigned int	super;
 	unsigned int	super;
+	struct ethtool_cmd ecmd;
 
 
 	unsigned int ret_type;   /* Return  Success/Failure */
 	unsigned int ret_type;   /* Return  Success/Failure */
 };
 };

+ 4 - 2
net/core/ethtool.c

@@ -434,7 +434,7 @@ EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
 /* return false if legacy contained non-0 deprecated fields
 /* return false if legacy contained non-0 deprecated fields
  * maxtxpkt/maxrxpkt. rest of ksettings always updated
  * maxtxpkt/maxrxpkt. rest of ksettings always updated
  */
  */
-static bool
+bool
 convert_legacy_settings_to_link_ksettings(
 convert_legacy_settings_to_link_ksettings(
 	struct ethtool_link_ksettings *link_ksettings,
 	struct ethtool_link_ksettings *link_ksettings,
 	const struct ethtool_cmd *legacy_settings)
 	const struct ethtool_cmd *legacy_settings)
@@ -478,11 +478,12 @@ convert_legacy_settings_to_link_ksettings(
 		= legacy_settings->eth_tp_mdix_ctrl;
 		= legacy_settings->eth_tp_mdix_ctrl;
 	return retval;
 	return retval;
 }
 }
+EXPORT_SYMBOL_GPL(convert_legacy_settings_to_link_ksettings);
 
 
 /* return false if ksettings link modes had higher bits
 /* return false if ksettings link modes had higher bits
  * set. legacy_settings always updated (best effort)
  * set. legacy_settings always updated (best effort)
  */
  */
-static bool
+bool
 convert_link_ksettings_to_legacy_settings(
 convert_link_ksettings_to_legacy_settings(
 	struct ethtool_cmd *legacy_settings,
 	struct ethtool_cmd *legacy_settings,
 	const struct ethtool_link_ksettings *link_ksettings)
 	const struct ethtool_link_ksettings *link_ksettings)
@@ -524,6 +525,7 @@ convert_link_ksettings_to_legacy_settings(
 		= link_ksettings->base.transceiver;
 		= link_ksettings->base.transceiver;
 	return retval;
 	return retval;
 }
 }
+EXPORT_SYMBOL_GPL(convert_link_ksettings_to_legacy_settings);
 
 
 /* number of 32-bit words to store the user's link mode bitmaps */
 /* number of 32-bit words to store the user's link mode bitmaps */
 #define __ETHTOOL_LINK_MODE_MASK_NU32			\
 #define __ETHTOOL_LINK_MODE_MASK_NU32			\