#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mips_dsp.c,v 1.6 2017/05/07 05:45:07 skrll Exp $");
#include <sys/param.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/cpu.h>
#include <sys/proc.h>
#include <sys/lwp.h>
#include <sys/pcu.h>
#include <mips/locore.h>
#include <mips/regnum.h>
#include <mips/pcb.h>
static void mips_dsp_state_save(lwp_t *);
static void mips_dsp_state_load(lwp_t *, u_int);
static void mips_dsp_state_release(lwp_t *);
const pcu_ops_t mips_dsp_ops = {
.pcu_id = PCU_DSP,
.pcu_state_save = mips_dsp_state_save,
.pcu_state_load = mips_dsp_state_load,
.pcu_state_release = mips_dsp_state_release
};
void
dsp_discard(lwp_t *l)
{
pcu_discard(&mips_dsp_ops, l, false);
}
void
dsp_load(void)
{
pcu_load(&mips_dsp_ops);
}
void
dsp_save(lwp_t *l)
{
pcu_save(&mips_dsp_ops, l);
}
bool
dsp_used_p(const lwp_t *l)
{
return pcu_valid_p(&mips_dsp_ops, l);
}
void
mips_dsp_state_save(lwp_t *l)
{
struct trapframe * const tf = l->l_md.md_utf;
struct pcb * const pcb = lwp_getpcb(l);
mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs;
uint32_t status;
if ((tf->tf_regs[_R_SR] & MIPS_SR_MX) == 0)
return;
l->l_cpu->ci_ev_dsp_saves.ev_count++;
__asm volatile (
".set push" "\n\t"
".set mips32r2" "\n\t"
".set dspr2" "\n\t"
".set noat" "\n\t"
".set noreorder" "\n\t"
"mfc0 %[status], $%[cp0_status]" "\n\t"
"or %[status], %[mips_sr_mx]" "\n\t"
"mtc0 %[status], $%[cp0_status]" "\n\t"
"ehb" "\n\t"
"mflo %[mullo1], $ac1" "\n\t"
"mfhi %[mulhi1], $ac1" "\n\t"
"mflo %[mullo2], $ac2" "\n\t"
"mfhi %[mulhi2], $ac2" "\n\t"
"mflo %[mullo3], $ac3" "\n\t"
"mfhi %[mulhi3], $ac3" "\n\t"
"rddsp %[dspctl]" "\n\t"
"xor %[status], %[mips_sr_mx]" "\n\t"
"mtc0 %[status], $%[cp0_status]" "\n\t"
"ehb" "\n\t"
".set pop"
: [status] "=&r" (status),
[mullo1] "=r"(dsp[_R_MULLO1 - _R_DSPBASE]),
[mulhi1] "=r"(dsp[_R_MULHI1 - _R_DSPBASE]),
[mullo2] "=r"(dsp[_R_MULLO2 - _R_DSPBASE]),
[mulhi2] "=r"(dsp[_R_MULHI2 - _R_DSPBASE]),
[mullo3] "=r"(dsp[_R_MULLO3 - _R_DSPBASE]),
[mulhi3] "=r"(dsp[_R_MULHI3 - _R_DSPBASE]),
[dspctl] "=r"(dsp[_R_DSPCTL - _R_DSPBASE])
: [mips_sr_mx] "r"(MIPS_SR_MX),
[cp0_status] "n"(MIPS_COP_0_STATUS));
}
void
mips_dsp_state_load(lwp_t *l, u_int flags)
{
struct trapframe * const tf = l->l_md.md_utf;
struct pcb * const pcb = lwp_getpcb(l);
mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs;
uint32_t status;
l->l_cpu->ci_ev_dsp_loads.ev_count++;
if (__predict_false((flags & PCU_VALID) == 0)) {
memset(&pcb->pcb_dspregs, 0, sizeof(pcb->pcb_dspregs));
}
tf->tf_regs[_R_SR] |= MIPS_SR_MX;
__asm volatile (
".set push" "\n\t"
".set mips32r2" "\n\t"
".set dspr2" "\n\t"
".set noat" "\n\t"
".set noreorder" "\n\t"
"mfc0 %[status], $%[cp0_status]" "\n\t"
"or %[status], %[mips_sr_mx]" "\n\t"
"mtc0 %[status], $%[cp0_status]" "\n\t"
"ehb" "\n\t"
"mtlo %[mullo1], $ac1" "\n\t"
"mthi %[mulhi1], $ac1" "\n\t"
"mtlo %[mullo2], $ac2" "\n\t"
"mthi %[mulhi2], $ac2" "\n\t"
"mtlo %[mullo3], $ac3" "\n\t"
"mthi %[mulhi3], $ac3" "\n\t"
"wrdsp %[dspctl]" "\n\t"
"xor %[status], %[mips_sr_mx]" "\n\t"
"mtc0 %[status], $%[cp0_status]" "\n\t"
"ehb" "\n\t"
".set pop"
: [status] "=&r" (status)
: [mullo1] "r"(dsp[_R_MULLO1 - _R_DSPBASE]),
[mulhi1] "r"(dsp[_R_MULHI1 - _R_DSPBASE]),
[mullo2] "r"(dsp[_R_MULLO2 - _R_DSPBASE]),
[mulhi2] "r"(dsp[_R_MULHI2 - _R_DSPBASE]),
[mullo3] "r"(dsp[_R_MULLO3 - _R_DSPBASE]),
[mulhi3] "r"(dsp[_R_MULHI3 - _R_DSPBASE]),
[dspctl] "r"(dsp[_R_DSPCTL - _R_DSPBASE]),
[mips_sr_mx] "r"(MIPS_SR_MX),
[cp0_status] "n"(MIPS_COP_0_STATUS));
}
void
mips_dsp_state_release(lwp_t *l)
{
KASSERT(l == curlwp);
l->l_md.md_utf->tf_regs[_R_SR] &= ~MIPS_SR_MX;
}