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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [ppc/] [mm/] [pgtable.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * This file contains the routines setting up the linux page tables.
3
 *  -- paulus
4
 *
5
 *  Derived from arch/ppc/mm/init.c:
6
 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
7
 *
8
 *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
9
 *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
10
 *    Copyright (C) 1996 Paul Mackerras
11
 *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
12
 *
13
 *  Derived from "arch/i386/mm/init.c"
14
 *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
15
 *
16
 *  This program is free software; you can redistribute it and/or
17
 *  modify it under the terms of the GNU General Public License
18
 *  as published by the Free Software Foundation; either version
19
 *  2 of the License, or (at your option) any later version.
20
 *
21
 */
22
 
23
#include <linux/config.h>
24
#include <linux/kernel.h>
25
#include <linux/types.h>
26
#include <linux/vmalloc.h>
27
#include <linux/init.h>
28
 
29
#include <asm/pgtable.h>
30
#include <asm/pgalloc.h>
31
#include <asm/io.h>
32
#include <asm/machdep.h>
33
 
34
#include "mmu_decl.h"
35
 
36
unsigned long ioremap_base;
37
unsigned long ioremap_bot;
38
int io_bat_index;
39
 
40
/* The maximum lowmem defaults to 768Mb, but this can be configured to
41
 * another value.  On SMP, this value will be trimmed down to whatever
42
 * can be covered by BATs.
43
 */
44
#define MAX_LOW_MEM     CONFIG_LOWMEM_SIZE
45
 
46
#ifndef CONFIG_SMP
47
struct pgtable_cache_struct quicklists;
48
#endif
49
 
50
#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
51
#define HAVE_BATS       1
52
#endif
53
 
54
#ifdef HAVE_BATS
55
static unsigned long __bat2, __bat3;
56
#endif
57
 
58
extern char etext[], _stext[];
59
 
60
#ifdef HAVE_BATS
61
extern unsigned long v_mapped_by_bats(unsigned long va);
62
extern unsigned long p_mapped_by_bats(unsigned long pa);
63
void setbat(int index, unsigned long virt, unsigned long phys,
64
            unsigned int size, int flags);
65
 
66
#else /* !HAVE_BATS */
67
#define v_mapped_by_bats(x)     (0UL)
68
#define p_mapped_by_bats(x)     (0UL)
69
#endif /* HAVE_BATS */
70
 
71
#ifdef CONFIG_PTE_64BIT
72
void *
73
ioremap(phys_addr_t addr, unsigned long size)
74
{
75
        phys_addr_t addr64 = fixup_bigphys_addr(addr, size);;
76
 
77
        return ioremap64(addr64, size);
78
}
79
 
80
void *
81
ioremap64(unsigned long long addr, unsigned long size)
82
{
83
        return __ioremap(addr, size, _PAGE_NO_CACHE);
84
}
85
 
86
#else /* !CONFIG_PTE_64BIT */
87
 
88
void *
89
ioremap(phys_addr_t addr, unsigned long size)
90
{
91
        return __ioremap(addr, size, _PAGE_NO_CACHE);
92
}
93
#endif /* CONFIG_PTE_64BIT */
94
 
95
void *
96
__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
97
{
98
        unsigned long v, i;
99
        phys_addr_t p;
100
        int err;
101
 
102
        /*
103
         * Choose an address to map it to.
104
         * Once the vmalloc system is running, we use it.
105
         * Before then, we use space going down from ioremap_base
106
         * (ioremap_bot records where we're up to).
107
         */
108
        p = addr & PAGE_MASK;
109
        size = PAGE_ALIGN(addr + size) - p;
110
 
111
        /*
112
         * If the address lies within the first 16 MB, assume it's in ISA
113
         * memory space
114
         */
115
        if (p < 16*1024*1024)
116
                p += _ISA_MEM_BASE;
117
 
118
        /*
119
         * Don't allow anybody to remap normal RAM that we're using.
120
         * mem_init() sets high_memory so only do the check after that.
121
         */
122
        if ( mem_init_done && (p < virt_to_phys(high_memory)) )
123
        {
124
                printk("__ioremap(): phys addr "PTE_FMT" is RAM lr %p\n", p,
125
                       __builtin_return_address(0));
126
                return NULL;
127
        }
128
 
129
        if (size == 0)
130
                return NULL;
131
 
132
        /*
133
         * Is it already mapped?  Perhaps overlapped by a previous
134
         * BAT mapping.  If the whole area is mapped then we're done,
135
         * otherwise remap it since we want to keep the virt addrs for
136
         * each request contiguous.
137
         *
138
         * We make the assumption here that if the bottom and top
139
         * of the range we want are mapped then it's mapped to the
140
         * same virt address (and this is contiguous).
141
         *  -- Cort
142
         */
143
        if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
144
                goto out;
145
 
146
        if (mem_init_done) {
147
                struct vm_struct *area;
148
                area = get_vm_area(size, VM_IOREMAP);
149
                if (area == 0)
150
                        return NULL;
151
                v = VMALLOC_VMADDR(area->addr);
152
        } else {
153
                v = (ioremap_bot -= size);
154
        }
155
 
156
        if ((flags & _PAGE_PRESENT) == 0)
157
                flags |= _PAGE_KERNEL;
158
        if (flags & _PAGE_NO_CACHE)
159
                flags |= _PAGE_GUARDED;
160
 
161
        /*
162
         * Should check if it is a candidate for a BAT mapping
163
         */
164
 
165
        err = 0;
166
        for (i = 0; i < size && err == 0; i += PAGE_SIZE)
167
                err = map_page(v+i, p+i, flags);
168
        if (err) {
169
                if (mem_init_done)
170
                        vfree((void *)v);
171
                return NULL;
172
        }
173
 
174
out:
175
        return (void *) (v + ((unsigned long)addr & ~PAGE_MASK));
176
}
177
 
178
void iounmap(void *addr)
179
{
180
        /*
181
         * If mapped by BATs then there is nothing to do.
182
         * Calling vfree() generates a benign warning.
183
         */
184
        if (v_mapped_by_bats((unsigned long)addr)) return;
185
 
186
        if (addr > high_memory && (unsigned long) addr < ioremap_bot)
187
                vfree((void *) (PAGE_MASK & (unsigned long) addr));
188
}
189
 
190
int
191
map_page(unsigned long va, phys_addr_t pa, int flags)
192
{
193
        pmd_t *pd;
194
        pte_t *pg;
195
        int err = -ENOMEM;
196
 
197
        spin_lock(&init_mm.page_table_lock);
198
        /* Use upper 10 bits of VA to index the first level map */
199
        pd = pmd_offset(pgd_offset_k(va), va);
200
        /* Use middle 10 bits of VA to index the second-level map */
201
        pg = pte_alloc(&init_mm, pd, va);
202
        if (pg != 0) {
203
                err = 0;
204
                set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
205
                if (mem_init_done)
206
                        flush_HPTE(0, va, pg);
207
        }
208
        spin_unlock(&init_mm.page_table_lock);
209
        return err;
210
}
211
 
212
void __init
213
adjust_total_lowmem(void)
214
{
215
        unsigned long max_low_mem = MAX_LOW_MEM;
216
 
217
#ifdef HAVE_BATS
218
        unsigned long bat_max = 0x10000000;
219
        unsigned long align;
220
        unsigned long ram;
221
        int is601 = 0;
222
 
223
        /* 601s have smaller BATs */
224
        if (PVR_VER(mfspr(PVR)) == 1) {
225
                bat_max = 0x00800000;
226
                is601 = 1;
227
        }
228
 
229
        /* adjust BAT block size to max_low_mem */
230
        if (max_low_mem < bat_max)
231
                bat_max = max_low_mem;
232
 
233
        /* adjust lowmem size to max_low_mem */
234
        if (max_low_mem < total_lowmem)
235
                ram = max_low_mem;
236
        else
237
                ram = total_lowmem;
238
 
239
        /* Make sure we don't map a block larger than the
240
           smallest alignment of the physical address. */
241
        /* alignment of PPC_MEMSTART */
242
        align = ~(PPC_MEMSTART-1) & PPC_MEMSTART;
243
        /* set BAT block size to MIN(max_size, align) */
244
        if (align && align < bat_max)
245
                bat_max = align;
246
 
247
        /* Calculate BAT values */
248
        __bat2 = 1UL << __ilog2(ram);
249
        if (__bat2 > bat_max)
250
                __bat2 = bat_max;
251
        ram -= __bat2;
252
        if (ram) {
253
                __bat3 = 1UL << __ilog2(ram);
254
                if (__bat3 > bat_max)
255
                        __bat3 = bat_max;
256
                ram -= __bat3;
257
        }
258
 
259
        printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb,"
260
                        " residual: %ldMb\n", __bat2 >> 20, __bat3 >> 20,
261
                        (total_lowmem - (__bat2 + __bat3)) >> 20);
262
 
263
        /* On SMP, we limit the lowmem to the area mapped with BATs.
264
         * We also assume nobody will do SMP with 601s
265
         */
266
#ifdef CONFIG_SMP
267
        if (!is601)
268
                max_low_mem = __bat2 + __bat3;
269
#endif /* CONFIG_SMP */
270
 
271
#endif /* HAVE_BATS */
272
        if (total_lowmem > max_low_mem) {
273
                total_lowmem = max_low_mem;
274
#ifndef CONFIG_HIGHMEM
275
                printk(KERN_INFO "Warning, memory limited to %ld Mb, use "
276
                                "CONFIG_HIGHMEM to reach %ld Mb\n",
277
                                max_low_mem >> 20, total_memory >> 20);
278
                total_memory = total_lowmem;
279
#endif /* CONFIG_HIGHMEM */
280
        }
281
}
282
 
