Esempio n. 1
0
/*
 * Turn power on or off to the SCC and associated stuff
 * (port drivers, modem, IR port, etc.)
 * Returns the number of milliseconds we should wait before
 * trying to use the port.
 */
static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
{
	int delay = 0;
	int rc;

	if (state) {
		rc = pmac_call_feature(
			PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 1);
		pmz_debug("port power on result: %d\n", rc);
		if (ZS_IS_INTMODEM(uap)) {
			rc = pmac_call_feature(
				PMAC_FTR_MODEM_ENABLE, uap->node, 0, 1);
			delay = 2500;	/* wait for 2.5s before using */
			pmz_debug("modem power result: %d\n", rc);
		}
	} else {
		/* TODO: Make that depend on a timer, don't power down
		 * immediately
		 */
		if (ZS_IS_INTMODEM(uap)) {
			rc = pmac_call_feature(
				PMAC_FTR_MODEM_ENABLE, uap->node, 0, 0);
			pmz_debug("port power off result: %d\n", rc);
		}
		pmac_call_feature(PMAC_FTR_SCC_ENABLE, uap->node, uap->port_type, 0);
	}
	return delay;
}
Esempio n. 2
0
static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
{
	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
	struct uart_state *state;
	unsigned long flags;

	if (uap == NULL) {
		printk("HRM... pmz_suspend with NULL uap\n");
		return 0;
	}

	if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
		return 0;

	pmz_debug("suspend, switching to state %d\n", pm_state);

	state = pmz_uart_reg.state + uap->port.line;

	mutex_lock(&pmz_irq_mutex);
	mutex_lock(&state->mutex);

	spin_lock_irqsave(&uap->port.lock, flags);

	if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
		/* Disable receiver and transmitter.  */
		uap->curregs[R3] &= ~RxENABLE;
		uap->curregs[R5] &= ~TxENABLE;

		/* Disable all interrupts and BRK assertion.  */
		uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
		uap->curregs[R5] &= ~SND_BRK;
		pmz_load_zsregs(uap, uap->curregs);
		uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
		mb();
	}

	spin_unlock_irqrestore(&uap->port.lock, flags);

	if (ZS_IS_OPEN(uap) || ZS_IS_OPEN(uap->mate))
		if (ZS_IS_ASLEEP(uap->mate) && ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
			pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
			disable_irq(uap->port.irq);
		}

	if (ZS_IS_CONS(uap))
		uap->port.cons->flags &= ~CON_ENABLED;

	/* Shut the chip down */
	pmz_set_scc_power(uap, 0);

	mutex_unlock(&state->mutex);
	mutex_unlock(&pmz_irq_mutex);

	pmz_debug("suspend, switching complete\n");

	mdev->ofdev.dev.power.power_state = pm_state;

	return 0;
}
Esempio n. 3
0
static void pmz_shutdown(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned long flags;

	pmz_debug("pmz: shutdown()\n");

	if (uap->node == NULL)
		return;

	mutex_lock(&pmz_irq_mutex);

	/* Release interrupt handler */
       	free_irq(uap->port.irq, uap);

	spin_lock_irqsave(&port->lock, flags);

	uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;

	if (!ZS_IS_OPEN(uap->mate))
		pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;

	/* Disable interrupts */
	if (!ZS_IS_ASLEEP(uap)) {
		uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
		write_zsreg(uap, R1, uap->curregs[R1]);
		zssync(uap);
	}

	if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
		spin_unlock_irqrestore(&port->lock, flags);
		mutex_unlock(&pmz_irq_mutex);
		return;
	}

	/* Disable receiver and transmitter.  */
	uap->curregs[R3] &= ~RxENABLE;
	uap->curregs[R5] &= ~TxENABLE;

	/* Disable all interrupts and BRK assertion.  */
	uap->curregs[R5] &= ~SND_BRK;
	pmz_maybe_update_regs(uap);

	/* Shut the chip down */
	pmz_set_scc_power(uap, 0);

	spin_unlock_irqrestore(&port->lock, flags);

	mutex_unlock(&pmz_irq_mutex);

	pmz_debug("pmz: shutdown() done.\n");
}
Esempio n. 4
0
static void __pmz_set_termios(struct uart_port *port, struct ktermios *termios,
			      struct ktermios *old)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned long baud;

	pmz_debug("pmz: set_termios()\n");

	if (ZS_IS_ASLEEP(uap))
		return;

	memcpy(&uap->termios_cache, termios, sizeof(struct ktermios));

	/* XXX Check which revs of machines actually allow 1 and 4Mb speeds
	 * on the IR dongle. Note that the IRTTY driver currently doesn't know
	 * about the FIR mode and high speed modes. So these are unused. For
	 * implementing proper support for these, we should probably add some
	 * DMA as well, at least on the Rx side, which isn't a simple thing
	 * at this point.
	 */
	if (ZS_IS_IRDA(uap)) {
		/* Calc baud rate */
		baud = uart_get_baud_rate(port, termios, old, 1200, 4000000);
		pmz_debug("pmz: switch IRDA to %ld bauds\n", baud);
		/* Cet the irda codec to the right rate */
		pmz_irda_setup(uap, &baud);
		/* Set final baud rate */
		pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
		pmz_load_zsregs(uap, uap->curregs);
		zssync(uap);
	} else {
		baud = uart_get_baud_rate(port, termios, old, 1200, 230400);
		pmz_convert_to_zs(uap, termios->c_cflag, termios->c_iflag, baud);
		/* Make sure modem status interrupts are correctly configured */
		if (UART_ENABLE_MS(&uap->port, termios->c_cflag)) {
			uap->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
			uap->flags |= PMACZILOG_FLAG_MODEM_STATUS;
		} else {
			uap->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
			uap->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
		}

		/* Load registers to the chip */
		pmz_maybe_update_regs(uap);
	}
	uart_update_timeout(port, termios->c_cflag, baud);

	pmz_debug("pmz: set_termios() done.\n");
}
Esempio n. 5
0
/* 
 * Stop Rx side, basically disable emitting of
 * Rx interrupts on the port. We don't disable the rx
 * side of the chip proper though
 * The port lock is held.
 */
