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
24 * Linux memory management routines for Cimarron
25 * William Morrow (william.morrow@amd.com)
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/string.h>
31 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
38 #include "build_num.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;
82 module_param(cmdbufsize
, int, 0);
83 MODULE_PARM_DESC(cmdbufsize
, "Size of the GP command buffer (default=2MB)");
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
104 proc_cim_mem_read(char *page
, char **start
, off_t off
, int count
,
105 int *eof
, void *data
)
108 struct s_cim_mem
*lp
= cim_mem_head
;
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
);
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 */
138 if (!(ptr
->flags
& CIM_F_FREE
) || size
> ptr
->size
) {
139 ptr
= (policy
== CIM_ALLOC_BOTTOM
) ? ptr
->next
: ptr
->prev
;
143 if (ptr
->size
== size
) {
147 ret
= kmalloc(sizeof(struct s_cim_mem
), GFP_KERNEL
);
152 if (policy
== CIM_ALLOC_TOP
) {
153 ret
->offset
= ptr
->offset
+ (ptr
->size
- size
);
154 ret
->next
= ptr
->next
;
158 ptr
->next
->prev
= ret
;
165 else { /* CIM_ALLOC_BOTTOM */
166 ret
->offset
= ptr
->offset
;
168 ret
->prev
= ptr
->prev
;
170 ptr
->prev
->next
= ret
;
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;
197 static void cim_free(struct s_cim_mem
*block
) {
199 struct s_cim_mem
*ret
= block
;
200 struct s_cim_mem
*prev
, *next
;
204 /* Check to see if we can merge the previous block */
206 if (prev
&& prev
->flags
& CIM_F_FREE
) {
208 ret
->size
+= block
->size
;
209 ret
->next
= block
->next
;
211 if (block
->next
) block
->next
->prev
= ret
;
212 else cim_mem_tail
= ret
;
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
;
231 ret
->flags
= CIM_F_FREE
;
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
);
252 if( init_detect_cpu(&cpu_version
, &companion
) != CIM_STATUS_OK
)
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
);
311 cim_fget_memory(char *owner
, char *entity
, struct file
*file
, int size
, int flags
)
313 struct s_cim_mem
*lp
;
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
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
))
332 if (!(lp
= cim_alloc(owner
, entity
, file
, size
, policy
, flags
)))
340 cim_get_memory(char *owner
, char *entity
, int size
, int flags
)
342 return cim_fget_memory(owner
,entity
,0,size
,flags
);
346 cim_find_memory(cim_mem_find_t
*find
, int *size
) {
347 struct s_cim_mem
*lp
= 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;
367 *size
= lp
? lp
->size
: 0;
369 return lp
? lp
->offset
: 0;
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
)) {
386 cim_release_memory(struct file
*file
)
388 struct s_cim_mem
*lp
;
390 for( lp
=cim_mem_head
; lp
!=NULL
&& lp
->file
!=file
; lp
=lp
->next
);
391 if( lp
== NULL
) break;
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
);
405 for( ; lp
!=NULL
; lp
=np
) kfree((np
=lp
->next
, lp
));
407 cim_mem_head
= cim_mem_tail
= 0;
411 EXPORT_SYMBOL(cim_get_memory
);
412 EXPORT_SYMBOL(cim_free_memory
);
413 EXPORT_SYMBOL(cim_find_memory
);