aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze
diff options
context:
space:
mode:
Diffstat (limited to 'arch/microblaze')
-rw-r--r--arch/microblaze/Kconfig34
-rw-r--r--arch/microblaze/boot/Makefile12
-rw-r--r--arch/microblaze/include/asm/atomic.h1
-rw-r--r--arch/microblaze/include/asm/barrier.h27
-rw-r--r--arch/microblaze/include/asm/cmpxchg.h40
-rw-r--r--arch/microblaze/include/asm/exec.h14
-rw-r--r--arch/microblaze/include/asm/fixmap.h109
-rw-r--r--arch/microblaze/include/asm/hardirq.h16
-rw-r--r--arch/microblaze/include/asm/highmem.h96
-rw-r--r--arch/microblaze/include/asm/irq.h42
-rw-r--r--arch/microblaze/include/asm/mmu.h12
-rw-r--r--arch/microblaze/include/asm/page.h4
-rw-r--r--arch/microblaze/include/asm/pci-bridge.h1
-rw-r--r--arch/microblaze/include/asm/pci.h8
-rw-r--r--arch/microblaze/include/asm/pgtable.h5
-rw-r--r--arch/microblaze/include/asm/processor.h11
-rw-r--r--arch/microblaze/include/asm/setup.h9
-rw-r--r--arch/microblaze/include/asm/switch_to.h24
-rw-r--r--arch/microblaze/include/asm/system.h97
-rw-r--r--arch/microblaze/include/asm/uaccess.h2
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c2
-rw-r--r--arch/microblaze/kernel/cpu/pvr.c1
-rw-r--r--arch/microblaze/kernel/early_printk.c16
-rw-r--r--arch/microblaze/kernel/head.S129
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S13
-rw-r--r--arch/microblaze/kernel/intc.c65
-rw-r--r--arch/microblaze/kernel/irq.c24
-rw-r--r--arch/microblaze/kernel/microblaze_ksyms.c1
-rw-r--r--arch/microblaze/kernel/misc.S13
-rw-r--r--arch/microblaze/kernel/process.c5
-rw-r--r--arch/microblaze/kernel/prom.c1
-rw-r--r--arch/microblaze/kernel/setup.c27
-rw-r--r--arch/microblaze/kernel/timer.c7
-rw-r--r--arch/microblaze/kernel/traps.c1
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S2
-rw-r--r--arch/microblaze/lib/memcpy.c1
-rw-r--r--arch/microblaze/mm/Makefile1
-rw-r--r--arch/microblaze/mm/fault.c1
-rw-r--r--arch/microblaze/mm/highmem.c88
-rw-r--r--arch/microblaze/mm/init.c224
-rw-r--r--arch/microblaze/mm/pgtable.c20
-rw-r--r--arch/microblaze/pci/pci-common.c117
42 files changed, 894 insertions, 429 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index c8d6efb99dbf..ac22dc7f4cab 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -1,6 +1,7 @@
config MICROBLAZE
def_bool y
select HAVE_MEMBLOCK
+ select HAVE_MEMBLOCK_NODE_MAP
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_FUNCTION_GRAPH_TRACER
@@ -14,6 +15,7 @@ config MICROBLAZE
select TRACING_SUPPORT
select OF
select OF_EARLY_FLATTREE
+ select IRQ_DOMAIN
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
@@ -27,6 +29,12 @@ config SWAP
config RWSEM_GENERIC_SPINLOCK
def_bool y
+config ZONE_DMA
+ def_bool y
+
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
config RWSEM_XCHGADD_ALGORITHM
bool
@@ -152,20 +160,18 @@ config XILINX_UNCACHED_SHADOW
The feature requires the design to define the RAM memory controller
window to be twice as large as the actual physical memory.
-config HIGHMEM_START_BOOL
- bool "Set high memory pool address"
- depends on ADVANCED_OPTIONS && HIGHMEM
+config HIGHMEM
+ bool "High memory support"
+ depends on MMU
help
- This option allows you to set the base address of the kernel virtual
- area used to map high memory pages. This can be useful in
- optimizing the layout of kernel virtual memory.
+ The address space of Microblaze processors is only 4 Gigabytes large
+ and it has to accommodate user address space, kernel address
+ space as well as some memory mapped IO. That means that, if you
+ have a large amount of physical memory and/or IO, not all of the
+ memory can be "permanently mapped" by the kernel. The physical
+ memory that is not permanently mapped is called "high memory".
- Say N here unless you know what you are doing.
-
-config HIGHMEM_START
- hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL
- depends on MMU
- default "0xfe000000"
+ If unsure, say n.
config LOWMEM_SIZE_BOOL
bool "Set maximum low memory"
@@ -254,6 +260,10 @@ config MICROBLAZE_32K_PAGES
endchoice
+config KERNEL_PAD
+ hex "Kernel PAD for unpacking" if ADVANCED_OPTIONS
+ default "0x80000" if MMU
+
endmenu
source "mm/Kconfig"
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 0c796cf81586..fa83ea497db7 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -2,13 +2,11 @@
# arch/microblaze/boot/Makefile
#
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-
obj-y += linked_dtb.o
targets := linux.bin linux.bin.gz simpleImage.%
-OBJCOPYFLAGS := -O binary
+OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary
# Ensure system.dtb exists
$(obj)/linked_dtb.o: $(obj)/system.dtb
@@ -35,11 +33,9 @@ quiet_cmd_strip = STRIP $@
cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
-K _fdt_start vmlinux -o $@
-quiet_cmd_uimage = UIMAGE $@.ub
- cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
- -C none -n 'Linux-$(KERNELRELEASE)' \
- -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
- -d $@ $@.ub
+UIMAGE_IN = $@
+UIMAGE_OUT = $@.ub
+UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
$(obj)/simpleImage.%: vmlinux FORCE
$(call if_changed,cp,.unstrip)
diff --git a/arch/microblaze/include/asm/atomic.h b/arch/microblaze/include/asm/atomic.h
index 615f53992c65..472d8bf726df 100644
--- a/arch/microblaze/include/asm/atomic.h
+++ b/arch/microblaze/include/asm/atomic.h
@@ -1,6 +1,7 @@
#ifndef _ASM_MICROBLAZE_ATOMIC_H
#define _ASM_MICROBLAZE_ATOMIC_H
+#include <asm/cmpxchg.h>
#include <asm-generic/atomic.h>
#include <asm-generic/atomic64.h>
diff --git a/arch/microblaze/include/asm/barrier.h b/arch/microblaze/include/asm/barrier.h
new file mode 100644
index 000000000000..df5be3e87044
--- /dev/null
+++ b/arch/microblaze/include/asm/barrier.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_MICROBLAZE_BARRIER_H
+#define _ASM_MICROBLAZE_BARRIER_H
+
+#define nop() asm volatile ("nop")
+
+#define smp_read_barrier_depends() do {} while (0)
+#define read_barrier_depends() do {} while (0)
+
+#define mb() barrier()
+#define rmb() mb()
+#define wmb() mb()
+#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define smp_mb() mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+
+#endif /* _ASM_MICROBLAZE_BARRIER_H */
diff --git a/arch/microblaze/include/asm/cmpxchg.h b/arch/microblaze/include/asm/cmpxchg.h
new file mode 100644
index 000000000000..0094859abd9b
--- /dev/null
+++ b/arch/microblaze/include/asm/cmpxchg.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_MICROBLAZE_CMPXCHG_H
+#define _ASM_MICROBLAZE_CMPXCHG_H
+
+void __bad_xchg(volatile void *ptr, int size);
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+ int size)
+{
+ unsigned long ret;
+ unsigned long flags;
+
+ switch (size) {
+ case 1:
+ local_irq_save(flags);
+ ret = *(volatile unsigned char *)ptr;
+ *(volatile unsigned char *)ptr = x;
+ local_irq_restore(flags);
+ break;
+
+ case 4:
+ local_irq_save(flags);
+ ret = *(volatile unsigned long *)ptr;
+ *(volatile unsigned long *)ptr = x;
+ local_irq_restore(flags);
+ break;
+ default:
+ __bad_xchg(ptr, size), ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+#define xchg(ptr, x) \
+ ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+#include <asm-generic/cmpxchg.h>
+#include <asm-generic/cmpxchg-local.h>
+
+#endif /* _ASM_MICROBLAZE_CMPXCHG_H */
diff --git a/arch/microblaze/include/asm/exec.h b/arch/microblaze/include/asm/exec.h
new file mode 100644
index 000000000000..e750de1fe8fb
--- /dev/null
+++ b/arch/microblaze/include/asm/exec.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_MICROBLAZE_EXEC_H
+#define _ASM_MICROBLAZE_EXEC_H
+
+#define arch_align_stack(x) (x)
+
+#endif /* _ASM_MICROBLAZE_EXEC_H */
diff --git a/arch/microblaze/include/asm/fixmap.h b/arch/microblaze/include/asm/fixmap.h
new file mode 100644
index 000000000000..f2b312e10b10
--- /dev/null
+++ b/arch/microblaze/include/asm/fixmap.h
@@ -0,0 +1,109 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ *
+ * Copyright 2008 Freescale Semiconductor Inc.
+ * Port to powerpc added by Kumar Gala
+ *
+ * Copyright 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright 2011 PetaLogix Qld Pty Ltd
+ * Port to Microblaze
+ */
+
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#include <asm/page.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+#define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE))
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+enum fixed_addresses {
+ FIX_HOLE,
+#ifdef CONFIG_HIGHMEM
+ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+ FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * num_possible_cpus()) - 1,
+#endif
+ __end_of_fixed_addresses
+};
+
+extern void __set_fixmap(enum fixed_addresses idx,
+ phys_addr_t phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL_CI)
+
+#define clear_fixmap(idx) \
+ __set_fixmap(idx, 0, __pgprot(0))
+
+#define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE)
+
+#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+ /*
+ * this branch gets completely eliminated after inlining,
+ * except when someone tries to use fixaddr indices in an
+ * illegal way. (such as mixing up address types or using
+ * out-of-range indices).
+ *
+ * If it doesn't get removed, the linker will complain
+ * loudly with a reasonably clear error message..
+ */
+ if (idx >= __end_of_fixed_addresses)
+ __this_fixmap_does_not_exist();
+
+ return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+ BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+ return __virt_to_fix(vaddr);
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif
diff --git a/arch/microblaze/include/asm/hardirq.h b/arch/microblaze/include/asm/hardirq.h
index cd1ac9aad56c..fb3c05a0cbbf 100644
--- a/arch/microblaze/include/asm/hardirq.h
+++ b/arch/microblaze/include/asm/hardirq.h
@@ -1,17 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_HARDIRQ_H
-#define _ASM_MICROBLAZE_HARDIRQ_H
-
-/* should be defined in each interrupt controller driver */
-extern unsigned int get_irq(struct pt_regs *regs);
-
#include <asm-generic/hardirq.h>
-
-#endif /* _ASM_MICROBLAZE_HARDIRQ_H */
diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h
new file mode 100644
index 000000000000..2446a73140ac
--- /dev/null
+++ b/arch/microblaze/include/asm/highmem.h
@@ -0,0 +1,96 @@
+/*
+ * highmem.h: virtual kernel memory mappings for high memory
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ * Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ */
+#ifndef _ASM_HIGHMEM_H
+#define _ASM_HIGHMEM_H
+
+#ifdef __KERNEL__
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/fixmap.h>
+
+extern pte_t *kmap_pte;
+extern pgprot_t kmap_prot;
+extern pte_t *pkmap_page_table;
+
+/*
+ * Right now we initialize only a single pte table. It can be extended
+ * easily, subsequent pte tables have to be allocated in one physical
+ * chunk of RAM.
+ */
+/*
+ * We use one full pte table with 4K pages. And with 16K/64K/256K pages pte
+ * table covers enough memory (32MB/512MB/2GB resp.), so that both FIXMAP
+ * and PKMAP can be placed in a single pte table. We use 512 pages for PKMAP
+ * in case of 16K/64K/256K page sizes.
+ */
+
+#define PKMAP_ORDER PTE_SHIFT
+#define LAST_PKMAP (1 << PKMAP_ORDER)
+
+#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
+ & PMD_MASK)
+
+#define LAST_PKMAP_MASK (LAST_PKMAP - 1)
+#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+
+extern void *kmap_high(struct page *page);
+extern void kunmap_high(struct page *page);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
+
+static inline void *kmap(struct page *page)
+{
+ might_sleep();
+ if (!PageHighMem(page))
+ return page_address(page);
+ return kmap_high(page);
+}
+
+static inline void kunmap(struct page *page)
+{
+ BUG_ON(in_interrupt());
+ if (!PageHighMem(page))
+ return;
+ kunmap_high(page);
+}
+
+static inline void *__kmap_atomic(struct page *page)
+{
+ return kmap_atomic_prot(page, kmap_prot);
+}
+
+static inline struct page *kmap_atomic_to_page(void *ptr)
+{
+ unsigned long idx, vaddr = (unsigned long) ptr;
+ pte_t *pte;
+
+ if (vaddr < FIXADDR_START)
+ return virt_to_page(ptr);
+
+ idx = virt_to_fix(vaddr);
+ pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+ return pte_page(*pte);
+}
+
+#define flush_cache_kmaps() { flush_icache(); flush_dcache(); }
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_HIGHMEM_H */
diff --git a/arch/microblaze/include/asm/irq.h b/arch/microblaze/include/asm/irq.h
index a175132e4496..bab3b1393ad4 100644
--- a/arch/microblaze/include/asm/irq.h
+++ b/arch/microblaze/include/asm/irq.h
@@ -9,49 +9,13 @@
#ifndef _ASM_MICROBLAZE_IRQ_H
#define _ASM_MICROBLAZE_IRQ_H
-
-/*
- * Linux IRQ# is currently offset by one to map to the hardware
- * irq number. So hardware IRQ0 maps to Linux irq 1.
- */
-#define NO_IRQ_OFFSET 1
-#define IRQ_OFFSET NO_IRQ_OFFSET
-#define NR_IRQS (32 + IRQ_OFFSET)
+#define NR_IRQS (32 + 1)
#include <asm-generic/irq.h>
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-extern unsigned int nr_irq;
-
struct pt_regs;
extern void do_IRQ(struct pt_regs *regs);
-/** FIXME - not implement
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
- return;
-}
-
-struct irq_host;
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_host *host,
- irq_hw_number_t hwirq);
+/* should be defined in each interrupt controller driver */
+extern unsigned int get_irq(void);
#endif /* _ASM_MICROBLAZE_IRQ_H */
diff --git a/arch/microblaze/include/asm/mmu.h b/arch/microblaze/include/asm/mmu.h
index 8d6a654ceffb..1f9edddf7f4b 100644
--- a/arch/microblaze/include/asm/mmu.h
+++ b/arch/microblaze/include/asm/mmu.h
@@ -56,6 +56,12 @@ typedef struct _SEGREG {
extern void _tlbie(unsigned long va); /* invalidate a TLB entry */
extern void _tlbia(void); /* invalidate all TLB entries */
+
+/*
+ * tlb_skip size stores actual number skipped TLBs from TLB0 - every directy TLB
+ * mapping has to increase tlb_skip size.
+ */
+extern u32 tlb_skip;
# endif /* __ASSEMBLY__ */
/*
@@ -69,6 +75,12 @@ extern void _tlbia(void); /* invalidate all TLB entries */
# define MICROBLAZE_TLB_SIZE 64
+/* For cases when you want to skip some TLB entries */
+# define MICROBLAZE_TLB_SKIP 0
+
+/* Use the last TLB for temporary access to LMB */
+# define MICROBLAZE_LMB_TLB_ID 63
+
/*
* TLB entries are defined by a "high" tag portion and a "low" data
* portion. The data portion is 32-bits.
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index a25e6b5e2ad4..287c5485d286 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -135,8 +135,10 @@ extern unsigned long min_low_pfn;
extern unsigned long max_pfn;
extern unsigned long memory_start;
-extern unsigned long memory_end;
extern unsigned long memory_size;
+extern unsigned long lowmem_size;
+
+extern unsigned long kernel_tlb;
extern int page_is_ram(unsigned long pfn);
diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
index e9834b2991d0..cb5d39794800 100644
--- a/arch/microblaze/include/asm/pci-bridge.h
+++ b/arch/microblaze/include/asm/pci-bridge.h
@@ -10,7 +10,6 @@
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/ioport.h>
-#include <asm-generic/pci-bridge.h>
struct device_node;
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 033137628e8a..a0da88bf70c5 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -94,14 +94,6 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-extern void pcibios_resource_to_bus(struct pci_dev *dev,
- struct pci_bus_region *region,
- struct resource *res);
-
-extern void pcibios_bus_to_resource(struct pci_dev *dev,
- struct resource *res,
- struct pci_bus_region *region);
-
static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
struct resource *res)
{
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index b2af42311a12..3ef7b9cafeca 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -94,8 +94,7 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/* Start and end of the vmalloc area. */
/* Make sure to map the vmalloc area above the pinned kernel memory area
of 32Mb. */
-#define VMALLOC_START (CONFIG_KERNEL_START + \
- max(32 * 1024 * 1024UL, memory_size))
+#define VMALLOC_START (CONFIG_KERNEL_START + CONFIG_LOWMEM_SIZE)
#define VMALLOC_END ioremap_bot
#endif /* __ASSEMBLY__ */
@@ -543,8 +542,6 @@ extern unsigned long iopa(unsigned long addr);
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
#define kern_addr_valid(addr) (1)
-#define io_remap_page_range remap_page_range
-
/*
* No page table caches to initialise
*/
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index 7283bfb2f7e4..510a8e1c16ba 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -125,7 +125,6 @@ struct thread_struct {
.pgdir = swapper_pg_dir, \
}
-
/* Free all resources held by a thread. */
extern inline void release_thread(struct task_struct *dead_task)
{
@@ -144,6 +143,8 @@ static inline void exit_thread(void)
unsigned long get_wchan(struct task_struct *p);
+extern void ret_from_fork(void);
+
/* The size allocated for kernel stacks. This _must_ be a power of two! */
# define KERNEL_STACK_SIZE 0x2000
@@ -166,6 +167,14 @@ unsigned long get_wchan(struct task_struct *p);
# define STACK_TOP TASK_SIZE
# define STACK_TOP_MAX STACK_TOP
+void disable_hlt(void);
+void enable_hlt(void);
+void default_idle(void);
+
+#ifdef CONFIG_DEBUG_FS
+extern struct dentry *of_debugfs_root;
+#endif
+
# endif /* __ASSEMBLY__ */
# endif /* CONFIG_MMU */
#endif /* _ASM_MICROBLAZE_PROCESSOR_H */
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 6c72ed7eba98..0061aa13a340 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -20,6 +20,8 @@ extern unsigned int boot_cpuid; /* move to smp.h */
extern char cmd_line[COMMAND_LINE_SIZE];
+extern char *klimit;
+
void early_printk(const char *fmt, ...);
int setup_early_printk(char *opt);
@@ -39,13 +41,18 @@ extern void of_platform_reset_gpio_probe(void);
void time_init(void);
void init_IRQ(void);
void machine_early_init(const char *cmdline, unsigned int ram,
- unsigned int fdt, unsigned int msr);
+ unsigned int fdt, unsigned int msr, unsigned int tlb0,
+ unsigned int tlb1);
void machine_restart(char *cmd);
void machine_shutdown(void);
void machine_halt(void);
void machine_power_off(void);
+void free_init_pages(char *what, unsigned long begin, unsigned long end);
+extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
+extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+
# endif/* __KERNEL__ */
# endif /* __ASSEMBLY__ */
#endif /* _ASM_MICROBLAZE_SETUP_H */
diff --git a/arch/microblaze/include/asm/switch_to.h b/arch/microblaze/include/asm/switch_to.h
new file mode 100644
index 000000000000..f45baa2c5e09
--- /dev/null
+++ b/arch/microblaze/include/asm/switch_to.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006 Atmark Techno, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_MICROBLAZE_SWITCH_TO_H
+#define _ASM_MICROBLAZE_SWITCH_TO_H
+
+struct task_struct;
+struct thread_info;
+
+extern struct task_struct *_switch_to(struct thread_info *prev,
+ struct thread_info *next);
+
+#define switch_to(prev, next, last) \
+ do { \
+ (last) = _switch_to(task_thread_info(prev), \
+ task_thread_info(next)); \
+ } while (0)
+
+#endif /* _ASM_MICROBLAZE_SWITCH_TO_H */
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
deleted file mode 100644
index 5a433cbaafb3..000000000000
--- a/arch/microblaze/include/asm/system.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_SYSTEM_H
-#define _ASM_MICROBLAZE_SYSTEM_H
-
-#include <asm/registers.h>
-#include <asm/setup.h>
-#include <asm/irqflags.h>
-#include <asm/cache.h>
-
-#include <asm-generic/cmpxchg.h>
-#include <asm-generic/cmpxchg-local.h>
-
-struct task_struct;
-struct thread_info;
-
-extern struct task_struct *_switch_to(struct thread_info *prev,
- struct thread_info *next);
-
-#define switch_to(prev, next, last) \
- do { \
- (last) = _switch_to(task_thread_info(prev), \
- task_thread_info(next)); \
- } while (0)
-
-#define smp_read_barrier_depends() do {} while (0)
-#define read_barrier_depends() do {} while (0)
-
-#define nop() asm volatile ("nop")
-#define mb() barrier()
-#define rmb() mb()
-#define wmb() mb()
-#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define set_wmb(var, value) do { var = value; wmb(); } while (0)
-
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() wmb()
-
-void __bad_xchg(volatile void *ptr, int size);
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
- int size)
-{
- unsigned long ret;
- unsigned long flags;
-
- switch (size) {
- case 1:
- local_irq_save(flags);
- ret = *(volatile unsigned char *)ptr;
- *(volatile unsigned char *)ptr = x;
- local_irq_restore(flags);
- break;
-
- case 4:
- local_irq_save(flags);
- ret = *(volatile unsigned long *)ptr;
- *(volatile unsigned long *)ptr = x;
- local_irq_restore(flags);
- break;
- default:
- __bad_xchg(ptr, size), ret = 0;
- break;
- }
-
- return ret;
-}
-
-void disable_hlt(void);
-void enable_hlt(void);
-void default_idle(void);
-
-#define xchg(ptr, x) \
- ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-void free_init_pages(char *what, unsigned long begin, unsigned long end);
-void free_initmem(void);
-extern char *klimit;
-extern void ret_from_fork(void);
-
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
-extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
-
-#ifdef CONFIG_DEBUG_FS
-extern struct dentry *of_debugfs_root;
-#endif
-
-#define arch_align_stack(x) (x)
-
-#endif /* _ASM_MICROBLAZE_SYSTEM_H */
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 072b0077abf9..ef25f7538d4a 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -80,7 +80,7 @@ extern unsigned long search_exception_table(unsigned long);
static inline int ___range_ok(unsigned long addr, unsigned long size)
{
return ((addr < memory_start) ||
- ((addr + size) > memory_end));
+ ((addr + size - 1) > (memory_start + memory_size - 1)));
}
#define __range_ok(addr, size) \
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index 54194b28574a..eab6abf5652e 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -35,6 +35,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"8.00.b", 0x13},
{"8.10.a", 0x14},
{"8.20.a", 0x15},
+ {"8.20.b", 0x16},
+ {"8.30.a", 0x17},
{NULL, 0},
};
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
index 488c1ed24e38..3a749d5e71fd 100644
--- a/arch/microblaze/kernel/cpu/pvr.c
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/compiler.h>
-#include <asm/system.h>
#include <asm/exceptions.h>
#include <asm/pvr.h>
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 8356e47631c4..ec485876d0d0 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -171,10 +171,24 @@ void __init remap_early_printk(void)
{
if (!early_console_initialized || !early_console)
return;
- printk(KERN_INFO "early_printk_console remaping from 0x%x to ",
+ printk(KERN_INFO "early_printk_console remapping from 0x%x to ",
base_addr);
base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
printk(KERN_CONT "0x%x\n", base_addr);
+
+ /*
+ * Early console is on the top of skipped TLB entries
+ * decrease tlb_skip size ensure that hardcoded TLB entry will be
+ * used by generic algorithm
+ * FIXME check if early console mapping is on the top by rereading
+ * TLB entry and compare baseaddr
+ * mts rtlbx, (tlb_skip - 1)
+ * nop
+ * mfs rX, rtlblo
+ * nop
+ * cmp rX, orig_base_addr
+ */
+ tlb_skip -= 1;
}
void __init disable_early_printk(void)
diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S
index 77320b8fc16a..98b17f9f904b 100644
--- a/arch/microblaze/kernel/head.S
+++ b/arch/microblaze/kernel/head.S
@@ -63,9 +63,7 @@ ENTRY(_start)
real_start:
#endif
- mfs r1, rmsr
- andi r1, r1, ~2
- mts rmsr, r1
+ mts rmsr, r0
/*
* According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
* if the msrclr instruction is not enabled. We use this to detect
@@ -73,6 +71,7 @@ real_start:
* r8 == 0 - msr instructions are implemented
* r8 != 0 - msr instructions are not implemented
*/
+ mfs r1, rmsr
msrclr r8, 0 /* clear nothing - just read msr for test */
cmpu r8, r8, r1 /* r1 must contain msr reg content */
@@ -96,7 +95,7 @@ big_endian:
_prepare_copy_fdt:
or r11, r0, r0 /* incremment */
ori r4, r0, TOPHYS(_fdt_start)
- ori r3, r0, (0x4000 - 4)
+ ori r3, r0, (0x8000 - 4)
_copy_fdt:
lw r12, r7, r11 /* r12 = r7 + r11 */
sw r12, r4, r11 /* addr[r4 + r11] = r12 */
@@ -150,6 +149,7 @@ _copy_bram:
_invalidate:
mts rtlbx, r3
mts rtlbhi, r0 /* flush: ensure V is clear */
+ mts rtlblo, r0
bgtid r3, _invalidate /* loop for all entries */
addik r3, r3, -1
/* sync */
@@ -169,6 +169,53 @@ _invalidate:
addik r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
tophys(r4,r3) /* Load the kernel physical address */
+ /* start to do TLB calculation */
+ addik r12, r0, _end
+ rsub r12, r3, r12
+ addik r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
+
+ or r9, r0, r0 /* TLB0 = 0 */
+ or r10, r0, r0 /* TLB1 = 0 */
+
+ addik r11, r12, -0x1000000
+ bgei r11, GT16 /* size is greater than 16MB */
+ addik r11, r12, -0x0800000
+ bgei r11, GT8 /* size is greater than 8MB */
+ addik r11, r12, -0x0400000
+ bgei r11, GT4 /* size is greater than 4MB */
+ /* size is less than 4MB */
+ addik r11, r12, -0x0200000
+ bgei r11, GT2 /* size is greater than 2MB */
+ addik r9, r0, 0x0100000 /* TLB0 must be 1MB */
+ addik r11, r12, -0x0100000
+ bgei r11, GT1 /* size is greater than 1MB */
+ /* TLB1 is 0 which is setup above */
+ bri tlb_end
+GT4: /* r11 contains the rest - will be either 1 or 4 */
+ ori r9, r0, 0x400000 /* TLB0 is 4MB */
+ bri TLB1
+GT16: /* TLB0 is 16MB */
+ addik r9, r0, 0x1000000 /* means TLB0 is 16MB */
+TLB1:
+ /* must be used r2 because of substract if failed */
+ addik r2, r11, -0x0400000
+ bgei r2, GT20 /* size is greater than 16MB */
+ /* size is >16MB and <20MB */
+ addik r11, r11, -0x0100000
+ bgei r11, GT17 /* size is greater than 17MB */
+ /* kernel is >16MB and < 17MB */
+GT1:
+ addik r10, r0, 0x0100000 /* means TLB1 is 1MB */
+ bri tlb_end
+GT2: /* TLB0 is 0 and TLB1 will be 4MB */
+GT17: /* TLB1 is 4MB - kernel size <20MB */
+ addik r10, r0, 0x0400000 /* means TLB1 is 4MB */
+ bri tlb_end
+GT8: /* TLB0 is still zero that's why I can use only TLB1 */
+GT20: /* TLB1 is 16MB - kernel size >20MB */
+ addik r10, r0, 0x1000000 /* means TLB1 is 16MB */
+tlb_end:
+
/*
* Configure and load two entries into TLB slots 0 and 1.
* In case we are pinning TLBs, these are reserved in by the
@@ -178,28 +225,81 @@ _invalidate:
andi r4,r4,0xfffffc00 /* Mask off the real page number */
ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
+ /*
+ * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
+ * if is use TLB1 value and clear it (r10 stores TLB1 value)
+ */
+ bnei r9, tlb0_not_zero
+ add r9, r10, r0
+ add r10, r0, r0
+tlb0_not_zero:
+
+ /* look at the code below */
+ ori r30, r0, 0x200
+ andi r29, r9, 0x100000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+ andi r29, r9, 0x400000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+ andi r29, r9, 0x1000000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+1:
andi r3,r3,0xfffffc00 /* Mask off the effective page number */
- ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+ ori r3,r3,(TLB_VALID)
+ or r3, r3, r30
- mts rtlbx,r0 /* TLB slow 0 */
+ /* Load tlb_skip size value which is index to first unused TLB entry */
+ lwi r11, r0, TOPHYS(tlb_skip)
+ mts rtlbx,r11 /* TLB slow 0 */
mts rtlblo,r4 /* Load the data portion of the entry */
mts rtlbhi,r3 /* Load the tag portion of the entry */
- addik r4, r4, 0x01000000 /* Map next 16 M entries */
- addik r3, r3, 0x01000000
+ /* Increase tlb_skip size */
+ addik r11, r11, 1
+ swi r11, r0, TOPHYS(tlb_skip)
+
+ /* TLB1 can be zeroes that's why we not setup it */
+ beqi r10, jump_over2
+
+ /* look at the code below */
+ ori r30, r0, 0x200
+ andi r29, r10, 0x100000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+ andi r29, r10, 0x400000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+ andi r29, r10, 0x1000000
+ bneid r29, 1f
+ addik r30, r30, 0x80
+1:
+ addk r4, r4, r9 /* previous addr + TLB0 size */
+ addk r3, r3, r9
- ori r6,r0,1 /* TLB slot 1 */
- mts rtlbx,r6
+ andi r3,r3,0xfffffc00 /* Mask off the effective page number */
+ ori r3,r3,(TLB_VALID)
+ or r3, r3, r30
+
+ lwi r11, r0, TOPHYS(tlb_skip)
+ mts rtlbx, r11 /* r11 is used from TLB0 */
mts rtlblo,r4 /* Load the data portion of the entry */
mts rtlbhi,r3 /* Load the tag portion of the entry */
+ /* Increase tlb_skip size */
+ addik r11, r11, 1
+ swi r11, r0, TOPHYS(tlb_skip)
+
+jump_over2:
/*
* Load a TLB entry for LMB, since we need access to
* the exception vectors, using a 4k real==virtual mapping.
*/
- ori r6,r0,3 /* TLB slot 3 */
+ /* Use temporary TLB_ID for LMB - clear this temporary mapping later */
+ ori r6, r0, MICROBLAZE_LMB_TLB_ID
mts rtlbx,r6
ori r4,r0,(TLB_WR | TLB_EX)
@@ -238,8 +338,8 @@ start_here:
* Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
* the function.
*/
- addik r9, r0, machine_early_init
- brald r15, r9
+ addik r11, r0, machine_early_init
+ brald r15, r11
nop
#ifndef CONFIG_MMU
@@ -268,8 +368,7 @@ start_here:
/* Load up the kernel context */
kernel_load_context:
- # Keep entry 0 and 1 valid. Entry 3 mapped to LMB can go away.
- ori r5,r0,3
+ ori r5, r0, MICROBLAZE_LMB_TLB_ID
mts rtlbx,r5
nop
mts rtlbhi,r0
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index e62be8379604..aa510f450ac6 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -820,19 +820,26 @@ ex_handler_done:
* Upon exit, we reload everything and RFI.
* A common place to load the TLB.
*/
+.section .data
+.align 4
+.global tlb_skip
+ tlb_skip:
+ .long MICROBLAZE_TLB_SKIP
tlb_index:
- .long 1 /* MS: storing last used tlb index */
+ /* MS: storing last used tlb index */
+ .long MICROBLAZE_TLB_SIZE/2
+.previous
finish_tlb_load:
/* MS: load the last used TLB index. */
lwi r5, r0, TOPHYS(tlb_index)
addik r5, r5, 1 /* MS: inc tlb_index -> use next one */
/* MS: FIXME this is potential fault, because this is mask not count */
- andi r5, r5, (MICROBLAZE_TLB_SIZE-1)
+ andi r5, r5, MICROBLAZE_TLB_SIZE - 1
ori r6, r0, 1
cmp r31, r5, r6
blti r31, ex12
- addik r5, r6, 1
+ lwi r5, r0, TOPHYS(tlb_skip)
ex12:
/* MS: save back current TLB index */
swi r5, r0, TOPHYS(tlb_index)
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
index 44b177e2ab12..6c54d4dcdec3 100644
--- a/arch/microblaze/kernel/intc.c
+++ b/arch/microblaze/kernel/intc.c
@@ -9,6 +9,7 @@
*/
#include <linux/init.h>
+#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <asm/page.h>
#include <linux/io.h>
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
#define INTC_BASE intc_baseaddr
#endif
-unsigned int nr_irq;
-
/* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */
#define IPR 0x04 /* Interrupt Pending Register */
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
.irq_mask_ack = intc_mask_ack,
};
-unsigned int get_irq(struct pt_regs *regs)
+static struct irq_domain *root_domain;
+
+unsigned int get_irq(void)
{
- int irq;
+ unsigned int hwirq, irq = -1;
- /*
- * NOTE: This function is the one that needs to be improved in
- * order to handle multiple interrupt controllers. It currently
- * is hardcoded to check for interrupts only on the first INTC.
- */
- irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
- pr_debug("get_irq: %d\n", irq);
+ hwirq = in_be32(INTC_BASE + IVR);
+ if (hwirq != -1U)
+ irq = irq_find_mapping(root_domain, hwirq);
+
+ pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
return irq;
}
+int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+ u32 intr_mask = (u32)d->host_data;
+
+ if (intr_mask & (1 << hw)) {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_edge_irq, "edge");
+ irq_clear_status_flags(irq, IRQ_LEVEL);
+ } else {
+ irq_set_chip_and_handler_name(irq, &intc_dev,
+ handle_level_irq, "level");
+ irq_set_status_flags(irq, IRQ_LEVEL);
+ }
+ return 0;
+}
+
+static const struct irq_domain_ops xintc_irq_domain_ops = {
+ .xlate = irq_domain_xlate_onetwocell,
+ .map = xintc_map,
+};
+
void __init init_IRQ(void)
{
- u32 i, intr_mask;
+ u32 nr_irq, intr_mask;
struct device_node *intc = NULL;
#ifdef CONFIG_SELFMOD_INTC
unsigned int intc_baseaddr = 0;
@@ -131,8 +151,8 @@ void __init init_IRQ(void)
#ifdef CONFIG_SELFMOD_INTC
selfmod_function((int *) arr_func, intc_baseaddr);
#endif
- printk(KERN_INFO "XPS intc #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
- intc_baseaddr, nr_irq, intr_mask);
+ printk(KERN_INFO "%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
+ intc->name, intc_baseaddr, nr_irq, intr_mask);
/*
* Disable all external interrupts until they are
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
/* Turn on the Master Enable. */
out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
- for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
- if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
- irq_set_chip_and_handler_name(i, &intc_dev,
- handle_edge_irq, "edge");
- irq_clear_status_flags(i, IRQ_LEVEL);
- } else {
- irq_set_chip_and_handler_name(i, &intc_dev,
- handle_level_irq, "level");
- irq_set_status_flags(i, IRQ_LEVEL);
- }
- irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
- }
+ /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
+ * lazy and Michal can clean it up to something nicer when he tests
+ * and commits this patch. ~~gcl */
+ root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
+ (void *)intr_mask);
}
diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
index bbebcae72c02..ace700afbfdf 100644
--- a/arch/microblaze/kernel/irq.c
+++ b/arch/microblaze/kernel/irq.c
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
trace_hardirqs_off();
irq_enter();
- irq = get_irq(regs);
+ irq = get_irq();
next_irq:
BUG_ON(!irq);
- /* Substract 1 because of get_irq */
- generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
+ generic_handle_irq(irq);
- irq = get_irq(regs);
- if (irq) {
+ irq = get_irq();
+ if (irq != -1U) {
pr_debug("next irq: %d\n", irq);
++concurrent_irq;
goto next_irq;
@@ -48,18 +47,3 @@ next_irq:
set_irq_regs(old_regs);
trace_hardirqs_on();
}
-
-/* MS: There is no any advance mapping mechanism. We are using simple 32bit
- intc without any cascades or any connection that's why mapping is 1:1 */
-unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
-{
- return hwirq + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
- const u32 *intspec, unsigned int intsize)
-{
- return intspec[0] + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
index 49faeb429599..bb4907c828dc 100644
--- a/arch/microblaze/kernel/microblaze_ksyms.c
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -18,7 +18,6 @@
#include <asm/cacheflush.h>
#include <linux/io.h>
#include <asm/page.h>
-#include <asm/system.h>
#include <linux/ftrace.h>
#include <linux/uaccess.h>
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
index 206da3da361f..1dafddeb8a0b 100644
--- a/arch/microblaze/kernel/misc.S
+++ b/arch/microblaze/kernel/misc.S
@@ -29,16 +29,16 @@
.type _tlbia, @function
.align 4;
_tlbia:
- addik r12, r0, MICROBLAZE_TLB_SIZE - 1 /* flush all entries (63 - 3) */
+ lwi r12, r0, tlb_skip;
/* isync */
_tlbia_1:
mts rtlbx, r12
nop
mts rtlbhi, r0 /* flush: ensure V is clear */
nop
- addik r11, r12, -2
+ rsubi r11, r12, MICROBLAZE_TLB_SIZE - 1
bneid r11, _tlbia_1 /* loop for all entries */
- addik r12, r12, -1
+ addik r12, r12, 1
/* sync */
rtsd r15, 8
nop
@@ -75,7 +75,7 @@ early_console_reg_tlb_alloc:
* Load a TLB entry for the UART, so that microblaze_progress() can use
* the UARTs nice and early. We use a 4k real==virtual mapping.
*/
- ori r4, r0, MICROBLAZE_TLB_SIZE - 1
+ lwi r4, r0, tlb_skip
mts rtlbx, r4 /* TLB slot 63 */
or r4,r5,r0
@@ -89,6 +89,11 @@ early_console_reg_tlb_alloc:
nop
mts rtlbhi,r5 /* Load the tag portion of the entry */
nop
+
+ lwi r5, r0, tlb_skip
+ addik r5, r5, 1
+ swi r5, r0, tlb_skip
+
rtsd r15, 8
nop
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 7dcb5bfffb75..883b92789cdf 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -13,7 +13,6 @@
#include <linux/pm.h>
#include <linux/tick.h>
#include <linux/bitops.h>
-#include <asm/system.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h> /* for USER_DS macros */
#include <asm/cacheflush.h>
@@ -110,9 +109,7 @@ void cpu_idle(void)
rcu_idle_exit();
tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
+ schedule_preempt_disabled();
check_pgt_cache();
}
}
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index 80d314e81901..4a764ccb9f26 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -36,7 +36,6 @@
#include <asm/processor.h>
#include <asm/irq.h>
#include <linux/io.h>
-#include <asm/system.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 604cd9dd1333..71af974aa24a 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -30,7 +30,6 @@
#include <asm/entry.h>
#include <asm/cpuinfo.h>
-#include <asm/system.h>
#include <asm/prom.h>
#include <asm/pgtable.h>
@@ -51,8 +50,6 @@ void __init setup_arch(char **cmdline_p)
unflatten_device_tree();
- /* NOTE I think that this function is not necessary to call */
- /* irq_early_init(); */
setup_cpuinfo();
microblaze_cache_init();
@@ -97,8 +94,11 @@ inline unsigned get_romfs_len(unsigned *addr)
}
#endif /* CONFIG_MTD_UCLINUX_EBSS */
+unsigned long kernel_tlb;
+
void __init machine_early_init(const char *cmdline, unsigned int ram,
- unsigned int fdt, unsigned int msr)
+ unsigned int fdt, unsigned int msr, unsigned int tlb0,
+ unsigned int tlb1)
{
unsigned long *src, *dst;
unsigned int offset = 0;
@@ -145,6 +145,12 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
setup_early_printk(NULL);
#endif
+ /* setup kernel_tlb after BSS cleaning
+ * Maybe worth to move to asm code */
+ kernel_tlb = tlb0 + tlb1;
+ /* printk("TLB1 0x%08x, TLB0 0x%08x, tlb 0x%x\n", tlb0,
+ tlb1, kernel_tlb); */
+
printk("Ramdisk addr 0x%08x, ", ram);
if (fdt)
printk("FDT at 0x%08x\n", fdt);
@@ -199,6 +205,19 @@ static int microblaze_debugfs_init(void)
return of_debugfs_root == NULL;
}
arch_initcall(microblaze_debugfs_init);
+
+static int __init debugfs_tlb(void)
+{
+ struct dentry *d;
+
+ if (!of_debugfs_root)
+ return -ENODEV;
+
+ d = debugfs_create_u32("tlb_skip", S_IRUGO, of_debugfs_root, &tlb_skip);
+ if (!d)
+ return -ENOMEM;
+}
+device_initcall(debugfs_tlb);
#endif
static int dflt_bus_notify(struct notifier_block *nb,
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index 3cb0bf640135..522defa7d41f 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -27,7 +27,6 @@
#include <asm/setup.h>
#include <asm/prom.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <linux/cnt32_to_63.h>
#ifdef CONFIG_SELFMOD_TIMER
@@ -79,7 +78,7 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)
* !PWMA - disable pwm
* TINT - clear interrupt status
* ENT- enable timer itself
- * EINT - enable interrupt
+ * ENIT - enable interrupt
* !LOAD - clear the bit to let go
* ARHT - auto reload
* !CAPT - no external trigger
@@ -274,8 +273,8 @@ void __init time_init(void)
#ifdef CONFIG_SELFMOD_TIMER
selfmod_function((int *) arr_func, timer_baseaddr);
#endif
- printk(KERN_INFO "XPS timer #0 at 0x%08x, irq=%d\n",
- timer_baseaddr, irq);
+ printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
+ timer->name, timer_baseaddr, irq);
/* If there is clock-frequency property than use it */
prop = of_get_property(timer, "clock-frequency", NULL);
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
index ba034d421ec2..5541ac559593 100644
--- a/arch/microblaze/kernel/traps.c
+++ b/arch/microblaze/kernel/traps.c
@@ -15,7 +15,6 @@
#include <linux/debug_locks.h>
#include <asm/exceptions.h>
-#include <asm/system.h>
#include <asm/unwind.h>
void trap_init(void)
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index ac0e1a5d4782..109e9d86ade4 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -44,7 +44,7 @@ SECTIONS {
__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) {
_fdt_start = . ; /* place for fdt blob */
*(__fdt_blob) ; /* Any link-placed DTB */
- . = _fdt_start + 0x4000; /* Pad up to 16kbyte */
+ . = _fdt_start + 0x8000; /* Pad up to 32kbyte */
_fdt_end = . ;
}
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 52746e718dfa..fe9c53fafdea 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
#include <linux/string.h>
-#include <asm/system.h>
#ifdef __HAVE_ARCH_MEMCPY
#ifndef CONFIG_OPT_LIB_FUNCTION
diff --git a/arch/microblaze/mm/Makefile b/arch/microblaze/mm/Makefile
index 09c49ed87235..7313bd8acbb7 100644
--- a/arch/microblaze/mm/Makefile
+++ b/arch/microblaze/mm/Makefile
@@ -5,3 +5,4 @@
obj-y := consistent.o init.o
obj-$(CONFIG_MMU) += pgtable.o mmu_context.o fault.o
+obj-$(CONFIG_HIGHMEM) += highmem.o
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index ae97d2ccdc22..c38a265846de 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -33,7 +33,6 @@
#include <asm/pgtable.h>
#include <asm/mmu.h>
#include <asm/mmu_context.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <asm/exceptions.h>
diff --git a/arch/microblaze/mm/highmem.c b/arch/microblaze/mm/highmem.c
new file mode 100644
index 000000000000..7d78838e8bfa
--- /dev/null
+++ b/arch/microblaze/mm/highmem.c
@@ -0,0 +1,88 @@
+/*
+ * highmem.c: virtual kernel memory mappings for high memory
+ *
+ * PowerPC version, stolen from the i386 version.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ * Gerhard.Wichert@pdb.siemens.de
+ *
+ *
+ * Redesigned the x86 32-bit VM architecture to deal with
+ * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * we now support up to 64 Gigabytes physical RAM.
+ *
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+ *
+ * Reworked for PowerPC by various contributors. Moved from
+ * highmem.h by Benjamin Herrenschmidt (c) 2009 IBM Corp.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap
+ * gives a more generic (and caching) interface. But kmap_atomic can
+ * be used in IRQ contexts, so in some (very limited) cases we need
+ * it.
+ */
+#include <asm/tlbflush.h>
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
+{
+
+ unsigned long vaddr;
+ int idx, type;
+
+ /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ pagefault_disable();
+ if (!PageHighMem(page))
+ return page_address(page);
+
+
+ type = kmap_atomic_idx_push();
+ idx = type + KM_TYPE_NR*smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+#ifdef CONFIG_DEBUG_HIGHMEM
+ BUG_ON(!pte_none(*(kmap_pte-idx)));
+#endif
+ set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+ local_flush_tlb_page(NULL, vaddr);
+
+ return (void *) vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void __kunmap_atomic(void *kvaddr)
+{
+ unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+ int type;
+
+ if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
+ pagefault_enable();
+ return;
+ }
+
+ type = kmap_atomic_idx();
+#ifdef CONFIG_DEBUG_HIGHMEM
+ {
+ unsigned int idx;
+
+ idx = type + KM_TYPE_NR * smp_processor_id();
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+ /*
+ * force other mappings to Oops if they'll try to access
+ * this pte without first remap it
+ */
+ pte_clear(&init_mm, vaddr, kmap_pte-idx);
+ local_flush_tlb_page(NULL, vaddr);
+ }
+#endif
+ kmap_atomic_idx_pop();
+ pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 565d193c7ebf..ce80823051ba 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -24,6 +24,7 @@
#include <asm/pgalloc.h>
#include <asm/sections.h>
#include <asm/tlb.h>
+#include <asm/fixmap.h>
/* Use for MMU and noMMU because of PCI generic code */
int mem_init_done;
@@ -44,9 +45,56 @@ char *klimit = _end;
*/
unsigned long memory_start;
EXPORT_SYMBOL(memory_start);
-unsigned long memory_end; /* due to mm/nommu.c */
unsigned long memory_size;
EXPORT_SYMBOL(memory_size);
+unsigned long lowmem_size;
+
+#ifdef CONFIG_HIGHMEM
+pte_t *kmap_pte;
+EXPORT_SYMBOL(kmap_pte);
+pgprot_t kmap_prot;
+EXPORT_SYMBOL(kmap_prot);
+
+static inline pte_t *virt_to_kpte(unsigned long vaddr)
+{
+ return pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr),
+ vaddr), vaddr);
+}
+
+static void __init highmem_init(void)
+{
+ pr_debug("%x\n", (u32)PKMAP_BASE);
+ map_page(PKMAP_BASE, 0, 0); /* XXX gross */
+ pkmap_page_table = virt_to_kpte(PKMAP_BASE);
+
+ kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
+ kmap_prot = PAGE_KERNEL;
+}
+
+static unsigned long highmem_setup(void)
+{
+ unsigned long pfn;
+ unsigned long reservedpages = 0;
+
+ for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
+ struct page *page = pfn_to_page(pfn);
+
+ /* FIXME not sure about */
+ if (memblock_is_reserved(pfn << PAGE_SHIFT))
+ continue;
+ ClearPageReserved(page);
+ init_page_count(page);
+ __free_page(page);
+ totalhigh_pages++;
+ reservedpages++;
+ }
+ totalram_pages += totalhigh_pages;
+ printk(KERN_INFO "High memory: %luk\n",
+ totalhigh_pages << (PAGE_SHIFT-10));
+
+ return reservedpages;
+}
+#endif /* CONFIG_HIGHMEM */
/*
* paging_init() sets up the page tables - in fact we've already done this.
@@ -54,17 +102,28 @@ EXPORT_SYMBOL(memory_size);
static void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES];
+#ifdef CONFIG_MMU
+ int idx;
+
+ /* Setup fixmaps */
+ for (idx = 0; idx < __end_of_fixed_addresses; idx++)
+ clear_fixmap(idx);
+#endif
/* Clean every zones */
memset(zones_size, 0, sizeof(zones_size));
- /*
- * old: we can DMA to/from any address.put all page into ZONE_DMA
- * We use only ZONE_NORMAL
- */
- zones_size[ZONE_NORMAL] = max_mapnr;
+#ifdef CONFIG_HIGHMEM
+ highmem_init();
- free_area_init(zones_size);
+ zones_size[ZONE_DMA] = max_low_pfn;
+ zones_size[ZONE_HIGHMEM] = max_pfn;
+#else
+ zones_size[ZONE_DMA] = max_pfn;
+#endif
+
+ /* We don't have holes in memory map */
+ free_area_init_nodes(zones_size);
}
void __init setup_memory(void)
@@ -78,32 +137,31 @@ void __init setup_memory(void)
/* Find main memory where is the kernel */
for_each_memblock(memory, reg) {
memory_start = (u32)reg->base;
- memory_end = (u32) reg->base + reg->size;
+ lowmem_size = reg->size;
if ((memory_start <= (u32)_text) &&
- ((u32)_text <= memory_end)) {
- memory_size = memory_end - memory_start;
+ ((u32)_text <= (memory_start + lowmem_size - 1))) {
+ memory_size = lowmem_size;
PAGE_OFFSET = memory_start;
- printk(KERN_INFO "%s: Main mem: 0x%x-0x%x, "
+ printk(KERN_INFO "%s: Main mem: 0x%x, "
"size 0x%08x\n", __func__, (u32) memory_start,
- (u32) memory_end, (u32) memory_size);
+ (u32) memory_size);
break;
}
}
- if (!memory_start || !memory_end) {
- panic("%s: Missing memory setting 0x%08x-0x%08x\n",
- __func__, (u32) memory_start, (u32) memory_end);
+ if (!memory_start || !memory_size) {
+ panic("%s: Missing memory setting 0x%08x, size=0x%08x\n",
+ __func__, (u32) memory_start, (u32) memory_size);
}
/* reservation of region where is the kernel */
kernel_align_start = PAGE_DOWN((u32)_text);
/* ALIGN can be remove because _end in vmlinux.lds.S is align */
kernel_align_size = PAGE_UP((u32)klimit) - kernel_align_start;
- memblock_reserve(kernel_align_start, kernel_align_size);
- printk(KERN_INFO "%s: kernel addr=0x%08x-0x%08x size=0x%08x\n",
+ printk(KERN_INFO "%s: kernel addr:0x%08x-0x%08x size=0x%08x\n",
__func__, kernel_align_start, kernel_align_start
+ kernel_align_size, kernel_align_size);
-
+ memblock_reserve(kernel_align_start, kernel_align_size);
#endif
/*
* Kernel:
@@ -120,11 +178,13 @@ void __init setup_memory(void)
min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
/* RAM is assumed contiguous */
num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
- max_pfn = max_low_pfn = memory_end >> PAGE_SHIFT;
+ max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
+ max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
printk(KERN_INFO "%s: max_mapnr: %#lx\n", __func__, max_mapnr);
printk(KERN_INFO "%s: min_low_pfn: %#lx\n", __func__, min_low_pfn);
printk(KERN_INFO "%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
+ printk(KERN_INFO "%s: max_pfn: %#lx\n", __func__, max_pfn);
/*
* Find an area to use for the bootmem bitmap.
@@ -137,15 +197,39 @@ void __init setup_memory(void)
PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
+ /* Add active regions with valid PFNs */
+ for_each_memblock(memory, reg) {
+ unsigned long start_pfn, end_pfn;
+
+ start_pfn = memblock_region_memory_base_pfn(reg);
+ end_pfn = memblock_region_memory_end_pfn(reg);
+ memblock_set_node(start_pfn << PAGE_SHIFT,
+ (end_pfn - start_pfn) << PAGE_SHIFT, 0);
+ }
+
/* free bootmem is whole main memory */
- free_bootmem(memory_start, memory_size);
+ free_bootmem_with_active_regions(0, max_low_pfn);
/* reserve allocate blocks */
for_each_memblock(reserved, reg) {
- pr_debug("reserved - 0x%08x-0x%08x\n",
- (u32) reg->base, (u32) reg->size);
- reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+ unsigned long top = reg->base + reg->size - 1;
+
+ pr_debug("reserved - 0x%08x-0x%08x, %lx, %lx\n",
+ (u32) reg->base, (u32) reg->size, top,
+ memory_start + lowmem_size - 1);
+
+ if (top <= (memory_start + lowmem_size - 1)) {
+ reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+ } else if (reg->base < (memory_start + lowmem_size - 1)) {
+ unsigned long trunc_size = memory_start + lowmem_size -
+ reg->base;
+ reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
+ }
}
+
+ /* XXX need to clip this if using highmem? */
+ sparse_memory_present_with_active_regions(0);
+
#ifdef CONFIG_MMU
init_bootmem_done = 1;
#endif
@@ -190,13 +274,58 @@ void free_initmem(void)
void __init mem_init(void)
{
- high_memory = (void *)__va(memory_end);
+ pg_data_t *pgdat;
+ unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
+
+ high_memory = (void *)__va(memory_start + lowmem_size - 1);
+
/* this will put all memory onto the freelists */
totalram_pages += free_all_bootmem();
- printk(KERN_INFO "Memory: %luk/%luk available\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10));
+ for_each_online_pgdat(pgdat) {
+ unsigned long i;
+ struct page *page;
+
+ for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ if (!pfn_valid(pgdat->node_start_pfn + i))
+ continue;
+ page = pgdat_page_nr(pgdat, i);
+ if (PageReserved(page))
+ reservedpages++;
+ }
+ }
+
+#ifdef CONFIG_HIGHMEM
+ reservedpages -= highmem_setup();
+#endif
+
+ codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
+ datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
+ initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
+ bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
+
+ pr_info("Memory: %luk/%luk available (%luk kernel code, "
+ "%luk reserved, %luk data, %luk bss, %luk init)\n",
+ nr_free_pages() << (PAGE_SHIFT-10),
+ num_physpages << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ bsssize >> 10,
+ initsize >> 10);
+
+#ifdef CONFIG_MMU
+ pr_info("Kernel virtual memory layout:\n");
+ pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP);
+#ifdef CONFIG_HIGHMEM
+ pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n",
+ PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
+#endif /* CONFIG_HIGHMEM */
+ pr_info(" * 0x%08lx..0x%08lx : early ioremap\n",
+ ioremap_bot, ioremap_base);
+ pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n",
+ (unsigned long)VMALLOC_START, VMALLOC_END);
+#endif
mem_init_done = 1;
}
@@ -226,7 +355,6 @@ static void mm_cmdline_setup(void)
maxmem = memparse(p, &p);
if (maxmem && memory_size > maxmem) {
memory_size = maxmem;
- memory_end = memory_start + memory_size;
memblock.memory.regions[0].size = memory_size;
}
}
@@ -270,15 +398,26 @@ asmlinkage void __init mmu_init(void)
machine_restart(NULL);
}
- if ((u32) memblock.memory.regions[0].size < 0x1000000) {
- printk(KERN_EMERG "Memory must be greater than 16MB\n");
+ if ((u32) memblock.memory.regions[0].size < 0x400000) {
+ printk(KERN_EMERG "Memory must be greater than 4MB\n");
+ machine_restart(NULL);
+ }
+
+ if ((u32) memblock.memory.regions[0].size < kernel_tlb) {
+ printk(KERN_EMERG "Kernel size is greater than memory node\n");
machine_restart(NULL);
}
+
/* Find main memory where the kernel is */
memory_start = (u32) memblock.memory.regions[0].base;
- memory_end = (u32) memblock.memory.regions[0].base +
- (u32) memblock.memory.regions[0].size;
- memory_size = memory_end - memory_start;
+ lowmem_size = memory_size = (u32) memblock.memory.regions[0].size;
+
+ if (lowmem_size > CONFIG_LOWMEM_SIZE) {
+ lowmem_size = CONFIG_LOWMEM_SIZE;
+#ifndef CONFIG_HIGHMEM
+ memory_size = lowmem_size;
+#endif
+ }
mm_cmdline_setup(); /* FIXME parse args from command line - not used */
@@ -305,15 +444,20 @@ asmlinkage void __init mmu_init(void)
/* Map in all of RAM starting at CONFIG_KERNEL_START */
mapin_ram();
-#ifdef CONFIG_HIGHMEM_START_BOOL
- ioremap_base = CONFIG_HIGHMEM_START;
+ /* Extend vmalloc and ioremap area as big as possible */
+#ifdef CONFIG_HIGHMEM
+ ioremap_base = ioremap_bot = PKMAP_BASE;
#else
- ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */
-#endif /* CONFIG_HIGHMEM_START_BOOL */
- ioremap_bot = ioremap_base;
+ ioremap_base = ioremap_bot = FIXADDR_START;
+#endif
/* Initialize the context management stuff */
mmu_context_init();
+
+ /* Shortly after that, the entire linear mapping will be available */
+ /* This will also cause that unflatten device tree will be allocated
+ * inside 768MB limit */
+ memblock_set_current_limit(memory_start + lowmem_size - 1);
}
/* This is only called until mem_init is done. */
@@ -324,11 +468,11 @@ void __init *early_get_page(void)
p = alloc_bootmem_pages(PAGE_SIZE);
} else {
/*
- * Mem start + 32MB -> here is limit
+ * Mem start + kernel_tlb -> here is limit
* because of mem mapping from head.S
*/
p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
- memory_start + 0x2000000));
+ memory_start + kernel_tlb));
}
return p;
}
diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c
index 59bf2335a4ce..d1c06d07fed8 100644
--- a/arch/microblaze/mm/pgtable.c
+++ b/arch/microblaze/mm/pgtable.c
@@ -37,6 +37,7 @@
#include <linux/io.h>
#include <asm/mmu.h>
#include <asm/sections.h>
+#include <asm/fixmap.h>
#define flush_HPTE(X, va, pg) _tlbie(va)
@@ -44,11 +45,6 @@ unsigned long ioremap_base;
unsigned long ioremap_bot;
EXPORT_SYMBOL(ioremap_bot);
-/* The maximum lowmem defaults to 768Mb, but this can be configured to
- * another value.
- */
-#define MAX_LOW_MEM CONFIG_LOWMEM_SIZE
-
#ifndef CONFIG_SMP
struct pgtable_cache_struct quicklists;
#endif
@@ -80,7 +76,7 @@ static void __iomem *__ioremap(phys_addr_t addr, unsigned long size,
!(p >= virt_to_phys((unsigned long)&__bss_stop) &&
p < virt_to_phys((unsigned long)__bss_stop))) {
printk(KERN_WARNING "__ioremap(): phys addr "PTE_FMT
- " is RAM lr %p\n", (unsigned long)p,
+ " is RAM lr %pf\n", (unsigned long)p,
__builtin_return_address(0));
return NULL;
}
@@ -171,7 +167,7 @@ void __init mapin_ram(void)
v = CONFIG_KERNEL_START;
p = memory_start;
- for (s = 0; s < memory_size; s += PAGE_SIZE) {
+ for (s = 0; s < lowmem_size; s += PAGE_SIZE) {
f = _PAGE_PRESENT | _PAGE_ACCESSED |
_PAGE_SHARED | _PAGE_HWEXEC;
if ((char *) v < _stext || (char *) v >= _etext)
@@ -254,3 +250,13 @@ __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
}
return pte;
}
+
+void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
+{
+ unsigned long address = __fix_to_virt(idx);
+
+ if (idx >= __end_of_fixed_addresses)
+ BUG();
+
+ map_page(address, phys, pgprot_val(flags));
+}
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 85f2ac1230a8..d10403dadd2b 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -46,9 +46,6 @@ static int global_phb_number; /* Global phb counter */
/* ISA Memory physical address */
resource_size_t isa_mem_base;
-/* Default PCI flags is 0 on ppc32, modified at boot on ppc64 */
-unsigned int pci_flags;
-
static struct dma_map_ops *pci_dma_ops = &dma_direct_ops;
unsigned long isa_io_base;
@@ -833,64 +830,7 @@ int pci_proc_domain(struct pci_bus *bus)
{
struct pci_controller *hose = pci_bus_to_host(bus);
- if (!(pci_flags & PCI_ENABLE_PROC_DOMAINS))
- return 0;
- if (pci_flags & PCI_COMPAT_DOMAIN_0)
- return hose->global_number != 0;
- return 1;
-}
-
-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- region->start = (res->start - offset) & mask;
- region->end = (res->end - offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_resource_to_bus);
-
-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
-{
- resource_size_t offset = 0, mask = (resource_size_t)-1;
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
-
- if (!hose)
- return;
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
- res->start = (region->start + offset) & mask;
- res->end = (region->end + offset) & mask;
-}
-EXPORT_SYMBOL(pcibios_bus_to_resource);
-
-/* Fixup a bus resource into a linux resource */
-static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- resource_size_t offset = 0, mask = (resource_size_t)-1;
-
- if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
- mask = 0xffffffffu;
- } else if (res->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-
- res->start = (res->start + offset) & mask;
- res->end = (res->end + offset) & mask;
+ return 0;
}
/* This header fixup will do the resource fixup for all devices as they are
@@ -910,13 +850,7 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
struct resource *res = dev->resource + i;
if (!res->flags)
continue;
- /* On platforms that have PCI_PROBE_ONLY set, we don't
- * consider 0 as an unassigned BAR value. It's technically
- * a valid value, but linux doesn't like it... so when we can
- * re-assign things, we do so, but if we can't, we keep it
- * around and hope for the best...
- */
- if (res->start == 0 && !(pci_flags & PCI_PROBE_ONLY)) {
+ if (res->start == 0) {
pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]" \
"is unassigned\n",
pci_name(dev), i,
@@ -929,18 +863,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
continue;
}
- pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n",
+ pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n",
pci_name(dev), i,
(unsigned long long)res->start,\
(unsigned long long)res->end,
(unsigned int)res->flags);
-
- fixup_resource(res, dev);
-
- pr_debug("PCI:%s %016llx-%016llx\n",
- pci_name(dev),
- (unsigned long long)res->start,
- (unsigned long long)res->end);
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
@@ -959,10 +886,6 @@ static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
u16 command;
int i;
- /* We don't do anything if PCI_PROBE_ONLY is set */
- if (pci_flags & PCI_PROBE_ONLY)
- return 0;
-
/* Job is a bit different between memory and IO */
if (res->flags & IORESOURCE_MEM) {
/* If the BAR is non-0 (res != pci_mem_offset) then it's
@@ -1037,9 +960,6 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
(unsigned long long)res->end,
(unsigned int)res->flags);
- /* Perform fixup */
- fixup_resource(res, dev);
-
/* Try to detect uninitialized P2P bridge resources,
* and clear them out so they get re-assigned later
*/
@@ -1107,9 +1027,6 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
static int skip_isa_ioresource_align(struct pci_dev *dev)
{
- if ((pci_flags & PCI_CAN_SKIP_ISA_ALIGN) &&
- !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
- return 1;
return 0;
}
@@ -1236,8 +1153,6 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
* and as such ensure proper re-allocation
* later.
*/
- if (pci_flags & PCI_REASSIGN_ALL_RSRC)
- goto clear_resource;
pr = pci_find_parent_resource(bus->self, res);
if (pr == res) {
/* this happens when the generic PCI
@@ -1422,27 +1337,19 @@ void __init pcibios_resource_survey(void)
list_for_each_entry(b, &pci_root_buses, node)
pcibios_allocate_bus_resources(b);
- if (!(pci_flags & PCI_REASSIGN_ALL_RSRC)) {
- pcibios_allocate_resources(0);
- pcibios_allocate_resources(1);
- }
+ pcibios_allocate_resources(0);
+ pcibios_allocate_resources(1);
/* Before we start assigning unassigned resource, we try to reserve
* the low IO area and the VGA memory area if they intersect the
* bus available resources to avoid allocating things on top of them
*/
- if (!(pci_flags & PCI_PROBE_ONLY)) {
- list_for_each_entry(b, &pci_root_buses, node)
- pcibios_reserve_legacy_regions(b);
- }
+ list_for_each_entry(b, &pci_root_buses, node)
+ pcibios_reserve_legacy_regions(b);
- /* Now, if the platform didn't decide to blindly trust the firmware,
- * we proceed to assigning things that were left unassigned
- */
- if (!(pci_flags & PCI_PROBE_ONLY)) {
- pr_debug("PCI: Assigning unassigned resources...\n");
- pci_assign_unassigned_resources();
- }
+ /* Now proceed to assigning things that were left unassigned */
+ pr_debug("PCI: Assigning unassigned resources...\n");
+ pci_assign_unassigned_resources();
}
#ifdef CONFIG_HOTPLUG
@@ -1535,7 +1442,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
res->end = res->start + IO_SPACE_LIMIT;
res->flags = IORESOURCE_IO;
}
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, hose->io_base_virt - _IO_BASE);
pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
(unsigned long long)res->start,
@@ -1558,7 +1465,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
res->flags = IORESOURCE_MEM;
}
- pci_add_resource(resources, res);
+ pci_add_resource_offset(resources, res, hose->pci_mem_offset);
pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n",
i, (unsigned long long)res->start,