All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH linux dev-5.4 v2 0/3] occ: Add support for P10
@ 2020-04-30 22:06 Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 1/3] dt-bindings: fsi: Add P10 OCC device documentation Eddie James
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Eddie James @ 2020-04-30 22:06 UTC (permalink / raw)
  To: openbmc; +Cc: joel, Eddie James

The OCC in the P10 has a number of differences from the P9. Add some logic to
handle the differences in accessing the OCC from the service processor, and
support the new temperature sensor type.

Changes since v1:
 - Add missing stuff for the new temperature sensor.

Eddie James (3):
  dt-bindings: fsi: Add P10 OCC device documentation
  fsi: occ: Add support for P10
  hwmon: (occ) Add new temperature sensor type

 .../devicetree/bindings/fsi/ibm,p9-occ.txt    |  12 +-
 drivers/fsi/fsi-occ.c                         | 126 +++++++++++++-----
 drivers/hwmon/occ/common.c                    |  75 +++++++++++
 3 files changed, 173 insertions(+), 40 deletions(-)

-- 
2.24.0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH linux dev-5.4 v2 1/3] dt-bindings: fsi: Add P10 OCC device documentation
  2020-04-30 22:06 [PATCH linux dev-5.4 v2 0/3] occ: Add support for P10 Eddie James
