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#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Assembler routines to make some DDI routines go faster.
31 * These routines should ONLY be ISA-dependent.
32 */
33
34#if defined(lint)
35
36#include <sys/types.h>
37#include <sys/systm.h>
38#include <sys/file.h>
39#include <sys/sunddi.h>
40
41#else	/* lint */
42
43#include <sys/asm_linkage.h>
44#include <sys/clock.h>
45#include <sys/intreg.h>
46
47#include "assym.h"		/* for FKIOCTL etc. */
48
49#endif	/* lint */
50
51
52/*
53 * Layered driver routines.
54 *
55 * At the time of writing, the compiler converts
56 *
57 * a() { return (b()); }
58 *
59 * into
60 *	save, call b, restore
61 *
62 * Though this is sort of ok, if the called routine is leaf routine,
63 * then we just burnt a register window.
64 *
65 * When the compiler understands this optimization, many
66 * of these routines can go back to C again.
67 */
68
69#define	FLATCALL(routine)	\
70	mov	%o7, %g1;	\
71	call	routine;	\
72	mov	%g1, %o7
73
74#ifdef	lint
75
76int
77ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
78{
79	if (flags & FKIOCTL)
80		return (kcopy(buf, kernbuf, size) ? -1 : 0);
81	return (copyin(buf, kernbuf, size));
82}
83
84#else	/* lint */
85
86	ENTRY(ddi_copyin)
87	set	FKIOCTL, %o4
88	andcc	%o3, %o4, %g0
89	bne	.do_kcopy	! share code with ddi_copyout
90	FLATCALL(copyin)
91	/*NOTREACHED*/
92
93.do_kcopy:
94	save	%sp, -SA(MINFRAME), %sp
95	mov	%i2, %o2
96	mov	%i1, %o1
97	call	kcopy
98	mov	%i0, %o0
99	orcc	%g0, %o0, %i0	! if kcopy returns EFAULT ..
100	bne,a	1f
101	mov	-1, %i0		! .. we return -1
1021:	ret
103	restore
104	SET_SIZE(ddi_copyin)
105
106#endif	/* lint */
107
108#ifdef	lint
109
110int
111ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
112{
113	if (flags & FKIOCTL)
114		return (kcopy(buf, kernbuf, size) ? -1 : 0);
115	return (copyout(buf, kernbuf, size));
116}
117
118#else	/* lint */
119
120	ENTRY(ddi_copyout)
121	set	FKIOCTL, %o4
122	andcc	%o3, %o4, %g0
123	bne	.do_kcopy	! share code with ddi_copyin
124	FLATCALL(copyout)
125	/*NOTREACHED*/
126	SET_SIZE(ddi_copyout)
127
128#endif	/* lint */
129
130/*
131 * DDI spine wrapper routines - here so as to not have to
132 * buy register windows when climbing the device tree (which cost!)
133 */
134
135#if	defined(lint)
136
137/*ARGSUSED*/
138int
139ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
140{
141	return (DDI_SUCCESS);
142}
143
144#else	/* lint */
145
146	ENTRY(ddi_ctlops)
147	tst	%o0		! dip != 0?
148	be,pn	%ncc, 2f	! nope
149	tst	%o1		! rdip != 0?
150	be,pn	%ncc, 2f	! nope
151	ldn	[%o0 + DEVI_BUS_CTL], %o0
152				! dip = (dev_info_t *)DEVI(dip)->devi_bus_ctl;
153	brz,pn	%o0, 2f
154	nop			! Delay slot
155	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
156	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
157	ldn	[%g1 + OPS_CTL], %g1	! dip->dev_ops->devo_bus_ops->bus_ctl
158	jmpl	%g1, %g0	! bop off to new routine
159	nop			! as if we had never been here
1602:	retl
161	sub	%g0, 1, %o0	! return (DDI_FAILURE);
162	SET_SIZE(ddi_ctlops)
163
164#endif	/* lint */
165
166#if	defined(lint)
167
168/* ARGSUSED */
169int
170ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
171    struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
172{
173	return (DDI_SUCCESS);
174}
175
176#else	/* lint */
177
178	ENTRY(ddi_dma_map)
179	ldn	[%o0 + DEVI_BUS_DMA_MAP], %o0
180			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_map;
181	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
182	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
183	ldn	[%g1 + OPS_MAP], %g1 ! dip->dev_ops->devo_bus_ops->bus_dma_map
184	jmpl	%g1, %g0	! bop off to new routine
185	nop			! as if we had never been here
186	SET_SIZE(ddi_dma_map)
187
188#endif	/* lint */
189
190#if	defined(lint)
191
192/* ARGSUSED */
193int
194ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
195	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
196{
197	return (DDI_SUCCESS);
198}
199
200#else	/* lint */
201
202	ENTRY(ddi_dma_allochdl)
203	ldn	[%o0 + DEVI_BUS_DMA_ALLOCHDL], %o0
204			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
205	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
206	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
207	ldn	[%g1 + OPS_ALLOCHDL], %g1
208			! dip->dev_ops->devo_bus_ops->bus_dma_allochdl
209	jmpl	%g1, %g0	! bop off to new routine
210	nop			! as if we had never been here
211	SET_SIZE(ddi_dma_allochdl)
212
213#endif	/* lint */
214
215#if	defined(lint)
216
217/* ARGSUSED */
218int
219ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
220{
221	return (DDI_SUCCESS);
222}
223
224#else	/* lint */
225
226	ENTRY(ddi_dma_freehdl)
227	ldn	[%o0 + DEVI_BUS_DMA_FREEHDL], %o0
228			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_freehdl;
229	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
230	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
231	ldn	[%g1 + OPS_FREEHDL], %g1
232			! dip->dev_ops->devo_bus_ops->bus_dma_freehdl
233	jmpl	%g1, %g0	! bop off to new routine
234	nop			! as if we had never been here
235	SET_SIZE(ddi_dma_freehdl)
236
237#endif	/* lint */
238
239#if	defined(lint)
240
241/* ARGSUSED */
242int
243ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
244	ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
245	ddi_dma_cookie_t *cp, u_int *ccountp)
246{
247	return (DDI_SUCCESS);
248}
249
250#else	/* lint */
251
252	ENTRY(ddi_dma_bindhdl)
253	ldn	[%o0 + DEVI_BUS_DMA_BINDHDL], %o0
254			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
255	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
256	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
257	ldn	[%g1 + OPS_BINDHDL], %g1
258			! dip->dev_ops->devo_bus_ops->bus_dma_bindhdl
259	jmpl	%g1, %g0	! bop off to new routine
260	nop			! as if we had never been here
261	SET_SIZE(ddi_dma_bindhdl)
262
263#endif	/* lint */
264
265#if	defined(lint)
266
267/* ARGSUSED */
268int
269ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
270	ddi_dma_handle_t handle)
271{
272	return (DDI_SUCCESS);
273}
274
275#else	/* lint */
276
277	ENTRY(ddi_dma_unbindhdl)
278	ldn	[%o0 + DEVI_BUS_DMA_UNBINDHDL], %o0
279			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
280	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
281	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
282	ldn	[%g1 + OPS_UNBINDHDL], %g1
283			! dip->dev_ops->devo_bus_ops->bus_dma_unbindhdl
284	jmpl	%g1, %g0	! bop off to new routine
285	nop			! as if we had never been here
286	SET_SIZE(ddi_dma_unbindhdl)
287
288#endif	/* lint */
289
290#if	defined(lint)
291
292/* ARGSUSED */
293int
294ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
295	ddi_dma_handle_t handle, off_t off, size_t len,
296	u_int cache_flags)
297{
298	return (DDI_SUCCESS);
299}
300
301#else	/* lint */
302
303	ENTRY(ddi_dma_flush)
304	ldn	[%o0 + DEVI_BUS_DMA_FLUSH], %o0
305			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
306	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
307	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
308	ldn	[%g1 + OPS_FLUSH], %g1
309			! dip->dev_ops->devo_bus_ops->bus_dma_flush
310	jmpl	%g1, %g0	! bop off to new routine
311	nop			! as if we had never been here
312	SET_SIZE(ddi_dma_flush)
313
314#endif	/* lint */
315
316#if	defined(lint)
317
318/* ARGSUSED */
319int
320ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
321	ddi_dma_handle_t handle, uint_t win, off_t *offp,
322	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
323{
324	return (DDI_SUCCESS);
325}
326
327#else	/* lint */
328
329	ENTRY(ddi_dma_win)
330	ldn	[%o0 + DEVI_BUS_DMA_WIN], %o0
331			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
332	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
333	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
334	ldn	[%g1 + OPS_WIN], %g1
335			! dip->dev_ops->devo_bus_ops->bus_dma_win
336	jmpl	%g1, %g0	! bop off to new routine
337	nop			! as if we had never been here
338	SET_SIZE(ddi_dma_win)
339
340#endif	/* lint */
341
342#if	defined(lint)
343
344/* ARGSUSED */
345int
346ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, u_int whom)
347{
348	return (DDI_SUCCESS);
349}
350
351#else	/* lint */
352
353	ENTRY(ddi_dma_sync)
354	ld	[%o0 + DMA_HANDLE_RFLAGS], %o4	! hp->dmai_rflags;
355	sethi	%hi(DMP_NOSYNC), %o5
356	and	%o4, %o5, %o4
357	cmp	%o4, %o5
358	bne	1f
359	mov	%o3, %o5
360	retl
361	clr	%o0
3621:	mov	%o1, %o3
363	ldn	[%o0 + DMA_HANDLE_RDIP], %o1	! dip = hp->dmai_rdip;
364	mov	%o0, %g2
365	ldn	[%o1 + DEVI_BUS_DMA_FLUSH], %o0
366			! dip = DEVI(dip)->devi_bus_dma_flush;
367	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
368	mov	%o2, %o4
369	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
370	mov	%g2, %o2
371	ldn	[%g1 + OPS_FLUSH], %g1
372			! dip->dev_ops->devo_bus_ops->bus_dma_flush
373	jmpl	%g1, %g0	! bop off to new routine
374	nop			! as if we had never been here
375	SET_SIZE(ddi_dma_sync)
376
377#endif	/* lint */
378
379#if	defined(lint)
380
381/* ARGSUSED */
382int
383ddi_dma_unbind_handle(ddi_dma_handle_t h)
384{
385	return (DDI_SUCCESS);
386}
387
388#else	/* lint */
389
390	ENTRY(ddi_dma_unbind_handle)
391	ldn	[%o0 + DMA_HANDLE_RDIP], %o1	! dip = hp->dmai_rdip;
392	mov	%o0, %o2
393	ldn	[%o1 + DEVI_BUS_DMA_UNBINDFUNC ], %g1
394		    ! funcp = DEVI(dip)->devi_bus_dma_unbindfunc;
395	jmpl	%g1, %g0	! bop off to new routine
396	ldn	[%o1 + DEVI_BUS_DMA_UNBINDHDL], %o0
397		    ! hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
398	SET_SIZE(ddi_dma_unbind_handle)
399
400#endif	/* lint */
401
402
403#if	defined(lint)
404
405/*ARGSUSED*/
406int
407ddi_dma_mctl(register dev_info_t *dip, dev_info_t *rdip,
408    ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
409    off_t *offp, size_t *lenp, caddr_t *objp, u_int flags)
410{
411	return (DDI_SUCCESS);
412}
413
414#else	/* lint */
415
416	ENTRY(ddi_dma_mctl)
417	ldn	[%o0 + DEVI_BUS_DMA_CTL], %o0
418			! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
419	ldn	[%o0 + DEVI_DEV_OPS], %g1	! dip->dev_ops
420	ldn	[%g1 + DEVI_BUS_OPS], %g1	! dip->dev_ops->devo_bus_ops
421	ldn	[%g1 + OPS_MCTL], %g1 ! dip->dev_ops->devo_bus_ops->bus_dma_ctl
422	jmpl	%g1, %g0	! bop off to new routine
423	nop			! as if we had never been here
424	SET_SIZE(ddi_dma_mctl)
425
426#endif	/* lint */
427