treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / thermal / intel / int340x_thermal / acpi_thermal_rel.c
blob7130e90773ed6e4c4f91caec9421136b34e4bc1c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* acpi_thermal_rel.c driver for exporting ACPI thermal relationship
4 * Copyright (c) 2014 Intel Corp
5 */
7 /*
8 * Two functionalities included:
9 * 1. Export _TRT, _ART, via misc device interface to the userspace.
10 * 2. Provide parsing result to kernel drivers
13 #include <linux/init.h>
14 #include <linux/export.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/platform_device.h>
18 #include <linux/io.h>
19 #include <linux/acpi.h>
20 #include <linux/uaccess.h>
21 #include <linux/miscdevice.h>
22 #include "acpi_thermal_rel.h"
24 static acpi_handle acpi_thermal_rel_handle;
25 static DEFINE_SPINLOCK(acpi_thermal_rel_chrdev_lock);
26 static int acpi_thermal_rel_chrdev_count; /* #times opened */
27 static int acpi_thermal_rel_chrdev_exclu; /* already open exclusive? */
29 static int acpi_thermal_rel_open(struct inode *inode, struct file *file)
31 spin_lock(&acpi_thermal_rel_chrdev_lock);
32 if (acpi_thermal_rel_chrdev_exclu ||
33 (acpi_thermal_rel_chrdev_count && (file->f_flags & O_EXCL))) {
34 spin_unlock(&acpi_thermal_rel_chrdev_lock);
35 return -EBUSY;
38 if (file->f_flags & O_EXCL)
39 acpi_thermal_rel_chrdev_exclu = 1;
40 acpi_thermal_rel_chrdev_count++;
42 spin_unlock(&acpi_thermal_rel_chrdev_lock);
44 return nonseekable_open(inode, file);
47 static int acpi_thermal_rel_release(struct inode *inode, struct file *file)
49 spin_lock(&acpi_thermal_rel_chrdev_lock);
50 acpi_thermal_rel_chrdev_count--;
51 acpi_thermal_rel_chrdev_exclu = 0;
52 spin_unlock(&acpi_thermal_rel_chrdev_lock);
54 return 0;
57 /**
58 * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling
60 * @handle: ACPI handle of the device contains _TRT
61 * @trt_count: the number of valid entries resulted from parsing _TRT
62 * @trtp: pointer to pointer of array of _TRT entries in parsing result
63 * @create_dev: whether to create platform devices for target and source
66 int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
67 bool create_dev)
69 acpi_status status;
70 int result = 0;
71 int i;
72 int nr_bad_entries = 0;
73 struct trt *trts;
74 struct acpi_device *adev;
75 union acpi_object *p;
76 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
77 struct acpi_buffer element = { 0, NULL };
78 struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
80 status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer);
81 if (ACPI_FAILURE(status))
82 return -ENODEV;
84 p = buffer.pointer;
85 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
86 pr_err("Invalid _TRT data\n");
87 result = -EFAULT;
88 goto end;
91 *trt_count = p->package.count;
92 trts = kcalloc(*trt_count, sizeof(struct trt), GFP_KERNEL);
93 if (!trts) {
94 result = -ENOMEM;
95 goto end;
98 for (i = 0; i < *trt_count; i++) {
99 struct trt *trt = &trts[i - nr_bad_entries];
101 element.length = sizeof(struct trt);
102 element.pointer = trt;
104 status = acpi_extract_package(&(p->package.elements[i]),
105 &trt_format, &element);
106 if (ACPI_FAILURE(status)) {
107 nr_bad_entries++;
108 pr_warn("_TRT package %d is invalid, ignored\n", i);
109 continue;
111 if (!create_dev)
112 continue;
114 result = acpi_bus_get_device(trt->source, &adev);
115 if (result)
116 pr_warn("Failed to get source ACPI device\n");
118 result = acpi_bus_get_device(trt->target, &adev);
119 if (result)
120 pr_warn("Failed to get target ACPI device\n");
123 result = 0;
125 *trtp = trts;
126 /* don't count bad entries */
127 *trt_count -= nr_bad_entries;
128 end:
129 kfree(buffer.pointer);
130 return result;
132 EXPORT_SYMBOL(acpi_parse_trt);
135 * acpi_parse_art - Parse Active Relationship Table _ART
137 * @handle: ACPI handle of the device contains _ART
138 * @art_count: the number of valid entries resulted from parsing _ART
139 * @artp: pointer to pointer of array of art entries in parsing result
140 * @create_dev: whether to create platform devices for target and source
143 int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
144 bool create_dev)
146 acpi_status status;
147 int result = 0;
148 int i;
149 int nr_bad_entries = 0;
150 struct art *arts;
151 struct acpi_device *adev;
152 union acpi_object *p;
153 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
154 struct acpi_buffer element = { 0, NULL };
155 struct acpi_buffer art_format = {
156 sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
158 status = acpi_evaluate_object(handle, "_ART", NULL, &buffer);
159 if (ACPI_FAILURE(status))
160 return -ENODEV;
162 p = buffer.pointer;
163 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
164 pr_err("Invalid _ART data\n");
165 result = -EFAULT;
166 goto end;
169 /* ignore p->package.elements[0], as this is _ART Revision field */
170 *art_count = p->package.count - 1;
171 arts = kcalloc(*art_count, sizeof(struct art), GFP_KERNEL);
172 if (!arts) {
173 result = -ENOMEM;
174 goto end;
177 for (i = 0; i < *art_count; i++) {
178 struct art *art = &arts[i - nr_bad_entries];
180 element.length = sizeof(struct art);
181 element.pointer = art;
183 status = acpi_extract_package(&(p->package.elements[i + 1]),
184 &art_format, &element);
185 if (ACPI_FAILURE(status)) {
186 pr_warn("_ART package %d is invalid, ignored", i);
187 nr_bad_entries++;
188 continue;
190 if (!create_dev)
191 continue;
193 if (art->source) {
194 result = acpi_bus_get_device(art->source, &adev);
195 if (result)
196 pr_warn("Failed to get source ACPI device\n");
198 if (art->target) {
199 result = acpi_bus_get_device(art->target, &adev);
200 if (result)
201 pr_warn("Failed to get target ACPI device\n");
205 *artp = arts;
206 /* don't count bad entries */
207 *art_count -= nr_bad_entries;
208 end:
209 kfree(buffer.pointer);
210 return result;
212 EXPORT_SYMBOL(acpi_parse_art);
215 /* get device name from acpi handle */
216 static void get_single_name(acpi_handle handle, char *name)
218 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
220 if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)))
221 pr_warn("Failed to get device name from acpi handle\n");
222 else {
223 memcpy(name, buffer.pointer, ACPI_NAMESEG_SIZE);
224 kfree(buffer.pointer);
228 static int fill_art(char __user *ubuf)
230 int i;
231 int ret;
232 int count;
233 int art_len;
234 struct art *arts = NULL;
235 union art_object *art_user;
237 ret = acpi_parse_art(acpi_thermal_rel_handle, &count, &arts, false);
238 if (ret)
239 goto free_art;
240 art_len = count * sizeof(union art_object);
241 art_user = kzalloc(art_len, GFP_KERNEL);
242 if (!art_user) {
243 ret = -ENOMEM;
244 goto free_art;
246 /* now fill in user art data */
247 for (i = 0; i < count; i++) {
248 /* userspace art needs device name instead of acpi reference */
249 get_single_name(arts[i].source, art_user[i].source_device);
250 get_single_name(arts[i].target, art_user[i].target_device);
251 /* copy the rest int data in addition to source and target */
252 memcpy(&art_user[i].weight, &arts[i].weight,
253 sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
256 if (copy_to_user(ubuf, art_user, art_len))
257 ret = -EFAULT;
258 kfree(art_user);
259 free_art:
260 kfree(arts);
261 return ret;
264 static int fill_trt(char __user *ubuf)
266 int i;
267 int ret;
268 int count;
269 int trt_len;
270 struct trt *trts = NULL;
271 union trt_object *trt_user;
273 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, &trts, false);
274 if (ret)
275 goto free_trt;
276 trt_len = count * sizeof(union trt_object);
277 trt_user = kzalloc(trt_len, GFP_KERNEL);
278 if (!trt_user) {
279 ret = -ENOMEM;
280 goto free_trt;
282 /* now fill in user trt data */
283 for (i = 0; i < count; i++) {
284 /* userspace trt needs device name instead of acpi reference */
285 get_single_name(trts[i].source, trt_user[i].source_device);
286 get_single_name(trts[i].target, trt_user[i].target_device);
287 trt_user[i].sample_period = trts[i].sample_period;
288 trt_user[i].influence = trts[i].influence;
291 if (copy_to_user(ubuf, trt_user, trt_len))
292 ret = -EFAULT;
293 kfree(trt_user);
294 free_trt:
295 kfree(trts);
296 return ret;
299 static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
300 unsigned long __arg)
302 int ret = 0;
303 unsigned long length = 0;
304 int count = 0;
305 char __user *arg = (void __user *)__arg;
306 struct trt *trts = NULL;
307 struct art *arts = NULL;
309 switch (cmd) {
310 case ACPI_THERMAL_GET_TRT_COUNT:
311 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count,
312 &trts, false);
313 kfree(trts);
314 if (!ret)
315 return put_user(count, (unsigned long __user *)__arg);
316 return ret;
317 case ACPI_THERMAL_GET_TRT_LEN:
318 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count,
319 &trts, false);
320 kfree(trts);
321 length = count * sizeof(union trt_object);
322 if (!ret)
323 return put_user(length, (unsigned long __user *)__arg);
324 return ret;
325 case ACPI_THERMAL_GET_TRT:
326 return fill_trt(arg);
327 case ACPI_THERMAL_GET_ART_COUNT:
328 ret = acpi_parse_art(acpi_thermal_rel_handle, &count,
329 &arts, false);
330 kfree(arts);
331 if (!ret)
332 return put_user(count, (unsigned long __user *)__arg);
333 return ret;
334 case ACPI_THERMAL_GET_ART_LEN:
335 ret = acpi_parse_art(acpi_thermal_rel_handle, &count,
336 &arts, false);
337 kfree(arts);
338 length = count * sizeof(union art_object);
339 if (!ret)
340 return put_user(length, (unsigned long __user *)__arg);
341 return ret;
343 case ACPI_THERMAL_GET_ART:
344 return fill_art(arg);
346 default:
347 return -ENOTTY;
351 static const struct file_operations acpi_thermal_rel_fops = {
352 .owner = THIS_MODULE,
353 .open = acpi_thermal_rel_open,
354 .release = acpi_thermal_rel_release,
355 .unlocked_ioctl = acpi_thermal_rel_ioctl,
356 .llseek = no_llseek,
359 static struct miscdevice acpi_thermal_rel_misc_device = {
360 .minor = MISC_DYNAMIC_MINOR,
361 "acpi_thermal_rel",
362 &acpi_thermal_rel_fops
365 int acpi_thermal_rel_misc_device_add(acpi_handle handle)
367 acpi_thermal_rel_handle = handle;
369 return misc_register(&acpi_thermal_rel_misc_device);
371 EXPORT_SYMBOL(acpi_thermal_rel_misc_device_add);
373 int acpi_thermal_rel_misc_device_remove(acpi_handle handle)
375 misc_deregister(&acpi_thermal_rel_misc_device);
377 return 0;
379 EXPORT_SYMBOL(acpi_thermal_rel_misc_device_remove);
381 MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
382 MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com");
383 MODULE_DESCRIPTION("Intel acpi thermal rel misc dev driver");
384 MODULE_LICENSE("GPL v2");