[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