Skip to contentSkip to conversation

On-Chip Controller (OCC) hwmon driver

PATCH New [email protected] 3 participants 23 messages Nov 7, 2016 – Dec 6, 2016

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

v5 cover On-Chip Controller (OCC) hwmon driver

From: "Edward A. James" <[email protected]>

This patchset provides a new OCC hwmon driver. There are a number of issues with the existing driver. Firstly, i2c access was embedded throughout the driver. Secondly, there is no way to easily differentiate versions of the OCC.

This patchset addresses the first issue by abstracting the bus transfer protocol into a modular structure. In this way, any low level transfer method may be easily implemented.

The second issue is addressed by separating the "version specific" code for the OCC and the common hwmon code. This task is not yet complete, but the general structure is in place. Ultimately, different OCC versions could be probed up using the device tree.

Edward A. James (5):
Revert "hwmon: Add Power8 OCC hwmon driver"
drivers: Add hwmon occ driver framework
drivers: hwmon OCC scom bus operations
drivers: Add hwmon OCC version specific functions
drivers: OCC hwmon driver and sysfs

 .../devicetree/bindings/i2c/i2c-ibm-occ.txt        |    2 +-
 drivers/hwmon/Kconfig                              |   13 +-
 drivers/hwmon/Makefile                             |    2 +-
 drivers/hwmon/occ/Kconfig                          |   15 +
 drivers/hwmon/occ/Makefile                         |    1 +
 drivers/hwmon/occ/occ.c                            |  892 ++++++++++++++
 drivers/hwmon/occ/occ.h                            |   58 +
 drivers/hwmon/occ/occ_i2c.c                        |  147 +++
 drivers/hwmon/occ/p8.c                             |  222 ++++
 drivers/hwmon/occ/p8.h                             |   29 +
 drivers/hwmon/occ/p9.c                             |  253 ++++
 drivers/hwmon/occ/p9.h                             |   29 +
 drivers/hwmon/occ/scom.h                           |   31 +
 drivers/hwmon/power8_occ_i2c.c                     | 1254 --------------------
 14 files changed, 1680 insertions(+), 1268 deletions(-)
 create mode 100644 drivers/hwmon/occ/Kconfig
 create mode 100644 drivers/hwmon/occ/Makefile
 create mode 100644 drivers/hwmon/occ/occ.c
 create mode 100644 drivers/hwmon/occ/occ.h
 create mode 100644 drivers/hwmon/occ/occ_i2c.c
 create mode 100644 drivers/hwmon/occ/p8.c
 create mode 100644 drivers/hwmon/occ/p8.h
 create mode 100644 drivers/hwmon/occ/p9.c
 create mode 100644 drivers/hwmon/occ/p9.h
 create mode 100644 drivers/hwmon/occ/scom.h
 delete mode 100644 drivers/hwmon/power8_occ_i2c.c
Signature · 1 line
1.9.1
#1 lore raw

cover On-Chip Controller (OCC) hwmon driver

Hi Eddie,

Quoted 5 lines

This patchset provides a new OCC hwmon driver. There are a number of issues with the existing driver. Firstly, i2c access was embedded throughout the driver. Secondly, there is no way to easily differentiate versions of the OCC.

Quoted 8 lines

This patchset addresses the first issue by abstracting the bus transfer protocol into a modular structure. In this way, any low level transfer method may be easily implemented.

The second issue is addressed by separating the "version specific" code for the OCC and the common hwmon code. This task is not yet complete, but the general structure is in place. Ultimately, different OCC versions could be probed up using the device tree.

I agree with all of this. However, I thought some of the layering could still be improved, so rather than provide a review through prose I figured it might be better for both of us if I mangled the patches directly.

I've attacked two things. The first is I found the series hard to review due to the way the patches were split, as the patches went from trivial to huge (and complex) in a fairly short step:

Quoted 7 lines

Edward A. James (5):
Revert "hwmon: Add Power8 OCC hwmon driver"
drivers: Add hwmon occ driver framework
drivers: hwmon OCC scom bus operations
drivers: Add hwmon OCC version specific functions
drivers: OCC hwmon driver and sysfs

So I have reworked them into what is now 8 patches (see below) and tried to tell a bit more of a story with them (hopefully I succeeded!) Second, I tried my hand at reworking the layering as mentioned above, such that hardware interaction is split from sysfs, and that the SCOM transport and sensor configuration is decoupled from the data parsing. You largely had all of these in-place already, I just cut and pasted code around a bit.

Please review the patches and provide feedback! I'd like to hear arguments for or against both of our approaches. Note though that I've only tested that these patches compile, I absolutely have not done any further testing.

Joel: Any chance you could chime in with an architectural review?

When the dust has settled on the bigger issues we can start to look at the finer details of the APIs (there are some bugs, oddities and complexities that I would like to address before they are applied to openbmc/linux).

Cheers,

Andrew

Andrew Jeffery (8):
hwmon: Add core On-Chip Controller support for POWER CPUs
hwmon: occ: Add sysfs interface
hwmon: occ: Add I2C SCOM transport implementation
hwmon: occ: Add callbacks for parsing P8 OCC datastructures
hwmon: occ: Add hwmon implementation for the P8 OCC
arm: aspeed: dt: Fix OCC compatible strings
hwmon: occ: Add callbacks for parsing P9 OCC datastructures
wip: hwmon: occ: Add sketch of the hwmon implementation for the P9 OCC

Edward A. James (1):
Revert "hwmon: Add Power8 OCC hwmon driver"

 .../devicetree/bindings/i2c/i2c-ibm-occ.txt        |   13 -
 arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts     |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-firestone.dts     |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-garrison.dts      |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts      |    2 +-
 drivers/hwmon/Kconfig                              |   13 +-
 drivers/hwmon/Makefile                             |    2 +-
 drivers/hwmon/occ/Kconfig                          |   38 +
 drivers/hwmon/occ/Makefile                         |    3 +
 drivers/hwmon/occ/occ.c                            |  494 ++++++++
 drivers/hwmon/occ/occ.h                            |   79 ++
 drivers/hwmon/occ/occ_p8.c                         |  219 ++++
 drivers/hwmon/occ/occ_p8.h                         |   30 +
 drivers/hwmon/occ/occ_p8_i2c.c                     |  133 +++
 drivers/hwmon/occ/occ_p9.c                         |  261 ++++
 drivers/hwmon/occ/occ_p9.h                         |   30 +
 drivers/hwmon/occ/occ_p9_fsi.c                     |   93 ++
 drivers/hwmon/occ/occ_scom_i2c.c                   |   68 ++
 drivers/hwmon/occ/occ_scom_i2c.h                   |   20 +
 drivers/hwmon/occ/occ_sysfs.c                      |  498 ++++++++
 drivers/hwmon/occ/occ_sysfs.h                      |   51 +
 drivers/hwmon/occ/scom.h                           |   50 +
 drivers/hwmon/power8_occ_i2c.c                     | 1254 --------------------
 23 files changed, 2076 insertions(+), 1287 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-ibm-occ.txt
 create mode 100644 drivers/hwmon/occ/Kconfig
 create mode 100644 drivers/hwmon/occ/Makefile
 create mode 100644 drivers/hwmon/occ/occ.c
 create mode 100644 drivers/hwmon/occ/occ.h
 create mode 100644 drivers/hwmon/occ/occ_p8.c
 create mode 100644 drivers/hwmon/occ/occ_p8.h
 create mode 100644 drivers/hwmon/occ/occ_p8_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_p9.c
 create mode 100644 drivers/hwmon/occ/occ_p9.h
 create mode 100644 drivers/hwmon/occ/occ_p9_fsi.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.h
 create mode 100644 drivers/hwmon/occ/occ_sysfs.c
 create mode 100644 drivers/hwmon/occ/occ_sysfs.h
 create mode 100644 drivers/hwmon/occ/scom.h
 delete mode 100644 drivers/hwmon/power8_occ_i2c.c
Signature · 1 line
2.9.3
#2 lore raw

RFC PATCH 1/9 Revert "hwmon: Add Power8 OCC hwmon driver"

From: "Edward A. James" <[email protected]>

Remove old P8 OCC driver.

---
 .../devicetree/bindings/i2c/i2c-ibm-occ.txt        |   13 -
 drivers/hwmon/Kconfig                              |   13 -
 drivers/hwmon/Makefile                             |    1 -
 drivers/hwmon/power8_occ_i2c.c                     | 1254 --------------------
 4 files changed, 1281 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-ibm-occ.txt
 delete mode 100644 drivers/hwmon/power8_occ_i2c.c
Documentation/devicetree/bindings/i2c/i2c-ibm-occ.txt deleted +0 -13
deleted file mode 100644
index 9aab2df8c5ed..000000000000
@@ -1,13 +0,0 @@
-HWMON i2c driver for IBM POWER CPU OCC (On Chip Controller)
-
-Required properties:
- - compatible: must be "ibm,power8-occ-i2c"
- - reg: physical address
-
-Example:
-i2c3: i2c-bus@100 {
-	occ@50 {
-		compatible = "ibm,occ-i2c";
-		reg = <0x50>;
-	};
-};
drivers/hwmon/Kconfig +0 -13
index d4de8d5aeed4..367496c9a721 100644
@@ -1226,19 +1226,6 @@ config SENSORS_NSA320
 	  This driver can also be built as a module. If so, the module
 	  will be called nsa320-hwmon.
 
