]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/dt3155/allocator.c
iwlwifi: don't include iwl-dev.h from iwl-devtrace.h
[net-next-2.6.git] / drivers / staging / dt3155 / allocator.c
CommitLineData
aa337ef1
SS
1/*
2 * allocator.c -- allocate after high_memory, if available
3 *
4 * NOTE: this is different from my previous allocator, the one that
5 * assembles pages, which revealed itself both slow and unreliable.
6 *
7 * Copyright (C) 1998 rubini@linux.it (Alessandro Rubini)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23
24-- Changes --
25
26 Date Programmer Description of changes made
27 -------------------------------------------------------------------
28 02-Aug-2002 NJC allocator now steps in 1MB increments, rather
1769fd86 29 than doubling its size each time.
dcff74ce 30 Also, allocator_init(u32 *) now returns
aa337ef1
SS
31 (in the first arg) the size of the free
32 space. This is no longer consistent with
33 using the allocator as a module, and some changes
34 may be necessary for that purpose. This was
35 designed to work with the DT3155 driver, in
36 stand alone mode only!!!
37 26-Oct-2009 SS Port to 2.6.30 kernel.
38 */
39
40
41#ifndef __KERNEL__
42# define __KERNEL__
43#endif
44#ifndef MODULE
45# define MODULE
46#endif
47
48#include <linux/version.h>
49
50#include <linux/sched.h>
51#include <linux/kernel.h>
52#include <linux/fs.h>
53#include <linux/proc_fs.h>
54#include <linux/errno.h>
55#include <linux/types.h>
56#include <linux/mm.h> /* PAGE_ALIGN() */
2141ec62 57#include <linux/io.h>
aa337ef1
SS
58
59#include <asm/page.h>
60
aa337ef1
SS
61/*#define ALL_DEBUG*/
62#define ALL_MSG "allocator: "
63
64#undef PDEBUG /* undef it, just in case */
65#ifdef ALL_DEBUG
66# define __static
67# define DUMP_LIST() dump_list()
68# ifdef __KERNEL__
69 /* This one if debugging is on, and kernel space */
1769fd86 70# define PDEBUG(fmt, args...) printk(KERN_DEBUG ALL_MSG fmt, ## args)
aa337ef1
SS
71# else
72 /* This one for user space */
73# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
74# endif
75#else
76# define PDEBUG(fmt, args...) /* not debugging: nothing */
77# define DUMP_LIST()
78# define __static static
79#endif
80
81#undef PDEBUGG
82#define PDEBUGG(fmt, args...)
83/*#define PDEBUGG(fmt, args...) printk( KERN_DEBUG ALL_MSG fmt, ## args)*/
84
85
86int allocator_himem = 1; /* 0 = probe, pos. = megs, neg. = disable */
87int allocator_step = 1; /* This is the step size in MB */
88int allocator_probe = 1; /* This is a flag -- 1=probe, 0=don't probe */
89
1769fd86
GKH
90static unsigned long allocator_buffer; /* physical address */
91static unsigned long allocator_buffer_size; /* kilobytes */
aa337ef1
SS
92
93/*
94 * The allocator keeps a list of DMA areas, so multiple devices
95 * can coexist. The list is kept sorted by address
96 */
97
98struct allocator_struct {
1769fd86
GKH
99 unsigned long address;
100 unsigned long size;
101 struct allocator_struct *next;
aa337ef1
SS
102};
103
1769fd86 104struct allocator_struct *allocator_list;
aa337ef1
SS
105
106
107#ifdef ALL_DEBUG
108static int dump_list(void)
109{
1769fd86 110 struct allocator_struct *ptr;
aa337ef1 111
1769fd86
GKH
112 PDEBUG("Current list:\n");
113 for (ptr = allocator_list; ptr; ptr = ptr->next)
114 PDEBUG("0x%08lx (size %likB)\n", ptr->address, ptr->size>>10);
115 return 0;
aa337ef1
SS
116}
117#endif
118
119/* ========================================================================
120 * This function is the actual allocator.
121 *
122 * If space is available in high memory (as detected at load time), that
123 * one is returned. The return value is a physical address (i.e., it can
124 * be used straight ahead for DMA, but needs remapping for program use).
125 */
126
1769fd86 127unsigned long allocator_allocate_dma(unsigned long kilobytes, int prio)
aa337ef1 128{
1769fd86
GKH
129 struct allocator_struct *ptr = allocator_list, *newptr;
130 unsigned long bytes = kilobytes << 10;
131
132 /* check if high memory is available */
133 if (!allocator_buffer)
134 return 0;
135
136 /* Round it to a multiple of the pagesize */
137 bytes = PAGE_ALIGN(bytes);
138 PDEBUG("request for %li bytes\n", bytes);
139
140 while (ptr && ptr->next) {
141 if (ptr->next->address - (ptr->address + ptr->size) >= bytes)
142 break; /* enough space */
143 ptr = ptr->next;
144 }
145 if (!ptr->next) {
146 DUMP_LIST();
147 PDEBUG("alloc failed\n");
148 return 0; /* end of list */
149 }
150 newptr = kmalloc(sizeof(struct allocator_struct), prio);
151 if (!newptr)
152 return 0;
153
154 /* ok, now stick it after ptr */
155 newptr->address = ptr->address + ptr->size;
156 newptr->size = bytes;
157 newptr->next = ptr->next;
158 ptr->next = newptr;
159
160 DUMP_LIST();
161 PDEBUG("returning 0x%08lx\n", newptr->address);
162 return newptr->address;
aa337ef1
SS
163}
164
1769fd86 165int allocator_free_dma(unsigned long address)
aa337ef1 166{
1769fd86 167 struct allocator_struct *ptr = allocator_list, *prev;
aa337ef1 168
1769fd86
GKH
169 while (ptr && ptr->next) {
170 if (ptr->next->address == address)
171 break;
172 ptr = ptr->next;
173 }
174 /* the one being freed is ptr->next */
175 prev = ptr; ptr = ptr->next;
176
177 if (!ptr) {
178 printk(KERN_ERR ALL_MSG
179 "free_dma(0x%08lx) but add. not allocated\n",
180 ptr->address);
181 return -EINVAL;
aa337ef1 182 }
1769fd86
GKH
183 PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,
184 ptr->next->address);
185 prev->next = ptr->next;
186 kfree(ptr);
187
188 /* dump_list(); */
189 return 0;
aa337ef1
SS
190}
191
192/* ========================================================================
193 * Init and cleanup
194 *
195 * On cleanup everything is released. If the list is not empty, that a
196 * problem of our clients
197 */
3a8954e8 198int allocator_init(u32 *allocator_max)
aa337ef1 199{
1769fd86
GKH
200 /* check how much free memory is there */
201 void *remapped;
202 unsigned long max;
203 unsigned long trial_size = allocator_himem<<20;
204 unsigned long last_trial = 0;
205 unsigned long step = allocator_step<<20;
206 unsigned long i = 0;
207 struct allocator_struct *head, *tail;
208 char test_string[] = "0123456789abcde"; /* 16 bytes */
209
210 PDEBUGG("himem = %i\n", allocator_himem);
211 if (allocator_himem < 0) /* don't even try */
212 return -EINVAL;
213
214 if (!trial_size)
215 trial_size = 1<<20; /* not specified: try one meg */
216
217 while (1) {
218 remapped = ioremap(__pa(high_memory), trial_size);
219 if (!remapped) {
220 PDEBUGG("%li megs failed!\n", trial_size>>20);
221 break;
222 }
223 PDEBUGG("Trying %li megs (at %p, %p)\n", trial_size>>20,
224 (void *)__pa(high_memory), remapped);
225 for (i = last_trial; i < trial_size; i += 16) {
226 strcpy((char *)(remapped)+i, test_string);
227 if (strcmp((char *)(remapped)+i, test_string))
228 break;
229 }
230 iounmap((void *)remapped);
231 schedule();
232 last_trial = trial_size;
233 if (i == trial_size)
234 trial_size += step; /* increment, if all went well */
235 else {
236 PDEBUGG("%li megs copy test failed!\n", trial_size>>20);
237 break;
238 }
239 if (!allocator_probe)
240 break;
241 }
242 PDEBUG("%li megs (%li k, %li b)\n", i>>20, i>>10, i);
243 allocator_buffer_size = i>>10; /* kilobytes */
244 allocator_buffer = __pa(high_memory);
245 if (!allocator_buffer_size) {
246 printk(KERN_WARNING ALL_MSG "no free high memory to use\n");
247 return -ENOMEM;
248 }
249
250 /*
251 * to simplify things, always have two cells in the list:
252 * the first and the last. This avoids some conditionals and
253 * extra code when allocating and deallocating: we only play
254 * in the middle of the list
255 */
256 head = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
257 if (!head)
258 return -ENOMEM;
259 tail = kmalloc(sizeof(struct allocator_struct), GFP_KERNEL);
260 if (!tail) {
261 kfree(head);
262 return -ENOMEM;
263 }
264
265 max = allocator_buffer_size<<10;
266
267 head->size = tail->size = 0;
268 head->address = allocator_buffer;
269 tail->address = allocator_buffer + max;
270 head->next = tail;
271 tail->next = NULL;
272 allocator_list = head;
273
274 /* Back to the user code, in KB */
275 *allocator_max = allocator_buffer_size;
276
277 return 0; /* ok, ready */
aa337ef1
SS
278}
279
280void allocator_cleanup(void)
281{
1769fd86 282 struct allocator_struct *ptr, *next;
aa337ef1 283
1769fd86
GKH
284 for (ptr = allocator_list; ptr; ptr = next) {
285 next = ptr->next;
286 PDEBUG("freeing list: 0x%08lx\n", ptr->address);
287 kfree(ptr);
288 }
aa337ef1 289
1769fd86
GKH
290 allocator_buffer = 0;
291 allocator_buffer_size = 0;
292 allocator_list = NULL;
aa337ef1
SS
293}
294
295