Message ID | 1348052021-1714-3-git-send-email-colin.king@canonical.com |
---|---|
State | Rejected |
Headers | show |
On Wed, Sep 19, 2012 at 6:53 PM, Colin King <colin.king@canonical.com> wrote: > From: Colin Ian King <colin.king@canonical.com> > > The test functions were systematically randomized which > made it a complete headache to maintain. Re-order them > in order of the ACPI specific sections and also tidy > up some white spaces. > > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > src/acpi/method/method.c | 2220 +++++++++++++++++++++++++--------------------- > 1 file changed, 1218 insertions(+), 1002 deletions(-) > > diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c > index afba21f..b706a56 100644 > --- a/src/acpi/method/method.c > +++ b/src/acpi/method/method.c > @@ -261,6 +261,15 @@ static int method_test ## name(fwts_framework *fw) \ > > typedef void (*method_test_return)(fwts_framework *fw, char *name, ACPI_BUFFER *ret_buff, ACPI_OBJECT *ret_obj, void *private); > > + > + > + > +/* > + * Helper functions to facilitate the evaluations > + */ > + > +/****************************************************************************/ > + > static int method_init(fwts_framework *fw) > { > fwts_acpi_table_info *info; > @@ -492,591 +501,990 @@ static void method_test_passed_failed_return(fwts_framework *fw, char *name, ACP > } > } > > -/* Section 10.1.1.1 Smart Battery */ > - > -static void method_test_SBS_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_polling_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > { > - static char *sbs_info[] = { > - "Maximum 1 Smart Battery, system manager/selector not present", > - "Maximum 1 Smart Battery, system manager/selector present", > - "Maximum 2 Smart Batteries, system manager/selector present", > - "Maximum 3 Smart Batteries, system manager/selector present", > - "Maximum 4 Smart Batteries, system manager/selector present" > - }; > - > if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > - switch (obj->Integer.Value) { > - case 0 ... 4: > - fwts_passed(fw, "_SBS correctly returned value %d %s", > - (uint32_t)obj->Integer.Value, > - sbs_info[obj->Integer.Value]); > - break; > - default: > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SBSReturn", "_SBS returned %d, should be between 0 and 4.", > - (uint32_t)obj->Integer.Value); > + char *method = (char *)private; > + if (obj->Integer.Value < 36000) { > + fwts_passed(fw, "%s correctly returned sane looking value %f seconds", > + method, (float)obj->Integer.Value / 10.0); > + } else { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodPollTimeTooLong", > + "%s returned a value %f seconds > (1 hour) which is probably incorrect.", > + method, (float)obj->Integer.Value / 10.0); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - fwts_advice(fw, "Smart Battery _SBS is incorrectly informing the OS about the smart battery " > - "configuration. This is a bug and needs to be fixed."); > - break; > + fwts_advice(fw, "The method is returning a polling interval which is very long and hence " > + "most probably incorrect."); > } > } > } > > -static int method_test_SBS(fwts_framework *fw) > +/****************************************************************************/ > + > +/* > + * Section 5.6 ACPI Event Programming Model > + */ > +static int method_test_AEI(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_MOBILE, "_SBS", NULL, 0, method_test_SBS_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_AEI", NULL, 0, method_test_buffer_return, NULL); > } > > +/* > + * Section 6.1 Device Identification Objects > + */ > +static int method_test_SUN(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_SUN", NULL, 0, method_test_integer_return, NULL); > +} > > -/* Section 10.2.2 Battery Control Methods */ > +static void method_test_UID_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + if (obj == NULL){ > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); > + return; > + } > + switch (obj->Type) { > + case ACPI_TYPE_STRING: > + if (obj->String.Pointer) > + fwts_passed(fw, "Object _UID returned a string '%s' as expected.", > + obj->String.Pointer); > + else { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDNullString", > + "Object _UID returned a NULL string."); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + } > + break; > + case ACPI_TYPE_INTEGER: > + fwts_passed(fw, "Object _UID returned am integer 0x%8.8llx.", > + (unsigned long long)obj->Integer.Value); > + break; > + default: > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType", > + "Method _UID did not return a string or an integer."); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + break; > + } > +} > > -static void method_test_BIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static int method_test_UID(fwts_framework *fw) > { > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > - int i; > - int failed = 0; > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_UID", NULL, 0, method_test_UID_return, NULL); > +} > > - fwts_method_dump_object(fw, obj); > > - if (obj->Package.Count != 13) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFElementCount", "_BIF package should return 13 elements, got %d instead.", > - obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } > +/* > + * Section 6.2 Device Configurations Objects > + */ > +static int method_test_CRS(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MANDITORY, > + "_CRS", NULL, 0, method_test_buffer_return, NULL); > +} > > - for (i=0;(i<9) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type DWORD Integer.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > - for (i=9;(i<13) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type STRING.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > +static int method_test_DMA(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DMA", NULL, 0, method_test_buffer_return, NULL); > +} > > - /* Sanity check each field */ > - /* Power Unit */ > - if (obj->Package.Elements[0].Integer.Value > 0x00000002) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadUnits", "_BIF: Expected Power Unit (Element 0) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[0].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#ifdef FWTS_METHOD_PEDANDTIC > - /* > - * Since this information may be evaluated by communicating with > - * the EC we skip these checks as we can't do this from userspace > - */ > - /* Design Capacity */ > - if (obj->Package.Elements[1].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFBadCapacity", "_BIF: Design Capacity (Element 1) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[1].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Last Full Charge Capacity */ > - if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFChargeCapacity", "_BIF: Last Full Charge Capacity (Element 2) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[2].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#endif > - /* Battery Technology */ > - if (obj->Package.Elements[3].Integer.Value > 0x00000002) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBatTechUnit", "_BIF: Expected Battery Technology Unit (Element 3) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[3].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#ifdef FWTS_METHOD_PEDANDTIC > - /* > - * Since this information may be evaluated by communicating with > - * the EC we skip these checks as we can't do this from userspace > - */ > - /* Design Voltage */ > - if (obj->Package.Elements[4].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignVoltage", "_BIF: Design Voltage (Element 4) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[4].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Design capacity warning */ > - if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE5", "_BIF: Design Capacity Warning (Element 5) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[5].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Design capacity low */ > - if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE6", "_BIF: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[6].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#endif > - if (failed) > - fwts_advice(fw, "Battery _BIF package contains errors. It is worth running the " > - "firmware test suite interactive 'battery' test to see if this " > - "is problematic. This is a bug an needs to be fixed."); > - else > - fwts_passed(fw, "Battery _BIF package looks sane."); > - } > +static int method_test_DIS(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DIS", NULL, 0, method_test_NULL_return, NULL); > } > > -static int method_test_BIF(fwts_framework *fw) > +static int method_test_PXM(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_MOBILE, "_BIF", NULL, 0, method_test_BIF_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PXM", NULL, 0, method_test_integer_return, NULL); > } > > -static void method_test_BIX_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > + > +/* > + * Section 6.3 Device Insertion, Removal and Status Objects > + */ > +static int method_test_EJD(fwts_framework *fw) > { > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > - int i; > - int failed = 0; > + return method_evaluate_method(fw, METHOD_OPTIONAL, "_EJD", NULL, 0, method_test_string_return, NULL); > +} > > - fwts_method_dump_object(fw, obj); > +#define method_test_EJx(name) \ > +static int method_test ## name(fwts_framework *fw) \ > +{ \ > + ACPI_OBJECT arg[1]; \ > + \ > + arg[0].Type = ACPI_TYPE_INTEGER; \ > + arg[0].Integer.Value = 1; \ > + \ > + return method_evaluate_method(fw, METHOD_OPTIONAL, # name, arg, 1, method_test_NULL_return, # name); \ > +} > > - if (obj->Package.Count != 16) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXElementCount", "_BIX package should return 16 elements, got %d instead.", > - obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > +method_test_EJx(_EJ0) > +method_test_EJx(_EJ1) > +method_test_EJx(_EJ2) > +method_test_EJx(_EJ3) > +method_test_EJx(_EJ4) > > - for (i=0;(i<16) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type DWORD Integer.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > - for (i=16;(i<20) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type STRING.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > +static int method_test_LCK(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[1]; > > - /* Sanity check each field */ > - /* Power Unit */ > - if (obj->Package.Elements[1].Integer.Value > 0x00000002) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXPowerUnit", > - "_BIX: Expected Power Unit (Element 1) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[1].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#ifdef FWTS_METHOD_PEDANDTIC > - /* > - * Since this information may be evaluated by communicating with > - * the EC we skip these checks as we can't do this from userspace > - */ > - /* Design Capacity */ > - if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacity", > - "_BIX: Design Capacity (Element 2) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[2].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Last Full Charge Capacity */ > - if (obj->Package.Elements[3].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXFullChargeCapacity", > - "_BIX: Last Full Charge Capacity (Element 3) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[3].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#endif > - /* Battery Technology */ > - if (obj->Package.Elements[4].Integer.Value > 0x00000002) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBatteryTechUnit", > - "_BIX: Expected Battery Technology Unit (Element 4) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[4].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#ifdef FWTS_METHOD_PEDANDTIC > - /* > - * Since this information may be evaluated by communicating with > - * the EC we skip these checks as we can't do this from userspace > - */ > - /* Design Voltage */ > - if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignVoltage", > - "_BIX: Design Voltage (Element 5) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[5].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Design capacity warning */ > - if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE6", > - "_BIX: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[6].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Design capacity low */ > - if (obj->Package.Elements[7].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE7", > - "_BIX: Design Capacity Warning (Element 7) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[7].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Cycle Count */ > - if (obj->Package.Elements[10].Integer.Value > 0x7fffffff) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXCyleCount", > - "_BIX: Cycle Count (Element 10) is unknown: 0x%8.8x.", > - (uint32_t)obj->Package.Elements[10].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > -#endif > - if (failed) > - fwts_advice(fw, "Battery _BIX package contains errors. It is worth running the " > - "firmware test suite interactive 'battery' test to see if this " > - "is problematic. This is a bug an needs to be fixed."); > - else > - fwts_passed(fw, "Battery _BIX package looks sane."); > - } > -} > - > -static int method_test_BIX(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_MOBILE, "_BIX", NULL, 0, method_test_BIX_return, NULL); > -} > - > -static int method_test_BMA(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = 1; > - return method_evaluate_method(fw, METHOD_MOBILE, "_BMA", arg, 1, method_test_integer_return, NULL); > -} > > -static int method_test_BMS(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; > - return method_evaluate_method(fw, METHOD_MOBILE, "_BMS", arg, 1, method_test_integer_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, "_LCK", arg, 1, method_test_NULL_return, NULL); > } > > -static void method_test_BST_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > - int i; > - int failed = 0; > - > - fwts_method_dump_object(fw, obj); > - > - if (obj->Package.Count != 4) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTElementCount", "_BST package should return 4 elements, got %d instead.", > - obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - > - for (i=0;(i<4) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadType", > - "_BST package element %d is not of type DWORD Integer.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > > - /* Sanity check each field */ > - /* Battery State */ > - if ((obj->Package.Elements[0].Integer.Value) > 7) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", > - "_BST: Expected Battery State (Element 0) to be 0..7, got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[0].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Ensure bits 0 (discharging) and 1 (charging) are not both set, see 10.2.2.6 */ > - if (((obj->Package.Elements[0].Integer.Value) & 3) == 3) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", > - "_BST: Battery State (Element 0) is indicating both charging " > - "and discharginng which is not allowed. Got value 0x%8.8x.", > - (uint32_t)obj->Package.Elements[0].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - /* Battery Present Rate - cannot check, pulled from EC */ > - /* Battery Remaining Capacity - cannot check, pulled from EC */ > - /* Battery Present Voltage - cannot check, pulled from EC */ > - if (failed) > - fwts_advice(fw, "Battery _BST package contains errors. It is worth running the " > - "firmware test suite interactive 'battery' test to see if this " > - "is problematic. This is a bug an needs to be fixed."); > - else > - fwts_passed(fw, "Battery _BST package looks sane."); > - } > +/* > + * Section 6.5 Other Objects and Controls > + */ > +static int method_test_BBN(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, "_BBN", > + NULL, 0, method_test_integer_return, "_BBN"); > } > > -static int method_test_BST(fwts_framework *fw) > +static int method_test_BDN(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_MOBILE, "_BST", NULL, 0, method_test_BST_return, NULL); > + return method_evaluate_method(fw, METHOD_MOBILE, "_BDN", > + NULL, 0, method_test_integer_return, "_BDN"); > } > > -static int method_test_BTP(fwts_framework *fw) > +static int method_test_DCK(fwts_framework *fw) > { > - static int values[] = { 0, 1, 100, 200, 0x7fffffff }; > int i; > > - for (i=0;i<5;i++) { > + for (i=0;i<=1;i++) { /* Undock, Dock */ > ACPI_OBJECT arg[1]; > arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = values[i]; > - if (method_evaluate_method(fw, METHOD_MOBILE, "_BTP", arg, 1, > - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + arg[0].Integer.Value = i; > + if (method_evaluate_method(fw, METHOD_MOBILE, "_DCK", arg, 1, method_test_passed_failed_return, "_DCK") != FWTS_OK) > break; > fwts_log_nl(fw); > } > return FWTS_OK; > } > > -static void method_test_PCL_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - /* FIXME */ > -} > > -static int method_test_PCL(fwts_framework *fw) > +/* > + * Section 7.1 Declaring a Power Resource Object > + */ > +static int method_test_ON(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_MOBILE, "_PCL", NULL, 0, method_test_PCL_return, "_PCL"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_ON", NULL, 0, method_test_NULL_return, NULL); > } > > -static int method_test_BTM(fwts_framework *fw) > +static int method_test_OFF(fwts_framework *fw) > { > - static int values[] = { 0, 1, 100, 200, 0x7fffffff }; > - int i; > - > - for (i=0;i<5;i++) { > - ACPI_OBJECT arg[1]; > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = values[i]; > - if (method_evaluate_method(fw, METHOD_MOBILE, "_BTM", arg, 1, > - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > - break; > - fwts_log_nl(fw); > - } > - return FWTS_OK; > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_OFF", NULL, 0, method_test_NULL_return, NULL); > } > > -static void method_test_BMD_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > + > +/* > + * Section 7.2 Device Power Management Objects > + */ > +static int method_test_DSW(fwts_framework *fw) > { > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > - int i; > - int failed = 0; > + ACPI_OBJECT arg[3]; > > - fwts_method_dump_object(fw, obj); > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; > + arg[1].Type = ACPI_TYPE_INTEGER; > + arg[1].Integer.Value = 0; > + arg[2].Type = ACPI_TYPE_INTEGER; > + arg[2].Integer.Value = 3; > > - if (obj->Package.Count != 5) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDElementCount", "_BMD package should return 4 elements, got %d instead.", > - obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > + return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSW", > + arg, 3, method_test_NULL_return, NULL); > +} > > - for (i=0;(i<4) && (i<obj->Package.Count);i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDBadType", "_BMD package element %d is not of type DWORD Integer.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - } > - /* TODO: check return values */ > - } > +#define method_test_PSx(name) \ > +static int method_test ## name(fwts_framework *fw) \ > +{ \ > + return method_evaluate_method(fw, METHOD_OPTIONAL, \ > + # name, NULL, 0, method_test_NULL_return, # name); \ > } > > -static int method_test_BMD(fwts_framework *fw) > +method_test_PSx(_PS0) > +method_test_PSx(_PS1) > +method_test_PSx(_PS2) > +method_test_PSx(_PS3) > + > +static int method_test_PSC(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_MOBILE, "_BMD", NULL, 0, method_test_BMD_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PSC", NULL, 0, method_test_integer_return, NULL); > } > > -static int method_test_BMC(fwts_framework *fw) > +static int method_test_PSE(fwts_framework *fw) > { > - static int values[] = { 0, 1, 2, 4 }; > - int i; > + ACPI_OBJECT arg[1]; > > - for (i=0;i<4;i++) { > - ACPI_OBJECT arg[1]; > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = values[i]; > - if (method_evaluate_method(fw, METHOD_MOBILE, "_BMC", arg, 1, > - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > - break; > - fwts_log_nl(fw); > - } > - return FWTS_OK; > -} > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; > > -/* Section 15, Waking and Sleeping */ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PSE", arg, 1, method_test_NULL_return, NULL); > +} > > -static int method_test_PTS(fwts_framework *fw) > +static void method_test_PRE_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > int i; > > - for (i=1; i<6; i++) { > - ACPI_OBJECT arg[1]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = i; > - > - fwts_log_info(fw, "Test _PTS(%d).", i); > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > > - if (method_evaluate_method(fw, METHOD_MANDITORY, "_PTS", arg, 1, > - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) { > - fwts_advice(fw, "Could not find _PTS. This method provides a mechanism to " > - "do housekeeping functions, such as write sleep state to the " > - "embedded controller before entering a sleep state. If the " > - "machine cannot suspend (S3), hibernate (S4) or shutdown (S5) " > - "then it could be because _PTS is missing."); > - break; > + /* All elements in the package must be references */ > + for (i=0; i < obj->Package.Count; i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_LOCAL_REFERENCE) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PREElementType", > + "_PRE package element %d was not a reference.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > } > - fwts_log_nl(fw); > } > - return FWTS_OK; > } > > -static int method_test_TTS(fwts_framework *fw) > +static int method_test_PRE(fwts_framework *fw) > { > - int i; > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PRE", NULL, 0, method_test_PRE_return, NULL); > +} > > - if (fwts_method_exists("_BFS") != NULL) { > - for (i=1; i<6; i++) { > - ACPI_OBJECT arg[1]; > +static int method_test_PSW(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[1]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PSW", arg, 1, method_test_NULL_return, NULL); > +} > + > +static int method_test_IRC(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_IRC", NULL, 0, method_test_NULL_return, NULL); > +} > + > + > +/* > + * Section 8.4 Declaring Processors > + */ > +static void method_test_PSS_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + int i; > + bool failed = false; > + uint32_t max_freq = 0; > + uint32_t prev_power = 0; > + bool max_freq_valid = false; > + > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + /* Something is really wrong if we don't have any elements in _PSS */ > + if (obj->Package.Count < 1) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementCount", > + "_PSS should return package of at least 1 element, " > + "got %d elements instead.", > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + return; > + } > + > + for (i=0; i < obj->Package.Count; i++) { > + ACPI_OBJECT *pstate; > + > + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementType", > + "_PSS package element %d was not a package.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed = true; > + continue; /* Skip processing sub-package */ > + } > + > + pstate = &obj->Package.Elements[i]; > + if (pstate->Package.Count != 6) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementCount", > + "_PSS P-State sub-package %d was expected to have " > + "6 elements, got %d elements instead.", > + i, obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed = true; > + continue; /* Skip processing sub-package */ > + } > + > + /* Elements need to be all ACPI integer types */ > + if ((pstate->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || > + (pstate->Package.Elements[1].Type != ACPI_TYPE_INTEGER) || > + (pstate->Package.Elements[2].Type != ACPI_TYPE_INTEGER) || > + (pstate->Package.Elements[3].Type != ACPI_TYPE_INTEGER) || > + (pstate->Package.Elements[4].Type != ACPI_TYPE_INTEGER) || > + (pstate->Package.Elements[5].Type != ACPI_TYPE_INTEGER)) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementType", > + "_PSS P-State sub-package %d was expected to have " > + "6 Integer elements but didn't", i); > + failed = true; > + continue; > + } > + > + fwts_log_info(fw, "P-State %d: CPU %ld Mhz, %lu mW, latency %lu us, bus master latency %lu us.", > + i, > + (unsigned long)pstate->Package.Elements[0].Integer.Value, > + (unsigned long)pstate->Package.Elements[1].Integer.Value, > + (unsigned long)pstate->Package.Elements[2].Integer.Value, > + (unsigned long)pstate->Package.Elements[3].Integer.Value); > + > + /* > + * Collect maximum frequency. The sub-packages are sorted in > + * descending power dissipation order, so one would assume that > + * the highest frequency is first. However, it is not clear > + * from the ACPI spec that this is necessarily an assumption we > + * should make, so instead we should probably scan through all > + * the valid sub-packages and find the highest frequency. > + */ > + if (max_freq < pstate->Package.Elements[0].Integer.Value) { > + max_freq = pstate->Package.Elements[0].Integer.Value; > + max_freq_valid = true; > + } > + > + /* Sanity check descending power dissipation levels */ > + if ((i > 0) && (prev_power != 0) && > + (pstate->Package.Elements[1].Integer.Value > prev_power)) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackagePowerNotDecending", > + "_PSS P-State sub-package %d has a larger power dissipation " > + "setting than the previous sub-package.", i); > + fwts_advice(fw, "_PSS P-States must be ordered in decending order of " > + "power dissipation, so that the zero'th entry has the highest " > + "power dissipation level and the Nth has the lowest."); > + failed = true; > + } > + prev_power = pstate->Package.Elements[1].Integer.Value; > + } > + > + /* > + * Sanity check maximum frequency. We could also check the DMI data > + * for a BIOS date (but this can be wrong) or check the CPU identity > + * (which requires adding in new CPU identity checks) to make a decision > + * on when it is reasonable to assume a CPU is modern and hence clocked > + * incorrectly. For now, just flag up a low level error that the > + * frequency looks rather low rather than try to be intelligent (and > + * possibly make a mistake). I'd rather flag up a few false positives > + * on older machines than miss flagging up bad _PSS settings on new > + * machines. > + */ > + if (max_freq_valid && max_freq < 1000) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_PSSSubPackageLowFreq", > + "Maximum CPU frequency is %dHz and this is low for " > + "a modern processor. This may indicate the _PSS P-States " > + "are incorrect\n", max_freq); > + fwts_advice(fw, > + "The _PSS P-States are used by the Linux CPU frequency " > + "driver to set the CPU frequencies according to system " > + "load. Sometimes the firmware sets these incorrectly " > + "and the machine runs at a sub-optimal speed. One can " > + "view the firmware defined CPU frequencies via " > + "/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies"); > + failed = true; > + } > + > + if (!failed) > + fwts_passed(fw, "_PSS correctly returned sane looking package."); > +} > + > +static int method_test_PSS(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSS", NULL, 0, method_test_PSS_return, NULL); > +} > + > + > +/* > + * Section 9.2 Ambient Light Sensor Device > + */ > +method_test_integer(_ALC, METHOD_OPTIONAL) > +method_test_integer(_ALI, METHOD_OPTIONAL) > +method_test_integer(_ALT, METHOD_OPTIONAL) > + > +/* TODO _ALR */ > + > +static int method_test_ALP(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_ALP", NULL, 0, method_test_polling_return, "_ALP"); > +} > + > + > +/* > + * Section 9.4 Lid control > + */ > +static void method_test_LID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +{ > + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) > + fwts_passed(fw, "_LID correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); > +} > + > +static int method_test_LID(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_LID", NULL, 0, method_test_LID_return, NULL); > +} > + > + > +/* > + * Section 9.18 Wake Alarm Device > + */ > +static int method_test_STP(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[2]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; /* DC timer */ > + arg[1].Type = ACPI_TYPE_INTEGER; > + arg[1].Integer.Value = 0; /* wake up instantly */ > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_STP", arg, 2, method_test_passed_failed_return, "_STP"); > +} > + > +static int method_test_STV(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[2]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; /* DC timer */ > + arg[1].Type = ACPI_TYPE_INTEGER; > + arg[1].Integer.Value = 100; /* timer value */ > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_STV", arg, 2, method_test_passed_failed_return, "_STV"); > +} > + > +static int method_test_TIP(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[1]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; /* DC timer */ > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TIP", arg, 1, method_test_integer_return, NULL); > +} > + > +static int method_test_TIV(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[1]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; /* DC timer */ > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TIV", arg, 1, method_test_integer_return, NULL); > +} > + > + > +/* > + * Section 10.1 Smart Battery > + */ > +static void method_test_SBS_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + static char *sbs_info[] = { > + "Maximum 1 Smart Battery, system manager/selector not present", > + "Maximum 1 Smart Battery, system manager/selector present", > + "Maximum 2 Smart Batteries, system manager/selector present", > + "Maximum 3 Smart Batteries, system manager/selector present", > + "Maximum 4 Smart Batteries, system manager/selector present" > + }; > + > + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > + switch (obj->Integer.Value) { > + case 0 ... 4: > + fwts_passed(fw, "_SBS correctly returned value %d %s", > + (uint32_t)obj->Integer.Value, > + sbs_info[obj->Integer.Value]); > + break; > + default: > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SBSReturn", "_SBS returned %d, should be between 0 and 4.", > + (uint32_t)obj->Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + fwts_advice(fw, "Smart Battery _SBS is incorrectly informing the OS about the smart battery " > + "configuration. This is a bug and needs to be fixed."); > + break; > + } > + } > +} > + > +static int method_test_SBS(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_SBS", NULL, 0, method_test_SBS_return, NULL); > +} > + > + > +/* > + * Section 10.2 Battery Control Methods > + */ > +static void method_test_BIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + int i; > + int failed = 0; > + > + fwts_method_dump_object(fw, obj); > + > + if (obj->Package.Count != 13) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFElementCount", "_BIF package should return 13 elements, got %d instead.", > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + } > + > + for (i=0;(i<9) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type DWORD Integer.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + } > + for (i=9;(i<13) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type STRING.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + } > + > + /* Sanity check each field */ > + /* Power Unit */ > + if (obj->Package.Elements[0].Integer.Value > 0x00000002) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadUnits", "_BIF: Expected Power Unit (Element 0) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[0].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#ifdef FWTS_METHOD_PEDANDTIC > + /* > + * Since this information may be evaluated by communicating with > + * the EC we skip these checks as we can't do this from userspace > + */ > + /* Design Capacity */ > + if (obj->Package.Elements[1].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFBadCapacity", "_BIF: Design Capacity (Element 1) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[1].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Last Full Charge Capacity */ > + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFChargeCapacity", "_BIF: Last Full Charge Capacity (Element 2) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[2].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#endif > + /* Battery Technology */ > + if (obj->Package.Elements[3].Integer.Value > 0x00000002) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBatTechUnit", "_BIF: Expected Battery Technology Unit (Element 3) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[3].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#ifdef FWTS_METHOD_PEDANDTIC > + /* > + * Since this information may be evaluated by communicating with > + * the EC we skip these checks as we can't do this from userspace > + */ > + /* Design Voltage */ > + if (obj->Package.Elements[4].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignVoltage", "_BIF: Design Voltage (Element 4) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[4].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Design capacity warning */ > + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE5", "_BIF: Design Capacity Warning (Element 5) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[5].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Design capacity low */ > + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE6", "_BIF: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[6].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#endif > + if (failed) > + fwts_advice(fw, "Battery _BIF package contains errors. It is worth running the " > + "firmware test suite interactive 'battery' test to see if this " > + "is problematic. This is a bug an needs to be fixed."); > + else > + fwts_passed(fw, "Battery _BIF package looks sane."); > + } > +} > > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = i; > +static int method_test_BIF(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BIF", NULL, 0, method_test_BIF_return, NULL); > +} > > - fwts_log_info(fw, "Test _TTS(%d) Transition To State S%d.", i, i); > +static void method_test_BIX_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + int i; > + int failed = 0; > > - if (method_evaluate_method(fw, METHOD_MANDITORY, "_TTS", arg, 1, > - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > - break; > - fwts_log_nl(fw); > + fwts_method_dump_object(fw, obj); > + > + if (obj->Package.Count != 16) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXElementCount", "_BIX package should return 16 elements, got %d instead.", > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > } > + > + for (i=0;(i<16) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type DWORD Integer.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + } > + for (i=16;(i<20) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type STRING.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + } > + > + /* Sanity check each field */ > + /* Power Unit */ > + if (obj->Package.Elements[1].Integer.Value > 0x00000002) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXPowerUnit", > + "_BIX: Expected Power Unit (Element 1) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[1].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#ifdef FWTS_METHOD_PEDANDTIC > + /* > + * Since this information may be evaluated by communicating with > + * the EC we skip these checks as we can't do this from userspace > + */ > + /* Design Capacity */ > + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacity", > + "_BIX: Design Capacity (Element 2) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[2].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Last Full Charge Capacity */ > + if (obj->Package.Elements[3].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXFullChargeCapacity", > + "_BIX: Last Full Charge Capacity (Element 3) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[3].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#endif > + /* Battery Technology */ > + if (obj->Package.Elements[4].Integer.Value > 0x00000002) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBatteryTechUnit", > + "_BIX: Expected Battery Technology Unit (Element 4) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[4].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#ifdef FWTS_METHOD_PEDANDTIC > + /* > + * Since this information may be evaluated by communicating with > + * the EC we skip these checks as we can't do this from userspace > + */ > + /* Design Voltage */ > + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignVoltage", > + "_BIX: Design Voltage (Element 5) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[5].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Design capacity warning */ > + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE6", > + "_BIX: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[6].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Design capacity low */ > + if (obj->Package.Elements[7].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE7", > + "_BIX: Design Capacity Warning (Element 7) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[7].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Cycle Count */ > + if (obj->Package.Elements[10].Integer.Value > 0x7fffffff) { > + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXCyleCount", > + "_BIX: Cycle Count (Element 10) is unknown: 0x%8.8x.", > + (uint32_t)obj->Package.Elements[10].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > +#endif > + if (failed) > + fwts_advice(fw, "Battery _BIX package contains errors. It is worth running the " > + "firmware test suite interactive 'battery' test to see if this " > + "is problematic. This is a bug an needs to be fixed."); > + else > + fwts_passed(fw, "Battery _BIX package looks sane."); > } > - else { > - fwts_skipped(fw, "Optional control method _TTS does not exist."); > - } > - return FWTS_OK; > } > > -static void method_test_Sx_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static int method_test_BIX(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BIX", NULL, 0, method_test_BIX_return, NULL); > +} > + > +static int method_test_BMA(fwts_framework *fw) > { > - char *method = (char *)private; > + ACPI_OBJECT arg[1]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; > + > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BMA", arg, 1, method_test_integer_return, NULL); > +} > + > +static int method_test_BMS(fwts_framework *fw) > +{ > + ACPI_OBJECT arg[1]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 1; > > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BMS", arg, 1, method_test_integer_return, NULL); > +} > + > +static void method_test_BST_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + int i; > + int failed = 0; > + > fwts_method_dump_object(fw, obj); > > - if (obj->Package.Count != 3) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SElementCount", "%s should return package of 3 integers, got %d elements instead.", method, > + if (obj->Package.Count != 4) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTElementCount", "_BST package should return 4 elements, got %d instead.", > obj->Package.Count); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + > + for (i=0;(i<4) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadType", > + "_BST package element %d is not of type DWORD Integer.", i); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + } > + > + /* Sanity check each field */ > + /* Battery State */ > + if ((obj->Package.Elements[0].Integer.Value) > 7) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", > + "_BST: Expected Battery State (Element 0) to be 0..7, got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[0].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + /* Ensure bits 0 (discharging) and 1 (charging) are not both set, see 10.2.2.6 */ > + if (((obj->Package.Elements[0].Integer.Value) & 3) == 3) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", > + "_BST: Battery State (Element 0) is indicating both charging " > + "and discharginng which is not allowed. Got value 0x%8.8x.", > + (uint32_t)obj->Package.Elements[0].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > } > + /* Battery Present Rate - cannot check, pulled from EC */ > + /* Battery Remaining Capacity - cannot check, pulled from EC */ > + /* Battery Present Voltage - cannot check, pulled from EC */ > + if (failed) > + fwts_advice(fw, "Battery _BST package contains errors. It is worth running the " > + "firmware test suite interactive 'battery' test to see if this " > + "is problematic. This is a bug an needs to be fixed."); > + else > + fwts_passed(fw, "Battery _BST package looks sane."); > } > } > > -#define method_test_Sx(name) \ > -static int method_test ## name(fwts_framework *fw) \ > -{ \ > - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, NULL, 0, method_test_Sx_return, # name); \ > +static int method_test_BST(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BST", NULL, 0, method_test_BST_return, NULL); > +} > + > +static int method_test_BTP(fwts_framework *fw) > +{ > + static int values[] = { 0, 1, 100, 200, 0x7fffffff }; > + int i; > + > + for (i=0;i<5;i++) { > + ACPI_OBJECT arg[1]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = values[i]; > + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTP", arg, 1, > + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + break; > + fwts_log_nl(fw); > + } > + return FWTS_OK; > +} > + > +static void method_test_PCL_return(fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + /* FIXME */ > +} > + > +static int method_test_PCL(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_PCL", NULL, 0, method_test_PCL_return, "_PCL"); > +} > + > +static int method_test_BTM(fwts_framework *fw) > +{ > + static int values[] = { 0, 1, 100, 200, 0x7fffffff }; > + int i; > + > + for (i=0;i<5;i++) { > + ACPI_OBJECT arg[1]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = values[i]; > + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTM", arg, 1, > + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + break; > + fwts_log_nl(fw); > + } > + return FWTS_OK; > } > > -method_test_Sx(_S0) > -method_test_Sx(_S1) > -method_test_Sx(_S2) > -method_test_Sx(_S3) > -method_test_Sx(_S4) > -method_test_Sx(_S5) > - > -static void method_test_WAK_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_BMD_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > - uint32_t Sstate = *(uint32_t*)private; > - int failed = 0; > - > if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + int i; > + int failed = 0; > + > fwts_method_dump_object(fw, obj); > > - if (obj->Package.Count != 2) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKElementCount", "_WAK should return package of 2 integers, got %d elements instead.", > + if (obj->Package.Count != 5) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDElementCount", "_BMD package should return 4 elements, got %d instead.", > obj->Package.Count); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > failed++; > - } else { > - if ((obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || > - (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBadType", "_WAK should return package of 2 integers, got %d instead.", > - obj->Package.Count); > + } > + > + for (i=0;(i<4) && (i<obj->Package.Count);i++) { > + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDBadType", "_BMD package element %d is not of type DWORD Integer.", i); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > failed++; > } > - else { > - if (obj->Package.Elements[0].Integer.Value > 0x00000002) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBitField", > - "_WAK: expecting condition bit-field (element 0) of packages to be in range, got 0x%8.8x.", > - (uint32_t)obj->Package.Elements[0].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - if (!( > - ((obj->Package.Elements[1].Integer.Value == Sstate) && (obj->Package.Elements[0].Integer.Value == 0)) || > - ((obj->Package.Elements[1].Integer.Value == 0) && (obj->Package.Elements[0].Integer.Value != 0)) )) { > - fwts_warning(fw, > - "_WAK: expecting power supply S-state (element 1) of packages to be 0x%8.8x, got 0x%8.8x.", > - Sstate, (uint32_t)obj->Package.Elements[0].Integer.Value); > - fwts_advice(fw, "_WAK should return 0 if the wake failed and was unsuccessful (i.e. element[0] " > - "is non-zero) OR should return the S-state. " > - "This can confuse the operating system as this _WAK return indicates that the " > - "S-state was not entered because of too much current being drawn from the " > - "power supply, however, the BIOS may have actually entered this state and the " > - "_WAK method is misinforming the operating system. Currently Linux does not " > - "check for the return type from _WAK, so it should theoretically not affect the " > - "operation of suspend/resume."); > - > - failed++; > - } > - } > } > - if (!failed) > - fwts_passed(fw, "_WAK correctly returned sane looking package."); > + /* TODO: check return values */ > } > } > > -static int method_test_WAK(fwts_framework *fw) > +static int method_test_BMD(fwts_framework *fw) > { > - uint32_t i; > + return method_evaluate_method(fw, METHOD_MOBILE, > + "_BMD", NULL, 0, method_test_BMD_return, NULL); > +} > > - for (i=1; i<6; i++) { > +static int method_test_BMC(fwts_framework *fw) > +{ > + static int values[] = { 0, 1, 2, 4 }; > + int i; > + > + for (i=0;i<4;i++) { > ACPI_OBJECT arg[1]; > arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = i; > - fwts_log_info(fw, "Test _WAK(%d) System Wake, State S%d.", i, i); > - if (method_evaluate_method(fw, METHOD_MANDITORY, "_WAK", arg, 1, > - method_test_WAK_return, &i) == FWTS_NOT_EXIST) > + arg[0].Integer.Value = values[i]; > + if (method_evaluate_method(fw, METHOD_MOBILE, "_BMC", arg, 1, > + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > break; > fwts_log_nl(fw); > } > return FWTS_OK; > } > > -/* Section 10.3 AC Adapters and Power Sources Objects */ > > -static void method_test_PSR_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +/* > + * Section 10.3 AC Adapters and Power Sources Objects > + */ > +static void method_test_PSR_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > if (obj->Integer.Value > 2) { > @@ -1090,12 +1498,17 @@ static void method_test_PSR_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_PSR(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSR", NULL, 0, method_test_PSR_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PSR", NULL, 0, method_test_PSR_return, NULL); > } > > -static void method_test_PIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_PIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > - > if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > fwts_method_dump_object(fw, obj); > > @@ -1123,26 +1536,20 @@ static void method_test_PIF_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_PIF(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PIF", NULL, 0, method_test_PIF_return, NULL); > -} > - > - > -/* Section 9.4.1 Lid control */ > - > -static void method_test_LID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) > - fwts_passed(fw, "_LID correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); > -} > - > -static int method_test_LID(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_MOBILE, "_LID", NULL, 0, method_test_LID_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_PIF", NULL, 0, method_test_PIF_return, NULL); > } > > -/* Section 11.3 Fan Devices */ > > -static void method_test_FIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +/* > + * Section 11.3 Fan Devices > + */ > +static void method_test_FIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > fwts_method_dump_object(fw, obj); > @@ -1172,7 +1579,8 @@ static void method_test_FIF_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_FIF(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FIF", NULL, 0, method_test_FIF_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_FIF", NULL, 0, method_test_FIF_return, NULL); > } > > static int method_test_FSL(fwts_framework *fw) > @@ -1181,7 +1589,8 @@ static int method_test_FSL(fwts_framework *fw) > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = 50; > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FSL", arg, 1, method_test_NULL_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_FSL", arg, 1, method_test_NULL_return, NULL); > } > > static void method_test_FST_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > @@ -1213,22 +1622,30 @@ static void method_test_FST_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_FST(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FST", NULL, 0, method_test_FST_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_FST", NULL, 0, method_test_FST_return, NULL); > } > > -/* Section 11.4 Thermal */ > > -static void method_test_THERM_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +/* > + * Section 11.4 Thermal > + */ > +static void method_test_THERM_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > char *method = (char*)private; > - > + > if (fwts_acpi_region_handler_called_get()) { > /* > * We accessed some memory or I/O region during the evaluation > * which returns spoofed values, so we should not test the value > * being returned. In this case, just pass this as a valid > - * return type. > + * return type. > */ > fwts_passed(fw, "%s correctly returned sane looking return type.", name); > } else { > @@ -1267,7 +1684,8 @@ static void method_test_THERM_return(fwts_framework *fw, char *name, ACPI_BUFFER > static int method_test ## name(fwts_framework *fw) \ > { \ > fwts_acpi_region_handler_called_set(false); \ > - return method_evaluate_method(fw, type, # name, NULL, 0, method_test_THERM_return, # name); \ > + return method_evaluate_method(fw, type, # name, \ > + NULL, 0, method_test_THERM_return, # name); \ > } > > method_test_THERM(_CRT, METHOD_OPTIONAL) > @@ -1277,7 +1695,18 @@ method_test_THERM(_NTT, METHOD_OPTIONAL) > method_test_THERM(_PSV, METHOD_OPTIONAL) > method_test_THERM(_TST, METHOD_OPTIONAL) > > -static void method_test_TCx_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static int method_test_TSP(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TSP", NULL, 0, method_test_polling_return, "_TSP"); > +} > + > +static void method_test_TCx_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > char *method = (char *)private; > @@ -1287,12 +1716,14 @@ static void method_test_TCx_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_TC1(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TC1", NULL, 0, method_test_TCx_return, "_TC1"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TC1", NULL, 0, method_test_TCx_return, "_TC1"); > } > > static int method_test_TC2(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TC2", NULL, 0, method_test_TCx_return, "_TC1"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TC2", NULL, 0, method_test_TCx_return, "_TC1"); > } > > static int method_test_ACx(fwts_framework *fw) > @@ -1302,7 +1733,8 @@ static int method_test_ACx(fwts_framework *fw) > for (i=0;i<10;i++) { > char buffer[5]; > snprintf(buffer, sizeof(buffer), "AC%d", i); > - method_evaluate_method(fw, METHOD_OPTIONAL, buffer, NULL, 0, method_test_THERM_return, buffer); > + method_evaluate_method(fw, METHOD_OPTIONAL, > + buffer, NULL, 0, method_test_THERM_return, buffer); > fwts_log_nl(fw); > } > return FWTS_OK; > @@ -1313,7 +1745,9 @@ static int method_test_DTI(fwts_framework *fw) > ACPI_OBJECT arg[1]; > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = 2732 + 800; /* 80 degrees C */ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL); > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DTI", arg, 1, method_test_NULL_return, NULL); > } > > static int method_test_SCP(fwts_framework *fw) > @@ -1329,7 +1763,9 @@ static int method_test_SCP(fwts_framework *fw) > arg[1].Integer.Value = 5; /* Acoustic limit */ > arg[2].Type = ACPI_TYPE_INTEGER; > arg[2].Integer.Value = 5; /* Power limit */ > - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + > + if (method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > break; > fwts_log_nl(fw); > > @@ -1339,14 +1775,20 @@ static int method_test_SCP(fwts_framework *fw) > arg[1].Integer.Value = 1; /* Acoustic limit */ > arg[2].Type = ACPI_TYPE_INTEGER; > arg[2].Integer.Value = 1; /* Power limit */ > - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + > + if (method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > break; > } > return FWTS_OK; > } > > - > -static void method_test_RTV_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_RTV_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) > fwts_passed(fw, "_RTV correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); > @@ -1354,7 +1796,8 @@ static void method_test_RTV_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_RTV(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_RTV", NULL, 0, method_test_RTV_return, "_RTV"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_RTV", NULL, 0, method_test_RTV_return, "_RTV"); > } > > static int method_test_TPT(fwts_framework *fw) > @@ -1362,139 +1805,206 @@ static int method_test_TPT(fwts_framework *fw) > ACPI_OBJECT arg[1]; > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = 2732 + 900; /* 90 degrees C */ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TPT", arg, 1, method_test_NULL_return, NULL); > -} > - > -static void method_test_polling_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { > - char *method = (char *)private; > - if (obj->Integer.Value < 36000) { > - fwts_passed(fw, "%s correctly returned sane looking value %f seconds", > - method, (float)obj->Integer.Value / 10.0); > - } else { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodPollTimeTooLong", > - "%s returned a value %f seconds > (1 hour) which is probably incorrect.", > - method, (float)obj->Integer.Value / 10.0); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - fwts_advice(fw, "The method is returning a polling interval which is very long and hence " > - "most probably incorrect."); > - } > - } > -} > > -static int method_test_TSP(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TSP", NULL, 0, method_test_polling_return, "_TSP"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TPT", arg, 1, method_test_NULL_return, NULL); > } > > static int method_test_TZP(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TZP", NULL, 0, method_test_polling_return, "_TZP"); > -} > - > -/* Section 9.2, Ambient Light Sensor Device */ > - > -method_test_integer(_ALC, METHOD_OPTIONAL) > -method_test_integer(_ALI, METHOD_OPTIONAL) > -method_test_integer(_ALT, METHOD_OPTIONAL) > - > -/* TODO _ALR */ > - > -static int method_test_ALP(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ALP", NULL, 0, method_test_polling_return, "_ALP"); > -} > - > - > -/* Section 6.5 Other Objects and Control Methods */ > - > -static int method_test_BBN(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BBN", NULL, 0, method_test_integer_return, "_BBN"); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_TZP", NULL, 0, method_test_polling_return, "_TZP"); > } > > -static int method_test_BDN(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_MOBILE, "_BDN", NULL, 0, method_test_integer_return, "_BDN"); > -} > > -static int method_test_DCK(fwts_framework *fw) > +/* > + * Section 16 Waking and Sleeping > + */ > +static int method_test_PTS(fwts_framework *fw) > { > int i; > > - for (i=0;i<=1;i++) { /* Undock, Dock */ > + for (i=1; i<6; i++) { > ACPI_OBJECT arg[1]; > + > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = i; > - if (method_evaluate_method(fw, METHOD_MOBILE, "_DCK", arg, 1, method_test_passed_failed_return, "_DCK") != FWTS_OK) > + > + fwts_log_info(fw, "Test _PTS(%d).", i); > + > + if (method_evaluate_method(fw, METHOD_MANDITORY, "_PTS", arg, 1, > + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) { > + fwts_advice(fw, "Could not find _PTS. This method provides a mechanism to " > + "do housekeeping functions, such as write sleep state to the " > + "embedded controller before entering a sleep state. If the " > + "machine cannot suspend (S3), hibernate (S4) or shutdown (S5) " > + "then it could be because _PTS is missing."); > break; > + } > fwts_log_nl(fw); > } > return FWTS_OK; > } > > -/* Section 9.18 Wake Alarm Device */ > +static int method_test_TTS(fwts_framework *fw) > +{ > + int i; > > + if (fwts_method_exists("_BFS") != NULL) { > + for (i=1; i<6; i++) { > + ACPI_OBJECT arg[1]; > > -static int method_test_STP(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[2]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = i; > > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; /* DC timer */ > - arg[1].Type = ACPI_TYPE_INTEGER; > - arg[1].Integer.Value = 0; /* wake up instantly */ > + fwts_log_info(fw, "Test _TTS(%d) Transition To State S%d.", i, i); > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_STP", arg, 2, method_test_passed_failed_return, "_STP"); > + if (method_evaluate_method(fw, METHOD_MANDITORY, "_TTS", arg, 1, > + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) > + break; > + fwts_log_nl(fw); > + } > + } > + else { > + fwts_skipped(fw, "Optional control method _TTS does not exist."); > + } > + return FWTS_OK; > } > > -static int method_test_STV(fwts_framework *fw) > +static void method_test_Sx_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > - ACPI_OBJECT arg[2]; > + char *method = (char *)private; > > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; /* DC timer */ > - arg[1].Type = ACPI_TYPE_INTEGER; > - arg[1].Integer.Value = 100; /* timer value */ > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + fwts_method_dump_object(fw, obj); > + > + if (obj->Package.Count != 3) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SElementCount", "%s should return package of 3 integers, got %d elements instead.", method, > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + } > + } > +} > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_STV", arg, 2, method_test_passed_failed_return, "_STV"); > +#define method_test_Sx(name) \ > +static int method_test ## name(fwts_framework *fw) \ > +{ \ > + return method_evaluate_method(fw, METHOD_OPTIONAL, \ > + # name, NULL, 0, method_test_Sx_return, # name);\ > } > > -static int method_test_TIP(fwts_framework *fw) > +method_test_Sx(_S0) > +method_test_Sx(_S1) > +method_test_Sx(_S2) > +method_test_Sx(_S3) > +method_test_Sx(_S4) > +method_test_Sx(_S5) > + > +static void method_test_WAK_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > - ACPI_OBJECT arg[1]; > + uint32_t Sstate = *(uint32_t*)private; > + int failed = 0; > > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; /* DC timer */ > + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > + fwts_method_dump_object(fw, obj); > + > + if (obj->Package.Count != 2) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKElementCount", "_WAK should return package of 2 integers, got %d elements instead.", > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } else { > + if ((obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || > + (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBadType", "_WAK should return package of 2 integers, got %d instead.", > + obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + else { > + if (obj->Package.Elements[0].Integer.Value > 0x00000002) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBitField", > + "_WAK: expecting condition bit-field (element 0) of packages to be in range, got 0x%8.8x.", > + (uint32_t)obj->Package.Elements[0].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > + if (!( > + ((obj->Package.Elements[1].Integer.Value == Sstate) && (obj->Package.Elements[0].Integer.Value == 0)) || > + ((obj->Package.Elements[1].Integer.Value == 0) && (obj->Package.Elements[0].Integer.Value != 0)) )) { > + fwts_warning(fw, > + "_WAK: expecting power supply S-state (element 1) of packages to be 0x%8.8x, got 0x%8.8x.", > + Sstate, (uint32_t)obj->Package.Elements[0].Integer.Value); > + fwts_advice(fw, "_WAK should return 0 if the wake failed and was unsuccessful (i.e. element[0] " > + "is non-zero) OR should return the S-state. " > + "This can confuse the operating system as this _WAK return indicates that the " > + "S-state was not entered because of too much current being drawn from the " > + "power supply, however, the BIOS may have actually entered this state and the " > + "_WAK method is misinforming the operating system. Currently Linux does not " > + "check for the return type from _WAK, so it should theoretically not affect the " > + "operation of suspend/resume."); > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TIP", arg, 1, method_test_integer_return, NULL); > + failed++; > + } > + } > + } > + if (!failed) > + fwts_passed(fw, "_WAK correctly returned sane looking package."); > + } > } > > -static int method_test_TIV(fwts_framework *fw) > +static int method_test_WAK(fwts_framework *fw) > { > - ACPI_OBJECT arg[1]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; /* DC timer */ > + uint32_t i; > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TIV", arg, 1, method_test_integer_return, NULL); > + for (i=1; i<6; i++) { > + ACPI_OBJECT arg[1]; > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = i; > + fwts_log_info(fw, "Test _WAK(%d) System Wake, State S%d.", i, i); > + if (method_evaluate_method(fw, METHOD_MANDITORY, "_WAK", arg, 1, > + method_test_WAK_return, &i) == FWTS_NOT_EXIST) > + break; > + fwts_log_nl(fw); > + } > + return FWTS_OK; > } > > -/* Appendix B, ACPI Extensions for Display Adapters */ > > +/* > + * Appendix B ACPI Extensions for Display Adapters > + */ > static int method_test_DOS(fwts_framework *fw) > { > ACPI_OBJECT arg[1]; > > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = 0 << 2 | 1; > - /* BIOS should toggle active display, BIOS controls brightness of LCD on AC/DC power changes */ > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DOS", arg, 1, method_test_NULL_return, NULL); > + /* > + * BIOS should toggle active display, BIOS controls brightness of > + * LCD on AC/DC power changes > + */ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DOS", arg, 1, method_test_NULL_return, NULL); > } > > -static void method_test_DOD_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_DOD_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > int failed = 0; > static char *dod_type[] = { > @@ -1554,10 +2064,16 @@ static void method_test_DOD_return(fwts_framework *fw, char *name, ACPI_BUFFER * > > static int method_test_DOD(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DOD", NULL, 0, method_test_DOD_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DOD", NULL, 0, method_test_DOD_return, NULL); > } > > -static void method_test_ROM_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_ROM_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > method_check_type(fw, name, buf, ACPI_TYPE_BUFFER); > } > @@ -1571,12 +2087,14 @@ static int method_test_ROM(fwts_framework *fw) > arg[1].Type = ACPI_TYPE_INTEGER; > arg[1].Integer.Value = 4096; > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ROM", arg, 2, method_test_ROM_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_ROM", arg, 2, method_test_ROM_return, NULL); > } > > static int method_test_GPD(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_GPD", NULL, 0, method_test_integer_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_GPD", NULL, 0, method_test_integer_return, NULL); > } > > static int method_test_SPD(fwts_framework *fw) > @@ -1588,7 +2106,8 @@ static int method_test_SPD(fwts_framework *fw) > arg[0].Type = ACPI_TYPE_INTEGER; > arg[0].Integer.Value = i; /* bits 00..11, post device */ > > - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_SPD", arg, 1, method_test_passed_failed_return, NULL) == FWTS_NOT_EXIST) > + if (method_evaluate_method(fw, METHOD_OPTIONAL, > + "_SPD", arg, 1, method_test_passed_failed_return, NULL) == FWTS_NOT_EXIST) > break; > } > return FWTS_OK; > @@ -1596,15 +2115,22 @@ static int method_test_SPD(fwts_framework *fw) > > static int method_test_VPO(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_VPO", NULL, 0, method_test_integer_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_VPO", NULL, 0, method_test_integer_return, NULL); > } > > static int method_test_ADR(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ADR", NULL, 0, method_test_integer_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_ADR", NULL, 0, method_test_integer_return, NULL); > } > > -static void method_test_BCL_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static void method_test_BCL_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { > int i; > @@ -1620,467 +2146,157 @@ static void method_test_BCL_return(fwts_framework *fw, char *name, ACPI_BUFFER * > fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLNoPackage", > "Method _BCL did not return a package of %d integers.", obj->Package.Count); > } else { > - if (obj->Package.Count < 3) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLElementCount", > - "Method _BCL should return a package of more than 2 integers, got just %d.", obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } else { > - bool ascending_levels = false; > - > - if (obj->Package.Elements[0].Integer.Value < > - obj->Package.Elements[1].Integer.Value) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLMaxLevel", > - "Brightness level when on full power (%d) is less than " > - "brightness level when on battery power (%d).", > - (uint32_t)obj->Package.Elements[0].Integer.Value, > - (uint32_t)obj->Package.Elements[1].Integer.Value); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed++; > - } > - > - for (i=2;i<obj->Package.Count-1;i++) { > - if (obj->Package.Elements[i].Integer.Value > > - obj->Package.Elements[i+1].Integer.Value) { > - fwts_log_info(fw, "Brightness level %d (index %d) is greater than " > - "brightness level %d (index %d), should be in ascending order.", > - (uint32_t)obj->Package.Elements[i].Integer.Value, i, > - (uint32_t)obj->Package.Elements[i+1].Integer.Value, i+1); > - ascending_levels = true; > - failed++; > - } > - } > - if (ascending_levels) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLAscendingOrder", > - "Some or all of the brightness level are not in ascending order which " > - "should be fixed in the firmware."); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } > - > - if (failed) > - fwts_advice(fw, "Method _BCL seems to be misconfigured and is returning incorrect brightness levels." > - "It is worth sanity checking this with the firmware test suite interactive test " > - "'brightness' to see how broken this is. As it is, _BCL is broken and needs to be " > - "fixed."); > - else > - fwts_passed(fw, "Method _BCL returned a sane package of %d integers.", obj->Package.Count); > - } > - } > - } > -} > - > -static int method_test_BCL(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BCL", NULL, 0, method_test_BCL_return, NULL); > -} > - > -static int method_test_BCM(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 0; > - > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BCM", arg, 1, method_test_NULL_return, NULL); > -} > - > -static int method_test_BQC(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BQC", NULL, 0, method_test_integer_return, NULL); > -} > - > -static void method_test_DDC_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - uint32_t requested = *(uint32_t*)private; > - > - if (obj == NULL){ > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); > - return; > - } > - switch (obj->Type) { > - case ACPI_TYPE_BUFFER: > - if (requested != obj->Buffer.Length) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCElementCount", > - "Method _DDC returned a buffer of %d items, expected %d.", > - obj->Buffer.Length, requested); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } else > - fwts_passed(fw, "Method _DDC returned a buffer of %d items as expected.", > - obj->Buffer.Length); > - break; > - case ACPI_TYPE_INTEGER: > - fwts_passed(fw, "Method _DDC could not return a buffer of %d items" > - "and instead returned an error status.", > - obj->Buffer.Length); > - break; > - default: > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCBadReturnType", > - "Method _DDC did not return a buffer or an integer."); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - break; > - } > -} > - > -static int method_test_DDC(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > - uint32_t i; > - > - for (i=128; i<=256; i <<= 1) { > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 128; > - > - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DDC", arg, 1, method_test_DDC_return, &i) == FWTS_NOT_EXIST) > - break; > - } > - return FWTS_OK; > -} > - > -static int method_test_DCS(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DCS", NULL, 0, method_test_integer_return, NULL); > -} > - > -static int method_test_DGS(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DGS", NULL, 0, method_test_integer_return, NULL); > -} > - > -static int method_test_DSS(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 0; > - > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSS", arg, 1, method_test_NULL_return, NULL); > -} > - > -/* Section 6.5 Other Objects and Controls */ > - > -static int method_test_CRS(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_MANDITORY, "_CRS", NULL, 0, method_test_buffer_return, NULL); > -} > - > -static int method_test_DMA(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DMA", NULL, 0, method_test_buffer_return, NULL); > -} > - > -static int method_test_DIS(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DIS", NULL, 0, method_test_NULL_return, NULL); > -} > - > -static int method_test_PXM(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PXM", NULL, 0, method_test_integer_return, NULL); > -} > - > -/* Section 7.2 */ > - > -static int method_test_DSW(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[3]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; > - arg[1].Type = ACPI_TYPE_INTEGER; > - arg[1].Integer.Value = 0; > - arg[2].Type = ACPI_TYPE_INTEGER; > - arg[2].Integer.Value = 3; > - > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSW", arg, 3, method_test_NULL_return, NULL); > -} > - > -#define method_test_PSx(name) \ > -static int method_test ## name(fwts_framework *fw) \ > -{ \ > - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, NULL, 0, method_test_NULL_return, # name); \ > -} > - > -method_test_PSx(_PS0) > -method_test_PSx(_PS1) > -method_test_PSx(_PS2) > -method_test_PSx(_PS3) > - > -static int method_test_PSC(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSC", NULL, 0, method_test_integer_return, NULL); > -} > - > -static int method_test_PSE(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > - > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; > - > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSE", arg, 1, method_test_NULL_return, NULL); > -} > - > -static void method_test_PRE_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > - int i; > - > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > - return; > - > - /* All elements in the package must be references */ > - for (i=0; i < obj->Package.Count; i++) { > - if (obj->Package.Elements[i].Type != ACPI_TYPE_LOCAL_REFERENCE) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PREElementType", > - "_PRE package element %d was not a reference.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } > - } > -} > - > -static int method_test_PRE(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PRE", NULL, 0, method_test_PRE_return, NULL); > -} > - > -static int method_test_PSW(fwts_framework *fw) > -{ > - ACPI_OBJECT arg[1]; > + if (obj->Package.Count < 3) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLElementCount", > + "Method _BCL should return a package of more than 2 integers, got just %d.", obj->Package.Count); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + } else { > + bool ascending_levels = false; > > - arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; > + if (obj->Package.Elements[0].Integer.Value < > + obj->Package.Elements[1].Integer.Value) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLMaxLevel", > + "Brightness level when on full power (%d) is less than " > + "brightness level when on battery power (%d).", > + (uint32_t)obj->Package.Elements[0].Integer.Value, > + (uint32_t)obj->Package.Elements[1].Integer.Value); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + failed++; > + } > > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSW", arg, 1, method_test_NULL_return, NULL); > -} > + for (i=2;i<obj->Package.Count-1;i++) { > + if (obj->Package.Elements[i].Integer.Value > > + obj->Package.Elements[i+1].Integer.Value) { > + fwts_log_info(fw, "Brightness level %d (index %d) is greater than " > + "brightness level %d (index %d), should be in ascending order.", > + (uint32_t)obj->Package.Elements[i].Integer.Value, i, > + (uint32_t)obj->Package.Elements[i+1].Integer.Value, i+1); > + ascending_levels = true; > + failed++; > + } > + } > + if (ascending_levels) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLAscendingOrder", > + "Some or all of the brightness level are not in ascending order which " > + "should be fixed in the firmware."); > + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > + } > > -static int method_test_IRC(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_IRC", NULL, 0, method_test_NULL_return, NULL); > + if (failed) > + fwts_advice(fw, "Method _BCL seems to be misconfigured and is returning incorrect brightness levels." > + "It is worth sanity checking this with the firmware test suite interactive test " > + "'brightness' to see how broken this is. As it is, _BCL is broken and needs to be " > + "fixed."); > + else > + fwts_passed(fw, "Method _BCL returned a sane package of %d integers.", obj->Package.Count); > + } > + } > + } > } > > -/* Section 6.3 */ > - > -static int method_test_EJD(fwts_framework *fw) > +static int method_test_BCL(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_EJD", NULL, 0, method_test_string_return, NULL); > -} > - > -#define method_test_EJx(name) \ > -static int method_test ## name(fwts_framework *fw) \ > -{ \ > - ACPI_OBJECT arg[1]; \ > - \ > - arg[0].Type = ACPI_TYPE_INTEGER; \ > - arg[0].Integer.Value = 1; \ > - \ > - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, arg, 1, method_test_NULL_return, # name); \ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_BCL", NULL, 0, method_test_BCL_return, NULL); > } > > -method_test_EJx(_EJ0) > -method_test_EJx(_EJ1) > -method_test_EJx(_EJ2) > -method_test_EJx(_EJ3) > -method_test_EJx(_EJ4) > - > -static int method_test_LCK(fwts_framework *fw) > +static int method_test_BCM(fwts_framework *fw) > { > ACPI_OBJECT arg[1]; > > arg[0].Type = ACPI_TYPE_INTEGER; > - arg[0].Integer.Value = 1; > - > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_LCK", arg, 1, method_test_NULL_return, NULL); > -} > - > -/* Section 7.1 */ > + arg[0].Integer.Value = 0; > > -static int method_test_ON(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ON", NULL, 0, method_test_NULL_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_BCM", arg, 1, method_test_NULL_return, NULL); > } > > -static int method_test_OFF(fwts_framework *fw) > +static int method_test_BQC(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_OFF", NULL, 0, method_test_NULL_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_BQC", NULL, 0, method_test_integer_return, NULL); > } > > -/* Section 6.1 */ > - > -static int method_test_SUN(fwts_framework *fw) > +static void method_test_DDC_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_SUN", NULL, 0, method_test_integer_return, NULL); > -} > + uint32_t requested = *(uint32_t*)private; > > -static void method_test_UID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > -{ > if (obj == NULL){ > fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); > return; > } > switch (obj->Type) { > - case ACPI_TYPE_STRING: > - if (obj->String.Pointer) > - fwts_passed(fw, "Object _UID returned a string '%s' as expected.", > - obj->String.Pointer); > - else { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDNullString", > - "Object _UID returned a NULL string."); > + case ACPI_TYPE_BUFFER: > + if (requested != obj->Buffer.Length) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCElementCount", > + "Method _DDC returned a buffer of %d items, expected %d.", > + obj->Buffer.Length, requested); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - } > + } else > + fwts_passed(fw, "Method _DDC returned a buffer of %d items as expected.", > + obj->Buffer.Length); > break; > case ACPI_TYPE_INTEGER: > - fwts_passed(fw, "Object _UID returned am integer 0x%8.8llx.", > - (unsigned long long)obj->Integer.Value); > + fwts_passed(fw, "Method _DDC could not return a buffer of %d items" > + "and instead returned an error status.", > + obj->Buffer.Length); > break; > default: > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType", > - "Method _UID did not return a string or an integer."); > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCBadReturnType", > + "Method _DDC did not return a buffer or an integer."); > fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > break; > } > } > > -static int method_test_UID(fwts_framework *fw) > -{ > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_UID", NULL, 0, method_test_UID_return, NULL); > -} > - > - > -/* Section 8.4 */ > - > -static void method_test_PSS_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) > +static int method_test_DDC(fwts_framework *fw) > { > - int i; > - bool failed = false; > - uint32_t max_freq = 0; > - uint32_t prev_power = 0; > - bool max_freq_valid = false; > - > - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > - return; > - > - /* Something is really wrong if we don't have any elements in _PSS */ > - if (obj->Package.Count < 1) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementCount", > - "_PSS should return package of at least 1 element, " > - "got %d elements instead.", > - obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - return; > - } > - > - for (i=0; i < obj->Package.Count; i++) { > - ACPI_OBJECT *pstate; > - > - if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementType", > - "_PSS package element %d was not a package.", i); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed = true; > - continue; /* Skip processing sub-package */ > - } > - > - pstate = &obj->Package.Elements[i]; > - if (pstate->Package.Count != 6) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementCount", > - "_PSS P-State sub-package %d was expected to have " > - "6 elements, got %d elements instead.", > - i, obj->Package.Count); > - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); > - failed = true; > - continue; /* Skip processing sub-package */ > - } > - > - /* Elements need to be all ACPI integer types */ > - if ((pstate->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || > - (pstate->Package.Elements[1].Type != ACPI_TYPE_INTEGER) || > - (pstate->Package.Elements[2].Type != ACPI_TYPE_INTEGER) || > - (pstate->Package.Elements[3].Type != ACPI_TYPE_INTEGER) || > - (pstate->Package.Elements[4].Type != ACPI_TYPE_INTEGER) || > - (pstate->Package.Elements[5].Type != ACPI_TYPE_INTEGER)) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementType", > - "_PSS P-State sub-package %d was expected to have " > - "6 Integer elements but didn't", i); > - failed = true; > - continue; > - } > - > - fwts_log_info(fw, "P-State %d: CPU %ld Mhz, %lu mW, latency %lu us, bus master latency %lu us.", > - i, > - (unsigned long)pstate->Package.Elements[0].Integer.Value, > - (unsigned long)pstate->Package.Elements[1].Integer.Value, > - (unsigned long)pstate->Package.Elements[2].Integer.Value, > - (unsigned long)pstate->Package.Elements[3].Integer.Value); > - > - /* > - * Collect maximum frequency. The sub-packages are sorted in > - * descending power dissipation order, so one would assume that > - * the highest frequency is first. However, it is not clear > - * from the ACPI spec that this is necessarily an assumption we > - * should make, so instead we should probably scan through all > - * the valid sub-packages and find the highest frequency. > - */ > - if (max_freq < pstate->Package.Elements[0].Integer.Value) { > - max_freq = pstate->Package.Elements[0].Integer.Value; > - max_freq_valid = true; > - } > + ACPI_OBJECT arg[1]; > + uint32_t i; > > - /* Sanity check descending power dissipation levels */ > - if ((i > 0) && (prev_power != 0) && > - (pstate->Package.Elements[1].Integer.Value > prev_power)) { > - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackagePowerNotDecending", > - "_PSS P-State sub-package %d has a larger power dissipation " > - "setting than the previous sub-package.", i); > - fwts_advice(fw, "_PSS P-States must be ordered in decending order of " > - "power dissipation, so that the zero'th entry has the highest " > - "power dissipation level and the Nth has the lowest."); > - failed = true; > - } > - prev_power = pstate->Package.Elements[1].Integer.Value; > - } > + for (i=128; i<=256; i <<= 1) { > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 128; > > - /* > - * Sanity check maximum frequency. We could also check the DMI data > - * for a BIOS date (but this can be wrong) or check the CPU identity > - * (which requires adding in new CPU identity checks) to make a decision > - * on when it is reasonable to assume a CPU is modern and hence clocked > - * incorrectly. For now, just flag up a low level error that the > - * frequency looks rather low rather than try to be intelligent (and > - * possibly make a mistake). I'd rather flag up a few false positives > - * on older machines than miss flagging up bad _PSS settings on new > - * machines. > - */ > - if (max_freq_valid && max_freq < 1000) { > - fwts_failed(fw, LOG_LEVEL_LOW, "Method_PSSSubPackageLowFreq", > - "Maximum CPU frequency is %dHz and this is low for " > - "a modern processor. This may indicate the _PSS P-States " > - "are incorrect\n", max_freq); > - fwts_advice(fw, > - "The _PSS P-States are used by the Linux CPU frequency " > - "driver to set the CPU frequencies according to system " > - "load. Sometimes the firmware sets these incorrectly " > - "and the machine runs at a sub-optimal speed. One can " > - "view the firmware defined CPU frequencies via " > - "/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies"); > - failed = true; > + if (method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DDC", arg, 1, method_test_DDC_return, &i) == FWTS_NOT_EXIST) > + break; > } > - > - if (!failed) > - fwts_passed(fw, "_PSS correctly returned sane looking package."); > + return FWTS_OK; > } > > -static int method_test_PSS(fwts_framework *fw) > +static int method_test_DCS(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSS", NULL, 0, method_test_PSS_return, NULL); > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DCS", NULL, 0, method_test_integer_return, NULL); > } > > -/* Section 5.6 */ > +static int method_test_DGS(fwts_framework *fw) > +{ > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DGS", NULL, 0, method_test_integer_return, NULL); > +} > > -static int method_test_AEI(fwts_framework *fw) > +static int method_test_DSS(fwts_framework *fw) > { > - return method_evaluate_method(fw, METHOD_OPTIONAL, "_AEI", NULL, 0, method_test_buffer_return, NULL); > + ACPI_OBJECT arg[1]; > + > + arg[0].Type = ACPI_TYPE_INTEGER; > + arg[0].Integer.Value = 0; > + > + return method_evaluate_method(fw, METHOD_OPTIONAL, > + "_DSS", arg, 1, method_test_NULL_return, NULL); > } > > -/* Tests */ > > +/* > + * Tests > + */ > static fwts_framework_minor_test method_tests[] = { > { method_name_check, "Check Method Names." }, > > -- > 1.7.10.4 > Acked-by: Keng-Yu Lin <kengyu@canonical.com>
diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c index afba21f..b706a56 100644 --- a/src/acpi/method/method.c +++ b/src/acpi/method/method.c @@ -261,6 +261,15 @@ static int method_test ## name(fwts_framework *fw) \ typedef void (*method_test_return)(fwts_framework *fw, char *name, ACPI_BUFFER *ret_buff, ACPI_OBJECT *ret_obj, void *private); + + + +/* + * Helper functions to facilitate the evaluations + */ + +/****************************************************************************/ + static int method_init(fwts_framework *fw) { fwts_acpi_table_info *info; @@ -492,591 +501,990 @@ static void method_test_passed_failed_return(fwts_framework *fw, char *name, ACP } } -/* Section 10.1.1.1 Smart Battery */ - -static void method_test_SBS_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_polling_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) { - static char *sbs_info[] = { - "Maximum 1 Smart Battery, system manager/selector not present", - "Maximum 1 Smart Battery, system manager/selector present", - "Maximum 2 Smart Batteries, system manager/selector present", - "Maximum 3 Smart Batteries, system manager/selector present", - "Maximum 4 Smart Batteries, system manager/selector present" - }; - if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { - switch (obj->Integer.Value) { - case 0 ... 4: - fwts_passed(fw, "_SBS correctly returned value %d %s", - (uint32_t)obj->Integer.Value, - sbs_info[obj->Integer.Value]); - break; - default: - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SBSReturn", "_SBS returned %d, should be between 0 and 4.", - (uint32_t)obj->Integer.Value); + char *method = (char *)private; + if (obj->Integer.Value < 36000) { + fwts_passed(fw, "%s correctly returned sane looking value %f seconds", + method, (float)obj->Integer.Value / 10.0); + } else { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodPollTimeTooLong", + "%s returned a value %f seconds > (1 hour) which is probably incorrect.", + method, (float)obj->Integer.Value / 10.0); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - fwts_advice(fw, "Smart Battery _SBS is incorrectly informing the OS about the smart battery " - "configuration. This is a bug and needs to be fixed."); - break; + fwts_advice(fw, "The method is returning a polling interval which is very long and hence " + "most probably incorrect."); } } } -static int method_test_SBS(fwts_framework *fw) +/****************************************************************************/ + +/* + * Section 5.6 ACPI Event Programming Model + */ +static int method_test_AEI(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_MOBILE, "_SBS", NULL, 0, method_test_SBS_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_AEI", NULL, 0, method_test_buffer_return, NULL); } +/* + * Section 6.1 Device Identification Objects + */ +static int method_test_SUN(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_SUN", NULL, 0, method_test_integer_return, NULL); +} -/* Section 10.2.2 Battery Control Methods */ +static void method_test_UID_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + if (obj == NULL){ + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); + return; + } + switch (obj->Type) { + case ACPI_TYPE_STRING: + if (obj->String.Pointer) + fwts_passed(fw, "Object _UID returned a string '%s' as expected.", + obj->String.Pointer); + else { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDNullString", + "Object _UID returned a NULL string."); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + } + break; + case ACPI_TYPE_INTEGER: + fwts_passed(fw, "Object _UID returned am integer 0x%8.8llx.", + (unsigned long long)obj->Integer.Value); + break; + default: + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType", + "Method _UID did not return a string or an integer."); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + break; + } +} -static void method_test_BIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static int method_test_UID(fwts_framework *fw) { - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { - int i; - int failed = 0; + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_UID", NULL, 0, method_test_UID_return, NULL); +} - fwts_method_dump_object(fw, obj); - if (obj->Package.Count != 13) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFElementCount", "_BIF package should return 13 elements, got %d instead.", - obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } +/* + * Section 6.2 Device Configurations Objects + */ +static int method_test_CRS(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MANDITORY, + "_CRS", NULL, 0, method_test_buffer_return, NULL); +} - for (i=0;(i<9) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type DWORD Integer.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } - for (i=9;(i<13) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type STRING.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } +static int method_test_DMA(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DMA", NULL, 0, method_test_buffer_return, NULL); +} - /* Sanity check each field */ - /* Power Unit */ - if (obj->Package.Elements[0].Integer.Value > 0x00000002) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadUnits", "_BIF: Expected Power Unit (Element 0) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", - (uint32_t)obj->Package.Elements[0].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#ifdef FWTS_METHOD_PEDANDTIC - /* - * Since this information may be evaluated by communicating with - * the EC we skip these checks as we can't do this from userspace - */ - /* Design Capacity */ - if (obj->Package.Elements[1].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFBadCapacity", "_BIF: Design Capacity (Element 1) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[1].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Last Full Charge Capacity */ - if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFChargeCapacity", "_BIF: Last Full Charge Capacity (Element 2) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[2].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#endif - /* Battery Technology */ - if (obj->Package.Elements[3].Integer.Value > 0x00000002) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBatTechUnit", "_BIF: Expected Battery Technology Unit (Element 3) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", - (uint32_t)obj->Package.Elements[3].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#ifdef FWTS_METHOD_PEDANDTIC - /* - * Since this information may be evaluated by communicating with - * the EC we skip these checks as we can't do this from userspace - */ - /* Design Voltage */ - if (obj->Package.Elements[4].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignVoltage", "_BIF: Design Voltage (Element 4) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[4].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Design capacity warning */ - if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE5", "_BIF: Design Capacity Warning (Element 5) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[5].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Design capacity low */ - if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE6", "_BIF: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[6].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#endif - if (failed) - fwts_advice(fw, "Battery _BIF package contains errors. It is worth running the " - "firmware test suite interactive 'battery' test to see if this " - "is problematic. This is a bug an needs to be fixed."); - else - fwts_passed(fw, "Battery _BIF package looks sane."); - } +static int method_test_DIS(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DIS", NULL, 0, method_test_NULL_return, NULL); } -static int method_test_BIF(fwts_framework *fw) +static int method_test_PXM(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_MOBILE, "_BIF", NULL, 0, method_test_BIF_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PXM", NULL, 0, method_test_integer_return, NULL); } -static void method_test_BIX_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) + +/* + * Section 6.3 Device Insertion, Removal and Status Objects + */ +static int method_test_EJD(fwts_framework *fw) { - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { - int i; - int failed = 0; + return method_evaluate_method(fw, METHOD_OPTIONAL, "_EJD", NULL, 0, method_test_string_return, NULL); +} - fwts_method_dump_object(fw, obj); +#define method_test_EJx(name) \ +static int method_test ## name(fwts_framework *fw) \ +{ \ + ACPI_OBJECT arg[1]; \ + \ + arg[0].Type = ACPI_TYPE_INTEGER; \ + arg[0].Integer.Value = 1; \ + \ + return method_evaluate_method(fw, METHOD_OPTIONAL, # name, arg, 1, method_test_NULL_return, # name); \ +} - if (obj->Package.Count != 16) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXElementCount", "_BIX package should return 16 elements, got %d instead.", - obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } +method_test_EJx(_EJ0) +method_test_EJx(_EJ1) +method_test_EJx(_EJ2) +method_test_EJx(_EJ3) +method_test_EJx(_EJ4) - for (i=0;(i<16) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type DWORD Integer.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } - for (i=16;(i<20) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type STRING.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } +static int method_test_LCK(fwts_framework *fw) +{ + ACPI_OBJECT arg[1]; - /* Sanity check each field */ - /* Power Unit */ - if (obj->Package.Elements[1].Integer.Value > 0x00000002) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXPowerUnit", - "_BIX: Expected Power Unit (Element 1) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", - (uint32_t)obj->Package.Elements[1].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#ifdef FWTS_METHOD_PEDANDTIC - /* - * Since this information may be evaluated by communicating with - * the EC we skip these checks as we can't do this from userspace - */ - /* Design Capacity */ - if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacity", - "_BIX: Design Capacity (Element 2) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[2].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Last Full Charge Capacity */ - if (obj->Package.Elements[3].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXFullChargeCapacity", - "_BIX: Last Full Charge Capacity (Element 3) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[3].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#endif - /* Battery Technology */ - if (obj->Package.Elements[4].Integer.Value > 0x00000002) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBatteryTechUnit", - "_BIX: Expected Battery Technology Unit (Element 4) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", - (uint32_t)obj->Package.Elements[4].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#ifdef FWTS_METHOD_PEDANDTIC - /* - * Since this information may be evaluated by communicating with - * the EC we skip these checks as we can't do this from userspace - */ - /* Design Voltage */ - if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignVoltage", - "_BIX: Design Voltage (Element 5) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[5].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Design capacity warning */ - if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE6", - "_BIX: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[6].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Design capacity low */ - if (obj->Package.Elements[7].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE7", - "_BIX: Design Capacity Warning (Element 7) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[7].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Cycle Count */ - if (obj->Package.Elements[10].Integer.Value > 0x7fffffff) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXCyleCount", - "_BIX: Cycle Count (Element 10) is unknown: 0x%8.8x.", - (uint32_t)obj->Package.Elements[10].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } -#endif - if (failed) - fwts_advice(fw, "Battery _BIX package contains errors. It is worth running the " - "firmware test suite interactive 'battery' test to see if this " - "is problematic. This is a bug an needs to be fixed."); - else - fwts_passed(fw, "Battery _BIX package looks sane."); - } -} - -static int method_test_BIX(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_MOBILE, "_BIX", NULL, 0, method_test_BIX_return, NULL); -} - -static int method_test_BMA(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = 1; - return method_evaluate_method(fw, METHOD_MOBILE, "_BMA", arg, 1, method_test_integer_return, NULL); -} -static int method_test_BMS(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; - return method_evaluate_method(fw, METHOD_MOBILE, "_BMS", arg, 1, method_test_integer_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, "_LCK", arg, 1, method_test_NULL_return, NULL); } -static void method_test_BST_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { - int i; - int failed = 0; - - fwts_method_dump_object(fw, obj); - - if (obj->Package.Count != 4) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTElementCount", "_BST package should return 4 elements, got %d instead.", - obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - - for (i=0;(i<4) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadType", - "_BST package element %d is not of type DWORD Integer.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } - /* Sanity check each field */ - /* Battery State */ - if ((obj->Package.Elements[0].Integer.Value) > 7) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", - "_BST: Expected Battery State (Element 0) to be 0..7, got 0x%8.8x.", - (uint32_t)obj->Package.Elements[0].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Ensure bits 0 (discharging) and 1 (charging) are not both set, see 10.2.2.6 */ - if (((obj->Package.Elements[0].Integer.Value) & 3) == 3) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", - "_BST: Battery State (Element 0) is indicating both charging " - "and discharginng which is not allowed. Got value 0x%8.8x.", - (uint32_t)obj->Package.Elements[0].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - /* Battery Present Rate - cannot check, pulled from EC */ - /* Battery Remaining Capacity - cannot check, pulled from EC */ - /* Battery Present Voltage - cannot check, pulled from EC */ - if (failed) - fwts_advice(fw, "Battery _BST package contains errors. It is worth running the " - "firmware test suite interactive 'battery' test to see if this " - "is problematic. This is a bug an needs to be fixed."); - else - fwts_passed(fw, "Battery _BST package looks sane."); - } +/* + * Section 6.5 Other Objects and Controls + */ +static int method_test_BBN(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, "_BBN", + NULL, 0, method_test_integer_return, "_BBN"); } -static int method_test_BST(fwts_framework *fw) +static int method_test_BDN(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_MOBILE, "_BST", NULL, 0, method_test_BST_return, NULL); + return method_evaluate_method(fw, METHOD_MOBILE, "_BDN", + NULL, 0, method_test_integer_return, "_BDN"); } -static int method_test_BTP(fwts_framework *fw) +static int method_test_DCK(fwts_framework *fw) { - static int values[] = { 0, 1, 100, 200, 0x7fffffff }; int i; - for (i=0;i<5;i++) { + for (i=0;i<=1;i++) { /* Undock, Dock */ ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = values[i]; - if (method_evaluate_method(fw, METHOD_MOBILE, "_BTP", arg, 1, - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + arg[0].Integer.Value = i; + if (method_evaluate_method(fw, METHOD_MOBILE, "_DCK", arg, 1, method_test_passed_failed_return, "_DCK") != FWTS_OK) break; fwts_log_nl(fw); } return FWTS_OK; } -static void method_test_PCL_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - /* FIXME */ -} -static int method_test_PCL(fwts_framework *fw) +/* + * Section 7.1 Declaring a Power Resource Object + */ +static int method_test_ON(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_MOBILE, "_PCL", NULL, 0, method_test_PCL_return, "_PCL"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_ON", NULL, 0, method_test_NULL_return, NULL); } -static int method_test_BTM(fwts_framework *fw) +static int method_test_OFF(fwts_framework *fw) { - static int values[] = { 0, 1, 100, 200, 0x7fffffff }; - int i; - - for (i=0;i<5;i++) { - ACPI_OBJECT arg[1]; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = values[i]; - if (method_evaluate_method(fw, METHOD_MOBILE, "_BTM", arg, 1, - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) - break; - fwts_log_nl(fw); - } - return FWTS_OK; + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_OFF", NULL, 0, method_test_NULL_return, NULL); } -static void method_test_BMD_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) + +/* + * Section 7.2 Device Power Management Objects + */ +static int method_test_DSW(fwts_framework *fw) { - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { - int i; - int failed = 0; + ACPI_OBJECT arg[3]; - fwts_method_dump_object(fw, obj); + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; + arg[1].Type = ACPI_TYPE_INTEGER; + arg[1].Integer.Value = 0; + arg[2].Type = ACPI_TYPE_INTEGER; + arg[2].Integer.Value = 3; - if (obj->Package.Count != 5) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDElementCount", "_BMD package should return 4 elements, got %d instead.", - obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } + return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSW", + arg, 3, method_test_NULL_return, NULL); +} - for (i=0;(i<4) && (i<obj->Package.Count);i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDBadType", "_BMD package element %d is not of type DWORD Integer.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - } - /* TODO: check return values */ - } +#define method_test_PSx(name) \ +static int method_test ## name(fwts_framework *fw) \ +{ \ + return method_evaluate_method(fw, METHOD_OPTIONAL, \ + # name, NULL, 0, method_test_NULL_return, # name); \ } -static int method_test_BMD(fwts_framework *fw) +method_test_PSx(_PS0) +method_test_PSx(_PS1) +method_test_PSx(_PS2) +method_test_PSx(_PS3) + +static int method_test_PSC(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_MOBILE, "_BMD", NULL, 0, method_test_BMD_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PSC", NULL, 0, method_test_integer_return, NULL); } -static int method_test_BMC(fwts_framework *fw) +static int method_test_PSE(fwts_framework *fw) { - static int values[] = { 0, 1, 2, 4 }; - int i; + ACPI_OBJECT arg[1]; - for (i=0;i<4;i++) { - ACPI_OBJECT arg[1]; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = values[i]; - if (method_evaluate_method(fw, METHOD_MOBILE, "_BMC", arg, 1, - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) - break; - fwts_log_nl(fw); - } - return FWTS_OK; -} + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; -/* Section 15, Waking and Sleeping */ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PSE", arg, 1, method_test_NULL_return, NULL); +} -static int method_test_PTS(fwts_framework *fw) +static void method_test_PRE_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { int i; - for (i=1; i<6; i++) { - ACPI_OBJECT arg[1]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = i; - - fwts_log_info(fw, "Test _PTS(%d).", i); + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) + return; - if (method_evaluate_method(fw, METHOD_MANDITORY, "_PTS", arg, 1, - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) { - fwts_advice(fw, "Could not find _PTS. This method provides a mechanism to " - "do housekeeping functions, such as write sleep state to the " - "embedded controller before entering a sleep state. If the " - "machine cannot suspend (S3), hibernate (S4) or shutdown (S5) " - "then it could be because _PTS is missing."); - break; + /* All elements in the package must be references */ + for (i=0; i < obj->Package.Count; i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_LOCAL_REFERENCE) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PREElementType", + "_PRE package element %d was not a reference.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); } - fwts_log_nl(fw); } - return FWTS_OK; } -static int method_test_TTS(fwts_framework *fw) +static int method_test_PRE(fwts_framework *fw) { - int i; + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PRE", NULL, 0, method_test_PRE_return, NULL); +} - if (fwts_method_exists("_BFS") != NULL) { - for (i=1; i<6; i++) { - ACPI_OBJECT arg[1]; +static int method_test_PSW(fwts_framework *fw) +{ + ACPI_OBJECT arg[1]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PSW", arg, 1, method_test_NULL_return, NULL); +} + +static int method_test_IRC(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_IRC", NULL, 0, method_test_NULL_return, NULL); +} + + +/* + * Section 8.4 Declaring Processors + */ +static void method_test_PSS_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + int i; + bool failed = false; + uint32_t max_freq = 0; + uint32_t prev_power = 0; + bool max_freq_valid = false; + + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) + return; + + /* Something is really wrong if we don't have any elements in _PSS */ + if (obj->Package.Count < 1) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementCount", + "_PSS should return package of at least 1 element, " + "got %d elements instead.", + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + return; + } + + for (i=0; i < obj->Package.Count; i++) { + ACPI_OBJECT *pstate; + + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementType", + "_PSS package element %d was not a package.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed = true; + continue; /* Skip processing sub-package */ + } + + pstate = &obj->Package.Elements[i]; + if (pstate->Package.Count != 6) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementCount", + "_PSS P-State sub-package %d was expected to have " + "6 elements, got %d elements instead.", + i, obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed = true; + continue; /* Skip processing sub-package */ + } + + /* Elements need to be all ACPI integer types */ + if ((pstate->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || + (pstate->Package.Elements[1].Type != ACPI_TYPE_INTEGER) || + (pstate->Package.Elements[2].Type != ACPI_TYPE_INTEGER) || + (pstate->Package.Elements[3].Type != ACPI_TYPE_INTEGER) || + (pstate->Package.Elements[4].Type != ACPI_TYPE_INTEGER) || + (pstate->Package.Elements[5].Type != ACPI_TYPE_INTEGER)) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementType", + "_PSS P-State sub-package %d was expected to have " + "6 Integer elements but didn't", i); + failed = true; + continue; + } + + fwts_log_info(fw, "P-State %d: CPU %ld Mhz, %lu mW, latency %lu us, bus master latency %lu us.", + i, + (unsigned long)pstate->Package.Elements[0].Integer.Value, + (unsigned long)pstate->Package.Elements[1].Integer.Value, + (unsigned long)pstate->Package.Elements[2].Integer.Value, + (unsigned long)pstate->Package.Elements[3].Integer.Value); + + /* + * Collect maximum frequency. The sub-packages are sorted in + * descending power dissipation order, so one would assume that + * the highest frequency is first. However, it is not clear + * from the ACPI spec that this is necessarily an assumption we + * should make, so instead we should probably scan through all + * the valid sub-packages and find the highest frequency. + */ + if (max_freq < pstate->Package.Elements[0].Integer.Value) { + max_freq = pstate->Package.Elements[0].Integer.Value; + max_freq_valid = true; + } + + /* Sanity check descending power dissipation levels */ + if ((i > 0) && (prev_power != 0) && + (pstate->Package.Elements[1].Integer.Value > prev_power)) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackagePowerNotDecending", + "_PSS P-State sub-package %d has a larger power dissipation " + "setting than the previous sub-package.", i); + fwts_advice(fw, "_PSS P-States must be ordered in decending order of " + "power dissipation, so that the zero'th entry has the highest " + "power dissipation level and the Nth has the lowest."); + failed = true; + } + prev_power = pstate->Package.Elements[1].Integer.Value; + } + + /* + * Sanity check maximum frequency. We could also check the DMI data + * for a BIOS date (but this can be wrong) or check the CPU identity + * (which requires adding in new CPU identity checks) to make a decision + * on when it is reasonable to assume a CPU is modern and hence clocked + * incorrectly. For now, just flag up a low level error that the + * frequency looks rather low rather than try to be intelligent (and + * possibly make a mistake). I'd rather flag up a few false positives + * on older machines than miss flagging up bad _PSS settings on new + * machines. + */ + if (max_freq_valid && max_freq < 1000) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_PSSSubPackageLowFreq", + "Maximum CPU frequency is %dHz and this is low for " + "a modern processor. This may indicate the _PSS P-States " + "are incorrect\n", max_freq); + fwts_advice(fw, + "The _PSS P-States are used by the Linux CPU frequency " + "driver to set the CPU frequencies according to system " + "load. Sometimes the firmware sets these incorrectly " + "and the machine runs at a sub-optimal speed. One can " + "view the firmware defined CPU frequencies via " + "/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies"); + failed = true; + } + + if (!failed) + fwts_passed(fw, "_PSS correctly returned sane looking package."); +} + +static int method_test_PSS(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSS", NULL, 0, method_test_PSS_return, NULL); +} + + +/* + * Section 9.2 Ambient Light Sensor Device + */ +method_test_integer(_ALC, METHOD_OPTIONAL) +method_test_integer(_ALI, METHOD_OPTIONAL) +method_test_integer(_ALT, METHOD_OPTIONAL) + +/* TODO _ALR */ + +static int method_test_ALP(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_ALP", NULL, 0, method_test_polling_return, "_ALP"); +} + + +/* + * Section 9.4 Lid control + */ +static void method_test_LID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +{ + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) + fwts_passed(fw, "_LID correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); +} + +static int method_test_LID(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_LID", NULL, 0, method_test_LID_return, NULL); +} + + +/* + * Section 9.18 Wake Alarm Device + */ +static int method_test_STP(fwts_framework *fw) +{ + ACPI_OBJECT arg[2]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; /* DC timer */ + arg[1].Type = ACPI_TYPE_INTEGER; + arg[1].Integer.Value = 0; /* wake up instantly */ + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_STP", arg, 2, method_test_passed_failed_return, "_STP"); +} + +static int method_test_STV(fwts_framework *fw) +{ + ACPI_OBJECT arg[2]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; /* DC timer */ + arg[1].Type = ACPI_TYPE_INTEGER; + arg[1].Integer.Value = 100; /* timer value */ + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_STV", arg, 2, method_test_passed_failed_return, "_STV"); +} + +static int method_test_TIP(fwts_framework *fw) +{ + ACPI_OBJECT arg[1]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; /* DC timer */ + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TIP", arg, 1, method_test_integer_return, NULL); +} + +static int method_test_TIV(fwts_framework *fw) +{ + ACPI_OBJECT arg[1]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; /* DC timer */ + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TIV", arg, 1, method_test_integer_return, NULL); +} + + +/* + * Section 10.1 Smart Battery + */ +static void method_test_SBS_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + static char *sbs_info[] = { + "Maximum 1 Smart Battery, system manager/selector not present", + "Maximum 1 Smart Battery, system manager/selector present", + "Maximum 2 Smart Batteries, system manager/selector present", + "Maximum 3 Smart Batteries, system manager/selector present", + "Maximum 4 Smart Batteries, system manager/selector present" + }; + + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { + switch (obj->Integer.Value) { + case 0 ... 4: + fwts_passed(fw, "_SBS correctly returned value %d %s", + (uint32_t)obj->Integer.Value, + sbs_info[obj->Integer.Value]); + break; + default: + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SBSReturn", "_SBS returned %d, should be between 0 and 4.", + (uint32_t)obj->Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + fwts_advice(fw, "Smart Battery _SBS is incorrectly informing the OS about the smart battery " + "configuration. This is a bug and needs to be fixed."); + break; + } + } +} + +static int method_test_SBS(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_SBS", NULL, 0, method_test_SBS_return, NULL); +} + + +/* + * Section 10.2 Battery Control Methods + */ +static void method_test_BIF_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + int i; + int failed = 0; + + fwts_method_dump_object(fw, obj); + + if (obj->Package.Count != 13) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFElementCount", "_BIF package should return 13 elements, got %d instead.", + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + } + + for (i=0;(i<9) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type DWORD Integer.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + } + for (i=9;(i<13) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadType", "_BIF package element %d is not of type STRING.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + } + + /* Sanity check each field */ + /* Power Unit */ + if (obj->Package.Elements[0].Integer.Value > 0x00000002) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBadUnits", "_BIF: Expected Power Unit (Element 0) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", + (uint32_t)obj->Package.Elements[0].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#ifdef FWTS_METHOD_PEDANDTIC + /* + * Since this information may be evaluated by communicating with + * the EC we skip these checks as we can't do this from userspace + */ + /* Design Capacity */ + if (obj->Package.Elements[1].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFBadCapacity", "_BIF: Design Capacity (Element 1) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[1].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Last Full Charge Capacity */ + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFChargeCapacity", "_BIF: Last Full Charge Capacity (Element 2) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[2].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#endif + /* Battery Technology */ + if (obj->Package.Elements[3].Integer.Value > 0x00000002) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIFBatTechUnit", "_BIF: Expected Battery Technology Unit (Element 3) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", + (uint32_t)obj->Package.Elements[3].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#ifdef FWTS_METHOD_PEDANDTIC + /* + * Since this information may be evaluated by communicating with + * the EC we skip these checks as we can't do this from userspace + */ + /* Design Voltage */ + if (obj->Package.Elements[4].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignVoltage", "_BIF: Design Voltage (Element 4) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[4].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Design capacity warning */ + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE5", "_BIF: Design Capacity Warning (Element 5) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[5].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Design capacity low */ + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIFDesignCapacityE6", "_BIF: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[6].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#endif + if (failed) + fwts_advice(fw, "Battery _BIF package contains errors. It is worth running the " + "firmware test suite interactive 'battery' test to see if this " + "is problematic. This is a bug an needs to be fixed."); + else + fwts_passed(fw, "Battery _BIF package looks sane."); + } +} - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = i; +static int method_test_BIF(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_BIF", NULL, 0, method_test_BIF_return, NULL); +} - fwts_log_info(fw, "Test _TTS(%d) Transition To State S%d.", i, i); +static void method_test_BIX_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + int i; + int failed = 0; - if (method_evaluate_method(fw, METHOD_MANDITORY, "_TTS", arg, 1, - method_test_NULL_return, NULL) == FWTS_NOT_EXIST) - break; - fwts_log_nl(fw); + fwts_method_dump_object(fw, obj); + + if (obj->Package.Count != 16) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXElementCount", "_BIX package should return 16 elements, got %d instead.", + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; } + + for (i=0;(i<16) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type DWORD Integer.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + } + for (i=16;(i<20) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_STRING) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBadType", "_BIX package element %d is not of type STRING.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + } + + /* Sanity check each field */ + /* Power Unit */ + if (obj->Package.Elements[1].Integer.Value > 0x00000002) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXPowerUnit", + "_BIX: Expected Power Unit (Element 1) to be 0 (mWh) or 1 (mAh), got 0x%8.8x.", + (uint32_t)obj->Package.Elements[1].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#ifdef FWTS_METHOD_PEDANDTIC + /* + * Since this information may be evaluated by communicating with + * the EC we skip these checks as we can't do this from userspace + */ + /* Design Capacity */ + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacity", + "_BIX: Design Capacity (Element 2) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[2].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Last Full Charge Capacity */ + if (obj->Package.Elements[3].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXFullChargeCapacity", + "_BIX: Last Full Charge Capacity (Element 3) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[3].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#endif + /* Battery Technology */ + if (obj->Package.Elements[4].Integer.Value > 0x00000002) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BIXBatteryTechUnit", + "_BIX: Expected Battery Technology Unit (Element 4) to be 0 (Primary) or 1 (Secondary), got 0x%8.8x.", + (uint32_t)obj->Package.Elements[4].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#ifdef FWTS_METHOD_PEDANDTIC + /* + * Since this information may be evaluated by communicating with + * the EC we skip these checks as we can't do this from userspace + */ + /* Design Voltage */ + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignVoltage", + "_BIX: Design Voltage (Element 5) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[5].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Design capacity warning */ + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE6", + "_BIX: Design Capacity Warning (Element 6) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[6].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Design capacity low */ + if (obj->Package.Elements[7].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXDesignCapacityE7", + "_BIX: Design Capacity Warning (Element 7) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[7].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Cycle Count */ + if (obj->Package.Elements[10].Integer.Value > 0x7fffffff) { + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXCyleCount", + "_BIX: Cycle Count (Element 10) is unknown: 0x%8.8x.", + (uint32_t)obj->Package.Elements[10].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } +#endif + if (failed) + fwts_advice(fw, "Battery _BIX package contains errors. It is worth running the " + "firmware test suite interactive 'battery' test to see if this " + "is problematic. This is a bug an needs to be fixed."); + else + fwts_passed(fw, "Battery _BIX package looks sane."); } - else { - fwts_skipped(fw, "Optional control method _TTS does not exist."); - } - return FWTS_OK; } -static void method_test_Sx_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static int method_test_BIX(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_BIX", NULL, 0, method_test_BIX_return, NULL); +} + +static int method_test_BMA(fwts_framework *fw) { - char *method = (char *)private; + ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; + + return method_evaluate_method(fw, METHOD_MOBILE, + "_BMA", arg, 1, method_test_integer_return, NULL); +} + +static int method_test_BMS(fwts_framework *fw) +{ + ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 1; + return method_evaluate_method(fw, METHOD_MOBILE, + "_BMS", arg, 1, method_test_integer_return, NULL); +} + +static void method_test_BST_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + int i; + int failed = 0; + fwts_method_dump_object(fw, obj); - if (obj->Package.Count != 3) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SElementCount", "%s should return package of 3 integers, got %d elements instead.", method, + if (obj->Package.Count != 4) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTElementCount", "_BST package should return 4 elements, got %d instead.", obj->Package.Count); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + + for (i=0;(i<4) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadType", + "_BST package element %d is not of type DWORD Integer.", i); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + } + + /* Sanity check each field */ + /* Battery State */ + if ((obj->Package.Elements[0].Integer.Value) > 7) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", + "_BST: Expected Battery State (Element 0) to be 0..7, got 0x%8.8x.", + (uint32_t)obj->Package.Elements[0].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + /* Ensure bits 0 (discharging) and 1 (charging) are not both set, see 10.2.2.6 */ + if (((obj->Package.Elements[0].Integer.Value) & 3) == 3) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BSTBadState", + "_BST: Battery State (Element 0) is indicating both charging " + "and discharginng which is not allowed. Got value 0x%8.8x.", + (uint32_t)obj->Package.Elements[0].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; } + /* Battery Present Rate - cannot check, pulled from EC */ + /* Battery Remaining Capacity - cannot check, pulled from EC */ + /* Battery Present Voltage - cannot check, pulled from EC */ + if (failed) + fwts_advice(fw, "Battery _BST package contains errors. It is worth running the " + "firmware test suite interactive 'battery' test to see if this " + "is problematic. This is a bug an needs to be fixed."); + else + fwts_passed(fw, "Battery _BST package looks sane."); } } -#define method_test_Sx(name) \ -static int method_test ## name(fwts_framework *fw) \ -{ \ - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, NULL, 0, method_test_Sx_return, # name); \ +static int method_test_BST(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_BST", NULL, 0, method_test_BST_return, NULL); +} + +static int method_test_BTP(fwts_framework *fw) +{ + static int values[] = { 0, 1, 100, 200, 0x7fffffff }; + int i; + + for (i=0;i<5;i++) { + ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = values[i]; + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTP", arg, 1, + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + break; + fwts_log_nl(fw); + } + return FWTS_OK; +} + +static void method_test_PCL_return(fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + /* FIXME */ +} + +static int method_test_PCL(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_MOBILE, + "_PCL", NULL, 0, method_test_PCL_return, "_PCL"); +} + +static int method_test_BTM(fwts_framework *fw) +{ + static int values[] = { 0, 1, 100, 200, 0x7fffffff }; + int i; + + for (i=0;i<5;i++) { + ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = values[i]; + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTM", arg, 1, + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + break; + fwts_log_nl(fw); + } + return FWTS_OK; } -method_test_Sx(_S0) -method_test_Sx(_S1) -method_test_Sx(_S2) -method_test_Sx(_S3) -method_test_Sx(_S4) -method_test_Sx(_S5) - -static void method_test_WAK_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_BMD_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { - uint32_t Sstate = *(uint32_t*)private; - int failed = 0; - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + int i; + int failed = 0; + fwts_method_dump_object(fw, obj); - if (obj->Package.Count != 2) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKElementCount", "_WAK should return package of 2 integers, got %d elements instead.", + if (obj->Package.Count != 5) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDElementCount", "_BMD package should return 4 elements, got %d instead.", obj->Package.Count); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); failed++; - } else { - if ((obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || - (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBadType", "_WAK should return package of 2 integers, got %d instead.", - obj->Package.Count); + } + + for (i=0;(i<4) && (i<obj->Package.Count);i++) { + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BMDBadType", "_BMD package element %d is not of type DWORD Integer.", i); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); failed++; } - else { - if (obj->Package.Elements[0].Integer.Value > 0x00000002) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBitField", - "_WAK: expecting condition bit-field (element 0) of packages to be in range, got 0x%8.8x.", - (uint32_t)obj->Package.Elements[0].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - if (!( - ((obj->Package.Elements[1].Integer.Value == Sstate) && (obj->Package.Elements[0].Integer.Value == 0)) || - ((obj->Package.Elements[1].Integer.Value == 0) && (obj->Package.Elements[0].Integer.Value != 0)) )) { - fwts_warning(fw, - "_WAK: expecting power supply S-state (element 1) of packages to be 0x%8.8x, got 0x%8.8x.", - Sstate, (uint32_t)obj->Package.Elements[0].Integer.Value); - fwts_advice(fw, "_WAK should return 0 if the wake failed and was unsuccessful (i.e. element[0] " - "is non-zero) OR should return the S-state. " - "This can confuse the operating system as this _WAK return indicates that the " - "S-state was not entered because of too much current being drawn from the " - "power supply, however, the BIOS may have actually entered this state and the " - "_WAK method is misinforming the operating system. Currently Linux does not " - "check for the return type from _WAK, so it should theoretically not affect the " - "operation of suspend/resume."); - - failed++; - } - } } - if (!failed) - fwts_passed(fw, "_WAK correctly returned sane looking package."); + /* TODO: check return values */ } } -static int method_test_WAK(fwts_framework *fw) +static int method_test_BMD(fwts_framework *fw) { - uint32_t i; + return method_evaluate_method(fw, METHOD_MOBILE, + "_BMD", NULL, 0, method_test_BMD_return, NULL); +} - for (i=1; i<6; i++) { +static int method_test_BMC(fwts_framework *fw) +{ + static int values[] = { 0, 1, 2, 4 }; + int i; + + for (i=0;i<4;i++) { ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = i; - fwts_log_info(fw, "Test _WAK(%d) System Wake, State S%d.", i, i); - if (method_evaluate_method(fw, METHOD_MANDITORY, "_WAK", arg, 1, - method_test_WAK_return, &i) == FWTS_NOT_EXIST) + arg[0].Integer.Value = values[i]; + if (method_evaluate_method(fw, METHOD_MOBILE, "_BMC", arg, 1, + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) break; fwts_log_nl(fw); } return FWTS_OK; } -/* Section 10.3 AC Adapters and Power Sources Objects */ -static void method_test_PSR_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +/* + * Section 10.3 AC Adapters and Power Sources Objects + */ +static void method_test_PSR_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { if (obj->Integer.Value > 2) { @@ -1090,12 +1498,17 @@ static void method_test_PSR_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_PSR(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSR", NULL, 0, method_test_PSR_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PSR", NULL, 0, method_test_PSR_return, NULL); } -static void method_test_PIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_PIF_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { fwts_method_dump_object(fw, obj); @@ -1123,26 +1536,20 @@ static void method_test_PIF_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_PIF(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PIF", NULL, 0, method_test_PIF_return, NULL); -} - - -/* Section 9.4.1 Lid control */ - -static void method_test_LID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) - fwts_passed(fw, "_LID correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); -} - -static int method_test_LID(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_MOBILE, "_LID", NULL, 0, method_test_LID_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_PIF", NULL, 0, method_test_PIF_return, NULL); } -/* Section 11.3 Fan Devices */ -static void method_test_FIF_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +/* + * Section 11.3 Fan Devices + */ +static void method_test_FIF_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { fwts_method_dump_object(fw, obj); @@ -1172,7 +1579,8 @@ static void method_test_FIF_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_FIF(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FIF", NULL, 0, method_test_FIF_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_FIF", NULL, 0, method_test_FIF_return, NULL); } static int method_test_FSL(fwts_framework *fw) @@ -1181,7 +1589,8 @@ static int method_test_FSL(fwts_framework *fw) arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = 50; - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FSL", arg, 1, method_test_NULL_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_FSL", arg, 1, method_test_NULL_return, NULL); } static void method_test_FST_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) @@ -1213,22 +1622,30 @@ static void method_test_FST_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_FST(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_FST", NULL, 0, method_test_FST_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_FST", NULL, 0, method_test_FST_return, NULL); } -/* Section 11.4 Thermal */ -static void method_test_THERM_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +/* + * Section 11.4 Thermal + */ +static void method_test_THERM_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { char *method = (char*)private; - + if (fwts_acpi_region_handler_called_get()) { /* * We accessed some memory or I/O region during the evaluation * which returns spoofed values, so we should not test the value * being returned. In this case, just pass this as a valid - * return type. + * return type. */ fwts_passed(fw, "%s correctly returned sane looking return type.", name); } else { @@ -1267,7 +1684,8 @@ static void method_test_THERM_return(fwts_framework *fw, char *name, ACPI_BUFFER static int method_test ## name(fwts_framework *fw) \ { \ fwts_acpi_region_handler_called_set(false); \ - return method_evaluate_method(fw, type, # name, NULL, 0, method_test_THERM_return, # name); \ + return method_evaluate_method(fw, type, # name, \ + NULL, 0, method_test_THERM_return, # name); \ } method_test_THERM(_CRT, METHOD_OPTIONAL) @@ -1277,7 +1695,18 @@ method_test_THERM(_NTT, METHOD_OPTIONAL) method_test_THERM(_PSV, METHOD_OPTIONAL) method_test_THERM(_TST, METHOD_OPTIONAL) -static void method_test_TCx_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static int method_test_TSP(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TSP", NULL, 0, method_test_polling_return, "_TSP"); +} + +static void method_test_TCx_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { char *method = (char *)private; @@ -1287,12 +1716,14 @@ static void method_test_TCx_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_TC1(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TC1", NULL, 0, method_test_TCx_return, "_TC1"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TC1", NULL, 0, method_test_TCx_return, "_TC1"); } static int method_test_TC2(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TC2", NULL, 0, method_test_TCx_return, "_TC1"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TC2", NULL, 0, method_test_TCx_return, "_TC1"); } static int method_test_ACx(fwts_framework *fw) @@ -1302,7 +1733,8 @@ static int method_test_ACx(fwts_framework *fw) for (i=0;i<10;i++) { char buffer[5]; snprintf(buffer, sizeof(buffer), "AC%d", i); - method_evaluate_method(fw, METHOD_OPTIONAL, buffer, NULL, 0, method_test_THERM_return, buffer); + method_evaluate_method(fw, METHOD_OPTIONAL, + buffer, NULL, 0, method_test_THERM_return, buffer); fwts_log_nl(fw); } return FWTS_OK; @@ -1313,7 +1745,9 @@ static int method_test_DTI(fwts_framework *fw) ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = 2732 + 800; /* 80 degrees C */ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL); + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DTI", arg, 1, method_test_NULL_return, NULL); } static int method_test_SCP(fwts_framework *fw) @@ -1329,7 +1763,9 @@ static int method_test_SCP(fwts_framework *fw) arg[1].Integer.Value = 5; /* Acoustic limit */ arg[2].Type = ACPI_TYPE_INTEGER; arg[2].Integer.Value = 5; /* Power limit */ - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + + if (method_evaluate_method(fw, METHOD_OPTIONAL, + "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) break; fwts_log_nl(fw); @@ -1339,14 +1775,20 @@ static int method_test_SCP(fwts_framework *fw) arg[1].Integer.Value = 1; /* Acoustic limit */ arg[2].Type = ACPI_TYPE_INTEGER; arg[2].Integer.Value = 1; /* Power limit */ - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + + if (method_evaluate_method(fw, METHOD_OPTIONAL, + "_DTI", arg, 1, method_test_NULL_return, NULL) == FWTS_NOT_EXIST) break; } return FWTS_OK; } - -static void method_test_RTV_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_RTV_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) fwts_passed(fw, "_RTV correctly returned sane looking value 0x%8.8x", (uint32_t)obj->Integer.Value); @@ -1354,7 +1796,8 @@ static void method_test_RTV_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_RTV(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_RTV", NULL, 0, method_test_RTV_return, "_RTV"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_RTV", NULL, 0, method_test_RTV_return, "_RTV"); } static int method_test_TPT(fwts_framework *fw) @@ -1362,139 +1805,206 @@ static int method_test_TPT(fwts_framework *fw) ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = 2732 + 900; /* 90 degrees C */ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TPT", arg, 1, method_test_NULL_return, NULL); -} - -static void method_test_polling_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) { - char *method = (char *)private; - if (obj->Integer.Value < 36000) { - fwts_passed(fw, "%s correctly returned sane looking value %f seconds", - method, (float)obj->Integer.Value / 10.0); - } else { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodPollTimeTooLong", - "%s returned a value %f seconds > (1 hour) which is probably incorrect.", - method, (float)obj->Integer.Value / 10.0); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - fwts_advice(fw, "The method is returning a polling interval which is very long and hence " - "most probably incorrect."); - } - } -} -static int method_test_TSP(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TSP", NULL, 0, method_test_polling_return, "_TSP"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TPT", arg, 1, method_test_NULL_return, NULL); } static int method_test_TZP(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TZP", NULL, 0, method_test_polling_return, "_TZP"); -} - -/* Section 9.2, Ambient Light Sensor Device */ - -method_test_integer(_ALC, METHOD_OPTIONAL) -method_test_integer(_ALI, METHOD_OPTIONAL) -method_test_integer(_ALT, METHOD_OPTIONAL) - -/* TODO _ALR */ - -static int method_test_ALP(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ALP", NULL, 0, method_test_polling_return, "_ALP"); -} - - -/* Section 6.5 Other Objects and Control Methods */ - -static int method_test_BBN(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BBN", NULL, 0, method_test_integer_return, "_BBN"); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_TZP", NULL, 0, method_test_polling_return, "_TZP"); } -static int method_test_BDN(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_MOBILE, "_BDN", NULL, 0, method_test_integer_return, "_BDN"); -} -static int method_test_DCK(fwts_framework *fw) +/* + * Section 16 Waking and Sleeping + */ +static int method_test_PTS(fwts_framework *fw) { int i; - for (i=0;i<=1;i++) { /* Undock, Dock */ + for (i=1; i<6; i++) { ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = i; - if (method_evaluate_method(fw, METHOD_MOBILE, "_DCK", arg, 1, method_test_passed_failed_return, "_DCK") != FWTS_OK) + + fwts_log_info(fw, "Test _PTS(%d).", i); + + if (method_evaluate_method(fw, METHOD_MANDITORY, "_PTS", arg, 1, + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) { + fwts_advice(fw, "Could not find _PTS. This method provides a mechanism to " + "do housekeeping functions, such as write sleep state to the " + "embedded controller before entering a sleep state. If the " + "machine cannot suspend (S3), hibernate (S4) or shutdown (S5) " + "then it could be because _PTS is missing."); break; + } fwts_log_nl(fw); } return FWTS_OK; } -/* Section 9.18 Wake Alarm Device */ +static int method_test_TTS(fwts_framework *fw) +{ + int i; + if (fwts_method_exists("_BFS") != NULL) { + for (i=1; i<6; i++) { + ACPI_OBJECT arg[1]; -static int method_test_STP(fwts_framework *fw) -{ - ACPI_OBJECT arg[2]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = i; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; /* DC timer */ - arg[1].Type = ACPI_TYPE_INTEGER; - arg[1].Integer.Value = 0; /* wake up instantly */ + fwts_log_info(fw, "Test _TTS(%d) Transition To State S%d.", i, i); - return method_evaluate_method(fw, METHOD_OPTIONAL, "_STP", arg, 2, method_test_passed_failed_return, "_STP"); + if (method_evaluate_method(fw, METHOD_MANDITORY, "_TTS", arg, 1, + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) + break; + fwts_log_nl(fw); + } + } + else { + fwts_skipped(fw, "Optional control method _TTS does not exist."); + } + return FWTS_OK; } -static int method_test_STV(fwts_framework *fw) +static void method_test_Sx_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { - ACPI_OBJECT arg[2]; + char *method = (char *)private; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; /* DC timer */ - arg[1].Type = ACPI_TYPE_INTEGER; - arg[1].Integer.Value = 100; /* timer value */ + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + fwts_method_dump_object(fw, obj); + + if (obj->Package.Count != 3) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SElementCount", "%s should return package of 3 integers, got %d elements instead.", method, + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + } + } +} - return method_evaluate_method(fw, METHOD_OPTIONAL, "_STV", arg, 2, method_test_passed_failed_return, "_STV"); +#define method_test_Sx(name) \ +static int method_test ## name(fwts_framework *fw) \ +{ \ + return method_evaluate_method(fw, METHOD_OPTIONAL, \ + # name, NULL, 0, method_test_Sx_return, # name);\ } -static int method_test_TIP(fwts_framework *fw) +method_test_Sx(_S0) +method_test_Sx(_S1) +method_test_Sx(_S2) +method_test_Sx(_S3) +method_test_Sx(_S4) +method_test_Sx(_S5) + +static void method_test_WAK_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { - ACPI_OBJECT arg[1]; + uint32_t Sstate = *(uint32_t*)private; + int failed = 0; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; /* DC timer */ + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { + fwts_method_dump_object(fw, obj); + + if (obj->Package.Count != 2) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKElementCount", "_WAK should return package of 2 integers, got %d elements instead.", + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } else { + if ((obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || + (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBadType", "_WAK should return package of 2 integers, got %d instead.", + obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + else { + if (obj->Package.Elements[0].Integer.Value > 0x00000002) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_WAKBitField", + "_WAK: expecting condition bit-field (element 0) of packages to be in range, got 0x%8.8x.", + (uint32_t)obj->Package.Elements[0].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } + if (!( + ((obj->Package.Elements[1].Integer.Value == Sstate) && (obj->Package.Elements[0].Integer.Value == 0)) || + ((obj->Package.Elements[1].Integer.Value == 0) && (obj->Package.Elements[0].Integer.Value != 0)) )) { + fwts_warning(fw, + "_WAK: expecting power supply S-state (element 1) of packages to be 0x%8.8x, got 0x%8.8x.", + Sstate, (uint32_t)obj->Package.Elements[0].Integer.Value); + fwts_advice(fw, "_WAK should return 0 if the wake failed and was unsuccessful (i.e. element[0] " + "is non-zero) OR should return the S-state. " + "This can confuse the operating system as this _WAK return indicates that the " + "S-state was not entered because of too much current being drawn from the " + "power supply, however, the BIOS may have actually entered this state and the " + "_WAK method is misinforming the operating system. Currently Linux does not " + "check for the return type from _WAK, so it should theoretically not affect the " + "operation of suspend/resume."); - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TIP", arg, 1, method_test_integer_return, NULL); + failed++; + } + } + } + if (!failed) + fwts_passed(fw, "_WAK correctly returned sane looking package."); + } } -static int method_test_TIV(fwts_framework *fw) +static int method_test_WAK(fwts_framework *fw) { - ACPI_OBJECT arg[1]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; /* DC timer */ + uint32_t i; - return method_evaluate_method(fw, METHOD_OPTIONAL, "_TIV", arg, 1, method_test_integer_return, NULL); + for (i=1; i<6; i++) { + ACPI_OBJECT arg[1]; + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = i; + fwts_log_info(fw, "Test _WAK(%d) System Wake, State S%d.", i, i); + if (method_evaluate_method(fw, METHOD_MANDITORY, "_WAK", arg, 1, + method_test_WAK_return, &i) == FWTS_NOT_EXIST) + break; + fwts_log_nl(fw); + } + return FWTS_OK; } -/* Appendix B, ACPI Extensions for Display Adapters */ +/* + * Appendix B ACPI Extensions for Display Adapters + */ static int method_test_DOS(fwts_framework *fw) { ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = 0 << 2 | 1; - /* BIOS should toggle active display, BIOS controls brightness of LCD on AC/DC power changes */ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DOS", arg, 1, method_test_NULL_return, NULL); + /* + * BIOS should toggle active display, BIOS controls brightness of + * LCD on AC/DC power changes + */ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DOS", arg, 1, method_test_NULL_return, NULL); } -static void method_test_DOD_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_DOD_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { int failed = 0; static char *dod_type[] = { @@ -1554,10 +2064,16 @@ static void method_test_DOD_return(fwts_framework *fw, char *name, ACPI_BUFFER * static int method_test_DOD(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DOD", NULL, 0, method_test_DOD_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DOD", NULL, 0, method_test_DOD_return, NULL); } -static void method_test_ROM_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_ROM_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { method_check_type(fw, name, buf, ACPI_TYPE_BUFFER); } @@ -1571,12 +2087,14 @@ static int method_test_ROM(fwts_framework *fw) arg[1].Type = ACPI_TYPE_INTEGER; arg[1].Integer.Value = 4096; - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ROM", arg, 2, method_test_ROM_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_ROM", arg, 2, method_test_ROM_return, NULL); } static int method_test_GPD(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_GPD", NULL, 0, method_test_integer_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_GPD", NULL, 0, method_test_integer_return, NULL); } static int method_test_SPD(fwts_framework *fw) @@ -1588,7 +2106,8 @@ static int method_test_SPD(fwts_framework *fw) arg[0].Type = ACPI_TYPE_INTEGER; arg[0].Integer.Value = i; /* bits 00..11, post device */ - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_SPD", arg, 1, method_test_passed_failed_return, NULL) == FWTS_NOT_EXIST) + if (method_evaluate_method(fw, METHOD_OPTIONAL, + "_SPD", arg, 1, method_test_passed_failed_return, NULL) == FWTS_NOT_EXIST) break; } return FWTS_OK; @@ -1596,15 +2115,22 @@ static int method_test_SPD(fwts_framework *fw) static int method_test_VPO(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_VPO", NULL, 0, method_test_integer_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_VPO", NULL, 0, method_test_integer_return, NULL); } static int method_test_ADR(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ADR", NULL, 0, method_test_integer_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_ADR", NULL, 0, method_test_integer_return, NULL); } -static void method_test_BCL_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static void method_test_BCL_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) == FWTS_OK) { int i; @@ -1620,467 +2146,157 @@ static void method_test_BCL_return(fwts_framework *fw, char *name, ACPI_BUFFER * fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLNoPackage", "Method _BCL did not return a package of %d integers.", obj->Package.Count); } else { - if (obj->Package.Count < 3) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLElementCount", - "Method _BCL should return a package of more than 2 integers, got just %d.", obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } else { - bool ascending_levels = false; - - if (obj->Package.Elements[0].Integer.Value < - obj->Package.Elements[1].Integer.Value) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLMaxLevel", - "Brightness level when on full power (%d) is less than " - "brightness level when on battery power (%d).", - (uint32_t)obj->Package.Elements[0].Integer.Value, - (uint32_t)obj->Package.Elements[1].Integer.Value); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed++; - } - - for (i=2;i<obj->Package.Count-1;i++) { - if (obj->Package.Elements[i].Integer.Value > - obj->Package.Elements[i+1].Integer.Value) { - fwts_log_info(fw, "Brightness level %d (index %d) is greater than " - "brightness level %d (index %d), should be in ascending order.", - (uint32_t)obj->Package.Elements[i].Integer.Value, i, - (uint32_t)obj->Package.Elements[i+1].Integer.Value, i+1); - ascending_levels = true; - failed++; - } - } - if (ascending_levels) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLAscendingOrder", - "Some or all of the brightness level are not in ascending order which " - "should be fixed in the firmware."); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } - - if (failed) - fwts_advice(fw, "Method _BCL seems to be misconfigured and is returning incorrect brightness levels." - "It is worth sanity checking this with the firmware test suite interactive test " - "'brightness' to see how broken this is. As it is, _BCL is broken and needs to be " - "fixed."); - else - fwts_passed(fw, "Method _BCL returned a sane package of %d integers.", obj->Package.Count); - } - } - } -} - -static int method_test_BCL(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BCL", NULL, 0, method_test_BCL_return, NULL); -} - -static int method_test_BCM(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 0; - - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BCM", arg, 1, method_test_NULL_return, NULL); -} - -static int method_test_BQC(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_BQC", NULL, 0, method_test_integer_return, NULL); -} - -static void method_test_DDC_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - uint32_t requested = *(uint32_t*)private; - - if (obj == NULL){ - fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); - return; - } - switch (obj->Type) { - case ACPI_TYPE_BUFFER: - if (requested != obj->Buffer.Length) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCElementCount", - "Method _DDC returned a buffer of %d items, expected %d.", - obj->Buffer.Length, requested); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } else - fwts_passed(fw, "Method _DDC returned a buffer of %d items as expected.", - obj->Buffer.Length); - break; - case ACPI_TYPE_INTEGER: - fwts_passed(fw, "Method _DDC could not return a buffer of %d items" - "and instead returned an error status.", - obj->Buffer.Length); - break; - default: - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCBadReturnType", - "Method _DDC did not return a buffer or an integer."); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - break; - } -} - -static int method_test_DDC(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; - uint32_t i; - - for (i=128; i<=256; i <<= 1) { - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 128; - - if (method_evaluate_method(fw, METHOD_OPTIONAL, "_DDC", arg, 1, method_test_DDC_return, &i) == FWTS_NOT_EXIST) - break; - } - return FWTS_OK; -} - -static int method_test_DCS(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DCS", NULL, 0, method_test_integer_return, NULL); -} - -static int method_test_DGS(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DGS", NULL, 0, method_test_integer_return, NULL); -} - -static int method_test_DSS(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 0; - - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSS", arg, 1, method_test_NULL_return, NULL); -} - -/* Section 6.5 Other Objects and Controls */ - -static int method_test_CRS(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_MANDITORY, "_CRS", NULL, 0, method_test_buffer_return, NULL); -} - -static int method_test_DMA(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DMA", NULL, 0, method_test_buffer_return, NULL); -} - -static int method_test_DIS(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DIS", NULL, 0, method_test_NULL_return, NULL); -} - -static int method_test_PXM(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PXM", NULL, 0, method_test_integer_return, NULL); -} - -/* Section 7.2 */ - -static int method_test_DSW(fwts_framework *fw) -{ - ACPI_OBJECT arg[3]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; - arg[1].Type = ACPI_TYPE_INTEGER; - arg[1].Integer.Value = 0; - arg[2].Type = ACPI_TYPE_INTEGER; - arg[2].Integer.Value = 3; - - return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSW", arg, 3, method_test_NULL_return, NULL); -} - -#define method_test_PSx(name) \ -static int method_test ## name(fwts_framework *fw) \ -{ \ - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, NULL, 0, method_test_NULL_return, # name); \ -} - -method_test_PSx(_PS0) -method_test_PSx(_PS1) -method_test_PSx(_PS2) -method_test_PSx(_PS3) - -static int method_test_PSC(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSC", NULL, 0, method_test_integer_return, NULL); -} - -static int method_test_PSE(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; - - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; - - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSE", arg, 1, method_test_NULL_return, NULL); -} - -static void method_test_PRE_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ - int i; - - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) - return; - - /* All elements in the package must be references */ - for (i=0; i < obj->Package.Count; i++) { - if (obj->Package.Elements[i].Type != ACPI_TYPE_LOCAL_REFERENCE) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PREElementType", - "_PRE package element %d was not a reference.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } - } -} - -static int method_test_PRE(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PRE", NULL, 0, method_test_PRE_return, NULL); -} - -static int method_test_PSW(fwts_framework *fw) -{ - ACPI_OBJECT arg[1]; + if (obj->Package.Count < 3) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLElementCount", + "Method _BCL should return a package of more than 2 integers, got just %d.", obj->Package.Count); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + } else { + bool ascending_levels = false; - arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; + if (obj->Package.Elements[0].Integer.Value < + obj->Package.Elements[1].Integer.Value) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLMaxLevel", + "Brightness level when on full power (%d) is less than " + "brightness level when on battery power (%d).", + (uint32_t)obj->Package.Elements[0].Integer.Value, + (uint32_t)obj->Package.Elements[1].Integer.Value); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + failed++; + } - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSW", arg, 1, method_test_NULL_return, NULL); -} + for (i=2;i<obj->Package.Count-1;i++) { + if (obj->Package.Elements[i].Integer.Value > + obj->Package.Elements[i+1].Integer.Value) { + fwts_log_info(fw, "Brightness level %d (index %d) is greater than " + "brightness level %d (index %d), should be in ascending order.", + (uint32_t)obj->Package.Elements[i].Integer.Value, i, + (uint32_t)obj->Package.Elements[i+1].Integer.Value, i+1); + ascending_levels = true; + failed++; + } + } + if (ascending_levels) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_BCLAscendingOrder", + "Some or all of the brightness level are not in ascending order which " + "should be fixed in the firmware."); + fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); + } -static int method_test_IRC(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_IRC", NULL, 0, method_test_NULL_return, NULL); + if (failed) + fwts_advice(fw, "Method _BCL seems to be misconfigured and is returning incorrect brightness levels." + "It is worth sanity checking this with the firmware test suite interactive test " + "'brightness' to see how broken this is. As it is, _BCL is broken and needs to be " + "fixed."); + else + fwts_passed(fw, "Method _BCL returned a sane package of %d integers.", obj->Package.Count); + } + } + } } -/* Section 6.3 */ - -static int method_test_EJD(fwts_framework *fw) +static int method_test_BCL(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_EJD", NULL, 0, method_test_string_return, NULL); -} - -#define method_test_EJx(name) \ -static int method_test ## name(fwts_framework *fw) \ -{ \ - ACPI_OBJECT arg[1]; \ - \ - arg[0].Type = ACPI_TYPE_INTEGER; \ - arg[0].Integer.Value = 1; \ - \ - return method_evaluate_method(fw, METHOD_OPTIONAL, # name, arg, 1, method_test_NULL_return, # name); \ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_BCL", NULL, 0, method_test_BCL_return, NULL); } -method_test_EJx(_EJ0) -method_test_EJx(_EJ1) -method_test_EJx(_EJ2) -method_test_EJx(_EJ3) -method_test_EJx(_EJ4) - -static int method_test_LCK(fwts_framework *fw) +static int method_test_BCM(fwts_framework *fw) { ACPI_OBJECT arg[1]; arg[0].Type = ACPI_TYPE_INTEGER; - arg[0].Integer.Value = 1; - - return method_evaluate_method(fw, METHOD_OPTIONAL, "_LCK", arg, 1, method_test_NULL_return, NULL); -} - -/* Section 7.1 */ + arg[0].Integer.Value = 0; -static int method_test_ON(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_ON", NULL, 0, method_test_NULL_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_BCM", arg, 1, method_test_NULL_return, NULL); } -static int method_test_OFF(fwts_framework *fw) +static int method_test_BQC(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_OFF", NULL, 0, method_test_NULL_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_BQC", NULL, 0, method_test_integer_return, NULL); } -/* Section 6.1 */ - -static int method_test_SUN(fwts_framework *fw) +static void method_test_DDC_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_SUN", NULL, 0, method_test_integer_return, NULL); -} + uint32_t requested = *(uint32_t*)private; -static void method_test_UID_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) -{ if (obj == NULL){ fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj", "Method %s returned a NULL object, and did not return a buffer or integer.", name); return; } switch (obj->Type) { - case ACPI_TYPE_STRING: - if (obj->String.Pointer) - fwts_passed(fw, "Object _UID returned a string '%s' as expected.", - obj->String.Pointer); - else { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDNullString", - "Object _UID returned a NULL string."); + case ACPI_TYPE_BUFFER: + if (requested != obj->Buffer.Length) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCElementCount", + "Method _DDC returned a buffer of %d items, expected %d.", + obj->Buffer.Length, requested); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - } + } else + fwts_passed(fw, "Method _DDC returned a buffer of %d items as expected.", + obj->Buffer.Length); break; case ACPI_TYPE_INTEGER: - fwts_passed(fw, "Object _UID returned am integer 0x%8.8llx.", - (unsigned long long)obj->Integer.Value); + fwts_passed(fw, "Method _DDC could not return a buffer of %d items" + "and instead returned an error status.", + obj->Buffer.Length); break; default: - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType", - "Method _UID did not return a string or an integer."); + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCBadReturnType", + "Method _DDC did not return a buffer or an integer."); fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); break; } } -static int method_test_UID(fwts_framework *fw) -{ - return method_evaluate_method(fw, METHOD_OPTIONAL, "_UID", NULL, 0, method_test_UID_return, NULL); -} - - -/* Section 8.4 */ - -static void method_test_PSS_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private) +static int method_test_DDC(fwts_framework *fw) { - int i; - bool failed = false; - uint32_t max_freq = 0; - uint32_t prev_power = 0; - bool max_freq_valid = false; - - if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) - return; - - /* Something is really wrong if we don't have any elements in _PSS */ - if (obj->Package.Count < 1) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementCount", - "_PSS should return package of at least 1 element, " - "got %d elements instead.", - obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - return; - } - - for (i=0; i < obj->Package.Count; i++) { - ACPI_OBJECT *pstate; - - if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSElementType", - "_PSS package element %d was not a package.", i); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed = true; - continue; /* Skip processing sub-package */ - } - - pstate = &obj->Package.Elements[i]; - if (pstate->Package.Count != 6) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementCount", - "_PSS P-State sub-package %d was expected to have " - "6 elements, got %d elements instead.", - i, obj->Package.Count); - fwts_tag_failed(fw, FWTS_TAG_ACPI_METHOD_RETURN); - failed = true; - continue; /* Skip processing sub-package */ - } - - /* Elements need to be all ACPI integer types */ - if ((pstate->Package.Elements[0].Type != ACPI_TYPE_INTEGER) || - (pstate->Package.Elements[1].Type != ACPI_TYPE_INTEGER) || - (pstate->Package.Elements[2].Type != ACPI_TYPE_INTEGER) || - (pstate->Package.Elements[3].Type != ACPI_TYPE_INTEGER) || - (pstate->Package.Elements[4].Type != ACPI_TYPE_INTEGER) || - (pstate->Package.Elements[5].Type != ACPI_TYPE_INTEGER)) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackageElementType", - "_PSS P-State sub-package %d was expected to have " - "6 Integer elements but didn't", i); - failed = true; - continue; - } - - fwts_log_info(fw, "P-State %d: CPU %ld Mhz, %lu mW, latency %lu us, bus master latency %lu us.", - i, - (unsigned long)pstate->Package.Elements[0].Integer.Value, - (unsigned long)pstate->Package.Elements[1].Integer.Value, - (unsigned long)pstate->Package.Elements[2].Integer.Value, - (unsigned long)pstate->Package.Elements[3].Integer.Value); - - /* - * Collect maximum frequency. The sub-packages are sorted in - * descending power dissipation order, so one would assume that - * the highest frequency is first. However, it is not clear - * from the ACPI spec that this is necessarily an assumption we - * should make, so instead we should probably scan through all - * the valid sub-packages and find the highest frequency. - */ - if (max_freq < pstate->Package.Elements[0].Integer.Value) { - max_freq = pstate->Package.Elements[0].Integer.Value; - max_freq_valid = true; - } + ACPI_OBJECT arg[1]; + uint32_t i; - /* Sanity check descending power dissipation levels */ - if ((i > 0) && (prev_power != 0) && - (pstate->Package.Elements[1].Integer.Value > prev_power)) { - fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_PSSSubPackagePowerNotDecending", - "_PSS P-State sub-package %d has a larger power dissipation " - "setting than the previous sub-package.", i); - fwts_advice(fw, "_PSS P-States must be ordered in decending order of " - "power dissipation, so that the zero'th entry has the highest " - "power dissipation level and the Nth has the lowest."); - failed = true; - } - prev_power = pstate->Package.Elements[1].Integer.Value; - } + for (i=128; i<=256; i <<= 1) { + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 128; - /* - * Sanity check maximum frequency. We could also check the DMI data - * for a BIOS date (but this can be wrong) or check the CPU identity - * (which requires adding in new CPU identity checks) to make a decision - * on when it is reasonable to assume a CPU is modern and hence clocked - * incorrectly. For now, just flag up a low level error that the - * frequency looks rather low rather than try to be intelligent (and - * possibly make a mistake). I'd rather flag up a few false positives - * on older machines than miss flagging up bad _PSS settings on new - * machines. - */ - if (max_freq_valid && max_freq < 1000) { - fwts_failed(fw, LOG_LEVEL_LOW, "Method_PSSSubPackageLowFreq", - "Maximum CPU frequency is %dHz and this is low for " - "a modern processor. This may indicate the _PSS P-States " - "are incorrect\n", max_freq); - fwts_advice(fw, - "The _PSS P-States are used by the Linux CPU frequency " - "driver to set the CPU frequencies according to system " - "load. Sometimes the firmware sets these incorrectly " - "and the machine runs at a sub-optimal speed. One can " - "view the firmware defined CPU frequencies via " - "/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_frequencies"); - failed = true; + if (method_evaluate_method(fw, METHOD_OPTIONAL, + "_DDC", arg, 1, method_test_DDC_return, &i) == FWTS_NOT_EXIST) + break; } - - if (!failed) - fwts_passed(fw, "_PSS correctly returned sane looking package."); + return FWTS_OK; } -static int method_test_PSS(fwts_framework *fw) +static int method_test_DCS(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSS", NULL, 0, method_test_PSS_return, NULL); + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DCS", NULL, 0, method_test_integer_return, NULL); } -/* Section 5.6 */ +static int method_test_DGS(fwts_framework *fw) +{ + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DGS", NULL, 0, method_test_integer_return, NULL); +} -static int method_test_AEI(fwts_framework *fw) +static int method_test_DSS(fwts_framework *fw) { - return method_evaluate_method(fw, METHOD_OPTIONAL, "_AEI", NULL, 0, method_test_buffer_return, NULL); + ACPI_OBJECT arg[1]; + + arg[0].Type = ACPI_TYPE_INTEGER; + arg[0].Integer.Value = 0; + + return method_evaluate_method(fw, METHOD_OPTIONAL, + "_DSS", arg, 1, method_test_NULL_return, NULL); } -/* Tests */ +/* + * Tests + */ static fwts_framework_minor_test method_tests[] = { { method_name_check, "Check Method Names." },