/* * Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ #include <linux/delay.h>#include <linux/console.h>#include <linux/bootmem.h>#include <linux/seq_file.h>#include <linux/cpu.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/tty.h>#include <linux/pfn.h> #ifdef CONFIG_MTD_UCLINUX#include <linux/mtd/map.h>#include <linux/ext2_fs.h>#include <linux/cramfs_fs.h>#include <linux/romfs_fs.h>#endif #include <asm/cplb.h>#include <asm/cacheflush.h>#include <asm/blackfin.h>#include <asm/cplbinit.h>#include <asm/clocks.h>#include <asm/div64.h>#include <asm/cpu.h>#include <asm/fixed_code.h>#include <asm/early_printk.h>#include <asm/irq_handler.h>#include <asm/pda.h>#ifdef CONFIG_BF60x#include <mach/pm.h>#endif#ifdef CONFIG_SCB_PRIORITY#include <asm/scb.h>#endif u16 _bfin_swrst;EXPORT_SYMBOL(_bfin_swrst); unsigned long memory_start, memory_end, physical_mem_end;unsigned long _rambase, _ramstart, _ramend;unsigned long reserved_mem_dcache_on;unsigned long reserved_mem_icache_on;EXPORT_SYMBOL(memory_start);EXPORT_SYMBOL(memory_end);EXPORT_SYMBOL(physical_mem_end);EXPORT_SYMBOL(_ramend);EXPORT_SYMBOL(reserved_mem_dcache_on); #ifdef CONFIG_MTD_UCLINUXextern struct map_info uclinux_ram_map;unsigned long memory_mtd_end, memory_mtd_start, mtd_size;EXPORT_SYMBOL(memory_mtd_end);EXPORT_SYMBOL(memory_mtd_start);EXPORT_SYMBOL(mtd_size);#endif char __initdata command_line[COMMAND_LINE_SIZE];struct blackfin_initial_pda __initdata initial_pda; /* boot memmap, for parsing "memmap=" */#define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */#define BFIN_MEMMAP_RAM 1#define BFIN_MEMMAP_RESERVED 2static struct bfin_memmap { int nr_map; struct bfin_memmap_entry { unsigned long long addr; /* start of memory segment */ unsigned long long size; unsigned long type; } map[BFIN_MEMMAP_MAX];} bfin_memmap __initdata; /* for memmap sanitization */struct change_member { struct bfin_memmap_entry *pentry; /* pointer to original entry */ unsigned long long addr; /* address for this change point */};static struct change_member change_point_list[2*BFIN_MEMMAP_MAX] __initdata;static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata;static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata;static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata; DEFINE_PER_CPU(struct blackfin_cpudata, cpu_data); static int early_init_clkin_hz(char *buf); #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE)void __init generate_cplb_tables(void){ unsigned int cpu; generate_cplb_tables_all(); /* Generate per-CPU I&D CPLB tables */ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) generate_cplb_tables_cpu(cpu);}#endif void bfin_setup_caches(unsigned int cpu){#ifdef CONFIG_BFIN_ICACHE bfin_icache_init(icplb_tbl[cpu]);#endif #ifdef CONFIG_BFIN_DCACHE bfin_dcache_init(dcplb_tbl[cpu]);#endif bfin_setup_cpudata(cpu); /* * In cache coherence emulation mode, we need to have the * D-cache enabled before running any atomic operation which * might involve cache invalidation (i.e. spinlock, rwlock). * So printk's are deferred until then. */#ifdef CONFIG_BFIN_ICACHE printk(KERN_INFO "Instruction Cache Enabled for CPU%u\n", cpu); printk(KERN_INFO " External memory:"# ifdef CONFIG_BFIN_EXTMEM_ICACHEABLE " cacheable"# else " uncacheable"# endif " in instruction cache\n"); if (L2_LENGTH) printk(KERN_INFO " L2 SRAM :"# ifdef CONFIG_BFIN_L2_ICACHEABLE " cacheable"# else " uncacheable"# endif " in instruction cache\n"); #else printk(KERN_INFO "Instruction Cache Disabled for CPU%u\n", cpu);#endif #ifdef CONFIG_BFIN_DCACHE printk(KERN_INFO "Data Cache Enabled for CPU%u\n", cpu); printk(KERN_INFO " External memory:"# if defined CONFIG_BFIN_EXTMEM_WRITEBACK " cacheable (write-back)"# elif defined CONFIG_BFIN_EXTMEM_WRITETHROUGH " cacheable (write-through)"# else " uncacheable"# endif " in data cache\n"); if (L2_LENGTH) printk(KERN_INFO " L2 SRAM :"# if defined CONFIG_BFIN_L2_WRITEBACK " cacheable (write-back)"# elif defined CONFIG_BFIN_L2_WRITETHROUGH " cacheable (write-through)"# else " uncacheable"# endif " in data cache\n");#else printk(KERN_INFO "Data Cache Disabled for CPU%u\n", cpu);#endif} void bfin_setup_cpudata(unsigned int cpu){ struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu); cpudata->imemctl = bfin_read_IMEM_CONTROL(); cpudata->dmemctl = bfin_read_DMEM_CONTROL();} void __init bfin_cache_init(void){#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) generate_cplb_tables();#endif bfin_setup_caches(0);} void __init bfin_relocate_l1_mem(void){ unsigned long text_l1_len = (unsigned long)_text_l1_len; unsigned long data_l1_len = (unsigned long)_data_l1_len; unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len; unsigned long l2_len = (unsigned long)_l2_len; early_shadow_stamp(); /* * due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S * we know that everything about l1 text/data is nice and aligned, * so copy by 4 byte chunks, and don't worry about overlapping * src/dest. * * We can't use the dma_memcpy functions, since they can call * scheduler functions which might be in L1 :( and core writes * into L1 instruction cause bad access errors, so we are stuck, * we are required to use DMA, but can't use the common dma * functions. We can't use memcpy either - since that might be * going to be in the relocated L1 */ blackfin_dma_early_init(); /* if necessary, copy L1 text to L1 instruction SRAM */ if (L1_CODE_LENGTH && text_l1_len) early_dma_memcpy(_stext_l1, _text_l1_lma, text_l1_len); /* if necessary, copy L1 data to L1 data bank A SRAM */ if (L1_DATA_A_LENGTH && data_l1_len) early_dma_memcpy(_sdata_l1, _data_l1_lma, data_l1_len); /* if necessary, copy L1 data B to L1 data bank B SRAM */ if (L1_DATA_B_LENGTH && data_b_l1_len) early_dma_memcpy(_sdata_b_l1, _data_b_l1_lma, data_b_l1_len); early_dma_memcpy_done(); #if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1) blackfin_iflush_l1_entry[0] = (unsigned long)blackfin_icache_flush_range_l1;#endif /* if necessary, copy L2 text/data to L2 SRAM */ if (L2_LENGTH && l2_len) memcpy(_stext_l2, _l2_lma, l2_len);} #ifdef CONFIG_SMPvoid __init bfin_relocate_coreb_l1_mem(void){ unsigned long text_l1_len = (unsigned long)_text_l1_len; unsigned long data_l1_len = (unsigned long)_data_l1_len; unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len; blackfin_dma_early_init(); /* if necessary, copy L1 text to L1 instruction SRAM */ if (L1_CODE_LENGTH && text_l1_len) early_dma_memcpy((void *)COREB_L1_CODE_START, _text_l1_lma, text_l1_len); /* if necessary, copy L1 data to L1 data bank A SRAM */ if (L1_DATA_A_LENGTH && data_l1_len) early_dma_memcpy((void *)COREB_L1_DATA_A_START, _data_l1_lma, data_l1_len); /* if necessary, copy L1 data B to L1 data bank B SRAM */ if (L1_DATA_B_LENGTH && data_b_l1_len) early_dma_memcpy((void *)COREB_L1_DATA_B_START, _data_b_l1_lma, data_b_l1_len); early_dma_memcpy_done(); #ifdef CONFIG_ICACHE_FLUSH_L1 blackfin_iflush_l1_entry[1] = (unsigned long)blackfin_icache_flush_range_l1 - (unsigned long)_stext_l1 + COREB_L1_CODE_START;#endif}#endif #ifdef CONFIG_ROMKERNELvoid __init bfin_relocate_xip_data(void){ early_shadow_stamp(); memcpy(_sdata, _data_lma, (unsigned long)_data_len - THREAD_SIZE + sizeof(struct thread_info)); memcpy(_sinitdata, _init_data_lma, (unsigned long)_init_data_len);}#endif /* add_memory_region to memmap */static void __init add_memory_region(unsigned long long start, unsigned long long size, int type){ int i; i = bfin_memmap.nr_map; if (i == BFIN_MEMMAP_MAX) { printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); return; } bfin_memmap.map[i].addr = start; bfin_memmap.map[i].size = size; bfin_memmap.map[i].type = type; bfin_memmap.nr_map++;} /* * Sanitize the boot memmap, removing overlaps. */static int __init sanitize_memmap(struct bfin_memmap_entry *map, int *pnr_map){ struct change_member *change_tmp; unsigned long current_type, last_type; unsigned long long last_addr; int chgidx, still_changing; int overlap_entries; int new_entry; int old_nr, new_nr, chg_nr; int i; /* Visually we're performing the following (1,2,3,4 = memory types) Sample memory map (w/overlaps): ____22__________________ ______________________4_ ____1111________________ _44_____________________ 11111111________________ ____________________33__ ___________44___________ __________33333_________ ______________22________ ___________________2222_ _________111111111______ _____________________11_ _________________4______ Sanitized equivalent (no overlap): 1_______________________ _44_____________________ ___1____________________ ____22__________________ ______11________________ _________1______________ __________3_____________ ___________44___________ _____________33_________ _______________2________ ________________1_______ _________________4______ ___________________2____ ____________________33__ ______________________4_ */ /* if there's only one memory region, don't bother */ if (*pnr_map < 2) return -1; old_nr = *pnr_map; /* bail out if we find any unreasonable addresses in memmap */ for (i = 0; i < old_nr; i++) if (map[i].addr + map[i].size < map[i].addr) return -1; /* create pointers for initial change-point information (for sorting) */ for (i = 0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; /* record all known change-points (starting and ending addresses), omitting those that are for empty memory regions */ chgidx = 0; for (i = 0; i < old_nr; i++) { if (map[i].size != 0) { change_point[chgidx]->addr = map[i].addr; change_point[chgidx++]->pentry = &map[i]; change_point[chgidx]->addr = map[i].addr + map[i].size; change_point[chgidx++]->pentry = &map[i]; } } chg_nr = chgidx; /* true number of change-points */ /* sort change-point list by memory addresses (low -> high) */ still_changing = 1; while (still_changing) { still_changing = 0; for (i = 1; i < chg_nr; i++) { /* if <current_addr> > <last_addr>, swap */ /* or, if current=<start_addr> & last=<end_addr>, swap */ if ((change_point[i]->addr < change_point[i-1]->addr) || ((change_point[i]->addr == change_point[i-1]->addr) && (change_point[i]->addr == change_point[i]->pentry->addr) && (change_point[i-1]->addr != change_point[i-1]->pentry->addr)) ) { change_tmp = change_point[i]; change_point[i] = change_point[i-1]; change_point[i-1] = change_tmp; still_changing = 1; } } } /* create a new memmap, removing overlaps */ overlap_entries = 0; /* number of entries in the overlap table */ new_entry = 0; /* index for creating new memmap entries */ last_type = 0; /* start with undefined memory type */ last_addr = 0; /* start with 0 as last starting address */ /* loop through change-points, determining affect on the new memmap */ for (chgidx = 0; chgidx < chg_nr; chgidx++) { /* keep track of all overlapping memmap entries */ if (change_point[chgidx]->addr == change_point[chgidx]->pentry->addr) { /* add map entry to overlap list (> 1 entry implies an overlap) */ overlap_list[overlap_entries++] = change_point[chgidx]->pentry; } else { /* remove entry from list (order independent, so swap with last) */ for (i = 0; i < overlap_entries; i++) { if (overlap_list[i] == change_point[chgidx]->pentry) overlap_list[i] = overlap_list[overlap_entries-1]; } overlap_entries--; } /* if there are overlapping entries, decide which "type" to use */ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ current_type = 0; for (i = 0; i < overlap_entries; i++) if (overlap_list[i]->type > current_type) current_type = overlap_list[i]->type; /* continue building up new memmap based on this information */ if (current_type != last_type) { if (last_type != 0) { new_map[new_entry].size = change_point[chgidx]->addr - last_addr; /* move forward only if the new size was non-zero */ if (new_map[new_entry].size != 0) if (++new_entry >= BFIN_MEMMAP_MAX) break; /* no more space left for new entries */ } if (current_type != 0) { new_map[new_entry].addr = change_point[chgidx]->addr; new_map[new_entry].type = current_type; last_addr = change_point[chgidx]->addr; } last_type = current_type; } } new_nr = new_entry; /* retain count for new entries */ /* copy new mapping into original location */ memcpy(map, new_map, new_nr*sizeof(struct bfin_memmap_entry)); *pnr_map = new_nr; return 0;} static void __init print_memory_map(char *who){ int i; for (i = 0; i < bfin_memmap.nr_map; i++) { printk(KERN_DEBUG " %s: %016Lx - %016Lx ", who, bfin_memmap.map[i].addr, bfin_memmap.map[i].addr + bfin_memmap.map[i].size); switch (bfin_memmap.map[i].type) { case BFIN_MEMMAP_RAM: printk(KERN_CONT "(usable)\n"); break; case BFIN_MEMMAP_RESERVED: printk(KERN_CONT "(reserved)\n"); break; default: printk(KERN_CONT "type %lu\n", bfin_memmap.map[i].type); break; } }} static __init int parse_memmap(char *arg){ unsigned long long start_at, mem_size; if (!arg) return -EINVAL; mem_size = memparse(arg, &arg); if (*arg == '@') { start_at = memparse(arg+1, &arg); add_memory_region(start_at, mem_size, BFIN_MEMMAP_RAM); } else if (*arg == '$') { start_at = memparse(arg+1, &arg); add_memory_region(start_at, mem_size, BFIN_MEMMAP_RESERVED); } return 0;} /* * Initial parsing of the command line. Currently, we support: * - Controlling the linux memory size: mem=xxx[KMG] * - Controlling the physical memory size: max_mem=xxx[KMG][$][#] * $ -> reserved memory is dcacheable * # -> reserved memory is icacheable * - "memmap=XXX[KkmM][@][$]XXX[KkmM]" defines a memory region * @ from <start> to <start>+<mem>, type RAM * $ from <start> to <start>+<mem>, type RESERVED */static __init void parse_cmdline_early(char *cmdline_p){ char c = ' ', *to = cmdline_p; unsigned int memsize;Lines 1–500 of 1468. Load more
/* * Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later. */ #include <linux/delay.h> #include <linux/console.h> #include <linux/bootmem.h> #include <linux/seq_file.h> #include <linux/cpu.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/tty.h> #include <linux/pfn.h> #ifdef CONFIG_MTD_UCLINUX #include <linux/mtd/map.h> #include <linux/ext2_fs.h> #include <linux/cramfs_fs.h> #include <linux/romfs_fs.h> #endif #include <asm/cplb.h> #include <asm/cacheflush.h> #include <asm/blackfin.h> #include <asm/cplbinit.h> #include <asm/clocks.h> #include <asm/div64.h> #include <asm/cpu.h> #include <asm/fixed_code.h> #include <asm/early_printk.h> #include <asm/irq_handler.h> #include <asm/pda.h> #ifdef CONFIG_BF60x #include <mach/pm.h> #endif #ifdef CONFIG_SCB_PRIORITY #include <asm/scb.h> #endif u16 _bfin_swrst; EXPORT_SYMBOL(_bfin_swrst); unsigned long memory_start, memory_end, physical_mem_end; unsigned long _rambase, _ramstart, _ramend; unsigned long reserved_mem_dcache_on; unsigned long reserved_mem_icache_on; EXPORT_SYMBOL(memory_start); EXPORT_SYMBOL(memory_end); EXPORT_SYMBOL(physical_mem_end); EXPORT_SYMBOL(_ramend); EXPORT_SYMBOL(reserved_mem_dcache_on); #ifdef CONFIG_MTD_UCLINUX extern struct map_info uclinux_ram_map; unsigned long memory_mtd_end, memory_mtd_start, mtd_size; EXPORT_SYMBOL(memory_mtd_end); EXPORT_SYMBOL(memory_mtd_start); EXPORT_SYMBOL(mtd_size); #endif char __initdata command_line[COMMAND_LINE_SIZE]; struct blackfin_initial_pda __initdata initial_pda; /* boot memmap, for parsing "memmap=" */ #define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */ #define BFIN_MEMMAP_RAM 1 #define BFIN_MEMMAP_RESERVED 2 static struct bfin_memmap { int nr_map; struct bfin_memmap_entry { unsigned long long addr; /* start of memory segment */ unsigned long long size; unsigned long type; } map[BFIN_MEMMAP_MAX]; } bfin_memmap __initdata; /* for memmap sanitization */ struct change_member { struct bfin_memmap_entry *pentry; /* pointer to original entry */ unsigned long long addr; /* address for this change point */ }; static struct change_member change_point_list[2*BFIN_MEMMAP_MAX] __initdata; static struct change_member *change_point[2*BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry *overlap_list[BFIN_MEMMAP_MAX] __initdata; static struct bfin_memmap_entry new_map[BFIN_MEMMAP_MAX] __initdata; DEFINE_PER_CPU(struct blackfin_cpudata, cpu_data); static int early_init_clkin_hz(char *buf); #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) void __init generate_cplb_tables(void) { unsigned int cpu; generate_cplb_tables_all(); /* Generate per-CPU I&D CPLB tables */ for (cpu = 0; cpu < num_possible_cpus(); ++cpu) generate_cplb_tables_cpu(cpu); } #endif void bfin_setup_caches(unsigned int cpu) { #ifdef CONFIG_BFIN_ICACHE bfin_icache_init(icplb_tbl[cpu]); #endif #ifdef CONFIG_BFIN_DCACHE bfin_dcache_init(dcplb_tbl[cpu]); #endif bfin_setup_cpudata(cpu); /* * In cache coherence emulation mode, we need to have the * D-cache enabled before running any atomic operation which * might involve cache invalidation (i.e. spinlock, rwlock). * So printk's are deferred until then. */ #ifdef CONFIG_BFIN_ICACHE printk(KERN_INFO "Instruction Cache Enabled for CPU%u\n", cpu); printk(KERN_INFO " External memory:" # ifdef CONFIG_BFIN_EXTMEM_ICACHEABLE " cacheable" # else " uncacheable" # endif " in instruction cache\n"); if (L2_LENGTH) printk(KERN_INFO " L2 SRAM :" # ifdef CONFIG_BFIN_L2_ICACHEABLE " cacheable" # else " uncacheable" # endif " in instruction cache\n"); #else printk(KERN_INFO "Instruction Cache Disabled for CPU%u\n", cpu); #endif #ifdef CONFIG_BFIN_DCACHE printk(KERN_INFO "Data Cache Enabled for CPU%u\n", cpu); printk(KERN_INFO " External memory:" # if defined CONFIG_BFIN_EXTMEM_WRITEBACK " cacheable (write-back)" # elif defined CONFIG_BFIN_EXTMEM_WRITETHROUGH " cacheable (write-through)" # else " uncacheable" # endif " in data cache\n"); if (L2_LENGTH) printk(KERN_INFO " L2 SRAM :" # if defined CONFIG_BFIN_L2_WRITEBACK " cacheable (write-back)" # elif defined CONFIG_BFIN_L2_WRITETHROUGH " cacheable (write-through)" # else " uncacheable" # endif " in data cache\n"); #else printk(KERN_INFO "Data Cache Disabled for CPU%u\n", cpu); #endif } void bfin_setup_cpudata(unsigned int cpu) { struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu); cpudata->imemctl = bfin_read_IMEM_CONTROL(); cpudata->dmemctl = bfin_read_DMEM_CONTROL(); } void __init bfin_cache_init(void) { #if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) generate_cplb_tables(); #endif bfin_setup_caches(0); } void __init bfin_relocate_l1_mem(void) { unsigned long text_l1_len = (unsigned long)_text_l1_len; unsigned long data_l1_len = (unsigned long)_data_l1_len; unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len; unsigned long l2_len = (unsigned long)_l2_len; early_shadow_stamp(); /* * due to the ALIGN(4) in the arch/blackfin/kernel/vmlinux.lds.S * we know that everything about l1 text/data is nice and aligned, * so copy by 4 byte chunks, and don't worry about overlapping * src/dest. * * We can't use the dma_memcpy functions, since they can call * scheduler functions which might be in L1 :( and core writes * into L1 instruction cause bad access errors, so we are stuck, * we are required to use DMA, but can't use the common dma * functions. We can't use memcpy either - since that might be * going to be in the relocated L1 */ blackfin_dma_early_init(); /* if necessary, copy L1 text to L1 instruction SRAM */ if (L1_CODE_LENGTH && text_l1_len) early_dma_memcpy(_stext_l1, _text_l1_lma, text_l1_len); /* if necessary, copy L1 data to L1 data bank A SRAM */ if (L1_DATA_A_LENGTH && data_l1_len) early_dma_memcpy(_sdata_l1, _data_l1_lma, data_l1_len); /* if necessary, copy L1 data B to L1 data bank B SRAM */ if (L1_DATA_B_LENGTH && data_b_l1_len) early_dma_memcpy(_sdata_b_l1, _data_b_l1_lma, data_b_l1_len); early_dma_memcpy_done(); #if defined(CONFIG_SMP) && defined(CONFIG_ICACHE_FLUSH_L1) blackfin_iflush_l1_entry[0] = (unsigned long)blackfin_icache_flush_range_l1; #endif /* if necessary, copy L2 text/data to L2 SRAM */ if (L2_LENGTH && l2_len) memcpy(_stext_l2, _l2_lma, l2_len); } #ifdef CONFIG_SMP void __init bfin_relocate_coreb_l1_mem(void) { unsigned long text_l1_len = (unsigned long)_text_l1_len; unsigned long data_l1_len = (unsigned long)_data_l1_len; unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len; blackfin_dma_early_init(); /* if necessary, copy L1 text to L1 instruction SRAM */ if (L1_CODE_LENGTH && text_l1_len) early_dma_memcpy((void *)COREB_L1_CODE_START, _text_l1_lma, text_l1_len); /* if necessary, copy L1 data to L1 data bank A SRAM */ if (L1_DATA_A_LENGTH && data_l1_len) early_dma_memcpy((void *)COREB_L1_DATA_A_START, _data_l1_lma, data_l1_len); /* if necessary, copy L1 data B to L1 data bank B SRAM */ if (L1_DATA_B_LENGTH && data_b_l1_len) early_dma_memcpy((void *)COREB_L1_DATA_B_START, _data_b_l1_lma, data_b_l1_len); early_dma_memcpy_done(); #ifdef CONFIG_ICACHE_FLUSH_L1 blackfin_iflush_l1_entry[1] = (unsigned long)blackfin_icache_flush_range_l1 - (unsigned long)_stext_l1 + COREB_L1_CODE_START; #endif } #endif #ifdef CONFIG_ROMKERNEL void __init bfin_relocate_xip_data(void) { early_shadow_stamp(); memcpy(_sdata, _data_lma, (unsigned long)_data_len - THREAD_SIZE + sizeof(struct thread_info)); memcpy(_sinitdata, _init_data_lma, (unsigned long)_init_data_len); } #endif /* add_memory_region to memmap */ static void __init add_memory_region(unsigned long long start, unsigned long long size, int type) { int i; i = bfin_memmap.nr_map; if (i == BFIN_MEMMAP_MAX) { printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); return; } bfin_memmap.map[i].addr = start; bfin_memmap.map[i].size = size; bfin_memmap.map[i].type = type; bfin_memmap.nr_map++; } /* * Sanitize the boot memmap, removing overlaps. */ static int __init sanitize_memmap(struct bfin_memmap_entry *map, int *pnr_map) { struct change_member *change_tmp; unsigned long current_type, last_type; unsigned long long last_addr; int chgidx, still_changing; int overlap_entries; int new_entry; int old_nr, new_nr, chg_nr; int i; /* Visually we're performing the following (1,2,3,4 = memory types) Sample memory map (w/overlaps): ____22__________________ ______________________4_ ____1111________________ _44_____________________ 11111111________________ ____________________33__ ___________44___________ __________33333_________ ______________22________ ___________________2222_ _________111111111______ _____________________11_ _________________4______ Sanitized equivalent (no overlap): 1_______________________ _44_____________________ ___1____________________ ____22__________________ ______11________________ _________1______________ __________3_____________ ___________44___________ _____________33_________ _______________2________ ________________1_______ _________________4______ ___________________2____ ____________________33__ ______________________4_ */ /* if there's only one memory region, don't bother */ if (*pnr_map < 2) return -1; old_nr = *pnr_map; /* bail out if we find any unreasonable addresses in memmap */ for (i = 0; i < old_nr; i++) if (map[i].addr + map[i].size < map[i].addr) return -1; /* create pointers for initial change-point information (for sorting) */ for (i = 0; i < 2*old_nr; i++) change_point[i] = &change_point_list[i]; /* record all known change-points (starting and ending addresses), omitting those that are for empty memory regions */ chgidx = 0; for (i = 0; i < old_nr; i++) { if (map[i].size != 0) { change_point[chgidx]->addr = map[i].addr; change_point[chgidx++]->pentry = &map[i]; change_point[chgidx]->addr = map[i].addr + map[i].size; change_point[chgidx++]->pentry = &map[i]; } } chg_nr = chgidx; /* true number of change-points */ /* sort change-point list by memory addresses (low -> high) */ still_changing = 1; while (still_changing) { still_changing = 0; for (i = 1; i < chg_nr; i++) { /* if <current_addr> > <last_addr>, swap */ /* or, if current=<start_addr> & last=<end_addr>, swap */ if ((change_point[i]->addr < change_point[i-1]->addr) || ((change_point[i]->addr == change_point[i-1]->addr) && (change_point[i]->addr == change_point[i]->pentry->addr) && (change_point[i-1]->addr != change_point[i-1]->pentry->addr)) ) { change_tmp = change_point[i]; change_point[i] = change_point[i-1]; change_point[i-1] = change_tmp; still_changing = 1; } } } /* create a new memmap, removing overlaps */ overlap_entries = 0; /* number of entries in the overlap table */ new_entry = 0; /* index for creating new memmap entries */ last_type = 0; /* start with undefined memory type */ last_addr = 0; /* start with 0 as last starting address */ /* loop through change-points, determining affect on the new memmap */ for (chgidx = 0; chgidx < chg_nr; chgidx++) { /* keep track of all overlapping memmap entries */ if (change_point[chgidx]->addr == change_point[chgidx]->pentry->addr) { /* add map entry to overlap list (> 1 entry implies an overlap) */ overlap_list[overlap_entries++] = change_point[chgidx]->pentry; } else { /* remove entry from list (order independent, so swap with last) */ for (i = 0; i < overlap_entries; i++) { if (overlap_list[i] == change_point[chgidx]->pentry) overlap_list[i] = overlap_list[overlap_entries-1]; } overlap_entries--; } /* if there are overlapping entries, decide which "type" to use */ /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ current_type = 0; for (i = 0; i < overlap_entries; i++) if (overlap_list[i]->type > current_type) current_type = overlap_list[i]->type; /* continue building up new memmap based on this information */ if (current_type != last_type) { if (last_type != 0) { new_map[new_entry].size = change_point[chgidx]->addr - last_addr; /* move forward only if the new size was non-zero */ if (new_map[new_entry].size != 0) if (++new_entry >= BFIN_MEMMAP_MAX) break; /* no more space left for new entries */ } if (current_type != 0) { new_map[new_entry].addr = change_point[chgidx]->addr; new_map[new_entry].type = current_type; last_addr = change_point[chgidx]->addr; } last_type = current_type; } } new_nr = new_entry; /* retain count for new entries */ /* copy new mapping into original location */ memcpy(map, new_map, new_nr*sizeof(struct bfin_memmap_entry)); *pnr_map = new_nr; return 0; } static void __init print_memory_map(char *who) { int i; for (i = 0; i < bfin_memmap.nr_map; i++) { printk(KERN_DEBUG " %s: %016Lx - %016Lx ", who, bfin_memmap.map[i].addr, bfin_memmap.map[i].addr + bfin_memmap.map[i].size); switch (bfin_memmap.map[i].type) { case BFIN_MEMMAP_RAM: printk(KERN_CONT "(usable)\n"); break; case BFIN_MEMMAP_RESERVED: printk(KERN_CONT "(reserved)\n"); break; default: printk(KERN_CONT "type %lu\n", bfin_memmap.map[i].type); break; } } } static __init int parse_memmap(char *arg) { unsigned long long start_at, mem_size; if (!arg) return -EINVAL; mem_size = memparse(arg, &arg); if (*arg == '@') { start_at = memparse(arg+1, &arg); add_memory_region(start_at, mem_size, BFIN_MEMMAP_RAM); } else if (*arg == '$') { start_at = memparse(arg+1, &arg); add_memory_region(start_at, mem_size, BFIN_MEMMAP_RESERVED); } return 0; } /* * Initial parsing of the command line. Currently, we support: * - Controlling the linux memory size: mem=xxx[KMG] * - Controlling the physical memory size: max_mem=xxx[KMG][$][#] * $ -> reserved memory is dcacheable * # -> reserved memory is icacheable * - "memmap=XXX[KkmM][@][$]XXX[KkmM]" defines a memory region * @ from <start> to <start>+<mem>, type RAM * $ from <start> to <start>+<mem>, type RESERVED */ static __init void parse_cmdline_early(char *cmdline_p) { char c = ' ', *to = cmdline_p; unsigned int memsize;