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

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

diff -u --recursive --new-file v2.2.3/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.32 1998/11/08 11:15:29 davem Exp $
+/* $Id: zs.c,v 1.40 1999/02/23 15:14:45 jj Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -53,6 +53,22 @@
 #define KEYBOARD_LINE 0x2
 #define MOUSE_LINE    0x3
 
+/* On 32-bit sparcs we need to delay after register accesses
+ * to accomodate sun4 systems, but we do not need to flush writes.
+ * On 64-bit sparc we only need to flush single writes to ensure
+ * completion.
+ */
+#ifndef __sparc_v9__
+#define ZSDELAY()		udelay(5)
+#define ZSDELAY_LONG()		udelay(20)
+#define ZS_WSYNC(channel)	do { } while(0)
+#else
+#define ZSDELAY()
+#define ZSDELAY_LONG()
+#define ZS_WSYNC(channel) \
+	((void) *((volatile unsigned char *)(&((channel)->control))))
+#endif
+
 struct sun_zslayout **zs_chips;
 struct sun_zschannel **zs_channels;
 struct sun_zschannel *zs_mousechan;
@@ -200,9 +216,9 @@
 	unsigned char retval;
 
 	channel->control = reg;
-	udelay(5);
+	ZSDELAY();
 	retval = channel->control;
-	udelay(5);
+	ZSDELAY();
 	return retval;
 }
 
@@ -210,9 +226,9 @@
 			       unsigned char reg, unsigned char value)
 {
 	channel->control = reg;
-	udelay(5);
+	ZSDELAY();
 	channel->control = value;
-	udelay(5);
+	ZSDELAY();
 }
 
 static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
@@ -239,7 +255,7 @@
 		write_zsreg(channel, R9, CHRA);
 	else
 		write_zsreg(channel, R9, CHRB);
-	udelay(20);	/* wait for some old sun4's */
+	ZSDELAY_LONG();
 	write_zsreg(channel, R4, regs[R4]);
 	write_zsreg(channel, R3, regs[R3] & ~RxENAB);
 	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
@@ -267,10 +283,16 @@
 {
 	int loops = ZS_PUT_CHAR_MAX_DELAY;
 
+	/* Do not change this to use ZSDELAY as this is
+	 * a timed polling loop and on sparc64 ZSDELAY
+	 * is a nop.  -DaveM
+	 */
 	while((channel->control & Tx_BUF_EMP) == 0 && --loops)
 		udelay(5);
+
 	channel->data = ch;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(channel);
 }
 
 /* Sets or clears DTR/RTS on the requested line */
@@ -420,7 +442,7 @@
 
 	do {
 		ch = (info->zs_channel->data) & info->parity_mask;
-		udelay(5);
+		ZSDELAY();
 
 		/* If this is the console keyboard, we need to handle
 		 * L1-A's here.
@@ -482,7 +504,7 @@
 
 		/* Check if we have another character... */
 		stat = info->zs_channel->control;
-		udelay(5);
+		ZSDELAY();
 		if (!(stat & Rx_CH_AV))
 			break;
 
@@ -507,7 +529,8 @@
 	if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) {
 		/* That's peculiar... */
 		info->zs_channel->control = RES_Tx_P;
-		udelay(5);
+		ZSDELAY();
+		ZS_WSYNC(info->zs_channel);
 		return;
 	}
 
@@ -521,7 +544,8 @@
 
 	if(info->xmit_cnt <= 0) {
 		info->zs_channel->control = RES_Tx_P;
-		udelay(5);
+		ZSDELAY();
+		ZS_WSYNC(info->zs_channel);
 	}
 }
 
@@ -531,10 +555,11 @@
 
 	/* Get status from Read Register 0 */
 	status = info->zs_channel->control;
-	udelay(5);
+	ZSDELAY();
 	/* Clear status condition... */
 	info->zs_channel->control = RES_EXT_INT;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
 
 #if 0
 	if(status & DCD) {
@@ -571,7 +596,7 @@
 	stat = read_zsreg(info->zs_channel, R1);
 	if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) {
 		ch = info->zs_channel->data;
-		udelay(5);
+		ZSDELAY();
 	}
 
 	if (!tty)
@@ -592,7 +617,8 @@
 	queue_task(&tty->flip.tqueue, &tq_timer);
 clear:
 	info->zs_channel->control = ERR_RES;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
 }
 
 
@@ -772,9 +798,12 @@
 	 * Clear the interrupt registers.
 	 */
 	info->zs_channel->control = ERR_RES;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
+
 	info->zs_channel->control = RES_H_IUS;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
 
 	/*
 	 * Now, initialize the Zilog
@@ -798,9 +827,12 @@
 	 * And clear the interrupt registers again for luck.
 	 */
 	info->zs_channel->control = ERR_RES;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
+
 	info->zs_channel->control = RES_H_IUS;
-	udelay(5);
+	ZSDELAY();
+	ZS_WSYNC(info->zs_channel);
 
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1006,6 +1038,7 @@
 	while((chan->control & Tx_BUF_EMP)==0)
 		udelay(5);
 	chan->data = kgdb_char;
+	ZS_WSYNC(chan);
 }
 
 char getDebugChar(void)
@@ -1013,7 +1046,7 @@
 	struct sun_zschannel *chan = zs_kgdbchan;
 
 	while((chan->control & Rx_CH_AV)==0)
-		barrier();
+		udelay(5);
 	return chan->data;
 }
 
@@ -1254,6 +1287,9 @@
 		goto check_and_exit;
 	}
 
+	if(new_serial.baud_base < 9600)
+		return -EINVAL;
+
 	if (info->count > 1)
 		return -EBUSY;
 
@@ -1291,6 +1327,7 @@
 
 	cli();
 	status = info->zs_channel->control;
