aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/utilities/utmath.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/utilities/utmath.c')
-rw-r--r--drivers/acpi/utilities/utmath.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
new file mode 100644
index 000000000000..2525c1a93547
--- /dev/null
+++ b/drivers/acpi/utilities/utmath.c
@@ -0,0 +1,333 @@
1/*******************************************************************************
2 *
3 * Module Name: utmath - Integer math support routines
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2005, R. Byron Moore
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44
45#include <acpi/acpi.h>
46
47
48#define _COMPONENT ACPI_UTILITIES
49 ACPI_MODULE_NAME ("utmath")
50
51/*
52 * Support for double-precision integer divide. This code is included here
53 * in order to support kernel environments where the double-precision math
54 * library is not available.
55 */
56
57#ifndef ACPI_USE_NATIVE_DIVIDE
58/*******************************************************************************
59 *
60 * FUNCTION: acpi_ut_short_divide
61 *
62 * PARAMETERS: Dividend - 64-bit dividend
63 * Divisor - 32-bit divisor
64 * out_quotient - Pointer to where the quotient is returned
65 * out_remainder - Pointer to where the remainder is returned
66 *
67 * RETURN: Status (Checks for divide-by-zero)
68 *
69 * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
70 * divide and modulo. The result is a 64-bit quotient and a
71 * 32-bit remainder.
72 *
73 ******************************************************************************/
74
75acpi_status
76acpi_ut_short_divide (
77 acpi_integer dividend,
78 u32 divisor,
79 acpi_integer *out_quotient,
80 u32 *out_remainder)
81{
82 union uint64_overlay dividend_ovl;
83 union uint64_overlay quotient;
84 u32 remainder32;
85
86
87 ACPI_FUNCTION_TRACE ("ut_short_divide");
88
89
90 /* Always check for a zero divisor */
91
92 if (divisor == 0) {
93 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
94 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
95 }
96
97 dividend_ovl.full = dividend;
98
99 /*
100 * The quotient is 64 bits, the remainder is always 32 bits,
101 * and is generated by the second divide.
102 */
103 ACPI_DIV_64_BY_32 (0, dividend_ovl.part.hi, divisor,
104 quotient.part.hi, remainder32);
105 ACPI_DIV_64_BY_32 (remainder32, dividend_ovl.part.lo, divisor,
106 quotient.part.lo, remainder32);
107
108 /* Return only what was requested */
109
110 if (out_quotient) {
111 *out_quotient = quotient.full;
112 }
113 if (out_remainder) {
114 *out_remainder = remainder32;
115 }
116
117 return_ACPI_STATUS (AE_OK);
118}
119
120
121/*******************************************************************************
122 *
123 * FUNCTION: acpi_ut_divide
124 *
125 * PARAMETERS: in_dividend - Dividend
126 * in_divisor - Divisor
127 * out_quotient - Pointer to where the quotient is returned
128 * out_remainder - Pointer to where the remainder is returned
129 *
130 * RETURN: Status (Checks for divide-by-zero)
131 *
132 * DESCRIPTION: Perform a divide and modulo.
133 *
134 ******************************************************************************/
135
136acpi_status
137acpi_ut_divide (
138 acpi_integer in_dividend,
139 acpi_integer in_divisor,
140 acpi_integer *out_quotient,
141 acpi_integer *out_remainder)
142{
143 union uint64_overlay dividend;
144 union uint64_overlay divisor;
145 union uint64_overlay quotient;
146 union uint64_overlay remainder;
147 union uint64_overlay normalized_dividend;
148 union uint64_overlay normalized_divisor;
149 u32 partial1;
150 union uint64_overlay partial2;
151 union uint64_overlay partial3;
152
153
154 ACPI_FUNCTION_TRACE ("ut_divide");
155
156
157 /* Always check for a zero divisor */
158
159 if (in_divisor == 0) {
160 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
161 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
162 }
163
164 divisor.full = in_divisor;
165 dividend.full = in_dividend;
166 if (divisor.part.hi == 0) {
167 /*
168 * 1) Simplest case is where the divisor is 32 bits, we can
169 * just do two divides
170 */
171 remainder.part.hi = 0;
172
173 /*
174 * The quotient is 64 bits, the remainder is always 32 bits,
175 * and is generated by the second divide.
176 */
177 ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor.part.lo,
178 quotient.part.hi, partial1);
179 ACPI_DIV_64_BY_32 (partial1, dividend.part.lo, divisor.part.lo,
180 quotient.part.lo, remainder.part.lo);
181 }
182
183 else {
184 /*
185 * 2) The general case where the divisor is a full 64 bits
186 * is more difficult
187 */
188 quotient.part.hi = 0;
189 normalized_dividend = dividend;
190 normalized_divisor = divisor;
191
192 /* Normalize the operands (shift until the divisor is < 32 bits) */
193
194 do {
195 ACPI_SHIFT_RIGHT_64 (normalized_divisor.part.hi,
196 normalized_divisor.part.lo);
197 ACPI_SHIFT_RIGHT_64 (normalized_dividend.part.hi,
198 normalized_dividend.part.lo);
199
200 } while (normalized_divisor.part.hi != 0);
201
202 /* Partial divide */
203
204 ACPI_DIV_64_BY_32 (normalized_dividend.part.hi,
205 normalized_dividend.part.lo,
206 normalized_divisor.part.lo,
207 quotient.part.lo, partial1);
208
209 /*
210 * The quotient is always 32 bits, and simply requires adjustment.
211 * The 64-bit remainder must be generated.
212 */
213 partial1 = quotient.part.lo * divisor.part.hi;
214 partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo;
215 partial3.full = (acpi_integer) partial2.part.hi + partial1;
216
217 remainder.part.hi = partial3.part.lo;
218 remainder.part.lo = partial2.part.lo;
219
220 if (partial3.part.hi == 0) {
221 if (partial3.part.lo >= dividend.part.hi) {
222 if (partial3.part.lo == dividend.part.hi) {
223 if (partial2.part.lo > dividend.part.lo) {
224 quotient.part.lo--;
225 remainder.full -= divisor.full;
226 }
227 }
228 else {
229 quotient.part.lo--;
230 remainder.full -= divisor.full;
231 }
232 }
233
234 remainder.full = remainder.full - dividend.full;
235 remainder.part.hi = (u32) -((s32) remainder.part.hi);
236 remainder.part.lo = (u32) -((s32) remainder.part.lo);
237
238 if (remainder.part.lo) {
239 remainder.part.hi--;
240 }
241 }
242 }
243
244 /* Return only what was requested */
245
246 if (out_quotient) {
247 *out_quotient = quotient.full;
248 }
249 if (out_remainder) {
250 *out_remainder = remainder.full;
251 }
252
253 return_ACPI_STATUS (AE_OK);
254}
255
256#else
257
258/*******************************************************************************
259 *
260 * FUNCTION: acpi_ut_short_divide, acpi_ut_divide
261 *
262 * DESCRIPTION: Native versions of the ut_divide functions. Use these if either
263 * 1) The target is a 64-bit platform and therefore 64-bit
264 * integer math is supported directly by the machine.
265 * 2) The target is a 32-bit or 16-bit platform, and the
266 * double-precision integer math library is available to
267 * perform the divide.
268 *
269 ******************************************************************************/
270
271acpi_status
272acpi_ut_short_divide (
273 acpi_integer in_dividend,
274 u32 divisor,
275 acpi_integer *out_quotient,
276 u32 *out_remainder)
277{
278
279 ACPI_FUNCTION_TRACE ("ut_short_divide");
280
281
282 /* Always check for a zero divisor */
283
284 if (divisor == 0) {
285 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
286 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
287 }
288
289 /* Return only what was requested */
290
291 if (out_quotient) {
292 *out_quotient = in_dividend / divisor;
293 }
294 if (out_remainder) {
295 *out_remainder = (u32) in_dividend % divisor;
296 }
297
298 return_ACPI_STATUS (AE_OK);
299}
300
301acpi_status
302acpi_ut_divide (
303 acpi_integer in_dividend,
304 acpi_integer in_divisor,
305 acpi_integer *out_quotient,
306 acpi_integer *out_remainder)
307{
308 ACPI_FUNCTION_TRACE ("ut_divide");
309
310
311 /* Always check for a zero divisor */
312
313 if (in_divisor == 0) {
314 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
315 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
316 }
317
318
319 /* Return only what was requested */
320
321 if (out_quotient) {
322 *out_quotient = in_dividend / in_divisor;
323 }
324 if (out_remainder) {
325 *out_remainder = in_dividend % in_divisor;
326 }
327
328 return_ACPI_STATUS (AE_OK);
329}
330
331#endif
332
333