blob: 303d867e287114a05dbfe364ba344b66050c4022 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/*
* OPAL Sensor APIs
*
* Copyright 2013-2018 IBM Corp.
*/
#include <sensor.h>
#include <skiboot.h>
#include <device.h>
#include <opal.h>
#include <dts.h>
#include <lock.h>
#include <occ.h>
struct dt_node *sensor_node;
static struct lock async_read_list_lock = LOCK_UNLOCKED;
static LIST_HEAD(async_read_list);
struct sensor_async_read {
struct list_node link;
__be64 *val;
__be32 *opal_data;
int token;
};
static int add_to_async_read_list(int token, __be32 *opal_data, __be64 *val)
{
struct sensor_async_read *req;
req = zalloc(sizeof(*req));
if (!req)
return OPAL_NO_MEM;
req->token = token;
req->val = val;
req->opal_data = opal_data;
lock(&async_read_list_lock);
list_add_tail(&async_read_list, &req->link);
unlock(&async_read_list_lock);
return OPAL_ASYNC_COMPLETION;
}
void check_sensor_read(int token)
{
struct sensor_async_read *req = NULL;
lock(&async_read_list_lock);
if (list_empty(&async_read_list))
goto out;
list_for_each(&async_read_list, req, link) {
if (req->token == token)
break;
}
if (!req)
goto out;
*req->opal_data = cpu_to_be32(be64_to_cpu(*req->val));
free(req->val);
list_del(&req->link);
free(req);
out:
unlock(&async_read_list_lock);
}
static s64 opal_sensor_read_64(u32 sensor_hndl, int token, __be64 *data)
{
s64 rc;
switch (sensor_get_family(sensor_hndl)) {
case SENSOR_DTS:
rc = dts_sensor_read(sensor_hndl, token, data);
return rc;
case SENSOR_OCC:
rc = occ_sensor_read(sensor_hndl, data);
return rc;
default:
break;
}
if (platform.sensor_read) {
rc = platform.sensor_read(sensor_hndl, token, data);
return rc;
}
return OPAL_UNSUPPORTED;
}
static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
__be32 *data)
{
__be64 *val;
s64 rc;
val = zalloc(sizeof(*val));
if (!val)
return OPAL_NO_MEM;
rc = opal_sensor_read_64(sensor_hndl, token, val);
if (rc == OPAL_SUCCESS) {
*data = cpu_to_be32(be64_to_cpu(*val));
free(val);
} else if (rc == OPAL_ASYNC_COMPLETION) {
rc = add_to_async_read_list(token, data, val);
}
return rc;
}
static int opal_sensor_group_clear(u32 group_hndl, int token)
{
switch (sensor_get_family(group_hndl)) {
case SENSOR_OCC:
return occ_sensor_group_clear(group_hndl, token);
default:
break;
}
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");
dt_add_property_string(sensor_node, "compatible", "ibm,opal-sensor");
dt_add_property_cells(sensor_node, "#address-cells", 1);
dt_add_property_cells(sensor_node, "#size-cells", 0);
/* 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_READ_U64, opal_sensor_read_64, 3);
opal_register(OPAL_SENSOR_GROUP_ENABLE, opal_sensor_group_enable, 3);
}