diff options
Diffstat (limited to 'drivers/acpi/acpica/utmath.c')
-rw-r--r-- | drivers/acpi/acpica/utmath.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c new file mode 100644 index 000000000000..c9f682d640ef --- /dev/null +++ b/drivers/acpi/acpica/utmath.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Module Name: utmath - Integer math support routines | ||
4 | * | ||
5 | ******************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2008, Intel Corp. | ||
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 | #include <acpi/acpi.h> | ||
45 | #include "accommon.h" | ||
46 | |||
47 | #define _COMPONENT ACPI_UTILITIES | ||
48 | ACPI_MODULE_NAME("utmath") | ||
49 | |||
50 | /* | ||
51 | * Support for double-precision integer divide. This code is included here | ||
52 | * in order to support kernel environments where the double-precision math | ||
53 | * library is not available. | ||
54 | */ | ||
55 | #ifndef ACPI_USE_NATIVE_DIVIDE | ||
56 | /******************************************************************************* | ||
57 | * | ||
58 | * FUNCTION: acpi_ut_short_divide | ||
59 | * | ||
60 | * PARAMETERS: Dividend - 64-bit dividend | ||
61 | * Divisor - 32-bit divisor | ||
62 | * out_quotient - Pointer to where the quotient is returned | ||
63 | * out_remainder - Pointer to where the remainder is returned | ||
64 | * | ||
65 | * RETURN: Status (Checks for divide-by-zero) | ||
66 | * | ||
67 | * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) | ||
68 | * divide and modulo. The result is a 64-bit quotient and a | ||
69 | * 32-bit remainder. | ||
70 | * | ||
71 | ******************************************************************************/ | ||
72 | acpi_status | ||
73 | acpi_ut_short_divide(acpi_integer dividend, | ||
74 | u32 divisor, | ||
75 | acpi_integer * out_quotient, u32 * out_remainder) | ||
76 | { | ||
77 | union uint64_overlay dividend_ovl; | ||
78 | union uint64_overlay quotient; | ||
79 | u32 remainder32; | ||
80 | |||
81 | ACPI_FUNCTION_TRACE(ut_short_divide); | ||
82 | |||
83 | /* Always check for a zero divisor */ | ||
84 | |||
85 | if (divisor == 0) { | ||
86 | ACPI_ERROR((AE_INFO, "Divide by zero")); | ||
87 | return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); | ||
88 | } | ||
89 | |||
90 | dividend_ovl.full = dividend; | ||
91 | |||
92 | /* | ||
93 | * The quotient is 64 bits, the remainder is always 32 bits, | ||
94 | * and is generated by the second divide. | ||
95 | */ | ||
96 | ACPI_DIV_64_BY_32(0, dividend_ovl.part.hi, divisor, | ||
97 | quotient.part.hi, remainder32); | ||
98 | ACPI_DIV_64_BY_32(remainder32, dividend_ovl.part.lo, divisor, | ||
99 | quotient.part.lo, remainder32); | ||
100 | |||
101 | /* Return only what was requested */ | ||
102 | |||
103 | if (out_quotient) { | ||
104 | *out_quotient = quotient.full; | ||
105 | } | ||
106 | if (out_remainder) { | ||
107 | *out_remainder = remainder32; | ||
108 | } | ||
109 | |||
110 | return_ACPI_STATUS(AE_OK); | ||
111 | } | ||
112 | |||
113 | /******************************************************************************* | ||
114 | * | ||
115 | * FUNCTION: acpi_ut_divide | ||
116 | * | ||
117 | * PARAMETERS: in_dividend - Dividend | ||
118 | * in_divisor - Divisor | ||
119 | * out_quotient - Pointer to where the quotient is returned | ||
120 | * out_remainder - Pointer to where the remainder is returned | ||
121 | * | ||
122 | * RETURN: Status (Checks for divide-by-zero) | ||
123 | * | ||
124 | * DESCRIPTION: Perform a divide and modulo. | ||
125 | * | ||
126 | ******************************************************************************/ | ||
127 | |||
128 | acpi_status | ||
129 | acpi_ut_divide(acpi_integer in_dividend, | ||
130 | acpi_integer in_divisor, | ||
131 | acpi_integer * out_quotient, acpi_integer * out_remainder) | ||
132 | { | ||
133 | union uint64_overlay dividend; | ||
134 | union uint64_overlay divisor; | ||
135 | union uint64_overlay quotient; | ||
136 | union uint64_overlay remainder; | ||
137 | union uint64_overlay normalized_dividend; | ||
138 | union uint64_overlay normalized_divisor; | ||
139 | u32 partial1; | ||
140 | union uint64_overlay partial2; | ||
141 | union uint64_overlay partial3; | ||
142 | |||
143 | ACPI_FUNCTION_TRACE(ut_divide); | ||
144 | |||
145 | /* Always check for a zero divisor */ | ||
146 | |||
147 | if (in_divisor == 0) { | ||
148 | ACPI_ERROR((AE_INFO, "Divide by zero")); | ||
149 | return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); | ||
150 | } | ||
151 | |||
152 | divisor.full = in_divisor; | ||
153 | dividend.full = in_dividend; | ||
154 | if (divisor.part.hi == 0) { | ||
155 | /* | ||
156 | * 1) Simplest case is where the divisor is 32 bits, we can | ||
157 | * just do two divides | ||
158 | */ | ||
159 | remainder.part.hi = 0; | ||
160 | |||
161 | /* | ||
162 | * The quotient is 64 bits, the remainder is always 32 bits, | ||
163 | * and is generated by the second divide. | ||
164 | */ | ||
165 | ACPI_DIV_64_BY_32(0, dividend.part.hi, divisor.part.lo, | ||
166 | quotient.part.hi, partial1); | ||
167 | ACPI_DIV_64_BY_32(partial1, dividend.part.lo, divisor.part.lo, | ||
168 | quotient.part.lo, remainder.part.lo); | ||
169 | } | ||
170 | |||
171 | else { | ||
172 | /* | ||
173 | * 2) The general case where the divisor is a full 64 bits | ||
174 | * is more difficult | ||
175 | */ | ||
176 | quotient.part.hi = 0; | ||
177 | normalized_dividend = dividend; | ||
178 | normalized_divisor = divisor; | ||
179 | |||
180 | /* Normalize the operands (shift until the divisor is < 32 bits) */ | ||
181 | |||
182 | do { | ||
183 | ACPI_SHIFT_RIGHT_64(normalized_divisor.part.hi, | ||
184 | normalized_divisor.part.lo); | ||
185 | ACPI_SHIFT_RIGHT_64(normalized_dividend.part.hi, | ||
186 | normalized_dividend.part.lo); | ||
187 | |||
188 | } while (normalized_divisor.part.hi != 0); | ||
189 | |||
190 | /* Partial divide */ | ||
191 | |||
192 | ACPI_DIV_64_BY_32(normalized_dividend.part.hi, | ||
193 | normalized_dividend.part.lo, | ||
194 | normalized_divisor.part.lo, | ||
195 | quotient.part.lo, partial1); | ||
196 | |||
197 | /* | ||
198 | * The quotient is always 32 bits, and simply requires adjustment. | ||
199 | * The 64-bit remainder must be generated. | ||
200 | */ | ||
201 | partial1 = quotient.part.lo * divisor.part.hi; | ||
202 | partial2.full = | ||
203 | (acpi_integer) quotient.part.lo * divisor.part.lo; | ||
204 | partial3.full = (acpi_integer) partial2.part.hi + partial1; | ||
205 | |||
206 | remainder.part.hi = partial3.part.lo; | ||
207 | remainder.part.lo = partial2.part.lo; | ||
208 | |||
209 | if (partial3.part.hi == 0) { | ||
210 | if (partial3.part.lo >= dividend.part.hi) { | ||
211 | if (partial3.part.lo == dividend.part.hi) { | ||
212 | if (partial2.part.lo > dividend.part.lo) { | ||
213 | quotient.part.lo--; | ||
214 | remainder.full -= divisor.full; | ||
215 | } | ||
216 | } else { | ||
217 | quotient.part.lo--; | ||
218 | remainder.full -= divisor.full; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | remainder.full = remainder.full - dividend.full; | ||
223 | remainder.part.hi = (u32) - ((s32) remainder.part.hi); | ||
224 | remainder.part.lo = (u32) - ((s32) remainder.part.lo); | ||
225 | |||
226 | if (remainder.part.lo) { | ||
227 | remainder.part.hi--; | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | /* Return only what was requested */ | ||
233 | |||
234 | if (out_quotient) { | ||
235 | *out_quotient = quotient.full; | ||
236 | } | ||
237 | if (out_remainder) { | ||
238 | *out_remainder = remainder.full; | ||
239 | } | ||
240 | |||
241 | return_ACPI_STATUS(AE_OK); | ||
242 | } | ||
243 | |||
244 | #else | ||
245 | /******************************************************************************* | ||
246 | * | ||
247 | * FUNCTION: acpi_ut_short_divide, acpi_ut_divide | ||
248 | * | ||
249 | * PARAMETERS: See function headers above | ||
250 | * | ||
251 | * DESCRIPTION: Native versions of the ut_divide functions. Use these if either | ||
252 | * 1) The target is a 64-bit platform and therefore 64-bit | ||
253 | * integer math is supported directly by the machine. | ||
254 | * 2) The target is a 32-bit or 16-bit platform, and the | ||
255 | * double-precision integer math library is available to | ||
256 | * perform the divide. | ||
257 | * | ||
258 | ******************************************************************************/ | ||
259 | acpi_status | ||
260 | acpi_ut_short_divide(acpi_integer in_dividend, | ||
261 | u32 divisor, | ||
262 | acpi_integer * out_quotient, u32 * out_remainder) | ||
263 | { | ||
264 | |||
265 | ACPI_FUNCTION_TRACE(ut_short_divide); | ||
266 | |||
267 | /* Always check for a zero divisor */ | ||
268 | |||
269 | if (divisor == 0) { | ||
270 | ACPI_ERROR((AE_INFO, "Divide by zero")); | ||
271 | return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); | ||
272 | } | ||
273 | |||
274 | /* Return only what was requested */ | ||
275 | |||
276 | if (out_quotient) { | ||
277 | *out_quotient = in_dividend / divisor; | ||
278 | } | ||
279 | if (out_remainder) { | ||
280 | *out_remainder = (u32) (in_dividend % divisor); | ||
281 | } | ||
282 | |||
283 | return_ACPI_STATUS(AE_OK); | ||
284 | } | ||
285 | |||
286 | acpi_status | ||
287 | acpi_ut_divide(acpi_integer in_dividend, | ||
288 | acpi_integer in_divisor, | ||
289 | acpi_integer * out_quotient, acpi_integer * out_remainder) | ||
290 | { | ||
291 | ACPI_FUNCTION_TRACE(ut_divide); | ||
292 | |||
293 | /* Always check for a zero divisor */ | ||
294 | |||
295 | if (in_divisor == 0) { | ||
296 | ACPI_ERROR((AE_INFO, "Divide by zero")); | ||
297 | return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO); | ||
298 | } | ||
299 | |||
300 | /* Return only what was requested */ | ||
301 | |||
302 | if (out_quotient) { | ||
303 | *out_quotient = in_dividend / in_divisor; | ||
304 | } | ||
305 | if (out_remainder) { | ||
306 | *out_remainder = in_dividend % in_divisor; | ||
307 | } | ||
308 | |||
309 | return_ACPI_STATUS(AE_OK); | ||
310 | } | ||
311 | |||
312 | #endif | ||