diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpica/acutils.h | 7 | ||||
-rw-r--r-- | drivers/acpi/acpica/uthex.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/utmath.c | 222 | ||||
-rw-r--r-- | drivers/acpi/acpica/utprint.c | 2 | ||||
-rw-r--r-- | drivers/acpi/acpica/utstrtoul64.c | 9 |
5 files changed, 228 insertions, 16 deletions
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 2a3cc4296481..0a5601405584 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -538,6 +538,13 @@ acpi_status acpi_ut_short_divide(u64 in_dividend, u32 divisor, u64 *out_quotient, u32 *out_remainder); +acpi_status +acpi_ut_short_multiply(u64 in_multiplicand, u32 multiplier, u64 *outproduct); + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result); + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result); + /* * utmisc */ diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 6600bc257516..fb406daf47fa 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -69,8 +69,10 @@ static const char acpi_gbl_hex_to_ascii[] = { char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) { + u64 index; - return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); + acpi_ut_short_shift_right(integer, position, &index); + return (acpi_gbl_hex_to_ascii[index & 0xF]); } /******************************************************************************* diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index aa0502d1d019..5f9c680076c4 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -47,15 +47,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmath") -/* - * Optional support for 64-bit double-precision integer divide. This code - * is configurable and is implemented in order to support 32-bit kernel - * environments where a 64-bit double-precision math library is not available. - * - * Support for a more normal 64-bit divide/modulo (with check for a divide- - * by-zero) appears after this optional section of code. - */ -#ifndef ACPI_USE_NATIVE_DIVIDE /* Structures used only for 64-bit divide */ typedef struct uint64_struct { u32 lo; @@ -69,6 +60,217 @@ typedef union uint64_overlay { } uint64_overlay; +/* + * Optional support for 64-bit double-precision integer multiply and shift. + * This code is configurable and is implemented in order to support 32-bit + * kernel environments where a 64-bit double-precision math library is not + * available. + */ +#ifndef ACPI_USE_NATIVE_MATH64 + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_multiply + * + * PARAMETERS: multiplicand - 64-bit multiplicand + * multiplier - 32-bit multiplier + * out_product - Pointer to where the product is returned + * + * DESCRIPTION: Perform a short multiply. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product) +{ + union uint64_overlay multiplicand_ovl; + union uint64_overlay product; + u32 carry32; + + ACPI_FUNCTION_TRACE(ut_short_multiply); + + multiplicand_ovl.full = multiplicand; + + /* + * The Product is 64 bits, the carry is always 32 bits, + * and is generated by the second multiply. + */ + ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.hi, multiplier, + product.part.hi, carry32); + + ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.lo, multiplier, + product.part.lo, carry32); + + product.part.hi += carry32; + + /* Return only what was requested */ + + if (out_product) { + *out_product = product.full; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_left + * + * PARAMETERS: operand - 64-bit shift operand + * count - 32-bit shift count + * out_result - Pointer to where the result is returned + * + * DESCRIPTION: Perform a short left shift. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) +{ + union uint64_overlay operand_ovl; + + ACPI_FUNCTION_TRACE(ut_short_shift_left); + + operand_ovl.full = operand; + + if ((count & 63) >= 32) { + operand_ovl.part.hi = operand_ovl.part.lo; + operand_ovl.part.lo ^= operand_ovl.part.lo; + count = (count & 63) - 32; + } + ACPI_SHIFT_LEFT_64_BY_32(operand_ovl.part.hi, + operand_ovl.part.lo, count); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand_ovl.full; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_right + * + * PARAMETERS: operand - 64-bit shift operand + * count - 32-bit shift count + * out_result - Pointer to where the result is returned + * + * DESCRIPTION: Perform a short right shift. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) +{ + union uint64_overlay operand_ovl; + + ACPI_FUNCTION_TRACE(ut_short_shift_right); + + operand_ovl.full = operand; + + if ((count & 63) >= 32) { + operand_ovl.part.lo = operand_ovl.part.hi; + operand_ovl.part.hi ^= operand_ovl.part.hi; + count = (count & 63) - 32; + } + ACPI_SHIFT_RIGHT_64_BY_32(operand_ovl.part.hi, + operand_ovl.part.lo, count); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand_ovl.full; + } + + return_ACPI_STATUS(AE_OK); +} +#else + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_multiply + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_multiply function. + * + ******************************************************************************/ + +acpi_status +acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product) +{ + + ACPI_FUNCTION_TRACE(ut_short_multiply); + + /* Return only what was requested */ + + if (out_product) { + *out_product = multiplicand * multiplier; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_left + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_shift_left function. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result) +{ + + ACPI_FUNCTION_TRACE(ut_short_shift_left); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand << count; + } + + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_short_shift_right + * + * PARAMETERS: See function headers above + * + * DESCRIPTION: Native version of the ut_short_shift_right function. + * + ******************************************************************************/ + +acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result) +{ + + ACPI_FUNCTION_TRACE(ut_short_shift_right); + + /* Return only what was requested */ + + if (out_result) { + *out_result = operand >> count; + } + + return_ACPI_STATUS(AE_OK); +} +#endif + +/* + * Optional support for 64-bit double-precision integer divide. This code + * is configurable and is implemented in order to support 32-bit kernel + * environments where a 64-bit double-precision math library is not available. + * + * Support for a more normal 64-bit divide/modulo (with check for a divide- + * by-zero) appears after this optional section of code. + */ +#ifndef ACPI_USE_NATIVE_DIVIDE + /******************************************************************************* * * FUNCTION: acpi_ut_short_divide @@ -258,6 +460,7 @@ acpi_ut_divide(u64 in_dividend, } #else + /******************************************************************************* * * FUNCTION: acpi_ut_short_divide, acpi_ut_divide @@ -272,6 +475,7 @@ acpi_ut_divide(u64 in_dividend, * perform the divide. * ******************************************************************************/ + acpi_status acpi_ut_short_divide(u64 in_dividend, u32 divisor, u64 *out_quotient, u32 *out_remainder) diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 7e6e1ae6140f..23cb472e5dc8 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -176,7 +176,7 @@ const char *acpi_ut_scan_number(const char *string, u64 *number_ptr) u64 number = 0; while (isdigit((int)*string)) { - number *= 10; + acpi_ut_short_multiply(number, 10, &number); number += *(string++) - '0'; } diff --git a/drivers/acpi/acpica/utstrtoul64.c b/drivers/acpi/acpica/utstrtoul64.c index f42be01d99fd..9633ee142855 100644 --- a/drivers/acpi/acpica/utstrtoul64.c +++ b/drivers/acpi/acpica/utstrtoul64.c @@ -276,8 +276,8 @@ static u64 acpi_ut_strtoul_base10(char *string, u32 flags) /* Convert and insert (add) the decimal digit */ - next_value = - (return_value * 10) + (ascii_digit - ACPI_ASCII_ZERO); + acpi_ut_short_multiply(return_value, 10, &next_value); + next_value += (ascii_digit - ACPI_ASCII_ZERO); /* Check for overflow (32 or 64 bit) - return current converted value */ @@ -335,9 +335,8 @@ static u64 acpi_ut_strtoul_base16(char *string, u32 flags) /* Convert and insert the hex digit */ - return_value = - (return_value << 4) | - acpi_ut_ascii_char_to_hex(ascii_digit); + acpi_ut_short_shift_left(return_value, 4, &return_value); + return_value |= acpi_ut_ascii_char_to_hex(ascii_digit); string++; valid_digits++; |