static void pmz_stop_rx(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);

	if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
		return;

	pmz_debug("pmz: stop_rx()()\n");

	/* Disable all RX interrupts.  */
	uap->curregs[R1] &= ~RxINT_MASK;
	pmz_maybe_update_regs(uap);

	pmz_debug("pmz: stop_rx() done.\n");
}
Esempio n. 6
0
/* 
 * We do like sunzilog to avoid disrupting pending Tx
 * Reprogram the Zilog channel HW registers with the copies found in the
 * software state struct.  If the transmitter is busy, we defer this update
 * until the next TX complete interrupt.  Else, we do it right now.
 *
 * The UART port lock must be held and local interrupts disabled.
 */
static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
{
       	if (!ZS_REGS_HELD(uap)) {
		if (ZS_TX_ACTIVE(uap)) {
			uap->flags |= PMACZILOG_FLAG_REGS_HELD;
		} else {
			pmz_debug("pmz: maybe_update_regs: updating\n");
			pmz_load_zsregs(uap, uap->curregs);
		}
	}
}
Esempio n. 7
0
/* 
 * Kick the Tx side.
 * The port lock is held and interrupts are disabled.
 */
static void pmz_start_tx(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned char status;

	pmz_debug("pmz: start_tx()\n");

	uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
	uap->flags &= ~PMACZILOG_FLAG_TX_STOPPED;

	if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
		return;

	status = read_zsreg(uap, R0);

	/* TX busy?  Just wait for the TX done interrupt.  */
	if (!(status & Tx_BUF_EMP))
		return;

	/* Send the first character to jump-start the TX done
	 * IRQ sending engine.
	 */
	if (port->x_char) {
		write_zsdata(uap, port->x_char);
		zssync(uap);
		port->icount.tx++;
		port->x_char = 0;
	} else {
		struct circ_buf *xmit = &port->info->xmit;

		write_zsdata(uap, xmit->buf[xmit->tail]);
		zssync(uap);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		port->icount.tx++;

		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
			uart_write_wakeup(&uap->port);
	}
	pmz_debug("pmz: start_tx() done.\n");
}
Esempio n. 8
0
/* 
 * Set Modem Control (RTS & DTR) bits
 * The port lock is held and interrupts are disabled.
 * Note: Shall we really filter out RTS on external ports or
 * should that be dealt at higher level only ?
 */