@ 2020-04-30 22:06 ` Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10 Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 3/3] hwmon: (occ) Add new temperature sensor type Eddie James
  2 siblings, 0 replies; 7+ messages in thread
From: Eddie James @ 2020-04-30 22:06 UTC (permalink / raw)
  To: openbmc; +Cc: joel, Eddie James

Add the P10 compatible string.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
 Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
index 99ca9862a586..e73358075a90 100644
--- a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
+++ b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
@@ -1,13 +1,13 @@
-Device-tree bindings for FSI-attached POWER9 On-Chip Controller (OCC)
----------------------------------------------------------------------
+Device-tree bindings for FSI-attached POWER9/POWER10 On-Chip Controller (OCC)
+-----------------------------------------------------------------------------
 
-This is the binding for the P9 On-Chip Controller accessed over FSI from a
-service processor. See fsi.txt for details on bindings for FSI slave and CFAM
+This is the binding for the P9 or P10 On-Chip Controller accessed over FSI from
+a service processor. See fsi.txt for details on bindings for FSI slave and CFAM
 nodes. The OCC is not an FSI slave device itself, rather it is accessed
-through the SBE fifo.
+through the SBE FIFO.
 
 Required properties:
- - compatible = "ibm,p9-occ"
+ - compatible = "ibm,p9-occ" or "ibm,p10-occ"
 
 Examples:
 
-- 
2.24.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10
  2020-04-30 22:06 [PATCH linux dev-5.4 v2 0/3] occ: Add support for P10 Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 1/3] dt-bindings: fsi: Add P10 OCC device documentation Eddie James
@ 2020-04-30 22:06 ` Eddie James
  2020-05-04  5:04   ` Andrew Jeffery
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 3/3] hwmon: (occ) Add new temperature sensor type Eddie James
  2 siblings, 1 reply; 7+ messages in thread
From: Eddie James @ 2020-04-30 22:06 UTC (permalink / raw)
  To: openbmc; +Cc: joel, Eddie James

The P10 OCC has a different SRAM address for the command and response
buffers. In addition, the SBE commands to access the SRAM have changed
format. Add versioning to the driver to handle these differences.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
 drivers/fsi/fsi-occ.c | 126 ++++++++++++++++++++++++++++++------------
 1 file changed, 92 insertions(+), 34 deletions(-)

diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
index 7da9c81759ac..942eff4032b0 100644
--- a/drivers/fsi/fsi-occ.c
+++ b/drivers/fsi/fsi-occ.c
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/fsi-occ.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -24,8 +25,13 @@
 #define OCC_CMD_DATA_BYTES	4090
 #define OCC_RESP_DATA_BYTES	4089
 
-#define OCC_SRAM_CMD_ADDR	0xFFFBE000
-#define OCC_SRAM_RSP_ADDR	0xFFFBF000
+#define OCC_P9_SRAM_CMD_ADDR	0xFFFBE000
+#define OCC_P9_SRAM_RSP_ADDR	0xFFFBF000
+
+#define OCC_P10_SRAM_CMD_ADDR	0xFFFFD000
+#define OCC_P10_SRAM_RSP_ADDR	0xFFFFE000
+
+#define OCC_P10_SRAM_MODE	0x58	/* Normal mode, OCB channel 2 */
 
 /*
  * Assume we don't have much FFDC, if we do we'll overflow and
@@ -37,11 +43,14 @@
 #define OCC_TIMEOUT_MS		1000
 #define OCC_CMD_IN_PRG_WAIT_MS	50
 
+enum versions { occ_p9, occ_p10 };
+
 struct occ {
 	struct device *dev;
 	struct device *sbefifo;
 	char name[32];
 	int idx;
+	enum versions version;
 	struct miscdevice mdev;
 	struct mutex occ_lock;
 };
@@ -235,29 +244,43 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
 	return 0;
 }
 
-static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
+static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
 {
 	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
-	size_t resp_len, resp_data_len;
-	__be32 *resp, cmd[5];
-	int rc;
+	size_t cmd_len, resp_len, resp_data_len;
+	__be32 *resp, cmd[6];
+	int idx = 0, rc;
 
 	/*
 	 * Magic sequence to do SBE getsram command. SBE will fetch data from
 	 * specified SRAM address.
 	 */
-	cmd[0] = cpu_to_be32(0x5);
+	switch (occ->version) {
+	default:
+	case occ_p9:
+		cmd_len = 5;
+		cmd[2] = cpu_to_be32(1);	/* Normal mode */
+		cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
+		break;
+	case occ_p10:
+		idx = 1;
+		cmd_len = 6;
+		cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
+		cmd[3] = 0;
+		cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
+		break;
+	}
+
+	cmd[0] = cpu_to_be32(cmd_len);
 	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
-	cmd[2] = cpu_to_be32(1);
-	cmd[3] = cpu_to_be32(address);
-	cmd[4] = cpu_to_be32(data_len);
+	cmd[4 + idx] = cpu_to_be32(data_len);
 
 	resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
 	resp = kzalloc(resp_len << 2, GFP_KERNEL);
 	if (!resp)
 		return -ENOMEM;
 
-	rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
+	rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
 	if (rc)
 		goto free;
 
@@ -287,20 +310,21 @@ static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
 	return rc;
 }
 
-static int occ_putsram(struct occ *occ, u32 address, const void *data,
-		       ssize_t len)
+static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
 {
 	size_t cmd_len, buf_len, resp_len, resp_data_len;
 	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
 	__be32 *buf;
-	int rc;
+	int idx = 0, rc;
+
+	cmd_len = (occ->version == occ_p10) ? 6 : 5;
 
 	/*
 	 * We use the same buffer for command and response, make
 	 * sure it's big enough
 	 */
 	resp_len = OCC_SBE_STATUS_WORDS;
-	cmd_len = (data_len >> 2) + 5;
+	cmd_len += data_len >> 2;
 	buf_len = max(cmd_len, resp_len);
 	buf = kzalloc(buf_len << 2, GFP_KERNEL);
 	if (!buf)
@@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data,
 	 */
 	buf[0] = cpu_to_be32(cmd_len);
 	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
-	buf[2] = cpu_to_be32(1);
-	buf[3] = cpu_to_be32(address);
-	buf[4] = cpu_to_be32(data_len);
 
-	memcpy(&buf[5], data, len);
+	switch (occ->version) {
+	default:
+	case occ_p9:
+		buf[2] = cpu_to_be32(1);	/* Normal mode */
+		buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
+		break;
+	case occ_p10:
+		idx = 1;
+		buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
+		buf[3] = 0;
+		buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
+		break;
+	}
+
+	buf[4 + idx] = cpu_to_be32(data_len);
+	memcpy(&buf[5 + idx], data, len);
 
 	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
 	if (rc)
@@ -356,21 +392,35 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data,
 static int occ_trigger_attn(struct occ *occ)
 {
 	__be32 buf[OCC_SBE_STATUS_WORDS];
-	size_t resp_len, resp_data_len;
-	int rc;
+	size_t cmd_len, resp_len, resp_data_len;
+	int idx = 0, rc;
 
-	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
+	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
 	resp_len = OCC_SBE_STATUS_WORDS;
 
-	buf[0] = cpu_to_be32(0x5 + 0x2);        /* Chip-op length in words */
+	switch (occ->version) {
+	default:
+	case occ_p9:
+		cmd_len = 7;
+		buf[2] = cpu_to_be32(3); /* Circular mode */
+		buf[3] = 0;
+		break;
+	case occ_p10:
+		idx = 1;
+		cmd_len = 8;
+		buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
+		buf[3] = 0;
+		buf[4] = 0;
+		break;
+	}
+
+	buf[0] = cpu_to_be32(cmd_len);		/* Chip-op length in words */
 	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
-	buf[2] = cpu_to_be32(0x3);              /* Mode: Circular */
-	buf[3] = cpu_to_be32(0x0);              /* Address: ignore in mode 3 */
-	buf[4] = cpu_to_be32(0x8);              /* Data length in bytes */
-	buf[5] = cpu_to_be32(0x20010000);       /* Trigger OCC attention */
-	buf[6] = 0;
+	buf[4 + idx] = cpu_to_be32(8);		/* Data length in bytes */
+	buf[5 + idx] = cpu_to_be32(0x20010000);	/* Trigger OCC attention */
+	buf[6 + idx] = 0;
 
-	rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
+	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
 	if (rc)
 		goto error;
 
@@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
 
 	/* Extract the seq_no from the command (first byte) */
 	seq_no = *(const u8 *)request;
-	rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
+	rc = occ_putsram(occ, request, req_len);
 	if (rc)
 		goto done;
 
@@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
 	/* Read occ response header */
 	start = jiffies;
 	do {
-		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
+		rc = occ_getsram(occ, 0, resp, 8);
 		if (rc)
 			goto done;
 
@@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
 	/* Grab the rest */
 	if (resp_data_length > 1) {
 		/* already got 3 bytes resp, also need 2 bytes checksum */
-		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
-				 &resp->data[3], resp_data_length - 1);
+		rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
 		if (rc)
 			goto done;
 	}
@@ -508,6 +557,7 @@ static int occ_probe(struct platform_device *pdev)
 	struct occ *occ;
 	struct platform_device *hwmon_dev;
 	struct device *dev = &pdev->dev;
+	const void *md =  of_device_get_match_data(dev);
 	struct platform_device_info hwmon_dev_info = {
 		.parent = dev,
 		.name = "occ-hwmon",
@@ -517,6 +567,7 @@ static int occ_probe(struct platform_device *pdev)
 	if (!occ)
 		return -ENOMEM;
 
+	occ->version = (enum versions)md;
 	occ->dev = dev;
 	occ->sbefifo = dev->parent;
 	mutex_init(&occ->occ_lock);
@@ -575,7 +626,14 @@ static int occ_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id occ_match[] = {
-	{ .compatible = "ibm,p9-occ" },
+	{
+		.compatible = "ibm,p9-occ",
+		.data = (void *)occ_p9
+	},
+	{
+		.compatible = "ibm,p10-occ",
+		.data = (void *)occ_p10
+	},
 	{ },
 };
 
-- 
2.24.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH linux dev-5.4 v2 3/3] hwmon: (occ) Add new temperature sensor type
  2020-04-30 22:06 [PATCH linux dev-5.4 v2 0/3] occ: Add support for P10 Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 1/3] dt-bindings: fsi: Add P10 OCC device documentation Eddie James
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10 Eddie James
@ 2020-04-30 22:06 ` Eddie James
  2 siblings, 0 replies; 7+ messages in thread
From: Eddie James @ 2020-04-30 22:06 UTC (permalink / raw)
  To: openbmc; +Cc: joel, Eddie James

