@@ -203,6 +203,151 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
203
203
}
204
204
EXPORT_SYMBOL (acpi_parse_art );
205
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
+ static 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 = 0 ;
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 - 1 ) {
291
+ pr_info ("PSVT package %d limit string len exceeds max\n" , i );
292
+ knob -> string .length = ACPI_LIMIT_STR_MAX_LEN - 1 ;
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 ));
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
+ }
206
351
207
352
/* get device name from acpi handle */
208
353
static void get_single_name (acpi_handle handle , char * name )
@@ -289,6 +434,57 @@ static int fill_trt(char __user *ubuf)
289
434
return ret ;
290
435
}
291
436
437
+ static int fill_psvt (char __user * ubuf )
438
+ {
439
+ int i , ret , count , psvt_len ;
440
+ union psvt_object * psvt_user ;
441
+ struct psvt * psvts ;
442
+
443
+ ret = acpi_parse_psvt (acpi_thermal_rel_handle , & count , & psvts );
444
+ if (ret )
445
+ return ret ;
446
+
447
+ psvt_len = count * sizeof (* psvt_user );
448
+
449
+ psvt_user = kzalloc (psvt_len , GFP_KERNEL );
450
+ if (!psvt_user ) {
451
+ ret = - ENOMEM ;
452
+ goto free_psvt ;
453
+ }
454
+
455
+ /* now fill in user psvt data */
456
+ for (i = 0 ; i < count ; i ++ ) {
457
+ /* userspace psvt needs device name instead of acpi reference */
458
+ get_single_name (psvts [i ].source , psvt_user [i ].source_device );
459
+ get_single_name (psvts [i ].target , psvt_user [i ].target_device );
460
+
461
+ psvt_user [i ].priority = psvts [i ].priority ;
462
+ psvt_user [i ].sample_period = psvts [i ].sample_period ;
463
+ psvt_user [i ].passive_temp = psvts [i ].passive_temp ;
464
+ psvt_user [i ].source_domain = psvts [i ].source_domain ;
465
+ psvt_user [i ].control_knob = psvts [i ].control_knob ;
466
+ psvt_user [i ].step_size = psvts [i ].step_size ;
467
+ psvt_user [i ].limit_coeff = psvts [i ].limit_coeff ;
468
+ psvt_user [i ].unlimit_coeff = psvts [i ].unlimit_coeff ;
469
+ psvt_user [i ].control_knob_type = psvts [i ].control_knob_type ;
470
+ if (psvt_user [i ].control_knob_type == ACPI_TYPE_STRING )
471
+ strncpy (psvt_user [i ].limit .string , psvts [i ].limit .string ,
472
+ ACPI_LIMIT_STR_MAX_LEN );
473
+ else
474
+ psvt_user [i ].limit .integer = psvts [i ].limit .integer ;
475
+
476
+ }
477
+
478
+ if (copy_to_user (ubuf , psvt_user , psvt_len ))
479
+ ret = - EFAULT ;
480
+
481
+ kfree (psvt_user );
482
+
483
+ free_psvt :
484
+ kfree (psvts );
485
+ return ret ;
486
+ }
487
+
292
488
static long acpi_thermal_rel_ioctl (struct file * f , unsigned int cmd ,
293
489
unsigned long __arg )
294
490
{
@@ -298,6 +494,7 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
298
494
char __user * arg = (void __user * )__arg ;
299
495
struct trt * trts = NULL ;
300
496
struct art * arts = NULL ;
497
+ struct psvt * psvts ;
301
498
302
499
switch (cmd ) {
303
500
case ACPI_THERMAL_GET_TRT_COUNT :
@@ -336,6 +533,27 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
336
533
case ACPI_THERMAL_GET_ART :
337
534
return fill_art (arg );
338
535
536
+ case ACPI_THERMAL_GET_PSVT_COUNT :
537
+ ret = acpi_parse_psvt (acpi_thermal_rel_handle , & count , & psvts );
538
+ if (!ret ) {
539
+ kfree (psvts );
540
+ return put_user (count , (unsigned long __user * )__arg );
541
+ }
542
+ return ret ;
543
+
544
+ case ACPI_THERMAL_GET_PSVT_LEN :
545
+ /* total length of the data retrieved (count * PSVT entry size) */
546
+ ret = acpi_parse_psvt (acpi_thermal_rel_handle , & count , & psvts );
547
+ length = count * sizeof (union psvt_object );
548
+ if (!ret ) {
549
+ kfree (psvts );
550
+ return put_user (length , (unsigned long __user * )__arg );
551
+ }
552
+ return ret ;
553
+
554
+ case ACPI_THERMAL_GET_PSVT :
555
+ return fill_psvt (arg );
556
+
339
557
default :
340
558
return - ENOTTY ;
341
559
}
0 commit comments