[Skiboot] [PATCH 2/2] dts: add DIMM temperature sensors

Cédric Le Goater clg at fr.ibm.com
Mon Jun 22 21:53:07 AEST 2015


The DIMM temperatures are stored in the Centaur's sensor cache. This 
patch adds the necessary interface to read theses values and expose
them to the host OS through the sensor framework of OPAL.

Signed-off-by: Cédric Le Goater <clg at fr.ibm.com>
---
 hw/dts.c |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)

Index: skiboot.git/hw/dts.c
===================================================================
--- skiboot.git.orig/hw/dts.c
+++ skiboot.git/hw/dts.c
@@ -42,6 +42,7 @@ struct dts {
 	uint8_t		valid;
 	uint8_t		trip;
 	int16_t		temp;
+	int8_t		status;
 };
 
 /* Different sensor locations */
@@ -209,6 +210,98 @@ static int dts_read_core_temp(uint32_t p
 	return rc;
 }
 
+/*
+ * Centaur Sensor Cache Registers
+ */
+#define CENTAUR_SCAC_DATA0_3	0x020115CA
+#define CENTAUR_SCAC_DATA4_7	0x020115CB
+#define CENTAUR_SCAC_ENABLE	0x020115CC
+#define CENTAUR_SCAC_LFIR	0x020115C0
+
+enum centaur_scac_status {
+	SCAC_STATUS_STALLED_OR_DISABLED	= 0x0, /* should check LFIR */
+	SCAC_STATUS_ERROR		= 0x1, /* should check LFIR */
+	SCAC_STATUS_VALID_READING	= 0x2,
+	SCAC_STATUS_VALID_READING_NEW	= 0x3  /* First read */
+};
+
+/*
+ * 0		Critical Trip Alarm
+ * 1		Above Window Alarm
+ * 2		Below Window Alarm
+ * 3		Temperature Sign Bit
+ * [4:13]	Temperature = A(4:11) + B(12:13) (Celsius)
+ * [14:15]	Status Indicator (see enum centaur_scac_status)
+ */
+static void dts_decode_one_dimm_dts(uint16_t raw, struct dts *dts)
+{
+	uint8_t sign;
+
+	dts->status = raw & 0x3;
+	dts->valid  = raw & 0x2;
+	dts->temp   = ((raw >> 4) & 0xff) + ((raw >> 2) & 0x3);
+	dts->trip   = (raw >> 13) & 0x7;
+
+	sign = (raw >> 12) & 0x1;
+	if (sign)
+		dts->temp *= -1;
+}
+
+#define MAX_DIMMS 8
+
+static const uint64_t scac_data_addrs[MAX_DIMMS] = {
+	[0 ... 3] = CENTAUR_SCAC_DATA0_3,
+	[4 ... 7] = CENTAUR_SCAC_DATA4_7
+};
+
+static int dts_read_dimm_temp(uint32_t chip_id, uint8_t dimm_id,
+			      struct dts *dts)
+{
+	uint64_t data;
+	uint64_t enable;
+	int rc;
+	struct dts temps[4];
+
+	if (dimm_id >= MAX_DIMMS) {
+		prerror("DTS: Chip %x Dimm %x does not exist\n", chip_id,
+		       dimm_id);
+		return OPAL_PARAMETER;
+	}
+
+	rc = xscom_read(chip_id, CENTAUR_SCAC_ENABLE, &enable);
+	if (rc)
+		return rc;
+
+	if (!(enable & PPC_BIT(dimm_id))) {
+		prerror("DTS: Chip %x Dimm %x is disabled\n", chip_id,
+		       dimm_id);
+		return OPAL_RESOURCE;
+	}
+
+	rc = xscom_read(chip_id, scac_data_addrs[dimm_id], &data);
+	if (rc)
+		return rc;
+
+	dts_decode_one_dimm_dts(data >> 48, &temps[0]);
+	dts_decode_one_dimm_dts(data >> 32, &temps[1]);
+	dts_decode_one_dimm_dts(data >> 16, &temps[2]);
+	dts_decode_one_dimm_dts(data >> 0,  &temps[3]);
+
+	memcpy(dts, &temps[dimm_id % 4], sizeof(*dts));
+
+	if (!dts->valid) {
+		uint64_t lfir;
+
+		xscom_read(chip_id, CENTAUR_SCAC_LFIR, &lfir);
+		prerror("DTS: Chip %x Dimm %x invalid status:%x fir:%016llx\n",
+			chip_id, dimm_id, dts->status, lfir);
+		return OPAL_HARDWARE;
+	}
+
+	prlog(PR_TRACE, "DTS: Chip %x Dimm %x temp:%dC trip:%x status:%x\n",
+	      chip_id, dimm_id, dts->temp, dts->trip, dts->status);
+	return 0;
+}
 
 /* Different sensor locations */
 #define P8_MEM_DTS0	0
