rscalc.c 17.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/*******************************************************************************
 *
 * Module Name: rscalc - Calculate stream and list lengths
 *
 ******************************************************************************/

/*
 * Copyright (C) 2000 - 2005, R. Byron Moore
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
#include <acpi/acresrc.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>

#define _COMPONENT          ACPI_RESOURCES
L
Len Brown 已提交
50
ACPI_MODULE_NAME("rscalc")
L
Linus Torvalds 已提交
51

R
Robert Moore 已提交
52 53 54
/* Local prototypes */
static u8 acpi_rs_count_set_bits(u16 bit_field);

B
Bob Moore 已提交
55
static acpi_rs_length
R
Robert Moore 已提交
56 57 58 59 60
acpi_rs_struct_option_length(struct acpi_resource_source *resource_source);

static u32
acpi_rs_stream_option_length(u32 resource_length, u32 minimum_total_length);

L
Linus Torvalds 已提交
61 62
/*******************************************************************************
 *
R
Robert Moore 已提交
63
 * FUNCTION:    acpi_rs_count_set_bits
L
Linus Torvalds 已提交
64
 *
R
Robert Moore 已提交
65
 * PARAMETERS:  bit_field       - Field in which to count bits
L
Linus Torvalds 已提交
66
 *
R
Robert Moore 已提交
67
 * RETURN:      Number of bits set within the field
L
Linus Torvalds 已提交
68
 *
R
Robert Moore 已提交
69 70
 * DESCRIPTION: Count the number of bits set in a resource field. Used for
 *              (Short descriptor) interrupt and DMA lists.
L
Linus Torvalds 已提交
71 72 73
 *
 ******************************************************************************/

R
Robert Moore 已提交
74 75 76
static u8 acpi_rs_count_set_bits(u16 bit_field)
{
	u8 bits_set;
R
Robert Moore 已提交
77

R
Robert Moore 已提交
78
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
79

R
Robert Moore 已提交
80 81
	for (bits_set = 0; bit_field; bits_set++) {
		/* Zero the least significant bit that is set */
L
Linus Torvalds 已提交
82

R
Robert Moore 已提交
83 84
		bit_field &= (bit_field - 1);
	}
L
Linus Torvalds 已提交
85

R
Robert Moore 已提交
86 87
	return (bits_set);
}
L
Linus Torvalds 已提交
88 89 90

/*******************************************************************************
 *
R
Robert Moore 已提交
91
 * FUNCTION:    acpi_rs_struct_option_length
L
Linus Torvalds 已提交
92
 *
R
Robert Moore 已提交
93
 * PARAMETERS:  resource_source     - Pointer to optional descriptor field
L
Linus Torvalds 已提交
94 95 96
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
97 98 99
 * DESCRIPTION: Common code to handle optional resource_source_index and
 *              resource_source fields in some Large descriptors. Used during
 *              list-to-stream conversion
L
Linus Torvalds 已提交
100 101 102
 *
 ******************************************************************************/

B
Bob Moore 已提交
103
static acpi_rs_length
R
Robert Moore 已提交
104
acpi_rs_struct_option_length(struct acpi_resource_source *resource_source)
L
Linus Torvalds 已提交
105
{
R
Robert Moore 已提交
106 107 108 109 110 111 112 113
	ACPI_FUNCTION_ENTRY();

	/*
	 * If the resource_source string is valid, return the size of the string
	 * (string_length includes the NULL terminator) plus the size of the
	 * resource_source_index (1).
	 */
	if (resource_source->string_ptr) {
B
Bob Moore 已提交
114
		return ((acpi_rs_length) (resource_source->string_length + 1));
R
Robert Moore 已提交
115
	}
L
Linus Torvalds 已提交
116

R
Robert Moore 已提交
117 118
	return (0);
}
L
Linus Torvalds 已提交
119

R
Robert Moore 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
/*******************************************************************************
 *
 * FUNCTION:    acpi_rs_stream_option_length
 *
 * PARAMETERS:  resource_length     - Length from the resource header
 *              minimum_total_length - Minimum length of this resource, before
 *                                    any optional fields. Includes header size
 *
 * RETURN:      Length of optional string (0 if no string present)
 *
 * DESCRIPTION: Common code to handle optional resource_source_index and
 *              resource_source fields in some Large descriptors. Used during
 *              stream-to-list conversion
 *
 ******************************************************************************/
