Nothing lives outside the repo: the bench ixgbe driver source moves in tracked at kernel/ixgbe-sff/ (build artifacts gitignored, load-ixgbe repointed, module build verified from the new home — the reg_ops/ts_bench bench extras are finally versioned), the ice sff_i2c patch is vendored at docs/nics/e810/ice-sff-i2c.patch with its out-of-tree build recipe (TRACE_INCLUDE_PATH fixup, version-matched Makefile), the e810 NVM flash logistics land in the e810 README (exact package name, rollback -m B49691D578EC into the inactive bank, post-flash inventory failing until power cycle is the expected tell), and every ~/work/phydiag-work pointer becomes an inline statement; phydiag-work, ice-sff, e810nvm and the wiitekphy CLI (a duplicate of documented transport+protocol) are deleted
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Intel E810 (ice)
|
||||
|
||||
Out of the box. The measurement path was originally built against it — its datapath delivers per-packet MAC RX timestamps (`rx_filter=ALL`), which the committed rate design no longer needs ([../README.md](../README.md)). A patched ice + `sff_i2c` exists for read-side diagnostics work.
|
||||
Out of the box. The measurement path was originally built against it — its datapath delivers per-packet MAC RX timestamps (`rx_filter=ALL`), which the committed rate design no longer needs ([../README.md](../README.md)). The `sff_i2c` ice patch for read-side diagnostics is vendored here as [ice-sff-i2c.patch](ice-sff-i2c.patch); to run it, apply to a copy of the kernel's ice source and build out of tree (`make -C /usr/lib/modules/$(uname -r)/build M=<dir> modules`, then `rmmod irdma ice; insmod`), with two out-of-tree fixups: `ice_trace.h` needs `TRACE_INCLUDE_PATH` set to the build dir's absolute path and `TRACE_INCLUDE_FILE ice_trace`, and the Makefile's object list must match the source snapshot's kernel version.
|
||||
|
||||
## Host notes (if it returns)
|
||||
|
||||
@@ -26,8 +26,8 @@ Read-side transport details (the patched ice exists for read-side work, so these
|
||||
- No offset-less read mode exists, so the plain mdio-i2c clause-45 read phase (bcm84881-style at 0x56) cannot be formed. RollBall fits fully (≤4 B native multi-byte writes).
|
||||
- Latency is the wire-truth judge on this transport: on 3.10 firmware, silently-dropped 1-byte writes completed in ~63 µs while real wire traffic ran ~103 µs/byte (reads) and multi-ms ack-polling (writes), and `ok` returns even for writes at an empty address — protocol-level readback is the only delivery confirmation.
|
||||
|
||||
Firmware on the card: NVM 5.01 (release 31.2.2, EETRACK 0x80021FA2). The update package and logs live in `~/work/e810nvm/`; `nvmupdate64e` needs `-AllowMissingCert` on this platform (harmless — nothing boots from the NIC), writes no file backup, and rollback lives in the card's inactive flash bank (`nvmupdate64e -r -m <MAC>`).
|
||||
Firmware on the card: NVM 5.01 (release 31.2.2, EETRACK 0x80021FA2), flashed with `nvmupdate64e` 1.43.37.1a from Intel's `E810_NVMUpdatePackage_v5_01_Linux.tar.gz` (re-downloadable; nothing kept locally). Flash logistics: the tool needs `-AllowMissingCert` on this platform (the MS UEFI CA 2023 cert is absent — harmless, nothing boots from the NIC), writes no file backup even with `-b` ("Backup images created" means the card's inactive flash bank, where rollback lives: `nvmupdate64e -r -m B49691D578EC`), and the post-flash inventory fails until a power cycle activates the new bank — that failure is the expected tell, not an error.
|
||||
|
||||
## The bit-bang-below-the-AQ idea — retired with the timestamp requirement
|
||||
|
||||
The write block is at the **Admin Queue** (firmware) level — the `0x06E2/E3` topo-I2C commands are refused with EPERM. That is not the same as the module's SDA/SCL being unreachable: the 82599 reaches the module I2C **without firmware** by toggling SDA/SCL as GPIO bits in `I2CCTL` (the `~/work/ixgbe-sff/` patch bit-bangs arbitrary START…STOP from those primitives), and whether the E810 exposes an equivalent register-level / SDP-GPIO path below the AQ policy was never tested. The idea existed to marry all-packet stamps to raw I2C in one card; the smoothed-bucket rate plan ([../x520/README.md](../x520/README.md)) dissolves the stamps requirement, so the X520 covers everything and this investigation is not needed. It stays recorded as the E810's one open door if per-frame arrival times are ever wanted again — the investigation would start at the datasheet's SDP/GPIO and low-level I2C controller registers, asking whether the cage's SDA/SCL are host-addressable.
|
||||
The write block is at the **Admin Queue** (firmware) level — the `0x06E2/E3` topo-I2C commands are refused with EPERM. That is not the same as the module's SDA/SCL being unreachable: the 82599 reaches the module I2C **without firmware** by toggling SDA/SCL as GPIO bits in `I2CCTL` (the `kernel/ixgbe-sff/` bench driver bit-bangs arbitrary START…STOP from those primitives), and whether the E810 exposes an equivalent register-level / SDP-GPIO path below the AQ policy was never tested. The idea existed to marry all-packet stamps to raw I2C in one card; the smoothed-bucket rate plan ([../x520/README.md](../x520/README.md)) dissolves the stamps requirement, so the X520 covers everything and this investigation is not needed. It stays recorded as the E810's one open door if per-frame arrival times are ever wanted again — the investigation would start at the datasheet's SDP/GPIO and low-level I2C controller registers, asking whether the cage's SDA/SCL are host-addressable.
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
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, ¶ms, &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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user