lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 23 Jan 2018 17:47:06 -0800
From:   Florian Fainelli <f.fainelli@...il.com>
To:     linux-mips@...ux-mips.org
Cc:     Florian Fainelli <florian.fainelli@...adcom.com>,
        Ralf Baechle <ralf@...ux-mips.org>,
        Kevin Cernekee <cernekee@...il.com>,
        Florian Fainelli <f.fainelli@...il.com>,
        James Hogan <jhogan@...nel.org>,
        Paul Burton <paul.burton@...s.com>,
        Matt Redfearn <matt.redfearn@...s.com>,
        "Maciej W. Rozycki" <macro@...s.com>,
        Huacai Chen <chenhc@...ote.com>,
        Kate Stewart <kstewart@...uxfoundation.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Marcin Nowakowski <marcin.nowakowski@...s.com>,
        Andrew Morton <akpm@...ux-foundation.org>,
        "Eric W. Biederman" <ebiederm@...ssion.com>,
        Ingo Molnar <mingo@...nel.org>,
        David Howells <dhowells@...hat.com>,
        Kees Cook <keescook@...omium.org>,
        Thomas Meyer <thomas@...3r.de>,
        "Bryan O'Donoghue" <pure.logic@...us-software.ie>,
        Robin Murphy <robin.murphy@....com>,
        Michal Hocko <mhocko@...e.com>,
        Lucas Stach <l.stach@...gutronix.de>,
        Vladimir Murzin <vladimir.murzin@....com>,
        Bart Van Assche <bart.vanassche@...disk.com>,
        linux-kernel@...r.kernel.org (open list)
Subject: [PATCH RFC 6/6] MIPS: BMIPS: Add support for eXtended KSEG0/1 (XKS01)

From: Florian Fainelli <florian.fainelli@...adcom.com>

We need to implement a few things in order for XKS01 to work:

- a coherent allocator is needed for some portions of the memory space,
  this is loosely inspired from an old ARM implementation
- we need to obtain how much DRAM we have on our first memory controller
  (MEMC0) which is what govers how big the extended region can be
- a bunch of ioremap and dma-coherent functions need to be re-defined to
  take our special ranges into account

Signed-off-by: Florian Fainelli <florian.fainelli@...adcom.com>
---
 arch/mips/Kconfig                                  |   2 +
 arch/mips/bmips/Makefile                           |   2 +-
 arch/mips/bmips/memory.c                           | 427 +++++++++++++++++++++
 arch/mips/bmips/setup.c                            |  35 ++
 arch/mips/include/asm/addrspace.h                  |   8 +
 arch/mips/include/asm/mach-bmips/dma-coherence.h   |   6 +
 arch/mips/include/asm/mach-bmips/ioremap.h         |  26 +-
 .../include/asm/mach-bmips/kernel-entry-init.h     |  18 +
 arch/mips/include/asm/mach-bmips/spaces.h          | 102 +++++
 9 files changed, 603 insertions(+), 23 deletions(-)
 create mode 100644 arch/mips/bmips/memory.c
 create mode 100644 arch/mips/include/asm/mach-bmips/kernel-entry-init.h

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 659e0079487f..b7c0306c9051 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -234,6 +234,7 @@ config BMIPS_GENERIC
 	select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
 	select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
 	select HARDIRQS_SW_RESEND
+	select FW_CFE
 	help
 	  Build a generic DT-based kernel image that boots on select
 	  BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top
@@ -1690,6 +1691,7 @@ config CPU_BMIPS
 	select CPU_HAS_PREFETCH
 	select CPU_SUPPORTS_CPUFREQ
 	select MIPS_EXTERNAL_TIMER
+	select XKS01
 	help
 	  Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
 
