Skip to contentSkip to conversation

fsi: Add IBM I2C Responder virtual FSI master

PATCH Superseded Eddie James 5 participants 11 messages Jan 19, 2023 – Jan 25, 2023

Subsystems (3)

v1 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Eddie James

author maintainer
#0 lore raw

cover fsi: Add IBM I2C Responder virtual FSI master

The I2C Responder (I2CR) is an I2C device that translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master and bus.

Eddie James (2):
dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master
fsi: Add IBM I2C Responder virtual FSI master

 .../devicetree/bindings/fsi/ibm,i2cr.yaml     |  42 ++++
 drivers/fsi/Kconfig                           |   9 +
 drivers/fsi/Makefile                          |   1 +
 drivers/fsi/fsi-master-i2cr.c                 | 225 ++++++++++++++++++
 include/trace/events/fsi_master_i2cr.h        |  96 ++++++++
 5 files changed, 373 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml
 create mode 100644 drivers/fsi/fsi-master-i2cr.c
 create mode 100644 include/trace/events/fsi_master_i2cr.h
Signature · 1 line
2.31.1
author maintainer
#1 lore raw

PATCH 1/2 dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master

The I2C Responder translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master.

---
 .../devicetree/bindings/fsi/ibm,i2cr.yaml     | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +42 -0
new file mode 100644
index 000000000000..929ca10988f9
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fsi/ibm,i2cr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM I2C Responder virtual FSI master
+
+maintainers:
+  - Eddie James <[email protected]>
+
+description: |
+  This binding describes an I2C device called the I2C Responder (I2CR). The
+  I2CR translates commands sent over I2C bus to FSI CFAM reads and writes or
+  SCOM operations. The CFAM access means that the I2CR can act as an FSI
+  master.
+
+properties:
+  compatible:
+    enum:
+      - ibm,i2cr
+
+   reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+ - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      i2cr@20 {
+        compatible = "ibm,i2cr";
+        reg = <0x20>;
+      };
+    };
Signature · 1 line
2.31.1
#2 lore raw

Re: [PATCH 1/2] dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master

Quoted 34 lines · Eddie James

The I2C Responder translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master.

---
 .../devicetree/bindings/fsi/ibm,i2cr.yaml     | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +13 -0
new file mode 100644
index 000000000000..929ca10988f9
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fsi/ibm,i2cr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM I2C Responder virtual FSI master
+
+maintainers:
+  - Eddie James <[email protected]>
+
+description: |
+  This binding describes an I2C device called the I2C Responder 

(I2CR). The
+ I2CR translates commands sent over I2C bus to FSI CFAM reads and writes or
+ SCOM operations. The CFAM access means that the I2CR can act as an FSI

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 21

Quoted 6 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +6 -0
+  master.
+
+properties:
+  compatible:
+    enum:
+      - ibm,i2cr

I think this should be a bit more descriptive and at least mention that it's FSI-related, e.g. ibm,fsi-i2cr? Thoughts?

Quoted 8 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +8 -0
+
+   reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 39

