1 /*
2  *  lib.c - Architecture-Specific Low-Level ACPI Support
3  *
4  *  Copyright (C) 2015, Shannon Zhao <shannon.zhao@linaro.org>
5  *
6  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; If not, see <http://www.gnu.org/licenses/>.
20  *
21  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22  */
23 
24 #include <xen/acpi.h>
25 #include <xen/init.h>
26 #include <xen/mm.h>
27 
28 #include <asm/fixmap.h>
29 
30 static bool fixmap_inuse;
31 
__acpi_map_table(paddr_t phys,unsigned long size)32 char *__acpi_map_table(paddr_t phys, unsigned long size)
33 {
34     unsigned long base, offset;
35     mfn_t mfn;
36     unsigned int idx;
37 
38     /* No arch specific implementation after early boot */
39     if ( system_state >= SYS_STATE_boot )
40         return NULL;
41 
42     offset = phys & (PAGE_SIZE - 1);
43     base = FIXMAP_ADDR(FIX_ACPI_BEGIN) + offset;
44 
45     /* Check the fixmap is big enough to map the region */
46     if ( (FIXMAP_ADDR(FIX_ACPI_END) + PAGE_SIZE - base) < size )
47         return NULL;
48 
49     /* With the fixmap, we can only map one region at the time */
50     if ( fixmap_inuse )
51         return NULL;
52 
53     fixmap_inuse = true;
54 
55     size += offset;
56     mfn = maddr_to_mfn(phys);
57     idx = FIX_ACPI_BEGIN;
58 
59     do {
60         set_fixmap(idx, mfn, PAGE_HYPERVISOR);
61         size -= min(size, (unsigned long)PAGE_SIZE);
62         mfn = mfn_add(mfn, 1);
63         idx++;
64     } while ( size > 0 );
65 
66     return (char *)base;
67 }
68 
__acpi_unmap_table(const void * ptr,unsigned long size)69 bool __acpi_unmap_table(const void *ptr, unsigned long size)
70 {
71     vaddr_t vaddr = (vaddr_t)ptr;
72     unsigned int idx;
73 
74     /* We are only handling fixmap address in the arch code */
75     if ( (vaddr < FIXMAP_ADDR(FIX_ACPI_BEGIN)) ||
76          (vaddr >= (FIXMAP_ADDR(FIX_ACPI_END) + PAGE_SIZE)) )
77         return false;
78 
79     /*
80      * __acpi_map_table() will always return a pointer in the first page
81      * for the ACPI fixmap region. The caller is expected to free with
82      * the same address.
83      */
84     ASSERT((vaddr & PAGE_MASK) == FIXMAP_ADDR(FIX_ACPI_BEGIN));
85 
86     /* The region allocated fit in the ACPI fixmap region. */
87     ASSERT(size < (FIXMAP_ADDR(FIX_ACPI_END) + PAGE_SIZE - vaddr));
88     ASSERT(fixmap_inuse);
89 
90     fixmap_inuse = false;
91 
92     size += vaddr - FIXMAP_ADDR(FIX_ACPI_BEGIN);
93     idx = FIX_ACPI_BEGIN;
94 
95     do
96     {
97         clear_fixmap(idx);
98         size -= min(size, (unsigned long)PAGE_SIZE);
99         idx++;
100     } while ( size > 0 );
101 
102     return true;
103 }
104 
105 /* True to indicate PSCI 0.2+ is implemented */
acpi_psci_present(void)106 bool __init acpi_psci_present(void)
107 {
108     return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
109 }
110 
111 /* True to indicate HVC is present instead of SMC as the PSCI conduit */
acpi_psci_hvc_present(void)112 bool __init acpi_psci_hvc_present(void)
113 {
114     return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
115 }
116 
acpi_get_table_offset(struct membank tbl_add[],EFI_MEM_RES index)117 paddr_t __init acpi_get_table_offset(struct membank tbl_add[],
118                                      EFI_MEM_RES index)
119 {
120     int i;
121     paddr_t offset = 0;
122 
123     for ( i = 0; i < index; i++ )
124     {
125         /* Aligned with 64bit (8 bytes) */
126         offset += ROUNDUP(tbl_add[i].size, 8);
127     }
128 
129     return offset;
130 }
131