-config SENSORS_POWER8_OCC_I2C
-	tristate "Power8 On Chip Controller i2c driver"
-	depends on I2C
-	help
-	  If you say yes here you get support to monitor Power8 CPU
-	  sensors via the On Chip Controller (OCC) over the i2c bus.
-
-	  Generally this is used by management controllers such as a BMC
-	  on an OpenPower system.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called power8_occ_i2c.
-
 config SENSORS_PCF8591
 	tristate "Philips PCF8591 ADC/DAC"
 	depends on I2C
drivers/hwmon/Makefile +0 -1
index 4455478e9e7a..d7ccb02ef220 100644
@@ -128,7 +128,6 @@ obj-$(CONFIG_SENSORS_NCT7802)	+= nct7802.o
 obj-$(CONFIG_SENSORS_NCT7904)	+= nct7904.o
 obj-$(CONFIG_SENSORS_NSA320)	+= nsa320-hwmon.o
 obj-$(CONFIG_SENSORS_NTC_THERMISTOR)	+= ntc_thermistor.o
-obj-$(CONFIG_SENSORS_POWER8_OCC_I2C)	+= power8_occ_i2c.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
drivers/hwmon/power8_occ_i2c.c deleted +0 -1254

1,254 lines not on this page · raw message

Signature · 1 line
2.9.3
#3 lore raw

RFC PATCH 2/9 hwmon: Add core On-Chip Controller support for POWER CPUs

In reply to Andrew Jeffery

The On-Chip Controller (OCC) exposes frequency and temperature sensor information along with power draw measurement and capping for POWER chips. The information is gathered by SCOM reads and writes over a transport of choice, and structured in a flexible fashion to accomodate differences in sensors across designs.

Add core support for querying and parsing the data structures provided by the OCC via SCOMs.

---
 drivers/hwmon/Kconfig      |   2 +
 drivers/hwmon/Makefile     |   1 +
 drivers/hwmon/occ/Kconfig  |  15 ++
 drivers/hwmon/occ/Makefile |   1 +
 drivers/hwmon/occ/occ.c    | 494 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ.h    |  79 ++++++++
 drivers/hwmon/occ/scom.h   |  50 +++++
 7 files changed, 642 insertions(+)
 create mode 100644 drivers/hwmon/occ/Kconfig
 create mode 100644 drivers/hwmon/occ/Makefile
 create mode 100644 drivers/hwmon/occ/occ.c
 create mode 100644 drivers/hwmon/occ/occ.h
 create mode 100644 drivers/hwmon/occ/scom.h
drivers/hwmon/Kconfig +2 -0
index 367496c9a721..f4b0180925a0 100644
@@ -1226,6 +1226,8 @@ config SENSORS_NSA320
 	  This driver can also be built as a module. If so, the module
 	  will be called nsa320-hwmon.
 
+source drivers/hwmon/occ/Kconfig
+
 config SENSORS_PCF8591
 	tristate "Philips PCF8591 ADC/DAC"
 	depends on I2C
drivers/hwmon/Makefile +1 -0
index d7ccb02ef220..f6af1a7713f1 100644
@@ -165,6 +165,7 @@ obj-$(CONFIG_SENSORS_WM831X)	+= wm831x-hwmon.o
 obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
 
 obj-$(CONFIG_PMBUS)		+= pmbus/
+obj-$(CONFIG_SENSORS_PPC_OCC)	+= occ/
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
 
drivers/hwmon/occ/Kconfig new file +15 -0
new file mode 100644
index 000000000000..cdb64a71af6e
@@ -0,0 +1,15 @@
+#
+# On Chip Controller configuration
+#
+
+menuconfig SENSORS_PPC_OCC
+	bool "PPC On-Chip Controller"
+	help
+	  If you say yes here you get support to monitor Power CPU
+	  sensors via the On-Chip Controller (OCC).
+
+	  Generally this is used by management controllers such as a BMC
+	  on an OpenPower system.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called occ.
drivers/hwmon/occ/Makefile new file +1 -0
new file mode 100644
index 000000000000..93cb52f8dd8c
@@ -0,0 +1 @@
+obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o
drivers/hwmon/occ/occ.c new file +494 -0

494 lines not on this page · raw message

drivers/hwmon/occ/occ.h new file +79 -0

79 lines not on this page · raw message

drivers/hwmon/occ/scom.h new file +50 -0

50 lines not on this page · raw message

Signature · 1 line
2.9.3
#4 lore raw

RFC PATCH 3/9 hwmon: occ: Add sysfs interface

In reply to Andrew Jeffery

Add a generic mechanism to expose the sensors provided by the OCC in sysfs.

---
 drivers/hwmon/occ/Makefile    |   2 +-
 drivers/hwmon/occ/occ_sysfs.c | 498 ++++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ_sysfs.h |  51 +++++
 3 files changed, 550 insertions(+), 1 deletion(-)
 create mode 100644 drivers/hwmon/occ/occ_sysfs.c
 create mode 100644 drivers/hwmon/occ/occ_sysfs.h
drivers/hwmon/occ/Makefile +1 -1
index 93cb52f8dd8c..a6881f93067c 100644
@@ -1 +1 @@
-obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o
+obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
drivers/hwmon/occ/occ_sysfs.c new file +498 -0

498 lines not on this page · raw message

drivers/hwmon/occ/occ_sysfs.h new file +51 -0

51 lines not on this page · raw message

Signature · 1 line
2.9.3
#5 lore raw

RFC PATCH 4/9 hwmon: occ: Add I2C SCOM transport implementation

In reply to Andrew Jeffery

The BMC queries the OCC on POWER8 chips with SCOMs over I2C.

---
 drivers/hwmon/occ/occ_scom_i2c.c | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ_scom_i2c.h | 20 ++++++++++++
 2 files changed, 88 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.h
drivers/hwmon/occ/occ_scom_i2c.c new file +68 -0
new file mode 100644
index 000000000000..b1a060331c4a
@@ -0,0 +1,68 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "scom.h"
+#include "occ_scom_i2c.h"
+
+#define OCC_I2C_NAME	"occ-p8-i2c"
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+	ssize_t rc;
+	u64 buf;
+	struct i2c_client *client = bus;
+
+	rc = i2c_master_send(client, (const char *)&address, sizeof(u32));
+	if (rc != sizeof(u32))
+		return -SCOM_WRITE_ERROR;
+
+	rc = i2c_master_recv(client, (char *)&buf, sizeof(u64));
+	if (rc != sizeof(u64))
+		return -SCOM_READ_ERROR;
+
+	*((u64 *)&data[offset]) = be64_to_cpu(buf);
+
+	return 0;
+}
+EXPORT_SYMBOL(occ_i2c_getscom);
+
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+	u32 buf[3];
+	ssize_t rc;
+	struct i2c_client *client = bus;
+
+	buf[0] = address;
+	buf[1] = data1;
+	buf[2] = data0;
+
+	rc = i2c_master_send(client, (const char *)buf, sizeof(u32) * 3);
+	if (rc != sizeof(u32) * 3)
+		return -SCOM_WRITE_ERROR;
+
+	return 0;
+}
+EXPORT_SYMBOL(occ_i2c_putscom);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("I2C OCC SCOM transport");
+MODULE_LICENSE("GPL");
drivers/hwmon/occ/occ_scom_i2c.h new file +20 -0
new file mode 100644
index 000000000000..92225f4cd584
@@ -0,0 +1,20 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset);
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1);
Signature · 1 line
2.9.3
#6 lore raw

Re: [RFC PATCH linux 4/9] hwmon: occ: Add I2C SCOM transport implementation

Hi Andrew,

Just a general comment on this one. I'm not sure it's worth having an extra layer just to isolate these functions from the p8_i2c_getscom/putscom. Those just do the address shift for P8. But there's no situation where i2c is used that's not on the P8. So this seems like unnecessary complexity to me. I'm not sure, just a thought.

Thanks,
Eddie

Quoted 113 lines · Andrew Jeffery

The BMC queries the OCC on POWER8 chips with SCOMs over I2C.

---
 drivers/hwmon/occ/occ_scom_i2c.c | 68 ++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ_scom_i2c.h | 20 ++++++++++++
 2 files changed, 88 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.h
