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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: generic.c,v 1.13 2001/07/17 16:17:33 anton Exp $
  2.  * generic.c: Generic Sparc mm routines that are not dependent upon
  3.  *            MMU type but are Sparc specific.
  4.  *
  5.  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  6.  */
  7. #include <linux/kernel.h>
  8. #include <linux/mm.h>
  9. #include <linux/swap.h>
  10. #include <linux/pagemap.h>
  11. #include <asm/pgalloc.h>
  12. #include <asm/pgtable.h>
  13. #include <asm/page.h>
  14. static inline void forget_pte(pte_t page)
  15. {
  16. if (pte_none(page))
  17. return;
  18. if (pte_present(page)) {
  19. struct page *ptpage = pte_page(page);
  20. if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
  21. return;
  22. page_cache_release(ptpage);
  23. return;
  24. }
  25. swap_free(pte_to_swp_entry(page));
  26. }
  27. /* Remap IO memory, the same way as remap_page_range(), but use
  28.  * the obio memory space.
  29.  *
  30.  * They use a pgprot that sets PAGE_IO and does not check the
  31.  * mem_map table as this is independent of normal memory.
  32.  */
  33. static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size,
  34. unsigned long offset, pgprot_t prot, int space)
  35. {
  36. unsigned long end;
  37. address &= ~PMD_MASK;
  38. end = address + size;
  39. if (end > PMD_SIZE)
  40. end = PMD_SIZE;
  41. do {
  42. pte_t oldpage = *pte;
  43. pte_clear(pte);
  44. set_pte(pte, mk_pte_io(offset, prot, space));
  45. forget_pte(oldpage);
  46. address += PAGE_SIZE;
  47. offset += PAGE_SIZE;
  48. pte++;
  49. } while (address < end);
  50. }
  51. static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
  52. unsigned long offset, pgprot_t prot, int space)
  53. {
  54. unsigned long end;
  55. address &= ~PGDIR_MASK;
  56. end = address + size;
  57. if (end > PGDIR_SIZE)
  58. end = PGDIR_SIZE;
  59. offset -= address;
  60. do {
  61. pte_t * pte = pte_alloc(current->mm, pmd, address);
  62. if (!pte)
  63. return -ENOMEM;
  64. io_remap_pte_range(pte, address, end - address, address + offset, prot, space);
  65. address = (address + PMD_SIZE) & PMD_MASK;
  66. pmd++;
  67. } while (address < end);
  68. return 0;
  69. }
  70. int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space)
  71. {
  72. int error = 0;
  73. pgd_t * dir;
  74. unsigned long beg = from;
  75. unsigned long end = from + size;
  76. struct mm_struct *mm = current->mm;
  77. prot = __pgprot(pg_iobits);
  78. offset -= from;
  79. dir = pgd_offset(mm, from);
  80. flush_cache_range(mm, beg, end);
  81. spin_lock(&mm->page_table_lock);
  82. while (from < end) {
  83. pmd_t *pmd = pmd_alloc(current->mm, dir, from);
  84. error = -ENOMEM;
  85. if (!pmd)
  86. break;
  87. error = io_remap_pmd_range(pmd, from, end - from, offset + from, prot, space);
  88. if (error)
  89. break;
  90. from = (from + PGDIR_SIZE) & PGDIR_MASK;
  91. dir++;
  92. }
  93. spin_unlock(&mm->page_table_lock);
  94. flush_tlb_range(current->mm, beg, end);
  95. return error;
  96. }