patch-2.3.35 linux/drivers/sbus/char/zs.c

Next file: linux/drivers/sbus/char/zs.h
Previous file: linux/drivers/sbus/char/vfc_i2c.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.34/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.45 1999/09/01 08:09:35 davem Exp $
+/* $Id: zs.c,v 1.52 1999/12/15 14:29:20 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/bootmem.h>
 #include <linux/sysrq.h>
 
 #include <asm/io.h>
@@ -32,6 +33,8 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/kdebug.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
 #include <asm/sbus.h>
 #ifdef __sparc_v9__
@@ -65,8 +68,8 @@
 #else
 #define ZSDELAY()
 #define ZSDELAY_LONG()
-#define ZS_WSYNC(channel) \
-	((void) *((volatile unsigned char *)(&((channel)->control))))
+#define ZS_WSYNC(__channel) \
+	sbus_readb(&((__channel)->control))
 #endif
 
 struct sun_zslayout **zs_chips;
@@ -164,6 +167,47 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
+#undef ZS_LOG
+#ifdef ZS_LOG
+struct zs_logent {
+	u8 reg, val;
+	u8 write, __pad;
+#define REGIRQ	0xff
+#define REGDATA	0xfe
+#define REGCTRL	0xfd
+};
+struct zs_logent zslog[32];
+int zs_curlog = 0;
+#define ZSLOG(__reg, __val, __write) \
+do{	int index = zs_curlog; \
+	zslog[index].reg = (__reg); \
+	zslog[index].val = (__val); \
+	zslog[index].write = (__write); \
+	zs_curlog = (index + 1) & (32 - 1); \
+}while(0)
+int zs_dumplog(char *buffer)
+{
+	int len = 0;
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		u8 reg, val, write;
+
+		reg = zslog[i].reg;
+		val = zslog[i].val;
+		write = zslog[i].write;
+		len += sprintf(buffer + len,
+			       "ZSLOG[%2d]: reg %2x val %2x %s\n",
+			       i, reg, val, write ? "write" : "read");
+	}
+	len += sprintf(buffer + len, "ZS current log index %d\n",
+		       zs_curlog);
+	return len;
+}
+#else
+#define ZSLOG(x,y,z)	do { } while (0)
+#endif
+
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the memcpy_fromfs blocks while swapping in a page,
@@ -197,15 +241,13 @@
 	return 0;
 }
 
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
+/* This is used to figure out the divisor speeds and the timeouts. */
 static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 76800, 0 };
+	9600, 19200, 38400, 76800, 0
+};
 
-/* 
- * Reading and writing Zilog8530 registers.  The delays are to make this
+/* Reading and writing Zilog8530 registers.  The delays are to make this
  * driver work on the Sun4 which needs a settling delay after each chip
  * register access, other machines handle this in hardware via auxiliary
  * flip-flops which implement the settle time we do in software.
@@ -215,26 +257,28 @@
 {
 	unsigned char retval;
 
-	channel->control = reg;
+	sbus_writeb(reg, &channel->control);
 	ZSDELAY();
-	retval = channel->control;
+	retval = sbus_readb(&channel->control);
 	ZSDELAY();
+	ZSLOG(reg, retval, 0);
 	return retval;
 }
 
 static inline void write_zsreg(struct sun_zschannel *channel,
 			       unsigned char reg, unsigned char value)
 {
-	channel->control = reg;
+	ZSLOG(reg, value, 1);
+	sbus_writeb(reg, &channel->control);
 	ZSDELAY();
-	channel->control = value;
+	sbus_writeb(value, &channel->control);
 	ZSDELAY();
 }
 
 static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
 {
-	unsigned long flags;
 	struct sun_zschannel *channel = info->zs_channel;
+	unsigned long flags;
 	unsigned char stat;
 	int i;
 
@@ -287,12 +331,18 @@
 	 * a timed polling loop and on sparc64 ZSDELAY
 	 * is a nop.  -DaveM
 	 */
-	while((channel->control & Tx_BUF_EMP) == 0 && --loops)
+	do {
+		u8 val = sbus_readb(&channel->control);
+		ZSLOG(REGCTRL, val, 0);
+		if (val & Tx_BUF_EMP)
+			break;
 		udelay(5);
+	} while (--loops);
 
-	channel->data = ch;
+	sbus_writeb(ch, &channel->data);
 	ZSDELAY();
 	ZS_WSYNC(channel);
