]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/exfldio.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sys / contrib / dev / acpica / exfldio.c
1 /******************************************************************************
2  *
3  * Module Name: exfldio - Aml Field I/O
4  *              $Revision: 111 $
5  *
6  *****************************************************************************/
7
8 /******************************************************************************
9  *
10  * 1. Copyright Notice
11  *
12  * Some or all of this work - Copyright (c) 1999 - 2004, Intel Corp.
13  * All rights reserved.
14  *
15  * 2. License
16  *
17  * 2.1. This is your license from Intel Corp. under its intellectual property
18  * rights.  You may have additional license terms from the party that provided
19  * you this software, covering your right to use that party's intellectual
20  * property rights.
21  *
22  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23  * copy of the source code appearing in this file ("Covered Code") an
24  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25  * base code distributed originally by Intel ("Original Intel Code") to copy,
26  * make derivatives, distribute, use and display any portion of the Covered
27  * Code in any form, with the right to sublicense such rights; and
28  *
29  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30  * license (with the right to sublicense), under only those claims of Intel
31  * patents that are infringed by the Original Intel Code, to make, use, sell,
32  * offer to sell, and import the Covered Code and derivative works thereof
33  * solely to the minimum extent necessary to exercise the above copyright
34  * license, and in no event shall the patent license extend to any additions
35  * to or modifications of the Original Intel Code.  No other license or right
36  * is granted directly or by implication, estoppel or otherwise;
37  *
38  * The above copyright and patent license is granted only if the following
39  * conditions are met:
40  *
41  * 3. Conditions
42  *
43  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44  * Redistribution of source code of any substantial portion of the Covered
45  * Code or modification with rights to further distribute source must include
46  * the above Copyright Notice, the above License, this list of Conditions,
47  * and the following Disclaimer and Export Compliance provision.  In addition,
48  * Licensee must cause all Covered Code to which Licensee contributes to
49  * contain a file documenting the changes Licensee made to create that Covered
50  * Code and the date of any change.  Licensee must include in that file the
51  * documentation of any changes made by any predecessor Licensee.  Licensee
52  * must include a prominent statement that the modification is derived,
53  * directly or indirectly, from Original Intel Code.
54  *
55  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56  * Redistribution of source code of any substantial portion of the Covered
57  * Code or modification without rights to further distribute source must
58  * include the following Disclaimer and Export Compliance provision in the
59  * documentation and/or other materials provided with distribution.  In
60  * addition, Licensee may not authorize further sublicense of source of any
61  * portion of the Covered Code, and must include terms to the effect that the
62  * license from Licensee to its licensee is limited to the intellectual
63  * property embodied in the software Licensee provides to its licensee, and
64  * not to intellectual property embodied in modifications its licensee may
65  * make.
66  *
67  * 3.3. Redistribution of Executable. Redistribution in executable form of any
68  * substantial portion of the Covered Code or modification must reproduce the
69  * above Copyright Notice, and the following Disclaimer and Export Compliance
70  * provision in the documentation and/or other materials provided with the
71  * distribution.
72  *
73  * 3.4. Intel retains all right, title, and interest in and to the Original
74  * Intel Code.
75  *
76  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77  * Intel shall be used in advertising or otherwise to promote the sale, use or
78  * other dealings in products derived from or relating to the Covered Code
79  * without prior written authorization from Intel.
80  *
81  * 4. Disclaimer and Export Compliance
82  *
83  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
88  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89  * PARTICULAR PURPOSE.
90  *
91  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
97  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98  * LIMITED REMEDY.
99  *
100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
101  * software or system incorporating such software without first obtaining any
102  * required license or other approval from the U. S. Department of Commerce or
103  * any other agency or department of the United States Government.  In the
104  * event Licensee exports any such software from the United States or
105  * re-exports any such software from a foreign destination, Licensee shall
106  * ensure that the distribution and export/re-export of the software is in
107  * compliance with all laws, regulations, orders, or other restrictions of the
108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109  * any of its subsidiaries will export/re-export any technical data, process,
110  * software, or service, directly or indirectly, to any country for which the
111  * United States government or any agency thereof requires an export license,
112  * other governmental approval, or letter of assurance, without first obtaining
113  * such license, approval or letter.
114  *
115  *****************************************************************************/
116
117
118 #define __EXFLDIO_C__
119
120 #include <contrib/dev/acpica/acpi.h>
121 #include <contrib/dev/acpica/acinterp.h>
122 #include <contrib/dev/acpica/amlcode.h>
123 #include <contrib/dev/acpica/acevents.h>
124 #include <contrib/dev/acpica/acdispat.h>
125
126
127 #define _COMPONENT          ACPI_EXECUTER
128         ACPI_MODULE_NAME    ("exfldio")
129
130
131 /*******************************************************************************
132  *
133  * FUNCTION:    AcpiExSetupRegion
134  *
135  * PARAMETERS:  *ObjDesc                - Field to be read or written
136  *              FieldDatumByteOffset    - Byte offset of this datum within the
137  *                                        parent field
138  *
139  * RETURN:      Status
140  *
141  * DESCRIPTION: Common processing for AcpiExExtractFromField and
142  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
143  *              validate the request.
144  *
145  ******************************************************************************/
146
147 ACPI_STATUS
148 AcpiExSetupRegion (
149     ACPI_OPERAND_OBJECT     *ObjDesc,
150     UINT32                  FieldDatumByteOffset)
151 {
152     ACPI_STATUS             Status = AE_OK;
153     ACPI_OPERAND_OBJECT     *RgnDesc;
154
155
156     ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
157
158
159     RgnDesc = ObjDesc->CommonField.RegionObj;
160
161     /* We must have a valid region */
162
163     if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
164     {
165         ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
166             ACPI_GET_OBJECT_TYPE (RgnDesc),
167             AcpiUtGetObjectTypeName (RgnDesc)));
168
169         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
170     }
171
172     /*
173      * If the Region Address and Length have not been previously evaluated,
174      * evaluate them now and save the results.
175      */
176     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
177     {
178         Status = AcpiDsGetRegionArguments (RgnDesc);
179         if (ACPI_FAILURE (Status))
180         {
181             return_ACPI_STATUS (Status);
182         }
183     }
184
185     if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
186     {
187         /* SMBus has a non-linear address space */
188
189         return_ACPI_STATUS (AE_OK);
190     }
191
192 #ifdef ACPI_UNDER_DEVELOPMENT
193     /*
194      * If the Field access is AnyAcc, we can now compute the optimal
195      * access (because we know know the length of the parent region)
196      */
197     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
198     {
199         if (ACPI_FAILURE (Status))
200         {
201             return_ACPI_STATUS (Status);
202         }
203     }
204 #endif
205
206     /*
207      * Validate the request.  The entire request from the byte offset for a
208      * length of one field datum (access width) must fit within the region.
209      * (Region length is specified in bytes)
210      */
211     if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
212                                     + FieldDatumByteOffset
213                                     + ObjDesc->CommonField.AccessByteWidth))
214     {
215         if (AcpiGbl_EnableInterpreterSlack)
216         {
217             /*
218              * Slack mode only:  We will go ahead and allow access to this
219              * field if it is within the region length rounded up to the next
220              * access width boundary.
221              */
222             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
223                                 ObjDesc->CommonField.AccessByteWidth) >=
224                 (ObjDesc->CommonField.BaseByteOffset +
225                  (ACPI_NATIVE_UINT) ObjDesc->CommonField.AccessByteWidth +
226                  FieldDatumByteOffset))
227             {
228                 return_ACPI_STATUS (AE_OK);
229             }
230         }
231
232         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
233         {
234             /*
235              * This is the case where the AccessType (AccWord, etc.) is wider
236              * than the region itself.  For example, a region of length one
237              * byte, and a field with Dword access specified.
238              */
239             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
240                 "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
241                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
242                 ObjDesc->CommonField.AccessByteWidth,
243                 AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
244         }
245
246         /*
247          * Offset rounded up to next multiple of field width
248          * exceeds region length, indicate an error
249          */
250         ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
251             "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
252             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
253             ObjDesc->CommonField.BaseByteOffset,
254             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
255             AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
256
257         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
258     }
259
260     return_ACPI_STATUS (AE_OK);
261 }
262
263
264 /*******************************************************************************
265  *
266  * FUNCTION:    AcpiExAccessRegion
267  *
268  * PARAMETERS:  *ObjDesc                - Field to be read
269  *              FieldDatumByteOffset    - Byte offset of this datum within the
270  *                                        parent field
271  *              *Value                  - Where to store value (must at least
272  *                                        the size of ACPI_INTEGER)
273  *              Function                - Read or Write flag plus other region-
274  *                                        dependent flags
275  *
276  * RETURN:      Status
277  *
278  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
279  *
280  ******************************************************************************/
281
282 ACPI_STATUS
283 AcpiExAccessRegion (
284     ACPI_OPERAND_OBJECT     *ObjDesc,
285     UINT32                  FieldDatumByteOffset,
286     ACPI_INTEGER            *Value,
287     UINT32                  Function)
288 {
289     ACPI_STATUS             Status;
290     ACPI_OPERAND_OBJECT     *RgnDesc;
291     ACPI_PHYSICAL_ADDRESS   Address;
292
293
294     ACPI_FUNCTION_TRACE ("ExAccessRegion");
295
296
297     /*
298      * Ensure that the region operands are fully evaluated and verify
299      * the validity of the request
300      */
301     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
302     if (ACPI_FAILURE (Status))
303     {
304         return_ACPI_STATUS (Status);
305     }
306
307     /*
308      * The physical address of this field datum is:
309      *
310      * 1) The base of the region, plus
311      * 2) The base offset of the field, plus
312      * 3) The current offset into the field
313      */
314     RgnDesc = ObjDesc->CommonField.RegionObj;
315     Address = RgnDesc->Region.Address
316                 + ObjDesc->CommonField.BaseByteOffset
317                 + FieldDatumByteOffset;
318
319     if ((Function & ACPI_IO_MASK) == ACPI_READ)
320     {
321         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
322     }
323     else
324     {
325         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
326     }
327
328     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
329         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
330         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
331         RgnDesc->Region.SpaceId,
332         ObjDesc->CommonField.AccessByteWidth,
333         ObjDesc->CommonField.BaseByteOffset,
334         FieldDatumByteOffset,
335         ACPI_FORMAT_UINT64 (Address)));
336
337     /* Invoke the appropriate AddressSpace/OpRegion handler */
338
339     Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
340                     Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
341
342     if (ACPI_FAILURE (Status))
343     {
344         if (Status == AE_NOT_IMPLEMENTED)
345         {
346             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
347                 "Region %s(%X) not implemented\n",
348                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
349                 RgnDesc->Region.SpaceId));
350         }
351         else if (Status == AE_NOT_EXIST)
352         {
353             ACPI_REPORT_ERROR ((
354                 "Region %s(%X) has no handler\n",
355                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
356                 RgnDesc->Region.SpaceId));
357         }
358     }
359
360     return_ACPI_STATUS (Status);
361 }
362
363
364 /*******************************************************************************
365  *
366  * FUNCTION:    AcpiExRegisterOverflow
367  *
368  * PARAMETERS:  *ObjDesc                - Register(Field) to be written
369  *              Value                   - Value to be stored
370  *
371  * RETURN:      TRUE if value overflows the field, FALSE otherwise
372  *
373  * DESCRIPTION: Check if a value is out of range of the field being written.
374  *              Used to check if the values written to Index and Bank registers
375  *              are out of range.  Normally, the value is simply truncated
376  *              to fit the field, but this case is most likely a serious
377  *              coding error in the ASL.
378  *
379  ******************************************************************************/
380
381 BOOLEAN
382 AcpiExRegisterOverflow (
383     ACPI_OPERAND_OBJECT     *ObjDesc,
384     ACPI_INTEGER            Value)
385 {
386
387     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
388     {
389         /*
390          * The field is large enough to hold the maximum integer, so we can
391          * never overflow it.
392          */
393         return (FALSE);
394     }
395
396     if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
397     {
398         /*
399          * The Value is larger than the maximum value that can fit into
400          * the register.
401          */
402         return (TRUE);
403     }
404
405     /* The Value will fit into the field with no truncation */
406
407     return (FALSE);
408 }
409
410
411 /*******************************************************************************
412  *
413  * FUNCTION:    AcpiExFieldDatumIo
414  *
415  * PARAMETERS:  *ObjDesc                - Field to be read
416  *              FieldDatumByteOffset    - Byte offset of this datum within the
417  *                                        parent field
418  *              *Value                  - Where to store value (must be 64 bits)
419  *              ReadWrite               - Read or Write flag
420  *
421  * RETURN:      Status
422  *
423  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
424  *              demultiplexed here to handle the different types of fields
425  *              (BufferField, RegionField, IndexField, BankField)
426  *
427  ******************************************************************************/
428
429 ACPI_STATUS
430 AcpiExFieldDatumIo (
431     ACPI_OPERAND_OBJECT     *ObjDesc,
432     UINT32                  FieldDatumByteOffset,
433     ACPI_INTEGER            *Value,
434     UINT32                  ReadWrite)
435 {
436     ACPI_STATUS             Status;
437     ACPI_INTEGER            LocalValue;
438
439
440     ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
441
442
443     if (ReadWrite == ACPI_READ)
444     {
445         if (!Value)
446         {
447             LocalValue = 0;
448             Value = &LocalValue;  /* To support reads without saving return value */
449         }
450
451         /* Clear the entire return buffer first, [Very Important!] */
452
453         *Value = 0;
454     }
455
456     /*
457      * The four types of fields are:
458      *
459      * BufferField - Read/write from/to a Buffer
460      * RegionField - Read/write from/to a Operation Region.
461      * BankField   - Write to a Bank Register, then read/write from/to an OpRegion
462      * IndexField  - Write to an Index Register, then read/write from/to a Data Register
463      */
464     switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
465     {
466     case ACPI_TYPE_BUFFER_FIELD:
467         /*
468          * If the BufferField arguments have not been previously evaluated,
469          * evaluate them now and save the results.
470          */
471         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
472         {
473             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
474             if (ACPI_FAILURE (Status))
475             {
476                 return_ACPI_STATUS (Status);
477             }
478         }
479
480         if (ReadWrite == ACPI_READ)
481         {
482             /*
483              * Copy the data from the source buffer.
484              * Length is the field width in bytes.
485              */
486             ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
487                             + ObjDesc->BufferField.BaseByteOffset
488                             + FieldDatumByteOffset,
489                             ObjDesc->CommonField.AccessByteWidth);
490         }
491         else
492         {
493             /*
494              * Copy the data to the target buffer.
495              * Length is the field width in bytes.
496              */
497             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
498                     + ObjDesc->BufferField.BaseByteOffset
499                     + FieldDatumByteOffset,
500                     Value, ObjDesc->CommonField.AccessByteWidth);
501         }
502
503         Status = AE_OK;
504         break;
505
506
507     case ACPI_TYPE_LOCAL_BANK_FIELD:
508
509         /* Ensure that the BankValue is not beyond the capacity of the register */
510
511         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
512                                     (ACPI_INTEGER) ObjDesc->BankField.Value))
513         {
514             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
515         }
516
517         /*
518          * For BankFields, we must write the BankValue to the BankRegister
519          * (itself a RegionField) before we can access the data.
520          */
521         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
522                                 &ObjDesc->BankField.Value,
523                                 sizeof (ObjDesc->BankField.Value));
524         if (ACPI_FAILURE (Status))
525         {
526             return_ACPI_STATUS (Status);
527         }
528
529         /*
530          * Now that the Bank has been selected, fall through to the
531          * RegionField case and write the datum to the Operation Region
532          */
533
534         /*lint -fallthrough */
535
536
537     case ACPI_TYPE_LOCAL_REGION_FIELD:
538         /*
539          * For simple RegionFields, we just directly access the owning
540          * Operation Region.
541          */
542         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
543                         ReadWrite);
544         break;
545
546
547     case ACPI_TYPE_LOCAL_INDEX_FIELD:
548
549
550         /* Ensure that the IndexValue is not beyond the capacity of the register */
551
552         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
553                                     (ACPI_INTEGER) ObjDesc->IndexField.Value))
554         {
555             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
556         }
557
558         /* Write the index value to the IndexRegister (itself a RegionField) */
559
560         FieldDatumByteOffset += ObjDesc->IndexField.Value;
561
562         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
563                 "Write to Index Register: Value %8.8X\n",
564                 FieldDatumByteOffset));
565
566         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
567                                 &FieldDatumByteOffset,
568                                 sizeof (FieldDatumByteOffset));
569         if (ACPI_FAILURE (Status))
570         {
571             return_ACPI_STATUS (Status);
572         }
573
574         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
575                 "I/O to Data Register: ValuePtr %p\n",
576                 Value));
577
578         if (ReadWrite == ACPI_READ)
579         {
580             /* Read the datum from the DataRegister */
581
582             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
583                             Value, sizeof (ACPI_INTEGER));
584         }
585         else
586         {
587             /* Write the datum to the DataRegister */
588
589             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
590                             Value, sizeof (ACPI_INTEGER));
591         }
592         break;
593
594
595     default:
596
597         ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
598             ACPI_GET_OBJECT_TYPE (ObjDesc)));
599         Status = AE_AML_INTERNAL;
600         break;
601     }
602
603     if (ACPI_SUCCESS (Status))
604     {
605         if (ReadWrite == ACPI_READ)
606         {
607             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
608                                 ACPI_FORMAT_UINT64 (*Value),
609                                 ObjDesc->CommonField.AccessByteWidth));
610         }
611         else
612         {
613             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
614                                 ACPI_FORMAT_UINT64 (*Value),
615                                 ObjDesc->CommonField.AccessByteWidth));
616         }
617     }
618
619     return_ACPI_STATUS (Status);
620 }
621
622
623 /*******************************************************************************
624  *
625  * FUNCTION:    AcpiExWriteWithUpdateRule
626  *
627  * PARAMETERS:  *ObjDesc            - Field to be set
628  *              Value               - Value to store
629  *
630  * RETURN:      Status
631  *
632  * DESCRIPTION: Apply the field update rule to a field write
633  *
634  ******************************************************************************/
635
636 ACPI_STATUS
637 AcpiExWriteWithUpdateRule (
638     ACPI_OPERAND_OBJECT     *ObjDesc,
639     ACPI_INTEGER            Mask,
640     ACPI_INTEGER            FieldValue,
641     UINT32                  FieldDatumByteOffset)
642 {
643     ACPI_STATUS             Status = AE_OK;
644     ACPI_INTEGER            MergedValue;
645     ACPI_INTEGER            CurrentValue;
646
647
648     ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
649
650
651     /* Start with the new bits  */
652
653     MergedValue = FieldValue;
654
655     /* If the mask is all ones, we don't need to worry about the update rule */
656
657     if (Mask != ACPI_INTEGER_MAX)
658     {
659         /* Decode the update rule */
660
661         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
662         {
663         case AML_FIELD_UPDATE_PRESERVE:
664             /*
665              * Check if update rule needs to be applied (not if mask is all
666              * ones)  The left shift drops the bits we want to ignore.
667              */
668             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
669                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
670             {
671                 /*
672                  * Read the current contents of the byte/word/dword containing
673                  * the field, and merge with the new field value.
674                  */
675                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
676                                 &CurrentValue, ACPI_READ);
677                 if (ACPI_FAILURE (Status))
678                 {
679                     return_ACPI_STATUS (Status);
680                 }
681
682                 MergedValue |= (CurrentValue & ~Mask);
683             }
684             break;
685
686         case AML_FIELD_UPDATE_WRITE_AS_ONES:
687
688             /* Set positions outside the field to all ones */
689
690             MergedValue |= ~Mask;
691             break;
692
693         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
694
695             /* Set positions outside the field to all zeros */
696
697             MergedValue &= Mask;
698             break;
699
700         default:
701
702             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
703                 "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
704                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
705             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
706         }
707     }
708
709     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
710         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
711         ACPI_FORMAT_UINT64 (Mask),
712         FieldDatumByteOffset,
713         ObjDesc->CommonField.AccessByteWidth,
714         ACPI_FORMAT_UINT64 (FieldValue),
715         ACPI_FORMAT_UINT64 (MergedValue)));
716
717     /* Write the merged value */
718
719     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
720                     &MergedValue, ACPI_WRITE);
721
722     return_ACPI_STATUS (Status);
723 }
724
725
726 /*******************************************************************************
727  *
728  * FUNCTION:    AcpiExGetBufferDatum
729  *
730  * PARAMETERS:  Datum               - Where the Datum is returned
731  *              Buffer              - Raw field buffer
732  *              BufferLength        - Entire length (used for big-endian only)
733  *              ByteGranularity     - 1/2/4/8 Granularity of the field
734  *                                    (aka Datum Size)
735  *              BufferOffset        - Datum offset into the buffer
736  *
737  * RETURN:      none
738  *
739  * DESCRIPTION: Get a datum from the buffer according to the buffer field
740  *              byte granularity
741  *
742  ******************************************************************************/
743
744 void
745 AcpiExGetBufferDatum (
746     ACPI_INTEGER            *Datum,
747     void                    *Buffer,
748     UINT32                  BufferLength,
749     UINT32                  ByteGranularity,
750     UINT32                  BufferOffset)
751 {
752     UINT32                  Index;
753
754
755     ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity);
756
757
758     /* Get proper index into buffer (handles big/little endian) */
759
760     Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
761
762     /* Move the requested number of bytes */
763
764     switch (ByteGranularity)
765     {
766     case ACPI_FIELD_BYTE_GRANULARITY:
767
768         *Datum = ((UINT8 *) Buffer) [Index];
769         break;
770
771     case ACPI_FIELD_WORD_GRANULARITY:
772
773         ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index]));
774         break;
775
776     case ACPI_FIELD_DWORD_GRANULARITY:
777
778         ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index]));
779         break;
780
781     case ACPI_FIELD_QWORD_GRANULARITY:
782
783         ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index]));
784         break;
785
786     default:
787         /* Should not get here */
788         break;
789     }
790
791     return_VOID;
792 }
793
794
795 /*******************************************************************************
796  *
797  * FUNCTION:    AcpiExSetBufferDatum
798  *
799  * PARAMETERS:  MergedDatum         - Value to store
800  *              Buffer              - Receiving buffer
801  *              BufferLength        - Entire length (used for big-endian only)
802  *              ByteGranularity     - 1/2/4/8 Granularity of the field
803  *                                    (aka Datum Size)
804  *              BufferOffset        - Datum offset into the buffer
805  *
806  * RETURN:      none
807  *
808  * DESCRIPTION: Store the merged datum to the buffer according to the
809  *              byte granularity
810  *
811  ******************************************************************************/
812
813 void
814 AcpiExSetBufferDatum (
815     ACPI_INTEGER            MergedDatum,
816     void                    *Buffer,
817     UINT32                  BufferLength,
818     UINT32                  ByteGranularity,
819     UINT32                  BufferOffset)
820 {
821     UINT32                  Index;
822
823
824     ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity);
825
826
827     /* Get proper index into buffer (handles big/little endian) */
828
829     Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
830
831     /* Move the requested number of bytes */
832
833     switch (ByteGranularity)
834     {
835     case ACPI_FIELD_BYTE_GRANULARITY:
836
837         ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum;
838         break;
839
840     case ACPI_FIELD_WORD_GRANULARITY:
841
842         ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum);
843         break;
844
845     case ACPI_FIELD_DWORD_GRANULARITY:
846
847         ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum);
848         break;
849
850     case ACPI_FIELD_QWORD_GRANULARITY:
851
852         ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum);
853         break;
854
855     default:
856         /* Should not get here */
857         break;
858     }
859
860     return_VOID;
861 }
862
863
864 /*******************************************************************************
865  *
866  * FUNCTION:    AcpiExCommonBufferSetup
867  *
868  * PARAMETERS:  ObjDesc             - Field object
869  *              BufferLength        - Length of caller's buffer
870  *              DatumCount          - Where the DatumCount is returned
871  *
872  * RETURN:      Status, DatumCount
873  *
874  * DESCRIPTION: Common code to validate the incoming buffer size and compute
875  *              the number of field "datums" that must be read or written.
876  *              A "datum" is the smallest unit that can be read or written
877  *              to the field, it is either 1,2,4, or 8 bytes.
878  *
879  ******************************************************************************/
880
881 ACPI_STATUS
882 AcpiExCommonBufferSetup (
883     ACPI_OPERAND_OBJECT     *ObjDesc,
884     UINT32                  BufferLength,
885     UINT32                  *DatumCount)
886 {
887     UINT32                  ByteFieldLength;
888     UINT32                  ActualByteFieldLength;
889
890
891     ACPI_FUNCTION_TRACE ("ExCommonBufferSetup");
892
893
894     /*
895      * Incoming buffer must be at least as long as the field, we do not
896      * allow "partial" field reads/writes.  We do not care if the buffer is
897      * larger than the field, this typically happens when an integer is
898      * read/written to a field that is actually smaller than an integer.
899      */
900     ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
901                             ObjDesc->CommonField.BitLength);
902     if (ByteFieldLength > BufferLength)
903     {
904         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
905             "Field size %X (bytes) is too large for buffer (%X)\n",
906             ByteFieldLength, BufferLength));
907
908         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
909     }
910
911     /*
912      * Create "actual" field byte count (minimum number of bytes that
913      * must be read), then convert to datum count (minimum number
914      * of datum-sized units that must be read)
915      */
916     ActualByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
917                                 ObjDesc->CommonField.StartFieldBitOffset +
918                                 ObjDesc->CommonField.BitLength);
919
920
921     *DatumCount = ACPI_ROUND_UP_TO (ActualByteFieldLength,
922                         ObjDesc->CommonField.AccessByteWidth);
923
924     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
925         "BufferBytes %X, ActualBytes %X, Datums %X, ByteGran %X\n",
926         ByteFieldLength, ActualByteFieldLength,
927         *DatumCount, ObjDesc->CommonField.AccessByteWidth));
928
929     return_ACPI_STATUS (AE_OK);
930 }
931
932
933 /*******************************************************************************
934  *
935  * FUNCTION:    AcpiExExtractFromField
936  *
937  * PARAMETERS:  ObjDesc             - Field to be read
938  *              Buffer              - Where to store the field data
939  *              BufferLength        - Length of Buffer
940  *
941  * RETURN:      Status
942  *
943  * DESCRIPTION: Retrieve the current value of the given field
944  *
945  ******************************************************************************/
946
947 ACPI_STATUS
948 AcpiExExtractFromField (
949     ACPI_OPERAND_OBJECT     *ObjDesc,
950     void                    *Buffer,
951     UINT32                  BufferLength)
952 {
953     ACPI_STATUS             Status;
954     UINT32                  FieldDatumByteOffset;
955     UINT32                  BufferDatumOffset;
956     ACPI_INTEGER            PreviousRawDatum = 0;
957     ACPI_INTEGER            ThisRawDatum = 0;
958     ACPI_INTEGER            MergedDatum = 0;
959     UINT32                  DatumCount;
960     UINT32                  i;
961
962
963     ACPI_FUNCTION_TRACE ("ExExtractFromField");
964
965
966     /* Validate buffer, compute number of datums */
967
968     Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
969     if (ACPI_FAILURE (Status))
970     {
971         return_ACPI_STATUS (Status);
972     }
973
974     /*
975      * Clear the caller's buffer (the whole buffer length as given)
976      * This is very important, especially in the cases where the buffer
977      * is longer than the size of the field.
978      */
979     ACPI_MEMSET (Buffer, 0, BufferLength);
980
981     FieldDatumByteOffset = 0;
982     BufferDatumOffset= 0;
983
984     /* Read the entire field */
985
986     for (i = 0; i < DatumCount; i++)
987     {
988         Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
989                         &ThisRawDatum, ACPI_READ);
990         if (ACPI_FAILURE (Status))
991         {
992             return_ACPI_STATUS (Status);
993         }
994
995         /* We might actually be done if the request fits in one datum */
996
997         if ((DatumCount == 1) &&
998             (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
999         {
1000             /* 1) Shift the valid data bits down to start at bit 0 */
1001
1002             MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1003
1004             /* 2) Mask off any upper unused bits (bits not part of the field) */
1005
1006             if (ObjDesc->CommonField.EndBufferValidBits)
1007             {
1008                 MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
1009             }
1010
1011             /* Store the datum to the caller buffer */
1012
1013             AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1014                     ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1015
1016             return_ACPI_STATUS (AE_OK);
1017         }
1018
1019         /* Special handling for the last datum to ignore extra bits */
1020
1021         if ((i >= (DatumCount -1))           &&
1022             (ObjDesc->CommonField.EndFieldValidBits))
1023         {
1024             /*
1025              * This is the last iteration of the loop.  We need to clear
1026              * any unused bits (bits that are not part of this field) before
1027              * we store the final merged datum into the caller buffer.
1028              */
1029             ThisRawDatum &=
1030                 ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1031         }
1032
1033         /*
1034          * Create the (possibly) merged datum to be stored to the caller buffer
1035          */
1036         if (ObjDesc->CommonField.StartFieldBitOffset == 0)
1037         {
1038             /* Field is not skewed and we can just copy the datum */
1039
1040             AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength,
1041                     ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1042             BufferDatumOffset++;
1043         }
1044         else
1045         {
1046             /* Not aligned -- on the first iteration, just save the datum */
1047
1048             if (i != 0)
1049             {
1050                 /*
1051                  * Put together the appropriate bits of the two raw data to make a
1052                  * single complete field datum
1053                  *
1054                  * 1) Normalize the first datum down to bit 0
1055                  */
1056                 MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1057
1058                 /* 2) Insert the second datum "above" the first datum */
1059
1060                 MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
1061
1062                 AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1063                         ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1064                 BufferDatumOffset++;
1065             }
1066
1067             /*
1068              * Save the raw datum that was just acquired since it may contain bits
1069              * of the *next* field datum
1070              */
1071             PreviousRawDatum = ThisRawDatum;
1072         }
1073
1074         FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1075     }
1076
1077     /* For non-aligned case, there is one last datum to insert */
1078
1079     if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1080     {
1081         MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1082
1083         AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1084                 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1085     }
1086
1087     return_ACPI_STATUS (AE_OK);
1088 }
1089
1090
1091 /*******************************************************************************
1092  *
1093  * FUNCTION:    AcpiExInsertIntoField
1094  *
1095  * PARAMETERS:  ObjDesc             - Field to be written
1096  *              Buffer              - Data to be written
1097  *              BufferLength        - Length of Buffer
1098  *
1099  * RETURN:      Status
1100  *
1101  * DESCRIPTION: Store the Buffer contents into the given field
1102  *
1103  ******************************************************************************/
1104
1105 ACPI_STATUS
1106 AcpiExInsertIntoField (
1107     ACPI_OPERAND_OBJECT     *ObjDesc,
1108     void                    *Buffer,
1109     UINT32                  BufferLength)
1110 {
1111     ACPI_STATUS             Status;
1112     UINT32                  FieldDatumByteOffset;
1113     UINT32                  DatumOffset;
1114     ACPI_INTEGER            Mask;
1115     ACPI_INTEGER            MergedDatum;
1116     ACPI_INTEGER            PreviousRawDatum;
1117     ACPI_INTEGER            ThisRawDatum;
1118     UINT32                  DatumCount;
1119
1120
1121     ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1122
1123
1124     /* Validate buffer, compute number of datums */
1125
1126     Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
1127     if (ACPI_FAILURE (Status))
1128     {
1129         return_ACPI_STATUS (Status);
1130     }
1131
1132     /*
1133      * Break the request into up to three parts (similar to an I/O request):
1134      * 1) non-aligned part at start
1135      * 2) aligned part in middle
1136      * 3) non-aligned part at the end
1137      */
1138     FieldDatumByteOffset = 0;
1139     DatumOffset= 0;
1140
1141     /* Get a single datum from the caller's buffer */
1142
1143     AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1144             ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1145
1146     /*
1147      * Part1:
1148      * Write a partial field datum if field does not begin on a datum boundary
1149      * Note: The code in this section also handles the aligned case
1150      *
1151      * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1152      * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1153      *
1154      * Mask off bits that are "below" the field (if any)
1155      */
1156     Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1157
1158     /* If the field fits in one datum, may need to mask upper bits */
1159
1160     if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1161          ObjDesc->CommonField.EndFieldValidBits)
1162     {
1163         /* There are bits above the field, mask them off also */
1164
1165         Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1166     }
1167
1168     /* Shift and mask the value into the field position */
1169
1170     MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1171     MergedDatum &= Mask;
1172
1173     /* Apply the update rule (if necessary) and write the datum to the field */
1174
1175     Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1176                         FieldDatumByteOffset);
1177     if (ACPI_FAILURE (Status))
1178     {
1179         return_ACPI_STATUS (Status);
1180     }
1181
1182     /* We just wrote the first datum */
1183
1184     DatumOffset++;
1185
1186     /* If the entire field fits within one datum, we are done. */
1187
1188     if ((DatumCount == 1) &&
1189        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1190     {
1191         return_ACPI_STATUS (AE_OK);
1192     }
1193
1194     /*
1195      * Part2:
1196      * Write the aligned data.
1197      *
1198      * We don't need to worry about the update rule for these data, because
1199      * all of the bits in each datum are part of the field.
1200      *
1201      * The last datum must be special cased because it might contain bits
1202      * that are not part of the field -- therefore the "update rule" must be
1203      * applied in Part3 below.
1204      */
1205     while (DatumOffset < DatumCount)
1206     {
1207         FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1208
1209         /*
1210          * Get the next raw buffer datum.  It may contain bits of the previous
1211          * field datum
1212          */
1213         AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1214                 ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1215
1216         /* Create the field datum based on the field alignment */
1217
1218         if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1219         {
1220             /*
1221              * Put together appropriate bits of the two raw buffer data to make
1222              * a single complete field datum
1223              */
1224             MergedDatum =
1225                 (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1226                 (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1227         }
1228         else
1229         {
1230             /* Field began aligned on datum boundary */
1231
1232             MergedDatum = ThisRawDatum;
1233         }
1234
1235         /*
1236          * Special handling for the last datum if the field does NOT end on
1237          * a datum boundary.  Update Rule must be applied to the bits outside
1238          * the field.
1239          */
1240         DatumOffset++;
1241         if ((DatumOffset == DatumCount) &&
1242             (ObjDesc->CommonField.EndFieldValidBits))
1243         {
1244             /*
1245              * If there are dangling non-aligned bits, perform one more merged write
1246              * Else - field is aligned at the end, no need for any more writes
1247              */
1248
1249             /*
1250              * Part3:
1251              * This is the last datum and the field does not end on a datum boundary.
1252              * Build the partial datum and write with the update rule.
1253              *
1254              * Mask off the unused bits above (after) the end-of-field
1255              */
1256             Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1257             MergedDatum &= Mask;
1258
1259             /* Write the last datum with the update rule */
1260
1261             Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1262                                 FieldDatumByteOffset);
1263             if (ACPI_FAILURE (Status))
1264             {
1265                 return_ACPI_STATUS (Status);
1266             }
1267         }
1268         else
1269         {
1270             /* Normal (aligned) case -- write the completed datum */
1271
1272             Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1273                             &MergedDatum, ACPI_WRITE);
1274             if (ACPI_FAILURE (Status))
1275             {
1276                 return_ACPI_STATUS (Status);
1277             }
1278         }
1279
1280         /*
1281          * Save the most recent datum since it may contain bits of the *next*
1282          * field datum.  Update current byte offset.
1283          */
1284         PreviousRawDatum = ThisRawDatum;
1285     }
1286
1287     return_ACPI_STATUS (Status);
1288 }
1289
1290