diff --git a/arch/mips/bmips/Makefile b/arch/mips/bmips/Makefile
index a393955cba08..990dc814b7d8 100644
--- a/arch/mips/bmips/Makefile
+++ b/arch/mips/bmips/Makefile
@@ -1 +1 @@
-obj-y		+= setup.o irq.o dma.o
+obj-y		+= setup.o irq.o dma.o memory.o
diff --git a/arch/mips/bmips/memory.c b/arch/mips/bmips/memory.c
new file mode 100644
index 000000000000..847954b8686e
--- /dev/null
+++ b/arch/mips/bmips/memory.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/compiler.h>
+#include <linux/atomic.h>
+#include <linux/printk.h>
+#include <linux/module.h>
+#include <linux/init_task.h>
+
+#include <asm/page.h>
+#include <asm/pgtable-32.h>
+#include <asm/pgtable-bits.h>
+#include <asm/addrspace.h>
+#include <asm/tlbflush.h>
+#include <asm/r4kcache.h>
+
+#include <spaces.h>
+
+/*
+ * Override default behavior to allow cached access to all valid DRAM ranges
+ */
+int __uncached_access(struct file *file, unsigned long addr)
+{
+	if (file->f_flags & O_SYNC)
+		return 1;
+	if (addr >= 0x10000000 && addr < UPPERMEM_START)
+		return 1;
+	if (addr >= 0xa0000000)
+		return 1;
+	return 0;
+}
+
+/***********************************************************************
+ * Wired TLB mappings for upper memory support
+ ***********************************************************************/
+
+#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
+
+/* (PFN << 6) | GLOBAL | VALID | DIRTY | cacheability */
+#define ENTRYLO_CACHED(paddr)	(((paddr) >> 6) | (0x07) | (0x03 << 3))
+#define ENTRYLO_UNCACHED(paddr)	(((paddr) >> 6) | (0x07) | (0x02 << 3))
+
+/* GLOBAL | !VALID */
+#define ENTRYLO_INVALID()	(0x01)
+
+struct tlb_entry {
+	unsigned long entrylo0;
+	unsigned long entrylo1;
+	unsigned long entryhi;
+	unsigned long pagemask;
+};
+
+static struct tlb_entry __maybe_unused uppermem_mappings[] = {
+{
+	.entrylo0		= ENTRYLO_CACHED(TLB_UPPERMEM_PA),
+	.entrylo1		= ENTRYLO_INVALID(),
+	.entryhi		= TLB_UPPERMEM_VA,
+	.pagemask		= PM_256M,
+},
+};
+
+static inline void brcm_write_tlb_entry(int idx, unsigned long entrylo0,
+					unsigned long entrylo1,
+					unsigned long entryhi,
+					unsigned long pagemask)
+{
+	write_c0_entrylo0(entrylo0);
+	write_c0_entrylo1(entrylo1);
+	write_c0_entryhi(entryhi);
+	write_c0_pagemask(pagemask);
+	write_c0_index(idx);
+	mtc0_tlbw_hazard();
+	tlb_write_indexed();
+	tlbw_use_hazard();
+}
+
+/*
+ * This function is used instead of add_wired_entry(), because it does not
+ * have any external dependencies and is not marked __init
+ */
+static inline void brcm_add_wired_entry(unsigned long entrylo0,
+					unsigned long entrylo1,
+					unsigned long entryhi,
+					unsigned long pagemask)
+{
+	int i = read_c0_wired();
+	write_c0_wired(i + 1);
+	brcm_write_tlb_entry(i, entrylo0, entrylo1, entryhi, pagemask);
+}
+
+extern void build_tlb_refill_handler(void);
+extern void tlb_init(void);
+
+void bmips_tlb_init(void)
+{
+	if (!cpu_has_xks01) {
+		tlb_init();
+		return;
+	}
+
+	if (smp_processor_id() == 0) {
+		int i;
+		struct tlb_entry *e = uppermem_mappings;
+
+		tlb_init();
+		for (i = 0; i < ARRAY_SIZE(uppermem_mappings); i++, e++)
+			brcm_add_wired_entry(e->entrylo0, e->entrylo1,
+				e->entryhi, e->pagemask);
+		write_c0_pagemask(PM_DEFAULT_MASK);
+	} else {
+		/* bypass tlb_init() / probe_tlb() for secondary CPU */
+		cpu_data[smp_processor_id()].tlbsize = cpu_data[0].tlbsize;
+		build_tlb_refill_handler();
+	}
+}
+
+/*
+ * Initialize upper memory TLB entries
+ *
+ * On TP1 this must happen before we set up $sp/$gp .  It is always
+ * possible for stacks, task_structs, thread_info's, and other
+ * important structures to be allocated out of upper memory so
+ * this happens early on.
+ */
+asmlinkage void plat_wired_tlb_setup(void)
+{
+	int __maybe_unused i, tlbsz;
+
+	if (!cpu_has_xks01)
+		return;
+
+	/* Flush TLB.  local_flush_tlb_all() is not available yet. */
+	write_c0_entrylo0(0);
+	write_c0_entrylo1(0);
+	write_c0_pagemask(PM_DEFAULT_MASK);
+	write_c0_wired(0);
+
+	tlbsz = (read_c0_config1() >> 25) & 0x3f;
+	for (i = 0; i <= tlbsz; i++) {
+		write_c0_entryhi(UNIQUE_ENTRYHI(i));
+		write_c0_index(i);
+		mtc0_tlbw_hazard();
+		tlb_write_indexed();
+		tlbw_use_hazard();
+	}
+
+	write_c0_wired(0);
+	mtc0_tlbw_hazard();
+
+	for (i = 0; i < ARRAY_SIZE(uppermem_mappings); i++) {
+		struct tlb_entry *e = &uppermem_mappings[i];
+		brcm_add_wired_entry(e->entrylo0, e->entrylo1, e->entryhi,
+			e->pagemask);
+	}
+
+	write_c0_pagemask(PM_DEFAULT_MASK);
+}
+
+/***********************************************************************
+ * Special allocator for coherent (uncached) memory
+ * (Required for >256MB upper memory)
+ ***********************************************************************/
+
+#define CONSISTENT_DMA_SIZE	(CONSISTENT_END - CONSISTENT_BASE)
+#define CONSISTENT_OFFSET(x)	(((unsigned long)(x) - CONSISTENT_BASE) >> \
+	PAGE_SHIFT)
+#define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> \
+	PGDIR_SHIFT)
+#define NUM_CONSISTENT_PTES	(CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
+
+/*
+ * These are the page tables (4MB each) covering uncached, DMA consistent
+ * allocations
+ */
+static pte_t *consistent_pte[NUM_CONSISTENT_PTES];
+static DEFINE_SPINLOCK(consistent_lock);
+
+struct bmips_vm_region {
+	struct list_head	vm_list;
+	unsigned long		vm_start;
+	unsigned long		vm_end;
+	void			*vm_cac_va;
+	int			vm_active;
+};
+
+static struct bmips_vm_region consistent_head = {
+	.vm_list	= LIST_HEAD_INIT(consistent_head.vm_list),
+	.vm_start	= CONSISTENT_BASE,
+	.vm_end		= CONSISTENT_END,
+};
+
+static struct bmips_vm_region *
+bmips_vm_region_alloc(struct bmips_vm_region *head, size_t size, gfp_t gfp)
+{
+	unsigned long addr = head->vm_start, end = head->vm_end - size;
+	unsigned long flags;
+	struct bmips_vm_region *c, *new;
+
+	new = kmalloc(sizeof(struct bmips_vm_region), gfp);
+	if (!new)
+		goto out;
+
+	spin_lock_irqsave(&consistent_lock, flags);
+
+	list_for_each_entry(c, &head->vm_list, vm_list) {
+		if ((addr + size) < addr)
+			goto nospc;
+		if ((addr + size) <= c->vm_start)
+			goto found;
+		addr = c->vm_end;
+		if (addr > end)
+			goto nospc;
+	}
+
+found:
+	/*
+	 * Insert this entry _before_ the one we found.
+	 */
+	list_add_tail(&new->vm_list, &c->vm_list);
+	new->vm_start = addr;
+	new->vm_end = addr + size;
+	new->vm_active = 1;
+
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	return new;
+
+nospc:
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	kfree(new);
+out:
+	return NULL;
+}
+
+static struct bmips_vm_region *bmips_vm_region_find(struct bmips_vm_region *head,
+	unsigned long addr)
+{
+	struct bmips_vm_region *c;
+
+	list_for_each_entry(c, &head->vm_list, vm_list) {
+		if (c->vm_active && c->vm_start == addr)
+			goto out;
+	}
+	c = NULL;
+out:
+	return c;
+}
+
+static int __init consistent_init(void)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	int ret = 0, i = 0;
+	u32 base = CONSISTENT_BASE;
+
+	do {
+		pgd = pgd_offset(&init_mm, base);
+		pud = pud_alloc(&init_mm, pgd, base);
+		if (!pud) {
+			pr_err("%s: no pud tables\n", __func__);
+			ret = -ENOMEM;
+			break;
+		}
+		pmd = pmd_alloc(&init_mm, pud, base);
+		if (!pmd) {
+			pr_err("%s: no pmd tables\n", __func__);
+			ret = -ENOMEM;
+			break;
+		}
+
+		pte = pte_alloc_kernel(pmd, base);
+		if (!pte) {
+			pr_err("%s: no pte tables\n", __func__);
+			ret = -ENOMEM;
+			break;
+		}
+
+		consistent_pte[i++] = pte;
+		base += (1 << PGDIR_SHIFT);
+	} while (base < CONSISTENT_END);
+
+	return ret;
+}
+
+core_initcall(consistent_init);
+
+int plat_map_coherent(dma_addr_t dma_handle, void *cac_va, size_t size,
+		      void **uncac_va, gfp_t gfp)
+{
+	struct bmips_vm_region *c;
+	struct page *page;
+	pte_t *pte;
+	int idx;
+	u32 off;
+
+	c = bmips_vm_region_alloc(&consistent_head, size, gfp);
+	if (!c)
+		return -EINVAL;
+
+	c->vm_cac_va = cac_va;
+
+	page = virt_to_page(cac_va);
+	idx = CONSISTENT_PTE_INDEX(c->vm_start);
+	off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
+	pte = consistent_pte[idx] + off;
+
+	pr_debug("map addr %08lx idx %x off %x pte %p\n",
+		c->vm_start, idx, off, pte);
+
+	do {
+		if (off >= PTRS_PER_PTE) {
+			off = 0;
+			BUG_ON(idx >= NUM_CONSISTENT_PTES - 1);
+			pte = consistent_pte[++idx];
+		}
+
+		BUG_ON(!pte_none(*pte));
+		set_pte(pte, mk_pte(page, PAGE_KERNEL_UNCACHED));
+		page++;
+		pte++;
+		off++;
+	} while (size -= PAGE_SIZE);
+
+	*uncac_va = (void *)c->vm_start;
+	return 0;
+}
+
+void *plat_unmap_coherent(void *vaddr)
+{
+	struct bmips_vm_region *c;
+	unsigned long flags, addr;
+	void *ret = NULL;
+	pte_t *pte;
+	int idx;
+	u32 off;
+
+	spin_lock_irqsave(&consistent_lock, flags);
+	c = bmips_vm_region_find(&consistent_head, (unsigned long)vaddr);
+	if (!c) {
+		spin_unlock_irqrestore(&consistent_lock, flags);
+		pr_err("%s: invalid VA %p\n", __func__, vaddr);
+		return NULL;
+	}
+	c->vm_active = 0;
+	spin_unlock_irqrestore(&consistent_lock, flags);
+
+	ret = c->vm_cac_va;
+	addr = c->vm_start;
+
+	idx = CONSISTENT_PTE_INDEX(addr);
+	off = CONSISTENT_OFFSET(addr) & (PTRS_PER_PTE-1);
+	pte = consistent_pte[idx] + off;
+
+	pr_debug("unmap addr %08lx idx %x off %x pte %p\n",
+		addr, idx, off, pte);
+
+	do {
+		if (off >= PTRS_PER_PTE) {
+			off = 0;
+			BUG_ON(idx >= NUM_CONSISTENT_PTES - 1);
+			pte = consistent_pte[++idx];
+		}
+
+		pte_clear(&init_mm, addr, pte);
+		pte++;
+		off++;
+		addr += PAGE_SIZE;
+	} while (addr < c->vm_end);
+	flush_tlb_kernel_range(c->vm_start, c->vm_end);
+
+	spin_lock_irqsave(&consistent_lock, flags);
+	list_del(&c->vm_list);
+	spin_unlock_irqrestore(&consistent_lock, flags);
+
+	kfree(c);
+
+	return ret;
+}
+
+void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
+	unsigned long flags)
+{
+	/* sanity check */
+	if ((offset + size - 1) < offset ||
+	    !size ||
+	    offset > max(KSEG0_SIZE, KSEG1_SIZE))
+		return NULL;
+
+	/* !XKS01, XKS01: uncached access to EBI/registers @ PA 1000_0000 */
+	if (offset >= 0x10000000 &&
+	    (offset + size) <= 0x20000000 &&
+	    flags == _CACHE_UNCACHED)
+		return (void *)(KSEG1 + offset);
+
+	/* !XKS01, XKS01: easy cached access to some DRAM */
+	if ((offset + size) <= KSEG0_SIZE &&
+	    flags == _CACHE_CACHABLE_NONCOHERENT)
+		return (void *)(KSEG0 + offset);
+
+	/* !XKS01 only: easy uncached access to some DRAM */
+	if ((offset + size) <= KSEG1_SIZE &&
+	    flags == _CACHE_UNCACHED)
+		return (void *)(KSEG1 + offset);
+
+	/* anything else gets mapped using page tables */
+	return NULL;
+}
+EXPORT_SYMBOL(plat_ioremap);
+
+int plat_iounmap(const volatile void __iomem *addr)
+{
+	phys_addr_t va = (unsigned long)addr;
+
+	if (va >= KSEG0 && va < (KSEG0 + KSEG0_SIZE))
+		return 1;
+	if (va >= KSEG1 && va < (KSEG1 + KSEG1_SIZE))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(plat_iounmap);
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
index d1b7b8b82ae1..4f565f2df977 100644
--- a/arch/mips/bmips/setup.c
+++ b/arch/mips/bmips/setup.c
@@ -134,6 +134,39 @@ static unsigned long dram0_size_mb;
 
 extern void bmips_tlb_init(void);
 
+static void bmips_add_memory_regions(void)
+{
+	board_tlb_init = bmips_tlb_init;
+
+	do {
+		unsigned long dram0_mb = dram0_size_mb, mb;
+
+		mb = min(dram0_mb, BRCM_MAX_LOWER_MB);
+		dram0_mb -= mb;
+
+		add_memory_region(0, mb << 20, BOOT_MEM_RAM);
+		if (!dram0_mb)
+			break;
+
+		if (cpu_has_xks01) {
+			mb = min(dram0_mb, BRCM_MAX_UPPER_MB);
+			dram0_mb -= mb;
+
+			plat_wired_tlb_setup();
+			add_memory_region(UPPERMEM_START, mb << 20, BOOT_MEM_RAM);
+			if (!dram0_mb)
+				break;
+		}
+
+#ifdef CONFIG_HIGHMEM
+		add_memory_region(HIGHMEM_START, dram0_mb << 20, BOOT_MEM_RAM);
+		break;
+#endif
+		/* Linux memory */
+		mb = dram0_size_mb - dram0_mb;
+	} while (0);
+}
+
 static char __initdata cfe_buf[COMMAND_LINE_SIZE];
 
 static inline int __init parse_ulong(const char *buf, unsigned long *val)
@@ -230,6 +263,8 @@ void __init plat_mem_setup(void)
 			q->quirk_fn();
 		}
 	}
