diff options
Diffstat (limited to 'src/arch/ppc')
-rw-r--r-- | src/arch/ppc/boot/linuxbios_table.c | 219 | ||||
-rw-r--r-- | src/arch/ppc/boot/tables.c | 5 | ||||
-rw-r--r-- | src/arch/ppc/lib/cpu.c | 44 | ||||
-rw-r--r-- | src/arch/ppc/lib/cpuid.c | 82 |
4 files changed, 231 insertions, 119 deletions
diff --git a/src/arch/ppc/boot/linuxbios_table.c b/src/arch/ppc/boot/linuxbios_table.c index 2b37e877e5..0866639f1e 100644 --- a/src/arch/ppc/boot/linuxbios_table.c +++ b/src/arch/ppc/boot/linuxbios_table.c @@ -1,11 +1,11 @@ #include <console/console.h> -#include <mem.h> #include <ip_checksum.h> #include <boot/linuxbios_tables.h> #include "linuxbios_table.h" #include <string.h> #include <version.h> - +#include <device/device.h> +#include <stdlib.h> struct lb_header *lb_table_init(unsigned long addr) { @@ -128,11 +128,8 @@ void lb_strings(struct lb_header *header) } -/* Some version of gcc have problems with 64 bit types so - * take an unsigned long instead of a uint64_t for now. - */ void lb_memory_range(struct lb_memory *mem, - uint32_t type, unsigned long start, unsigned long size) + uint32_t type, uint64_t start, uint64_t size) { int entries; entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); @@ -142,19 +139,6 @@ void lb_memory_range(struct lb_memory *mem, mem->size += sizeof(mem->map[0]); } -static void lb_memory_rangek(struct lb_memory *mem, - uint32_t type, unsigned long startk, unsigned long endk) -{ - int entries; - entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); - mem->map[entries].start = startk; - mem->map[entries].start <<= 10; - mem->map[entries].size = endk - startk; - mem->map[entries].size <<= 10; - mem->map[entries].type = type; - mem->size += sizeof(mem->map[0]); -} - static void lb_reserve_table_memory(struct lb_header *head) { struct lb_record *last_rec; @@ -187,7 +171,6 @@ static void lb_reserve_table_memory(struct lb_header *head) } } - unsigned long lb_table_fini(struct lb_header *head) { struct lb_record *rec, *first_rec; @@ -205,6 +188,112 @@ unsigned long lb_table_fini(struct lb_header *head) return (unsigned long)rec; } +static void lb_cleanup_memory_ranges(struct lb_memory *mem) +{ + int entries; + int i, j; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + + /* Sort the lb memory ranges */ + for(i = 0; i < entries; i++) { + for(j = i; j < entries; j++) { + if (mem->map[j].start < mem->map[i].start) { + struct lb_memory_range tmp; + tmp = mem->map[i]; + mem->map[i] = mem->map[j]; + mem->map[j] = tmp; + } + } + } + + /* Merge adjacent entries */ + for(i = 0; (i + 1) < entries; i++) { + uint64_t start, end, nstart, nend; + if (mem->map[i].type != mem->map[i + 1].type) { + continue; + } + start = mem->map[i].start; + end = start + mem->map[i].size; + nstart = mem->map[i + 1].start; + nend = nstart + mem->map[i + 1].size; + if ((start <= nstart) && (end > nstart)) { + if (start > nstart) { + start = nstart; + } + if (end < nend) { + end = nend; + } + /* Record the new region size */ + mem->map[i].start = start; + mem->map[i].size = end - start; + + /* Delete the entry I have merged with */ + memmove(&mem->map[i + 1], &mem->map[i + 2], + ((entries - i - 2) * sizeof(mem->map[0]))); + mem->size -= sizeof(mem->map[0]); + entries -= 1; + /* See if I can merge with the next entry as well */ + i -= 1; + } + } +} + +static void lb_remove_memory_range(struct lb_memory *mem, + uint64_t start, uint64_t size) +{ + uint64_t end; + int entries; + int i; + + end = start + size; + entries = (mem->size - sizeof(*mem))/sizeof(mem->map[0]); + + /* Remove a reserved area from the memory map */ + for(i = 0; i < entries; i++) { + uint64_t map_start = mem->map[i].start; + uint64_t map_end = map_start + mem->map[i].size; + if ((start <= map_start) && (end >= map_end)) { + /* Remove the completely covered range */ + memmove(&mem->map[i], &mem->map[i + 1], + ((entries - i - 1) * sizeof(mem->map[0]))); + mem->size -= sizeof(mem->map[0]); + entries -= 1; + /* Since the index will disappear revisit what will appear here */ + i -= 1; + } + else if ((start > map_start) && (end < map_end)) { + /* Split the memory range */ + memmove(&mem->map[i + 1], &mem->map[i], + ((entries - i) * sizeof(mem->map[0]))); + mem->size += sizeof(mem->map[0]); + entries += 1; + /* Update the first map entry */ + mem->map[i].size = start - map_start; + /* Update the second map entry */ + mem->map[i + 1].start = end; + mem->map[i + 1].size = map_end - end; + /* Don't bother with this map entry again */ + i += 1; + } + else if ((start <= map_start) && (end > map_start)) { + /* Shrink the start of the memory range */ + mem->map[i].start = end; + mem->map[i].size = map_end - end; + } + else if ((start < map_end) && (start > map_start)) { + /* Shrink the end of the memory range */ + mem->map[i].size = start - map_start; + } + } +} + +static void lb_add_memory_range(struct lb_memory *mem, + uint32_t type, uint64_t start, uint64_t size) +{ + lb_remove_memory_range(mem, start, size); + lb_memory_range(mem, type, start, size); + lb_cleanup_memory_ranges(mem); +} /* Routines to extract part so the linuxBIOS table or * information from the linuxBIOS table after we have written it. @@ -217,58 +306,68 @@ struct lb_memory *get_lb_mem(void) return mem_ranges; } +static struct lb_memory *build_lb_mem(struct lb_header *head) +{ + struct lb_memory *mem; + struct device *dev; + + /* Record where the lb memory ranges will live */ + mem = lb_memory(head); + mem_ranges = mem; + + /* Build the raw table of memory */ + for(dev = all_devices; dev; dev = dev->next) { + struct resource *res, *last; + last = &dev->resource[dev->resources]; + for(res = &dev->resource[0]; res < last; res++) { + if (!(res->flags & IORESOURCE_MEM) || + !(res->flags & IORESOURCE_CACHEABLE)) { + continue; + } + lb_memory_range(mem, LB_MEM_RAM, res->base, res->size); + } + } + lb_cleanup_memory_ranges(mem); + return mem; +} + unsigned long write_linuxbios_table( - struct mem_range *ram, unsigned long low_table_start, unsigned long low_table_end, unsigned long rom_table_startk, unsigned long rom_table_endk) { unsigned long table_size; - struct mem_range *ramp; struct lb_header *head; struct lb_memory *mem; -#if HAVE_OPTION_TABLE == 1 - struct lb_record *rec_dest, *rec_src; -#endif head = lb_table_init(low_table_end); low_table_end = (unsigned long)head; -#if HAVE_OPTION_TABLE == 1 - /* Write the option config table... */ - rec_dest = lb_new_record(head); - rec_src = (struct lb_record *)&option_table; - memcpy(rec_dest, rec_src, rec_src->size); -#endif - mem = lb_memory(head); - mem_ranges = mem; - /* I assume there is always ram at address 0 */ - /* Reserve our tables in low memory */ + if (HAVE_OPTION_TABLE == 1) { + struct lb_record *rec_dest, *rec_src; + /* Write the option config table... */ + rec_dest = lb_new_record(head); + rec_src = (struct lb_record *)&option_table; + memcpy(rec_dest, rec_src, rec_src->size); + } + /* Record where RAM is located */ + mem = build_lb_mem(head); + + /* Find the current mptable size */ table_size = (low_table_end - low_table_start); - lb_memory_range(mem, LB_MEM_TABLE, 0, table_size); - lb_memory_range(mem, LB_MEM_RAM, table_size, (ram[0].sizek << 10) - table_size); - /* Reserving pci memory mapped space will keep the kernel from booting seeing - * any pci resources. + + /* Record the mptable and the the lb_table (This will be adjusted later) */ + lb_add_memory_range(mem, LB_MEM_TABLE, + low_table_start, table_size); + + /* Record the pirq table */ + lb_add_memory_range(mem, LB_MEM_TABLE, + rom_table_startk << 10, (rom_table_endk - rom_table_startk) << 10); + + /* Note: + * I assume that there is always memory at immediately after + * the low_table_end. This means that after I setup the linuxbios table. + * I can trivially fixup the reserved memory ranges to hold the correct + * size of the linuxbios table. */ - for(ramp = &ram[1]; ramp->sizek; ramp++) { - unsigned long startk, endk; - startk = ramp->basek; - endk = startk + ramp->sizek; - if ((startk < rom_table_startk) && (endk > rom_table_startk)) { - lb_memory_rangek(mem, LB_MEM_RAM, startk, rom_table_startk); - startk = rom_table_startk; - } - if ((startk == rom_table_startk) && (endk > startk)) { - unsigned long tend; - tend = rom_table_endk; - if (tend > endk) { - tend = endk; - } - lb_memory_rangek(mem, LB_MEM_TABLE, rom_table_startk, tend); - startk = tend; - } - if (endk > startk) { - lb_memory_rangek(mem, LB_MEM_RAM, startk, endk); - } - } /* Record our motheboard */ lb_mainboard(head); diff --git a/src/arch/ppc/boot/tables.c b/src/arch/ppc/boot/tables.c index 468fbcabe8..7d8bd318ba 100644 --- a/src/arch/ppc/boot/tables.c +++ b/src/arch/ppc/boot/tables.c @@ -1,12 +1,11 @@ #include <console/console.h> -#include <mem.h> #include <cpu/cpu.h> #include <boot/tables.h> #include <boot/linuxbios_tables.h> #include "linuxbios_table.h" struct lb_memory * -write_tables(struct mem_range *mem) +write_tables(void) { unsigned long low_table_start, low_table_end; unsigned long rom_table_start, rom_table_end; @@ -20,7 +19,7 @@ write_tables(struct mem_range *mem) low_table_end = 16; /* The linuxbios table must be in 0-4K or 960K-1M */ - write_linuxbios_table(mem, + write_linuxbios_table( low_table_start, low_table_end, rom_table_start >> 10, rom_table_end >> 10); diff --git a/src/arch/ppc/lib/cpu.c b/src/arch/ppc/lib/cpu.c index 7a8e46f5cd..efb914b059 100644 --- a/src/arch/ppc/lib/cpu.c +++ b/src/arch/ppc/lib/cpu.c @@ -1,35 +1,49 @@ #include <console/console.h> -#include <mem.h> #include <arch/io.h> #include <string.h> #include <cpu/cpu.h> #include <cpu/ppc/cpuid.h> #include <smp/start_stop.h> +#include "ppc.h" +#include "ppcreg.h" -static void cache_on(struct mem_range *mem) -{ -} - -static void interrupts_on() -{ -} +#error "FIXME what should call cpu_initialize?" -unsigned long cpu_initialize(struct mem_range *mem) +void cpu_initialize(void) { /* Because we busy wait at the printk spinlock. * It is important to keep the number of printed messages * from secondary cpus to a minimum, when debugging is * disabled. */ - unsigned long processor_id = this_processors_id(); - printk_notice("Initializing CPU #%d\n", processor_id); + struct device *cpu; + struct cpu_info *info; + info = cpu_info(); + + printk_notice("Initializing CPU #%d\n", info->index); + + cpu = info->cpu; + if (!cpu) { + die("CPU: missing cpu device structure"); + } - /* Turn on caching if we haven't already */ - cache_on(mem); + /* Find what type of cpu we are dealing with */ + cpu->vendor 0; /* PPC cpus do not have a vendor field */ + cpu->device = ppc_getpvr(); + display_cpuid(cpu); - display_cpuid(); +#if 0 + /* Lookup the cpu's operations */ + set_cpu_ops(cpu); - interrupts_on(); + /* Initialize the cpu */ + if (cpu->ops && cpu->ops->init) { + cpu->enabled = 1; + cpu->initialized = 1; + cpu->ops->init(); + } +#endif + /* Turn on caching if we haven't already */ printk_info("CPU #%d Initialized\n", processor_id); return processor_id; diff --git a/src/arch/ppc/lib/cpuid.c b/src/arch/ppc/lib/cpuid.c index 09a7865b1b..0ff12774bd 100644 --- a/src/arch/ppc/lib/cpuid.c +++ b/src/arch/ppc/lib/cpuid.c @@ -5,62 +5,62 @@ #include "ppcreg.h" #include <console/console.h> -void display_cpuid(void) +void display_cpuid(struct device *cpu) { - unsigned type = ppc_getpvr() >> 16; - unsigned version = ppc_getpvr() & 0xffff; - const char *cpu_string = 0; - switch(type) { + unsigned type = cpu->device >> 16; + unsigned version = cpu->device & 0xffff; + const char *cpu_string = 0; + switch(type) { case 0x0001: - cpu_string = "601"; - break; + cpu_string = "601"; + break; case 0x0003: - cpu_string = "603"; - break; + cpu_string = "603"; + break; case 0x0004: - cpu_string = "604"; - break; + cpu_string = "604"; + break; case 0x0006: - cpu_string = "603e"; - break; + cpu_string = "603e"; + break; case 0x0007: - cpu_string = "603ev"; - break; + cpu_string = "603ev"; + break; case 0x0008: - cpu_string = "750"; - break; + cpu_string = "750"; + break; case 0x0009: - cpu_string = "604e"; - break; + cpu_string = "604e"; + break; case 0x000a: - cpu_string = "604ev5 (MachV)"; - break; + cpu_string = "604ev5 (MachV)"; + break; case 0x000c: - cpu_string = "7400"; - break; + cpu_string = "7400"; + break; case 0x0032: - cpu_string = "821"; - break; + cpu_string = "821"; + break; case 0x0050: - cpu_string = "860"; - break; + cpu_string = "860"; + break; case 0x4011: - cpu_string = "405GP"; - break; + cpu_string = "405GP"; + break; case 0x5091: - cpu_string = "405GPr"; - break; + cpu_string = "405GPr"; + break; case 0x5121: - cpu_string = "405EP"; - break; + cpu_string = "405EP"; + break; case 0x800c: - cpu_string = "7410"; - break; - } - if (cpu_string) - printk_info("PowerPC %s", cpu_string); - else - printk_info("PowerPC unknown (0x%x)", type); - printk_info(" CPU, version %d.%d\n", version >> 8, version & 0xff); + cpu_string = "7410"; + break; + } + if (cpu_string) + printk_info("PowerPC %s", cpu_string); + else + printk_info("PowerPC unknown (0x%x)", type); + printk_info(" CPU, version %d.%d\n", version >> 8, version & 0xff); } |