aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/kernel/head.S')
-rw-r--r--arch/ia64/kernel/head.S280
1 files changed, 250 insertions, 30 deletions
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 105c7fec8c6d..0d535d65eea6 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -15,6 +15,8 @@
15 * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com> 15 * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
16 * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com> 16 * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
17 * -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2. 17 * -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
18 * Copyright (C) 2004 Ashok Raj <ashok.raj@intel.com>
19 * Support for CPU Hotplug
18 */ 20 */
19 21
20#include <linux/config.h> 22#include <linux/config.h>
@@ -29,6 +31,134 @@
29#include <asm/processor.h> 31#include <asm/processor.h>
30#include <asm/ptrace.h> 32#include <asm/ptrace.h>
31#include <asm/system.h> 33#include <asm/system.h>
34#include <asm/mca_asm.h>
35
36#ifdef CONFIG_HOTPLUG_CPU
37#define SAL_PSR_BITS_TO_SET \
38 (IA64_PSR_AC | IA64_PSR_BN | IA64_PSR_MFH | IA64_PSR_MFL)
39
40#define SAVE_FROM_REG(src, ptr, dest) \
41 mov dest=src;; \
42 st8 [ptr]=dest,0x08
43
44#define RESTORE_REG(reg, ptr, _tmp) \
45 ld8 _tmp=[ptr],0x08;; \
46 mov reg=_tmp
47
48#define SAVE_BREAK_REGS(ptr, _idx, _breg, _dest)\
49 mov ar.lc=IA64_NUM_DBG_REGS-1;; \
50 mov _idx=0;; \
511: \
52 SAVE_FROM_REG(_breg[_idx], ptr, _dest);; \
53 add _idx=1,_idx;; \
54 br.cloop.sptk.many 1b
55
56#define RESTORE_BREAK_REGS(ptr, _idx, _breg, _tmp, _lbl)\
57 mov ar.lc=IA64_NUM_DBG_REGS-1;; \
58 mov _idx=0;; \
59_lbl: RESTORE_REG(_breg[_idx], ptr, _tmp);; \
60 add _idx=1, _idx;; \
61 br.cloop.sptk.many _lbl
62
63#define SAVE_ONE_RR(num, _reg, _tmp) \
64 movl _tmp=(num<<61);; \
65 mov _reg=rr[_tmp]
66
67#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \
68 SAVE_ONE_RR(0,_r0, _tmp);; \
69 SAVE_ONE_RR(1,_r1, _tmp);; \
70 SAVE_ONE_RR(2,_r2, _tmp);; \
71 SAVE_ONE_RR(3,_r3, _tmp);; \
72 SAVE_ONE_RR(4,_r4, _tmp);; \
73 SAVE_ONE_RR(5,_r5, _tmp);; \
74 SAVE_ONE_RR(6,_r6, _tmp);; \
75 SAVE_ONE_RR(7,_r7, _tmp);;
76
77#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7) \
78 st8 [ptr]=_r0, 8;; \
79 st8 [ptr]=_r1, 8;; \
80 st8 [ptr]=_r2, 8;; \
81 st8 [ptr]=_r3, 8;; \
82 st8 [ptr]=_r4, 8;; \
83 st8 [ptr]=_r5, 8;; \
84 st8 [ptr]=_r6, 8;; \
85 st8 [ptr]=_r7, 8;;
86
87#define RESTORE_REGION_REGS(ptr, _idx1, _idx2, _tmp) \
88 mov ar.lc=0x08-1;; \
89 movl _idx1=0x00;; \
90RestRR: \
91 dep.z _idx2=_idx1,61,3;; \
92 ld8 _tmp=[ptr],8;; \
93 mov rr[_idx2]=_tmp;; \
94 srlz.d;; \
95 add _idx1=1,_idx1;; \
96 br.cloop.sptk.few RestRR
97
98/*
99 * Adjust region registers saved before starting to save
100 * break regs and rest of the states that need to be preserved.
101 */
102#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(_reg1,_reg2,_pred) \
103 SAVE_FROM_REG(b0,_reg1,_reg2);; \
104 SAVE_FROM_REG(b1,_reg1,_reg2);; \
105 SAVE_FROM_REG(b2,_reg1,_reg2);; \
106 SAVE_FROM_REG(b3,_reg1,_reg2);; \
107 SAVE_FROM_REG(b4,_reg1,_reg2);; \
108 SAVE_FROM_REG(b5,_reg1,_reg2);; \
109 st8 [_reg1]=r1,0x08;; \
110 st8 [_reg1]=r12,0x08;; \
111 st8 [_reg1]=r13,0x08;; \
112 SAVE_FROM_REG(ar.fpsr,_reg1,_reg2);; \
113 SAVE_FROM_REG(ar.pfs,_reg1,_reg2);; \
114 SAVE_FROM_REG(ar.rnat,_reg1,_reg2);; \
115 SAVE_FROM_REG(ar.unat,_reg1,_reg2);; \
116 SAVE_FROM_REG(ar.bspstore,_reg1,_reg2);; \
117 SAVE_FROM_REG(cr.dcr,_reg1,_reg2);; \
118 SAVE_FROM_REG(cr.iva,_reg1,_reg2);; \
119 SAVE_FROM_REG(cr.pta,_reg1,_reg2);; \
120 SAVE_FROM_REG(cr.itv,_reg1,_reg2);; \
121 SAVE_FROM_REG(cr.pmv,_reg1,_reg2);; \
122 SAVE_FROM_REG(cr.cmcv,_reg1,_reg2);; \
123 SAVE_FROM_REG(cr.lrr0,_reg1,_reg2);; \
124 SAVE_FROM_REG(cr.lrr1,_reg1,_reg2);; \
125 st8 [_reg1]=r4,0x08;; \
126 st8 [_reg1]=r5,0x08;; \
127 st8 [_reg1]=r6,0x08;; \
128 st8 [_reg1]=r7,0x08;; \
129 st8 [_reg1]=_pred,0x08;; \
130 SAVE_FROM_REG(ar.lc, _reg1, _reg2);; \
131 stf.spill.nta [_reg1]=f2,16;; \
132 stf.spill.nta [_reg1]=f3,16;; \
133 stf.spill.nta [_reg1]=f4,16;; \
134 stf.spill.nta [_reg1]=f5,16;; \
135 stf.spill.nta [_reg1]=f16,16;; \
136 stf.spill.nta [_reg1]=f17,16;; \
137 stf.spill.nta [_reg1]=f18,16;; \
138 stf.spill.nta [_reg1]=f19,16;; \
139 stf.spill.nta [_reg1]=f20,16;; \
140 stf.spill.nta [_reg1]=f21,16;; \
141 stf.spill.nta [_reg1]=f22,16;; \
142 stf.spill.nta [_reg1]=f23,16;; \
143 stf.spill.nta [_reg1]=f24,16;; \
144 stf.spill.nta [_reg1]=f25,16;; \
145 stf.spill.nta [_reg1]=f26,16;; \
146 stf.spill.nta [_reg1]=f27,16;; \
147 stf.spill.nta [_reg1]=f28,16;; \
148 stf.spill.nta [_reg1]=f29,16;; \
149 stf.spill.nta [_reg1]=f30,16;; \
150 stf.spill.nta [_reg1]=f31,16;;
151
152#else
153#define SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(a1,a2)
154#define SAVE_REGION_REGS(_tmp, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)
155#define STORE_REGION_REGS(ptr, _r0, _r1, _r2, _r3, _r4, _r5, _r6, _r7)
156#endif
157
158#define SET_ONE_RR(num, pgsize, _tmp1, _tmp2, vhpt) \
159 movl _tmp1=(num << 61);; \
160 mov _tmp2=((ia64_rid(IA64_REGION_ID_KERNEL, (num<<61)) << 8) | (pgsize << 2) | vhpt);; \
161 mov rr[_tmp1]=_tmp2
32 162
33 .section __special_page_section,"ax" 163 .section __special_page_section,"ax"
34 164
@@ -64,6 +194,12 @@ start_ap:
64 srlz.i 194 srlz.i
65 ;; 195 ;;
66 /* 196 /*
197 * Save the region registers, predicate before they get clobbered
198 */
199 SAVE_REGION_REGS(r2, r8,r9,r10,r11,r12,r13,r14,r15);
200 mov r25=pr;;
201
202 /*
67 * Initialize kernel region registers: 203 * Initialize kernel region registers:
68 * rr[0]: VHPT enabled, page size = PAGE_SHIFT 204 * rr[0]: VHPT enabled, page size = PAGE_SHIFT
69 * rr[1]: VHPT enabled, page size = PAGE_SHIFT 205 * rr[1]: VHPT enabled, page size = PAGE_SHIFT
@@ -76,32 +212,14 @@ start_ap:
76 * We initialize all of them to prevent inadvertently assuming 212 * We initialize all of them to prevent inadvertently assuming
77 * something about the state of address translation early in boot. 213 * something about the state of address translation early in boot.
78 */ 214 */
79 mov r6=((ia64_rid(IA64_REGION_ID_KERNEL, (0<<61)) << 8) | (PAGE_SHIFT << 2) | 1) 215 SET_ONE_RR(0, PAGE_SHIFT, r2, r16, 1);;
80 movl r7=(0<<61) 216 SET_ONE_RR(1, PAGE_SHIFT, r2, r16, 1);;
81 mov r8=((ia64_rid(IA64_REGION_ID_KERNEL, (1<<61)) << 8) | (PAGE_SHIFT << 2) | 1) 217 SET_ONE_RR(2, PAGE_SHIFT, r2, r16, 1);;
82 movl r9=(1<<61) 218 SET_ONE_RR(3, PAGE_SHIFT, r2, r16, 1);;
83 mov r10=((ia64_rid(IA64_REGION_ID_KERNEL, (2<<61)) << 8) | (PAGE_SHIFT << 2) | 1) 219 SET_ONE_RR(4, PAGE_SHIFT, r2, r16, 1);;
84 movl r11=(2<<61) 220 SET_ONE_RR(5, PAGE_SHIFT, r2, r16, 1);;
85 mov r12=((ia64_rid(IA64_REGION_ID_KERNEL, (3<<61)) << 8) | (PAGE_SHIFT << 2) | 1) 221 SET_ONE_RR(6, IA64_GRANULE_SHIFT, r2, r16, 0);;
86 movl r13=(3<<61) 222 SET_ONE_RR(7, IA64_GRANULE_SHIFT, r2, r16, 0);;
87 mov r14=((ia64_rid(IA64_REGION_ID_KERNEL, (4<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
88 movl r15=(4<<61)
89 mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, (5<<61)) << 8) | (PAGE_SHIFT << 2) | 1)
90 movl r17=(5<<61)
91 mov r18=((ia64_rid(IA64_REGION_ID_KERNEL, (6<<61)) << 8) | (IA64_GRANULE_SHIFT << 2))
92 movl r19=(6<<61)
93 mov r20=((ia64_rid(IA64_REGION_ID_KERNEL, (7<<61)) << 8) | (IA64_GRANULE_SHIFT << 2))
94 movl r21=(7<<61)
95 ;;
96 mov rr[r7]=r6
97 mov rr[r9]=r8
98 mov rr[r11]=r10
99 mov rr[r13]=r12
100 mov rr[r15]=r14
101 mov rr[r17]=r16
102 mov rr[r19]=r18
103 mov rr[r21]=r20
104 ;;
105 /* 223 /*
106 * Now pin mappings into the TLB for kernel text and data 224 * Now pin mappings into the TLB for kernel text and data
107 */ 225 */
@@ -142,6 +260,13 @@ start_ap:
142 ;; 260 ;;
1431: // now we are in virtual mode 2611: // now we are in virtual mode
144 262
263 movl r2=sal_state_for_booting_cpu;;
264 ld8 r16=[r2];;
265
266 STORE_REGION_REGS(r16, r8,r9,r10,r11,r12,r13,r14,r15);
267 SAL_TO_OS_BOOT_HANDOFF_STATE_SAVE(r16,r17,r25)
268 ;;
269
145 // set IVT entry point---can't access I/O ports without it 270 // set IVT entry point---can't access I/O ports without it
146 movl r3=ia64_ivt 271 movl r3=ia64_ivt
147 ;; 272 ;;
@@ -211,12 +336,13 @@ start_ap:
211 mov IA64_KR(CURRENT_STACK)=r16 336 mov IA64_KR(CURRENT_STACK)=r16
212 mov r13=r2 337 mov r13=r2
213 /* 338 /*
214 * Reserve space at the top of the stack for "struct pt_regs". Kernel threads 339 * Reserve space at the top of the stack for "struct pt_regs". Kernel
215 * don't store interesting values in that structure, but the space still needs 340 * threads don't store interesting values in that structure, but the space
216 * to be there because time-critical stuff such as the context switching can 341 * still needs to be there because time-critical stuff such as the context
217 * be implemented more efficiently (for example, __switch_to() 342 * switching can be implemented more efficiently (for example, __switch_to()
218 * always sets the psr.dfh bit of the task it is switching to). 343 * always sets the psr.dfh bit of the task it is switching to).
219 */ 344 */
345
220 addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2 346 addl r12=IA64_STK_OFFSET-IA64_PT_REGS_SIZE-16,r2
221 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE 347 addl r2=IA64_RBS_OFFSET,r2 // initialize the RSE
222 mov ar.rsc=0 // place RSE in enforced lazy mode 348 mov ar.rsc=0 // place RSE in enforced lazy mode
@@ -993,4 +1119,98 @@ END(ia64_spinlock_contention)
993 1119
994#endif 1120#endif
995 1121
1122#ifdef CONFIG_HOTPLUG_CPU
1123GLOBAL_ENTRY(ia64_jump_to_sal)
1124 alloc r16=ar.pfs,1,0,0,0;;
1125 rsm psr.i | psr.ic
1126{
1127 flushrs
1128 srlz.i
1129}
1130 tpa r25=in0
1131 movl r18=tlb_purge_done;;
1132 DATA_VA_TO_PA(r18);;
1133 mov b1=r18 // Return location
1134 movl r18=ia64_do_tlb_purge;;
1135 DATA_VA_TO_PA(r18);;
1136 mov b2=r18 // doing tlb_flush work
1137 mov ar.rsc=0 // Put RSE in enforced lazy, LE mode
1138 movl r17=1f;;
1139 DATA_VA_TO_PA(r17);;
1140 mov cr.iip=r17
1141 movl r16=SAL_PSR_BITS_TO_SET;;
1142 mov cr.ipsr=r16
1143 mov cr.ifs=r0;;
1144 rfi;;
11451:
1146 /*
1147 * Invalidate all TLB data/inst
1148 */
1149 br.sptk.many b2;; // jump to tlb purge code
1150
1151tlb_purge_done:
1152 RESTORE_REGION_REGS(r25, r17,r18,r19);;
1153 RESTORE_REG(b0, r25, r17);;
1154 RESTORE_REG(b1, r25, r17);;
1155 RESTORE_REG(b2, r25, r17);;
1156 RESTORE_REG(b3, r25, r17);;
1157 RESTORE_REG(b4, r25, r17);;
1158 RESTORE_REG(b5, r25, r17);;
1159 ld8 r1=[r25],0x08;;
1160 ld8 r12=[r25],0x08;;
1161 ld8 r13=[r25],0x08;;
1162 RESTORE_REG(ar.fpsr, r25, r17);;
1163 RESTORE_REG(ar.pfs, r25, r17);;
1164 RESTORE_REG(ar.rnat, r25, r17);;
1165 RESTORE_REG(ar.unat, r25, r17);;
1166 RESTORE_REG(ar.bspstore, r25, r17);;
1167 RESTORE_REG(cr.dcr, r25, r17);;
1168 RESTORE_REG(cr.iva, r25, r17);;
1169 RESTORE_REG(cr.pta, r25, r17);;
1170 RESTORE_REG(cr.itv, r25, r17);;
1171 RESTORE_REG(cr.pmv, r25, r17);;
1172 RESTORE_REG(cr.cmcv, r25, r17);;
1173 RESTORE_REG(cr.lrr0, r25, r17);;
1174 RESTORE_REG(cr.lrr1, r25, r17);;
1175 ld8 r4=[r25],0x08;;
1176 ld8 r5=[r25],0x08;;
1177 ld8 r6=[r25],0x08;;
1178 ld8 r7=[r25],0x08;;
1179 ld8 r17=[r25],0x08;;
1180 mov pr=r17,-1;;
1181 RESTORE_REG(ar.lc, r25, r17);;
1182 /*
1183 * Now Restore floating point regs
1184 */
1185 ldf.fill.nta f2=[r25],16;;
1186 ldf.fill.nta f3=[r25],16;;
1187 ldf.fill.nta f4=[r25],16;;
1188 ldf.fill.nta f5=[r25],16;;
1189 ldf.fill.nta f16=[r25],16;;
1190 ldf.fill.nta f17=[r25],16;;
1191 ldf.fill.nta f18=[r25],16;;
1192 ldf.fill.nta f19=[r25],16;;
1193 ldf.fill.nta f20=[r25],16;;
1194 ldf.fill.nta f21=[r25],16;;
1195 ldf.fill.nta f22=[r25],16;;
1196 ldf.fill.nta f23=[r25],16;;
1197 ldf.fill.nta f24=[r25],16;;
1198 ldf.fill.nta f25=[r25],16;;
1199 ldf.fill.nta f26=[r25],16;;
1200 ldf.fill.nta f27=[r25],16;;
1201 ldf.fill.nta f28=[r25],16;;
1202 ldf.fill.nta f29=[r25],16;;
1203 ldf.fill.nta f30=[r25],16;;
1204 ldf.fill.nta f31=[r25],16;;
1205
1206 /*
1207 * Now that we have done all the register restores
1208 * we are now ready for the big DIVE to SAL Land
1209 */
1210 ssm psr.ic;;
1211 srlz.d;;
1212 br.ret.sptk.many b0;;
1213END(ia64_jump_to_sal)
1214#endif /* CONFIG_HOTPLUG_CPU */
1215
996#endif /* CONFIG_SMP */ 1216#endif /* CONFIG_SMP */