+
+	bmips_add_memory_regions();
 }
 
 void __init device_tree_init(void)
diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h
index 4856adc8906e..f66e2f90c604 100644
--- a/arch/mips/include/asm/addrspace.h
+++ b/arch/mips/include/asm/addrspace.h
@@ -96,13 +96,21 @@
  */
 #define KUSEG			0x00000000
 #define KSEG0			0x80000000
+#ifdef CONFIG_XKS01
+#define KSEG1			plat_kseg1()
+#else
 #define KSEG1			0xa0000000
+#endif
 #define KSEG2			0xc0000000
 #define KSEG3			0xe0000000
 
 #define CKUSEG			0x00000000
 #define CKSEG0			0x80000000
+#ifdef CONFIG_XKS01
+#define CKSEG1			plat_kseg1()
+#else
 #define CKSEG1			0xa0000000
+#endif
 #define CKSEG2			0xc0000000
 #define CKSEG3			0xe0000000
 
diff --git a/arch/mips/include/asm/mach-bmips/dma-coherence.h b/arch/mips/include/asm/mach-bmips/dma-coherence.h
index b56380066573..9fbb6355fd8d 100644
--- a/arch/mips/include/asm/mach-bmips/dma-coherence.h
+++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
@@ -37,6 +37,12 @@ static inline int plat_device_is_coherent(struct device *dev)
 
 #define plat_post_dma_flush	bmips_post_dma_flush
 
