|
42 | 42 | #include <machine/fpu.h>
|
43 | 43 | #include <machine/pcb.h>
|
44 | 44 | #include <machine/psl.h>
|
| 45 | +#include <machine/altivec.h> |
45 | 46 |
|
46 | 47 | static void
|
47 | 48 | save_fpu_int(struct thread *td)
|
@@ -259,3 +260,127 @@ get_fpu_exception(struct thread *td)
|
259 | 260 | return ucode;
|
260 | 261 | }
|
261 | 262 |
|
| 263 | +void |
| 264 | +enable_fpu_kern(void) |
| 265 | +{ |
| 266 | + register_t msr; |
| 267 | + |
| 268 | + msr = mfmsr() | PSL_FP; |
| 269 | + |
| 270 | + if (cpu_features & PPC_FEATURE_HAS_VSX) |
| 271 | + msr |= PSL_VSX; |
| 272 | + |
| 273 | + mtmsr(msr); |
| 274 | +} |
| 275 | + |
| 276 | +void |
| 277 | +disable_fpu(struct thread *td) |
| 278 | +{ |
| 279 | + register_t msr; |
| 280 | + struct pcb *pcb; |
| 281 | + struct trapframe *tf; |
| 282 | + |
| 283 | + pcb = td->td_pcb; |
| 284 | + tf = trapframe(td); |
| 285 | + |
| 286 | + /* Disable FPU in kernel (if enabled) */ |
| 287 | + msr = mfmsr() & ~(PSL_FP | PSL_VSX); |
| 288 | + isync(); |
| 289 | + mtmsr(msr); |
| 290 | + |
| 291 | + /* |
| 292 | + * Disable FPU in userspace. It will be re-enabled when |
| 293 | + * an FP or VSX instruction is executed. |
| 294 | + */ |
| 295 | + tf->srr1 &= ~(PSL_FP | PSL_VSX); |
| 296 | + pcb->pcb_flags &= ~(PCB_FPU | PCB_VSX); |
| 297 | +} |
| 298 | + |
| 299 | +#ifndef __SPE__ |
| 300 | +/* |
| 301 | + * XXX: Implement fpu_kern_alloc_ctx/fpu_kern_free_ctx once fpu_kern_enter and |
| 302 | + * fpu_kern_leave can handle !FPU_KERN_NOCTX. |
| 303 | + */ |
| 304 | +struct fpu_kern_ctx { |
| 305 | +#define FPU_KERN_CTX_DUMMY 0x01 /* avoided save for the kern thread */ |
| 306 | +#define FPU_KERN_CTX_INUSE 0x02 |
| 307 | + uint32_t flags; |
| 308 | +}; |
| 309 | + |
| 310 | +void |
| 311 | +fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) |
| 312 | +{ |
| 313 | + struct pcb *pcb; |
| 314 | + |
| 315 | + pcb = td->td_pcb; |
| 316 | + |
| 317 | + KASSERT((flags & FPU_KERN_NOCTX) != 0 || ctx != NULL, |
| 318 | + ("ctx is required when !FPU_KERN_NOCTX")); |
| 319 | + KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0, |
| 320 | + ("using inuse ctx")); |
| 321 | + KASSERT((pcb->pcb_flags & PCB_KERN_FPU_NOSAVE) == 0, |
| 322 | + ("recursive fpu_kern_enter while in PCB_KERN_FPU_NOSAVE state")); |
| 323 | + |
| 324 | + if ((flags & FPU_KERN_NOCTX) != 0) { |
| 325 | + critical_enter(); |
| 326 | + |
| 327 | + if (pcb->pcb_flags & PCB_FPU) { |
| 328 | + save_fpu(td); |
| 329 | + pcb->pcb_flags |= PCB_FPREGS; |
| 330 | + } |
| 331 | + enable_fpu_kern(); |
| 332 | + |
| 333 | + if (pcb->pcb_flags & PCB_VEC) { |
| 334 | + save_vec(td); |
| 335 | + pcb->pcb_flags |= PCB_VECREGS; |
| 336 | + } |
| 337 | + enable_vec_kern(); |
| 338 | + |
| 339 | + pcb->pcb_flags |= PCB_KERN_FPU | PCB_KERN_FPU_NOSAVE; |
| 340 | + return; |
| 341 | + } |
| 342 | + |
| 343 | + KASSERT(0, ("fpu_kern_enter with !FPU_KERN_NOCTX not implemented!")); |
| 344 | +} |
| 345 | + |
| 346 | +int |
| 347 | +fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) |
| 348 | +{ |
| 349 | + struct pcb *pcb; |
| 350 | + |
| 351 | + pcb = td->td_pcb; |
| 352 | + |
| 353 | + if ((pcb->pcb_flags & PCB_KERN_FPU_NOSAVE) != 0) { |
| 354 | + KASSERT(ctx == NULL, ("non-null ctx after FPU_KERN_NOCTX")); |
| 355 | + KASSERT(PCPU_GET(fpcurthread) == NULL, |
| 356 | + ("non-NULL fpcurthread for PCB_FP_NOSAVE")); |
| 357 | + CRITICAL_ASSERT(td); |
| 358 | + |
| 359 | + /* Disable FPU, VMX, and VSX */ |
| 360 | + disable_fpu(td); |
| 361 | + disable_vec(td); |
| 362 | + |
| 363 | + pcb->pcb_flags &= ~PCB_KERN_FPU_NOSAVE; |
| 364 | + |
| 365 | + critical_exit(); |
| 366 | + } else { |
| 367 | + KASSERT(0, ("fpu_kern_leave with !FPU_KERN_NOCTX not implemented!")); |
| 368 | + } |
| 369 | + |
| 370 | + pcb->pcb_flags &= ~PCB_KERN_FPU; |
| 371 | + |
| 372 | + return 0; |
| 373 | +} |
| 374 | + |
| 375 | +int |
| 376 | +is_fpu_kern_thread(u_int flags __unused) |
| 377 | +{ |
| 378 | + struct pcb *curpcb; |
| 379 | + |
| 380 | + if ((curthread->td_pflags & TDP_KTHREAD) == 0) |
| 381 | + return (0); |
| 382 | + curpcb = curthread->td_pcb; |
| 383 | + return ((curpcb->pcb_flags & PCB_KERN_FPU) != 0); |
| 384 | +} |
| 385 | + |
| 386 | +#endif /* !__SPE__ */ |
0 commit comments