PageRenderTime 27ms CodeModel.GetById 10ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/acpi/utilities/utmath.c

https://bitbucket.org/evzijst/gittest
C | 333 lines | 152 code | 63 blank | 118 comment | 29 complexity | fea1775731ecaa1508e78af14b660169 MD5 | raw file
  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