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:
parent
cc420b6c04
commit
3c5f553e65
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user