patch-2.2.15 linux/drivers/s390/char/con3215.c

Next file: linux/drivers/s390/char/hwc.h
Previous file: linux/drivers/s390/block/mdisk.h
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
@@ -3,7 +3,7 @@
  *    3215 line mode terminal driver.
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  */
 
@@ -22,7 +22,7 @@
 #include <asm/uaccess.h>
 
 #include "../../../arch/s390/kernel/cpcmd.h"
-#include "../../../arch/s390/kernel/irq.h"
+#include <asm/irq.h>
 
 #define NR_3215		    1
 #define NR_3215_REQ	    (4*NR_3215)
@@ -42,14 +42,17 @@
 #define RAW3215_CLOSING	    32	      /* set while in close process */
 #define RAW3215_TIMER_RUNS  64	      /* set if the output delay timer is on */
 #define RAW3215_FLUSHING    128	      /* set to flush buffer (no delay) */
+#define RAW3215_BH_PENDING  256       /* indication for bh scheduling */
 
 struct _raw3215_info;		      /* forward declaration ... */
 
+int raw3215_condevice = -1;           /* preset console device */
+
 /*
  * Request types for a 3215 device
  */
 typedef enum {
-	RAW3215_READ, RAW3215_WRITE
+	RAW3215_FREE, RAW3215_READ, RAW3215_WRITE
 } raw3215_type;
 
 /*
@@ -97,6 +100,16 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
+__initfunc(void con3215_setup(char *str, char *ints))
+{
+        int vdev;
+
+        vdev = simple_strtoul(str,&str,16);
+        if (vdev >= 0 && vdev < 65536)
+                raw3215_condevice = vdev;
+        return;
+}
+
 /*
  * Get a request structure from the free list
  */
@@ -117,6 +130,9 @@
 extern inline void raw3215_free_req(raw3215_req *req) {
 	unsigned long flags;
 
+        if (req->type == RAW3215_FREE)
+                return;         /* don't free a free request */
+        req->type = RAW3215_FREE;
 	spin_lock_irqsave(&raw3215_freelist_lock, flags);
 	req->next = raw3215_freelist;
 	raw3215_freelist = req;
@@ -196,12 +212,6 @@
 		ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
 		ccw++;
 	}
-	if (ccw > req->ccws)
-		ccw[-1].flags |= 0x40;	/* use command chaining */
-	ccw->cmd_code = 0x03; /* nop at the end */
-	ccw->flags = 0x20;    /* ignore incorrect length */
-	ccw->cda = NULL;      /* no data address for nop */
-	ccw->count = 0;	      /* no count for nop */
 	return len;
 }
 
@@ -214,14 +224,9 @@
 
 	ccw = req->ccws;
 	ccw->cmd_code = 0x0A; /* read inquiry */
-	ccw->flags = 0x60;    /* ignore incorrect length & command chaining */
+	ccw->flags = 0x20;    /* ignore incorrect length */
 	ccw->count = 160;
 	ccw->cda = (void *) virt_to_phys(raw->inbuf);
