xref: /openbmc/linux/drivers/acpi/acpica/rsmisc.c (revision e190bfe5)
1 /*******************************************************************************
2  *
3  * Module Name: rsmisc - Miscellaneous resource descriptors
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2010, 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