Merge remote-tracking branch 'jwb/next' into next

This commit is contained in:
Benjamin Herrenschmidt 2011-07-22 13:16:41 +10:00
commit 4b575f3e8a
12 changed files with 186 additions and 85 deletions

View file

@ -3876,7 +3876,7 @@ F: arch/powerpc/platforms/512x/
F: arch/powerpc/platforms/52xx/ F: arch/powerpc/platforms/52xx/
LINUX FOR POWERPC EMBEDDED PPC4XX LINUX FOR POWERPC EMBEDDED PPC4XX
M: Josh Boyer <jwboyer@linux.vnet.ibm.com> M: Josh Boyer <jwboyer@gmail.com>
M: Matt Porter <mporter@kernel.crashing.org> M: Matt Porter <mporter@kernel.crashing.org>
W: http://www.penguinppc.org/ W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org L: linuxppc-dev@lists.ozlabs.org

View file

@ -842,7 +842,7 @@ config LOWMEM_CAM_NUM
config RELOCATABLE config RELOCATABLE
bool "Build a relocatable kernel (EXPERIMENTAL)" 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 help
This builds a kernel image that is capable of running at the This builds a kernel image that is capable of running at the
location the kernel is loaded at (some alignment restrictions may location the kernel is loaded at (some alignment restrictions may

View file

@ -337,7 +337,7 @@
rx-fifo-size = <4096>; rx-fifo-size = <4096>;
tx-fifo-size = <2048>; tx-fifo-size = <2048>;
phy-mode = "rgmii"; phy-mode = "rgmii";
phy-map = <0x00000001>; phy-address = <1>;
rgmii-device = <&RGMII0>; rgmii-device = <&RGMII0>;
rgmii-channel = <0>; rgmii-channel = <0>;
zmii-device = <&ZMII0>; zmii-device = <&ZMII0>;
@ -361,7 +361,7 @@
rx-fifo-size = <4096>; rx-fifo-size = <4096>;
tx-fifo-size = <2048>; tx-fifo-size = <2048>;
phy-mode = "rgmii"; phy-mode = "rgmii";
phy-map = <0x00000003>; phy-address = <3>;
rgmii-device = <&RGMII0>; rgmii-device = <&RGMII0>;
rgmii-channel = <1>; rgmii-channel = <1>;
zmii-device = <&ZMII0>; zmii-device = <&ZMII0>;

View file

@ -34,9 +34,29 @@
BSS_STACK(4096); BSS_STACK(4096);
static u32 ibm4xx_memstart;
static void iss_4xx_fixups(void) 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 */ #define SPRN_PIR 0x11E /* Processor Indentification Register */
@ -48,6 +68,7 @@ void platform_init(void)
simple_alloc_init(_end, avail_ram, 128, 64); simple_alloc_init(_end, avail_ram, 128, 64);
platform_ops.fixups = iss_4xx_fixups; platform_ops.fixups = iss_4xx_fixups;
platform_ops.vmlinux_alloc = iss_4xx_vmlinux_alloc;
platform_ops.exit = ibm44x_dbcr_reset; platform_ops.exit = ibm44x_dbcr_reset;
pir_reg = mfspr(SPRN_PIR); pir_reg = mfspr(SPRN_PIR);
fdt_set_boot_cpuid_phys(_dtb_start, pir_reg); fdt_set_boot_cpuid_phys(_dtb_start, pir_reg);

View file

@ -3,8 +3,8 @@ CONFIG_SMP=y
CONFIG_EXPERIMENTAL=y CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14 CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y CONFIG_EXPERT=y
@ -21,10 +21,11 @@ CONFIG_ISS4xx=y
CONFIG_HZ_100=y CONFIG_HZ_100=y
CONFIG_MATH_EMULATION=y CONFIG_MATH_EMULATION=y
CONFIG_IRQ_ALL_CPUS=y CONFIG_IRQ_ALL_CPUS=y
CONFIG_SPARSE_IRQ=y
CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="root=/dev/issblk0" CONFIG_CMDLINE="root=/dev/issblk0"
# CONFIG_PCI is not set # CONFIG_PCI is not set
CONFIG_ADVANCED_OPTIONS=y
CONFIG_RELOCATABLE=y
CONFIG_NET=y CONFIG_NET=y
CONFIG_PACKET=y CONFIG_PACKET=y
CONFIG_UNIX=y CONFIG_UNIX=y
@ -67,7 +68,6 @@ CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y CONFIG_EXT3_FS_SECURITY=y
CONFIG_INOTIFY=y
CONFIG_PROC_KCORE=y CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y CONFIG_TMPFS=y
CONFIG_CRAMFS=y CONFIG_CRAMFS=y

View file

@ -125,9 +125,14 @@ static inline int mmu_has_feature(unsigned long feature)
return (cur_cpu_spec->mmu_features & 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; 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(void);
extern void early_init_mmu_secondary(void); extern void early_init_mmu_secondary(void);

View file

@ -93,6 +93,30 @@ _ENTRY(_start);
bl early_init 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. * Decide what sort of machine this is and initialize the MMU.
*/ */
@ -1001,9 +1025,6 @@ clear_utlb_entry:
lis r3,PAGE_OFFSET@h lis r3,PAGE_OFFSET@h
ori r3,r3,PAGE_OFFSET@l 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 */ /* Load the kernel PID = 0 */
li r0,0 li r0,0
mtspr SPRN_PID,r0 mtspr SPRN_PID,r0
@ -1013,9 +1034,8 @@ clear_utlb_entry:
clrrwi r3,r3,12 /* Mask off the effective page number */ clrrwi r3,r3,12 /* Mask off the effective page number */
ori r3,r3,PPC47x_TLB0_VALID | PPC47x_TLB0_256M ori r3,r3,PPC47x_TLB0_VALID | PPC47x_TLB0_256M
/* Word 1 */ /* Word 1 - use r25. RPN is the same as the original entry */
clrrwi r4,r4,12 /* Mask off the real page number */
/* ERPN is 0 for first 4GB page */
/* Word 2 */ /* Word 2 */
li r5,0 li r5,0
ori r5,r5,PPC47x_TLB2_S_RWX ori r5,r5,PPC47x_TLB2_S_RWX
@ -1026,7 +1046,7 @@ clear_utlb_entry:
/* We write to way 0 and bolted 0 */ /* We write to way 0 and bolted 0 */
lis r0,0x8800 lis r0,0x8800
tlbwe r3,r0,0 tlbwe r3,r0,0
tlbwe r4,r0,1 tlbwe r25,r0,1
tlbwe r5,r0,2 tlbwe r5,r0,2
/* /*
@ -1124,7 +1144,13 @@ head_start_common:
lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */
mtspr SPRN_IVPR,r4 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 mtlr r22
isync isync
blr blr

View file

@ -127,6 +127,8 @@ notrace void __init machine_init(unsigned long dt_ptr)
/* Do some early initialization based on the flat device tree */ /* Do some early initialization based on the flat device tree */
early_init_devtree(__va(dt_ptr)); early_init_devtree(__va(dt_ptr));
early_init_mmu();
probe_machine(); probe_machine();
setup_kdump_trampoline(); setup_kdump_trampoline();

View file

@ -186,10 +186,11 @@ void __init MMU_init_hw(void)
unsigned long __init mmu_mapin_ram(unsigned long top) unsigned long __init mmu_mapin_ram(unsigned long top)
{ {
unsigned long addr; unsigned long addr;
unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1);
/* Pin in enough TLBs to cover any lowmem not covered by the /* Pin in enough TLBs to cover any lowmem not covered by the
* initial 256M mapping established in head_44x.S */ * 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) { addr += PPC_PIN_SIZE) {
if (mmu_has_feature(MMU_FTR_TYPE_47x)) if (mmu_has_feature(MMU_FTR_TYPE_47x))
ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); 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, void setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size) phys_addr_t first_memblock_size)
{ {
u64 size;
#ifndef CONFIG_RELOCATABLE
/* We don't currently support the first MEMBLOCK not mapping 0 /* We don't currently support the first MEMBLOCK not mapping 0
* physical on those processors * physical on those processors
*/ */
BUG_ON(first_memblock_base != 0); BUG_ON(first_memblock_base != 0);
#endif
/* 44x has a 256M TLB entry pinned at boot */ /* 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 #ifdef CONFIG_SMP
void __cpuinit mmu_init_secondary(int cpu) void __cpuinit mmu_init_secondary(int cpu)
{ {
unsigned long addr; unsigned long addr;
unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1);
/* Pin in enough TLBs to cover any lowmem not covered by the /* Pin in enough TLBs to cover any lowmem not covered by the
* initial 256M mapping established in head_44x.S * 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() * stack. current (r2) isn't initialized, smp_processor_id()
* will not work, current thread info isn't accessible, ... * 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) { addr += PPC_PIN_SIZE) {
if (mmu_has_feature(MMU_FTR_TYPE_47x)) if (mmu_has_feature(MMU_FTR_TYPE_47x))
ppc47x_pin_tlb(addr + PAGE_OFFSET, addr); ppc47x_pin_tlb(addr + PAGE_OFFSET, addr);

View file

@ -177,3 +177,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
flush_range(vma->vm_mm, start, end); flush_range(vma->vm_mm, start, end);
} }
EXPORT_SYMBOL(flush_tlb_range); EXPORT_SYMBOL(flush_tlb_range);
void __init early_init_mmu(void)
{
}

View file

@ -35,6 +35,7 @@
#include <linux/preempt.h> #include <linux/preempt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/tlb.h> #include <asm/tlb.h>
@ -272,6 +273,17 @@ EXPORT_SYMBOL(flush_tlb_page);
#endif /* CONFIG_SMP */ #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 * 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 */ /* Finally limit subsequent allocations */
memblock_set_current_limit(first_memblock_base + ppc64_rma_size); 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 */ #endif /* CONFIG_PPC64 */

View file

@ -650,12 +650,74 @@ struct ppc4xx_pciex_hwops
int (*core_init)(struct device_node *np); int (*core_init)(struct device_node *np);
int (*port_init_hw)(struct ppc4xx_pciex_port *port); int (*port_init_hw)(struct ppc4xx_pciex_port *port);
int (*setup_utl)(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; static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops;
#ifdef CONFIG_44x #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 */ /* Check various reset bits of the 440SPe PCIe core */
static int __init ppc440spe_pciex_check_reset(struct device_node *np) 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, dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
(1 << 24) | (1 << 16), 1 << 12); (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) 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, .core_init = ppc440spe_pciex_core_init,
.port_init_hw = ppc440speA_pciex_init_port_hw, .port_init_hw = ppc440speA_pciex_init_port_hw,
.setup_utl = ppc440speA_pciex_init_utl, .setup_utl = ppc440speA_pciex_init_utl,
.check_link = ppc4xx_pciex_check_link_sdr,
}; };
static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = 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, .core_init = ppc440spe_pciex_core_init,
.port_init_hw = ppc440speB_pciex_init_port_hw, .port_init_hw = ppc440speB_pciex_init_port_hw,
.setup_utl = ppc440speB_pciex_init_utl, .setup_utl = ppc440speB_pciex_init_utl,
.check_link = ppc4xx_pciex_check_link_sdr,
}; };
static int __init ppc460ex_pciex_core_init(struct device_node *np) 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; port->has_ibpre = 1;
return 0; return ppc4xx_pciex_port_reset_sdr(port);
} }
static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *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, .core_init = ppc460ex_pciex_core_init,
.port_init_hw = ppc460ex_pciex_init_port_hw, .port_init_hw = ppc460ex_pciex_init_port_hw,
.setup_utl = ppc460ex_pciex_init_utl, .setup_utl = ppc460ex_pciex_init_utl,
.check_link = ppc4xx_pciex_check_link_sdr,
}; };
static int __init ppc460sx_pciex_core_init(struct device_node *np) 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; port->has_ibpre = 1;
return 0; return ppc4xx_pciex_port_reset_sdr(port);
} }
static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *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, .core_init = ppc460sx_pciex_core_init,
.port_init_hw = ppc460sx_pciex_init_port_hw, .port_init_hw = ppc460sx_pciex_init_port_hw,
.setup_utl = ppc460sx_pciex_init_utl, .setup_utl = ppc460sx_pciex_init_utl,
.check_link = ppc4xx_pciex_check_link_sdr,
}; };
#endif /* CONFIG_44x */ #endif /* CONFIG_44x */
@ -1154,7 +1220,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
port->has_ibpre = 1; port->has_ibpre = 1;
return 0; return ppc4xx_pciex_port_reset_sdr(port);
} }
static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *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, .core_init = ppc405ex_pciex_core_init,
.port_init_hw = ppc405ex_pciex_init_port_hw, .port_init_hw = ppc405ex_pciex_init_port_hw,
.setup_utl = ppc405ex_pciex_init_utl, .setup_utl = ppc405ex_pciex_init_utl,
.check_link = ppc4xx_pciex_check_link_sdr,
}; };
#endif /* CONFIG_40x */ #endif /* CONFIG_40x */
/* Check that the core has been initied and if not, do it */ /* Check that the core has been initied and if not, do it */
static int __init ppc4xx_pciex_check_core_init(struct device_node *np) 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); 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) static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
{ {
int rc = 0; int rc = 0;
@ -1291,40 +1337,8 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
if (rc != 0) if (rc != 0)
return rc; return rc;
printk(KERN_INFO "PCIE%d: Checking link...\n", if (ppc4xx_pciex_hwops->check_link)
port->index); ppc4xx_pciex_hwops->check_link(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;
}
/* 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);
/* /*
* Initialize mapping: disable all regions and configure * 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. * Check for VC0 active and assert RDY.
*/ */
if (port->link && if (port->sdr_base) {
ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, if (port->link &&
1 << 16, 1 << 16, 5000)) { ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); 1 << 16, 1 << 16, 5000)) {
port->link = 0; 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); msleep(100);
return 0; return 0;