summaryrefslogtreecommitdiff
path: root/arch/arm26/mm/small_page.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm26/mm/small_page.c')
-rw-r--r--arch/arm26/mm/small_page.c192
1 files changed, 0 insertions, 192 deletions
diff --git a/arch/arm26/mm/small_page.c b/arch/arm26/mm/small_page.c
deleted file mode 100644
index 30447106c25f..000000000000
--- a/arch/arm26/mm/small_page.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * linux/arch/arm26/mm/small_page.c
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 2003 Ian Molton
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Changelog:
- * 26/01/1996 RMK Cleaned up various areas to make little more generic
- * 07/02/1999 RMK Support added for 16K and 32K page sizes
- * containing 8K blocks
- * 23/05/2004 IM Fixed to use struct page->lru (thanks wli)
- *
- */
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/smp.h>
-#include <linux/bitops.h>
-
-#include <asm/pgtable.h>
-
-#define PEDANTIC
-
-/*
- * Requirement:
- * We need to be able to allocate naturally aligned memory of finer
- * granularity than the page size. This is typically used for the
- * second level page tables on 32-bit ARMs.
- *
- * FIXME - this comment is *out of date*
- * Theory:
- * We "misuse" the Linux memory management system. We use alloc_page
- * to allocate a page and then mark it as reserved. The Linux memory
- * management system will then ignore the "offset", "next_hash" and
- * "pprev_hash" entries in the mem_map for this page.
- *
- * We then use a bitstring in the "offset" field to mark which segments
- * of the page are in use, and manipulate this as required during the
- * allocation and freeing of these small pages.
- *
- * We also maintain a queue of pages being used for this purpose using
- * the "next_hash" and "pprev_hash" entries of mem_map;
- */
-
-struct order {
- struct list_head queue;
- unsigned int mask; /* (1 << shift) - 1 */
- unsigned int shift; /* (1 << shift) size of page */
- unsigned int block_mask; /* nr_blocks - 1 */
- unsigned int all_used; /* (1 << nr_blocks) - 1 */
-};
-
-
-static struct order orders[] = {
-#if PAGE_SIZE == 32768
- { LIST_HEAD_INIT(orders[0].queue), 2047, 11, 15, 0x0000ffff },
- { LIST_HEAD_INIT(orders[1].queue), 8191, 13, 3, 0x0000000f }
-#else
-#error unsupported page size (ARGH!)
-#endif
-};
-
-#define USED_MAP(pg) ((pg)->index)
-#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg)))
-#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg)))
-
-static DEFINE_SPINLOCK(small_page_lock);
-
-static unsigned long __get_small_page(int priority, struct order *order)
-{
- unsigned long flags;
- struct page *page;
- int offset;
-
- do {
- spin_lock_irqsave(&small_page_lock, flags);
-
- if (list_empty(&order->queue))
- goto need_new_page;
-
- page = list_entry(order->queue.next, struct page, lru);
-again:
-#ifdef PEDANTIC
- BUG_ON(USED_MAP(page) & ~order->all_used);
-#endif
- offset = ffz(USED_MAP(page));
- SET_USED(page, offset);
- if (USED_MAP(page) == order->all_used)
- list_del_init(&page->lru);
- spin_unlock_irqrestore(&small_page_lock, flags);
-
- return (unsigned long) page_address(page) + (offset << order->shift);
-
-need_new_page:
- spin_unlock_irqrestore(&small_page_lock, flags);
- page = alloc_page(priority);
- spin_lock_irqsave(&small_page_lock, flags);
-
- if (list_empty(&order->queue)) {
- if (!page)
- goto no_page;
- SetPageReserved(page);
- USED_MAP(page) = 0;
- list_add(&page->lru, &order->queue);
- goto again;
- }
-
- spin_unlock_irqrestore(&small_page_lock, flags);
- __free_page(page);
- } while (1);
-
-no_page:
- spin_unlock_irqrestore(&small_page_lock, flags);
- return 0;
-}
-
-static void __free_small_page(unsigned long spage, struct order *order)
-{
- unsigned long flags;
- struct page *page;
-
- if (virt_addr_valid(spage)) {
- page = virt_to_page(spage);
-
- /*
- * The container-page must be marked Reserved
- */
- if (!PageReserved(page) || spage & order->mask)
- goto non_small;
-
-#ifdef PEDANTIC
- BUG_ON(USED_MAP(page) & ~order->all_used);
-#endif
-
- spage = spage >> order->shift;
- spage &= order->block_mask;
-
- /*
- * the following must be atomic wrt get_page
- */
- spin_lock_irqsave(&small_page_lock, flags);
-
- if (USED_MAP(page) == order->all_used)
- list_add(&page->lru, &order->queue);
-
- if (!TEST_AND_CLEAR_USED(page, spage))
- goto already_free;
-
- if (USED_MAP(page) == 0)
- goto free_page;
-
- spin_unlock_irqrestore(&small_page_lock, flags);
- }
- return;
-
-free_page:
- /*
- * unlink the page from the small page queue and free it
- */
- list_del_init(&page->lru);
- spin_unlock_irqrestore(&small_page_lock, flags);
- ClearPageReserved(page);
- __free_page(page);
- return;
-
-non_small:
- printk("Trying to free non-small page from %p\n", __builtin_return_address(0));
- return;
-already_free:
- printk("Trying to free free small page from %p\n", __builtin_return_address(0));
-}
-
-unsigned long get_page_8k(int priority)
-{
- return __get_small_page(priority, orders+1);
-}
-
-void free_page_8k(unsigned long spage)
-{
- __free_small_page(spage, orders+1);
-}