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