source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/arch/i386/mm/ioremap-xen.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 10.9 KB
Line 
1/*
2 * arch/i386/mm/ioremap.c
3 *
4 * Re-map IO memory to kernel address space so that we can access it.
5 * This is needed for high PCI addresses that aren't mapped in the
6 * 640k-1MB IO memory area on PC's
7 *
8 * (C) Copyright 1995 1996 Linus Torvalds
9 */
10
11#include <linux/vmalloc.h>
12#include <linux/init.h>
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <asm/io.h>
16#include <asm/fixmap.h>
17#include <asm/cacheflush.h>
18#include <asm/tlbflush.h>
19#include <asm/pgtable.h>
20#include <asm/pgalloc.h>
21
22#define ISA_START_ADDRESS       0x0
23#define ISA_END_ADDRESS         0x100000
24
25static int direct_remap_area_pte_fn(pte_t *pte, 
26                                    struct page *pmd_page,
27                                    unsigned long address, 
28                                    void *data)
29{
30        mmu_update_t **v = (mmu_update_t **)data;
31
32        BUG_ON(!pte_none(*pte));
33
34        (*v)->ptr = ((u64)pfn_to_mfn(page_to_pfn(pmd_page)) <<
35                     PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
36        (*v)++;
37
38        return 0;
39}
40
41static int __direct_remap_pfn_range(struct mm_struct *mm,
42                                    unsigned long address, 
43                                    unsigned long mfn,
44                                    unsigned long size, 
45                                    pgprot_t prot,
46                                    domid_t  domid)
47{
48        int rc;
49        unsigned long i, start_address;
50        mmu_update_t *u, *v, *w;
51
52        u = v = w = (mmu_update_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
53        if (u == NULL)
54                return -ENOMEM;
55
56        start_address = address;
57
58        flush_cache_all();
59
60        for (i = 0; i < size; i += PAGE_SIZE) {
61                if ((v - u) == (PAGE_SIZE / sizeof(mmu_update_t))) {
62                        /* Flush a full batch after filling in the PTE ptrs. */
63                        rc = apply_to_page_range(mm, start_address, 
64                                                 address - start_address,
65                                                 direct_remap_area_pte_fn, &w);
66                        if (rc)
67                                goto out;
68                        rc = -EFAULT;
69                        if (HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0)
70                                goto out;
71                        v = w = u;
72                        start_address = address;
73                }
74
75                /*
76                 * Fill in the machine address: PTE ptr is done later by
77                 * __direct_remap_area_pages().
78                 */
79                v->val = pte_val_ma(pfn_pte_ma(mfn, prot));
80
81                mfn++;
82                address += PAGE_SIZE; 
83                v++;
84        }
85
86        if (v != u) {
87                /* Final batch. */
88                rc = apply_to_page_range(mm, start_address,
89                                         address - start_address,
90                                         direct_remap_area_pte_fn, &w);
91                if (rc)
92                        goto out;
93                rc = -EFAULT;
94                if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0))
95                        goto out;
96        }
97
98        rc = 0;
99
100 out:
101        flush_tlb_all();
102
103        free_page((unsigned long)u);
104
105        return rc;
106}
107
108int direct_remap_pfn_range(struct vm_area_struct *vma,
109                           unsigned long address, 
110                           unsigned long mfn,
111                           unsigned long size, 
112                           pgprot_t prot,
113                           domid_t  domid)
114{
115        if (xen_feature(XENFEAT_auto_translated_physmap))
116                return remap_pfn_range(vma, address, mfn, size, prot);
117
118        if (domid == DOMID_SELF)
119                return -EINVAL;
120
121        vma->vm_flags |= VM_IO | VM_RESERVED;
122
123        vma->vm_mm->context.has_foreign_mappings = 1;
124
125        return __direct_remap_pfn_range(
126                vma->vm_mm, address, mfn, size, prot, domid);
127}
128EXPORT_SYMBOL(direct_remap_pfn_range);
129
130int direct_kernel_remap_pfn_range(unsigned long address, 
131                                  unsigned long mfn,
132                                  unsigned long size, 
133                                  pgprot_t prot,
134                                  domid_t  domid)
135{
136        return __direct_remap_pfn_range(
137                &init_mm, address, mfn, size, prot, domid);
138}
139EXPORT_SYMBOL(direct_kernel_remap_pfn_range);
140
141static int lookup_pte_fn(
142        pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
143{
144        uint64_t *ptep = (uint64_t *)data;
145        if (ptep)
146                *ptep = ((uint64_t)pfn_to_mfn(page_to_pfn(pmd_page)) <<
147                         PAGE_SHIFT) | ((unsigned long)pte & ~PAGE_MASK);
148        return 0;
149}
150
151int create_lookup_pte_addr(struct mm_struct *mm, 
152                           unsigned long address,
153                           uint64_t *ptep)
154{
155        return apply_to_page_range(mm, address, PAGE_SIZE,
156                                   lookup_pte_fn, ptep);
157}
158
159EXPORT_SYMBOL(create_lookup_pte_addr);
160
161static int noop_fn(
162        pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
163{
164        return 0;
165}
166
167int touch_pte_range(struct mm_struct *mm,
168                    unsigned long address,
169                    unsigned long size)
170{
171        return apply_to_page_range(mm, address, size, noop_fn, NULL);
172} 
173
174EXPORT_SYMBOL(touch_pte_range);
175
176/*
177 * Does @address reside within a non-highmem page that is local to this virtual
178 * machine (i.e., not an I/O page, nor a memory page belonging to another VM).
179 * See the comment that accompanies mfn_to_local_pfn() in page.h to understand
180 * why this works.
181 */
182static inline int is_local_lowmem(unsigned long address)
183{
184        extern unsigned long max_low_pfn;
185        return (mfn_to_local_pfn(address >> PAGE_SHIFT) < max_low_pfn);
186}
187
188/*
189 * Generic mapping function (not visible outside):
190 */
191
192/*
193 * Remap an arbitrary physical address space into the kernel virtual
194 * address space. Needed when the kernel wants to access high addresses
195 * directly.
196 *
197 * NOTE! We need to allow non-page-aligned mappings too: we will obviously
198 * have to convert them into an offset in a page-aligned mapping, but the
199 * caller shouldn't need to know that small detail.
200 */
201void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
202{
203        void __iomem * addr;
204        struct vm_struct * area;
205        unsigned long offset, last_addr;
206        domid_t domid = DOMID_IO;
207
208        /* Don't allow wraparound or zero size */
209        last_addr = phys_addr + size - 1;
210        if (!size || last_addr < phys_addr)
211                return NULL;
212
213        /*
214         * Don't remap the low PCI/ISA area, it's always mapped..
215         */
216        if (is_initial_xendomain() &&
217            phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
218                return (void __iomem *) isa_bus_to_virt(phys_addr);
219
220        /*
221         * Don't allow anybody to remap normal RAM that we're using..
222         */
223        if (is_local_lowmem(phys_addr)) {
224                char *t_addr, *t_end;
225                struct page *page;
226
227                t_addr = bus_to_virt(phys_addr);
228                t_end = t_addr + (size - 1);
229           
230                for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
231                        if(!PageReserved(page))
232                                return NULL;
233
234                domid = DOMID_SELF;
235        }
236
237        /*
238         * Mappings have to be page-aligned
239         */
240        offset = phys_addr & ~PAGE_MASK;
241        phys_addr &= PAGE_MASK;
242        size = PAGE_ALIGN(last_addr+1) - phys_addr;
243
244        /*
245         * Ok, go for it..
246         */
247        area = get_vm_area(size, VM_IOREMAP | (flags << 20));
248        if (!area)
249                return NULL;
250        area->phys_addr = phys_addr;
251        addr = (void __iomem *) area->addr;
252        flags |= _KERNPG_TABLE;
253        if (__direct_remap_pfn_range(&init_mm, (unsigned long)addr,
254                                     phys_addr>>PAGE_SHIFT,
255                                     size, __pgprot(flags), domid)) {
256                vunmap((void __force *) addr);
257                return NULL;
258        }
259        return (void __iomem *) (offset + (char __iomem *)addr);
260}
261EXPORT_SYMBOL(__ioremap);
262
263/**
264 * ioremap_nocache     -   map bus memory into CPU space
265 * @offset:    bus address of the memory
266 * @size:      size of the resource to map
267 *
268 * ioremap_nocache performs a platform specific sequence of operations to
269 * make bus memory CPU accessible via the readb/readw/readl/writeb/
270 * writew/writel functions and the other mmio helpers. The returned
271 * address is not guaranteed to be usable directly as a virtual
272 * address.
273 *
274 * This version of ioremap ensures that the memory is marked uncachable
275 * on the CPU as well as honouring existing caching rules from things like
276 * the PCI bus. Note that there are other caches and buffers on many
277 * busses. In particular driver authors should read up on PCI writes
278 *
279 * It's useful if some control registers are in such an area and
280 * write combining or read caching is not desirable:
281 *
282 * Must be freed with iounmap.
283 */
284
285void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
286{
287        unsigned long last_addr;
288        void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
289        if (!p) 
290                return p; 
291
292        /* Guaranteed to be > phys_addr, as per __ioremap() */
293        last_addr = phys_addr + size - 1;
294
295        if (is_local_lowmem(last_addr)) { 
296                struct page *ppage = virt_to_page(bus_to_virt(phys_addr));
297                unsigned long npages;
298
299                phys_addr &= PAGE_MASK;
300
301                /* This might overflow and become zero.. */
302                last_addr = PAGE_ALIGN(last_addr);
303
304                /* .. but that's ok, because modulo-2**n arithmetic will make
305                * the page-aligned "last - first" come out right.
306                */
307                npages = (last_addr - phys_addr) >> PAGE_SHIFT;
308
309                if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) { 
310                        iounmap(p); 
311                        p = NULL;
312                }
313                global_flush_tlb();
314        }
315
316        return p;                                       
317}
318EXPORT_SYMBOL(ioremap_nocache);
319
320/**
321 * iounmap - Free a IO remapping
322 * @addr: virtual address from ioremap_*
323 *
324 * Caller must ensure there is only one unmapping for the same pointer.
325 */
326void iounmap(volatile void __iomem *addr)
327{
328        struct vm_struct *p, *o;
329
330        if ((void __force *)addr <= high_memory)
331                return;
332
333        /*
334         * __ioremap special-cases the PCI/ISA range by not instantiating a
335         * vm_area and by simply returning an address into the kernel mapping
336         * of ISA space.   So handle that here.
337         */
338        if ((unsigned long) addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
339                return;
340
341        addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long __force)addr);
342
343        /* Use the vm area unlocked, assuming the caller
344           ensures there isn't another iounmap for the same address
345           in parallel. Reuse of the virtual address is prevented by
346           leaving it in the global lists until we're done with it.
347           cpa takes care of the direct mappings. */
348        read_lock(&vmlist_lock);
349        for (p = vmlist; p; p = p->next) {
350                if (p->addr == addr)
351                        break;
352        }
353        read_unlock(&vmlist_lock);
354
355        if (!p) {
356                printk("iounmap: bad address %p\n", addr);
357                dump_stack();
358                return;
359        }
360
361        /* Reset the direct mapping. Can block */
362        if ((p->flags >> 20) && is_local_lowmem(p->phys_addr)) {
363                /* p->size includes the guard page, but cpa doesn't like that */
364                change_page_attr(virt_to_page(bus_to_virt(p->phys_addr)),
365                                 (p->size - PAGE_SIZE) >> PAGE_SHIFT,
366                                 PAGE_KERNEL);
367                global_flush_tlb();
368        } 
369
370        /* Finally remove it */
371        o = remove_vm_area((void *)addr);
372        BUG_ON(p != o || o == NULL);
373        kfree(p); 
374}
375EXPORT_SYMBOL(iounmap);
376
377void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
378{
379        unsigned long offset, last_addr;
380        unsigned int nrpages;
381        enum fixed_addresses idx;
382
383        /* Don't allow wraparound or zero size */
384        last_addr = phys_addr + size - 1;
385        if (!size || last_addr < phys_addr)
386                return NULL;
387
388        /*
389         * Don't remap the low PCI/ISA area, it's always mapped..
390         */
391        if (is_initial_xendomain() &&
392            phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS)
393                return isa_bus_to_virt(phys_addr);
394
395        /*
396         * Mappings have to be page-aligned
397         */
398        offset = phys_addr & ~PAGE_MASK;
399        phys_addr &= PAGE_MASK;
400        size = PAGE_ALIGN(last_addr) - phys_addr;
401
402        /*
403         * Mappings have to fit in the FIX_BTMAP area.
404         */
405        nrpages = size >> PAGE_SHIFT;
406        if (nrpages > NR_FIX_BTMAPS)
407                return NULL;
408
409        /*
410         * Ok, go for it..
411         */
412        idx = FIX_BTMAP_BEGIN;
413        while (nrpages > 0) {
414                set_fixmap(idx, phys_addr);
415                phys_addr += PAGE_SIZE;
416                --idx;
417                --nrpages;
418        }
419        return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN));
420}
421
422void __init bt_iounmap(void *addr, unsigned long size)
423{
424        unsigned long virt_addr;
425        unsigned long offset;
426        unsigned int nrpages;
427        enum fixed_addresses idx;
428
429        virt_addr = (unsigned long)addr;
430        if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN))
431                return;
432        if (virt_addr >= fix_to_virt(FIX_ISAMAP_BEGIN))
433                return;
434        offset = virt_addr & ~PAGE_MASK;
435        nrpages = PAGE_ALIGN(offset + size - 1) >> PAGE_SHIFT;
436
437        idx = FIX_BTMAP_BEGIN;
438        while (nrpages > 0) {
439                clear_fixmap(idx);
440                --idx;
441                --nrpages;
442        }
443}
Note: See TracBrowser for help on using the repository browser.