283
/*
284
 * Map in all of physical memory starting at KERNELBASE.
285
 */
286
void __init mapin_ram(void)
287
{
288
        unsigned long v, p, s, f;
289
 
290
#ifdef HAVE_BATS
291
        if (!__map_without_bats)
292
                bat_mapin_ram(__bat2, __bat3);
293
#endif /* HAVE_BATS */
294
 
295
        v = KERNELBASE;
296
        p = PPC_MEMSTART;
297
        for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
298
                /* On the MPC8xx, we want the page shared so we
299
                 * don't get ASID compares on kernel space.
300
                 */
301
                f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED | _PAGE_HWEXEC;
302
#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH)
303
                /* Allows stub to set breakpoints everywhere */
304
                f |= _PAGE_WRENABLE;
305
#else   /* !CONFIG_KGDB && !CONFIG_XMON && !CONFIG_BDI_SWITCH */
306
                if ((char *) v < _stext || (char *) v >= etext)
307
                        f |= _PAGE_WRENABLE;
308
#ifdef CONFIG_PPC_STD_MMU
309
                else
310
                        /* On the powerpc (not all), no user access
311
                           forces R/W kernel access */
312
                        f |= _PAGE_USER;
313
#endif /* CONFIG_PPC_STD_MMU */
314
#endif /* CONFIG_KGDB || CONFIG_XMON */
315
                map_page(v, p, f);
316
                v += PAGE_SIZE;
317
                p += PAGE_SIZE;
318
        }
