[U-Boot] [PATCH 1/3] Introduce addr_map library

Add a library that helps in translating between virtual and physical addresses. This library can be useful as a simple means to implement map_physmem() and virt_to_phys() for platforms that need functionality beyond the simple 1:1 mapping.
Signed-off-by: Kumar Gala galak@kernel.crashing.org --- include/addr_map.h | 29 +++++++++++++++++ lib_generic/Makefile | 1 + lib_generic/addr_map.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 0 deletions(-) create mode 100644 include/addr_map.h create mode 100644 lib_generic/addr_map.c
diff --git a/include/addr_map.h b/include/addr_map.h new file mode 100644 index 0000000..c87c3a8 --- /dev/null +++ b/include/addr_map.h @@ -0,0 +1,29 @@ +#ifndef __ADDR_MAP_H +#define __ADDR_MAP_H + +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <asm/types.h> + +extern phys_addr_t addrmap_virt_to_phys(unsigned int vaddr); +extern unsigned int addrmap_phys_to_virt(phys_addr_t paddr); +extern void addrmap_set_entry(unsigned int vaddr, phys_addr_t paddr, + unsigned int size, int idx); + +#endif diff --git a/lib_generic/Makefile b/lib_generic/Makefile index d62c39b..3f04022 100644 --- a/lib_generic/Makefile +++ b/lib_generic/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)libgeneric.a
+COBJS-$(CONFIG_ADDR_MAP) += addr_map.o COBJS-y += bzlib.o COBJS-y += bzlib_crctable.o COBJS-y += bzlib_decompress.o diff --git a/lib_generic/addr_map.c b/lib_generic/addr_map.c new file mode 100644 index 0000000..9f6596a --- /dev/null +++ b/lib_generic/addr_map.c @@ -0,0 +1,81 @@ +/* + * Copyright 2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * Version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <addr_map.h> + +static struct { + phys_addr_t paddr; + unsigned int vaddr; + unsigned int size; +} address_map[CONFIG_SYS_NUM_ADDR_MAP]; + +phys_addr_t addrmap_virt_to_phys(unsigned int vaddr) +{ + int i; + + for (i = 0; i < CONFIG_SYS_NUM_ADDR_MAP; i++) { + u64 base, upper, addr; + + if (address_map[i].size == 0) + continue; + + addr = (u64)vaddr; + base = (u64)(address_map[i].vaddr); + upper = (u64)(address_map[i].size) + base; + + if (addr >= base && addr < upper) { + return vaddr - address_map[i].vaddr + address_map[i].paddr; + } + } + + return (phys_addr_t)(~0); +} + +unsigned int addrmap_phys_to_virt(phys_addr_t paddr) +{ + int i; + + for (i = 0; i < CONFIG_SYS_NUM_ADDR_MAP; i++) { + u64 base, upper, addr; + + if (address_map[i].size == 0) + continue; + + addr = (u64)paddr; + base = (u64)(address_map[i].paddr); + upper = (u64)(address_map[i].size) + base; + + if (addr >= base && addr < upper) { + return paddr - address_map[i].paddr + address_map[i].paddr; + } + } + + return (unsigned int)(~0); +} + +void addrmap_set_entry(unsigned int vaddr, phys_addr_t paddr, + unsigned int size, int idx) +{ + if (idx > CONFIG_SYS_NUM_ADDR_MAP) + return ; + + address_map[idx].vaddr = vaddr; + address_map[idx].paddr = paddr; + address_map[idx].size = size; +}

Signed-off-by: Kumar Gala galak@kernel.crashing.org --- cpu/mpc85xx/tlb.c | 34 ++++++++++++++++++++++++++++++++++ include/asm-ppc/mmu.h | 3 +++ lib_ppc/board.c | 8 ++++++++ 3 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/cpu/mpc85xx/tlb.c b/cpu/mpc85xx/tlb.c index a2d16ae..f80d8b2 100644 --- a/cpu/mpc85xx/tlb.c +++ b/cpu/mpc85xx/tlb.c @@ -26,6 +26,11 @@ #include <common.h> #include <asm/processor.h> #include <asm/mmu.h> +#ifdef CONFIG_ADDR_MAP +#include <addr_map.h> +#endif + +DECLARE_GLOBAL_DATA_PTR;
void set_tlb(u8 tlb, u32 epn, u64 rpn, u8 perms, u8 wimge, @@ -47,6 +52,11 @@ void set_tlb(u8 tlb, u32 epn, u64 rpn, mtspr(MAS7, _mas7); #endif asm volatile("isync;msync;tlbwe;isync"); + +#ifdef CONFIG_ADDR_MAP + if ((tlb == 1) && (gd->flags & GD_FLG_RELOC)) + addrmap_set_entry(epn, rpn, (1 << ((tsize * 2) + 10)), esel); +#endif }
void disable_tlb(u8 esel) @@ -67,6 +77,11 @@ void disable_tlb(u8 esel) mtspr(MAS7, _mas7); #endif asm volatile("isync;msync;tlbwe;isync"); + +#ifdef CONFIG_ADDR_MAP + if (gd->flags & GD_FLG_RELOC) + addrmap_set_entry(0, 0, 0, esel); +#endif }
void invalidate_tlb(u8 tlb) @@ -91,6 +106,25 @@ void init_tlbs(void) return ; }
+#ifdef CONFIG_ADDR_MAP +void init_addr_map(void) +{ + int i; + + for (i = 0; i < num_tlb_entries; i++) { + if (tlb_table[i].tlb == 0) + continue; + + addrmap_set_entry(tlb_table[i].epn, + tlb_table[i].rpn, + (1 << ((tlb_table[i].tsize * 2) + 10)), + tlb_table[i].esel); + } + + return ; +} +#endif + unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) { unsigned int tlb_size; diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h index 8975e6c..6d942d0 100644 --- a/include/asm-ppc/mmu.h +++ b/include/asm-ppc/mmu.h @@ -431,6 +431,9 @@ extern void set_tlb(u8 tlb, u32 epn, u64 rpn, extern void disable_tlb(u8 esel); extern void invalidate_tlb(u8 tlb); extern void init_tlbs(void); +#ifdef CONFIG_ADDR_MAP +extern void init_addr_map(void); +#endif extern unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg);
#define SET_TLB_ENTRY(_tlb, _epn, _rpn, _perms, _wimge, _ts, _esel, _sz, _iprot) \ diff --git a/lib_ppc/board.c b/lib_ppc/board.c index 289a32a..61c29b5 100644 --- a/lib_ppc/board.c +++ b/lib_ppc/board.c @@ -75,6 +75,10 @@ #include <keyboard.h> #endif
+#ifdef CONFIG_ADDR_MAP +#include <asm/mmu.h> +#endif + #ifdef CONFIG_SYS_UPDATE_FLASH_SIZE extern int update_flash_size (int flash_size); #endif @@ -694,6 +698,10 @@ void board_init_r (gd_t *id, ulong dest_addr) */ trap_init (dest_addr);
+#if defined(CONFIG_ADDR_MAP) && defined(CONFIG_E500) + init_addr_map(); +#endif + #if defined(CONFIG_BOARD_EARLY_INIT_R) board_early_init_r (); #endif

