lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 17 Aug 2017 19:02:50 -0500
From:   Tom Lendacky <thomas.lendacky@....com>
To:     netdev@...r.kernel.org
Cc:     David Miller <davem@...emloft.net>
Subject: [PATCH net-next v1 05/14] amd-xgbe: Add additional debugfs support

Add additional debugfs support for reading / writing registers of any
attached external phy devices as well as the SFP eeprom data.

These debugfs files will only be created if the phy implementation
supports them.

Signed-off-by: Tom Lendacky <thomas.lendacky@....com>
---
 drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c |  151 ++++++++++++++++++++++++++
 drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c  |   87 +++++++++++++++
 drivers/net/ethernet/amd/xgbe/xgbe.h         |   12 ++
 3 files changed, 250 insertions(+)

diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
index 7546b66..7409705 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
@@ -436,6 +436,126 @@ static ssize_t xi2c_reg_value_write(struct file *filp,
 	.write = xi2c_reg_value_write,
 };
 
+static ssize_t sfp_eeprom_read(struct file *filp, char __user *buffer,
+			       size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+	struct xgbe_phy_impl_if *phy_impl;
+	unsigned char *eeprom;
+	ssize_t len;
+
+	phy_impl = &pdata->phy_if.phy_impl;
+	eeprom = phy_impl->sfp_eeprom(pdata);
+	if (!eeprom)
+		return 0;
+
+	len = simple_read_from_buffer(buffer, count, ppos,
+				      eeprom, strlen(eeprom));
+
+	kfree(eeprom);
+
+	return len;
+}
+
+static const struct file_operations sfp_eeprom_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = sfp_eeprom_read,
+};
+
+static ssize_t phydev_mmd_read(struct file *filp, char __user *buffer,
+			       size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+
+	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_phydev_mmd);
+}
+
+static ssize_t phydev_mmd_write(struct file *filp, const char __user *buffer,
+				size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+
+	return xgbe_common_write(buffer, count, ppos,
+				 &pdata->debugfs_phydev_mmd);
+}
+
+static ssize_t phydev_reg_addr_read(struct file *filp, char __user *buffer,
+				    size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+
+	return xgbe_common_read(buffer, count, ppos, pdata->debugfs_phydev_reg);
+}
+
+static ssize_t phydev_reg_addr_write(struct file *filp,
+				     const char __user *buffer,
+				     size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+
+	return xgbe_common_write(buffer, count, ppos,
+				 &pdata->debugfs_phydev_reg);
+}
+
+static ssize_t phydev_reg_value_read(struct file *filp, char __user *buffer,
+				     size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+	struct xgbe_phy_impl_if *phy_impl;
+	unsigned int value;
+
+	phy_impl = &pdata->phy_if.phy_impl;
+	value = phy_impl->phydev_read(pdata,
+				      pdata->debugfs_phydev_mmd,
+				      pdata->debugfs_phydev_reg);
+
+	return xgbe_common_read(buffer, count, ppos, value);
+}
+
+static ssize_t phydev_reg_value_write(struct file *filp,
+				      const char __user *buffer,
+				      size_t count, loff_t *ppos)
+{
+	struct xgbe_prv_data *pdata = filp->private_data;
+	struct xgbe_phy_impl_if *phy_impl;
+	unsigned int value;
+	ssize_t len;
+
+	len = xgbe_common_write(buffer, count, ppos, &value);
+	if (len < 0)
+		return len;
+
+	phy_impl = &pdata->phy_if.phy_impl;
+	phy_impl->phydev_write(pdata,
+			       pdata->debugfs_phydev_mmd,
+			       pdata->debugfs_phydev_reg,
+			       value);
+
+	return len;
+}
+
+static const struct file_operations phydev_mmd_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = phydev_mmd_read,
+	.write = phydev_mmd_write,
+};
+
+static const struct file_operations phydev_reg_addr_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = phydev_reg_addr_read,
+	.write = phydev_reg_addr_write,
+};
+
+static const struct file_operations phydev_reg_value_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.read = phydev_reg_value_read,
+	.write = phydev_reg_value_write,
+};
+
 void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
 {
 	struct dentry *pfile;
@@ -445,6 +565,8 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
 	pdata->debugfs_xgmac_reg = 0;
 	pdata->debugfs_xpcs_mmd = 1;
 	pdata->debugfs_xpcs_reg = 0;
+	pdata->debugfs_phydev_mmd = 1;
+	pdata->debugfs_phydev_reg = 0;
 
 	buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
 	if (!buf)
@@ -519,6 +641,35 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
 				   "debugfs_create_file failed\n");
 	}
 
