sensor-groups: occ: Add support to disable/enable sensor group

Message ID 1511505374-32222-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State New
Headers show
Series
  • sensor-groups: occ: Add support to disable/enable sensor group
Related show

Commit Message

Shilpasri G Bhat Nov. 24, 2017, 6:36 a.m.
This patch adds a new opal call to enable/disable a sensor group. This
call is used to select the sensor groups that needs to be copied to
main memory by OCC at runtime.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
---
 core/sensor.c                                 |  12 ++
 doc/opal-api/opal-sensor-group-enable-158.rst |  46 +++++
 hw/occ-sensor.c                               | 243 +-----------------------
 hw/occ.c                                      | 137 ++++++++++++--
 include/occ-sensor.h                          | 259 ++++++++++++++++++++++++++
 include/opal-api.h                            |   3 +-
 include/skiboot.h                             |   3 +-
 7 files changed, 450 insertions(+), 253 deletions(-)
 create mode 100644 doc/opal-api/opal-sensor-group-enable-158.rst
 create mode 100644 include/occ-sensor.h

Patch

diff --git a/core/sensor.c b/core/sensor.c
index 0e2a5ca..4b7775d 100644
--- a/core/sensor.c
+++ b/core/sensor.c
@@ -53,6 +53,17 @@  static int opal_sensor_group_clear(u32 group_hndl, int token)
 	return OPAL_UNSUPPORTED;
 }
 
+static int opal_sensor_group_enable(u32 group_hndl, int token, bool enable)
+{
+	switch (sensor_get_family(group_hndl)) {
+	case SENSOR_OCC:
+		return occ_sensor_group_enable(group_hndl, token, enable);
+	default:
+		break;
+	}
+
+	return OPAL_UNSUPPORTED;
+}
 void sensor_init(void)
 {
 	sensor_node = dt_new(opal_node, "sensors");
@@ -63,4 +74,5 @@  void sensor_init(void)
 	/* Register OPAL interface */
 	opal_register(OPAL_SENSOR_READ, opal_sensor_read, 3);
 	opal_register(OPAL_SENSOR_GROUP_CLEAR, opal_sensor_group_clear, 2);
+	opal_register(OPAL_SENSOR_GROUP_ENABLE, opal_sensor_group_enable, 3);
 }
diff --git a/doc/opal-api/opal-sensor-group-enable-158.rst b/doc/opal-api/opal-sensor-group-enable-158.rst
new file mode 100644
index 0000000..2f7650f
--- /dev/null
+++ b/doc/opal-api/opal-sensor-group-enable-158.rst
@@ -0,0 +1,46 @@ 
+.. _opal-sensor-groups-enable:
+
+OPAL_SENSOR_GROUP_ENABLE
+==============================
+OPAL call to enable/disable the sensor group using a handle to identify
+the type of sensor group provided in the device tree.
+
+For example this call is used to disable/enable copying of sensor
+group by OCC to main memory.
+
+The call can be asynchronus, where the token parameter is used to wait
+for the completion.
+
+Parameters
+----------
+::
+        u32 handle
+        int token
+        bool enable
+
+Returns
+-------
+OPAL_SUCCESS
+  Success
+
+OPAL_UNSUPPORTED
+  No support to enable/disable the sensor group
+
+OPAL_HARDWARE
+  Unable to procced due to the current hardware state
+
+OPAL_PERMISSION
+  Hardware cannot take the request
+
+OPAL_ASYNC_COMPLETION
+  Request was sent and an async completion message will be sent with
+  token and status of the request.
+
+OPAL_BUSY
+  Previous request in progress
+
+OPAL_INTERNAL_ERROR
+  Error in request response
+
+OPAL_TIMEOUT
+  Timeout in request completion
diff --git a/hw/occ-sensor.c b/hw/occ-sensor.c
index 1042c11..c0c95ee 100644
--- a/hw/occ-sensor.c
+++ b/hw/occ-sensor.c
@@ -20,240 +20,7 @@ 
 #include <sensor.h>
 #include <device.h>
 #include <cpu.h>