@@ -261,6 +354,7 @@ static int dts_read_mem_temp(uint32_t ch
 enum sensor_dts_class {
 	SENSOR_DTS_CORE_TEMP,
 	SENSOR_DTS_MEM_TEMP,
+	SENSOR_DTS_DIMM_TEMP,
 	/* To be continued */
 };
 
@@ -277,6 +371,7 @@ enum {
  * resource identifier field of the sensor handler
  */
 #define centaur_get_id(rid) (0x80000000 | ((rid) & 0x3ff))
+#define dimm_get_id(rid) ((rid) >> 10)
 
 int64_t dts_sensor_read(uint32_t sensor_hndl, uint32_t *sensor_data)
 {
@@ -297,6 +392,10 @@ int64_t dts_sensor_read(uint32_t sensor_
 	case SENSOR_DTS_MEM_TEMP:
 		rc = dts_read_mem_temp(centaur_get_id(rid), &dts);
 		break;
+	case SENSOR_DTS_DIMM_TEMP:
+		rc = dts_read_dimm_temp(centaur_get_id(rid), dimm_get_id(rid),
+					&dts);
+		break;
 	default:
 		rc = OPAL_PARAMETER;
 		break;
@@ -333,11 +432,16 @@ int64_t dts_sensor_read(uint32_t sensor_
 	sensor_make_handler(SENSOR_DTS_MEM_TEMP|SENSOR_DTS,		\
 			    centaur_make_id(chip_id, 0), attr_id)
 
+#define dimm_handler(cen_id, dimm_id, attr_id)				\
+	sensor_make_handler(SENSOR_DTS_DIMM_TEMP|SENSOR_DTS,		\
+			    centaur_make_id(chip_id, i), attr_id)
+
 bool dts_sensor_create_nodes(struct dt_node *sensors)
 {
 	struct proc_chip *chip;
 	struct dt_node *cn;
 	char name[64];
+	int dimm_num = 1;
 
 	/* build the device tree nodes :
 	 *
@@ -375,6 +479,9 @@ bool dts_sensor_create_nodes(struct dt_n
 		uint32_t chip_id;
 		struct dt_node *node;
 		uint32_t handler;
+		uint64_t enable;
+		int rc;
+		int i;
 
 		chip_id = dt_prop_get_u32(cn, "ibm,chip-id");
 
@@ -391,6 +498,48 @@ bool dts_sensor_create_nodes(struct dt_n
 		dt_add_property_string(node, "sensor-type", "temp");
 		dt_add_property_cells(node, "ibm,chip-id", chip_id);
 		dt_add_property_string(node, "label", "Centaur");
+
+		rc = xscom_read(chip_id, CENTAUR_SCAC_ENABLE, &enable);
+		if (rc) {
+			prerror("DTS: Chip %x failed to create nodes for DIMMs",
+			       chip_id);
+			continue;
+		}
+
+		for (i = 0; i < MAX_DIMMS; i++, dimm_num++) {
+			if (!(enable & PPC_BIT(i))) {
+				prlog(PR_INFO, "DTS: Chip %x Dimm %x is disabled\n",
+					chip_id, i);
+				continue;
+			}
+
+			snprintf(name, sizeof(name), "dimm-temp@%x-%x",
+				 chip_id, i);
+
+			/*
+			 * We only have two bytes for the resource
+			 * identifier. Let's trunctate the centaur chip id
+			 */
+			handler = dimm_handler(chip_id, i,
+					       SENSOR_DTS_ATTR_TEMP_MAX);
+			node = dt_new(sensors, name);
+			dt_add_property_string(node, "compatible",
+					       "ibm,opal-sensor");
+			dt_add_property_cells(node, "sensor-data", handler);
+
+			handler = dimm_handler(chip_id, i,
+					       SENSOR_DTS_ATTR_TEMP_TRIP);
+			dt_add_property_cells(node, "sensor-status", handler);
+			dt_add_property_string(node, "sensor-type", "temp");
+
+			/*
+			 *  Use a global increment for the DIMMs. It
+			 *  gives a quick idea on how slots are
+			 *  populated on the system.
+			 */
+			snprintf(name, sizeof(name), "Dimm %d", dimm_num);
+			dt_add_property_string(node, "label", name);
+		}
 	}
 
 	return true;



More information about the Skiboot mailing list