drivers/hwmon/occ/occ_scom_i2c.c new file +68 -0
new file mode 100644
index 000000000000..b1a060331c4a
@@ -0,0 +1,68 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "scom.h"
+#include "occ_scom_i2c.h"
+
+#define OCC_I2C_NAME   "occ-p8-i2c"
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+       ssize_t rc;
+       u64 buf;
+       struct i2c_client *client = bus;
+
+       rc = i2c_master_send(client, (const char *)&address, sizeof(u32));
+       if (rc != sizeof(u32))
+               return -SCOM_WRITE_ERROR;
+
+       rc = i2c_master_recv(client, (char *)&buf, sizeof(u64));
+       if (rc != sizeof(u64))
+               return -SCOM_READ_ERROR;
+
+       *((u64 *)&data[offset]) = be64_to_cpu(buf);
+
+       return 0;
+}
+EXPORT_SYMBOL(occ_i2c_getscom);
+
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+       u32 buf[3];
+       ssize_t rc;
+       struct i2c_client *client = bus;
+
+       buf[0] = address;
+       buf[1] = data1;
+       buf[2] = data0;
+
+       rc = i2c_master_send(client, (const char *)buf, sizeof(u32) * 3);
+       if (rc != sizeof(u32) * 3)
+               return -SCOM_WRITE_ERROR;
+
+       return 0;
+}
+EXPORT_SYMBOL(occ_i2c_putscom);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("I2C OCC SCOM transport");
+MODULE_LICENSE("GPL");
drivers/hwmon/occ/occ_scom_i2c.h new file +20 -1
new file mode 100644
index 000000000000..92225f4cd584
@@ -0,0 +1,20 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset);
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1);
--

2.9.3

#7 lore raw

Re: [RFC PATCH linux 4/9] hwmon: occ: Add I2C SCOM transport implementation

Quoted 7 lines · Eddie James

Hi Andrew,

Just a general comment on this one. I'm not sure it's worth having an extra layer just to isolate these functions from the p8_i2c_getscom/putscom. Those just do the address shift for P8. But there's no situation where i2c is used that's not on the P8. So this seems like unnecessary complexity to me. I'm not sure, just a thought.

My perspective is that baking P8 knowledge into the I2C SCOM operations
makes the code surprising. Maybe renaming the functions is enough,
something like p8_occ_getscom(). To me it doesn't seem like much cost in complexity to separate the transport from implementation-specific quirks with the addressing, and gaining a general approach in the process.

Maybe Joel can weigh in here?

Andrew

Quoted 118 lines

Thanks,
Eddie

Quoted 114 lines · Andrew Jeffery

The BMC queries the OCC on POWER8 chips with SCOMs over I2C.

Quoted 1 line
Quoted 1 line

---
 drivers/hwmon/occ/occ_scom_i2c.c | 68 ++++++++++++++++++++++++++++++++++++++++ drivers/hwmon/occ/occ_scom_i2c.h | 20 ++++++++++++

 2 files changed, 88 insertions(+)

 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.c create mode 100644 drivers/hwmon/occ/occ_scom_i2c.h

drivers/hwmon/occ/occ_scom_i2c.c new file +65 -0
new file mode 100644
index 000000000000..b1a060331c4a
@@ -0,0 +1,68 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "scom.h"
+#include "occ_scom_i2c.h"
+
+#define OCC_I2C_NAME   "occ-p8-i2c"
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+       ssize_t rc;
+       u64 buf;
+       struct i2c_client *client = bus;
+
+       rc = i2c_master_send(client, (const char *)&address, sizeof(u32));
+       if (rc != sizeof(u32))
+               return -SCOM_WRITE_ERROR;
+
+       rc = i2c_master_recv(client, (char *)&buf, sizeof(u64));
+       if (rc != sizeof(u64))
+               return -SCOM_READ_ERROR;
+
+       *((u64 *)&data[offset]) = be64_to_cpu(buf);
+
+       return 0;
+}
+EXPORT_SYMBOL(occ_i2c_getscom);
+
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+       u32 buf[3];
+       ssize_t rc;
+       struct i2c_client *client = bus;
+
+       buf[0] = address;
+       buf[1] = data1;
+       buf[2] = data0;
+
+       rc = i2c_master_send(client, (const char *)buf, sizeof(u32) * 3);
+       if (rc != sizeof(u32) * 3)
+               return -SCOM_WRITE_ERROR;
+
+       return 0;
+}
+EXPORT_SYMBOL(occ_i2c_putscom);
+
Quoted 1 line
Quoted 1 line

+MODULE_AUTHOR("Eddie James <[email protected]>");

drivers/hwmon/occ/occ_scom_i2c.c new file +2 -0
+MODULE_DESCRIPTION("I2C OCC SCOM transport");
+MODULE_LICENSE("GPL");
drivers/hwmon/occ/occ_scom_i2c.h new file +20 -1
new file mode 100644
index 000000000000..92225f4cd584
@@ -0,0 +1,20 @@
+/*
+ * occ_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+int occ_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset);
+int occ_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1);
--

2.9.3

#8 lore raw

RFC PATCH 5/9 hwmon: occ: Add callbacks for parsing P8 OCC datastructures

In reply to Andrew Jeffery
---
 drivers/hwmon/occ/occ_p8.c | 219 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ_p8.h |  30 +++++++
 2 files changed, 249 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p8.c
 create mode 100644 drivers/hwmon/occ/occ_p8.h
drivers/hwmon/occ/occ_p8.c new file +219 -0
new file mode 100644
index 000000000000..b2fa0cb6eb28
@@ -0,0 +1,219 @@
+/*
+ * p8.c - OCC hwmon driver
+ *
+ * This file contains the Power8-specific methods and data structures for
+ * the OCC hwmon driver.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "occ.h"
+#include "occ_p8.h"
+
+/* P8 OCC sensor data format */
+struct occ_sensor_p8 {
+	u16 sensor_id;
+	u16 value;
+};
+
+struct power_sensor_p8 {
+	u16 sensor_id;
+	u32 update_tag;
+	u32 accumulator;
+	u16 value;
+};
+
+struct caps_sensor_p8 {
+	u16 curr_powercap;
+	u16 curr_powerreading;
+	u16 norm_powercap;
+	u16 max_powercap;
+	u16 min_powercap;
+	u16 user_powerlimit;
+};
+
+void p8_parse_sensor(u8 *data, void *sensor, int sensor_type, int off,
+		     int snum)
+{
+	switch (sensor_type) {
+		case FREQ:
+		case TEMP:
+		{
+			struct occ_sensor_p8 *os =
+				&(((struct occ_sensor_p8 *)sensor)[snum]);
+			os->sensor_id =
+				be16_to_cpup((const __be16 *)&data[off]);
+			os->value =
+				be16_to_cpup((const __be16 *)&data[off + 2]);
+		}
+			break;
+		case POWER:
+		{
+			struct power_sensor_p8 *ps =
+				&(((struct power_sensor_p8 *)sensor)[snum]);
+			ps->sensor_id =
+				be16_to_cpup((const __be16 *)&data[off]);
+			ps->update_tag =
+				be32_to_cpup((const __be32 *)&data[off + 2]);
+			ps->accumulator =
+				be32_to_cpup((const __be32 *)&data[off + 6]);
+			ps->value =
+				be16_to_cpup((const __be16 *)&data[off + 10]);
+		}
+			break;
+		case CAPS:
+		{
+			struct caps_sensor_p8 *cs =
+				&(((struct caps_sensor_p8 *)sensor)[snum]);
+			cs->curr_powercap =
+				be16_to_cpup((const __be16 *)&data[off]);
+			cs->curr_powerreading =
+				be16_to_cpup((const __be16 *)&data[off + 2]);
+			cs->norm_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 4]);
+			cs->max_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 6]);
+			cs->min_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 8]);
+			cs->user_powerlimit =
+				be16_to_cpup((const __be16 *)&data[off + 10]);
+		}
+			break;
+	};
+}
+
+void * p8_alloc_sensor(int sensor_type, int num_sensors)
+{
+	switch (sensor_type) {
+		case FREQ:
+		case TEMP:
+			return kcalloc(num_sensors,
+				       sizeof(struct occ_sensor_p8),
+				       GFP_KERNEL);
+		case POWER:
+			return kcalloc(num_sensors,
+				       sizeof(struct power_sensor_p8),
+				       GFP_KERNEL);
+		case CAPS:
+			return kcalloc(num_sensors,
+				       sizeof(struct caps_sensor_p8),
+				       GFP_KERNEL);
+		default:
+			return NULL;
+	}
+}
+
+int p8_get_sensor_value(struct occ *driver, int sensor_type, int snum)
+{
+	void *sensor;
+
+	if (sensor_type == CAPS)
+		return -1;
+
+	sensor = occ_get_sensor(driver, sensor_type);
+	if (!sensor)
+		return -1;
+
+	switch (sensor_type) {
+		case FREQ:
+		case TEMP:
+			return ((struct occ_sensor_p8 *)sensor)[snum].value;
+		case POWER:
+			return ((struct power_sensor_p8 *)sensor)[snum].value;
+		default:
+			return -1;
+	}
+}
+
+int p8_get_sensor_id(struct occ *driver, int sensor_type, int snum)
+{
+	void *sensor;
+	int i = snum;
+
+	if (sensor_type == CAPS)
+		return -1;
+
+	sensor = occ_get_sensor(driver, sensor_type);
+	if (!sensor)
+		return -1;
+
+	switch (sensor_type) {
+		case FREQ:
+		case TEMP:
+			return ((struct occ_sensor_p8 *)sensor)[i].sensor_id;
+		case POWER:
+			return ((struct power_sensor_p8 *)sensor)[i].sensor_id;
+		default:
+			return -1;
+	}
+}
+
+int p8_get_caps_value(void *sensor, int snum, int caps_field)
+{
+	struct caps_sensor_p8 *caps_sensor = sensor;
+
+	switch (caps_field) {
+	case 0:
+		return caps_sensor[snum].curr_powercap;
+	case 1:
+		return caps_sensor[snum].curr_powerreading;
+	case 2:
+		return caps_sensor[snum].norm_powercap;
+	case 3:
+		return caps_sensor[snum].max_powercap;
+	case 4:
+		return caps_sensor[snum].min_powercap;
+	case 5:
+		return caps_sensor[snum].user_powerlimit;
+	default:
+		return -1;
+	}
+}
+
+static const struct occ_ops p8_ops = {
+	.parse_sensor = p8_parse_sensor,
+	.alloc_sensor = p8_alloc_sensor,
+	.get_sensor_value = p8_get_sensor_value,
+	.get_sensor_id = p8_get_sensor_id,
+	.get_caps_value = p8_get_caps_value,
+};
+
+static const struct occ_config p8_config = {
+	.command_addr = 0xFFFF6000,
+	.response_addr = 0xFFFF7000,
+};
+
+struct occ *occ_p8_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops)
+{
+	return occ_start(dev, bus, bus_ops, p8_ops, p8_config);
+}
+EXPORT_SYMBOL(occ_p8_start);
+
+int occ_p8_stop(struct occ *occ)
+{
+	return occ_stop(occ);
+}
+EXPORT_SYMBOL(occ_p8_stop);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("P8 OCC sensors");
+MODULE_LICENSE("GPL");
drivers/hwmon/occ/occ_p8.h new file +30 -0
new file mode 100644
index 000000000000..acae34323a6b
@@ -0,0 +1,30 @@
+/*
+ * p8.h - OCC hwmon driver
+ *
+ * This file contains Power8-specific function prototypes
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __P8_H__
+#define __P8_H__
+
+#include "scom.h"
+
+struct device;
+
+struct occ *occ_p8_start(struct device *dev, void *bus,
+			 struct occ_bus_ops bus_ops);
+int occ_p8_stop(struct occ *occ);
+
+#endif /* __P8_H__ */
Signature · 1 line
2.9.3
#9 lore raw

