diff options
Diffstat (limited to 'drivers/acpi/acpica/rscalc.c')
| -rw-r--r-- | drivers/acpi/acpica/rscalc.c | 135 |
1 files changed, 116 insertions, 19 deletions
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index d6ebf7ec622..689556744b0 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2014, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -84,7 +84,7 @@ static u8 acpi_rs_count_set_bits(u16 bit_field) bit_field &= (u16) (bit_field - 1); } - return bits_set; + return (bits_set); } /******************************************************************************* @@ -173,7 +173,8 @@ acpi_rs_stream_option_length(u32 resource_length, * * FUNCTION: acpi_rs_get_aml_length * - * PARAMETERS: Resource - Pointer to the resource linked list + * PARAMETERS: resource - Pointer to the resource linked list + * resource_list_size - Size of the resource linked list * size_needed - Where the required size is returned * * RETURN: Status @@ -185,16 +186,20 @@ acpi_rs_stream_option_length(u32 resource_length, ******************************************************************************/ acpi_status -acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) +acpi_rs_get_aml_length(struct acpi_resource *resource, + acpi_size resource_list_size, acpi_size * size_needed) { acpi_size aml_size_needed = 0; + struct acpi_resource *resource_end; acpi_rs_length total_size; ACPI_FUNCTION_TRACE(rs_get_aml_length); /* Traverse entire list of internal resource descriptors */ - while (resource) { + resource_end = + ACPI_ADD_PTR(struct acpi_resource, resource, resource_list_size); + while (resource < resource_end) { /* Validate the descriptor type */ @@ -202,6 +207,12 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } + /* Sanity check the length. It must not be zero, or we loop forever */ + + if (!resource->length) { + return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); + } + /* Get the base size of the (external stream) resource descriptor */ total_size = acpi_gbl_aml_resource_sizes[resource->type]; @@ -313,7 +324,40 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) resource_source)); break; + case ACPI_RESOURCE_TYPE_GPIO: + + total_size = + (acpi_rs_length) (total_size + + (resource->data.gpio. + pin_table_length * 2) + + resource->data.gpio. + resource_source.string_length + + resource->data.gpio. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_SERIAL_BUS: + + total_size = + acpi_gbl_aml_resource_serial_bus_sizes[resource-> + data. + common_serial_bus. + type]; + + total_size = (acpi_rs_length) (total_size + + resource->data. + i2c_serial_bus. + resource_source. + string_length + + resource->data. + i2c_serial_bus. + vendor_length); + + break; + default: + break; } @@ -362,10 +406,11 @@ acpi_rs_get_list_length(u8 * aml_buffer, u32 extra_struct_bytes; u8 resource_index; u8 minimum_aml_resource_length; + union aml_resource *aml_resource; ACPI_FUNCTION_TRACE(rs_get_list_length); - *size_needed = 0; + *size_needed = ACPI_RS_SIZE_MIN; /* Minimum size is one end_tag */ end_aml = aml_buffer + aml_buffer_length; /* Walk the list of AML resource descriptors */ @@ -374,11 +419,19 @@ acpi_rs_get_list_length(u8 * aml_buffer, /* Validate the Resource Type and Resource Length */ - status = acpi_ut_validate_resource(aml_buffer, &resource_index); + status = + acpi_ut_validate_resource(NULL, aml_buffer, + &resource_index); if (ACPI_FAILURE(status)) { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ return_ACPI_STATUS(status); } + aml_resource = (void *)aml_buffer; + /* Get the resource length and base (minimum) AML size */ resource_length = acpi_ut_get_resource_length(aml_buffer); @@ -418,14 +471,21 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Get the number of vendor data bytes */ extra_struct_bytes = resource_length; + + /* + * There is already one byte included in the minimum + * descriptor size. If there are extra struct bytes, + * subtract one from the count. + */ + if (extra_struct_bytes) { + extra_struct_bytes--; + } break; case ACPI_RESOURCE_NAME_END_TAG: /* - * End Tag: - * This is the normal exit, add size of end_tag + * End Tag: This is the normal exit */ - *size_needed += ACPI_RS_SIZE_MIN; return_ACPI_STATUS(AE_OK); case ACPI_RESOURCE_NAME_ADDRESS32: @@ -457,7 +517,35 @@ acpi_rs_get_list_length(u8 * aml_buffer, minimum_aml_resource_length); break; + case ACPI_RESOURCE_NAME_GPIO: + + /* Vendor data is optional */ + + if (aml_resource->gpio.vendor_length) { + extra_struct_bytes += + aml_resource->gpio.vendor_offset - + aml_resource->gpio.pin_table_offset + + aml_resource->gpio.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->gpio.pin_table_offset; + } + break; + + case ACPI_RESOURCE_NAME_SERIAL_BUS: + + minimum_aml_resource_length = + acpi_gbl_resource_aml_serial_bus_sizes + [aml_resource->common_serial_bus.type]; + extra_struct_bytes += + aml_resource->common_serial_bus.resource_length - + minimum_aml_resource_length; + break; + default: + break; } @@ -467,9 +555,18 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Important: Round the size up for the appropriate alignment. This * is a requirement on IA64. */ - buffer_size = acpi_gbl_resource_struct_sizes[resource_index] + - extra_struct_bytes; - buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + if (acpi_ut_get_resource_type(aml_buffer) == + ACPI_RESOURCE_NAME_SERIAL_BUS) { + buffer_size = + acpi_gbl_resource_struct_serial_bus_sizes + [aml_resource->common_serial_bus.type] + + extra_struct_bytes; + } else { + buffer_size = + acpi_gbl_resource_struct_sizes[resource_index] + + extra_struct_bytes; + } + buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); *size_needed += buffer_size; @@ -528,7 +625,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, /* * Calculate the size of the return buffer. * The base size is the number of elements * the sizes of the - * structures. Additional space for the strings is added below. + * structures. Additional space for the strings is added below. * The minus one is to subtract the size of the u8 Source[1] * member because it is added below. * @@ -539,7 +636,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, for (index = 0; index < number_of_elements; index++) { - /* Dereference the sub-package */ + /* Dereference the subpackage */ package_element = *top_object_list; @@ -560,8 +657,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, name_found = FALSE; - for (table_index = 0; table_index < 4 && !name_found; - table_index++) { + for (table_index = 0; + table_index < package_element->package.count + && !name_found; table_index++) { if (*sub_object_list && /* Null object allowed */ ((ACPI_TYPE_STRING == (*sub_object_list)->common.type) || @@ -591,8 +689,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, (*sub_object_list)->string. length + 1); } else { - temp_size_needed += - acpi_ns_get_pathname_length((*sub_object_list)->reference.node); + temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); } } else { /* |