-
-/*
- * OCC Sensor Data
- *
- * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
- * Starting address is at offset 0x00580000 from BAR2 base address.
- * Maximum size is 1.5MB.
- *
- * -------------------------------------------------------------------------
- * | Start (Offset from |	End	| Size	   |Description		   |
- * | BAR2 base address) |		|	   |			   |
- * -------------------------------------------------------------------------
- * |	0x00580000      |  0x005A57FF   |150kB     |OCC 0 Sensor Data Block|
- * |	0x005A5800      |  0x005CAFFF   |150kB	   |OCC 1 Sensor Data Block|
- * |	    :		|	:	|  :	   |		:          |
- * |	0x00686800	|  0x006ABFFF   |150kB	   |OCC 7 Sensor Data Block|
- * |	0x006AC000	|  0x006FFFFF   |336kB     |Reserved		   |
- * -------------------------------------------------------------------------
- *
- *
- * OCC N Sensor Data Block Layout (150kB)
- *
- * The sensor data block layout is the same for each OCC N. It contains
- * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
- * sensor-readings-pong buffer.
- *
- * ----------------------------------------------------------------------------
- * | Start (Offset from OCC |   End	   | Size |Description		      |
- * | N Sensor Data Block)   |		   |	  |			      |
- * ----------------------------------------------------------------------------
- * |	0x00000000	    |  0x000003FF  |1kB   |Sensor Data Header Block   |
- * |	0x00000400	    |  0x0000CBFF  |50kB  |Sensor Names		      |
- * |	0x0000CC00	    |  0x0000DBFF  |4kB   |Reserved		      |
- * |	0x0000DC00	    |  0x00017BFF  |40kB  |Sensor Readings ping buffer|
- * |	0x00017C00	    |  0x00018BFF  |4kB   |Reserved		      |
- * |	0x00018C00	    |  0x00022BFF  |40kB  |Sensor Readings pong buffer|
- * |	0x00022C00	    |  0x000257FF  |11kB  |Reserved		      |
- * ----------------------------------------------------------------------------
- *
- * Sensor Data Header Block : This is written once by the OCC during
- * initialization after a load or reset. Layout is defined in 'struct
- * occ_sensor_data_header'
- *
- * Sensor Names : This is written once by the OCC during initialization after a
- * load or reset. It contains static information for each sensor. The number of
- * sensors, format version and length of each sensor is defined in
- * 'Sensor Data Header Block'. Format of each sensor name is defined in
- * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
- * immediately by the next sensor.
- *
- * Sensor Readings Ping/Pong Buffer:
- * There are two 40kB buffers to store the sensor readings. One buffer that
- * is currently being updated by the OCC and one that is available to be read.
- * Each of these buffers will be of the same format. The number of sensors and
- * the format version of the ping and pong buffers is defined in the
- * 'Sensor Data Header Block'.
- *
- * Each sensor within the ping and pong buffers may be of a different format
- * and length. For each sensor the length and format is determined by its
- * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
- *
- * --------------------------------------------------------------------------
- * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
- * --------------------------------------------------------------------------
- * | 0x0000 |Valid  |		   Reserved				    |
- * |        |(0x01) |							    |
- * --------------------------------------------------------------------------
- * | 0x0008 |			Sensor Readings				    |
- * --------------------------------------------------------------------------
- * |	:   |				:				    |
- * --------------------------------------------------------------------------
- * | 0xA000 |                     End of Data				    |
- * --------------------------------------------------------------------------
- *
- */
-
-#define MAX_OCCS			8
-#define MAX_CHARS_SENSOR_NAME		16
-#define MAX_CHARS_SENSOR_UNIT		4
-
-#define OCC_SENSOR_DATA_BLOCK_OFFSET		0x00580000
-#define OCC_SENSOR_DATA_BLOCK_SIZE		0x00025800
-
-enum occ_sensor_type {
-	OCC_SENSOR_TYPE_GENERIC		= 0x0001,
-	OCC_SENSOR_TYPE_CURRENT		= 0x0002,
-	OCC_SENSOR_TYPE_VOLTAGE		= 0x0004,
-	OCC_SENSOR_TYPE_TEMPERATURE	= 0x0008,
-	OCC_SENSOR_TYPE_UTILIZATION	= 0x0010,
-	OCC_SENSOR_TYPE_TIME		= 0x0020,
-	OCC_SENSOR_TYPE_FREQUENCY	= 0x0040,
-	OCC_SENSOR_TYPE_POWER		= 0x0080,
-	OCC_SENSOR_TYPE_PERFORMANCE	= 0x0200,
-};
-
-enum occ_sensor_location {
-	OCC_SENSOR_LOC_SYSTEM		= 0x0001,
-	OCC_SENSOR_LOC_PROCESSOR	= 0x0002,
-	OCC_SENSOR_LOC_PARTITION	= 0x0004,
-	OCC_SENSOR_LOC_MEMORY		= 0x0008,
-	OCC_SENSOR_LOC_VRM		= 0x0010,
-	OCC_SENSOR_LOC_OCC		= 0x0020,
-	OCC_SENSOR_LOC_CORE		= 0x0040,
-	OCC_SENSOR_LOC_QUAD		= 0x0080,
-	OCC_SENSOR_LOC_GPU		= 0x0100,
-};
-
-enum sensor_struct_type {
-	OCC_SENSOR_READING_FULL		= 0x01,
-	OCC_SENSOR_READING_COUNTER	= 0x02,
-};
-
-/**
- * struct occ_sensor_data_header -	Sensor Data Header Block
- * @valid:				When the value is 0x01 it indicates
- *					that this header block and the sensor
- *					names buffer are ready
- * @version:				Format version of this block
- * @nr_sensors:				Number of sensors in names, ping and
- *					pong buffer
- * @reading_version:			Format version of the Ping/Pong buffer
- * @names_offset:			Offset to the location of names buffer
- * @names_version:			Format version of names buffer
- * @names_length:			Length of each sensor in names buffer
- * @reading_ping_offset:		Offset to the location of Ping buffer
- * @reading_pong_offset:		Offset to the location of Pong buffer
- * @pad/reserved:			Unused data
- */
-struct occ_sensor_data_header {
-	u8 valid;
-	u8 version;
-	u16 nr_sensors;
-	u8 reading_version;
-	u8 pad[3];
-	u32 names_offset;
-	u8 names_version;
-	u8 name_length;
-	u16 reserved;
-	u32 reading_ping_offset;
-	u32 reading_pong_offset;
-} __packed;
-
-/**
- * struct occ_sensor_name -		Format of Sensor Name
- * @name:				Sensor name
- * @units:				Sensor units of measurement
- * @gsid:				Global sensor id (OCC)
- * @freq:				Update frequency
- * @scale_factor:			Scaling factor
- * @type:				Sensor type as defined in
- *					'enum occ_sensor_type'
- * @location:				Sensor location as defined in
- *					'enum occ_sensor_location'
- * @structure_type:			Indicates type of data structure used
- *					for the sensor readings in the ping and
- *					pong buffers for this sensor as defined
- *					in 'enum sensor_struct_type'
- * @reading_offset:			Offset from the start of the ping/pong
- *					reading buffers for this sensor
- * @sensor_data:			Sensor specific info
- * @pad:				Padding to fit the size of 48 bytes.
- */
-struct occ_sensor_name {
-	char name[MAX_CHARS_SENSOR_NAME];
-	char units[MAX_CHARS_SENSOR_UNIT];
-	u16 gsid;
-	u32 freq;
-	u32 scale_factor;
-	u16 type;
-	u16 location;
-	u8 structure_type;
-	u32 reading_offset;
-	u8 sensor_data;
-	u8 pad[8];
-} __packed;
-
-/**
- * struct occ_sensor_record -		Sensor Reading Full
- * @gsid:				Global sensor id (OCC)
- * @timestamp:				Time base counter value while updating
- *					the sensor
- * @sample:				Latest sample of this sensor
- * @sample_min:				Minimum value since last OCC reset
- * @sample_max:				Maximum value since last OCC reset
- * @csm_min:				Minimum value since last reset request
- *					by CSM (CORAL)
- * @csm_max:				Maximum value since last reset request
- *					by CSM (CORAL)
- * @profiler_min:			Minimum value since last reset request
- *					by profiler (CORAL)
- * @profiler_max:			Maximum value since last reset request
- *					by profiler (CORAL)
- * @job_scheduler_min:			Minimum value since last reset request
- *					by job scheduler(CORAL)
- * @job_scheduler_max:			Maximum value since last reset request
- *					by job scheduler (CORAL)
- * @accumulator:			Accumulator for this sensor
- * @update_tag:				Count of the number of ticks that have
- *					passed between updates
- * @pad:				Padding to fit the size of 48 bytes
- */
-struct occ_sensor_record {
-	u16 gsid;
-	u64 timestamp;
-	u16 sample;
-	u16 sample_min;
-	u16 sample_max;
-	u16 csm_min;
-	u16 csm_max;
-	u16 profiler_min;
-	u16 profiler_max;
-	u16 job_scheduler_min;
-	u16 job_scheduler_max;
-	u64 accumulator;
-	u32 update_tag;
-	u8 pad[8];
-} __packed;
-
-/**
- * struct occ_sensor_counter -		Sensor Reading Counter
- * @gsid:				Global sensor id (OCC)
- * @timestamp:				Time base counter value while updating
- *					the sensor
- * @accumulator:			Accumulator/Counter
- * @sample:				Latest sample of this sensor (0/1)
- * @pad:				Padding to fit the size of 24 bytes
- */
-struct occ_sensor_counter {
-	u16 gsid;
-	u64 timestamp;
-	u64 accumulator;
-	u8 sample;
-	u8 pad[5];
-} __packed;
+#include <occ-sensor.h>
 
 enum sensor_attr {
 	SENSOR_SAMPLE,
@@ -572,7 +339,7 @@  void occ_sensors_init(void)
 	for_each_chip(chip) {
 		struct occ_sensor_data_header *hb;
 		struct occ_sensor_name *md;
-		u32 *phandles, phcount = 0;
+		u32 *phandles, *ptype, phcount = 0;
 
 		hb = get_sensor_header_block(occ_num);
 		md = get_names_block(hb);
@@ -583,6 +350,8 @@  void occ_sensors_init(void)
 
 		phandles = malloc(hb->nr_sensors * sizeof(u32));
 		assert(phandles);
+		ptype = malloc(hb->nr_sensors * sizeof(u32));
+		assert(ptype);
 
 		for (i = 0; i < hb->nr_sensors; i++) {
 			char name[30];
@@ -627,11 +396,13 @@  void occ_sensors_init(void)
 
 			if (md[i].location == OCC_SENSOR_LOC_CORE)
 				dt_add_property_cells(node, "ibm,pir", c->pir);
+			ptype[phcount] = md[i].type;
 			phandles[phcount++] = node->phandle;
 		}
 		occ_num++;
-		occ_add_sensor_groups(sg, phandles, phcount, chip->id);
+		occ_add_sensor_groups(sg, phandles, ptype, phcount, chip->id);
 		free(phandles);
+		free(ptype);
 	}
 
 	if (!occ_num)
diff --git a/hw/occ.c b/hw/occ.c
index 8ad0dfe..281f5d3 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -31,6 +31,7 @@ 
 #include <powercap.h>
 #include <psr.h>
 #include <sensor.h>
+#include <occ-sensor.h>
 
 /* OCC Communication Area for PStates */
 
@@ -954,7 +955,7 @@  enum occ_cmd {
 	OCC_CMD_CLEAR_SENSOR_DATA,
 	OCC_CMD_SET_POWER_CAP,
 	OCC_CMD_SET_POWER_SHIFTING_RATIO,
-	OCC_CMD_LAST
+	OCC_CMD_SELECT_SENSOR_GROUP,
 };
 
 struct opal_occ_cmd_info {
@@ -989,6 +990,13 @@  static struct opal_occ_cmd_info occ_cmds[] = {
 		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
 		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
 	},
+	{	OCC_CMD_SELECT_SENSOR_GROUP,
+		0xD3, 2, 2, 1000,
+		PPC_BIT16(OCC_STATE_OBSERVATION) |
+		PPC_BIT16(OCC_STATE_ACTIVE) |
+		PPC_BIT16(OCC_STATE_CHARACTERIZATION),
+		PPC_BIT8(OCC_ROLE_MASTER) | PPC_BIT8(OCC_ROLE_SLAVE)
+	},
 };
 
 enum occ_response_status {
@@ -1018,6 +1026,7 @@  static struct cmd_interface {
 	u8 *valid;
 	u32 chip_id;
 	u32 token;
+	u16 enabled_sensor_mask;
 	u8 occ_role;
 	u8 request_id;
 	bool cmd_in_progress;
@@ -1212,6 +1221,10 @@  static void handle_occ_rsp(uint32_t chip_id)
 		goto exit;
 	}
 
+	if (rsp->cmd == occ_cmds[OCC_CMD_SELECT_SENSOR_GROUP].cmd_value &&
+	    rsp->status == OCC_RSP_SUCCESS)
+		chip->enabled_sensor_mask = *(u16 *)chip->cdata->data;
+
 	chip->cmd_in_progress = false;
 	queue_occ_rsp_msg(chip->token, read_occ_rsp(chip->rsp));
 exit:
@@ -1252,6 +1265,7 @@  static void occ_cmd_interface_init(void)
 		init_lock(&chips[i].queue_lock);
 		chips[i].cmd_in_progress = false;
 		chips[i].request_id = 0;
+		chips[i].enabled_sensor_mask = OCC_ENABLED_SENSOR_MASK;
 		init_timer(&chips[i].timeout, occ_cmd_timeout_handler,
 			   &chips[i]);
 		i++;
@@ -1500,16 +1514,93 @@  int occ_sensor_group_clear(u32 group_hndl, int token)
 	return opal_occ_command(&chips[i], token, &slimit_data);
 }
 
-void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
-			   int chipid)
+static u16 sensor_enable;
+static struct opal_occ_cmd_data sensor_mask_data = {
+	.data		= (u8 *)&sensor_enable,
+	.cmd		= OCC_CMD_SELECT_SENSOR_GROUP,
+};
+
+int occ_sensor_group_enable(u32 group_hndl, int token, bool enable)
+{
+	u16 type = sensor_get_rid(group_hndl);
+	u8 i = sensor_get_attr(group_hndl);
+
+	if (i > nr_occs)
+		return OPAL_UNSUPPORTED;
+
+	switch (type) {
+	case OCC_SENSOR_TYPE_GENERIC:
+	case OCC_SENSOR_TYPE_CURRENT:
+	case OCC_SENSOR_TYPE_VOLTAGE:
+	case OCC_SENSOR_TYPE_TEMPERATURE:
+	case OCC_SENSOR_TYPE_UTILIZATION:
+	case OCC_SENSOR_TYPE_TIME:
+	case OCC_SENSOR_TYPE_FREQUENCY:
+	case OCC_SENSOR_TYPE_POWER:
+	case OCC_SENSOR_TYPE_PERFORMANCE:
+		break;
+	default:
+		return OPAL_UNSUPPORTED;
+	}
+
+	if (!(*chips[i].valid))
+		return OPAL_HARDWARE;
+
+	if (enable && (type & chips[i].enabled_sensor_mask))
+		return OPAL_SUCCESS;
+	else if (!enable && !(type & chips[i].enabled_sensor_mask))
+		return OPAL_SUCCESS;
+
+	sensor_enable = enable ? type | chips[i].enabled_sensor_mask :
+				~type & chips[i].enabled_sensor_mask;
+
+	return opal_occ_command(&chips[i], token, &sensor_mask_data);
+}
+
+void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, u32 *ptype,
+			   int nr_phandles, int chipid)
 {
-	struct limit_group_info {
-		int limit;
+	struct group_info {
+		int type;
 		const char *str;
-	} limits[] = {
-		{ OCC_SENSOR_LIMIT_GROUP_CSM, "csm" },
-		{ OCC_SENSOR_LIMIT_GROUP_PROFILER, "profiler" },
-		{ OCC_SENSOR_LIMIT_GROUP_JOB_SCHED, "js" },
+		u32 ops;
+	} groups[] = {
+		{ OCC_SENSOR_LIMIT_GROUP_CSM, "csm",
+		  OPAL_SENSOR_GROUP_CLEAR
+		},
+		{ OCC_SENSOR_LIMIT_GROUP_PROFILER, "profiler",
+		  OPAL_SENSOR_GROUP_CLEAR
+		},
+		{ OCC_SENSOR_LIMIT_GROUP_JOB_SCHED, "js",
+		  OPAL_SENSOR_GROUP_CLEAR
+		},
+		{ OCC_SENSOR_TYPE_GENERIC, "generic",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_CURRENT, "current",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_VOLTAGE, "voltage",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_TEMPERATURE, "temperature",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_UTILIZATION, "utilization",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_TIME, "time",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_FREQUENCY, "frequency",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_POWER, "power",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
+		{ OCC_SENSOR_TYPE_PERFORMANCE, "performance",
+		  OPAL_SENSOR_GROUP_ENABLE
+		},
 	};
 	int i, j;
 
@@ -1517,14 +1608,14 @@  void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
 		if (chips[i].chip_id == chipid)
 			break;
 
-	for (j = 0; j < ARRAY_SIZE(limits); j++) {
+	for (j = 0; j < ARRAY_SIZE(groups); j++) {
 		struct dt_node *node;
 		char name[20];
 		u32 handle;
 
-		snprintf(name, 20, "occ-%s", limits[j].str);
+		snprintf(name, 20, "occ-%s", groups[j].str);
 		handle = sensor_make_handler(SENSOR_OCC, 0,
-					     limits[j].limit, i);
+					     groups[j].type, i);
 		node = dt_new_addr(sg, name, handle);
 		if (!node) {
 			prerror("Failed to create sensor group nodes\n");
@@ -1532,10 +1623,26 @@  void occ_add_sensor_groups(struct dt_node *sg, u32 *phandles, int nr_phandles,
 		}
 
 		dt_add_property_cells(node, "sensor-group-id", handle);
-		dt_add_property_string(node, "type", limits[j].str);
+		dt_add_property_string(node, "type", groups[j].str);
 		dt_add_property_cells(node, "ibm,chip-id", chipid);
-		dt_add_property(node, "sensors", phandles, nr_phandles);
-		dt_add_property_cells(node, "ops", OPAL_SENSOR_GROUP_CLEAR);
+		if (groups[j].ops == OPAL_SENSOR_GROUP_ENABLE) {
+			u32 *_phandles;
+			int k, pcount = 0;
+
+			_phandles = malloc(sizeof(u32) * nr_phandles);
+			assert(_phandles);
+			for (k = 0; k < nr_phandles; k++)
+				if (ptype[k] == groups[j].type)
+					_phandles[pcount++] = phandles[k];
+			if (pcount)
+				dt_add_property(node, "sensors", _phandles,
+						pcount);
+			free(_phandles);
+		} else {
+			dt_add_property(node, "sensors", phandles,
+					nr_phandles);
+		}
+		dt_add_property_cells(node, "ops", groups[j].ops);
 	}
 }
 
diff --git a/include/occ-sensor.h b/include/occ-sensor.h
new file mode 100644
index 0000000..153f295
--- /dev/null
+++ b/include/occ-sensor.h
@@ -0,0 +1,259 @@ 
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * OCC Sensor Data
+ *
+ * OCC sensor data will use BAR2 (OCC Common is per physical drawer).
+ * Starting address is at offset 0x00580000 from BAR2 base address.
+ * Maximum size is 1.5MB.
+ *
+ * -------------------------------------------------------------------------
+ * | Start (Offset from |	End	| Size	   |Description		   |
+ * | BAR2 base address) |		|	   |			   |
+ * -------------------------------------------------------------------------
+ * |	0x00580000      |  0x005A57FF   |150kB     |OCC 0 Sensor Data Block|
+ * |	0x005A5800      |  0x005CAFFF   |150kB	   |OCC 1 Sensor Data Block|
+ * |	    :		|	:	|  :	   |		:          |
+ * |	0x00686800	|  0x006ABFFF   |150kB	   |OCC 7 Sensor Data Block|
+ * |	0x006AC000	|  0x006FFFFF   |336kB     |Reserved		   |
+ * -------------------------------------------------------------------------
+ *
+ *
+ * OCC N Sensor Data Block Layout (150kB)
+ *
+ * The sensor data block layout is the same for each OCC N. It contains
+ * sensor-header-block, sensor-names buffer, sensor-readings-ping buffer and
+ * sensor-readings-pong buffer.
+ *
+ * ----------------------------------------------------------------------------
+ * | Start (Offset from OCC |   End	   | Size |Description		      |
+ * | N Sensor Data Block)   |		   |	  |			      |
+ * ----------------------------------------------------------------------------
+ * |	0x00000000	    |  0x000003FF  |1kB   |Sensor Data Header Block   |
+ * |	0x00000400	    |  0x0000CBFF  |50kB  |Sensor Names		      |
+ * |	0x0000CC00	    |  0x0000DBFF  |4kB   |Reserved		      |
+ * |	0x0000DC00	    |  0x00017BFF  |40kB  |Sensor Readings ping buffer|
+ * |	0x00017C00	    |  0x00018BFF  |4kB   |Reserved		      |
+ * |	0x00018C00	    |  0x00022BFF  |40kB  |Sensor Readings pong buffer|
+ * |	0x00022C00	    |  0x000257FF  |11kB  |Reserved		      |
+ * ----------------------------------------------------------------------------
+ *
+ * Sensor Data Header Block : This is written once by the OCC during
+ * initialization after a load or reset. Layout is defined in 'struct
+ * occ_sensor_data_header'
+ *
+ * Sensor Names : This is written once by the OCC during initialization after a
+ * load or reset. It contains static information for each sensor. The number of
+ * sensors, format version and length of each sensor is defined in
+ * 'Sensor Data Header Block'. Format of each sensor name is defined in
+ * 'struct occ_sensor_name'. The first sensor starts at offset 0 followed
+ * immediately by the next sensor.
+ *
+ * Sensor Readings Ping/Pong Buffer:
+ * There are two 40kB buffers to store the sensor readings. One buffer that
+ * is currently being updated by the OCC and one that is available to be read.
+ * Each of these buffers will be of the same format. The number of sensors and
+ * the format version of the ping and pong buffers is defined in the
+ * 'Sensor Data Header Block'.
+ *
+ * Each sensor within the ping and pong buffers may be of a different format
+ * and length. For each sensor the length and format is determined by its
+ * 'struct occ_sensor_name.structure_type' in the Sensor Names buffer.
+ *
+ * --------------------------------------------------------------------------
+ * | Offset | Byte0 | Byte1 | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | Byte7 |
+ * --------------------------------------------------------------------------
+ * | 0x0000 |Valid  |		   Reserved				    |
+ * |        |(0x01) |							    |
+ * --------------------------------------------------------------------------
+ * | 0x0008 |			Sensor Readings				    |
+ * --------------------------------------------------------------------------
+ * |	:   |				:				    |
+ * --------------------------------------------------------------------------
+ * | 0xA000 |                     End of Data				    |
+ * --------------------------------------------------------------------------
+ *
+ */
+
+#define MAX_OCCS			8
+#define MAX_CHARS_SENSOR_NAME		16
+#define MAX_CHARS_SENSOR_UNIT		4
+
+#define OCC_SENSOR_DATA_BLOCK_OFFSET		0x00580000
+#define OCC_SENSOR_DATA_BLOCK_SIZE		0x00025800
+
+enum occ_sensor_type {
+	OCC_SENSOR_TYPE_GENERIC		= 0x0001,
+	OCC_SENSOR_TYPE_CURRENT		= 0x0002,
+	OCC_SENSOR_TYPE_VOLTAGE		= 0x0004,
+	OCC_SENSOR_TYPE_TEMPERATURE	= 0x0008,
+	OCC_SENSOR_TYPE_UTILIZATION	= 0x0010,
+	OCC_SENSOR_TYPE_TIME		= 0x0020,
+	OCC_SENSOR_TYPE_FREQUENCY	= 0x0040,
+	OCC_SENSOR_TYPE_POWER		= 0x0080,
+	OCC_SENSOR_TYPE_PERFORMANCE	= 0x0200,
+};
+
+#define OCC_ENABLED_SENSOR_MASK	(OCC_SENSOR_TYPE_GENERIC |	\
+				 OCC_SENSOR_TYPE_CURRENT |	\
+				 OCC_SENSOR_TYPE_VOLTAGE |	\
+				 OCC_SENSOR_TYPE_TIME    |	\
+				 OCC_SENSOR_TYPE_TEMPERATURE |	\
+				 OCC_SENSOR_TYPE_POWER |	\
+				 OCC_SENSOR_TYPE_UTILIZATION |	\
+				 OCC_SENSOR_TYPE_FREQUENCY   |	\
+				 OCC_SENSOR_TYPE_PERFORMANCE);
+
+enum occ_sensor_location {
+	OCC_SENSOR_LOC_SYSTEM		= 0x0001,
+	OCC_SENSOR_LOC_PROCESSOR	= 0x0002,
+	OCC_SENSOR_LOC_PARTITION	= 0x0004,
+	OCC_SENSOR_LOC_MEMORY		= 0x0008,
+	OCC_SENSOR_LOC_VRM		= 0x0010,
+	OCC_SENSOR_LOC_OCC		= 0x0020,
+	OCC_SENSOR_LOC_CORE		= 0x0040,
+	OCC_SENSOR_LOC_QUAD		= 0x0080,
+	OCC_SENSOR_LOC_GPU		= 0x0100,
+};
+
+enum sensor_struct_type {
+	OCC_SENSOR_READING_FULL		= 0x01,
+	OCC_SENSOR_READING_COUNTER	= 0x02,
+};
+
+/**
+ * struct occ_sensor_data_header -	Sensor Data Header Block
+ * @valid:				When the value is 0x01 it indicates
+ *					that this header block and the sensor
+ *					names buffer are ready
+ * @version:				Format version of this block
+ * @nr_sensors:				Number of sensors in names, ping and
+ *					pong buffer
+ * @reading_version:			Format version of the Ping/Pong buffer
+ * @names_offset:			Offset to the location of names buffer
+ * @names_version:			Format version of names buffer
+ * @names_length:			Length of each sensor in names buffer
+ * @reading_ping_offset:		Offset to the location of Ping buffer
+ * @reading_pong_offset:		Offset to the location of Pong buffer
+ * @pad/reserved:			Unused data
+ */
+struct occ_sensor_data_header {
+	u8 valid;
+	u8 version;
+	u16 nr_sensors;
+	u8 reading_version;
+	u8 pad[3];
+	u32 names_offset;
+	u8 names_version;
+	u8 name_length;
+	u16 reserved;
+	u32 reading_ping_offset;
+	u32 reading_pong_offset;
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_name -		Format of Sensor Name
+ * @name:				Sensor name
+ * @units:				Sensor units of measurement
+ * @gsid:				Global sensor id (OCC)
+ * @freq:				Update frequency
+ * @scale_factor:			Scaling factor
+ * @type:				Sensor type as defined in
+ *					'enum occ_sensor_type'
+ * @location:				Sensor location as defined in
+ *					'enum occ_sensor_location'
+ * @structure_type:			Indicates type of data structure used
+ *					for the sensor readings in the ping and
+ *					pong buffers for this sensor as defined
+ *					in 'enum sensor_struct_type'
+ * @reading_offset:			Offset from the start of the ping/pong
+ *					reading buffers for this sensor
+ * @sensor_data:			Sensor specific info
+ * @pad:				Padding to fit the size of 48 bytes.
+ */
+struct occ_sensor_name {
+	char name[MAX_CHARS_SENSOR_NAME];
+	char units[MAX_CHARS_SENSOR_UNIT];
+	u16 gsid;
+	u32 freq;
+	u32 scale_factor;
+	u16 type;
+	u16 location;
+	u8 structure_type;
+	u32 reading_offset;
+	u8 sensor_data;
+	u8 pad[8];
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_record -		Sensor Reading Full
+ * @gsid:				Global sensor id (OCC)
+ * @timestamp:				Time base counter value while updating
+ *					the sensor
+ * @sample:				Latest sample of this sensor
+ * @sample_min:				Minimum value since last OCC reset
+ * @sample_max:				Maximum value since last OCC reset
+ * @csm_min:				Minimum value since last reset request
+ *					by CSM (CORAL)
+ * @csm_max:				Maximum value since last reset request
+ *					by CSM (CORAL)
+ * @profiler_min:			Minimum value since last reset request
+ *					by profiler (CORAL)
+ * @profiler_max:			Maximum value since last reset request
+ *					by profiler (CORAL)
+ * @job_scheduler_min:			Minimum value since last reset request
+ *					by job scheduler(CORAL)
+ * @job_scheduler_max:			Maximum value since last reset request
+ *					by job scheduler (CORAL)
+ * @accumulator:			Accumulator for this sensor
+ * @update_tag:				Count of the number of ticks that have
+ *					passed between updates
+ * @pad:				Padding to fit the size of 48 bytes
+ */
+struct occ_sensor_record {
+	u16 gsid;
+	u64 timestamp;
+	u16 sample;
+	u16 sample_min;
+	u16 sample_max;
+	u16 csm_min;
+	u16 csm_max;
+	u16 profiler_min;
+	u16 profiler_max;
+	u16 job_scheduler_min;
+	u16 job_scheduler_max;
+	u64 accumulator;
+	u32 update_tag;
+	u8 pad[8];
+} __attribute__((__packed__));
+
+/**
+ * struct occ_sensor_counter -		Sensor Reading Counter
+ * @gsid:				Global sensor id (OCC)
+ * @timestamp:				Time base counter value while updating
+ *					the sensor
+ * @accumulator:			Accumulator/Counter
+ * @sample:				Latest sample of this sensor (0/1)
+ * @pad:				Padding to fit the size of 24 bytes
+ */
+struct occ_sensor_counter {
+	u16 gsid;
+	u64 timestamp;
+	u64 accumulator;
+	u8 sample;
+	u8 pad[5];
+} __attribute__((__packed__));
diff --git a/include/opal-api.h b/include/opal-api.h
index 0bc036e..466640e 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -214,7 +214,8 @@ 
 #define OPAL_SET_POWER_SHIFT_RATIO		155
 #define OPAL_SENSOR_GROUP_CLEAR			156
 #define OPAL_PCI_SET_P2P			157
-#define OPAL_LAST				157
+#define OPAL_SENSOR_GROUP_ENABLE		158
+#define OPAL_LAST				158
 
 /* Device tree flags */
 
diff --git a/include/skiboot.h b/include/skiboot.h
index db91325..1d6af7b 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -331,6 +331,7 @@  extern void occ_sensors_init(void);
 extern int occ_sensor_read(u32 handle, u32 *data);
 extern int occ_sensor_group_clear(u32 group_hndl, int token);
 extern void occ_add_sensor_groups(struct dt_node *sg, u32  *phandles,
-				  int nr_phandles, int chipid);
+				  u32 *ptype, int nr_phandles, int chipid);
 
+extern int occ_sensor_group_enable(u32 group_hndl, int token, bool enable);
 #endif /* __SKIBOOT_H */