aboutsummaryrefslogtreecommitdiff
path: root/core/sensor.c
blob: 303d867e287114a05dbfe364ba344b66050c4022 (plain)
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);
}