+	if (pdata->phy_if.phy_impl.sfp_eeprom) {
+		pfile = debugfs_create_file("sfp_eeprom", 0400,
+					    pdata->xgbe_debugfs, pdata,
+					    &sfp_eeprom_fops);
+		if (!pfile)
+			netdev_err(pdata->netdev, "debugfs_create_file failed\n");
+	}
+
+	if (pdata->phy_if.phy_impl.phydev_read &&
+	    pdata->phy_if.phy_impl.phydev_write) {
+		pfile = debugfs_create_file("phydev_mmd", 0600,
+					    pdata->xgbe_debugfs, pdata,
+					    &phydev_mmd_fops);
+		if (!pfile)
+			netdev_err(pdata->netdev, "debugfs_create_file failed\n");
+
+		pfile = debugfs_create_file("phydev_register", 0600,
+					    pdata->xgbe_debugfs, pdata,
+					    &phydev_reg_addr_fops);
+		if (!pfile)
+			netdev_err(pdata->netdev, "debugfs_create_file failed\n");
+
+		pfile = debugfs_create_file("phydev_register_value", 0600,
+					    pdata->xgbe_debugfs, pdata,
+					    &phydev_reg_value_fops);
+		if (!pfile)
+			netdev_err(pdata->netdev, "debugfs_create_file failed\n");
+	}
+
 	kfree(buf);
 }
 
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
index 81c45fa..4463487 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c
@@ -258,6 +258,8 @@ struct xgbe_sfp_eeprom {
 	u8 vendor[32];
 };
 
+#define XGBE_SFP_EEPROM_LINE			16
+
 #define XGBE_BEL_FUSE_VENDOR	"BEL-FUSE        "
 #define XGBE_BEL_FUSE_PARTNO	"1GBT-SFP06      "
 
@@ -1275,6 +1277,79 @@ static void xgbe_phy_sfp_detect(struct xgbe_prv_data *pdata)
 	xgbe_phy_put_comm_ownership(pdata);
 }
 
+static int xgbe_phy_phydev_write(struct xgbe_prv_data *pdata, unsigned int mmd,
+				 unsigned int reg, unsigned int val)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+	unsigned int ret;
+
+	if (!phy_data->phydev)
+		return -ENOTSUPP;
+
+	if (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45)
+		reg = MII_ADDR_C45 | (mmd << 16) | (reg & 0xffff);
+
+	ret = xgbe_phy_mii_write(phy_data->mii, phy_data->mdio_addr, reg, val);
+
+	return ret;
+}
+
+static int xgbe_phy_phydev_read(struct xgbe_prv_data *pdata, unsigned int mmd,
+				unsigned int reg)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+	unsigned int ret;
+
+	if (!phy_data->phydev)
+		return -ENOTSUPP;
+
+	if (phy_data->phydev_mode == XGBE_MDIO_MODE_CL45)
+		reg = MII_ADDR_C45 | (mmd << 16) | (reg & 0xffff);
+
+	ret = xgbe_phy_mii_read(phy_data->mii, phy_data->mdio_addr, reg);
+
+	return ret;
+}
+
+static unsigned char *xgbe_phy_sfp_eeprom(struct xgbe_prv_data *pdata)
+{
+	struct xgbe_phy_data *phy_data = pdata->phy_data;
+	unsigned char *eeprom, *eeprom_end;
+	char *buffer, *cur;
+	size_t size;
+
+	/* Calculate the buffer needed for hex_dump_to_buffer()
+	 * assuming XGBE_SFP_EEPROM_LINE bytes per line and ASCII data:
+	 *   sizeof(struct xgbe_sfp_eeprom) * 3  for the hex output
+	 *   sizeof(struct xgbe_sfp_eeprom)      for the ASCII output
+	 *   sizeof(struct xgbe_sfp_eeprom)
+	 *       / XGBE_SFP_EEPROM_LINE * 4      for extra spaces and newlines
+	 */
+	size = (sizeof(struct xgbe_sfp_eeprom) * 4) +
+	       (sizeof(struct xgbe_sfp_eeprom) / XGBE_SFP_EEPROM_LINE * 4);
+	buffer = kzalloc(size, GFP_ATOMIC);
+	if (!buffer)
+		return NULL;
+
+	cur = buffer;
+	eeprom = (unsigned char *)&phy_data->sfp_eeprom;
+	eeprom_end = eeprom + sizeof(struct xgbe_sfp_eeprom);
+	for (; eeprom < eeprom_end; eeprom += XGBE_SFP_EEPROM_LINE) {
+		hex_dump_to_buffer(eeprom, XGBE_SFP_EEPROM_LINE,
+				   XGBE_SFP_EEPROM_LINE, 1, cur, size, true);
+
+		/* Reduce size by new string length (including newline) */
+		size -= strlen(cur);
+		size--;
+
+		/* Adjust buffer and add a new line */
+		cur += strlen(cur);
+		*cur++ = '\n';
+	}
+
+	return buffer;
+}
+
 static void xgbe_phy_phydev_flowctrl(struct xgbe_prv_data *pdata)
 {
 	struct xgbe_phy_data *phy_data = pdata->phy_data;
@@ -2744,6 +2819,7 @@ static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
 
 static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 {
+	struct xgbe_phy_impl_if *phy_impl = &pdata->phy_if.phy_impl;
 	struct xgbe_phy_data *phy_data;
 	struct mii_bus *mii;
 	unsigned int reg;
@@ -2869,6 +2945,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 		}
 
 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
+		phy_impl->phydev_read = xgbe_phy_phydev_read;
+		phy_impl->phydev_write = xgbe_phy_phydev_write;
 		break;
 
 	/* MDIO Base-X support */
@@ -2880,6 +2958,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 		phy_data->start_mode = XGBE_MODE_X;
 
 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
+		phy_impl->phydev_read = xgbe_phy_phydev_read;
+		phy_impl->phydev_write = xgbe_phy_phydev_write;
 		break;
 
 	/* MDIO NBase-T support */
@@ -2901,6 +2981,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 		}
 
 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL45;
