@@ -203,6 +203,151 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
203203}
204204EXPORT_SYMBOL (acpi_parse_art );
205205
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+ }
206351
207352/* get device name from acpi handle */
208353static void get_single_name (acpi_handle handle , char * name )
@@ -289,6 +434,57 @@ static int fill_trt(char __user *ubuf)
289434 return ret ;
290435}
291436
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+
292488static long acpi_thermal_rel_ioctl (struct file * f , unsigned int cmd ,
293489 unsigned long __arg )
294490{
@@ -298,6 +494,7 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
298494 char __user * arg = (void __user * )__arg ;
299495 struct trt * trts = NULL ;
300496 struct art * arts = NULL ;
497+ struct psvt * psvts ;
301498
302499 switch (cmd ) {
303500 case ACPI_THERMAL_GET_TRT_COUNT :
@@ -336,6 +533,27 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
336533 case ACPI_THERMAL_GET_ART :
337534 return fill_art (arg );
338535
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+
339557 default :
340558 return - ENOTTY ;
341559 }
0 commit comments