Files

203 lines
5.3 KiB
Diff
Raw Permalink Normal View History

diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c
index f450250fc..f0205e58a 100644
--- a/drivers/net/ethernet/intel/ice/ice_debugfs.c
+++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c
@@ -2,10 +2,187 @@
/* Copyright (c) 2022, Intel Corporation. */
#include <linux/debugfs.h>
+#include <linux/uaccess.h>
#include "ice.h"
static struct dentry *ice_debugfs_root;
+#define ICE_SFF_I2C_MAX_DATA 16
+
+struct ice_sff_i2c_ctx {
+ struct ice_pf *pf;
+ char resp[ICE_SFF_I2C_MAX_DATA * 3 + 32];
+ size_t resp_len;
+};
+
+static int ice_sff_i2c_open(struct inode *inode, struct file *filp)
+{
+ struct ice_sff_i2c_ctx *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->pf = inode->i_private;
+ filp->private_data = ctx;
+
+ return 0;
+}
+
+static int ice_sff_i2c_release(struct inode *inode, struct file *filp)
+{
+ kfree(filp->private_data);
+
+ return 0;
+}
+
+static ssize_t ice_sff_i2c_write(struct file *filp, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_sff_i2c_ctx *ctx = filp->private_data;
+ struct ice_hw *hw = &ctx->pf->hw;
+ u8 data[ICE_SFF_I2C_MAX_DATA] = {};
+ u8 bus, off, arg;
+ char cmd[64];
+ char op;
+ int ret;
+
+ if (!count || count >= sizeof(cmd))
+ return -EINVAL;
+ if (copy_from_user(cmd, ubuf, count))
+ return -EFAULT;
+ cmd[count] = '\0';
+
+ switch (cmd[0]) {
+ case 'r':
+ if (sscanf(cmd, "%c %hhx %hhx %hhx", &op, &bus, &off, &arg) != 4)
+ return -EINVAL;
+ if (arg < 1 || arg > ICE_SFF_I2C_MAX_DATA)
+ return -EINVAL;
+ ret = ice_aq_sff_eeprom(hw, 0, bus, off, 0, 0, data, arg,
+ false, NULL);
+ break;
+ case 'w':
+ if (sscanf(cmd, "%c %hhx %hhx %hhx", &op, &bus, &off, &arg) != 4)
+ return -EINVAL;
+ data[0] = arg;
+ ret = ice_aq_sff_eeprom(hw, 0, bus, off, 0, 0, data, 1,
+ true, NULL);
+ break;
+ case 't': {
+ struct ice_aqc_get_link_topo tcmd = {};
+ u8 part;
+ u16 handle;
+
+ if (sscanf(cmd, "%c %hhx %hhx", &op,
+ &tcmd.addr.topo_params.node_type_ctx,
+ &tcmd.addr.topo_params.index) != 3)
+ return -EINVAL;
+ ret = ice_aq_get_netlist_node(hw, &tcmd, &part, &handle);
+ if (!ret) {
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp),
+ "ok %02x %04x\n", part,
+ handle);
+ *ppos = 0;
+ return count;
+ }
+ break;
+ }
+ case 'i': case 'j': {
+ struct ice_aqc_link_topo_addr topo = {};
+ u16 bus16, addr16, handle;
+ u8 params, n;
+ int fields;
+
+ fields = sscanf(cmd,
+ "%c %hhx %hhx %hx %hx %hx %hhx %hhx %hhx %hhx %hhx",
+ &op, &topo.topo_params.node_type_ctx,
+ &topo.topo_params.index, &handle, &bus16,
+ &addr16, &params, &data[0], &data[1], &data[2],
+ &data[3]);
+ if (fields < 7)
+ return -EINVAL;
+ topo.handle = cpu_to_le16(handle);
+ n = params & ICE_AQC_I2C_DATA_SIZE_M;
+ arg = n;
+ if (op == 'i') {
+ if (fields != 7 || n < 1)
+ return -EINVAL;
+ ret = ice_aq_read_i2c(hw, topo, bus16,
+ cpu_to_le16(addr16), params,
+ data, NULL);
+ } else {
+ if (n < 1 || n > 4 || fields != 7 + n)
+ return -EINVAL;
+ ret = ice_aq_write_i2c(hw, topo, bus16,
+ cpu_to_le16(addr16), params,
+ data, NULL);
+ }
+ op = op == 'i' ? 'r' : 'w';
+ break;
+ }
+ case 'x': {
+ struct libie_aq_desc desc = {};
+ u16 opcode, flags;
+ u32 p[4] = {};
+
+ if (sscanf(cmd, "%c %hx %hx %x %x %x %x", &op, &flags, &opcode,
+ &p[0], &p[1], &p[2], &p[3]) != 7)
+ return -EINVAL;
+ desc.flags = cpu_to_le16(flags);
+ desc.opcode = cpu_to_le16(opcode);
+ desc.params.generic.param0 = cpu_to_le32(p[0]);
+ desc.params.generic.param1 = cpu_to_le32(p[1]);
+ desc.params.generic.addr_high = cpu_to_le32(p[2]);
+ desc.params.generic.addr_low = cpu_to_le32(p[3]);
+ ret = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp),
+ "%s %d aq %d wb %08x %08x %08x %08x\n",
+ ret ? "err" : "ok", ret,
+ hw->adminq.sq_last_status,
+ le32_to_cpu(desc.params.generic.param0),
+ le32_to_cpu(desc.params.generic.param1),
+ le32_to_cpu(desc.params.generic.addr_high),
+ le32_to_cpu(desc.params.generic.addr_low));
+ *ppos = 0;
+ return count;
+ }
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp),
+ "err %d aq %d\n", ret,
+ hw->adminq.sq_last_status);
+ else if (op == 'r')
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp),
+ "ok %*ph\n", (int)arg, data);
+ else
+ ctx->resp_len = scnprintf(ctx->resp, sizeof(ctx->resp), "ok\n");
+
+ *ppos = 0;
+
+ return count;
+}
+
+static ssize_t ice_sff_i2c_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_sff_i2c_ctx *ctx = filp->private_data;
+
+ return simple_read_from_buffer(ubuf, count, ppos, ctx->resp,
+ ctx->resp_len);
+}
+
+static const struct file_operations ice_sff_i2c_fops = {
+ .owner = THIS_MODULE,
+ .open = ice_sff_i2c_open,
+ .release = ice_sff_i2c_release,
+ .read = ice_sff_i2c_read,
+ .write = ice_sff_i2c_write,
+};
+
int ice_debugfs_pf_init(struct ice_pf *pf)
{
const char *name = pci_name(pf->pdev);
@@ -14,6 +191,9 @@ int ice_debugfs_pf_init(struct ice_pf *pf)
if (IS_ERR(pf->ice_debugfs_pf))
return PTR_ERR(pf->ice_debugfs_pf);
+ debugfs_create_file("sff_i2c", 0600, pf->ice_debugfs_pf, pf,
+ &ice_sff_i2c_fops);
+
return 0;
}