mbox series

[net-next,v3,0/6] MCTP I2C driver

Message ID 20211115024926.205385-1-matt@codeconstruct.com.au (mailing list archive)
Headers show
Series MCTP I2C driver | expand

Message

Matt Johnston Nov. 15, 2021, 2:49 a.m. UTC
Hi,

This patch series adds a netdev driver providing MCTP transport over
I2C. 

It applies against net-next using recent MCTP changes there, though also
has I2C core changes for review. I'll leave it to maintainers where it
should be applied - please let me know if it needs to be submitted
differently.

The I2C patches were previously sent as RFC though the only feedback
there was an ack to 255 bytes for aspeed.

The dt-bindings patch went through review on the list.

Cheers,
Matt

--
v3:
 - Added Reviewed-bys for npcm7xx
 - Resend with net-next open
v2:
 - Simpler Kconfig condition for i2c-mux dependency, from Randy Dunlap

Matt Johnston (6):
  i2c: core: Allow 255 byte transfers for SMBus 3.x
  i2c: dev: Handle 255 byte blocks for i2c ioctl
  i2c: aspeed: Allow 255 byte block transfers
  i2c: npcm7xx: Allow 255 byte block SMBus transfers
  dt-bindings: net: New binding mctp-i2c-controller
  mctp i2c: MCTP I2C binding driver

 Documentation/devicetree/bindings/i2c/i2c.txt |   4 +
 .../bindings/net/mctp-i2c-controller.yaml     |  92 ++
 drivers/i2c/busses/i2c-aspeed.c               |   5 +-
 drivers/i2c/busses/i2c-npcm7xx.c              |   3 +-
 drivers/i2c/i2c-core-smbus.c                  |  20 +-
 drivers/i2c/i2c-dev.c                         |  93 +-
 drivers/net/mctp/Kconfig                      |  12 +
 drivers/net/mctp/Makefile                     |   1 +
 drivers/net/mctp/mctp-i2c.c                   | 982 ++++++++++++++++++
 include/linux/i2c.h                           |  13 +
 include/uapi/linux/i2c-dev.h                  |   2 +
 include/uapi/linux/i2c.h                      |   7 +-
 12 files changed, 1209 insertions(+), 25 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/mctp-i2c-controller.yaml
 create mode 100644 drivers/net/mctp/mctp-i2c.c

Comments

patchwork-bot+netdevbpf@kernel.org Nov. 15, 2021, 2:20 p.m. UTC | #1
Hello:

This series was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:

On Mon, 15 Nov 2021 10:49:20 +0800 you wrote:
> Hi,
> 
> This patch series adds a netdev driver providing MCTP transport over
> I2C.
> 
> It applies against net-next using recent MCTP changes there, though also
> has I2C core changes for review. I'll leave it to maintainers where it
> should be applied - please let me know if it needs to be submitted
> differently.
> 
> [...]

Here is the summary with links:
  - [net-next,v3,1/6] i2c: core: Allow 255 byte transfers for SMBus 3.x
    https://git.kernel.org/netdev/net-next/c/13cae4a104d2
  - [net-next,v3,2/6] i2c: dev: Handle 255 byte blocks for i2c ioctl
    https://git.kernel.org/netdev/net-next/c/84a107e68b34
  - [net-next,v3,3/6] i2c: aspeed: Allow 255 byte block transfers
    https://git.kernel.org/netdev/net-next/c/1b2ba1f591c9
  - [net-next,v3,4/6] i2c: npcm7xx: Allow 255 byte block SMBus transfers
    https://git.kernel.org/netdev/net-next/c/3ef2de27a05a
  - [net-next,v3,5/6] dt-bindings: net: New binding mctp-i2c-controller
    https://git.kernel.org/netdev/net-next/c/0b6141eb2b14
  - [net-next,v3,6/6] mctp i2c: MCTP I2C binding driver
    https://git.kernel.org/netdev/net-next/c/80be9b2c0d93

