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