Quoted 10 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +10 -0
+additionalProperties: false
+
+examples:
+ - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      i2cr@20 {
+        compatible = "ibm,i2cr";

Change this in accordance with the above.

Andrew

author maintainer
#3 lore raw

Re: [PATCH 1/2] dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master

Quoted 37 lines · Andrew Jeffery
Quoted 35 lines · Eddie James

The I2C Responder translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master.

---
  .../devicetree/bindings/fsi/ibm,i2cr.yaml     | 42 +++++++++++++++++++
  1 file changed, 42 insertions(+)

create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +13 -0
new file mode 100644
index 000000000000..929ca10988f9
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fsi/ibm,i2cr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM I2C Responder virtual FSI master
+
+maintainers:
+  - Eddie James <[email protected]>
+
+description: |
+  This binding describes an I2C device called the I2C Responder

(I2CR). The
+ I2CR translates commands sent over I2C bus to FSI CFAM reads and writes or
+ SCOM operations. The CFAM access means that the I2CR can act as an FSI
+ master.

Quoted 8 lines

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 21

Quoted 5 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +5 -0
+
+properties:
+  compatible:
+    enum:
+      - ibm,i2cr

I think this should be a bit more descriptive and at least mention that it's FSI-related, e.g. ibm,fsi-i2cr? Thoughts?

Yea that probably makes sense.

Thanks for the suggestion!

Eddie

Quoted 22 lines
Quoted 9 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +8 -0
+
+   reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 39

Quoted 10 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +10 -0
+additionalProperties: false
+
+examples:
+ - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      i2cr@20 {
+        compatible = "ibm,i2cr";

Change this in accordance with the above.

Andrew

maintainer
#4 lore raw

Re: [PATCH 1/2] dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master

In reply to Eddie James
Quoted 9 lines · Eddie James

The I2C Responder translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master.

---
 .../devicetree/bindings/fsi/ibm,i2cr.yaml     | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml:23:4: [error] syntax error: expected <block end>, but found '<block mapping start>' (syntax) ./Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml:24:5: [warning] wrong indentation: expected 5 but found 4 (indentation) ./Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml:33:2: [warning] wrong indentation: expected 2 but found 1 (indentation)

dtschema/dtc warnings/errors:
make[1]: *** Deleting file 'Documentation/devicetree/bindings/fsi/ibm,i2cr.example.dts' Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml:23:4: did not find expected key
make[1]: *** [Documentation/devicetree/bindings/Makefile:26: Documentation/devicetree/bindings/fsi/ibm,i2cr.example.dts] Error 1 make[1]: *** Waiting for unfinished jobs....
./Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml:23:4: did not find expected key /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml: ignoring, error parsing file
make: *** [Makefile:1508: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note that DT_SCHEMA_FILES can be set to your schema file to speed up checking your schema. However, it must be unset to test all examples with your schema.

#5 lore raw

Re: [PATCH 1/2] dt-bindings: fsi: Document the IBM I2C Responder virtual FSI master

In reply to Eddie James
Quoted 18 lines · Eddie James

The I2C Responder translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master.

---
 .../devicetree/bindings/fsi/ibm,i2cr.yaml     | 42 +++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +3 -0
new file mode 100644
index 000000000000..929ca10988f9
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 13

Quoted 10 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +10 -0
+$id: http://devicetree.org/schemas/fsi/ibm,i2cr.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM I2C Responder virtual FSI master
+
+maintainers:
+  - Eddie James <[email protected]>
+
+description: |
+  This binding describes an I2C device called the I2C Responder (I2CR). The

In the binding, don't write description of the binding. In the binding, write about the hardware. Rephrase it so the hardware is the subject.

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 24

Quoted 11 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +11 -0
+  I2CR translates commands sent over I2C bus to FSI CFAM reads and writes or
+  SCOM operations. The CFAM access means that the I2CR can act as an FSI
+  master.
+
+properties:
+  compatible:
+    enum:
+      - ibm,i2cr
+
+   reg:
+    maxItems: 1

Does not look like you tested the bindings. Please run make dt_binding_check (see Documentation/devicetree/bindings/writing-schema.rst for instructions).

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 34

Quoted 10 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +10 -0
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+ - |
+    i2c {

Use 4 spaces for example indentation.

Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml line 42

Quoted 8 lines
Documentation/devicetree/bindings/fsi/ibm,i2cr.yaml new file +8 -0
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      i2cr@20 {
+        compatible = "ibm,i2cr";
+        reg = <0x20>;
+      };
+    };

Best regards,
Krzysztof

author maintainer
#6 lore raw

PATCH 2/2 fsi: Add IBM I2C Responder virtual FSI master

In reply to Eddie James

The I2C Responder (I2CR) is an I2C device that translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master and bus.

---
 drivers/fsi/Kconfig                    |   9 +
 drivers/fsi/Makefile                   |   1 +
 drivers/fsi/fsi-master-i2cr.c          | 225 +++++++++++++++++++++++++
 include/trace/events/fsi_master_i2cr.h |  96 +++++++++++
 4 files changed, 331 insertions(+)
 create mode 100644 drivers/fsi/fsi-master-i2cr.c
 create mode 100644 include/trace/events/fsi_master_i2cr.h
drivers/fsi/Kconfig +9 -0
index e6668a869913..999be82720c5 100644
@@ -62,6 +62,15 @@ config FSI_MASTER_ASPEED
 
 	 Enable it for your BMC kernel in an OpenPower or IBM Power system.
 
+config FSI_MASTER_I2CR
+	tristate "IBM I2C Responder virtual FSI master"
+	depends on I2C
+	help
+	  This option enables a virtual FSI master in order to access a CFAM
+	  behind an IBM I2C Responder (I2CR) chip. The I2CR is an I2C device
+	  that translates I2C commands to CFAM or SCOM operations, effectively
+	  implementing an FSI master and bus.
+
 config FSI_SCOM
 	tristate "SCOM FSI client device driver"
 	help
drivers/fsi/Makefile +1 -0
index da218a1ad8e1..34dbaa1c452e 100644
@@ -4,6 +4,7 @@ obj-$(CONFIG_FSI) += fsi-core.o
 obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
 obj-$(CONFIG_FSI_MASTER_ASPEED) += fsi-master-aspeed.o
 obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
+obj-$(CONFIG_FSI_MASTER_I2CR) += fsi-master-i2cr.o
 obj-$(CONFIG_FSI_MASTER_AST_CF) += fsi-master-ast-cf.o
 obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
 obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o
drivers/fsi/fsi-master-i2cr.c new file +225 -0

225 lines not on this page · raw message

include/trace/events/fsi_master_i2cr.h new file +96 -0

96 lines not on this page · raw message

Signature · 1 line
2.31.1
#7 lore raw
Quoted 107 lines · Eddie James

The I2C Responder (I2CR) is an I2C device that translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master and bus.

---
 drivers/fsi/Kconfig                    |   9 +
 drivers/fsi/Makefile                   |   1 +
 drivers/fsi/fsi-master-i2cr.c          | 225 +++++++++++++++++++++++++
 include/trace/events/fsi_master_i2cr.h |  96 +++++++++++
 4 files changed, 331 insertions(+)
 create mode 100644 drivers/fsi/fsi-master-i2cr.c
 create mode 100644 include/trace/events/fsi_master_i2cr.h
drivers/fsi/Kconfig +9 -0
index e6668a869913..999be82720c5 100644
@@ -62,6 +62,15 @@ config FSI_MASTER_ASPEED
 
 	 Enable it for your BMC kernel in an OpenPower or IBM Power system.
 
+config FSI_MASTER_I2CR
+	tristate "IBM I2C Responder virtual FSI master"
+	depends on I2C
+	help
+	  This option enables a virtual FSI master in order to access a CFAM
+	  behind an IBM I2C Responder (I2CR) chip. The I2CR is an I2C device
+	  that translates I2C commands to CFAM or SCOM operations, effectively
+	  implementing an FSI master and bus.
+
 config FSI_SCOM
 	tristate "SCOM FSI client device driver"
 	help
drivers/fsi/Makefile +1 -0
index da218a1ad8e1..34dbaa1c452e 100644
@@ -4,6 +4,7 @@ obj-$(CONFIG_FSI) += fsi-core.o
 obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
 obj-$(CONFIG_FSI_MASTER_ASPEED) += fsi-master-aspeed.o
 obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
+obj-$(CONFIG_FSI_MASTER_I2CR) += fsi-master-i2cr.o
 obj-$(CONFIG_FSI_MASTER_AST_CF) += fsi-master-ast-cf.o
 obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
 obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o
drivers/fsi/fsi-master-i2cr.c new file +54 -0
new file mode 100644
index 000000000000..d19ac96c0a83
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) IBM Corporation 2023 */
+
+#include <linux/device.h>
+#include <linux/fsi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+
+#include "fsi-master.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi_master_i2cr.h>
+
+#define I2CR_ADDRESS_CFAM(a)	((a) >> 2)
+#define I2CR_STATUS		0x30001
+#define  I2CR_STATUS_ERR	 BIT_ULL(61)
+#define I2CR_ERROR		0x30002
+
+struct fsi_master_i2cr {
+	struct fsi_master master;
+	struct mutex lock;	/* protect HW access */
+	struct i2c_client *client;
+};
+
+static bool i2cr_check_parity(u32 v, bool parity)
+{
+	u32 i;
+
+	for (i = 0; i < 32; ++i) {
+		if (v & (1 << i))
+			parity = !parity;
+	}
+
+	return parity;
+}
+
+static __be32 i2cr_get_command(u32 address, bool parity)
+{
+	__be32 command;
+
+	address <<= 1;
+
+	if (i2cr_check_parity(address, parity))
+		address |= 1;
+
+	command = cpu_to_be32(address);
+	trace_i2cr_command((__force uint32_t)command);
+
+	return command;
+}
+
+static int i2cr_transfer(struct i2c_client *client, u32 address, 
Quoted 1 line

__be64 *data)

Is there a reason to use __be64 *data here and not void *data, size_t len? We never actually use it as the declared type internally, only cast it to __u8 *.

Quoted 64 lines
drivers/fsi/fsi-master-i2cr.c new file +46 -0
+{
+	struct i2c_msg msgs[2];
+	__be32 command;
+	int ret;
+
+	command = i2cr_get_command(address, true);
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(command);
+	msgs[0].buf = (__u8 *)&command;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(*data);
+	msgs[1].buf = (__u8 *)data;
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2)
+		return 0;
+
+	trace_i2cr_i2c_error(ret);
+
+	if (ret < 0)
+		return ret;
+
+	return -EIO;
+}
+
+static int i2cr_check_status(struct i2c_client *client)
+{
+	__be64 status_be = 0;
+	u64 status;
+	int ret;
+
+	ret = i2cr_transfer(client, I2CR_STATUS, &status_be);
+	if (ret)
+		return ret;
+
+	status = be64_to_cpu(status_be);
+	if (status & I2CR_STATUS_ERR) {
+		__be64 error_be = 0;
+		u64 error;
+
+		i2cr_transfer(client, I2CR_ERROR, &error_be);
+		error = be64_to_cpu(error_be);
+		trace_i2cr_status_error(status, error);
+		dev_err(&client->dev, "status:%016llx error:%016llx\n", status, 

error);

drivers/fsi/fsi-master-i2cr.c new file +8 -0
+		return -EREMOTEIO;
+	}
+
+	trace_i2cr_status(status);
+	return 0;
+}
+
+static int i2cr_read(struct fsi_master *master, int link, uint8_t id, 

uint32_t addr, void *val,

drivers/fsi/fsi-master-i2cr.c new file +3 -0
+		     size_t size)
+{
+	struct fsi_master_i2cr *i2cr = container_of(master, struct 

fsi_master_i2cr, master);

drivers/fsi/fsi-master-i2cr.c new file +4 -0
+	__be64 data = 0;
+	int ret;
+
+	if (link || id || (addr & 0xffff0000) || !size || size > 4 || size == 
Quoted 1 line

3)

These size constraints are a bit funky. Instead of !size || size > 4 || size == 3 we write !(size == 1 || size == 2 || size == 4)?

Quoted 30 lines
drivers/fsi/fsi-master-i2cr.c new file +21 -0
+		return -EINVAL;
+
+	mutex_lock(&i2cr->lock);
+
+	ret = i2cr_transfer(i2cr->client, I2CR_ADDRESS_CFAM(addr), &data);
+	if (ret)
+		goto unlock;
+
+	ret = i2cr_check_status(i2cr->client);
+	if (ret)
+		goto unlock;
+
+	trace_i2cr_read(addr, size, (__force uint32_t)data);
+	memcpy(val, &data, size);
+
+unlock:
+	mutex_unlock(&i2cr->lock);
+	return ret;
+}
+
+static int i2cr_write(struct fsi_master *master, int link, uint8_t id, 

uint32_t addr,

drivers/fsi/fsi-master-i2cr.c new file +3 -0
+		      const void *val, size_t size)
+{
+	struct fsi_master_i2cr *i2cr = container_of(master, struct 

fsi_master_i2cr, master);

drivers/fsi/fsi-master-i2cr.c new file +4 -0
+	__be32 data[3];
+	int ret;
+
+	if (link || id || (addr & 0xffff0000) || !size || size > 4 || size == 
Quoted 1 line

3)

As above

Quoted 5 lines
drivers/fsi/fsi-master-i2cr.c new file +5 -0
+		return -EINVAL;
+
+	data[1] = 0;
+	memcpy(&data[1], val, size);
+	data[0] = i2cr_get_command(I2CR_ADDRESS_CFAM(addr),

drivers/fsi/fsi-master-i2cr.c line 158

Quoted 10 lines
drivers/fsi/fsi-master-i2cr.c new file +10 -0
+				   i2cr_check_parity((__force u32)data[1], true));
+	data[2] = 0;
+
+	mutex_lock(&i2cr->lock);
+
+	ret = i2c_master_send(i2cr->client, (const char *)data, sizeof(data));
+	if (ret == sizeof(data)) {
+		ret = i2cr_check_status(i2cr->client);
+		if (!ret)
+			trace_i2cr_write(addr, size, (__force uint32_t)data[1]);

I think we can reduce the amount of __force if we flip the endianness of the data variable?

```
u32 data[3];
__be32 cmd_be;

data[1] = 0;
memcpy(&data[1], val, size);
cmd_be = i2cr_get_command(I2CR_ADDRESS_CFAM(addr),
						    i2cr_check_parity(data[1], true));
data[0] = (__force u32)cmd_be;
data[2] = 0;
....
trace_i2cr_write(addr, size, data[1]);
```

?

Or define i2cr_check_parity() and the tracepoint in terms of big-endian?

Quoted 39 lines
drivers/fsi/fsi-master-i2cr.c new file +39 -0
+	} else {
+		trace_i2cr_i2c_error(ret);
+
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	mutex_unlock(&i2cr->lock);
+	return ret;
+}
+
+static int i2cr_probe(struct i2c_client *client)
+{
+	struct fsi_master_i2cr *i2cr;
+	int ret;
+
+	i2cr = devm_kzalloc(&client->dev, sizeof(*i2cr), GFP_KERNEL);
+	if (!i2cr)
+		return -ENOMEM;
+
+	i2cr->master.dev.parent = &client->dev;
+	i2cr->master.dev.of_node = of_node_get(dev_of_node(&client->dev));
+
+	i2cr->master.n_links = 1;
+	i2cr->master.read = i2cr_read;
+	i2cr->master.write = i2cr_write;
+
+	mutex_init(&i2cr->lock);
+	i2cr->client = client;
+
+	ret = fsi_master_register(&i2cr->master);
+	if (ret)
+		return ret;
+
+	i2c_set_clientdata(client, i2cr);
+	return 0;
+}
+
+static int i2cr_remove(struct i2c_client *client)

drivers/fsi/fsi-master-i2cr.c line 207

Quoted 10 lines
drivers/fsi/fsi-master-i2cr.c new file +10 -0
+{
+	struct fsi_master_i2cr *i2cr = i2c_get_clientdata(client);
+
+	fsi_master_unregister(&i2cr->master);
+
+	return 0;
+}
+
+static const struct of_device_id i2cr_i2c_ids[] = {
+	{ .compatible = "ibm,i2cr", },

This may need an update after discussion on the binding patch.

Andrew

author maintainer
#8 lore raw
Quoted 105 lines · Andrew Jeffery
Quoted 103 lines · Eddie James

The I2C Responder (I2CR) is an I2C device that translates I2C commands to CFAM or SCOM operations, effectively implementing an FSI master and bus.

---
  drivers/fsi/Kconfig                    |   9 +
  drivers/fsi/Makefile                   |   1 +
  drivers/fsi/fsi-master-i2cr.c          | 225 +++++++++++++++++++++++++
  include/trace/events/fsi_master_i2cr.h |  96 +++++++++++
  4 files changed, 331 insertions(+)

create mode 100644 drivers/fsi/fsi-master-i2cr.c create mode 100644 include/trace/events/fsi_master_i2cr.h

drivers/fsi/Kconfig +9 -0
index e6668a869913..999be82720c5 100644
@@ -62,6 +62,15 @@ config FSI_MASTER_ASPEED
 
  	 Enable it for your BMC kernel in an OpenPower or IBM Power system.
 
+config FSI_MASTER_I2CR
+	tristate "IBM I2C Responder virtual FSI master"
+	depends on I2C
+	help
+	  This option enables a virtual FSI master in order to access a CFAM
+	  behind an IBM I2C Responder (I2CR) chip. The I2CR is an I2C device
+	  that translates I2C commands to CFAM or SCOM operations, effectively
+	  implementing an FSI master and bus.
+
  config FSI_SCOM
  	tristate "SCOM FSI client device driver"
  	help
drivers/fsi/Makefile +1 -0
index da218a1ad8e1..34dbaa1c452e 100644
@@ -4,6 +4,7 @@ obj-$(CONFIG_FSI) += fsi-core.o
  obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
  obj-$(CONFIG_FSI_MASTER_ASPEED) += fsi-master-aspeed.o
  obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
+obj-$(CONFIG_FSI_MASTER_I2CR) += fsi-master-i2cr.o
  obj-$(CONFIG_FSI_MASTER_AST_CF) += fsi-master-ast-cf.o
  obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
  obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o
drivers/fsi/fsi-master-i2cr.c new file +50 -0
new file mode 100644
index 000000000000..d19ac96c0a83
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) IBM Corporation 2023 */
+
+#include <linux/device.h>
+#include <linux/fsi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+
+#include "fsi-master.h"
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi_master_i2cr.h>
+
+#define I2CR_ADDRESS_CFAM(a)	((a) >> 2)
+#define I2CR_STATUS		0x30001
+#define  I2CR_STATUS_ERR	 BIT_ULL(61)
+#define I2CR_ERROR		0x30002
+
+struct fsi_master_i2cr {
+	struct fsi_master master;
+	struct mutex lock;	/* protect HW access */
+	struct i2c_client *client;
+};
+
+static bool i2cr_check_parity(u32 v, bool parity)
+{
+	u32 i;
+
+	for (i = 0; i < 32; ++i) {
+		if (v & (1 << i))
+			parity = !parity;
+	}
+
+	return parity;
+}
+
+static __be32 i2cr_get_command(u32 address, bool parity)
+{
+	__be32 command;
+
+	address <<= 1;
+
+	if (i2cr_check_parity(address, parity))
+		address |= 1;
+
+	command = cpu_to_be32(address);
+	trace_i2cr_command((__force uint32_t)command);
+
Quoted 8 lines
Quoted 5 lines
drivers/fsi/fsi-master-i2cr.c new file +4 -0
+	return command;
+}
+
+static int i2cr_transfer(struct i2c_client *client, u32 address,

__be64 *data)

Is there a reason to use __be64 *data here and not void *data, size_t len? We never actually use it as the declared type internally, only cast it to __u8 *.

Well, its mostly to ensure the user buffer is at least 8 bytes. We have to read 8 bytes of data, so passing in a length doesn't really make sense?

Quoted 60 lines
Quoted 60 lines
drivers/fsi/fsi-master-i2cr.c new file +46 -0
+{
+	struct i2c_msg msgs[2];
+	__be32 command;
+	int ret;
+
+	command = i2cr_get_command(address, true);
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = sizeof(command);
+	msgs[0].buf = (__u8 *)&command;
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = sizeof(*data);
+	msgs[1].buf = (__u8 *)data;
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2)
+		return 0;
+
+	trace_i2cr_i2c_error(ret);
+
+	if (ret < 0)
+		return ret;
+
+	return -EIO;
+}
+
+static int i2cr_check_status(struct i2c_client *client)
+{
+	__be64 status_be = 0;
+	u64 status;
+	int ret;
+
+	ret = i2cr_transfer(client, I2CR_STATUS, &status_be);
+	if (ret)
+		return ret;
+
+	status = be64_to_cpu(status_be);
+	if (status & I2CR_STATUS_ERR) {
+		__be64 error_be = 0;
+		u64 error;
+
+		i2cr_transfer(client, I2CR_ERROR, &error_be);
+		error = be64_to_cpu(error_be);
+		trace_i2cr_status_error(status, error);
+		dev_err(&client->dev, "status:%016llx error:%016llx\n", status,

error);

drivers/fsi/fsi-master-i2cr.c new file +8 -0
+		return -EREMOTEIO;
+	}
+
+	trace_i2cr_status(status);
+	return 0;
+}
+
+static int i2cr_read(struct fsi_master *master, int link, uint8_t id,

uint32_t addr, void *val,

drivers/fsi/fsi-master-i2cr.c new file +3 -0
+		     size_t size)
+{
+	struct fsi_master_i2cr *i2cr = container_of(master, struct
Quoted 8 lines
Quoted 6 lines

fsi_master_i2cr, master);

drivers/fsi/fsi-master-i2cr.c new file +4 -0
+	__be64 data = 0;
+	int ret;
+
+	if (link || id || (addr & 0xffff0000) || !size || size > 4 || size ==

3)

These size constraints are a bit funky. Instead of !size || size > 4 || size == 3 we write !(size == 1 || size == 2 || size == 4)?

Good idea, thanks.

Quoted 66 lines
Quoted 31 lines
drivers/fsi/fsi-master-i2cr.c new file +21 -0
+		return -EINVAL;
+
+	mutex_lock(&i2cr->lock);
+
+	ret = i2cr_transfer(i2cr->client, I2CR_ADDRESS_CFAM(addr), &data);
+	if (ret)
+		goto unlock;
+
+	ret = i2cr_check_status(i2cr->client);
+	if (ret)
+		goto unlock;
+
+	trace_i2cr_read(addr, size, (__force uint32_t)data);
+	memcpy(val, &data, size);
+
+unlock:
+	mutex_unlock(&i2cr->lock);
+	return ret;
+}
+
+static int i2cr_write(struct fsi_master *master, int link, uint8_t id,

uint32_t addr,

drivers/fsi/fsi-master-i2cr.c new file +3 -0
+		      const void *val, size_t size)
+{
+	struct fsi_master_i2cr *i2cr = container_of(master, struct

fsi_master_i2cr, master);

drivers/fsi/fsi-master-i2cr.c new file +4 -0
+	__be32 data[3];
+	int ret;
+
+	if (link || id || (addr & 0xffff0000) || !size || size > 4 || size ==
Quoted 1 line

3)

As above

Quoted 5 lines
drivers/fsi/fsi-master-i2cr.c new file +5 -0
+		return -EINVAL;
+
+	data[1] = 0;
+	memcpy(&data[1], val, size);
+	data[0] = i2cr_get_command(I2CR_ADDRESS_CFAM(addr),

drivers/fsi/fsi-master-i2cr.c line 158

Quoted 10 lines
drivers/fsi/fsi-master-i2cr.c new file +10 -0
+				   i2cr_check_parity((__force u32)data[1], true));
+	data[2] = 0;
+
+	mutex_lock(&i2cr->lock);
+
+	ret = i2c_master_send(i2cr->client, (const char *)data, sizeof(data));
+	if (ret == sizeof(data)) {
+		ret = i2cr_check_status(i2cr->client);
+		if (!ret)
+			trace_i2cr_write(addr, size, (__force uint32_t)data[1]);

I think we can reduce the amount of __force if we flip the endianness of the data variable?

```
u32 data[3];
__be32 cmd_be;

data[1] = 0;
memcpy(&data[1], val, size);
cmd_be = i2cr_get_command(I2CR_ADDRESS_CFAM(addr),
						    i2cr_check_parity(data[1], true));
data[0] = (__force u32)cmd_be;
data[2] = 0;
....
trace_i2cr_write(addr, size, data[1]);
```
Quoted 3 lines

?

Or define i2cr_check_parity() and the tracepoint in terms of big-endian?

I think I'll define a struct with the command as __be32 and the data as u32. That should clean it up.

Quoted 43 lines
Quoted 43 lines
drivers/fsi/fsi-master-i2cr.c new file +42 -0
+	} else {
+		trace_i2cr_i2c_error(ret);
+
+		if (ret >= 0)
+			ret = -EIO;
+	}
+
+	mutex_unlock(&i2cr->lock);
+	return ret;
+}
+
+static int i2cr_probe(struct i2c_client *client)
+{
+	struct fsi_master_i2cr *i2cr;
+	int ret;
+
+	i2cr = devm_kzalloc(&client->dev, sizeof(*i2cr), GFP_KERNEL);
+	if (!i2cr)
+		return -ENOMEM;
+
+	i2cr->master.dev.parent = &client->dev;
+	i2cr->master.dev.of_node = of_node_get(dev_of_node(&client->dev));
+
+	i2cr->master.n_links = 1;
+	i2cr->master.read = i2cr_read;
+	i2cr->master.write = i2cr_write;
+
+	mutex_init(&i2cr->lock);
+	i2cr->client = client;
+
+	ret = fsi_master_register(&i2cr->master);
+	if (ret)
+		return ret;
+
+	i2c_set_clientdata(client, i2cr);
+	return 0;
+}
+
+static int i2cr_remove(struct i2c_client *client)
+{
+	struct fsi_master_i2cr *i2cr = i2c_get_clientdata(client);
+
Quoted 8 lines

drivers/fsi/fsi-master-i2cr.c line 207

Quoted 7 lines
drivers/fsi/fsi-master-i2cr.c new file +7 -0
+	fsi_master_unregister(&i2cr->master);
+
+	return 0;
+}
+
+static const struct of_device_id i2cr_i2c_ids[] = {
+	{ .compatible = "ibm,i2cr", },

This may need an update after discussion on the binding patch.

Yep.

Thanks for the review!

Eddie

Quoted 2 lines

Andrew

#9 lore raw
In reply to Eddie James
I love your patch! Yet something to improve:

Hi Eddie,

I love your patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.2-rc4 next-20230120] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Eddie-James/dt-bindings-fsi-Document-the-IBM-I2C-Responder-virtual-FSI-master/20230120-014831
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20230119174714.1486042-3-eajames%40linux.ibm.com
patch subject: [PATCH 2/2] fsi: Add IBM I2C Responder virtual FSI master
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20230120/[email protected]/config)
compiler: alpha-linux-gcc (GCC) 12.1.0

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/1312ba80b81ef02457d213ee6bc6ee80739c3e01
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Eddie-James/dt-bindings-fsi-Document-the-IBM-I2C-Responder-virtual-FSI-master/20230120-014831 git checkout 1312ba80b81ef02457d213ee6bc6ee80739c3e01
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=alpha olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