+#define plat_map_coherent	plat_map_coherent
+extern int plat_map_coherent(dma_addr_t handle, void *cac_va, size_t size,
+			     void **uncac_va, gfp_t gfp);
+#define plat_unmap_coherent	plat_unmap_coherent
+extern void *plat_unmap_coherent(void *addr);
+
 #include <asm/mach-generic/dma-coherence.h>
 
 #endif /* __ASM_MACH_BMIPS_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/mach-bmips/ioremap.h b/arch/mips/include/asm/mach-bmips/ioremap.h
index 52632ebc705f..e3333d1e52c6 100644
--- a/arch/mips/include/asm/mach-bmips/ioremap.h
+++ b/arch/mips/include/asm/mach-bmips/ioremap.h
@@ -9,26 +9,8 @@ static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t
 	return phys_addr;
 }
 
-static inline int is_bmips_internal_registers(phys_addr_t offset)
-{
-	if (offset >= 0xfff80000)
-		return 1;
-
-	return 0;
-}
-
-static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
-					 unsigned long flags)
-{
-	if (is_bmips_internal_registers(offset))
-		return (void __iomem *)offset;
-
-	return NULL;
-}
-
-static inline int plat_iounmap(const volatile void __iomem *addr)
-{
-	return is_bmips_internal_registers((unsigned long)addr);
-}
+extern void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
+		        unsigned long flags);
+extern int plat_iounmap(const volatile void __iomem *addr);
 