L
Linus Torvalds 已提交
135

R
Robert Moore 已提交
136
static u32
B
Bob Moore 已提交
137 138
acpi_rs_stream_option_length(u32 resource_length,
			     u32 minimum_aml_resource_length)
R
Robert Moore 已提交
139 140
{
	u32 string_length = 0;
L
Linus Torvalds 已提交
141

R
Robert Moore 已提交
142
	ACPI_FUNCTION_ENTRY();
L
Linus Torvalds 已提交
143

R
Robert Moore 已提交
144 145 146 147
	/*
	 * The resource_source_index and resource_source are optional elements of some
	 * Large-type resource descriptors.
	 */
R
Robert Moore 已提交
148

R
Robert Moore 已提交
149 150 151 152 153 154 155
	/*
	 * If the length of the actual resource descriptor is greater than the ACPI
	 * spec-defined minimum length, it means that a resource_source_index exists
	 * and is followed by a (required) null terminated string. The string length
	 * (including the null terminator) is the resource length minus the minimum
	 * length, minus one byte for the resource_source_index itself.
	 */
B
Bob Moore 已提交
156
	if (resource_length > minimum_aml_resource_length) {
R
Robert Moore 已提交
157
		/* Compute the length of the optional string */
L
Linus Torvalds 已提交
158

B
Bob Moore 已提交
159 160
		string_length =
		    resource_length - minimum_aml_resource_length - 1;
R
Robert Moore 已提交
161
	}
L
Linus Torvalds 已提交
162

R
Robert Moore 已提交
163
	/* Round up length to 32 bits for internal structure alignment */
L
Linus Torvalds 已提交
164

R
Robert Moore 已提交
165 166
	return (ACPI_ROUND_UP_to_32_bITS(string_length));
}
L
Linus Torvalds 已提交
167

R
Robert Moore 已提交
168 169
/*******************************************************************************
 *
B
Bob Moore 已提交
170
 * FUNCTION:    acpi_rs_get_aml_length
R
Robert Moore 已提交
171 172 173 174 175 176 177 178 179 180 181
 *
 * PARAMETERS:  Resource            - Pointer to the resource linked list
 *              size_needed         - Where the required size is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Takes a linked list of internal resource descriptors and
 *              calculates the size buffer needed to hold the corresponding
 *              external resource byte stream.
 *
 ******************************************************************************/
L
Linus Torvalds 已提交
182

R
Robert Moore 已提交
183
acpi_status
B
Bob Moore 已提交
184
acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
R
Robert Moore 已提交
185
{
B
Bob Moore 已提交
186
	acpi_size aml_size_needed = 0;
B
Bob Moore 已提交
187
	acpi_rs_length total_size;
L
Linus Torvalds 已提交
188

B
Bob Moore 已提交
189
	ACPI_FUNCTION_TRACE("rs_get_aml_length");
L
Linus Torvalds 已提交
190

R
Robert Moore 已提交
191
	/* Traverse entire list of internal resource descriptors */
L
Linus Torvalds 已提交
192

R
Robert Moore 已提交
193 194
	while (resource) {
		/* Validate the descriptor type */
L
Linus Torvalds 已提交
195

B
Bob Moore 已提交
196
		if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
R
Robert Moore 已提交
197 198
			return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE);
		}
R
Robert Moore 已提交
199

R
Robert Moore 已提交
200
		/* Get the base size of the (external stream) resource descriptor */
L
Linus Torvalds 已提交
201

B
Bob Moore 已提交
202
		total_size = acpi_gbl_aml_resource_sizes[resource->type];
L
Linus Torvalds 已提交
203