>> drivers/fsi/fsi-master-i2cr.c:214:19: error: initialization of 'void (*)(struct i2c_client *)' from incompatible pointer type 'int (*)(struct i2c_client *)' [-Werror=incompatible-pointer-types]

214 | .remove = i2cr_remove,
| ^~~~~~~~~~~
drivers/fsi/fsi-master-i2cr.c:214:19: note: (near initialization for 'i2cr_driver.remove')
cc1: some warnings being treated as errors

vim +214 drivers/fsi/fsi-master-i2cr.c

211
212 static struct i2c_driver i2cr_driver = {
213 .probe_new = i2cr_probe,

 > 214		.remove = i2cr_remove,

215 .driver = {
216 .name = "i2cr",
217 .of_match_table = i2cr_i2c_ids,
218 },
219 };
220

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests
#10 lore raw
In reply to Eddie James
I love your patch! Yet something to improve:

Hi Eddie,

I love your patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on linus/master v6.2-rc4 next-20230120] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Eddie-James/dt-bindings-fsi-Document-the-IBM-I2C-Responder-virtual-FSI-master/20230120-014831
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link:    https://lore.kernel.org/r/20230119174714.1486042-3-eajames%40linux.ibm.com
patch subject: [PATCH 2/2] fsi: Add IBM I2C Responder virtual FSI master
config: arm-randconfig-c002-20230120 (https://download.01.org/0day-ci/archive/20230121/[email protected]/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 4196ca3278f78c6e19246e54ab0ecb364e37d66a)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm cross compiling tool for clang build
# apt-get install binutils-arm-linux-gnueabi
# https://github.com/intel-lab-lkp/linux/commit/1312ba80b81ef02457d213ee6bc6ee80739c3e01
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Eddie-James/dt-bindings-fsi-Document-the-IBM-I2C-Responder-virtual-FSI-master/20230120-014831 git checkout 1312ba80b81ef02457d213ee6bc6ee80739c3e01
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm olddefconfig COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/fsi/

If you fix the issue, kindly add following tag where applicable | Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

>> drivers/fsi/fsi-master-i2cr.c:214:12: error: incompatible function pointer types initializing 'void (*)(struct i2c_client *)' with an expression of type 'int (struct i2c_client *)' [-Wincompatible-function-pointer-types]

.remove = i2cr_remove,
^~~~~~~~~~~
1 error generated.

vim +214 drivers/fsi/fsi-master-i2cr.c

211
212 static struct i2c_driver i2cr_driver = {
213 .probe_new = i2cr_probe,

 > 214		.remove = i2cr_remove,

215 .driver = {
216 .name = "i2cr",
217 .of_match_table = i2cr_i2c_ids,
218 },
219 };
220

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests