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