rscalc.c revision 229989
1/******************************************************************************* 2 * 3 * Module Name: rscalc - Calculate stream and list lengths 4 * 5 ******************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2012, 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 case ACPI_RESOURCE_TYPE_GPIO: 349 350 TotalSize = (ACPI_RS_LENGTH) (TotalSize + (Resource->Data.Gpio.PinTableLength * 2) + 351 Resource->Data.Gpio.ResourceSource.StringLength + 352 Resource->Data.Gpio.VendorLength); 353 354 break; 355 356 357 case ACPI_RESOURCE_TYPE_SERIAL_BUS: 358 359 TotalSize = AcpiGbl_AmlResourceSerialBusSizes [Resource->Data.CommonSerialBus.Type]; 360 361 TotalSize = (ACPI_RS_LENGTH) (TotalSize + 362 Resource->Data.I2cSerialBus.ResourceSource.StringLength + 363 Resource->Data.I2cSerialBus.VendorLength); 364 365 break; 366 367 368 default: 369 break; 370 } 371 372 /* Update the total */ 373 374 AmlSizeNeeded += TotalSize; 375 376 /* Point to the next object */ 377 378 Resource = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, Resource->Length); 379 } 380 381 /* Did not find an EndTag resource descriptor */ 382 383 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 384} 385 386 387/******************************************************************************* 388 * 389 * FUNCTION: AcpiRsGetListLength 390 * 391 * PARAMETERS: AmlBuffer - Pointer to the resource byte stream 392 * AmlBufferLength - Size of AmlBuffer 393 * SizeNeeded - Where the size needed is returned 394 * 395 * RETURN: Status 396 * 397 * DESCRIPTION: Takes an external resource byte stream and calculates the size 398 * buffer needed to hold the corresponding internal resource 399 * descriptor linked list. 400 * 401 ******************************************************************************/ 402 403ACPI_STATUS 404AcpiRsGetListLength ( 405 UINT8 *AmlBuffer, 406 UINT32 AmlBufferLength, 407 ACPI_SIZE *SizeNeeded) 408{ 409 ACPI_STATUS Status; 410 UINT8 *EndAml; 411 UINT8 *Buffer; 412 UINT32 BufferSize; 413 UINT16 Temp16; 414 UINT16 ResourceLength; 415 UINT32 ExtraStructBytes; 416 UINT8 ResourceIndex; 417 UINT8 MinimumAmlResourceLength; 418 AML_RESOURCE *AmlResource; 419 420 421 ACPI_FUNCTION_TRACE (RsGetListLength); 422 423 424 *SizeNeeded = ACPI_RS_SIZE_MIN; /* Minimum size is one EndTag */ 425 EndAml = AmlBuffer + AmlBufferLength; 426 427 /* Walk the list of AML resource descriptors */ 428 429 while (AmlBuffer < EndAml) 430 { 431 /* Validate the Resource Type and Resource Length */ 432 433 Status = AcpiUtValidateResource (AmlBuffer, &ResourceIndex); 434 if (ACPI_FAILURE (Status)) 435 { 436 /* 437 * Exit on failure. Cannot continue because the descriptor length 438 * may be bogus also. 439 */ 440 return_ACPI_STATUS (Status); 441 } 442 443 AmlResource = (void *) AmlBuffer; 444 445 /* Get the resource length and base (minimum) AML size */ 446 447 ResourceLength = AcpiUtGetResourceLength (AmlBuffer); 448 MinimumAmlResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex]; 449 450 /* 451 * Augment the size for descriptors with optional 452 * and/or variable length fields 453 */ 454 ExtraStructBytes = 0; 455 Buffer = AmlBuffer + AcpiUtGetResourceHeaderLength (AmlBuffer); 456 457 switch (AcpiUtGetResourceType (AmlBuffer)) 458 { 459 case ACPI_RESOURCE_NAME_IRQ: 460 /* 461 * IRQ Resource: 462 * Get the number of bits set in the 16-bit IRQ mask 463 */ 464 ACPI_MOVE_16_TO_16 (&Temp16, Buffer); 465 ExtraStructBytes = AcpiRsCountSetBits (Temp16); 466 break; 467 468 469 case ACPI_RESOURCE_NAME_DMA: 470 /* 471 * DMA Resource: 472 * Get the number of bits set in the 8-bit DMA mask 473 */ 474 ExtraStructBytes = AcpiRsCountSetBits (*Buffer); 475 break; 476 477 478 case ACPI_RESOURCE_NAME_VENDOR_SMALL: 479 case ACPI_RESOURCE_NAME_VENDOR_LARGE: 480 /* 481 * Vendor Resource: 482 * Get the number of vendor data bytes 483 */ 484 ExtraStructBytes = ResourceLength; 485 break; 486 487 488 case ACPI_RESOURCE_NAME_END_TAG: 489 /* 490 * End Tag: This is the normal exit 491 */ 492 return_ACPI_STATUS (AE_OK); 493 494 495 case ACPI_RESOURCE_NAME_ADDRESS32: 496 case ACPI_RESOURCE_NAME_ADDRESS16: 497 case ACPI_RESOURCE_NAME_ADDRESS64: 498 /* 499 * Address Resource: 500 * Add the size of the optional ResourceSource 501 */ 502 ExtraStructBytes = AcpiRsStreamOptionLength ( 503 ResourceLength, MinimumAmlResourceLength); 504 break; 505 506 507 case ACPI_RESOURCE_NAME_EXTENDED_IRQ: 508 /* 509 * Extended IRQ Resource: 510 * Using the InterruptTableLength, add 4 bytes for each additional 511 * interrupt. Note: at least one interrupt is required and is 512 * included in the minimum descriptor size (reason for the -1) 513 */ 514 ExtraStructBytes = (Buffer[1] - 1) * sizeof (UINT32); 515 516 /* Add the size of the optional ResourceSource */ 517 518 ExtraStructBytes += AcpiRsStreamOptionLength ( 519 ResourceLength - ExtraStructBytes, MinimumAmlResourceLength); 520 break; 521 522 case ACPI_RESOURCE_NAME_GPIO: 523 524 /* Vendor data is optional */ 525 526 if (AmlResource->Gpio.VendorLength) 527 { 528 ExtraStructBytes += AmlResource->Gpio.VendorOffset - 529 AmlResource->Gpio.PinTableOffset + AmlResource->Gpio.VendorLength; 530 } 531 else 532 { 533 ExtraStructBytes += AmlResource->LargeHeader.ResourceLength + 534 sizeof (AML_RESOURCE_LARGE_HEADER) - 535 AmlResource->Gpio.PinTableOffset; 536 } 537 break; 538 539 case ACPI_RESOURCE_NAME_SERIAL_BUS: 540 541 MinimumAmlResourceLength = AcpiGbl_ResourceAmlSerialBusSizes[ 542 AmlResource->CommonSerialBus.Type]; 543 ExtraStructBytes += AmlResource->CommonSerialBus.ResourceLength - 544 MinimumAmlResourceLength; 545 break; 546 547 default: 548 break; 549 } 550 551 /* 552 * Update the required buffer size for the internal descriptor structs 553 * 554 * Important: Round the size up for the appropriate alignment. This 555 * is a requirement on IA64. 556 */ 557 if (AcpiUtGetResourceType (AmlBuffer) == ACPI_RESOURCE_NAME_SERIAL_BUS) 558 { 559 BufferSize = AcpiGbl_ResourceStructSerialBusSizes[ 560 AmlResource->CommonSerialBus.Type] + ExtraStructBytes; 561 } 562 else 563 { 564 BufferSize = AcpiGbl_ResourceStructSizes[ResourceIndex] + 565 ExtraStructBytes; 566 } 567 BufferSize = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (BufferSize); 568 569 *SizeNeeded += BufferSize; 570 571 ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES, 572 "Type %.2X, AmlLength %.2X InternalLength %.2X\n", 573 AcpiUtGetResourceType (AmlBuffer), 574 AcpiUtGetDescriptorLength (AmlBuffer), BufferSize)); 575 576 /* 577 * Point to the next resource within the AML stream using the length 578 * contained in the resource descriptor header 579 */ 580 AmlBuffer += AcpiUtGetDescriptorLength (AmlBuffer); 581 } 582 583 /* Did not find an EndTag resource descriptor */ 584 585 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG); 586} 587 588 589/******************************************************************************* 590 * 591 * FUNCTION: AcpiRsGetPciRoutingTableLength 592 * 593 * PARAMETERS: PackageObject - Pointer to the package object 594 * BufferSizeNeeded - UINT32 pointer of the size buffer 595 * needed to properly return the 596 * parsed data 597 * 598 * RETURN: Status 599 * 600 * DESCRIPTION: Given a package representing a PCI routing table, this 601 * calculates the size of the corresponding linked list of 602 * descriptions. 603 * 604 ******************************************************************************/ 605 606ACPI_STATUS 607AcpiRsGetPciRoutingTableLength ( 608 ACPI_OPERAND_OBJECT *PackageObject, 609 ACPI_SIZE *BufferSizeNeeded) 610{ 611 UINT32 NumberOfElements; 612 ACPI_SIZE TempSizeNeeded = 0; 613 ACPI_OPERAND_OBJECT **TopObjectList; 614 UINT32 Index; 615 ACPI_OPERAND_OBJECT *PackageElement; 616 ACPI_OPERAND_OBJECT **SubObjectList; 617 BOOLEAN NameFound; 618 UINT32 TableIndex; 619 620 621 ACPI_FUNCTION_TRACE (RsGetPciRoutingTableLength); 622 623 624 NumberOfElements = PackageObject->Package.Count; 625 626 /* 627 * Calculate the size of the return buffer. 628 * The base size is the number of elements * the sizes of the 629 * structures. Additional space for the strings is added below. 630 * The minus one is to subtract the size of the UINT8 Source[1] 631 * member because it is added below. 632 * 633 * But each PRT_ENTRY structure has a pointer to a string and 634 * the size of that string must be found. 635 */ 636 TopObjectList = PackageObject->Package.Elements; 637 638 for (Index = 0; Index < NumberOfElements; Index++) 639 { 640 /* Dereference the sub-package */ 641 642 PackageElement = *TopObjectList; 643 644 /* We must have a valid Package object */ 645 646 if (!PackageElement || 647 (PackageElement->Common.Type != ACPI_TYPE_PACKAGE)) 648 { 649 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 650 } 651 652 /* 653 * The SubObjectList will now point to an array of the 654 * four IRQ elements: Address, Pin, Source and SourceIndex 655 */ 656 SubObjectList = PackageElement->Package.Elements; 657 658 /* Scan the IrqTableElements for the Source Name String */ 659 660 NameFound = FALSE; 661 662 for (TableIndex = 0; TableIndex < 4 && !NameFound; TableIndex++) 663 { 664 if (*SubObjectList && /* Null object allowed */ 665 666 ((ACPI_TYPE_STRING == 667 (*SubObjectList)->Common.Type) || 668 669 ((ACPI_TYPE_LOCAL_REFERENCE == 670 (*SubObjectList)->Common.Type) && 671 672 ((*SubObjectList)->Reference.Class == 673 ACPI_REFCLASS_NAME)))) 674 { 675 NameFound = TRUE; 676 } 677 else 678 { 679 /* Look at the next element */ 680 681 SubObjectList++; 682 } 683 } 684 685 TempSizeNeeded += (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); 686 687 /* Was a String type found? */ 688 689 if (NameFound) 690 { 691 if ((*SubObjectList)->Common.Type == ACPI_TYPE_STRING) 692 { 693 /* 694 * The length String.Length field does not include the 695 * terminating NULL, add 1 696 */ 697 TempSizeNeeded += ((ACPI_SIZE) 698 (*SubObjectList)->String.Length + 1); 699 } 700 else 701 { 702 TempSizeNeeded += AcpiNsGetPathnameLength ( 703 (*SubObjectList)->Reference.Node); 704 } 705 } 706 else 707 { 708 /* 709 * If no name was found, then this is a NULL, which is 710 * translated as a UINT32 zero. 711 */ 712 TempSizeNeeded += sizeof (UINT32); 713 } 714 715 /* Round up the size since each element must be aligned */ 716 717 TempSizeNeeded = ACPI_ROUND_UP_TO_64BIT (TempSizeNeeded); 718 719 /* Point to the next ACPI_OPERAND_OBJECT */ 720 721 TopObjectList++; 722 } 723 724 /* 725 * Add an extra element to the end of the list, essentially a 726 * NULL terminator 727 */ 728 *BufferSizeNeeded = TempSizeNeeded + sizeof (ACPI_PCI_ROUTING_TABLE); 729 return_ACPI_STATUS (AE_OK); 730} 731