RFC PATCH 6/9 hwmon: occ: Add hwmon implementation for the P8 OCC

In reply to Andrew Jeffery
---
 drivers/hwmon/occ/Kconfig      |  14 +++++
 drivers/hwmon/occ/Makefile     |   1 +
 drivers/hwmon/occ/occ_p8_i2c.c | 133 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p8_i2c.c
drivers/hwmon/occ/Kconfig +14 -0
index cdb64a71af6e..085e1f370c42 100644
@@ -13,3 +13,17 @@ menuconfig SENSORS_PPC_OCC
 
 	  This driver can also be built as a module. If so, the module
 	  will be called occ.
+
+if SENSORS_PPC_OCC
+
+config SENSORS_PPC_OCC_P8_I2C
+	tristate "POWER8 OCC hwmon support"
+	depends on I2C
+	help
+	  Provide a hwmon sysfs interface for the POWER8 On-Chip Controller,
+	  exposing temperature, frequency and power measurements.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called occ-p8-i2c.
+
+endif
drivers/hwmon/occ/Makefile +1 -0
index a6881f93067c..05a84e987127 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
+obj-$(CONFIG_SENSORS_PPC_OCC_P8_I2C) += occ_scom_i2c.o occ_p8.o occ_p8_i2c.o
drivers/hwmon/occ/occ_p8_i2c.c new file +133 -0

133 lines not on this page · raw message

Signature · 1 line
2.9.3
#10 lore raw

Re: [RFC PATCH linux 6/9] hwmon: occ: Add hwmon implementation for the P8 OCC

Hi Andrew,

One comment on this one.

Thanks,
Eddie

Quoted 76 lines · Andrew Jeffery
---
 drivers/hwmon/occ/Kconfig      |  14 +++++
 drivers/hwmon/occ/Makefile     |   1 +
 drivers/hwmon/occ/occ_p8_i2c.c | 133 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p8_i2c.c
drivers/hwmon/occ/Kconfig +14 -0
index cdb64a71af6e..085e1f370c42 100644
@@ -13,3 +13,17 @@ menuconfig SENSORS_PPC_OCC
 
          This driver can also be built as a module. If so, the module
          will be called occ.
+
+if SENSORS_PPC_OCC
+
+config SENSORS_PPC_OCC_P8_I2C
+       tristate "POWER8 OCC hwmon support"
+       depends on I2C
+       help
+         Provide a hwmon sysfs interface for the POWER8 On-Chip Controller,
+         exposing temperature, frequency and power measurements.
+
+         This driver can also be built as a module. If so, the module will be
+         called occ-p8-i2c.
+
+endif
drivers/hwmon/occ/Makefile +1 -0
index a6881f93067c..05a84e987127 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
+obj-$(CONFIG_SENSORS_PPC_OCC_P8_I2C) += occ_scom_i2c.o occ_p8.o occ_p8_i2c.o
drivers/hwmon/occ/occ_p8_i2c.c new file +33 -0
new file mode 100644
index 000000000000..1b66f302fe16
@@ -0,0 +1,133 @@
+/*
+ * occ_p8_i2c.c - hwmon OCC driver
+ *
+ * This file contains the i2c layer for accessing the OCC over i2c bus.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "scom.h"
+#include "occ_scom_i2c.h"
+#include "occ_p8.h"
+#include "occ_sysfs.h"
+

drivers/hwmon/occ/occ_p8_i2c.c line 43

Quoted 10 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +10 -0
+#define OCC_I2C_NAME   "occ-p8-i2c"
+
+static char *caps_sensor_names[] = {
+       "curr_powercap",
+       "curr_powerreading",
+       "norm_powercap",
+       "max_powercap",
+       "min_powercap",
+       "user_powerlimit"
+};

Does it make more sense to define this in the P8 callbacks code?

Quoted 16 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +16 -0
+
+int p8_i2c_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+       /* P8 i2c slave requires address to be shifted by 1 */
+       address = address << 1;
+
+       return occ_i2c_getscom(bus, address, data, offset);
+}
+
+int p8_i2c_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+       /* P8 i2c slave requires address to be shifted by 1 */
+       address = address << 1;
+
+       return occ_i2c_putscom(bus, address, data0, data1);
+}

drivers/hwmon/occ/occ_p8_i2c.c line 69

Quoted 10 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +10 -0
+
+static struct occ_bus_ops p8_bus_ops = {
+       .getscom = p8_i2c_getscom,
+       .putscom = p8_i2c_putscom,
+};
+
+static struct occ_sysfs_config p8_sysfs_config = {
+       .num_caps_fields = ARRAY_SIZE(caps_sensor_names),
+       .caps_names = caps_sensor_names,
+};

Same as above for this structure.

drivers/hwmon/occ/occ_p8_i2c.c line 81

Quoted 12 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +12 -0
+
+static int occ_p8_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct occ *occ;
+       struct occ_sysfs *hwmon;
+
+       occ = occ_p8_start(&client->dev, client, p8_bus_ops);
+       if (IS_ERR(occ))
+               return PTR_ERR(occ);
+
+       hwmon = occ_sysfs_start(&client->dev, occ, &p8_sysfs_config);

I see why you defined those here. But I guess I don't see why occ_sysfs_config has to be separate from occ_config structure. It could be populated in occ_p8_start and then passed to occ_sysfs_start here.

