[RESEND] thermal: intel: int340x_thermal: New IOCTLs for thermal
Commit Message
Export Passive version 2 table similar to the way _TRT and _ART tables
via IOCTLs.
This removes need for binary utility to read ACPI Passive 2 table by
providing open source support. This table already has open source
implementation in the user space thermald, when the table is part of
data vault exported by the int3400 sysfs.
This table is supported in some older platforms before Ice Lake
generation.
Passive 2 tables contain multiple entries. Each entry has following
fields:
Source: Named Reference (String). This is the source device for
temperature.
Target: Named Reference (String). This is the target device to control.
Priority: Priority of this device compared to others.
SamplingPeriod: Time Period in 1/10 of seconds unit.
PassiveTemp: Passive Temperature in 1/10 of Kelvin.
SourceDomain: Domain for the source (00:Processor, others reserved).
ControlKnob: Type of control knob (00:Power Limit 1, others: reserved)
Limit: The target state to set on reaching passive temperature.
This can be a string "max", "min" or a power limit value.
LimitStepSize: Step size during activation.
UnLimitStepSize: Step size during deactivation.
Reserved1: Reserved
Four IOCTLs are added similar to IOCTLs for reading TRT:
ACPI_THERMAL_GET_PSVT_COUNT: Number of passive 2 entries.
ACPI_THERMAL_GET_PSVT_LEN: Total return data size (count x each
passive 2 entry size).
ACPI_THERMAL_GET_PSVT: Get the data as an array of objects with
passive 2 entries.
This change is based on original development done by:
Todd Brandt <todd.e.brandt@linux.intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
Resent with the correct series. Sorry about previous posts.
.../intel/int340x_thermal/acpi_thermal_rel.c | 218 ++++++++++++++++++
.../intel/int340x_thermal/acpi_thermal_rel.h | 57 +++++
2 files changed, 275 insertions(+)
Comments
Hi Srinivas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rafael-pm/thermal]
[also build test WARNING on linus/master v6.4-rc3 next-20230523]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Srinivas-Pandruvada/thermal-intel-int340x_thermal-New-IOCTLs-for-thermal/20230524-062514
base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git thermal
patch link: https://lore.kernel.org/r/20230523221339.2377625-1-srinivas.pandruvada%40linux.intel.com
patch subject: [RESEND][PATCH] thermal: intel: int340x_thermal: New IOCTLs for thermal
config: x86_64-randconfig-x083
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce (this is a W=1 build):
# https://github.com/intel-lab-lkp/linux/commit/d9cdbb3a7b52afac5dcbf0aaa2d1593964554c7c
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Srinivas-Pandruvada/thermal-intel-int340x_thermal-New-IOCTLs-for-thermal/20230524-062514
git checkout d9cdbb3a7b52afac5dcbf0aaa2d1593964554c7c
# save the config file
mkdir build_dir && cp config build_dir/.config
make W=1 O=build_dir ARCH=x86_64 olddefconfig
make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/thermal/intel/int340x_thermal/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305241341.gbrnvwNY-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:214:5: warning: no previous prototype for 'acpi_parse_psvt' [-Wmissing-prototypes]
214 | int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
| ^~~~~~~~~~~~~~~
vim +/acpi_parse_psvt +214 drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
205
206 /*
207 * acpi_parse_psvt - Passive Table (PSVT) for passive cooling
208 *
209 * @handle: ACPI handle of the device which contains PSVT
210 * @psvt_count: the number of valid entries resulted from parsing PSVT
211 * @psvtp: pointer to array of psvt entries
212 *
213 */
> 214 int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
215 {
216 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
217 int nr_bad_entries = 0, revision;
218 union acpi_object *p;
219 acpi_status status;
220 int i, result = 0;
221 struct psvt *psvts;
222
223 if (!acpi_has_method(handle, "PSVT"))
224 return -ENODEV;
225
226 status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer);
227 if (ACPI_FAILURE(status))
228 return -ENODEV;
229
230 p = buffer.pointer;
231 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
232 result = -EFAULT;
233 goto end;
234 }
235
236 /* first package is the revision number */
237 if (p->package.count > 0) {
238 union acpi_object *prev = &(p->package.elements[0]);
239
240 if (prev->type == ACPI_TYPE_INTEGER)
241 revision = (int)prev->integer.value;
242 } else {
243 result = -EFAULT;
244 goto end;
245 }
246
247 /* Support only version 2 */
248 if (revision != 2) {
249 result = -EFAULT;
250 goto end;
251 }
252
253 *psvt_count = p->package.count - 1;
254 if (!*psvt_count) {
255 result = -EFAULT;
256 goto end;
257 }
258
259 psvts = kcalloc(*psvt_count, sizeof(*psvts), GFP_KERNEL);
260 if (!psvts) {
261 result = -ENOMEM;
262 goto end;
263 }
264
265 /* Start index is 1 because the first package is the revision number */
266 for (i = 1; i < p->package.count; i++) {
267 struct acpi_buffer psvt_int_format = { sizeof("RRNNNNNNNNNN"), "RRNNNNNNNNNN" };
268 struct acpi_buffer psvt_str_format = { sizeof("RRNNNNNSNNNN"), "RRNNNNNSNNNN" };
269 union acpi_object *package = &(p->package.elements[i]);
270 struct psvt *psvt = &psvts[i - 1 - nr_bad_entries];
271 struct acpi_buffer *psvt_format = &psvt_int_format;
272 struct acpi_buffer element = { 0, NULL };
273 union acpi_object *knob;
274 struct acpi_device *res;
275 struct psvt *psvt_ptr;
276
277 element.length = ACPI_ALLOCATE_BUFFER;
278 element.pointer = NULL;
279
280 if (package->package.count >= ACPI_NR_PSVT_ELEMENTS) {
281 knob = &(package->package.elements[ACPI_PSVT_CONTROL_KNOB]);
282 } else {
283 nr_bad_entries++;
284 pr_info("PSVT package %d is invalid, ignored\n", i);
285 continue;
286 }
287
288 if (knob->type == ACPI_TYPE_STRING) {
289 psvt_format = &psvt_str_format;
290 if (knob->string.length > ACPI_LIMIT_STR_MAX_LEN) {
291 pr_info("PSVT package %d limit string len exceeds max\n", i);
292 knob->string.length = ACPI_LIMIT_STR_MAX_LEN;
293 }
294 }
295
296 status = acpi_extract_package(&(p->package.elements[i]), psvt_format, &element);
297 if (ACPI_FAILURE(status)) {
298 nr_bad_entries++;
299 pr_info("PSVT package %d is invalid, ignored\n", i);
300 continue;
301 }
302
303 psvt_ptr = (struct psvt *)element.pointer;
304
305 memcpy(psvt, psvt_ptr, sizeof(*psvt_ptr));
306
307 /* The limit element can be string or U64 */
308 psvt->control_knob_type = (u64)knob->type;
309
310 if (knob->type == ACPI_TYPE_STRING) {
311 memset(&psvt->limit, 0, sizeof(u64));
312 strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
313 } else {
314 psvt->limit.integer = psvt_ptr->limit.integer;
315 }
316
317 kfree(element.pointer);
318
319 res = acpi_fetch_acpi_dev(psvt->source);
320 if (!res) {
321 nr_bad_entries++;
322 pr_info("Failed to get source ACPI device\n");
323 continue;
324 }
325
326 res = acpi_fetch_acpi_dev(psvt->target);
327 if (!res) {
328 nr_bad_entries++;
329 pr_info("Failed to get target ACPI device\n");
330 continue;
331 }
332 }
333
334 /* don't count bad entries */
335 *psvt_count -= nr_bad_entries;
336
337 if (!*psvt_count) {
338 result = -EFAULT;
339 kfree(psvts);
340 goto end;
341 }
342
343 *psvtp = psvts;
344
345 return 0;
346
347 end:
348 kfree(buffer.pointer);
349 return result;
350 }
351
Hi Srinivas,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rafael-pm/thermal]
[also build test WARNING on linus/master v6.4-rc3 next-20230524]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Srinivas-Pandruvada/thermal-intel-int340x_thermal-New-IOCTLs-for-thermal/20230524-062514
base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git thermal
patch link: https://lore.kernel.org/r/20230523221339.2377625-1-srinivas.pandruvada%40linux.intel.com
patch subject: [RESEND][PATCH] thermal: intel: int340x_thermal: New IOCTLs for thermal
config: x86_64-randconfig-x075
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
mkdir -p ~/bin
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/d9cdbb3a7b52afac5dcbf0aaa2d1593964554c7c
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Srinivas-Pandruvada/thermal-intel-int340x_thermal-New-IOCTLs-for-thermal/20230524-062514
git checkout d9cdbb3a7b52afac5dcbf0aaa2d1593964554c7c
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=x86_64 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/thermal/intel/int340x_thermal/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202305241812.MJMEMRiJ-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:214:5: warning: no previous prototype for function 'acpi_parse_psvt' [-Wmissing-prototypes]
int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
^
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:214:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
^
static
>> drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:240:7: warning: variable 'revision' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
if (prev->type == ACPI_TYPE_INTEGER)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:248:6: note: uninitialized use occurs here
if (revision != 2) {
^~~~~~~~
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:240:3: note: remove the 'if' if its condition is always true
if (prev->type == ACPI_TYPE_INTEGER)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c:217:34: note: initialize the variable 'revision' to silence this warning
int nr_bad_entries = 0, revision;
^
= 0
2 warnings generated.
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for CRYPTO_CRC32C_INTEL
Depends on [n]: CRYPTO [=y] && !KMSAN [=y] && X86 [=y]
Selected by [m]:
- ISCSI_TARGET [=m] && TARGET_CORE [=y] && INET [=y] && X86 [=y]
vim +/acpi_parse_psvt +214 drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
205
206 /*
207 * acpi_parse_psvt - Passive Table (PSVT) for passive cooling
208 *
209 * @handle: ACPI handle of the device which contains PSVT
210 * @psvt_count: the number of valid entries resulted from parsing PSVT
211 * @psvtp: pointer to array of psvt entries
212 *
213 */
> 214 int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
215 {
216 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
217 int nr_bad_entries = 0, revision;
218 union acpi_object *p;
219 acpi_status status;
220 int i, result = 0;
221 struct psvt *psvts;
222
223 if (!acpi_has_method(handle, "PSVT"))
224 return -ENODEV;
225
226 status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer);
227 if (ACPI_FAILURE(status))
228 return -ENODEV;
229
230 p = buffer.pointer;
231 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
232 result = -EFAULT;
233 goto end;
234 }
235
236 /* first package is the revision number */
237 if (p->package.count > 0) {
238 union acpi_object *prev = &(p->package.elements[0]);
239
> 240 if (prev->type == ACPI_TYPE_INTEGER)
241 revision = (int)prev->integer.value;
242 } else {
243 result = -EFAULT;
244 goto end;
245 }
246
247 /* Support only version 2 */
248 if (revision != 2) {
249 result = -EFAULT;
250 goto end;
251 }
252
253 *psvt_count = p->package.count - 1;
254 if (!*psvt_count) {
255 result = -EFAULT;
256 goto end;
257 }
258
259 psvts = kcalloc(*psvt_count, sizeof(*psvts), GFP_KERNEL);
260 if (!psvts) {
261 result = -ENOMEM;
262 goto end;
263 }
264
265 /* Start index is 1 because the first package is the revision number */
266 for (i = 1; i < p->package.count; i++) {
267 struct acpi_buffer psvt_int_format = { sizeof("RRNNNNNNNNNN"), "RRNNNNNNNNNN" };
268 struct acpi_buffer psvt_str_format = { sizeof("RRNNNNNSNNNN"), "RRNNNNNSNNNN" };
269 union acpi_object *package = &(p->package.elements[i]);
270 struct psvt *psvt = &psvts[i - 1 - nr_bad_entries];
271 struct acpi_buffer *psvt_format = &psvt_int_format;
272 struct acpi_buffer element = { 0, NULL };
273 union acpi_object *knob;
274 struct acpi_device *res;
275 struct psvt *psvt_ptr;
276
277 element.length = ACPI_ALLOCATE_BUFFER;
278 element.pointer = NULL;
279
280 if (package->package.count >= ACPI_NR_PSVT_ELEMENTS) {
281 knob = &(package->package.elements[ACPI_PSVT_CONTROL_KNOB]);
282 } else {
283 nr_bad_entries++;
284 pr_info("PSVT package %d is invalid, ignored\n", i);
285 continue;
286 }
287
288 if (knob->type == ACPI_TYPE_STRING) {
289 psvt_format = &psvt_str_format;
290 if (knob->string.length > ACPI_LIMIT_STR_MAX_LEN) {
291 pr_info("PSVT package %d limit string len exceeds max\n", i);
292 knob->string.length = ACPI_LIMIT_STR_MAX_LEN;
293 }
294 }
295
296 status = acpi_extract_package(&(p->package.elements[i]), psvt_format, &element);
297 if (ACPI_FAILURE(status)) {
298 nr_bad_entries++;
299 pr_info("PSVT package %d is invalid, ignored\n", i);
300 continue;
301 }
302
303 psvt_ptr = (struct psvt *)element.pointer;
304
305 memcpy(psvt, psvt_ptr, sizeof(*psvt_ptr));
306
307 /* The limit element can be string or U64 */
308 psvt->control_knob_type = (u64)knob->type;
309
310 if (knob->type == ACPI_TYPE_STRING) {
311 memset(&psvt->limit, 0, sizeof(u64));
312 strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
313 } else {
314 psvt->limit.integer = psvt_ptr->limit.integer;
315 }
316
317 kfree(element.pointer);
318
319 res = acpi_fetch_acpi_dev(psvt->source);
320 if (!res) {
321 nr_bad_entries++;
322 pr_info("Failed to get source ACPI device\n");
323 continue;
324 }
325
326 res = acpi_fetch_acpi_dev(psvt->target);
327 if (!res) {
328 nr_bad_entries++;
329 pr_info("Failed to get target ACPI device\n");
330 continue;
331 }
332 }
333
334 /* don't count bad entries */
335 *psvt_count -= nr_bad_entries;
336
337 if (!*psvt_count) {
338 result = -EFAULT;
339 kfree(psvts);
340 goto end;
341 }
342
343 *psvtp = psvts;
344
345 return 0;
346
347 end:
348 kfree(buffer.pointer);
349 return result;
350 }
351
@@ -203,6 +203,151 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
}
EXPORT_SYMBOL(acpi_parse_art);
+/*
+ * acpi_parse_psvt - Passive Table (PSVT) for passive cooling
+ *
+ * @handle: ACPI handle of the device which contains PSVT
+ * @psvt_count: the number of valid entries resulted from parsing PSVT
+ * @psvtp: pointer to array of psvt entries
+ *
+ */
+int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **psvtp)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int nr_bad_entries = 0, revision;
+ union acpi_object *p;
+ acpi_status status;
+ int i, result = 0;
+ struct psvt *psvts;
+
+ if (!acpi_has_method(handle, "PSVT"))
+ return -ENODEV;
+
+ status = acpi_evaluate_object(handle, "PSVT", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ p = buffer.pointer;
+ if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
+ result = -EFAULT;
+ goto end;
+ }
+
+ /* first package is the revision number */
+ if (p->package.count > 0) {
+ union acpi_object *prev = &(p->package.elements[0]);
+
+ if (prev->type == ACPI_TYPE_INTEGER)
+ revision = (int)prev->integer.value;
+ } else {
+ result = -EFAULT;
+ goto end;
+ }
+
+ /* Support only version 2 */
+ if (revision != 2) {
+ result = -EFAULT;
+ goto end;
+ }
+
+ *psvt_count = p->package.count - 1;
+ if (!*psvt_count) {
+ result = -EFAULT;
+ goto end;
+ }
+
+ psvts = kcalloc(*psvt_count, sizeof(*psvts), GFP_KERNEL);
+ if (!psvts) {
+ result = -ENOMEM;
+ goto end;
+ }
+
+ /* Start index is 1 because the first package is the revision number */
+ for (i = 1; i < p->package.count; i++) {
+ struct acpi_buffer psvt_int_format = { sizeof("RRNNNNNNNNNN"), "RRNNNNNNNNNN" };
+ struct acpi_buffer psvt_str_format = { sizeof("RRNNNNNSNNNN"), "RRNNNNNSNNNN" };
+ union acpi_object *package = &(p->package.elements[i]);
+ struct psvt *psvt = &psvts[i - 1 - nr_bad_entries];
+ struct acpi_buffer *psvt_format = &psvt_int_format;
+ struct acpi_buffer element = { 0, NULL };
+ union acpi_object *knob;
+ struct acpi_device *res;
+ struct psvt *psvt_ptr;
+
+ element.length = ACPI_ALLOCATE_BUFFER;
+ element.pointer = NULL;
+
+ if (package->package.count >= ACPI_NR_PSVT_ELEMENTS) {
+ knob = &(package->package.elements[ACPI_PSVT_CONTROL_KNOB]);
+ } else {
+ nr_bad_entries++;
+ pr_info("PSVT package %d is invalid, ignored\n", i);
+ continue;
+ }
+
+ if (knob->type == ACPI_TYPE_STRING) {
+ psvt_format = &psvt_str_format;
+ if (knob->string.length > ACPI_LIMIT_STR_MAX_LEN) {
+ pr_info("PSVT package %d limit string len exceeds max\n", i);
+ knob->string.length = ACPI_LIMIT_STR_MAX_LEN;
+ }
+ }
+
+ status = acpi_extract_package(&(p->package.elements[i]), psvt_format, &element);
+ if (ACPI_FAILURE(status)) {
+ nr_bad_entries++;
+ pr_info("PSVT package %d is invalid, ignored\n", i);
+ continue;
+ }
+
+ psvt_ptr = (struct psvt *)element.pointer;
+
+ memcpy(psvt, psvt_ptr, sizeof(*psvt_ptr));
+
+ /* The limit element can be string or U64 */
+ psvt->control_knob_type = (u64)knob->type;
+
+ if (knob->type == ACPI_TYPE_STRING) {
+ memset(&psvt->limit, 0, sizeof(u64));
+ strncpy(psvt->limit.string, psvt_ptr->limit.str_ptr, knob->string.length);
+ } else {
+ psvt->limit.integer = psvt_ptr->limit.integer;
+ }
+
+ kfree(element.pointer);
+
+ res = acpi_fetch_acpi_dev(psvt->source);
+ if (!res) {
+ nr_bad_entries++;
+ pr_info("Failed to get source ACPI device\n");
+ continue;
+ }
+
+ res = acpi_fetch_acpi_dev(psvt->target);
+ if (!res) {
+ nr_bad_entries++;
+ pr_info("Failed to get target ACPI device\n");
+ continue;
+ }
+ }
+
+ /* don't count bad entries */
+ *psvt_count -= nr_bad_entries;
+
+ if (!*psvt_count) {
+ result = -EFAULT;
+ kfree(psvts);
+ goto end;
+ }
+
+ *psvtp = psvts;
+
+ return 0;
+
+end:
+ kfree(buffer.pointer);
+ return result;
+}
/* get device name from acpi handle */
static void get_single_name(acpi_handle handle, char *name)
@@ -289,6 +434,57 @@ static int fill_trt(char __user *ubuf)
return ret;
}
+static int fill_psvt(char __user *ubuf)
+{
+ int i, ret, count, psvt_len;
+ union psvt_object *psvt_user;
+ struct psvt *psvts;
+
+ ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
+ if (ret)
+ return ret;
+
+ psvt_len = count * sizeof(*psvt_user);
+
+ psvt_user = kzalloc(psvt_len, GFP_KERNEL);
+ if (!psvt_user) {
+ ret = -ENOMEM;
+ goto free_psvt;
+ }
+
+ /* now fill in user psvt data */
+ for (i = 0; i < count; i++) {
+ /* userspace psvt needs device name instead of acpi reference */
+ get_single_name(psvts[i].source, psvt_user[i].source_device);
+ get_single_name(psvts[i].target, psvt_user[i].target_device);
+
+ psvt_user[i].priority = psvts[i].priority;
+ psvt_user[i].sample_period = psvts[i].sample_period;
+ psvt_user[i].passive_temp = psvts[i].passive_temp;
+ psvt_user[i].source_domain = psvts[i].source_domain;
+ psvt_user[i].control_knob = psvts[i].control_knob;
+ psvt_user[i].step_size = psvts[i].step_size;
+ psvt_user[i].limit_coeff = psvts[i].limit_coeff;
+ psvt_user[i].unlimit_coeff = psvts[i].unlimit_coeff;
+ psvt_user[i].control_knob_type = psvts[i].control_knob_type;
+ if (psvt_user[i].control_knob_type == ACPI_TYPE_STRING)
+ strncpy(psvt_user[i].limit.string, psvts[i].limit.string,
+ ACPI_LIMIT_STR_MAX_LEN);
+ else
+ psvt_user[i].limit.integer = psvts[i].limit.integer;
+
+ }
+
+ if (copy_to_user(ubuf, psvt_user, psvt_len))
+ ret = -EFAULT;
+
+ kfree(psvt_user);
+
+free_psvt:
+ kfree(psvts);
+ return ret;
+}
+
static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
unsigned long __arg)
{
@@ -298,6 +494,7 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
char __user *arg = (void __user *)__arg;
struct trt *trts = NULL;
struct art *arts = NULL;
+ struct psvt *psvts;
switch (cmd) {
case ACPI_THERMAL_GET_TRT_COUNT:
@@ -336,6 +533,27 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
case ACPI_THERMAL_GET_ART:
return fill_art(arg);
+ case ACPI_THERMAL_GET_PSVT_COUNT:
+ ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
+ if (!ret) {
+ kfree(psvts);
+ return put_user(count, (unsigned long __user *)__arg);
+ }
+ return ret;
+
+ case ACPI_THERMAL_GET_PSVT_LEN:
+ /* total length of the data retrieved (count * PSVT entry size) */
+ ret = acpi_parse_psvt(acpi_thermal_rel_handle, &count, &psvts);
+ length = count * sizeof(union psvt_object);
+ if (!ret) {
+ kfree(psvts);
+ return put_user(length, (unsigned long __user *)__arg);
+ }
+ return ret;
+
+ case ACPI_THERMAL_GET_PSVT:
+ return fill_psvt(arg);
+
default:
return -ENOTTY;
}
@@ -14,6 +14,16 @@
#define ACPI_THERMAL_GET_TRT _IOR(ACPI_THERMAL_MAGIC, 5, unsigned long)
#define ACPI_THERMAL_GET_ART _IOR(ACPI_THERMAL_MAGIC, 6, unsigned long)
+/*
+ * ACPI_THERMAL_GET_PSVT_COUNT = Number of PSVT entries
+ * ACPI_THERMAL_GET_PSVT_LEN = Total return data size (PSVT count x each
+ * PSVT entry size)
+ * ACPI_THERMAL_GET_PSVT = Get the data as an array of psvt_objects
+ */
+#define ACPI_THERMAL_GET_PSVT_LEN _IOR(ACPI_THERMAL_MAGIC, 7, unsigned long)
+#define ACPI_THERMAL_GET_PSVT_COUNT _IOR(ACPI_THERMAL_MAGIC, 8, unsigned long)
+#define ACPI_THERMAL_GET_PSVT _IOR(ACPI_THERMAL_MAGIC, 9, unsigned long)
+
struct art {
acpi_handle source;
acpi_handle target;
@@ -43,6 +53,32 @@ struct trt {
u64 reserved4;
} __packed;
+#define ACPI_NR_PSVT_ELEMENTS 12
+#define ACPI_PSVT_CONTROL_KNOB 7
+#define ACPI_LIMIT_STR_MAX_LEN 8
+
+struct psvt {
+ acpi_handle source;
+ acpi_handle target;
+ u64 priority;
+ u64 sample_period;
+ u64 passive_temp;
+ u64 source_domain;
+ u64 control_knob;
+ union {
+ /* For limit_type = ACPI_TYPE_INTEGER */
+ u64 integer;
+ /* For limit_type = ACPI_TYPE_STRING */
+ char string[ACPI_LIMIT_STR_MAX_LEN];
+ char *str_ptr;
+ } limit;
+ u64 step_size;
+ u64 limit_coeff;
+ u64 unlimit_coeff;
+ /* Spec calls this field reserved, so we borrow it for type info */
+ u64 control_knob_type; /* ACPI_TYPE_STRING or ACPI_TYPE_INTEGER */
+} __packed;
+
#define ACPI_NR_ART_ELEMENTS 13
/* for usrspace */
union art_object {
@@ -77,6 +113,27 @@ union trt_object {
u64 __data[8];
};
+union psvt_object {
+ struct {
+ char source_device[8];
+ char target_device[8];
+ u64 priority;
+ u64 sample_period;
+ u64 passive_temp;
+ u64 source_domain;
+ u64 control_knob;
+ union {
+ u64 integer;
+ char string[ACPI_LIMIT_STR_MAX_LEN];
+ } limit;
+ u64 step_size;
+ u64 limit_coeff;
+ u64 unlimit_coeff;
+ u64 control_knob_type;
+ };
+ u64 __data[ACPI_NR_PSVT_ELEMENTS];
+};
+
#ifdef __KERNEL__
int acpi_thermal_rel_misc_device_add(acpi_handle handle);
int acpi_thermal_rel_misc_device_remove(acpi_handle handle);