3858c5f53c
level 117. Reviewed by: Naofumi Honda <honda@Kururu.math.sci.hokudai.ac.jp>
260 lines
6.2 KiB
C
260 lines
6.2 KiB
C
/* $NecBSD: bshw_pdma.c,v 1.4 1997/10/31 17:43:39 honda Exp $ */
|
|
/* $NetBSD$ */
|
|
/*
|
|
* [NetBSD for NEC PC98 series]
|
|
* Copyright (c) 1994, 1995, 1996 NetBSD/pc98 porting staff.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
/*
|
|
* Copyright (c) 1994, 1995, 1996 Naofumi HONDA. All rights reserved.
|
|
*/
|
|
|
|
#define LC_SMIT_TIMEOUT 2 /* 2 sec: timeout for a fifo status ready */
|
|
|
|
static BS_INLINE void bshw_lc_smit_start __P((struct bs_softc *, int, u_int));
|
|
static int bshw_lc_smit_fstat __P((struct bs_softc *, int, int));
|
|
static BS_INLINE void bshw_lc_smit_stop __P((struct bs_softc *));
|
|
|
|
/*********************************************************
|
|
* SM FIFO (GENERIC)
|
|
*********************************************************/
|
|
void
|
|
bshw_smitabort(bsc)
|
|
struct bs_softc *bsc;
|
|
{
|
|
if (bsc->sc_hw->hw_flags & BSHW_SMFIFO)
|
|
bshw_lc_smit_stop(bsc);
|
|
|
|
bshw_set_count(bsc, 0);
|
|
bsc->sc_flags &= ~BSSMITSTART;
|
|
}
|
|
|
|
void
|
|
bs_smit_xfer_end(ti)
|
|
struct targ_info *ti;
|
|
{
|
|
struct bs_softc *bsc = ti->ti_bsc;
|
|
struct sc_p *sp = &bsc->sc_p;
|
|
u_int count;
|
|
u_char *s;
|
|
|
|
bshw_lc_smit_stop(bsc);
|
|
bsc->sc_flags &= ~BSSMITSTART;
|
|
|
|
if (ti->ti_phase == DATAPHASE)
|
|
{
|
|
count = bshw_get_count(bsc);
|
|
if (count < (u_int) sp->datalen)
|
|
{
|
|
sp->data += (sp->datalen - count);
|
|
sp->datalen = count;
|
|
/* XXX:
|
|
* strict double checks!
|
|
* target => wd33c93c transfer counts
|
|
* wd33c93c => memory transfer counts
|
|
*/
|
|
if ((bsc->sc_dmadir & BSHW_READ) &&
|
|
count != bsc->sm_tdatalen)
|
|
{
|
|
s = "read count miss";
|
|
goto bad;
|
|
}
|
|
return;
|
|
}
|
|
else if (count == (u_int) sp->datalen)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s = "strange count";
|
|
}
|
|
else
|
|
s = "extra smit interrupt";
|
|
|
|
bad:
|
|
bs_printf(ti, "smit_xfer_end", s);
|
|
ti->ti_error |= BSDMAABNORMAL;
|
|
}
|
|
|
|
/*********************************************************
|
|
* LOGITEC's SMIT TRANSFER
|
|
*********************************************************/
|
|
|
|
#define BSHW_LC_FSET 0x36
|
|
#define BSHW_LC_FCTRL 0x44
|
|
#define FCTRL_EN 0x01
|
|
#define FCTRL_WRITE 0x02
|
|
|
|
#define SF_ABORT 0x08
|
|
#define SF_RDY 0x10
|
|
|
|
#define LC_FSZ DEV_BSIZE
|
|
#define LC_SFSZ 0x0c
|
|
#define LC_REST (LC_FSZ - LC_SFSZ)
|
|
|
|
static BS_INLINE void
|
|
bshw_lc_smit_stop(bsc)
|
|
struct bs_softc *bsc;
|
|
{
|
|
|
|
write_wd33c93(bsc, BSHW_LC_FCTRL, 0);
|
|
BUS_IOW(cmd_port, CMDP_DMER);
|
|
}
|
|
|
|
static BS_INLINE void
|
|
bshw_lc_smit_start(bsc, count, direction)
|
|
struct bs_softc *bsc;
|
|
int count;
|
|
u_int direction;
|
|
{
|
|
u_int8_t pval, val = read_wd33c93(bsc, BSHW_LC_FSET);
|
|
|
|
bsc->sc_flags |= BSSMITSTART;
|
|
bshw_set_count(bsc, count);
|
|
|
|
pval = FCTRL_EN;
|
|
if ((direction & BSHW_READ) == 0)
|
|
pval |= (val & 0xe0) | FCTRL_WRITE;
|
|
write_wd33c93(bsc, BSHW_LC_FCTRL, pval);
|
|
bshw_start_xfer(bsc);
|
|
}
|
|
|
|
static int
|
|
bshw_lc_smit_fstat(bsc, wc, read)
|
|
struct bs_softc *bsc;
|
|
int wc, read;
|
|
{
|
|
u_int8_t stat;
|
|
|
|
#define ALWAYS_ABORT
|
|
#ifdef ALWAYS_ABORT
|
|
if (read == BSHW_READ)
|
|
{
|
|
while (wc -- > 0)
|
|
{
|
|
BUS_IO_WEIGHT;
|
|
stat = BUS_IOR(cmd_port);
|
|
if (stat & SF_RDY)
|
|
return 0;
|
|
if (stat & SF_ABORT)
|
|
return EIO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#endif /* ALWAYS_ABORT */
|
|
while (wc -- > 0)
|
|
{
|
|
BUS_IO_WEIGHT;
|
|
stat = BUS_IOR(cmd_port);
|
|
if (stat & SF_ABORT)
|
|
return EIO;
|
|
if (stat & SF_RDY)
|
|
return 0;
|
|
}
|
|
#ifdef ALWAYS_ABORT
|
|
}
|
|
#endif /* ALWAYS_ABORT */
|
|
|
|
bs_poll_timeout(bsc, "bshw_lc_smit");
|
|
return EIO;
|
|
}
|
|
|
|
void
|
|
bs_lc_smit_xfer(ti, direction)
|
|
struct targ_info *ti;
|
|
u_int direction;
|
|
{
|
|
struct bs_softc *bsc = ti->ti_bsc;
|
|
struct sc_p *sp = &bsc->sc_p;
|
|
int datalen, count, wc = LC_SMIT_TIMEOUT * 1024 * 1024;
|
|
u_int8_t *data;
|
|
|
|
sp->bufp = NULL;
|
|
sp->seglen = 0;
|
|
data = sp->data;
|
|
datalen = sp->datalen;
|
|
|
|
bsc->sc_dmadir = direction;
|
|
bshw_set_dma_trans(bsc, ti->ti_cfgflags);
|
|
bshw_lc_smit_start(bsc, sp->datalen, direction);
|
|
|
|
if (direction & BSHW_READ)
|
|
{
|
|
do
|
|
{
|
|
if (bshw_lc_smit_fstat(bsc, wc, BSHW_READ))
|
|
break;
|
|
|
|
count = (datalen > LC_FSZ ? LC_FSZ : datalen);
|
|
#ifdef __FreeBSD__
|
|
memcopy((u_int8_t *)ti->sm_offset, data, count);
|
|
#else /* NetBSD */
|
|
bus_space_read_region_4(bsc->sc_memt, bsc->sc_memh,
|
|
ti->sm_offset, (u_int32_t *) data, count >> 2);
|
|
#endif /* NetBSD */
|
|
data += count;
|
|
datalen -= count;
|
|
}
|
|
while (datalen > 0);
|
|
|
|
bsc->sm_tdatalen = datalen;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
|
|
break;
|
|
|
|
count = (datalen > LC_SFSZ ? LC_SFSZ : datalen);
|
|
#ifdef __FreeBSD__
|
|
memcopy(data, (u_int8_t *)ti->sm_offset, count);
|
|
#else /* NetBSD */
|
|
bus_space_write_region_4(bsc->sc_memt, bsc->sc_memh,
|
|
ti->sm_offset, (u_int32_t *) data, count >> 2);
|
|
#endif /* NetBSD */
|
|
data += count;
|
|
datalen -= count;
|
|
|
|
if (bshw_lc_smit_fstat(bsc, wc, BSHW_WRITE))
|
|
break;
|
|
|
|
count = (datalen > LC_REST ? LC_REST : datalen);
|
|
#ifdef __FreeBSD__
|
|
memcopy(data, (u_int8_t *)(ti->sm_offset + LC_SFSZ), count);
|
|
#else /* NetBSD */
|
|
bus_space_write_region_4(bsc->sc_memt, bsc->sc_memh,
|
|
ti->sm_offset + LC_SFSZ,
|
|
(u_int32_t *) data, count >> 2);
|
|
#endif /* NetBSD */
|
|
data += count;
|
|
datalen -= count;
|
|
}
|
|
while (datalen > 0);
|
|
}
|
|
}
|