Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / arch / mips / baget / baget.c
blobef03dca069546425405e5d27b62e8ffe4399a0a7
1 /* $Id: baget.c,v 1.1 1999/01/17 03:49:37 ralf Exp $
3 * baget.c: Baget low level stuff
5 * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
7 */
8 #include <stdarg.h>
10 #include <linux/kernel.h>
11 #include <linux/mm.h>
12 #include <asm/system.h>
13 #include <asm/bootinfo.h>
14 #include <asm/mipsregs.h>
15 #include <asm/pgtable.h>
16 #include <asm/pgalloc.h>
18 #include <asm/baget/baget.h>
21 * Following code is based on routines from 'mm/vmalloc.c'
22 * Additional parameters ioaddr is needed to iterate across real I/O address.
24 static inline int alloc_area_pte(pte_t * pte, unsigned long address,
25 unsigned long size, unsigned long ioaddr)
27 unsigned long end;
29 address &= ~PMD_MASK;
30 end = address + size;
31 if (end > PMD_SIZE)
32 end = PMD_SIZE;
33 while (address < end) {
34 unsigned long page;
35 if (!pte_none(*pte))
36 printk("kseg2_alloc_io: page already exists\n");
38 * For MIPS looks pretty to have transparent mapping
39 * for KSEG2 areas -- user can't access one, and no
40 * problems with virtual <--> physical translation.
42 page = ioaddr & PAGE_MASK;
44 set_pte(pte, __pte(page | pgprot_val(PAGE_USERIO) |
45 _PAGE_GLOBAL | __READABLE | __WRITEABLE));
46 address += PAGE_SIZE;
47 ioaddr += PAGE_SIZE;
48 pte++;
50 return 0;
53 static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address,
54 unsigned long size, unsigned long ioaddr)
56 unsigned long end;
58 address &= ~PGDIR_MASK;
59 end = address + size;
60 if (end > PGDIR_SIZE)
61 end = PGDIR_SIZE;
62 while (address < end) {
63 pte_t * pte = pte_alloc_kernel(pmd, address);
64 if (!pte)
65 return -ENOMEM;
66 if (alloc_area_pte(pte, address, end - address, ioaddr))
67 return -ENOMEM;
68 address = (address + PMD_SIZE) & PMD_MASK;
69 ioaddr += PMD_SIZE;
70 pmd++;
72 return 0;
75 int kseg2_alloc_io (unsigned long address, unsigned long size)
77 pgd_t * dir;
78 unsigned long end = address + size;
80 dir = pgd_offset_k(address);
81 flush_cache_all();
82 while (address < end) {
83 pmd_t *pmd;
84 pgd_t olddir = *dir;
86 pmd = pmd_alloc_kernel(dir, address);
87 if (!pmd)
88 return -ENOMEM;
89 if (alloc_area_pmd(pmd, address, end - address, address))
90 return -ENOMEM;
91 if (pgd_val(olddir) != pgd_val(*dir))
92 set_pgdir(address, *dir);
93 address = (address + PGDIR_SIZE) & PGDIR_MASK;
94 dir++;
96 flush_tlb_all();
97 return 0;