The latest version of the On-Chip Controller (OCC) has a different
format for the temperature sensor data. Add a new temperature sensor
version to handle this data.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
 drivers/hwmon/occ/common.c | 75 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 30e18eb60da7..52af0e728232 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -41,6 +41,14 @@ struct temp_sensor_2 {
 	u8 value;
 } __packed;
 
+struct temp_sensor_10 {
+	u32 sensor_id;
+	u8 fru_type;
+	u8 value;
+	u8 throttle;
+	u8 reserved;
+} __packed;
+
 struct freq_sensor_1 {
 	u16 sensor_id;
 	u16 value;
@@ -307,6 +315,60 @@ static ssize_t occ_show_temp_2(struct device *dev,
 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
 }
 
+static ssize_t occ_show_temp_10(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int rc;
+	u32 val = 0;
+	struct temp_sensor_10 *temp;
+	struct occ *occ = dev_get_drvdata(dev);
+	struct occ_sensors *sensors = &occ->sensors;
+	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+	rc = occ_update_response(occ);
+	if (rc)
+		return rc;
+
+	temp = ((struct temp_sensor_10 *)sensors->temp.data) + sattr->index;
+
+	switch (sattr->nr) {
+	case 0:
+		val = get_unaligned_be32(&temp->sensor_id);
+		break;
+	case 1:
+		val = temp->value;
+		if (val == OCC_TEMP_SENSOR_FAULT)
+			return -EREMOTEIO;
+
+		/*
+		 * VRM doesn't return temperature, only alarm bit. This
+		 * attribute maps to tempX_alarm instead of tempX_input for
+		 * VRM
+		 */
+		if (temp->fru_type != OCC_FRU_TYPE_VRM) {
+			/* sensor not ready */
+			if (val == 0)
+				return -EAGAIN;
+
+			val *= 1000;
+		}
+		break;
+	case 2:
+		val = temp->fru_type;
+		break;
+	case 3:
+		val = temp->value == OCC_TEMP_SENSOR_FAULT;
+		break;
+	case 4:
+		val = temp->throttle * 1000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
 static ssize_t occ_show_freq_1(struct device *dev,
 			       struct device_attribute *attr, char *buf)
 {
@@ -745,6 +807,10 @@ static int occ_setup_sensor_attrs(struct occ *occ)
 		num_attrs += (sensors->temp.num_sensors * 4);
 		show_temp = occ_show_temp_2;
 		break;
+	case 0x10:
+		num_attrs += (sensors->temp.num_sensors * 5);
+		show_temp = occ_show_temp_10;
+		break;
 	default:
 		sensors->temp.num_sensors = 0;
 	}
@@ -844,6 +910,15 @@ static int occ_setup_sensor_attrs(struct occ *occ)
 			attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
 						     show_temp, NULL, 3, i);
 			attr++;
+
+			if (sensors->temp.version == 0x10) {
+				snprintf(attr->name, sizeof(attr->name),
+					 "temp%d_max", s);
+				attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+							     show_temp, NULL,
+							     4, i);
+				attr++;
+			}
 		}
 	}
 
-- 
2.24.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10
  2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10 Eddie James
@ 2020-05-04  5:04   ` Andrew Jeffery
  2020-05-04 14:01     ` Eddie James
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Jeffery @ 2020-05-04  5:04 UTC (permalink / raw)
  To: Eddie James, openbmc



