/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2005-2008 Cavium Networks, Inc */ #ifndef __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H #define __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H #define CP0_CYCLE_COUNTER $9, 6 #define CP0_CVMCTL_REG $9, 7 #define CP0_CVMMEMCTL_REG $11,7 #define CP0_PRID_REG $15, 0 #define CP0_PRID_OCTEON_PASS1 0x000d0000 #define CP0_PRID_OCTEON_CN30XX 0x000d0200 .macro kernel_entry_setup # Registers set by bootloader: # (only 32 bits set by bootloader, all addresses are physical # addresses, and need to have the appropriate memory region set # by the kernel # a0 = argc # a1 = argv (kseg0 compat addr) # a2 = 1 if init core, zero otherwise # a3 = address of boot descriptor block .set push .set arch=octeon # Read the cavium mem control register dmfc0 v0, CP0_CVMMEMCTL_REG # Clear the lower 6 bits, the CVMSEG size dins v0, $0, 0, 6 ori v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE dmtc0 v0, CP0_CVMMEMCTL_REG # Write the cavium mem control register dmfc0 v0, CP0_CVMCTL_REG # Read the cavium control register # Disable unaligned load/store support but leave HW fixup enabled # Needed for octeon specific memcpy or v0, v0, 0x5001 xor v0, v0, 0x1001 # Read the processor ID register mfc0 v1, CP0_PRID_REG # Disable instruction prefetching (Octeon Pass1 errata) or v0, v0, 0x2000 # Skip reenable of prefetching for Octeon Pass1 beq v1, CP0_PRID_OCTEON_PASS1, skip nop # Reenable instruction prefetching, not on Pass1 xor v0, v0, 0x2000 # Strip off pass number off of processor id srl v1, 8 sll v1, 8 # CN30XX needs some extra stuff turned off for better performance bne v1, CP0_PRID_OCTEON_CN30XX, skip nop # CN30XX Use random Icache replacement or v0, v0, 0x400 # CN30XX Disable instruction prefetching or v0, v0, 0x2000 skip: # First clear off CvmCtl[IPPCI] bit and move the performance # counters interrupt to IRQ 6 li v1, ~(7 << 7) and v0, v0, v1 ori v0, v0, (6 << 7) mfc0 v1, CP0_PRID_REG and t1, v1, 0xfff8 xor t1, t1, 0x9000 # 63-P1 beqz t1, 4f and t1, v1, 0xfff8 xor t1, t1, 0x9008 # 63-P2 beqz t1, 4f and t1, v1, 0xfff8 xor t1, t1, 0x9100 # 68-P1 beqz t1, 4f and t1, v1, 0xff00 xor t1, t1, 0x9200 # 66-PX bnez t1, 5f # Skip WAR for others. and t1, v1, 0x00ff slti t1, t1, 2 # 66-P1.2 and later good. beqz t1, 5f 4: # core-16057 work around or v0, v0, 0x2000 # Set IPREF bit. 5: # No core-16057 work around # Write the cavium control register dmtc0 v0, CP0_CVMCTL_REG sync # Flush dcache after config change cache 9, 0($0) # Get my core id rdhwr v0, $0 # Jump the master to kernel_entry bne a2, zero, octeon_main_processor nop #ifdef CONFIG_SMP # # All cores other than the master need to wait here for SMP bootstrap # to begin # # This is the variable where the next core to boot os stored PTR_LA t0, octeon_processor_boot octeon_spin_wait_boot: # Get the core id of the next to be booted LONG_L t1, (t0) # Keep looping if it isn't me bne t1, v0, octeon_spin_wait_boot nop # Get my GP from the global variable PTR_LA t0, octeon_processor_gp LONG_L gp, (t0) # Get my SP from the global variable PTR_LA t0, octeon_processor_sp LONG_L sp, (t0) # Set the SP global variable to zero so the master knows we've started LONG_S zero, (t0) #ifdef __OCTEON__ syncw syncw #else sync #endif # Jump to the normal Linux SMP entry point j smp_bootstrap nop #else /* CONFIG_SMP */ # # Someone tried to boot SMP with a non SMP kernel. All extra cores # will halt here. # octeon_wait_forever: wait b octeon_wait_forever nop #endif /* CONFIG_SMP */ octeon_main_processor: .set pop .endm /* * Do SMP slave processor setup necessary before we can savely execute C code. */ .macro smp_slave_setup .endm #endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */