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
- Lines: 303
- Date:
Fri Apr 21 12:46:24 2000
- Orig file:
v2.2.14/drivers/s390/char/con3215.c
- Orig date:
Tue Jan 4 21:18:53 2000
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)