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
80 1: 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
111 2: 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
190 1: 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