aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/head.S
diff options
context:
space:
mode:
authorAshok Raj <ashok.raj@intel.com>2005-04-22 17:44:40 -0400
committerTony Luck <tony.luck@intel.com>2005-04-22 17:44:40 -0400
commitb8d8b883e6f029e99c35c88f853501740e322131 (patch)
tree391f2ade8823149f217991eb02911bf3dacce050 /arch/ia64/kernel/head.S
parent7130667107cd3ab9d6802b69bab63c7d22f20bd4 (diff)
[IA64] cpu hotplug: return offlined cpus to SAL
This patch is required to support cpu removal for IPF systems. Existing code just fakes the real offline by keeping it run the idle thread, and polling for the bit to re-appear in the cpu_state to get out of the idle loop. For the cpu-offline to work correctly, we need to pass control of this CPU back to SAL so it can continue in the boot-rendez mode. This gives the SAL control to not pick this cpu as the monarch processor for global MCA events, and addition does not wait for this cpu to checkin with SAL for global MCA events as well. The handoff is implemented as documented in SAL specification section 3.2.5.1 "OS_BOOT_RENDEZ to SAL return State" Signed-off-by: Ashok Raj <ashok.raj@intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
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 */