Quoted 55 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +52 -1
+       if (IS_ERR(hwmon))
+               return PTR_ERR(hwmon);
+
+       i2c_set_clientdata(client, hwmon);
+
+       return 0;
+}
+
+static int occ_p8_remove(struct i2c_client *client)
+{
+       return occ_p8_stop(i2c_get_clientdata(client));
+}
+
+/* used by old-style board info. */
+static const struct i2c_device_id occ_ids[] = {
+       { OCC_I2C_NAME, 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, occ_ids);
+
+/* used by device table */
+static const struct of_device_id occ_of_match[] = {
+       { .compatible = "ibm,occ-p8-i2c" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, occ_of_match);
+
+/*
+ * i2c-core uses i2c-detect() to detect device in below address list.
+ * If exists, address will be assigned to client.
+ * It is also possible to read address from device table.
+ */
+static const unsigned short normal_i2c[] = {0x50, 0x51, I2C_CLIENT_END };
+
+static struct i2c_driver occ_p8_driver = {
+       .class = I2C_CLASS_HWMON,
+       .driver = {
+               .name = OCC_I2C_NAME,
+               .pm = NULL,
+               .of_match_table = occ_of_match,
+       },
+       .probe = occ_p8_probe,
+       .remove = occ_p8_remove,
+       .id_table = occ_ids,
+       .address_list = normal_i2c,
+};
+
+module_i2c_driver(occ_p8_driver);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("BMC P8 OCC hwmon driver");
+MODULE_LICENSE("GPL");
--

2.9.3

#11 lore raw

Re: [RFC PATCH linux 6/9] hwmon: occ: Add hwmon implementation for the P8 OCC

Quoted 14 lines · Eddie James

drivers/hwmon/occ/occ_p8_i2c.c

Quoted 12 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +12 -0
+
+static int occ_p8_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct occ *occ;
+       struct occ_sysfs *hwmon;
+
+       occ = occ_p8_start(&client->dev, client, p8_bus_ops);
+       if (IS_ERR(occ))
+               return PTR_ERR(occ);
+
+       hwmon = occ_sysfs_start(&client->dev, occ,

&p8_sysfs_config);

Quoted 4 lines

I see why you defined those here. But I guess I don't see why occ_sysfs_config has to be separate from occ_config structure. It could be populated in occ_p8_start and then passed to occ_sysfs_start here.

I admit getting to this point was a little tricky, and I'm not completely satisfied by what I've come up with. Here's my reasoning:

I felt that only half of your struct occ_protocol dealt with SCOM protocol problems, specifically the command_addr and response_addr members. num_caps_fields and caps_names were only used in the sysfs code where they are relevant for interpretation of the payload, but are not in transacting SCOMs. Therefore I removed them from struct occ_protocol.

I also renamed struct occ_protocol to occ_config. I could live with either name but my feeling is it's more obvious that the consumer of the API needs to populate a struct with 'config' in its name.

Given I'd removed num_caps_fields and caps_names I had to put the information somewhere. One place might be in struct occ as I've interpreted your suggestion above. However, I was trying to keep struct occ opaque so in occ.c could fully encapsulate its behaviour. As struct occ is opaque, occ_sysfs.c has no visibility into its members and thus can't access anything we stash in it, e.g. num_caps_fields and caps_names.

That leaves us with needing some other solution, one of which I've implemented above. It achieves the goals I was outlining above and keeps the sysfs code free of any implementation specifics, at the cost of describing the information in a slightly weird spot.

An alternative might be to define struct occ_sysfs_config in occ_p8.c and add an extern to occ_p8.h. That bakes sysfs knowledge into the p8 header which to me feels more unfortunate than my current approach. Or, define say p8_caps_names and p8_num_caps in occ_p8.c and extern those in occ_p8.h and use them to define a struct occ_sysfs_config here. What do you think?

Andrew

#12 lore raw

Re: [RFC PATCH linux 6/9] hwmon: occ: Add hwmon implementation for the P8 OCC

Quoted 23 lines · Andrew Jeffery
Quoted 14 lines · Eddie James

drivers/hwmon/occ/occ_p8_i2c.c

Quoted 12 lines
drivers/hwmon/occ/occ_p8_i2c.c new file +12 -0
+
+static int occ_p8_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct occ *occ;
+       struct occ_sysfs *hwmon;
+
+       occ = occ_p8_start(&client->dev, client, p8_bus_ops);
+       if (IS_ERR(occ))
+               return PTR_ERR(occ);
+
+       hwmon = occ_sysfs_start(&client->dev, occ,

&p8_sysfs_config);

Quoted 4 lines

I see why you defined those here. But I guess I don't see why occ_sysfs_config has to be separate from occ_config structure. It could be populated in occ_p8_start and then passed to occ_sysfs_start here.

I admit getting to this point was a little tricky, and I'm not completely satisfied by what I've come up with. Here's my reasoning:

Quoted 6 lines

I felt that only half of your struct occ_protocol dealt with SCOM protocol problems, specifically the command_addr and response_addr members. num_caps_fields and caps_names were only used in the sysfs code where they are relevant for interpretation of the payload, but are not in transacting SCOMs. Therefore I removed them from struct occ_protocol.

Makes sense.

Quoted 18 lines

I also renamed struct occ_protocol to occ_config. I could live with either name but my feeling is it's more obvious that the consumer of the API needs to populate a struct with 'config' in its name.

Given I'd removed num_caps_fields and caps_names I had to put the information somewhere. One place might be in struct occ as I've interpreted your suggestion above. However, I was trying to keep struct occ opaque so in occ.c could fully encapsulate its behaviour. As struct occ is opaque, occ_sysfs.c has no visibility into its members and thus can't access anything we stash in it, e.g. num_caps_fields and caps_names.

That leaves us with needing some other solution, one of which I've implemented above. It achieves the goals I was outlining above and keeps the sysfs code free of any implementation specifics, at the cost of describing the information in a slightly weird spot.

Quoted 6 lines

An alternative might be to define struct occ_sysfs_config in occ_p8.c and add an extern to occ_p8.h. That bakes sysfs knowledge into the p8 header which to me feels more unfortunate than my current approach. Or, define say p8_caps_names and p8_num_caps in occ_p8.c and extern those in occ_p8.h and use them to define a struct occ_sysfs_config here. What do you think?

I think your solution is fine, I was just a bit confused as to why you decided to do that. Let's stick with your solution, it's better than putting it in the headers.

Thanks,
Eddie

#13 lore raw

RFC PATCH 7/9 arm: aspeed: dt: Fix OCC compatible strings

In reply to Andrew Jeffery
---
 arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts | 4 ++--
 arch/arm/boot/dts/aspeed-bmc-opp-firestone.dts | 4 ++--
 arch/arm/boot/dts/aspeed-bmc-opp-garrison.dts  | 4 ++--
 arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts  | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)
arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts +2 -2
index 6ca618bd331d..6bbc7817e823 100644
@@ -110,12 +110,12 @@
 	status = "okay";
 
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 
 	occ@51 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x51>;
 	};
 };
arch/arm/boot/dts/aspeed-bmc-opp-firestone.dts +2 -2
index e677e9ff00b8..b88baf5d7add 100644
@@ -122,7 +122,7 @@
 
 	// turismo
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 
@@ -137,7 +137,7 @@
 
 	// turismo
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 
arch/arm/boot/dts/aspeed-bmc-opp-garrison.dts +2 -2
index a4471fb3b36b..461de1eaf108 100644
@@ -63,7 +63,7 @@
 	status = "okay";
 
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 };
@@ -72,7 +72,7 @@
 	status = "okay";
 
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 };
arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts +1 -1
index 0fd60c4eafad..7426110f053f 100644
@@ -127,7 +127,7 @@
 	status = "okay";
 
 	occ@50 {
-		compatible = "ibm,occ-i2c";
+		compatible = "ibm,occ-p8-i2c";
 		reg = <0x50>;
 	};
 };
Signature · 1 line
2.9.3
#14 lore raw

RFC PATCH 8/9 hwmon: occ: Add callbacks for parsing P9 OCC datastructures

In reply to Andrew Jeffery
---
 drivers/hwmon/occ/occ_p9.c | 261 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/hwmon/occ/occ_p9.h |  30 ++++++
 2 files changed, 291 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p9.c
 create mode 100644 drivers/hwmon/occ/occ_p9.h
