Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: utmath - Integer math support routines
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 
0011 #define _COMPONENT          ACPI_UTILITIES
0012 ACPI_MODULE_NAME("utmath")
0013 
0014 /* Structures used only for 64-bit divide */
0015 typedef struct uint64_struct {
0016     u32 lo;
0017     u32 hi;
0018 
0019 } uint64_struct;
0020 
0021 typedef union uint64_overlay {
0022     u64 full;
0023     struct uint64_struct part;
0024 
0025 } uint64_overlay;
0026 
0027 /*
0028  * Optional support for 64-bit double-precision integer multiply and shift.
0029  * This code is configurable and is implemented in order to support 32-bit
0030  * kernel environments where a 64-bit double-precision math library is not
0031  * available.
0032  */
0033 #ifndef ACPI_USE_NATIVE_MATH64
0034 
0035 /*******************************************************************************
0036  *
0037  * FUNCTION:    acpi_ut_short_multiply
0038  *
0039  * PARAMETERS:  multiplicand        - 64-bit multiplicand
0040  *              multiplier          - 32-bit multiplier
0041  *              out_product         - Pointer to where the product is returned
0042  *
0043  * DESCRIPTION: Perform a short multiply.
0044  *
0045  ******************************************************************************/
0046 
0047 acpi_status
0048 acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product)
0049 {
0050     union uint64_overlay multiplicand_ovl;
0051     union uint64_overlay product;
0052     u32 carry32;
0053 
0054     ACPI_FUNCTION_TRACE(ut_short_multiply);
0055 
0056     multiplicand_ovl.full = multiplicand;
0057 
0058     /*
0059      * The Product is 64 bits, the carry is always 32 bits,
0060      * and is generated by the second multiply.
0061      */
0062     ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.hi, multiplier,
0063               product.part.hi, carry32);
0064 
0065     ACPI_MUL_64_BY_32(0, multiplicand_ovl.part.lo, multiplier,
0066               product.part.lo, carry32);
0067 
0068     product.part.hi += carry32;
0069 
0070     /* Return only what was requested */
0071 
0072     if (out_product) {
0073         *out_product = product.full;
0074     }
0075 
0076     return_ACPI_STATUS(AE_OK);
0077 }
0078 
0079 /*******************************************************************************
0080  *
0081  * FUNCTION:    acpi_ut_short_shift_left
0082  *
0083  * PARAMETERS:  operand             - 64-bit shift operand
0084  *              count               - 32-bit shift count
0085  *              out_result          - Pointer to where the result is returned
0086  *
0087  * DESCRIPTION: Perform a short left shift.
0088  *
0089  ******************************************************************************/
0090 
0091 acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result)
0092 {
0093     union uint64_overlay operand_ovl;
0094 
0095     ACPI_FUNCTION_TRACE(ut_short_shift_left);
0096 
0097     operand_ovl.full = operand;
0098 
0099     if ((count & 63) >= 32) {
0100         operand_ovl.part.hi = operand_ovl.part.lo;
0101         operand_ovl.part.lo = 0;
0102         count = (count & 63) - 32;
0103     }
0104     ACPI_SHIFT_LEFT_64_BY_32(operand_ovl.part.hi,
0105                  operand_ovl.part.lo, count);
0106 
0107     /* Return only what was requested */
0108 
0109     if (out_result) {
0110         *out_result = operand_ovl.full;
0111     }
0112 
0113     return_ACPI_STATUS(AE_OK);
0114 }
0115 
0116 /*******************************************************************************
0117  *
0118  * FUNCTION:    acpi_ut_short_shift_right
0119  *
0120  * PARAMETERS:  operand             - 64-bit shift operand
0121  *              count               - 32-bit shift count
0122  *              out_result          - Pointer to where the result is returned
0123  *
0124  * DESCRIPTION: Perform a short right shift.
0125  *
0126  ******************************************************************************/
0127 
0128 acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result)
0129 {
0130     union uint64_overlay operand_ovl;
0131 
0132     ACPI_FUNCTION_TRACE(ut_short_shift_right);
0133 
0134     operand_ovl.full = operand;
0135 
0136     if ((count & 63) >= 32) {
0137         operand_ovl.part.lo = operand_ovl.part.hi;
0138         operand_ovl.part.hi = 0;
0139         count = (count & 63) - 32;
0140     }
0141     ACPI_SHIFT_RIGHT_64_BY_32(operand_ovl.part.hi,
0142                   operand_ovl.part.lo, count);
0143 
0144     /* Return only what was requested */
0145 
0146     if (out_result) {
0147         *out_result = operand_ovl.full;
0148     }
0149 
0150     return_ACPI_STATUS(AE_OK);
0151 }
0152 #else
0153 
0154 /*******************************************************************************
0155  *
0156  * FUNCTION:    acpi_ut_short_multiply
0157  *
0158  * PARAMETERS:  See function headers above
0159  *
0160  * DESCRIPTION: Native version of the ut_short_multiply function.
0161  *
0162  ******************************************************************************/
0163 
0164 acpi_status
0165 acpi_ut_short_multiply(u64 multiplicand, u32 multiplier, u64 *out_product)
0166 {
0167 
0168     ACPI_FUNCTION_TRACE(ut_short_multiply);
0169 
0170     /* Return only what was requested */
0171 
0172     if (out_product) {
0173         *out_product = multiplicand * multiplier;
0174     }
0175 
0176     return_ACPI_STATUS(AE_OK);
0177 }
0178 
0179 /*******************************************************************************
0180  *
0181  * FUNCTION:    acpi_ut_short_shift_left
0182  *
0183  * PARAMETERS:  See function headers above
0184  *
0185  * DESCRIPTION: Native version of the ut_short_shift_left function.
0186  *
0187  ******************************************************************************/
0188 
0189 acpi_status acpi_ut_short_shift_left(u64 operand, u32 count, u64 *out_result)
0190 {
0191 
0192     ACPI_FUNCTION_TRACE(ut_short_shift_left);
0193 
0194     /* Return only what was requested */
0195 
0196     if (out_result) {
0197         *out_result = operand << count;
0198     }
0199 
0200     return_ACPI_STATUS(AE_OK);
0201 }
0202 
0203 /*******************************************************************************
0204  *
0205  * FUNCTION:    acpi_ut_short_shift_right
0206  *
0207  * PARAMETERS:  See function headers above
0208  *
0209  * DESCRIPTION: Native version of the ut_short_shift_right function.
0210  *
0211  ******************************************************************************/
0212 
0213 acpi_status acpi_ut_short_shift_right(u64 operand, u32 count, u64 *out_result)
0214 {
0215 
0216     ACPI_FUNCTION_TRACE(ut_short_shift_right);
0217 
0218     /* Return only what was requested */
0219 
0220     if (out_result) {
0221         *out_result = operand >> count;
0222     }
0223 
0224     return_ACPI_STATUS(AE_OK);
0225 }
0226 #endif
0227 
0228 /*
0229  * Optional support for 64-bit double-precision integer divide. This code
0230  * is configurable and is implemented in order to support 32-bit kernel
0231  * environments where a 64-bit double-precision math library is not available.
0232  *
0233  * Support for a more normal 64-bit divide/modulo (with check for a divide-
0234  * by-zero) appears after this optional section of code.
0235  */
0236 #ifndef ACPI_USE_NATIVE_DIVIDE
0237 
0238 /*******************************************************************************
0239  *
0240  * FUNCTION:    acpi_ut_short_divide
0241  *
0242  * PARAMETERS:  dividend            - 64-bit dividend
0243  *              divisor             - 32-bit divisor
0244  *              out_quotient        - Pointer to where the quotient is returned
0245  *              out_remainder       - Pointer to where the remainder is returned
0246  *
0247  * RETURN:      Status (Checks for divide-by-zero)
0248  *
0249  * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
0250  *              divide and modulo. The result is a 64-bit quotient and a
0251  *              32-bit remainder.
0252  *
0253  ******************************************************************************/
0254 
0255 acpi_status
0256 acpi_ut_short_divide(u64 dividend,
0257              u32 divisor, u64 *out_quotient, u32 *out_remainder)
0258 {
0259     union uint64_overlay dividend_ovl;
0260     union uint64_overlay quotient;
0261     u32 remainder32;
0262 
0263     ACPI_FUNCTION_TRACE(ut_short_divide);
0264 
0265     /* Always check for a zero divisor */
0266 
0267     if (divisor == 0) {
0268         ACPI_ERROR((AE_INFO, "Divide by zero"));
0269         return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
0270     }
0271 
0272     dividend_ovl.full = dividend;
0273 
0274     /*
0275      * The quotient is 64 bits, the remainder is always 32 bits,
0276      * and is generated by the second divide.
0277      */
0278     ACPI_DIV_64_BY_32(0, dividend_ovl.part.hi, divisor,
0279               quotient.part.hi, remainder32);
0280 
0281     ACPI_DIV_64_BY_32(remainder32, dividend_ovl.part.lo, divisor,
0282               quotient.part.lo, remainder32);
0283 
0284     /* Return only what was requested */
0285 
0286     if (out_quotient) {
0287         *out_quotient = quotient.full;
0288     }
0289     if (out_remainder) {
0290         *out_remainder = remainder32;
0291     }
0292 
0293     return_ACPI_STATUS(AE_OK);
0294 }
0295 
0296 /*******************************************************************************
0297  *
0298  * FUNCTION:    acpi_ut_divide
0299  *
0300  * PARAMETERS:  in_dividend         - Dividend
0301  *              in_divisor          - Divisor
0302  *              out_quotient        - Pointer to where the quotient is returned
0303  *              out_remainder       - Pointer to where the remainder is returned
0304  *
0305  * RETURN:      Status (Checks for divide-by-zero)
0306  *
0307  * DESCRIPTION: Perform a divide and modulo.
0308  *
0309  ******************************************************************************/
0310 
0311 acpi_status
0312 acpi_ut_divide(u64 in_dividend,
0313            u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
0314 {
0315     union uint64_overlay dividend;
0316     union uint64_overlay divisor;
0317     union uint64_overlay quotient;
0318     union uint64_overlay remainder;
0319     union uint64_overlay normalized_dividend;
0320     union uint64_overlay normalized_divisor;
0321     u32 partial1;
0322     union uint64_overlay partial2;
0323     union uint64_overlay partial3;
0324 
0325     ACPI_FUNCTION_TRACE(ut_divide);
0326 
0327     /* Always check for a zero divisor */
0328 
0329     if (in_divisor == 0) {
0330         ACPI_ERROR((AE_INFO, "Divide by zero"));
0331         return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
0332     }
0333 
0334     divisor.full = in_divisor;
0335     dividend.full = in_dividend;
0336     if (divisor.part.hi == 0) {
0337         /*
0338          * 1) Simplest case is where the divisor is 32 bits, we can
0339          * just do two divides
0340          */
0341         remainder.part.hi = 0;
0342 
0343         /*
0344          * The quotient is 64 bits, the remainder is always 32 bits,
0345          * and is generated by the second divide.
0346          */
0347         ACPI_DIV_64_BY_32(0, dividend.part.hi, divisor.part.lo,
0348                   quotient.part.hi, partial1);
0349 
0350         ACPI_DIV_64_BY_32(partial1, dividend.part.lo, divisor.part.lo,
0351                   quotient.part.lo, remainder.part.lo);
0352     }
0353 
0354     else {
0355         /*
0356          * 2) The general case where the divisor is a full 64 bits
0357          * is more difficult
0358          */
0359         quotient.part.hi = 0;
0360         normalized_dividend = dividend;
0361         normalized_divisor = divisor;
0362 
0363         /* Normalize the operands (shift until the divisor is < 32 bits) */
0364 
0365         do {
0366             ACPI_SHIFT_RIGHT_64(normalized_divisor.part.hi,
0367                         normalized_divisor.part.lo);
0368             ACPI_SHIFT_RIGHT_64(normalized_dividend.part.hi,
0369                         normalized_dividend.part.lo);
0370 
0371         } while (normalized_divisor.part.hi != 0);
0372 
0373         /* Partial divide */
0374 
0375         ACPI_DIV_64_BY_32(normalized_dividend.part.hi,
0376                   normalized_dividend.part.lo,
0377                   normalized_divisor.part.lo, quotient.part.lo,
0378                   partial1);
0379 
0380         /*
0381          * The quotient is always 32 bits, and simply requires
0382          * adjustment. The 64-bit remainder must be generated.
0383          */
0384         partial1 = quotient.part.lo * divisor.part.hi;
0385         partial2.full = (u64) quotient.part.lo * divisor.part.lo;
0386         partial3.full = (u64) partial2.part.hi + partial1;
0387 
0388         remainder.part.hi = partial3.part.lo;
0389         remainder.part.lo = partial2.part.lo;
0390 
0391         if (partial3.part.hi == 0) {
0392             if (partial3.part.lo >= dividend.part.hi) {
0393                 if (partial3.part.lo == dividend.part.hi) {
0394                     if (partial2.part.lo > dividend.part.lo) {
0395                         quotient.part.lo--;
0396                         remainder.full -= divisor.full;
0397                     }
0398                 } else {
0399                     quotient.part.lo--;
0400                     remainder.full -= divisor.full;
0401                 }
0402             }
0403 
0404             remainder.full = remainder.full - dividend.full;
0405             remainder.part.hi = (u32)-((s32)remainder.part.hi);
0406             remainder.part.lo = (u32)-((s32)remainder.part.lo);
0407 
0408             if (remainder.part.lo) {
0409                 remainder.part.hi--;
0410             }
0411         }
0412     }
0413 
0414     /* Return only what was requested */
0415 
0416     if (out_quotient) {
0417         *out_quotient = quotient.full;
0418     }
0419     if (out_remainder) {
0420         *out_remainder = remainder.full;
0421     }
0422 
0423     return_ACPI_STATUS(AE_OK);
0424 }
0425 
0426 #else
0427 
0428 /*******************************************************************************
0429  *
0430  * FUNCTION:    acpi_ut_short_divide, acpi_ut_divide
0431  *
0432  * PARAMETERS:  See function headers above
0433  *
0434  * DESCRIPTION: Native versions of the ut_divide functions. Use these if either
0435  *              1) The target is a 64-bit platform and therefore 64-bit
0436  *                 integer math is supported directly by the machine.
0437  *              2) The target is a 32-bit or 16-bit platform, and the
0438  *                 double-precision integer math library is available to
0439  *                 perform the divide.
0440  *
0441  ******************************************************************************/
0442 
0443 acpi_status
0444 acpi_ut_short_divide(u64 in_dividend,
0445              u32 divisor, u64 *out_quotient, u32 *out_remainder)
0446 {
0447 
0448     ACPI_FUNCTION_TRACE(ut_short_divide);
0449 
0450     /* Always check for a zero divisor */
0451 
0452     if (divisor == 0) {
0453         ACPI_ERROR((AE_INFO, "Divide by zero"));
0454         return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
0455     }
0456 
0457     /* Return only what was requested */
0458 
0459     if (out_quotient) {
0460         *out_quotient = in_dividend / divisor;
0461     }
0462     if (out_remainder) {
0463         *out_remainder = (u32) (in_dividend % divisor);
0464     }
0465 
0466     return_ACPI_STATUS(AE_OK);
0467 }
0468 
0469 acpi_status
0470 acpi_ut_divide(u64 in_dividend,
0471            u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
0472 {
0473     ACPI_FUNCTION_TRACE(ut_divide);
0474 
0475     /* Always check for a zero divisor */
0476 
0477     if (in_divisor == 0) {
0478         ACPI_ERROR((AE_INFO, "Divide by zero"));
0479         return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
0480     }
0481 
0482     /* Return only what was requested */
0483 
0484     if (out_quotient) {
0485         *out_quotient = in_dividend / in_divisor;
0486     }
0487     if (out_remainder) {
0488         *out_remainder = in_dividend % in_divisor;
0489     }
0490 
0491     return_ACPI_STATUS(AE_OK);
0492 }
0493 
0494 #endif