319
        if (ppc_md.progress)
320
                ppc_md.progress("MMU:mapin_ram done", 0x401);
321
}
322
 
323
/* is x a power of 2? */
324
#define is_power_of_2(x)        ((x) != 0 && (((x) & ((x) - 1)) == 0))
325
 
326
/*
327
 * Set up a mapping for a block of I/O.
328
 * virt, phys, size must all be page-aligned.
329
 * This should only be called before ioremap is called.
330
 */
331
void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
332
                             unsigned int size, int flags)
333
{
334
        int i;
335
 
336
        if (virt > KERNELBASE && virt < ioremap_bot)
337
                ioremap_bot = ioremap_base = virt;
338
 
339
#ifdef HAVE_BATS
340
        /*
341
         * Use a BAT for this if possible...
342
         */
343
        if (io_bat_index < 2 && is_power_of_2(size)
344
            && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
345
                setbat(io_bat_index, virt, phys, size, flags);
346
                ++io_bat_index;
347
                return;
348
        }
349
#endif /* HAVE_BATS */
350
 
351
        /* No BATs available, put it in the page tables. */
352
        for (i = 0; i < size; i += PAGE_SIZE)
353
                map_page(virt + i, phys + i, flags);
354
}
355
 
356
/* Scan the real Linux page tables and return a PTE pointer for
357
 * a virtual address in a context.
358
 * Returns true (1) if PTE was found, zero otherwise.  The pointer to
359
 * the PTE pointer is unmodified if PTE is not found.
360
 */
