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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * arch/cris/mm/ioremap.c
3
 *
4
 * Re-map IO memory to kernel address space so that we can access it.
5
 * Needed for memory-mapped I/O devices mapped outside our normal DRAM
6
 * window (that is, all memory-mapped I/O devices).
7
 *
8
 * (C) Copyright 1995 1996 Linus Torvalds
9
 * CRIS-port by Axis Communications AB
10
 */
11
 
12
#include <linux/vmalloc.h>
13
#include <asm/io.h>
14
#include <asm/pgalloc.h>
15
 
16
extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
17
        unsigned long phys_addr, unsigned long flags)
18
{
19
        unsigned long end;
20
 
21
        address &= ~PMD_MASK;
22
        end = address + size;
23
        if (end > PMD_SIZE)
24
                end = PMD_SIZE;
25
        if (address >= end)
26
                BUG();
27
        do {
28
                if (!pte_none(*pte)) {
29
                        printk("remap_area_pte: page already exists\n");
30
                        BUG();
31
                }
32
                set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE |
33
                                                             __WRITEABLE | _PAGE_GLOBAL |
34
                                                             _PAGE_KERNEL | flags)));
35
                address += PAGE_SIZE;
36
                phys_addr += PAGE_SIZE;
37
                pte++;
38
        } while (address && (address < end));
39
}
40
 
41
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
42
        unsigned long phys_addr, unsigned long flags)
43
{
44
        unsigned long end;
45
 
46
        address &= ~PGDIR_MASK;
47
        end = address + size;
48
        if (end > PGDIR_SIZE)
49
                end = PGDIR_SIZE;
50
        phys_addr -= address;
51
        if (address >= end)
52
                BUG();
53
        do {
54
                pte_t * pte = pte_alloc(&init_mm, pmd, address);
55
                if (!pte)
56
                        return -ENOMEM;
57
                remap_area_pte(pte, address, end - address, address + phys_addr, flags);
58
                address = (address + PMD_SIZE) & PMD_MASK;
59
                pmd++;
60
        } while (address && (address < end));
61
        return 0;
62
}
63
 
64
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
65
                                 unsigned long size, unsigned long flags)
66
{
67
        int error;
68
        pgd_t * dir;
69
        unsigned long end = address + size;
70
 
71
        phys_addr -= address;
72
        dir = pgd_offset(&init_mm, address);
73
        flush_cache_all();
74
        if (address >= end)
75
                BUG();
76
        spin_lock(&init_mm.page_table_lock);
77
        do {
78
                pmd_t *pmd;
79
                pmd = pmd_alloc(&init_mm, dir, address);
80
                error = -ENOMEM;
81
                if (!pmd)
82
                        break;
83
                if (remap_area_pmd(pmd, address, end - address,
84
                                   phys_addr + address, flags))
85
                        break;
86
                error = 0;
87
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
88
                dir++;
89
        } while (address && (address < end));
90
        spin_unlock(&init_mm.page_table_lock);
91
        flush_tlb_all();
92
        return error;
93
}
94
 
95
/*
96
 * Generic mapping function (not visible outside):
97
 */
98
 
99
/*
100
 * Remap an arbitrary physical address space into the kernel virtual
101
 * address space. Needed when the kernel wants to access high addresses
102
 * directly.
103
 *
104
 * NOTE! We need to allow non-page-aligned mappings too: we will obviously
105
 * have to convert them into an offset in a page-aligned mapping, but the
106
 * caller shouldn't need to know that small detail.
107
 */
108
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
109
{
110
        void * addr;
111
        struct vm_struct * area;
112
        unsigned long offset, last_addr;
113
 
114
        /* Don't allow wraparound or zero size */
115
        last_addr = phys_addr + size - 1;
116
        if (!size || last_addr < phys_addr)
117
                return NULL;
118
 
119
#if 0
120
        /* TODO: Here we can put checks for driver-writer abuse...  */
121
 
122
        /*
123
         * Don't remap the low PCI/ISA area, it's always mapped..
124
         */
125
        if (phys_addr >= 0xA0000 && last_addr < 0x100000)
126
                return phys_to_virt(phys_addr);
127
 
128
        /*
129
         * Don't allow anybody to remap normal RAM that we're using..
130
         */
131
        if (phys_addr < virt_to_phys(high_memory)) {
132
                char *t_addr, *t_end;
133
                struct page *page;
134
 
135
                t_addr = __va(phys_addr);
136
                t_end = t_addr + (size - 1);
137
 
138
                for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
139
                        if(!PageReserved(page))
140
                                return NULL;
141
        }
142
#endif
143
 
144
        /*
145
         * Mappings have to be page-aligned
146
         */
147
        offset = phys_addr & ~PAGE_MASK;
148
        phys_addr &= PAGE_MASK;
149
        size = PAGE_ALIGN(last_addr+1) - phys_addr;
150
 
151
        /*
152
         * Ok, go for it..
153
         */
154
        area = get_vm_area(size, VM_IOREMAP);
155
        if (!area)
156
                return NULL;
157
        addr = area->addr;
158
        if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
159
                vfree(addr);
160
                return NULL;
161
        }
162
        return (void *) (offset + (char *)addr);
163
}
164
 
165
void iounmap(void *addr)
166
{
167
        if (addr > high_memory)
168
                return vfree((void *) (PAGE_MASK & (unsigned long) addr));
169
}

powered by: WebSVN 2.1.0

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