kernel/acpi: Provide a local AcpiOsAllocateZeroed().
[dragonfly.git] / sys / dev / acpica / Osd / OsdMemory.c
1 /*-
2  * Copyright (c) 2000 Mitsaru Iwasaki
3  * Copyright (c) 2000 Michael Smith
4  * Copyright (c) 2000 BSDi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/acpica/Osd/OsdMemory.c,v 1.11 2004/04/14 03:39:08 njl Exp $
29  */
30
31 /*
32  * 6.2 : Memory Management
33  */
34
35 #include "acpi.h"
36
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41
42 MALLOC_DEFINE(M_ACPICA, "acpica", "ACPICA memory pool");
43
44 struct acpi_memtrack {
45     struct acpi_memtrack *next;
46     void *base;
47     ACPI_SIZE size;
48 #ifdef ACPI_DEBUG_MEMMAP
49     int freed;
50     struct {
51         const char *func;
52         int line;
53     } mapper, unmapper;
54 #endif
55 };
56
57 typedef struct acpi_memtrack *acpi_memtrack_t;
58
59 static acpi_memtrack_t acpi_mapbase;
60
61 void *
62 AcpiOsAllocate(ACPI_SIZE Size)
63 {
64     return (kmalloc(Size, M_ACPICA, M_INTWAIT));
65 }
66
67 void *
68 AcpiOsAllocateZeroed(ACPI_SIZE Size)
69 {
70     return (kmalloc(Size, M_ACPICA, M_INTWAIT | M_ZERO));
71 }
72
73 void
74 AcpiOsFree(void *Memory)
75 {
76     kfree(Memory, M_ACPICA);
77 }
78
79 #ifdef ACPI_DEBUG_MEMMAP
80 void *
81 _AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length,
82                  const char *caller, int line)
83 #else
84 void *
85 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
86 #endif
87 {
88     acpi_memtrack_t track;
89     void *map;
90
91     map = pmap_mapdev((vm_offset_t)Where, Length);
92     if (map == NULL)
93         return(NULL);
94     else {
95 #ifdef ACPI_DEBUG_MEMMAP
96         for (track = acpi_mapbase; track != NULL; track = track->next) {
97             if (track->base == map)
98                 break;
99         }
100 #else
101         track = NULL;
102 #endif
103         if (track == NULL) {
104             track = kmalloc(sizeof(*track), M_ACPICA, M_INTWAIT);
105             track->next = acpi_mapbase;
106             track->base = map;
107         }
108         track->size = Length;
109 #ifdef ACPI_DEBUG_MEMMAP
110         track->freed = 0;
111         track->mapper.func = caller;
112         track->mapper.line = line;
113         track->unmapper.func = "";
114         track->unmapper.line = 0;
115 #endif
116         acpi_mapbase = track;
117     }
118     return(map);
119 }
120
121 #ifdef ACPI_DEBUG_MEMMAP
122 void
123 _AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length,
124                    const char *caller, int line)
125 #else
126 void
127 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length)
128 #endif
129 {
130     struct acpi_memtrack **ptrack;
131     acpi_memtrack_t track;
132
133 again:
134     for (ptrack = &acpi_mapbase; (track = *ptrack); ptrack = &track->next) {
135 #ifdef ACPI_DEBUG_MEMMAP
136         if (track->freed)
137             continue;
138 #endif
139         /*
140          * Exact match, degenerate case
141          */
142         if (track->base == LogicalAddress && track->size == Length) {
143             *ptrack = track->next;
144             pmap_unmapdev((vm_offset_t)track->base, track->size);
145 #ifdef ACPI_DEBUG_MEMMAP
146             track->freed = 1;
147             track->unmapper.func = caller;
148             track->unmapper.line = line;
149 #else
150             kfree(track, M_ACPICA);
151 #endif
152             return;
153         }
154         /*
155          * Completely covered
156          */
157         if ((char *)LogicalAddress <= (char *)track->base &&
158             (char *)LogicalAddress + Length >= (char *)track->base + track->size
159         ) {
160             *ptrack = track->next;
161             pmap_unmapdev((vm_offset_t)track->base, track->size);
162             kprintf("AcpiOsUnmapMemory: Warning, deallocation request too"
163                    " large! %p/%08jx (actual was %p/%08jx)\n",
164                    LogicalAddress, (intmax_t)Length,
165                    track->base, (intmax_t)track->size);
166 #ifdef ACPI_DEBUG_MEMMAP
167             track->freed = 1;
168             track->unmapper.func = caller;
169             track->unmapper.line = line;
170 #else
171             kfree(track, M_ACPICA);
172 #endif
173             goto again;
174         }
175
176         /*
177          * Overlapping
178          */
179         if ((char *)LogicalAddress + Length >= (char *)track->base &&
180             (char *)LogicalAddress < (char *)track->base + track->size
181         ) {
182             kprintf("AcpiOsUnmapMemory: Warning, deallocation did not "
183                    "track allocation: %p/%08jx (actual was %p/%08jx)\n",
184                    LogicalAddress, (intmax_t)Length,
185                    track->base, (intmax_t)track->size);
186         }
187     }
188     kprintf("AcpiOsUnmapMemory: Warning, broken ACPI, bad unmap: %p/%08jx\n",
189             LogicalAddress, (intmax_t)Length);
190 #ifdef ACPI_DEBUG_MEMMAP
191     for (track = acpi_mapbase; track != NULL; track = track->next) {
192         if (track->freed && track->base == LogicalAddress) {
193             kprintf("%s: unmapping: %p/%08jx, mapped by %s:%d,"
194                    "last unmapped by %s:%d\n",
195                 __func__, LogicalAddress, (uintmax_t)Length,
196                 track->mapper.func, track->mapper.line,
197                 track->unmapper.func, track->unmapper.line
198             );
199         }
200     }
201 #endif
202 }
203
204 ACPI_STATUS
205 AcpiOsGetPhysicalAddress(void *LogicalAddress,
206     ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
207 {
208     /* We can't necessarily do this, so cop out. */
209     return (AE_BAD_ADDRESS);
210 }
211
212 /*
213  * There is no clean way to do this.  We make the charitable assumption
214  * that callers will not pass garbage to us.
215  */
216 BOOLEAN
217 AcpiOsReadable (void *Pointer, ACPI_SIZE Length)
218 {
219     return (TRUE);
220 }
221
222 BOOLEAN
223 AcpiOsWritable (void *Pointer, ACPI_SIZE Length)
224 {
225     return (TRUE);
226 }
227
228 ACPI_STATUS
229 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
230 {
231     void        *LogicalAddress;
232
233     LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
234     if (LogicalAddress == NULL)
235         return (AE_NOT_EXIST);
236
237     switch (Width) {
238     case 8:
239         *Value = *(volatile uint8_t *)LogicalAddress;
240         break;
241     case 16:
242         *Value = *(volatile uint16_t *)LogicalAddress;
243         break;
244     case 32:
245         *Value = *(volatile uint32_t *)LogicalAddress;
246         break;
247     case 64:
248         *Value = *(volatile uint64_t *)LogicalAddress;
249         break;
250     }
251
252     AcpiOsUnmapMemory(LogicalAddress, Width / 8);
253
254     return (AE_OK);
255 }
256
257 ACPI_STATUS
258 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
259 {
260     void        *LogicalAddress;
261
262     LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
263     if (LogicalAddress == NULL)
264         return (AE_NOT_EXIST);
265
266     switch (Width) {
267     case 8:
268         *(volatile uint8_t *)LogicalAddress = Value;
269         break;
270     case 16:
271         *(volatile uint16_t *)LogicalAddress = Value;
272         break;
273     case 32:
274         *(volatile uint32_t *)LogicalAddress = Value;
275         break;
276     case 64:
277         *(volatile uint64_t *)LogicalAddress = Value;
278         break;
279     }
280
281     AcpiOsUnmapMemory(LogicalAddress, Width / 8);
282
283     return (AE_OK);
284 }