R
Robert Moore 已提交
204 205 206 207 208
		/*
		 * Augment the base size for descriptors with optional and/or
		 * variable-length fields
		 */
		switch (resource->type) {
B
Bob Moore 已提交
209
		case ACPI_RESOURCE_TYPE_VENDOR:
L
Linus Torvalds 已提交
210
			/*
R
Robert Moore 已提交
211 212 213 214
			 * Vendor Defined Resource:
			 * For a Vendor Specific resource, if the Length is between 1 and 7
			 * it will be created as a Small Resource data type, otherwise it
			 * is a Large Resource data type.
L
Linus Torvalds 已提交
215
			 */
B
Bob Moore 已提交
216
			if (resource->data.vendor.byte_length > 7) {
R
Robert Moore 已提交
217
				/* Base size of a Large resource descriptor */
L
Linus Torvalds 已提交
218

B
Bob Moore 已提交
219
				total_size =
B
Bob Moore 已提交
220
				    sizeof(struct aml_resource_large_header);
L
Linus Torvalds 已提交
221 222
			}

R
Robert Moore 已提交
223
			/* Add the size of the vendor-specific data */
R
Robert Moore 已提交
224

B
Bob Moore 已提交
225 226
			total_size = (acpi_rs_length)
			    (total_size + resource->data.vendor.byte_length);
L
Linus Torvalds 已提交
227 228
			break;

B
Bob Moore 已提交
229
		case ACPI_RESOURCE_TYPE_END_TAG:
L
Linus Torvalds 已提交
230
			/*
R
Robert Moore 已提交
231 232
			 * End Tag:
			 * We are done -- return the accumulated total size.
L
Linus Torvalds 已提交
233
			 */
B
Bob Moore 已提交
234
			*size_needed = aml_size_needed + total_size;
L
Linus Torvalds 已提交
235

R
Robert Moore 已提交
236
			/* Normal exit */
L
Linus Torvalds 已提交
237

R
Robert Moore 已提交
238
			return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
239

B
Bob Moore 已提交
240
		case ACPI_RESOURCE_TYPE_ADDRESS16:
L
Linus Torvalds 已提交
241
			/*
R
Robert Moore 已提交
242 243
			 * 16-Bit Address Resource:
			 * Add the size of the optional resource_source info
L
Linus Torvalds 已提交
244
			 */
B
Bob Moore 已提交
245 246 247 248 249
			total_size = (acpi_rs_length)
			    (total_size +
			     acpi_rs_struct_option_length(&resource->data.
							  address16.
							  resource_source));
L
Linus Torvalds 已提交
250 251
			break;

B
Bob Moore 已提交
252
		case ACPI_RESOURCE_TYPE_ADDRESS32:
L
Linus Torvalds 已提交
253
			/*
R
Robert Moore 已提交
254 255
			 * 32-Bit Address Resource:
			 * Add the size of the optional resource_source info
L
Linus Torvalds 已提交
256
			 */
B
Bob Moore 已提交
257 258 259 260 261
			total_size = (acpi_rs_length)
			    (total_size +
			     acpi_rs_struct_option_length(&resource->data.
							  address32.
							  resource_source));
L
Linus Torvalds 已提交
262 263
			break;

B
Bob Moore 已提交
264
		case ACPI_RESOURCE_TYPE_ADDRESS64:
L
Linus Torvalds 已提交
265
			/*
R
Robert Moore 已提交
266 267
			 * 64-Bit Address Resource:
			 * Add the size of the optional resource_source info
L
Linus Torvalds 已提交
268
			 */
B
Bob Moore 已提交
269 270 271 272 273
			total_size = (acpi_rs_length)
			    (total_size +
			     acpi_rs_struct_option_length(&resource->data.
							  address64.
							  resource_source));
L
Linus Torvalds 已提交
274 275
			break;

B
Bob Moore 已提交
276
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
L
Linus Torvalds 已提交
277
			/*
R
Robert Moore 已提交
278 279 280
			 * Extended IRQ Resource:
			 * Add the size of each additional optional interrupt beyond the
			 * required 1 (4 bytes for each u32 interrupt number)
L
Linus Torvalds 已提交
281
			 */
B
Bob Moore 已提交
282 283 284 285 286 287 288 289
			total_size = (acpi_rs_length)
			    (total_size +
			     ((resource->data.extended_irq.interrupt_count -
			       1) * 4) +
			     /* Add the size of the optional resource_source info */
			     acpi_rs_struct_option_length(&resource->data.
							  extended_irq.
							  resource_source));
R
Robert Moore 已提交
290
			break;
L
Linus Torvalds 已提交
291

R
Robert Moore 已提交
292
		default:
L
Linus Torvalds 已提交
293
			break;
R
Robert Moore 已提交
294
		}
L
Linus Torvalds 已提交
295

R
Robert Moore 已提交
296
		/* Update the total */
L
Linus Torvalds 已提交
297

B
Bob Moore 已提交
298
		aml_size_needed += total_size;