-#endif /* __ASM_MACH_BMIPS_IOREMAP_H */
+#endif /* __ASM_MACH_BMIPS_GENERIC_IOREMAP_H */
diff --git a/arch/mips/include/asm/mach-bmips/kernel-entry-init.h b/arch/mips/include/asm/mach-bmips/kernel-entry-init.h
new file mode 100644
index 000000000000..48a6768cd664
--- /dev/null
+++ b/arch/mips/include/asm/mach-bmips/kernel-entry-init.h
@@ -0,0 +1,18 @@
+#ifndef __ASM_MACH_BMIPS_GENERIC_KERNEL_ENTRY_H
+#define __ASM_MACH_BMIPS_GENERIC_KERNEL_ENTRY_H
+
+	.macro kernel_entry_setup
+
+	# save arguments for CFE callback
+	sw      a0, cfe_handle
+	sw      a2, cfe_entry
+	sw      a3, cfe_seal
+
+	jal     bmips_enable_xks01
+
+	.endm
+
+	.macro  smp_slave_setup
+	.endm
+
+#endif /* __ASM_MACH_BMIPS_GENERIC_KERNEL_ENTRY_H */
diff --git a/arch/mips/include/asm/mach-bmips/spaces.h b/arch/mips/include/asm/mach-bmips/spaces.h
index c59b28fd9e1d..439e05a80ac9 100644
--- a/arch/mips/include/asm/mach-bmips/spaces.h
+++ b/arch/mips/include/asm/mach-bmips/spaces.h
@@ -13,6 +13,108 @@
 /* Avoid collisions with system base register (SBR) region on BMIPS3300 */
 #include <asm/bmips-spaces.h>
 
