xref: /illumos-gate/usr/src/uts/sparc/ml/sparc_ddi.S (revision 5d9d9091)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26/*
27 * Copyright 2012  Garrett D'Amore <garrett@damore.org>.  All rights reserved.
28 */
29
30/*
31 * Assembler routines to make some DDI routines go faster.
32 * These routines should ONLY be ISA-dependent.
33 */
34
35#include <sys/asm_linkage.h>
36#include <sys/clock.h>
37#include <sys/intreg.h>
38
39#include "assym.h"		/* for FKIOCTL etc. */
40
41
42/*
43 * Layered driver routines.
44 *
45 * At the time of writing, the compiler converts
46 *
47 * a() { return (b()); }
48 *
49 * into
50 *	save, call b, restore
51 *
52 * Though this is sort of ok, if the called routine is leaf routine,
53 * then we just burnt a register window.
54 *
55 * When the compiler understands this optimization, many
56 * of these routines can go back to C again.
57 */
58
59#define	FLATCALL(routine)	\
60	mov	%o7, %g1;	\
61	call	routine;	\
62	mov	%g1, %o7
63
64	ENTRY(ddi_copyin)
65	set	FKIOCTL, %o4
66	andcc	%o3, %o4, %g0
67	bne	.do_kcopy	! share code with ddi_copyout
68	FLATCALL(copyin)
69	/*NOTREACHED*/
70
71.do_kcopy:
72	save	%sp, -SA(MINFRAME), %sp
73	mov	%i2, %o2
74	mov	%i1, %o1
75	call	kcopy
76	mov	%i0, %o0
77	orcc	%g0, %o0, %i0	! if kcopy returns EFAULT ..
78	bne,a	1f
79	mov	-1, %i0		! .. we return -1
801:	ret
81	restore
82	SET_SIZE(ddi_copyin)
83
84	ENTRY(ddi_copyout)
85	set	FKIOCTL, %o4
86	andcc	%o3, %o4, %g0
87	bne	.do_kcopy	! share code with ddi_copyin
88	FLATCALL(copyout)
89	/*NOTREACHED*/
90	SET_SIZE(ddi_copyout)
91
92/*
93 * DDI spine wrapper routines - here so as to not have to
94 * buy register windows when climbing the device tree (which cost!)
95 */
96
97	ENTRY(ddi_ctlops)
98	tst	%o0		! dip != 0?
99	be,pn	%ncc, 2f	! nope
100	tst	%o1		! rdip != 0?
101	be,pn	%ncc, 2f	! nope
102	ldn	[%o0 + DEVI_BUS_CTL], %o0
103				! dip = (dev_info_t *)DEVI(dip)->devi_bus_ctl;
104	brz,pn	%o0, 2f
105	nop			! Delay slot
106	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
107	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
108	ldn	[%g1 + OPS_CTL], %g1	! dip->dev_ops->devo_bus_ops->bus_ctl
109	jmpl	%g1, %g0	! bop off to new routine
110	nop			! as if we had never been here
1112:	retl
112	sub	%g0, 1, %o0	! return (DDI_FAILURE);
113	SET_SIZE(ddi_ctlops)
114
115	ENTRY(ddi_dma_allochdl)
116	ldn	[%o0 + DEVI_BUS_DMA_ALLOCHDL], %o0
117			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
118	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
119	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
120	ldn	[%g1 + OPS_ALLOCHDL], %g1
121			! dip->dev_ops->devo_bus_ops->bus_dma_allochdl
122	jmpl	%g1, %g0	! bop off to new routine
123	nop			! as if we had never been here
124	SET_SIZE(ddi_dma_allochdl)
125
126	ENTRY(ddi_dma_freehdl)
127	ldn	[%o0 + DEVI_BUS_DMA_FREEHDL], %o0
128			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_freehdl;
129	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
130	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
131	ldn	[%g1 + OPS_FREEHDL], %g1
132			! dip->dev_ops->devo_bus_ops->bus_dma_freehdl
133	jmpl	%g1, %g0	! bop off to new routine
134	nop			! as if we had never been here
135	SET_SIZE(ddi_dma_freehdl)
136
137	ENTRY(ddi_dma_bindhdl)
138	ldn	[%o0 + DEVI_BUS_DMA_BINDHDL], %o0
139			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
140	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
141	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
142	ldn	[%g1 + OPS_BINDHDL], %g1
143			! dip->dev_ops->devo_bus_ops->bus_dma_bindhdl
144	jmpl	%g1, %g0	! bop off to new routine
145	nop			! as if we had never been here
146	SET_SIZE(ddi_dma_bindhdl)
147
148	ENTRY(ddi_dma_unbindhdl)
149	ldn	[%o0 + DEVI_BUS_DMA_UNBINDHDL], %o0
150			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
151	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
152	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
153	ldn	[%g1 + OPS_UNBINDHDL], %g1
154			! dip->dev_ops->devo_bus_ops->bus_dma_unbindhdl
155	jmpl	%g1, %g0	! bop off to new routine
156	nop			! as if we had never been here
157	SET_SIZE(ddi_dma_unbindhdl)
158
159	ENTRY(ddi_dma_flush)
160	ldn	[%o0 + DEVI_BUS_DMA_FLUSH], %o0
161			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
162	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
163	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
164	ldn	[%g1 + OPS_FLUSH], %g1
165			! dip->dev_ops->devo_bus_ops->bus_dma_flush
166	jmpl	%g1, %g0	! bop off to new routine
167	nop			! as if we had never been here
168	SET_SIZE(ddi_dma_flush)
169
170	ENTRY(ddi_dma_win)
171	ldn	[%o0 + DEVI_BUS_DMA_WIN], %o0
172			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
173	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
174	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
175	ldn	[%g1 + OPS_WIN], %g1
176			! dip->dev_ops->devo_bus_ops->bus_dma_win
177	jmpl	%g1, %g0	! bop off to new routine
178	nop			! as if we had never been here
179	SET_SIZE(ddi_dma_win)
180
181	ENTRY(ddi_dma_sync)
182	ld	[%o0 + DMA_HANDLE_RFLAGS], %o4	! hp->dmai_rflags;
183	sethi	%hi(DMP_NOSYNC), %o5
184	and	%o4, %o5, %o4
185	cmp	%o4, %o5
186	bne	1f
187	mov	%o3, %o5
188	retl
189	clr	%o0
1901:	mov	%o1, %o3
191	ldn	[%o0 + DMA_HANDLE_RDIP], %o1	! dip = hp->dmai_rdip;
192	mov	%o0, %g2
193	ldn	[%o1 + DEVI_BUS_DMA_FLUSH], %o0
194			! dip = DEVI(dip)->devi_bus_dma_flush;
195	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
196	mov	%o2, %o4
197	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
198	mov	%g2, %o2
199	ldn	[%g1 + OPS_FLUSH], %g1
200			! dip->dev_ops->devo_bus_ops->bus_dma_flush
201	jmpl	%g1, %g0	! bop off to new routine
202	nop			! as if we had never been here
203	SET_SIZE(ddi_dma_sync)
204
205	ENTRY(ddi_dma_unbind_handle)
206	ldn	[%o0 + DMA_HANDLE_RDIP], %o1	! dip = hp->dmai_rdip;
207	mov	%o0, %o2
208	ldn	[%o1 + DEVI_BUS_DMA_UNBINDFUNC ], %g1
209		    ! funcp = DEVI(dip)->devi_bus_dma_unbindfunc;
210	jmpl	%g1, %g0	! bop off to new routine
211	ldn	[%o1 + DEVI_BUS_DMA_UNBINDHDL], %o0
212		    ! hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
213	SET_SIZE(ddi_dma_unbind_handle)
214
215
216	ENTRY(ddi_dma_mctl)
217	ldn	[%o0 + DEVI_BUS_DMA_CTL], %o0
218			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
219	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
220	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
221	ldn	[%g1 + OPS_MCTL], %g1 ! dip->dev_ops->devo_bus_ops->bus_dma_ctl
222	jmpl	%g1, %g0	! bop off to new routine
223	nop			! as if we had never been here
224	SET_SIZE(ddi_dma_mctl)
225
226