/* Sensor suffix name from DT */ #define DT_FAULT_ATTR_SUFFIX "faulted" #define DT_DATA_ATTR_SUFFIX "data" #define DT_THRESHOLD_ATTR_SUFFIX "thrs"
/* * Enumerates all the types of sensors in the POWERNV platform and does index * into 'struct sensor_group'
*/ enum sensors {
FAN,
TEMP,
POWER_SUPPLY,
POWER_INPUT,
CURRENT,
ENERGY,
MAX_SENSOR_TYPE,
};
#define INVALID_INDEX (-1U)
/* * 'compatible' string properties for sensor types as defined in old * PowerNV firmware (skiboot). These are ordered as 'enum sensors'.
*/ staticconstchar * const legacy_compatibles[] = { "ibm,opal-sensor-cooling-fan", "ibm,opal-sensor-amb-temp", "ibm,opal-sensor-power-supply", "ibm,opal-sensor-power"
};
struct platform_data { conststruct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1]; struct sensor_group_data *sgrp_data;
u32 sensors_count; /* Total count of sensors from each group */
u32 nr_sensor_groups; /* Total number of sensor groups */
};
if (sdata->sgrp_data && !sdata->sgrp_data->enable) return -ENODATA;
ret = opal_get_sensor_data_u64(sdata->id, &x);
if (ret) return ret;
/* Convert temperature to milli-degrees */ if (sdata->type == TEMP)
x *= 1000; /* Convert power to micro-watts */ elseif (sdata->type == POWER_INPUT)
x *= 1000000;
n = scnprintf(sdata->label, sizeof(sdata->label), "%s", label);
/* * Core temp pretty print
*/ if (!of_property_read_u32(np, "ibm,pir", &id)) { int cpuid = get_logical_cpu(id);
if (cpuid >= 0) /* * The digital thermal sensors are associated * with a core.
*/
n += scnprintf(sdata->label + n, sizeof(sdata->label) - n, " %d",
cpuid); else
n += scnprintf(sdata->label + n, sizeof(sdata->label) - n, " phy%d", id);
}
/* * Membuffer pretty print
*/ if (!of_property_read_u32(np, "ibm,chip-id", &id))
n += scnprintf(sdata->label + n, sizeof(sdata->label) - n, " %d", id & 0xffff);
}
/* * This function translates the DT node name into the 'hwmon' attribute name. * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc. * which need to be mapped as fan2_input, temp1_max respectively before * populating them inside hwmon device class.
*/ staticconstchar *parse_opal_node_name(constchar *node_name, enum sensors type, u32 *index)
{ char attr_suffix[MAX_ATTR_LEN]; constchar *attr_name; int err;
err = get_sensor_index_attr(node_name, index, attr_suffix); if (err) return ERR_PTR(err);
attr_name = convert_opal_attr_name(type, attr_suffix); if (!attr_name) return ERR_PTR(-ENOENT);
for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) { if (of_device_is_compatible(np, legacy_compatibles[type])) return type;
}
/* * Let's check if we have a newer device tree
*/ if (!of_device_is_compatible(np, "ibm,opal-sensor")) return MAX_SENSOR_TYPE;
if (of_property_read_string(np, "sensor-type", &str)) return MAX_SENSOR_TYPE;
for (type = 0; type < MAX_SENSOR_TYPE; type++) if (!strcmp(str, sensor_groups[type].name)) return type;
return MAX_SENSOR_TYPE;
}
static u32 get_sensor_hwmon_index(struct sensor_data *sdata, struct sensor_data *sdata_table, int count)
{ int i;
/* * We don't use the OPAL index on newer device trees
*/ if (sdata->opal_index != INVALID_INDEX) { for (i = 0; i < count; i++) if (sdata_table[i].opal_index == sdata->opal_index &&
sdata_table[i].type == sdata->type) return sdata_table[i].hwmon_index;
} return ++sensor_groups[sdata->type].hwmon_index;
}
type = get_sensor_type(np); if (type == MAX_SENSOR_TYPE) continue;
sensor_groups[type].attr_count++;
/* * add attributes for labels, min and max
*/ if (!of_property_read_string(np, "label", &label))
sensor_groups[type].attr_count++; if (of_property_present(np, "sensor-data-min"))
sensor_groups[type].attr_count++; if (of_property_present(np, "sensor-data-max"))
sensor_groups[type].attr_count++;
}
of_node_put(opal);
for (type = 0; type < MAX_SENSOR_TYPE; type++) {
sensor_groups[type].group.attrs = devm_kcalloc(&pdev->dev,
sensor_groups[type].attr_count + 1, sizeof(struct attribute *),
GFP_KERNEL); if (!sensor_groups[type].group.attrs) return -ENOMEM;
/* * Iterate through the device tree for each child of 'sensors' node, create * a sysfs attribute file, the file is named by translating the DT node name * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max * etc..
*/ staticint create_device_attrs(struct platform_device *pdev)
{ struct platform_data *pdata = platform_get_drvdata(pdev); conststruct attribute_group **pgroups = pdata->attr_groups; struct device_node *opal, *np; struct sensor_data *sdata;
u32 count = 0;
u32 group_attr_id[MAX_SENSOR_TYPE] = {0};
sdata = devm_kcalloc(&pdev->dev,
pdata->sensors_count, sizeof(*sdata),
GFP_KERNEL); if (!sdata) return -ENOMEM;
type = get_sensor_type(np); if (type == MAX_SENSOR_TYPE) continue;
/* * Newer device trees use a "sensor-data" property * name for input.
*/ if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
of_property_read_u32(np, "sensor-data", &sensor_id)) {
dev_info(&pdev->dev, "'sensor-id' missing in the node '%pOFn'\n",
np); continue;
}
/* * If we can not parse the node name, it means we are * running on a newer device tree. We can just forget * about the OPAL index and use a defaut value for the * hwmon attribute name
*/
attr_name = parse_opal_node_name(np->name, type, &opal_index); if (IS_ERR(attr_name)) {
attr_name = "input";
opal_index = INVALID_INDEX;
}
if (!of_property_read_string(np, "label", &label)) { /* * For the label attribute, we can reuse the * "properties" of the previous "input" * attribute. They are related to the same * sensor.
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.