1 /******************************************************************************* 2 * 3 * Module Name: rscreate - Create resource lists/tables 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 __RSCREATE_C__ 45 46 #include "acpi.h" 47 #include "accommon.h" 48 #include "acresrc.h" 49 #include "acnamesp.h" 50 51 #define _COMPONENT ACPI_RESOURCES 52 ACPI_MODULE_NAME ("rscreate") 53 54 55 /******************************************************************************* 56 * 57 * FUNCTION: AcpiRsCreateResourceList 58 * 59 * PARAMETERS: AmlBuffer - Pointer to the resource byte stream 60 * OutputBuffer - Pointer to the user's buffer 61 * 62 * RETURN: Status: AE_OK if okay, else a valid ACPI_STATUS code 63 * If OutputBuffer is not large enough, OutputBufferLength 64 * indicates how large OutputBuffer should be, else it 65 * indicates how may UINT8 elements of OutputBuffer are valid. 66 * 67 * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method 68 * execution and parses the stream to create a linked list 69 * of device resources. 70 * 71 ******************************************************************************/ 72 73 ACPI_STATUS 74 AcpiRsCreateResourceList ( 75 ACPI_OPERAND_OBJECT *AmlBuffer, 76 ACPI_BUFFER *OutputBuffer) 77 { 78 79 ACPI_STATUS Status; 80 UINT8 *AmlStart; 81 ACPI_SIZE ListSizeNeeded = 0; 82 UINT32 AmlBufferLength; 83 void *Resource; 84 85 86 ACPI_FUNCTION_TRACE (RsCreateResourceList); 87 88 89 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AmlBuffer = %p\n", 90 AmlBuffer)); 91 92 /* Params already validated, so we don't re-validate here */ 93 94 AmlBufferLength = AmlBuffer->Buffer.Length; 95 AmlStart = AmlBuffer->Buffer.Pointer; 96 97 /* 98 * Pass the AmlBuffer into a module that can calculate 99 * the buffer size needed for the linked list 100 */ 101 Status = AcpiRsGetListLength (AmlStart, AmlBufferLength, 102 &ListSizeNeeded); 103 104 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n", 105 Status, (UINT32) ListSizeNeeded)); 106 if (ACPI_FAILURE (Status)) 107 { 108 return_ACPI_STATUS (Status); 109 } 110 111 /* Validate/Allocate/Clear caller buffer */ 112 113 Status = AcpiUtInitializeBuffer (OutputBuffer, ListSizeNeeded); 114 if (ACPI_FAILURE (Status)) 115 { 116 return_ACPI_STATUS (Status); 117 } 118 119 /* Do the conversion */ 120 121 Resource = OutputBuffer->Pointer; 122 Status = AcpiUtWalkAmlResources (AmlStart, AmlBufferLength, 123 AcpiRsConvertAmlToResources, &Resource); 124 if (ACPI_FAILURE (Status)) 125 { 126 return_ACPI_STATUS (Status); 127 } 128 129 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", 130 OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); 131 return_ACPI_STATUS (AE_OK); 132 } 133 134 135 /******************************************************************************* 136 * 137 * FUNCTION: AcpiRsCreatePciRoutingTable 138 * 139 * PARAMETERS: PackageObject - Pointer to an ACPI_OPERAND_OBJECT 140 * package 141 * OutputBuffer - Pointer to the user's buffer 142 * 143 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. 144 * If the OutputBuffer is too small, the error will be 145 * AE_BUFFER_OVERFLOW and OutputBuffer->Length will point 146 * to the size buffer needed. 147 * 148 * DESCRIPTION: Takes the ACPI_OPERAND_OBJECT package and creates a 149 * linked list of PCI interrupt descriptions 150 * 151 * NOTE: It is the caller's responsibility to ensure that the start of the 152 * output buffer is aligned properly (if necessary). 153 * 154 ******************************************************************************/ 155 156 ACPI_STATUS 157 AcpiRsCreatePciRoutingTable ( 158 ACPI_OPERAND_OBJECT *PackageObject, 159 ACPI_BUFFER *OutputBuffer) 160 { 161 UINT8 *Buffer; 162 ACPI_OPERAND_OBJECT **TopObjectList; 163 ACPI_OPERAND_OBJECT **SubObjectList; 164 ACPI_OPERAND_OBJECT *ObjDesc; 165 ACPI_SIZE BufferSizeNeeded = 0; 166 UINT32 NumberOfElements; 167 UINT32 Index; 168 ACPI_PCI_ROUTING_TABLE *UserPrt; 169 ACPI_NAMESPACE_NODE *Node; 170 ACPI_STATUS Status; 171 ACPI_BUFFER PathBuffer; 172 173 174 ACPI_FUNCTION_TRACE (RsCreatePciRoutingTable); 175 176 177 /* Params already validated, so we don't re-validate here */ 178 179 /* Get the required buffer length */ 180 181 Status = AcpiRsGetPciRoutingTableLength (PackageObject, 182 &BufferSizeNeeded); 183 if (ACPI_FAILURE (Status)) 184 { 185 return_ACPI_STATUS (Status); 186 } 187 188 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "BufferSizeNeeded = %X\n", 189 (UINT32) BufferSizeNeeded)); 190 191 /* Validate/Allocate/Clear caller buffer */ 192 193 Status = AcpiUtInitializeBuffer (OutputBuffer, BufferSizeNeeded); 194 if (ACPI_FAILURE (Status)) 195 { 196 return_ACPI_STATUS (Status); 197 } 198 199 /* 200 * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a 201 * package that in turn contains an UINT64 Address, a UINT8 Pin, 202 * a Name, and a UINT8 SourceIndex. 203 */ 204 TopObjectList = PackageObject->Package.Elements; 205 NumberOfElements = PackageObject->Package.Count; 206 Buffer = OutputBuffer->Pointer; 207 UserPrt = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, Buffer); 208 209 for (Index = 0; Index < NumberOfElements; Index++) 210 { 211 /* 212 * Point UserPrt past this current structure 213 * 214 * NOTE: On the first iteration, UserPrt->Length will 215 * be zero because we cleared the return buffer earlier 216 */ 217 Buffer += UserPrt->Length; 218 UserPrt = ACPI_CAST_PTR (ACPI_PCI_ROUTING_TABLE, Buffer); 219 220 /* 221 * Fill in the Length field with the information we have at this point. 222 * The minus four is to subtract the size of the UINT8 Source[4] member 223 * because it is added below. 224 */ 225 UserPrt->Length = (sizeof (ACPI_PCI_ROUTING_TABLE) - 4); 226 227 /* Each element of the top-level package must also be a package */ 228 229 if ((*TopObjectList)->Common.Type != ACPI_TYPE_PACKAGE) 230 { 231 ACPI_ERROR ((AE_INFO, 232 "(PRT[%u]) Need sub-package, found %s", 233 Index, AcpiUtGetObjectTypeName (*TopObjectList))); 234 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 235 } 236 237 /* Each sub-package must be of length 4 */ 238 239 if ((*TopObjectList)->Package.Count != 4) 240 { 241 ACPI_ERROR ((AE_INFO, 242 "(PRT[%u]) Need package of length 4, found length %u", 243 Index, (*TopObjectList)->Package.Count)); 244 return_ACPI_STATUS (AE_AML_PACKAGE_LIMIT); 245 } 246 247 /* 248 * Dereference the sub-package. 249 * The SubObjectList will now point to an array of the four IRQ 250 * elements: [Address, Pin, Source, SourceIndex] 251 */ 252 SubObjectList = (*TopObjectList)->Package.Elements; 253 254 /* 1) First subobject: Dereference the PRT.Address */ 255 256 ObjDesc = SubObjectList[0]; 257 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 258 { 259 ACPI_ERROR ((AE_INFO, "(PRT[%u].Address) Need Integer, found %s", 260 Index, AcpiUtGetObjectTypeName (ObjDesc))); 261 return_ACPI_STATUS (AE_BAD_DATA); 262 } 263 264 UserPrt->Address = ObjDesc->Integer.Value; 265 266 /* 2) Second subobject: Dereference the PRT.Pin */ 267 268 ObjDesc = SubObjectList[1]; 269 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 270 { 271 ACPI_ERROR ((AE_INFO, "(PRT[%u].Pin) Need Integer, found %s", 272 Index, AcpiUtGetObjectTypeName (ObjDesc))); 273 return_ACPI_STATUS (AE_BAD_DATA); 274 } 275 276 UserPrt->Pin = (UINT32) ObjDesc->Integer.Value; 277 278 /* 279 * If the BIOS has erroneously reversed the _PRT SourceName (index 2) 280 * and the SourceIndex (index 3), fix it. _PRT is important enough to 281 * workaround this BIOS error. This also provides compatibility with 282 * other ACPI implementations. 283 */ 284 ObjDesc = SubObjectList[3]; 285 if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) 286 { 287 SubObjectList[3] = SubObjectList[2]; 288 SubObjectList[2] = ObjDesc; 289 290 ACPI_WARNING ((AE_INFO, 291 "(PRT[%X].Source) SourceName and SourceIndex are reversed, fixed", 292 Index)); 293 } 294 295 /* 296 * 3) Third subobject: Dereference the PRT.SourceName 297 * The name may be unresolved (slack mode), so allow a null object 298 */ 299 ObjDesc = SubObjectList[2]; 300 if (ObjDesc) 301 { 302 switch (ObjDesc->Common.Type) 303 { 304 case ACPI_TYPE_LOCAL_REFERENCE: 305 306 if (ObjDesc->Reference.Class != ACPI_REFCLASS_NAME) 307 { 308 ACPI_ERROR ((AE_INFO, 309 "(PRT[%u].Source) Need name, found Reference Class 0x%X", 310 Index, ObjDesc->Reference.Class)); 311 return_ACPI_STATUS (AE_BAD_DATA); 312 } 313 314 Node = ObjDesc->Reference.Node; 315 316 /* Use *remaining* length of the buffer as max for pathname */ 317 318 PathBuffer.Length = OutputBuffer->Length - 319 (UINT32) ((UINT8 *) UserPrt->Source - 320 (UINT8 *) OutputBuffer->Pointer); 321 PathBuffer.Pointer = UserPrt->Source; 322 323 Status = AcpiNsHandleToPathname ((ACPI_HANDLE) Node, &PathBuffer); 324 325 /* +1 to include null terminator */ 326 327 UserPrt->Length += (UINT32) ACPI_STRLEN (UserPrt->Source) + 1; 328 break; 329 330 331 case ACPI_TYPE_STRING: 332 333 ACPI_STRCPY (UserPrt->Source, ObjDesc->String.Pointer); 334 335 /* 336 * Add to the Length field the length of the string 337 * (add 1 for terminator) 338 */ 339 UserPrt->Length += ObjDesc->String.Length + 1; 340 break; 341 342 343 case ACPI_TYPE_INTEGER: 344 /* 345 * If this is a number, then the Source Name is NULL, since the 346 * entire buffer was zeroed out, we can leave this alone. 347 * 348 * Add to the Length field the length of the UINT32 NULL 349 */ 350 UserPrt->Length += sizeof (UINT32); 351 break; 352 353 354 default: 355 356 ACPI_ERROR ((AE_INFO, 357 "(PRT[%u].Source) Need Ref/String/Integer, found %s", 358 Index, AcpiUtGetObjectTypeName (ObjDesc))); 359 return_ACPI_STATUS (AE_BAD_DATA); 360 } 361 } 362 363 /* Now align the current length */ 364 365 UserPrt->Length = (UINT32) ACPI_ROUND_UP_TO_64BIT (UserPrt->Length); 366 367 /* 4) Fourth subobject: Dereference the PRT.SourceIndex */ 368 369 ObjDesc = SubObjectList[3]; 370 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 371 { 372 ACPI_ERROR ((AE_INFO, 373 "(PRT[%u].SourceIndex) Need Integer, found %s", 374 Index, AcpiUtGetObjectTypeName (ObjDesc))); 375 return_ACPI_STATUS (AE_BAD_DATA); 376 } 377 378 UserPrt->SourceIndex = (UINT32) ObjDesc->Integer.Value; 379 380 /* Point to the next ACPI_OPERAND_OBJECT in the top level package */ 381 382 TopObjectList++; 383 } 384 385 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", 386 OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); 387 return_ACPI_STATUS (AE_OK); 388 } 389 390 391 /******************************************************************************* 392 * 393 * FUNCTION: AcpiRsCreateAmlResources 394 * 395 * PARAMETERS: LinkedListBuffer - Pointer to the resource linked list 396 * OutputBuffer - Pointer to the user's buffer 397 * 398 * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. 399 * If the OutputBuffer is too small, the error will be 400 * AE_BUFFER_OVERFLOW and OutputBuffer->Length will point 401 * to the size buffer needed. 402 * 403 * DESCRIPTION: Takes the linked list of device resources and 404 * creates a bytestream to be used as input for the 405 * _SRS control method. 406 * 407 ******************************************************************************/ 408 409 ACPI_STATUS 410 AcpiRsCreateAmlResources ( 411 ACPI_RESOURCE *LinkedListBuffer, 412 ACPI_BUFFER *OutputBuffer) 413 { 414 ACPI_STATUS Status; 415 ACPI_SIZE AmlSizeNeeded = 0; 416 417 418 ACPI_FUNCTION_TRACE (RsCreateAmlResources); 419 420 421 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "LinkedListBuffer = %p\n", 422 LinkedListBuffer)); 423 424 /* 425 * Params already validated, so we don't re-validate here 426 * 427 * Pass the LinkedListBuffer into a module that calculates 428 * the buffer size needed for the byte stream. 429 */ 430 Status = AcpiRsGetAmlLength (LinkedListBuffer, 431 &AmlSizeNeeded); 432 433 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", 434 (UINT32) AmlSizeNeeded, AcpiFormatException (Status))); 435 if (ACPI_FAILURE (Status)) 436 { 437 return_ACPI_STATUS (Status); 438 } 439 440 /* Validate/Allocate/Clear caller buffer */ 441 442 Status = AcpiUtInitializeBuffer (OutputBuffer, AmlSizeNeeded); 443 if (ACPI_FAILURE (Status)) 444 { 445 return_ACPI_STATUS (Status); 446 } 447 448 /* Do the conversion */ 449 450 Status = AcpiRsConvertResourcesToAml (LinkedListBuffer, AmlSizeNeeded, 451 OutputBuffer->Pointer); 452 if (ACPI_FAILURE (Status)) 453 { 454 return_ACPI_STATUS (Status); 455 } 456 457 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", 458 OutputBuffer->Pointer, (UINT32) OutputBuffer->Length)); 459 return_ACPI_STATUS (AE_OK); 460 } 461