All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC, net-next v0 0/2] Microsemi PHY cable
@ 2019-06-12  8:57 Raju Lakkaraju
  2019-06-12  8:57 ` [RFC, net-next v0 1/2] net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics command Raju Lakkaraju
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Raju Lakkaraju @ 2019-06-12  8:57 UTC (permalink / raw)
  To: netdev; +Cc: UNGLinuxDriver, f.fainelli, andrew, Raju Lakkaraju

This series of patches add the Microsemi PHY cable diagnostics command 
with PHY Netlink Interface.

1. phy_netlink.c and phy_netlink.h files add for PHY diagnostics features
implementation through PHY Netlink interface.
2. phy.c contain the generic functions of "PHY diagnostics". This layer
independ of the communication layer (i.e. Netlink or IOCTL etc)
3. mscc.c contain the 4-pair ethernet PHY driver along with
PHY diagnostics feature.

Patches test on VSC8531 Microsemi PHY - Beaglebone Black target

Test results:
------------
# nl-app eth0 request
GroupID = 2
GroupName = phy_monitor

Cable Diagnostics Request:
Operation Status : Success
Cable Pairs mask : 0xf
Timeout count    : 84
Cable diagnostics results:
    Pair A: Correctly terminated pair, Loop Length: 0 m
    Pair B: Correctly terminated pair, Loop Length: 0 m
    Pair C: Correctly terminated pair, Loop Length: 0 m
    Pair D: Correctly terminated pair, Loop Length: 0 m
 
Application git repository path:
-------------------------------
https://github.com/lakkarajun/bbb_nl_app

Raju Lakkaraju (2):
  net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics
    command
  net: phy: mscc: Add PHY driver for Cable Diagnostics command

 drivers/net/phy/Kconfig       |   6 ++
 drivers/net/phy/Makefile      |   1 +
 drivers/net/phy/mscc.c        | 128 ++++++++++++++++++++++++
 drivers/net/phy/phy.c         |  17 ++++
 drivers/net/phy/phy_netlink.c | 226 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/phy.h           |  88 ++++++++++++++++
 include/linux/phy_netlink.h   |  48 +++++++++
 7 files changed, 514 insertions(+)
 create mode 100644 drivers/net/phy/phy_netlink.c
 create mode 100644 include/linux/phy_netlink.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [RFC, net-next v0 1/2] net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics command
  2019-06-12  8:57 [RFC, net-next v0 0/2] Microsemi PHY cable Raju Lakkaraju
@ 2019-06-12  8:57 ` Raju Lakkaraju
  2019-06-12  8:57 ` [RFC, net-next v0 2/2] net: phy: mscc: Add PHY driver for " Raju Lakkaraju
  2019-06-12 19:40 ` [RFC, net-next v0 0/2] Microsemi PHY cable Florian Fainelli
  2 siblings, 0 replies; 4+ messages in thread
From: Raju Lakkaraju @ 2019-06-12  8:57 UTC (permalink / raw)
  To: netdev; +Cc: UNGLinuxDriver, f.fainelli, andrew, Raju Lakkaraju

From: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>

Add the PHY Netlink interface driver to implement the cable
diagnostics of Microsemi Ethernet PHYs.

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
---
 drivers/net/phy/Kconfig       |   6 ++
 drivers/net/phy/Makefile      |   1 +
 drivers/net/phy/phy.c         |  17 ++++
 drivers/net/phy/phy_netlink.c | 226 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/phy.h           |  88 ++++++++++++++++
 include/linux/phy_netlink.h   |  48 +++++++++
 6 files changed, 386 insertions(+)
 create mode 100644 drivers/net/phy/phy_netlink.c
 create mode 100644 include/linux/phy_netlink.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index db5645b..a105058 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -406,6 +406,12 @@ config MICROCHIP_T1_PHY
 	---help---
 	  Supports the LAN87XX PHYs.
 
+config PHY_NETLINK
+        tristate "PHY Netlink Interface"
+    depends on NET
+        ---help---
+          Supports the PHY netlink interface.
+
 config MICROSEMI_PHY
 	tristate "Microsemi PHYs"
 	---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index bac339e..96aad9b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_MICREL_KS8995MA)	+= spi_ks8995.o
 obj-$(CONFIG_MICREL_PHY)	+= micrel.o
 obj-$(CONFIG_MICROCHIP_PHY)	+= microchip.o
 obj-$(CONFIG_MICROCHIP_T1_PHY)	+= microchip_t1.o
