Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPICA: Update for generic_serial_bus and attrib_raw_process_bytes protocol

Cleanup for this write-then-read protocol. The ACPI specification
is rather unclear for the entire generic_serial_bus, but this
change works correctly on the Surface 3.

Reported-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Erik Schmauss <erik.schmauss@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Bob Moore and committed by
Rafael J. Wysocki
f99b89ee 17b57b18

+44 -12
+35 -9
drivers/acpi/acpica/exfield.c
··· 60 60 61 61 case AML_FIELD_ATTRIB_MULTIBYTE: 62 62 case AML_FIELD_ATTRIB_RAW_BYTES: 63 - case AML_FIELD_ATTRIB_RAW_PROCESS: 64 63 65 64 length = access_length; 65 + break; 66 + 67 + case AML_FIELD_ATTRIB_RAW_PROCESS: 68 + /* 69 + * Worst case bidirectional buffer size. This ignores the 70 + * access_length argument to access_as because it is not needed. 71 + * August 2018. 72 + */ 73 + length = ACPI_MAX_GSBUS_BUFFER_SIZE; 66 74 break; 67 75 68 76 case AML_FIELD_ATTRIB_BLOCK: ··· 155 147 } else if (obj_desc->field.region_obj->region.space_id == 156 148 ACPI_ADR_SPACE_GSBUS) { 157 149 accessor_type = obj_desc->field.attribute; 150 + if (accessor_type == AML_FIELD_ATTRIB_RAW_PROCESS) { 151 + ACPI_ERROR((AE_INFO, 152 + "Invalid direct read using bidirectional write-then-read protocol")); 153 + 154 + return_ACPI_STATUS(AE_AML_PROTOCOL); 155 + } 156 + 158 157 length = 159 158 acpi_ex_get_serial_access_length(accessor_type, 160 159 obj_desc->field. ··· 320 305 { 321 306 acpi_status status; 322 307 u32 length; 308 + u32 data_length; 323 309 void *buffer; 324 310 union acpi_operand_object *buffer_desc; 325 311 u32 function; ··· 377 361 if (obj_desc->field.region_obj->region.space_id == 378 362 ACPI_ADR_SPACE_SMBUS) { 379 363 length = ACPI_SMBUS_BUFFER_SIZE; 364 + data_length = length; 380 365 function = 381 366 ACPI_WRITE | (obj_desc->field.attribute << 16); 382 367 } else if (obj_desc->field.region_obj->region.space_id == ··· 389 372 access_length); 390 373 391 374 /* 392 - * Add additional 2 bytes for the generic_serial_bus data buffer: 393 - * 375 + * Buffer format for Generic Serial Bus protocols: 394 376 * Status; (Byte 0 of the data buffer) 395 377 * Length; (Byte 1 of the data buffer) 396 378 * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) 397 379 */ 398 - length += 2; 380 + data_length = source_desc->buffer.pointer[1]; /* Data length is 2nd byte */ 381 + if (!data_length) { 382 + ACPI_ERROR((AE_INFO, 383 + "Invalid zero data length in transfer buffer")); 384 + 385 + return_ACPI_STATUS(AE_AML_BUFFER_LENGTH); 386 + } 387 + 399 388 function = ACPI_WRITE | (accessor_type << 16); 400 389 } else { /* IPMI */ 401 390 402 391 length = ACPI_IPMI_BUFFER_SIZE; 392 + data_length = length; 403 393 function = ACPI_WRITE; 404 394 } 405 395 406 - if (source_desc->buffer.length < length) { 396 + if (source_desc->buffer.length < data_length) { 407 397 ACPI_ERROR((AE_INFO, 408 398 "SMBus/IPMI/GenericSerialBus write requires " 409 - "Buffer of length %u, found length %u", 410 - length, source_desc->buffer.length)); 399 + "Buffer data length %u, found buffer length %u", 400 + data_length, source_desc->buffer.length)); 411 401 412 402 return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); 413 403 } 414 404 415 - /* Create the bi-directional buffer */ 405 + /* Create the transfer/bidirectional buffer */ 416 406 417 407 buffer_desc = acpi_ut_create_buffer_object(length); 418 408 if (!buffer_desc) { 419 409 return_ACPI_STATUS(AE_NO_MEMORY); 420 410 } 421 411 412 + /* Copy the input buffer data to the transfer buffer */ 413 + 422 414 buffer = buffer_desc->buffer.pointer; 423 - memcpy(buffer, source_desc->buffer.pointer, length); 415 + memcpy(buffer, source_desc->buffer.pointer, data_length); 424 416 425 417 /* Lock entire transaction if requested */ 426 418
+2 -1
include/acpi/acconfig.h
··· 176 176 /* SMBus, GSBus and IPMI bidirectional buffer size */ 177 177 178 178 #define ACPI_SMBUS_BUFFER_SIZE 34 179 - #define ACPI_GSBUS_BUFFER_SIZE 34 180 179 #define ACPI_IPMI_BUFFER_SIZE 66 180 + #define ACPI_GSBUS_BUFFER_SIZE 34 /* Not clear if this is needed */ 181 + #define ACPI_MAX_GSBUS_BUFFER_SIZE 255 /* Worst-case bidirectional buffer */ 181 182 182 183 /* _sx_d and _sx_w control methods */ 183 184
+7 -2
include/acpi/acexcep.h
··· 171 171 #define AE_AML_LOOP_TIMEOUT EXCEP_AML (0x0021) 172 172 #define AE_AML_UNINITIALIZED_NODE EXCEP_AML (0x0022) 173 173 #define AE_AML_TARGET_TYPE EXCEP_AML (0x0023) 174 + #define AE_AML_PROTOCOL EXCEP_AML (0x0024) 175 + #define AE_AML_BUFFER_LENGTH EXCEP_AML (0x0025) 174 176 175 - #define AE_CODE_AML_MAX 0x0023 177 + #define AE_CODE_AML_MAX 0x0025 176 178 177 179 /* 178 180 * Internal exceptions used for control ··· 349 347 EXCEP_TXT("AE_AML_UNINITIALIZED_NODE", 350 348 "A namespace node is uninitialized or unresolved"), 351 349 EXCEP_TXT("AE_AML_TARGET_TYPE", 352 - "A target operand of an incorrect type was encountered") 350 + "A target operand of an incorrect type was encountered"), 351 + EXCEP_TXT("AE_AML_PROTOCOL", "Violation of a fixed ACPI protocol"), 352 + EXCEP_TXT("AE_AML_BUFFER_LENGTH", 353 + "The length of the buffer is invalid/incorrect") 353 354 }; 354 355 355 356 static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {