at v2.6.13 335 lines 10 kB view raw
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 * PARAMETERS: See function headers above 263 * 264 * DESCRIPTION: Native versions of the ut_divide functions. Use these if either 265 * 1) The target is a 64-bit platform and therefore 64-bit 266 * integer math is supported directly by the machine. 267 * 2) The target is a 32-bit or 16-bit platform, and the 268 * double-precision integer math library is available to 269 * perform the divide. 270 * 271 ******************************************************************************/ 272 273acpi_status 274acpi_ut_short_divide ( 275 acpi_integer in_dividend, 276 u32 divisor, 277 acpi_integer *out_quotient, 278 u32 *out_remainder) 279{ 280 281 ACPI_FUNCTION_TRACE ("ut_short_divide"); 282 283 284 /* Always check for a zero divisor */ 285 286 if (divisor == 0) { 287 ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n")); 288 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 289 } 290 291 /* Return only what was requested */ 292 293 if (out_quotient) { 294 *out_quotient = in_dividend / divisor; 295 } 296 if (out_remainder) { 297 *out_remainder = (u32) in_dividend % divisor; 298 } 299 300 return_ACPI_STATUS (AE_OK); 301} 302 303acpi_status 304acpi_ut_divide ( 305 acpi_integer in_dividend, 306 acpi_integer in_divisor, 307 acpi_integer *out_quotient, 308 acpi_integer *out_remainder) 309{ 310 ACPI_FUNCTION_TRACE ("ut_divide"); 311 312 313 /* Always check for a zero divisor */ 314 315 if (in_divisor == 0) { 316 ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n")); 317 return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 318 } 319 320 321 /* Return only what was requested */ 322 323 if (out_quotient) { 324 *out_quotient = in_dividend / in_divisor; 325 } 326 if (out_remainder) { 327 *out_remainder = in_dividend % in_divisor; 328 } 329 330 return_ACPI_STATUS (AE_OK); 331} 332 333#endif 334 335