+#include <linux/const.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cpu.h>
+
+/*
+ * 1024MB Broadcom 256+768 virtual address map
+ *
+ * 8000_0000 - 8fff_ffff: 256MB RAM @ 0000_0000, cached
+ * 9000_0000 - 9fff_ffff: 256MB EBI/Registers @ 1000_0000, uncached
+ * a000_0000 - cfff_ffff: 768MB RAM @ 2000_0000, cached
+ * d000_0000 - dfff_ffff: TBD
+ * e000_0000 - ff1f_7fff: vmalloc region
+ * ff1f_8000 - ff1f_ffff: FIXMAP
+ * ff40_0000 - ff7f_ffff: CONSISTENT region
+ *
+ * PA 5000_0000 and above are accessed through HIGHMEM (BMIPS5000 only).
+ */
+#define TLB_UPPERMEM_VA         _AC(0xc0000000, UL)
+#define TLB_UPPERMEM_PA         _AC(0x40000000, UL)
+
+#ifndef __ASSEMBLY__
+static inline unsigned long kseg0_size(void)
+{
+	switch (read_c0_prid() & PRID_IMP_MASK) {
+	case PRID_IMP_BMIPS5000:
+	case PRID_IMP_BMIPS5200:
+		return _AC(0x40000000, UL);
+	default:
+		return _AC(0x20000000, UL);
+	}
+}
+
+static inline unsigned long kseg1_size(void)
+{
+	switch (read_c0_prid() & PRID_IMP_MASK) {
+	case PRID_IMP_BMIPS5000:
+	case PRID_IMP_BMIPS5200:
+		return _AC(0x0, UL);
+	default:
+		return _AC(0x20000000, UL);
+	}
+}
+
+static inline unsigned long map_base(void)
+{
+	switch (read_c0_prid() & PRID_IMP_MASK) {
+	case PRID_IMP_BMIPS5000:
+	case PRID_IMP_BMIPS5200:
+		return _AC(0xe0000000, UL);
+	default:
+		return _AC(0xc0000000, UL);
+	}
+}
+
+static inline unsigned long brcm_max_upper_mb(void)
+{
+	switch (read_c0_prid() & PRID_IMP_MASK) {
+	case PRID_IMP_BMIPS5000:
+	case PRID_IMP_BMIPS5200:
+		return _AC(768, UL);
+	default:
+		return _AC(0, UL);
+	}
+}
+
+static inline unsigned long plat_kseg1(void)
+{
+	switch (read_c0_prid() & PRID_IMP_MASK) {
+	case PRID_IMP_BMIPS5000:
+	case PRID_IMP_BMIPS5200:
+		return 0x80000000;
+	default:
+		return 0xa0000000;
+	}
+}
+
+#define KSEG0_SIZE              kseg0_size()
+#define KSEG1_SIZE		kseg1_size()
+#define MAP_BASE		map_base()
+/* BASE and END must be 4MB-aligned (PGDIR_SIZE) */
+#define CONSISTENT_BASE         _AC(0xff400000, UL)
+#define CONSISTENT_END          _AC(0xff800000, UL)
+#define BRCM_MAX_UPPER_MB       brcm_max_upper_mb()
+#else
+
+#define TLB_UPPERMEM_VA         _AC(0xc0000000, UL)
+#define TLB_UPPERMEM_PA         _AC(0x40000000, UL)
+#define KSEG0_SIZE              _AC(0x40000000, UL)
+#define KSEG1_SIZE              _AC(0x00000000, UL)
+#define MAP_BASE                _AC(0xe0000000, UL)
+/* BASE and END must be 4MB-aligned (PGDIR_SIZE) */
+#define CONSISTENT_BASE         _AC(0xff400000, UL)
+#define CONSISTENT_END          _AC(0xff800000, UL)
+#define BRCM_MAX_UPPER_MB       _AC(768, UL)
+#endif
+
+#define BRCM_MAX_LOWER_MB	_AC(256, UL)
+
+#define UPPERMEM_START		_AC(0x20000000, UL)
+#define HIGHMEM_START		(UPPERMEM_START + (BRCM_MAX_UPPER_MB << 20))
+
 #include <asm/mach-generic/spaces.h>
 
 #endif /* __ASM_BMIPS_SPACES_H */
-- 
2.7.4

Powered by blists - more mailing lists