ACPI_STATUS AcpiExInsertIntoField ( ACPI_OPERAND_OBJECT *ObjDesc, void *Buffer, UINT32 BufferLength) { void *NewBuffer; ACPI_STATUS Status; UINT64 Mask; UINT64 WidthMask; UINT64 MergedDatum; UINT64 RawDatum = 0; UINT32 FieldOffset = 0; UINT32 BufferOffset = 0; UINT32 BufferTailBits; UINT32 DatumCount; UINT32 FieldDatumCount; UINT32 AccessBitWidth; UINT32 RequiredLength; UINT32 i; ACPI_FUNCTION_TRACE (ExInsertIntoField); /* Validate input buffer */ NewBuffer = NULL; RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( ObjDesc->CommonField.BitLength); /* * We must have a buffer that is at least as long as the field * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ if (BufferLength < RequiredLength) { /* We need to create a new buffer */ NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); if (!NewBuffer) { return_ACPI_STATUS (AE_NO_MEMORY); } /* * Copy the original data to the new buffer, starting * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength); Buffer = NewBuffer; BufferLength = RequiredLength; } /* TBD: Move to common setup code */ /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) { ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); } AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); /* Create the bitmasks used for bit insertion */ WidthMask = ACPI_MASK_BITS_ABOVE_64 (AccessBitWidth); Mask = WidthMask & ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); /* Compute the number of datums (access width data items) */ DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, AccessBitWidth); FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); /* Get initial Datum from the input buffer */ memcpy (&RawDatum, Buffer, ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, BufferLength - BufferOffset)); MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; /* Write the entire field */ for (i = 1; i < FieldDatumCount; i++) { /* Write merged datum to the target field */ MergedDatum &= Mask; Status = AcpiExWriteWithUpdateRule ( ObjDesc, Mask, MergedDatum, FieldOffset); if (ACPI_FAILURE (Status)) { goto Exit; } FieldOffset += ObjDesc->CommonField.AccessByteWidth; /* * Start new output datum by merging with previous input datum * if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE) { MergedDatum = RawDatum >> (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); } else {
acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 64, &address); if (ACPI_FAILURE(status)) { return (status); } /* Convert access_width into number of bits based */ access_width = acpi_hw_get_access_bit_width(address, reg, 64); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { /* * Use offset style bit reads because "Index * AccessWidth" is * ensured to be less than 64-bits by acpi_hw_validate_register(). */ value64 = ACPI_GET_BITS(&value, index * access_width, ACPI_MASK_BITS_ABOVE_64(access_width)); if (bit_offset >= access_width) { bit_offset -= access_width; } else { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_write_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), value64, access_width); } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_write_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), (u32)value64, access_width); } } /* * Index * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", ACPI_FORMAT_UINT64(value), access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
ACPI_STATUS AcpiHwWrite ( UINT64 Value, ACPI_GENERIC_ADDRESS *Reg) { UINT64 Address; UINT8 AccessWidth; UINT32 BitWidth; UINT8 BitOffset; UINT64 Value64; UINT8 Index; ACPI_STATUS Status; ACPI_FUNCTION_NAME (HwWrite); /* Validate contents of the GAS register */ Status = AcpiHwValidateRegister (Reg, 64, &Address); if (ACPI_FAILURE (Status)) { return (Status); } /* Convert AccessWidth into number of bits based */ AccessWidth = AcpiHwGetAccessBitWidth (Address, Reg, 64); BitWidth = Reg->BitOffset + Reg->BitWidth; BitOffset = Reg->BitOffset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ Index = 0; while (BitWidth) { /* * Use offset style bit reads because "Index * AccessWidth" is * ensured to be less than 64-bits by AcpiHwValidateRegister(). */ Value64 = ACPI_GET_BITS (&Value, Index * AccessWidth, ACPI_MASK_BITS_ABOVE_64 (AccessWidth)); if (BitOffset >= AccessWidth) { BitOffset -= AccessWidth; } else { if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) { Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), Value64, AccessWidth); } else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ { Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), (UINT32) Value64, AccessWidth); } } /* * Index * AccessWidth is ensured to be less than 32-bits by * AcpiHwValidateRegister(). */ BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; Index++; } ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", ACPI_FORMAT_UINT64 (Value), AccessWidth, ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId))); return (Status); }