baget.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:3k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * baget.c: Baget low level stuff
  3.  *
  4.  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  5.  *
  6.  */
  7. #include <stdarg.h>
  8. #include <linux/kernel.h>
  9. #include <linux/mm.h>
  10. #include <asm/system.h>
  11. #include <asm/bootinfo.h>
  12. #include <asm/mipsregs.h>
  13. #include <asm/pgtable.h>
  14. #include <asm/pgalloc.h>
  15. #include <asm/baget/baget.h>
  16. /*
  17.  *  Following code is based on routines from 'mm/vmalloc.c'
  18.  *  Additional parameters  ioaddr  is needed to iterate across real I/O address.
  19.  */
  20. static inline int alloc_area_pte(pte_t * pte, unsigned long address, 
  21.  unsigned long size, unsigned long ioaddr)
  22. {
  23.         unsigned long end;
  24.         address &= ~PMD_MASK;
  25.         end = address + size;
  26.         if (end > PMD_SIZE)
  27.                 end = PMD_SIZE;
  28.         while (address < end) {
  29.                 unsigned long page;
  30.                 if (!pte_none(*pte))
  31.                         printk("kseg2_alloc_io: page already existsn");
  32. /*
  33.  *  For MIPS looks pretty to have transparent mapping
  34.  *  for KSEG2 areas  -- user can't access one, and no 
  35.  *  problems with  virtual <--> physical  translation.
  36.  */
  37.                 page = ioaddr & PAGE_MASK;
  38.                 set_pte(pte, __pte(page | pgprot_val(PAGE_USERIO) |
  39.   _PAGE_GLOBAL | __READABLE | __WRITEABLE));
  40.                 address += PAGE_SIZE;
  41. ioaddr  += PAGE_SIZE;
  42.                 pte++;
  43.         }
  44.         return 0;
  45. }
  46. static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, 
  47.  unsigned long size, unsigned long ioaddr)
  48. {
  49.         unsigned long end;
  50.         address &= ~PGDIR_MASK;
  51.         end = address + size;
  52.         if (end > PGDIR_SIZE)
  53.                 end = PGDIR_SIZE;
  54.         while (address < end) {
  55.                 pte_t * pte = pte_alloc_kernel(pmd, address);
  56.                 if (!pte)
  57.                         return -ENOMEM;
  58.                 if (alloc_area_pte(pte, address, end - address, ioaddr))
  59.                         return -ENOMEM;
  60.                 address = (address + PMD_SIZE) & PMD_MASK;
  61. ioaddr  += PMD_SIZE;
  62.                 pmd++;
  63.         }
  64.         return 0;
  65. }
  66. int kseg2_alloc_io (unsigned long address, unsigned long size)
  67. {
  68.         pgd_t * dir;
  69.         unsigned long end = address + size;
  70.         dir = pgd_offset_k(address);
  71.         flush_cache_all();
  72.         while (address < end) {
  73.                 pmd_t *pmd;
  74.                 pgd_t olddir = *dir;
  75.                 pmd = pmd_alloc_kernel(dir, address);
  76.                 if (!pmd)
  77.                         return -ENOMEM;
  78.                 if (alloc_area_pmd(pmd, address, end - address, address))
  79.                         return -ENOMEM;
  80.                 if (pgd_val(olddir) != pgd_val(*dir))
  81.                         set_pgdir(address, *dir);
  82.                 address = (address + PGDIR_SIZE) & PGDIR_MASK;
  83.                 dir++;
  84.         }
  85.         flush_tlb_all();
  86.         return 0;
  87. }