rscalc.c revision 217365
1/******************************************************************************* 2 * 3 * Module Name: rscalc - Calculate stream and list lengths 4 * 5 ******************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2011, 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#define __RSCALC_C__ 45 46#include <contrib/dev/acpica/include/acpi.h> 47#include <contrib/dev/acpica/include/accommon.h> 48#include <contrib/dev/acpica/include/acresrc.h> 49#include <contrib/dev/acpica/include/acnamesp.h> 50 51 52#define _COMPONENT ACPI_RESOURCES 53 ACPI_MODULE_NAME ("rscalc") 54 55 56/* Local prototypes */ 57 58static UINT8 59AcpiRsCountSetBits ( 60 UINT16 BitField); 61 62static ACPI_RS_LENGTH 63AcpiRsStructOptionLength ( 64 ACPI_RESOURCE_SOURCE *ResourceSource); 65 66static UINT32 67AcpiRsStreamOptionLength ( 68 UINT32 ResourceLength, 69 UINT32 MinimumTotalLength); 70 71 72/******************************************************************************* 73 * 74 * FUNCTION: AcpiRsCountSetBits 75 * 76 * PARAMETERS: BitField - Field in which to count bits 77 * 78 * RETURN: Number of bits set within the field 79 * 80 * DESCRIPTION: Count the number of bits set in a resource field. Used for 81 * (Short descriptor) interrupt and DMA lists. 82 * 83 ******************************************************************************/ 84 85static UINT8 86AcpiRsCountSetBits ( 87 UINT16 BitField) 88{ 89 UINT8 BitsSet; 90 91 92 ACPI_FUNCTION_ENTRY (); 93 94 95 for (BitsSet = 0; BitField; BitsSet++) 96 { 97 /* Zero the least significant bit that is set */ 98 99 BitField &= (UINT16) (BitField - 1); 100 } 101 102 return (BitsSet); 103} 104 105 106/******************************************************************************* 107 * 108 * FUNCTION: AcpiRsStructOptionLength 109 * 110 * PARAMETERS: ResourceSource - Pointer to optional descriptor field 111 * 112 * RETURN: Status 113 * 114 * DESCRIPTION: Common code to handle optional ResourceSourceIndex and 115 * ResourceSource fields in some Large descriptors. Used during 116 * list-to-stream conversion 117 * 118 ******************************************************************************/ 119 120static ACPI_RS_LENGTH 121AcpiRsStructOptionLength ( 122 ACPI_RESOURCE_SOURCE *ResourceSource) 123{ 124 ACPI_FUNCTION_ENTRY (); 125 126 127 /* 128 * If the ResourceSource string is valid, return the size of the string 129 * (StringLength includes the NULL terminator) plus the size of the 130 * ResourceSourceIndex (1). 131 */ 132 if (ResourceSource->StringPtr) 133 { 134 return ((ACPI_RS_LENGTH) (ResourceSource->StringLength + 1)); 135 } 136 137 return (0); 138} 139 140 141/******************************************************************************* 142 * 143 * FUNCTION: AcpiRsStreamOptionLength 144 * 145 * PARAMETERS: ResourceLength - Length from the resource header 146 * MinimumTotalLength - Minimum length of this resource, before 147 * any optional fields. Includes header size 148 * 149 * RETURN: Length of optional string (0 if no string present) 150 * 151 * DESCRIPTION: Common code to handle optional ResourceSourceIndex and 152 * ResourceSource fields in some Large descriptors. Used during 153 * stream-to-list conversion 154 * 155 ******************************************************************************/ 156 157static UINT32 158AcpiRsStreamOptionLength ( 159 UINT32 ResourceLength, 160 UINT32 MinimumAmlResourceLength) 161{ 162 UINT32 StringLength = 0; 163 164 165 ACPI_FUNCTION_ENTRY (); 166 167 168 /* 169 * The ResourceSourceIndex and ResourceSource are optional elements of some 170 * Large-type resource descriptors. 171 */ 172 173 /* 174 * If the length of the actual resource descriptor is greater than the ACPI 175 * spec-defined minimum length, it means that a ResourceSourceIndex exists 176 * and is followed by a (required) null terminated string. The string length 177 * (including the null terminator) is the resource length minus the minimum 178 * length, minus one byte for the ResourceSourceIndex itself. 179 */ 180 if (ResourceLength > MinimumAmlResourceLength) 181 { 182 /* Compute the length of the optional string */ 183 184 StringLength = ResourceLength - MinimumAmlResourceLength - 1; 185 } 186 187 /* 188 * Round the length up to a multiple of the native word in order to 189 * guarantee that the entire resource descriptor is native word aligned 190 */ 191 return ((UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (StringLength)); 192} 193 194 195/******************************************************************************* 196 * 197 * FUNCTION: AcpiRsGetAmlLength 198 * 199 * PARAMETERS: Resource - Pointer to the resource linked list 200 * SizeNeeded - Where the required size is returned 201 * 202 * RETURN: Status 203 * 204 * DESCRIPTION: Takes a linked list of internal resource descriptors and 205 * calculates the size buffer needed to hold the corresponding 206 * external resource byte stream. 207 * 208 ******************************************************************************/ 209 210ACPI_STATUS 211AcpiRsGetAmlLength ( 212 ACPI_RESOURCE *Resource, 213 ACPI_SIZE *SizeNeeded) 214{ 215 ACPI_SIZE AmlSizeNeeded = 0; 216 ACPI_RS_LENGTH TotalSize; 217 218 219 ACPI_FUNCTION_TRACE (RsGetAmlLength); 220 221 222 /* Traverse entire list of internal resource descriptors */ 223 224 while (Resource) 225 { 226 /* Validate the descriptor type */ 227 228 if (Resource->Type > ACPI_RESOURCE_TYPE_MAX) 229 { 230 return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE); 231 } 232 233 /* Get the base size of the (external stream) resource descriptor */ 234 235 TotalSize = AcpiGbl_AmlResourceSizes [Resource->Type]; 236 237 /* 238 * Augment the base size for descriptors with optional and/or 239 * variable-length fields 240 */ 241 switch (Resource->Type) 242 { 243 case ACPI_RESOURCE_TYPE_IRQ: 244 245 /* Length can be 3 or 2 */ 246 247 if (Resource->Data.Irq.DescriptorLength == 2) 248 { 249 TotalSize--; 250 } 251 break; 252 253 254 case ACPI_RESOURCE_TYPE_START_DEPENDENT: 255 256 /* Length can be 1 or 0 */ 257 258 if (Resource->Data.Irq.DescriptorLength == 0) 259 { 260 TotalSize--; 261 } 262 break; 263 264 265 case ACPI_RESOURCE_TYPE_VENDOR: 266 /* 267 * Vendor Defined Resource: 268 * For a Vendor Specific resource, if the Length is between 1 and 7 269 * it will be created as a Small Resource data type, otherwise it 270 * is a Large Resource data type. 271 */ 272 if (Resource->Data.Vendor.ByteLength > 7) 273 { 274 /* Base size of a Large resource descriptor */ 275 276 TotalSize = sizeof (AML_RESOURCE_LARGE_HEADER); 277 } 278 279 /* Add the size of the vendor-specific data */ 280 281 TotalSize = (ACPI_RS_LENGTH) 282 (TotalSize + Resource->Data.Vendor.ByteLength); 283 break; 284 285 286 case ACPI_RESOURCE_TYPE_END_TAG: 287 /* 288 * End Tag: 289 * We are done -- return the accumulated total size. 290 */ 291 *SizeNeeded = AmlSizeNeeded + TotalSize; 292 293 /* Normal exit */ 294 295 return_ACPI_STATUS (AE_OK); 296 297 298 case ACPI_RESOURCE_TYPE_ADDRESS16: 299 /* 300 * 16-Bit Address Resource: 301 * Add the size of the optional ResourceSource info 302 */ 303 TotalSize = (ACPI_RS_LENGTH) 304 (TotalSize + AcpiRsStructOptionLength ( 305 &Resource->Data.Address16.ResourceSource)); 306 break; 307 308 309 case ACPI_RESOURCE_TYPE_ADDRESS32: 310 /* 311 * 32-Bit Address Resource: 312 * Add the size of the optional ResourceSource info 313 */ 314 TotalSize = (ACPI_RS_LENGTH) 315 (TotalSize + AcpiRsStructOptionLength ( 316 &Resource->Data.Address32.ResourceSource)); 317 break; 318 319 320 case ACPI_RESOURCE_TYPE_ADDRESS64: 321 /* 322 * 64-Bit Address Resource: 323 * Add the size of the optional ResourceSource info 324 */ 325 TotalSize = (ACPI_RS_LENGTH) 326 (TotalSize + AcpiRsStructOptionLength ( 327 &Resource->Data.Address64.ResourceSource)); 328 break; 329 330 331 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 332 /* 333 * Extended IRQ Resource: 334 * Add the size of each additional optional interrupt beyond the 335 * required 1 (4 bytes for each UINT32 interrupt number) 336 */ 337 TotalSize = (ACPI_RS_LENGTH) 338 (TotalSize + 339 ((Resource->Data.ExtendedIrq.InterruptCount - 1) * 4) + 340 341 /* Add the size of the optional ResourceSource info */ 342 343 AcpiRsStructOptionLength ( 344 &Resource->Data.ExtendedIrq.ResourceSource)); 345 break; 346 347 348 default: 349 break; 350 } 351 352 /* Update the total */ 353 354 AmlSizeNeeded += TotalSize; 355 356 /* Point to the next object */ 357 358 Resource = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, Resource->Length); 359 } 360 361 /* Did not find an EndTag resource descriptor */ 362 363 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 364} 365 366 367/******************************************************************************* 368 * 369 * FUNCTION: AcpiRsGetListLength 370 * 371 * PARAMETERS: AmlBuffer - Pointer to the resource byte stream 372 * AmlBufferLength - Size of AmlBuffer 373 * SizeNeeded - Where the size needed is returned 374 * 375 * RETURN: Status 376 * 377 * DESCRIPTION: Takes an external resource byte stream and calculates the size 378 * buffer needed to hold the corresponding internal resource 379 * descriptor linked list. 380 * 381 ******************************************************************************/ 382 383ACPI_STATUS 384AcpiRsGetListLength ( 385 UINT8 *AmlBuffer, 386 UINT32 AmlBufferLength, 387 ACPI_SIZE *SizeNeeded) 388{ 389 ACPI_STATUS Status; 390 UINT8 *EndAml; 391 UINT8 *Buffer; 392 UINT32 BufferSize; 393 UINT16 Temp16; 394 UINT16 ResourceLength; 395 UINT32 ExtraStructBytes; 396 UINT8 ResourceIndex; 397 UINT8 MinimumAmlResourceLength; 398 399 400 ACPI_FUNCTION_TRACE (RsGetListLength); 401 402 403 *SizeNeeded = 0; 404 EndAml = AmlBuffer + AmlBufferLength; 405 406 /* Walk the list of AML resource descriptors */ 407 408 while (AmlBuffer < EndAml) 409 { 410 /* Validate the Resource Type and Resource Length */ 411 412 Status = AcpiUtValidateResource (AmlBuffer, &ResourceIndex); 413 if (ACPI_FAILURE (Status)) 414 { 415 return_ACPI_STATUS (Status); 416 } 417 418 /* Get the resource length and base (minimum) AML size */ 419 420 ResourceLength = AcpiUtGetResourceLength (AmlBuffer); 421 MinimumAmlResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; 422 423 /* 424 * Augment the size for descriptors with optional 425 * and/or variable length fields 426 */ 427 ExtraStructBytes = 0; 428 Buffer = AmlBuffer + AcpiUtGetResourceHeaderLength (AmlBuffer); 429 430 switch (AcpiUtGetResourceType (AmlBuffer)) 431 { 432 case ACPI_RESOURCE_NAME_IRQ: 433 /* 434 * IRQ Resource: 435 * Get the number of bits set in the 16-bit IRQ mask 436 */ 437 ACPI_MOVE_16_TO_16 (&Temp16, Buffer); 438 ExtraStructBytes = AcpiRsCountSetBits (Temp16); 439 break; 440 441 442 case ACPI_RESOURCE_NAME_DMA: 443 /* 444 * DMA Resource: 445 * Get the number of bits set in the 8-bit DMA mask 446 */ 447 ExtraStructBytes = AcpiRsCountSetBits (*Buffer); 448 break; 449 450 451 case ACPI_RESOURCE_NAME_VENDOR_SMALL: 452 case ACPI_RESOURCE_NAME_VENDOR_LARGE: 453 /* 454 * Vendor Resource: 455 * Get the number of vendor data bytes 456 */ 457 ExtraStructBytes = ResourceLength; 458 break; 459 460 461 case ACPI_RESOURCE_NAME_END_TAG: 462 /* 463 * End Tag: 464 * This is the normal exit, add size of EndTag 465 */ 466 *SizeNeeded += ACPI_RS_SIZE_MIN; 467 return_ACPI_STATUS (AE_OK); 468 469 470 case ACPI_RESOURCE_NAME_ADDRESS32: 471 case ACPI_RESOURCE_NAME_ADDRESS16: 472 case ACPI_RESOURCE_NAME_ADDRESS64: 473 /* 474 * Address Resource: 475 * Add the size of the optional ResourceSource 476 */ 477 ExtraStructBytes = AcpiRsStreamOptionLength ( 478 ResourceLength, MinimumAmlResourceLength); 479 break; 480 481 482 case ACPI_RESOURCE_NAME_EXTENDED_IRQ: 483 /* 484 * Extended IRQ Resource: 485 * Using the InterruptTableLength, add 4 bytes for each additional 486 * interrupt. Note: at least one interrupt is required and is 487 * included in the minimum descriptor size (reason for the -1) 488 */ 489 ExtraStructBytes = (Buffer[1] - 1) * sizeof (UINT32); 490 491 /* Add the size of the optional ResourceSource */ 492 493 ExtraStructBytes += AcpiRsStreamOptionLength ( 494 ResourceLength - ExtraStructBytes, MinimumAmlResourceLength); 495 break; 496 497 498 default: 499 break; 500 } 501 502 /* 503 * Update the required buffer size for the internal descriptor structs 504 * 505 * Important: Round the size up for the appropriate alignment. This 506 * is a requirement on IA64. 507 */ 508 BufferSize = AcpiGbl_ResourceStructSizes[ResourceIndex] + 509 ExtraStructBytes; 510 BufferSize = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (BufferSize); 511 512 *SizeNeeded += BufferSize; 513 514 ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, 515 "Type %.2X, AmlLength %.2X InternalLength %.2X\n", 516 AcpiUtGetResourceType (AmlBuffer), 517 AcpiUtGetDescriptorLength (AmlBuffer), BufferSize)); 518 519 /* 520 * Point to the next resource within the AML stream using the length 521 * contained in the resource descriptor header 522 */ 523 AmlBuffer += AcpiUtGetDescriptorLength (AmlBuffer); 524 } 525 526 /* Did not find an EndTag resource descriptor */ 527 528 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 529} 530 531 532/******************************************************************************* 533 * 534 * FUNCTION: AcpiRsGetPciRoutingTableLength 535 * 536 * PARAMETERS: PackageObject - Pointer to the package object 537 * BufferSizeNeeded - UINT32 pointer of the size buffer 538 * needed to properly return the 539 * parsed data 540 * 541 * RETURN: Status 542 * 543 * DESCRIPTION: Given a package representing a PCI routing table, this 544 * calculates the size of the corresponding linked list of 545 * descriptions. 546 * 547 ******************************************************************************/ 548 549ACPI_STATUS 550AcpiRsGetPciRoutingTableLength ( 551 ACPI_OPERAND_OBJECT *PackageObject, 552 ACPI_SIZE *BufferSizeNeeded) 553{ 554 UINT32 NumberOfElements; 555 ACPI_SIZE TempSizeNeeded = 0; 556 ACPI_OPERAND_OBJECT **TopObjectList; 557 UINT32 Index; 558 ACPI_OPERAND_OBJECT *PackageElement; 559 ACPI_OPERAND_OBJECT **SubObjectList; 560 BOOLEAN NameFound; 561 UINT32 TableIndex; 562 563 564 ACPI_FUNCTION_TRACE (RsGetPciRoutingTableLength); 565 566 567 NumberOfElements = PackageObject->Package.Count; 568 569 /* 570 * Calculate the size of the return buffer. 571 * The base size is the number of elements * the sizes of the 572 * structures. Additional space for the strings is added below. 573 * The minus one is to subtract the size of the UINT8 Source[1] 574 * member because it is added below. 575 * 576 * But each PRT_ENTRY structure has a pointer to a string and 577 * the size of that string must be found. 578 */ 579 TopObjectList = PackageObject->Package.Elements; 580 581 for (Index = 0; Index < NumberOfElements; Index++) 582 { 583 /* Dereference the sub-package */ 584 585 PackageElement = *TopObjectList; 586 587 /* We must have a valid Package object */ 588 589 if (!PackageElement || 590 (PackageElement->Common.Type != ACPI_TYPE_PACKAGE)) 591 { 592 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 593 } 594 595 /* 596 * The SubObjectList will now point to an array of the 597 * four IRQ elements: Address, Pin, Source and SourceIndex 598 */ 599 SubObjectList = PackageElement->Package.Elements; 600 601 /* Scan the IrqTableElements for the Source Name String */ 602 603 NameFound = FALSE; 604 605 for (TableIndex = 0; TableIndex < 4 && !NameFound; TableIndex++) 606 { 607 if (*SubObjectList && /* Null object allowed */ 608 609 ((ACPI_TYPE_STRING == 610 (*SubObjectList)->Common.Type) || 611 612 ((ACPI_TYPE_LOCAL_REFERENCE == 613 (*SubObjectList)->Common.Type) && 614 615 ((*SubObjectList)->Reference.Class == 616 ACPI_REFCLASS_NAME)))) 617 { 618 NameFound = TRUE; 619 } 620 else 621 { 622 /* Look at the next element */ 623 624 SubObjectList++; 625 } 626 } 627 628 TempSizeNeeded += (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); 629 630 /* Was a String type found? */ 631 632 if (NameFound) 633 { 634 if ((*SubObjectList)->Common.Type == ACPI_TYPE_STRING) 635 { 636 /* 637 * The length String.Length field does not include the 638 * terminating NULL, add 1 639 */ 640 TempSizeNeeded += ((ACPI_SIZE) 641 (*SubObjectList)->String.Length + 1); 642 } 643 else 644 { 645 TempSizeNeeded += AcpiNsGetPathnameLength ( 646 (*SubObjectList)->Reference.Node); 647 } 648 } 649 else 650 { 651 /* 652 * If no name was found, then this is a NULL, which is 653 * translated as a UINT32 zero. 654 */ 655 TempSizeNeeded += sizeof (UINT32); 656 } 657 658 /* Round up the size since each element must be aligned */ 659 660 TempSizeNeeded = ACPI_ROUND_UP_TO_64BIT (TempSizeNeeded); 661 662 /* Point to the next ACPI_OPERAND_OBJECT */ 663 664 TopObjectList++; 665 } 666 667 /* 668 * Add an extra element to the end of the list, essentially a 669 * NULL terminator 670 */ 671 *BufferSizeNeeded = TempSizeNeeded + sizeof (ACPI_PCI_ROUTING_TABLE); 672 return_ACPI_STATUS (AE_OK); 673} 674