drivers/hwmon/occ/occ_p9.c new file +261 -0
new file mode 100644
index 000000000000..b8986290948b
@@ -0,0 +1,261 @@
+/*
+ * p9.c - OCC hwmon driver
+ *
+ * This file contains the Power9-specific methods and data structures for
+ * the OCC hwmon driver.
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "occ.h"
+#include "occ_p9.h"
+
+/* P9 OCC sensor data format */
+struct temp_sensor_p9 {
+	u32 sensor_id;
+	u8 fru_type;
+	u8 value;
+};
+
+struct freq_sensor_p9 {
+	u32 sensor_id;
+	u16 value;
+};
+
+struct power_sensor_p9 {
+	u32 sensor_id;
+	u8 function_id;
+	u8 apss_channel;
+	u16 reserved;
+	u32 update_tag;
+	u64 accumulator;
+	u16 value;
+};
+
+struct caps_sensor_p9 {
+	u16 curr_powercap;
+	u16 curr_powerreading;
+	u16 norm_powercap;
+	u16 max_powercap;
+	u16 min_powercap;
+	u16 user_powerlimit;
+	u8 user_powerlimit_source;
+};
+
+/*
+static char *caps_sensor_names[] = {
+	"curr_powercap",
+	"curr_powerreading",
+	"norm_powercap",
+	"max_powercap",
+	"min_powercap",
+	"user_powerlimit",
+	"user_powerlimit_source"
+};
+*/
+
+void p9_parse_sensor(u8 *data, void *sensor, int sensor_type, int off,
+		     int snum)
+{
+	switch (sensor_type) {
+		case FREQ:
+		{
+			struct freq_sensor_p9 *fs =
+				&(((struct freq_sensor_p9 *)sensor)[snum]);
+			fs->sensor_id =
+				be32_to_cpup((const __be32 *)&data[off]);
+			fs->value =
+				be16_to_cpup((const __be16 *)&data[off + 4]);
+		}
+			break;
+		case TEMP:
+		{
+			struct temp_sensor_p9 *ts =
+				&(((struct temp_sensor_p9 *)sensor)[snum]);
+			ts->sensor_id =
+				be32_to_cpup((const __be32 *)&data[off]);
+			ts->fru_type = data[off + 4];
+			ts->value = data[off + 5];
+		}
+			break;
+		case POWER:
+		{
+			struct power_sensor_p9 *ps =
+				&(((struct power_sensor_p9 *)sensor)[snum]);
+			ps->sensor_id =
+				be32_to_cpup((const __be32 *)&data[off]);
+			ps->function_id = data[off + 4];
+			ps->apss_channel = data[off + 5];
+			/* two bytes reserved */
+			ps->update_tag =
+				be32_to_cpup((const __be32 *)&data[off + 8]);
+			ps->accumulator =
+				be64_to_cpup((const __be64 *)&data[off + 12]);
+			ps->value =
+				be16_to_cpup((const __be16 *)&data[off + 20]);
+		}
+			break;
+		case CAPS:
+		{
+			struct caps_sensor_p9 *cs =
+				&(((struct caps_sensor_p9 *)sensor)[snum]);
+			cs->curr_powercap =
+				be16_to_cpup((const __be16 *)&data[off]);
+			cs->curr_powerreading =
+				be16_to_cpup((const __be16 *)&data[off + 2]);
+			cs->norm_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 4]);
+			cs->max_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 6]);
+			cs->min_powercap =
+				be16_to_cpup((const __be16 *)&data[off + 8]);
+			cs->user_powerlimit =
+				be16_to_cpup((const __be16 *)&data[off + 10]);
+			cs->user_powerlimit_source = data[off + 12];
+		}
+			break;
+	};
+}
+
+void * p9_alloc_sensor(int sensor_type, int num_sensors)
+{
+	switch (sensor_type) {
+		case FREQ:
+			return kcalloc(num_sensors,
+				       sizeof(struct freq_sensor_p9),
+				       GFP_KERNEL);
+		case TEMP:
+			return kcalloc(num_sensors,
+				       sizeof(struct temp_sensor_p9),
+				       GFP_KERNEL);
+		case POWER:
+			return kcalloc(num_sensors,
+				       sizeof(struct power_sensor_p9),
+				       GFP_KERNEL);
+		case CAPS:
+			return kcalloc(num_sensors,
+				       sizeof(struct caps_sensor_p9),
+				       GFP_KERNEL);
+		default:
+			return NULL;
+	}
+}
+
+int p9_get_sensor_value(struct occ *driver, int sensor_type, int snum)
+{
+	void *sensor;
+
+	if (sensor_type == CAPS)
+		return -1;
+
+	sensor = occ_get_sensor(driver, sensor_type);
+	if (!sensor)
+		return -1;
+
+	switch (sensor_type) {
+		case FREQ:
+			return ((struct freq_sensor_p9 *)sensor)[snum].value; 
+		case TEMP:
+			return ((struct temp_sensor_p9 *)sensor)[snum].value;
+		case POWER:
+			return ((struct power_sensor_p9 *)sensor)[snum].value;
+		default:
+			return -1;
+	}
+}
+
+int p9_get_sensor_id(struct occ *driver, int sensor_type, int snum)
+{
+	void *sensor;
+	int i = snum;
+
+	if (sensor_type == CAPS)
+		return -1;
+
+	sensor = occ_get_sensor(driver, sensor_type);
+	if (!sensor)
+		return -1;
+
+	switch (sensor_type) {
+		case FREQ:
+			return ((struct freq_sensor_p9 *)sensor)[i].sensor_id;
+		case TEMP:
+			return ((struct temp_sensor_p9 *)sensor)[i].sensor_id;
+		case POWER:
+			return ((struct power_sensor_p9 *)sensor)[i].sensor_id;
+		default:
+			return -1;
+	}
+}
+
+int p9_get_caps_value(void *sensor, int snum, int caps_field)
+{
+	struct caps_sensor_p9 *caps_sensor = sensor;
+
+	switch (caps_field) {
+	case 0:
+		return caps_sensor[snum].curr_powercap;
+	case 1:
+		return caps_sensor[snum].curr_powerreading;
+	case 2:
+		return caps_sensor[snum].norm_powercap;
+	case 3:
+		return caps_sensor[snum].max_powercap;
+	case 4:
+		return caps_sensor[snum].min_powercap;
+	case 5:
+		return caps_sensor[snum].user_powerlimit;
+	case 6:
+		return caps_sensor[snum].user_powerlimit_source;
+	default:
+		return -1;
+	}
+}
+static const struct occ_ops p9_ops = {
+	.parse_sensor = p9_parse_sensor,
+	.alloc_sensor = p9_alloc_sensor,
+	.get_sensor_value = p9_get_sensor_value,
+	.get_sensor_id = p9_get_sensor_id,
+	.get_caps_value = p9_get_caps_value,
+};
+
+static const struct occ_config p9_config = {
+	.command_addr = 0xFFFBE000,
+	.response_addr = 0xFFFBF000,
+};
+
+struct occ *occ_p9_start(struct device *dev, void *bus,
+			 struct occ_bus_ops bus_ops)
+{
+	return occ_start(dev, bus, bus_ops, p9_ops, p9_config);
+}
+EXPORT_SYMBOL(occ_p9_start);
+
+int occ_p9_stop(struct occ *occ)
+{
+	return occ_stop(occ);
+}
+EXPORT_SYMBOL(occ_p9_stop);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("P9 OCC sensors");
+MODULE_LICENSE("GPL");
drivers/hwmon/occ/occ_p9.h new file +30 -0
new file mode 100644
index 000000000000..52b38278238b
@@ -0,0 +1,30 @@
+/*
+ * p9.h - OCC hwmon driver
+ *
+ * This file contains Power9-specific function prototypes
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __P9_H__
+#define __P9_H__
+
+#include "scom.h"
+#include "occ.h"
+
+struct device;
+
+struct occ *occ_p9_start(struct device *dev, void *bus, struct occ_bus_ops bus_ops);
+int occ_p9_stop(struct occ *occ);
+
+#endif /* __P9_H__ */
Signature · 1 line
2.9.3
#15 lore raw

RFC PATCH 9/9 wip: hwmon: occ: Add sketch of the hwmon implementation for the P9 OCC

In reply to Andrew Jeffery
---
 drivers/hwmon/occ/Kconfig      |  9 ++++
 drivers/hwmon/occ/Makefile     |  1 +
 drivers/hwmon/occ/occ_p9_fsi.c | 93 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p9_fsi.c
drivers/hwmon/occ/Kconfig +9 -0
index 085e1f370c42..97b97b391bf9 100644
@@ -26,4 +26,13 @@ config SENSORS_PPC_OCC_P8_I2C
 	  This driver can also be built as a module. If so, the module will be
 	  called occ-p8-i2c.
 
+config SENSORS_PPC_OCC_P9_FSI
+	tristate "POWER9 OCC hwmon support"
+	help
+	  Provide a hwmon sysfs interface for the POWER9 On-Chip Controller,
+	  exposing temperature, frequency and power measurements.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called occ-p9-fsi.
+
 endif
drivers/hwmon/occ/Makefile +1 -0
index 05a84e987127..77e47e10195e 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
 obj-$(CONFIG_SENSORS_PPC_OCC_P8_I2C) += occ_scom_i2c.o occ_p8.o occ_p8_i2c.o
+obj-$(CONFIG_SENSORS_PPC_OCC_P9_FSI) += occ_p9.o occ_p9_fsi.o
drivers/hwmon/occ/occ_p9_fsi.c new file +93 -0

93 lines not on this page · raw message

Signature · 1 line
2.9.3
#16 lore raw

Re: [RFC PATCH linux 9/9] wip: hwmon: occ: Add sketch of the hwmon implementation for the P9 OCC

Hi Andrew,

Looks pretty good. Do we need to get this finalized before getting into our kernel or submitting it upstream? I don't think the SBE or FSI interfaces are nailed down, are they?

Eddie

Quoted 136 lines · Andrew Jeffery
---
 drivers/hwmon/occ/Kconfig      |  9 ++++
 drivers/hwmon/occ/Makefile     |  1 +
 drivers/hwmon/occ/occ_p9_fsi.c | 93 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)
 create mode 100644 drivers/hwmon/occ/occ_p9_fsi.c
drivers/hwmon/occ/Kconfig +9 -0
index 085e1f370c42..97b97b391bf9 100644
@@ -26,4 +26,13 @@ config SENSORS_PPC_OCC_P8_I2C
          This driver can also be built as a module. If so, the module will be
          called occ-p8-i2c.
 
+config SENSORS_PPC_OCC_P9_FSI
+       tristate "POWER9 OCC hwmon support"
+       help
+         Provide a hwmon sysfs interface for the POWER9 On-Chip Controller,
+         exposing temperature, frequency and power measurements.
+
+         This driver can also be built as a module. If so, the module will be
+         called occ-p9-fsi.
+
 endif
drivers/hwmon/occ/Makefile +1 -0
index 05a84e987127..77e47e10195e 100644
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
 obj-$(CONFIG_SENSORS_PPC_OCC_P8_I2C) += occ_scom_i2c.o occ_p8.o occ_p8_i2c.o
