small_page.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/arm/mm/small_page.c
  3.  *
  4.  *  Copyright (C) 1996  Russell King
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License version 2 as
  8.  * published by the Free Software Foundation.
  9.  *
  10.  *  Changelog:
  11.  *   26/01/1996 RMK Cleaned up various areas to make little more generic
  12.  *   07/02/1999 RMK Support added for 16K and 32K page sizes
  13.  * containing 8K blocks
  14.  */
  15. #include <linux/signal.h>
  16. #include <linux/sched.h>
  17. #include <linux/kernel.h>
  18. #include <linux/errno.h>
  19. #include <linux/string.h>
  20. #include <linux/types.h>
  21. #include <linux/ptrace.h>
  22. #include <linux/mman.h>
  23. #include <linux/mm.h>
  24. #include <linux/swap.h>
  25. #include <linux/smp.h>
  26. #include <asm/bitops.h>
  27. #include <asm/pgtable.h>
  28. #define PEDANTIC
  29. /*
  30.  * Requirement:
  31.  *  We need to be able to allocate naturally aligned memory of finer
  32.  *  granularity than the page size.  This is typically used for the
  33.  *  second level page tables on 32-bit ARMs.
  34.  *
  35.  * Theory:
  36.  *  We "misuse" the Linux memory management system.  We use alloc_page
  37.  *  to allocate a page and then mark it as reserved.  The Linux memory
  38.  *  management system will then ignore the "offset", "next_hash" and
  39.  *  "pprev_hash" entries in the mem_map for this page.
  40.  *
  41.  *  We then use a bitstring in the "offset" field to mark which segments
  42.  *  of the page are in use, and manipulate this as required during the
  43.  *  allocation and freeing of these small pages.
  44.  *
  45.  *  We also maintain a queue of pages being used for this purpose using
  46.  *  the "next_hash" and "pprev_hash" entries of mem_map;
  47.  */
  48. struct order {
  49. struct page *queue;
  50. unsigned int mask; /* (1 << shift) - 1 */
  51. unsigned int shift; /* (1 << shift) size of page */
  52. unsigned int block_mask; /* nr_blocks - 1 */
  53. unsigned int all_used; /* (1 << nr_blocks) - 1 */
  54. };
  55. static struct order orders[] = {
  56. #if PAGE_SIZE == 4096
  57. { NULL, 2047, 11,  1, 0x00000003 }
  58. #elif PAGE_SIZE == 32768
  59. { NULL, 2047, 11, 15, 0x0000ffff },
  60. { NULL, 8191, 13,  3, 0x0000000f }
  61. #else
  62. #error unsupported page size
  63. #endif
  64. };
  65. #define USED_MAP(pg) ((pg)->index)
  66. #define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg)))
  67. #define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg)))
  68. static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED;
  69. static void add_page_to_queue(struct page *page, struct page **p)
  70. {
  71. #ifdef PEDANTIC
  72. if (page->pprev_hash)
  73. PAGE_BUG(page);
  74. #endif
  75. page->next_hash = *p;
  76. if (*p)
  77. (*p)->pprev_hash = &page->next_hash;
  78. *p = page;
  79. page->pprev_hash = p;
  80. }
  81. static void remove_page_from_queue(struct page *page)
  82. {
  83. if (page->pprev_hash) {
  84. if (page->next_hash)
  85. page->next_hash->pprev_hash = page->pprev_hash;
  86. *page->pprev_hash = page->next_hash;
  87. page->pprev_hash = NULL;
  88. }
  89. }
  90. static unsigned long __get_small_page(int priority, struct order *order)
  91. {
  92. unsigned long flags;
  93. struct page *page;
  94. int offset;
  95. if (!order->queue)
  96. goto need_new_page;
  97. spin_lock_irqsave(&small_page_lock, flags);
  98. page = order->queue;
  99. again:
  100. #ifdef PEDANTIC
  101. if (USED_MAP(page) & ~order->all_used)
  102. PAGE_BUG(page);
  103. #endif
  104. offset = ffz(USED_MAP(page));
  105. SET_USED(page, offset);
  106. if (USED_MAP(page) == order->all_used)
  107. remove_page_from_queue(page);
  108. spin_unlock_irqrestore(&small_page_lock, flags);
  109. return (unsigned long) page_address(page) + (offset << order->shift);
  110. need_new_page:
  111. page = alloc_page(priority);
  112. spin_lock_irqsave(&small_page_lock, flags);
  113. if (!order->queue) {
  114. if (!page)
  115. goto no_page;
  116. SetPageReserved(page);
  117. USED_MAP(page) = 0;
  118. cli();
  119. add_page_to_queue(page, &order->queue);
  120. } else {
  121. __free_page(page);
  122. cli();
  123. page = order->queue;
  124. }
  125. goto again;
  126. no_page:
  127. spin_unlock_irqrestore(&small_page_lock, flags);
  128. return 0;
  129. }
  130. static void __free_small_page(unsigned long spage, struct order *order)
  131. {
  132. unsigned long flags;
  133. struct page *page;
  134. page = virt_to_page(spage);
  135. if (VALID_PAGE(page)) {
  136. /*
  137.  * The container-page must be marked Reserved
  138.  */
  139. if (!PageReserved(page) || spage & order->mask)
  140. goto non_small;
  141. #ifdef PEDANTIC
  142. if (USED_MAP(page) & ~order->all_used)
  143. PAGE_BUG(page);
  144. #endif
  145. spage = spage >> order->shift;
  146. spage &= order->block_mask;
  147. /*
  148.  * the following must be atomic wrt get_page
  149.  */
  150. spin_lock_irqsave(&small_page_lock, flags);
  151. if (USED_MAP(page) == order->all_used)
  152. add_page_to_queue(page, &order->queue);
  153. if (!TEST_AND_CLEAR_USED(page, spage))
  154. goto already_free;
  155. if (USED_MAP(page) == 0)
  156. goto free_page;
  157. spin_unlock_irqrestore(&small_page_lock, flags);
  158. }
  159. return;
  160. free_page:
  161. /*
  162.  * unlink the page from the small page queue and free it
  163.  */
  164. remove_page_from_queue(page);
  165. spin_unlock_irqrestore(&small_page_lock, flags);
  166. ClearPageReserved(page);
  167. __free_page(page);
  168. return;
  169. non_small:
  170. printk("Trying to free non-small page from %pn", __builtin_return_address(0));
  171. return;
  172. already_free:
  173. printk("Trying to free free small page from %pn", __builtin_return_address(0));
  174. }
  175. unsigned long get_page_8k(int priority)
  176. {
  177. return __get_small_page(priority, orders+1);
  178. }
  179. void free_page_8k(unsigned long spage)
  180. {
  181. __free_small_page(spage, orders+1);
  182. }