summaryrefslogtreecommitdiffstats
path: root/arch/sh/mm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/mm')
-rw-r--r--arch/sh/mm/Kconfig6
-rw-r--r--arch/sh/mm/cache-debugfs.c6
-rw-r--r--arch/sh/mm/cache-sh4.c2
-rw-r--r--arch/sh/mm/consistent.c12
-rw-r--r--arch/sh/mm/fault_32.c63
-rw-r--r--arch/sh/mm/init.c74
-rw-r--r--arch/sh/mm/pg-nommu.c1
-rw-r--r--arch/sh/mm/pmb.c2
-rw-r--r--arch/sh/mm/tlb-nommu.c1
9 files changed, 124 insertions, 43 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 8a03926ea84..555ec9714b9 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -132,7 +132,11 @@ config ARCH_SELECT_MEMORY_MODEL
config ARCH_ENABLE_MEMORY_HOTPLUG
def_bool y
- depends on SPARSEMEM
+ depends on SPARSEMEM && MMU
+
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+ def_bool y
+ depends on SPARSEMEM && MMU
config ARCH_MEMORY_PROBE
def_bool y
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
index 0e189ccd4a7..5ba067b2659 100644
--- a/arch/sh/mm/cache-debugfs.c
+++ b/arch/sh/mm/cache-debugfs.c
@@ -130,12 +130,18 @@ static int __init cache_debugfs_init(void)
dcache_dentry = debugfs_create_file("dcache", S_IRUSR, sh_debugfs_root,
(unsigned int *)CACHE_TYPE_DCACHE,
&cache_debugfs_fops);
+ if (!dcache_dentry)
+ return -ENOMEM;
if (IS_ERR(dcache_dentry))
return PTR_ERR(dcache_dentry);
icache_dentry = debugfs_create_file("icache", S_IRUSR, sh_debugfs_root,
(unsigned int *)CACHE_TYPE_ICACHE,
&cache_debugfs_fops);
+ if (!icache_dentry) {
+ debugfs_remove(dcache_dentry);
+ return -ENOMEM;
+ }
if (IS_ERR(icache_dentry)) {
debugfs_remove(dcache_dentry);
return PTR_ERR(icache_dentry);
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 1fdc8d90254..5cfe08dbb59 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -261,7 +261,7 @@ void flush_dcache_page(struct page *page)
}
/* TODO: Selective icache invalidation through IC address array.. */
-static inline void __uses_jump_to_uncached flush_icache_all(void)
+static void __uses_jump_to_uncached flush_icache_all(void)
{
unsigned long flags, ccr;
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index 64b8f7f96f9..9f8ea3ada4d 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -16,14 +16,6 @@
#include <asm/addrspace.h>
#include <asm/io.h>
-struct dma_coherent_mem {
- void *virt_base;
- u32 device_base;
- int size;
- int flags;
- unsigned long *bitmap;
-};
-
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp)
{
@@ -44,7 +36,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
*/
dma_cache_sync(dev, ret, size, DMA_BIDIRECTIONAL);
- ret_nocache = ioremap_nocache(virt_to_phys(ret), size);
+ ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size);
if (!ret_nocache) {
free_pages((unsigned long)ret, order);
return NULL;
@@ -58,12 +50,10 @@ EXPORT_SYMBOL(dma_alloc_coherent);
void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
- struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
int order = get_order(size);
if (!dma_release_from_coherent(dev, order, vaddr)) {
WARN_ON(irqs_disabled()); /* for portability */
- BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE);
free_pages((unsigned long)phys_to_virt(dma_handle), order);
iounmap(vaddr);
}
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
index 0c776fdfbdd..898d477e47c 100644
--- a/arch/sh/mm/fault_32.c
+++ b/arch/sh/mm/fault_32.c
@@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU.
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 - 2007 Paul Mundt
+ * Copyright (C) 2003 - 2008 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/hardirq.h>
#include <linux/kprobes.h>
+#include <linux/marker.h>
#include <asm/io_trapped.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
@@ -37,10 +38,10 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
int fault;
siginfo_t info;
-#ifdef CONFIG_SH_KGDB
- if (kgdb_nofault && kgdb_bus_err_hook)
- kgdb_bus_err_hook();
-#endif
+ /*
+ * We don't bother with any notifier callbacks here, as they are
+ * all handled through the __do_page_fault() fast-path.
+ */
tsk = current;
si_code = SEGV_MAPERR;
@@ -61,7 +62,6 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
pgd = get_TTB() + offset;
pgd_k = swapper_pg_dir + offset;
- /* This will never happen with the folded page table. */
if (!pgd_present(*pgd)) {
if (!pgd_present(*pgd_k))
goto bad_area_nosemaphore;
@@ -71,9 +71,13 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
pud = pud_offset(pgd, address);
pud_k = pud_offset(pgd_k, address);
- if (pud_present(*pud) || !pud_present(*pud_k))
- goto bad_area_nosemaphore;
- set_pud(pud, *pud_k);
+
+ if (!pud_present(*pud)) {
+ if (!pud_present(*pud_k))
+ goto bad_area_nosemaphore;
+ set_pud(pud, *pud_k);
+ return;
+ }
pmd = pmd_offset(pud, address);
pmd_k = pmd_offset(pud_k, address);
@@ -242,6 +246,25 @@ do_sigbus:
goto no_context;
}
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+ int ret = 0;
+
+ trace_mark(kernel_arch_trap_entry, "trap_id %d ip #p%ld",
+ trap >> 5, instruction_pointer(regs));
+
+#ifdef CONFIG_KPROBES
+ if (!user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, trap))
+ ret = 1;
+ preempt_enable();
+ }
+#endif
+
+ return ret;
+}
+
#ifdef CONFIG_SH_STORE_QUEUES
/*
* This is a special case for the SH-4 store queues, as pages for this
@@ -265,12 +288,18 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
pmd_t *pmd;
pte_t *pte;
pte_t entry;
+ int ret = 0;
+
+ if (notify_page_fault(regs, lookup_exception_vector()))
+ goto out;
#ifdef CONFIG_SH_KGDB
if (kgdb_nofault && kgdb_bus_err_hook)
kgdb_bus_err_hook();
#endif
+ ret = 1;
+
/*
* We don't take page faults for P1, P2, and parts of P4, these
* are always mapped, whether it be due to legacy behaviour in
@@ -280,24 +309,23 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
pgd = pgd_offset_k(address);
} else {
if (unlikely(address >= TASK_SIZE || !current->mm))
- return 1;
+ goto out;
pgd = pgd_offset(current->mm, address);
}
pud = pud_offset(pgd, address);
if (pud_none_or_clear_bad(pud))
- return 1;
+ goto out;
pmd = pmd_offset(pud, address);
if (pmd_none_or_clear_bad(pmd))
- return 1;
-
+ goto out;
pte = pte_offset_kernel(pmd, address);
entry = *pte;
if (unlikely(pte_none(entry) || pte_not_present(entry)))
- return 1;
+ goto out;
if (unlikely(writeaccess && !pte_write(entry)))
- return 1;
+ goto out;
if (writeaccess)
entry = pte_mkdirty(entry);
@@ -314,5 +342,8 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
set_pte(pte, entry);
update_mmu_cache(NULL, address, entry);
- return 0;
+ ret = 0;
+out:
+ trace_mark(kernel_arch_trap_exit, MARK_NOARGS);
+ return ret;
}
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index b75a7acd62f..2a53943924b 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -23,7 +23,19 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-unsigned long cached_to_uncached = 0;
+
+#ifdef CONFIG_SUPERH32
+/*
+ * Handle trivial transitions between cached and uncached
+ * segments, making use of the 1:1 mapping relationship in
+ * 512MB lowmem.
+ *
+ * This is the offset of the uncached section from its cached alias.
+ * Default value only valid in 29 bit mode, in 32bit mode will be
+ * overridden in pmb_init.
+ */
+unsigned long cached_to_uncached = P2SEG - P1SEG;
+#endif
#ifdef CONFIG_MMU
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -58,9 +70,7 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
}
set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot));
-
- if (cached_to_uncached)
- flush_tlb_one(get_asid(), addr);
+ flush_tlb_one(get_asid(), addr);
}
/*
@@ -113,7 +123,6 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
if (!pmd_present(*pmd)) {
pte_t *pte_table;
pte_table = (pte_t *)alloc_bootmem_low_pages(PAGE_SIZE);
- memset(pte_table, 0, PAGE_SIZE);
pmd_populate_kernel(&init_mm, pmd, pte_table);
}
@@ -165,15 +174,6 @@ void __init paging_init(void)
#ifdef CONFIG_SUPERH32
/* Set up the uncached fixmap */
set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start));
-
-#ifdef CONFIG_29BIT
- /*
- * Handle trivial transitions between cached and uncached
- * segments, making use of the 1:1 mapping relationship in
- * 512MB lowmem.
- */
- cached_to_uncached = P2SEG - P1SEG;
-#endif
#endif
}
@@ -265,6 +265,35 @@ void free_initrd_mem(unsigned long start, unsigned long end)
}
#endif
+#if THREAD_SHIFT < PAGE_SHIFT
+static struct kmem_cache *thread_info_cache;
+
+struct thread_info *alloc_thread_info(struct task_struct *tsk)
+{
+ struct thread_info *ti;
+
+ ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
+ if (unlikely(ti == NULL))
+ return NULL;
+#ifdef CONFIG_DEBUG_STACK_USAGE
+ memset(ti, 0, THREAD_SIZE);
+#endif
+ return ti;
+}
+
+void free_thread_info(struct thread_info *ti)
+{
+ kmem_cache_free(thread_info_cache, ti);
+}
+
+void thread_info_cache_init(void)
+{
+ thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
+ THREAD_SIZE, 0, NULL);
+ BUG_ON(thread_info_cache == NULL);
+}
+#endif /* THREAD_SHIFT < PAGE_SHIFT */
+
#ifdef CONFIG_MEMORY_HOTPLUG
int arch_add_memory(int nid, u64 start, u64 size)
{
@@ -292,4 +321,21 @@ int memory_add_physaddr_to_nid(u64 addr)
}
EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
#endif
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int remove_memory(u64 start, u64 size)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long end_pfn = start_pfn + (size >> PAGE_SHIFT);
+ int ret;
+
+ ret = offline_pages(start_pfn, end_pfn, 120 * HZ);
+ if (unlikely(ret))
+ printk("%s: Failed, offline_pages() == %d\n", __func__, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(remove_memory);
#endif
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
index 677dd57f087..91ed4e695ff 100644
--- a/arch/sh/mm/pg-nommu.c
+++ b/arch/sh/mm/pg-nommu.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/page.h>
+#include <asm/uaccess.h>
void copy_page(void *to, void *from)
{
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index cef727669c8..84241676265 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -394,6 +394,8 @@ static int __init pmb_debugfs_init(void)
dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
sh_debugfs_root, NULL, &pmb_debugfs_fops);
+ if (!dentry)
+ return -ENOMEM;
if (IS_ERR(dentry))
return PTR_ERR(dentry);
diff --git a/arch/sh/mm/tlb-nommu.c b/arch/sh/mm/tlb-nommu.c
index 15111bc7ddd..71c742b5aee 100644
--- a/arch/sh/mm/tlb-nommu.c
+++ b/arch/sh/mm/tlb-nommu.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
/*
* Nothing too terribly exciting here ..