linux-zen-server/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h

169 lines
4.0 KiB
C

/*
* 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_CVMCTL_REG $9, 7
#define CP0_CVMMEMCTL_REG $11,7
#define CP0_PRID_REG $15, 0
#define CP0_DCACHE_ERR_REG $27, 1
#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
# First clear off CvmCtl[IPPCI] bit and move the performance
# counters interrupt to IRQ 6
dli 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)
# Zero all of CVMSEG to make sure parity is correct
dli v0, CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE
dsll v0, 7
beqz v0, 2f
1: dsubu v0, 8
sd $0, -32768(v0)
bnez v0, 1b
2:
mfc0 v0, CP0_PRID_REG
bbit0 v0, 15, 1f
# OCTEON II or better have bit 15 set. Clear the error bits.
and t1, v0, 0xff00
dli v0, 0x9500
bge t1, v0, 1f # OCTEON III has no DCACHE_ERR_REG COP0
dli v0, 0x27
dmtc0 v0, CP0_DCACHE_ERR_REG
1:
# 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
#
octeon_spin_wait_boot:
#ifdef CONFIG_RELOCATABLE
PTR_LA t0, octeon_processor_relocated_kernel_entry
LONG_L t0, (t0)
beq zero, t0, 1f
nop
jr t0
nop
1:
#endif /* CONFIG_RELOCATABLE */
# This is the variable where the next core to boot is stored
PTR_LA t0, octeon_processor_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 safely execute C code.
*/
.macro smp_slave_setup
.endm
#define USE_KEXEC_SMP_WAIT_FINAL
.macro kexec_smp_wait_final
.set push
.set noreorder
synci 0($0)
.set pop
.endm
#endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */