repo init
[linux-rt-nao.git] / lib / cimarron / cim_mem.c
blob722cb20d68c1747905662172ac10f012f32d985d
1 /* <LIC_AMD_STD>
2 * Copyright (c) 2003-2005 Advanced Micro Devices, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * The full GNU General Public License is included in this distribution in the
19 * file called COPYING
20 * </LIC_AMD_STD> */
21 /* <CTL_AMD_STD>
22 * </CTL_AMD_STD> */
23 /* <DOC_AMD_STD>
24 * Linux memory management routines for Cimarron
25 * William Morrow (william.morrow@amd.com)
26 * </DOC_AMD_STD> */
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/string.h>
31 #include <linux/slab.h>
32 #include <asm/io.h>
34 #ifdef CONFIG_PROC_FS
35 #include <linux/proc_fs.h>
36 #endif
38 #include "build_num.h"
40 #include "cim_mem.h"
41 #include "cim/cim_parm.h"
42 #include "cim/cim_rtns.h"
44 /* cimarron related data */
46 unsigned char *cim_get_gp_ptr(void) { return cim_gp_ptr; }
47 unsigned char *cim_get_fb_ptr(void) { return cim_fb_ptr; }
48 unsigned char *cim_get_vg_ptr(void) { return cim_vg_ptr; }
49 unsigned char *cim_get_vid_ptr(void) { return cim_vid_ptr; }
50 unsigned char *cim_get_vip_ptr(void) { return cim_vip_ptr; }
51 unsigned char *cim_get_cmd_base_ptr(void) { return cim_cmd_base_ptr; }
52 unsigned char *cim_get_cmd_ptr(void) { return cim_cmd_ptr; }
54 /* initalization parameters for above */
56 unsigned long cim_gp_base = 0;
57 unsigned long cim_fb_base = 0;
58 unsigned long cim_fb_size = 0;
59 unsigned long cim_vg_base = 0;
60 unsigned long cim_vid_base = 0;
61 unsigned long cim_vip_base = 0;
62 unsigned long cim_cmd_size = 0;
63 unsigned long cim_cmd_base = 0;
64 unsigned long cim_scr_size = 0;
65 unsigned long cim_fb_active = 0;
67 unsigned long cim_get_gp_base(void) { return cim_gp_base; }
68 unsigned long cim_get_fb_base(void) { return cim_fb_base; }
69 unsigned long cim_get_fb_size(void) { return cim_fb_size; }
70 unsigned long cim_get_vg_base(void) { return cim_vg_base; }
71 unsigned long cim_get_vid_base(void) { return cim_vid_base; }
72 unsigned long cim_get_vip_base(void) { return cim_vip_base; }
73 unsigned long cim_get_cmd_size(void) { return cim_cmd_size; }
74 unsigned long cim_get_cmd_base(void) { return cim_cmd_base; }
75 unsigned long cim_get_scr_size(void) { return cim_scr_size; }
76 unsigned long cim_get_fb_active(void) { return cim_fb_active; }
78 /* Size of the cmd buffer size - this is settable by the module param */
79 static int cmdbufsize = 0x200000;
81 #ifdef MODULE
82 module_param(cmdbufsize, int, 0);
83 MODULE_PARM_DESC(cmdbufsize, "Size of the GP command buffer (default=2MB)");
84 #endif
86 struct s_cim_mem {
87 struct s_cim_mem *next, *prev; /* Double linked list */
88 unsigned long offset; /* Offset of the block from the FB memory base */
89 unsigned long size; /* Size of the block in bytes */
90 unsigned long flags; /* Flags indicating ownership */
91 struct file *file; /* file owning volatile resource */
92 char name[15]; /* Block identifier */
93 char owner[10]; /* Owner of the block */
96 static struct s_cim_mem *cim_mem_head = 0;
97 static struct s_cim_mem *cim_mem_tail = 0;
99 static int cim_mem_init = 0; /* initialization done */
101 #ifdef CONFIG_PROC_FS
103 static int
104 proc_cim_mem_read(char *page, char **start, off_t off, int count,
105 int *eof, void *data)
107 int len = 0;
108 struct s_cim_mem *lp = cim_mem_head;
110 while(lp) {
111 len += sprintf(page + len, "%-10s %-15s ",
112 lp->flags & CIM_F_FREE ? "_free_" : lp->owner,
113 lp->flags & CIM_F_FREE ? "_free_" : lp->name);
115 len += sprintf(page + len, "0x%02lx 0x%08lx 0x%08lx\n",
116 lp->flags, lp->offset, lp->size);
118 lp = lp->next;
121 return len;
124 #endif
126 static struct s_cim_mem *
127 cim_alloc(const char *owner, const char *name, struct file *file,
128 unsigned long size, int policy, int flags) {
130 struct s_cim_mem *ptr =
131 (policy == CIM_ALLOC_BOTTOM) ? cim_mem_head : cim_mem_tail;
133 struct s_cim_mem *ret = 0;
135 /* Traverse the list looking for a free block */
136 while(ptr) {
138 if (!(ptr->flags & CIM_F_FREE) || size > ptr->size) {
139 ptr = (policy == CIM_ALLOC_BOTTOM) ? ptr->next : ptr->prev;
140 continue;
143 if (ptr->size == size) {
144 ret = ptr;
146 else {
147 ret = kmalloc(sizeof(struct s_cim_mem), GFP_KERNEL);
148 if (!ret) break;
150 ret->size = size;
152 if (policy == CIM_ALLOC_TOP) {
153 ret->offset = ptr->offset + (ptr->size - size);
154 ret->next = ptr->next;
155 ret->prev = ptr;
157 if (ptr->next)
158 ptr->next->prev = ret;
159 else
160 cim_mem_tail = ret;
162 ptr->size -= size;
163 ptr->next = ret;
165 else { /* CIM_ALLOC_BOTTOM */
166 ret->offset = ptr->offset;
167 ret->next = ptr;
168 ret->prev = ptr->prev;
169 if (ptr->prev)
170 ptr->prev->next = ret;
171 else
172 cim_mem_head = ret;
174 ptr->offset += size;
175 ptr->size -= size;
177 ptr->prev = ret;
181 break;
184 if (ret) {
185 ret->flags = flags;
186 strncpy(ret->name, name, sizeof(ret->name) - 1);
187 strncpy(ret->owner, owner, sizeof(ret->owner) - 1);
189 ret->name[sizeof(ret->name) - 1] = 0;
190 ret->owner[sizeof(ret->owner) - 1] = 0;
191 ret->file = file;
194 return ret;
197 static void cim_free(struct s_cim_mem *block) {
199 struct s_cim_mem *ret = block;
200 struct s_cim_mem *prev, *next;
202 prev = block->prev;
204 /* Check to see if we can merge the previous block */
206 if (prev && prev->flags & CIM_F_FREE) {
207 ret = prev;
208 ret->size += block->size;
209 ret->next = block->next;
211 if (block->next) block->next->prev = ret;
212 else cim_mem_tail = ret;
214 kfree(block);
217 next = ret->next;
219 /* Merge the next block in, if we can */
221 if (next && next->flags & CIM_F_FREE) {
222 ret->size += next->size;
223 ret->next = next->next;
225 if (next->next) next->next->prev = ret;
226 else cim_mem_tail = ret;
228 kfree(next);
231 ret->flags = CIM_F_FREE;
233 ret->name[0] = 0;
234 ret->owner[0] = 0;
235 ret->file = 0;
239 cim_init_memory(void)
241 unsigned long cpu_version = 0, companion = 0;
242 struct proc_dir_entry *procdir = 0;
243 INIT_BASE_ADDRESSES cim_base_addr;
245 if( cim_mem_init != 0 ) return 0; /* Already set up */
247 /* Allocate the inital free block */
248 cim_mem_head = cim_mem_tail = kmalloc(sizeof(struct s_cim_mem), GFP_KERNEL);
249 if (!cim_mem_head)
250 return -ENOMEM;
252 if( init_detect_cpu(&cpu_version, &companion) != CIM_STATUS_OK )
253 return -ENODEV;
255 init_read_base_addresses(&cim_base_addr);
257 /* publicize the init phys addresses used for virtual mappings */
258 cim_gp_base = cim_base_addr.gp_register_base;
259 cim_fb_base = cim_base_addr.framebuffer_base;
260 cim_fb_size = cim_base_addr.framebuffer_size;
261 cim_vg_base = cim_base_addr.vg_register_base;
262 cim_vid_base = cim_base_addr.df_register_base;
263 cim_vip_base = cim_base_addr.vip_register_base;
264 cim_cmd_size = cmdbufsize;
265 cim_scr_size = CIM_SCRATCH_SIZE;
266 cim_fb_active = cim_fb_size - cim_cmd_size - cim_scr_size;
268 /* initialize cimarron */
269 cim_gp_ptr = (unsigned char *)ioremap(cim_gp_base,0x4000);
270 cim_fb_ptr = (unsigned char *)ioremap(cim_fb_base,cim_fb_size);
271 cim_vg_ptr = (unsigned char *)ioremap(cim_vg_base,0x4000);
272 cim_vid_ptr = (unsigned char *)ioremap(cim_vid_base,0x4000);
273 cim_vip_ptr = (unsigned char *)ioremap(cim_vip_base,0x4000);
275 if( !cim_gp_ptr || !cim_fb_ptr || !cim_vg_ptr ||
276 !cim_vid_ptr || !cim_vip_ptr ) return -ENODEV;
278 gp_set_frame_buffer_base(cim_fb_base,cim_fb_size-cim_cmd_size);
279 cim_cmd_base_ptr = cim_fb_ptr + cim_fb_size - cim_cmd_size;
280 cim_cmd_base = cim_fb_base + cim_fb_size - cim_cmd_size;
281 gp_set_command_buffer_base(cim_cmd_base,0,cim_cmd_size);
283 /* Initalize the heap memory */
285 cim_mem_head->next = cim_mem_head->prev = NULL;
287 cim_mem_head->offset = cim_base_addr.framebuffer_base;
288 cim_mem_head->size = cim_base_addr.framebuffer_size;
289 cim_mem_head->name[0] = 0;
290 cim_mem_head->owner[0] = 0;
291 cim_mem_head->file = 0;
293 cim_mem_head->flags = CIM_F_FREE; /* Mark the whole block as free */
295 /* Now, allocate the space for the GP block */
296 cim_alloc("cimarron", "gp_cmd_buffer", 0, cim_cmd_size,
297 CIM_ALLOC_TOP, CIM_F_CMDBUF);
298 cim_alloc("cimarron", "gp_scr_buffer", 0, cim_scr_size,
299 CIM_ALLOC_TOP, CIM_F_PRIVATE);
301 #ifdef CONFIG_PROC_FS
302 procdir = proc_mkdir("driver/cimarron", 0);
303 create_proc_read_entry ("map", 0, procdir, proc_cim_mem_read, NULL);
304 #endif
306 cim_mem_init = 1;
307 return 0;
310 unsigned long
311 cim_fget_memory(char *owner, char *entity, struct file *file, int size, int flags)
313 struct s_cim_mem *lp;
314 int policy;
316 /* Policy is 0 if it should come from the top, or 1 if it should
317 come from the bottom of memory */
319 /* Public memory space should be allocated from the bottom, anything
320 else from the top */
322 policy = (flags & CIM_F_PUBLIC) ? CIM_ALLOC_BOTTOM : CIM_ALLOC_TOP;
324 if (size <= 0) return 0;
326 for(lp = cim_mem_head; lp; lp = lp->next) {
327 if (!strcmp(lp->owner, owner) && !strcmp(lp->name, entity))
328 break;
331 if (!lp) {
332 if (!(lp = cim_alloc(owner, entity, file, size, policy, flags)))
333 return 0;
336 return lp->offset;
339 unsigned long
340 cim_get_memory(char *owner, char *entity, int size, int flags)
342 return cim_fget_memory(owner,entity,0,size,flags);
345 unsigned long
346 cim_find_memory(cim_mem_find_t *find, int *size) {
347 struct s_cim_mem *lp = 0;
349 if (!find)
350 return *size=0;
352 for( lp = cim_mem_head; lp; lp = lp->next) {
354 if (find->match & CIM_MATCH_OWNER)
355 if (!lp->owner || strcmp(lp->owner, find->owner)) continue;
357 if (find->match & CIM_MATCH_NAME)
358 if (!lp->name || strcmp(lp->name, find->name)) continue;
360 if (find->match & CIM_MATCH_FLAGS)
361 if (!(lp->flags & find->flags)) continue;
363 break;
366 if (size)
367 *size = lp ? lp->size : 0;
369 return lp ? lp->offset : 0;
372 void
373 cim_free_memory(char *owner, unsigned long offset)
375 struct s_cim_mem *lp;
377 for(lp = cim_mem_head; lp; lp = lp->next) {
378 if (lp->offset == offset && !strcmp(lp->owner, owner)) {
379 cim_free(lp);
380 return;
385 void
386 cim_release_memory(struct file *file)
388 struct s_cim_mem *lp;
389 for(;;) {
390 for( lp=cim_mem_head; lp!=NULL && lp->file!=file; lp=lp->next );
391 if( lp == NULL ) break;
392 cim_free(lp);
396 void
397 cim_exit_memory(void)
399 struct s_cim_mem *lp = cim_mem_head, *np = 0;
401 #ifdef CONFIG_PROC_FS
402 remove_proc_entry ("driver/cimarron", NULL);
403 #endif
405 for( ; lp!=NULL; lp=np ) kfree((np=lp->next, lp));
407 cim_mem_head = cim_mem_tail = 0;
408 cim_mem_init = 0;
411 EXPORT_SYMBOL(cim_get_memory);
412 EXPORT_SYMBOL(cim_free_memory);
413 EXPORT_SYMBOL(cim_find_memory);