@@ -325,6 +325,92 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
325325}
326326EXPORT_SYMBOL (acpi_run_osc );
327327
328+ static int acpi_osc_handshake (acpi_handle handle , const char * uuid_str ,
329+ int rev , struct acpi_buffer * cap )
330+ {
331+ union acpi_object in_params [4 ], * out_obj ;
332+ size_t bufsize = cap -> length / sizeof (u32 );
333+ struct acpi_object_list input ;
334+ struct acpi_buffer output ;
335+ u32 * capbuf , * retbuf , test ;
336+ guid_t guid ;
337+ int ret , i ;
338+
339+ if (!cap || cap -> length < 2 * sizeof (32 ) || guid_parse (uuid_str , & guid ))
340+ return - EINVAL ;
341+
342+ /* First evaluate _OSC with OSC_QUERY_ENABLE set. */
343+ capbuf = cap -> pointer ;
344+ capbuf [OSC_QUERY_DWORD ] = OSC_QUERY_ENABLE ;
345+
346+ ret = acpi_eval_osc (handle , & guid , rev , cap , in_params , & output );
347+ if (ret )
348+ return ret ;
349+
350+ out_obj = output .pointer ;
351+ retbuf = (u32 * )out_obj -> buffer .pointer ;
352+
353+ if (acpi_osc_error_check (handle , & guid , rev , cap , retbuf )) {
354+ ret = - ENODATA ;
355+ goto out ;
356+ }
357+
358+ /*
359+ * Clear the feature bits in the capabilities buffer that have not been
360+ * acknowledged and clear the return buffer.
361+ */
362+ for (i = OSC_QUERY_DWORD + 1 , test = 0 ; i < bufsize ; i ++ ) {
363+ capbuf [i ] &= retbuf [i ];
364+ test |= capbuf [i ];
365+ retbuf [i ] = 0 ;
366+ }
367+ /*
368+ * If none of the feature bits have been acknowledged, there's nothing
369+ * more to do. capbuf[] contains a feature mask of all zeros.
370+ */
371+ if (!test )
372+ goto out ;
373+
374+ retbuf [OSC_QUERY_DWORD ] = 0 ;
375+ /*
376+ * Now evaluate _OSC again (directly) with OSC_QUERY_ENABLE clear and
377+ * the updated input and output buffers used before. Since the feature
378+ * bits that were clear in the return buffer from the previous _OSC
379+ * evaluation are also clear in the capabilities buffer now, this _OSC
380+ * evaluation is not expected to fail.
381+ */
382+ capbuf [OSC_QUERY_DWORD ] = 0 ;
383+ /* Reuse in_params[] populated by acpi_eval_osc(). */
384+ input .pointer = in_params ;
385+ input .count = 4 ;
386+
387+ if (ACPI_FAILURE (acpi_evaluate_object (handle , "_OSC" , & input , & output ))) {
388+ ret = - ENODATA ;
389+ goto out ;
390+ }
391+
392+ /*
393+ * Clear the feature bits in capbuf[] that have not been acknowledged.
394+ * After that, capbuf[] contains the resultant feature mask.
395+ */
396+ for (i = OSC_QUERY_DWORD + 1 ; i < bufsize ; i ++ )
397+ capbuf [i ] &= retbuf [i ];
398+
399+ if (retbuf [OSC_QUERY_DWORD ] & OSC_ERROR_MASK ) {
400+ /*
401+ * Complain about the unexpected errors and print diagnostic
402+ * information related to them.
403+ */
404+ acpi_handle_err (handle , "_OSC: errors while processing control request\n" );
405+ acpi_handle_err (handle , "_OSC: some features may be missing\n" );
406+ acpi_osc_error_check (handle , & guid , rev , cap , retbuf );
407+ }
408+
409+ out :
410+ ACPI_FREE (out_obj );
411+ return ret ;
412+ }
413+
328414bool osc_sb_apei_support_acked ;
329415
330416/*
@@ -356,19 +442,16 @@ EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
356442
357443bool osc_sb_cppc2_support_acked ;
358444
359- static u8 sb_uuid_str [] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48" ;
360445static void acpi_bus_osc_negotiate_platform_control (void )
361446{
362- u32 capbuf [2 ], * capbuf_ret ;
363- struct acpi_osc_context context = {
364- .uuid_str = sb_uuid_str ,
365- .rev = 1 ,
366- .cap .length = 8 ,
367- .cap .pointer = capbuf ,
447+ static const u8 sb_uuid_str [] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48" ;
448+ u32 capbuf [2 ];
449+ struct acpi_buffer cap = {
450+ .pointer = capbuf ,
451+ .length = sizeof (capbuf ),
368452 };
369453 acpi_handle handle ;
370454
371- capbuf [OSC_QUERY_DWORD ] = OSC_QUERY_ENABLE ;
372455 capbuf [OSC_SUPPORT_DWORD ] = OSC_SB_PR3_SUPPORT ; /* _PR3 is in use */
373456 if (IS_ENABLED (CONFIG_ACPI_PROCESSOR_AGGREGATOR ))
374457 capbuf [OSC_SUPPORT_DWORD ] |= OSC_SB_PAD_SUPPORT ;
@@ -414,43 +497,21 @@ static void acpi_bus_osc_negotiate_platform_control(void)
414497 if (ACPI_FAILURE (acpi_get_handle (NULL , "\\_SB" , & handle )))
415498 return ;
416499
417- if (ACPI_FAILURE (acpi_run_osc (handle , & context )))
418- return ;
419-
420- capbuf_ret = context .ret .pointer ;
421- if (context .ret .length <= OSC_SUPPORT_DWORD ) {
422- kfree (context .ret .pointer );
423- return ;
424- }
425-
426- /*
427- * Now run _OSC again with query flag clear and with the caps
428- * supported by both the OS and the platform.
429- */
430- capbuf [OSC_QUERY_DWORD ] = 0 ;
431- capbuf [OSC_SUPPORT_DWORD ] = capbuf_ret [OSC_SUPPORT_DWORD ];
432- kfree (context .ret .pointer );
433-
434- if (ACPI_FAILURE (acpi_run_osc (handle , & context )))
500+ if (acpi_osc_handshake (handle , sb_uuid_str , 1 , & cap ))
435501 return ;
436502
437- capbuf_ret = context .ret .pointer ;
438- if (context .ret .length > OSC_SUPPORT_DWORD ) {
439503#ifdef CONFIG_ACPI_CPPC_LIB
440- osc_sb_cppc2_support_acked = capbuf_ret [OSC_SUPPORT_DWORD ] & OSC_SB_CPCV2_SUPPORT ;
504+ osc_sb_cppc2_support_acked = capbuf [OSC_SUPPORT_DWORD ] & OSC_SB_CPCV2_SUPPORT ;
441505#endif
442506
443- osc_sb_apei_support_acked =
444- capbuf_ret [OSC_SUPPORT_DWORD ] & OSC_SB_APEI_SUPPORT ;
445- osc_pc_lpi_support_confirmed =
446- capbuf_ret [OSC_SUPPORT_DWORD ] & OSC_SB_PCLPI_SUPPORT ;
447- osc_sb_native_usb4_support_confirmed =
448- capbuf_ret [OSC_SUPPORT_DWORD ] & OSC_SB_NATIVE_USB4_SUPPORT ;
449- osc_cpc_flexible_adr_space_confirmed =
450- capbuf_ret [OSC_SUPPORT_DWORD ] & OSC_SB_CPC_FLEXIBLE_ADR_SPACE ;
451- }
452-
453- kfree (context .ret .pointer );
507+ osc_sb_apei_support_acked =
508+ capbuf [OSC_SUPPORT_DWORD ] & OSC_SB_APEI_SUPPORT ;
509+ osc_pc_lpi_support_confirmed =
510+ capbuf [OSC_SUPPORT_DWORD ] & OSC_SB_PCLPI_SUPPORT ;
511+ osc_sb_native_usb4_support_confirmed =
512+ capbuf [OSC_SUPPORT_DWORD ] & OSC_SB_NATIVE_USB4_SUPPORT ;
513+ osc_cpc_flexible_adr_space_confirmed =
514+ capbuf [OSC_SUPPORT_DWORD ] & OSC_SB_CPC_FLEXIBLE_ADR_SPACE ;
454515}
455516
456517/*
0 commit comments