+obj-$(CONFIG_PHY_NETLINK)	+= phy_netlink.o
 obj-$(CONFIG_MICROSEMI_PHY)	+= mscc.o
 obj-$(CONFIG_NATIONAL_PHY)	+= national.o
 obj-$(CONFIG_NXP_TJA11XX_PHY)	+= nxp-tja11xx.o
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index d915076..29b2921 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1251,3 +1251,20 @@ int phy_ethtool_nway_reset(struct net_device *ndev)
 	return phy_restart_aneg(phydev);
 }
 EXPORT_SYMBOL(phy_ethtool_nway_reset);
+
+int phy_cabdiag_request(struct net_device *ndev, struct phy_cabdiag_req *cfg)
+{
+	struct phy_device *phydev = ndev->phydev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	if (!phydev->drv)
+		return -EIO;
+
+	if (phydev->drv->request_cable_diag)
+		return phydev->drv->request_cable_diag(phydev, cfg);
+
+	return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(phy_cabdiag_request);
diff --git a/drivers/net/phy/phy_netlink.c b/drivers/net/phy/phy_netlink.c
new file mode 100644
index 0000000..896c1b2
--- /dev/null
+++ b/drivers/net/phy/phy_netlink.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2019 Microchip Technology
+
+#include <linux/bitmap.h>
+#include <linux/rtnetlink.h>
+#include <net/sock.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+#include <net/sock.h>
+#include <linux/phy_netlink.h>
+
+static struct genl_family phynl_genl_family;
+
+static const struct nla_policy cabdiag_op_policy[CABDIAG_OP_ATTR_MAX + 1] = {
+	[CABDIAG_OP_ATTR_NOOP]     = { .type = NLA_UNSPEC },
+	[CABDIAG_OP_ATTR_REQUEST]  = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+cabdiag_pair_sta_policy[CABDIAG_PAIR_STA_ATTR_MAX + 1] = {
+	[CABDIAG_PAIR_STA_ATTR_NOOP]     = { .type = NLA_UNSPEC },
+	[CABDIAG_PAIR_STA_ATTR_STATUS]   = { .type = NLA_U8 },
+	[CABDIAG_PAIR_STA_ATTR_LENGTH]   = { .type = NLA_U8 },
+};
+
+static const struct nla_policy cabdiag_req_policy[CABDIAG_REQ_ATTR_MAX + 1] = {
+	[CABDIAG_REQ_ATTR_NOOP]       = { .type = NLA_UNSPEC },
+	[CABDIAG_REQ_ATTR_IFNAME]     = { .type = NLA_STRING },
+	[CABDIAG_REQ_ATTR_OP_STA]     = { .type = NLA_U8 },
+	[CABDIAG_REQ_ATTR_PAIRS_MASK] = { .type = NLA_U8 },
+	[CABDIAG_REQ_ATTR_TIMEOUT]    = { .type = NLA_U8 },
+	[CABDIAG_REQ_ATTR_STATUS]     =
+	NLA_POLICY_NESTED_ARRAY(cabdiag_pair_sta_policy),
+};
+
+static int phynl_interface_check(struct genl_info *info, const char *ifname)
+{
+	struct net *net = genl_info_net(info);
+	struct net_device *netdev;
+	int ret = 0;
+
+	netdev = dev_get_by_name(net, ifname);
+	if (netdev) {
+		if (netdev->phydev) {
+			if (!netdev->phydev->drv) {
+				pr_err("PHYNL: netdev->phydev->drv == NULL\n");
+				ret = -EINVAL;
+				goto out_dev_put;
+			}
+		} else {
+			pr_err("PHYNL: netdev->phydev == NULL\n");
+			ret = -EINVAL;
+			goto out_dev_put;
+		}
+	} else {
+		pr_err("PHYNL: can't find net device\n");
+		return -ENODEV;
+	}
+
+out_dev_put:
+	dev_put(netdev);
+
+	return ret;
+}
+
+static int phynl_cabdiag_request(struct genl_info *info, struct nlattr *nest)
+{
+	struct nlattr *tb[CABDIAG_REQ_ATTR_MAX + 1];
+	struct net *net = genl_info_net(info);
+	struct phy_cabdiag_req cfg;
+	struct net_device *netdev;
+	struct sk_buff *msg;
+	__be64 val_64;
+	char *ifname;
+	void *hdr;
+	int ret;
+
+	if (!nest) {
+		pr_err("PHYNL: nelink message error\n");
+		return -EINVAL;
+	}
+
+	memset(&cfg, 0, sizeof(struct phy_cabdiag_req));
+	ret = nla_parse_nested(tb, CABDIAG_REQ_ATTR_MAX, nest,
+			       cabdiag_req_policy, info->extack);
+	if (ret < 0)
+		return ret;
+
+	ifname = (char *)nla_data(tb[CABDIAG_REQ_ATTR_IFNAME]);
+	if (tb[CABDIAG_REQ_ATTR_IFNAME]) {
+		ret = phynl_interface_check(info, ifname);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (tb[CABDIAG_REQ_ATTR_PAIRS_MASK])
+		cfg.pairs_bitmask =
+		nla_get_u8(tb[CABDIAG_REQ_ATTR_PAIRS_MASK]);
+
+	if (tb[CABDIAG_REQ_ATTR_TIMEOUT])
+		cfg.timeout_cnt = nla_get_u8(tb[CABDIAG_REQ_ATTR_TIMEOUT]);
+
+	netdev = dev_get_by_name(net, ifname);
+
+	/* Initialize to default status */
+	cfg.pairs[CABDIAG_PAIR_A].length = CD_LENGTH_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_B].length = CD_LENGTH_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_C].length = CD_LENGTH_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_D].length = CD_LENGTH_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_A].status = CD_STATUS_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_B].status = CD_STATUS_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_C].status = CD_STATUS_NOT_SUPPORTED;
+	cfg.pairs[CABDIAG_PAIR_D].status = CD_STATUS_NOT_SUPPORTED;
+	ret = phy_cabdiag_request(netdev, &cfg);
+	if (ret < 0)
+		goto out_dev_put;
+
+	/* Reply back */
+	msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		ret = -ENOMEM;
+		goto out_dev_put;
+	}
+
+	hdr = genlmsg_put_reply(msg, info, &phynl_genl_family, 0,
+				PHYNL_CMD_CABDIAG);
+
+	nest = nla_nest_start(msg, CABDIAG_OP_ATTR_REQUEST | NLA_F_NESTED);
+	nla_put_u8(msg, CABDIAG_REQ_ATTR_OP_STA, cfg.op_status);
+	nla_put_u8(msg, CABDIAG_REQ_ATTR_PAIRS_MASK, cfg.pairs_bitmask);
+	nla_put_u8(msg, CABDIAG_REQ_ATTR_TIMEOUT, cfg.timeout_cnt);
+	val_64 = ((__be64)cfg.pairs[CABDIAG_PAIR_D].length << 56 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_D].status << 48 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_C].length << 40 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_C].status << 32 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_B].length << 24 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_B].status << 16 |
+		  (__be64)cfg.pairs[CABDIAG_PAIR_A].length << 8  |
+		  cfg.pairs[CABDIAG_PAIR_A].status);
+	nla_put_be64(msg, CABDIAG_REQ_ATTR_STATUS, val_64, 4);
+	nla_nest_end(msg, nest);
+
+	genlmsg_end(msg, hdr);
+	genlmsg_reply(msg, info);
+
+out_dev_put:
+	if (netdev)
+		dev_put(netdev);
+
+	return ret;
+}
+
+static int phynl_cabdiag_doit(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *tb[CABDIAG_OP_ATTR_MAX + 1];
+	int ret;
+
+	ret = genlmsg_parse(info->nlhdr, &phynl_genl_family, tb,
+			    CABDIAG_OP_ATTR_MAX, cabdiag_op_policy,
+			    info ? info->extack : NULL);
+	if (ret < 0) {
+		pr_err("PHYNL: genlmsg_parse returns:%d\n", ret);
+		return ret;
+	}
+
+	if (tb[CABDIAG_OP_ATTR_REQUEST]) {
+		ret = phynl_cabdiag_request(info, tb[CABDIAG_OP_ATTR_REQUEST]);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+#define PHYNL_GENL_NAME	"phynl"
+#define	PHYNL_GENL_VERSION	1
+#define	PHYNL_MCGRP_MONITOR	"phy_monitor"
+static struct genl_multicast_group phynl_genl_mcgroups[] = {
+	{
+		.name = PHYNL_MCGRP_MONITOR
+	},
+};
+
+static const struct genl_ops phynl_genl_ops[] = {
+	{
+		.cmd    = PHYNL_CMD_CABDIAG,
+		.doit   = phynl_cabdiag_doit,
+	},
+};
+
+static struct genl_family phynl_genl_family = {
+	.hdrsize	= 0,
+	.name		= PHYNL_GENL_NAME,
+	.version	= PHYNL_GENL_VERSION,
+	.netnsok	= true,
+	.parallel_ops	= false,
+	.ops		= phynl_genl_ops,
+	.n_ops		= ARRAY_SIZE(phynl_genl_ops),
+	.mcgrps		= phynl_genl_mcgroups,
+	.n_mcgrps	= ARRAY_SIZE(phynl_genl_mcgroups),
+};
+
+static int __init phynl_genl_init(void)
+{
+	int ret;
+
+	ret = genl_register_family(&phynl_genl_family);
+	if (ret < 0)
+		panic("PHYNL: Could not register genetlink family\n");
+
+	return 0;
+}
+
+static void __exit phynl_genl_exit(void)
+{
+	genl_unregister_family(&phynl_genl_family);
+}
+
+module_init(phynl_genl_init);
+module_exit(phynl_genl_exit);
+
+MODULE_DESCRIPTION("PHY Netlink Interface driver");
+MODULE_AUTHOR("Nagaraju Lakkaraju");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/phy.h b/include/linux/phy.h
index d0af7d3..b045ddf 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -320,6 +320,91 @@ struct phy_c45_device_ids {
 	u32 device_ids[8];
 };
 
+#define CABDIAG_PAIR_A_MASK 0x0001
+#define CABDIAG_PAIR_B_MASK 0x0002
+#define CABDIAG_PAIR_C_MASK 0x0004
+#define CABDIAG_PAIR_D_MASK 0x0008
+enum phy_cabdiag_pairs {
+	CABDIAG_PAIR_A,
+	CABDIAG_PAIR_B,
+	CABDIAG_PAIR_C,
+	CABDIAG_PAIR_D,
+
+	CABDIAG_PAIR_CNT,
+};
+
+/**
+ * phy_cabdiag_op_sta - Cable diagnostics operational status
+ * CD_REQ_NONE                    - Unknown
+ * CD_REQ_INVALID_PAIR_MASK       - Invalid pair mask
+ * CD_REQ_INVALID_TIMEOUT         - Invalid Timeout counter
+ * CD_REQ_REJECTED_BUSY           - Previous command execution busy
+ * CD_STATUS_SUCCESS              - Operation success
+ * CD_STATUS_FAILED_TIMEOUT       - Failed due to Timeout
+ * CD_STATUS_FAILED_INVALID       - Status results invalid
+ */
+enum phy_cabdiag_op_sta {
+	CD_REQ_NONE,
+	CD_REQ_INVALID_PAIR_MASK,
+	CD_REQ_INVALID_TIMEOUT,
+	CD_REQ_REJECTED_BUSY,
+	CD_STATUS_SUCCESS,
+	CD_STATUS_FAILED_TIMEOUT,
+	CD_STATUS_FAILED_INVALID
+};
+
+#define CD_LENGTH_NOT_SUPPORTED 0xFF
+#define CD_STATUS_NOT_SUPPORTED 0xFF
+
+/**
+ * phy_cabdiag_sta_code - Cable diagnostics fault codes
+ * b0000 - 0100: Individual cable pair fault codes
+ * b10xx       : Cross pair short to pair 'xx'
+ * b11xx       : Abnormal Cross pair coupling with pair 'xx'
+ *    xx       : b00 - Pair-A,
+ *             : b01 - Pair-B,
+ *             : b10 - Pair-C,
+ *             : b11 - Pair-D
+ */
+enum phy_cabdiag_sta_code {
+	CD_NORMAL_PAIR            = 0x0,
+	CD_OPEN_PAIR              = 0x1,
+	CD_SHORTED_PAIR           = 0x2,
+	CD_ABNORMAL_TERMINATION   = 0x4,
+	CD_X_PAIR_SHORT_TO_PAIR_A = 0x8,
+	CD_X_PAIR_SHORT_TO_PAIR_B = 0x9,
+	CD_X_PAIR_SHORT_TO_PAIR_C = 0xA,
+	CD_X_PAIR_SHORT_TO_PAIR_D = 0xB,
+	CD_ABNORMAL_X_PAIR_A      = 0xC,
+	CD_ABNORMAL_X_PAIR_B      = 0xD,
+	CD_ABNORMAL_X_PAIR_C      = 0xE,
+	CD_ABNORMAL_X_PAIR_D      = 0xF
+};
+
+/**
+ * struct phy_cabdiag_pair_sta - PHY diagnostics pair status
+ * @status: Fault codes
+ * @length: Length in meters
+ */
+struct phy_cabdiag_pair_sta {
+	enum phy_cabdiag_sta_code status;
+	u8 length;
+};
+
+/**
+ * struct phy_cabdiag_req - PHY diagnostics request/status command
+ * @op_status: Cable Diagnostics Operational status
+ * @pairs_bitmask: Allows settings diag request just for a pair
+ * @timeout_cnt: Timeout count (i.e. Multiples of driver wait time)
+ * @pairs[CABDIAG_PAIR_CNT]: Status of 4 pairs of cable
+ */
+struct phy_cabdiag_req {
+	enum phy_cabdiag_op_sta op_status;
+	u8 pairs_bitmask;
+	u8 timeout_cnt;
+	struct phy_cabdiag_pair_sta pairs[CABDIAG_PAIR_CNT];
+};
+
 /* phy_device: An instance of a PHY
  *
  * drv: Pointer to the driver for this PHY instance
@@ -621,6 +706,8 @@ struct phy_driver {
 			    struct ethtool_tunable *tuna,
 			    const void *data);
 	int (*set_loopback)(struct phy_device *dev, bool enable);
+	int (*request_cable_diag)(struct phy_device *dev,
+				  struct phy_cabdiag_req *cfg);
 };
 #define to_phy_driver(d) container_of(to_mdio_common_driver(d),		\
 				      struct phy_driver, mdiodrv)
@@ -1170,6 +1257,7 @@ int phy_ethtool_get_link_ksettings(struct net_device *ndev,
 int phy_ethtool_set_link_ksettings(struct net_device *ndev,
 				   const struct ethtool_link_ksettings *cmd);
 int phy_ethtool_nway_reset(struct net_device *ndev);
+int phy_cabdiag_request(struct net_device *ndev, struct phy_cabdiag_req *cfg);
 
 #if IS_ENABLED(CONFIG_PHYLIB)
 int __init mdio_bus_init(void);
diff --git a/include/linux/phy_netlink.h b/include/linux/phy_netlink.h
new file mode 100644
index 0000000..2823d67
--- /dev/null
+++ b/include/linux/phy_netlink.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+#ifndef __PHY_NETLINK_H
+#define __PHY_NETLINK_H
+
+#include <linux/rtnetlink.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+
+/* Genetlink setup */
+enum {
+	PHYNL_CMD_NOOP,
+	PHYNL_CMD_CABDIAG,
+
+	__PHYNL_CMD_CNT,
+	PHYNL_CMD_MAX = (__PHYNL_CMD_CNT - 1)
+};
+
+enum {
+	CABDIAG_OP_ATTR_NOOP,
+	CABDIAG_OP_ATTR_REQUEST,
+
+	__CABDIAG_OP_ATTR_CNT,
+	CABDIAG_OP_ATTR_MAX = (__CABDIAG_OP_ATTR_CNT - 1)
+};
+
+enum {
+	CABDIAG_PAIR_STA_ATTR_NOOP,
+	CABDIAG_PAIR_STA_ATTR_STATUS,
+	CABDIAG_PAIR_STA_ATTR_LENGTH,
+
+	__CABDIAG_PAIR_STA_ATTR_CNT,
+	CABDIAG_PAIR_STA_ATTR_MAX = (__CABDIAG_PAIR_STA_ATTR_CNT - 1)
+};
+
+enum {
+	CABDIAG_REQ_ATTR_NOOP,
+	CABDIAG_REQ_ATTR_IFNAME,
+	CABDIAG_REQ_ATTR_OP_STA,
+	CABDIAG_REQ_ATTR_PAIRS_MASK,
+	CABDIAG_REQ_ATTR_TIMEOUT,
+	CABDIAG_REQ_ATTR_STATUS,
+
+	__CABDIAG_REQ_ATTR_CNT,
+	CABDIAG_REQ_ATTR_MAX = (__CABDIAG_REQ_ATTR_CNT - 1)
+};
+
+#endif /* __PHY_NETLINK_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [RFC, net-next v0 2/2] net: phy: mscc: Add PHY driver for Cable Diagnostics command
  2019-06-12  8:57 [RFC, net-next v0 0/2] Microsemi PHY cable Raju Lakkaraju
  2019-06-12  8:57 ` [RFC, net-next v0 1/2] net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics command Raju Lakkaraju
@ 2019-06-12  8:57 ` Raju Lakkaraju
  2019-06-12 19:40 ` [RFC, net-next v0 0/2] Microsemi PHY cable Florian Fainelli
  2 siblings, 0 replies; 4+ messages in thread
From: Raju Lakkaraju @ 2019-06-12  8:57 UTC (permalink / raw)
  To: netdev; +Cc: UNGLinuxDriver, f.fainelli, andrew, Raju Lakkaraju

From: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>

Add the Cable diagnostics command to VSC85xx PHYs.

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
---
 drivers/net/phy/mscc.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c
index 28676af..98e3925 100644
--- a/drivers/net/phy/mscc.c
+++ b/drivers/net/phy/mscc.c
@@ -153,9 +153,29 @@ enum rgmii_rx_clock_delay {
 #define MSCC_PHY_EXT_PHY_CNTL_4		  23
 #define PHY_CNTL_4_ADDR_POS		  11
 
+#define MSCC_PHY_VERIPHY_CNTL_1           24
+#define VERIPHY_TRIGGER_CNTL_MASK	  0x8000
+#define VERIPHY_VALID_MASK		  0x4000
+#define VERIPHY_PAIR_A_DISTANCE_MASK	  0x2F00
+#define VERIPHY_PAIR_A_DISTANCE_POS	  8
+#define VERIPHY_PAIR_B_DISTANCE_MASK	  0x002F
+#define VERIPHY_PAIR_B_DISTANCE_POS	  0
+
 #define MSCC_PHY_VERIPHY_CNTL_2		  25
+#define VERIPHY_PAIR_C_DISTANCE_MASK	  0x2F00
+#define VERIPHY_PAIR_C_DISTANCE_POS	  8
+#define VERIPHY_PAIR_D_DISTANCE_MASK	  0x002F
+#define VERIPHY_PAIR_D_DISTANCE_POS	  0
 
 #define MSCC_PHY_VERIPHY_CNTL_3		  26
+#define VERIPHY_PAIR_A_STATUS_MASK	  0xF000
+#define VERIPHY_PAIR_A_STATUS_POS	  12
+#define VERIPHY_PAIR_B_STATUS_MASK	  0x0F00
+#define VERIPHY_PAIR_B_STATUS_POS	  8
+#define VERIPHY_PAIR_C_STATUS_MASK	  0x00F0
+#define VERIPHY_PAIR_C_STATUS_POS	  4
+#define VERIPHY_PAIR_D_STATUS_MASK	  0x000F
+#define VERIPHY_PAIR_D_STATUS_POS	  0
 
 /* Extended Page 2 Registers */
 #define MSCC_PHY_CU_PMD_TX_CNTL		  16
@@ -442,6 +462,107 @@ static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
 	return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
 }
 
+static int vsc85xx_cabdiag_request(struct phy_device *phydev,
+				   struct phy_cabdiag_req *cfg)
+{
+	u16 reg_val;
+	u8 timeout_cnt = 0;
+	int rc;
+
+	if (cfg->pairs_bitmask < CABDIAG_PAIR_A_MASK   ||
+	    (cfg->pairs_bitmask > (CABDIAG_PAIR_A_MASK |
+				   CABDIAG_PAIR_B_MASK |
+				   CABDIAG_PAIR_C_MASK |
+				   CABDIAG_PAIR_D_MASK))) {
+		cfg->op_status = CD_REQ_INVALID_PAIR_MASK;
+		return 0;
+	}
+	if (cfg->timeout_cnt == 0) {
+		cfg->op_status = CD_REQ_INVALID_TIMEOUT;
+		return 0;
+	}
+
+	mutex_lock(&phydev->lock);
+	rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED);
+	if (rc < 0)
+		goto out_unlock;
+
+	reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_1);
+	if (reg_val & VERIPHY_TRIGGER_CNTL_MASK) {
+		cfg->op_status = CD_REQ_REJECTED_BUSY;
+		goto out_unlock;
+	}
+	/* Start Cable Diagnostics operation */
+	reg_val |= VERIPHY_TRIGGER_CNTL_MASK;
+	__phy_write(phydev, MSCC_PHY_VERIPHY_CNTL_1, reg_val);
+
+	/* Wait till VeriPHY has completed */
+	do {
+		msleep(30);
+		reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_1);
+	} while ((reg_val & VERIPHY_TRIGGER_CNTL_MASK) &&
+		 (timeout_cnt++ < cfg->timeout_cnt));
+
+	if (timeout_cnt >= cfg->timeout_cnt) {
+		cfg->op_status = CD_STATUS_FAILED_TIMEOUT;
+		goto out_unlock;
+	}
+	cfg->timeout_cnt = timeout_cnt;
+
+	if (reg_val & VERIPHY_VALID_MASK) {
+		/* VeriPHY results are valid */
+		if (cfg->pairs_bitmask & CABDIAG_PAIR_A_MASK) {
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_1);
+			cfg->pairs[CABDIAG_PAIR_A].length =
+			(reg_val & VERIPHY_PAIR_A_DISTANCE_MASK) >>
+			VERIPHY_PAIR_A_DISTANCE_POS;
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_3);
+			cfg->pairs[CABDIAG_PAIR_A].status =
+			(reg_val & VERIPHY_PAIR_A_STATUS_MASK) >>
+			VERIPHY_PAIR_A_STATUS_POS;
+		}
+		if (cfg->pairs_bitmask & CABDIAG_PAIR_B_MASK) {
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_1);
+			cfg->pairs[CABDIAG_PAIR_B].length =
+			(reg_val & VERIPHY_PAIR_B_DISTANCE_MASK) >>
+			VERIPHY_PAIR_B_DISTANCE_POS;
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_3);
+			cfg->pairs[CABDIAG_PAIR_B].status =
+			(reg_val & VERIPHY_PAIR_B_STATUS_MASK) >>
+			VERIPHY_PAIR_B_STATUS_POS;
+		}
+		if (cfg->pairs_bitmask & CABDIAG_PAIR_C_MASK) {
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
+			cfg->pairs[CABDIAG_PAIR_C].length =
+			(reg_val & VERIPHY_PAIR_C_DISTANCE_MASK) >>
+			VERIPHY_PAIR_C_DISTANCE_POS;
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_3);
+			cfg->pairs[CABDIAG_PAIR_C].status =
+			(reg_val & VERIPHY_PAIR_C_STATUS_MASK) >>
+			VERIPHY_PAIR_C_STATUS_POS;
+		}
+		if (cfg->pairs_bitmask & CABDIAG_PAIR_D_MASK) {
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_2);
+			cfg->pairs[CABDIAG_PAIR_D].length =
+			(reg_val & VERIPHY_PAIR_D_DISTANCE_MASK) >>
+			VERIPHY_PAIR_D_DISTANCE_POS;
+			reg_val = __phy_read(phydev, MSCC_PHY_VERIPHY_CNTL_3);
+			cfg->pairs[CABDIAG_PAIR_D].status =
+			(reg_val & VERIPHY_PAIR_D_STATUS_MASK) >>
+			VERIPHY_PAIR_D_STATUS_POS;
+		}
+		cfg->op_status = CD_STATUS_SUCCESS;
+	} else {
+		cfg->op_status = CD_STATUS_FAILED_INVALID;
+	}
+
+out_unlock:
+	phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
+	mutex_unlock(&phydev->lock);
+
+	return rc;
+}
+
 static int vsc85xx_get_sset_count(struct phy_device *phydev)
 {
 	struct vsc8531_private *priv = phydev->priv;
@@ -2343,6 +2464,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8530,
@@ -2368,6 +2490,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8531,
@@ -2393,6 +2516,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8540,
@@ -2418,6 +2542,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8541,
@@ -2443,6 +2568,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8574,
@@ -2469,6 +2595,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 },
 {
 	.phy_id		= PHY_ID_VSC8584,
@@ -2493,6 +2620,7 @@ static struct phy_driver vsc85xx_driver[] = {
 	.get_sset_count = &vsc85xx_get_sset_count,
 	.get_strings    = &vsc85xx_get_strings,
 	.get_stats      = &vsc85xx_get_stats,
+	.request_cable_diag = &vsc85xx_cabdiag_request,
 }
 
 };
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [RFC, net-next v0 0/2] Microsemi PHY cable
  2019-06-12  8:57 [RFC, net-next v0 0/2] Microsemi PHY cable Raju Lakkaraju
  2019-06-12  8:57 ` [RFC, net-next v0 1/2] net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics command Raju Lakkaraju
  2019-06-12  8:57 ` [RFC, net-next v0 2/2] net: phy: mscc: Add PHY driver for " Raju Lakkaraju
@ 2019-06-12 19:40 ` Florian Fainelli
  2 siblings, 0 replies; 4+ messages in thread
From: Florian Fainelli @ 2019-06-12 19:40 UTC (permalink / raw)
  To: Raju Lakkaraju, netdev; +Cc: UNGLinuxDriver, andrew

On 6/12/19 1:57 AM, Raju Lakkaraju wrote:
> This series of patches add the Microsemi PHY cable diagnostics command 
> with PHY Netlink Interface.
> 
> 1. phy_netlink.c and phy_netlink.h files add for PHY diagnostics features
> implementation through PHY Netlink interface.
> 2. phy.c contain the generic functions of "PHY diagnostics". This layer
> independ of the communication layer (i.e. Netlink or IOCTL etc)
> 3. mscc.c contain the 4-pair ethernet PHY driver along with
> PHY diagnostics feature.

Andrew just submitted a similar feature set, except that his changes are
much more comprehensive, and also build on top of ethtool-nl, meaning he
has payed attention to the work that was going on within the netdev
community.

Your submission on the other end appears to be looking for the minimum
amount of code necessary to support the Microsemi PHYs product lines and
does not try very hard to possibly think about an abstraction layer for
other PHYs but Microsemi, that does not really give maintainers
confidence that you have.

Can you review Andrew's patch series and see if you find something
missing for you to plug in support for the Microsemi PHYs?

> ------------
> # nl-app eth0 request
> GroupID = 2
> GroupName = phy_monitor
> 
> Cable Diagnostics Request:
> Operation Status : Success
> Cable Pairs mask : 0xf
> Timeout count    : 84
> Cable diagnostics results:
>     Pair A: Correctly terminated pair, Loop Length: 0 m
>     Pair B: Correctly terminated pair, Loop Length: 0 m
>     Pair C: Correctly terminated pair, Loop Length: 0 m
>     Pair D: Correctly terminated pair, Loop Length: 0 m
>  
> Application git repository path:
> -------------------------------
> https://github.com/lakkarajun/bbb_nl_app
> 
> Raju Lakkaraju (2):
>   net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics
>     command
>   net: phy: mscc: Add PHY driver for Cable Diagnostics command
> 
>  drivers/net/phy/Kconfig       |   6 ++
>  drivers/net/phy/Makefile      |   1 +
>  drivers/net/phy/mscc.c        | 128 ++++++++++++++++++++++++
>  drivers/net/phy/phy.c         |  17 ++++
>  drivers/net/phy/phy_netlink.c | 226 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/phy.h           |  88 ++++++++++++++++
>  include/linux/phy_netlink.h   |  48 +++++++++
>  7 files changed, 514 insertions(+)
>  create mode 100644 drivers/net/phy/phy_netlink.c
>  create mode 100644 include/linux/phy_netlink.h
> 


-- 
Florian

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-06-12 19:40 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-12  8:57 [RFC, net-next v0 0/2] Microsemi PHY cable Raju Lakkaraju
2019-06-12  8:57 ` [RFC, net-next v0 1/2] net: phy: mscc: Add PHY Netlink Interface along with Cable Diagnostics command Raju Lakkaraju
2019-06-12  8:57 ` [RFC, net-next v0 2/2] net: phy: mscc: Add PHY driver for " Raju Lakkaraju
2019-06-12 19:40 ` [RFC, net-next v0 0/2] Microsemi PHY cable Florian Fainelli

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.