Fix map register/DMA wait queues.

Still to do:
	BDP handling. Currently missing.
	Ubareset's won't work at all.
This commit is contained in:
ragge 1999-06-06 19:14:48 +00:00
parent 3bb07459cd
commit a2692d780b
8 changed files with 194 additions and 442 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: dhu.c,v 1.15 1999/05/28 20:17:29 ragge Exp $ */
/* $NetBSD: dhu.c,v 1.16 1999/06/06 19:14:48 ragge Exp $ */
/*
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
* Copyright (c) 1992, 1993
@ -71,10 +71,11 @@ struct dhu_softc {
int sc_type; /* controller type, DHU or DHV */
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
struct {
struct tty *dhu_tty; /* what we work on */
bus_dmamap_t dhu_dmah;
int dhu_state; /* to manage TX output status */
int dhu_txaddr; /* UBA map address to TX buf */
short dhu_cc; /* character count on TX */
short dhu_modem; /* modem bits state */
} sc_dhu[NDHULINE];
@ -207,10 +208,11 @@ dhu_attach(parent, self, aux)
register struct dhu_softc *sc = (void *)self;
register struct uba_attach_args *ua = aux;
register unsigned c;
register int n;
register int n, i;
sc->sc_iot = ua->ua_iot;
sc->sc_ioh = ua->ua_ioh;
sc->sc_dmat = ua->ua_dmat;
/* Process the 8 bytes of diagnostic info put into */
/* the FIFO following the master reset operation. */
@ -233,6 +235,18 @@ dhu_attach(parent, self, aux)
sc->sc_type = (c & DHU_STAT_DHU)? IS_DHU: IS_DHV;
printf("\n%s: DH%s-11\n", self->dv_xname, (c & DHU_STAT_DHU)?"U":"V");
for (i = 0; i < sc->sc_type; i++) {
struct tty *tp;
tp = sc->sc_dhu[i].dhu_tty = ttymalloc();
sc->sc_dhu[i].dhu_state = STATE_IDLE;
bus_dmamap_create(sc->sc_dmat, tp->t_outq.c_cn, 1,
tp->t_outq.c_cn, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT,
&sc->sc_dhu[i].dhu_dmah);
bus_dmamap_load(sc->sc_dmat, sc->sc_dhu[i].dhu_dmah,
tp->t_outq.c_cs, tp->t_outq.c_cn, 0, BUS_DMA_NOWAIT);
}
/* Now stuff TX interrupt handler in place */
scb_vecalloc(ua->ua_cvec + 4, dhuxint, self->dv_unit, SCB_ISTACK);
}
@ -365,24 +379,12 @@ dhuopen(dev, flag, mode, p)
if (line >= sc->sc_type)
return ENXIO;
s = spltty();
DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT);
(void) splx(s);
tp = sc->sc_dhu[line].dhu_tty;
if (tp == NULL) {
tp = sc->sc_dhu[line].dhu_tty = ttymalloc();
if (tp == NULL)
return ENXIO;
sc->sc_dhu[line].dhu_state = STATE_IDLE;
sc->sc_dhu[line].dhu_txaddr =
uballoc((struct uba_softc *)sc->sc_dev.dv_parent,
tp->t_outq.c_cs, tp->t_outq.c_cn, 0);
s = spltty();
DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT);
(void) splx(s);
}
tp->t_oproc = dhustart;
tp->t_param = dhuparam;
@ -634,7 +636,7 @@ dhustart(tp)
sc->sc_dhu[line].dhu_state = STATE_DMA_RUNNING;
addr = UBAI_ADDR(sc->sc_dhu[line].dhu_txaddr) +
addr = sc->sc_dhu[line].dhu_dmah->dm_segs[0].ds_addr +
(tp->t_outq.c_cf - tp->t_outq.c_cs);
DHU_WRITE_WORD(DHU_UBA_TBUFCNT, cc);

View File