You are awesome, thank you!
Wolfram Sang Nov. 15, 2021, 3:30 p.m. UTC | #2
> This series was applied to netdev/net-next.git (master)
> by David S. Miller <davem@davemloft.net>:

NACK. Please revert. Besides the driver in net, it modifies the I2C core
code. This has not been acked by the I2C maintainer (in this case me).
So, please don't pull this in via the net tree. The question raised here
(extending SMBus calls to 255 byte) is complicated because we need ABI
backwards compatibility.
Jakub Kicinski Nov. 15, 2021, 4:08 p.m. UTC | #3
On Mon, 15 Nov 2021 16:30:39 +0100 Wolfram Sang wrote:
> > This series was applied to netdev/net-next.git (master)
> > by David S. Miller <davem@davemloft.net>:  
> 
> NACK. Please revert. Besides the driver in net, it modifies the I2C core
> code. This has not been acked by the I2C maintainer (in this case me).
> So, please don't pull this in via the net tree. The question raised here
> (extending SMBus calls to 255 byte) is complicated because we need ABI
> backwards compatibility.

Done, sorry: 2f6a470d6545 ("Revert "Merge branch 'mctp-i2c-driver'"")
Wolfram Sang Nov. 15, 2021, 4:11 p.m. UTC | #4
> Done, sorry: 2f6a470d6545 ("Revert "Merge branch 'mctp-i2c-driver'"")

No worries. Thanks for the quick fix!
Matt Johnston Nov. 24, 2021, 3:15 a.m. UTC | #5
Hi Wolfram,

> (extending SMBus calls to 255 byte) is complicated because we need ABI
> backwards compatibility.

Is it only the i2c-dev ABI that you are concerned about?

I've tested various edge cases of the I2C dev interface, the only ABI
change seen is that I2C_RDWR ioctl will now read larger messages with
I2C_M_RECV_LEN if userspace provides a larger buffer. I think that is a
reasonable change. The i2ctransfer tool provides a 256 byte buffer
already.

The attached driver patch creates an artifical I2C bus for testing, with
fixed I2C endpoints 0x30 (for block reads) and 0x40 (for block writes).
This was written just to test this case, though could be committed if
you think it's more useful generally.

The script below runs through the edge cases around 32 bytes, with
either 32 or 255 blockmax on two separate i2c-testbus adapters. The
patch applies on top of the 255 byte patch series. The script behaviour
is the same applied on a clean tree (after fixing up 'V3' code), apart
from the final test as expected.

Cheers,
Matt


#!/bin/sh

# Tests for edge cases around 32 byte block size handling in i2c dev
# Matt Johnston <matt@codeconstruct.com.au> 2021

# Two i2c-testbus adapter numbers.
# Bus 15 has v2-only set on i2c-testbus devicetree node, 32 block max
V2_BUS=15
# Bus 14 accepts 255 block max
V3_BUS=14

EXPECT_FAIL="exit 3"
FAIL="exit 2"

# Behaviour of 32 byte (V2) and 255 byte (V3) busses is the same for most operations
for b in $V2_BUS $V3_BUS; do

echo "Testing bus $b"

############

echo "Testing 31 byte read"
i2cget -y $b 0x30 31 s || $FAIL
echo "Testing 32 byte read"
i2cget -y $b 0x30 32 s || $FAIL

echo "Testing 33 byte read, should fail"
i2cget -y $b 0x30 33 s && $EXPECT_FAIL

echo "Testing 35 byte i2c read, should succeed"
i2cget -y $b 0x30 35 i || $FAIL

echo "Testing 32 byte i2c set length"
i2cset -y $b 0x30 32 || $FAIL
echo "Testing 32 byte i2c read, should succeed"
i2ctransfer -y $b 'r?@0x30' || $FAIL

############

echo "Testing 31 byte smbus write"
i2cset -y $b 0x40 0x0f 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 s || $FAIL
wl=$(i2cget -y $b 0x40)
echo "check length ($wl) is 33==0x21"
[ $wl = 0x21 ] || $FAIL