+	ZSLOG(REGDATA, ch, 1);
 }
 
 /* Sets or clears DTR/RTS on the requested line */
@@ -339,7 +389,7 @@
  */
 static void zs_stop(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->device, "zs_stop"))
@@ -355,7 +405,7 @@
 
 static void zs_start(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 	unsigned long flags;
 	
 	if (serial_paranoia_check(info, tty->device, "zs_start"))
@@ -374,6 +424,8 @@
  */
 void batten_down_hatches(void)
 {
+	if (!stop_a_enabled)
+		return;
 	/* If we are doing kadb, we call the debugger
 	 * else we just drop into the boot monitor.
 	 * Note that we must flush the user windows
@@ -424,7 +476,7 @@
  * processing in the software interrupt portion of the driver.
  */
 static _INLINE_ void zs_sched_event(struct sun_serial *info,
-				  int event)
+				    int event)
 {
 	info->event |= 1 << event;
 	queue_task(&info->tqueue, &tq_serial);
@@ -439,9 +491,12 @@
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat;
+	int do_queue_task = 1;
 
 	do {
-		ch = (info->zs_channel->data) & info->parity_mask;
+		ch = sbus_readb(&info->zs_channel->data);
+		ZSLOG(REGDATA, ch, 0);
+		ch &= info->parity_mask;
 		ZSDELAY();
 
 		/* If this is the console keyboard, we need to handle
@@ -466,14 +521,16 @@
 				return;
 			}
 			sunkbd_inchar(ch, regs);
-			return;
+			do_queue_task = 0;
+			goto next_char;
 		}
 		if(info->cons_mouse) {
-			sun_mouse_inbyte(ch);
-			return;
+			sun_mouse_inbyte(ch, 0);
+			do_queue_task = 0;
+			goto next_char;
 		}
 		if(info->is_cons) {
-			if(ch==0) {
+			if(ch == 0) {
 				/* whee, break received */
 				batten_down_hatches();
 				/* Continue execution... */
@@ -502,9 +559,11 @@
 		*tty->flip.flag_buf_ptr++ = 0;
 		*tty->flip.char_buf_ptr++ = ch;
 
+	next_char:
 		/* Check if we have another character... */
-		stat = info->zs_channel->control;
+		stat = sbus_readb(&info->zs_channel->control);
 		ZSDELAY();
+		ZSLOG(REGCTRL, stat, 0);
 		if (!(stat & Rx_CH_AV))
 			break;
 
@@ -512,7 +571,8 @@
 		stat = read_zsreg(info->zs_channel, R1);
 	} while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR)));
 
-	queue_task(&tty->flip.tqueue, &tq_timer);
+	if (do_queue_task != 0)
+		queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
 static _INLINE_ void transmit_chars(struct sun_serial *info)
@@ -528,9 +588,10 @@
 
 	if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
 		/* That's peculiar... */
-		info->zs_channel->control = RES_Tx_P;
+		sbus_writeb(RES_Tx_P, &info->zs_channel->control);
 		ZSDELAY();
 		ZS_WSYNC(info->zs_channel);
+		ZSLOG(REGCTRL, RES_Tx_P, 1);
 		return;
 	}
 
@@ -543,9 +604,10 @@
 		zs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 	if(info->xmit_cnt <= 0) {
-		info->zs_channel->control = RES_Tx_P;
+		sbus_writeb(RES_Tx_P, &info->zs_channel->control);
 		ZSDELAY();
 		ZS_WSYNC(info->zs_channel);
+		ZSLOG(REGCTRL, RES_Tx_P, 1);
 	}
 }
 
@@ -554,13 +616,14 @@
 	unsigned char status;
 
 	/* Get status from Read Register 0 */
-	status = info->zs_channel->control;
+	status = sbus_readb(&info->zs_channel->control);
 	ZSDELAY();
+	ZSLOG(REGCTRL, status, 0);
 	/* Clear status condition... */