On Fri, 1 May 2020, at 07:36, Eddie James wrote:
> The P10 OCC has a different SRAM address for the command and response
> buffers. In addition, the SBE commands to access the SRAM have changed
> format. Add versioning to the driver to handle these differences.
> 
> Signed-off-by: Eddie James <eajames@linux.ibm.com>
> ---
>  drivers/fsi/fsi-occ.c | 126 ++++++++++++++++++++++++++++++------------
>  1 file changed, 92 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
> index 7da9c81759ac..942eff4032b0 100644
> --- a/drivers/fsi/fsi-occ.c
> +++ b/drivers/fsi/fsi-occ.c
> @@ -14,6 +14,7 @@
>  #include <linux/mutex.h>
>  #include <linux/fsi-occ.h>
>  #include <linux/of.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
> @@ -24,8 +25,13 @@
>  #define OCC_CMD_DATA_BYTES	4090
>  #define OCC_RESP_DATA_BYTES	4089
>  
> -#define OCC_SRAM_CMD_ADDR	0xFFFBE000
> -#define OCC_SRAM_RSP_ADDR	0xFFFBF000
> +#define OCC_P9_SRAM_CMD_ADDR	0xFFFBE000
> +#define OCC_P9_SRAM_RSP_ADDR	0xFFFBF000
> +
> +#define OCC_P10_SRAM_CMD_ADDR	0xFFFFD000
> +#define OCC_P10_SRAM_RSP_ADDR	0xFFFFE000
> +
> +#define OCC_P10_SRAM_MODE	0x58	/* Normal mode, OCB channel 2 */
>  
>  /*
>   * Assume we don't have much FFDC, if we do we'll overflow and
> @@ -37,11 +43,14 @@
>  #define OCC_TIMEOUT_MS		1000
>  #define OCC_CMD_IN_PRG_WAIT_MS	50
>  
> +enum versions { occ_p9, occ_p10 };
> +
>  struct occ {
>  	struct device *dev;
>  	struct device *sbefifo;
>  	char name[32];
>  	int idx;
> +	enum versions version;
>  	struct miscdevice mdev;
>  	struct mutex occ_lock;
>  };
> @@ -235,29 +244,43 @@ static int occ_verify_checksum(struct 
> occ_response *resp, u16 data_length)
>  	return 0;
>  }
>  
> -static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
> +static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
>  {
>  	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
> -	size_t resp_len, resp_data_len;
> -	__be32 *resp, cmd[5];
> -	int rc;
> +	size_t cmd_len, resp_len, resp_data_len;
> +	__be32 *resp, cmd[6];
> +	int idx = 0, rc;
>  
>  	/*
>  	 * Magic sequence to do SBE getsram command. SBE will fetch data from
>  	 * specified SRAM address.
>  	 */
> -	cmd[0] = cpu_to_be32(0x5);
> +	switch (occ->version) {
> +	default:
> +	case occ_p9:
> +		cmd_len = 5;
> +		cmd[2] = cpu_to_be32(1);	/* Normal mode */
> +		cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
> +		break;
> +	case occ_p10:
> +		idx = 1;
> +		cmd_len = 6;
> +		cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
> +		cmd[3] = 0;
> +		cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
> +		break;
> +	}
> +
> +	cmd[0] = cpu_to_be32(cmd_len);
>  	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
> -	cmd[2] = cpu_to_be32(1);
> -	cmd[3] = cpu_to_be32(address);
> -	cmd[4] = cpu_to_be32(data_len);
> +	cmd[4 + idx] = cpu_to_be32(data_len);
>  
>  	resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
>  	resp = kzalloc(resp_len << 2, GFP_KERNEL);
>  	if (!resp)
>  		return -ENOMEM;
>  
> -	rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
> +	rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
>  	if (rc)
>  		goto free;
>  
> @@ -287,20 +310,21 @@ static int occ_getsram(struct occ *occ, u32 
> address, void *data, ssize_t len)
>  	return rc;
>  }
>  
> -static int occ_putsram(struct occ *occ, u32 address, const void *data,
> -		       ssize_t len)
> +static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
>  {
>  	size_t cmd_len, buf_len, resp_len, resp_data_len;
>  	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
>  	__be32 *buf;
> -	int rc;
> +	int idx = 0, rc;
> +
> +	cmd_len = (occ->version == occ_p10) ? 6 : 5;
>  
>  	/*
>  	 * We use the same buffer for command and response, make
>  	 * sure it's big enough
>  	 */
>  	resp_len = OCC_SBE_STATUS_WORDS;
> -	cmd_len = (data_len >> 2) + 5;
> +	cmd_len += data_len >> 2;
>  	buf_len = max(cmd_len, resp_len);
>  	buf = kzalloc(buf_len << 2, GFP_KERNEL);
>  	if (!buf)
> @@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32 
> address, const void *data,
>  	 */
>  	buf[0] = cpu_to_be32(cmd_len);
>  	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
> -	buf[2] = cpu_to_be32(1);
> -	buf[3] = cpu_to_be32(address);
> -	buf[4] = cpu_to_be32(data_len);
>  
> -	memcpy(&buf[5], data, len);
> +	switch (occ->version) {
> +	default:
> +	case occ_p9:
> +		buf[2] = cpu_to_be32(1);	/* Normal mode */
> +		buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
> +		break;
> +	case occ_p10:
> +		idx = 1;
> +		buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
> +		buf[3] = 0;
> +		buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
> +		break;
> +	}
> +
> +	buf[4 + idx] = cpu_to_be32(data_len);
> +	memcpy(&buf[5 + idx], data, len);
>  
>  	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
>  	if (rc)
> @@ -356,21 +392,35 @@ static int occ_putsram(struct occ *occ, u32 
> address, const void *data,
>  static int occ_trigger_attn(struct occ *occ)
>  {
>  	__be32 buf[OCC_SBE_STATUS_WORDS];
> -	size_t resp_len, resp_data_len;
> -	int rc;
> +	size_t cmd_len, resp_len, resp_data_len;
> +	int idx = 0, rc;
>  
> -	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
> +	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
>  	resp_len = OCC_SBE_STATUS_WORDS;
>  
> -	buf[0] = cpu_to_be32(0x5 + 0x2);        /* Chip-op length in words */
> +	switch (occ->version) {
> +	default:
> +	case occ_p9:
> +		cmd_len = 7;
> +		buf[2] = cpu_to_be32(3); /* Circular mode */
> +		buf[3] = 0;
> +		break;
> +	case occ_p10:
> +		idx = 1;
> +		cmd_len = 8;
> +		buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
> +		buf[3] = 0;
> +		buf[4] = 0;
> +		break;
> +	}
> +
> +	buf[0] = cpu_to_be32(cmd_len);		/* Chip-op length in words */
>  	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
> -	buf[2] = cpu_to_be32(0x3);              /* Mode: Circular */
> -	buf[3] = cpu_to_be32(0x0);              /* Address: ignore in mode 3 */
> -	buf[4] = cpu_to_be32(0x8);              /* Data length in bytes */
> -	buf[5] = cpu_to_be32(0x20010000);       /* Trigger OCC attention */
> -	buf[6] = 0;
> +	buf[4 + idx] = cpu_to_be32(8);		/* Data length in bytes */
> +	buf[5 + idx] = cpu_to_be32(0x20010000);	/* Trigger OCC attention */
> +	buf[6 + idx] = 0;
>  
> -	rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
> +	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
>  	if (rc)
>  		goto error;
>  
> @@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void 
> *request, size_t req_len,
>  
>  	/* Extract the seq_no from the command (first byte) */
>  	seq_no = *(const u8 *)request;
> -	rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
> +	rc = occ_putsram(occ, request, req_len);
>  	if (rc)
>  		goto done;
>  
> @@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void 
> *request, size_t req_len,
>  	/* Read occ response header */
>  	start = jiffies;
>  	do {
> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
> +		rc = occ_getsram(occ, 0, resp, 8);
>  		if (rc)
>  			goto done;
>  
> @@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void 
> *request, size_t req_len,
>  	/* Grab the rest */
>  	if (resp_data_length > 1) {
>  		/* already got 3 bytes resp, also need 2 bytes checksum */
> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
> -				 &resp->data[3], resp_data_length - 1);
> +		rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
>  		if (rc)
>  			goto done;
>  	}
> @@ -508,6 +557,7 @@ static int occ_probe(struct platform_device *pdev)
>  	struct occ *occ;
>  	struct platform_device *hwmon_dev;
>  	struct device *dev = &pdev->dev;
> +	const void *md =  of_device_get_match_data(dev);
>  	struct platform_device_info hwmon_dev_info = {
>  		.parent = dev,
>  		.name = "occ-hwmon",
> @@ -517,6 +567,7 @@ static int occ_probe(struct platform_device *pdev)
>  	if (!occ)
>  		return -ENOMEM;
>  
> +	occ->version = (enum versions)md;
>  	occ->dev = dev;
>  	occ->sbefifo = dev->parent;
>  	mutex_init(&occ->occ_lock);
> @@ -575,7 +626,14 @@ static int occ_remove(struct platform_device *pdev)
>  }
>  
>  static const struct of_device_id occ_match[] = {
> -	{ .compatible = "ibm,p9-occ" },
> +	{
> +		.compatible = "ibm,p9-occ",
> +		.data = (void *)occ_p9
> +	},
> +	{
> +		.compatible = "ibm,p10-occ",
> +		.data = (void *)occ_p10

Why not stick an ops struct pointer in .data and separate out the implementations
rather than stick a switch over the version in each of the affected functions?

Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10
  2020-05-04  5:04   ` Andrew Jeffery
@ 2020-05-04 14:01     ` Eddie James
  2020-05-05  3:07       ` Andrew Jeffery
  0 siblings, 1 reply; 7+ messages in thread
From: Eddie James @ 2020-05-04 14:01 UTC (permalink / raw)
  To: Andrew Jeffery, Eddie James, openbmc


On 5/4/20 12:04 AM, Andrew Jeffery wrote:
>
> On Fri, 1 May 2020, at 07:36, Eddie James wrote:
>> The P10 OCC has a different SRAM address for the command and response
>> buffers. In addition, the SBE commands to access the SRAM have changed
>> format. Add versioning to the driver to handle these differences.
>>
>> Signed-off-by: Eddie James <eajames@linux.ibm.com>
>> ---
>>   drivers/fsi/fsi-occ.c | 126 ++++++++++++++++++++++++++++++------------
>>   1 file changed, 92 insertions(+), 34 deletions(-)
>>
>> diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
>> index 7da9c81759ac..942eff4032b0 100644
>> --- a/drivers/fsi/fsi-occ.c
>> +++ b/drivers/fsi/fsi-occ.c
>> @@ -14,6 +14,7 @@
>>   #include <linux/mutex.h>
>>   #include <linux/fsi-occ.h>
>>   #include <linux/of.h>
>> +#include <linux/of_device.h>
>>   #include <linux/platform_device.h>
>>   #include <linux/sched.h>
>>   #include <linux/slab.h>
>> @@ -24,8 +25,13 @@
>>   #define OCC_CMD_DATA_BYTES	4090
>>   #define OCC_RESP_DATA_BYTES	4089
>>   
>> -#define OCC_SRAM_CMD_ADDR	0xFFFBE000
>> -#define OCC_SRAM_RSP_ADDR	0xFFFBF000
>> +#define OCC_P9_SRAM_CMD_ADDR	0xFFFBE000
>> +#define OCC_P9_SRAM_RSP_ADDR	0xFFFBF000
>> +
>> +#define OCC_P10_SRAM_CMD_ADDR	0xFFFFD000
>> +#define OCC_P10_SRAM_RSP_ADDR	0xFFFFE000
>> +
>> +#define OCC_P10_SRAM_MODE	0x58	/* Normal mode, OCB channel 2 */
>>   
>>   /*
>>    * Assume we don't have much FFDC, if we do we'll overflow and
>> @@ -37,11 +43,14 @@
>>   #define OCC_TIMEOUT_MS		1000
>>   #define OCC_CMD_IN_PRG_WAIT_MS	50
>>   
>> +enum versions { occ_p9, occ_p10 };
>> +
>>   struct occ {
>>   	struct device *dev;
>>   	struct device *sbefifo;
>>   	char name[32];
>>   	int idx;
>> +	enum versions version;
>>   	struct miscdevice mdev;
>>   	struct mutex occ_lock;
>>   };
>> @@ -235,29 +244,43 @@ static int occ_verify_checksum(struct
>> occ_response *resp, u16 data_length)
>>   	return 0;
>>   }
>>   
>> -static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
>> +static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
>>   {
>>   	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
>> -	size_t resp_len, resp_data_len;
>> -	__be32 *resp, cmd[5];
>> -	int rc;
>> +	size_t cmd_len, resp_len, resp_data_len;
>> +	__be32 *resp, cmd[6];
>> +	int idx = 0, rc;
>>   
>>   	/*
>>   	 * Magic sequence to do SBE getsram command. SBE will fetch data from
>>   	 * specified SRAM address.
>>   	 */
>> -	cmd[0] = cpu_to_be32(0x5);
>> +	switch (occ->version) {
>> +	default:
>> +	case occ_p9:
>> +		cmd_len = 5;
>> +		cmd[2] = cpu_to_be32(1);	/* Normal mode */
>> +		cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
>> +		break;
>> +	case occ_p10:
>> +		idx = 1;
>> +		cmd_len = 6;
>> +		cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
>> +		cmd[3] = 0;
>> +		cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
>> +		break;
>> +	}
>> +
>> +	cmd[0] = cpu_to_be32(cmd_len);
>>   	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
>> -	cmd[2] = cpu_to_be32(1);
>> -	cmd[3] = cpu_to_be32(address);
>> -	cmd[4] = cpu_to_be32(data_len);
>> +	cmd[4 + idx] = cpu_to_be32(data_len);
>>   
>>   	resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
>>   	resp = kzalloc(resp_len << 2, GFP_KERNEL);
>>   	if (!resp)
>>   		return -ENOMEM;
>>   
>> -	rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
>> +	rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
>>   	if (rc)
>>   		goto free;
>>   
>> @@ -287,20 +310,21 @@ static int occ_getsram(struct occ *occ, u32
>> address, void *data, ssize_t len)
>>   	return rc;
>>   }
>>   
>> -static int occ_putsram(struct occ *occ, u32 address, const void *data,
>> -		       ssize_t len)
>> +static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
>>   {
>>   	size_t cmd_len, buf_len, resp_len, resp_data_len;
>>   	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
>>   	__be32 *buf;
>> -	int rc;
>> +	int idx = 0, rc;
>> +
>> +	cmd_len = (occ->version == occ_p10) ? 6 : 5;
>>   
>>   	/*
>>   	 * We use the same buffer for command and response, make
>>   	 * sure it's big enough
>>   	 */
>>   	resp_len = OCC_SBE_STATUS_WORDS;
>> -	cmd_len = (data_len >> 2) + 5;
>> +	cmd_len += data_len >> 2;
>>   	buf_len = max(cmd_len, resp_len);
>>   	buf = kzalloc(buf_len << 2, GFP_KERNEL);
>>   	if (!buf)
>> @@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32
>> address, const void *data,
>>   	 */
>>   	buf[0] = cpu_to_be32(cmd_len);
>>   	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
>> -	buf[2] = cpu_to_be32(1);
>> -	buf[3] = cpu_to_be32(address);
>> -	buf[4] = cpu_to_be32(data_len);
>>   
>> -	memcpy(&buf[5], data, len);
>> +	switch (occ->version) {
>> +	default:
>> +	case occ_p9:
>> +		buf[2] = cpu_to_be32(1);	/* Normal mode */
>> +		buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
>> +		break;
>> +	case occ_p10:
>> +		idx = 1;
>> +		buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
>> +		buf[3] = 0;
>> +		buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
>> +		break;
>> +	}
>> +
>> +	buf[4 + idx] = cpu_to_be32(data_len);
>> +	memcpy(&buf[5 + idx], data, len);
>>   
>>   	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
>>   	if (rc)
>> @@ -356,21 +392,35 @@ static int occ_putsram(struct occ *occ, u32
>> address, const void *data,
>>   static int occ_trigger_attn(struct occ *occ)
>>   {
>>   	__be32 buf[OCC_SBE_STATUS_WORDS];
>> -	size_t resp_len, resp_data_len;
>> -	int rc;
>> +	size_t cmd_len, resp_len, resp_data_len;
>> +	int idx = 0, rc;
>>   
>> -	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
>> +	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
>>   	resp_len = OCC_SBE_STATUS_WORDS;
>>   
>> -	buf[0] = cpu_to_be32(0x5 + 0x2);        /* Chip-op length in words */
>> +	switch (occ->version) {
>> +	default:
>> +	case occ_p9:
>> +		cmd_len = 7;
>> +		buf[2] = cpu_to_be32(3); /* Circular mode */
>> +		buf[3] = 0;
>> +		break;
>> +	case occ_p10:
>> +		idx = 1;
>> +		cmd_len = 8;
>> +		buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
>> +		buf[3] = 0;
>> +		buf[4] = 0;
>> +		break;
>> +	}
>> +
>> +	buf[0] = cpu_to_be32(cmd_len);		/* Chip-op length in words */
>>   	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
>> -	buf[2] = cpu_to_be32(0x3);              /* Mode: Circular */
>> -	buf[3] = cpu_to_be32(0x0);              /* Address: ignore in mode 3 */
>> -	buf[4] = cpu_to_be32(0x8);              /* Data length in bytes */
>> -	buf[5] = cpu_to_be32(0x20010000);       /* Trigger OCC attention */
>> -	buf[6] = 0;
>> +	buf[4 + idx] = cpu_to_be32(8);		/* Data length in bytes */
>> +	buf[5 + idx] = cpu_to_be32(0x20010000);	/* Trigger OCC attention */
>> +	buf[6 + idx] = 0;
>>   
>> -	rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
>> +	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
>>   	if (rc)
>>   		goto error;
>>   
>> @@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void
>> *request, size_t req_len,
>>   
>>   	/* Extract the seq_no from the command (first byte) */
>>   	seq_no = *(const u8 *)request;
>> -	rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
>> +	rc = occ_putsram(occ, request, req_len);
>>   	if (rc)
>>   		goto done;
>>   
>> @@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void
>> *request, size_t req_len,
>>   	/* Read occ response header */
>>   	start = jiffies;
>>   	do {
>> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
>> +		rc = occ_getsram(occ, 0, resp, 8);
>>   		if (rc)
>>   			goto done;
>>   
>> @@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void
>> *request, size_t req_len,
>>   	/* Grab the rest */
>>   	if (resp_data_length > 1) {
>>   		/* already got 3 bytes resp, also need 2 bytes checksum */
>> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
>> -				 &resp->data[3], resp_data_length - 1);
>> +		rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
>>   		if (rc)
>>   			goto done;
>>   	}
>> @@ -508,6 +557,7 @@ static int occ_probe(struct platform_device *pdev)
>>   	struct occ *occ;
>>   	struct platform_device *hwmon_dev;
>>   	struct device *dev = &pdev->dev;
>> +	const void *md =  of_device_get_match_data(dev);
>>   	struct platform_device_info hwmon_dev_info = {
>>   		.parent = dev,
>>   		.name = "occ-hwmon",
>> @@ -517,6 +567,7 @@ static int occ_probe(struct platform_device *pdev)
>>   	if (!occ)
>>   		return -ENOMEM;
>>   
>> +	occ->version = (enum versions)md;
>>   	occ->dev = dev;
>>   	occ->sbefifo = dev->parent;
>>   	mutex_init(&occ->occ_lock);
>> @@ -575,7 +626,14 @@ static int occ_remove(struct platform_device *pdev)
>>   }
>>   
>>   static const struct of_device_id occ_match[] = {
>> -	{ .compatible = "ibm,p9-occ" },
>> +	{
>> +		.compatible = "ibm,p9-occ",
>> +		.data = (void *)occ_p9
>> +	},
>> +	{
>> +		.compatible = "ibm,p10-occ",
>> +		.data = (void *)occ_p10
> Why not stick an ops struct pointer in .data and separate out the implementations
> rather than stick a switch over the version in each of the affected functions?


I did try but I found I ended up with two copies of most of the code. 
There is too much in common and no good way to split out the 
processor-specific stuff without duplicating everything...


Thanks,

Eddie


>
> Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10
  2020-05-04 14:01     ` Eddie James
@ 2020-05-05  3:07       ` Andrew Jeffery
  0 siblings, 0 replies; 7+ messages in thread
From: Andrew Jeffery @ 2020-05-05  3:07 UTC (permalink / raw)
  To: Eddie James, Eddie James, openbmc



On Mon, 4 May 2020, at 23:31, Eddie James wrote:
> 
> On 5/4/20 12:04 AM, Andrew Jeffery wrote:
> >
> > On Fri, 1 May 2020, at 07:36, Eddie James wrote:
> >> The P10 OCC has a different SRAM address for the command and response
> >> buffers. In addition, the SBE commands to access the SRAM have changed
> >> format. Add versioning to the driver to handle these differences.
> >>
> >> Signed-off-by: Eddie James <eajames@linux.ibm.com>
> >> ---
> >>   drivers/fsi/fsi-occ.c | 126 ++++++++++++++++++++++++++++++------------
> >>   1 file changed, 92 insertions(+), 34 deletions(-)
> >>
> >> diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
> >> index 7da9c81759ac..942eff4032b0 100644
> >> --- a/drivers/fsi/fsi-occ.c
> >> +++ b/drivers/fsi/fsi-occ.c
> >> @@ -14,6 +14,7 @@
> >>   #include <linux/mutex.h>
> >>   #include <linux/fsi-occ.h>
> >>   #include <linux/of.h>
> >> +#include <linux/of_device.h>
> >>   #include <linux/platform_device.h>
> >>   #include <linux/sched.h>
> >>   #include <linux/slab.h>
> >> @@ -24,8 +25,13 @@
> >>   #define OCC_CMD_DATA_BYTES	4090
> >>   #define OCC_RESP_DATA_BYTES	4089
> >>   
> >> -#define OCC_SRAM_CMD_ADDR	0xFFFBE000
> >> -#define OCC_SRAM_RSP_ADDR	0xFFFBF000
> >> +#define OCC_P9_SRAM_CMD_ADDR	0xFFFBE000
> >> +#define OCC_P9_SRAM_RSP_ADDR	0xFFFBF000
> >> +
> >> +#define OCC_P10_SRAM_CMD_ADDR	0xFFFFD000
> >> +#define OCC_P10_SRAM_RSP_ADDR	0xFFFFE000
> >> +
> >> +#define OCC_P10_SRAM_MODE	0x58	/* Normal mode, OCB channel 2 */
> >>   
> >>   /*
> >>    * Assume we don't have much FFDC, if we do we'll overflow and
> >> @@ -37,11 +43,14 @@
> >>   #define OCC_TIMEOUT_MS		1000
> >>   #define OCC_CMD_IN_PRG_WAIT_MS	50
> >>   
> >> +enum versions { occ_p9, occ_p10 };
> >> +
> >>   struct occ {
> >>   	struct device *dev;
> >>   	struct device *sbefifo;
> >>   	char name[32];
> >>   	int idx;
> >> +	enum versions version;
> >>   	struct miscdevice mdev;
> >>   	struct mutex occ_lock;
> >>   };
> >> @@ -235,29 +244,43 @@ static int occ_verify_checksum(struct
> >> occ_response *resp, u16 data_length)
> >>   	return 0;
> >>   }
> >>   
> >> -static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
> >> +static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
> >>   {
> >>   	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
> >> -	size_t resp_len, resp_data_len;
> >> -	__be32 *resp, cmd[5];
> >> -	int rc;
> >> +	size_t cmd_len, resp_len, resp_data_len;
> >> +	__be32 *resp, cmd[6];
> >> +	int idx = 0, rc;
> >>   
> >>   	/*
> >>   	 * Magic sequence to do SBE getsram command. SBE will fetch data from
> >>   	 * specified SRAM address.
> >>   	 */
> >> -	cmd[0] = cpu_to_be32(0x5);
> >> +	switch (occ->version) {
> >> +	default:
> >> +	case occ_p9:
> >> +		cmd_len = 5;
> >> +		cmd[2] = cpu_to_be32(1);	/* Normal mode */
> >> +		cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
> >> +		break;
> >> +	case occ_p10:
> >> +		idx = 1;
> >> +		cmd_len = 6;
> >> +		cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
> >> +		cmd[3] = 0;
> >> +		cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
> >> +		break;
> >> +	}
> >> +
> >> +	cmd[0] = cpu_to_be32(cmd_len);
> >>   	cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
> >> -	cmd[2] = cpu_to_be32(1);
> >> -	cmd[3] = cpu_to_be32(address);
> >> -	cmd[4] = cpu_to_be32(data_len);
> >> +	cmd[4 + idx] = cpu_to_be32(data_len);
> >>   
> >>   	resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
> >>   	resp = kzalloc(resp_len << 2, GFP_KERNEL);
> >>   	if (!resp)
> >>   		return -ENOMEM;
> >>   
> >> -	rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
> >> +	rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
> >>   	if (rc)
> >>   		goto free;
> >>   
> >> @@ -287,20 +310,21 @@ static int occ_getsram(struct occ *occ, u32
> >> address, void *data, ssize_t len)
> >>   	return rc;
> >>   }
> >>   
> >> -static int occ_putsram(struct occ *occ, u32 address, const void *data,
> >> -		       ssize_t len)
> >> +static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
> >>   {
> >>   	size_t cmd_len, buf_len, resp_len, resp_data_len;
> >>   	u32 data_len = ((len + 7) / 8) * 8;	/* must be multiples of 8 B */
> >>   	__be32 *buf;
> >> -	int rc;
> >> +	int idx = 0, rc;
> >> +
> >> +	cmd_len = (occ->version == occ_p10) ? 6 : 5;
> >>   
> >>   	/*
> >>   	 * We use the same buffer for command and response, make
> >>   	 * sure it's big enough
> >>   	 */
> >>   	resp_len = OCC_SBE_STATUS_WORDS;
> >> -	cmd_len = (data_len >> 2) + 5;
> >> +	cmd_len += data_len >> 2;
> >>   	buf_len = max(cmd_len, resp_len);
> >>   	buf = kzalloc(buf_len << 2, GFP_KERNEL);
> >>   	if (!buf)
> >> @@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32
> >> address, const void *data,
> >>   	 */
> >>   	buf[0] = cpu_to_be32(cmd_len);
> >>   	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
> >> -	buf[2] = cpu_to_be32(1);
> >> -	buf[3] = cpu_to_be32(address);
> >> -	buf[4] = cpu_to_be32(data_len);
> >>   
> >> -	memcpy(&buf[5], data, len);
> >> +	switch (occ->version) {
> >> +	default:
> >> +	case occ_p9:
> >> +		buf[2] = cpu_to_be32(1);	/* Normal mode */
> >> +		buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
> >> +		break;
> >> +	case occ_p10:
> >> +		idx = 1;
> >> +		buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
> >> +		buf[3] = 0;
> >> +		buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
> >> +		break;
> >> +	}
> >> +
> >> +	buf[4 + idx] = cpu_to_be32(data_len);
> >> +	memcpy(&buf[5 + idx], data, len);
> >>   
> >>   	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
> >>   	if (rc)
> >> @@ -356,21 +392,35 @@ static int occ_putsram(struct occ *occ, u32
> >> address, const void *data,
> >>   static int occ_trigger_attn(struct occ *occ)
> >>   {
> >>   	__be32 buf[OCC_SBE_STATUS_WORDS];
> >> -	size_t resp_len, resp_data_len;
> >> -	int rc;
> >> +	size_t cmd_len, resp_len, resp_data_len;
> >> +	int idx = 0, rc;
> >>   
> >> -	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
> >> +	BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
> >>   	resp_len = OCC_SBE_STATUS_WORDS;
> >>   
> >> -	buf[0] = cpu_to_be32(0x5 + 0x2);        /* Chip-op length in words */
> >> +	switch (occ->version) {
> >> +	default:
> >> +	case occ_p9:
> >> +		cmd_len = 7;
> >> +		buf[2] = cpu_to_be32(3); /* Circular mode */
> >> +		buf[3] = 0;
> >> +		break;
> >> +	case occ_p10:
> >> +		idx = 1;
> >> +		cmd_len = 8;
> >> +		buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
> >> +		buf[3] = 0;
> >> +		buf[4] = 0;
> >> +		break;
> >> +	}
> >> +
> >> +	buf[0] = cpu_to_be32(cmd_len);		/* Chip-op length in words */
> >>   	buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
> >> -	buf[2] = cpu_to_be32(0x3);              /* Mode: Circular */
> >> -	buf[3] = cpu_to_be32(0x0);              /* Address: ignore in mode 3 */
> >> -	buf[4] = cpu_to_be32(0x8);              /* Data length in bytes */
> >> -	buf[5] = cpu_to_be32(0x20010000);       /* Trigger OCC attention */
> >> -	buf[6] = 0;
> >> +	buf[4 + idx] = cpu_to_be32(8);		/* Data length in bytes */
> >> +	buf[5 + idx] = cpu_to_be32(0x20010000);	/* Trigger OCC attention */
> >> +	buf[6 + idx] = 0;
> >>   
> >> -	rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
> >> +	rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
> >>   	if (rc)
> >>   		goto error;
> >>   
> >> @@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void
> >> *request, size_t req_len,
> >>   
> >>   	/* Extract the seq_no from the command (first byte) */
> >>   	seq_no = *(const u8 *)request;
> >> -	rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
> >> +	rc = occ_putsram(occ, request, req_len);
> >>   	if (rc)
> >>   		goto done;
> >>   
> >> @@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void
> >> *request, size_t req_len,
> >>   	/* Read occ response header */
> >>   	start = jiffies;
> >>   	do {
> >> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
> >> +		rc = occ_getsram(occ, 0, resp, 8);
> >>   		if (rc)
> >>   			goto done;
> >>   
> >> @@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void
> >> *request, size_t req_len,
> >>   	/* Grab the rest */
> >>   	if (resp_data_length > 1) {
> >>   		/* already got 3 bytes resp, also need 2 bytes checksum */
> >> -		rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
> >> -				 &resp->data[3], resp_data_length - 1);
> >> +		rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
> >>   		if (rc)
> >>   			goto done;
> >>   	}
> >> @@ -508,6 +557,7 @@ static int occ_probe(struct platform_device *pdev)
> >>   	struct occ *occ;
> >>   	struct platform_device *hwmon_dev;
> >>   	struct device *dev = &pdev->dev;
> >> +	const void *md =  of_device_get_match_data(dev);
> >>   	struct platform_device_info hwmon_dev_info = {
> >>   		.parent = dev,
> >>   		.name = "occ-hwmon",
> >> @@ -517,6 +567,7 @@ static int occ_probe(struct platform_device *pdev)
> >>   	if (!occ)
> >>   		return -ENOMEM;
> >>   
> >> +	occ->version = (enum versions)md;
> >>   	occ->dev = dev;
> >>   	occ->sbefifo = dev->parent;
> >>   	mutex_init(&occ->occ_lock);
> >> @@ -575,7 +626,14 @@ static int occ_remove(struct platform_device *pdev)
> >>   }
> >>   
> >>   static const struct of_device_id occ_match[] = {
> >> -	{ .compatible = "ibm,p9-occ" },
> >> +	{
> >> +		.compatible = "ibm,p9-occ",
> >> +		.data = (void *)occ_p9
> >> +	},
> >> +	{
> >> +		.compatible = "ibm,p10-occ",
> >> +		.data = (void *)occ_p10
> > Why not stick an ops struct pointer in .data and separate out the implementations
> > rather than stick a switch over the version in each of the affected functions?
> 
> 
> I did try but I found I ended up with two copies of most of the code. 
> There is too much in common and no good way to split out the 
> processor-specific stuff without duplicating everything...

Yep, fair anough. I find it useful to mention this kind of decision in
the commit message, can you do that in the future?

Cheers,

Andrew

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2020-05-05  3:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-30 22:06 [PATCH linux dev-5.4 v2 0/3] occ: Add support for P10 Eddie James
2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 1/3] dt-bindings: fsi: Add P10 OCC device documentation Eddie James
2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 2/3] fsi: occ: Add support for P10 Eddie James
2020-05-04  5:04   ` Andrew Jeffery
2020-05-04 14:01     ` Eddie James
2020-05-05  3:07       ` Andrew Jeffery
2020-04-30 22:06 ` [PATCH linux dev-5.4 v2 3/3] hwmon: (occ) Add new temperature sensor type Eddie James

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.