L
Linus Torvalds 已提交
299

R
Robert Moore 已提交
300
		/* Point to the next object */
L
Linus Torvalds 已提交
301

B
Bob Moore 已提交
302 303 304
		resource =
		    ACPI_PTR_ADD(struct acpi_resource, resource,
				 resource->length);
R
Robert Moore 已提交
305
	}
L
Linus Torvalds 已提交
306

B
Bob Moore 已提交
307
	/* Did not find an end_tag resource descriptor */
L
Linus Torvalds 已提交
308

B
Bob Moore 已提交
309
	return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
R
Robert Moore 已提交
310
}
L
Linus Torvalds 已提交
311

R
Robert Moore 已提交
312 313 314 315
/*******************************************************************************
 *
 * FUNCTION:    acpi_rs_get_list_length
 *
B
Bob Moore 已提交
316 317 318
 * PARAMETERS:  aml_buffer          - Pointer to the resource byte stream
 *              aml_buffer_length   - Size of aml_buffer
 *              size_needed         - Where the size needed is returned
R
Robert Moore 已提交
319 320 321 322 323 324 325 326 327 328
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Takes an external resource byte stream and calculates the size
 *              buffer needed to hold the corresponding internal resource
 *              descriptor linked list.
 *
 ******************************************************************************/

acpi_status
B
Bob Moore 已提交
329 330
acpi_rs_get_list_length(u8 * aml_buffer,
			u32 aml_buffer_length, acpi_size * size_needed)
