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