Try to avoid zstty hangs on higher speed:

z8530sc.c:
 Check pending interrupts in a loop until all requests are handled.
 The old comments said it would cause horrible latency to sun3x floppy etc,
 but serial ports should have higher priority than disks anyway.

z8530tty.c:
 Don't enable and disable TX interrupts on each transmit start and completion
 because it could cause possible race conditions.
 Instead, set ZSWR0_RESET_TXINT on each TIE interrupt to clear the request
 as other kbd drivers attached at zs(4).

Tested on cobalt, macppc, news68k, sparc, and sun3.
This commit is contained in:
tsutsui 2009-03-20 16:28:57 +00:00
parent cc420b6c04
commit 3c5f553e65
2 changed files with 51 additions and 52 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: z8530sc.c,v 1.28 2008/03/29 19:15:36 tsutsui Exp $ */
/* $NetBSD: z8530sc.c,v 1.29 2009/03/20 16:28:57 tsutsui Exp $ */
/*
* Copyright (c) 1992, 1993
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: z8530sc.c,v 1.28 2008/03/29 19:15:36 tsutsui Exp $");
__KERNEL_RCSID(0, "$NetBSD: z8530sc.c,v 1.29 2009/03/20 16:28:57 tsutsui Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -289,55 +289,65 @@ int
zsc_intr_hard(void *arg)
{
struct zsc_softc *zsc = arg;
struct zs_chanstate *cs;
struct zs_chanstate *cs0, *cs1;
int handled;
uint8_t rr3;
/* First look at channel A. */
cs = zsc->zsc_cs[0];
handled = 0;
/* Lock both channels */
mutex_spin_enter(&cs->cs_lock);
mutex_spin_enter(&zsc->zsc_cs[1]->cs_lock);
/* Note: only channel A has an RR3 */
rr3 = zs_read_reg(cs, 3);
/* First look at channel A. */
cs0 = zsc->zsc_cs[0];
cs1 = zsc->zsc_cs[1];
/*
* Clear interrupt first to avoid a race condition.
* If a new interrupt condition happens while we are
* servicing this one, we will get another interrupt
* shortly. We can NOT just sit here in a loop, or
* we will cause horrible latency for other devices
* on this interrupt level (i.e. sun3x floppy disk).
* We have to clear interrupt first to avoid a race condition,
* but it will be done in each MD handler.
*/
if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) {
zs_write_csr(cs, ZSWR0_CLR_INTR);
for (;;) {
/* Lock both channels */
mutex_spin_enter(&cs1->cs_lock);
mutex_spin_enter(&cs0->cs_lock);
/* Note: only channel A has an RR3 */
rr3 = zs_read_reg(cs0, 3);
if ((rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT |
ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) == 0) {
mutex_spin_exit(&cs0->cs_lock);
mutex_spin_exit(&cs1->cs_lock);
break;
}
handled = 1;
/* First look at channel A. */
if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT))
zs_write_csr(cs0, ZSWR0_CLR_INTR);
if (rr3 & ZSRR3_IP_A_RX)
(*cs->cs_ops->zsop_rxint)(cs);
(*cs0->cs_ops->zsop_rxint)(cs0);
if (rr3 & ZSRR3_IP_A_STAT)
(*cs->cs_ops->zsop_stint)(cs, 0);
(*cs0->cs_ops->zsop_stint)(cs0, 0);
if (rr3 & ZSRR3_IP_A_TX)
(*cs->cs_ops->zsop_txint)(cs);
}
(*cs0->cs_ops->zsop_txint)(cs0);
/* Done with channel A */
mutex_spin_exit(&cs->cs_lock);
/* Done with channel A */
mutex_spin_exit(&cs0->cs_lock);
/* Now look at channel B. */
if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT))
zs_write_csr(cs1, ZSWR0_CLR_INTR);
/* Now look at channel B. */
cs = zsc->zsc_cs[1];
if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) {
zs_write_csr(cs, ZSWR0_CLR_INTR);
if (rr3 & ZSRR3_IP_B_RX)
(*cs->cs_ops->zsop_rxint)(cs);
(*cs1->cs_ops->zsop_rxint)(cs1);
if (rr3 & ZSRR3_IP_B_STAT)
(*cs->cs_ops->zsop_stint)(cs, 0);
(*cs1->cs_ops->zsop_stint)(cs1, 0);
if (rr3 & ZSRR3_IP_B_TX)
(*cs->cs_ops->zsop_txint)(cs);
}
(*cs1->cs_ops->zsop_txint)(cs1);
mutex_spin_exit(&cs->cs_lock);
mutex_spin_exit(&cs1->cs_lock);
}
/* Note: caller will check cs_x->cs_softreq and DTRT. */
return (rr3);
return handled;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: z8530tty.c,v 1.123 2008/04/21 12:56:31 ad Exp $ */
/* $NetBSD: z8530tty.c,v 1.124 2009/03/20 16:28:57 tsutsui Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999
@ -137,7 +137,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: z8530tty.c,v 1.123 2008/04/21 12:56:31 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: z8530tty.c,v 1.124 2009/03/20 16:28:57 tsutsui Exp $");
#include "opt_kgdb.h"
#include "opt_ntp.h"
@ -439,7 +439,7 @@ zstty_attach(device_t parent, device_t self, void *aux)
* but we must make sure status interrupts are turned on by
* the time zsparam() reads the initial rr0 state.
*/
SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
/* Make sure zsparam will see changes. */
tp->t_ospeed = 0;
@ -511,7 +511,7 @@ zs_shutdown(struct zstty_softc *zst)
/* Turn off interrupts if not the console. */
if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) {
CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
cs->cs_creg[1] = cs->cs_preg[1];
zs_write_reg(cs, 1, cs->cs_creg[1]);
}
@ -597,7 +597,7 @@ zsopen(dev_t dev, int flags, int mode, struct lwp *l)
* but we must make sure status interrupts are turned on by
* the time zsparam() reads the initial rr0 state.
*/
SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE);
SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE);
/* Clear PPS capture state on first open. */
mutex_spin_enter(&timecounter_lock);
@ -915,13 +915,6 @@ zsstart(struct tty *tp)
}
#endif
/* Enable transmit completion interrupts if necessary. */
if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
SET(cs->cs_preg[1], ZSWR1_TIE);
cs->cs_creg[1] = cs->cs_preg[1];
zs_write_reg(cs, 1, cs->cs_creg[1]);
}
/* Output the first character of the contiguous buffer. */
zs_write_data(cs, *zst->zst_tba);
zst->zst_tbc--;
@ -1424,6 +1417,8 @@ zstty_txint(struct zs_chanstate *cs)
{
struct zstty_softc *zst = cs->cs_private;
zs_write_csr(cs, ZSWR0_RESET_TXINT);
/*
* If we've delayed a parameter change, do it now, and restart
* output.
@ -1441,12 +1436,6 @@ zstty_txint(struct zs_chanstate *cs)
zst->zst_tbc--;
zst->zst_tba++;
} else {
/* Disable transmit completion interrupts if necessary. */
if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) {
CLR(cs->cs_preg[1], ZSWR1_TIE);
cs->cs_creg[1] = cs->cs_preg[1];
zs_write_reg(cs, 1, cs->cs_creg[1]);
}
if (zst->zst_tx_busy) {
zst->zst_tx_busy = 0;
zst->zst_tx_done = 1;