+		phy_impl->phydev_read = xgbe_phy_phydev_read;
+		phy_impl->phydev_write = xgbe_phy_phydev_write;
 		break;
 
 	/* 10GBase-T support */
@@ -2922,6 +3004,8 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 		}
 
 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL45;
+		phy_impl->phydev_read = xgbe_phy_phydev_read;
+		phy_impl->phydev_write = xgbe_phy_phydev_write;
 		break;
 
 	/* 10GBase-R support */
@@ -2957,8 +3041,11 @@ static int xgbe_phy_init(struct xgbe_prv_data *pdata)
 		}
 
 		phy_data->phydev_mode = XGBE_MDIO_MODE_CL22;
+		phy_impl->phydev_read = xgbe_phy_phydev_read;
+		phy_impl->phydev_write = xgbe_phy_phydev_write;
 
 		xgbe_phy_sfp_setup(pdata);
+		phy_impl->sfp_eeprom = xgbe_phy_sfp_eeprom;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index e9282c9..8a3fb9d 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -776,6 +776,7 @@ struct xgbe_hw_if {
  * implementation of a PHY. All routines are required unless noted below.
  *   Optional routines:
  *     kr_training_pre, kr_training_post
+ *     eeprom_data, phydev_read, phydev_write
  */
 struct xgbe_phy_impl_if {
 	/* Perform Setup/teardown actions */
@@ -819,6 +820,14 @@ struct xgbe_phy_impl_if {
 	/* Pre/Post KR training enablement support */
 	void (*kr_training_pre)(struct xgbe_prv_data *);
 	void (*kr_training_post)(struct xgbe_prv_data *);
+
+	/* Return the eeprom data for an SFP */
+	unsigned char *(*sfp_eeprom)(struct xgbe_prv_data *);
+
+	/* Read the register of an attached PHY device */
+	int (*phydev_read)(struct xgbe_prv_data *, unsigned int, unsigned int);
+	int (*phydev_write)(struct xgbe_prv_data *, unsigned int, unsigned int,
+			    unsigned int);
 };
 
 struct xgbe_phy_if {
@@ -1183,6 +1192,9 @@ struct xgbe_prv_data {
 	unsigned int debugfs_xprop_reg;
 
 	unsigned int debugfs_xi2c_reg;
+
+	unsigned int debugfs_phydev_mmd;
+	unsigned int debugfs_phydev_reg;
 #endif
 };
 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