184493Smsmith/*******************************************************************************
284493Smsmith *
384493Smsmith * Module Name: utmath - Integer math support routines
484493Smsmith *
584493Smsmith ******************************************************************************/
684493Smsmith
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
984493Smsmith * All rights reserved.
1084493Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2584493Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2984493Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4384493Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
4684493Smsmith
4784493Smsmith
4884493Smsmith#define _COMPONENT          ACPI_UTILITIES
4991116Smsmith        ACPI_MODULE_NAME    ("utmath")
5084493Smsmith
5184493Smsmith/*
52212761Sjkim * Optional support for 64-bit double-precision integer divide. This code
53212761Sjkim * is configurable and is implemented in order to support 32-bit kernel
54212761Sjkim * environments where a 64-bit double-precision math library is not available.
55212761Sjkim *
56212761Sjkim * Support for a more normal 64-bit divide/modulo (with check for a divide-
57212761Sjkim * by-zero) appears after this optional section of code.
5884493Smsmith */
59212761Sjkim#ifndef ACPI_USE_NATIVE_DIVIDE
6084493Smsmith
61212761Sjkim/* Structures used only for 64-bit divide */
62212761Sjkim
63212761Sjkimtypedef struct uint64_struct
64212761Sjkim{
65212761Sjkim    UINT32                          Lo;
66212761Sjkim    UINT32                          Hi;
67212761Sjkim
68212761Sjkim} UINT64_STRUCT;
69212761Sjkim
70212761Sjkimtypedef union uint64_overlay
71212761Sjkim{
72212761Sjkim    UINT64                          Full;
73212761Sjkim    UINT64_STRUCT                   Part;
74212761Sjkim
75212761Sjkim} UINT64_OVERLAY;
76212761Sjkim
77212761Sjkim
7884493Smsmith/*******************************************************************************
7984493Smsmith *
8084493Smsmith * FUNCTION:    AcpiUtShortDivide
8184493Smsmith *
82138287Smarks * PARAMETERS:  Dividend            - 64-bit dividend
8384493Smsmith *              Divisor             - 32-bit divisor
8484493Smsmith *              OutQuotient         - Pointer to where the quotient is returned
8584493Smsmith *              OutRemainder        - Pointer to where the remainder is returned
8684493Smsmith *
8784493Smsmith * RETURN:      Status (Checks for divide-by-zero)
8884493Smsmith *
8984493Smsmith * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
90241973Sjkim *              divide and modulo. The result is a 64-bit quotient and a
9184493Smsmith *              32-bit remainder.
9284493Smsmith *
9384493Smsmith ******************************************************************************/
9484493Smsmith
9584493SmsmithACPI_STATUS
9684493SmsmithAcpiUtShortDivide (
97202771Sjkim    UINT64                  Dividend,
9884493Smsmith    UINT32                  Divisor,
99202771Sjkim    UINT64                  *OutQuotient,
10084493Smsmith    UINT32                  *OutRemainder)
10184493Smsmith{
102138287Smarks    UINT64_OVERLAY          DividendOvl;
10384493Smsmith    UINT64_OVERLAY          Quotient;
10484493Smsmith    UINT32                  Remainder32;
10584493Smsmith
10684493Smsmith
107167802Sjkim    ACPI_FUNCTION_TRACE (UtShortDivide);
10884493Smsmith
10984493Smsmith
11084493Smsmith    /* Always check for a zero divisor */
11184493Smsmith
11284493Smsmith    if (Divisor == 0)
11384493Smsmith    {
114167802Sjkim        ACPI_ERROR ((AE_INFO, "Divide by zero"));
11584493Smsmith        return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
11684493Smsmith    }
11784493Smsmith
118138287Smarks    DividendOvl.Full = Dividend;
119138287Smarks
12084493Smsmith    /*
12184493Smsmith     * The quotient is 64 bits, the remainder is always 32 bits,
12284493Smsmith     * and is generated by the second divide.
12384493Smsmith     */
124138287Smarks    ACPI_DIV_64_BY_32 (0, DividendOvl.Part.Hi, Divisor,
12584493Smsmith                       Quotient.Part.Hi, Remainder32);
126138287Smarks    ACPI_DIV_64_BY_32 (Remainder32, DividendOvl.Part.Lo, Divisor,
12784493Smsmith                       Quotient.Part.Lo, Remainder32);
12884493Smsmith
12984493Smsmith    /* Return only what was requested */
13084493Smsmith
13184493Smsmith    if (OutQuotient)
13284493Smsmith    {
13384493Smsmith        *OutQuotient = Quotient.Full;
13484493Smsmith    }
13584493Smsmith    if (OutRemainder)
13684493Smsmith    {
13784493Smsmith        *OutRemainder = Remainder32;
13884493Smsmith    }
13984493Smsmith
14084493Smsmith    return_ACPI_STATUS (AE_OK);
14184493Smsmith}
14284493Smsmith
14384493Smsmith
14484493Smsmith/*******************************************************************************
14584493Smsmith *
14684493Smsmith * FUNCTION:    AcpiUtDivide
14784493Smsmith *
148138287Smarks * PARAMETERS:  InDividend          - Dividend
149138287Smarks *              InDivisor           - Divisor
15084493Smsmith *              OutQuotient         - Pointer to where the quotient is returned
15184493Smsmith *              OutRemainder        - Pointer to where the remainder is returned
15284493Smsmith *
15384493Smsmith * RETURN:      Status (Checks for divide-by-zero)
15484493Smsmith *
15584493Smsmith * DESCRIPTION: Perform a divide and modulo.
15684493Smsmith *
15784493Smsmith ******************************************************************************/
15884493Smsmith
15984493SmsmithACPI_STATUS
16084493SmsmithAcpiUtDivide (
161202771Sjkim    UINT64                  InDividend,
162202771Sjkim    UINT64                  InDivisor,
163202771Sjkim    UINT64                  *OutQuotient,
164202771Sjkim    UINT64                  *OutRemainder)
16584493Smsmith{
16684493Smsmith    UINT64_OVERLAY          Dividend;
16784493Smsmith    UINT64_OVERLAY          Divisor;
16884493Smsmith    UINT64_OVERLAY          Quotient;
16984493Smsmith    UINT64_OVERLAY          Remainder;
17084493Smsmith    UINT64_OVERLAY          NormalizedDividend;
17184493Smsmith    UINT64_OVERLAY          NormalizedDivisor;
17284493Smsmith    UINT32                  Partial1;
17384493Smsmith    UINT64_OVERLAY          Partial2;
17484493Smsmith    UINT64_OVERLAY          Partial3;
17584493Smsmith
17684493Smsmith
177167802Sjkim    ACPI_FUNCTION_TRACE (UtDivide);
17884493Smsmith
17984493Smsmith
18084493Smsmith    /* Always check for a zero divisor */
18184493Smsmith
182138287Smarks    if (InDivisor == 0)
18384493Smsmith    {
184167802Sjkim        ACPI_ERROR ((AE_INFO, "Divide by zero"));
18584493Smsmith        return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
18684493Smsmith    }
18784493Smsmith
188138287Smarks    Divisor.Full  = InDivisor;
189138287Smarks    Dividend.Full = InDividend;
19084493Smsmith    if (Divisor.Part.Hi == 0)
19184493Smsmith    {
19284493Smsmith        /*
19384493Smsmith         * 1) Simplest case is where the divisor is 32 bits, we can
19484493Smsmith         * just do two divides
19584493Smsmith         */
19684493Smsmith        Remainder.Part.Hi = 0;
19784493Smsmith
19884493Smsmith        /*
19984493Smsmith         * The quotient is 64 bits, the remainder is always 32 bits,
20084493Smsmith         * and is generated by the second divide.
20184493Smsmith         */
20287031Smsmith        ACPI_DIV_64_BY_32 (0, Dividend.Part.Hi, Divisor.Part.Lo,
20384493Smsmith                           Quotient.Part.Hi, Partial1);
20487031Smsmith        ACPI_DIV_64_BY_32 (Partial1, Dividend.Part.Lo, Divisor.Part.Lo,
20584493Smsmith                           Quotient.Part.Lo, Remainder.Part.Lo);
20684493Smsmith    }
20784493Smsmith
20884493Smsmith    else
20984493Smsmith    {
21084493Smsmith        /*
21184493Smsmith         * 2) The general case where the divisor is a full 64 bits
21284493Smsmith         * is more difficult
21384493Smsmith         */
21484493Smsmith        Quotient.Part.Hi   = 0;
21584493Smsmith        NormalizedDividend = Dividend;
21684493Smsmith        NormalizedDivisor  = Divisor;
21784493Smsmith
21884493Smsmith        /* Normalize the operands (shift until the divisor is < 32 bits) */
21984493Smsmith
22084493Smsmith        do
22184493Smsmith        {
22287031Smsmith            ACPI_SHIFT_RIGHT_64 (NormalizedDivisor.Part.Hi,
22384493Smsmith                                 NormalizedDivisor.Part.Lo);
22487031Smsmith            ACPI_SHIFT_RIGHT_64 (NormalizedDividend.Part.Hi,
22584493Smsmith                                 NormalizedDividend.Part.Lo);
22684493Smsmith
22784493Smsmith        } while (NormalizedDivisor.Part.Hi != 0);
22884493Smsmith
22984493Smsmith        /* Partial divide */
23084493Smsmith
23187031Smsmith        ACPI_DIV_64_BY_32 (NormalizedDividend.Part.Hi,
23287031Smsmith                           NormalizedDividend.Part.Lo,
23387031Smsmith                           NormalizedDivisor.Part.Lo,
23484493Smsmith                           Quotient.Part.Lo, Partial1);
23584493Smsmith
23684493Smsmith        /*
23784493Smsmith         * The quotient is always 32 bits, and simply requires adjustment.
23884493Smsmith         * The 64-bit remainder must be generated.
23984493Smsmith         */
24084493Smsmith        Partial1      = Quotient.Part.Lo * Divisor.Part.Hi;
241202771Sjkim        Partial2.Full = (UINT64) Quotient.Part.Lo * Divisor.Part.Lo;
242202771Sjkim        Partial3.Full = (UINT64) Partial2.Part.Hi + Partial1;
24384493Smsmith
24484493Smsmith        Remainder.Part.Hi = Partial3.Part.Lo;
24584493Smsmith        Remainder.Part.Lo = Partial2.Part.Lo;
24684493Smsmith
24784493Smsmith        if (Partial3.Part.Hi == 0)
24884493Smsmith        {
24984493Smsmith            if (Partial3.Part.Lo >= Dividend.Part.Hi)
25084493Smsmith            {
25184493Smsmith                if (Partial3.Part.Lo == Dividend.Part.Hi)
25284493Smsmith                {
25384493Smsmith                    if (Partial2.Part.Lo > Dividend.Part.Lo)
25484493Smsmith                    {
25584493Smsmith                        Quotient.Part.Lo--;
25684493Smsmith                        Remainder.Full -= Divisor.Full;
25784493Smsmith                    }
25884493Smsmith                }
25984493Smsmith                else
26084493Smsmith                {
26184493Smsmith                    Quotient.Part.Lo--;
26284493Smsmith                    Remainder.Full -= Divisor.Full;
26384493Smsmith                }
26484493Smsmith            }
26584493Smsmith
26684493Smsmith            Remainder.Full    = Remainder.Full - Dividend.Full;
26799679Siwasaki            Remainder.Part.Hi = (UINT32) -((INT32) Remainder.Part.Hi);
26899679Siwasaki            Remainder.Part.Lo = (UINT32) -((INT32) Remainder.Part.Lo);
26984493Smsmith
27084493Smsmith            if (Remainder.Part.Lo)
27184493Smsmith            {
27284493Smsmith                Remainder.Part.Hi--;
27384493Smsmith            }
27484493Smsmith        }
27584493Smsmith    }
27684493Smsmith
27784493Smsmith    /* Return only what was requested */
27884493Smsmith
27984493Smsmith    if (OutQuotient)
28084493Smsmith    {
28184493Smsmith        *OutQuotient = Quotient.Full;
28284493Smsmith    }
28384493Smsmith    if (OutRemainder)
28484493Smsmith    {
28584493Smsmith        *OutRemainder = Remainder.Full;
28684493Smsmith    }
28784493Smsmith
28884493Smsmith    return_ACPI_STATUS (AE_OK);
28984493Smsmith}
29084493Smsmith
29184493Smsmith#else
29284493Smsmith
29384493Smsmith/*******************************************************************************
29484493Smsmith *
29584493Smsmith * FUNCTION:    AcpiUtShortDivide, AcpiUtDivide
29684493Smsmith *
297151937Sjkim * PARAMETERS:  See function headers above
298151937Sjkim *
29984493Smsmith * DESCRIPTION: Native versions of the UtDivide functions. Use these if either
30084493Smsmith *              1) The target is a 64-bit platform and therefore 64-bit
30184493Smsmith *                 integer math is supported directly by the machine.
30287031Smsmith *              2) The target is a 32-bit or 16-bit platform, and the
30387031Smsmith *                 double-precision integer math library is available to
30484493Smsmith *                 perform the divide.
30584493Smsmith *
30684493Smsmith ******************************************************************************/
30784493Smsmith
30884493SmsmithACPI_STATUS
30984493SmsmithAcpiUtShortDivide (
310202771Sjkim    UINT64                  InDividend,
31184493Smsmith    UINT32                  Divisor,
312202771Sjkim    UINT64                  *OutQuotient,
31384493Smsmith    UINT32                  *OutRemainder)
31484493Smsmith{
31584493Smsmith
316167802Sjkim    ACPI_FUNCTION_TRACE (UtShortDivide);
31784493Smsmith
31884493Smsmith
31984493Smsmith    /* Always check for a zero divisor */
32084493Smsmith
32184493Smsmith    if (Divisor == 0)
32284493Smsmith    {
323167802Sjkim        ACPI_ERROR ((AE_INFO, "Divide by zero"));
32484493Smsmith        return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
32584493Smsmith    }
32684493Smsmith
32784493Smsmith    /* Return only what was requested */
32884493Smsmith
32984493Smsmith    if (OutQuotient)
33084493Smsmith    {
331138287Smarks        *OutQuotient = InDividend / Divisor;
33284493Smsmith    }
33384493Smsmith    if (OutRemainder)
33484493Smsmith    {
335193267Sjkim        *OutRemainder = (UINT32) (InDividend % Divisor);
33684493Smsmith    }
33784493Smsmith
33884493Smsmith    return_ACPI_STATUS (AE_OK);
33984493Smsmith}
34084493Smsmith
34184493SmsmithACPI_STATUS
34284493SmsmithAcpiUtDivide (
343202771Sjkim    UINT64                  InDividend,
344202771Sjkim    UINT64                  InDivisor,
345202771Sjkim    UINT64                  *OutQuotient,
346202771Sjkim    UINT64                  *OutRemainder)
34784493Smsmith{
348167802Sjkim    ACPI_FUNCTION_TRACE (UtDivide);
34984493Smsmith
35084493Smsmith
35184493Smsmith    /* Always check for a zero divisor */
35284493Smsmith
353138287Smarks    if (InDivisor == 0)
35484493Smsmith    {
355167802Sjkim        ACPI_ERROR ((AE_INFO, "Divide by zero"));
35684493Smsmith        return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
35784493Smsmith    }
35884493Smsmith
35984493Smsmith
36084493Smsmith    /* Return only what was requested */
36184493Smsmith
36284493Smsmith    if (OutQuotient)
36384493Smsmith    {
364138287Smarks        *OutQuotient = InDividend / InDivisor;
36584493Smsmith    }
36684493Smsmith    if (OutRemainder)
36784493Smsmith    {
368138287Smarks        *OutRemainder = InDividend % InDivisor;
36984493Smsmith    }
37084493Smsmith
37185756Smsmith    return_ACPI_STATUS (AE_OK);
37284493Smsmith}
37384493Smsmith
37484493Smsmith#endif
375