diff options
Diffstat (limited to 'arch/ia64/kernel/head.S')
-rw-r--r-- | arch/ia64/kernel/head.S | 280 |
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;; \ | ||
51 | 1: \ | ||
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;; \ | ||
90 | RestRR: \ | ||
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 | ;; |
143 | 1: // now we are in virtual mode | 261 | 1: // 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 | ||
1123 | GLOBAL_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;; | ||
1145 | 1: | ||
1146 | /* | ||
1147 | * Invalidate all TLB data/inst | ||
1148 | */ | ||
1149 | br.sptk.many b2;; // jump to tlb purge code | ||
1150 | |||
1151 | tlb_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;; | ||
1213 | END(ia64_jump_to_sal) | ||
1214 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
1215 | |||
996 | #endif /* CONFIG_SMP */ | 1216 | #endif /* CONFIG_SMP */ |