diff options
Diffstat (limited to 'drivers/acpi/utilities/utmath.c')
-rw-r--r-- | drivers/acpi/utilities/utmath.c | 333 |
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 | |||
75 | acpi_status | ||
76 | acpi_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 | |||
136 | acpi_status | ||
137 | acpi_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 | |||
271 | acpi_status | ||
272 | acpi_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 | |||
301 | acpi_status | ||
302 | acpi_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 | |||