static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned char set_bits, clear_bits;

        /* Do nothing for irda for now... */
	if (ZS_IS_IRDA(uap))
		return;
	/* We get called during boot with a port not up yet */
	if (ZS_IS_ASLEEP(uap) ||
	    !(ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)))
		return;

	set_bits = clear_bits = 0;

	if (ZS_IS_INTMODEM(uap)) {
		if (mctrl & TIOCM_RTS)
			set_bits |= RTS;
		else
			clear_bits |= RTS;
	}
	if (mctrl & TIOCM_DTR)
		set_bits |= DTR;
	else
		clear_bits |= DTR;

	/* NOTE: Not subject to 'transmitter active' rule.  */ 
	uap->curregs[R5] |= set_bits;
	uap->curregs[R5] &= ~clear_bits;
	if (ZS_IS_ASLEEP(uap))
		return;
	write_zsreg(uap, R5, uap->curregs[R5]);
	pmz_debug("pmz_set_mctrl: set bits: %x, clear bits: %x -> %x\n",
		  set_bits, clear_bits, uap->curregs[R5]);
	zssync(uap);
}
Esempio n. 9
0
/*
 * This is the "normal" startup routine, using the above one
 * wrapped with the lock and doing a schedule delay
 */
static int pmz_startup(struct uart_port *port)
{
	struct uart_pmac_port *uap = to_pmz(port);
	unsigned long flags;
	int pwr_delay = 0;

	pmz_debug("pmz: startup()\n");

	if (ZS_IS_ASLEEP(uap))
		return -EAGAIN;
	if (uap->node == NULL)
		return -ENODEV;

	mutex_lock(&pmz_irq_mutex);

	uap->flags |= PMACZILOG_FLAG_IS_OPEN;

	/* A console is never powered down. Else, power up and
	 * initialize the chip
	 */
	if (!ZS_IS_CONS(uap)) {
		spin_lock_irqsave(&port->lock, flags);
		pwr_delay = __pmz_startup(uap);
		spin_unlock_irqrestore(&port->lock, flags);
	}	

	pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
	if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
		dev_err(&uap->dev->ofdev.dev,
			"Unable to register zs interrupt handler.\n");
		pmz_set_scc_power(uap, 0);
		mutex_unlock(&pmz_irq_mutex);
		return -ENXIO;
	}

	mutex_unlock(&pmz_irq_mutex);

	/* Right now, we deal with delay by blocking here, I'll be
	 * smarter later on
	 */
	if (pwr_delay != 0) {
		pmz_debug("pmz: delaying %d ms\n", pwr_delay);
		msleep(pwr_delay);
	}

	/* IrDA reset is done now */
	if (ZS_IS_IRDA(uap))
		pmz_irda_reset(uap);

	/* Enable interrupts emission from the chip */
	spin_lock_irqsave(&port->lock, flags);
	uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
	if (!ZS_IS_EXTCLK(uap))
		uap->curregs[R1] |= EXT_INT_ENAB;
	write_zsreg(uap, R1, uap->curregs[R1]);
       	spin_unlock_irqrestore(&port->lock, flags);

	pmz_debug("pmz: startup() done.\n");

	return 0;
}
Esempio n. 10
0
/* Hrm... we register that twice, fixme later.... */
static irqreturn_t pmz_interrupt(int irq, void *dev_id)
{
	struct uart_pmac_port *uap = dev_id;
	struct uart_pmac_port *uap_a;
	struct uart_pmac_port *uap_b;
	int rc = IRQ_NONE;
	struct tty_struct *tty;
	u8 r3;

	uap_a = pmz_get_port_A(uap);
	uap_b = uap_a->mate;
       
       	spin_lock(&uap_a->port.lock);
	r3 = read_zsreg(uap_a, R3);

#ifdef DEBUG_HARD
	pmz_debug("irq, r3: %x\n", r3);
#endif
       	/* Channel A */
	tty = NULL;
       	if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
		write_zsreg(uap_a, R0, RES_H_IUS);
		zssync(uap_a);		
       		if (r3 & CHAEXT)
       			pmz_status_handle(uap_a);
		if (r3 & CHARxIP)
			tty = pmz_receive_chars(uap_a);
       		if (r3 & CHATxIP)
       			pmz_transmit_chars(uap_a);
	        rc = IRQ_HANDLED;
       	}
       	spin_unlock(&uap_a->port.lock);
	if (tty != NULL)
		tty_flip_buffer_push(tty);

	if (uap_b->node == NULL)
		goto out;

       	spin_lock(&uap_b->port.lock);
	tty = NULL;
	if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
		write_zsreg(uap_b, R0, RES_H_IUS);
		zssync(uap_b);
       		if (r3 & CHBEXT)
       			pmz_status_handle(uap_b);
       	       	if (r3 & CHBRxIP)
       			tty = pmz_receive_chars(uap_b);
       		if (r3 & CHBTxIP)
       			pmz_transmit_chars(uap_b);
	       	rc = IRQ_HANDLED;
       	}
       	spin_unlock(&uap_b->port.lock);
	if (tty != NULL)
		tty_flip_buffer_push(tty);

 out:
