hc
2023-12-06 d38611ca164021d018c1b23eee65bbebc09c63e0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * 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
 
#endif /* __ASM_MACH_CAVIUM_OCTEON_KERNEL_ENTRY_H */