blob: bd329a183ee18d199e47cd87cb7c9e758aec75c4 [file] [log] [blame]
/* Copyright 2013-2018 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.
*/
#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;
u64 *sensor_data64;
u32 *sensor_data32;
int token;
};
static int add_to_async_read_list(int token, u32 *data32, u64 *data64)
{
struct sensor_async_read *req;
req = zalloc(sizeof(*req));
if (!req)
return OPAL_NO_MEM;
req->token = token;
req->sensor_data64 = data64;
req->sensor_data32 = data32;
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->sensor_data32 = *req->sensor_data64;
free(req->sensor_data64);
list_del(&req->link);
free(req);
out:
unlock(&async_read_list_lock);
}
static s64 opal_sensor_read_u64(u32 sensor_hndl, int token, u64 *sensor_data)
{
switch (sensor_get_family(sensor_hndl)) {
case SENSOR_DTS:
return dts_sensor_read(sensor_hndl, token, sensor_data);
case SENSOR_OCC:
return occ_sensor_read(sensor_hndl, sensor_data);
default:
break;
}
if (platform.sensor_read)
return platform.sensor_read(sensor_hndl, token, sensor_data);
return OPAL_UNSUPPORTED;
}
static int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
uint32_t *sensor_data)
{
u64 *val;
s64 ret;
val = zalloc(sizeof(*val));
if (!val)
return OPAL_NO_MEM;
ret = opal_sensor_read_u64(sensor_hndl, token, val);
if (!ret) {
*sensor_data = *val;
free(val);
} else if (ret == OPAL_ASYNC_COMPLETION) {
ret = add_to_async_read_list(token, sensor_data, val);
}
return ret;
}
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_u64, 3);
opal_register(OPAL_SENSOR_GROUP_ENABLE, opal_sensor_group_enable, 3);
}