2 * PowerNV OPAL Sensor-groups interface
4 * Copyright 2017 IBM Corp.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define pr_fmt(fmt) "opal-sensor-groups: " fmt
15 #include <linux/kobject.h>
16 #include <linux/slab.h>
20 DEFINE_MUTEX(sg_mutex
);
22 static struct kobject
*sg_kobj
;
26 struct kobj_attribute attr
;
29 static struct sensor_group
{
31 struct attribute_group sg
;
32 struct sg_attr
*sgattrs
;
35 static ssize_t
sg_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
36 const char *buf
, size_t count
)
38 struct sg_attr
*sattr
= container_of(attr
, struct sg_attr
, attr
);
43 ret
= kstrtoint(buf
, 0, &data
);
50 token
= opal_async_get_token_interruptible();
52 pr_devel("Failed to get token\n");
56 ret
= mutex_lock_interruptible(&sg_mutex
);
60 ret
= opal_sensor_group_clear(sattr
->handle
, token
);
62 case OPAL_ASYNC_COMPLETION
:
63 ret
= opal_async_wait_response(token
, &msg
);
65 pr_devel("Failed to wait for the async response\n");
69 ret
= opal_error_code(opal_get_async_rc(msg
));
77 ret
= opal_error_code(ret
);
81 mutex_unlock(&sg_mutex
);
83 opal_async_release_token(token
);
87 static struct sg_ops_info
{
89 const char *attr_name
;
90 ssize_t (*store
)(struct kobject
*kobj
, struct kobj_attribute
*attr
,
91 const char *buf
, size_t count
);
93 { OPAL_SENSOR_GROUP_CLEAR
, "clear", sg_store
},
96 static void add_attr(int handle
, struct sg_attr
*attr
, int index
)
98 attr
->handle
= handle
;
99 sysfs_attr_init(&attr
->attr
.attr
);
100 attr
->attr
.attr
.name
= ops_info
[index
].attr_name
;
101 attr
->attr
.attr
.mode
= 0220;
102 attr
->attr
.store
= ops_info
[index
].store
;
105 static int add_attr_group(const __be32
*ops
, int len
, struct sensor_group
*sg
,
111 for (i
= 0; i
< len
; i
++)
112 for (j
= 0; j
< ARRAY_SIZE(ops_info
); j
++)
113 if (be32_to_cpu(ops
[i
]) == ops_info
[j
].opal_no
) {
114 add_attr(handle
, &sg
->sgattrs
[count
], j
);
115 sg
->sg
.attrs
[count
] =
116 &sg
->sgattrs
[count
].attr
.attr
;
120 return sysfs_create_group(sg_kobj
, &sg
->sg
);
123 static int get_nr_attrs(const __be32
*ops
, int len
)
128 for (i
= 0; i
< len
; i
++)
129 for (j
= 0; j
< ARRAY_SIZE(ops_info
); j
++)
130 if (be32_to_cpu(ops
[i
]) == ops_info
[j
].opal_no
)
136 void __init
opal_sensor_groups_init(void)
138 struct device_node
*sg
, *node
;
141 sg
= of_find_compatible_node(NULL
, NULL
, "ibm,opal-sensor-group");
143 pr_devel("Sensor groups node not found\n");
147 sgs
= kcalloc(of_get_child_count(sg
), sizeof(*sgs
), GFP_KERNEL
);
151 sg_kobj
= kobject_create_and_add("sensor_groups", opal_kobj
);
153 pr_warn("Failed to create sensor group kobject\n");
157 for_each_child_of_node(sg
, node
) {
159 u32 sgid
, len
, nr_attrs
, chipid
;
161 ops
= of_get_property(node
, "ops", &len
);
165 nr_attrs
= get_nr_attrs(ops
, len
);
169 sgs
[i
].sgattrs
= kcalloc(nr_attrs
, sizeof(struct sg_attr
),
172 goto out_sgs_sgattrs
;
174 sgs
[i
].sg
.attrs
= kcalloc(nr_attrs
+ 1,
175 sizeof(struct attribute
*),
178 if (!sgs
[i
].sg
.attrs
) {
179 kfree(sgs
[i
].sgattrs
);
180 goto out_sgs_sgattrs
;
183 if (of_property_read_u32(node
, "sensor-group-id", &sgid
)) {
184 pr_warn("sensor-group-id property not found\n");
185 goto out_sgs_sgattrs
;
188 if (!of_property_read_u32(node
, "ibm,chip-id", &chipid
))
189 sprintf(sgs
[i
].name
, "%s%d", node
->name
, chipid
);
191 sprintf(sgs
[i
].name
, "%s", node
->name
);
193 sgs
[i
].sg
.name
= sgs
[i
].name
;
194 if (add_attr_group(ops
, len
, &sgs
[i
], sgid
)) {
195 pr_warn("Failed to create sensor attribute group %s\n",
197 goto out_sgs_sgattrs
;
206 kfree(sgs
[i
].sgattrs
);
207 kfree(sgs
[i
].sg
.attrs
);
209 kobject_put(sg_kobj
);