diff -urN linux-2.5/arch/ppc64/boot/Makefile linux-prom-clean/arch/ppc64/boot/Makefile --- linux-2.5/arch/ppc64/boot/Makefile 2004-08-26 15:46:30.000000000 +1000 +++ linux-prom-clean/arch/ppc64/boot/Makefile 2004-09-17 14:34:55.000000000 +1000 @@ -31,6 +31,7 @@ BOOTLD := $(CROSS32_COMPILE)ld BOOTLFLAGS := -Ttext 0x00400000 -e _start -T $(obj)/zImage.lds BOOTOBJCOPY := $(CROSS32_COMPILE)objcopy +BOOTSTRIP := $(CROSS32_COMPILE)strip OBJCOPYFLAGS := contents,alloc,load,readonly,data src-boot := crt0.S string.S prom.c main.c zlib.c imagesize.c div64.S @@ -51,36 +52,31 @@ #----------------------------------------------------------- # ELF sections within the zImage bootloader/wrapper #----------------------------------------------------------- -required := vmlinux .config System.map +required := vmlinux.strip initrd := initrd obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section))) src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section))) gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section))) -hostprogs-y := piggy addnote addSystemMap addRamDisk +hostprogs-y := piggy addnote addRamDisk targets += zImage zImage.initrd imagesize.c \ $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \ $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \ - vmlinux.sm vmlinux.initrd vmlinux.sminitrd -extra-y := sysmap.o initrd.o - -quiet_cmd_sysmap = SYSMAP $@ - cmd_sysmap = $(obj)/addSystemMap System.map $< $@ -$(obj)/vmlinux.sm: vmlinux $(obj)/addSystemMap System.map FORCE - $(call if_changed,sysmap) + vmlinux.initrd +extra-y := initrd.o quiet_cmd_ramdisk = RAMDISK $@ - cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map $< $@ -$(obj)/vmlinux.initrd: vmlinux $(obj)/addRamDisk $(obj)/ramdisk.image.gz System.map FORCE - $(call if_changed,ramdisk) + cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@ -$(obj)/vmlinux.sminitrd: $(obj)/vmlinux.sm $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE - $(call if_changed,ramdisk) +quiet_cmd_stripvm = STRIP $@ + cmd_stripvm = $(BOOTSTRIP) -s $< -o $@ -$(obj)/sysmap.o: System.map $(obj)/piggyback FORCE - $(call if_changed,piggy) +vmlinux.strip: vmlinux FORCE + $(call if_changed,stripvm) +$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE + $(call if_changed,ramdisk) addsection = $(BOOTOBJCOPY) $(1) \ --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $(1)))=$(patsubst %.o,%.gz, $(1)) \ @@ -113,9 +109,9 @@ $(obj)/zImage.initrd: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(obj)/addnote FORCE $(call if_changed,addnote) -$(obj)/imagesize.c: vmlinux +$(obj)/imagesize.c: vmlinux.strip @echo Generating $@ - ls -l vmlinux | \ + ls -l vmlinux.strip | \ awk '{printf "/* generated -- do not edit! */\n" \ "unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \ @@ -123,6 +119,6 @@ >> $(obj)/imagesize.c install: $(CONFIGURE) $(obj)/$(BOOTIMAGE) - sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(TOPDIR)/System.map" "$(INSTALL_PATH)" + sh -x $(src)/install.sh "$(KERNELRELEASE)" "$(obj)/$(BOOTIMAGE)" "$(INSTALL_PATH)" clean-files := $(patsubst $(obj)/%,%, $(obj-boot)) diff -urN linux-2.5/arch/ppc64/boot/addSystemMap.c linux-prom-clean/arch/ppc64/boot/addSystemMap.c --- linux-2.5/arch/ppc64/boot/addSystemMap.c 2004-07-21 01:35:49.000000000 +1000 +++ /dev/null 2004-09-16 11:45:22.000000000 +1000 @@ -1,248 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void xlate( char * inb, char * trb, unsigned len ) -{ - unsigned i; - for ( i=0; i> 4; - char c2 = c & 0xf; - if ( c1 > 9 ) - c1 = c1 + 'A' - 10; - else - c1 = c1 + '0'; - if ( c2 > 9 ) - c2 = c2 + 'A' - 10; - else - c2 = c2 + '0'; - *trb++ = c1; - *trb++ = c2; - } - *trb = 0; -} - -#define ElfHeaderSize (64 * 1024) -#define ElfPages (ElfHeaderSize / 4096) - -void get4k( /*istream *inf*/FILE *file, char *buf ) -{ - unsigned j; - unsigned num = fread(buf, 1, 4096, file); - for ( j=num; j<4096; ++j ) - buf[j] = 0; -} - -void put4k( /*ostream *outf*/FILE *file, char *buf ) -{ - fwrite(buf, 1, 4096, file); -} - -int main(int argc, char **argv) -{ - char inbuf[4096]; - FILE *sysmap = NULL; - char* ptr_end = NULL; - FILE *inputVmlinux = NULL; - FILE *outputVmlinux = NULL; - long i = 0; - unsigned long sysmapFileLen = 0; - unsigned long sysmapLen = 0; - unsigned long roundR = 0; - unsigned long kernelLen = 0; - unsigned long actualKernelLen = 0; - unsigned long round = 0; - unsigned long roundedKernelLen = 0; - unsigned long sysmapStartOffs = 0; - unsigned long sysmapPages = 0; - unsigned long roundedKernelPages = 0; - long padPages = 0; - if ( argc < 2 ) - { - fprintf(stderr, "Name of System Map file missing.\n"); - exit(1); - } - - if ( argc < 3 ) - { - fprintf(stderr, "Name of vmlinux file missing.\n"); - exit(1); - } - - if ( argc < 4 ) - { - fprintf(stderr, "Name of vmlinux output file missing.\n"); - exit(1); - } - - sysmap = fopen(argv[1], "r"); - if ( ! sysmap ) - { - fprintf(stderr, "System Map file \"%s\" failed to open.\n", argv[1]); - exit(1); - } - inputVmlinux = fopen(argv[2], "r"); - if ( ! inputVmlinux ) - { - fprintf(stderr, "vmlinux file \"%s\" failed to open.\n", argv[2]); - exit(1); - } - outputVmlinux = fopen(argv[3], "w"); - if ( ! outputVmlinux ) - { - fprintf(stderr, "output vmlinux file \"%s\" failed to open.\n", argv[3]); - exit(1); - } - - - - fseek(inputVmlinux, 0, SEEK_END); - kernelLen = ftell(inputVmlinux); - fseek(inputVmlinux, 0, SEEK_SET); - printf("kernel file size = %ld\n", kernelLen); - if ( kernelLen == 0 ) - { - fprintf(stderr, "You must have a linux kernel specified as argv[2]\n"); - exit(1); - } - - - actualKernelLen = kernelLen - ElfHeaderSize; - - printf("actual kernel length (minus ELF header) = %ld/%lxx \n", actualKernelLen, actualKernelLen); - - round = actualKernelLen % 4096; - roundedKernelLen = actualKernelLen; - if ( round ) - roundedKernelLen += (4096 - round); - - printf("Kernel length rounded up to a 4k multiple = %ld/%lxx \n", roundedKernelLen, roundedKernelLen); - roundedKernelPages = roundedKernelLen / 4096; - printf("Kernel pages to copy = %ld/%lxx\n", roundedKernelPages, roundedKernelPages); - - - - /* Sysmap file */ - fseek(sysmap, 0, SEEK_END); - sysmapFileLen = ftell(sysmap); - fseek(sysmap, 0, SEEK_SET); - printf("%s file size = %ld\n", argv[1], sysmapFileLen); - - sysmapLen = sysmapFileLen; - - roundR = 4096 - (sysmapLen % 4096); - if (roundR) - { - printf("Rounding System Map file up to a multiple of 4096, adding %ld\n", roundR); - sysmapLen += roundR; - } - printf("Rounded System Map size is %ld\n", sysmapLen); - - /* Process the Sysmap file to determine the true end of the kernel */ - sysmapPages = sysmapLen / 4096; - printf("System map pages to copy = %ld\n", sysmapPages); - /* read the whole file line by line, expect that it doesn't fail */ - while ( fgets(inbuf, 4096, sysmap) ) ; - /* search for _end in the last page of the system map */ - ptr_end = strstr(inbuf, " _end"); - if (!ptr_end) - { - fprintf(stderr, "Unable to find _end in the sysmap file \n"); - fprintf(stderr, "inbuf: \n"); - fprintf(stderr, "%s \n", inbuf); - exit(1); - } - printf("Found _end in the last page of the sysmap - backing up 10 characters it looks like %s", ptr_end-10); - sysmapStartOffs = (unsigned int)strtol(ptr_end-10, NULL, 16); - /* calc how many pages we need to insert between the vmlinux and the start of the sysmap */ - padPages = sysmapStartOffs/4096 - roundedKernelPages; - - /* Check and see if the vmlinux is larger than _end in System.map */ - if (padPages < 0) - { /* vmlinux is larger than _end - adjust the offset to start the embedded system map */ - sysmapStartOffs = roundedKernelLen; - printf("vmlinux is larger than _end indicates it needs to be - sysmapStartOffs = %lx \n", sysmapStartOffs); - padPages = 0; - printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); - } - else - { /* _end is larger than vmlinux - use the sysmapStartOffs we calculated from the system map */ - printf("vmlinux is smaller than _end indicates is needed - sysmapStartOffs = %lx \n", sysmapStartOffs); - printf("will insert %lx pages between the vmlinux and the start of the sysmap \n", padPages); - } - - - - - /* Copy 64K ELF header */ - for (i=0; i<(ElfPages); ++i) - { - get4k( inputVmlinux, inbuf ); - put4k( outputVmlinux, inbuf ); - } - - - /* Copy the vmlinux (as full pages). */ - fseek(inputVmlinux, ElfHeaderSize, SEEK_SET); - for ( i=0; i 0 ) { - sysmap.addr = (RAM_END - sysmap.size) & ~0xFFF; - claim(sysmap.addr, RAM_END - sysmap.addr, 0); - printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", - sysmap.addr, (unsigned long)_sysmap_start, sysmap.size); - memcpy((void *)sysmap.addr, (void *)_sysmap_start, sysmap.size); + /* + * Now we try to claim some memory for the kernel itself + * our "vmlinux_memsize" is the memory footprint in RAM, _HOWEVER_, what + * our Makefile stuffs in is an image containing all sort of junk including + * an ELF header. We need to do some calculations here to find the right + * size... In practice we add 1Mb, that is enough, but we should really + * consider fixing the Makefile to put a _raw_ kernel in there ! + */ + vmlinux_memsize += 0x100000; + printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux_memsize); + vmlinux.addr = try_claim(vmlinux_memsize); + if (vmlinux.addr == 0) { + printf("Can't allocate memory for kernel image !\n\r"); + exit(); } -#endif + vmlinuz.addr = (unsigned long)_vmlinux_start; + vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); + vmlinux.size = PAGE_ALIGN(vmlinux_filesize); + vmlinux.memsize = vmlinux_memsize; + /* + * Now we try to claim memory for the initrd (and copy it there) + */ initrd.size = (unsigned long)(_initrd_end - _initrd_start); initrd.memsize = initrd.size; if ( initrd.size > 0 ) { - initrd.addr = (RAM_END - initrd.size) & ~0xFFF; - a1 = a2 = 0; - claim(initrd.addr, RAM_END - initrd.addr, 0); + printf("Allocating 0x%lx bytes for initrd ...\n\r", initrd.size); + initrd.addr = try_claim(initrd.size); + if (initrd.addr == 0) { + printf("Can't allocate memory for initial ramdisk !\n\r"); + exit(); + } + a1 = initrd.addr; + a2 = initrd.size; printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r", initrd.addr, (unsigned long)_initrd_start, initrd.size); - memcpy((void *)initrd.addr, (void *)_initrd_start, initrd.size); - } - - vmlinuz.addr = (unsigned long)_vmlinux_start; - vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start); - vmlinux.addr = (unsigned long)(void *)-1; - vmlinux.size = PAGE_ALIGN(vmlinux_filesize); - vmlinux.memsize = vmlinux_memsize; - - claim_size = vmlinux.memsize /* PPPBBB: + fudge for bi_recs */; - for(claim_addr = PROG_START; - claim_addr <= PROG_START * 8; - claim_addr += 0x100000) { -#ifdef DEBUG - printf(" trying: 0x%08lx\n\r", claim_addr); -#endif - vmlinux.addr = (unsigned long)claim(claim_addr, claim_size, 0); - if ((void *)vmlinux.addr != (void *)-1) break; - } - if ((void *)vmlinux.addr == (void *)-1) { - printf("claim error, can't allocate kernel memory\n\r"); - exit(); + memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size); + printf("initrd head: 0x%lx\n", *((u32 *)initrd.addr)); } - /* PPPBBB: should kernel always be gziped? */ + /* Eventually gunzip the kernel */ if (*(unsigned short *)vmlinuz.addr == 0x1f8b) { + int len; avail_ram = scratch; begin_avail = avail_high = avail_ram; end_avail = scratch + sizeof(scratch); printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...", vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size); + len = vmlinuz.size; gunzip((void *)vmlinux.addr, vmlinux.size, - (unsigned char *)vmlinuz.addr, (int *)&vmlinuz.size); - printf("done %lu bytes\n\r", vmlinuz.size); - printf("%u bytes of heap consumed, max in use %u\n\r", + (unsigned char *)vmlinuz.addr, &len); + printf("done 0x%lx bytes\n\r", len); + printf("0x%x bytes of heap consumed, max in use 0x%\n\r", (unsigned)(avail_high - begin_avail), heap_max); } else { memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,vmlinuz.size); @@ -192,7 +202,8 @@ flush_cache((void *)vmlinux.addr, vmlinux.memsize); - bi_recs = make_bi_recs(vmlinux.addr + vmlinux.memsize); + if (a1) + printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr)); kernel_entry = (kernel_entry_t)vmlinux.addr; #ifdef DEBUG @@ -203,65 +214,16 @@ " prom = 0x%lx,\n\r" " bi_recs = 0x%lx,\n\r", (unsigned long)kernel_entry, a1, a2, - (unsigned long)prom, (unsigned long)bi_recs); + (unsigned long)prom, NULL); #endif - kernel_entry( a1, a2, prom, bi_recs ); + kernel_entry( a1, a2, prom, NULL ); printf("Error: Linux kernel returned to zImage bootloader!\n\r"); exit(); } -static struct bi_record * -make_bi_recs(unsigned long addr) -{ - struct bi_record *bi_recs; - struct bi_record *rec; - - bi_recs = rec = bi_rec_init(addr); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_FIRST; - /* rec->data[0] = ...; # Written below before return */ - /* rec->data[1] = ...; # Written below before return */ - - rec = bi_rec_alloc_bytes(rec, strlen("chrpboot")+1); - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, "chrpboot"); - - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_MACHTYPE; - rec->data[0] = PLATFORM_PSERIES; - rec->data[1] = 1; - - if ( initrd.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_INITRD; - rec->data[0] = initrd.addr; - rec->data[1] = initrd.size; - } - - if ( sysmap.size > 0 ) { - rec = bi_rec_alloc(rec, 2); - rec->tag = BI_SYSMAP; - rec->data[0] = (unsigned long)sysmap.addr; - rec->data[1] = (unsigned long)sysmap.size; - } - - rec = bi_rec_alloc(rec, 1); - rec->tag = BI_LAST; - rec->data[0] = (bi_rec_field)bi_recs; - - /* Save the _end_ address of the bi_rec's in the first bi_rec - * data field for easy access by the kernel. - */ - bi_recs->data[0] = (bi_rec_field)rec; - bi_recs->data[1] = (bi_rec_field)rec + rec->size - (bi_rec_field)bi_recs; - - return bi_recs; -} - struct memchunk { unsigned int size; unsigned int pad; diff -urN linux-2.5/arch/ppc64/boot/zImage.lds linux-prom-clean/arch/ppc64/boot/zImage.lds --- linux-2.5/arch/ppc64/boot/zImage.lds 2004-07-21 01:35:49.000000000 +1000 +++ linux-prom-clean/arch/ppc64/boot/zImage.lds 2004-09-17 14:34:55.000000000 +1000 @@ -61,20 +61,10 @@ . = ALIGN(4096); _vmlinux_start = .; - .kernel:vmlinux : { *(.kernel:vmlinux) } + .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) } _vmlinux_end = .; . = ALIGN(4096); - _dotconfig_start = .; - .kernel:.config : { *(.kernel:.config) } - _dotconfig_end = .; - - . = ALIGN(4096); - _sysmap_start = .; - .kernel:System.map : { *(.kernel:System.map) } - _sysmap_end = .; - - . = ALIGN(4096); _initrd_start = .; .kernel:initrd : { *(.kernel:initrd) } _initrd_end = .; diff -urN linux-2.5/arch/ppc64/kernel/Makefile linux-prom-clean/arch/ppc64/kernel/Makefile --- linux-2.5/arch/ppc64/kernel/Makefile 2004-08-26 15:46:30.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/Makefile 2004-09-13 15:15:14.000000000 +1000 @@ -31,7 +31,8 @@ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \ open_pic.o xics.o pSeries_htab.o rtas.o \ - chrp_setup.o i8259.o prom.o pSeries_iommu.o + chrp_setup.o i8259.o prom_init.o prom.o \ + pSeries_iommu.o obj-$(CONFIG_PROC_FS) += proc_ppc64.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o diff -urN linux-2.5/arch/ppc64/kernel/asm-offsets.c linux-prom-clean/arch/ppc64/kernel/asm-offsets.c --- linux-2.5/arch/ppc64/kernel/asm-offsets.c 2004-09-09 17:33:52.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/asm-offsets.c 2004-09-15 21:53:25.000000000 +1000 @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -108,7 +107,6 @@ DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1)); DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt)); DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt)); - DEFINE(PROMENTRY, offsetof(struct prom_t, entry)); /* RTAS */ DEFINE(RTASBASE, offsetof(struct rtas_t, base)); diff -urN linux-2.5/arch/ppc64/kernel/btext.c linux-prom-clean/arch/ppc64/kernel/btext.c --- linux-2.5/arch/ppc64/kernel/btext.c 2004-07-08 06:27:04.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/btext.c 2004-09-13 15:15:14.000000000 +1000 @@ -45,29 +45,31 @@ int boot_text_mapped; int force_printk_to_btext = 0; +extern int global_width, global_height, global_depth, global_pitch; +extern unsigned global_address; boot_infos_t disp_bi; /* This function will enable the early boot text when doing OF booting. This * way, xmon output should work too */ -void __init btext_setup_display(int width, int height, int depth, int pitch, +void btext_setup_display(int width, int height, int depth, int pitch, unsigned long address) { - unsigned long offset = reloc_offset(); - boot_infos_t* bi = PTRRELOC(&disp_bi); + //unsigned long offset = reloc_offset(); + boot_infos_t* bi = &disp_bi; - RELOC(g_loc_X) = 0; - RELOC(g_loc_Y) = 0; - RELOC(g_max_loc_X) = width / 8; - RELOC(g_max_loc_Y) = height / 16; - bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = (unsigned char *)address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = global_width / 8; + g_max_loc_Y = global_height / 16; + bi->logicalDisplayBase = (unsigned char *)global_address; + bi->dispDeviceBase = (unsigned char *)global_address; + bi->dispDeviceRowBytes = global_pitch; + bi->dispDeviceDepth = global_depth; bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - RELOC(boot_text_mapped) = 1; + bi->dispDeviceRect[2] = global_width; + bi->dispDeviceRect[3] = global_height; + boot_text_mapped = 1; } /* Here's a small text engine to use during early boot diff -urN linux-2.5/arch/ppc64/kernel/chrp_setup.c linux-prom-clean/arch/ppc64/kernel/chrp_setup.c --- linux-2.5/arch/ppc64/kernel/chrp_setup.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/chrp_setup.c 2004-09-15 21:53:25.000000000 +1000 @@ -205,7 +205,7 @@ hpte_init_pSeries(); - if (ppc64_iommu_off) + if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) pci_dma_init_direct(); else tce_init_pSeries(); @@ -223,9 +223,7 @@ ppc_md.udbg_getc_poll = udbg_getc_poll; } -void __init -chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +void __init chrp_init(void) { ppc_md.setup_arch = chrp_setup_arch; ppc_md.get_cpuinfo = chrp_get_cpuinfo; diff -urN linux-2.5/arch/ppc64/kernel/entry.S linux-prom-clean/arch/ppc64/kernel/entry.S --- linux-2.5/arch/ppc64/kernel/entry.S 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/entry.S 2004-09-15 17:05:42.000000000 +1000 @@ -777,11 +777,8 @@ std r11,_MSR(r1) /* Get the PROM entrypoint */ - bl .reloc_offset - LOADADDR(r12,prom) - sub r12,r12,r3 - ld r12,PROMENTRY(r12) - mtlr r12 + ld r0,GPR4(r1) + mtlr r0 /* Switch MSR to 32 bits mode */ diff -urN linux-2.5/arch/ppc64/kernel/head.S linux-prom-clean/arch/ppc64/kernel/head.S --- linux-2.5/arch/ppc64/kernel/head.S 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/head.S 2004-09-16 13:49:50.000000000 +1000 @@ -84,8 +84,9 @@ .globl _stext _stext: #ifdef CONFIG_PPC_PSERIES -_STATIC(__start) +_GLOBAL(__start) /* NOP this out unconditionally */ + li r28,0x5a00 BEGIN_FTR_SECTION b .__start_initialization_pSeries END_FTR_SECTION(0, 1) @@ -1223,7 +1224,7 @@ #endif b 1b /* Loop until told to go */ #ifdef CONFIG_PPC_ISERIES -_GLOBAL(__start_initialization_iSeries) +_STATIC(__start_initialization_iSeries) /* Clear out the BSS */ LOADADDR(r11,__bss_stop) @@ -1274,7 +1275,7 @@ #ifdef CONFIG_PPC_PSERIES -_STATIC(mmu_off) +_STATIC(__mmu_off) mfmsr r3 andi. r0,r3,MSR_IR|MSR_DR beqlr @@ -1284,13 +1285,83 @@ sync rfid b . /* prevent speculative execution */ + +/* + * Here is our main kernel entry point. We support currently 2 kind of entries + * depending on the value of r5. + * + * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content + * in r3...r7 + * + * r5 == NULL -> kexec style entry. r3 is a physical pointer to the + * DT block, r4 is a physical pointer to the kernel itself + * also TODO: pass klimit in there (r6) + */ _GLOBAL(__start_initialization_pSeries) - mr r31,r3 /* save parameters */ + /* + * Are we booted from a PROM Of-type client-interface ? + */ + cmpldi cr0,r5,0 + bne .__boot_from_prom /* yes -> prom */ + + li r28,0x5a01 + + /* + * We are booted from a kexec-style call + */ + + /* Save parameters */ + mr r31,r3 + mr r30,r4 + mr r29,r6 + + /* + * Make sure we are running in 64 bits mode + */ + bl .enable_64b_mode + + li r28,0x5a02 + + /* put a relocation offset into r3 */ + bl .reloc_offset + + LOADADDR(r2,__toc_start) + addi r2,r2,0x4000 + addi r2,r2,0x4000 + + /* Relocate the TOC from a virt addr to a real addr */ + sub r2,r2,r3 + + /* Setup some critical 970 SPRs before switching MMU off */ + bl .__970_cpu_preinit + + li r28,0x5a03 + + li r24,0 /* cpu # */ + + /* Switch off MMU if not already */ + LOADADDR(r4, .__after_prom_start - KERNELBASE) + add r4,r4,r30 + bl .__mmu_off + b .__after_prom_start + +_STATIC(__boot_from_prom) + /* + * We are booted from a PROM + */ + + /* Save parameters */ + mr r31,r3 mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 + /* + * Make sure we are running in 64 bits mode + * XXX kill that when no longer necessary, that is when prom_init finally + * becomes a 32 bits separate binary :) + */ bl .enable_64b_mode /* put a relocation offset into r3 */ @@ -1303,7 +1374,7 @@ /* Relocate the TOC from a virt addr to a real addr */ sub r2,r2,r3 - /* Save parameters */ + /* Restore parameters */ mr r3,r31 mr r4,r30 mr r5,r29 @@ -1312,17 +1383,8 @@ /* Do all of the interaction with OF client interface */ bl .prom_init - mr r23,r3 /* Save phys address we are running at */ - - /* Setup some critical 970 SPRs before switching MMU off */ - bl .__970_cpu_preinit - - li r24,0 /* cpu # */ - - /* Switch off MMU if not already */ - LOADADDR(r4, .__after_prom_start - KERNELBASE) - add r4,r4,r23 - bl .mmu_off + /* We never return */ + b . /* * At this point, r3 contains the physical address we are running at, @@ -1348,7 +1410,7 @@ li r3,0 /* target addr */ - // XXX FIXME: Use phys returned by OF (r23) + // XXX FIXME: Use phys returned by OF (r30) sub r4,r27,r26 /* source addr */ /* current address of _start */ /* i.e. where we are running */ @@ -1368,7 +1430,7 @@ mtctr r0 /* that we just made/relocated */ bctr -4: LOADADDR(r5,klimit) +4: LOADADDR(r5,klimit) // XXX FIXME: change klimit based on parameter r6 */ sub r5,r5,r26 ld r5,0(r5) /* get the value of klimit */ sub r5,r5,r27 @@ -1875,8 +1937,7 @@ mr r5,r26 bl .identify_cpu - /* Get the pointer to the segment table which is used by */ - /* stab_initialize */ + /* Setup a valid physical PACA pointer in SPRG3 for early_init */ LOADADDR(r27, boot_cpuid) sub r27,r27,r26 lwz r27,0(r27) @@ -1909,12 +1970,18 @@ 98: /* !(rpa hypervisor) || !(star) */ mtasr r4 /* set the stab location */ 99: - mfspr r6,SPRG3 - ld r3,PACASTABREAL(r6) /* restore r3 for stab_initialize */ - /* Initialize an initial memory mapping and turn on relocation. */ - bl .stab_initialize - bl .htab_initialize +#ifdef CONFIG_BOOTX_TEXT +/* bl .btext_setup_display */ +#endif + /* Do very early kernel initializations, including initial hash table setup + * and turn on relocation. */ + + /* Restore parameters passed from prom_init/kexec */ + mr r3,r31 + mr r4,r30 + mr r5,r29 + bl .early_init li r3,SYSTEMCFG_PHYS_ADDR /* r3 = ptr to systemcfg */ lwz r3,PLATFORM(r3) /* r3 = platform flags */ @@ -1980,13 +2047,7 @@ ld r2,PACATOC(r13) std r1,PACAKSAVE(r13) - /* Restore the parms passed in from the bootloader. */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - + /* Call some more initializations with a complete mmu environment */ bl .setup_system /* Load up the kernel context */ diff -urN linux-2.5/arch/ppc64/kernel/lmb.c linux-prom-clean/arch/ppc64/kernel/lmb.c --- linux-2.5/arch/ppc64/kernel/lmb.c 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/lmb.c 2004-09-17 20:58:41.000000000 +1000 @@ -22,6 +22,43 @@ struct lmb lmb; +#undef DEBUG + +void lmb_dump_all(void) +{ +#ifdef DEBUG + unsigned long i; + struct lmb *_lmb = &lmb; + + udbg_printf("lmb_dump_all:\n"); + udbg_printf(" memory.cnt = 0x%lx\n", + _lmb->memory.cnt); + udbg_printf(" memory.size = 0x%lx\n", + _lmb->memory.size); + for (i=0; i < _lmb->memory.cnt ;i++) { + udbg_printf(" memory.region[0x%x].base = 0x%lx\n", + i, _lmb->memory.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->memory.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->memory.region[i].size); + } + + udbg_printf("\n reserved.cnt = 0x%lx\n", + _lmb->reserved.cnt); + udbg_printf(" reserved.size = 0x%lx\n", + _lmb->reserved.size); + for (i=0; i < _lmb->reserved.cnt ;i++) { + udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", + i, _lmb->reserved.region[i].base); + udbg_printf(" .physbase = 0x%lx\n", + _lmb->reserved.region[i].physbase); + udbg_printf(" .size = 0x%lx\n", + _lmb->reserved.region[i].size); + } +#endif /* DEBUG */ +} + static unsigned long __init lmb_addrs_overlap(unsigned long base1, unsigned long size1, unsigned long base2, unsigned long size2) @@ -71,8 +108,7 @@ void __init lmb_init(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; /* Create a dummy zero size LMB which will get coalesced away later. * This simplifies the lmb_add() code below... @@ -94,8 +130,7 @@ unsigned long i; unsigned long mem_size = 0; unsigned long size_mask = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS unsigned long physbase = 0; #endif @@ -178,8 +213,7 @@ long __init lmb_add(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->memory); /* On pSeries LPAR systems, the first LMB is our RMO region. */ @@ -193,8 +227,7 @@ long __init lmb_reserve(unsigned long base, unsigned long size) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_rgn = &(_lmb->reserved); return lmb_add_region(_rgn, base, size); @@ -227,8 +260,7 @@ { long i, j; unsigned long base = 0; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); struct lmb_region *_rsv = &(_lmb->reserved); @@ -263,8 +295,7 @@ unsigned long __init lmb_phys_mem_size(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; #ifdef CONFIG_MSCHUNKS return _lmb->memory.size; #else @@ -282,8 +313,7 @@ unsigned long __init lmb_end_of_DRAM(void) { - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); int idx = _mem->cnt - 1; @@ -300,8 +330,7 @@ lmb_abs_to_phys(unsigned long aa) { unsigned long i, pa = aa; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); + struct lmb *_lmb = &lmb; struct lmb_region *_mem = &(_lmb->memory); for (i=0; i < _mem->cnt; i++) { diff -urN linux-2.5/arch/ppc64/kernel/misc.S linux-prom-clean/arch/ppc64/kernel/misc.S --- linux-2.5/arch/ppc64/kernel/misc.S 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/misc.S 2004-09-15 21:53:26.000000000 +1000 @@ -454,17 +454,6 @@ sync blr -_GLOBAL(_get_PVR) - mfspr r3,PVR - blr - -_GLOBAL(_get_PIR) - mfspr r3,PIR - blr - -_GLOBAL(_get_HID0) - mfspr r3,HID0 - blr _GLOBAL(cvt_fd) lfd 0,0(r5) /* load up fpscr value */ diff -urN linux-2.5/arch/ppc64/kernel/open_pic.c linux-prom-clean/arch/ppc64/kernel/open_pic.c --- linux-2.5/arch/ppc64/kernel/open_pic.c 2004-07-29 08:46:55.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/open_pic.c 2004-09-17 17:28:11.000000000 +1000 @@ -362,7 +362,6 @@ find_ISUs(); /* Initialize timer interrupts */ - ppc64_boot_msg(0x21, "OpenPic Timer"); for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { /* Disabled, Priority 0 */ openpic_inittimer(i, 0, openpic_vec_timer+i); @@ -372,7 +371,6 @@ #ifdef CONFIG_SMP /* Initialize IPI interrupts */ - ppc64_boot_msg(0x22, "OpenPic IPI"); openpic_test_broken_IPI(); for (i = 0; i < OPENPIC_NUM_IPI; i++) { /* Disabled, Priority 10..13 */ @@ -384,8 +382,6 @@ #endif /* Initialize external interrupts */ - ppc64_boot_msg(0x23, "OpenPic Ext"); - openpic_set_priority(0xf); /* SIOint (8259 cascade) is special */ @@ -420,7 +416,6 @@ irq_desc[i].handler = &open_pic; /* Initialize the spurious interrupt */ - ppc64_boot_msg(0x24, "OpenPic Spurious"); openpic_set_spurious(openpic_vec_spurious); openpic_set_priority(0); diff -urN linux-2.5/arch/ppc64/kernel/open_pic_u3.c linux-prom-clean/arch/ppc64/kernel/open_pic_u3.c --- linux-2.5/arch/ppc64/kernel/open_pic_u3.c 2004-07-08 06:27:06.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/open_pic_u3.c 2004-09-17 17:28:22.000000000 +1000 @@ -344,5 +344,5 @@ openpic2_set_priority(0); openpic2_disable_8259_pass_through(); - ppc64_boot_msg(0x25, "OpenPic2 Done"); + ppc64_boot_msg(0x25, "OpenPic U3 Done"); } diff -urN linux-2.5/arch/ppc64/kernel/pSeries_htab.c linux-prom-clean/arch/ppc64/kernel/pSeries_htab.c --- linux-2.5/arch/ppc64/kernel/pSeries_htab.c 2004-09-17 22:20:11.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pSeries_htab.c 2004-09-15 17:30:31.000000000 +1000 @@ -220,10 +220,12 @@ if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { tlbiel(va); } else { - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) spin_lock(&pSeries_tlbie_lock); tlbie(va, large); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock(&pSeries_tlbie_lock); } @@ -243,6 +245,7 @@ unsigned long vsid, va, vpn, flags; long slot; HPTE *hptep; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); vsid = get_kernel_vsid(ea); va = (vsid << 28) | (ea & 0x0fffffff); @@ -256,10 +259,10 @@ set_pp_bit(newpp, hptep); /* Ensure it is out of the tlb too */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock_irqsave(&pSeries_tlbie_lock, flags); tlbie(va, 0); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock_irqrestore(&pSeries_tlbie_lock, flags); } @@ -270,6 +273,7 @@ Hpte_dword0 dw0; unsigned long avpn = va >> 23; unsigned long flags; + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); if (large) avpn &= ~0x1UL; @@ -291,10 +295,10 @@ if ((cur_cpu_spec->cpu_features & CPU_FTR_TLBIEL) && !large && local) { tlbiel(va); } else { - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock(&pSeries_tlbie_lock); tlbie(va, large); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock(&pSeries_tlbie_lock); } local_irq_restore(flags); @@ -364,8 +368,9 @@ asm volatile("ptesync":::"memory"); } else { - /* XXX double check that it is safe to take this late */ - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); + + if (lock_tlbie) spin_lock(&pSeries_tlbie_lock); asm volatile("ptesync":::"memory"); @@ -375,7 +380,7 @@ asm volatile("eieio; tlbsync; ptesync":::"memory"); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock(&pSeries_tlbie_lock); } diff -urN linux-2.5/arch/ppc64/kernel/pSeries_iommu.c linux-prom-clean/arch/ppc64/kernel/pSeries_iommu.c --- linux-2.5/arch/ppc64/kernel/pSeries_iommu.c 2004-08-26 15:46:30.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pSeries_iommu.c 2004-09-16 13:46:10.000000000 +1000 @@ -166,24 +166,25 @@ struct device_node *dn, struct iommu_table *tbl) { - phandle node; - unsigned long i; - struct of_tce_table *oft; - - node = ((struct device_node *)(phb->arch_data))->node; - - oft = NULL; - - for (i=0; of_tce_table[i].node; i++) - if(of_tce_table[i].node == node) { - oft = &of_tce_table[i]; - break; - } - - if (!oft) - panic("PCI_DMA: iommu_table_setparms: Can't find phb named '%s' in of_tce_table\n", dn->full_name); - - memset((void *)oft->base, 0, oft->size); + struct device_node *node; + unsigned long *basep; + unsigned int *sizep; + + node = (struct device_node *)phb->arch_data; + + if (get_property(node, "linux,has-tce-table", NULL) == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has no tce table !\n", + dn->full_name); + return; + } + basep = (unsigned long *)get_property(node, "linux,tce-base", NULL); + sizep = (unsigned int *)get_property(node, "linux,tce-size", NULL); + if (basep == NULL || sizep == NULL) { + printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has missing tce" + " entries !\n", dn->full_name); + return; + } + memset((void *)(*basep), 0, *sizep); tbl->it_busno = phb->bus->number; @@ -207,7 +208,7 @@ if (phb->dma_window_base_cur > (1 << 19)) panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); - tbl->it_base = oft->base; + tbl->it_base = *basep; tbl->it_index = 0; tbl->it_entrysize = sizeof(union tce_entry); tbl->it_blocksize = 16; diff -urN linux-2.5/arch/ppc64/kernel/pSeries_lpar.c linux-prom-clean/arch/ppc64/kernel/pSeries_lpar.c --- linux-2.5/arch/ppc64/kernel/pSeries_lpar.c 2004-09-17 22:20:11.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pSeries_lpar.c 2004-09-17 22:18:42.000000000 +1000 @@ -352,24 +352,37 @@ } } +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +#if 0 +void udbg_init_debug_lpar(void) +{ + vtermno = 0; + ppc_md.udbg_putc = udbg_putcLP; + ppc_md.udbg_getc = udbg_getcLP; + ppc_md.udbg_getc_poll = udbg_getc_pollLP; +} +#endif + /* returns 0 if couldn't find or use /chosen/stdout as console */ static int find_udbg_vterm(void) { struct device_node *stdout_node; + phandle *stdout_ph; u32 *termno; char *name; int found = 0; /* find the boot console from /chosen/stdout */ - if (!of_stdout_device) { - printk(KERN_WARNING "couldn't get path from /chosen/stdout!\n"); - return found; - } - stdout_node = of_find_node_by_path(of_stdout_device); - if (!stdout_node) { - printk(KERN_WARNING "couldn't find node from /chosen/stdout\n"); - return found; - } + if (!of_chosen) + return 0; + stdout_ph = (phandle *)get_property(of_chosen, "linux,stdout-package", NULL); + if (stdout_ph == NULL) + return 0; + stdout_node = of_find_node_by_phandle(*stdout_ph); + if (!stdout_node) + return 0; /* now we have the stdout node; figure out what type of device it is. */ name = (char *)get_property(stdout_node, "name", NULL); @@ -391,15 +404,17 @@ } else { /* XXX implement udbg_putcLP_vtty for hvterm-protocol1 case */ printk(KERN_WARNING "%s doesn't speak hvterm1; " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } } else if (strncmp(name, "serial", 6)) { /* XXX fix ISA serial console */ printk(KERN_WARNING "serial stdout on LPAR ('%s')! " - "can't print udbg messages\n", of_stdout_device); + "can't print udbg messages\n", + stdout_node->full_name); } else { printk(KERN_WARNING "don't know how to print to stdout '%s'\n", - of_stdout_device); + stdout_node->full_name); } out: @@ -532,6 +547,19 @@ return -1; } +void pSeries_lpar_hptab_clear(void) +{ + unsigned long size_bytes = 1UL << naca->pftSize; + unsigned long hpte_count = size_bytes >> 4; + unsigned long lpar_rc; + unsigned long dummy1, dummy2; + int i; + + /* TODO: Use bulk call */ + for (i = 0; i < hpte_count; i++) + plpar_pte_remove(0, i, 0, &dummy1, &dummy2); +} + /* * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and * the low 3 bits of flags happen to line up. So no transform is needed. @@ -660,14 +688,15 @@ int i; unsigned long flags; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); + int lock_tlbie = !(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); for (i = 0; i < number; i++) flush_hash_page(context, batch->addr[i], batch->pte[i], local); - if (!(cur_cpu_spec->cpu_features & CPU_FTR_LOCKLESS_TLBIE)) + if (lock_tlbie) spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); } diff -urN linux-2.5/arch/ppc64/kernel/pSeries_pci.c linux-prom-clean/arch/ppc64/kernel/pSeries_pci.c --- linux-2.5/arch/ppc64/kernel/pSeries_pci.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pSeries_pci.c 2004-09-15 21:53:26.000000000 +1000 @@ -765,7 +765,8 @@ phbs_fixup_io(); chrp_request_regions(); pci_fix_bus_sysdata(); - if (!ppc64_iommu_off) + + if (!of_chosen || !get_property(of_chosen, "linux,iommu-off", NULL)) iommu_setup_pSeries(); } diff -urN linux-2.5/arch/ppc64/kernel/pmac_feature.c linux-prom-clean/arch/ppc64/kernel/pmac_feature.c --- linux-2.5/arch/ppc64/kernel/pmac_feature.c 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pmac_feature.c 2004-09-17 14:34:55.000000000 +1000 @@ -44,9 +44,9 @@ #undef DEBUG_FEATURE #ifdef DEBUG_FEATURE -#define DBG(fmt,...) printk(KERN_DEBUG fmt) +#define DBG(fmt...) printk(KERN_DEBUG fmt) #else -#define DBG(fmt,...) +#define DBG(fmt...) #endif /* diff -urN linux-2.5/arch/ppc64/kernel/pmac_iommu.c linux-prom-clean/arch/ppc64/kernel/pmac_iommu.c --- linux-2.5/arch/ppc64/kernel/pmac_iommu.c 2004-07-08 06:27:06.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pmac_iommu.c 2004-09-17 14:34:55.000000000 +1000 @@ -37,13 +37,14 @@ #include #include #include -#include #include #include #include #include #include #include +#include + #include "pci.h" @@ -76,8 +77,8 @@ #define DARTMAP_RPNMASK 0x00ffffff /* Physical base address and size of the DART table */ -unsigned long dart_tablebase; -unsigned long dart_tablesize; +unsigned long dart_tablebase; /* exported to htab_initialize */ +static unsigned long dart_tablesize; /* Virtual base address of the DART table */ static u32 *dart_vbase; @@ -300,6 +301,22 @@ } } +void __init pmac_iommu_alloc(void) +{ + /* Only reserve DART space if machine has more than 2GB of RAM + * or if requested with iommu=on on cmdline. + */ + if (lmb_end_of_DRAM() <= 0x80000000ull && + get_property(of_chosen, "linux,iommu-force-on", NULL) == NULL) + return; + /* 512 pages (2MB) is max DART tablesize. */ + dart_tablesize = 1UL << 21; + /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we + * will blow up an entire large page anyway in the kernel mapping + */ + dart_tablebase = (unsigned long) + abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - + printk(KERN_INFO "U3-DART allocated at: %lx\n", dart_tablebase); +} diff -urN linux-2.5/arch/ppc64/kernel/pmac_setup.c linux-prom-clean/arch/ppc64/kernel/pmac_setup.c --- linux-2.5/arch/ppc64/kernel/pmac_setup.c 2004-07-08 06:27:06.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/pmac_setup.c 2004-09-17 14:34:55.000000000 +1000 @@ -77,14 +77,10 @@ #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ extern int powersave_nap; -int sccdbg; +int sccdbg = 1; extern void udbg_init_scc(struct device_node *np); -#ifdef CONFIG_BOOTX_TEXT -void pmac_progress(char *s, unsigned short hex); -#endif - void __pmac pmac_show_cpuinfo(struct seq_file *m) { struct device_node *np; @@ -183,67 +179,13 @@ #endif } -extern char *bootpath; -extern char *bootdevice; -void *boot_host; -int boot_target; -int boot_part; -extern dev_t boot_dev; - #ifdef CONFIG_SCSI -void __init note_scsi_host(struct device_node *node, void *host) +void note_scsi_host(struct device_node *node, void *host) { - int l; - char *p; - - l = strlen(node->full_name); - if (bootpath != NULL && bootdevice != NULL - && strncmp(node->full_name, bootdevice, l) == 0 - && (bootdevice[l] == '/' || bootdevice[l] == 0)) { - boot_host = host; - /* - * There's a bug in OF 1.0.5. (Why am I not surprised.) - * If you pass a path like scsi/sd@1:0 to canon, it returns - * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 - * That is, the scsi target number doesn't get preserved. - * So we pick the target number out of bootpath and use that. - */ - p = strstr(bootpath, "/sd@"); - if (p != NULL) { - p += 4; - boot_target = simple_strtoul(p, NULL, 10); - p = strchr(p, ':'); - if (p != NULL) - boot_part = simple_strtoul(p + 1, NULL, 10); - } - } + /* Obsolete */ } #endif -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) -static dev_t __init find_ide_boot(void) -{ - char *p; - int n; - dev_t __init pmac_find_ide_boot(char *bootdevice, int n); - - if (bootdevice == NULL) - return 0; - p = strrchr(bootdevice, '/'); - if (p == NULL) - return 0; - n = p - bootdevice; - - return pmac_find_ide_boot(bootdevice, n); -} -#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */ - -void __init find_boot_device(void) -{ -#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) - boot_dev = find_ide_boot(); -#endif -} static int initializing = 1; @@ -258,7 +200,7 @@ /* can't be __init - can be called whenever a disk is first accessed */ void __pmac note_bootable_part(dev_t dev, int part, int goodness) { - static int found_boot = 0; + extern dev_t boot_dev; char *p; if (!initializing) @@ -270,10 +212,6 @@ if (p != NULL && (p == saved_command_line || p[-1] == ' ')) return; - if (!found_boot) { - find_boot_device(); - found_boot = 1; - } if (!boot_dev || dev == boot_dev) { ROOT_DEV = dev + part; boot_dev = 0; @@ -315,9 +253,6 @@ /* * Early initialization. - * Relocation is on but do not reference unbolted pages - * Also, device-tree hasn't been "finished", so don't muck with - * it too much */ void __init pmac_init_early(void) { @@ -417,17 +352,30 @@ core_initcall(pmac_irq_cascade_init); -void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +static void __init pmac_progress(char *s, unsigned short hex) +{ + if (sccdbg) { + udbg_puts(s); + udbg_putc('\n'); + } +#ifdef CONFIG_BOOTX_TEXT + else if (boot_text_mapped) { + btext_drawstring(s); + btext_drawchar('\n'); + } +#endif /* CONFIG_BOOTX_TEXT */ +} + +void __init pmac_init(void) { /* Probe motherboard chipset */ pmac_feature_init(); /* Init SCC */ - if (strstr(cmd_line, "sccdbg")) { + if (strstr(cmd_line, "sccdbg")) { sccdbg = 1; udbg_init_scc(NULL); - } + } /* Fill up the machine description */ ppc_md.setup_arch = pmac_setup_arch; @@ -450,28 +398,12 @@ ppc_md.feature_call = pmac_do_feature_call; -#ifdef CONFIG_BOOTX_TEXT ppc_md.progress = pmac_progress; -#endif /* CONFIG_BOOTX_TEXT */ if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); } -#ifdef CONFIG_BOOTX_TEXT -void __init pmac_progress(char *s, unsigned short hex) -{ - if (sccdbg) { - udbg_puts(s); - udbg_putc('\n'); - } - else if (boot_text_mapped) { - btext_drawstring(s); - btext_drawchar('\n'); - } -} -#endif /* CONFIG_BOOTX_TEXT */ - static int __init pmac_declare_of_platform_devices(void) { struct device_node *np; diff -urN linux-2.5/arch/ppc64/kernel/ppc_ksyms.c linux-prom-clean/arch/ppc64/kernel/ppc_ksyms.c --- linux-2.5/arch/ppc64/kernel/ppc_ksyms.c 2004-09-09 17:33:52.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/ppc_ksyms.c 2004-09-15 21:53:26.000000000 +1000 @@ -119,7 +119,6 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(flush_instruction_cache); -EXPORT_SYMBOL(_get_PVR); EXPORT_SYMBOL(giveup_fpu); #ifdef CONFIG_ALTIVEC EXPORT_SYMBOL(giveup_altivec); diff -urN linux-2.5/arch/ppc64/kernel/prom.c linux-prom-clean/arch/ppc64/kernel/prom.c --- linux-2.5/arch/ppc64/kernel/prom.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/prom.c 2004-09-17 22:10:35.000000000 +1000 @@ -15,7 +15,7 @@ * 2 of the License, or (at your option) any later version. */ -#undef DEBUG_PROM +#undef DEBUG #include #include @@ -54,1696 +54,53 @@ #include #include "open_pic.h" -#ifdef CONFIG_LOGO_LINUX_CLUT224 -#include -extern const struct linux_logo logo_linux_clut224; -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This value does need to be big enough to - * ensure that we don't lose things like the interrupt-map property - * on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) - -/* - * prom_init() is called very early on, before the kernel text - * and data have been mapped to KERNELBASE. At this point the code - * is running at whatever address it has been loaded at, so - * references to extern and static variables must be relocated - * explicitly. The procedure reloc_offset() returns the address - * we're currently running at minus the address we were linked at. - * (Note that strings count as static variables.) - * - * Because OF may have mapped I/O devices into the area starting at - * KERNELBASE, particularly on CHRP machines, we can't safely call - * OF once the kernel has been mapped to KERNELBASE. Therefore all - * OF calls should be done within prom_init(), and prom_init() - * and all routines called within it must be careful to relocate - * references as necessary. - * - * Note that the bss is cleared *after* prom_init runs, so we have - * to make sure that any static or extern variables it accesses - * are put in the data segment. - */ - - -#define PROM_BUG() do { \ - prom_printf("kernel BUG at %s line 0x%x!\n", \ - RELOC(__FILE__), __LINE__); \ - __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ -} while (0) - -#ifdef DEBUG_PROM -#define prom_debug(x...) prom_printf(x) -#else -#define prom_debug(x...) -#endif - - -struct pci_reg_property { - struct pci_address addr; - u32 size_hi; - u32 size_lo; -}; - - -struct isa_reg_property { - u32 space; - u32 address; - u32 size; -}; - -struct pci_intr_map { - struct pci_address addr; - u32 dunno; - phandle int_ctrler; - u32 intr; -}; - - -typedef unsigned long interpret_func(struct device_node *, unsigned long, - int, int, int); - -#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ -#define FB_MAX 8 -#endif - -/* prom structure */ -struct prom_t prom; - -char *prom_display_paths[FB_MAX] __initdata = { NULL, }; -phandle prom_display_nodes[FB_MAX] __initdata; -unsigned int prom_num_displays = 0; -char *of_stdout_device = NULL; - -static int iommu_force_on; -int ppc64_iommu_off; - -extern struct rtas_t rtas; -extern unsigned long klimit; -extern struct lmb lmb; - -#define MAX_PHB (32 * 6) /* 32 drawers * 6 PHBs/drawer */ -struct of_tce_table of_tce_table[MAX_PHB + 1]; - -char *bootpath = NULL; -char *bootdevice = NULL; - -int boot_cpuid = 0; -#define MAX_CPU_THREADS 2 - -struct device_node *allnodes = NULL; -/* use when traversing tree through the allnext, child, sibling, - * or parent members of struct device_node. - */ -static rwlock_t devtree_lock = RW_LOCK_UNLOCKED; - -extern unsigned long reloc_offset(void); - -extern void enter_prom(struct prom_args *args); -extern void copy_and_flush(unsigned long dest, unsigned long src, - unsigned long size, unsigned long offset); - -unsigned long dev_tree_size; -unsigned long _get_PIR(void); - -#ifdef CONFIG_HMT -struct { - unsigned int pir; - unsigned int threadid; -} hmt_thread_data[NR_CPUS]; -#endif /* CONFIG_HMT */ - -char testString[] = "LINUX\n"; - -/* - * This are used in calls to call_prom. The 4th and following - * arguments to call_prom should be 32-bit values. 64 bit values - * are truncated to 32 bits (and fortunately don't get interpreted - * as two arguments). - */ -#define ADDR(x) (u32) ((unsigned long)(x) - offset) - -/* This is the one and *ONLY* place where we actually call open - * firmware from, since we need to make sure we're running in 32b - * mode when we do. We switch back to 64b mode upon return. - */ - -#define PROM_ERROR (-1) - -static int __init call_prom(const char *service, int nargs, int nret, ...) -{ - int i; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - va_list list; - - _prom->args.service = ADDR(service); - _prom->args.nargs = nargs; - _prom->args.nret = nret; - _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); - - va_start(list, nret); - for (i=0; i < nargs; i++) - _prom->args.args[i] = va_arg(list, prom_arg_t); - va_end(list); - - for (i=0; i < nret ;i++) - _prom->args.rets[i] = 0; - - enter_prom(&_prom->args); - - return (nret > 0)? _prom->args.rets[0]: 0; -} - - -static void __init prom_print(const char *msg) -{ - const char *p, *q; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - if (_prom->stdout == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - ++q; - call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); - } -} - - -static void __init prom_print_hex(unsigned long val) -{ - unsigned long offset = reloc_offset(); - int i, nibbles = sizeof(val)*2; - char buf[sizeof(val)*2+1]; - struct prom_t *_prom = PTRRELOC(&prom); - - for (i = nibbles-1; i >= 0; i--) { - buf[i] = (val & 0xf) + '0'; - if (buf[i] > '9') - buf[i] += ('a'-'0'-10); - val >>= 4; - } - buf[nibbles] = '\0'; - call_prom("write", 3, 1, _prom->stdout, buf, nibbles); -} - - -static void __init prom_printf(const char *format, ...) -{ - unsigned long offset = reloc_offset(); - const char *p, *q, *s; - va_list args; - unsigned long v; - struct prom_t *_prom = PTRRELOC(&prom); - - va_start(args, format); - for (p = PTRRELOC(format); *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, _prom->stdout, p, q - p); - if (*q == 0) - break; - if (*q == '\n') { - ++q; - call_prom("write", 3, 1, _prom->stdout, - ADDR("\r\n"), 2); - continue; - } - ++q; - if (*q == 0) - break; - switch (*q) { - case 's': - ++q; - s = va_arg(args, const char *); - prom_print(s); - break; - case 'x': - ++q; - v = va_arg(args, unsigned long); - prom_print_hex(v); - break; - } - } -} - - -static void __init __attribute__((noreturn)) prom_panic(const char *reason) -{ - unsigned long offset = reloc_offset(); - - prom_print(PTRRELOC(reason)); - /* ToDo: should put up an SRC here */ - call_prom("exit", 0, 0); - - for (;;) /* should never get here */ - ; -} - - -static int __init prom_next_node(phandle *nodep) -{ - phandle node; - - if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - } -} - -static int __init prom_getprop(phandle node, const char *pname, - void *value, size_t valuelen) -{ - unsigned long offset = reloc_offset(); - - return call_prom("getprop", 4, 1, node, ADDR(pname), - (u32)(unsigned long) value, (u32) valuelen); -} - -static void __init prom_initialize_naca(void) -{ - phandle node; - char type[64]; - unsigned long num_cpus = 0; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct naca_struct *_naca = RELOC(naca); - struct systemcfg *_systemcfg = RELOC(systemcfg); - - /* NOTE: _naca->debug_switch is already initialized. */ - prom_debug("prom_initialize_naca: start...\n"); - - _naca->pftSize = 0; /* ilog2 of htab size. computed below. */ - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (!strcmp(type, RELOC("cpu"))) { - num_cpus += 1; - - /* We're assuming *all* of the CPUs have the same - * d-cache and i-cache sizes... -Peter - */ - if ( num_cpus == 1 ) { - u32 size, lsize; - const char *dc, *ic; - - if (_systemcfg->platform == PLATFORM_POWERMAC){ - dc = "d-cache-block-size"; - ic = "i-cache-block-size"; - } else { - dc = "d-cache-line-size"; - ic = "i-cache-line-size"; - } - - prom_getprop(node, "d-cache-size", - &size, sizeof(size)); - - prom_getprop(node, dc, &lsize, sizeof(lsize)); - - _systemcfg->dCacheL1Size = size; - _systemcfg->dCacheL1LineSize = lsize; - _naca->dCacheL1LogLineSize = __ilog2(lsize); - _naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize; - - prom_getprop(node, "i-cache-size", - &size, sizeof(size)); - - prom_getprop(node, ic, &lsize, sizeof(lsize)); - - _systemcfg->iCacheL1Size = size; - _systemcfg->iCacheL1LineSize = lsize; - _naca->iCacheL1LogLineSize = __ilog2(lsize); - _naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize; - - if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) { - u32 pft_size[2]; - prom_getprop(node, "ibm,pft-size", - &pft_size, sizeof(pft_size)); - /* pft_size[0] is the NUMA CEC cookie */ - _naca->pftSize = pft_size[1]; - } - } - } else if (!strcmp(type, RELOC("serial"))) { - phandle isa, pci; - struct isa_reg_property reg; - union pci_range ranges; - - if (_systemcfg->platform == PLATFORM_POWERMAC) - continue; - type[0] = 0; - prom_getprop(node, "ibm,aix-loc", type, sizeof(type)); - - if (strcmp(type, RELOC("S1"))) - continue; - - prom_getprop(node, "reg", ®, sizeof(reg)); - - isa = call_prom("parent", 1, 1, node); - if (!isa) - PROM_BUG(); - pci = call_prom("parent", 1, 1, isa); - if (!pci) - PROM_BUG(); - - prom_getprop(pci, "ranges", &ranges, sizeof(ranges)); - - if ( _prom->encode_phys_size == 32 ) - _naca->serialPortAddr = ranges.pci32.phys+reg.address; - else { - _naca->serialPortAddr = - ((((unsigned long)ranges.pci64.phys_hi) << 32) | - (ranges.pci64.phys_lo)) + reg.address; - } - } - } - - if (_systemcfg->platform == PLATFORM_POWERMAC) - _naca->interrupt_controller = IC_OPEN_PIC; - else { - _naca->interrupt_controller = IC_INVALID; - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "name", type, sizeof(type)); - if (strcmp(type, RELOC("interrupt-controller"))) - continue; - prom_getprop(node, "compatible", type, sizeof(type)); - if (strstr(type, RELOC("open-pic"))) - _naca->interrupt_controller = IC_OPEN_PIC; - else if (strstr(type, RELOC("ppc-xicp"))) - _naca->interrupt_controller = IC_PPC_XIC; - else - prom_printf("prom: failed to recognize" - " interrupt-controller\n"); - break; - } - } - - if (_naca->interrupt_controller == IC_INVALID) { - prom_printf("prom: failed to find interrupt-controller\n"); - PROM_BUG(); - } - - /* We gotta have at least 1 cpu... */ - if ( (_systemcfg->processorCount = num_cpus) < 1 ) - PROM_BUG(); - - _systemcfg->physicalMemorySize = lmb_phys_mem_size(); - - if (_systemcfg->platform == PLATFORM_PSERIES || - _systemcfg->platform == PLATFORM_POWERMAC) { - unsigned long rnd_mem_size, pteg_count; - - /* round mem_size up to next power of 2 */ - rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize); - if (rnd_mem_size < _systemcfg->physicalMemorySize) - rnd_mem_size <<= 1; - - /* # pages / 2 */ - pteg_count = (rnd_mem_size >> (12 + 1)); - - _naca->pftSize = __ilog2(pteg_count << 7); - } - - if (_naca->pftSize == 0) { - prom_printf("prom: failed to compute pftSize!\n"); - PROM_BUG(); - } - - /* Add an eye catcher and the systemcfg layout version number */ - strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64")); - _systemcfg->version.major = SYSTEMCFG_MAJOR; - _systemcfg->version.minor = SYSTEMCFG_MINOR; - _systemcfg->processor = _get_PVR(); - - prom_debug("systemcfg->processorCount = 0x%x\n", - _systemcfg->processorCount); - prom_debug("systemcfg->physicalMemorySize = 0x%x\n", - _systemcfg->physicalMemorySize); - prom_debug("naca->pftSize = 0x%x\n", - _naca->pftSize); - prom_debug("systemcfg->dCacheL1LineSize = 0x%x\n", - _systemcfg->dCacheL1LineSize); - prom_debug("systemcfg->iCacheL1LineSize = 0x%x\n", - _systemcfg->iCacheL1LineSize); - prom_debug("naca->serialPortAddr = 0x%x\n", - _naca->serialPortAddr); - prom_debug("naca->interrupt_controller = 0x%x\n", - _naca->interrupt_controller); - prom_debug("systemcfg->platform = 0x%x\n", - _systemcfg->platform); - prom_debug("prom_initialize_naca: end...\n"); -} - - -static void __init early_cmdline_parse(void) -{ - unsigned long offset = reloc_offset(); - char *opt; -#ifndef CONFIG_PMAC_DART - struct systemcfg *_systemcfg = RELOC(systemcfg); -#endif - - opt = strstr(RELOC(cmd_line), RELOC("iommu=")); - if (opt) { - prom_printf("opt is:%s\n", opt); - opt += 6; - while (*opt && *opt == ' ') - opt++; - if (!strncmp(opt, RELOC("off"), 3)) - RELOC(ppc64_iommu_off) = 1; - else if (!strncmp(opt, RELOC("force"), 5)) - RELOC(iommu_force_on) = 1; - } - -#ifndef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) { - RELOC(ppc64_iommu_off) = 1; - prom_printf("DART disabled on PowerMac !\n"); - } -#endif -} - -#ifdef DEBUG_PROM -void prom_dump_lmb(void) -{ - unsigned long i; - unsigned long offset = reloc_offset(); - struct lmb *_lmb = PTRRELOC(&lmb); - - prom_printf("\nprom_dump_lmb:\n"); - prom_printf(" memory.cnt = 0x%x\n", - _lmb->memory.cnt); - prom_printf(" memory.size = 0x%x\n", - _lmb->memory.size); - for (i=0; i < _lmb->memory.cnt ;i++) { - prom_printf(" memory.region[0x%x].base = 0x%x\n", - i, _lmb->memory.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->memory.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->memory.region[i].size); - } - - prom_printf("\n reserved.cnt = 0x%x\n", - _lmb->reserved.cnt); - prom_printf(" reserved.size = 0x%x\n", - _lmb->reserved.size); - for (i=0; i < _lmb->reserved.cnt ;i++) { - prom_printf(" reserved.region[0x%x\n].base = 0x%x\n", - i, _lmb->reserved.region[i].base); - prom_printf(" .physbase = 0x%x\n", - _lmb->reserved.region[i].physbase); - prom_printf(" .size = 0x%x\n", - _lmb->reserved.region[i].size); - } -} -#endif /* DEBUG_PROM */ - -static void __init prom_initialize_lmb(void) -{ - phandle node; - char type[64]; - unsigned long i, offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct systemcfg *_systemcfg = RELOC(systemcfg); - union lmb_reg_property reg; - unsigned long lmb_base, lmb_size; - unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8; - - lmb_init(); - - /* XXX Quick HACK. Proper fix is to drop those structures and properly use - * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2 - */ - if (_systemcfg->platform == PLATFORM_POWERMAC) - bytes_per_reg = 12; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - - if (strcmp(type, RELOC("memory"))) - continue; - - num_regs = prom_getprop(node, "reg", ®, sizeof(reg)) - / bytes_per_reg; - - for (i=0; i < num_regs ;i++) { - if (_systemcfg->platform == PLATFORM_POWERMAC) { - lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32; - lmb_base |= (unsigned long)reg.addrPM[i].address_lo; - lmb_size = reg.addrPM[i].size; - } else if (_prom->encode_phys_size == 32) { - lmb_base = reg.addr32[i].address; - lmb_size = reg.addr32[i].size; - } else { - lmb_base = reg.addr64[i].address; - lmb_size = reg.addr64[i].size; - } - - /* We limit memory to 2GB if the IOMMU is off */ - if (RELOC(ppc64_iommu_off)) { - if (lmb_base >= 0x80000000UL) - continue; - - if ((lmb_base + lmb_size) > 0x80000000UL) - lmb_size = 0x80000000UL - lmb_base; - } - - if (lmb_add(lmb_base, lmb_size) < 0) - prom_printf("Too many LMB's, discarding this one...\n"); - } - - } - - lmb_analyze(); -#ifdef DEBUG_PROM - prom_dump_lmb(); -#endif /* DEBUG_PROM */ -} - -static void __init -prom_instantiate_rtas(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct rtas_t *_rtas = PTRRELOC(&rtas); - struct systemcfg *_systemcfg = RELOC(systemcfg); - ihandle prom_rtas; - u32 getprop_rval; - char hypertas_funcs[4]; - - prom_debug("prom_instantiate_rtas: start...\n"); - - prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - if (prom_rtas != (ihandle) -1) { - unsigned long x; - x = prom_getprop(prom_rtas, "ibm,hypertas-functions", - hypertas_funcs, sizeof(hypertas_funcs)); - - if (x != PROM_ERROR) { - prom_printf("Hypertas detected, assuming LPAR !\n"); - _systemcfg->platform = PLATFORM_PSERIES_LPAR; - } - - prom_getprop(prom_rtas, "rtas-size", - &getprop_rval, sizeof(getprop_rval)); - _rtas->size = getprop_rval; - prom_printf("instantiating rtas"); - if (_rtas->size != 0) { - unsigned long rtas_region = RTAS_INSTANTIATE_MAX; - - /* Grab some space within the first RTAS_INSTANTIATE_MAX bytes - * of physical memory (or within the RMO region) because RTAS - * runs in 32-bit mode and relocate off. - */ - if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) { - struct lmb *_lmb = PTRRELOC(&lmb); - rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX); - } - - _rtas->base = lmb_alloc_base(_rtas->size, PAGE_SIZE, rtas_region); - - prom_printf(" at 0x%x", _rtas->base); - - prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); - prom_printf("..."); - - if (call_prom("call-method", 3, 2, - ADDR("instantiate-rtas"), - prom_rtas, - _rtas->base) != PROM_ERROR) { - _rtas->entry = (long)_prom->args.rets[1]; - } - RELOC(rtas_rmo_buf) - = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, - rtas_region); - } - - if (_rtas->entry <= 0) { - prom_printf(" failed\n"); - } else { - prom_printf(" done\n"); - } - - prom_debug("rtas->base = 0x%x\n", _rtas->base); - prom_debug("rtas->entry = 0x%x\n", _rtas->entry); - prom_debug("rtas->size = 0x%x\n", _rtas->size); - } - prom_debug("prom_instantiate_rtas: end...\n"); -} - - -#ifdef CONFIG_PMAC_DART -static void __init prom_initialize_dart_table(void) -{ - unsigned long offset = reloc_offset(); - extern unsigned long dart_tablebase; - extern unsigned long dart_tablesize; - - /* Only reserve DART space if machine has more than 2GB of RAM - * or if requested with iommu=on on cmdline. - */ - if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on)) - return; - - /* 512 pages (2MB) is max DART tablesize. */ - RELOC(dart_tablesize) = 1UL << 21; - /* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we - * will blow up an entire large page anyway in the kernel mapping - */ - RELOC(dart_tablebase) = (unsigned long) - abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L)); - - prom_printf("Dart at: %x\n", RELOC(dart_tablebase)); -} -#endif /* CONFIG_PMAC_DART */ - -static void __init prom_initialize_tce_table(void) -{ - phandle node; - ihandle phb_node; - unsigned long offset = reloc_offset(); - char compatible[64], path[64], type[64], model[64]; - unsigned long i, table = 0; - unsigned long base, vbase, align; - unsigned int minalign, minsize; - struct of_tce_table *prom_tce_table = RELOC(of_tce_table); - unsigned long tce_entry, *tce_entryp; - - if (RELOC(ppc64_iommu_off)) - return; - - prom_debug("starting prom_initialize_tce_table\n"); - - /* Search all nodes looking for PHBs. */ - for (node = 0; prom_next_node(&node); ) { - if (table == MAX_PHB) { - prom_printf("WARNING: PCI host bridge ignored, " - "need to increase MAX_PHB\n"); - continue; - } - - compatible[0] = 0; - type[0] = 0; - model[0] = 0; - prom_getprop(node, "compatible", - compatible, sizeof(compatible)); - prom_getprop(node, "device_type", type, sizeof(type)); - prom_getprop(node, "model", model, sizeof(model)); - - /* Keep the old logic in tack to avoid regression. */ - if (compatible[0] != 0) { - if ((strstr(compatible, RELOC("python")) == NULL) && - (strstr(compatible, RELOC("Speedwagon")) == NULL) && - (strstr(compatible, RELOC("Winnipeg")) == NULL)) - continue; - } else if (model[0] != 0) { - if ((strstr(model, RELOC("ython")) == NULL) && - (strstr(model, RELOC("peedwagon")) == NULL) && - (strstr(model, RELOC("innipeg")) == NULL)) - continue; - } - - if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) { - continue; - } - - if (prom_getprop(node, "tce-table-minalign", &minalign, - sizeof(minalign)) == PROM_ERROR) { - minalign = 0; - } - - if (prom_getprop(node, "tce-table-minsize", &minsize, - sizeof(minsize)) == PROM_ERROR) { - minsize = 4UL << 20; - } - - /* - * Even though we read what OF wants, we just set the table - * size to 4 MB. This is enough to map 2GB of PCI DMA space. - * By doing this, we avoid the pitfalls of trying to DMA to - * MMIO space and the DMA alias hole. - * - * On POWER4, firmware sets the TCE region by assuming - * each TCE table is 8MB. Using this memory for anything - * else will impact performance, so we always allocate 8MB. - * Anton - */ - if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) - minsize = 8UL << 20; - else - minsize = 4UL << 20; - - /* Align to the greater of the align or size */ - align = max(minalign, minsize); - - /* Carve out storage for the TCE table. */ - base = lmb_alloc(minsize, align); - - if ( !base ) { - prom_panic("ERROR, cannot find space for TCE table.\n"); - } - - vbase = (unsigned long)abs_to_virt(base); - - /* Save away the TCE table attributes for later use. */ - prom_tce_table[table].node = node; - prom_tce_table[table].base = vbase; - prom_tce_table[table].size = minsize; - - prom_debug("TCE table: 0x%x\n", table); - prom_debug("\tnode = 0x%x\n", node); - prom_debug("\tbase = 0x%x\n", vbase); - prom_debug("\tsize = 0x%x\n", minsize); - - /* Initialize the table to have a one-to-one mapping - * over the allocated size. - */ - tce_entryp = (unsigned long *)base; - for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { - tce_entry = (i << PAGE_SHIFT); - tce_entry |= 0x3; - *tce_entryp = tce_entry; - } - - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - /* Call OF to setup the TCE hardware */ - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) == PROM_ERROR) { - prom_printf("package-to-path failed\n"); - } else { - prom_printf("opening PHB %s", path); - } - - phb_node = call_prom("open", 1, 1, path); - if ( (long)phb_node <= 0) { - prom_printf("... failed\n"); - } else { - prom_printf("... done\n"); - } - call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), - phb_node, -1, minsize, - (u32) base, (u32) (base >> 32)); - call_prom("close", 1, 0, phb_node); - - table++; - } - - /* Flag the first invalid entry */ - prom_tce_table[table].node = 0; - prom_debug("ending prom_initialize_tce_table\n"); -} - -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of low memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. The holding pattern - * checks that address until its cpu # is there, when it is that - * cpu jumps to __secondary_start(). smp_boot_cpus() takes care - * of setting those values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * Fixup comment... DRENG / PPPBBB - Peter - * - * -- Cort - */ -static void __init prom_hold_cpus(unsigned long mem) -{ - unsigned long i; - unsigned int reg; - phandle node; - unsigned long offset = reloc_offset(); - char type[64], *path; - int cpuid = 0; - unsigned int interrupt_server[MAX_CPU_THREADS]; - unsigned int cpu_threads, hw_cpu_num; - int propsize; - extern void __secondary_hold(void); - extern unsigned long __secondary_hold_spinloop; - extern unsigned long __secondary_hold_acknowledge; - unsigned long *spinloop - = (void *)virt_to_abs(&__secondary_hold_spinloop); - unsigned long *acknowledge - = (void *)virt_to_abs(&__secondary_hold_acknowledge); - unsigned long secondary_hold - = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); - struct prom_t *_prom = PTRRELOC(&prom); - - prom_debug("prom_hold_cpus: start...\n"); - prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); - prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); - prom_debug(" 1) acknowledge = 0x%x\n", - (unsigned long)acknowledge); - prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); - prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); - - /* Set the common spinloop variable, so all of the secondary cpus - * will block when they are awakened from their OF spinloop. - * This must occur for both SMP and non SMP kernels, since OF will - * be trashed when we move the kernel. - */ - *spinloop = 0; - -#ifdef CONFIG_HMT - for (i=0; i < NR_CPUS; i++) { - RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; - } -#endif - /* look for cpus */ - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("cpu")) != 0) - continue; - - /* Skip non-configured cpus. */ - prom_getprop(node, "status", type, sizeof(type)); - if (strcmp(type, RELOC("okay")) != 0) - continue; - - reg = -1; - prom_getprop(node, "reg", ®, sizeof(reg)); - - path = (char *) mem; - memset(path, 0, 256); - if (call_prom("package-to-path", 3, 1, - node, path, 255) == PROM_ERROR) - continue; - - prom_debug("\ncpuid = 0x%x\n", cpuid); - prom_debug("cpu hw idx = 0x%x\n", reg); - - /* Init the acknowledge var which will be reset by - * the secondary cpu when it awakens from its OF - * spinloop. - */ - *acknowledge = (unsigned long)-1; - - propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", - &interrupt_server, - sizeof(interrupt_server)); - if (propsize < 0) { - /* no property. old hardware has no SMT */ - cpu_threads = 1; - interrupt_server[0] = reg; /* fake it with phys id */ - } else { - /* We have a threaded processor */ - cpu_threads = propsize / sizeof(u32); - if (cpu_threads > MAX_CPU_THREADS) { - prom_printf("SMT: too many threads!\n" - "SMT: found %x, max is %x\n", - cpu_threads, MAX_CPU_THREADS); - cpu_threads = 1; /* ToDo: panic? */ - } - } - - hw_cpu_num = interrupt_server[0]; - if (hw_cpu_num != _prom->cpu) { - /* Primary Thread of non-boot cpu */ - prom_printf("%x : starting cpu %s... ", cpuid, path); - call_prom("start-cpu", 3, 0, node, - secondary_hold, cpuid); - - for ( i = 0 ; (i < 100000000) && - (*acknowledge == ((unsigned long)-1)); i++ ) ; - - if (*acknowledge == cpuid) { - prom_printf(" done\n"); - /* We have to get every CPU out of OF, - * even if we never start it. */ - if (cpuid >= NR_CPUS) - goto next; - } else { - prom_printf(" failed: %x\n", *acknowledge); - } - } -#ifdef CONFIG_SMP - else - prom_printf("%x : boot cpu %s\n", cpuid, path); -#endif -next: -#ifdef CONFIG_SMP - /* Init paca for secondary threads. They start later. */ - for (i=1; i < cpu_threads; i++) { - cpuid++; - if (cpuid >= NR_CPUS) - continue; - } -#endif - cpuid++; - } -#ifdef CONFIG_HMT - /* Only enable HMT on processors that provide support. */ - if (__is_processor(PV_PULSAR) || - __is_processor(PV_ICESTAR) || - __is_processor(PV_SSTAR)) { - prom_printf(" starting secondary threads\n"); - - for (i = 0; i < NR_CPUS; i += 2) { - if (!cpu_online(i)) - continue; - - if (i == 0) { - unsigned long pir = _get_PIR(); - if (__is_processor(PV_PULSAR)) { - RELOC(hmt_thread_data)[i].pir = - pir & 0x1f; - } else { - RELOC(hmt_thread_data)[i].pir = - pir & 0x3ff; - } - } - } - } else { - prom_printf("Processor is not HMT capable\n"); - } -#endif - - if (cpuid > NR_CPUS) - prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) - ") exceeded: ignoring extras\n"); - - prom_debug("prom_hold_cpus: end...\n"); -} - -#ifdef CONFIG_BOOTX_TEXT - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -static void __init setup_disp_fake_bi(ihandle dp) -{ - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[64]; - unsigned long offset = reloc_offset(); - - memset(name, 0, sizeof(name)); - prom_getprop(dp, "name", name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_printf("Initializing fake screen: %s\n", name); - - prom_getprop(dp, "width", &width, sizeof(width)); - prom_getprop(dp, "height", &height, sizeof(height)); - prom_getprop(dp, "depth", &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - prom_getprop(dp, "linebytes", &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - - prom_printf("width %x height %x depth %x linebytes %x\n", - width, height, depth, depth); - - prom_getprop(dp, "address", &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = prom_getprop(dp, "assigned-addresses", - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_printf("Failed to get address of frame buffer\n"); - return; - } - } - btext_setup_display(width, height, depth, pitch, address); - prom_printf("Addr of fb: %x\n", address); - RELOC(boot_text_mapped) = 0; -} -#endif /* CONFIG_BOOTX_TEXT */ - -static void __init prom_init_client_services(unsigned long pp) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - - /* Get a handle to the prom entry point before anything else */ - _prom->entry = pp; - - /* Init default value for phys size */ - _prom->encode_phys_size = 32; - - /* get a handle for the stdout device */ - _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); - if ((long)_prom->chosen <= 0) - prom_panic("cannot find chosen"); /* msg won't be printed :( */ - - /* get device tree root */ - _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); - if ((long)_prom->root <= 0) - prom_panic("cannot find device tree root"); /* msg won't be printed :( */ -} - -static void __init prom_init_stdout(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - u32 val; - - if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) - prom_panic("cannot find stdout"); - - _prom->stdout = val; -} - -static int __init prom_find_machine_type(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char compat[256]; - int len, i = 0; - - len = prom_getprop(_prom->root, "compatible", - compat, sizeof(compat)-1); - if (len > 0) { - compat[len] = 0; - while (i < len) { - char *p = &compat[i]; - int sl = strlen(p); - if (sl == 0) - break; - if (strstr(p, RELOC("Power Macintosh")) || - strstr(p, RELOC("MacRISC4"))) - return PLATFORM_POWERMAC; - i += sl + 1; - } - } - /* Default to pSeries */ - return PLATFORM_PSERIES; -} - -static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - unsigned long offset = reloc_offset(); - - return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); -} - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i, j; - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - const unsigned char *clut; - - _prom->disp_node = 0; - - prom_printf("Looking for displays\n"); - if (RELOC(of_stdout_device) != 0) - prom_printf("OF stdout is : %s\n", - PTRRELOC(RELOC(of_stdout_device))); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - prom_getprop(node, "device_type", type, sizeof(type)); - if (strcmp(type, RELOC("display")) != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - - /* - * leave some room at the end of the path for appending extra - * arguments - */ - if (call_prom("package-to-path", 3, 1, node, path, 250) < 0) - continue; - prom_printf("found display : %s\n", path); - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - i = RELOC(prom_num_displays); - RELOC(prom_num_displays) = i + 1; - if (RELOC(of_stdout_device) != 0 && i > 0 - && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { - for (; i > 0; --i) { - RELOC(prom_display_paths[i]) - = RELOC(prom_display_paths[i-1]); - RELOC(prom_display_nodes[i]) - = RELOC(prom_display_nodes[i-1]); - } - _prom->disp_node = node; - } - RELOC(prom_display_paths[i]) = PTRUNRELOC(path); - RELOC(prom_display_nodes[i]) = node; - if (_prom->disp_node == 0) - _prom->disp_node = node; - if (RELOC(prom_num_displays) >= FB_MAX) - break; - } - prom_printf("Opening displays...\n"); - for (j = RELOC(prom_num_displays) - 1; j >= 0; j--) { - path = PTRRELOC(RELOC(prom_display_paths[j])); - prom_printf("opening display : %s", path); - ih = call_prom("open", 1, 1, path); - if (ih == (ihandle)0 || ih == (ihandle)-1) { - prom_printf("... failed\n"); - continue; - } - - prom_printf("... done\n"); - - /* Setup a useable color table when the appropriate - * method is available. Should update this to set-colors */ - clut = RELOC(default_colors); - for (i = 0; i < 32; i++, clut += 3) - if (prom_set_color(ih, i, clut[0], clut[1], - clut[2]) != 0) - break; - -#ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); - for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) - if (prom_set_color(ih, i + 32, clut[0], clut[1], - clut[2]) != 0) - break; -#endif /* CONFIG_LOGO_LINUX_CLUT224 */ - } - - return DOUBLEWORD_ALIGN(mem); -} - -/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ -static void __init *__make_room(unsigned long *mem_start, unsigned long *mem_end, - unsigned long needed, unsigned long align) -{ - void *ret; - - *mem_start = ALIGN(*mem_start, align); - if (*mem_start + needed > *mem_end) { -#ifdef CONFIG_BLK_DEV_INITRD - unsigned long offset = reloc_offset(); - /* FIXME: Apple OF doesn't map unclaimed mem. If this - * ever happened on G5, we'd need to fix. */ - unsigned long initrd_len; - - if (*mem_end != RELOC(initrd_start)) - prom_panic("No memory for copy_device_tree"); - - prom_printf("Huge device_tree: moving initrd\n"); - /* Move by 4M. */ - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - *mem_end = RELOC(initrd_start) + 4 * 1024 * 1024; - memmove((void *)*mem_end, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = *mem_end; - RELOC(initrd_end) = RELOC(initrd_start) + initrd_len; -#else - prom_panic("No memory for copy_device_tree"); -#endif - } - - ret = (void *)*mem_start; - *mem_start += needed; - - return ret; -} - -#define make_room(startp, endp, type) \ - __make_room(startp, endp, sizeof(type), __alignof__(type)) - -static void __init -inspect_node(phandle node, struct device_node *dad, - unsigned long *mem_start, unsigned long *mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - unsigned long offset = reloc_offset(); - phandle ibm_phandle; - - np = make_room(mem_start, mem_end, struct device_node); - memset(np, 0, sizeof(*np)); - - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = RELOC(""); - for (;;) { - /* 32 is max len of name including nul. */ - namep = make_room(mem_start, mem_end, char[32]); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { - /* No more nodes: unwind alloc */ - *mem_start = (unsigned long)namep; - break; - } - /* Trim off some if we can */ - *mem_start = DOUBLEWORD_ALIGN((unsigned long)namep - + strlen(namep) + 1); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - prev_name = namep; - - pp->length = call_prom("getproplen", 2, 1, node, namep); - if (pp->length < 0) - continue; - if (pp->length > MAX_PROPERTY_LENGTH) { - char path[128]; - - prom_printf("WARNING: ignoring large property "); - /* It seems OF doesn't null-terminate the path :-( */ - memset(path, 0, sizeof(path)); - if (call_prom("package-to-path", 3, 1, node, - path, sizeof(path)-1) > 0) - prom_printf("[%s] ", path); - prom_printf("%s length 0x%x\n", namep, pp->length); - continue; - } - valp = __make_room(mem_start, mem_end, pp->length, 1); - pp->value = PTRUNRELOC(valp); - call_prom("getprop", 4, 1, node, namep, valp, pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - - /* Add a "linux,phandle" property. */ - namep = make_room(mem_start, mem_end, char[16]); - strcpy(namep, RELOC("linux,phandle")); - pp = make_room(mem_start, mem_end, struct property); - pp->name = PTRUNRELOC(namep); - pp->length = sizeof(phandle); - valp = make_room(mem_start, mem_end, phandle); - pp->value = PTRUNRELOC(valp); - *(phandle *)valp = node; - *prev_propp = PTRUNRELOC(pp); - pp->next = NULL; - - /* Set np->linux_phandle to the value of the ibm,phandle property - if it exists, otherwise to the phandle for this node. */ - np->linux_phandle = node; - if (prom_getprop(node, "ibm,phandle", - &ibm_phandle, sizeof(ibm_phandle)) > 0) - np->linux_phandle = ibm_phandle; - - /* get the node's full name */ - namep = (char *)*mem_start; - l = call_prom("package-to-path", 3, 1, node, - namep, *mem_end - *mem_start); - if (l >= 0) { - /* Didn't fit? Get more room. */ - if (l+1 > *mem_end - *mem_start) { - namep = __make_room(mem_start, mem_end, l+1, 1); - call_prom("package-to-path", 3, 1, node, namep, l); - } - np->full_name = PTRUNRELOC(namep); - namep[l] = '\0'; - *mem_start = DOUBLEWORD_ALIGN(*mem_start + l + 1); - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != (phandle)0) { - inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom("peer", 1, 1, child); - } -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start) -{ - phandle root; - struct device_node **allnextp; - unsigned long offset = reloc_offset(); - unsigned long mem_end; - - /* We pass mem_end-mem_start to OF: keep it well under 32-bit */ - mem_end = mem_start + 1024*1024*1024; -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start) && RELOC(initrd_start) > mem_start) - mem_end = RELOC(initrd_start); -#endif /* CONFIG_BLK_DEV_INITRD */ - - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_panic("couldn't get device tree root\n"); - } - allnextp = &RELOC(allnodes); - inspect_node(root, NULL, &mem_start, &mem_end, &allnextp); - *allnextp = NULL; - return mem_start; -} - -/* Verify bi_recs are good */ -static struct bi_record * __init prom_bi_rec_verify(struct bi_record *bi_recs) -{ - struct bi_record *first, *last; - - prom_debug("birec_verify: r6=0x%x\n", (unsigned long)bi_recs); - if (bi_recs != NULL) - prom_debug(" tag=0x%x\n", bi_recs->tag); +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif - if ( bi_recs == NULL || bi_recs->tag != BI_FIRST ) - return NULL; +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; - last = (struct bi_record *)(long)bi_recs->data[0]; +struct isa_reg_property { + u32 space; + u32 address; + u32 size; +}; - prom_debug(" last=0x%x\n", (unsigned long)last); - if (last != NULL) - prom_debug(" last_tag=0x%x\n", last->tag); - if ( last == NULL || last->tag != BI_LAST ) - return NULL; +typedef unsigned long interpret_func(struct device_node *, unsigned long, + int, int, int); - first = (struct bi_record *)(long)last->data[0]; - prom_debug(" first=0x%x\n", (unsigned long)first); +extern struct rtas_t rtas; +extern struct lmb lmb; +extern unsigned long klimit; - if ( first == NULL || first != bi_recs ) - return NULL; +static int __initdata dt_root_addr_cells; +static int __initdata dt_root_size_cells; +static int __initdata iommu_is_off; +typedef u32 cell_t; - return bi_recs; -} +static struct boot_param_header *initial_boot_params __initdata; -static void __init prom_bi_rec_reserve(void) -{ - unsigned long offset = reloc_offset(); - struct prom_t *_prom = PTRRELOC(&prom); - struct bi_record *rec; - - if ( _prom->bi_recs != NULL) { - - for ( rec=_prom->bi_recs; - rec->tag != BI_LAST; - rec=bi_rec_next(rec) ) { - prom_debug("bi: 0x%x\n", rec->tag); - switch (rec->tag) { -#ifdef CONFIG_BLK_DEV_INITRD - case BI_INITRD: - RELOC(initrd_start) = (unsigned long)(rec->data[0]); - RELOC(initrd_end) = RELOC(initrd_start) + rec->data[1]; - break; -#endif /* CONFIG_BLK_DEV_INITRD */ - } - } - /* The next use of this field will be after relocation - * is enabled, so convert this physical address into a - * virtual address. - */ - _prom->bi_recs = PTRUNRELOC(_prom->bi_recs); - } -} +static struct device_node *allnodes = NULL; -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. +/* use when traversing tree through the allnext, child, sibling, + * or parent members of struct device_node. */ +static rwlock_t devtree_lock = RW_LOCK_UNLOCKED; -unsigned long __init -prom_init(unsigned long r3, unsigned long r4, unsigned long pp, - unsigned long r6, unsigned long r7) -{ - unsigned long mem; - ihandle prom_cpu; - phandle cpu_pkg; - unsigned long offset = reloc_offset(); - long l; - char *p, *d; - unsigned long phys; - u32 getprop_rval; - struct systemcfg *_systemcfg; - struct paca_struct *lpaca = PTRRELOC(&paca[0]); - struct prom_t *_prom = PTRRELOC(&prom); - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); - - /* Setup systemcfg and NACA pointers now */ - RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset); - RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset); - - /* Init interface to Open Firmware and pickup bi-recs */ - prom_init_client_services(pp); - - /* Init prom stdout device */ - prom_init_stdout(); - - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug("offset=0x%x\n", offset); - prom_debug("->mem=0x%x\n", RELOC(klimit) - offset); - - /* check out if we have bi_recs */ - _prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6); - if ( _prom->bi_recs != NULL ) { - RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + - _prom->bi_recs->data[1]); - prom_debug("bi_recs=0x%x\n", (unsigned long)_prom->bi_recs); - prom_debug("new mem=0x%x\n", RELOC(klimit) - offset); - } - - /* If we don't have birec's or didn't find them, check for an initrd - * using the "yaboot" way - */ -#ifdef CONFIG_BLK_DEV_INITRD - if ( _prom->bi_recs == NULL && r3 && r4 && r4 != 0xdeadbeef) { - RELOC(initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; - RELOC(initrd_end) = RELOC(initrd_start) + r4; - RELOC(initrd_below_start_ok) = 1; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - /* Default machine type. */ - _systemcfg->platform = prom_find_machine_type(); - - /* On pSeries, copy the CPU hold code */ - if (_systemcfg->platform == PLATFORM_PSERIES) - copy_and_flush(0, KERNELBASE - offset, 0x100, 0); - - /* Start storing things at klimit */ - mem = RELOC(klimit) - offset; - - /* Get the full OF pathname of the stdout device */ - p = (char *) mem; - memset(p, 0, 256); - call_prom("instance-to-path", 3, 1, _prom->stdout, p, 255); - RELOC(of_stdout_device) = PTRUNRELOC(p); - mem += strlen(p) + 1; - - getprop_rval = 1; - prom_getprop(_prom->root, "#size-cells", - &getprop_rval, sizeof(getprop_rval)); - _prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64; - - /* Determine which cpu is actually running right _now_ */ - if (prom_getprop(_prom->chosen, "cpu", - &prom_cpu, sizeof(prom_cpu)) <= 0) - prom_panic("cannot find boot cpu"); - - cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); - _prom->cpu = getprop_rval; - lpaca[0].hw_cpu_id = _prom->cpu; - - RELOC(boot_cpuid) = 0; - - prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); - - /* Get the boot device and translate it to a full OF pathname. */ - p = (char *) mem; - l = prom_getprop(_prom->chosen, "bootpath", p, 1<<20); - if (l > 0) { - p[l] = 0; /* should already be null-terminated */ - RELOC(bootpath) = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom("canon", 3, 1, p, d, 1<<20); - RELOC(bootdevice) = PTRUNRELOC(d); - mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1); - } - - RELOC(cmd_line[0]) = 0; -#ifdef CONFIG_CMDLINE - strlcpy(RELOC(cmd_line), CONFIG_CMDLINE, sizeof(cmd_line)); -#endif /* CONFIG_CMDLINE */ - if ((long)_prom->chosen > 0) { - prom_getprop(_prom->chosen, "bootargs", p, sizeof(cmd_line)); - if (p != NULL && p[0] != 0) - strlcpy(RELOC(cmd_line), p, sizeof(cmd_line)); - } - - early_cmdline_parse(); - - prom_initialize_lmb(); - - prom_bi_rec_reserve(); - - mem = check_display(mem); - - if (_systemcfg->platform != PLATFORM_POWERMAC) - prom_instantiate_rtas(); - - /* Initialize some system info into the Naca early... */ - prom_initialize_naca(); - - /* If we are on an SMP machine, then we *MUST* do the - * following, regardless of whether we have an SMP - * kernel or not. - */ - prom_hold_cpus(mem); - - prom_debug("after basic inits, mem=0x%x\n", mem); -#ifdef CONFIG_BLK_DEV_INITRD - prom_debug("initrd_start=0x%x\n", RELOC(initrd_start)); - prom_debug("initrd_end=0x%x\n", RELOC(initrd_end)); -#endif /* CONFIG_BLK_DEV_INITRD */ - prom_debug("copying OF device tree...\n"); - - mem = copy_device_tree(mem); - - RELOC(klimit) = mem + offset; - - prom_debug("new klimit is\n"); - prom_debug("klimit=0x%x\n", RELOC(klimit)); - prom_debug(" ->mem=0x%x\n", mem); - - lmb_reserve(0, __pa(RELOC(klimit))); - -#ifdef CONFIG_BLK_DEV_INITRD - if (RELOC(initrd_start)) { - unsigned long initrd_len; - initrd_len = RELOC(initrd_end) - RELOC(initrd_start); - - /* Move initrd if it's where we're going to copy kernel. */ - if (RELOC(initrd_start) < __pa(RELOC(klimit))) { - memmove((void *)mem, (void *)RELOC(initrd_start), - initrd_len); - RELOC(initrd_start) = mem; - RELOC(initrd_end) = mem + initrd_len; - } - - lmb_reserve(RELOC(initrd_start), initrd_len); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - if (_systemcfg->platform == PLATFORM_PSERIES) - prom_initialize_tce_table(); - -#ifdef CONFIG_PMAC_DART - if (_systemcfg->platform == PLATFORM_POWERMAC) - prom_initialize_dart_table(); -#endif - -#ifdef CONFIG_BOOTX_TEXT - if (_prom->disp_node) { - prom_printf("Setting up bi display...\n"); - setup_disp_fake_bi(_prom->disp_node); - } -#endif /* CONFIG_BOOTX_TEXT */ - - prom_printf("Calling quiesce ...\n"); - call_prom("quiesce", 0, 0); - phys = KERNELBASE - offset; - -#ifdef CONFIG_BLK_DEV_INITRD - /* If we had an initrd, we convert its address to virtual */ - if (RELOC(initrd_start)) { - RELOC(initrd_start) = (unsigned long)__va(RELOC(initrd_start)); - RELOC(initrd_end) = (unsigned long)__va(RELOC(initrd_end)); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - prom_printf("returning from prom_init\n"); - return phys; -} +/* export that to outside world */ +struct device_node *of_chosen; /* * Find the device_node with a given phandle. */ -static struct device_node * __devinit -find_phandle(phandle ph) +static struct device_node * find_phandle(phandle ph) { struct device_node *np; @@ -1756,8 +113,7 @@ /* * Find the interrupt parent of a node. */ -static struct device_node * __devinit -intr_parent(struct device_node *p) +static struct device_node * __devinit intr_parent(struct device_node *p) { phandle *parp; @@ -1798,14 +154,14 @@ * Map an interrupt from a device up to the platform interrupt * descriptor. */ -static int __devinit -map_interrupt(unsigned int **irq, struct device_node **ictrler, - struct device_node *np, unsigned int *ints, int nintrc) +static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler, + struct device_node *np, unsigned int *ints, + int nintrc) { struct device_node *p, *ipar; unsigned int *imap, *imask, *ip; int i, imaplen, match; - int newintrc, newaddrc; + int newintrc = 0, newaddrc = 0; unsigned int *reg; int naddrc; @@ -1894,9 +250,9 @@ return nintrc; } -static unsigned long __init -finish_node_interrupts(struct device_node *np, unsigned long mem_start, - int measure_only) +static unsigned long __init finish_node_interrupts(struct device_node *np, + unsigned long mem_start, + int measure_only) { unsigned int *ints; int intlen, intrcells, intrcount; @@ -1957,9 +313,10 @@ return mem_start; } -static unsigned long __init -interpret_pci_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_pci_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; struct pci_reg_property *pci_addrs; @@ -1985,9 +342,10 @@ return mem_start; } -static unsigned long __init -interpret_dbdma_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_dbdma_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2025,9 +383,10 @@ return mem_start; } -static unsigned long __init -interpret_macio_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_macio_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct reg_property32 *rp; struct address_range *adr; @@ -2065,9 +424,10 @@ return mem_start; } -static unsigned long __init -interpret_isa_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_isa_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct isa_reg_property *rp; struct address_range *adr; @@ -2093,9 +453,10 @@ return mem_start; } -static unsigned long __init -interpret_root_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec, int measure_only) +static unsigned long __init interpret_root_props(struct device_node *np, + unsigned long mem_start, + int naddrc, int nsizec, + int measure_only) { struct address_range *adr; int i, l; @@ -2123,21 +484,15 @@ return mem_start; } -static unsigned long __init -finish_node(struct device_node *np, unsigned long mem_start, - interpret_func *ifunc, int naddrc, int nsizec, int measure_only) +static unsigned long __init finish_node(struct device_node *np, + unsigned long mem_start, + interpret_func *ifunc, + int naddrc, int nsizec, + int measure_only) { struct device_node *child; int *ip; - np->name = get_property(np, "name", NULL); - np->type = get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - /* get the device addresses and interrupts */ if (ifunc != NULL) mem_start = ifunc(np, mem_start, naddrc, nsizec, measure_only); @@ -2188,24 +543,468 @@ /** * finish_device_tree is called once things are running normally * (i.e. with text and data mapped to the address they were linked at). - * It traverses the device tree and fills in the name, type, - * {n_}addrs and {n_}intrs fields of each node. + * It traverses the device tree and fills in some of the additional, + * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt + * mapping is also initialized at this point. */ -void __init -finish_device_tree(void) +void __init finish_device_tree(void) { - unsigned long mem = klimit; + unsigned long mem, size; + /* Initialize virtual IRQ map */ virt_irq_init(); - dev_tree_size = finish_node(allnodes, 0, NULL, 0, 0, 1); - mem = (long)abs_to_virt(lmb_alloc(dev_tree_size, - __alignof__(struct device_node))); - if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + dev_tree_size) + /* Finish device-tree (pre-parsing some properties etc...) */ + size = finish_node(allnodes, 0, NULL, 0, 0, 1); + mem = (unsigned long)abs_to_virt(lmb_alloc(size, 128)); + if (finish_node(allnodes, mem, NULL, 0, 0, 0) != mem + size) BUG(); - rtas.dev = of_find_node_by_name(NULL, "rtas"); } +#ifdef DEBUG +#define printk udbg_printf +#endif + +static inline char *find_flat_dt_string(u32 offset) +{ + return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings + + offset; +} + +/** + * This function is used to scan the flattened device-tree, it is + * used to extract the memory informations at boot before we can + * unflatten the tree + */ +static int __init scan_flat_dt(int (*it)(unsigned long node, + const char *full_path, void *data), + void *data) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + int rc = 0; + + do { + u32 tag = *((u32 *)p); + char *pathp; + + p += 4; + if (tag == OF_DT_END_NODE) + continue; + if (tag == OF_DT_END) + break; + if (tag == OF_DT_PROP) { + u32 sz = *((u32 *)p); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + p += sz; + p = _ALIGN(p, 4); + continue; + } + if (tag != OF_DT_BEGIN_NODE) { + printk(KERN_WARNING "Invalid tag %x scanning flattened" + " device tree !\n", tag); + return -EINVAL; + } + pathp = (char *)p; + p = _ALIGN(p + strlen(pathp) + 1, 4); + rc = it(p, pathp, data); + if (rc != 0) + break; + } while(1); + + return rc; +} + +/** + * This function can be used within scan_flattened_dt callback to get + * access to properties + */ +static void* __init get_flat_dt_prop(unsigned long node, const char *name, + unsigned long *size) +{ + unsigned long p = node; + + do { + u32 tag = *((u32 *)p); + u32 sz, noff; + const char *nstr; + + p += 4; + if (tag != OF_DT_PROP) + return NULL; + + sz = *((u32 *)p); + noff = *((u32 *)(p + 4)); + p += 8; + p = _ALIGN(p, sz >= 8 ? 8 : 4); + + nstr = find_flat_dt_string(noff); + if (nstr == NULL) { + printk(KERN_WARNING "Can't find property index name !\n"); + return NULL; + } + if (strcmp(name, nstr) == 0) { + if (size) + *size = sz; + return (void *)p; + } + p += sz; + p = _ALIGN(p, 4); + } while(1); +} + +static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = _ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +static unsigned long __init unflatten_dt_node(unsigned long mem, + unsigned long *p, + struct device_node *dad, + struct device_node ***allnextpp) +{ + struct device_node *np; + struct property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_BEGIN_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = strlen(pathp) + 1; + *p = _ALIGN(*p + l, 4); + + np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, + __alignof__(struct device_node)); + if (allnextpp) { + memset(np, 0, sizeof(*np)); + np->full_name = ((char*)np) + sizeof(struct device_node); + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if (dad != NULL) { + np->parent = dad; + /* we temporarily use the `next' field as `last_child'. */ + if (dad->next == 0) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + } + while(1) { + u32 sz, noff; + char *pname; + + tag = *((u32 *)(*p)); + if (tag != OF_DT_PROP) + break; + *p += 4; + sz = *((u32 *)(*p)); + noff = *((u32 *)((*p) + 4)); + *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); + + pname = find_flat_dt_string(noff); + if (pname == NULL) { + printk("Can't find property name in list !\n"); + break; + } + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct property), + __alignof__(struct property)); + if (allnextpp) { + if (strcmp(pname, "linux,phandle") == 0) { + np->node = *((u32 *)*p); + if (np->linux_phandle == 0) + np->linux_phandle = np->node; + } + if (strcmp(pname, "ibm,phandle") == 0) + np->linux_phandle = *((u32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = _ALIGN((*p) + sz, 4); + } + if (allnextpp) { + *prev_pp = NULL; + np->name = get_property(np, "name", NULL); + np->type = get_property(np, "device_type", NULL); + + if (!np->name) + np->name = ""; + if (!np->type) + np->type = ""; + } + while (tag == OF_DT_BEGIN_NODE) { + mem = unflatten_dt_node(mem, p, np, allnextpp); + tag = *((u32 *)(*p)); + } + if (tag != OF_DT_END_NODE) { + printk("Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + return mem; +} + + +/** + * unflattens the device-tree passed by the firmware, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used (this used to be done by finish_device_tree) + */ +void __init unflatten_device_tree(void) +{ + unsigned long start, mem, size; + struct device_node **allnextp = &allnodes; + char *p; + int l = 0; + + /* First pass, scan for size */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + size = unflatten_dt_node(0, &start, NULL, NULL); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long)abs_to_virt(lmb_alloc(size, + __alignof__(struct device_node))); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + unflatten_dt_node(mem, &start, NULL, &allnextp); + if (*((u32 *)start) != OF_DT_END) + printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); + *allnextp = NULL; + + /* Get pointer to OF "/chosen" node for use everywhere */ + of_chosen = of_find_node_by_path("/chosen"); + + /* Retreive command line */ + if (of_chosen != NULL) { + p = (char *)get_property(of_chosen, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE)); + } +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif /* CONFIG_CMDLINE */ +} + + +static int __init early_init_dt_scan_cpus(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "cpu" nodes only */ + if (type == NULL || strcmp(type, "cpu") != 0) + return 0; + + /* On LPAR, look for the first ibm,pft-size property for the hash table size + */ + if (systemcfg->platform == PLATFORM_PSERIES_LPAR && naca->pftSize == 0) { + u32 *pft_size; + pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL); + if (pft_size != NULL) { + /* pft_size[0] is the NUMA CEC cookie */ + naca->pftSize = pft_size[1]; + } + } + + /* Check if it's the boot-cpu, set it's hw index in paca now */ + if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) { + u32 *prop = get_flat_dt_prop(node, "reg", NULL); + paca[0].hw_cpu_id = *prop; + } + + return 0; +} + +static int __init early_init_dt_scan_chosen(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/chosen") != 0) + return 0; + + /* get platform type */ + prop = (u32 *)get_flat_dt_prop(node, "linux,platform", NULL); + if (prop == NULL) + return 0; + systemcfg->platform = *prop; + + /* check if iommu is forced off */ + if (get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) + iommu_is_off = 1; + + /* break now */ + return 1; +} + +static int __init early_init_dt_scan_root(unsigned long node, + const char *full_path, void *data) +{ + u32 *prop; + + if (strcmp(full_path, "/") != 0) + return 0; + + prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); + dt_root_size_cells = (prop == NULL) ? 1 : *prop; + + prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); + dt_root_addr_cells = (prop == NULL) ? 2 : *prop; + + /* break now */ + return 1; +} + +static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + + +static int __init early_init_dt_scan_memory(unsigned long node, + const char *full_path, void *data) +{ + char *type = get_flat_dt_prop(node, "device_type", NULL); + cell_t *reg, *endp; + unsigned long l; + + /* We are scanning "memory" nodes only */ + if (type == NULL || strcmp(type, "memory") != 0) + return 0; + + reg = (cell_t *)get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(cell_t)); + + DBG("memory scan node %s ...\n", full_path); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + unsigned long base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + if (size == 0) + continue; + DBG(" - %lx , %lx\n", base, size); + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } + lmb_add(base, size); + } + return 0; +} + +static void __init early_reserve_mem(void) +{ + u64 base, size; + u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) + + initial_boot_params->off_mem_rsvmap); + while (1) { + base = *(reserve_map++); + size = *(reserve_map++); + if (size == 0) + break; + lmb_reserve(base, size); + } + + DBG("emory reserved, lmbs :\n"); + lmb_dump_all(); +} + +void __init early_init_devtree(void *params) +{ + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* By default, hash size is not set */ + naca->pftSize = 0; + + /* Retreive various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size, TCE reserve, and more ... + */ + scan_flat_dt(early_init_dt_scan_chosen, NULL); + + /* Scan memory nodes and rebuild LMBs */ + lmb_init(); + scan_flat_dt(early_init_dt_scan_root, NULL); + scan_flat_dt(early_init_dt_scan_memory, NULL); + lmb_analyze(); + systemcfg->physicalMemorySize = lmb_phys_mem_size(); + + DBG("Physical mem : %lx\n", systemcfg->physicalMemorySize); + + /* Reserve LMB regions used by kernel, initrd, dt, etc... */ + early_reserve_mem(); + + /* Retreive hash table size from flattened tree */ + scan_flat_dt(early_init_dt_scan_cpus, NULL); + + /* If hash size wasn't obtained above, we calculate it now based on + * the total RAM size + */ + if (naca->pftSize == 0) { + unsigned long rnd_mem_size, pteg_count; + + /* round mem_size up to next power of 2 */ + rnd_mem_size = 1UL << __ilog2(systemcfg->physicalMemorySize); + if (rnd_mem_size < systemcfg->physicalMemorySize) + rnd_mem_size <<= 1; + + /* # pages / 2 */ + pteg_count = (rnd_mem_size >> (12 + 1)); + + naca->pftSize = __ilog2(pteg_count << 7); + } +} + +#undef printk + int prom_n_addr_cells(struct device_node* np) { @@ -2518,6 +1317,28 @@ EXPORT_SYMBOL(of_find_node_by_path); /** + * of_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_find_node_by_phandle(phandle handle) +{ + struct device_node *np; + + read_lock(&devtree_lock); + for (np = allnodes; np != 0; np = np->allnext) + if (np->linux_phandle == handle) + break; + if (np) + of_node_get(np); + read_unlock(&devtree_lock); + return np; +} +EXPORT_SYMBOL(of_find_node_by_phandle); + +/** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration * of_node_put() will be called on it @@ -3053,3 +1874,13 @@ } } #endif + + + + + + + + + + diff -urN linux-2.5/arch/ppc64/kernel/prom_init.c linux-prom-clean/arch/ppc64/kernel/prom_init.c --- /dev/null 2004-09-16 11:45:22.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/prom_init.c 2004-09-17 22:19:57.000000000 +1000 @@ -0,0 +1,1794 @@ +/* + * + * + * Procedures for interfacing to Open Firmware. + * + * Paul Mackerras August 1996. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. + * {engebret|bergner}@us.ibm.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define DEBUG_PROM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "open_pic.h" + +#ifdef CONFIG_LOGO_LINUX_CLUT224 +#include +extern const struct linux_logo logo_linux_clut224; +#endif + +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This value does need to be big enough to + * ensure that we don't lose things like the interrupt-map property + * on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) + +/* + * Eventually bump that one up + */ +#define DEVTREE_CHUNK_SIZE 0x100000 + +/* + * This is the size of the local memory reserve map that gets copied + * into the boot params passed to the kernel. That size is totally + * flexible as the kernel just reads the list until it encounters an + * entry with size 0, so it can be changed without breaking binary + * compatibility + */ +#define MEM_RESERVE_MAP_SIZE 8 + +/* + * prom_init() is called very early on, before the kernel text + * and data have been mapped to KERNELBASE. At this point the code + * is running at whatever address it has been loaded at, so + * references to extern and static variables must be relocated + * explicitly. The procedure reloc_offset() returns the address + * we're currently running at minus the address we were linked at. + * (Note that strings count as static variables.) + * + * Because OF may have mapped I/O devices into the area starting at + * KERNELBASE, particularly on CHRP machines, we can't safely call + * OF once the kernel has been mapped to KERNELBASE. Therefore all + * OF calls should be done within prom_init(), and prom_init() + * and all routines called within it must be careful to relocate + * references as necessary. + * + * Note that the bss is cleared *after* prom_init runs, so we have + * to make sure that any static or extern variables it accesses + * are put in the data segment. + */ + + +#define PROM_BUG() do { \ + prom_printf("kernel BUG at %s line 0x%x!\n", \ + RELOC(__FILE__), __LINE__); \ + __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \ +} while (0) + +#ifdef DEBUG_PROM +#define prom_debug(x...) prom_printf(x) +#else +#define prom_debug(x...) +#endif + + +typedef u32 prom_arg_t; + +struct prom_args { + u32 service; + u32 nargs; + u32 nret; + prom_arg_t args[10]; + prom_arg_t *rets; /* Pointer to return values in args[16]. */ +}; + +struct prom_t { + unsigned long entry; + ihandle root; + ihandle chosen; + int cpu; + ihandle stdout; + ihandle disp_node; + struct prom_args args; + unsigned long version; + unsigned long root_size_cells; + unsigned long root_addr_cells; +}; + +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + +struct mem_map_entry { + u64 base; + u64 size; +}; + +typedef u32 cell_t; + +extern void __start(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6); + +extern unsigned long reloc_offset(void); +extern void enter_prom(struct prom_args *args, unsigned long entry); +extern void copy_and_flush(unsigned long dest, unsigned long src, + unsigned long size, unsigned long offset); + +extern unsigned long klimit; + +//int global_width = 640, global_height = 480, global_depth = 8, global_pitch; +//unsigned global_address; +/* prom structure */ +static struct prom_t __initdata prom; + +#define PROM_SCRATCH_SIZE 256 + +static char __initdata of_stdout_device[256]; +static char __initdata prom_scratch[PROM_SCRATCH_SIZE]; + +static unsigned long __initdata dt_header_start; +static unsigned long __initdata dt_struct_start, dt_struct_end; +static unsigned long __initdata dt_string_start, dt_string_end; + +static unsigned long __initdata prom_initrd_start, prom_initrd_end; + +static int __initdata iommu_force_on; +static int __initdata ppc64_iommu_off; +static int __initdata of_platform; + +static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; + +static unsigned long __initdata alloc_top; +static unsigned long __initdata alloc_top_high; +static unsigned long __initdata alloc_bottom; +static unsigned long __initdata rmo_top; +static unsigned long __initdata ram_top; + +static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE]; +static int __initdata mem_reserve_cnt; + +static cell_t __initdata regbuf[1024]; + + +#define MAX_CPU_THREADS 2 + +/* TO GO */ +#ifdef CONFIG_HMT +struct { + unsigned int pir; + unsigned int threadid; +} hmt_thread_data[NR_CPUS]; +#endif /* CONFIG_HMT */ + +/* + * This are used in calls to call_prom. The 4th and following + * arguments to call_prom should be 32-bit values. 64 bit values + * are truncated to 32 bits (and fortunately don't get interpreted + * as two arguments). + */ +#define ADDR(x) (u32) ((unsigned long)(x) - offset) + +/* This is the one and *ONLY* place where we actually call open + * firmware from, since we need to make sure we're running in 32b + * mode when we do. We switch back to 64b mode upon return. + */ + +#define PROM_ERROR (-1) + +static int __init call_prom(const char *service, int nargs, int nret, ...) +{ + int i; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + va_list list; + + _prom->args.service = ADDR(service); + _prom->args.nargs = nargs; + _prom->args.nret = nret; + _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]); + + va_start(list, nret); + for (i=0; i < nargs; i++) + _prom->args.args[i] = va_arg(list, prom_arg_t); + va_end(list); + + for (i=0; i < nret ;i++) + _prom->args.rets[i] = 0; + + enter_prom(&_prom->args, _prom->entry); + + return (nret > 0) ? _prom->args.rets[0] : 0; +} + + +static unsigned int __init prom_claim(unsigned long virt, unsigned long size, + unsigned long align) +{ + return (unsigned int)call_prom("claim", 3, 1, + (prom_arg_t)virt, (prom_arg_t)size, + (prom_arg_t)align); +} + +static void __init prom_print(const char *msg) +{ + const char *p, *q; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if (_prom->stdout == 0) + return; + + for (p = msg; *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + ++q; + call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2); + } +} + + +static void __init prom_print_hex(unsigned long val) +{ + unsigned long offset = reloc_offset(); + int i, nibbles = sizeof(val)*2; + char buf[sizeof(val)*2+1]; + struct prom_t *_prom = PTRRELOC(&prom); + + for (i = nibbles-1; i >= 0; i--) { + buf[i] = (val & 0xf) + '0'; + if (buf[i] > '9') + buf[i] += ('a'-'0'-10); + val >>= 4; + } + buf[nibbles] = '\0'; + call_prom("write", 3, 1, _prom->stdout, buf, nibbles); +} + + +static void __init prom_printf(const char *format, ...) +{ + unsigned long offset = reloc_offset(); + const char *p, *q, *s; + va_list args; + unsigned long v; + struct prom_t *_prom = PTRRELOC(&prom); + + va_start(args, format); + for (p = PTRRELOC(format); *p != 0; p = q) { + for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q) + ; + if (q > p) + call_prom("write", 3, 1, _prom->stdout, p, q - p); + if (*q == 0) + break; + if (*q == '\n') { + ++q; + call_prom("write", 3, 1, _prom->stdout, + ADDR("\r\n"), 2); + continue; + } + ++q; + if (*q == 0) + break; + switch (*q) { + case 's': + ++q; + s = va_arg(args, const char *); + prom_print(s); + break; + case 'x': + ++q; + v = va_arg(args, unsigned long); + prom_print_hex(v); + break; + } + } +} + + +static void __init __attribute__((noreturn)) prom_panic(const char *reason) +{ + unsigned long offset = reloc_offset(); + + prom_print(PTRRELOC(reason)); + /* ToDo: should put up an SRC here */ + call_prom("exit", 0, 0); + + for (;;) /* should never get here */ + ; +} + + +static int __init prom_next_node(phandle *nodep) +{ + phandle node; + + if ((node = *nodep) != 0 + && (*nodep = call_prom("child", 1, 1, node)) != 0) + return 1; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + for (;;) { + if ((node = call_prom("parent", 1, 1, node)) == 0) + return 0; + if ((*nodep = call_prom("peer", 1, 1, node)) != 0) + return 1; + } +} + +static int __init prom_getprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + +static int __init prom_getproplen(phandle node, const char *pname) +{ + unsigned long offset = reloc_offset(); + + return call_prom("getproplen", 2, 1, node, ADDR(pname)); +} + +static int __init prom_setprop(phandle node, const char *pname, + void *value, size_t valuelen) +{ + unsigned long offset = reloc_offset(); + + return call_prom("setprop", 4, 1, node, ADDR(pname), + (u32)(unsigned long) value, (u32) valuelen); +} + + +/* + * Early parsing of the command line passed to the kernel, used for + * the options that affect the iommu + */ +static void __init early_cmdline_parse(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *opt, *p; + int l = 0; + + RELOC(prom_cmd_line[0]) = 0; + p = RELOC(prom_cmd_line); + if ((long)_prom->chosen > 0) + l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1); +#ifdef CONFIG_CMDLINE + if (l == 0) /* dbl check */ + strlcpy(RELOC(prom_cmd_line), CONFIG_CMDLINE, sizeof(prom_cmd_line)); +#endif /* CONFIG_CMDLINE */ + prom_printf("command line: %s\n", RELOC(prom_cmd_line)); + + opt = strstr(RELOC(prom_cmd_line), RELOC("iommu=")); + if (opt) { + prom_printf("iommu opt is: %s\n", opt); + opt += 6; + while (*opt && *opt == ' ') + opt++; + if (!strncmp(opt, RELOC("off"), 3)) + RELOC(ppc64_iommu_off) = 1; + else if (!strncmp(opt, RELOC("force"), 5)) + RELOC(iommu_force_on) = 1; + } + +#ifndef CONFIG_PMAC_DART + if (RELOC(of_platform) == PLATFORM_POWERMAC) { + RELOC(ppc64_iommu_off) = 1; + prom_printf("DART disabled on PowerMac !\n"); + } +#endif +} + +/* + * Memory allocation strategy... our layout is normally: + * + * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd + * might end up beeing before the kernel though. We assume this won't override + * the final kernel at 0, we have no provision to handle that in this version, + * but it should hopefully never happen. + * + * alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap + * alloc_bottom is set to the top of kernel/initrd + * + * from there, allocations are done that way : rtas is allocated topmost, and + * the device-tree is allocated from the bottom. We try to grow the device-tree + * allocation as we progress. If we can't, then we fail, we don't currently have + * a facility to restart elsewhere, but that shouldn't be necessary neither + * + * Note that calls to reserve_mem have to be done explicitely, memory allocated + * with either alloc_up or alloc_down isn't automatically reserved. + */ + + +/* + * Allocates memory in the RMO upward from the kernel/initrd + * + * When align is 0, this is a special case, it means to allocate in place + * at the current location of alloc_bottom or fail (that is basically + * extending the previous allocation). Used for the device-tree flattening + */ +static unsigned long __init alloc_up(unsigned long size, unsigned long align) +{ + unsigned long offset = reloc_offset(); + unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align); + unsigned long addr = 0; + + prom_debug("alloc_up(%x, %x)\n", size, align); + if (RELOC(ram_top) == 0) + prom_panic("alloc_up() called with mem not initialized\n"); + + if (align) + base = _ALIGN_UP(RELOC(alloc_bottom), align); + else + base = RELOC(alloc_bottom); + + for(; (base + size) <= RELOC(alloc_top); + base = _ALIGN_UP(base + 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + if (align == 0) + break; + } + if (addr == 0) + return 0; + RELOC(alloc_bottom) = addr; + + prom_printf(" -> %x\n", addr); + prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); + prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Allocates memory downard, either from top of RMO, or if highmem + * is set, from the top of RAM. Note that this one doesn't handle + * failures. In does claim memory if highmem is not set. + */ +static unsigned long __init alloc_down(unsigned long size, unsigned long align, + int highmem) +{ + unsigned long offset = reloc_offset(); + unsigned long base, addr = 0; + + prom_debug("alloc_down(%x, %x, %s)\n", size, align, + highmem ? RELOC("(high)") : RELOC("(low)")); + if (RELOC(ram_top) == 0) + prom_panic("alloc_down() called with mem not initialized\n"); + + if (highmem) { + /* Carve out storage for the TCE table. */ + addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align); + if (addr <= RELOC(alloc_bottom)) + return 0; + else { + /* Will we bump into the RMO ? If yes, check out that we + * didn't overlap existing allocations there, if we did, + * we are dead, we must be the first in town ! + */ + if (addr < RELOC(rmo_top)) { + /* Good, we are first */ + if (RELOC(alloc_top) == RELOC(rmo_top)) + RELOC(alloc_top) = addr; + else + return 0; + } + RELOC(alloc_top_high) = addr; + } + goto bail; + } + + base = _ALIGN_DOWN(RELOC(alloc_top) - size, align); + for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { + prom_debug(" trying: 0x%x\n\r", base); + addr = (unsigned long)prom_claim(base, size, 0); + if ((int)addr != PROM_ERROR) + break; + addr = 0; + } + if (addr == 0) + return 0; + RELOC(alloc_top) = addr; + + bail: + prom_printf(" -> %x\n", addr); + prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); + prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); + + return addr; +} + +/* + * Parse a "reg" cell + */ +static unsigned long __init prom_next_cell(int s, cell_t **cellp) +{ + cell_t *p = *cellp; + unsigned long r = 0; + + /* Ignore more than 2 cells */ + while (s > 2) { + p++; + s--; + } + while (s) { + r <<= 32; + r |= *(p++); + s--; + } + + *cellp = p; + return r; +} + +/* + * Very dumb function for adding to the memory reserve list, but + * we don't need anything smarter at this point + * + * XXX Eventually check for collisions. They should NEVER happen + * if problems seem to show up, it would be a good start to track + * them down. + */ +static void reserve_mem(unsigned long base, unsigned long size) +{ + unsigned long offset = reloc_offset(); + unsigned long top = base + size; + unsigned long cnt = RELOC(mem_reserve_cnt); + + /* We need to always keep one empty entry so that we + * have our terminator with "size" set to 0 since we are + * dumb and just copy this entire array to the boot params + */ + base = _ALIGN_DOWN(base, PAGE_SIZE); + top = _ALIGN_DOWN(top, PAGE_SIZE); + size = top - base; + + if (cnt >= (MEM_RESERVE_MAP_SIZE - 1)) + prom_panic("Memory reserve map exhausted !\n"); + RELOC(mem_reserve_map)[cnt].base = base; + RELOC(mem_reserve_map)[cnt].size = size; + RELOC(mem_reserve_cnt) = cnt + 1; +} + +/* + * Initialize memory allocation mecanism, parse "memory" nodes and + * obtain that way the top of memory and RMO to setup out local allocator + */ +static void __init prom_init_mem(void) +{ + phandle node; + char *path, type[64]; + unsigned int plen; + cell_t *p, *endp; + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* + * We iterate the memory nodes to find + * 1) top of RMO (first node) + * 2) top of memory + */ + prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells); + prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells); + + prom_debug("scanning memory:\n"); + path = RELOC(prom_scratch); + + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + + if (strcmp(type, RELOC("memory"))) + continue; + + plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf)); + if (plen > sizeof(regbuf)) { + prom_printf("memory node too large for buffer !\n"); + plen = sizeof(regbuf); + } + p = RELOC(regbuf); + endp = p + (plen / sizeof(cell_t)); + +#ifdef DEBUG_PROM + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + prom_debug(" node %s :\n", path); +#endif /* DEBUG_PROM */ + + while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) { + unsigned long base, size; + + base = prom_next_cell(_prom->root_addr_cells, &p); + size = prom_next_cell(_prom->root_size_cells, &p); + + if (size == 0) + continue; + prom_debug(" %x %x\n", base, size); + if (base == 0) + RELOC(rmo_top) = size; + if ((base + size) > RELOC(ram_top)) + RELOC(ram_top) = base + size; + } + } + + /* Setup our top/bottom alloc points, that is top of RMO or top of + * segment 0 when running non-LPAR + */ + if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR ) + RELOC(alloc_top) = RELOC(rmo_top); + else + RELOC(alloc_top) = min(0x40000000ul, RELOC(ram_top)); + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000); + RELOC(alloc_top_high) = RELOC(ram_top); + + /* Check if we have an initrd after the kernel, if we do move our bottom + * point to after it + */ + if (RELOC(prom_initrd_start)) { + if ((RELOC(prom_initrd_start) + RELOC(prom_initrd_end)) + > RELOC(alloc_bottom)) + RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end)); + } + + prom_printf("memory layout at init:\n"); + prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom)); + prom_printf(" alloc_top : %x\n", RELOC(alloc_top)); + prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high)); + prom_printf(" rmo_top : %x\n", RELOC(rmo_top)); + prom_printf(" ram_top : %x\n", RELOC(ram_top)); +} + + +/* + * Allocate room for and instanciate RTAS + */ +static void __init prom_instantiate_rtas(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + phandle prom_rtas; + u64 base, entry = 0; + u32 size; + + prom_debug("prom_instantiate_rtas: start...\n"); + + prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (prom_rtas != (phandle) -1) { + prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); + if (size != 0) { + base = alloc_down(size, PAGE_SIZE, 0); + if (base == 0) { + prom_printf("RTAS allocation failed !\n"); + return; + } + prom_printf("instantiating rtas at 0x%x", base); + + prom_rtas = call_prom("open", 1, 1, ADDR("/rtas")); + prom_printf("..."); + + if (call_prom("call-method", 3, 2, + ADDR("instantiate-rtas"), + prom_rtas, base) != PROM_ERROR) { + entry = (long)_prom->args.rets[1]; + } + if (entry == 0) { + prom_printf(" failed\n"); + return; + } + prom_printf(" done\n"); + + reserve_mem(base, size); + } + + prom_setprop(_prom->chosen, "linux,rtas-base", &base, sizeof(base)); + prom_setprop(_prom->chosen, "linux,rtas-entry", &entry, sizeof(entry)); + prom_setprop(_prom->chosen, "linux,rtas-size", &size, sizeof(size)); + + prom_debug("rtas base = 0x%x\n", base); + prom_debug("rtas entry = 0x%x\n", entry); + prom_debug("rtas size = 0x%x\n", (long)size); + } + prom_debug("prom_instantiate_rtas: end...\n"); +} + + +/* + * Allocate room for and initialize TCE tables + */ +static void __init prom_initialize_tce_table(void) +{ + phandle node; + ihandle phb_node; + unsigned long offset = reloc_offset(); + char compatible[64], type[64], model[64]; + char *path = RELOC(prom_scratch); + u64 i, table = 0; + u64 base, vbase, align; + u32 minalign, minsize; + u64 tce_entry, *tce_entryp; + u64 local_alloc_top, local_alloc_bottom; + + if (RELOC(ppc64_iommu_off)) + return; + + prom_debug("starting prom_initialize_tce_table\n"); + + /* Cache current top of allocs so we reserve a single block */ + local_alloc_top = RELOC(alloc_top_high); + local_alloc_bottom = local_alloc_top; + + /* Search all nodes looking for PHBs. */ + for (node = 0; prom_next_node(&node); ) { + compatible[0] = 0; + type[0] = 0; + model[0] = 0; + prom_getprop(node, "compatible", + compatible, sizeof(compatible)); + prom_getprop(node, "device_type", type, sizeof(type)); + prom_getprop(node, "model", model, sizeof(model)); + + if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL)) + continue; + + /* Keep the old logic in tack to avoid regression. */ + if (compatible[0] != 0) { + if ((strstr(compatible, RELOC("python")) == NULL) && + (strstr(compatible, RELOC("Speedwagon")) == NULL) && + (strstr(compatible, RELOC("Winnipeg")) == NULL)) + continue; + } else if (model[0] != 0) { + if ((strstr(model, RELOC("ython")) == NULL) && + (strstr(model, RELOC("peedwagon")) == NULL) && + (strstr(model, RELOC("innipeg")) == NULL)) + continue; + } + + if (prom_getprop(node, "tce-table-minalign", &minalign, + sizeof(minalign)) == PROM_ERROR) + minalign = 0; + if (prom_getprop(node, "tce-table-minsize", &minsize, + sizeof(minsize)) == PROM_ERROR) + minsize = 4UL << 20; + + /* + * Even though we read what OF wants, we just set the table + * size to 4 MB. This is enough to map 2GB of PCI DMA space. + * By doing this, we avoid the pitfalls of trying to DMA to + * MMIO space and the DMA alias hole. + * + * On POWER4, firmware sets the TCE region by assuming + * each TCE table is 8MB. Using this memory for anything + * else will impact performance, so we always allocate 8MB. + * Anton + */ + if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) + minsize = 8UL << 20; + else + minsize = 4UL << 20; + + /* Align to the greater of the align or size */ + align = max(minalign, minsize); + base = alloc_down(minsize, align, 1); + if (base == 0) + prom_panic("ERROR, cannot find space for TCE table.\n"); + if (base < local_alloc_bottom) + local_alloc_bottom = base; + + vbase = (unsigned long)abs_to_virt(base); + + /* Save away the TCE table attributes for later use. */ + prom_setprop(node, "linux,tce-base", &vbase, sizeof(vbase)); + prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize)); + prom_setprop(node, "linux,has-tce-table", NULL, 0); + + prom_debug("TCE table: 0x%x\n", table); + prom_debug("\tnode = 0x%x\n", node); + prom_debug("\tbase = 0x%x\n", vbase); + prom_debug("\tsize = 0x%x\n", minsize); + + /* Initialize the table to have a one-to-one mapping + * over the allocated size. + */ + tce_entryp = (unsigned long *)base; + for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) { + tce_entry = (i << PAGE_SHIFT); + tce_entry |= 0x3; + *tce_entryp = tce_entry; + } + + /* It seems OF doesn't null-terminate the path :-( */ + memset(path, 0, sizeof(path)); + /* Call OF to setup the TCE hardware */ + if (call_prom("package-to-path", 3, 1, node, + path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) { + prom_printf("package-to-path failed\n"); + } else + prom_printf("opening PHB %s", path); + + phb_node = call_prom("open", 1, 1, path); + if ( (long)phb_node <= 0) + prom_printf("... failed\n"); + else + prom_printf("... done\n"); + + call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"), + phb_node, -1, minsize, + (u32) base, (u32) (base >> 32)); + call_prom("close", 1, 0, phb_node); + + table++; + } + + reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom); + + /* Flag the first invalid entry */ + prom_debug("ending prom_initialize_tce_table\n"); +} + +/* + * With CHRP SMP we need to use the OF to start the other + * processors so we can't wait until smp_boot_cpus (the OF is + * trashed by then) so we have to put the processors into + * a holding pattern controlled by the kernel (not OF) before + * we destroy the OF. + * + * This uses a chunk of low memory, puts some holding pattern + * code there and sends the other processors off to there until + * smp_boot_cpus tells them to do something. The holding pattern + * checks that address until its cpu # is there, when it is that + * cpu jumps to __secondary_start(). smp_boot_cpus() takes care + * of setting those values. + * + * We also use physical address 0x4 here to tell when a cpu + * is in its holding pattern code. + * + * Fixup comment... DRENG / PPPBBB - Peter + * + * -- Cort + */ +static void __init prom_hold_cpus(void) +{ + unsigned long i; + unsigned int reg; + phandle node; + unsigned long offset = reloc_offset(); + char type[64]; + int cpuid = 0; + unsigned int interrupt_server[MAX_CPU_THREADS]; + unsigned int cpu_threads, hw_cpu_num; + int propsize; + extern void __secondary_hold(void); + extern unsigned long __secondary_hold_spinloop; + extern unsigned long __secondary_hold_acknowledge; + unsigned long *spinloop + = (void *)virt_to_abs(&__secondary_hold_spinloop); + unsigned long *acknowledge + = (void *)virt_to_abs(&__secondary_hold_acknowledge); + unsigned long secondary_hold + = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold)); + struct prom_t *_prom = PTRRELOC(&prom); + + prom_debug("prom_hold_cpus: start...\n"); + prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop); + prom_debug(" 1) *spinloop = 0x%x\n", *spinloop); + prom_debug(" 1) acknowledge = 0x%x\n", + (unsigned long)acknowledge); + prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge); + prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold); + + /* Set the common spinloop variable, so all of the secondary cpus + * will block when they are awakened from their OF spinloop. + * This must occur for both SMP and non SMP kernels, since OF will + * be trashed when we move the kernel. + */ + *spinloop = 0; + +#ifdef CONFIG_HMT + for (i=0; i < NR_CPUS; i++) { + RELOC(hmt_thread_data)[i].pir = 0xdeadbeef; + } +#endif + /* look for cpus */ + for (node = 0; prom_next_node(&node); ) { + type[0] = 0; + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("cpu")) != 0) + continue; + + /* Skip non-configured cpus. */ + prom_getprop(node, "status", type, sizeof(type)); + if (strcmp(type, RELOC("okay")) != 0) + continue; + + reg = -1; + prom_getprop(node, "reg", ®, sizeof(reg)); + + prom_debug("\ncpuid = 0x%x\n", cpuid); + prom_debug("cpu hw idx = 0x%x\n", reg); + + /* Init the acknowledge var which will be reset by + * the secondary cpu when it awakens from its OF + * spinloop. + */ + *acknowledge = (unsigned long)-1; + + propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", + &interrupt_server, + sizeof(interrupt_server)); + if (propsize < 0) { + /* no property. old hardware has no SMT */ + cpu_threads = 1; + interrupt_server[0] = reg; /* fake it with phys id */ + } else { + /* We have a threaded processor */ + cpu_threads = propsize / sizeof(u32); + if (cpu_threads > MAX_CPU_THREADS) { + prom_printf("SMT: too many threads!\n" + "SMT: found %x, max is %x\n", + cpu_threads, MAX_CPU_THREADS); + cpu_threads = 1; /* ToDo: panic? */ + } + } + + hw_cpu_num = interrupt_server[0]; + if (hw_cpu_num != _prom->cpu) { + /* Primary Thread of non-boot cpu */ + prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); + call_prom("start-cpu", 3, 0, node, + secondary_hold, cpuid); + + for ( i = 0 ; (i < 100000000) && + (*acknowledge == ((unsigned long)-1)); i++ ) ; + + if (*acknowledge == cpuid) { + prom_printf("done\n"); + /* We have to get every CPU out of OF, + * even if we never start it. */ + if (cpuid >= NR_CPUS) + goto next; + } else { + prom_printf("failed: %x\n", *acknowledge); + } + } +#ifdef CONFIG_SMP + else + prom_printf("%x : boot cpu %x\n", cpuid, reg); +#endif +next: +#ifdef CONFIG_SMP + /* Init paca for secondary threads. They start later. */ + for (i=1; i < cpu_threads; i++) { + cpuid++; + if (cpuid >= NR_CPUS) + continue; + } +#endif /* CONFIG_SMP */ + cpuid++; + } +#ifdef CONFIG_HMT + /* Only enable HMT on processors that provide support. */ + if (__is_processor(PV_PULSAR) || + __is_processor(PV_ICESTAR) || + __is_processor(PV_SSTAR)) { + prom_printf(" starting secondary threads\n"); + + for (i = 0; i < NR_CPUS; i += 2) { + if (!cpu_online(i)) + continue; + + if (i == 0) { + unsigned long pir = mfspr(SPRN_PIR); + if (__is_processor(PV_PULSAR)) { + RELOC(hmt_thread_data)[i].pir = + pir & 0x1f; + } else { + RELOC(hmt_thread_data)[i].pir = + pir & 0x3ff; + } + } + } + } else { + prom_printf("Processor is not HMT capable\n"); + } +#endif + + if (cpuid > NR_CPUS) + prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) + ") exceeded: ignoring extras\n"); + + prom_debug("prom_hold_cpus: end...\n"); +} + + +#ifdef CONFIG_BOOTX_TEXT__disabled + +/* This function will enable the early boot text when doing OF booting. This + * way, xmon output should work too + */ +static void __init setup_disp_fake_bi(ihandle dp) +{ + //int width = 640, height = 480, depth = 8, pitch; + //unsigned address; + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[64]; + unsigned long offset = reloc_offset(); + + memset(name, 0, sizeof(name)); + prom_getprop(dp, "name", name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_printf("Initializing fake screen: %s\n", name); + + prom_getprop(dp, "width", &global_width, sizeof(global_width)); + prom_getprop(dp, "height", &global_height, sizeof(global_height)); + prom_getprop(dp, "depth", &global_depth, sizeof(global_depth)); + global_pitch = global_width * ((global_depth + 7) / 8); + prom_getprop(dp, "linebytes", &global_pitch, sizeof(global_pitch)); + if (global_pitch == 1) + global_pitch = 0x1000; /* for strange IBM display */ + global_address = 0; + + prom_printf("width %x height %x depth %x linebytes %x\n", + global_width, global_height, global_depth, global_depth); + + prom_getprop(dp, "address", &global_address, sizeof(global_address)); + if (global_address == 0) { + /* look for an assigned address with a size of >= 1MB */ + naddrs = prom_getprop(dp, "assigned-addresses", + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + global_address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + global_address += (8 << 20); + break; + } + } + if (global_address == 0) { + prom_printf("Failed to get address of frame buffer\n"); + return; + } + } + //btext_setup_display(width, height, depth, pitch, address); + //prom_printf("Addr of fb: %x\n", global_address); + RELOC(boot_text_mapped) = 0; +} +#endif /* CONFIG_BOOTX_TEXT */ + +static void __init prom_init_client_services(unsigned long pp) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + /* Get a handle to the prom entry point before anything else */ + _prom->entry = pp; + + /* Init default value for phys size */ + _prom->root_size_cells = 1; + _prom->root_addr_cells = 2; + + /* get a handle for the stdout device */ + _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); + if ((long)_prom->chosen <= 0) + prom_panic("cannot find chosen"); /* msg won't be printed :( */ + + /* get device tree root */ + _prom->root = call_prom("finddevice", 1, 1, ADDR("/")); + if ((long)_prom->root <= 0) + prom_panic("cannot find device tree root"); /* msg won't be printed :( */ +} + +static void __init prom_init_stdout(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char *path = RELOC(of_stdout_device); + char type[16]; + u32 val; + + if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0) + prom_panic("cannot find stdout"); + + _prom->stdout = val; + + /* Get the full OF pathname of the stdout device */ + memset(path, 0, 256); + call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255); + val = call_prom("instance-to-package", 1, 1, _prom->stdout); + prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val)); + prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device)); + + /* If it's a display, note it */ + memset(type, 0, sizeof(type)); + prom_getprop(val, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) == 0) { + _prom->disp_node = val; + prom_setprop(val, "linux,boot-display", NULL, 0); + } +} + +static int __init prom_find_machine_type(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char compat[256]; + int len, i = 0; + phandle rtas; + + len = prom_getprop(_prom->root, "compatible", + compat, sizeof(compat)-1); + if (len > 0) { + compat[len] = 0; + while (i < len) { + char *p = &compat[i]; + int sl = strlen(p); + if (sl == 0) + break; + if (strstr(p, RELOC("Power Macintosh")) || + strstr(p, RELOC("MacRISC4"))) + return PLATFORM_POWERMAC; + i += sl + 1; + } + } + /* Default to pSeries. We need to know if we are running LPAR */ + rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); + if (rtas != (phandle) -1) { + unsigned long x; + x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (x != PROM_ERROR) { + prom_printf("Hypertas detected, assuming LPAR !\n"); + return PLATFORM_PSERIES_LPAR; + } + } + return PLATFORM_PSERIES; +} + +static int __init prom_set_color(ihandle ih, int i, int r, int g, int b) +{ + unsigned long offset = reloc_offset(); + + return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r); +} + +/* + * If we have a display that we don't know how to drive, + * we will want to try to execute OF's open method for it + * later. However, OF will probably fall over if we do that + * we've taken over the MMU. + * So we check whether we will need to open the display, + * and if so, open it now. + */ +static unsigned long __init prom_check_displays(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + char type[16], *path; + phandle node; + ihandle ih; + int i; + + static unsigned char default_colors[] = { + 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, + 0x00, 0xaa, 0x00, + 0x00, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, + 0xaa, 0x00, 0xaa, + 0xaa, 0xaa, 0x00, + 0xaa, 0xaa, 0xaa, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0xff, + 0x55, 0xff, 0x55, + 0x55, 0xff, 0xff, + 0xff, 0x55, 0x55, + 0xff, 0x55, 0xff, + 0xff, 0xff, 0x55, + 0xff, 0xff, 0xff + }; + const unsigned char *clut; + + prom_printf("Looking for displays\n"); + for (node = 0; prom_next_node(&node); ) { + memset(type, 0, sizeof(type)); + prom_getprop(node, "device_type", type, sizeof(type)); + if (strcmp(type, RELOC("display")) != 0) + continue; + + /* It seems OF doesn't null-terminate the path :-( */ + path = RELOC(prom_scratch); + memset(path, 0, PROM_SCRATCH_SIZE); + + /* + * leave some room at the end of the path for appending extra + * arguments + */ + if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) + continue; + prom_printf("found display : %s, opening ... ", path); + + ih = call_prom("open", 1, 1, path); + if (ih == (ihandle)0 || ih == (ihandle)-1) { + prom_printf("failed\n"); + continue; + } + + /* Success */ + prom_printf("done\n"); + prom_setprop(node, "linux,opened", NULL, 0); + + /* + * stdout wasn't a display node, pick the first we can find + * for btext + */ + if (_prom->disp_node == 0) + _prom->disp_node = node; + + /* Setup a useable color table when the appropriate + * method is available. Should update this to set-colors */ + clut = RELOC(default_colors); + for (i = 0; i < 32; i++, clut += 3) + if (prom_set_color(ih, i, clut[0], clut[1], + clut[2]) != 0) + break; + +#ifdef CONFIG_LOGO_LINUX_CLUT224 + clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); + for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) + if (prom_set_color(ih, i + 32, clut[0], clut[1], + clut[2]) != 0) + break; +#endif /* CONFIG_LOGO_LINUX_CLUT224 */ + } +} + + +/* Return (relocated) pointer to this much memory: moves initrd if reqd. */ +static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end, + unsigned long needed, unsigned long align) +{ + unsigned long offset = reloc_offset(); + void *ret; + + *mem_start = _ALIGN(*mem_start, align); + while ((*mem_start + needed) > *mem_end) { + unsigned long room, chunk; + + prom_debug("Chunk exhausted, claiming more at %x...\n", + RELOC(alloc_bottom)); + room = RELOC(alloc_top) - RELOC(alloc_bottom); + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + if (room < PAGE_SIZE) + prom_panic("No memory for flatten_device_tree (no room)"); + chunk = alloc_up(room, 0); + if (chunk == 0) + prom_panic("No memory for flatten_device_tree (claim failed)"); + *mem_end = RELOC(alloc_top); + } + + ret = (void *)*mem_start; + *mem_start += needed; + + return ret; +} + +#define dt_push_token(token, mem_start, mem_end) \ + do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0) + +static unsigned long __init dt_find_string(char *str) +{ + unsigned long offset = reloc_offset(); + char *s, *os; + + s = os = (char *)RELOC(dt_string_start); + s += 4; + while (s < (char *)RELOC(dt_string_end)) { + if (strcmp(s, str) == 0) + return s - os; + s += strlen(s) + 1; + } + return 0; +} + +static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + unsigned long offset = reloc_offset(); + char *prev_name, *namep, *sstart; + unsigned long soff; + phandle child; + + sstart = (char *)RELOC(dt_string_start); + + /* get and store all property names */ + prev_name = RELOC(""); + for (;;) { + + /* 32 is max len of name including nul. */ + namep = make_room(mem_start, mem_end, 32, 1); + if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { + /* No more nodes: unwind alloc */ + *mem_start = (unsigned long)namep; + break; + } + soff = dt_find_string(namep); + if (soff != 0) { + *mem_start = (unsigned long)namep; + namep = sstart + soff; + } else { + /* Trim off some if we can */ + *mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = *mem_start; + } + prev_name = namep; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_strings(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } +} + +static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, + unsigned long *mem_end) +{ + int l, align; + phandle child; + char *namep, *prev_name, *sstart; + unsigned long soff; + unsigned char *valp; + unsigned long offset = reloc_offset(); + char pname[32]; + char *path; + + path = RELOC(prom_scratch); + + dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); + + /* get the node's full name */ + namep = (char *)*mem_start; + l = call_prom("package-to-path", 3, 1, node, + namep, *mem_end - *mem_start); + if (l >= 0) { + /* Didn't fit? Get more room. */ + if (l+1 > *mem_end - *mem_start) { + namep = make_room(mem_start, mem_end, l+1, 1); + call_prom("package-to-path", 3, 1, node, namep, l); + } + namep[l] = '\0'; + *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); + } + + /* get it again for debugging */ + memset(path, 0, PROM_SCRATCH_SIZE); + call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); + + /* get and store all properties */ + prev_name = RELOC(""); + sstart = (char *)RELOC(dt_string_start); + for (;;) { + if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) + break; + + /* find string offset */ + soff = dt_find_string(pname); + if (soff == 0) { + prom_printf("WARNING: Can't find string index for <%s>, node %s\n", + pname, path); + break; + } + prev_name = sstart + soff; + + /* get length */ + l = call_prom("getproplen", 2, 1, node, pname); + + /* sanity checks */ + if (l < 0) + continue; + if (l > MAX_PROPERTY_LENGTH) { + prom_printf("WARNING: ignoring large property "); + /* It seems OF doesn't null-terminate the path :-( */ + prom_printf("[%s] ", path); + prom_printf("%s length 0x%x\n", pname, l); + continue; + } + + /* push property head */ + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(l, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + + /* push property content */ + align = (l >= 8) ? 8 : 4; + valp = make_room(mem_start, mem_end, l, align); + call_prom("getprop", 4, 1, node, pname, valp, l); + *mem_start = _ALIGN(*mem_start, 4); + } + + /* Add a "linux,phandle" property. */ + soff = dt_find_string(RELOC("linux,phandle")); + if (soff == 0) + prom_printf("WARNING: Can't find string index for " + " node %s\n", path); + else { + dt_push_token(OF_DT_PROP, mem_start, mem_end); + dt_push_token(4, mem_start, mem_end); + dt_push_token(soff, mem_start, mem_end); + valp = make_room(mem_start, mem_end, 4, 4); + *(u32 *)valp = node; + } + + /* do all our children */ + child = call_prom("child", 1, 1, node); + while (child != (phandle)0) { + scan_dt_build_struct(child, mem_start, mem_end); + child = call_prom("peer", 1, 1, child); + } + + dt_push_token(OF_DT_END_NODE, mem_start, mem_end); +} + +static void __init flatten_device_tree(void) +{ + phandle root; + unsigned long offset = reloc_offset(); + unsigned long mem_start, mem_end, room; + struct boot_param_header *hdr; + char *namep; + u64 *rsvmap; + + /* + * Check how much room we have between alloc top & bottom (+/- a + * few pages), crop to 4Mb, as this is our "chuck" size + */ + room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000; + if (room > DEVTREE_CHUNK_SIZE) + room = DEVTREE_CHUNK_SIZE; + prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom)); + + /* Now try to claim that */ + mem_start = (unsigned long)alloc_up(room, PAGE_SIZE); + if (mem_start == 0) + prom_panic("Can't allocate initial device-tree chunk\n"); + mem_end = RELOC(alloc_top); + + /* Get root of tree */ + root = call_prom("peer", 1, 1, (phandle)0); + if (root == (phandle)0) + prom_panic ("couldn't get device tree root\n"); + + /* Build header and make room for mem rsv map */ + mem_start = _ALIGN(mem_start, 4); + hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); + RELOC(dt_header_start) = (unsigned long)hdr; + rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); + + /* Start of strings */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_string_start) = mem_start; + mem_start += 4; /* hole */ + + /* Add "linux,phandle" in there, we'll need it */ + namep = make_room(&mem_start, &mem_end, 16, 1); + strcpy(namep, RELOC("linux,phandle")); + mem_start = (unsigned long)namep + strlen(namep) + 1; + RELOC(dt_string_end) = mem_start; + + /* Build string array */ + prom_printf("Building dt strings...\n"); + scan_dt_build_strings(root, &mem_start, &mem_end); + + /* Build structure */ + mem_start = PAGE_ALIGN(mem_start); + RELOC(dt_struct_start) = mem_start; + prom_printf("Building dt structure...\n"); + scan_dt_build_struct(root, &mem_start, &mem_end); + dt_push_token(OF_DT_END, &mem_start, &mem_end); + RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); + + /* Finish header */ + hdr->magic = OF_DT_HEADER; + hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); + hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); + hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); + hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); + hdr->version = OF_DT_VERSION; + hdr->last_comp_version = 1; + + /* Reserve the whole thing and copy the reserve map in, we + * also bump mem_reserve_cnt to cause further reservations to + * fail since it's too late. + */ + reserve_mem(RELOC(dt_header_start), hdr->totalsize); + memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map)); + +#ifdef DEBUG_PROM + { + int i; + prom_printf("reserved memory map:\n"); + for (i = 0; i < RELOC(mem_reserve_cnt); i++) + prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base, + RELOC(mem_reserve_map)[i].size); + } +#endif + RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE; + + prom_printf("Device tree strings 0x%x -> 0x%x\n", + RELOC(dt_string_start), RELOC(dt_string_end)); + prom_printf("Device tree struct 0x%x -> 0x%x\n", + RELOC(dt_struct_start), RELOC(dt_struct_end)); + + } + +static void __init prom_find_boot_cpu(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + u32 getprop_rval; + ihandle prom_cpu; + phandle cpu_pkg; + + if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0) + prom_panic("cannot find boot cpu"); + + cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); + + prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0); + prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); + _prom->cpu = getprop_rval; + + prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu); +} + +static void __init prom_check_initrd(unsigned long r3, unsigned long r4) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + + if ( r3 && r4 && r4 != 0xdeadbeef) { + u64 val; + + RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3; + RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4; + + val = (u64)RELOC(prom_initrd_start); + prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val)); + val = (u64)RELOC(prom_initrd_end); + prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val)); + + reserve_mem(RELOC(prom_initrd_start), + RELOC(prom_initrd_end) - RELOC(prom_initrd_start)); + + prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start)); + prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end)); + } +#endif /* CONFIG_BLK_DEV_INITRD */ +} + +/* + * We enter here early on, when the Open Firmware prom is still + * handling exceptions and the MMU hash table for us. + */ + +unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp, + unsigned long r6, unsigned long r7) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + unsigned long phys; + u32 getprop_rval; + + /* + * First zero the BSS + */ + memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start); + + /* + * Init interface to Open Firmware, get some node references, + * like /chosen + */ + prom_init_client_services(pp); + + /* + * Init prom stdout device + */ + prom_init_stdout(); + prom_debug("klimit=0x%x\n", RELOC(klimit)); + prom_debug("offset=0x%x\n", offset); + + /* + * Reserve kernel in reserve map + */ + reserve_mem(0, __pa(RELOC(klimit))); + + /* + * Check for an initrd + */ + prom_check_initrd(r3, r4); + + /* + * Get default machine type. At this point, we do not differenciate + * between pSeries SMP and pSeries LPAR + */ + RELOC(of_platform) = prom_find_machine_type(); + getprop_rval = RELOC(of_platform); + prom_setprop(_prom->chosen, "linux,platform", + &getprop_rval, sizeof(getprop_rval)); + + /* + * On pSeries, copy the CPU hold code + */ + if (RELOC(of_platform) & PLATFORM_PSERIES) + copy_and_flush(0, KERNELBASE - offset, 0x100, 0); + + /* + * Get memory cells format + */ + getprop_rval = 1; + prom_getprop(_prom->root, "#size-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_size_cells = getprop_rval; + getprop_rval = 2; + prom_getprop(_prom->root, "#address-cells", + &getprop_rval, sizeof(getprop_rval)); + _prom->root_addr_cells = getprop_rval; + + /* + * Do early parsing of command line + */ + early_cmdline_parse(); + + /* + * Initialize memory management within prom_init + */ + prom_init_mem(); + + /* + * Determine which cpu is actually running right _now_ + */ + prom_find_boot_cpu(); + + /* + * Initialize display devices + */ + prom_check_displays(); + + /* + * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else + * that uses the allocator, we need to make sure we get the top of memory + * available for us here... + */ + if (RELOC(of_platform) == PLATFORM_PSERIES) + prom_initialize_tce_table(); + + /* + * On non-powermacs, try to instantiate RTAS and puts all CPUs + * in spin-loops. PowerMacs don't have a working RTAS and use + * a different way to spin CPUs + */ + if (RELOC(of_platform) != PLATFORM_POWERMAC) { + prom_instantiate_rtas(); + prom_hold_cpus(); + } + + /* + * Fill in some infos for use by the kernel later on + */ + if (RELOC(ppc64_iommu_off)) + prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0); + if (RELOC(iommu_force_on)) + prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0); + + + // XXX KEXEC TEST HACK + if (0) { + extern unsigned long klimit; + u64 ksize = __pa(RELOC(klimit)); + u64 kcopy; + + kcopy = alloc_down(ksize, PAGE_SIZE, 0); + if (kcopy != 0) { + reserve_mem(kcopy, ksize); + prom_printf("duplicating kernel at %x ...\n", kcopy); + copy_and_flush(kcopy, KERNELBASE - offset, ksize, 0); + prom_setprop(_prom->chosen, "linux,kcopy-base", &kcopy, 8); + prom_setprop(_prom->chosen, "linux,kcopy-size", &ksize, 8); + } + } + + + /* + * Now finally create the flattened device-tree + */ + prom_printf("copying OF device tree ...\n"); + flatten_device_tree(); + + /* + * Call OF "quiesce" method to shut down pending DMA's from + * devices etc... + */ + prom_printf("Calling quiesce ...\n"); + call_prom("quiesce", 0, 0); + + /* + * And finally, call the kernel passing it the flattened device + * tree and NULL as r5, thus triggering the new entry point which + * is common to us and kexec + */ + phys = KERNELBASE - offset; + prom_printf("returning from prom_init\n"); + prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start)); + prom_debug("->phys=0x%x\n", phys); + + __start(RELOC(dt_header_start), phys, 0, RELOC(klimit)); + + return 0; +} + diff -urN linux-2.5/arch/ppc64/kernel/rtas.c linux-prom-clean/arch/ppc64/kernel/rtas.c --- linux-2.5/arch/ppc64/kernel/rtas.c 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/rtas.c 2004-09-17 21:52:58.000000000 +1000 @@ -42,6 +42,7 @@ spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED; char rtas_data_buf[RTAS_DATA_BUF_SIZE]__page_aligned; +unsigned long rtas_rmo_buf; void call_rtas_display_status(char c) @@ -425,7 +426,6 @@ } while (status == RTAS_BUSY); } -unsigned long rtas_rmo_buf = 0; asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { @@ -536,6 +536,50 @@ return rtas_error_log_max; } +/* + * Call early during boot, before mem init or bootmem, to retreive the RTAS + * informations from the device-tree and allocate the RMO buffer for userland + * accesses. + */ +void __init rtas_initialize(void) +{ + /* Get RTAS dev node and fill up our "rtas" structure with infos + * about it. + */ + rtas.dev = of_find_node_by_name(NULL, "rtas"); + if (rtas.dev) { + u64 *basep, *entryp; + u32 *sizep; + + basep = (u64 *)get_property(of_chosen, "linux,rtas-base", NULL); + sizep = (u32 *)get_property(of_chosen, "linux,rtas-size", NULL); + if (basep != NULL && sizep != NULL) { + rtas.base = *basep; + rtas.size = *sizep; + entryp = (u64 *)get_property(of_chosen, "linux,rtas-entry", NULL); + if (entryp == NULL) /* Ugh */ + rtas.entry = rtas.base; + else + rtas.entry = *entryp; + } else + rtas.dev = NULL; + } + /* If RTAS was found, allocate the RMO buffer for it */ + if (rtas.dev) { + unsigned long rtas_region = RTAS_INSTANTIATE_MAX; + if (systemcfg->platform == PLATFORM_PSERIES_LPAR) + rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); + + rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, + rtas_region); + } + +#ifdef CONFIG_HOTPLUG_CPU + rtas_stop_self_args.token = rtas_token("stop-self"); +#endif /* CONFIG_HOTPLUG_CPU */ +} + + EXPORT_SYMBOL(rtas_firmware_flash_list); EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); diff -urN linux-2.5/arch/ppc64/kernel/setup.c linux-prom-clean/arch/ppc64/kernel/setup.c --- linux-2.5/arch/ppc64/kernel/setup.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/setup.c 2004-09-17 22:09:01.000000000 +1000 @@ -48,24 +48,24 @@ #include #include -extern unsigned long klimit; +struct pci_reg_property { + struct pci_address addr; + u32 size_hi; + u32 size_lo; +}; + +struct isa_reg_property { + u32 space; + u32 address; + u32 size; +}; + /* extern void *stab; */ extern HTAB htab_data; +extern unsigned long klimit; -int have_of = 1; - -extern void chrp_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - -extern void pmac_init(unsigned long r3, - unsigned long r4, - unsigned long r5, - unsigned long r6, - unsigned long r7); - +extern void chrp_init(void); +extern void pmac_init(void); extern void fw_feature_init(void); extern void iSeries_init_early(void); extern void pSeries_init_early(void); @@ -76,6 +76,11 @@ extern int idle_setup(void); extern void vpa_init(int cpu); extern void iSeries_parse_cmdline(void); +extern void stab_initialize(unsigned long stab); +extern void htab_initialize(void); +extern void early_init_devtree(void *flat_dt); +extern void unflatten_device_tree(void); +extern void pmac_iommu_alloc(void); unsigned long decr_overclock = 1; unsigned long decr_overclock_proc0 = 1; @@ -83,8 +88,7 @@ unsigned long decr_overclock_proc0_set = 0; int powersave_nap; - -unsigned char aux_device_present; +int have_of = 1; #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; @@ -297,7 +301,6 @@ systemcfg->processorCount = num_present_cpus(); } - #endif /* !defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP) */ #ifdef CONFIG_XMON @@ -312,12 +315,178 @@ early_param("xmon", early_xmon); #endif + +#ifdef CONFIG_PPC_PSERIES +/* + * TODO: Kill as much of that as possible and/or move it to setup_system + * or setup_arch... or eventually kill setup_system + */ +static void __init initialize_naca(void) +{ + struct device_node *np; + char type[64]; + char *typep = type; + unsigned long num_cpus = 0; + struct naca_struct *_naca = naca; + struct systemcfg *_systemcfg = systemcfg; + unsigned long encode_phys_size = 32; + void *prop; + + np = of_find_node_by_path("/"); + if (!np) + return; + prop = get_property(np, "#size-cells", NULL); + if (prop != NULL) + encode_phys_size = (*((u32 *)prop)) << 5; + + for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { + num_cpus += 1; + + /* We're assuming *all* of the CPUs have the same + * d-cache and i-cache sizes... -Peter + */ + + if ( num_cpus == 1 ) { + u32 *sizep, *lsizep; + const char *dc, *ic; + + /* Then read cache informations */ + if (_systemcfg->platform == PLATFORM_POWERMAC){ + dc = "d-cache-block-size"; + ic = "i-cache-block-size"; + } else { + dc = "d-cache-line-size"; + ic = "i-cache-line-size"; + } + + sizep = (u32 *)get_property(np, "d-cache-size", NULL); + + lsizep = (u32 *) get_property(np, dc, NULL); + + _systemcfg->dCacheL1Size = *sizep; + _systemcfg->dCacheL1LineSize = *lsizep; + _naca->dCacheL1LogLineSize = __ilog2(*lsizep); + _naca->dCacheL1LinesPerPage = PAGE_SIZE/(*lsizep); + + sizep = (u32 *)get_property(np, "i-cache-size", NULL); + + lsizep = (u32 *)get_property(np, ic, NULL); + + _systemcfg->iCacheL1Size = *sizep; + _systemcfg->iCacheL1LineSize = *lsizep; + _naca->iCacheL1LogLineSize = __ilog2(*lsizep); + _naca->iCacheL1LinesPerPage = PAGE_SIZE/(*lsizep); + + } + } + + for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { + struct device_node *isa, *pci; + struct isa_reg_property *reg; + union pci_range ranges; + union pci_range *rangesp = &ranges; + + if (_systemcfg->platform == PLATFORM_POWERMAC) + continue; + type[0] = 0; + typep = (char *)get_property(np, "ibm,aix-loc", NULL); + if ((typep == NULL) || (typep && strcmp(typep, "S1"))) + continue; + + reg = (struct isa_reg_property *)get_property(np, "reg", NULL); + + isa = of_get_parent(np); + if (!isa) + panic("no isa parent found\n"); + pci = of_get_parent(isa); + if (!pci) + panic("no pci parent found\n"); + + rangesp = (union pci_range *)get_property(pci, "ranges", NULL); + + if ( encode_phys_size == 32 ) + _naca->serialPortAddr = ranges.pci32.phys+reg->address; + else { + _naca->serialPortAddr = + ((((unsigned long)ranges.pci64.phys_hi) << 32) + | + (ranges.pci64.phys_lo)) + reg->address; + } + } + + if (_systemcfg->platform == PLATFORM_POWERMAC) + _naca->interrupt_controller = IC_OPEN_PIC; + else { + __irq_offset_value = NUM_ISA_INTERRUPTS; + _naca->interrupt_controller = IC_INVALID; + np = NULL; + while ((np = of_find_node_by_name(np, "interrupt-controller"))) + { + typep = (char *)get_property(np, "compatible", NULL); + if (strstr(typep, "open-pic")) + naca->interrupt_controller = IC_OPEN_PIC; + else if (strstr(typep, "ppc-xicp")) + naca->interrupt_controller = IC_PPC_XIC; + else + printk("initialize_naca: failed to recognize" + " interrupt-controller\n"); + break; + } + } + + if (_naca->interrupt_controller == IC_INVALID) { + panic("failed to find interrupt-controller\n"); + } + + /* We gotta have at least 1 cpu... */ + if ( (_systemcfg->processorCount = num_cpus) < 1 ) + panic("no cpus found"); + + /* Add an eye catcher and the systemcfg layout version number */ + strcpy(_systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + _systemcfg->version.major = SYSTEMCFG_MAJOR; + _systemcfg->version.minor = SYSTEMCFG_MINOR; + _systemcfg->processor = mfspr(SPRN_PVR); +} + +static void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + u64 *prop; + + prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); + if (prop != NULL) { + initrd_start = (unsigned long)__va(*prop); + prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); + if (prop != NULL) { + initrd_end = (unsigned long)__va(*prop); + initrd_below_start_ok = 1; + } else + initrd_start = 0; + } + + /* If we were passed an initrd, set the ROOT_DEV properly if the values + * look sensible. If not, clear initrd reference. + */ + if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + initrd_end > initrd_start) + ROOT_DEV = Root_RAM0; + else + initrd_start = initrd_end = 0; + + if (initrd_start) + printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); +#endif /* CONFIG_BLK_DEV_INITRD */ +} + + +#endif /* CONFIG_PPC_PSERIES */ + /* * Do some initial setup of the system. The parameters are those which * were passed in from the bootloader. */ -void setup_system(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) +void __init setup_system(void) { #if defined(CONFIG_SMP) && defined(CONFIG_PPC_PSERIES) int ret, i; @@ -329,6 +498,45 @@ systemcfg->platform = PLATFORM_ISERIES_LPAR; #endif +#ifdef CONFIG_PPC_PSERIES + + /* + * Unflatten the device-tree passed by prom_init or kexec + */ + unflatten_device_tree(); + + /* + * Fill the naca & systemcfg structures with informations + * retreived from the device-tree. Need to be called before + * finish_device_tree() since the later requires some of the + * informations filled up here to properly parse the interrupt + * tree. + */ + initialize_naca(); + + /* + * "Finish" the device-tree, that is do the actual parsing of + * some of the properties like the interrupt map + */ + finish_device_tree(); + + /* + * Initialize RTAS if available + */ + rtas_initialize(); + + /* + * Check if we have an initrd provided via the device-tree + */ + check_for_initrd(); + +#endif /* CONFIG_PPC_PSERIES */ + + /* + * XXX Replace that by a call to a ppc_md call, the correct ppc_md is + * to be found via a probe() call iterating them all done from + * early init. May eventually be merged with setup_arch though .... + */ switch (systemcfg->platform) { #ifdef CONFIG_PPC_ISERIES case PLATFORM_ISERIES_LPAR: @@ -353,32 +561,33 @@ #endif /* CONFIG_PPC_PMAC */ } -#ifdef CONFIG_XMON_DEFAULT - xmon_init(); -#endif - /* If we were passed an initrd, set the ROOT_DEV properly if the values - * look sensible. If not, clear initrd reference. + /* Finish initializing the hash table (do the dynamic + * patching for the fast-path hashtable.S code). + * Done here after the above "early" code has setup the + * hash pointer callbacks */ -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && - initrd_end > initrd_start) - ROOT_DEV = Root_RAM0; - else - initrd_start = initrd_end = 0; -#endif /* CONFIG_BLK_DEV_INITRD */ + htab_finish_init(); + /* + * If we have BootX text initialized, map it now so it can be used + * for debugging + */ #ifdef CONFIG_BOOTX_TEXT map_boot_text(); - if (systemcfg->platform == PLATFORM_POWERMAC) { - early_console_initialized = 1; - register_console(&udbg_console); - } #endif /* CONFIG_BOOTX_TEXT */ + /* + * Initialize xmon + */ +#ifdef CONFIG_XMON_DEFAULT + xmon_init(); +#endif + #ifdef CONFIG_PPC_PMAC if (systemcfg->platform == PLATFORM_POWERMAC) { - finish_device_tree(); - pmac_init(r3, r4, r5, r6, r7); + early_console_initialized = 1; + register_console(&udbg_console); + pmac_init(); } #endif /* CONFIG_PPC_PMAC */ @@ -386,10 +595,9 @@ if (systemcfg->platform & PLATFORM_PSERIES) { early_console_initialized = 1; register_console(&udbg_console); - __irq_offset_value = NUM_ISA_INTERRUPTS; - finish_device_tree(); - chrp_init(r3, r4, r5, r6, r7); + chrp_init(); } + #endif /* CONFIG_PPC_PSERIES */ #ifdef CONFIG_PPC_ISERIES @@ -429,15 +637,6 @@ #endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_SMP */ -#if defined(CONFIG_HOTPLUG_CPU) && !defined(CONFIG_PPC_PMAC) - rtas_stop_self_args.token = rtas_token("stop-self"); -#endif /* CONFIG_HOTPLUG_CPU && !CONFIG_PPC_PMAC */ - - /* Finish initializing the hash table (do the dynamic - * patching for the fast-path hashtable.S code) - */ - htab_finish_init(); - printk("Starting Linux PPC64 %s\n", UTS_RELEASE); printk("-----------------------------------------------------\n"); @@ -526,7 +725,7 @@ #ifdef CONFIG_SMP pvr = per_cpu(pvr, cpu_id); #else - pvr = _get_PVR(); + pvr = mfpvr(PSRN_PVR); #endif maj = (pvr >> 8) & 0xFF; min = pvr & 0xFF; @@ -599,18 +798,24 @@ struct device_node *prom_stdout; char *name; int offset = 0; + phandle *stdout_ph; /* The user has requested a console so this is already set up. */ if (strstr(saved_command_line, "console=")) return -EBUSY; - prom_stdout = find_path_device(of_stdout_device); + if (!of_chosen) + return -ENODEV; + stdout_ph = (phandle *)get_property(of_chosen, "linux,stdout-package", NULL); + if (stdout_ph == NULL) + return -ENODEV; + prom_stdout = of_find_node_by_phandle(*stdout_ph); if (!prom_stdout) return -ENODEV; name = (char *)get_property(prom_stdout, "name", NULL); if (!name) - return -ENODEV; + goto not_found; if (strcmp(name, "serial") == 0) { int i; @@ -631,7 +836,7 @@ break; default: /* We dont recognise the serial port */ - return -ENODEV; + goto not_found; } } } else if (strcmp(name, "vty") == 0) { @@ -649,11 +854,13 @@ offset = 1; break; default: - return -ENODEV; + goto not_found; } + of_node_put(prom_stdout); return add_preferred_console("hvsi", offset, NULL); } else { /* pSeries LPAR virtual console */ + of_node_put(prom_stdout); return add_preferred_console("hvc", 0, NULL); } } else if (strcmp(name, "ch-a") == 0) @@ -661,10 +868,14 @@ else if (strcmp(name, "ch-b") == 0) offset = 1; else - return -ENODEV; + goto not_found; + of_node_put(prom_stdout); return add_preferred_console("ttyS", offset, NULL); + not_found: + of_node_put(prom_stdout); + return -ENODEV; } console_initcall(set_preferred_console); #endif @@ -877,6 +1088,43 @@ } +#ifdef CONFIG_PPC_PSERIES + +void __init early_init(unsigned long dt_ptr) +{ + struct paca_struct *lpaca = get_paca(); + + /* + * Do early initializations using the flattened device + * tree, like retreiving the physical memory map or + * calculating/retreiving the hash table size + */ + early_init_devtree(__va(dt_ptr)); + + /* + * On PowerMac, the DART (iommu) must be allocated now since it + * has an impact on htab_initialize (due to the large page it + * occupies having to be broken up so the DART itself is not + * part of the cacheable linar mapping + */ +#ifdef CONFIG_PMAC_DART + pmac_iommu_alloc(); +#endif + /* + * Initialize stab / SLB management + */ + stab_initialize(lpaca->stab_real); + + /* + * Initialize the MMU Hash table and create the linear mapping + * of memory + */ + htab_initialize(); +} + +#endif /* CONFIG_PPC_PSERIES */ + + __setup("spread_lpevents=", set_spread_lpevents ); __setup("decr_overclock_proc0=", set_decr_overclock_proc0 ); __setup("decr_overclock=", set_decr_overclock ); diff -urN linux-2.5/arch/ppc64/kernel/smp.c linux-prom-clean/arch/ppc64/kernel/smp.c --- linux-2.5/arch/ppc64/kernel/smp.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/kernel/smp.c 2004-09-15 21:53:26.000000000 +1000 @@ -75,6 +75,7 @@ unsigned long vpa); int smt_enabled_at_boot = 1; +int boot_cpuid = 0; /* Low level assembly function used to backup CPU 0 state */ extern void __save_cpu_setup(void); @@ -749,7 +750,7 @@ static void __devinit smp_store_cpu_info(int id) { - per_cpu(pvr, id) = _get_PVR(); + per_cpu(pvr, id) = mfspr(SPRN_PVR); } static void __init smp_create_idle(unsigned int cpu) diff -urN linux-2.5/arch/ppc64/mm/hash_utils.c linux-prom-clean/arch/ppc64/mm/hash_utils.c --- linux-2.5/arch/ppc64/mm/hash_utils.c 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/arch/ppc64/mm/hash_utils.c 2004-09-17 20:55:51.000000000 +1000 @@ -147,8 +147,11 @@ htab_data.htab_num_ptegs = pteg_count; htab_data.htab_hash_mask = pteg_count - 1; - if (systemcfg->platform == PLATFORM_PSERIES || - systemcfg->platform == PLATFORM_POWERMAC) { + if (systemcfg->platform & PLATFORM_LPAR) { + /* Using a hypervisor which owns the htab */ + htab_data.htab = NULL; + _SDR1 = 0; + } else { /* Find storage for the HPT. Must be contiguous in * the absolute address space. */ @@ -164,10 +167,6 @@ /* Initialize the HPT with no entries */ memset((void *)table, 0, htab_size_bytes); - } else { - /* Using a hypervisor which owns the htab */ - htab_data.htab = NULL; - _SDR1 = 0; } mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX; @@ -179,7 +178,7 @@ if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE) use_largepages = 1; - /* add all physical memory to the bootmem map */ + /* create bolted the linear mapping in the hash table */ for (i=0; i < lmb.memory.cnt; i++) { unsigned long base, size; diff -urN linux-2.5/arch/ppc64/oprofile/common.c linux-prom-clean/arch/ppc64/oprofile/common.c --- linux-2.5/arch/ppc64/oprofile/common.c 2004-08-26 15:46:30.000000000 +1000 +++ linux-prom-clean/arch/ppc64/oprofile/common.c 2004-09-15 21:53:26.000000000 +1000 @@ -133,7 +133,7 @@ { unsigned int pvr; - pvr = _get_PVR(); + pvr = mfspr(SPRN_PVR); switch (PVR_VER(pvr)) { case PV_630: diff -urN linux-2.5/include/asm-ppc64/lmb.h linux-prom-clean/include/asm-ppc64/lmb.h --- linux-2.5/include/asm-ppc64/lmb.h 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/include/asm-ppc64/lmb.h 2004-09-17 14:35:46.000000000 +1000 @@ -20,12 +20,6 @@ #define MAX_LMB_REGIONS 128 -union lmb_reg_property { - struct reg_property32 addr32[MAX_LMB_REGIONS]; - struct reg_property64 addr64[MAX_LMB_REGIONS]; - struct reg_property_pmac addrPM[MAX_LMB_REGIONS]; -}; - #define LMB_ALLOC_ANYWHERE 0 struct lmb_property { @@ -60,6 +54,8 @@ extern unsigned long __init lmb_end_of_DRAM(void); extern unsigned long __init lmb_abs_to_phys(unsigned long); +extern void lmb_dump_all(void); + extern unsigned long io_hole_start; #endif /* _PPC64_LMB_H */ diff -urN linux-2.5/include/asm-ppc64/prom.h linux-prom-clean/include/asm-ppc64/prom.h --- linux-2.5/include/asm-ppc64/prom.h 2004-08-10 10:22:37.000000000 +1000 +++ linux-prom-clean/include/asm-ppc64/prom.h 2004-09-17 17:34:38.000000000 +1000 @@ -24,14 +24,47 @@ #define LONG_LSW(X) (((unsigned long)X) & 0xffffffff) #define LONG_MSW(X) (((unsigned long)X) >> 32) +/* Definitions used by the flattened device tree */ +#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ +#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ +#define OF_DT_END_NODE 0x2 /* End node */ +#define OF_DT_PROP 0x3 /* Property: name off, size, content */ +#define OF_DT_END 0x9 + +#define OF_DT_VERSION 1 + +/* + * This is what gets passed to the kernel by prom_init or kexec + * + * The dt struct contains the device tree structure, full pathes and + * property contents. The dt strings contain a separate block with just + * the strings for the property names, and is fully page aligned and + * self contained in a page, so that it can be kept around by the kernel, + * each property name appears only once in this page (cheap compression) + * + * the mem_rsvmap contains a map of reserved ranges of physical memory, + * passing it here instead of in the device-tree itself greatly simplifies + * the job of everybody. It's just a list of u64 pairs (base/size) that + * ends when size is 0 + */ +struct boot_param_header +{ + u32 magic; /* magic word OF_DT_HEADER */ + u32 totalsize; /* total size of DT block */ + u32 off_dt_struct; /* offset to structure */ + u32 off_dt_strings; /* offset to strings */ + u32 off_mem_rsvmap; /* offset to memory reserve map */ + u32 version; /* format version */ + u32 last_comp_version; /* last compatible version */ +}; + + + typedef u32 phandle; typedef u32 ihandle; typedef u32 phandle32; typedef u32 ihandle32; -extern char *prom_display_paths[]; -extern unsigned int prom_num_displays; - struct address_range { unsigned long space; unsigned long address; @@ -136,6 +169,7 @@ */ struct pci_controller; struct iommu_table; + struct device_node { char *name; char *type; @@ -171,6 +205,8 @@ unsigned long _flags; }; +extern struct device_node *of_chosen; + /* flag descriptions */ #define OF_STALE 0 /* node is slated for deletion */ #define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ @@ -202,34 +238,6 @@ dn->addr_link = de; } -typedef u32 prom_arg_t; - -struct prom_args { - u32 service; - u32 nargs; - u32 nret; - prom_arg_t args[10]; - prom_arg_t *rets; /* Pointer to return values in args[16]. */ -}; - -struct prom_t { - unsigned long entry; - ihandle root; - ihandle chosen; - int cpu; - ihandle stdout; - ihandle disp_node; - struct prom_args args; - unsigned long version; - unsigned long encode_phys_size; - struct bi_record *bi_recs; -}; - -extern struct prom_t prom; -extern char *of_stdout_device; - -extern int boot_cpuid; - /* OBSOLETE: Old stlye node lookup */ extern struct device_node *find_devices(const char *name); extern struct device_node *find_type_devices(const char *type); @@ -246,6 +254,7 @@ extern struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compat); extern struct device_node *of_find_node_by_path(const char *path); +extern struct device_node *of_find_node_by_phandle(phandle handle); extern struct device_node *of_find_all_nodes(struct device_node *prev); extern struct device_node *of_get_parent(const struct device_node *node); extern struct device_node *of_get_next_child(const struct device_node *node, diff -urN linux-2.5/include/asm-ppc64/rtas.h linux-prom-clean/include/asm-ppc64/rtas.h --- linux-2.5/include/asm-ppc64/rtas.h 2004-09-06 16:43:57.000000000 +1000 +++ linux-prom-clean/include/asm-ppc64/rtas.h 2004-09-17 19:54:46.000000000 +1000 @@ -189,6 +189,7 @@ extern int rtas_get_power_level(int powerdomain, int *level); extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); extern int rtas_set_indicator(int indicator, int index, int new_value); +extern void rtas_initialize(void); /* Given an RTAS status code of 9900..9905 compute the hinted delay */ unsigned int rtas_extended_busy_delay_time(int status); diff -urN linux-2.5/include/asm-ppc64/smp.h linux-prom-clean/include/asm-ppc64/smp.h --- linux-2.5/include/asm-ppc64/smp.h 2004-09-15 16:25:15.000000000 +1000 +++ linux-prom-clean/include/asm-ppc64/smp.h 2004-09-15 21:53:31.000000000 +1000 @@ -37,6 +37,7 @@ #define hard_smp_processor_id() (get_paca()->hw_cpu_id) extern cpumask_t cpu_sibling_map[NR_CPUS]; +extern int boot_cpuid; /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. *