R
Robert Moore 已提交
331
{
B
Bob Moore 已提交
332 333
	acpi_status status;
	u8 *end_aml;
R
Robert Moore 已提交
334 335 336 337 338
	u8 *buffer;
	u32 buffer_size = 0;
	u16 temp16;
	u16 resource_length;
	u32 extra_struct_bytes;
B
Bob Moore 已提交
339 340
	u8 resource_index;
	u8 minimum_aml_resource_length;
L
Linus Torvalds 已提交
341

R
Robert Moore 已提交
342
	ACPI_FUNCTION_TRACE("rs_get_list_length");
L
Linus Torvalds 已提交
343

B
Bob Moore 已提交
344
	end_aml = aml_buffer + aml_buffer_length;
R
Robert Moore 已提交
345

B
Bob Moore 已提交
346
	/* Walk the list of AML resource descriptors */
L
Linus Torvalds 已提交
347

B
Bob Moore 已提交
348 349
	while (aml_buffer < end_aml) {
		/* Validate the Resource Type and Resource Length */
L
Linus Torvalds 已提交
350

B
Bob Moore 已提交
351 352 353
		status = acpi_ut_validate_resource(aml_buffer, &resource_index);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
354 355
		}

B
Bob Moore 已提交
356
		/* Get the resource length and base (minimum) AML size */
R
Robert Moore 已提交
357

B
Bob Moore 已提交
358
		resource_length = acpi_ut_get_resource_length(aml_buffer);
B
Bob Moore 已提交
359 360
		minimum_aml_resource_length =
		    acpi_gbl_resource_aml_sizes[resource_index];
R
Robert Moore 已提交
361

B
Bob Moore 已提交
362 363 364 365
		/*
		 * Augment the size for descriptors with optional
		 * and/or variable length fields
		 */
R
Robert Moore 已提交
366
		extra_struct_bytes = 0;
B
Bob Moore 已提交
367 368
		buffer =
		    aml_buffer + acpi_ut_get_resource_header_length(aml_buffer);
R
Robert Moore 已提交
369

B
Bob Moore 已提交
370 371
		switch (acpi_ut_get_resource_type(aml_buffer)) {
		case ACPI_RESOURCE_NAME_IRQ:
R
Robert Moore 已提交
372
			/*
B
Bob Moore 已提交
373 374
			 * IRQ Resource:
			 * Get the number of bits set in the 16-bit IRQ mask
R
Robert Moore 已提交
375
			 */
B
Bob Moore 已提交
376 377 378 379 380 381
			ACPI_MOVE_16_TO_16(&temp16, buffer);
			extra_struct_bytes =
			    acpi_rs_count_set_bits(temp16) * sizeof(u32);
			break;

		case ACPI_RESOURCE_NAME_DMA:
R
Robert Moore 已提交
382
			/*
B
Bob Moore 已提交
383 384
			 * DMA Resource:
			 * Get the number of bits set in the 8-bit DMA mask
R
Robert Moore 已提交
385
			 */
B
Bob Moore 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
			extra_struct_bytes =
			    acpi_rs_count_set_bits(*buffer) * sizeof(u32);
			break;

		case ACPI_RESOURCE_NAME_VENDOR_SMALL:
			/*
			 * Vendor Resource:
			 * Ensure a 32-bit boundary for the structure
			 */
			extra_struct_bytes =
			    ACPI_ROUND_UP_to_32_bITS(resource_length) -
			    resource_length;
			break;

		case ACPI_RESOURCE_NAME_END_TAG:
			/*
			 * End Tag: This is the normal exit
			 */
			*size_needed = buffer_size;
			return_ACPI_STATUS(AE_OK);

		case ACPI_RESOURCE_NAME_VENDOR_LARGE:
			/*
			 * Vendor Resource:
			 * Add vendor data and ensure a 32-bit boundary for the structure
			 */
			extra_struct_bytes =
			    ACPI_ROUND_UP_to_32_bITS(resource_length) -
			    resource_length;
			break;

		case ACPI_RESOURCE_NAME_ADDRESS32:
		case ACPI_RESOURCE_NAME_ADDRESS16:
			/*
			 * 32-Bit or 16-bit Address Resource:
			 * Add the size of any optional data (resource_source)
			 */
			extra_struct_bytes =
			    acpi_rs_stream_option_length(resource_length,
							 minimum_aml_resource_length);
			break;

		case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
			/*
			 * Extended IRQ:
			 * Point past the interrupt_vector_flags to get the
			 * interrupt_table_length.
			 */
			buffer++;

			extra_struct_bytes =
			    /*
			     * Add 4 bytes for each additional interrupt. Note: at
			     * least one interrupt is required and is included in
			     * the minimum descriptor size
			     */
			    ((*buffer - 1) * sizeof(u32)) +
			    /* Add the size of any optional data (resource_source) */
			    acpi_rs_stream_option_length(resource_length -
							 extra_struct_bytes,
							 minimum_aml_resource_length);
			break;

		case ACPI_RESOURCE_NAME_ADDRESS64:
			/*
			 * 64-Bit Address Resource:
			 * Add the size of any optional data (resource_source)
			 * Ensure a 64-bit boundary for the structure
			 */
			extra_struct_bytes =
			    ACPI_ROUND_UP_to_64_bITS
			    (acpi_rs_stream_option_length
			     (resource_length, minimum_aml_resource_length));
			break;

		default:
			break;
R
Robert Moore 已提交
463
		}
R
Robert Moore 已提交
464

R
Robert Moore 已提交
465
		/* Update the required buffer size for the internal descriptor structs */
L
Linus Torvalds 已提交
466

B
Bob Moore 已提交
467 468
		temp16 = (u16) (acpi_gbl_resource_struct_sizes[resource_index] +
				extra_struct_bytes);
R
Robert Moore 已提交
469
		buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE(temp16);
R
Robert Moore 已提交
470

R
Robert Moore 已提交
471
		/*
B
Bob Moore 已提交
472
		 * Point to the next resource within the stream
R
Robert Moore 已提交
473 474
		 * using the size of the header plus the length contained in the header
		 */
B
Bob Moore 已提交
475
		aml_buffer += acpi_ut_get_descriptor_length(aml_buffer);
L
Linus Torvalds 已提交
476 477
	}

B
Bob Moore 已提交
478
	/* Did not find an end_tag resource descriptor */
R
Robert Moore 已提交
479

B
Bob Moore 已提交
480
	return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_rs_get_pci_routing_table_length
 *
 * PARAMETERS:  package_object          - Pointer to the package object
 *              buffer_size_needed      - u32 pointer of the size buffer
 *                                        needed to properly return the
 *                                        parsed data
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Given a package representing a PCI routing table, this
 *              calculates the size of the corresponding linked list of
 *              descriptions.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
501 502
acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
				     acpi_size * buffer_size_needed)