+	ZSDELAY();
 	sti();
 	put_user_ret(status,value, -EFAULT);
 	return 0;
@@ -1303,6 +1340,7 @@
 
 	cli();
 	status = info->zs_channel->control;
+	ZSDELAY();
 	sti();
 	result =  ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
 		| ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
@@ -1806,7 +1844,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.32 $";
+	char *revision = "$Revision: 1.40 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -1853,8 +1891,8 @@
 			int len = prom_getproperty(zsnode, "address",
 						   (void *) vaddr, sizeof(vaddr));
 
-			if(len == -1) {
-				struct linux_sbus *sbus;
+			if(len == -1 || central_bus != NULL) {
+				struct linux_sbus *sbus = NULL;
 				struct linux_sbus_device *sdev = NULL;
 
 				/* "address" property is not guarenteed,
@@ -1862,20 +1900,40 @@
 				 * anyways by our clever TLB miss handling
 				 * scheme, so don't fail here.  -DaveM
 				 */
-				for_each_sbus(sbus) {
-					for_each_sbusdev(sdev, sbus) {
-						if (sdev->prom_node == zsnode)
-							goto found;
+				if (central_bus == NULL) {
+					for_each_sbus(sbus) {
+						for_each_sbusdev(sdev, sbus) {
+							if (sdev->prom_node == zsnode)
+								goto found;
+						}
 					}
 				}
 			found:
-				if (sdev == NULL)
+				if (sdev == NULL && central_bus == NULL)
 					prom_halt();
-				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);
+				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);
+				} else {
+					struct linux_prom_registers zsregs[1];
+					int err;
+
+					err = prom_getproperty(zsnode, "reg",
+							       (char *)&zsregs[0],
+							       sizeof(zsregs));
+					if (err == -1) {
+						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)));
+				}
 			} else if(len % sizeof(unsigned int)) {
 				prom_printf("WHOOPS:  proplen for %s "
 					    "was %d, need multiple of "
@@ -1954,25 +2012,27 @@
 		/* Can use the prom for other machine types */
 		zsnode = prom_getchild(prom_root_node);
 		if (sparc_cpu_model == sun4d) {
-			int board, node;
+			int node;
+			int no = 0;
 			
 			tmpnode = zsnode;
+			zsnode = 0;
+			bbnode = 0;
 			while (tmpnode && (tmpnode = prom_searchsiblings(tmpnode, "cpu-unit"))) {
-				board = prom_getintdefault (tmpnode, "board#", -1);
-				if (board == (chip >> 1)) {
-					node = prom_getchild(tmpnode);
-					if (node && (node = prom_searchsiblings(node, "bootbus"))) {
+				bbnode = prom_getchild(tmpnode);
+				if (bbnode && (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
+					if (no == (chip >> 1)) {
 						cpunode = tmpnode;
-						bbnode = node;
-						zsnode = prom_getchild(node);
+						zsnode = prom_getchild(bbnode);
 						chipid = (chip & 1);
 						break;
 					}
+					no++;
 				}
 				tmpnode = prom_getsibling(tmpnode);
 			}
 			if (!tmpnode)
-				panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1);
+				panic ("get_zs: couldn't find %dth bootbus\n", chip >> 1);
 		} else {
 			tmpnode = prom_searchsiblings(zsnode, "obio");
 			if(tmpnode)
@@ -2066,13 +2126,12 @@
 	
 	node = prom_getchild(prom_root_node);
 	if (sparc_cpu_model == sun4d) {
-		node = prom_searchsiblings(node, "boards");
-		if (!node)
-			panic ("Cannot find out count of boards");
-		else
-			node = prom_getchild(node);
-		while (node && (node = prom_searchsiblings(node, "bif"))) {
-			NUM_SERIAL += 2;
+		int bbnode;
+		
+		while (node && (node = prom_searchsiblings(node, "cpu-unit"))) {
+			bbnode = prom_getchild(node);
+			if (bbnode && prom_searchsiblings(bbnode, "bootbus"))
+				NUM_SERIAL += 2;
 			node = prom_getsibling(node);
 		}
 		goto no_probe;
@@ -2082,7 +2141,7 @@
 		int central_node;
 
 		/* Central bus zilogs must be checked for first,
-		 * since Enterprise boxes have SBUS as well.
+		 * since Enterprise boxes might have SBUSes as well.
 		 */
 		central_node = prom_finddevice("/central");
 		if(central_node != 0 && central_node != -1)
@@ -2290,13 +2349,21 @@
 	/* Initialize Softinfo */
 	zs_prepare();
 
+	/* Grab IRQ line before poking the chips so we do
+	 * not lose any interrupts.
+	 */
+	if (request_irq(zilog_irq, zs_interrupt,
+			(SA_INTERRUPT | SA_STATIC_ALLOC),
+			"Zilog8530", zs_chain))
+		panic("Unable to attach zs intr\n");
+
 	/* 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);
-			udelay(20);	/* wait for some old sun4's */
+			ZSDELAY_LONG();
 			dummy = read_zsreg(zs_soft[channel].zs_channel, R0);
 		}
 
@@ -2462,10 +2529,6 @@
 		printk(" is a Zilog8530\n");
 	}
 
-	if (request_irq(zilog_irq, zs_interrupt,
-			(SA_INTERRUPT | SA_STATIC_ALLOC),
-			"Zilog8530", zs_chain))
-		panic("Unable to attach zs intr\n");
 	restore_flags(flags);
 
 	keyboard_zsinit(kbd_put_char);
@@ -2549,7 +2612,7 @@
 
 	/* Last character is being transmitted now (hopefully). */
 	info->zs_channel->control = RES_Tx_P;
-	udelay(5);
+	ZSDELAY();
 
 	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)