summaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/Kconfig2
-rw-r--r--arch/arm/mm/copypage-v6.c6
-rw-r--r--arch/arm/mm/fault-armv.c31
-rw-r--r--arch/arm/mm/fault.c75
-rw-r--r--arch/arm/mm/flush.c44
-rw-r--r--arch/arm/mm/init.c92
-rw-r--r--arch/arm/mm/ioremap.c47
-rw-r--r--arch/arm/mm/mm-armv.c89
-rw-r--r--arch/arm/mm/mmap.c10
-rw-r--r--arch/arm/mm/proc-arm1020.S4
-rw-r--r--arch/arm/mm/proc-arm1020e.S4
-rw-r--r--arch/arm/mm/proc-v6.S6
12 files changed, 215 insertions, 195 deletions
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 3fefb43c67f7..95606b4a3ba6 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -62,7 +62,7 @@ config CPU_ARM720T
# ARM920T
config CPU_ARM920T
bool "Support ARM920T processor" if !ARCH_S3C2410
- depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX
+ depends on ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000
default y if ARCH_S3C2410
select CPU_32v4
select CPU_ABRT_EV4T
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index a8c00236bd3d..27d041574ea7 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -30,8 +30,6 @@
static DEFINE_SPINLOCK(v6_lock);
-#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
-
/*
* Copy the user page. No aliasing to deal with so we can just
* attack the kernel's existing mapping of these pages.
@@ -55,7 +53,7 @@ void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
*/
void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
{
- unsigned int offset = DCACHE_COLOUR(vaddr);
+ unsigned int offset = CACHE_COLOUR(vaddr);
unsigned long from, to;
/*
@@ -95,7 +93,7 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd
*/
void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
{
- unsigned int offset = DCACHE_COLOUR(vaddr);
+ unsigned int offset = CACHE_COLOUR(vaddr);
unsigned long to = to_address + (offset << PAGE_SHIFT);
/*
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 01967ddeef53..be4ab3d73c91 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -77,9 +77,8 @@ no_pmd:
}
static void
-make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
+make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
{
- struct address_space *mapping = page_mapping(page);
struct mm_struct *mm = vma->vm_mm;
struct vm_area_struct *mpnt;
struct prio_tree_iter iter;
@@ -87,9 +86,6 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
pgoff_t pgoff;
int aliases = 0;
- if (!mapping)
- return;
-
pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
/*
@@ -115,9 +111,11 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
if (aliases)
adjust_pte(vma, addr);
else
- flush_cache_page(vma, addr, page_to_pfn(page));
+ flush_cache_page(vma, addr, pfn);
}
+void __flush_dcache_page(struct address_space *mapping, struct page *page);
+
/*
* Take care of architecture specific things when placing a new PTE into
* a page table, or changing an existing PTE. Basically, there are two
@@ -134,29 +132,22 @@ make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page,
void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
{
unsigned long pfn = pte_pfn(pte);
+ struct address_space *mapping;
struct page *page;
if (!pfn_valid(pfn))
return;
+
page = pfn_to_page(pfn);
- if (page_mapping(page)) {
+ mapping = page_mapping(page);
+ if (mapping) {
int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
- if (dirty) {
- /*
- * This is our first userspace mapping of this page.
- * Ensure that the physical page is coherent with
- * the kernel mapping.
- *
- * FIXME: only need to do this on VIVT and aliasing
- * VIPT cache architectures. We can do that
- * by choosing whether to set this bit...
- */
- __cpuc_flush_dcache_page(page_address(page));
- }
+ if (dirty)
+ __flush_dcache_page(mapping, page);
if (cache_is_vivt())
- make_coherent(vma, addr, page, dirty);
+ make_coherent(mapping, vma, addr, pfn);
}
}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index e25b4fd8412c..65bfe84b6d67 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -372,49 +372,50 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
static struct fsr_info {
int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
int sig;
+ int code;
const char *name;
} fsr_info[] = {
/*
* The following are the standard ARMv3 and ARMv4 aborts. ARMv5
* defines these to be "precise" aborts.
*/
- { do_bad, SIGSEGV, "vector exception" },
- { do_bad, SIGILL, "alignment exception" },
- { do_bad, SIGKILL, "terminal exception" },
- { do_bad, SIGILL, "alignment exception" },
- { do_bad, SIGBUS, "external abort on linefetch" },
- { do_translation_fault, SIGSEGV, "section translation fault" },
- { do_bad, SIGBUS, "external abort on linefetch" },
- { do_page_fault, SIGSEGV, "page translation fault" },
- { do_bad, SIGBUS, "external abort on non-linefetch" },
- { do_bad, SIGSEGV, "section domain fault" },
- { do_bad, SIGBUS, "external abort on non-linefetch" },
- { do_bad, SIGSEGV, "page domain fault" },
- { do_bad, SIGBUS, "external abort on translation" },
- { do_sect_fault, SIGSEGV, "section permission fault" },
- { do_bad, SIGBUS, "external abort on translation" },
- { do_page_fault, SIGSEGV, "page permission fault" },
+ { do_bad, SIGSEGV, 0, "vector exception" },
+ { do_bad, SIGILL, BUS_ADRALN, "alignment exception" },
+ { do_bad, SIGKILL, 0, "terminal exception" },
+ { do_bad, SIGILL, BUS_ADRALN, "alignment exception" },
+ { do_bad, SIGBUS, 0, "external abort on linefetch" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
+ { do_bad, SIGBUS, 0, "external abort on linefetch" },
+ { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
+ { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
+ { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
/*
* The following are "imprecise" aborts, which are signalled by bit
* 10 of the FSR, and may not be recoverable. These are only
* supported if the CPU abort handler supports bit 10.
*/
- { do_bad, SIGBUS, "unknown 16" },
- { do_bad, SIGBUS, "unknown 17" },
- { do_bad, SIGBUS, "unknown 18" },
- { do_bad, SIGBUS, "unknown 19" },
- { do_bad, SIGBUS, "lock abort" }, /* xscale */
- { do_bad, SIGBUS, "unknown 21" },
- { do_bad, SIGBUS, "imprecise external abort" }, /* xscale */
- { do_bad, SIGBUS, "unknown 23" },
- { do_bad, SIGBUS, "dcache parity error" }, /* xscale */
- { do_bad, SIGBUS, "unknown 25" },
- { do_bad, SIGBUS, "unknown 26" },
- { do_bad, SIGBUS, "unknown 27" },
- { do_bad, SIGBUS, "unknown 28" },
- { do_bad, SIGBUS, "unknown 29" },
- { do_bad, SIGBUS, "unknown 30" },
- { do_bad, SIGBUS, "unknown 31" }
+ { do_bad, SIGBUS, 0, "unknown 16" },
+ { do_bad, SIGBUS, 0, "unknown 17" },
+ { do_bad, SIGBUS, 0, "unknown 18" },
+ { do_bad, SIGBUS, 0, "unknown 19" },
+ { do_bad, SIGBUS, 0, "lock abort" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 21" },
+ { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 23" },
+ { do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 25" },
+ { do_bad, SIGBUS, 0, "unknown 26" },
+ { do_bad, SIGBUS, 0, "unknown 27" },
+ { do_bad, SIGBUS, 0, "unknown 28" },
+ { do_bad, SIGBUS, 0, "unknown 29" },
+ { do_bad, SIGBUS, 0, "unknown 30" },
+ { do_bad, SIGBUS, 0, "unknown 31" }
};
void __init
@@ -435,15 +436,19 @@ asmlinkage void
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
+ struct siginfo info;
if (!inf->fn(addr, fsr, regs))
return;
printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);
- force_sig(inf->sig, current);
- show_pte(current->mm, addr);
- die_if_kernel("Oops", regs, 0);
+
+ info.si_signo = inf->sig;
+ info.si_errno = 0;
+ info.si_code = inf->code;
+ info.si_addr = (void __user *)addr;
+ notify_die("", regs, &info, fsr, 0);
}
asmlinkage void
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 4085ed983e46..191788fb18d1 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -37,13 +37,8 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
#define flush_pfn_alias(pfn,vaddr) do { } while (0)
#endif
-static void __flush_dcache_page(struct address_space *mapping, struct page *page)
+void __flush_dcache_page(struct address_space *mapping, struct page *page)
{
- struct mm_struct *mm = current->active_mm;
- struct vm_area_struct *mpnt;
- struct prio_tree_iter iter;
- pgoff_t pgoff;
-
/*
* Writeback any data associated with the kernel mapping of this
* page. This ensures that data in the physical page is mutually
@@ -52,24 +47,21 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
__cpuc_flush_dcache_page(page_address(page));
/*
- * If there's no mapping pointer here, then this page isn't
- * visible to userspace yet, so there are no cache lines
- * associated with any other aliases.
- */
- if (!mapping)
- return;
-
- /*
- * This is a page cache page. If we have a VIPT cache, we
- * only need to do one flush - which would be at the relevant
+ * If this is a page cache page, and we have an aliasing VIPT cache,
+ * we only need to do one flush - which would be at the relevant
* userspace colour, which is congruent with page->index.
*/
- if (cache_is_vipt()) {
- if (cache_is_vipt_aliasing())
- flush_pfn_alias(page_to_pfn(page),
- page->index << PAGE_CACHE_SHIFT);
- return;
- }
+ if (mapping && cache_is_vipt_aliasing())
+ flush_pfn_alias(page_to_pfn(page),
+ page->index << PAGE_CACHE_SHIFT);
+}
+
+static void __flush_dcache_aliases(struct address_space *mapping, struct page *page)
+{
+ struct mm_struct *mm = current->active_mm;
+ struct vm_area_struct *mpnt;
+ struct prio_tree_iter iter;
+ pgoff_t pgoff;
/*
* There are possible user space mappings of this page:
@@ -116,12 +108,12 @@ void flush_dcache_page(struct page *page)
{
struct address_space *mapping = page_mapping(page);
- if (cache_is_vipt_nonaliasing())
- return;
-
if (mapping && !mapping_mapped(mapping))
set_bit(PG_dcache_dirty, &page->flags);
- else
+ else {
__flush_dcache_page(mapping, page);
+ if (mapping && cache_is_vivt())
+ __flush_dcache_aliases(mapping, page);
+ }
}
EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 72a2b8cee319..edffa47a4b2a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -93,14 +93,7 @@ struct node_info {
};
#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x))
-
#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)
-#define V_PFN_UP(x) O_PFN_UP(__pa(x))
-
-#define PFN_SIZE(x) ((x) >> PAGE_SHIFT)
-#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \
- (((unsigned long)(s)) & PAGE_MASK))
/*
* FIXME: We really want to avoid allocating the bootmap bitmap
@@ -113,7 +106,7 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
{
unsigned int start_pfn, bank, bootmap_pfn;
- start_pfn = V_PFN_UP(&_end);
+ start_pfn = O_PFN_UP(__pa(&_end));
bootmap_pfn = 0;
for (bank = 0; bank < mi->nr_banks; bank ++) {
@@ -122,9 +115,9 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
if (mi->bank[bank].node != node)
continue;
- start = O_PFN_UP(mi->bank[bank].start);
- end = O_PFN_DOWN(mi->bank[bank].size +
- mi->bank[bank].start);
+ start = mi->bank[bank].start >> PAGE_SHIFT;
+ end = (mi->bank[bank].size +
+ mi->bank[bank].start) >> PAGE_SHIFT;
if (end < start_pfn)
continue;
@@ -191,8 +184,8 @@ find_memend_and_nodes(struct meminfo *mi, struct node_info *np)
/*
* Get the start and end pfns for this bank
*/
- start = O_PFN_UP(mi->bank[i].start);
- end = O_PFN_DOWN(mi->bank[i].start + mi->bank[i].size);
+ start = mi->bank[i].start >> PAGE_SHIFT;
+ end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT;
if (np[node].start > start)
np[node].start = start;
@@ -444,7 +437,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
memtable_init(mi);
if (mdesc->map_io)
mdesc->map_io();
- flush_tlb_all();
+ local_flush_tlb_all();
/*
* initialise the zones within each node
@@ -529,6 +522,69 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
}
+static inline void
+free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
+{
+ struct page *start_pg, *end_pg;
+ unsigned long pg, pgend;
+
+ /*
+ * Convert start_pfn/end_pfn to a struct page pointer.
+ */
+ start_pg = pfn_to_page(start_pfn);
+ end_pg = pfn_to_page(end_pfn);
+
+ /*
+ * Convert to physical addresses, and
+ * round start upwards and end downwards.
+ */
+ pg = PAGE_ALIGN(__pa(start_pg));
+ pgend = __pa(end_pg) & PAGE_MASK;
+
+ /*
+ * If there are free pages between these,
+ * free the section of the memmap array.
+ */
+ if (pg < pgend)
+ free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big. Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap_node(int node, struct meminfo *mi)
+{
+ unsigned long bank_start, prev_bank_end = 0;
+ unsigned int i;
+
+ /*
+ * [FIXME] This relies on each bank being in address order. This
+ * may not be the case, especially if the user has provided the
+ * information on the command line.
+ */
+ for (i = 0; i < mi->nr_banks; i++) {
+ if (mi->bank[i].size == 0 || mi->bank[i].node != node)
+ continue;
+
+ bank_start = mi->bank[i].start >> PAGE_SHIFT;
+ if (bank_start < prev_bank_end) {
+ printk(KERN_ERR "MEM: unordered memory banks. "
+ "Not freeing memmap.\n");
+ break;
+ }
+
+ /*
+ * If we had a previous bank, and there is a space
+ * between the current bank and the previous, free it.
+ */
+ if (prev_bank_end && prev_bank_end != bank_start)
+ free_memmap(node, prev_bank_end, bank_start);
+
+ prev_bank_end = (mi->bank[i].start +
+ mi->bank[i].size) >> PAGE_SHIFT;
+ }
+}
+
/*
* mem_init() marks the free areas in the mem_map and tells us how much
* memory is free. This is done after various parts of the system have
@@ -547,16 +603,12 @@ void __init mem_init(void)
max_mapnr = virt_to_page(high_memory) - mem_map;
#endif
- /*
- * We may have non-contiguous memory.
- */
- if (meminfo.nr_banks != 1)
- create_memmap_holes(&meminfo);
-
/* this will put all unused low memory onto the freelists */
for_each_online_node(node) {
pg_data_t *pgdat = NODE_DATA(node);
+ free_unused_memmap_node(node, &meminfo);
+
if (pgdat->node_spanned_pages != 0)
totalram_pages += free_all_bootmem_node(pgdat);
}
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 00bb8fd37a59..7110e54182b1 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -170,3 +170,50 @@ void __iounmap(void __iomem *addr)
vfree((void *) (PAGE_MASK & (unsigned long) addr));
}
EXPORT_SYMBOL(__iounmap);
+
+#ifdef __io
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+ return __io(port);
+}
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+}
+EXPORT_SYMBOL(ioport_unmap);
+#endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+ unsigned long start = pci_resource_start(dev, bar);
+ unsigned long len = pci_resource_len(dev, bar);
+ unsigned long flags = pci_resource_flags(dev, bar);
+
+ if (!len || !start)
+ return NULL;
+ if (maxlen && len > maxlen)
+ len = maxlen;
+ if (flags & IORESOURCE_IO)
+ return ioport_map(start, len);
+ if (flags & IORESOURCE_MEM) {
+ if (flags & IORESOURCE_CACHEABLE)
+ return ioremap(start, len);
+ return ioremap_nocache(start, len);
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+ if ((unsigned long)addr >= VMALLOC_START &&
+ (unsigned long)addr < VMALLOC_END)
+ iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
+#endif
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 2c2b93d77d43..c3bd503b43a2 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -169,7 +169,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+ /*
+ * Copy over the kernel and IO PGD entries
+ */
init_pgd = pgd_offset_k(0);
+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+ clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
if (!vectors_high()) {
/*
@@ -198,14 +205,6 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
spin_unlock(&mm->page_table_lock);
}
- /*
- * Copy over the kernel and IO PGD entries
- */
- memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
- (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-
- clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
-
return new_pgd;
no_pte:
@@ -683,7 +682,7 @@ void __init memtable_init(struct meminfo *mi)
}
flush_cache_all();
- flush_tlb_all();
+ local_flush_tlb_all();
top_pmd = pmd_off_k(0xffff0000);
}
@@ -698,75 +697,3 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
for (i = 0; i < nr; i++)
create_mapping(io_desc + i);
}
-
-static inline void
-free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
-{
- struct page *start_pg, *end_pg;
- unsigned long pg, pgend;
-
- /*
- * Convert start_pfn/end_pfn to a struct page pointer.
- */
- start_pg = pfn_to_page(start_pfn);
- end_pg = pfn_to_page(end_pfn);
-
- /*
- * Convert to physical addresses, and
- * round start upwards and end downwards.
- */
- pg = PAGE_ALIGN(__pa(start_pg));
- pgend = __pa(end_pg) & PAGE_MASK;
-
- /*
- * If there are free pages between these,
- * free the section of the memmap array.
- */
- if (pg < pgend)
- free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
-}
-
-static inline void free_unused_memmap_node(int node, struct meminfo *mi)
-{
- unsigned long bank_start, prev_bank_end = 0;
- unsigned int i;
-
- /*
- * [FIXME] This relies on each bank being in address order. This
- * may not be the case, especially if the user has provided the
- * information on the command line.
- */
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size == 0 || mi->bank[i].node != node)
- continue;
-
- bank_start = mi->bank[i].start >> PAGE_SHIFT;
- if (bank_start < prev_bank_end) {
- printk(KERN_ERR "MEM: unordered memory banks. "
- "Not freeing memmap.\n");
- break;
- }
-
- /*
- * If we had a previous bank, and there is a space
- * between the current bank and the previous, free it.
- */
- if (prev_bank_end && prev_bank_end != bank_start)
- free_memmap(node, prev_bank_end, bank_start);
-
- prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
- mi->bank[i].size) >> PAGE_SHIFT;
- }
-}
-
-/*
- * The mem_map array can get very big. Free
- * the unused area of the memory map.
- */
-void __init create_memmap_holes(struct meminfo *mi)
-{
- int node;
-
- for_each_online_node(node)
- free_unused_memmap_node(node, mi);
-}
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 32c4b0e35b37..3de7f84b53c2 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -73,7 +73,12 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
(!vma || addr + len <= vma->vm_start))
return addr;
}
- start_addr = addr = mm->free_area_cache;
+ if (len > mm->cached_hole_size) {
+ start_addr = addr = mm->free_area_cache;
+ } else {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
full_search:
if (do_align)
@@ -90,6 +95,7 @@ full_search:
*/
if (start_addr != TASK_UNMAPPED_BASE) {
start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
goto full_search;
}
return -ENOMEM;
@@ -101,6 +107,8 @@ full_search:
mm->free_area_cache = addr + len;
return addr;
}
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
addr = vma->vm_end;
if (do_align)
addr = COLOUR_ALIGN(addr, pgoff);
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 1f325231b9e4..5c0ae5260d1c 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -445,14 +445,14 @@ __arm1020_setup:
/*
* R
* .RVI ZFRS BLDP WCAM
- * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
+ * .011 1001 ..11 0101
*/
.type arm1020_cr1_clear, #object
.type arm1020_cr1_set, #object
arm1020_cr1_clear:
.word 0x593f
arm1020_cr1_set:
- .word 0x1935
+ .word 0x3935
__INITDATA
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 142a2c2d6f0b..d69389c4d4ba 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -427,14 +427,14 @@ __arm1020e_setup:
/*
* R
* .RVI ZFRS BLDP WCAM
- * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
+ * .011 1001 ..11 0101
*/
.type arm1020e_cr1_clear, #object
.type arm1020e_cr1_set, #object
arm1020e_cr1_clear:
.word 0x5f3f
arm1020e_cr1_set:
- .word 0x1935
+ .word 0x3935
__INITDATA
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 0aa73d414783..e3d8510f4340 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -132,8 +132,8 @@ ENTRY(cpu_v6_switch_mm)
* 100x 1 0 1 r/o no acc
* 10x0 1 0 1 r/o no acc
* 1011 0 0 1 r/w no acc
- * 110x 1 1 0 r/o r/o
- * 11x0 1 1 0 r/o r/o
+ * 110x 0 1 0 r/w r/o
+ * 11x0 0 1 0 r/w r/o
* 1111 0 1 1 r/w r/w
*/
ENTRY(cpu_v6_set_pte)
@@ -150,7 +150,7 @@ ENTRY(cpu_v6_set_pte)
tst r1, #L_PTE_USER
orrne r2, r2, #AP1 | nG
tstne r2, #APX
- eorne r2, r2, #AP0
+ bicne r2, r2, #APX | AP0
tst r1, #L_PTE_YOUNG
biceq r2, r2, #APX | AP1 | AP0