#ifdef DEBUG_HARD
	pmz_debug("irq done.\n");
#endif
	return rc;
}
Esempio n. 11
0
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
	struct tty_struct *tty = NULL;
	unsigned char ch, r1, drop, error, flag;
	int loops = 0;

	/* The interrupt can be enabled when the port isn't open, typically
	 * that happens when using one port is open and the other closed (stale
	 * interrupt) or when one port is used as a console.
	 */
	if (!ZS_IS_OPEN(uap)) {
		pmz_debug("pmz: draining input\n");
		/* Port is closed, drain input data */
		for (;;) {
			if ((++loops) > 1000)
				goto flood;
			(void)read_zsreg(uap, R1);
			write_zsreg(uap, R0, ERR_RES);
			(void)read_zsdata(uap);
			ch = read_zsreg(uap, R0);
			if (!(ch & Rx_CH_AV))
				break;
		}
		return NULL;
	}

	/* Sanity check, make sure the old bug is no longer happening */
	if (uap->port.info == NULL || uap->port.info->tty == NULL) {
		WARN_ON(1);
		(void)read_zsdata(uap);
		return NULL;
	}
	tty = uap->port.info->tty;

	while (1) {
		error = 0;
		drop = 0;

		r1 = read_zsreg(uap, R1);
		ch = read_zsdata(uap);

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			write_zsreg(uap, R0, ERR_RES);
			zssync(uap);
		}

		ch &= uap->parity_mask;
		if (ch == 0 && uap->flags & PMACZILOG_FLAG_BREAK) {
			uap->flags &= ~PMACZILOG_FLAG_BREAK;
		}

#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_SERIAL_CORE_CONSOLE)
#ifdef USE_CTRL_O_SYSRQ
		/* Handle the SysRq ^O Hack */
		if (ch == '\x0f') {
			uap->port.sysrq = jiffies + HZ*5;
			goto next_char;
		}
#endif /* USE_CTRL_O_SYSRQ */
		if (uap->port.sysrq) {
			int swallow;
			spin_unlock(&uap->port.lock);
			swallow = uart_handle_sysrq_char(&uap->port, ch);
			spin_lock(&uap->port.lock);
			if (swallow)
				goto next_char;
 		}