echo "Testing 32 byte smbus write"
i2cset -y $b 0x40 0x0f 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 s || $FAIL
wl=$(i2cget -y $b 0x40)
echo "Check length ($wl) is 34==0x22"
[ $wl = 0x22 ] || $FAIL

echo "Testing 33 byte smbus write (fails)"
i2cset -y $b 0x40 0x0f 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 0x77 s && $EXPECT_FAIL

echo "Testing 70 byte i2c write"
i2ctransfer -y $b w70@0x40 123- || $FAIL
wl=$(i2cget -y $b 0x40)
echo "Check length ($wl) is 70==0x46"
[ $wl = 0x46 ] || $FAIL

echo "Done testing bus $b"

done

########## Behaviour V2 vs V3 differs with tests below

echo "Testing difference of V2 bus $V2_BUS"
b=$V2_BUS

echo "Testing 44 byte read set-length (succeeds with a warning of further failure)"
i2cset -y $b 0x30 44 || $FAIL
# i2c-testbus checks size against I2C_SMBUS_BLOCK_MAX in the v2-only case.
# This is similar to the I2C_SMBUS_BLOCK_MAX vs I2C_SMBUS_V3_BLOCK_MAX
# checks changed in i2c-npcm7xx and i2c-aspeed
echo "Testing 44 byte i2c read, fails"
i2ctransfer -y $b 'r?@0x30' && $EXPECT_FAIL

echo "Done with difference of V2 bus $V2_BUS"

############

echo "Testing difference of V3 bus $V3_BUS"
b=$V3_BUS

echo "Testing 44 byte read set-length"
i2cset -y $b 0x30 44 || $FAIL
echo "Testing 44 byte i2c read, succeeds. (failed prior to 255 byte patch)"
i2ctransfer -y $b 'r?@0x30' || $FAIL

echo "Done with difference of V3 bus $V3_BUS"

############

echo
echo "All tests completed as expected"

--
Subject: [PATCH] i2c testbus: Add an I2C bus for testing

The bus provides fixed endpoints to be used for testing i2c-dev or
drivers, without needing real hardware. In particular these can test
block size limitations.

Devicetree property "v2-only" will limit the bus to 32 byte
SMBus messages, otherwise it supports 255 byte SMBus v3 message.

Examples have i2c-testbus attached as bus number 14:

Address 0x30 provides an endpoint to test block reads

    i2cget -y 14 0x30 31 s

will read 31 bytes as an smbus read. >32 bytes will fail.

    i2cset -y 14 0x30 200
    i2ctransfer -y 14 r?@0x30

will read 200 bytes as an I2C read.

Address 0x40 is an endpoint to test block writes. The number of bytes
written can be read back from the endpoint.

i2cset -y 14 0x40 0x32 0x12 0x13 s

i2ctransfer -y 14 w30@0x40 0xff 0x19-

Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
---
 drivers/i2c/busses/Kconfig       |   9 ++
 drivers/i2c/busses/Makefile      |   1 +
 drivers/i2c/busses/i2c-testbus.c | 252 +++++++++++++++++++++++++++++++
 3 files changed, 262 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-testbus.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index dce392839017..238d48b42d93 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -1418,4 +1418,13 @@ config I2C_VIRTIO
           This driver can also be built as a module. If so, the module
           will be called i2c-virtio.
 
+config I2C_TESTBUS
+        tristate "Testing I2C Bus Adapter"
+        help
+          Build a driver for testing I2C functionality. The bus provides
+          various clients at fixed addresses with different functionality.
+
+          This driver can also be built as a module. If so, the module
+          will be called i2c-testbus.
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index d85899fef8c7..e67773637f01 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -149,5 +149,6 @@ obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_FSI)		+= i2c-fsi.o
 obj-$(CONFIG_I2C_VIRTIO)	+= i2c-virtio.o