-	info->zs_channel->control = RES_EXT_INT;
+	sbus_writeb(RES_EXT_INT, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
-
+	ZSLOG(REGCTRL, RES_EXT_INT, 1);
 #if 0
 	if(status & DCD) {
 		if((info->tty->termios->c_cflag & CRTSCTS) &&
@@ -579,8 +642,12 @@
 	 * 'break asserted' status change interrupt, call
 	 * the boot prom.
 	 */
-	if((status & BRK_ABRT) && info->break_abort)
-		batten_down_hatches();
+	if(status & BRK_ABRT) {
+		if (info->break_abort)
+			batten_down_hatches();
+		if (info->cons_mouse)
+			sun_mouse_inbyte(0, 1);
+	}
 
 	/* XXX Whee, put in a buffer somewhere, the status information
 	 * XXX whee whee whee... Where does the information go...
@@ -595,8 +662,9 @@
 
 	stat = read_zsreg(info->zs_channel, R1);
 	if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
-		ch = info->zs_channel->data;
+		ch = sbus_readb(&info->zs_channel->data);
 		ZSDELAY();
+		ZSLOG(REGDATA, ch, 0);
 	}
 
 	if (!tty)
@@ -616,9 +684,10 @@
 done:
 	queue_task(&tty->flip.tqueue, &tq_timer);
 clear:
-	info->zs_channel->control = ERR_RES;
+	sbus_writeb(ERR_RES, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
+	ZSLOG(REGCTRL, ERR_RES, 1);
 }
 
 
@@ -632,6 +701,7 @@
 	int i;
 
 	info = (struct sun_serial *)dev_id;
+	ZSLOG(REGIRQ, 0, 0);
 	for (i = 0; i < NUM_SERIAL; i++) {
 		zs_intreg = read_zsreg(info->zs_next->zs_channel, 2);
 		zs_intreg &= STATUS_MASK;
@@ -797,13 +867,15 @@
 	/*
 	 * Clear the interrupt registers.
 	 */
-	info->zs_channel->control = ERR_RES;
+	sbus_writeb(ERR_RES, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
+	ZSLOG(REGCTRL, ERR_RES, 1);
 
-	info->zs_channel->control = RES_H_IUS;
+	sbus_writeb(RES_H_IUS, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
+	ZSLOG(REGCTRL, RES_H_IUS, 1);
 
 	/*
 	 * Now, initialize the Zilog
@@ -826,13 +898,15 @@
 	/*
 	 * And clear the interrupt registers again for luck.
 	 */
-	info->zs_channel->control = ERR_RES;
+	sbus_writeb(ERR_RES, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
+	ZSLOG(REGCTRL, ERR_RES, 1);
 
-	info->zs_channel->control = RES_H_IUS;
+	sbus_writeb(RES_H_IUS, &info->zs_channel->control);
 	ZSDELAY();
 	ZS_WSYNC(info->zs_channel);
+	ZSLOG(REGCTRL, RES_H_IUS, 1);
 
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1035,24 +1109,32 @@
 {
 	struct sun_zschannel *chan = zs_kgdbchan;
 
-	while((chan->control & Tx_BUF_EMP)==0)
+	while((sbus_readb(&chan->control) & Tx_BUF_EMP)==0)
 		udelay(5);
-	chan->data = kgdb_char;
+	sbus_writeb(kgdb_char, &chan->data);
 	ZS_WSYNC(chan);
+	ZSLOG(REGDATA, kgdb_char, 1);
 }
 
 char getDebugChar(void)
 {
 	struct sun_zschannel *chan = zs_kgdbchan;
+	u8 val;
 
-	while((chan->control & Rx_CH_AV)==0)
+	do {
+		val = sbus_readb(&chan->control);
+		ZSLOG(REGCTRL, val, 0);
 		udelay(5);
-	return chan->data;
+	} while ((val & Rx_CH_AV) == 0);
+
+	val = sbus_readb(&chan->data);
+	ZSLOG(REGDATA, val, 0);
+	return val;
 }
 
 static void zs_flush_chars(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 	unsigned long flags;
 
 	if (serial_paranoia_check(info, tty->device, "zs_flush_chars"))
@@ -1087,9 +1169,9 @@
 static int zs_write(struct tty_struct * tty, int from_user,
 		    const unsigned char *buf, int count)
 {
-	int	c, total = 0;
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 	unsigned long flags;
+	int c, total = 0;
 
 	if (serial_paranoia_check(info, tty->device, "zs_write"))
 		return 0;
@@ -1143,8 +1225,8 @@
 
 static int zs_write_room(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
-	int	ret;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
+	int ret;
 
 	if (serial_paranoia_check(info, tty->device, "zs_write_room"))
 		return 0;
@@ -1156,7 +1238,7 @@
 
 static int zs_chars_in_buffer(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->device, "zs_chars_in_buffer"))
 		return 0;
@@ -1165,7 +1247,7 @@
 
 static void zs_flush_buffer(struct tty_struct *tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->device, "zs_flush_buffer"))
 		return;
@@ -1188,7 +1270,7 @@
  */
 static void zs_throttle(struct tty_struct * tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
 	
@@ -1211,7 +1293,7 @@
 
 static void zs_unthrottle(struct tty_struct * tty)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
 	
@@ -1268,7 +1350,7 @@
 {
 	struct serial_struct new_serial;
 	struct sun_serial old_info;
-	int 			retval = 0;
+	int retval = 0;
 
 	if (!new_info || copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
@@ -1326,10 +1408,11 @@
 	unsigned char status;
 
 	cli();
-	status = info->zs_channel->control;
+	status = sbus_readb(&info->zs_channel->control);
 	ZSDELAY();
+	ZSLOG(REGCTRL, status, 0);
 	sti();
-	put_user_ret(status,value, -EFAULT);
+	put_user_ret(status, value, -EFAULT);
 	return 0;
 }
 
@@ -1339,8 +1422,9 @@
 	unsigned int result;
 
 	cli();
-	status = info->zs_channel->control;
+	status = sbus_readb(&info->zs_channel->control);
 	ZSDELAY();
+	ZSLOG(REGCTRL, status, 0);
 	sti();
 	result =  ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
 		| ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
@@ -1402,7 +1486,7 @@
 static int zs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
-	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial * info = (struct sun_serial *) tty->driver_data;
 	int retval;
 
 	if (serial_paranoia_check(info, tty->device, "zs_ioctl"))
@@ -1469,7 +1553,7 @@
 
 static void zs_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
-	struct sun_serial *info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial *info = (struct sun_serial *) tty->driver_data;
 
 	if (tty->termios->c_cflag == old_termios->c_cflag)
 		return;
@@ -1495,7 +1579,7 @@
  */
 static void zs_close(struct tty_struct *tty, struct file * filp)
 {
-	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial * info = (struct sun_serial *) tty->driver_data;
 	unsigned long flags;
 
 	if (!info || serial_paranoia_check(info, tty->device, "zs_close"))
@@ -1598,7 +1682,7 @@
  */
 void zs_hangup(struct tty_struct *tty)
 {
-	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
+	struct sun_serial * info = (struct sun_serial *) tty->driver_data;
 
 	if (serial_paranoia_check(info, tty->device, "zs_hangup"))
 		return;
@@ -1629,9 +1713,8 @@
 			   struct sun_serial *info)
 {
 	DECLARE_WAITQUEUE(wait, current);
-	int		retval;
-	int		do_clocal = 0;
-	unsigned char	r0;
+	int retval, do_clocal = 0;
+	unsigned char r0;
 
 	/*
 	 * If the device is in the middle of being closed, then block
@@ -1769,10 +1852,11 @@
  */
 int zs_open(struct tty_struct *tty, struct file * filp)
 {
-	struct sun_serial	*info;
-	int 			retval, line;
+	struct sun_serial *info;
+	int retval, line;
 
 	line = MINOR(tty->device) - tty->driver.minor_start;
+
 	/* The zilog lines for the mouse/keyboard must be
 	 * opened using their respective drivers.
 	 */
@@ -1844,7 +1928,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.45 $";
+	char *revision = "$Revision: 1.52 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -1869,16 +1953,19 @@
 	int busnode, seen, zsnode, sun4u_ino;
 	static int irq = 0;
 
-	if(chip < 0 || chip >= NUM_SERIAL)
-		panic("get_zs bogon zs chip number");
+	if(chip < 0 || chip >= NUM_SERIAL) {
+		prom_printf("get_zs bogon zs chip number");
+		prom_halt();
+	}
 
 	if(central_bus)
 		busnode = central_bus->child->prom_node;
 	else
 		busnode = prom_searchsiblings(prom_getchild(prom_root_node), "sbus");
-	if(busnode == 0 || busnode == -1)
-		panic("get_zs: no zs bus to search");
-
+	if(busnode == 0 || busnode == -1) {
+		prom_printf("get_zs: no zs bus to search");
+		prom_halt();
+	}
 	zsnode = prom_getchild(busnode);
 	seen = 0;
 	while(zsnode) {
@@ -1891,8 +1978,8 @@
 						   (void *) vaddr, sizeof(vaddr));
 
 			if(len == -1 || central_bus != NULL) {
-				struct linux_sbus *sbus = NULL;
-				struct linux_sbus_device *sdev = NULL;
+				struct sbus_bus *sbus = NULL;
+				struct sbus_dev *sdev = NULL;
 
 				/* "address" property is not guarenteed,
 				 * everything in I/O is implicitly mapped
@@ -1911,11 +1998,9 @@
 				if (sdev == NULL && central_bus == NULL)
 					prom_halt();
 				if (central_bus == NULL) {
-					prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev);
-					mapped_addr = (unsigned long)
-						sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
-							       PAGE_SIZE, "Zilog Registers",
-							       sdev->reg_addrs[0].which_io, 0x0);
+					mapped_addr =
+					    sbus_ioremap(&sdev->resource[0], 0,
+							 PAGE_SIZE, "Zilog Registers");
 				} else {
 					struct linux_prom_registers zsregs[1];
 					int err;
@@ -1927,11 +2012,11 @@
 						prom_printf("ZS: Cannot map Zilog regs.\n");
 						prom_halt();
 					}
-					prom_apply_fhc_ranges(central_bus->child, &zsregs[0], 1);
-					prom_apply_central_ranges(central_bus, &zsregs[0], 1);
-					mapped_addr = (unsigned long)
-						__va((((unsigned long)zsregs[0].which_io)<<32) |
-						     (((unsigned long)zsregs[0].phys_addr)));
+					apply_fhc_ranges(central_bus->child, &zsregs[0], 1);
+					apply_central_ranges(central_bus, &zsregs[0], 1);
+					mapped_addr =
+						((((u64)zsregs[0].which_io)<<32UL)|
+						 ((u64)zsregs[0].phys_addr));
 				}
 			} else if(len % sizeof(unsigned int)) {
 				prom_printf("WHOOPS:  proplen for %s "
@@ -1946,13 +2031,14 @@
 					       (sizeof(sun4u_ino)));
 			if(!irq) {
 				if (central_bus) {
-					irq = zilog_irq = 
-						build_irq(12, 0, 
-							&central_bus->child->fhc_regs.uregs->fhc_uart_iclr,
-							&central_bus->child->fhc_regs.uregs->fhc_uart_imap);
+					unsigned long iclr, imap;
+
+					iclr = central_bus->child->fhc_regs.uregs + FHC_UREGS_ICLR;
+					imap = central_bus->child->fhc_regs.uregs + FHC_UREGS_IMAP;
+					irq = zilog_irq = build_irq(12, 0, iclr, imap);
 				} else {
 					irq = zilog_irq = 
-						sbus_build_irq(SBus_chain, sun4u_ino);
+						sbus_build_irq(sbus_root, sun4u_ino);
 				}
 			}
 			break;
@@ -1964,10 +2050,20 @@
 		panic("get_zs: whee chip not found");
 	if(!vaddr[0] && !mapped_addr)
 		panic("get_zs: whee no serial chip mappable");
-	if (mapped_addr != 0)
+	if (mapped_addr != 0) {
 		return (struct sun_zslayout *) mapped_addr;
-	else
-		return (struct sun_zslayout *) (unsigned long) vaddr[0];
+	} else {
+		pgd_t *pgd = pgd_offset_k((unsigned long)vaddr[0]);
+		pmd_t *pmd = pmd_offset(pgd, (unsigned long)vaddr[0]);
+		pte_t *pte = pte_offset(pmd, (unsigned long)vaddr[0]);
+		unsigned long base = pte_val(*pte) & _PAGE_PADDR;
+
+		/* Translate PROM's mapping we captured at boot
+		 * time into physical address.
+		 */
+		base += ((unsigned long)vaddr[0] & ~PAGE_MASK);
+		return (struct sun_zslayout *) base;
+	}
 }
 #else /* !(__sparc_v9__) */
 static struct sun_zslayout * __init get_zs(int chip)
@@ -1990,6 +2086,8 @@
 		panic("get_zs bogon zs chip number");
 
 	if(sparc_cpu_model == sun4) {
+		struct resource dummy_resource;
+
 		/* Grrr, these have to be hardcoded aieee */
 		switch(chip) {
 		case 0:
@@ -2003,9 +2101,11 @@
 		zs_nodes[chip] = 0;
 		if(!irq)
 			zilog_irq = irq = 12;
-		vaddr[0] = (unsigned long)
-				sparc_alloc_io(paddr, 0, 8,
-					       "Zilog Serial", iospace, 0);
+		dummy_resource.start = paddr;
+		dummy_resource.end = paddr + 8 - 1;
+		dummy_resource.flags = IORESOURCE_IO;
+		vaddr[0] = sbus_ioremap(&dummy_resource, 0,
+					8, "Zilog Serial");
 	} else {
 		/* Can use the prom for other machine types */
 		zsnode = prom_getchild(prom_root_node);
@@ -2056,15 +2156,18 @@
 				} else {
 					/* On sun4d don't have address property :( */
 					struct linux_prom_registers zsreg[4];
+					struct resource res;
 					
 					if (prom_getproperty(zsnode, "reg", (char *)zsreg, sizeof(zsreg)) == -1) {
 						prom_printf ("Cannot map zs regs\n");
 						prom_halt();
 					}
 					prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1);
-					vaddr[0] = (unsigned long)
-							sparc_alloc_io(zsreg[0].phys_addr, 0, 8,
-								       "Zilog Serial", zsreg[0].which_io, 0);
+					res.start = zsreg[0].phys_addr;
+					res.end = res.start + 8 - 1;
+					res.flags = zsreg[0].which_io | IORESOURCE_IO;
+					vaddr[0] = sbus_ioremap(&res, 0,
+								8, "Zilog Serial");
 				}
 				zs_nodes[chip] = zsnode;
 				len = prom_getproperty(zsnode, "intr",
@@ -2074,9 +2177,9 @@
 					prom_printf(
 					      "WHOOPS:  proplen for %s "
 					      "was %d, need multiple of "
-					      "%d\n", "address", len,
+					      "%d\n", "intr", len,
 					      sizeof(struct linux_prom_irqs));
-					panic("zilog: address property");
+					panic("zilog: intr property");
 				}
 				if(!irq) {
 					irq = zilog_irq = tmp_irq[0].pri;
@@ -2110,11 +2213,62 @@
 	write_zsreg(zs_soft[channel].zs_channel, R13, ((brg >> 8) & 0xff));
 }
 
-int __init zs_probe (unsigned long *memory_start)
+void __init zs_init_alloc_failure(const char *table_name)
+{
+	prom_printf("zs_probe: Cannot alloc %s.\n", table_name);
+	prom_halt();
+}
+
+void * __init zs_alloc_bootmem(unsigned long size)
+{
+	void *ret;
+
+	ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+	if (ret != NULL)
+		memset(ret, 0, size);
+
+	return ret;
+}
+
+void __init zs_alloc_tables(void)
+{
+	zs_chips = (struct sun_zslayout **)
+		zs_alloc_bootmem(NUM_SERIAL * sizeof(struct sun_zslayout *));
+	if (zs_chips == NULL)
+		zs_init_alloc_failure("zs_chips");
+	zs_channels = (struct sun_zschannel **)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct sun_zschannel *));
+	if (zs_channels == NULL)
+		zs_init_alloc_failure("zs_channels");
+	zs_nodes = (int *)
+		zs_alloc_bootmem(NUM_SERIAL * sizeof(int));
+	if (zs_nodes == NULL)
+		zs_init_alloc_failure("zs_nodes");
+	zs_soft = (struct sun_serial *)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct sun_serial));
+	if (zs_soft == NULL)
+		zs_init_alloc_failure("zs_soft");
+	zs_ttys = (struct tty_struct *)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct tty_struct));
+	if (zs_ttys == NULL)
+		zs_init_alloc_failure("zs_ttys");
+	serial_table = (struct tty_struct **)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct tty_struct *));
+	if (serial_table == NULL)
+		zs_init_alloc_failure("serial_table");
+	serial_termios = (struct termios **)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct termios *));
+	if (serial_termios == NULL)
+		zs_init_alloc_failure("serial_termios");
+	serial_termios_locked = (struct termios **)
+		zs_alloc_bootmem(NUM_CHANNELS * sizeof(struct termios *));
+	if (serial_termios_locked == NULL)
+		zs_init_alloc_failure("serial_termios_locked");
+}
+
+int __init zs_probe(void)
 {
-	char *p;
 	int node;
-	int i;
 
 	if(sparc_cpu_model == sun4)
 		goto no_probe;
@@ -2166,42 +2320,24 @@
 	NUM_SERIAL = 2;
 
 no_probe:
-	p = (char *)((*memory_start + 7) & ~7);
-	zs_chips = (struct sun_zslayout **)(p);
-	i = NUM_SERIAL * sizeof (struct sun_zslayout *);
-	zs_channels = (struct sun_zschannel **)(p + i);
-	i += NUM_CHANNELS * sizeof (struct sun_zschannel *);
-	zs_nodes = (int *)(p + i);
-	i += NUM_SERIAL * sizeof (int);
-	zs_soft = (struct sun_serial *)(p + i);
-	i += NUM_CHANNELS * sizeof (struct sun_serial);
-	zs_ttys = (struct tty_struct *)(p + i);
-	i += NUM_CHANNELS * sizeof (struct tty_struct);
-	serial_table = (struct tty_struct **)(p + i);
-	i += NUM_CHANNELS * sizeof (struct tty_struct *);
-	serial_termios = (struct termios **)(p + i);
-	i += NUM_CHANNELS * sizeof (struct termios *);
-	serial_termios_locked = (struct termios **)(p + i);
-	i += NUM_CHANNELS * sizeof (struct termios *);
-	memset (p, 0, i);
-	*memory_start = (((unsigned long)p) + i + 7) & ~7;
+	zs_alloc_tables();
 
 	/* Fill in rs_ops struct... */
 #ifdef CONFIG_SERIAL_CONSOLE
-	sunserial_setinitfunc(memory_start, zs_console_init);
+	sunserial_setinitfunc(zs_console_init);
 #endif
-	sunserial_setinitfunc(memory_start, zs_init);
+	sunserial_setinitfunc(zs_init);
 	rs_ops.rs_kgdb_hook = zs_kgdb_hook;
 	rs_ops.rs_change_mouse_baud = zs_change_mouse_baud;
 
-	sunkbd_setinitfunc(memory_start, sun_kbd_init);
+	sunkbd_setinitfunc(sun_kbd_init);
 	kbd_ops.compute_shiftstate = sun_compute_shiftstate;
 	kbd_ops.setledstate = sun_setledstate;
 	kbd_ops.getledstate = sun_getledstate;
 	kbd_ops.setkeycode = sun_setkeycode;
 	kbd_ops.getkeycode = sun_getkeycode;
 #if defined(__sparc_v9__) && defined(CONFIG_PCI)
-	sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
+	sunkbd_install_keymaps(sun_key_maps, sun_keymap_count,
 			       sun_func_buf, sun_func_table,
 			       sun_funcbufsize, sun_funcbufleft,
 			       sun_accent_table, sun_accent_table_size);
@@ -2214,7 +2350,8 @@
 	int channel, chip;
 	unsigned long flags;
 
-	if (!NUM_SERIAL) return;
+	if (!NUM_SERIAL)
+		return;
 	
 	save_and_cli(flags);
 	
@@ -2346,12 +2483,13 @@
 	 */
 	if (request_irq(zilog_irq, zs_interrupt,
 			(SA_INTERRUPT | SA_STATIC_ALLOC),
-			"Zilog8530", zs_chain))
-		panic("Unable to attach zs intr\n");
+			"Zilog8530", zs_chain)) {
+		prom_printf("Unable to attach zs intr\n");
+		prom_halt();
+	}
 
 	/* Initialize Hardware */
 	for(channel = 0; channel < NUM_CHANNELS; channel++) {
-
 		/* Hardware reset each chip */
 		if (!(channel & 1)) {
 			write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES);
@@ -2580,12 +2718,14 @@
  */
 static void zs_fair_output(struct sun_serial *info)
 {
-	int left;		/* Output no more than that */
 	unsigned long flags;
+	int left;		/* Output no more than that */
 	char c;
 
-	if (info == 0) return;
-	if (info->xmit_buf == 0) return;
+	if (info == NULL)
+		return;
+	if (info->xmit_buf == NULL)
+		return;
 
 	save_flags(flags);  cli();
 	left = info->xmit_cnt;
@@ -2602,8 +2742,9 @@
 	}
 
 	/* Last character is being transmitted now (hopefully). */
-	info->zs_channel->control = RES_Tx_P;
+	sbus_writeb(RES_Tx_P, &info->zs_channel->control);
 	ZSDELAY();
+	ZSLOG(REGCTRL, RES_Tx_P, 1);
 
 	restore_flags(flags);
 	return;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)