diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/boot/dts/taishan.dts | 4 | ||||
-rw-r--r-- | arch/powerpc/boot/treeboot-iss4xx.c | 23 | ||||
-rw-r--r-- | arch/powerpc/configs/44x/iss476-smp_defconfig | 6 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mmu.h | 7 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_44x.S | 42 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_32.c | 2 | ||||
-rw-r--r-- | arch/powerpc/mm/44x_mmu.c | 13 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_hash32.c | 4 | ||||
-rw-r--r-- | arch/powerpc/mm/tlb_nohash.c | 19 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 147 |
11 files changed, 185 insertions, 84 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index c15f2e61e4fd..f8e578be5806 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -842,7 +842,7 @@ config LOWMEM_CAM_NUM config RELOCATABLE bool "Build a relocatable kernel (EXPERIMENTAL)" - depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE + depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && (FSL_BOOKE || PPC_47x) help This builds a kernel image that is capable of running at the location the kernel is loaded at (some alignment restrictions may diff --git a/arch/powerpc/boot/dts/taishan.dts b/arch/powerpc/boot/dts/taishan.dts index 058438f9629b..1657ad0bf8a6 100644 --- a/arch/powerpc/boot/dts/taishan.dts +++ b/arch/powerpc/boot/dts/taishan.dts @@ -337,7 +337,7 @@ rx-fifo-size = <4096>; tx-fifo-size = <2048>; phy-mode = "rgmii"; - phy-map = <0x00000001>; + phy-address = <1>; rgmii-device = <&RGMII0>; rgmii-channel = <0>; zmii-device = <&ZMII0>; @@ -361,7 +361,7 @@ rx-fifo-size = <4096>; tx-fifo-size = <2048>; phy-mode = "rgmii"; - phy-map = <0x00000003>; + phy-address = <3>; rgmii-device = <&RGMII0>; rgmii-channel = <1>; zmii-device = <&ZMII0>; diff --git a/arch/powerpc/boot/treeboot-iss4xx.c b/arch/powerpc/boot/treeboot-iss4xx.c index fcc44952874e..329e710feda2 100644 --- a/arch/powerpc/boot/treeboot-iss4xx.c +++ b/arch/powerpc/boot/treeboot-iss4xx.c @@ -34,9 +34,29 @@ BSS_STACK(4096); +static u32 ibm4xx_memstart; + static void iss_4xx_fixups(void) { - ibm4xx_sdram_fixup_memsize(); + void *memory; + u32 reg[3]; + + memory = finddevice("/memory"); + if (!memory) + fatal("Can't find memory node\n"); + /* This assumes #address-cells = 2, #size-cells =1 and that */ + getprop(memory, "reg", reg, sizeof(reg)); + if (reg[2]) + /* If the device tree specifies the memory range, use it */ + ibm4xx_memstart = reg[1]; + else + /* othersize, read it from the SDRAM controller */ + ibm4xx_sdram_fixup_memsize(); +} + +static void *iss_4xx_vmlinux_alloc(unsigned long size) +{ + return (void *)ibm4xx_memstart; } #define SPRN_PIR 0x11E /* Processor Indentification Register */ @@ -48,6 +68,7 @@ void platform_init(void) simple_alloc_init(_end, avail_ram, 128, 64); platform_ops.fixups = iss_4xx_fixups; + platform_ops.vmlinux_alloc = iss_4xx_vmlinux_alloc; platform_ops.exit = ibm44x_dbcr_reset; pir_reg = mfspr(SPRN_PIR); fdt_set_boot_cpuid_phys(_dtb_start, pir_reg); diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig index 92f863ac8443..a6eb6ad05b2d 100644 --- a/arch/powerpc/configs/44x/iss476-smp_defconfig +++ b/arch/powerpc/configs/44x/iss476-smp_defconfig @@ -3,8 +3,8 @@ CONFIG_SMP=y CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y +CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y @@ -21,10 +21,11 @@ CONFIG_ISS4xx=y CONFIG_HZ_100=y CONFIG_MATH_EMULATION=y CONFIG_IRQ_ALL_CPUS=y -CONFIG_SPARSE_IRQ=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="root=/dev/issblk0" # CONFIG_PCI is not set +CONFIG_ADVANCED_OPTIONS=y +CONFIG_RELOCATABLE=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -67,7 +68,6 @@ CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_CRAMFS=y diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index b427a55ce2ab..698b30638681 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -125,9 +125,14 @@ static inline int mmu_has_feature(unsigned long feature) return (cur_cpu_spec->mmu_features & feature); } +static inline void mmu_clear_feature(unsigned long feature) +{ + cur_cpu_spec->mmu_features &= ~feature; +} + extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup; -/* MMU initialization (64-bit only fo now) */ +/* MMU initialization */ extern void early_init_mmu(void); extern void early_init_mmu_secondary(void); diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index 5e12b741ba5f..f8e971ba94f5 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S @@ -93,6 +93,30 @@ _ENTRY(_start); bl early_init +#ifdef CONFIG_RELOCATABLE + /* + * r25 will contain RPN/ERPN for the start address of memory + * + * Add the difference between KERNELBASE and PAGE_OFFSET to the + * start of physical memory to get kernstart_addr. + */ + lis r3,kernstart_addr@ha + la r3,kernstart_addr@l(r3) + + lis r4,KERNELBASE@h + ori r4,r4,KERNELBASE@l + lis r5,PAGE_OFFSET@h + ori r5,r5,PAGE_OFFSET@l + subf r4,r5,r4 + + rlwinm r6,r25,0,28,31 /* ERPN */ + rlwinm r7,r25,0,0,3 /* RPN - assuming 256 MB page size */ + add r7,r7,r4 + + stw r6,0(r3) + stw r7,4(r3) +#endif + /* * Decide what sort of machine this is and initialize the MMU. */ @@ -1001,9 +1025,6 @@ clear_utlb_entry: lis r3,PAGE_OFFSET@h ori r3,r3,PAGE_OFFSET@l - /* Kernel is at the base of RAM */ - li r4, 0 /* Load the kernel physical address */ - /* Load the kernel PID = 0 */ li r0,0 mtspr SPRN_PID,r0 @@ -1013,9 +1034,8 @@ clear_utlb_entry: clrrwi r3,r3,12 /* Mask off the effective page number */ ori r3,r3,PPC47x_TLB0_VALID | PPC47x_TLB0_256M - /* Word 1 */ - clrrwi r4,r4,12 /* Mask off the real page number */ - /* ERPN is 0 for first 4GB page */ + /* Word 1 - use r25. RPN is the same as the original entry */ + /* Word 2 */ li r5,0 ori r5,r5,PPC47x_TLB2_S_RWX @@ -1026,7 +1046,7 @@ clear_utlb_entry: /* We write to way 0 and bolted 0 */ lis r0,0x8800 tlbwe r3,r0,0 - tlbwe r4,r0,1 + tlbwe r25,r0,1 tlbwe r5,r0,2 /* @@ -1124,7 +1144,13 @@ head_start_common: lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ mtspr SPRN_IVPR,r4 - addis r22,r22,KERNELBASE@h + /* + * If the kernel was loaded at a non-zero 256 MB page, we need to + * mask off the most significant 4 bits to get the relative address + * from the start of physical memory + */ + rlwinm r22,r22,0,4,31 + addis r22,r22,PAGE_OFFSET@h mtlr r22 isync blr diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 3dffce673c1f..209135af0a40 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -127,6 +127,8 @@ notrace void __init machine_init(unsigned long dt_ptr) /* Do some early initialization based on the flat device tree */ early_init_devtree(__va(dt_ptr)); + early_init_mmu(); + probe_machine(); setup_kdump_trampoline(); diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c index 024acab588fd..f60e006d90c3 100644 --- a/arch/powerpc/mm/44x_mmu.c +++ b/arch/powerpc/mm/44x_mmu.c @@ -186,10 +186,11 @@ void __init MMU_init_hw(void) unsigned long __init mmu_mapin_ram(unsigned long top) { unsigned long addr; + unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1); /* Pin in enough TLBs to cover any lowmem not covered by the * initial 256M mapping established in head_44x.S */ - for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; + for (addr = memstart + PPC_PIN_SIZE; addr < lowmem_end_addr; addr += PPC_PIN_SIZE) { if (mmu_has_feature(MMU_FTR_TYPE_47x)) ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); @@ -218,19 +219,25 @@ unsigned long __init mmu_mapin_ram(unsigned long top) void setup_initial_memory_limit(phys_addr_t first_memblock_base, phys_addr_t first_memblock_size) { + u64 size; + +#ifndef CONFIG_RELOCATABLE /* We don't currently support the first MEMBLOCK not mapping 0 * physical on those processors */ BUG_ON(first_memblock_base != 0); +#endif /* 44x has a 256M TLB entry pinned at boot */ - memblock_set_current_limit(min_t(u64, first_memblock_size, PPC_PIN_SIZE)); + size = (min_t(u64, first_memblock_size, PPC_PIN_SIZE)); + memblock_set_current_limit(first_memblock_base + size); } #ifdef CONFIG_SMP void __cpuinit mmu_init_secondary(int cpu) { unsigned long addr; + unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1); /* Pin in enough TLBs to cover any lowmem not covered by the * initial 256M mapping established in head_44x.S @@ -241,7 +248,7 @@ void __cpuinit mmu_init_secondary(int cpu) * stack. current (r2) isn't initialized, smp_processor_id() * will not work, current thread info isn't accessible, ... */ - for (addr = PPC_PIN_SIZE; addr < lowmem_end_addr; + for (addr = memstart + PPC_PIN_SIZE; addr < lowmem_end_addr; addr += PPC_PIN_SIZE) { if (mmu_has_feature(MMU_FTR_TYPE_47x)) ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c index 27b863c14941..9a445f64accd 100644 --- a/arch/powerpc/mm/tlb_hash32.c +++ b/arch/powerpc/mm/tlb_hash32.c @@ -177,3 +177,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, flush_range(vma->vm_mm, start, end); } EXPORT_SYMBOL(flush_tlb_range); + +void __init early_init_mmu(void) +{ +} diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index e80ed1093e2f..d32ec643c231 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -35,6 +35,7 @@ #include <linux/preempt.h> #include <linux/spinlock.h> #include <linux/memblock.h> +#include <linux/of_fdt.h> #include <asm/tlbflush.h> #include <asm/tlb.h> @@ -272,6 +273,17 @@ EXPORT_SYMBOL(flush_tlb_page); #endif /* CONFIG_SMP */ +#ifdef CONFIG_PPC_47x +void __init early_init_mmu_47x(void) +{ +#ifdef CONFIG_SMP + unsigned long root = of_get_flat_dt_root(); + if (of_get_flat_dt_prop(root, "cooperative-partition", NULL)) + mmu_clear_feature(MMU_FTR_USE_TLBIVAX_BCAST); +#endif /* CONFIG_SMP */ +} +#endif /* CONFIG_PPC_47x */ + /* * Flush kernel TLB entries in the given range */ @@ -599,4 +611,11 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, /* Finally limit subsequent allocations */ memblock_set_current_limit(first_memblock_base + ppc64_rma_size); } +#else /* ! CONFIG_PPC64 */ +void __init early_init_mmu(void) +{ +#ifdef CONFIG_PPC_47x + early_init_mmu_47x(); +#endif +} #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 156aa7d36258..3cf59b661156 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -650,12 +650,74 @@ struct ppc4xx_pciex_hwops int (*core_init)(struct device_node *np); int (*port_init_hw)(struct ppc4xx_pciex_port *port); int (*setup_utl)(struct ppc4xx_pciex_port *port); + void (*check_link)(struct ppc4xx_pciex_port *port); }; static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; #ifdef CONFIG_44x +static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, + unsigned int sdr_offset, + unsigned int mask, + unsigned int value, + int timeout_ms) +{ + u32 val; + + while(timeout_ms--) { + val = mfdcri(SDR0, port->sdr_base + sdr_offset); + if ((val & mask) == value) { + pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", + port->index, sdr_offset, timeout_ms, val); + return 0; + } + msleep(1); + } + return -1; +} + +static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port) +{ + /* Wait for reset to complete */ + if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { + printk(KERN_WARNING "PCIE%d: PGRST failed\n", + port->index); + return -1; + } + return 0; +} + +static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port) +{ + printk(KERN_INFO "PCIE%d: Checking link...\n", port->index); + + /* Check for card presence detect if supported, if not, just wait for + * link unconditionally. + * + * note that we don't fail if there is no link, we just filter out + * config space accesses. That way, it will be easier to implement + * hotplug later on. + */ + if (!port->has_ibpre || + !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, + 1 << 28, 1 << 28, 100)) { + printk(KERN_INFO + "PCIE%d: Device detected, waiting for link...\n", + port->index); + if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, + 0x1000, 0x1000, 2000)) + printk(KERN_WARNING + "PCIE%d: Link up failed\n", port->index); + else { + printk(KERN_INFO + "PCIE%d: link is up !\n", port->index); + port->link = 1; + } + } else + printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); +} + /* Check various reset bits of the 440SPe PCIe core */ static int __init ppc440spe_pciex_check_reset(struct device_node *np) { @@ -806,7 +868,7 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, (1 << 24) | (1 << 16), 1 << 12); - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) @@ -856,6 +918,7 @@ static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = .core_init = ppc440spe_pciex_core_init, .port_init_hw = ppc440speA_pciex_init_port_hw, .setup_utl = ppc440speA_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = @@ -863,6 +926,7 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = .core_init = ppc440spe_pciex_core_init, .port_init_hw = ppc440speB_pciex_init_port_hw, .setup_utl = ppc440speB_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static int __init ppc460ex_pciex_core_init(struct device_node *np) @@ -944,7 +1008,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) @@ -972,6 +1036,7 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = .core_init = ppc460ex_pciex_core_init, .port_init_hw = ppc460ex_pciex_init_port_hw, .setup_utl = ppc460ex_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; static int __init ppc460sx_pciex_core_init(struct device_node *np) @@ -1075,7 +1140,7 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) @@ -1089,6 +1154,7 @@ static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { .core_init = ppc460sx_pciex_core_init, .port_init_hw = ppc460sx_pciex_init_port_hw, .setup_utl = ppc460sx_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; #endif /* CONFIG_44x */ @@ -1154,7 +1220,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) port->has_ibpre = 1; - return 0; + return ppc4xx_pciex_port_reset_sdr(port); } static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) @@ -1183,11 +1249,11 @@ static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = .core_init = ppc405ex_pciex_core_init, .port_init_hw = ppc405ex_pciex_init_port_hw, .setup_utl = ppc405ex_pciex_init_utl, + .check_link = ppc4xx_pciex_check_link_sdr, }; #endif /* CONFIG_40x */ - /* Check that the core has been initied and if not, do it */ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) { @@ -1261,26 +1327,6 @@ static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); } -static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, - unsigned int sdr_offset, - unsigned int mask, - unsigned int value, - int timeout_ms) -{ - u32 val; - - while(timeout_ms--) { - val = mfdcri(SDR0, port->sdr_base + sdr_offset); - if ((val & mask) == value) { - pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", - port->index, sdr_offset, timeout_ms, val); - return 0; - } - msleep(1); - } - return -1; -} - static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) { int rc = 0; @@ -1291,40 +1337,8 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) if (rc != 0) return rc; - printk(KERN_INFO "PCIE%d: Checking link...\n", - port->index); - - /* Wait for reset to complete */ - if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { - printk(KERN_WARNING "PCIE%d: PGRST failed\n", - port->index); - return -1; - } - - /* Check for card presence detect if supported, if not, just wait for - * link unconditionally. - * - * note that we don't fail if there is no link, we just filter out - * config space accesses. That way, it will be easier to implement - * hotplug later on. - */ - if (!port->has_ibpre || - !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, - 1 << 28, 1 << 28, 100)) { - printk(KERN_INFO - "PCIE%d: Device detected, waiting for link...\n", - port->index); - if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, - 0x1000, 0x1000, 2000)) - printk(KERN_WARNING - "PCIE%d: Link up failed\n", port->index); - else { - printk(KERN_INFO - "PCIE%d: link is up !\n", port->index); - port->link = 1; - } - } else - printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); + if (ppc4xx_pciex_hwops->check_link) + ppc4xx_pciex_hwops->check_link(port); /* * Initialize mapping: disable all regions and configure @@ -1347,14 +1361,17 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) /* * Check for VC0 active and assert RDY. */ - if (port->link && - ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, - 1 << 16, 1 << 16, 5000)) { - printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); - port->link = 0; + if (port->sdr_base) { + if (port->link && + ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, + 1 << 16, 1 << 16, 5000)) { + printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); + port->link = 0; + } + + dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); } - dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); msleep(100); return 0; |