1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include <acpi/acpi.h>
45#include "accommon.h"
46
47#define _COMPONENT ACPI_UTILITIES
48ACPI_MODULE_NAME("utmath")
49
50
51
52
53
54
55
56
57
58#ifndef ACPI_USE_NATIVE_DIVIDE
59
60typedef struct uint64_struct {
61 u32 lo;
62 u32 hi;
63
64} uint64_struct;
65
66typedef union uint64_overlay {
67 u64 full;
68 struct uint64_struct part;
69
70} uint64_overlay;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89acpi_status
90acpi_ut_short_divide(u64 dividend,
91 u32 divisor, u64 *out_quotient, u32 *out_remainder)
92{
93 union uint64_overlay dividend_ovl;
94 union uint64_overlay quotient;
95 u32 remainder32;
96
97 ACPI_FUNCTION_TRACE(ut_short_divide);
98
99
100
101 if (divisor == 0) {
102 ACPI_ERROR((AE_INFO, "Divide by zero"));
103 return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
104 }
105
106 dividend_ovl.full = dividend;
107
108
109
110
111
112 ACPI_DIV_64_BY_32(0, dividend_ovl.part.hi, divisor,
113 quotient.part.hi, remainder32);
114 ACPI_DIV_64_BY_32(remainder32, dividend_ovl.part.lo, divisor,
115 quotient.part.lo, remainder32);
116
117
118
119 if (out_quotient) {
120 *out_quotient = quotient.full;
121 }
122 if (out_remainder) {
123 *out_remainder = remainder32;
124 }
125
126 return_ACPI_STATUS(AE_OK);
127}
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144acpi_status
145acpi_ut_divide(u64 in_dividend,
146 u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
147{
148 union uint64_overlay dividend;
149 union uint64_overlay divisor;
150 union uint64_overlay quotient;
151 union uint64_overlay remainder;
152 union uint64_overlay normalized_dividend;
153 union uint64_overlay normalized_divisor;
154 u32 partial1;
155 union uint64_overlay partial2;
156 union uint64_overlay partial3;
157
158 ACPI_FUNCTION_TRACE(ut_divide);
159
160
161
162 if (in_divisor == 0) {
163 ACPI_ERROR((AE_INFO, "Divide by zero"));
164 return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
165 }
166
167 divisor.full = in_divisor;
168 dividend.full = in_dividend;
169 if (divisor.part.hi == 0) {
170
171
172
173
174 remainder.part.hi = 0;
175
176
177
178
179
180 ACPI_DIV_64_BY_32(0, dividend.part.hi, divisor.part.lo,
181 quotient.part.hi, partial1);
182 ACPI_DIV_64_BY_32(partial1, dividend.part.lo, divisor.part.lo,
183 quotient.part.lo, remainder.part.lo);
184 }
185
186 else {
187
188
189
190
191 quotient.part.hi = 0;
192 normalized_dividend = dividend;
193 normalized_divisor = divisor;
194
195
196
197 do {
198 ACPI_SHIFT_RIGHT_64(normalized_divisor.part.hi,
199 normalized_divisor.part.lo);
200 ACPI_SHIFT_RIGHT_64(normalized_dividend.part.hi,
201 normalized_dividend.part.lo);
202
203 } while (normalized_divisor.part.hi != 0);
204
205
206
207 ACPI_DIV_64_BY_32(normalized_dividend.part.hi,
208 normalized_dividend.part.lo,
209 normalized_divisor.part.lo,
210 quotient.part.lo, partial1);
211
212
213
214
215
216 partial1 = quotient.part.lo * divisor.part.hi;
217 partial2.full = (u64) quotient.part.lo * divisor.part.lo;
218 partial3.full = (u64) partial2.part.hi + partial1;
219
220 remainder.part.hi = partial3.part.lo;
221 remainder.part.lo = partial2.part.lo;
222
223 if (partial3.part.hi == 0) {
224 if (partial3.part.lo >= dividend.part.hi) {
225 if (partial3.part.lo == dividend.part.hi) {
226 if (partial2.part.lo > dividend.part.lo) {
227 quotient.part.lo--;
228 remainder.full -= divisor.full;
229 }
230 } else {
231 quotient.part.lo--;
232 remainder.full -= divisor.full;
233 }
234 }
235
236 remainder.full = remainder.full - dividend.full;
237 remainder.part.hi = (u32) - ((s32) remainder.part.hi);
238 remainder.part.lo = (u32) - ((s32) remainder.part.lo);
239
240 if (remainder.part.lo) {
241 remainder.part.hi--;
242 }
243 }
244 }
245
246
247
248 if (out_quotient) {
249 *out_quotient = quotient.full;
250 }
251 if (out_remainder) {
252 *out_remainder = remainder.full;
253 }
254
255 return_ACPI_STATUS(AE_OK);
256}
257
258#else
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273acpi_status
274acpi_ut_short_divide(u64 in_dividend,
275 u32 divisor, u64 *out_quotient, u32 *out_remainder)
276{
277
278 ACPI_FUNCTION_TRACE(ut_short_divide);
279
280
281
282 if (divisor == 0) {
283 ACPI_ERROR((AE_INFO, "Divide by zero"));
284 return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
285 }
286
287
288
289 if (out_quotient) {
290 *out_quotient = in_dividend / divisor;
291 }
292 if (out_remainder) {
293 *out_remainder = (u32) (in_dividend % divisor);
294 }
295
296 return_ACPI_STATUS(AE_OK);
297}
298
299acpi_status
300acpi_ut_divide(u64 in_dividend,
301 u64 in_divisor, u64 *out_quotient, u64 *out_remainder)
302{
303 ACPI_FUNCTION_TRACE(ut_divide);
304
305
306
307 if (in_divisor == 0) {
308 ACPI_ERROR((AE_INFO, "Divide by zero"));
309 return_ACPI_STATUS(AE_AML_DIVIDE_BY_ZERO);
310 }
311
312
313
314 if (out_quotient) {
315 *out_quotient = in_dividend / in_divisor;
316 }
317 if (out_remainder) {
318 *out_remainder = in_dividend % in_divisor;
319 }
320
321 return_ACPI_STATUS(AE_OK);
322}
323
324#endif
325