]>
Commit | Line | Data |
---|---|---|
51533b61 MS |
1 | /* |
2 | * Simple allocator for internal RAM in ETRAX FS | |
3 | * | |
4 | * Copyright (c) 2004 Axis Communications AB. | |
5 | */ | |
6 | ||
7 | #include <linux/list.h> | |
8 | #include <linux/slab.h> | |
9 | #include <asm/io.h> | |
108ecfbc | 10 | #include <memmap.h> |
51533b61 MS |
11 | |
12 | #define STATUS_FREE 0 | |
13 | #define STATUS_ALLOCATED 1 | |
14 | ||
108ecfbc JN |
15 | #ifdef CONFIG_ETRAX_L2CACHE |
16 | #define RESERVED_SIZE 66*1024 | |
17 | #else | |
18 | #define RESERVED_SIZE 0 | |
19 | #endif | |
20 | ||
51533b61 MS |
21 | struct intmem_allocation { |
22 | struct list_head entry; | |
23 | unsigned int size; | |
24 | unsigned offset; | |
25 | char status; | |
26 | }; | |
27 | ||
28 | ||
29 | static struct list_head intmem_allocations; | |
30 | static void* intmem_virtual; | |
31 | ||
32 | static void crisv32_intmem_init(void) | |
33 | { | |
34 | static int initiated = 0; | |
35 | if (!initiated) { | |
36 | struct intmem_allocation* alloc = | |
37 | (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL); | |
38 | INIT_LIST_HEAD(&intmem_allocations); | |
108ecfbc JN |
39 | intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE, |
40 | MEM_INTMEM_SIZE - RESERVED_SIZE); | |
51533b61 | 41 | initiated = 1; |
108ecfbc | 42 | alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE; |
51533b61 MS |
43 | alloc->offset = 0; |
44 | alloc->status = STATUS_FREE; | |
45 | list_add_tail(&alloc->entry, &intmem_allocations); | |
46 | } | |
47 | } | |
48 | ||
49 | void* crisv32_intmem_alloc(unsigned size, unsigned align) | |
50 | { | |
51 | struct intmem_allocation* allocation; | |
52 | struct intmem_allocation* tmp; | |
53 | void* ret = NULL; | |
54 | ||
55 | preempt_disable(); | |
56 | crisv32_intmem_init(); | |
57 | ||
58 | list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { | |
59 | int alignment = allocation->offset % align; | |
60 | alignment = alignment ? align - alignment : alignment; | |
61 | ||
62 | if (allocation->status == STATUS_FREE && | |
63 | allocation->size >= size + alignment) { | |
64 | if (allocation->size > size + alignment) { | |
65 | struct intmem_allocation* alloc = | |
66 | (struct intmem_allocation*) | |
67 | kmalloc(sizeof *alloc, GFP_ATOMIC); | |
68 | alloc->status = STATUS_FREE; | |
108ecfbc JN |
69 | alloc->size = allocation->size - size - |
70 | alignment; | |
71 | alloc->offset = allocation->offset + size + | |
72 | alignment; | |
51533b61 MS |
73 | list_add(&alloc->entry, &allocation->entry); |
74 | ||
75 | if (alignment) { | |
108ecfbc JN |
76 | struct intmem_allocation *tmp; |
77 | tmp = (struct intmem_allocation *) | |
78 | kmalloc(sizeof *tmp, | |
79 | GFP_ATOMIC); | |
51533b61 MS |
80 | tmp->offset = allocation->offset; |
81 | tmp->size = alignment; | |
82 | tmp->status = STATUS_FREE; | |
83 | allocation->offset += alignment; | |
108ecfbc JN |
84 | list_add_tail(&tmp->entry, |
85 | &allocation->entry); | |
51533b61 MS |
86 | } |
87 | } | |
88 | allocation->status = STATUS_ALLOCATED; | |
89 | allocation->size = size; | |
90 | ret = (void*)((int)intmem_virtual + allocation->offset); | |
91 | } | |
92 | } | |
93 | preempt_enable(); | |
94 | return ret; | |
95 | } | |
96 | ||
97 | void crisv32_intmem_free(void* addr) | |
98 | { | |
99 | struct intmem_allocation* allocation; | |
100 | struct intmem_allocation* tmp; | |
101 | ||
102 | if (addr == NULL) | |
103 | return; | |
104 | ||
105 | preempt_disable(); | |
106 | crisv32_intmem_init(); | |
107 | ||
108 | list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { | |
109 | if (allocation->offset == (int)(addr - intmem_virtual)) { | |
108ecfbc | 110 | struct intmem_allocation *prev = |
51533b61 MS |
111 | list_entry(allocation->entry.prev, |
112 | struct intmem_allocation, entry); | |
108ecfbc | 113 | struct intmem_allocation *next = |
51533b61 MS |
114 | list_entry(allocation->entry.next, |
115 | struct intmem_allocation, entry); | |
116 | ||
117 | allocation->status = STATUS_FREE; | |
118 | /* Join with prev and/or next if also free */ | |
108ecfbc JN |
119 | if ((prev != &intmem_allocations) && |
120 | (prev->status == STATUS_FREE)) { | |
51533b61 MS |
121 | prev->size += allocation->size; |
122 | list_del(&allocation->entry); | |
123 | kfree(allocation); | |
124 | allocation = prev; | |
125 | } | |
108ecfbc JN |
126 | if ((next != &intmem_allocations) && |
127 | (next->status == STATUS_FREE)) { | |
51533b61 MS |
128 | allocation->size += next->size; |
129 | list_del(&next->entry); | |
130 | kfree(next); | |
131 | } | |
132 | preempt_enable(); | |
133 | return; | |
134 | } | |
135 | } | |
136 | preempt_enable(); | |
137 | } | |
138 | ||
139 | void* crisv32_intmem_phys_to_virt(unsigned long addr) | |
140 | { | |
108ecfbc JN |
141 | return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) + |
142 | (unsigned long)intmem_virtual); | |
51533b61 MS |
143 | } |
144 | ||
145 | unsigned long crisv32_intmem_virt_to_phys(void* addr) | |
146 | { | |
147 | return (unsigned long)((unsigned long )addr - | |
108ecfbc JN |
148 | (unsigned long)intmem_virtual + MEM_INTMEM_START + |
149 | RESERVED_SIZE); | |
51533b61 MS |
150 | } |
151 | ||
108ecfbc | 152 | module_init(crisv32_intmem_init); |
51533b61 | 153 |