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