#endif /* CONFIG_MAGIC_SYSRQ && CONFIG_SERIAL_CORE_CONSOLE */

		/* A real serial line, record the character and status.  */
		if (drop)
			goto next_char;

		flag = TTY_NORMAL;
		uap->port.icount.rx++;

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
			error = 1;
			if (r1 & BRK_ABRT) {
				pmz_debug("pmz: got break !\n");
				r1 &= ~(PAR_ERR | CRC_ERR);
				uap->port.icount.brk++;
				if (uart_handle_break(&uap->port))
					goto next_char;
			}
			else if (r1 & PAR_ERR)
				uap->port.icount.parity++;
			else if (r1 & CRC_ERR)
				uap->port.icount.frame++;
			if (r1 & Rx_OVR)
				uap->port.icount.overrun++;
			r1 &= uap->port.read_status_mask;
			if (r1 & BRK_ABRT)
				flag = TTY_BREAK;
			else if (r1 & PAR_ERR)
				flag = TTY_PARITY;
			else if (r1 & CRC_ERR)
				flag = TTY_FRAME;
		}

		if (uap->port.ignore_status_mask == 0xff ||
		    (r1 & uap->port.ignore_status_mask) == 0) {
		    	tty_insert_flip_char(tty, ch, flag);
		}
		if (r1 & Rx_OVR)
			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
	next_char:
		/* We can get stuck in an infinite loop getting char 0 when the
		 * line is in a wrong HW state, we break that here.
		 * When that happens, I disable the receive side of the driver.
		 * Note that what I've been experiencing is a real irq loop where
		 * I'm getting flooded regardless of the actual port speed.
		 * Something stange is going on with the HW
		 */
		if ((++loops) > 1000)
			goto flood;
		ch = read_zsreg(uap, R0);
		if (!(ch & Rx_CH_AV))
			break;
	}

	return tty;
 flood:
	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
	write_zsreg(uap, R1, uap->curregs[R1]);
	zssync(uap);
	dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
	return tty;
}
Esempio n. 12
0
static int pmz_resume(struct macio_dev *mdev)
{
	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
	struct uart_state *state;
	unsigned long flags;
	int pwr_delay = 0;

	if (uap == NULL)
		return 0;

	if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON)
		return 0;
	
	pmz_debug("resume, switching to state 0\n");

	state = pmz_uart_reg.state + uap->port.line;

	mutex_lock(&pmz_irq_mutex);
	mutex_lock(&state->mutex);

	spin_lock_irqsave(&uap->port.lock, flags);
	if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
		spin_unlock_irqrestore(&uap->port.lock, flags);
		goto bail;
	}
	pwr_delay = __pmz_startup(uap);

	/* Take care of config that may have changed while asleep */
	__pmz_set_termios(&uap->port, &uap->termios_cache, NULL);

	if (ZS_IS_OPEN(uap)) {
		/* Enable interrupts */		
		uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
		if (!ZS_IS_EXTCLK(uap))
			uap->curregs[R1] |= EXT_INT_ENAB;
		write_zsreg(uap, R1, uap->curregs[R1]);
	}

	spin_unlock_irqrestore(&uap->port.lock, flags);

	if (ZS_IS_CONS(uap))
		uap->port.cons->flags |= CON_ENABLED;

	/* Re-enable IRQ on the controller */
	if (ZS_IS_OPEN(uap) && !ZS_IS_IRQ_ON(pmz_get_port_A(uap))) {
		pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
		enable_irq(uap->port.irq);
	}

 bail:
	mutex_unlock(&state->mutex);
	mutex_unlock(&pmz_irq_mutex);

	/* Right now, we deal with delay by blocking here, I'll be
	 * smarter later on
	 */
	if (pwr_delay != 0) {
		pmz_debug("pmz: delaying %d ms\n", pwr_delay);
		msleep(pwr_delay);
	}

	pmz_debug("resume, switching complete\n");

	mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON;

	return 0;
}
Esempio n. 13
0
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
					    struct pt_regs *regs)
{
	struct tty_struct *tty = NULL;
	unsigned char ch, r1, drop, error;
	int loops = 0;

