1 /******************************************************************************* 2 * 3 * Module Name: rsmisc - Miscellaneous resource descriptors 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 #include <acpi/acpi.h> 45 #include "accommon.h" 46 #include "acresrc.h" 47 48 #define _COMPONENT ACPI_RESOURCES 49 ACPI_MODULE_NAME("rsmisc") 50 #define INIT_RESOURCE_TYPE(i) i->resource_offset 51 #define INIT_RESOURCE_LENGTH(i) i->aml_offset 52 #define INIT_TABLE_LENGTH(i) i->value 53 #define COMPARE_OPCODE(i) i->resource_offset 54 #define COMPARE_TARGET(i) i->aml_offset 55 #define COMPARE_VALUE(i) i->value 56 /******************************************************************************* 57 * 58 * FUNCTION: acpi_rs_convert_aml_to_resource 59 * 60 * PARAMETERS: Resource - Pointer to the resource descriptor 61 * Aml - Where the AML descriptor is returned 62 * Info - Pointer to appropriate conversion table 63 * 64 * RETURN: Status 65 * 66 * DESCRIPTION: Convert an external AML resource descriptor to the corresponding 67 * internal resource descriptor 68 * 69 ******************************************************************************/ 70 acpi_status 71 acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, 72 union aml_resource *aml, 73 struct acpi_rsconvert_info *info) 74 { 75 acpi_rs_length aml_resource_length; 76 void *source; 77 void *destination; 78 char *target; 79 u8 count; 80 u8 flags_mode = FALSE; 81 u16 item_count = 0; 82 u16 temp16 = 0; 83 84 ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); 85 86 if (((acpi_size) resource) & 0x3) { 87 88 /* Each internal resource struct is expected to be 32-bit aligned */ 89 90 ACPI_WARNING((AE_INFO, 91 "Misaligned resource pointer (get): %p Type 0x%2.2X Length %u", 92 resource, resource->type, resource->length)); 93 } 94 95 /* Extract the resource Length field (does not include header length) */ 96 97 aml_resource_length = acpi_ut_get_resource_length(aml); 98 99 /* 100 * First table entry must be ACPI_RSC_INITxxx and must contain the 101 * table length (# of table entries) 102 */ 103 count = INIT_TABLE_LENGTH(info); 104 105 while (count) { 106 /* 107 * Source is the external AML byte stream buffer, 108 * destination is the internal resource descriptor 109 */ 110 source = ACPI_ADD_PTR(void, aml, info->aml_offset); 111 destination = 112 ACPI_ADD_PTR(void, resource, info->resource_offset); 113 114 switch (info->opcode) { 115 case ACPI_RSC_INITGET: 116 /* 117 * Get the resource type and the initial (minimum) length 118 */ 119 ACPI_MEMSET(resource, 0, INIT_RESOURCE_LENGTH(info)); 120 resource->type = INIT_RESOURCE_TYPE(info); 121 resource->length = INIT_RESOURCE_LENGTH(info); 122 break; 123 124 case ACPI_RSC_INITSET: 125 break; 126 127 case ACPI_RSC_FLAGINIT: 128 129 flags_mode = TRUE; 130 break; 131 132 case ACPI_RSC_1BITFLAG: 133 /* 134 * Mask and shift the flag bit 135 */ 136 ACPI_SET8(destination) = (u8) 137 ((ACPI_GET8(source) >> info->value) & 0x01); 138 break; 139 140 case ACPI_RSC_2BITFLAG: 141 /* 142 * Mask and shift the flag bits 143 */ 144 ACPI_SET8(destination) = (u8) 145 ((ACPI_GET8(source) >> info->value) & 0x03); 146 break; 147 148 case ACPI_RSC_COUNT: 149 150 item_count = ACPI_GET8(source); 151 ACPI_SET8(destination) = (u8) item_count; 152 153 resource->length = resource->length + 154 (info->value * (item_count - 1)); 155 break; 156 157 case ACPI_RSC_COUNT16: 158 159 item_count = aml_resource_length; 160 ACPI_SET16(destination) = item_count; 161 162 resource->length = resource->length + 163 (info->value * (item_count - 1)); 164 break; 165 166 case ACPI_RSC_LENGTH: 167 168 resource->length = resource->length + info->value; 169 break; 170 171 case ACPI_RSC_MOVE8: 172 case ACPI_RSC_MOVE16: 173 case ACPI_RSC_MOVE32: 174 case ACPI_RSC_MOVE64: 175 /* 176 * Raw data move. Use the Info value field unless item_count has 177 * been previously initialized via a COUNT opcode 178 */ 179 if (info->value) { 180 item_count = info->value; 181 } 182 acpi_rs_move_data(destination, source, item_count, 183 info->opcode); 184 break; 185 186 case ACPI_RSC_SET8: 187 188 ACPI_MEMSET(destination, info->aml_offset, info->value); 189 break; 190 191 case ACPI_RSC_DATA8: 192 193 target = ACPI_ADD_PTR(char, resource, info->value); 194 ACPI_MEMCPY(destination, source, ACPI_GET16(target)); 195 break; 196 197 case ACPI_RSC_ADDRESS: 198 /* 199 * Common handler for address descriptor flags 200 */ 201 if (!acpi_rs_get_address_common(resource, aml)) { 202 return_ACPI_STATUS 203 (AE_AML_INVALID_RESOURCE_TYPE); 204 } 205 break; 206 207 case ACPI_RSC_SOURCE: 208 /* 209 * Optional resource_source (Index and String) 210 */ 211 resource->length += 212 acpi_rs_get_resource_source(aml_resource_length, 213 info->value, 214 destination, aml, NULL); 215 break; 216 217 case ACPI_RSC_SOURCEX: 218 /* 219 * Optional resource_source (Index and String). This is the more 220 * complicated case used by the Interrupt() macro 221 */ 222 target = 223 ACPI_ADD_PTR(char, resource, 224 info->aml_offset + (item_count * 4)); 225 226 resource->length += 227 acpi_rs_get_resource_source(aml_resource_length, 228 (acpi_rs_length) (((item_count - 1) * sizeof(u32)) + info->value), destination, aml, target); 229 break; 230 231 case ACPI_RSC_BITMASK: 232 /* 233 * 8-bit encoded bitmask (DMA macro) 234 */ 235 item_count = 236 acpi_rs_decode_bitmask(ACPI_GET8(source), 237 destination); 238 if (item_count) { 239 resource->length += (item_count - 1); 240 } 241 242 target = ACPI_ADD_PTR(char, resource, info->value); 243 ACPI_SET8(target) = (u8) item_count; 244 break; 245 246 case ACPI_RSC_BITMASK16: 247 /* 248 * 16-bit encoded bitmask (IRQ macro) 249 */ 250 ACPI_MOVE_16_TO_16(&temp16, source); 251 252 item_count = 253 acpi_rs_decode_bitmask(temp16, destination); 254 if (item_count) { 255 resource->length += (item_count - 1); 256 } 257 258 target = ACPI_ADD_PTR(char, resource, info->value); 259 ACPI_SET8(target) = (u8) item_count; 260 break; 261 262 case ACPI_RSC_EXIT_NE: 263 /* 264 * Control - Exit conversion if not equal 265 */ 266 switch (info->resource_offset) { 267 case ACPI_RSC_COMPARE_AML_LENGTH: 268 if (aml_resource_length != info->value) { 269 goto exit; 270 } 271 break; 272 273 case ACPI_RSC_COMPARE_VALUE: 274 if (ACPI_GET8(source) != info->value) { 275 goto exit; 276 } 277 break; 278 279 default: 280 281 ACPI_ERROR((AE_INFO, 282 "Invalid conversion sub-opcode")); 283 return_ACPI_STATUS(AE_BAD_PARAMETER); 284 } 285 break; 286 287 default: 288 289 ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 290 return_ACPI_STATUS(AE_BAD_PARAMETER); 291 } 292 293 count--; 294 info++; 295 } 296 297 exit: 298 if (!flags_mode) { 299 300 /* Round the resource struct length up to the next boundary (32 or 64) */ 301 302 resource->length = 303 (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(resource->length); 304 } 305 return_ACPI_STATUS(AE_OK); 306 } 307 308 /******************************************************************************* 309 * 310 * FUNCTION: acpi_rs_convert_resource_to_aml 311 * 312 * PARAMETERS: Resource - Pointer to the resource descriptor 313 * Aml - Where the AML descriptor is returned 314 * Info - Pointer to appropriate conversion table 315 * 316 * RETURN: Status 317 * 318 * DESCRIPTION: Convert an internal resource descriptor to the corresponding 319 * external AML resource descriptor. 320 * 321 ******************************************************************************/ 322 323 acpi_status 324 acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, 325 union aml_resource *aml, 326 struct acpi_rsconvert_info *info) 327 { 328 void *source = NULL; 329 void *destination; 330 acpi_rsdesc_size aml_length = 0; 331 u8 count; 332 u16 temp16 = 0; 333 u16 item_count = 0; 334 335 ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); 336 337 /* 338 * First table entry must be ACPI_RSC_INITxxx and must contain the 339 * table length (# of table entries) 340 */ 341 count = INIT_TABLE_LENGTH(info); 342 343 while (count) { 344 /* 345 * Source is the internal resource descriptor, 346 * destination is the external AML byte stream buffer 347 */ 348 source = ACPI_ADD_PTR(void, resource, info->resource_offset); 349 destination = ACPI_ADD_PTR(void, aml, info->aml_offset); 350 351 switch (info->opcode) { 352 case ACPI_RSC_INITSET: 353 354 ACPI_MEMSET(aml, 0, INIT_RESOURCE_LENGTH(info)); 355 aml_length = INIT_RESOURCE_LENGTH(info); 356 acpi_rs_set_resource_header(INIT_RESOURCE_TYPE(info), 357 aml_length, aml); 358 break; 359 360 case ACPI_RSC_INITGET: 361 break; 362 363 case ACPI_RSC_FLAGINIT: 364 /* 365 * Clear the flag byte 366 */ 367 ACPI_SET8(destination) = 0; 368 break; 369 370 case ACPI_RSC_1BITFLAG: 371 /* 372 * Mask and shift the flag bit 373 */ 374 ACPI_SET8(destination) |= (u8) 375 ((ACPI_GET8(source) & 0x01) << info->value); 376 break; 377 378 case ACPI_RSC_2BITFLAG: 379 /* 380 * Mask and shift the flag bits 381 */ 382 ACPI_SET8(destination) |= (u8) 383 ((ACPI_GET8(source) & 0x03) << info->value); 384 break; 385 386 case ACPI_RSC_COUNT: 387 388 item_count = ACPI_GET8(source); 389 ACPI_SET8(destination) = (u8) item_count; 390 391 aml_length = 392 (u16) (aml_length + 393 (info->value * (item_count - 1))); 394 break; 395 396 case ACPI_RSC_COUNT16: 397 398 item_count = ACPI_GET16(source); 399 aml_length = (u16) (aml_length + item_count); 400 acpi_rs_set_resource_length(aml_length, aml); 401 break; 402 403 case ACPI_RSC_LENGTH: 404 405 acpi_rs_set_resource_length(info->value, aml); 406 break; 407 408 case ACPI_RSC_MOVE8: 409 case ACPI_RSC_MOVE16: 410 case ACPI_RSC_MOVE32: 411 case ACPI_RSC_MOVE64: 412 413 if (info->value) { 414 item_count = info->value; 415 } 416 acpi_rs_move_data(destination, source, item_count, 417 info->opcode); 418 break; 419 420 case ACPI_RSC_ADDRESS: 421 422 /* Set the Resource Type, General Flags, and Type-Specific Flags */ 423 424 acpi_rs_set_address_common(aml, resource); 425 break; 426 427 case ACPI_RSC_SOURCEX: 428 /* 429 * Optional resource_source (Index and String) 430 */ 431 aml_length = 432 acpi_rs_set_resource_source(aml, (acpi_rs_length) 433 aml_length, source); 434 acpi_rs_set_resource_length(aml_length, aml); 435 break; 436 437 case ACPI_RSC_SOURCE: 438 /* 439 * Optional resource_source (Index and String). This is the more 440 * complicated case used by the Interrupt() macro 441 */ 442 aml_length = 443 acpi_rs_set_resource_source(aml, info->value, 444 source); 445 acpi_rs_set_resource_length(aml_length, aml); 446 break; 447 448 case ACPI_RSC_BITMASK: 449 /* 450 * 8-bit encoded bitmask (DMA macro) 451 */ 452 ACPI_SET8(destination) = (u8) 453 acpi_rs_encode_bitmask(source, 454 *ACPI_ADD_PTR(u8, resource, 455 info->value)); 456 break; 457 458 case ACPI_RSC_BITMASK16: 459 /* 460 * 16-bit encoded bitmask (IRQ macro) 461 */ 462 temp16 = acpi_rs_encode_bitmask(source, 463 *ACPI_ADD_PTR(u8, 464 resource, 465 info-> 466 value)); 467 ACPI_MOVE_16_TO_16(destination, &temp16); 468 break; 469 470 case ACPI_RSC_EXIT_LE: 471 /* 472 * Control - Exit conversion if less than or equal 473 */ 474 if (item_count <= info->value) { 475 goto exit; 476 } 477 break; 478 479 case ACPI_RSC_EXIT_NE: 480 /* 481 * Control - Exit conversion if not equal 482 */ 483 switch (COMPARE_OPCODE(info)) { 484 case ACPI_RSC_COMPARE_VALUE: 485 486 if (*ACPI_ADD_PTR(u8, resource, 487 COMPARE_TARGET(info)) != 488 COMPARE_VALUE(info)) { 489 goto exit; 490 } 491 break; 492 493 default: 494 495 ACPI_ERROR((AE_INFO, 496 "Invalid conversion sub-opcode")); 497 return_ACPI_STATUS(AE_BAD_PARAMETER); 498 } 499 break; 500 501 case ACPI_RSC_EXIT_EQ: 502 /* 503 * Control - Exit conversion if equal 504 */ 505 if (*ACPI_ADD_PTR(u8, resource, 506 COMPARE_TARGET(info)) == 507 COMPARE_VALUE(info)) { 508 goto exit; 509 } 510 break; 511 512 default: 513 514 ACPI_ERROR((AE_INFO, "Invalid conversion opcode")); 515 return_ACPI_STATUS(AE_BAD_PARAMETER); 516 } 517 518 count--; 519 info++; 520 } 521 522 exit: 523 return_ACPI_STATUS(AE_OK); 524 } 525 526 #if 0 527 /* Previous resource validations */ 528 529 if (aml->ext_address64.revision_iD != AML_RESOURCE_EXTENDED_ADDRESS_REVISION) { 530 return_ACPI_STATUS(AE_SUPPORT); 531 } 532 533 if (resource->data.start_dpf.performance_robustness >= 3) { 534 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_VALUE); 535 } 536 537 if (((aml->irq.flags & 0x09) == 0x00) || ((aml->irq.flags & 0x09) == 0x09)) { 538 /* 539 * Only [active_high, edge_sensitive] or [active_low, level_sensitive] 540 * polarity/trigger interrupts are allowed (ACPI spec, section 541 * "IRQ Format"), so 0x00 and 0x09 are illegal. 542 */ 543 ACPI_ERROR((AE_INFO, 544 "Invalid interrupt polarity/trigger in resource list, 0x%X", 545 aml->irq.flags)); 546 return_ACPI_STATUS(AE_BAD_DATA); 547 } 548 549 resource->data.extended_irq.interrupt_count = temp8; 550 if (temp8 < 1) { 551 552 /* Must have at least one IRQ */ 553 554 return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); 555 } 556 557 if (resource->data.dma.transfer == 0x03) { 558 ACPI_ERROR((AE_INFO, "Invalid DMA.Transfer preference (3)")); 559 return_ACPI_STATUS(AE_BAD_DATA); 560 } 561 #endif 562