1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// 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);
}
|