diff options
author | Isaku Yamahata <yamahata@valinux.co.jp> | 2009-03-04 07:05:39 -0500 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2009-03-26 13:50:32 -0400 |
commit | 496203b15b7249599712525c2b6aafe231b4628d (patch) | |
tree | ee8c5dbe02b820ac208fe6f3b7982a49a502cc28 /arch | |
parent | 94752a794ddfdef65289a16627faefa7e2e62d58 (diff) |
ia64/pv_ops/xen: paravirtualize read/write ar.itc and ar.itm
paravirtualize ar.itc and ar.itm in order to support save/restore.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/include/asm/xen/inst.h | 21 | ||||
-rw-r--r-- | arch/ia64/include/asm/xen/interface.h | 9 | ||||
-rw-r--r-- | arch/ia64/include/asm/xen/minstate.h | 11 | ||||
-rw-r--r-- | arch/ia64/include/asm/xen/privop.h | 2 | ||||
-rw-r--r-- | arch/ia64/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/ia64/xen/xen_pv_ops.c | 80 |
6 files changed, 123 insertions, 2 deletions
diff --git a/arch/ia64/include/asm/xen/inst.h b/arch/ia64/include/asm/xen/inst.h index e8e01b28d2ae..90537dc15efe 100644 --- a/arch/ia64/include/asm/xen/inst.h +++ b/arch/ia64/include/asm/xen/inst.h | |||
@@ -113,6 +113,27 @@ | |||
113 | .endm | 113 | .endm |
114 | #define MOV_FROM_PSR(pred, reg, clob) __MOV_FROM_PSR pred, reg, clob | 114 | #define MOV_FROM_PSR(pred, reg, clob) __MOV_FROM_PSR pred, reg, clob |
115 | 115 | ||
116 | /* assuming ar.itc is read with interrupt disabled. */ | ||
117 | #define MOV_FROM_ITC(pred, pred_clob, reg, clob) \ | ||
118 | (pred) movl clob = XSI_ITC_OFFSET; \ | ||
119 | ;; \ | ||
120 | (pred) ld8 clob = [clob]; \ | ||
121 | (pred) mov reg = ar.itc; \ | ||
122 | ;; \ | ||
123 | (pred) add reg = reg, clob; \ | ||
124 | ;; \ | ||
125 | (pred) movl clob = XSI_ITC_LAST; \ | ||
126 | ;; \ | ||
127 | (pred) ld8 clob = [clob]; \ | ||
128 | ;; \ | ||
129 | (pred) cmp.geu.unc pred_clob, p0 = clob, reg; \ | ||
130 | ;; \ | ||
131 | (pred_clob) add reg = 1, clob; \ | ||
132 | ;; \ | ||
133 | (pred) movl clob = XSI_ITC_LAST; \ | ||
134 | ;; \ | ||
135 | (pred) st8 [clob] = reg | ||
136 | |||
116 | 137 | ||
117 | #define MOV_TO_IFA(reg, clob) \ | 138 | #define MOV_TO_IFA(reg, clob) \ |
118 | movl clob = XSI_IFA; \ | 139 | movl clob = XSI_IFA; \ |
diff --git a/arch/ia64/include/asm/xen/interface.h b/arch/ia64/include/asm/xen/interface.h index f00fab40854d..e951e740bdf2 100644 --- a/arch/ia64/include/asm/xen/interface.h +++ b/arch/ia64/include/asm/xen/interface.h | |||
@@ -209,6 +209,15 @@ struct mapped_regs { | |||
209 | unsigned long krs[8]; /* kernel registers */ | 209 | unsigned long krs[8]; /* kernel registers */ |
210 | unsigned long tmp[16]; /* temp registers | 210 | unsigned long tmp[16]; /* temp registers |
211 | (e.g. for hyperprivops) */ | 211 | (e.g. for hyperprivops) */ |
212 | |||
213 | /* itc paravirtualization | ||
214 | * vAR.ITC = mAR.ITC + itc_offset | ||
215 | * itc_last is one which was lastly passed to | ||
216 | * the guest OS in order to prevent it from | ||
217 | * going backwords. | ||
218 | */ | ||
219 | unsigned long itc_offset; | ||
220 | unsigned long itc_last; | ||
212 | }; | 221 | }; |
213 | }; | 222 | }; |
214 | }; | 223 | }; |
diff --git a/arch/ia64/include/asm/xen/minstate.h b/arch/ia64/include/asm/xen/minstate.h index 4d92d9bbda7b..c57fa910f2c9 100644 --- a/arch/ia64/include/asm/xen/minstate.h +++ b/arch/ia64/include/asm/xen/minstate.h | |||
@@ -1,3 +1,12 @@ | |||
1 | |||
2 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
3 | /* read ar.itc in advance, and use it before leaving bank 0 */ | ||
4 | #define XEN_ACCOUNT_GET_STAMP \ | ||
5 | MOV_FROM_ITC(pUStk, p6, r20, r2); | ||
6 | #else | ||
7 | #define XEN_ACCOUNT_GET_STAMP | ||
8 | #endif | ||
9 | |||
1 | /* | 10 | /* |
2 | * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves | 11 | * DO_SAVE_MIN switches to the kernel stacks (if necessary) and saves |
3 | * the minimum state necessary that allows us to turn psr.ic back | 12 | * the minimum state necessary that allows us to turn psr.ic back |
@@ -123,7 +132,7 @@ | |||
123 | ;; \ | 132 | ;; \ |
124 | .mem.offset 0,0; st8.spill [r16]=r2,16; \ | 133 | .mem.offset 0,0; st8.spill [r16]=r2,16; \ |
125 | .mem.offset 8,0; st8.spill [r17]=r3,16; \ | 134 | .mem.offset 8,0; st8.spill [r17]=r3,16; \ |
126 | ACCOUNT_GET_STAMP \ | 135 | XEN_ACCOUNT_GET_STAMP \ |
127 | adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ | 136 | adds r2=IA64_PT_REGS_R16_OFFSET,r1; \ |
128 | ;; \ | 137 | ;; \ |
129 | EXTRA; \ | 138 | EXTRA; \ |
diff --git a/arch/ia64/include/asm/xen/privop.h b/arch/ia64/include/asm/xen/privop.h index 71ec7546e100..2261dda578ff 100644 --- a/arch/ia64/include/asm/xen/privop.h +++ b/arch/ia64/include/asm/xen/privop.h | |||
@@ -55,6 +55,8 @@ | |||
55 | #define XSI_BANK1_R16 (XSI_BASE + XSI_BANK1_R16_OFS) | 55 | #define XSI_BANK1_R16 (XSI_BASE + XSI_BANK1_R16_OFS) |
56 | #define XSI_BANKNUM (XSI_BASE + XSI_BANKNUM_OFS) | 56 | #define XSI_BANKNUM (XSI_BASE + XSI_BANKNUM_OFS) |
57 | #define XSI_IHA (XSI_BASE + XSI_IHA_OFS) | 57 | #define XSI_IHA (XSI_BASE + XSI_IHA_OFS) |
58 | #define XSI_ITC_OFFSET (XSI_BASE + XSI_ITC_OFFSET_OFS) | ||
59 | #define XSI_ITC_LAST (XSI_BASE + XSI_ITC_LAST_OFS) | ||
58 | #endif | 60 | #endif |
59 | 61 | ||
60 | #ifndef __ASSEMBLY__ | 62 | #ifndef __ASSEMBLY__ |
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index 742dbb1d5a4f..af5650169043 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c | |||
@@ -316,5 +316,7 @@ void foo(void) | |||
316 | DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]); | 316 | DEFINE_MAPPED_REG_OFS(XSI_BANK1_R16_OFS, bank1_regs[0]); |
317 | DEFINE_MAPPED_REG_OFS(XSI_B0NATS_OFS, vbnat); | 317 | DEFINE_MAPPED_REG_OFS(XSI_B0NATS_OFS, vbnat); |
318 | DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat); | 318 | DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat); |
319 | DEFINE_MAPPED_REG_OFS(XSI_ITC_OFFSET_OFS, itc_offset); | ||
320 | DEFINE_MAPPED_REG_OFS(XSI_ITC_LAST_OFS, itc_last); | ||
319 | #endif /* CONFIG_XEN */ | 321 | #endif /* CONFIG_XEN */ |
320 | } | 322 | } |
diff --git a/arch/ia64/xen/xen_pv_ops.c b/arch/ia64/xen/xen_pv_ops.c index fe72308321b6..d91336114344 100644 --- a/arch/ia64/xen/xen_pv_ops.c +++ b/arch/ia64/xen/xen_pv_ops.c | |||
@@ -183,6 +183,75 @@ struct pv_fsys_data xen_fsys_data __initdata = { | |||
183 | * intrinsics hooks. | 183 | * intrinsics hooks. |
184 | */ | 184 | */ |
185 | 185 | ||
186 | static void | ||
187 | xen_set_itm_with_offset(unsigned long val) | ||
188 | { | ||
189 | /* ia64_cpu_local_tick() calls this with interrupt enabled. */ | ||
190 | /* WARN_ON(!irqs_disabled()); */ | ||
191 | xen_set_itm(val - XEN_MAPPEDREGS->itc_offset); | ||
192 | } | ||
193 | |||
194 | static unsigned long | ||
195 | xen_get_itm_with_offset(void) | ||
196 | { | ||
197 | /* unused at this moment */ | ||
198 | printk(KERN_DEBUG "%s is called.\n", __func__); | ||
199 | |||
200 | WARN_ON(!irqs_disabled()); | ||
201 | return ia64_native_getreg(_IA64_REG_CR_ITM) + | ||
202 | XEN_MAPPEDREGS->itc_offset; | ||
203 | } | ||
204 | |||
205 | /* ia64_set_itc() is only called by | ||
206 | * cpu_init() with ia64_set_itc(0) and ia64_sync_itc(). | ||
207 | * So XEN_MAPPEDRESG->itc_offset cal be considered as almost constant. | ||
208 | */ | ||
209 | static void | ||
210 | xen_set_itc(unsigned long val) | ||
211 | { | ||
212 | unsigned long mitc; | ||
213 | |||
214 | WARN_ON(!irqs_disabled()); | ||
215 | mitc = ia64_native_getreg(_IA64_REG_AR_ITC); | ||
216 | XEN_MAPPEDREGS->itc_offset = val - mitc; | ||
217 | XEN_MAPPEDREGS->itc_last = val; | ||
218 | } | ||
219 | |||
220 | static unsigned long | ||
221 | xen_get_itc(void) | ||
222 | { | ||
223 | unsigned long res; | ||
224 | unsigned long itc_offset; | ||
225 | unsigned long itc_last; | ||
226 | unsigned long ret_itc_last; | ||
227 | |||
228 | itc_offset = XEN_MAPPEDREGS->itc_offset; | ||
229 | do { | ||
230 | itc_last = XEN_MAPPEDREGS->itc_last; | ||
231 | res = ia64_native_getreg(_IA64_REG_AR_ITC); | ||
232 | res += itc_offset; | ||
233 | if (itc_last >= res) | ||
234 | res = itc_last + 1; | ||
235 | ret_itc_last = cmpxchg(&XEN_MAPPEDREGS->itc_last, | ||
236 | itc_last, res); | ||
237 | } while (unlikely(ret_itc_last != itc_last)); | ||
238 | return res; | ||
239 | |||
240 | #if 0 | ||
241 | /* ia64_itc_udelay() calls ia64_get_itc() with interrupt enabled. | ||
242 | Should it be paravirtualized instead? */ | ||
243 | WARN_ON(!irqs_disabled()); | ||
244 | itc_offset = XEN_MAPPEDREGS->itc_offset; | ||
245 | itc_last = XEN_MAPPEDREGS->itc_last; | ||
246 | res = ia64_native_getreg(_IA64_REG_AR_ITC); | ||
247 | res += itc_offset; | ||
248 | if (itc_last >= res) | ||
249 | res = itc_last + 1; | ||
250 | XEN_MAPPEDREGS->itc_last = res; | ||
251 | return res; | ||
252 | #endif | ||
253 | } | ||
254 | |||
186 | static void xen_setreg(int regnum, unsigned long val) | 255 | static void xen_setreg(int regnum, unsigned long val) |
187 | { | 256 | { |
188 | switch (regnum) { | 257 | switch (regnum) { |
@@ -194,11 +263,14 @@ static void xen_setreg(int regnum, unsigned long val) | |||
194 | xen_set_eflag(val); | 263 | xen_set_eflag(val); |
195 | break; | 264 | break; |
196 | #endif | 265 | #endif |
266 | case _IA64_REG_AR_ITC: | ||
267 | xen_set_itc(val); | ||
268 | break; | ||
197 | case _IA64_REG_CR_TPR: | 269 | case _IA64_REG_CR_TPR: |
198 | xen_set_tpr(val); | 270 | xen_set_tpr(val); |
199 | break; | 271 | break; |
200 | case _IA64_REG_CR_ITM: | 272 | case _IA64_REG_CR_ITM: |
201 | xen_set_itm(val); | 273 | xen_set_itm_with_offset(val); |
202 | break; | 274 | break; |
203 | case _IA64_REG_CR_EOI: | 275 | case _IA64_REG_CR_EOI: |
204 | xen_eoi(val); | 276 | xen_eoi(val); |
@@ -222,6 +294,12 @@ static unsigned long xen_getreg(int regnum) | |||
222 | res = xen_get_eflag(); | 294 | res = xen_get_eflag(); |
223 | break; | 295 | break; |
224 | #endif | 296 | #endif |
297 | case _IA64_REG_AR_ITC: | ||
298 | res = xen_get_itc(); | ||
299 | break; | ||
300 | case _IA64_REG_CR_ITM: | ||
301 | res = xen_get_itm_with_offset(); | ||
302 | break; | ||
225 | case _IA64_REG_CR_IVR: | 303 | case _IA64_REG_CR_IVR: |
226 | res = xen_get_ivr(); | 304 | res = xen_get_ivr(); |
227 | break; | 305 | break; |