@ -1,4 +1,4 @@
/* $NetBSD: dl.c,v 1.9 1999/05/27 16:00:45 ragge Exp $ */
/* $NetBSD: dl.c,v 1.10 1999/06/06 19:14:49 ragge Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@ -97,10 +97,9 @@
#include <machine/bus.h>
#include <machine/scb.h>
#include <dev/dec/qbus/ubareg.h>
#include <dev/dec/qbus/ubavar.h>
#include <dev/qbus/ubavar.h>
#include <dev/dec/qbus/dlreg.h>
#include <dev/qbus/dlreg.h>
#include "ioconf.h"

View File

@ -1,4 +1,4 @@
/* $NetBSD: dz.c,v 1.17 1999/05/27 16:02:32 ragge Exp $ */
/* $NetBSD: dz.c,v 1.18 1999/06/06 19:14:49 ragge Exp $ */
/*
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
* Copyright (c) 1992, 1993
@ -61,11 +61,8 @@
#include <machine/trap.h>
#include <machine/cpu.h>
#include <dev/dec/qbus/ubareg.h>
#include <dev/dec/qbus/ubavar.h>
#include <dev/dec/qbus/dzreg.h>
#include <dev/dec/qbus/dzvar.h>
#include <dev/qbus/dzreg.h>
#include <dev/qbus/dzvar.h>
#define DZ_READ_BYTE(adr) \
bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_dr.adr)

View File

@ -1,4 +1,4 @@
/* $NetBSD: dz_uba.c,v 1.6 1999/05/27 16:02:50 ragge Exp $ */
/* $NetBSD: dz_uba.c,v 1.7 1999/06/06 19:14:49 ragge Exp $ */
/*
* Copyright (c) 1998 Ludd, University of Lule}, Sweden. All rights reserved.
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
@ -49,11 +49,10 @@
#include <machine/trap.h>
#include <machine/scb.h>
#include <dev/dec/qbus/ubareg.h>
#include <dev/dec/qbus/ubavar.h>
#include <dev/qbus/ubavar.h>
#include <dev/dec/qbus/dzreg.h>
#include <dev/dec/qbus/dzvar.h>
#include <dev/qbus/dzreg.h>
#include <dev/qbus/dzvar.h>
#include "ioconf.h"

View File

@ -1,19 +1,30 @@
# $NetBSD: files.uba,v 1.4 1999/05/27 16:03:57 ragge Exp $
# $NetBSD: files.uba,v 1.5 1999/06/06 19:14:49 ragge Exp $
#
# Config file and device description for machine-independent
# code for devices Digital Equipment Corp. Unibus and Q22 bus.
# Included by ports that need it.
device uba { csr }
file dev/dec/uba/uba.c uba & new_uba
file dev/qbus/uba.c uba & new_uba
# DZ-11 (-compatible) tty device driver.
device dz { }: tty
attach dz at uba with dz_uba
file dev/dec/qbus/dz.c dz needs-flag
file dev/dec/qbus/dz_uba.c dz_uba & new_uba
file dev/qbus/dz.c dz needs-flag
file dev/qbus/dz_uba.c dz_uba & new_uba
# DL-11 at UBA
device dl: tty
attach dl at uba
file dev/dec/qbus/dl.c dl needs-flag
file dev/qbus/dl.c dl needs-flag
# DHU-11 at UBA
device dhu: tty
attach dhu at uba
file dev/qbus/dhu.c dhu needs-flag
device mtc: mscp
attach mtc at uba
device uda: mscp
attach uda at uba
file dev/qbus/uda.c uda | mtc

View File

@ -1,4 +1,4 @@
/* $NetBSD: uba.c,v 1.46 1999/05/27 16:04:13 ragge Exp $ */
/* $NetBSD: uba.c,v 1.47 1999/06/06 19:14:49 ragge Exp $ */
/*
* Copyright (c) 1996 Jonathan Stone.
* Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
@ -58,263 +58,54 @@
#include <machine/scb.h>
#include <machine/cpu.h>
#ifdef __vax__
#include <machine/pte.h>
#endif
#include <dev/qbus/ubavar.h>
#include <dev/dec/qbus/ubareg.h>
#include <dev/dec/qbus/ubavar.h>
#include "ioconf.h"
static int ubasearch __P((struct device *, struct cfdata *, void *));
static int ubaprint __P((void *, const char *));
static void ubainitmaps __P((struct uba_softc *));
extern struct cfdriver uba_cd;
#define spluba spl7
/*
* Do transfer on device argument. The controller
* and uba involved are implied by the device.
* We queue for resource wait in the uba code if necessary.
* We return 1 if the transfer was started, 0 if it was not.
*
* The onq argument must be zero iff the device is not on the
* queue for this UBA. If onq is set, the device must be at the
* head of the queue. In any case, if the transfer is started,
* the device will be off the queue, and if not, it will be on.
*
* Drivers that allocate one BDP and hold it for some time should
* set ud_keepbdp. In this case um_bdp tells which BDP is allocated
* to the controller, unless it is zero, indicating that the controller
* does not now have a BDP.
* If we failed to allocate uba resources, put us on a queue to wait
* until there is available resources. Resources to compete about
* are map registers and BDPs. This is normally only a problem on
* Unibus systems, Qbus systems have more map registers than usable.
*/
int
ubaqueue(uu, bp)
register struct uba_unit *uu;
struct buf *bp;
void
uba_enqueue(uu)
struct uba_unit *uu;
{
register struct uba_softc *uh;
register int s;
struct uba_softc *uh;
int s;
uh = (void *)((struct device *)(uu->uu_softc))->dv_parent;
s = spluba();
/*
* Honor exclusive BDP use requests.
*/
if ((uu->uu_xclu && uh->uh_users > 0) || uh->uh_xclu)
goto rwait;
if (uu->uu_keepbdp) {
/*
* First get just a BDP (though in fact it comes with
* one map register too).
*/
if (uu->uu_bdp == 0) {
uu->uu_bdp = uballoc(uh, (caddr_t)0, 0,
UBA_NEEDBDP|UBA_CANTWAIT);
if (uu->uu_bdp == 0)
goto rwait;
}
/* now share it with this transfer */
uu->uu_ubinfo = ubasetup(uh, bp,
uu->uu_bdp|UBA_HAVEBDP|UBA_CANTWAIT);
} else
uu->uu_ubinfo = ubasetup(uh, bp, UBA_NEEDBDP|UBA_CANTWAIT);
if (uu->uu_ubinfo == 0)
goto rwait;
uh->uh_users++;
if (uu->uu_xclu)
uh->uh_xclu = 1;
splx(s);
return (1);
rwait:
s = splimp();
SIMPLEQ_INSERT_TAIL(&uh->uh_resq, uu, uu_resq);
splx(s);
return (0);
}
void
ubadone(uu)
struct uba_unit *uu;
{
struct uba_softc *uh = (void *)((struct device *)
(uu->uu_softc))->dv_parent;
if (uu->uu_xclu)
uh->uh_xclu = 0;
uh->uh_users--;
if (uu->uu_keepbdp)
uu->uu_ubinfo &= ~BDPMASK; /* keep BDP for misers */
ubarelse(uh, &uu->uu_ubinfo);
}
/*
* Allocate and setup UBA map registers, and bdp's
* Flags says whether bdp is needed, whether the caller can't
* wait (e.g. if the caller is at interrupt level).
* Return value encodes map register plus page offset,
* bdp number and number of map registers.
*/
int
ubasetup(uh, bp, flags)
struct uba_softc *uh;
struct buf *bp;
int flags;
{
int npf;
int temp;
int reg, bdp;
int a, o, ubinfo;
if (uh->uh_nbdp == 0)
flags &= ~UBA_NEEDBDP;
o = (int)bp->b_un.b_addr & VAX_PGOFSET;
npf = vax_btoc(bp->b_bcount + o) + 1;
if (npf > UBA_MAXNMR)
panic("uba xfer too big");
a = spluba();
while ((reg = rmalloc(uh->uh_map, (long)npf)) == 0) {
if (flags & UBA_CANTWAIT) {
splx(a);
return (0);
}
uh->uh_mrwant++;
sleep((caddr_t)&uh->uh_mrwant, PSWP);
}
if ((flags & UBA_NEED16) && reg + npf > 128) {
/*
* Could hang around and try again (if we can ever succeed).
* Won't help any current device...
*/
rmfree(uh->uh_map, (long)npf, (long)reg);
splx(a);
return (0);
}
bdp = 0;
if (flags & UBA_NEEDBDP) {
while ((bdp = ffs((long)uh->uh_bdpfree)) == 0) {
if (flags & UBA_CANTWAIT) {
rmfree(uh->uh_map, (long)npf, (long)reg);
splx(a);
return (0);
}
uh->uh_bdpwant++;
sleep((caddr_t)&uh->uh_bdpwant, PSWP);
}
uh->uh_bdpfree &= ~(1 << (bdp-1));
} else if (flags & UBA_HAVEBDP)
bdp = (flags >> 28) & 0xf;
splx(a);
reg--;
ubinfo = UBAI_INFO(o, reg, npf, bdp);
temp = (bdp << 21) | UBAMR_MRV;
if (bdp && (o & 01))
temp |= UBAMR_BO;
disk_reallymapin(bp, uh->uh_mr, reg, temp | PG_V);
return (ubinfo);
}
/*
* Non buffer setup interface... set up a buffer and call ubasetup.
*/
int
uballoc(uh, addr, bcnt, flags)
struct uba_softc *uh;
caddr_t addr;
int bcnt, flags;
{
struct buf ubabuf;
ubabuf.b_un.b_addr = addr;
ubabuf.b_flags = B_BUSY;
ubabuf.b_bcount = bcnt;
/* that's all the fields ubasetup() needs */
return (ubasetup(uh, &ubabuf, flags));
}
/*
* Release resources on uba uban, and then unblock resource waiters.
* The map register parameter is by value since we need to block
* against uba resets on 11/780's.
* When a routine that uses resources is finished, the next device
* in queue for map registers etc is called. If it succeeds to get
* resources, call next, and next, and next...
* This routine must be called at splimp.
*/
void
ubarelse(uh, amr)
struct uba_softc *uh;
int *amr;
uba_done(uh)
struct uba_softc *uh;
{
struct uba_unit *uu;
register int bdp, reg, npf, s;
int mr;
/*
* Carefully see if we should release the space, since
* it may be released asynchronously at uba reset time.
*/
s = spluba();
mr = *amr;
if (mr == 0) {
/*
* A ubareset() occurred before we got around
* to releasing the space... no need to bother.
*/
splx(s);
return;
}
*amr = 0;
bdp = UBAI_BDP(mr);
if (bdp) {
if (uh->uh_ubapurge)
(*uh->uh_ubapurge)(uh, bdp);
uh->uh_bdpfree |= 1 << (bdp-1); /* atomic */
if (uh->uh_bdpwant) {
uh->uh_bdpwant = 0;
wakeup((caddr_t)&uh->uh_bdpwant);
}
}
/*
* Put back the registers in the resource map.
* The map code must not be reentered,
* nor can the registers be freed twice.
* Unblock interrupts once this is done.
*/
npf = UBAI_NMR(mr);
reg = UBAI_MR(mr) + 1;
rmfree(uh->uh_map, (long)npf, (long)reg);
splx(s);
/*
* Wakeup sleepers for map registers,
* and also, if there are processes blocked in dgo(),
* give them a chance at the UNIBUS.
*/
if (uh->uh_mrwant) {
uh->uh_mrwant = 0;
wakeup((caddr_t)&uh->uh_mrwant);
}
while ((uu = uh->uh_resq.sqh_first)) {
while ((uu = SIMPLEQ_FIRST(&uh->uh_resq))) {
SIMPLEQ_REMOVE_HEAD(&uh->uh_resq, uu, uu_resq);
if ((*uu->uu_ready)(uu) == 0)
if ((*uu->uu_ready)(uu) == 0) {
SIMPLEQ_INSERT_HEAD(&uh->uh_resq, uu, uu_resq);
break;
}
}
}
void
ubainitmaps(uhp)
register struct uba_softc *uhp;
{
if (uhp->uh_memsize > UBA_MAXMR)
uhp->uh_memsize = UBA_MAXMR;
rminit(uhp->uh_map, (long)uhp->uh_memsize, (long)1, "uba", UAMSIZ);
uhp->uh_bdpfree = (1 << uhp->uh_nbdp) - 1;
}
/*
* Generate a reset on uba number uban. Then
* call each device that asked to be called during attach,
@ -327,16 +118,8 @@ ubareset(uban)
register struct uba_softc *uh = uba_cd.cd_devs[uban];
int s, i;
s = spluba();
uh->uh_users = 0;
uh->uh_zvcnt = 0;
uh->uh_xclu = 0;
s = splimp();
SIMPLEQ_INIT(&uh->uh_resq);
uh->uh_bdpwant = 0;
uh->uh_mrwant = 0;
ubainitmaps(uh);
wakeup((caddr_t)&uh->uh_bdpwant);
wakeup((caddr_t)&uh->uh_mrwant);
printf("%s: reset", uh->uh_dev.dv_xname);
(*uh->uh_ubainit)(uh);
@ -347,9 +130,7 @@ ubareset(uban)
}
/*
* The common attach routines:
* Allocates interrupt vectors.
* Puts correct values in uba_softc.
* The common attach routine:
* Calls the scan routine to search for uba devices.
*/
void
@ -371,14 +152,6 @@ uba_attach(sc, iopagephys)
*/
if (bus_space_map(sc->uh_iot, iopagephys, UBAIOSIZE, 0, &sc->uh_ioh))
return;
/*
* Initialize the UNIBUS, by freeing the map
* registers and the buffered data path registers
*/
sc->uh_map = (struct map *)malloc((u_long)
(UAMSIZ * sizeof(struct map)), M_DEVBUF, M_NOWAIT);
bzero((caddr_t)sc->uh_map, (unsigned)(UAMSIZ * sizeof (struct map)));
ubainitmaps(sc);
if (sc->uh_beforescan)
(*sc->uh_beforescan)(sc);
@ -403,6 +176,7 @@ ubasearch(parent, cf, aux)
ua.ua_ioh = ubdevreg(cf->cf_loc[0]) + sc->uh_ioh;
ua.ua_iot = sc->uh_iot;
ua.ua_dmat = sc->uh_dmat;
ua.ua_reset = NULL;
if (badaddr((caddr_t)ua.ua_ioh, 2) ||

View File

@ -1,4 +1,4 @@
/* $NetBSD: ubavar.h,v 1.24 1999/05/27 16:04:48 ragge Exp $ */
/* $NetBSD: ubavar.h,v 1.25 1999/06/06 19:14:49 ragge Exp $ */
/*
* Copyright (c) 1982, 1986 Regents of the University of California.
@ -44,10 +44,6 @@
* Each unibus device has a uba_device structure.
*/
#include <sys/buf.h>
#include <sys/device.h>
#include <machine/trap.h> /* For struct ivec_dsp */
/*
* Per-uba structure.
*
@ -72,39 +68,21 @@
struct uba_softc {
struct device uh_dev; /* Device struct, autoconfig */
SIMPLEQ_HEAD(, uba_unit) uh_resq; /* resource wait chain */
int uh_type; /* type of adaptor */
struct uba_regs *uh_uba; /* virt addr of uba adaptor regs */
struct pte *uh_mr; /* start of page map */
int uh_memsize; /* size of uba memory, pages */
caddr_t uh_iopage; /* start of uba io page */
void (**uh_reset) __P((int));/* UBA reset function array */
int *uh_resarg; /* array of ubareset args */
int uh_resno; /* Number of devices to reset */
short uh_mrwant; /* someone is waiting for map reg */
short uh_bdpwant; /* someone awaits bdp's */
int uh_bdpfree; /* free bdp's */
int uh_zvcnt; /* number of recent 0 vectors */
long uh_zvtime; /* time over which zvcnt accumulated */
int uh_zvtotal; /* total number of 0 vectors */
int uh_lastiv; /* last free interrupt vector */
short uh_users; /* transient bdp use count */
short uh_xclu; /* an rk07 is using this uba! */
int uh_lastmem; /* limit of any unibus memory */
struct map *uh_map; /* register free map */
int (*uh_errchk) __P((struct uba_softc *));
void (*uh_beforescan) __P((struct uba_softc *));
void (*uh_afterscan) __P((struct uba_softc *));
void (*uh_ubainit) __P((struct uba_softc *));
void (*uh_ubapurge) __P((struct uba_softc *, int));
short uh_nr; /* Unibus sequential number */
short uh_nbdp; /* # of BDP's */
int uh_ibase; /* Base address for vectors */
bus_space_tag_t uh_iot; /* Tag for this Unibus */
bus_space_handle_t uh_ioh; /* Handle for I/O space */
bus_dma_tag_t uh_dmat;
};
#define UAMSIZ 100
/*
* Per-controller structure.
* The unit struct is common to both the adapter and the controller
@ -114,9 +92,9 @@ struct uba_softc {
struct uba_unit {
SIMPLEQ_ENTRY(uba_unit) uu_resq;/* Queue while waiting for resources */
void *uu_softc; /* Pointer to units softc */
int uu_ubinfo; /* save unibus registers, etc */
int uu_bdp; /* for controllers that hang on to bdp's */
int (*uu_ready) __P((struct uba_unit *));
void *uu_ref; /* Buffer this is related to */
short uu_xclu; /* want exclusive use of bdp's */
short uu_keepbdp; /* hang on to bdp's once allocated */
};
@ -128,6 +106,7 @@ struct uba_unit {
struct uba_attach_args {
bus_space_tag_t ua_iot; /* Tag for this bus I/O-space */
bus_addr_t ua_ioh; /* I/O regs addr */
bus_dma_tag_t ua_dmat;
/* Pointer to int routine, filled in by probe*/
void (*ua_ivec) __P((int));
/* UBA reset routine, filled in by probe */
@ -144,44 +123,21 @@ struct uba_attach_args {
#define UBA_CANTWAIT 0x02 /* don't block me */
#define UBA_NEED16 0x04 /* need 16 bit addresses only */
#define UBA_HAVEBDP 0x08 /* use bdp specified in high bits */
#define UBA_DONTQUE 0x10 /* Do not enqueue xfer */
/*
* Macros to bust return word from map allocation routines.
* SHOULD USE STRUCTURE TO STORE UBA RESOURCE ALLOCATION:
* Some common defines for all subtypes of U/Q-buses/adapters.
*/
#ifdef notyet
struct ubinfo {
long ub_addr; /* unibus address: mr + boff */
int ub_nmr; /* number of registers, 0 if empty */
int ub_bdp; /* bdp number, 0 if none */
};
#define UBAI_MR(i) (((i) >> 9) & 0x7ff) /* starting map register */
#define UBAI_BOFF(i) ((i)&0x1ff) /* page offset */
#else
#define UBAI_BDP(i) ((int)(((unsigned)(i)) >> 28))
#define BDPMASK 0xf0000000
#define UBAI_NMR(i) ((int)((i) >> 20) & 0xff) /* max 255 (=127.5K) */
#define UBA_MAXNMR 255
#define UBAI_MR(i) ((int)((i) >> 9) & 0x7ff) /* max 2047 */
#define UBA_MAXMR 2047
#define UBAI_BOFF(i) ((int)((i) & 0x1ff))
#define UBAI_ADDR(i) ((int)((i) & 0xfffff)) /* uba addr (boff+mr) */
#define UBAI_INFO(off, mr, nmr, bdp) \
(((bdp) << 28) | ((nmr) << 20) | ((mr) << 9) | (off))
#endif
#define MAXUBAXFER (63*1024) /* Max transfer size in bytes */
#define UBAIOSIZE (8*1024) /* 8K I/O space */
#define ubdevreg(addr) ((addr) & 017777)
#ifndef _LOCORE
#ifdef _KERNEL
#define ubago(ui) ubaqueue(ui)
#define b_forw b_hash.le_next /* Nice to have when handling uba queues */
void uba_attach __P((struct uba_softc *, unsigned long));
int uballoc __P((struct uba_softc *, caddr_t, int, int));
void ubarelse __P((struct uba_softc *, int *));
int ubaqueue __P((struct uba_unit *, struct buf *));
void ubadone __P((struct uba_unit *));
void uba_enqueue __P((struct uba_unit *));
void uba_done __P((struct uba_softc *));
void ubareset __P((int));
int ubasetup __P((struct uba_softc *, struct buf *, int));
#endif /* _KERNEL */
#endif !_LOCORE

View File

@ -1,4 +1,4 @@
/* $NetBSD: uda.c,v 1.29 1999/05/29 17:03:17 ragge Exp $ */
/* $NetBSD: uda.c,v 1.30 1999/06/06 19:14:49 ragge Exp $ */
/*
* Copyright (c) 1996 Ludd, University of Lule}, Sweden.
* Copyright (c) 1988 Regents of the University of California.
@ -45,18 +45,20 @@
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/sid.h>
#include <machine/pte.h>
#include <machine/cpu.h>
#include <vax/uba/ubareg.h>
#include <vax/uba/ubavar.h>
#include <vax/uba/udareg.h>
#include <dev/qbus/ubavar.h>
#include <vax/mscp/mscp.h>
#include <vax/mscp/mscpvar.h>
#include <vax/mscp/mscpreg.h>
#include <dev/mscp/mscp.h>
#include <dev/mscp/mscpreg.h>
#include <dev/mscp/mscpvar.h>
#include "ioconf.h"
/*
* Variants of SIMPLEQ macros for use with buf structs.
@ -81,11 +83,15 @@ struct uda_softc {
SIMPLEQ_HEAD(, buf) sc_bufq; /* bufs awaiting for resources */
struct mscp_pack *sc_uuda; /* Unibus address of uda struct */
struct mscp_pack sc_uda; /* Struct for uda communication */
struct udadevice *sc_udadev; /* pointer to ip/sa regs */
bus_dma_tag_t sc_dmat;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_iph;
bus_space_handle_t sc_sah;
bus_dmamap_t sc_cmap;/* Control structures */
struct mscp *sc_mscp; /* Keep pointer to active mscp */
short sc_ipl; /* interrupt priority, Q-bus */
struct mscp_softc *sc_softc; /* MSCP info (per mscpvar.h) */
int sc_wticks; /* watchdog timer ticks */
int sc_inq;
};
static int udamatch __P((struct device *, struct cfdata *, void *));
@ -97,19 +103,15 @@ static void udaintr __P((int));
static void mtcintr __P((int));
static void intr __P((struct uda_softc *));
int udaready __P((struct uba_unit *));
void udactlrdone __P((struct device *, int));
void udactlrdone __P((struct device *));
int udaprint __P((void *, const char *));
void udasaerror __P((struct device *, int));
int udago __P((struct device *, struct buf *));
extern struct cfdriver mtc_cd;
void udago __P((struct device *, struct mscp_xi *));
struct cfattach mtc_ca = {
sizeof(struct uda_softc), udamatch, udaattach
};
extern struct cfdriver uda_cd;
struct cfattach uda_ca = {
sizeof(struct uda_softc), udamatch, udaattach
};
@ -151,17 +153,15 @@ udamatch(parent, cf, aux)
struct mscp_softc mi; /* Nice hack */
struct uba_softc *ubasc;
int tries;
#if QBA && notyet
extern volatile int rbr;
int s;
#endif
/* Get an interrupt vector. */
ubasc = (void *)parent;
ivec_no = ubasc->uh_lastiv - 4;
mi.mi_sa = &((struct udadevice *)ua->ua_addr)->udasa;
mi.mi_ip = &((struct udadevice *)ua->ua_addr)->udaip;
mi.mi_iot = ua->ua_iot;
mi.mi_iph = ua->ua_ioh;
mi.mi_sah = ua->ua_ioh + 2;
mi.mi_swh = ua->ua_ioh + 2;
/*
* Initialise the controller (partially). The UDA50 programmer's
@ -171,28 +171,23 @@ udamatch(parent, cf, aux)
* initialise within ten seconds. Or so I hear; I have not seen
* this manual myself.
*/
#if 0
s = spl6();
#endif
tries = 0;
again:
*mi.mi_ip = 0;
bus_space_write_2(mi.mi_iot, mi.mi_iph, 0, 0); /* Start init */
if (mscp_waitstep(&mi, MP_STEP1, MP_STEP1) == 0)
return 0; /* Nothing here... */
*mi.mi_sa = MP_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | MP_IE |
(ivec_no >> 2);
bus_space_write_2(mi.mi_iot, mi.mi_sah, 0,
MP_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | MP_IE | (ivec_no >> 2));
if (mscp_waitstep(&mi, MP_STEP2, MP_STEP2) == 0) {
printf("udaprobe: init step2 no change. sa=%x\n", *mi.mi_sa);
printf("udaprobe: init step2 no change. sa=%x\n",
bus_space_read_2(mi.mi_iot, mi.mi_sah, 0));
goto bad;
}
/* should have interrupted by now */
#if 0
rbr = qbgetpri();
#endif
if (strcmp(cf->cf_driver->cd_name, mtc_cd.cd_name)) {
ua->ua_ivec = udaintr;
ua->ua_reset = udareset;
@ -205,9 +200,6 @@ again:
bad:
if (++tries < 2)
goto again;
#if 0
splx(s);
#endif
return 0;
}
@ -220,17 +212,18 @@ udaattach(parent, self, aux)
struct uba_attach_args *ua = aux;
struct uba_softc *uh = (void *)parent;
struct mscp_attach_args ma;
int ctlr, ubinfo;
int ctlr, error, rseg;
bus_dma_segment_t seg;
printf("\n");
uh->uh_lastiv -= 4; /* remove dynamic interrupt vector */
#ifdef QBA
sc->sc_ipl = ua->ua_br;
#endif
sc->sc_iot = ua->ua_iot;
sc->sc_iph = ua->ua_ioh;
sc->sc_sah = ua->ua_ioh + 2;
sc->sc_dmat = ua->ua_dmat;
ctlr = sc->sc_dev.dv_unit;
sc->sc_udadev = (struct udadevice *)ua->ua_addr;
SIMPLEQ_INIT(&sc->sc_bufq);
/*
@ -244,16 +237,31 @@ udaattach(parent, self, aux)
* Map the communication area and command and
* response packets into Unibus space.
*/
ubinfo = uballoc((struct uba_softc *)sc->sc_dev.dv_parent,
(caddr_t) &sc->sc_uda, sizeof (struct mscp_pack), UBA_CANTWAIT);
#ifdef DIAGNOSTIC
if (ubinfo == 0) {
printf("%s: uballoc map failed\n", sc->sc_dev.dv_xname);
if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct mscp_pack),
NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
printf("Alloc ctrl area %d\n", error);
return;
}
#endif
sc->sc_uuda = (struct mscp_pack *) UBAI_ADDR(ubinfo);
if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
sizeof(struct mscp_pack), (caddr_t *) &sc->sc_uda,
BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
printf("Map ctrl area %d\n", error);
err: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
return;
}
if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct mscp_pack),
1, sizeof(struct mscp_pack), 0, BUS_DMA_NOWAIT, &sc->sc_cmap))) {
printf("Create DMA map %d\n", error);
err2: bus_dmamem_unmap(sc->sc_dmat, (caddr_t)&sc->sc_uda,
sizeof(struct mscp_pack));
goto err;
}
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cmap,
&sc->sc_uda, sizeof(struct mscp_pack), 0, BUS_DMA_NOWAIT))) {
printf("Load ctrl map %d\n", error);
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmap);
goto err2;
}
bzero(&sc->sc_uda, sizeof (struct mscp_pack));
@ -268,11 +276,14 @@ udaattach(parent, self, aux)
ma.ma_mc = &uda_mscp_ctlr;
ma.ma_type |= MSCPBUS_UDA;
ma.ma_uuda = sc->sc_uuda;
ma.ma_uda = &sc->sc_uda;
ma.ma_softc = &sc->sc_softc;
ma.ma_ip = &sc->sc_udadev->udaip;
ma.ma_sa = ma.ma_sw = &sc->sc_udadev->udasa;
ma.ma_iot = sc->sc_iot;
ma.ma_iph = sc->sc_iph;
ma.ma_sah = sc->sc_sah;
ma.ma_swh = sc->sc_sah;
ma.ma_dmat = sc->sc_dmat;
ma.ma_dmam = sc->sc_cmap;
ma.ma_ivec = ivec_no;
ma.ma_ctlrnr = (ua->ua_iaddr == 0172150 ? 0 : 1); /* XXX */
ma.ma_adapnr = uh->uh_nr;
@ -282,53 +293,63 @@ udaattach(parent, self, aux)
/*
* Start a transfer if there are free resources available, otherwise
* let it go in udaready, forget it for now.
* Called from mscp routines.
*/
int
udago(usc, bp)
void
udago(usc, mxi)
struct device *usc;
struct buf *bp;
struct mscp_xi *mxi;
{
struct uda_softc *sc = (void *)usc;
struct uba_unit *uu = &sc->sc_unit;
struct uba_unit *uu;
struct buf *bp = mxi->mxi_bp;
int err;
/*
* If we already are queued for resources, don't call ubaqueue
* again. (Then we would trash the wait queue). Just queue the
* buf and let the rest be done in udaready.
* If we already have transfers queued, don't try to load
* the map again.
*/
if (sc->sc_bufq.sqh_first)
BUFQ_INSERT_TAIL(&sc->sc_bufq, bp)
else {
if (ubaqueue(uu, bp))
mscp_dgo(sc->sc_softc, (UBAI_ADDR(uu->uu_ubinfo) |
(UBAI_BDP(uu->uu_ubinfo) << 24)),uu->uu_ubinfo,bp);
else
BUFQ_INSERT_TAIL(&sc->sc_bufq, bp)
if (sc->sc_inq == 0) {
err = bus_dmamap_load(sc->sc_dmat, mxi->mxi_dmam,
bp->b_un.b_addr,
bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT);
if (err == 0) {
mscp_dgo(sc->sc_softc, mxi);
return;
}
}
return 0;
uu = malloc(sizeof(struct uba_unit), M_DEVBUF, M_NOWAIT);
if (uu == 0)
panic("udago: no mem");
uu->uu_ready = udaready;
uu->uu_softc = sc;
uu->uu_ref = mxi;
uba_enqueue(uu);
sc->sc_inq++;
}
/*
* Called if we have been blocked for resources, and resources
* have been freed again. Return 1 if we could start all
* transfers again, 0 if we still are waiting.
* Called from uba resource free routines.
*/
int
udaready(uu)
struct uba_unit *uu;
{
struct uda_softc *sc = uu->uu_softc;
struct buf *bp;
struct mscp_xi *mxi = uu->uu_ref;
struct buf *bp = mxi->mxi_bp;
int err;
while ((bp = sc->sc_bufq.sqh_first)) {
if (ubaqueue(uu, bp)) {
BUFQ_REMOVE_HEAD(&sc->sc_bufq, bp);
mscp_dgo(sc->sc_softc, (UBAI_ADDR(uu->uu_ubinfo) |
(UBAI_BDP(uu->uu_ubinfo) << 24)),uu->uu_ubinfo,bp);
} else
return 0;
}
err = bus_dmamap_load(sc->sc_dmat, mxi->mxi_dmam, bp->b_un.b_addr,
bp->b_bcount, bp->b_proc, BUS_DMA_NOWAIT);
if (err)
return 0;
mscp_dgo(sc->sc_softc, mxi);
sc->sc_inq--;
free(uu, M_DEVBUF);
return 1;
}
@ -387,7 +408,7 @@ udasaerror(usc, doreset)
int doreset;
{
struct uda_softc *sc = (void *)usc;
register int code = sc->sc_udadev->udasa;
register int code = bus_space_read_2(sc->sc_iot, sc->sc_sah, 0);
register struct saerr *e;
if ((code & MP_ERR) == 0)
@ -429,30 +450,28 @@ static void
intr(sc)
struct uda_softc *sc;
{
volatile struct udadevice *udaddr = sc->sc_udadev;
struct uba_softc *uh;
struct mscp_pack *ud;
#ifdef QBA
if(vax_cputype == VAX_TYP_UV2)
splx(sc->sc_ipl); /* Qbus interrupt protocol is odd */
#endif
sc->sc_wticks = 0; /* reset interrupt watchdog */
if (udaddr->udasa & MP_ERR) { /* ctlr fatal error */
/* ctlr fatal error */
if (bus_space_read_2(sc->sc_iot, sc->sc_sah, 0) & MP_ERR) {
udasaerror(&sc->sc_dev, 1);
return;
}
ud = &sc->sc_uda;
/*
* Handle buffer purge requests.
* XXX - should be done in bus_dma_sync().
*/
uh = (void *)sc->sc_dev.dv_parent;
if (ud->mp_ca.ca_bdp) {
if (uh->uh_ubapurge)
(*uh->uh_ubapurge)(uh, ud->mp_ca.ca_bdp);
ud->mp_ca.ca_bdp = 0;
udaddr->udasa = 0; /* signal purge complete */
/* signal purge complete */
bus_space_write_2(sc->sc_iot, sc->sc_sah, 0, 0);
}
mscp_intr(sc->sc_softc);
@ -488,11 +507,9 @@ reset(sc)
* UDA50 is not yet initialised.
*/
if (sc->sc_unit.uu_bdp) {
printf("<%d>", UBAI_BDP(sc->sc_unit.uu_bdp));
/* printf("<%d>", UBAI_BDP(sc->sc_unit.uu_bdp)); */
sc->sc_unit.uu_bdp = 0;
}
sc->sc_unit.uu_ubinfo = 0;
/* sc->sc_unit.uu_cmd = 0; XXX */
/* reset queues and requeue pending transfers */
mscp_requeue(sc->sc_softc);
@ -508,13 +525,10 @@ reset(sc)
}
void
udactlrdone(usc, info)
udactlrdone(usc)
struct device *usc;
int info;
{
struct uda_softc *sc = (void *)usc;
/* XXX check if we shall release the BDP */
sc->sc_unit.uu_ubinfo = info;
ubadone(&sc->sc_unit);
uba_done((struct uba_softc *)sc->sc_dev.dv_parent);
}