Home | History | Annotate | Line # | Download | only in mips
      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