+obj-$(CONFIG_SENSORS_PPC_OCC_P9_FSI) += occ_p9.o occ_p9_fsi.o
drivers/hwmon/occ/occ_p9_fsi.c new file +93 -1
new file mode 100644
index 000000000000..2f651d1b16bf
@@ -0,0 +1,93 @@
+/*
+ * occ_p9_fsi.c - hwmon OCC driver
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "scom.h"
+#include "occ_p9.h"
+#include "occ_sysfs.h"
+
+#define OCC_I2C_NAME   "occ-p9-fsi"
+
+static char *caps_sensor_names[] = {
+       "curr_powercap",
+       "curr_powerreading",
+       "norm_powercap",
+       "max_powercap",
+       "min_powercap",
+       "user_powerlimit"
+};
+
+int p9_fsi_getscom(void *bus, u32 address, u8 *data, size_t offset)
+{
+       return -SCOM_READ_ERROR;
+}
+
+int p9_fsi_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+       return -SCOM_WRITE_ERROR;
+}
+
+static struct occ_bus_ops p9_bus_ops = {
+       .getscom = p9_fsi_getscom,
+       .putscom = p9_fsi_putscom,
+};
+
+static struct occ_sysfs_config p9_sysfs_config = {
+       .num_caps_fields = ARRAY_SIZE(caps_sensor_names),
+       .caps_names = caps_sensor_names,
+};
+
+int occ_p9_probe(struct device *dev, void *client)
+{
+       struct occ *occ;
+       struct occ_sysfs *hwmon;
+
+       occ = occ_p9_start(dev, client, p9_bus_ops);
+       if (IS_ERR(occ))
+               return PTR_ERR(occ);
+
+       hwmon = occ_sysfs_start(dev, occ, &p9_sysfs_config);
+       if (IS_ERR(hwmon))
+               return PTR_ERR(hwmon);
+
+       return 0;
+}
+
+int occ_p9_remove(void)
+{
+       struct occ *occ = NULL;
+
+       return occ_p9_stop(occ);
+}
+
+/* used by device table */
+static const struct of_device_id occ_of_match[] = {
+       { .compatible = "ibm,occ-p9-fsi" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, occ_of_match);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("BMC P9 OCC hwmon driver");
+MODULE_LICENSE("GPL");
--

2.9.3

#17 lore raw

Re: [RFC PATCH linux 9/9] wip: hwmon: occ: Add sketch of the hwmon implementation for the P9 OCC

Quoted 5 lines · Eddie James

Hi Andrew,

Looks pretty good. Do we need to get this finalized before getting into our kernel or submitting it upstream? I don't think the SBE or FSI interfaces are nailed down, are they?

This patch is a complete hack only to illustrate how the abstractions would work for P9. It doesn't actually work in any way. So yes, we definitely need to finalise it before it goes anywhere.

FSI is coming together but we don't yet have it in the tree.

Andrew

Quoted 152 lines

Eddie

Quoted 147 lines · Andrew Jeffery

---
 drivers/hwmon/occ/Kconfig      |  9 ++++
 drivers/hwmon/occ/Makefile     |  1 +
 drivers/hwmon/occ/occ_p9_fsi.c | 93
++++++++++++++++++++++++++++++++++++++++++

 3 files changed, 103 insertions(+)

 create mode 100644 drivers/hwmon/occ/occ_p9_fsi.c

drivers/hwmon/occ/Kconfig +0 -0
index 085e1f370c42..97b97b391bf9 100644
@@ -26,4 +26,13 @@ config SENSORS_PPC_OCC_P8_I2C

          This driver can also be built as a module. If so, the module will be
          called occ-p8-i2c.

+config SENSORS_PPC_OCC_P9_FSI
+       tristate "POWER9 OCC hwmon support"
+       help
+         Provide a hwmon sysfs interface for the POWER9 On-Chip Controller,
+         exposing temperature, frequency and power measurements. +
+         This driver can also be built as a module. If so, the module will be
+         called occ-p9-fsi.
+
 endif

drivers/hwmon/occ/Makefile +0 -0
index 05a84e987127..77e47e10195e 100644
@@ -1,2 +1,3 @@

 obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o obj-$(CONFIG_SENSORS_PPC_OCC_P8_I2C) += occ_scom_i2c.o occ_p8.o occ_p8_i2c.o

drivers/hwmon/occ/Makefile +1 -0
+obj-$(CONFIG_SENSORS_PPC_OCC_P9_FSI) += occ_p9.o occ_p9_fsi.o
drivers/hwmon/occ/occ_p9_fsi.c new file +6 -0
new file mode 100644
index 000000000000..2f651d1b16bf
@@ -0,0 +1,93 @@
+/*
+ * occ_p9_fsi.c - hwmon OCC driver
+ *
+ * Copyright 2016 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or

modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */

drivers/hwmon/occ/occ_p9_fsi.c new file +26 -0
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+#include "scom.h"
+#include "occ_p9.h"
+#include "occ_sysfs.h"
+
+#define OCC_I2C_NAME   "occ-p9-fsi"
+
+static char *caps_sensor_names[] = {
+       "curr_powercap",
+       "curr_powerreading",
+       "norm_powercap",
+       "max_powercap",
+       "min_powercap",
+       "user_powerlimit"
+};
+
+int p9_fsi_getscom(void *bus, u32 address, u8 *data, size_t

offset)

drivers/hwmon/occ/occ_p9_fsi.c new file +52 -1
+{
+       return -SCOM_READ_ERROR;
+}
+
+int p9_fsi_putscom(void *bus, u32 address, u32 data0, u32 data1)
+{
+       return -SCOM_WRITE_ERROR;
+}
+
+static struct occ_bus_ops p9_bus_ops = {
+       .getscom = p9_fsi_getscom,
+       .putscom = p9_fsi_putscom,
+};
+
+static struct occ_sysfs_config p9_sysfs_config = {
+       .num_caps_fields = ARRAY_SIZE(caps_sensor_names),
+       .caps_names = caps_sensor_names,
+};
+
+int occ_p9_probe(struct device *dev, void *client)
+{
+       struct occ *occ;
+       struct occ_sysfs *hwmon;
+
+       occ = occ_p9_start(dev, client, p9_bus_ops);
+       if (IS_ERR(occ))
+               return PTR_ERR(occ);
+
+       hwmon = occ_sysfs_start(dev, occ, &p9_sysfs_config);
+       if (IS_ERR(hwmon))
+               return PTR_ERR(hwmon);
+
+       return 0;
+}
+
+int occ_p9_remove(void)
+{
+       struct occ *occ = NULL;
+
+       return occ_p9_stop(occ);
+}
+
+/* used by device table */
+static const struct of_device_id occ_of_match[] = {
+       { .compatible = "ibm,occ-p9-fsi" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, occ_of_match);
+
+MODULE_AUTHOR("Eddie James <[email protected]>");
+MODULE_DESCRIPTION("BMC P9 OCC hwmon driver");
+MODULE_LICENSE("GPL");
--

2.9.3

maintainer
#18 lore raw
In reply to Andrew Jeffery
Quoted 1 line · Andrew Jeffery

So I have reworked them into what is now 8 patches (see below) and tried

to

Quoted 1 line

tell a bit more of a story with them (hopefully I succeeded!) Second, I

tried

Quoted 3 lines

my hand at reworking the layering as mentioned above, such that hardware interaction is split from sysfs, and that the SCOM transport and sensor configuration is decoupled from the data parsing. You largely had all of

these

Quoted 1 line

in-place already, I just cut and pasted code around a bit.

Did you look at Jeremy and Chris B's FSI patches? I think you would be the first client of their new interfaces.

Quoted 1 line

Please review the patches and provide feedback! I'd like to hear

arguments for

Quoted 1 line

or against both of our approaches. Note though that I've only tested that

these

Quoted 3 lines

patches compile, I absolutely have not done any further testing.

Joel: Any chance you could chime in with an architectural review?

No worries.

Quoted 2 lines

When the dust has settled on the bigger issues we can start to look at the finer details of the APIs (there are some bugs, oddities and complexities

that

Quoted 1 line

I would like to address before they are applied to openbmc/linux).

I suggest the next step is upstream review. We can put them in the tree if it's urgent, but I trust that you and Eddie will beat them into shape in no time. If you succeed we can then apply the upstream versions directly.

Cheers,

Joel

#19 lore raw
In reply to Andrew Jeffery

Hi Andrew,

Thanks a lot for putting together this new patchset! On the whole, it looks very good! The split between sysfs, occ, and hardware transport layers is solid. I'm pretty satisfied with your modified structuring, although I had a couple of comments and questions. I'll send those out in the applicable patches.

I also tested this on palmetto and barreleye systems and fixed a couple of bugs. I went ahead and put them in a new patchset, which I'm about to send out. For reference, here's my only diffs though:

---
 drivers/hwmon/occ/occ.c       |  2 ++
 drivers/hwmon/occ/occ_sysfs.c | 15 +++++++--------
 2 files changed, 9 insertions(+), 8 deletions(-)
drivers/hwmon/occ/occ.c +0 -0
index 18936c8..d2fd81e 100644
@@ -469,6 +470,7 @@ struct occ *occ_start(struct device *dev, void

*bus, struct occ_bus_ops bus_ops,
if (!driver)
return ERR_PTR(-ENOMEM);

+ driver->dev = dev;
driver->bus = bus;
driver->bus_ops = bus_ops;
driver->ops = ops;

drivers/hwmon/occ/occ_sysfs.c +2 -2
index ef45bd0..aab4fbe 100644
@@ -63,9 +63,9 @@ static ssize_t show_input(struct device *dev,
        struct sensor_attr_data *sdata = container_of(attr,
                                                      struct sensor_attr_data,
                                                      dev_attr);
-       struct occ *driver = dev_get_drvdata(dev);
+       struct occ_sysfs *driver = dev_get_drvdata(dev);
 
-       val = occ_get_sensor_value(driver, sdata->type, sdata->hwmon_index - 1);
+       val = occ_get_sensor_value(driver->occ, sdata->type,

sdata->hwmon_index - 1);
if (sdata->type == TEMP)
val *= 1000; /* in millidegree Celsius */

@@ -79,9 +79,9 @@ static ssize_t show_label(struct device *dev,
struct sensor_attr_data *sdata = container_of(attr,
struct sensor_attr_data, dev_attr);
- struct occ *driver = dev_get_drvdata(dev);
+ struct occ_sysfs *driver = dev_get_drvdata(dev);

- val = occ_get_sensor_id(driver, sdata->type,
+ val = occ_get_sensor_id(driver->occ, sdata->type,

                                        sdata->hwmon_index - 1);

        return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);

@@ -95,15 +95,15 @@ static ssize_t show_caps(struct device *dev,
struct sensor_attr_data *sdata = container_of(attr,
struct sensor_attr_data, dev_attr);
- struct occ *driver = dev_get_drvdata(dev);
+ struct occ_sysfs *driver = dev_get_drvdata(dev);

- sensor = occ_get_sensor(driver, CAPS);

+       sensor = occ_get_sensor(driver->occ, CAPS);
        if (!sensor) {
                val = -1;
                return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
        }

- val = occ_get_caps_value(driver, sensor, sdata->hwmon_index - 1,
+ val = occ_get_caps_value(driver->occ, sensor, sdata->hwmon_index - 1,

                                         sdata->attr_id);

        return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
@@ -467,7 +467,6 @@ struct occ_sysfs *occ_sysfs_start(struct device
*dev, struct occ *occ,
        if (!hwmon)
                return ERR_PTR(-ENOMEM);
-       hwmon->dev = dev;
        hwmon->occ = occ;
        hwmon->num_caps_fields = config->num_caps_fields;
        hwmon->caps_names = config->caps_names;
Signature · 1 line
1.9.1
Quoted 111 lines · Andrew Jeffery

Hi Eddie,

Quoted 5 lines

This patchset provides a new OCC hwmon driver. There are a number of issues with the existing driver. Firstly, i2c access was embedded throughout the driver. Secondly, there is no way to easily differentiate versions of the OCC.

Quoted 8 lines

This patchset addresses the first issue by abstracting the bus transfer protocol into a modular structure. In this way, any low level transfer method may be easily implemented.

The second issue is addressed by separating the "version specific" code for the OCC and the common hwmon code. This task is not yet complete, but the general structure is in place. Ultimately, different OCC versions could be probed up using the device tree.

I agree with all of this. However, I thought some of the layering could still be improved, so rather than provide a review through prose I figured it might be better for both of us if I mangled the patches directly.

I've attacked two things. The first is I found the series hard to review due to the way the patches were split, as the patches went from trivial to huge (and complex) in a fairly short step:

Quoted 7 lines

Edward A. James (5):
Revert "hwmon: Add Power8 OCC hwmon driver"
drivers: Add hwmon occ driver framework
drivers: hwmon OCC scom bus operations
drivers: Add hwmon OCC version specific functions
drivers: OCC hwmon driver and sysfs

So I have reworked them into what is now 8 patches (see below) and tried to tell a bit more of a story with them (hopefully I succeeded!) Second, I tried my hand at reworking the layering as mentioned above, such that hardware interaction is split from sysfs, and that the SCOM transport and sensor configuration is decoupled from the data parsing. You largely had all of these in-place already, I just cut and pasted code around a bit.

Please review the patches and provide feedback! I'd like to hear arguments for or against both of our approaches. Note though that I've only tested that these patches compile, I absolutely have not done any further testing.

Joel: Any chance you could chime in with an architectural review?

When the dust has settled on the bigger issues we can start to look at the finer details of the APIs (there are some bugs, oddities and complexities that I would like to address before they are applied to openbmc/linux).

Cheers,

Andrew

Andrew Jeffery (8):
hwmon: Add core On-Chip Controller support for POWER CPUs
hwmon: occ: Add sysfs interface
hwmon: occ: Add I2C SCOM transport implementation
hwmon: occ: Add callbacks for parsing P8 OCC datastructures
hwmon: occ: Add hwmon implementation for the P8 OCC
arm: aspeed: dt: Fix OCC compatible strings
hwmon: occ: Add callbacks for parsing P9 OCC datastructures
wip: hwmon: occ: Add sketch of the hwmon implementation for the P9 OCC

Edward A. James (1):
Revert "hwmon: Add Power8 OCC hwmon driver"

 .../devicetree/bindings/i2c/i2c-ibm-occ.txt        |   13 -
 arch/arm/boot/dts/aspeed-bmc-opp-barreleye.dts     |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-firestone.dts     |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-garrison.dts      |    4 +-
 arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts      |    2 +-
 drivers/hwmon/Kconfig                              |   13 +-
 drivers/hwmon/Makefile                             |    2 +-
 drivers/hwmon/occ/Kconfig                          |   38 +
 drivers/hwmon/occ/Makefile                         |    3 +
 drivers/hwmon/occ/occ.c                            |  494 ++++++++
 drivers/hwmon/occ/occ.h                            |   79 ++
 drivers/hwmon/occ/occ_p8.c                         |  219 ++++
 drivers/hwmon/occ/occ_p8.h                         |   30 +
 drivers/hwmon/occ/occ_p8_i2c.c                     |  133 +++
 drivers/hwmon/occ/occ_p9.c                         |  261 ++++
 drivers/hwmon/occ/occ_p9.h                         |   30 +
 drivers/hwmon/occ/occ_p9_fsi.c                     |   93 ++
 drivers/hwmon/occ/occ_scom_i2c.c                   |   68 ++
 drivers/hwmon/occ/occ_scom_i2c.h                   |   20 +
 drivers/hwmon/occ/occ_sysfs.c                      |  498 ++++++++
 drivers/hwmon/occ/occ_sysfs.h                      |   51 +
 drivers/hwmon/occ/scom.h                           |   50 +
 drivers/hwmon/power8_occ_i2c.c                     | 1254 --------------------
 23 files changed, 2076 insertions(+), 1287 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-ibm-occ.txt
 create mode 100644 drivers/hwmon/occ/Kconfig
 create mode 100644 drivers/hwmon/occ/Makefile
 create mode 100644 drivers/hwmon/occ/occ.c
 create mode 100644 drivers/hwmon/occ/occ.h
 create mode 100644 drivers/hwmon/occ/occ_p8.c
 create mode 100644 drivers/hwmon/occ/occ_p8.h
 create mode 100644 drivers/hwmon/occ/occ_p8_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_p9.c
 create mode 100644 drivers/hwmon/occ/occ_p9.h
 create mode 100644 drivers/hwmon/occ/occ_p9_fsi.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.c
 create mode 100644 drivers/hwmon/occ/occ_scom_i2c.h
 create mode 100644 drivers/hwmon/occ/occ_sysfs.c
 create mode 100644 drivers/hwmon/occ/occ_sysfs.h
 create mode 100644 drivers/hwmon/occ/scom.h
 delete mode 100644 drivers/hwmon/power8_occ_i2c.c

--
2.9.3

#20 lore raw
Quoted 7 lines · Eddie James

Hi Andrew,

Thanks a lot for putting together this new patchset! On the whole, it looks very good! The split between sysfs, occ, and hardware transport layers is solid. I'm pretty satisfied with your modified structuring, although I had a couple of comments and questions. I'll send those out in the applicable patches.

I've just finished replying to your comments. The most controversial one was the cap_names/num_cap_names problem, but we have some alternatives there.

Quoted 3 lines

I also tested this on palmetto and barreleye systems and fixed a couple of bugs.

Great!

Quoted 2 lines

I went ahead and put them in a new patchset, which I'm
about to send out. For reference, here's my only diffs though:

Good ol' void conversions eh.

Thanks for testing!

Andrew

#21 lore raw

Hi Andrew,

What's the status on this? I last sent out a tested patch set that I'm pretty happy with. I'm not sure what the next step for me is, any ideas?

Thanks,
Eddie

Quoted 27 lines · Andrew Jeffery
Quoted 7 lines · Eddie James

Hi Andrew,

Thanks a lot for putting together this new patchset! On the whole, it looks very good! The split between sysfs, occ, and hardware transport layers is solid. I'm pretty satisfied with your modified structuring, although I had a couple of comments and questions. I'll send those out in the applicable patches.

I've just finished replying to your comments. The most controversial one was the cap_names/num_cap_names problem, but we have some alternatives there.

Quoted 3 lines

I also tested this on palmetto and barreleye systems and fixed a couple of bugs.

Great!

Quoted 2 lines

I went ahead and put them in a new patchset, which I'm
about to send out. For reference, here's my only diffs though:

Good ol' void conversions eh.

Thanks for testing!

Andrew

#22 lore raw
Quoted 6 lines · Eddie James

Hi Andrew,

What's the status on this? I last sent out a tested patch set that I'm pretty happy with. I'm not sure what the next step for me is, any ideas?

Sorry, I've been busy on other things but will now have some time to look at the series. I'll take a look in the morning.

Andrew