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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  arch/s390/mm/ioremap.c
3
 *
4
 *  S390 version
5
 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6
 *    Author(s): Hartmut Penner (hp@de.ibm.com)
7
 *
8
 *  Derived from "arch/i386/mm/extable.c"
9
 *    (C) Copyright 1995 1996 Linus Torvalds
10
 *
11
 * Re-map IO memory to kernel address space so that we can access it.
12
 * This is needed for high PCI addresses that aren't mapped in the
13
 * 640k-1MB IO memory area on PC's
14
 */
15
 
16
#include <linux/vmalloc.h>
17
#include <asm/io.h>
18
#include <asm/pgalloc.h>
19
 
20
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
21
        unsigned long phys_addr, unsigned long flags)
22
{
23
        unsigned long end;
24
 
25
        address &= ~PMD_MASK;
26
        end = address + size;
27
        if (end > PMD_SIZE)
28
                end = PMD_SIZE;
29
        if (address >= end)
30
                BUG();
31
        do {
32
                if (!pte_none(*pte)) {
33
                        printk("remap_area_pte: page already exists\n");
34
                        BUG();
35
                }
36
                set_pte(pte, mk_pte_phys(phys_addr,
37
                                         __pgprot(_PAGE_PRESENT | flags)));
38
                address += PAGE_SIZE;
39
                phys_addr += PAGE_SIZE;
40
                pte++;
41
        } while (address && (address < end));
42
}
43
 
44
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
45
        unsigned long phys_addr, unsigned long flags)
46
{
47
        unsigned long end;
48
 
49
        address &= ~PGDIR_MASK;
50
        end = address + size;
51
        if (end > PGDIR_SIZE)
52
                end = PGDIR_SIZE;
53
        phys_addr -= address;
54
        if (address >= end)
55
                BUG();
56
        do {
57
                pte_t * pte = pte_alloc(&init_mm, pmd, address);
58
                if (!pte)
59
                        return -ENOMEM;
60
                remap_area_pte(pte, address, end - address, address + phys_addr, flags);
61
                address = (address + PMD_SIZE) & PMD_MASK;
62
                pmd++;
63
        } while (address && (address < end));
64
        return 0;
65
}
66
 
67
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
68
                                 unsigned long size, unsigned long flags)
69
{
70
        int error;
71
        pgd_t * dir;
72
        unsigned long end = address + size;
73
 
74
        phys_addr -= address;
75
        dir = pgd_offset(&init_mm, address);
76
        flush_cache_all();
77
        if (address >= end)
78
                BUG();
79
        spin_lock(&init_mm.page_table_lock);
80
        do {
81
                pmd_t *pmd;
82
                pmd = pmd_alloc(&init_mm, dir, address);
83
                error = -ENOMEM;
84
                if (!pmd)
85
                        break;
86
                if (remap_area_pmd(pmd, address, end - address,
87
                                         phys_addr + address, flags))
88
                        break;
89
                error = 0;
90
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
91
                dir++;
92
        } while (address && (address < end));
93
        spin_unlock(&init_mm.page_table_lock);
94
        flush_tlb_all();
95
        return 0;
96
}
97
 
98
/*
99
 * Generic mapping function (not visible outside):
100
 */
101
 
102
/*
103
 * Remap an arbitrary physical address space into the kernel virtual
104
 * address space. Needed when the kernel wants to access high addresses
105
 * directly.
106
 */
107
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
108
{
109
        void * addr;
110
        struct vm_struct * area;
111
 
112
        if (phys_addr < virt_to_phys(high_memory))
113
                return phys_to_virt(phys_addr);
114
        if (phys_addr & ~PAGE_MASK)
115
                return NULL;
116
        size = PAGE_ALIGN(size);
117
        if (!size || size > phys_addr + size)
118
                return NULL;
119
        area = get_vm_area(size, VM_IOREMAP);
120
        if (!area)
121
                return NULL;
122
        addr = area->addr;
123
        if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
124
                vfree(addr);
125
                return NULL;
126
        }
127
        return addr;
128
}
129
 
130
void iounmap(void *addr)
131
{
132
        if (addr > high_memory)
133
                return vfree(addr);
134
}

powered by: WebSVN 2.1.0

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