xref: /freebsd/sys/contrib/dev/acpica/components/executer/exregion.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
1 /******************************************************************************
2  *
3  * Module Name: exregion - ACPI default OpRegion (address space) handlers
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2012, 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 
45 #define __EXREGION_C__
46 
47 #include <contrib/dev/acpica/include/acpi.h>
48 #include <contrib/dev/acpica/include/accommon.h>
49 #include <contrib/dev/acpica/include/acinterp.h>
50 
51 
52 #define _COMPONENT          ACPI_EXECUTER
53         ACPI_MODULE_NAME    ("exregion")
54 
55 
56 /*******************************************************************************
57  *
58  * FUNCTION:    AcpiExSystemMemorySpaceHandler
59  *
60  * PARAMETERS:  Function            - Read or Write operation
61  *              Address             - Where in the space to read or write
62  *              BitWidth            - Field width in bits (8, 16, or 32)
63  *              Value               - Pointer to in or out value
64  *              HandlerContext      - Pointer to Handler's context
65  *              RegionContext       - Pointer to context specific to the
66  *                                    accessed region
67  *
68  * RETURN:      Status
69  *
70  * DESCRIPTION: Handler for the System Memory address space (Op Region)
71  *
72  ******************************************************************************/
73 
74 ACPI_STATUS
75 AcpiExSystemMemorySpaceHandler (
76     UINT32                  Function,
77     ACPI_PHYSICAL_ADDRESS   Address,
78     UINT32                  BitWidth,
79     UINT64                  *Value,
80     void                    *HandlerContext,
81     void                    *RegionContext)
82 {
83     ACPI_STATUS             Status = AE_OK;
84     void                    *LogicalAddrPtr = NULL;
85     ACPI_MEM_SPACE_CONTEXT  *MemInfo = RegionContext;
86     UINT32                  Length;
87     ACPI_SIZE               MapLength;
88     ACPI_SIZE               PageBoundaryMapLength;
89 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
90     UINT32                  Remainder;
91 #endif
92 
93 
94     ACPI_FUNCTION_TRACE (ExSystemMemorySpaceHandler);
95 
96 
97     /* Validate and translate the bit width */
98 
99     switch (BitWidth)
100     {
101     case 8:
102         Length = 1;
103         break;
104 
105     case 16:
106         Length = 2;
107         break;
108 
109     case 32:
110         Length = 4;
111         break;
112 
113     case 64:
114         Length = 8;
115         break;
116 
117     default:
118         ACPI_ERROR ((AE_INFO, "Invalid SystemMemory width %u",
119             BitWidth));
120         return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
121     }
122 
123 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
124     /*
125      * Hardware does not support non-aligned data transfers, we must verify
126      * the request.
127      */
128     (void) AcpiUtShortDivide ((UINT64) Address, Length, NULL, &Remainder);
129     if (Remainder != 0)
130     {
131         return_ACPI_STATUS (AE_AML_ALIGNMENT);
132     }
133 #endif
134 
135     /*
136      * Does the request fit into the cached memory mapping?
137      * Is 1) Address below the current mapping? OR
138      *    2) Address beyond the current mapping?
139      */
140     if ((Address < MemInfo->MappedPhysicalAddress) ||
141         (((UINT64) Address + Length) >
142             ((UINT64)
143             MemInfo->MappedPhysicalAddress + MemInfo->MappedLength)))
144     {
145         /*
146          * The request cannot be resolved by the current memory mapping;
147          * Delete the existing mapping and create a new one.
148          */
149         if (MemInfo->MappedLength)
150         {
151             /* Valid mapping, delete it */
152 
153             AcpiOsUnmapMemory (MemInfo->MappedLogicalAddress,
154                 MemInfo->MappedLength);
155         }
156 
157         /*
158          * October 2009: Attempt to map from the requested address to the
159          * end of the region. However, we will never map more than one
160          * page, nor will we cross a page boundary.
161          */
162         MapLength = (ACPI_SIZE)
163             ((MemInfo->Address + MemInfo->Length) - Address);
164 
165         /*
166          * If mapping the entire remaining portion of the region will cross
167          * a page boundary, just map up to the page boundary, do not cross.
168          * On some systems, crossing a page boundary while mapping regions
169          * can cause warnings if the pages have different attributes
170          * due to resource management.
171          *
172          * This has the added benefit of constraining a single mapping to
173          * one page, which is similar to the original code that used a 4k
174          * maximum window.
175          */
176         PageBoundaryMapLength =
177             ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address;
178         if (PageBoundaryMapLength == 0)
179         {
180             PageBoundaryMapLength = ACPI_DEFAULT_PAGE_SIZE;
181         }
182 
183         if (MapLength > PageBoundaryMapLength)
184         {
185             MapLength = PageBoundaryMapLength;
186         }
187 
188         /* Create a new mapping starting at the address given */
189 
190         MemInfo->MappedLogicalAddress = AcpiOsMapMemory (
191             (ACPI_PHYSICAL_ADDRESS) Address, MapLength);
192         if (!MemInfo->MappedLogicalAddress)
193         {
194             ACPI_ERROR ((AE_INFO,
195                 "Could not map memory at 0x%8.8X%8.8X, size %u",
196                 ACPI_FORMAT_NATIVE_UINT (Address), (UINT32) MapLength));
197             MemInfo->MappedLength = 0;
198             return_ACPI_STATUS (AE_NO_MEMORY);
199         }
200 
201         /* Save the physical address and mapping size */
202 
203         MemInfo->MappedPhysicalAddress = Address;
204         MemInfo->MappedLength = MapLength;
205     }
206 
207     /*
208      * Generate a logical pointer corresponding to the address we want to
209      * access
210      */
211     LogicalAddrPtr = MemInfo->MappedLogicalAddress +
212         ((UINT64) Address - (UINT64) MemInfo->MappedPhysicalAddress);
213 
214     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
215         "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
216         BitWidth, Function, ACPI_FORMAT_NATIVE_UINT (Address)));
217 
218     /*
219      * Perform the memory read or write
220      *
221      * Note: For machines that do not support non-aligned transfers, the target
222      * address was checked for alignment above. We do not attempt to break the
223      * transfer up into smaller (byte-size) chunks because the AML specifically
224      * asked for a transfer width that the hardware may require.
225      */
226     switch (Function)
227     {
228     case ACPI_READ:
229 
230         *Value = 0;
231         switch (BitWidth)
232         {
233         case 8:
234             *Value = (UINT64) ACPI_GET8 (LogicalAddrPtr);
235             break;
236 
237         case 16:
238             *Value = (UINT64) ACPI_GET16 (LogicalAddrPtr);
239             break;
240 
241         case 32:
242             *Value = (UINT64) ACPI_GET32 (LogicalAddrPtr);
243             break;
244 
245         case 64:
246             *Value = (UINT64) ACPI_GET64 (LogicalAddrPtr);
247             break;
248 
249         default:
250             /* BitWidth was already validated */
251             break;
252         }
253         break;
254 
255     case ACPI_WRITE:
256 
257         switch (BitWidth)
258         {
259         case 8:
260             ACPI_SET8 (LogicalAddrPtr, *Value);
261             break;
262 
263         case 16:
264             ACPI_SET16 (LogicalAddrPtr, *Value);
265             break;
266 
267         case 32:
268             ACPI_SET32 (LogicalAddrPtr, *Value);
269             break;
270 
271         case 64:
272             ACPI_SET64 (LogicalAddrPtr, *Value);
273             break;
274 
275         default:
276             /* BitWidth was already validated */
277             break;
278         }
279         break;
280 
281     default:
282         Status = AE_BAD_PARAMETER;
283         break;
284     }
285 
286     return_ACPI_STATUS (Status);
287 }
288 
289 
290 /*******************************************************************************
291  *
292  * FUNCTION:    AcpiExSystemIoSpaceHandler
293  *
294  * PARAMETERS:  Function            - Read or Write operation
295  *              Address             - Where in the space to read or write
296  *              BitWidth            - Field width in bits (8, 16, or 32)
297  *              Value               - Pointer to in or out value
298  *              HandlerContext      - Pointer to Handler's context
299  *              RegionContext       - Pointer to context specific to the
300  *                                    accessed region
301  *
302  * RETURN:      Status
303  *
304  * DESCRIPTION: Handler for the System IO address space (Op Region)
305  *
306  ******************************************************************************/
307 
308 ACPI_STATUS
309 AcpiExSystemIoSpaceHandler (
310     UINT32                  Function,
311     ACPI_PHYSICAL_ADDRESS   Address,
312     UINT32                  BitWidth,
313     UINT64                  *Value,
314     void                    *HandlerContext,
315     void                    *RegionContext)
316 {
317     ACPI_STATUS             Status = AE_OK;
318     UINT32                  Value32;
319 
320 
321     ACPI_FUNCTION_TRACE (ExSystemIoSpaceHandler);
322 
323 
324     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
325         "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
326         BitWidth, Function, ACPI_FORMAT_NATIVE_UINT (Address)));
327 
328     /* Decode the function parameter */
329 
330     switch (Function)
331     {
332     case ACPI_READ:
333 
334         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) Address,
335                     &Value32, BitWidth);
336         *Value = Value32;
337         break;
338 
339     case ACPI_WRITE:
340 
341         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) Address,
342                     (UINT32) *Value, BitWidth);
343         break;
344 
345     default:
346         Status = AE_BAD_PARAMETER;
347         break;
348     }
349 
350     return_ACPI_STATUS (Status);
351 }
352 
353 
354 /*******************************************************************************
355  *
356  * FUNCTION:    AcpiExPciConfigSpaceHandler
357  *
358  * PARAMETERS:  Function            - Read or Write operation
359  *              Address             - Where in the space to read or write
360  *              BitWidth            - Field width in bits (8, 16, or 32)
361  *              Value               - Pointer to in or out value
362  *              HandlerContext      - Pointer to Handler's context
363  *              RegionContext       - Pointer to context specific to the
364  *                                    accessed region
365  *
366  * RETURN:      Status
367  *
368  * DESCRIPTION: Handler for the PCI Config address space (Op Region)
369  *
370  ******************************************************************************/
371 
372 ACPI_STATUS
373 AcpiExPciConfigSpaceHandler (
374     UINT32                  Function,
375     ACPI_PHYSICAL_ADDRESS   Address,
376     UINT32                  BitWidth,
377     UINT64                  *Value,
378     void                    *HandlerContext,
379     void                    *RegionContext)
380 {
381     ACPI_STATUS             Status = AE_OK;
382     ACPI_PCI_ID             *PciId;
383     UINT16                  PciRegister;
384 
385 
386     ACPI_FUNCTION_TRACE (ExPciConfigSpaceHandler);
387 
388 
389     /*
390      *  The arguments to AcpiOs(Read|Write)PciConfiguration are:
391      *
392      *  PciSegment  is the PCI bus segment range 0-31
393      *  PciBus      is the PCI bus number range 0-255
394      *  PciDevice   is the PCI device number range 0-31
395      *  PciFunction is the PCI device function number
396      *  PciRegister is the Config space register range 0-255 bytes
397      *
398      *  Value - input value for write, output address for read
399      *
400      */
401     PciId       = (ACPI_PCI_ID *) RegionContext;
402     PciRegister = (UINT16) (UINT32) Address;
403 
404     ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
405         "Pci-Config %u (%u) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
406         Function, BitWidth, PciId->Segment, PciId->Bus, PciId->Device,
407         PciId->Function, PciRegister));
408 
409     switch (Function)
410     {
411     case ACPI_READ:
412 
413         *Value = 0;
414         Status = AcpiOsReadPciConfiguration (PciId, PciRegister,
415                     Value, BitWidth);
416         break;
417 
418     case ACPI_WRITE:
419 
420         Status = AcpiOsWritePciConfiguration (PciId, PciRegister,
421                     *Value, BitWidth);
422         break;
423 
424     default:
425 
426         Status = AE_BAD_PARAMETER;
427         break;
428     }
429 
430     return_ACPI_STATUS (Status);
431 }
432 
433 
434 /*******************************************************************************
435  *
436  * FUNCTION:    AcpiExCmosSpaceHandler
437  *
438  * PARAMETERS:  Function            - Read or Write operation
439  *              Address             - Where in the space to read or write
440  *              BitWidth            - Field width in bits (8, 16, or 32)
441  *              Value               - Pointer to in or out value
442  *              HandlerContext      - Pointer to Handler's context
443  *              RegionContext       - Pointer to context specific to the
444  *                                    accessed region
445  *
446  * RETURN:      Status
447  *
448  * DESCRIPTION: Handler for the CMOS address space (Op Region)
449  *
450  ******************************************************************************/
451 
452 ACPI_STATUS
453 AcpiExCmosSpaceHandler (
454     UINT32                  Function,
455     ACPI_PHYSICAL_ADDRESS   Address,
456     UINT32                  BitWidth,
457     UINT64                  *Value,
458     void                    *HandlerContext,
459     void                    *RegionContext)
460 {
461     ACPI_STATUS             Status = AE_OK;
462 
463 
464     ACPI_FUNCTION_TRACE (ExCmosSpaceHandler);
465 
466 
467     return_ACPI_STATUS (Status);
468 }
469 
470 
471 /*******************************************************************************
472  *
473  * FUNCTION:    AcpiExPciBarSpaceHandler
474  *
475  * PARAMETERS:  Function            - Read or Write operation
476  *              Address             - Where in the space to read or write
477  *              BitWidth            - Field width in bits (8, 16, or 32)
478  *              Value               - Pointer to in or out value
479  *              HandlerContext      - Pointer to Handler's context
480  *              RegionContext       - Pointer to context specific to the
481  *                                    accessed region
482  *
483  * RETURN:      Status
484  *
485  * DESCRIPTION: Handler for the PCI BarTarget address space (Op Region)
486  *
487  ******************************************************************************/
488 
489 ACPI_STATUS
490 AcpiExPciBarSpaceHandler (
491     UINT32                  Function,
492     ACPI_PHYSICAL_ADDRESS   Address,
493     UINT32                  BitWidth,
494     UINT64                  *Value,
495     void                    *HandlerContext,
496     void                    *RegionContext)
497 {
498     ACPI_STATUS             Status = AE_OK;
499 
500 
501     ACPI_FUNCTION_TRACE (ExPciBarSpaceHandler);
502 
503 
504     return_ACPI_STATUS (Status);
505 }
506 
507 
508 /*******************************************************************************
509  *
510  * FUNCTION:    AcpiExDataTableSpaceHandler
511  *
512  * PARAMETERS:  Function            - Read or Write operation
513  *              Address             - Where in the space to read or write
514  *              BitWidth            - Field width in bits (8, 16, or 32)
515  *              Value               - Pointer to in or out value
516  *              HandlerContext      - Pointer to Handler's context
517  *              RegionContext       - Pointer to context specific to the
518  *                                    accessed region
519  *
520  * RETURN:      Status
521  *
522  * DESCRIPTION: Handler for the Data Table address space (Op Region)
523  *
524  ******************************************************************************/
525 
526 ACPI_STATUS
527 AcpiExDataTableSpaceHandler (
528     UINT32                  Function,
529     ACPI_PHYSICAL_ADDRESS   Address,
530     UINT32                  BitWidth,
531     UINT64                  *Value,
532     void                    *HandlerContext,
533     void                    *RegionContext)
534 {
535     ACPI_FUNCTION_TRACE (ExDataTableSpaceHandler);
536 
537 
538     /*
539      * Perform the memory read or write. The BitWidth was already
540      * validated.
541      */
542     switch (Function)
543     {
544     case ACPI_READ:
545 
546         ACPI_MEMCPY (ACPI_CAST_PTR (char, Value), ACPI_PHYSADDR_TO_PTR (Address),
547             ACPI_DIV_8 (BitWidth));
548         break;
549 
550     case ACPI_WRITE:
551 
552         ACPI_MEMCPY (ACPI_PHYSADDR_TO_PTR (Address), ACPI_CAST_PTR (char, Value),
553             ACPI_DIV_8 (BitWidth));
554         break;
555 
556     default:
557 
558         return_ACPI_STATUS (AE_BAD_PARAMETER);
559     }
560 
561     return_ACPI_STATUS (AE_OK);
562 }
563