361
int
362
get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
363
{
364
        pgd_t   *pgd;
365
        pmd_t   *pmd;
366
        pte_t   *pte;
367
        int     retval = 0;
368
 
369
        pgd = pgd_offset(mm, addr & PAGE_MASK);
370
        if (pgd) {
371
                pmd = pmd_offset(pgd, addr & PAGE_MASK);
372
                if (pmd_present(*pmd)) {
373
                        pte = pte_offset(pmd, addr & PAGE_MASK);
374
                        if (pte) {
375
                                retval = 1;
376
                                *ptep = pte;
377
                        }
378
                }
379
        }
380
        return(retval);
381
}
382
 
383
/* Find physical address for this virtual address.  Normally used by
384
 * I/O functions, but anyone can call it.
385
 */
386
unsigned long iopa(unsigned long addr)
387
{
388
        unsigned long pa;
389
 
390
        /* I don't know why this won't work on PMacs or CHRP.  It
391
         * appears there is some bug, or there is some implicit
392
         * mapping done not properly represented by BATs or in page
393
         * tables.......I am actively working on resolving this, but
394
         * can't hold up other stuff.  -- Dan
395
         */
396
        pte_t *pte;
397
        struct mm_struct *mm;
398
 
399
        /* Check the BATs */
400
        pa = v_mapped_by_bats(addr);
401
        if (pa)
402
                return pa;
403
 
404
        /* Allow mapping of user addresses (within the thread)
405
         * for DMA if necessary.
406
         */
407
        if (addr < TASK_SIZE)
408
                mm = current->mm;
409
        else
410
                mm = &init_mm;
411
 
412
        pa = 0;
413
        if (get_pteptr(mm, addr, &pte))
414
                pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
415
 
416
        return(pa);
417
}
418
 
419
/* This is will find the virtual address for a physical one....
420
 * Swiped from APUS, could be dangerous :-).
421
 * This is only a placeholder until I really find a way to make this
422
 * work.  -- Dan
423
 */
424
unsigned long
425
mm_ptov (unsigned long paddr)
426
{
427
        unsigned long ret;
428
#if 0
429
        if (paddr < 16*1024*1024)
430
                ret = ZTWO_VADDR(paddr);
431
        else {
432
                int i;
433
 
434
                for (i = 0; i < kmap_chunk_count;){
435
                        unsigned long phys = kmap_chunks[i++];
436
                        unsigned long size = kmap_chunks[i++];
437
                        unsigned long virt = kmap_chunks[i++];
438
                        if (paddr >= phys
439
                            && paddr < (phys + size)){
440
                                ret = virt + paddr - phys;
441
                                goto exit;
442
                        }
443
                }
444
 
445
                ret = (unsigned long) __va(paddr);
446
        }
447
exit:
448
#ifdef DEBUGPV
449
        printk ("PTOV(%lx)=%lx\n", paddr, ret);
450
#endif
451
#else
452
        ret = (unsigned long)paddr + KERNELBASE;
453
#endif
454
        return ret;
455
}
456
 

powered by: WebSVN 2.1.0

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