Subject: DHU driver fixups
To: None <port-vax@netbsd.org>
From: Hugh Graham <hugh@openbsd.org>
List: port-vax
Date: 04/05/2003 20:16:16
I recently purchased a CXA16 card, found the dhu.c driver to be in
pretty bad condition, and figured you all might be interested in my
efforts to fix it up somewhat.
This diff is against OpenBSD's tree, so it will likely require some
minor tweaking to apply on NetBSD, but the basic effects are:
Comment at line 58 is disproved by a CXY08 in DHU mode,
so use the state of the "modem low" bit to make a better
guess about how many lines we have. Will still be incorrect
for a CXA16 in DHV mode, but without a "real" DHV11 to
compare with I'll leave it alone.
Transmit interrupt handler at line 300 was servicing at
most one "action report" per interrupt and could get behind
when under load. Eventually the device would stop generating
transmit interrupts and deadlock, so take care to service
all reports as soon as we can.
Clause at line 381 enables the "recieve interrupt timer"
available on true DHU models and sets it to 10ms. This allows
roughly 50 characters to accumulate in the fifo per interrupt
at 38400 baud, rather than 1:1, reducing the resource usage
considerably.
The check for DHV11 at line 630 seems to fix the biggest
problem with the existing driver. It appears that the DHU11
device doesn't have a TXCHAR register (it's the receive
interrupt timer on this model), and the attempt to write there
would deadlock the driver because no interrupt would result.
The check just avoids doing single character output on DHU11.
With these fixes, I'm able to use my CXA16 in DHU mode and run looped
back transfers at 38400 baud on 8 lines (all the MMJ cables I have)
without data loss or performance degredation.
I hope it works as well for you.
/Hugh
PS: I'm interested in looking at the onboard "DHW" serial IO adaptors
for the MicroVAX class machines. If you have a spare card, back panel
connector, cables and any necessary peripherals for a VAX 4000 100
machine you can donate to me (in Canada), please get in touch.
Index: dhu.c
===================================================================
RCS file: /cvs/src/sys/arch/vax/qbus/dhu.c,v
retrieving revision 1.5
retrieving revision 1.9
diff -u -r1.5 -r1.9
--- dhu.c 2002/10/19 22:40:44 1.5
+++ dhu.c 2003/04/06 01:34:56 1.9
@@ -1,6 +1,7 @@
-/* $OpenBSD: dhu.c,v 1.5 2002/10/19 22:40:44 hugh Exp $ */
+/* $OpenBSD: dhu.c,v 1.9 2003/04/06 01:34:56 hugh Exp $ */
/* $NetBSD: dhu.c,v 1.19 2000/06/04 06:17:01 matt Exp $ */
/*
+ * Copyright (c) 2003, Hugh Graham.
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -56,8 +57,6 @@
#include <arch/vax/qbus/ubavar.h>
#include <arch/vax/qbus/dhureg.h>
-/* A DHU-11 has 16 ports while a DHV-11 has only 8. We use 16 by default */
-
#define NDHULINE 16
#define DHU_M2U(c) ((c)>>4) /* convert minor(dev) to unit # */
@@ -68,6 +67,7 @@
struct evcnt sc_rintrcnt; /* Interrupt statistics */
struct evcnt sc_tintrcnt; /* Interrupt statistics */
int sc_type; /* controller type, DHU or DHV */
+ int sc_lines; /* number of lines */
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
@@ -230,11 +230,21 @@
}
c = DHU_READ_WORD(DHU_UBA_STAT);
+
+ sc->sc_type = (c & DHU_STAT_DHU) ? IS_DHU : IS_DHV;
- 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");
+ if (sc->sc_type == IS_DHU) {
+ if (c & DHU_STAT_MDL)
+ sc->sc_lines = 16; /* "Modem Low" */
+ else
+ sc->sc_lines = 8; /* Has modem support */
+ } else
+ sc->sc_lines = 8;
- for (i = 0; i < sc->sc_type; i++) {
+ printf("\n%s: DH%s-11 %d lines\n", self->dv_xname,
+ (sc->sc_type == IS_DHU) ? "U" : "V", sc->sc_lines);
+
+ for (i = 0; i < sc->sc_lines; i++) {
struct tty *tp;
tp = sc->sc_dhu[i].dhu_tty = ttymalloc();
sc->sc_dhu[i].dhu_state = STATE_IDLE;
@@ -289,8 +299,8 @@
(void)(*linesw[tp->t_line].l_modem)(tp, 1);
}
else if ((tp->t_state & TS_CARR_ON) &&
- (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
- (void) dhumctl(sc, line, 0, DMSET);
+ (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
+ (void) dhumctl(sc, line, 0, DMSET);
/* Do CRTSCTS flow control */
delta = c ^ sc->sc_dhu[line].dhu_modem;
@@ -337,29 +347,41 @@
{
struct dhu_softc *sc = arg;
struct tty *tp;
- int line;
+ int line, i;
- line = DHU_LINE(DHU_READ_BYTE(DHU_UBA_CSR_HI));
+ while ((i = DHU_READ_BYTE(DHU_UBA_CSR_HI)) & (DHU_CSR_TX_ACTION >> 8)) {
- tp = sc->sc_dhu[line].dhu_tty;
+ line = DHU_LINE(i);
- tp->t_state &= ~TS_BUSY;
- if (tp->t_state & TS_FLUSH)
- tp->t_state &= ~TS_FLUSH;
- else {
- if (sc->sc_dhu[line].dhu_state == STATE_DMA_STOPPED)
- sc->sc_dhu[line].dhu_cc -=
- DHU_READ_WORD(DHU_UBA_TBUFCNT);
- ndflush(&tp->t_outq, sc->sc_dhu[line].dhu_cc);
- sc->sc_dhu[line].dhu_cc = 0;
- }
+ tp = sc->sc_dhu[line].dhu_tty;
- sc->sc_dhu[line].dhu_state = STATE_IDLE;
+ if (i & (DHU_CSR_TX_DMA_ERROR >> 8))
+ printf("dhu%d: DMA ERROR on line: %d\n",
+ DHU_M2U(minor(tp->t_dev)), line);
+
+ if (i & (DHU_CSR_DIAG_FAIL >> 8))
+ printf("dhu%d: DIAG FAIL on line: %d\n",
+ DHU_M2U(minor(tp->t_dev)), line);
+
+ tp->t_state &= ~TS_BUSY;
+
+ if (tp->t_state & TS_FLUSH)
+ tp->t_state &= ~TS_FLUSH;
+ else {
+ if (sc->sc_dhu[line].dhu_state == STATE_DMA_STOPPED)
+ sc->sc_dhu[line].dhu_cc -=
+ DHU_READ_WORD(DHU_UBA_TBUFCNT);
+ ndflush(&tp->t_outq, sc->sc_dhu[line].dhu_cc);
+ sc->sc_dhu[line].dhu_cc = 0;
+ }
- if (tp->t_line)
- (*linesw[tp->t_line].l_start)(tp);
- else
- dhustart(tp);
+ sc->sc_dhu[line].dhu_state = STATE_IDLE;
+
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ dhustart(tp);
+ }
}
int
@@ -381,9 +403,16 @@
sc = dhu_cd.cd_devs[unit];
- if (line >= sc->sc_type)
+ if (line >= sc->sc_lines)
return ENXIO;
+ if (sc->sc_type == IS_DHU) {
+ s = spltty(); /* CSR 3:0 must be 0 */
+ DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE);
+ DHU_WRITE_BYTE(DHU_UBA_RXTIME, 10);
+ splx(s); /* RX int delay 10ms */
+ }
+
s = spltty();
DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT);
@@ -605,6 +634,7 @@
int s;
s = spltty();
+
if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
goto out;
if (tp->t_outq.c_cc <= tp->t_lowat) {
@@ -630,15 +660,13 @@
sc->sc_dhu[line].dhu_cc = cc;
- if (cc == 1) {
+ if (cc == 1 && sc->sc_type == IS_DHV) {
sc->sc_dhu[line].dhu_state = STATE_TX_ONE_CHAR;
DHU_WRITE_WORD(DHU_UBA_TXCHAR,
DHU_TXCHAR_DATA_VALID | *tp->t_outq.c_cf);
-
} else {
-
sc->sc_dhu[line].dhu_state = STATE_DMA_RUNNING;
addr = sc->sc_dhu[line].dhu_dmah->dm_segs[0].ds_addr +
Index: dhureg.h
===================================================================
RCS file: /cvs/src/sys/arch/vax/qbus/dhureg.h,v
retrieving revision 1.1
retrieving revision 1.4
diff -u -r1.1 -r1.4
--- dhureg.h 2000/04/27 03:14:47 1.1
+++ dhureg.h 2003/04/06 01:33:32 1.4
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhureg.h,v 1.1 2000/04/27 03:14:47 bjc Exp $ */
+/* $OpenBSD: dhureg.h,v 1.4 2003/04/06 01:33:32 hugh Exp $ */
/* $NetBSD: dhureg.h,v 1.4 1999/05/28 20:17:29 ragge Exp $ */
/*
* Copyright (c) 1996 Ken C. Wellsch. All rights reserved.
@@ -66,8 +66,10 @@
#define DHU_UBA_CSR_HI 1
#define DHU_UBA_RBUF 2
#define DHU_UBA_TXCHAR 2
+#define DHU_UBA_RXTIME DHU_UBA_TXCHAR /* on a real dhu only */
#define DHU_UBA_LPR 4
#define DHU_UBA_STAT 6
+#define DHU_UBA_FIFO DHU_UBA_STAT /* on a real dhu only */
#define DHU_UBA_LNCTRL 8
#define DHU_UBA_TBUFAD1 10
#define DHU_UBA_TBUFAD2 12
@@ -134,6 +136,7 @@
#define DHU_STAT_RI 0020000
#define DHU_STAT_DCD 0010000
#define DHU_STAT_CTS 0004000
+#define DHU_STAT_MDL 0001000
#define DHU_STAT_DHU 0000400
/* LNCTRL bits */