-	ccw++;
-	ccw->cmd_code = 0x03; /* nop at the end */
-	ccw->flags = 0x20;    /* ignore incorrect length ind. */
-	ccw->cda = NULL;      /* no data address for nop */
-	ccw->count = 0;	      /* no count for nop */
 }
 
 /*
@@ -323,6 +328,7 @@
 	raw = (raw3215_info *) data;
 	s390irq_spin_lock_irqsave(raw->irq, flags);
 	raw3215_try_io((raw3215_info *) data);
+        raw->flags &= ~RAW3215_BH_PENDING;
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 	/* Check for pending message from raw3215_irq */
 	if (raw->message != NULL) {
@@ -340,6 +346,21 @@
 }
 
 /*
+ * Function to safely add raw3215_softint to tq_immediate.
+ * The s390irq spinlock must be held.
+ */
+static inline void raw3215_sched_bh(raw3215_info *raw)
+{
+        if (raw->flags & RAW3215_BH_PENDING)
+                return;       /* already pending */
+        raw->flags |= RAW3215_BH_PENDING;
+        raw->tqueue.routine = raw3215_softint;
+        raw->tqueue.data = raw;
+        queue_task(&raw->tqueue, &tq_immediate);
+        mark_bh(IMMEDIATE_BH);
+}
+
+/*
  * Find the raw3215_info structure associated with irq
  */
 static inline raw3215_info *raw3215_find_info(int irq) {
@@ -365,7 +386,7 @@
 	struct tty_struct *tty;
 	devstat_t *stat;
         int cstat, dstat;
-	int count;
+	int count, slen;
 
 	stat = (devstat_t *) int_parm;
 	req = (raw3215_req *) stat->intparm;
@@ -379,22 +400,11 @@
 				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
 			raw->msg_dstat = dstat;
 			raw->msg_cstat = cstat;
-			queue_task(&raw->tqueue, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
+                        raw3215_sched_bh(raw);
 		}
 	}
         if (dstat & 0x01) { /* we got a unit exception */
-		raw = raw3215_find_info(irq);
-		if (raw != NULL) {
-                        raw->message = KERN_WARNING
-                                "Got a unit exception in raw3215_irq "
-                                "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
-                        raw->msg_dstat = dstat;
-                        raw->msg_cstat = cstat;
-                        queue_task(&raw->tqueue, &tq_immediate);
-                        mark_bh(IMMEDIATE_BH);
-		}
-		dstat &= ~0x01;
+		dstat &= ~0x01;  /* we can ignore it */
         }
 	switch (dstat) {
 	case 0x80:
@@ -407,8 +417,9 @@
 		req = raw3215_mk_read_req(raw);
 		raw3215_mk_read_ccw(raw, req);
 		raw->queued_read = req;
-		queue_task(&raw->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+                if (MACHINE_IS_P390)
+                        memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
+                raw3215_sched_bh(raw);
 		break;
 	case 0x08:
 	case 0x0C:
@@ -426,6 +437,11 @@
 		if (req->type == RAW3215_READ && raw->tty != NULL) {
 			tty = raw->tty;
 			count = 160 - req->residual;
+                        if (MACHINE_IS_P390) {
+                                slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
+                                if (count > slen)
+                                        count = slen;
+                        } else
 			if (count >= TTY_FLIPBUF_SIZE - tty->flip.count)
 				count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
 			EBCASC(raw->inbuf, count);
@@ -480,28 +496,26 @@
 			wake_up_interruptible(&raw->empty_wait);
 			raw->empty_wait = NULL;
 		}
-		queue_task(&raw->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+                raw3215_sched_bh(raw);
 		break;
 	default:
-		if (dstat & 0x04) {
 			/* Strange interrupt, I'll do my best to clean up */
-			if (req != NULL && req->info != NULL &&
-			    req->type == RAW3215_WRITE) {
-				req->info->count -= ((req->end - req->start) &
+                if ((raw = raw3215_find_info(irq)) == NULL)
+                        return;              /* That shouldn't happen ... */
+                if (raw == NULL) break;
+		if (req != NULL && req->type != RAW3215_FREE) {
+		        if (req->type == RAW3215_WRITE) 
+			        raw->count -= ((req->end - req->start) &
 					            (RAW3215_BUFFER_SIZE-1))+1;
+                        raw->flags &= ~RAW3215_WORKING;
+                        raw3215_free_req(req);
 			}
-		}
-		raw = raw3215_find_info(irq);
-		if (raw != NULL) {
 			raw->message = KERN_WARNING
 				"Spurious interrupt in in raw3215_irq "
 				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
 			raw->msg_dstat = dstat;
 			raw->msg_cstat = cstat;
-			queue_task(&raw->tqueue, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
-		}
+                raw3215_sched_bh(raw);
 	}
 	return;
 }
@@ -687,19 +701,21 @@
 	int irq;
 	int count;
 
-	irq = 0;
+	irq = get_irq_first();
 	count = 0;
-	while (count <= number && get_dev_info(irq, &dinfo) != -ENODEV) {
-		if (dinfo.sid_data.cu_type == 0x3215)
+        while (count <= number && irq != -ENODEV) {
+                if (get_dev_info(irq, &dinfo) == -ENODEV)
+                        break;
+		if (dinfo.devno == raw3215_condevice ||
+                    dinfo.sid_data.cu_type == 0x3215) {
 			count++;
-		irq++;
-	}
-	if (count <= number)
-		irq = -1;     /* console not found */
-	else
-		irq--;
+                    if (count > number)
 	return irq;
 }
+                irq = get_irq_next(irq);
+        }
+        return -1;            /* console not found */
+}
 
 #ifdef CONFIG_3215_CONSOLE
 
@@ -710,7 +726,7 @@
 {
 	raw3215_info *raw;
 
-        if (!MACHINE_IS_VM)
+        if (!MACHINE_IS_VM && !MACHINE_IS_P390)
                 return 0;
 	raw = raw3215[0];  /* 3215 console is the first one */
 	if (raw->irq == -1) /* now console device found in con3215_init */
@@ -748,7 +764,7 @@
 
 	raw = raw3215[0];  /* console 3215 is the first one */
 	s390irq_spin_lock_irqsave(raw->irq, flags);
-	while (RAW3215_BUFFER_SIZE > raw->count) {
+	while (raw->count > 0) {
 		/* there might be a request pending */
 		raw->flags |= RAW3215_FLUSHING;
 		raw3215_try_io(raw);
@@ -761,7 +777,7 @@
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 }
 
-__initfunc(static int con3215_setup(struct console *co, char *options))
+__initfunc(static int con3215_consetup(struct console *co, char *options))
 {
 	return 0;
 }
@@ -776,7 +792,7 @@
 	con3215_device,
 	NULL,
 	con3215_unblank,
-	con3215_setup,
+	con3215_consetup,
 	CON_PRINTBUFFER,
 	0,
 	0,
@@ -1008,12 +1024,14 @@
 	raw3215_req *req;
 	int i;
 
-	if (!MACHINE_IS_VM)
+	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
                 return kmem_start;
+        if (MACHINE_IS_VM) {
 	cpcmd("TERM CONMODE 3215", NULL, 0);
 	cpcmd("TERM AUTOCR OFF", NULL, 0);
 	cpcmd("TERM HOLD OFF", NULL, 0);
 	cpcmd("TERM MORE 5 5", NULL, 0);
+        }
 
 	kmem_start = (kmem_start + 7) & -8L;
 

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