sparc_ddi.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Assembler routines to make some DDI routines go faster.
* These routines should ONLY be ISA-dependent.
*/
#if defined(lint)
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/file.h>
#include <sys/sunddi.h>
#else /* lint */
#include <sys/asm_linkage.h>
#include <sys/clock.h>
#include <sys/intreg.h>
#include "assym.h" /* for FKIOCTL etc. */
#endif /* lint */
/*
* Layered driver routines.
*
* At the time of writing, the compiler converts
*
* a() { return (b()); }
*
* into
* save, call b, restore
*
* Though this is sort of ok, if the called routine is leaf routine,
* then we just burnt a register window.
*
* When the compiler understands this optimization, many
* of these routines can go back to C again.
*/
#define FLATCALL(routine) \
mov %o7, %g1; \
call routine; \
mov %g1, %o7
#ifdef lint
int
ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
{
if (flags & FKIOCTL)
return (kcopy(buf, kernbuf, size) ? -1 : 0);
return (copyin(buf, kernbuf, size));
}
#else /* lint */
ENTRY(ddi_copyin)
set FKIOCTL, %o4
andcc %o3, %o4, %g0
bne .do_kcopy ! share code with ddi_copyout
FLATCALL(copyin)
/*NOTREACHED*/
.do_kcopy:
save %sp, -SA(MINFRAME), %sp
mov %i2, %o2
mov %i1, %o1
call kcopy
mov %i0, %o0
orcc %g0, %o0, %i0 ! if kcopy returns EFAULT ..
bne,a 1f
mov -1, %i0 ! .. we return -1
1: ret
restore
SET_SIZE(ddi_copyin)
#endif /* lint */
#ifdef lint
int
ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
{
if (flags & FKIOCTL)
return (kcopy(buf, kernbuf, size) ? -1 : 0);
return (copyout(buf, kernbuf, size));
}
#else /* lint */
ENTRY(ddi_copyout)
set FKIOCTL, %o4
andcc %o3, %o4, %g0
bne .do_kcopy ! share code with ddi_copyin
FLATCALL(copyout)
/*NOTREACHED*/
SET_SIZE(ddi_copyout)
#endif /* lint */
/*
* DDI spine wrapper routines - here so as to not have to
* buy register windows when climbing the device tree (which cost!)
*/
#if defined(lint)
/*ARGSUSED*/
int
ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_ctlops)
tst %o0 ! dip != 0?
be,pn %ncc, 2f ! nope
tst %o1 ! rdip != 0?
be,pn %ncc, 2f ! nope
ldn [%o0 + DEVI_BUS_CTL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_ctl;
brz,pn %o0, 2f
nop ! Delay slot
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_CTL], %g1 ! dip->dev_ops->devo_bus_ops->bus_ctl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
2: retl
sub %g0, 1, %o0 ! return (DDI_FAILURE);
SET_SIZE(ddi_ctlops)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_map)
ldn [%o0 + DEVI_BUS_DMA_MAP], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_map;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_MAP], %g1 ! dip->dev_ops->devo_bus_ops->bus_dma_map
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_map)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_allochdl)
ldn [%o0 + DEVI_BUS_DMA_ALLOCHDL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_ALLOCHDL], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_allochdl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_allochdl)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_freehdl)
ldn [%o0 + DEVI_BUS_DMA_FREEHDL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_freehdl;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_FREEHDL], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_freehdl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_freehdl)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
ddi_dma_cookie_t *cp, u_int *ccountp)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_bindhdl)
ldn [%o0 + DEVI_BUS_DMA_BINDHDL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_BINDHDL], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_bindhdl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_bindhdl)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_handle_t handle)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_unbindhdl)
ldn [%o0 + DEVI_BUS_DMA_UNBINDHDL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_UNBINDHDL], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_unbindhdl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_unbindhdl)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_handle_t handle, off_t off, size_t len,
u_int cache_flags)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_flush)
ldn [%o0 + DEVI_BUS_DMA_FLUSH], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_FLUSH], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_flush
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_flush)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
ddi_dma_handle_t handle, uint_t win, off_t *offp,
size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_win)
ldn [%o0 + DEVI_BUS_DMA_WIN], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_WIN], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_win
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_win)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, u_int whom)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_sync)
ld [%o0 + DMA_HANDLE_RFLAGS], %o4 ! hp->dmai_rflags;
sethi %hi(DMP_NOSYNC), %o5
and %o4, %o5, %o4
cmp %o4, %o5
bne 1f
mov %o3, %o5
retl
clr %o0
1: mov %o1, %o3
ldn [%o0 + DMA_HANDLE_RDIP], %o1 ! dip = hp->dmai_rdip;
mov %o0, %g2
ldn [%o1 + DEVI_BUS_DMA_FLUSH], %o0
! dip = DEVI(dip)->devi_bus_dma_flush;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
mov %o2, %o4
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
mov %g2, %o2
ldn [%g1 + OPS_FLUSH], %g1
! dip->dev_ops->devo_bus_ops->bus_dma_flush
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_sync)
#endif /* lint */
#if defined(lint)
/* ARGSUSED */
int
ddi_dma_unbind_handle(ddi_dma_handle_t h)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_unbind_handle)
ldn [%o0 + DMA_HANDLE_RDIP], %o1 ! dip = hp->dmai_rdip;
mov %o0, %o2
ldn [%o1 + DEVI_BUS_DMA_UNBINDFUNC ], %g1
! funcp = DEVI(dip)->devi_bus_dma_unbindfunc;
jmpl %g1, %g0 ! bop off to new routine
ldn [%o1 + DEVI_BUS_DMA_UNBINDHDL], %o0
! hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
SET_SIZE(ddi_dma_unbind_handle)
#endif /* lint */
#if defined(lint)
/*ARGSUSED*/
int
ddi_dma_mctl(register dev_info_t *dip, dev_info_t *rdip,
ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
off_t *offp, size_t *lenp, caddr_t *objp, u_int flags)
{
return (DDI_SUCCESS);
}
#else /* lint */
ENTRY(ddi_dma_mctl)
ldn [%o0 + DEVI_BUS_DMA_CTL], %o0
! dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
ldn [%o0 + DEVI_DEV_OPS], %g1 ! dip->dev_ops
ldn [%g1 + DEVI_BUS_OPS], %g1 ! dip->dev_ops->devo_bus_ops
ldn [%g1 + OPS_MCTL], %g1 ! dip->dev_ops->devo_bus_ops->bus_dma_ctl
jmpl %g1, %g0 ! bop off to new routine
nop ! as if we had never been here
SET_SIZE(ddi_dma_mctl)
#endif /* lint */