exfldio.c revision 228110
1289848Sjkim/******************************************************************************
2289848Sjkim *
3289848Sjkim * Module Name: exfldio - Aml Field I/O
4289848Sjkim *
5289848Sjkim *****************************************************************************/
6289848Sjkim
7289848Sjkim/*
8289848Sjkim * Copyright (C) 2000 - 2011, Intel Corp.
9289848Sjkim * All rights reserved.
10289848Sjkim *
11289848Sjkim * Redistribution and use in source and binary forms, with or without
12289848Sjkim * modification, are permitted provided that the following conditions
13289848Sjkim * are met:
14289848Sjkim * 1. Redistributions of source code must retain the above copyright
15289848Sjkim *    notice, this list of conditions, and the following disclaimer,
16289848Sjkim *    without modification.
17289848Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18289848Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19289848Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20289848Sjkim *    including a substantially similar Disclaimer requirement for further
21289848Sjkim *    binary redistribution.
22289848Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23289848Sjkim *    of any contributors may be used to endorse or promote products derived
24289848Sjkim *    from this software without specific prior written permission.
25289848Sjkim *
26289848Sjkim * Alternatively, this software may be distributed under the terms of the
27289848Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28289848Sjkim * Software Foundation.
29289848Sjkim *
30289848Sjkim * NO WARRANTY
31289848Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32289848Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33289848Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34289848Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35289848Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36289848Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37289848Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38289848Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39289848Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40289848Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41289848Sjkim * POSSIBILITY OF SUCH DAMAGES.
42289848Sjkim */
43289848Sjkim
44289848Sjkim
45289848Sjkim#define __EXFLDIO_C__
46289848Sjkim
47289848Sjkim#include <contrib/dev/acpica/include/acpi.h>
48289848Sjkim#include <contrib/dev/acpica/include/accommon.h>
49289848Sjkim#include <contrib/dev/acpica/include/acinterp.h>
50289848Sjkim#include <contrib/dev/acpica/include/amlcode.h>
51289848Sjkim#include <contrib/dev/acpica/include/acevents.h>
52289848Sjkim#include <contrib/dev/acpica/include/acdispat.h>
53289848Sjkim
54289848Sjkim
55289848Sjkim#define _COMPONENT          ACPI_EXECUTER
56289848Sjkim        ACPI_MODULE_NAME    ("exfldio")
57289848Sjkim
58289848Sjkim/* Local prototypes */
59289848Sjkim
60289848Sjkimstatic ACPI_STATUS
61289848SjkimAcpiExFieldDatumIo (
62289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
63289848Sjkim    UINT32                  FieldDatumByteOffset,
64289848Sjkim    UINT64                  *Value,
65289848Sjkim    UINT32                  ReadWrite);
66289848Sjkim
67289848Sjkimstatic BOOLEAN
68289848SjkimAcpiExRegisterOverflow (
69289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
70289848Sjkim    UINT64                  Value);
71289848Sjkim
72289848Sjkimstatic ACPI_STATUS
73289848SjkimAcpiExSetupRegion (
74289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
75289848Sjkim    UINT32                  FieldDatumByteOffset);
76289848Sjkim
77289848Sjkim
78289848Sjkim/*******************************************************************************
79289848Sjkim *
80289848Sjkim * FUNCTION:    AcpiExSetupRegion
81289848Sjkim *
82289848Sjkim * PARAMETERS:  ObjDesc                 - Field to be read or written
83289848Sjkim *              FieldDatumByteOffset    - Byte offset of this datum within the
84289848Sjkim *                                        parent field
85289848Sjkim *
86289848Sjkim * RETURN:      Status
87289848Sjkim *
88289848Sjkim * DESCRIPTION: Common processing for AcpiExExtractFromField and
89289848Sjkim *              AcpiExInsertIntoField.  Initialize the Region if necessary and
90289848Sjkim *              validate the request.
91289848Sjkim *
92289848Sjkim ******************************************************************************/
93289848Sjkim
94289848Sjkimstatic ACPI_STATUS
95289848SjkimAcpiExSetupRegion (
96289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
97289848Sjkim    UINT32                  FieldDatumByteOffset)
98289848Sjkim{
99306198Sjkim    ACPI_STATUS             Status = AE_OK;
100289848Sjkim    ACPI_OPERAND_OBJECT     *RgnDesc;
101289848Sjkim    UINT8                   SpaceId;
102289848Sjkim
103289848Sjkim
104289848Sjkim    ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
105289848Sjkim
106289848Sjkim
107289848Sjkim    RgnDesc = ObjDesc->CommonField.RegionObj;
108289848Sjkim
109289848Sjkim    /* We must have a valid region */
110289848Sjkim
111289848Sjkim    if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
112289848Sjkim    {
113289848Sjkim        ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
114289848Sjkim            RgnDesc->Common.Type,
115289848Sjkim            AcpiUtGetObjectTypeName (RgnDesc)));
116289848Sjkim
117289848Sjkim        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
118289848Sjkim    }
119289848Sjkim
120289848Sjkim    SpaceId = RgnDesc->Region.SpaceId;
121289848Sjkim
122289848Sjkim    /* Validate the Space ID */
123289848Sjkim
124289848Sjkim    if (!AcpiIsValidSpaceId (SpaceId))
125289848Sjkim    {
126289848Sjkim        ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
127289848Sjkim        return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
128289848Sjkim    }
129289848Sjkim
130289848Sjkim    /*
131289848Sjkim     * If the Region Address and Length have not been previously evaluated,
132289848Sjkim     * evaluate them now and save the results.
133289848Sjkim     */
134289848Sjkim    if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
135289848Sjkim    {
136289848Sjkim        Status = AcpiDsGetRegionArguments (RgnDesc);
137289848Sjkim        if (ACPI_FAILURE (Status))
138289848Sjkim        {
139289848Sjkim            return_ACPI_STATUS (Status);
140289848Sjkim        }
141289848Sjkim    }
142289848Sjkim
143289848Sjkim    /*
144289848Sjkim     * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
145289848Sjkim     * address space and the request cannot be directly validated
146289848Sjkim     */
147289848Sjkim    if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
148289848Sjkim        SpaceId == ACPI_ADR_SPACE_GSBUS ||
149289848Sjkim        SpaceId == ACPI_ADR_SPACE_IPMI)
150289848Sjkim    {
151289848Sjkim        /* SMBus or IPMI has a non-linear address space */
152289848Sjkim
153289848Sjkim        return_ACPI_STATUS (AE_OK);
154289848Sjkim    }
155289848Sjkim
156289848Sjkim#ifdef ACPI_UNDER_DEVELOPMENT
157289848Sjkim    /*
158289848Sjkim     * If the Field access is AnyAcc, we can now compute the optimal
159289848Sjkim     * access (because we know know the length of the parent region)
160289848Sjkim     */
161289848Sjkim    if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
162289848Sjkim    {
163289848Sjkim        if (ACPI_FAILURE (Status))
164289848Sjkim        {
165289848Sjkim            return_ACPI_STATUS (Status);
166289848Sjkim        }
167289848Sjkim    }
168289848Sjkim#endif
169289848Sjkim
170289848Sjkim    /*
171289848Sjkim     * Validate the request.  The entire request from the byte offset for a
172289848Sjkim     * length of one field datum (access width) must fit within the region.
173289848Sjkim     * (Region length is specified in bytes)
174289848Sjkim     */
175289848Sjkim    if (RgnDesc->Region.Length <
176289848Sjkim            (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
177289848Sjkim            ObjDesc->CommonField.AccessByteWidth))
178289848Sjkim    {
179289848Sjkim        if (AcpiGbl_EnableInterpreterSlack)
180289848Sjkim        {
181289848Sjkim            /*
182289848Sjkim             * Slack mode only:  We will go ahead and allow access to this
183289848Sjkim             * field if it is within the region length rounded up to the next
184289848Sjkim             * access width boundary. ACPI_SIZE cast for 64-bit compile.
185289848Sjkim             */
186289848Sjkim            if (ACPI_ROUND_UP (RgnDesc->Region.Length,
187289848Sjkim                    ObjDesc->CommonField.AccessByteWidth) >=
188289848Sjkim                ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
189289848Sjkim                    ObjDesc->CommonField.AccessByteWidth +
190289848Sjkim                    FieldDatumByteOffset))
191289848Sjkim            {
192289848Sjkim                return_ACPI_STATUS (AE_OK);
193289848Sjkim            }
194289848Sjkim        }
195289848Sjkim
196289848Sjkim        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
197289848Sjkim        {
198289848Sjkim            /*
199289848Sjkim             * This is the case where the AccessType (AccWord, etc.) is wider
200306198Sjkim             * than the region itself.  For example, a region of length one
201289848Sjkim             * byte, and a field with Dword access specified.
202289848Sjkim             */
203289848Sjkim            ACPI_ERROR ((AE_INFO,
204289848Sjkim                "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
205289848Sjkim                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
206289848Sjkim                ObjDesc->CommonField.AccessByteWidth,
207289848Sjkim                AcpiUtGetNodeName (RgnDesc->Region.Node),
208289848Sjkim                RgnDesc->Region.Length));
209289848Sjkim        }
210289848Sjkim
211289848Sjkim        /*
212289848Sjkim         * Offset rounded up to next multiple of field width
213289848Sjkim         * exceeds region length, indicate an error
214289848Sjkim         */
215289848Sjkim        ACPI_ERROR ((AE_INFO,
216289848Sjkim            "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
217289848Sjkim            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
218289848Sjkim            ObjDesc->CommonField.BaseByteOffset,
219289848Sjkim            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
220289848Sjkim            AcpiUtGetNodeName (RgnDesc->Region.Node),
221289848Sjkim            RgnDesc->Region.Length));
222289848Sjkim
223289848Sjkim        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
224289848Sjkim    }
225289848Sjkim
226289848Sjkim    return_ACPI_STATUS (AE_OK);
227289848Sjkim}
228289848Sjkim
229289848Sjkim
230289848Sjkim/*******************************************************************************
231289848Sjkim *
232289848Sjkim * FUNCTION:    AcpiExAccessRegion
233289848Sjkim *
234289848Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
235289848Sjkim *              FieldDatumByteOffset    - Byte offset of this datum within the
236289848Sjkim *                                        parent field
237289848Sjkim *              Value                   - Where to store value (must at least
238289848Sjkim *                                        64 bits)
239289848Sjkim *              Function                - Read or Write flag plus other region-
240289848Sjkim *                                        dependent flags
241289848Sjkim *
242289848Sjkim * RETURN:      Status
243289848Sjkim *
244289848Sjkim * DESCRIPTION: Read or Write a single field datum to an Operation Region.
245289848Sjkim *
246289848Sjkim ******************************************************************************/
247289848Sjkim
248289848SjkimACPI_STATUS
249289848SjkimAcpiExAccessRegion (
250289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
251289848Sjkim    UINT32                  FieldDatumByteOffset,
252289848Sjkim    UINT64                  *Value,
253289848Sjkim    UINT32                  Function)
254289848Sjkim{
255289848Sjkim    ACPI_STATUS             Status;
256289848Sjkim    ACPI_OPERAND_OBJECT     *RgnDesc;
257289848Sjkim    UINT32                  RegionOffset;
258289848Sjkim
259289848Sjkim
260289848Sjkim    ACPI_FUNCTION_TRACE (ExAccessRegion);
261289848Sjkim
262289848Sjkim
263289848Sjkim    /*
264289848Sjkim     * Ensure that the region operands are fully evaluated and verify
265289848Sjkim     * the validity of the request
266289848Sjkim     */
267289848Sjkim    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
268289848Sjkim    if (ACPI_FAILURE (Status))
269289848Sjkim    {
270289848Sjkim        return_ACPI_STATUS (Status);
271289848Sjkim    }
272289848Sjkim
273289848Sjkim    /*
274289848Sjkim     * The physical address of this field datum is:
275289848Sjkim     *
276289848Sjkim     * 1) The base of the region, plus
277289848Sjkim     * 2) The base offset of the field, plus
278289848Sjkim     * 3) The current offset into the field
279289848Sjkim     */
280289848Sjkim    RgnDesc = ObjDesc->CommonField.RegionObj;
281289848Sjkim    RegionOffset =
282289848Sjkim        ObjDesc->CommonField.BaseByteOffset +
283289848Sjkim        FieldDatumByteOffset;
284289848Sjkim
285289848Sjkim    if ((Function & ACPI_IO_MASK) == ACPI_READ)
286289848Sjkim    {
287289848Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
288289848Sjkim    }
289289848Sjkim    else
290289848Sjkim    {
291289848Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
292289848Sjkim    }
293289848Sjkim
294289848Sjkim    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
295289848Sjkim        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
296289848Sjkim        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
297289848Sjkim        RgnDesc->Region.SpaceId,
298289848Sjkim        ObjDesc->CommonField.AccessByteWidth,
299289848Sjkim        ObjDesc->CommonField.BaseByteOffset,
300289848Sjkim        FieldDatumByteOffset,
301289848Sjkim        ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
302289848Sjkim
303289848Sjkim    /* Invoke the appropriate AddressSpace/OpRegion handler */
304289848Sjkim
305289848Sjkim    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc,
306289848Sjkim                Function, RegionOffset,
307289848Sjkim                ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
308306198Sjkim
309289848Sjkim    if (ACPI_FAILURE (Status))
310289848Sjkim    {
311289848Sjkim        if (Status == AE_NOT_IMPLEMENTED)
312289848Sjkim        {
313289848Sjkim            ACPI_ERROR ((AE_INFO,
314289848Sjkim                "Region %s (ID=%u) not implemented",
315289848Sjkim                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
316289848Sjkim                RgnDesc->Region.SpaceId));
317289848Sjkim        }
318289848Sjkim        else if (Status == AE_NOT_EXIST)
319289848Sjkim        {
320289848Sjkim            ACPI_ERROR ((AE_INFO,
321289848Sjkim                "Region %s (ID=%u) has no handler",
322289848Sjkim                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
323289848Sjkim                RgnDesc->Region.SpaceId));
324289848Sjkim        }
325289848Sjkim    }
326289848Sjkim
327289848Sjkim    return_ACPI_STATUS (Status);
328289848Sjkim}
329289848Sjkim
330289848Sjkim
331289848Sjkim/*******************************************************************************
332289848Sjkim *
333289848Sjkim * FUNCTION:    AcpiExRegisterOverflow
334289848Sjkim *
335289848Sjkim * PARAMETERS:  ObjDesc                 - Register(Field) to be written
336289848Sjkim *              Value                   - Value to be stored
337289848Sjkim *
338289848Sjkim * RETURN:      TRUE if value overflows the field, FALSE otherwise
339289848Sjkim *
340289848Sjkim * DESCRIPTION: Check if a value is out of range of the field being written.
341289848Sjkim *              Used to check if the values written to Index and Bank registers
342289848Sjkim *              are out of range.  Normally, the value is simply truncated
343289848Sjkim *              to fit the field, but this case is most likely a serious
344289848Sjkim *              coding error in the ASL.
345289848Sjkim *
346289848Sjkim ******************************************************************************/
347289848Sjkim
348289848Sjkimstatic BOOLEAN
349289848SjkimAcpiExRegisterOverflow (
350289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
351289848Sjkim    UINT64                  Value)
352289848Sjkim{
353289848Sjkim    ACPI_FUNCTION_NAME (ExRegisterOverflow);
354289848Sjkim
355289848Sjkim
356289848Sjkim    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
357289848Sjkim    {
358289848Sjkim        /*
359289848Sjkim         * The field is large enough to hold the maximum integer, so we can
360289848Sjkim         * never overflow it.
361289848Sjkim         */
362289848Sjkim        return (FALSE);
363289848Sjkim    }
364289848Sjkim
365289848Sjkim    if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
366289848Sjkim    {
367289848Sjkim        /*
368289848Sjkim         * The Value is larger than the maximum value that can fit into
369289848Sjkim         * the register.
370289848Sjkim         */
371289848Sjkim        ACPI_ERROR ((AE_INFO,
372289848Sjkim            "Index value 0x%8.8X%8.8X overflows field width 0x%X",
373289848Sjkim            ACPI_FORMAT_UINT64 (Value),
374289848Sjkim            ObjDesc->CommonField.BitLength));
375289848Sjkim
376289848Sjkim        return (TRUE);
377289848Sjkim    }
378289848Sjkim
379289848Sjkim    /* The Value will fit into the field with no truncation */
380289848Sjkim
381289848Sjkim    return (FALSE);
382289848Sjkim}
383289848Sjkim
384289848Sjkim
385289848Sjkim/*******************************************************************************
386289848Sjkim *
387289848Sjkim * FUNCTION:    AcpiExFieldDatumIo
388289848Sjkim *
389289848Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
390289848Sjkim *              FieldDatumByteOffset    - Byte offset of this datum within the
391289848Sjkim *                                        parent field
392289848Sjkim *              Value                   - Where to store value (must be 64 bits)
393289848Sjkim *              ReadWrite               - Read or Write flag
394289848Sjkim *
395289848Sjkim * RETURN:      Status
396289848Sjkim *
397289848Sjkim * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
398289848Sjkim *              demultiplexed here to handle the different types of fields
399289848Sjkim *              (BufferField, RegionField, IndexField, BankField)
400289848Sjkim *
401289848Sjkim ******************************************************************************/
402289848Sjkim
403289848Sjkimstatic ACPI_STATUS
404289848SjkimAcpiExFieldDatumIo (
405289848Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
406289848Sjkim    UINT32                  FieldDatumByteOffset,
407289848Sjkim    UINT64                  *Value,
408289848Sjkim    UINT32                  ReadWrite)
409289848Sjkim{
410289848Sjkim    ACPI_STATUS             Status;
411289848Sjkim    UINT64                  LocalValue;
412289848Sjkim
413289848Sjkim
414289848Sjkim    ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
415289848Sjkim
416289848Sjkim
417289848Sjkim    if (ReadWrite == ACPI_READ)
418289848Sjkim    {
419289848Sjkim        if (!Value)
420289848Sjkim        {
421289848Sjkim            LocalValue = 0;
422289848Sjkim
423289848Sjkim            /* To support reads without saving return value */
424289848Sjkim            Value = &LocalValue;
425289848Sjkim        }
426289848Sjkim
427289848Sjkim        /* Clear the entire return buffer first, [Very Important!] */
428289848Sjkim
429289848Sjkim        *Value = 0;
430289848Sjkim    }
431289848Sjkim
432289848Sjkim    /*
433289848Sjkim     * The four types of fields are:
434289848Sjkim     *
435289848Sjkim     * BufferField - Read/write from/to a Buffer
436289848Sjkim     * RegionField - Read/write from/to a Operation Region.
437289848Sjkim     * BankField   - Write to a Bank Register, then read/write from/to an
438289848Sjkim     *               OperationRegion
439289848Sjkim     * IndexField  - Write to an Index Register, then read/write from/to a
440289848Sjkim     *               Data Register
441289848Sjkim     */
442289848Sjkim    switch (ObjDesc->Common.Type)
443289848Sjkim    {
444289848Sjkim    case ACPI_TYPE_BUFFER_FIELD:
445289848Sjkim        /*
446289848Sjkim         * If the BufferField arguments have not been previously evaluated,
447289848Sjkim         * evaluate them now and save the results.
448289848Sjkim         */
449289848Sjkim        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
450289848Sjkim        {
451289848Sjkim            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
452289848Sjkim            if (ACPI_FAILURE (Status))
453289848Sjkim            {
454289848Sjkim                return_ACPI_STATUS (Status);
455289848Sjkim            }
456289848Sjkim        }
457289848Sjkim
458289848Sjkim        if (ReadWrite == ACPI_READ)
459289848Sjkim        {
460306198Sjkim            /*
461289848Sjkim             * Copy the data from the source buffer.
462289848Sjkim             * Length is the field width in bytes.
463289848Sjkim             */
464289848Sjkim            ACPI_MEMCPY (Value,
465289848Sjkim                (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
466289848Sjkim                    ObjDesc->BufferField.BaseByteOffset +
467289848Sjkim                    FieldDatumByteOffset,
468289848Sjkim                ObjDesc->CommonField.AccessByteWidth);
469289848Sjkim        }
470289848Sjkim        else
471289848Sjkim        {
472289848Sjkim            /*
473289848Sjkim             * Copy the data to the target buffer.
474289848Sjkim             * Length is the field width in bytes.
475289848Sjkim             */
476289848Sjkim            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
477289848Sjkim                ObjDesc->BufferField.BaseByteOffset +
478289848Sjkim                FieldDatumByteOffset,
479289848Sjkim                Value, ObjDesc->CommonField.AccessByteWidth);
480289848Sjkim        }
481289848Sjkim
482289848Sjkim        Status = AE_OK;
483289848Sjkim        break;
484289848Sjkim
485289848Sjkim
486289848Sjkim    case ACPI_TYPE_LOCAL_BANK_FIELD:
487289848Sjkim
488289848Sjkim        /*
489289848Sjkim         * Ensure that the BankValue is not beyond the capacity of
490289848Sjkim         * the register
491289848Sjkim         */
492289848Sjkim        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
493289848Sjkim                (UINT64) ObjDesc->BankField.Value))
494289848Sjkim        {
495289848Sjkim            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
496289848Sjkim        }
497289848Sjkim
498289848Sjkim        /*
499289848Sjkim         * For BankFields, we must write the BankValue to the BankRegister
500289848Sjkim         * (itself a RegionField) before we can access the data.
501289848Sjkim         */
502289848Sjkim        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
503289848Sjkim                    &ObjDesc->BankField.Value,
504289848Sjkim                    sizeof (ObjDesc->BankField.Value));
505289848Sjkim        if (ACPI_FAILURE (Status))
506289848Sjkim        {
507289848Sjkim            return_ACPI_STATUS (Status);
508289848Sjkim        }
509289848Sjkim
510289848Sjkim        /*
511289848Sjkim         * Now that the Bank has been selected, fall through to the
512289848Sjkim         * RegionField case and write the datum to the Operation Region
513289848Sjkim         */
514289848Sjkim
515289848Sjkim        /*lint -fallthrough */
516289848Sjkim
517289848Sjkim
518289848Sjkim    case ACPI_TYPE_LOCAL_REGION_FIELD:
519289848Sjkim        /*
520289848Sjkim         * For simple RegionFields, we just directly access the owning
521289848Sjkim         * Operation Region.
522289848Sjkim         */
523289848Sjkim        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
524289848Sjkim                    ReadWrite);
525289848Sjkim        break;
526289848Sjkim
527289848Sjkim
528289848Sjkim    case ACPI_TYPE_LOCAL_INDEX_FIELD:
529289848Sjkim
530289848Sjkim
531289848Sjkim        /*
532289848Sjkim         * Ensure that the IndexValue is not beyond the capacity of
533289848Sjkim         * the register
534289848Sjkim         */
535289848Sjkim        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
536289848Sjkim                (UINT64) ObjDesc->IndexField.Value))
537289848Sjkim        {
538289848Sjkim            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
539289848Sjkim        }
540289848Sjkim
541289848Sjkim        /* Write the index value to the IndexRegister (itself a RegionField) */
542289848Sjkim
543289848Sjkim        FieldDatumByteOffset += ObjDesc->IndexField.Value;
544289848Sjkim
545289848Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
546289848Sjkim            "Write to Index Register: Value %8.8X\n",
547289848Sjkim            FieldDatumByteOffset));
548289848Sjkim
549289848Sjkim        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
550289848Sjkim                    &FieldDatumByteOffset,
551289848Sjkim                    sizeof (FieldDatumByteOffset));
552289848Sjkim        if (ACPI_FAILURE (Status))
553289848Sjkim        {
554289848Sjkim            return_ACPI_STATUS (Status);
555289848Sjkim        }
556289848Sjkim
557289848Sjkim        if (ReadWrite == ACPI_READ)
558289848Sjkim        {
559289848Sjkim            /* Read the datum from the DataRegister */
560289848Sjkim
561289848Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
562289848Sjkim                "Read from Data Register\n"));
563289848Sjkim
564289848Sjkim            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
565289848Sjkim                        Value, sizeof (UINT64));
566289848Sjkim        }
567289848Sjkim        else
568289848Sjkim        {
569289848Sjkim            /* Write the datum to the DataRegister */
570289848Sjkim
571289848Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
572289848Sjkim                "Write to Data Register: Value %8.8X%8.8X\n",
573289848Sjkim                ACPI_FORMAT_UINT64 (*Value)));
574289848Sjkim
575289848Sjkim            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
576289848Sjkim                        Value, sizeof (UINT64));
577289848Sjkim        }
578289848Sjkim        break;
579289848Sjkim
580289848Sjkim
581289848Sjkim    default:
582289848Sjkim
583289848Sjkim        ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
584289848Sjkim            ObjDesc->Common.Type));
585289848Sjkim        Status = AE_AML_INTERNAL;
586289848Sjkim        break;
587289848Sjkim    }
588289848Sjkim
589289848Sjkim    if (ACPI_SUCCESS (Status))
590289848Sjkim    {
591289848Sjkim        if (ReadWrite == ACPI_READ)
592289848Sjkim        {
593289848Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
594289848Sjkim                "Value Read %8.8X%8.8X, Width %u\n",
595289848Sjkim                ACPI_FORMAT_UINT64 (*Value),
596289848Sjkim                ObjDesc->CommonField.AccessByteWidth));
597289848Sjkim        }
598289848Sjkim        else
599289848Sjkim        {
600289848Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
601289848Sjkim                "Value Written %8.8X%8.8X, Width %u\n",
602289848Sjkim                ACPI_FORMAT_UINT64 (*Value),
603289848Sjkim                ObjDesc->CommonField.AccessByteWidth));
604289848Sjkim        }
605289848Sjkim    }
606289848Sjkim
607289848Sjkim    return_ACPI_STATUS (Status);
608289848Sjkim}
609289848Sjkim
610289848Sjkim
611289848Sjkim/*******************************************************************************
612289848Sjkim *
613289848Sjkim * FUNCTION:    AcpiExWriteWithUpdateRule
614289848Sjkim *
615289848Sjkim * PARAMETERS:  ObjDesc                 - Field to be written
616289848Sjkim *              Mask                    - bitmask within field datum
617289848Sjkim *              FieldValue              - Value to write
618 *              FieldDatumByteOffset    - Offset of datum within field
619 *
620 * RETURN:      Status
621 *
622 * DESCRIPTION: Apply the field update rule to a field write
623 *
624 ******************************************************************************/
625
626ACPI_STATUS
627AcpiExWriteWithUpdateRule (
628    ACPI_OPERAND_OBJECT     *ObjDesc,
629    UINT64                  Mask,
630    UINT64                  FieldValue,
631    UINT32                  FieldDatumByteOffset)
632{
633    ACPI_STATUS             Status = AE_OK;
634    UINT64                  MergedValue;
635    UINT64                  CurrentValue;
636
637
638    ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
639
640
641    /* Start with the new bits  */
642
643    MergedValue = FieldValue;
644
645    /* If the mask is all ones, we don't need to worry about the update rule */
646
647    if (Mask != ACPI_UINT64_MAX)
648    {
649        /* Decode the update rule */
650
651        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
652        {
653        case AML_FIELD_UPDATE_PRESERVE:
654            /*
655             * Check if update rule needs to be applied (not if mask is all
656             * ones)  The left shift drops the bits we want to ignore.
657             */
658            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
659                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
660            {
661                /*
662                 * Read the current contents of the byte/word/dword containing
663                 * the field, and merge with the new field value.
664                 */
665                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
666                            &CurrentValue, ACPI_READ);
667                if (ACPI_FAILURE (Status))
668                {
669                    return_ACPI_STATUS (Status);
670                }
671
672                MergedValue |= (CurrentValue & ~Mask);
673            }
674            break;
675
676        case AML_FIELD_UPDATE_WRITE_AS_ONES:
677
678            /* Set positions outside the field to all ones */
679
680            MergedValue |= ~Mask;
681            break;
682
683        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
684
685            /* Set positions outside the field to all zeros */
686
687            MergedValue &= Mask;
688            break;
689
690        default:
691
692            ACPI_ERROR ((AE_INFO,
693                "Unknown UpdateRule value: 0x%X",
694                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
695            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
696        }
697    }
698
699    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
700        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
701        ACPI_FORMAT_UINT64 (Mask),
702        FieldDatumByteOffset,
703        ObjDesc->CommonField.AccessByteWidth,
704        ACPI_FORMAT_UINT64 (FieldValue),
705        ACPI_FORMAT_UINT64 (MergedValue)));
706
707    /* Write the merged value */
708
709    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
710                &MergedValue, ACPI_WRITE);
711
712    return_ACPI_STATUS (Status);
713}
714
715
716/*******************************************************************************
717 *
718 * FUNCTION:    AcpiExExtractFromField
719 *
720 * PARAMETERS:  ObjDesc             - Field to be read
721 *              Buffer              - Where to store the field data
722 *              BufferLength        - Length of Buffer
723 *
724 * RETURN:      Status
725 *
726 * DESCRIPTION: Retrieve the current value of the given field
727 *
728 ******************************************************************************/
729
730ACPI_STATUS
731AcpiExExtractFromField (
732    ACPI_OPERAND_OBJECT     *ObjDesc,
733    void                    *Buffer,
734    UINT32                  BufferLength)
735{
736    ACPI_STATUS             Status;
737    UINT64                  RawDatum;
738    UINT64                  MergedDatum;
739    UINT32                  FieldOffset = 0;
740    UINT32                  BufferOffset = 0;
741    UINT32                  BufferTailBits;
742    UINT32                  DatumCount;
743    UINT32                  FieldDatumCount;
744    UINT32                  AccessBitWidth;
745    UINT32                  i;
746
747
748    ACPI_FUNCTION_TRACE (ExExtractFromField);
749
750
751    /* Validate target buffer and clear it */
752
753    if (BufferLength <
754        ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
755    {
756        ACPI_ERROR ((AE_INFO,
757            "Field size %u (bits) is too large for buffer (%u)",
758            ObjDesc->CommonField.BitLength, BufferLength));
759
760        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
761    }
762
763    ACPI_MEMSET (Buffer, 0, BufferLength);
764    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
765
766    /* Handle the simple case here */
767
768    if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
769        (ObjDesc->CommonField.BitLength == AccessBitWidth))
770    {
771        Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
772        return_ACPI_STATUS (Status);
773    }
774
775/* TBD: Move to common setup code */
776
777    /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
778
779    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
780    {
781        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
782        AccessBitWidth = sizeof (UINT64) * 8;
783    }
784
785    /* Compute the number of datums (access width data items) */
786
787    DatumCount = ACPI_ROUND_UP_TO (
788        ObjDesc->CommonField.BitLength, AccessBitWidth);
789
790    FieldDatumCount = ACPI_ROUND_UP_TO (
791        ObjDesc->CommonField.BitLength +
792        ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
793
794    /* Priming read from the field */
795
796    Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
797    if (ACPI_FAILURE (Status))
798    {
799        return_ACPI_STATUS (Status);
800    }
801    MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
802
803    /* Read the rest of the field */
804
805    for (i = 1; i < FieldDatumCount; i++)
806    {
807        /* Get next input datum from the field */
808
809        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
810        Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
811                    &RawDatum, ACPI_READ);
812        if (ACPI_FAILURE (Status))
813        {
814            return_ACPI_STATUS (Status);
815        }
816
817        /*
818         * Merge with previous datum if necessary.
819         *
820         * Note: Before the shift, check if the shift value will be larger than
821         * the integer size. If so, there is no need to perform the operation.
822         * This avoids the differences in behavior between different compilers
823         * concerning shift values larger than the target data width.
824         */
825        if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
826            ACPI_INTEGER_BIT_SIZE)
827        {
828            MergedDatum |= RawDatum <<
829                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
830        }
831
832        if (i == DatumCount)
833        {
834            break;
835        }
836
837        /* Write merged datum to target buffer */
838
839        ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
840            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
841                BufferLength - BufferOffset));
842
843        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
844        MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
845    }
846
847    /* Mask off any extra bits in the last datum */
848
849    BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
850    if (BufferTailBits)
851    {
852        MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
853    }
854
855    /* Write the last datum to the buffer */
856
857    ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
858        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
859            BufferLength - BufferOffset));
860
861    return_ACPI_STATUS (AE_OK);
862}
863
864
865/*******************************************************************************
866 *
867 * FUNCTION:    AcpiExInsertIntoField
868 *
869 * PARAMETERS:  ObjDesc             - Field to be written
870 *              Buffer              - Data to be written
871 *              BufferLength        - Length of Buffer
872 *
873 * RETURN:      Status
874 *
875 * DESCRIPTION: Store the Buffer contents into the given field
876 *
877 ******************************************************************************/
878
879ACPI_STATUS
880AcpiExInsertIntoField (
881    ACPI_OPERAND_OBJECT     *ObjDesc,
882    void                    *Buffer,
883    UINT32                  BufferLength)
884{
885    void                    *NewBuffer;
886    ACPI_STATUS             Status;
887    UINT64                  Mask;
888    UINT64                  WidthMask;
889    UINT64                  MergedDatum;
890    UINT64                  RawDatum = 0;
891    UINT32                  FieldOffset = 0;
892    UINT32                  BufferOffset = 0;
893    UINT32                  BufferTailBits;
894    UINT32                  DatumCount;
895    UINT32                  FieldDatumCount;
896    UINT32                  AccessBitWidth;
897    UINT32                  RequiredLength;
898    UINT32                  i;
899
900
901    ACPI_FUNCTION_TRACE (ExInsertIntoField);
902
903
904    /* Validate input buffer */
905
906    NewBuffer = NULL;
907    RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
908                        ObjDesc->CommonField.BitLength);
909    /*
910     * We must have a buffer that is at least as long as the field
911     * we are writing to.  This is because individual fields are
912     * indivisible and partial writes are not supported -- as per
913     * the ACPI specification.
914     */
915    if (BufferLength < RequiredLength)
916    {
917        /* We need to create a new buffer */
918
919        NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
920        if (!NewBuffer)
921        {
922            return_ACPI_STATUS (AE_NO_MEMORY);
923        }
924
925        /*
926         * Copy the original data to the new buffer, starting
927         * at Byte zero.  All unused (upper) bytes of the
928         * buffer will be 0.
929         */
930        ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
931        Buffer = NewBuffer;
932        BufferLength = RequiredLength;
933    }
934
935/* TBD: Move to common setup code */
936
937    /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
938    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
939    {
940        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
941    }
942
943    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
944
945    /*
946     * Create the bitmasks used for bit insertion.
947     * Note: This if/else is used to bypass compiler differences with the
948     * shift operator
949     */
950    if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
951    {
952        WidthMask = ACPI_UINT64_MAX;
953    }
954    else
955    {
956        WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
957    }
958
959    Mask = WidthMask &
960        ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
961
962    /* Compute the number of datums (access width data items) */
963
964    DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
965        AccessBitWidth);
966
967    FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
968        ObjDesc->CommonField.StartFieldBitOffset,
969        AccessBitWidth);
970
971    /* Get initial Datum from the input buffer */
972
973    ACPI_MEMCPY (&RawDatum, Buffer,
974        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
975            BufferLength - BufferOffset));
976
977    MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
978
979    /* Write the entire field */
980
981    for (i = 1; i < FieldDatumCount; i++)
982    {
983        /* Write merged datum to the target field */
984
985        MergedDatum &= Mask;
986        Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
987                    MergedDatum, FieldOffset);
988        if (ACPI_FAILURE (Status))
989        {
990            goto Exit;
991        }
992
993        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
994
995        /*
996         * Start new output datum by merging with previous input datum
997         * if necessary.
998         *
999         * Note: Before the shift, check if the shift value will be larger than
1000         * the integer size. If so, there is no need to perform the operation.
1001         * This avoids the differences in behavior between different compilers
1002         * concerning shift values larger than the target data width.
1003         */
1004        if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
1005            ACPI_INTEGER_BIT_SIZE)
1006        {
1007            MergedDatum = RawDatum >>
1008                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
1009        }
1010        else
1011        {
1012            MergedDatum = 0;
1013        }
1014
1015        Mask = WidthMask;
1016
1017        if (i == DatumCount)
1018        {
1019            break;
1020        }
1021
1022        /* Get the next input datum from the buffer */
1023
1024        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1025        ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1026            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1027                 BufferLength - BufferOffset));
1028
1029        MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1030    }
1031
1032    /* Mask off any extra bits in the last datum */
1033
1034    BufferTailBits = (ObjDesc->CommonField.BitLength +
1035        ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1036    if (BufferTailBits)
1037    {
1038        Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1039    }
1040
1041    /* Write the last datum to the field */
1042
1043    MergedDatum &= Mask;
1044    Status = AcpiExWriteWithUpdateRule (ObjDesc,
1045                Mask, MergedDatum, FieldOffset);
1046
1047Exit:
1048    /* Free temporary buffer if we used one */
1049
1050    if (NewBuffer)
1051    {
1052        ACPI_FREE (NewBuffer);
1053    }
1054    return_ACPI_STATUS (Status);
1055}
1056
1057
1058