 retry:
	/* The interrupt can be enabled when the port isn't open, typically
	 * that happens when using one port is open and the other closed (stale
	 * interrupt) or when one port is used as a console.
	 */
	if (!ZS_IS_OPEN(uap)) {
		pmz_debug("pmz: draining input\n");
		/* Port is closed, drain input data */
		for (;;) {
			if ((++loops) > 1000)
				goto flood;
			(void)read_zsreg(uap, R1);
			write_zsreg(uap, R0, ERR_RES);
			(void)read_zsdata(uap);
			ch = read_zsreg(uap, R0);
			if (!(ch & Rx_CH_AV))
				break;
		}
		return NULL;
	}

	/* Sanity check, make sure the old bug is no longer happening */
	if (uap->port.info == NULL || uap->port.info->tty == NULL) {
		WARN_ON(1);
		(void)read_zsdata(uap);
		return NULL;
	}
	tty = uap->port.info->tty;

	while (1) {
		error = 0;
		drop = 0;

		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
			/* Have to drop the lock here */
			pmz_debug("pmz: flip overflow\n");
			spin_unlock(&uap->port.lock);
			tty->flip.work.func((void *)tty);
			spin_lock(&uap->port.lock);
			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
				drop = 1;
			if (ZS_IS_ASLEEP(uap))
				return NULL;
			if (!ZS_IS_OPEN(uap))
				goto retry;
		}

		r1 = read_zsreg(uap, R1);
		ch = read_zsdata(uap);

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
			write_zsreg(uap, R0, ERR_RES);
			zssync(uap);
		}

		ch &= uap->parity_mask;
		if (ch == 0 && uap->prev_status & BRK_ABRT)
			r1 |= BRK_ABRT;

		/* A real serial line, record the character and status.  */
		if (drop)
			goto next_char;

		*tty->flip.char_buf_ptr = ch;
		*tty->flip.flag_buf_ptr = TTY_NORMAL;
		uap->port.icount.rx++;

		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
			error = 1;
			if (r1 & BRK_ABRT) {
				pmz_debug("pmz: got break !\n");
				r1 &= ~(PAR_ERR | CRC_ERR);
				uap->port.icount.brk++;
				if (uart_handle_break(&uap->port)) {
					pmz_debug("pmz: do handle break !\n");
					goto next_char;
				}
			}
			else if (r1 & PAR_ERR)
				uap->port.icount.parity++;
			else if (r1 & CRC_ERR)
				uap->port.icount.frame++;
			if (r1 & Rx_OVR)
				uap->port.icount.overrun++;
			r1 &= uap->port.read_status_mask;
			if (r1 & BRK_ABRT)
				*tty->flip.flag_buf_ptr = TTY_BREAK;
			else if (r1 & PAR_ERR)
				*tty->flip.flag_buf_ptr = TTY_PARITY;
			else if (r1 & CRC_ERR)
				*tty->flip.flag_buf_ptr = TTY_FRAME;
		}
		if (uart_handle_sysrq_char(&uap->port, ch, regs)) {
			pmz_debug("pmz: sysrq swallowed the char\n");
			goto next_char;
		}

		if (uap->port.ignore_status_mask == 0xff ||
		    (r1 & uap->port.ignore_status_mask) == 0) {
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
		if ((r1 & Rx_OVR) &&
		    tty->flip.count < TTY_FLIPBUF_SIZE) {
			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
			tty->flip.flag_buf_ptr++;
			tty->flip.char_buf_ptr++;
			tty->flip.count++;
		}
	next_char:
		/* We can get stuck in an infinite loop getting char 0 when the
		 * line is in a wrong HW state, we break that here.
		 * When that happens, I disable the receive side of the driver.
		 * Note that what I've been experiencing is a real irq loop where
		 * I'm getting flooded regardless of the actual port speed.
		 * Something stange is going on with the HW
		 */
		if ((++loops) > 1000)
			goto flood;
		ch = read_zsreg(uap, R0);
		if (!(ch & Rx_CH_AV))
			break;
	}

	return tty;
 flood:
	uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
	write_zsreg(uap, R1, uap->curregs[R1]);
	zssync(uap);
	dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
	return tty;
}