- * Each of these threads has three PCB pointers. The normal PCB, the FPU pcb,
- * and the VMX pcb. There is also a bit for each in the savearea flags.
- * When we take an exception, or need to use the FPU/VMX in the kernel, we call
- * this routine. It checks to see if there is an owner thread for the facility.
- * If so, it saves the facility's state information in the normal PCB. Then, it
- * turns on the appropriate flag in the savearea to indicate that the state is
- * in that particular savearea. Also, the thread pointer for the owner in
- * the per_processor block is cleared. Note that we don't have to worry about the
- * PCB pointers in the thread because whenever the state is loaded, the associated
- * savearea is released and the pointer cleared. This is done so that the facility
- * context always migrates to the normal savearea/PCB. This always insures that
- * no more than 2 saveareas are used for a thread.
- *
- * When the context is loaded into the facility, the associated PCB is released if
- * its usage flags indicate that it is empty. (Note that return from exception and
- * context switch honor these flags and won't release a savearea if there is unrestored
- * facility context.) The per_processor is set to point to the facility owner's
- * thread and the associated PCB pointer within the thread is cleared because
- * the PCB has been released.
- *
- * Part of loading a context is to release the savearea. If the savearea contains
- * other context, the savearea cannot be released. So, what we're left with is
- * that there will be no normal context savearea, but one for the as-not-yet
- * restored facility savearea. Again, when that context is reloaded, the PCB
- * is released, and when it is again stored, it goes into the "normal" savearea.
- *
- * So, what do we do when there is no general context, and we have some FPU/VMX
- * state to save? Heck if I know, but it happens when we switch threads when
- * we shortcut system calls. The question is: does the target thread carry the
- * FPU/VMX context with it or not? Actually, it don't matter, not one little bit.
- * If we are asked to save it, we gotta. It's a really lousy way to do it, but
- * short of starting over with FPUs, it's what's what. Therefore, we'll
- * allocate an FPU context save and attach it.
- *
- * Actually, it's not quite that simple: since we aren't in
- * in interrupt handler context (that's only in fpu_switch) we can't use
- * quickfret to merge FPU into general context. So, if there is an FPU
- * savearea, we need to use that. So what we do is: if there is FPU context
- * use that. If there is a general context, then use that. If neither,
- * allocate a savearea and make that the FPU context.
- *
- * The next thing we have to do is to allow the kernel to use both the
- * floating point and Altivec. It is not recommended, but there may be a
- * good reason to do so. So, what we need to do is to treat each of the
- * three types of context the same, by keeping a LIFO chain of states.
- * We do have a problem with that in that there can be multiple levels of
- * kernel context. For example, we are using floating point and we take a
- * page fault, and somehow start using the FPU, and take another page fault,
- * etc.
- *
- * Anyway, we will hope that we only reasonably use floating point and vectors in
- * the kernel. And try to pack the context in as few saveareas as possible.
- *
- * The way we keep these "levels" of floating point or vector context straight is
- * to remember the top of the normal savearea chain when we activate the
- * facility when it is first used. Then, when we save that context, this value
- * is saved in its level field.
- *
- * What the level concept gives us is a way to distinguish between multiple
- * independent contexts under the same thread activation. Any time we take
- * any kind of interruption (trap, system call, I/O interruption), we are,
- * in effect, running with a different context even though we are in the
- * same thread. The top savearea address is used only as a marker. It does not
- * point to any context associated with the float or vector context. For example,
- * the top savearea pointer will always be 0 for the user context, because there
- * it it always last on the list.
- *
- * As normal context is unstacked, the first facility context is checked and
- * if there is a match, the facility savearea is released. This is because we
- * are returning to a level before the facility saved there was used. In effect,
- * this allows us to unwind the facility context saveareas at different rates.
- *
- * In conjunction with the current activation, these markers are also used to
- * determine the state of the facility enablement. Whenever the facility context is
- * "live," i.e., loaded in the hardware registers and belonging to the currently
- * running context, the facility is enabled before dispatch.
- *
- * There is nothing special about using floating point or vector facilities,
- * no preliminary saving, enabling, or disabling. You just use them. The only exception
- * is during context switching on an SMP system. In this case, the context must
- * be saved as there is no guarantee that the thread will resume on the same
- * processor. This is not a good thing, not at all.
- *
- * Whenever we switch out a thread with a dirty context, we always need to save it
- * because it can wake up on a different processor. However, once the context has
- * been saved, we don't need to save it again until it gets dirty, nor do we need
- * to reload it unless someone else's context has been loaded. To handle this
- * optimization, we need 3 things. We need to know what processor the saved context
- * was last loaded on, whether the loaded context could be dirty, and if we've already
- * saved it.
- *
- * Whenever the facility is enabled, the processor ID is saved in the activation. This
- * will show which processor has dirty data. When a context switch occurs, the facility
- * contexts are saved, but are still remembered as live. The next time we need to
- * context switch, we first check if the state is live, and if not, do no state
- * saving. Then we check if the state has already been save and if not, save it.
- * The facility is always disabled on a context switch. On a UP, this save function
- * does not occur.
- *
- * Whenever a facility unavailable interruption occurs, the current state is saved
- * if it is live and unsaved. However, if the live state is the same as the new
- * one to be loaded, the processor ID is checked and if it is the current processor
- * the state does not need to be loaded or saved. The facility is simply enabled.
- *
- * Once allocated, facility saveareas are not released until a return is made to a
- * previous level. Once a facility has been enabled, there is no way to tell if
- * it will ever be used again, but it is likely. Therefore, discarding a savearea
- * when its context is made live is extra overhead. So, we don't do it, but we
- * do mark the savearea contents as invalid.
- *