/* 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 #include #include #include #include #include #include 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); }