+obj-$(CONFIG_I2C_TESTBUS)	+= i2c-testbus.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-testbus.c b/drivers/i2c/busses/i2c-testbus.c
new file mode 100644
index 000000000000..e04c9e96c9bc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-testbus.c
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Testing I2C adapter.
+ * Copyright (c) 2021 Code Construct
+ *
+ * Presents artificial I2C client endpoints for testing I2C core/dev
+ * functionality, in particular block transfer sizes.
+ *
+ *
+ * Should be instantiated in devicetree, with an optional v2-only
+ * property to limit to 32 byte block transfers.
+
+	testi2c1 {
+		compatible = "testing-i2c-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		// optional limit to 32 byte blocks
+		v2-only;
+	};
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+struct testing_i2c_bus {
+	struct i2c_adapter		adap;
+	struct device			*dev;
+	spinlock_t			lock;
+
+	// Don't advertise I2C_FUNC_SMBUS_V3_BLOCK functionality
+	bool v2_only;
+
+	int client_30_len;
+	u8 client_30_val;
+
+	int client_40_len;
+};
+
+static int bus_block_max(struct testing_i2c_bus *bus)
+{
+	return bus->v2_only ? I2C_SMBUS_BLOCK_MAX : I2C_SMBUS_V3_BLOCK_MAX;
+}
+
+/*
+ * 0x30 is a 'read block' i2c endpoint.
+ * A single byte can be written to the "client", indicating the length
+ * of subsequent block reads.
+ */
+int handle_xfer_30(struct testing_i2c_bus *bus, struct i2c_msg *msg)
+{
+	int len, index, i;
+	int block_max = bus_block_max(bus);
+
+	if (msg->flags & I2C_M_RD) {
+		// Read
+		if (msg->flags & I2C_M_RECV_LEN) {
+			// sanity check, should already be limited by Write path below
+			if (bus->client_30_len > block_max) {
+				dev_warn(bus->dev,
+					"%s: addr 0x30 read length %d too large, -EPROTO",
+					__func__, bus->client_30_len);
+				return -EPROTO;
+			}
+			len = bus->client_30_len;
+			msg->buf[0] = len;
+			index = 1;
+			msg->len = len+1;
+		} else {
+			len = msg->len;
+			index = 0;
+		}
+		dev_dbg(bus->dev, "%s read len %d\n", __func__, len);
+		// Fill the buffer with something arbitrary
+		for (i = 0; i < len; i++) {
+			msg->buf[index + i] = bus->client_30_val;
+			(bus->client_30_val)++;
+		}
+	} else {
+		// Write
+		if (msg->len != 1) {
+			dev_warn(bus->dev, "%s: Bad write length to 0x30, must be 1\n",
+				__func__);
+			return -EIO;
+		}
+		len = msg->buf[0];
+		if (len > block_max) {
+			dev_warn(bus->dev,
+				"%s: addr 0x30 read length was set to %d which is > %d (BLOCK_MAX). smbus reads will fail.",
+				__func__, len, block_max);
+		}
+		dev_dbg(bus->dev, "%s write set len %d\n", __func__, len);
+		bus->client_30_len = len;
+	}
+	return 0;
+}
+
+/*
+ * 0x40 is a 'write block' i2c endpoint.
+ * After a block write, the block length can be read back.
+ */
+int handle_xfer_40(struct testing_i2c_bus *bus, struct i2c_msg *msg)
+{
+	int index;
+
+	if (msg->flags & I2C_M_RD) {
+		// Read
+		index = 0;
+		if (msg->flags & I2C_M_RECV_LEN) {
+			// limit to valid API buffer lengths
+			msg->buf[0] = 1;
+			index = 1;
+			msg->len = 2;
+		} else if (msg->len != 1) {
+			dev_warn(bus->dev, "%s bad read len to 0x40, must be 1\n",
+				__func__);
+			return -EIO;
+		}
+		// return the byte count previously written
+		msg->buf[index] = bus->client_40_len;
+	} else {
+		// Write
+		bus->client_40_len = msg->len;
+		dev_dbg(bus->dev, "%s wrote %d bytes: %*ph\n",
+			__func__, bus->client_40_len,
+			msg->len, msg->buf);
+	}
+	return 0;
+}
+static int testing_i2c_master_xfer(struct i2c_adapter *adap,
+				  struct i2c_msg *msgs, int num)
+{
+	struct testing_i2c_bus *bus = i2c_get_adapdata(adap);
+	int i, rc = 0;
+
+	for (i = 0; i < num; i++) {
+		struct i2c_msg *msg = &msgs[i];
+
+		switch (msg->addr) {
+		case 0x30:
+			rc = handle_xfer_30(bus, msg);
+			break;
+		case 0x40:
+			rc = handle_xfer_40(bus, msg);
+			break;
+		default:
+			// unused address
+			rc = -ENXIO;
+		}
+
+		if (rc) {
+			dev_warn(bus->dev, "%s return err %d\n", __func__, rc);
+			return rc;
+		}
+	}
+
+	return num;
+}
+
+static u32 testing_i2c_functionality(struct i2c_adapter *adap)
+{
+	struct testing_i2c_bus *bus = i2c_get_adapdata(adap);
+	int func = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+		I2C_FUNC_SMBUS_BLOCK_DATA;
+
+	if (!bus->v2_only)
+		func |= I2C_FUNC_SMBUS_V3_BLOCK;
+	return func;
+}
+
+static const struct i2c_algorithm testing_i2c_algo = {
+	.master_xfer	= testing_i2c_master_xfer,
+	.functionality	= testing_i2c_functionality,
+};
+
+static const struct of_device_id testing_i2c_bus_of_table[] = {
+	{
+		.compatible = "testing-i2c-bus",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, testing_i2c_bus_of_table);
+
+static int testing_i2c_probe_bus(struct platform_device *pdev)
+{
+	struct testing_i2c_bus *bus;
+	int ret;
+
+	bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* Initialize the I2C adapter */
+	spin_lock_init(&bus->lock);
+	bus->adap.owner = THIS_MODULE;
+	bus->adap.retries = 0;
+	bus->adap.algo = &testing_i2c_algo;
+	bus->adap.dev.parent = &pdev->dev;
+	bus->adap.dev.of_node = pdev->dev.of_node;
+	strscpy(bus->adap.name, pdev->name, sizeof(bus->adap.name));
+	i2c_set_adapdata(&bus->adap, bus);
+	bus->dev = &pdev->dev;
+	bus->v2_only = of_property_read_bool(pdev->dev.of_node, "v2-only");
+
+	ret = i2c_add_adapter(&bus->adap);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, bus);
+
+	dev_info(bus->dev, "testing i2c bus %d registered. max block %d bytes.\n",
+		 bus->adap.nr, bus_block_max(bus));
+
+	return 0;
+}
+
+static int testing_i2c_remove_bus(struct platform_device *pdev)
+{
+	struct testing_i2c_bus *bus = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&bus->adap);
+
+	return 0;
+}
+
+static struct platform_driver testing_i2c_bus_driver = {
+	.probe		= testing_i2c_probe_bus,
+	.remove		= testing_i2c_remove_bus,
+	.driver		= {
+		.name		= "testing-i2c-bus",
+		.of_match_table	= testing_i2c_bus_of_table,
+	},
+};
+module_platform_driver(testing_i2c_bus_driver);
+
Wolfram Sang Nov. 29, 2021, 7:34 p.m. UTC | #6
Hi Matt,

sorry for the long delay. This cycle, I am concentrating on overhauling the
bus_recovery handling. I am rather unsure if I have the bandwidth for
larger block reads this cycle. But it is planned for next cycle.

> > (extending SMBus calls to 255 byte) is complicated because we need ABI
> > backwards compatibility.
> 
> Is it only the i2c-dev ABI that you are concerned about?

To at least give you a pointer what we discussed last time, have a look
here:

https://lore.kernel.org/r/20200728004708.4430-1-daniel.stodden@gmail.com

I can't go into details now because they escaped my mind :/ But I'll
work into it again when the bus_recovery thing is done and the recent
driver patches are handled. But you probably will get the idea without
me...

Thanks for sharing your script and working on the issue.

Happy hacking,

   Wolfram