L
Linus Torvalds 已提交
503
{
L
Len Brown 已提交
504 505 506 507 508 509 510 511
	u32 number_of_elements;
	acpi_size temp_size_needed = 0;
	union acpi_operand_object **top_object_list;
	u32 index;
	union acpi_operand_object *package_element;
	union acpi_operand_object **sub_object_list;
	u8 name_found;
	u32 table_index;
L
Linus Torvalds 已提交
512

L
Len Brown 已提交
513
	ACPI_FUNCTION_TRACE("rs_get_pci_routing_table_length");
L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529

	number_of_elements = package_object->package.count;

	/*
	 * Calculate the size of the return buffer.
	 * The base size is the number of elements * the sizes of the
	 * structures.  Additional space for the strings is added below.
	 * The minus one is to subtract the size of the u8 Source[1]
	 * member because it is added below.
	 *
	 * But each PRT_ENTRY structure has a pointer to a string and
	 * the size of that string must be found.
	 */
	top_object_list = package_object->package.elements;

	for (index = 0; index < number_of_elements; index++) {
R
Robert Moore 已提交
530 531
		/* Dereference the sub-package */

L
Linus Torvalds 已提交
532 533 534 535 536 537 538 539
		package_element = *top_object_list;

		/*
		 * The sub_object_list will now point to an array of the
		 * four IRQ elements: Address, Pin, Source and source_index
		 */
		sub_object_list = package_element->package.elements;

R
Robert Moore 已提交
540 541
		/* Scan the irq_table_elements for the Source Name String */

L
Linus Torvalds 已提交
542 543
		name_found = FALSE;

L
Len Brown 已提交
544 545
		for (table_index = 0; table_index < 4 && !name_found;
		     table_index++) {
R
Robert Moore 已提交
546
			if ((ACPI_TYPE_STRING ==
L
Len Brown 已提交
547 548 549 550 551 552
			     ACPI_GET_OBJECT_TYPE(*sub_object_list))
			    ||
			    ((ACPI_TYPE_LOCAL_REFERENCE ==
			      ACPI_GET_OBJECT_TYPE(*sub_object_list))
			     && ((*sub_object_list)->reference.opcode ==
				 AML_INT_NAMEPATH_OP))) {
L
Linus Torvalds 已提交
553
				name_found = TRUE;
L
Len Brown 已提交
554
			} else {
R
Robert Moore 已提交
555 556
				/* Look at the next element */

L
Linus Torvalds 已提交
557 558 559 560
				sub_object_list++;
			}
		}

L
Len Brown 已提交
561
		temp_size_needed += (sizeof(struct acpi_pci_routing_table) - 4);
L
Linus Torvalds 已提交
562

R
Robert Moore 已提交
563 564
		/* Was a String type found? */

L
Linus Torvalds 已提交
565
		if (name_found) {
L
Len Brown 已提交
566 567
			if (ACPI_GET_OBJECT_TYPE(*sub_object_list) ==
			    ACPI_TYPE_STRING) {
L
Linus Torvalds 已提交
568 569 570 571
				/*
				 * The length String.Length field does not include the
				 * terminating NULL, add 1
				 */
R
Robert Moore 已提交
572
				temp_size_needed += ((acpi_size)
L
Len Brown 已提交
573 574 575
						     (*sub_object_list)->string.
						     length + 1);
			} else {
B
Bob Moore 已提交
576
				temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
L
Linus Torvalds 已提交
577
			}
L
Len Brown 已提交
578
		} else {
L
Linus Torvalds 已提交
579 580 581 582
			/*
			 * If no name was found, then this is a NULL, which is
			 * translated as a u32 zero.
			 */
L
Len Brown 已提交
583
			temp_size_needed += sizeof(u32);
L
Linus Torvalds 已提交
584 585 586 587
		}

		/* Round up the size since each element must be aligned */

L
Len Brown 已提交
588
		temp_size_needed = ACPI_ROUND_UP_to_64_bITS(temp_size_needed);
L
Linus Torvalds 已提交
589

R
Robert Moore 已提交
590 591
		/* Point to the next union acpi_operand_object */

L
Linus Torvalds 已提交
592 593 594 595
		top_object_list++;
	}

	/*
R
Robert Moore 已提交
596 597
	 * Adding an extra element to the end of the list, essentially a
	 * NULL terminator
L
Linus Torvalds 已提交
598
	 */
L
Len Brown 已提交
599 600 601
	*buffer_size_needed =
	    temp_size_needed + sizeof(struct acpi_pci_routing_table);
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
602
}