1 /* $NetBSD: mips_dsp.c,v 1.6 2017/05/07 05:45:07 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: mips_dsp.c,v 1.6 2017/05/07 05:45:07 skrll Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/mutex.h> 37 #include <sys/condvar.h> 38 #include <sys/cpu.h> 39 #include <sys/proc.h> 40 #include <sys/lwp.h> 41 #include <sys/pcu.h> 42 43 #include <mips/locore.h> 44 #include <mips/regnum.h> 45 #include <mips/pcb.h> 46 47 static void mips_dsp_state_save(lwp_t *); 48 static void mips_dsp_state_load(lwp_t *, u_int); 49 static void mips_dsp_state_release(lwp_t *); 50 51 const pcu_ops_t mips_dsp_ops = { 52 .pcu_id = PCU_DSP, 53 .pcu_state_save = mips_dsp_state_save, 54 .pcu_state_load = mips_dsp_state_load, 55 .pcu_state_release = mips_dsp_state_release 56 }; 57 58 void 59 dsp_discard(lwp_t *l) 60 { 61 pcu_discard(&mips_dsp_ops, l, false); 62 } 63 64 void 65 dsp_load(void) 66 { 67 pcu_load(&mips_dsp_ops); 68 } 69 70 void 71 dsp_save(lwp_t *l) 72 { 73 pcu_save(&mips_dsp_ops, l); 74 } 75 76 bool 77 dsp_used_p(const lwp_t *l) 78 { 79 return pcu_valid_p(&mips_dsp_ops, l); 80 } 81 82 void 83 mips_dsp_state_save(lwp_t *l) 84 { 85 struct trapframe * const tf = l->l_md.md_utf; 86 struct pcb * const pcb = lwp_getpcb(l); 87 mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs; 88 uint32_t status; 89 90 /* 91 * Don't do anything if the DSP is already off. 92 */ 93 if ((tf->tf_regs[_R_SR] & MIPS_SR_MX) == 0) 94 return; 95 96 l->l_cpu->ci_ev_dsp_saves.ev_count++; 97 98 /* 99 * load DSP registers and establish lwp's DSP context. 100 */ 101 __asm volatile ( 102 ".set push" "\n\t" 103 ".set mips32r2" "\n\t" 104 ".set dspr2" "\n\t" 105 ".set noat" "\n\t" 106 ".set noreorder" "\n\t" 107 "mfc0 %[status], $%[cp0_status]" "\n\t" 108 "or %[status], %[mips_sr_mx]" "\n\t" 109 "mtc0 %[status], $%[cp0_status]" "\n\t" 110 "ehb" "\n\t" 111 "mflo %[mullo1], $ac1" "\n\t" 112 "mfhi %[mulhi1], $ac1" "\n\t" 113 "mflo %[mullo2], $ac2" "\n\t" 114 "mfhi %[mulhi2], $ac2" "\n\t" 115 "mflo %[mullo3], $ac3" "\n\t" 116 "mfhi %[mulhi3], $ac3" "\n\t" 117 "rddsp %[dspctl]" "\n\t" 118 "xor %[status], %[mips_sr_mx]" "\n\t" 119 "mtc0 %[status], $%[cp0_status]" "\n\t" 120 "ehb" "\n\t" 121 ".set pop" 122 : [status] "=&r" (status), 123 [mullo1] "=r"(dsp[_R_MULLO1 - _R_DSPBASE]), 124 [mulhi1] "=r"(dsp[_R_MULHI1 - _R_DSPBASE]), 125 [mullo2] "=r"(dsp[_R_MULLO2 - _R_DSPBASE]), 126 [mulhi2] "=r"(dsp[_R_MULHI2 - _R_DSPBASE]), 127 [mullo3] "=r"(dsp[_R_MULLO3 - _R_DSPBASE]), 128 [mulhi3] "=r"(dsp[_R_MULHI3 - _R_DSPBASE]), 129 [dspctl] "=r"(dsp[_R_DSPCTL - _R_DSPBASE]) 130 : [mips_sr_mx] "r"(MIPS_SR_MX), 131 [cp0_status] "n"(MIPS_COP_0_STATUS)); 132 } 133 134 void 135 mips_dsp_state_load(lwp_t *l, u_int flags) 136 { 137 struct trapframe * const tf = l->l_md.md_utf; 138 struct pcb * const pcb = lwp_getpcb(l); 139 mips_reg_t * const dsp = pcb->pcb_dspregs.r_regs; 140 uint32_t status; 141 142 l->l_cpu->ci_ev_dsp_loads.ev_count++; 143 144 /* 145 * If this is the first time the state is being loaded, zero it first. 146 */ 147 if (__predict_false((flags & PCU_VALID) == 0)) { 148 memset(&pcb->pcb_dspregs, 0, sizeof(pcb->pcb_dspregs)); 149 } 150 151 /* 152 * Enable the DSP when this lwp return to userspace. 153 */ 154 tf->tf_regs[_R_SR] |= MIPS_SR_MX; 155 156 /* 157 * load DSP registers and establish lwp's DSP context. 158 */ 159 __asm volatile ( 160 ".set push" "\n\t" 161 ".set mips32r2" "\n\t" 162 ".set dspr2" "\n\t" 163 ".set noat" "\n\t" 164 ".set noreorder" "\n\t" 165 "mfc0 %[status], $%[cp0_status]" "\n\t" 166 "or %[status], %[mips_sr_mx]" "\n\t" 167 "mtc0 %[status], $%[cp0_status]" "\n\t" 168 "ehb" "\n\t" 169 "mtlo %[mullo1], $ac1" "\n\t" 170 "mthi %[mulhi1], $ac1" "\n\t" 171 "mtlo %[mullo2], $ac2" "\n\t" 172 "mthi %[mulhi2], $ac2" "\n\t" 173 "mtlo %[mullo3], $ac3" "\n\t" 174 "mthi %[mulhi3], $ac3" "\n\t" 175 "wrdsp %[dspctl]" "\n\t" 176 "xor %[status], %[mips_sr_mx]" "\n\t" 177 "mtc0 %[status], $%[cp0_status]" "\n\t" 178 "ehb" "\n\t" 179 ".set pop" 180 : [status] "=&r" (status) 181 : [mullo1] "r"(dsp[_R_MULLO1 - _R_DSPBASE]), 182 [mulhi1] "r"(dsp[_R_MULHI1 - _R_DSPBASE]), 183 [mullo2] "r"(dsp[_R_MULLO2 - _R_DSPBASE]), 184 [mulhi2] "r"(dsp[_R_MULHI2 - _R_DSPBASE]), 185 [mullo3] "r"(dsp[_R_MULLO3 - _R_DSPBASE]), 186 [mulhi3] "r"(dsp[_R_MULHI3 - _R_DSPBASE]), 187 [dspctl] "r"(dsp[_R_DSPCTL - _R_DSPBASE]), 188 [mips_sr_mx] "r"(MIPS_SR_MX), 189 [cp0_status] "n"(MIPS_COP_0_STATUS)); 190 } 191 192 void 193 mips_dsp_state_release(lwp_t *l) 194 { 195 KASSERT(l == curlwp); 196 l->l_md.md_utf->tf_regs[_R_SR] &= ~MIPS_SR_MX; 197 } 198