If we have addr map support enabled use the mapping functions to implement virt_to_phys() and map_physmem().
Signed-off-by: Kumar Gala galak@kernel.crashing.org --- include/asm-ppc/io.h | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index c00de45..57ff32c 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -10,6 +10,10 @@ #include <linux/config.h> #include <asm/byteorder.h>
+#ifdef CONFIG_ADDR_MAP +#include <addr_map.h> +#endif + #define SIO_CONFIG_RA 0x398 #define SIO_CONFIG_RD 0x399
@@ -287,7 +291,11 @@ extern inline void out_be32(volatile unsigned __iomem *addr, int val) static inline void * map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) { +#ifdef CONFIG_ADDR_MAP + return (void *)(addrmap_phys_to_virt(paddr)); +#else return (void *)((unsigned long)paddr); +#endif }
/* @@ -300,7 +308,11 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)
static inline phys_addr_t virt_to_phys(void * vaddr) { +#ifdef CONFIG_ADDR_MAP + return addrmap_phys_to_virt((unsigned int)vaddr); +#else return (phys_addr_t)(vaddr); +#endif }
#endif

On Mon, Nov 24, 2008 at 10:47:40AM -0600, Kumar Gala wrote:
@@ -287,7 +291,11 @@ extern inline void out_be32(volatile unsigned __iomem *addr, int val) static inline void * map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) { +#ifdef CONFIG_ADDR_MAP
- return (void *)(addrmap_phys_to_virt(paddr));
+#else return (void *)((unsigned long)paddr); +#endif }
/* @@ -300,7 +308,11 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)
static inline phys_addr_t virt_to_phys(void * vaddr) { +#ifdef CONFIG_ADDR_MAP
- return addrmap_phys_to_virt((unsigned int)vaddr);
+#else return (phys_addr_t)(vaddr); +#endif }
Shouldn't phys_to_virt return, and virt_to_phys accept, a virtual address without needing the caller to cast?
Also, don't treat virtual addresses as "unsigned int". Use unsigned long or uintptr_t.
-Scott

On Mon, Nov 24, 2008 at 10:47:38AM -0600, Kumar Gala wrote:
+static struct {
- phys_addr_t paddr;
- unsigned int vaddr;
- unsigned int size;
vaddr/size should be unsigned long (or uintptr_t/size_t).
+phys_addr_t addrmap_virt_to_phys(unsigned int vaddr) +{
- int i;
- for (i = 0; i < CONFIG_SYS_NUM_ADDR_MAP; i++) {
u64 base, upper, addr;
if (address_map[i].size == 0)
continue;
addr = (u64)vaddr;
base = (u64)(address_map[i].vaddr);
upper = (u64)(address_map[i].size) + base;
if (addr >= base && addr < upper) {
return vaddr - address_map[i].vaddr + address_map[i].paddr;
}
upper should be base + size - 1, and addr <= upper. Otherwise, this will fail for a mapping at the end of a 64-bit address space.
+void addrmap_set_entry(unsigned int vaddr, phys_addr_t paddr,
unsigned int size, int idx)
+{
- if (idx > CONFIG_SYS_NUM_ADDR_MAP)
return ;
No space before ;
-Scott
participants (2)
-
Kumar Gala
-
Scott Wood