Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/acpi/acpica/dsfield.c
15109 views
1
/******************************************************************************
2
*
3
* Module Name: dsfield - Dispatcher field routines
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 "amlcode.h"
47
#include "acdispat.h"
48
#include "acinterp.h"
49
#include "acnamesp.h"
50
#include "acparser.h"
51
52
#define _COMPONENT ACPI_DISPATCHER
53
ACPI_MODULE_NAME("dsfield")
54
55
/* Local prototypes */
56
static acpi_status
57
acpi_ds_get_field_names(struct acpi_create_field_info *info,
58
struct acpi_walk_state *walk_state,
59
union acpi_parse_object *arg);
60
61
/*******************************************************************************
62
*
63
* FUNCTION: acpi_ds_create_buffer_field
64
*
65
* PARAMETERS: Op - Current parse op (create_xXField)
66
* walk_state - Current state
67
*
68
* RETURN: Status
69
*
70
* DESCRIPTION: Execute the create_field operators:
71
* create_bit_field_op,
72
* create_byte_field_op,
73
* create_word_field_op,
74
* create_dword_field_op,
75
* create_qword_field_op,
76
* create_field_op (all of which define a field in a buffer)
77
*
78
******************************************************************************/
79
80
acpi_status
81
acpi_ds_create_buffer_field(union acpi_parse_object *op,
82
struct acpi_walk_state *walk_state)
83
{
84
union acpi_parse_object *arg;
85
struct acpi_namespace_node *node;
86
acpi_status status;
87
union acpi_operand_object *obj_desc;
88
union acpi_operand_object *second_desc = NULL;
89
u32 flags;
90
91
ACPI_FUNCTION_TRACE(ds_create_buffer_field);
92
93
/*
94
* Get the name_string argument (name of the new buffer_field)
95
*/
96
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
97
98
/* For create_field, name is the 4th argument */
99
100
arg = acpi_ps_get_arg(op, 3);
101
} else {
102
/* For all other create_xXXField operators, name is the 3rd argument */
103
104
arg = acpi_ps_get_arg(op, 2);
105
}
106
107
if (!arg) {
108
return_ACPI_STATUS(AE_AML_NO_OPERAND);
109
}
110
111
if (walk_state->deferred_node) {
112
node = walk_state->deferred_node;
113
status = AE_OK;
114
} else {
115
/* Execute flag should always be set when this function is entered */
116
117
if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
118
return_ACPI_STATUS(AE_AML_INTERNAL);
119
}
120
121
/* Creating new namespace node, should not already exist */
122
123
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
124
ACPI_NS_ERROR_IF_FOUND;
125
126
/*
127
* Mark node temporary if we are executing a normal control
128
* method. (Don't mark if this is a module-level code method)
129
*/
130
if (walk_state->method_node &&
131
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
132
flags |= ACPI_NS_TEMPORARY;
133
}
134
135
/* Enter the name_string into the namespace */
136
137
status =
138
acpi_ns_lookup(walk_state->scope_info,
139
arg->common.value.string, ACPI_TYPE_ANY,
140
ACPI_IMODE_LOAD_PASS1, flags, walk_state,
141
&node);
142
if (ACPI_FAILURE(status)) {
143
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
144
return_ACPI_STATUS(status);
145
}
146
}
147
148
/*
149
* We could put the returned object (Node) on the object stack for later,
150
* but for now, we will put it in the "op" object that the parser uses,
151
* so we can get it again at the end of this scope.
152
*/
153
op->common.node = node;
154
155
/*
156
* If there is no object attached to the node, this node was just created
157
* and we need to create the field object. Otherwise, this was a lookup
158
* of an existing node and we don't want to create the field object again.
159
*/
160
obj_desc = acpi_ns_get_attached_object(node);
161
if (obj_desc) {
162
return_ACPI_STATUS(AE_OK);
163
}
164
165
/*
166
* The Field definition is not fully parsed at this time.
167
* (We must save the address of the AML for the buffer and index operands)
168
*/
169
170
/* Create the buffer field object */
171
172
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD);
173
if (!obj_desc) {
174
status = AE_NO_MEMORY;
175
goto cleanup;
176
}
177
178
/*
179
* Remember location in AML stream of the field unit opcode and operands --
180
* since the buffer and index operands must be evaluated.
181
*/
182
second_desc = obj_desc->common.next_object;
183
second_desc->extra.aml_start = op->named.data;
184
second_desc->extra.aml_length = op->named.length;
185
obj_desc->buffer_field.node = node;
186
187
/* Attach constructed field descriptors to parent node */
188
189
status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD);
190
if (ACPI_FAILURE(status)) {
191
goto cleanup;
192
}
193
194
cleanup:
195
196
/* Remove local reference to the object */
197
198
acpi_ut_remove_reference(obj_desc);
199
return_ACPI_STATUS(status);
200
}
201
202
/*******************************************************************************
203
*
204
* FUNCTION: acpi_ds_get_field_names
205
*
206
* PARAMETERS: Info - create_field info structure
207
* ` walk_state - Current method state
208
* Arg - First parser arg for the field name list
209
*
210
* RETURN: Status
211
*
212
* DESCRIPTION: Process all named fields in a field declaration. Names are
213
* entered into the namespace.
214
*
215
******************************************************************************/
216
217
static acpi_status
218
acpi_ds_get_field_names(struct acpi_create_field_info *info,
219
struct acpi_walk_state *walk_state,
220
union acpi_parse_object *arg)
221
{
222
acpi_status status;
223
u64 position;
224
225
ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
226
227
/* First field starts at bit zero */
228
229
info->field_bit_position = 0;
230
231
/* Process all elements in the field list (of parse nodes) */
232
233
while (arg) {
234
/*
235
* Three types of field elements are handled:
236
* 1) Offset - specifies a bit offset
237
* 2) access_as - changes the access mode
238
* 3) Name - Enters a new named field into the namespace
239
*/
240
switch (arg->common.aml_opcode) {
241
case AML_INT_RESERVEDFIELD_OP:
242
243
position = (u64) info->field_bit_position
244
+ (u64) arg->common.value.size;
245
246
if (position > ACPI_UINT32_MAX) {
247
ACPI_ERROR((AE_INFO,
248
"Bit offset within field too large (> 0xFFFFFFFF)"));
249
return_ACPI_STATUS(AE_SUPPORT);
250
}
251
252
info->field_bit_position = (u32) position;
253
break;
254
255
case AML_INT_ACCESSFIELD_OP:
256
257
/*
258
* Get a new access_type and access_attribute -- to be used for all
259
* field units that follow, until field end or another access_as
260
* keyword.
261
*
262
* In field_flags, preserve the flag bits other than the
263
* ACCESS_TYPE bits
264
*/
265
info->field_flags = (u8)
266
((info->
267
field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
268
((u8) ((u32) arg->common.value.integer >> 8)));
269
270
info->attribute = (u8) (arg->common.value.integer);
271
break;
272
273
case AML_INT_NAMEDFIELD_OP:
274
275
/* Lookup the name, it should already exist */
276
277
status = acpi_ns_lookup(walk_state->scope_info,
278
(char *)&arg->named.name,
279
info->field_type,
280
ACPI_IMODE_EXECUTE,
281
ACPI_NS_DONT_OPEN_SCOPE,
282
walk_state, &info->field_node);
283
if (ACPI_FAILURE(status)) {
284
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
285
status);
286
return_ACPI_STATUS(status);
287
} else {
288
arg->common.node = info->field_node;
289
info->field_bit_length = arg->common.value.size;
290
291
/*
292
* If there is no object attached to the node, this node was
293
* just created and we need to create the field object.
294
* Otherwise, this was a lookup of an existing node and we
295
* don't want to create the field object again.
296
*/
297
if (!acpi_ns_get_attached_object
298
(info->field_node)) {
299
status = acpi_ex_prep_field_value(info);
300
if (ACPI_FAILURE(status)) {
301
return_ACPI_STATUS(status);
302
}
303
}
304
}
305
306
/* Keep track of bit position for the next field */
307
308
position = (u64) info->field_bit_position
309
+ (u64) arg->common.value.size;
310
311
if (position > ACPI_UINT32_MAX) {
312
ACPI_ERROR((AE_INFO,
313
"Field [%4.4s] bit offset too large (> 0xFFFFFFFF)",
314
ACPI_CAST_PTR(char,
315
&info->field_node->
316
name)));
317
return_ACPI_STATUS(AE_SUPPORT);
318
}
319
320
info->field_bit_position += info->field_bit_length;
321
break;
322
323
default:
324
325
ACPI_ERROR((AE_INFO,
326
"Invalid opcode in field list: 0x%X",
327
arg->common.aml_opcode));
328
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
329
}
330
331
arg = arg->common.next;
332
}
333
334
return_ACPI_STATUS(AE_OK);
335
}
336
337
/*******************************************************************************
338
*
339
* FUNCTION: acpi_ds_create_field
340
*
341
* PARAMETERS: Op - Op containing the Field definition and args
342
* region_node - Object for the containing Operation Region
343
* ` walk_state - Current method state
344
*
345
* RETURN: Status
346
*
347
* DESCRIPTION: Create a new field in the specified operation region
348
*
349
******************************************************************************/
350
351
acpi_status
352
acpi_ds_create_field(union acpi_parse_object *op,
353
struct acpi_namespace_node *region_node,
354
struct acpi_walk_state *walk_state)
355
{
356
acpi_status status;
357
union acpi_parse_object *arg;
358
struct acpi_create_field_info info;
359
360
ACPI_FUNCTION_TRACE_PTR(ds_create_field, op);
361
362
/* First arg is the name of the parent op_region (must already exist) */
363
364
arg = op->common.value.arg;
365
if (!region_node) {
366
status =
367
acpi_ns_lookup(walk_state->scope_info,
368
arg->common.value.name, ACPI_TYPE_REGION,
369
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
370
walk_state, &region_node);
371
if (ACPI_FAILURE(status)) {
372
ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
373
return_ACPI_STATUS(status);
374
}
375
}
376
377
/* Second arg is the field flags */
378
379
arg = arg->common.next;
380
info.field_flags = (u8) arg->common.value.integer;
381
info.attribute = 0;
382
383
/* Each remaining arg is a Named Field */
384
385
info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD;
386
info.region_node = region_node;
387
388
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
389
390
return_ACPI_STATUS(status);
391
}
392
393
/*******************************************************************************
394
*
395
* FUNCTION: acpi_ds_init_field_objects
396
*
397
* PARAMETERS: Op - Op containing the Field definition and args
398
* ` walk_state - Current method state
399
*
400
* RETURN: Status
401
*
402
* DESCRIPTION: For each "Field Unit" name in the argument list that is
403
* part of the field declaration, enter the name into the
404
* namespace.
405
*
406
******************************************************************************/
407
408
acpi_status
409
acpi_ds_init_field_objects(union acpi_parse_object *op,
410
struct acpi_walk_state *walk_state)
411
{
412
acpi_status status;
413
union acpi_parse_object *arg = NULL;
414
struct acpi_namespace_node *node;
415
u8 type = 0;
416
u32 flags;
417
418
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
419
420
/* Execute flag should always be set when this function is entered */
421
422
if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
423
if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {
424
425
/* bank_field Op is deferred, just return OK */
426
427
return_ACPI_STATUS(AE_OK);
428
}
429
430
return_ACPI_STATUS(AE_AML_INTERNAL);
431
}
432
433
/*
434
* Get the field_list argument for this opcode. This is the start of the
435
* list of field elements.
436
*/
437
switch (walk_state->opcode) {
438
case AML_FIELD_OP:
439
arg = acpi_ps_get_arg(op, 2);
440
type = ACPI_TYPE_LOCAL_REGION_FIELD;
441
break;
442
443
case AML_BANK_FIELD_OP:
444
arg = acpi_ps_get_arg(op, 4);
445
type = ACPI_TYPE_LOCAL_BANK_FIELD;
446
break;
447
448
case AML_INDEX_FIELD_OP:
449
arg = acpi_ps_get_arg(op, 3);
450
type = ACPI_TYPE_LOCAL_INDEX_FIELD;
451
break;
452
453
default:
454
return_ACPI_STATUS(AE_BAD_PARAMETER);
455
}
456
457
/* Creating new namespace node(s), should not already exist */
458
459
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
460
ACPI_NS_ERROR_IF_FOUND;
461
462
/*
463
* Mark node(s) temporary if we are executing a normal control
464
* method. (Don't mark if this is a module-level code method)
465
*/
466
if (walk_state->method_node &&
467
!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {
468
flags |= ACPI_NS_TEMPORARY;
469
}
470
471
/*
472
* Walk the list of entries in the field_list
473
* Note: field_list can be of zero length. In this case, Arg will be NULL.
474
*/
475
while (arg) {
476
/*
477
* Ignore OFFSET and ACCESSAS terms here; we are only interested in the
478
* field names in order to enter them into the namespace.
479
*/
480
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
481
status = acpi_ns_lookup(walk_state->scope_info,
482
(char *)&arg->named.name, type,
483
ACPI_IMODE_LOAD_PASS1, flags,
484
walk_state, &node);
485
if (ACPI_FAILURE(status)) {
486
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
487
status);
488
if (status != AE_ALREADY_EXISTS) {
489
return_ACPI_STATUS(status);
490
}
491
492
/* Name already exists, just ignore this error */
493
494
status = AE_OK;
495
}
496
497
arg->common.node = node;
498
}
499
500
/* Get the next field element in the list */
501
502
arg = arg->common.next;
503
}
504
505
return_ACPI_STATUS(AE_OK);
506
}
507
508
/*******************************************************************************
509
*
510
* FUNCTION: acpi_ds_create_bank_field
511
*
512
* PARAMETERS: Op - Op containing the Field definition and args
513
* region_node - Object for the containing Operation Region
514
* walk_state - Current method state
515
*
516
* RETURN: Status
517
*
518
* DESCRIPTION: Create a new bank field in the specified operation region
519
*
520
******************************************************************************/
521
522
acpi_status
523
acpi_ds_create_bank_field(union acpi_parse_object *op,
524
struct acpi_namespace_node *region_node,
525
struct acpi_walk_state *walk_state)
526
{
527
acpi_status status;
528
union acpi_parse_object *arg;
529
struct acpi_create_field_info info;
530
531
ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op);
532
533
/* First arg is the name of the parent op_region (must already exist) */
534
535
arg = op->common.value.arg;
536
if (!region_node) {
537
status =
538
acpi_ns_lookup(walk_state->scope_info,
539
arg->common.value.name, ACPI_TYPE_REGION,
540
ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
541
walk_state, &region_node);
542
if (ACPI_FAILURE(status)) {
543
ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
544
return_ACPI_STATUS(status);
545
}
546
}
547
548
/* Second arg is the Bank Register (Field) (must already exist) */
549
550
arg = arg->common.next;
551
status =
552
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
553
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
554
ACPI_NS_SEARCH_PARENT, walk_state,
555
&info.register_node);
556
if (ACPI_FAILURE(status)) {
557
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
558
return_ACPI_STATUS(status);
559
}
560
561
/*
562
* Third arg is the bank_value
563
* This arg is a term_arg, not a constant
564
* It will be evaluated later, by acpi_ds_eval_bank_field_operands
565
*/
566
arg = arg->common.next;
567
568
/* Fourth arg is the field flags */
569
570
arg = arg->common.next;
571
info.field_flags = (u8) arg->common.value.integer;
572
573
/* Each remaining arg is a Named Field */
574
575
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
576
info.region_node = region_node;
577
578
/*
579
* Use Info.data_register_node to store bank_field Op
580
* It's safe because data_register_node will never be used when create bank field
581
* We store aml_start and aml_length in the bank_field Op for late evaluation
582
* Used in acpi_ex_prep_field_value(Info)
583
*
584
* TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
585
*/
586
info.data_register_node = (struct acpi_namespace_node *)op;
587
588
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
589
return_ACPI_STATUS(status);
590
}
591
592
/*******************************************************************************
593
*
594
* FUNCTION: acpi_ds_create_index_field
595
*
596
* PARAMETERS: Op - Op containing the Field definition and args
597
* region_node - Object for the containing Operation Region
598
* ` walk_state - Current method state
599
*
600
* RETURN: Status
601
*
602
* DESCRIPTION: Create a new index field in the specified operation region
603
*
604
******************************************************************************/
605
606
acpi_status
607
acpi_ds_create_index_field(union acpi_parse_object *op,
608
struct acpi_namespace_node *region_node,
609
struct acpi_walk_state *walk_state)
610
{
611
acpi_status status;
612
union acpi_parse_object *arg;
613
struct acpi_create_field_info info;
614
615
ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op);
616
617
/* First arg is the name of the Index register (must already exist) */
618
619
arg = op->common.value.arg;
620
status =
621
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
622
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
623
ACPI_NS_SEARCH_PARENT, walk_state,
624
&info.register_node);
625
if (ACPI_FAILURE(status)) {
626
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
627
return_ACPI_STATUS(status);
628
}
629
630
/* Second arg is the data register (must already exist) */
631
632
arg = arg->common.next;
633
status =
634
acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
635
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
636
ACPI_NS_SEARCH_PARENT, walk_state,
637
&info.data_register_node);
638
if (ACPI_FAILURE(status)) {
639
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
640
return_ACPI_STATUS(status);
641
}
642
643
/* Next arg is the field flags */
644
645
arg = arg->common.next;
646
info.field_flags = (u8) arg->common.value.integer;
647
648
/* Each remaining arg is a Named Field */
649
650
info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD;
651
info.region_node = region_node;
652
653
status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
654
655
return_ACPI_STATUS(status);
656
}
657
658