OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [m68k/] [sun3/] [sun3dvma.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/arch/m68k/mm/sun3dvma.c
3
 *
4
 * Copyright (C) 2000 Sam Creasey
5
 *
6
 * Contains common routines for sun3/sun3x DVMA management.
7
 */
8
 
9
#include <linux/kernel.h>
10
#include <linux/mm.h>
11
#include <linux/list.h>
12
 
13
#include <asm/page.h>
14
#include <asm/pgtable.h>
15
#include <asm/dvma.h>
16
 
17
#undef DVMA_DEBUG
18
 
19
#ifdef CONFIG_SUN3X
20
extern void dvma_unmap_iommu(unsigned long baddr, int len);
21
#else
22
static inline void dvma_unmap_iommu(unsigned long a, int b)
23
{
24
}
25
#endif
26
 
27
#ifdef CONFIG_SUN3
28
extern void sun3_dvma_init(void);
29
#endif
30
 
31
unsigned long iommu_use[IOMMU_TOTAL_ENTRIES];
32
 
33
#define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT)
34
 
35
#define dvma_entry_use(baddr)           (iommu_use[dvma_index(baddr)])
36
 
37
struct hole {
38
        unsigned long start;
39
        unsigned long end;
40
        unsigned long size;
41
        struct list_head list;
42
};
43
 
44
static struct list_head hole_list;
45
static struct list_head hole_cache;
46
static struct hole initholes[64];
47
 
48
#ifdef DVMA_DEBUG
49
 
50
static unsigned long dvma_allocs = 0;
51
static unsigned long dvma_frees = 0;
52
static unsigned long long dvma_alloc_bytes = 0;
53
static unsigned long long dvma_free_bytes = 0;
54
 
55
static void print_use(void)
56
{
57
 
58
        int i;
59
        int j = 0;
60
 
61
        printk("dvma entry usage:\n");
62
 
63
        for(i = 0; i < IOMMU_TOTAL_ENTRIES; i++) {
64
                if(!iommu_use[i])
65
                        continue;
66
 
67
                j++;
68
 
69
                printk("dvma entry: %08lx len %08lx\n",
70
                       ( i << DVMA_PAGE_SHIFT) + DVMA_START,
71
                       iommu_use[i]);
72
        }
73
 
74
        printk("%d entries in use total\n", j);
75
 
76
        printk("allocation/free calls: %lu/%lu\n", dvma_allocs, dvma_frees);
77
        printk("allocation/free bytes: %Lx/%Lx\n", dvma_alloc_bytes,
78
               dvma_free_bytes);
79
}
80
 
81
static void print_holes(struct list_head *holes)
82
{
83
 
84
        struct list_head *cur;
85
        struct hole *hole;
86
 
87
        printk("listing dvma holes\n");
88
        list_for_each(cur, holes) {
89
                hole = list_entry(cur, struct hole, list);
90
 
91
                if((hole->start == 0) && (hole->end == 0) && (hole->size == 0))
92
                        continue;
93
 
94
                printk("hole: start %08lx end %08lx size %08lx\n", hole->start, hole->end, hole->size);
95
        }
96
 
97
        printk("end of hole listing...\n");
98
 
99
}
100
#endif /* DVMA_DEBUG */
101
 
102
static inline int refill(void)
103
{
104
 
105
        struct hole *hole;
106
        struct hole *prev = NULL;
107
        struct list_head *cur;
108
        int ret = 0;
109
 
110
        list_for_each(cur, &hole_list) {
111
                hole = list_entry(cur, struct hole, list);
112
 
113
                if(!prev) {
114
                        prev = hole;
115
                        continue;
116
                }
117
 
118
                if(hole->end == prev->start) {
119
                        hole->size += prev->size;
120
                        hole->end = prev->end;
121
                        list_del(&(prev->list));
122
                        list_add(&(prev->list), &hole_cache);
123
                        ret++;
124
                }
125
 
126
        }
127
 
128
        return ret;
129
}
130
 
131
static inline struct hole *rmcache(void)
132
{
133
        struct hole *ret;
134
 
135
        if(list_empty(&hole_cache)) {
136
                if(!refill()) {
137
                        printk("out of dvma hole cache!\n");
138
                        BUG();
139
                }
140
        }
141
 
142
        ret = list_entry(hole_cache.next, struct hole, list);
143
        list_del(&(ret->list));
144
 
145
        return ret;
146
 
147
}
148
 
149
static inline unsigned long get_baddr(int len, unsigned long align)
150
{
151
 
152
        struct list_head *cur;
153
        struct hole *hole;
154
 
155
        if(list_empty(&hole_list)) {
156
#ifdef DVMA_DEBUG
157
                printk("out of dvma holes! (printing hole cache)\n");
158
                print_holes(&hole_cache);
159
                print_use();
160
#endif
161
                BUG();
162
        }
163
 
164
        list_for_each(cur, &hole_list) {
165
                unsigned long newlen;
166
 
167
                hole = list_entry(cur, struct hole, list);
168
 
169
                if(align > DVMA_PAGE_SIZE)
170
                        newlen = len + ((hole->end - len) & (align-1));
171
                else
172
                        newlen = len;
173
 
174
                if(hole->size > newlen) {
175
                        hole->end -= newlen;
176
                        hole->size -= newlen;
177
                        dvma_entry_use(hole->end) = newlen;
178
#ifdef DVMA_DEBUG
179
                        dvma_allocs++;
180
                        dvma_alloc_bytes += newlen;
181
#endif
182
                        return hole->end;
183
                } else if(hole->size == newlen) {
184
                        list_del(&(hole->list));
185
                        list_add(&(hole->list), &hole_cache);
186
                        dvma_entry_use(hole->start) = newlen;
187
#ifdef DVMA_DEBUG
188
                        dvma_allocs++;
189
                        dvma_alloc_bytes += newlen;
190
#endif
191
                        return hole->start;
192
                }
193
 
194
        }
195
 
196
        printk("unable to find dvma hole!\n");
197
        BUG();
198
        return 0;
199
}
200
 
201
static inline int free_baddr(unsigned long baddr)
202
{
203
 
204
        unsigned long len;
205
        struct hole *hole;
206
        struct list_head *cur;
207
        unsigned long orig_baddr;
208
 
209
        orig_baddr = baddr;
210
        len = dvma_entry_use(baddr);
211
        dvma_entry_use(baddr) = 0;
212
        baddr &= DVMA_PAGE_MASK;
213
        dvma_unmap_iommu(baddr, len);
214
 
215
#ifdef DVMA_DEBUG
216
        dvma_frees++;
217
        dvma_free_bytes += len;
218
#endif
219
 
220
        list_for_each(cur, &hole_list) {
221
                hole = list_entry(cur, struct hole, list);
222
 
223
                if(hole->end == baddr) {
224
                        hole->end += len;
225
                        hole->size += len;
226
                        return 0;
227
                } else if(hole->start == (baddr + len)) {
228
                        hole->start = baddr;
229
                        hole->size += len;
230
                        return 0;
231
                }
232
 
233
        }
234
 
235
        hole = rmcache();
236
 
237
        hole->start = baddr;
238
        hole->end = baddr + len;
239
        hole->size = len;
240
 
241
//      list_add_tail(&(hole->list), cur);
242
        list_add(&(hole->list), cur);
243
 
244
        return 0;
245
 
246
}
247
 
248
void dvma_init(void)
249
{
250
 
251
        struct hole *hole;
252
        int i;
253
 
254
        INIT_LIST_HEAD(&hole_list);
255
        INIT_LIST_HEAD(&hole_cache);
256
 
257
        /* prepare the hole cache */
258
        for(i = 0; i < 64; i++)
259
                list_add(&(initholes[i].list), &hole_cache);
260
 
261
        hole = rmcache();
262
        hole->start = DVMA_START;
263
        hole->end = DVMA_END;
264
        hole->size = DVMA_SIZE;
265
 
266
        list_add(&(hole->list), &hole_list);
267
 
268
        memset(iommu_use, 0, sizeof(iommu_use));
269
 
270
        dvma_unmap_iommu(DVMA_START, DVMA_SIZE);
271
 
272
#ifdef CONFIG_SUN3
273
        sun3_dvma_init();
274
#endif
275
 
276
}
277
 
278
inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
279
{
280
 
281
        unsigned long baddr;
282
        unsigned long off;
283
 
284
        if(!len)
285
                len = 0x800;
286
 
287
        if(!kaddr || !len) {
288
//              printk("error: kaddr %lx len %x\n", kaddr, len);
289
//              *(int *)4 = 0;
290
                return 0;
291
        }
292
 
293
#ifdef DEBUG
294
        printk("dvma_map request %08lx bytes from %08lx\n",
295
               len, kaddr);
296
#endif
297
        off = kaddr & ~DVMA_PAGE_MASK;
298
        kaddr &= PAGE_MASK;
299
        len += off;
300
        len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
301
 
302
        if(align == 0)
303
                align = DVMA_PAGE_SIZE;
304
        else
305
                align = ((align + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
306
 
307
        baddr = get_baddr(len, align);
308
//      printk("using baddr %lx\n", baddr);
309
 
310
        if(!dvma_map_iommu(kaddr, baddr, len))
311
                return (baddr + off);
312
 
313
        printk("dvma_map failed kaddr %lx baddr %lx len %x\n", kaddr, baddr, len);
314
        BUG();
315
        return 0;
316
}
317
 
318
void dvma_unmap(void *baddr)
319
{
320
        unsigned long addr;
321
 
322
        addr = (unsigned long)baddr;
323
        /* check if this is a vme mapping */
324
        if(!(addr & 0x00f00000))
325
                addr |= 0xf00000;
326
 
327
        free_baddr(addr);
328
 
329
        return;
330
 
331
}
332
 
333
 
334
void *dvma_malloc_align(unsigned long len, unsigned long align)
335
{
336
        unsigned long kaddr;
337
        unsigned long baddr;
338
        unsigned long vaddr;
339
 
340
        if(!len)
341
                return NULL;
342
 
343
#ifdef DEBUG
344
        printk("dvma_malloc request %lx bytes\n", len);
345
#endif
346
        len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
347
 
348
        if((kaddr = __get_free_pages(GFP_ATOMIC, get_order(len))) == 0)
349
                return NULL;
350
 
351
        if((baddr = (unsigned long)dvma_map_align(kaddr, len, align)) == 0) {
352
                free_pages(kaddr, get_order(len));
353
                return NULL;
354
        }
355
 
356
        vaddr = dvma_btov(baddr);
357
 
358
        if(dvma_map_cpu(kaddr, vaddr, len) < 0) {
359
                dvma_unmap((void *)baddr);
360
                free_pages(kaddr, get_order(len));
361
                return NULL;
362
        }
363
 
364
#ifdef DEBUG
365
        printk("mapped %08lx bytes %08lx kern -> %08lx bus\n",
366
               len, kaddr, baddr);
367
#endif
368
 
369
        return (void *)vaddr;
370
 
371
}
372
 
373
void dvma_free(void *vaddr)
374
{
375
 
376
        return;
377
 
378
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.