linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] s390 (8/10): console device drivers.
@ 2003-05-26 17:27 Martin Schwidefsky
  0 siblings, 0 replies; only message in thread
From: Martin Schwidefsky @ 2003-05-26 17:27 UTC (permalink / raw)
  To: linux-kernel, torvalds

s390 console driver fixes: 
 - Register console ttys via module_init. Remove sclp_tty_init and
   tty3215_init from tty_io.c
 - con3215: use set_current_state.
 - sclp: Fix race condition in sclp interrupt handler. Fix deadlock on
   sclp_conbuf_lock for certain error conditions.

diffstat:
 drivers/char/tty_io.c        |    5 ---
 drivers/s390/char/con3215.c  |    4 +--
 drivers/s390/char/sclp.c     |   42 +++++++++++++++++++++------------
 drivers/s390/char/sclp_con.c |   54 ++++++++++++++++++++++++-------------------
 drivers/s390/char/sclp_tty.c |   25 +++++++++++--------
 drivers/s390/char/sclp_tty.h |    4 +++
 6 files changed, 79 insertions(+), 55 deletions(-)

diff -urN linux-2.5/drivers/char/tty_io.c linux-2.5-s390/drivers/char/tty_io.c
--- linux-2.5/drivers/char/tty_io.c	Mon May 26 19:20:26 2003
+++ linux-2.5-s390/drivers/char/tty_io.c	Mon May 26 19:20:47 2003
@@ -145,8 +145,6 @@
 extern int vme_scc_init (void);
 extern int serial167_init(void);
 extern int rs_8xx_init(void);
-extern void sclp_tty_init(void);
-extern void tty3215_init(void);
 extern void tub3270_init(void);
 extern void rs_360_init(void);
 extern void tx3912_rs_init(void);
@@ -2480,9 +2478,6 @@
 #ifdef CONFIG_TN3270
 	tub3270_init();
 #endif
-#ifdef CONFIG_SCLP_TTY
-	sclp_tty_init();
-#endif
 #ifdef CONFIG_A2232
 	a2232board_init();
 #endif
diff -urN linux-2.5/drivers/s390/char/con3215.c linux-2.5-s390/drivers/s390/char/con3215.c
--- linux-2.5/drivers/s390/char/con3215.c	Mon May  5 01:53:35 2003
+++ linux-2.5-s390/drivers/s390/char/con3215.c	Mon May 26 19:20:47 2003
@@ -697,12 +697,12 @@
 	    raw->queued_read != NULL) {
 		raw->flags |= RAW3215_CLOSING;
 		add_wait_queue(&raw->empty_wait, &wait);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(raw->lock, flags);
 		schedule();
 		spin_lock_irqsave(raw->lock, flags);
 		remove_wait_queue(&raw->empty_wait, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 		raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
 	}
 	spin_unlock_irqrestore(raw->lock, flags);
diff -urN linux-2.5/drivers/s390/char/sclp.c linux-2.5-s390/drivers/s390/char/sclp.c
--- linux-2.5/drivers/s390/char/sclp.c	Mon May  5 01:53:32 2003
+++ linux-2.5-s390/drivers/s390/char/sclp.c	Mon May 26 19:20:47 2003
@@ -18,7 +18,9 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/timer.h>
+#include <linux/init.h>
 #include <asm/s390_ext.h>
+#include <asm/processor.h>
 
 #include "sclp.h"
 
@@ -49,7 +51,7 @@
 /* Timer for init mask retries. */
 static struct timer_list retry_timer;
 
-static unsigned long sclp_status = 0;
+static volatile unsigned long sclp_status = 0;
 /* some status flags */
 #define SCLP_INIT		0
 #define SCLP_RUNNING		1
@@ -275,20 +277,24 @@
 	struct list_head *l;
 	struct sclp_req *req, *tmp;
 
+	spin_lock(&sclp_lock);
 	/*
 	 * Only process interrupt if sclp is initialized.
 	 * This avoids strange effects for a pending request
 	 * from before the last re-ipl.
 	 */
-	if (!test_bit(SCLP_INIT, &sclp_status))
+	if (!test_bit(SCLP_INIT, &sclp_status)) {
+		/* Now clear the running bit */
+		clear_bit(SCLP_RUNNING, &sclp_status);
+		spin_unlock(&sclp_lock);
 		return;
+	}
 	ext_int_param = S390_lowcore.ext_params;
 	finished_sccb = ext_int_param & EXT_INT_SCCB_MASK;
 	evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING |
 					 EXT_INT_STATECHANGE_PENDING);
 	irq_enter();
 	req = NULL;
-	spin_lock(&sclp_lock);
 	if (finished_sccb != 0U) {
 		list_for_each(l, &sclp_req_queue) {
 			tmp = list_entry(l, struct sclp_req, list);
@@ -299,9 +305,6 @@
 			}
 		}
 	}
-	/* Head queue a read sccb if an event buffer is pending */
-	if (evbuf_pending)
-		__sclp_unconditional_read();
 	spin_unlock(&sclp_lock);
 	/* Perform callback */
 	if (req != NULL) {
@@ -309,8 +312,13 @@
 		if (req->callback != NULL)
 			req->callback(req, req->callback_data);
 	}
+	spin_lock(&sclp_lock);
+	/* Head queue a read sccb if an event buffer is pending */
+	if (evbuf_pending)
+		__sclp_unconditional_read();
 	/* Now clear the running bit */
 	clear_bit(SCLP_RUNNING, &sclp_status);
+	spin_unlock(&sclp_lock);
 	/* and start next request on the queue */
 	sclp_start_request();
 	irq_exit();
@@ -344,8 +352,10 @@
 		      : "=m" (psw_mask) : "a" (&psw_mask) : "memory");
 
 	/* wait until ISR signals receipt of interrupt */
-	while (test_bit(SCLP_RUNNING, &sclp_status))
+	while (test_bit(SCLP_RUNNING, &sclp_status)) {
 		barrier();
+		cpu_relax();
+	}
 
 	/* disable external interruptions */
 	asm volatile ("SSM 0(%0)"
@@ -631,6 +641,14 @@
 		/* Already initialized. */
 		return 0;
 
+	spin_lock_init(&sclp_lock);
+	INIT_LIST_HEAD(&sclp_req_queue);
+
+	/* init event list */
+	INIT_LIST_HEAD(&sclp_reg_list);
+	list_add(&sclp_state_change_event.list, &sclp_reg_list);
+	list_add(&sclp_quiesce_event.list, &sclp_reg_list);
+
 	/*
 	 * request the 0x2401 external interrupt
 	 * The sclp driver is initialized early (before kmalloc works). We
@@ -640,14 +658,6 @@
 					      &ext_int_info_hwc) != 0)
 		return -EBUSY;
 
-	spin_lock_init(&sclp_lock);
-	INIT_LIST_HEAD(&sclp_req_queue);
-
-	/* init event list */
-	INIT_LIST_HEAD(&sclp_reg_list);
-	list_add(&sclp_state_change_event.list, &sclp_reg_list);
-	list_add(&sclp_quiesce_event.list, &sclp_reg_list);
-
 	/* enable service-signal external interruptions,
 	 * Control Register 0 bit 22 := 1
 	 * (besides PSW bit 7 must be set to 1 sometimes for external
@@ -762,6 +772,8 @@
 	return unprocessed;
 }
 
+module_init(sclp_init);
+
 EXPORT_SYMBOL(sclp_add_request);
 EXPORT_SYMBOL(sclp_sync_wait);
 EXPORT_SYMBOL(sclp_register);
diff -urN linux-2.5/drivers/s390/char/sclp_con.c linux-2.5-s390/drivers/s390/char/sclp_con.c
--- linux-2.5/drivers/s390/char/sclp_con.c	Mon May  5 01:53:29 2003
+++ linux-2.5-s390/drivers/s390/char/sclp_con.c	Mon May 26 19:20:47 2003
@@ -15,9 +15,11 @@
 #include <linux/timer.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
+#include <linux/err.h>
 
 #include "sclp.h"
 #include "sclp_rw.h"
+#include "sclp_tty.h"
 
 #define SCLP_CON_PRINT_HEADER "sclp console driver: "
 
@@ -69,10 +71,23 @@
 }
 
 static inline void
-__sclp_conbuf_emit(struct sclp_buffer *buffer)
+sclp_conbuf_emit(void)
 {
+	struct sclp_buffer* buffer;
+	unsigned long flags;
+	int count;
+
+	spin_lock_irqsave(&sclp_con_lock, flags);
+	buffer = sclp_conbuf;
+	sclp_conbuf = NULL;
+	if (buffer == NULL) {
+		spin_unlock_irqrestore(&sclp_con_lock, flags);
+		return;
+	}
 	list_add_tail(&buffer->list, &sclp_con_outqueue);
-	if (sclp_con_buffer_count++ == 0)
+	count = sclp_con_buffer_count++;
+	spin_unlock_irqrestore(&sclp_con_lock, flags);
+	if (count == 0)
 		sclp_emit_buffer(buffer, sclp_conbuf_callback);
 }
 
@@ -83,14 +98,7 @@
 static void
 sclp_console_timeout(unsigned long data)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&sclp_con_lock, flags);
-	if (sclp_conbuf != NULL) {
-		__sclp_conbuf_emit(sclp_conbuf);
-		sclp_conbuf = NULL;
-	}
-	spin_unlock_irqrestore(&sclp_con_lock, flags);
+	sclp_conbuf_emit();
 }
 
 /*
@@ -134,8 +142,9 @@
 		 * output buffer. Emit the buffer, create a new buffer
 		 * and then output the rest of the string.
 		 */
-		__sclp_conbuf_emit(sclp_conbuf);
-		sclp_conbuf = NULL;
+		spin_unlock_irqrestore(&sclp_con_lock, flags);
+		sclp_conbuf_emit();
+		spin_lock_irqsave(&sclp_con_lock, flags);
 		message += written;
 		count -= written;
 	} while (count > 0);
@@ -150,11 +159,11 @@
 	spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
-/* returns the device number of the SCLP console */
-static kdev_t
-sclp_console_device(struct console *c)
+static struct tty_driver *
+sclp_console_device(struct console *c, int *index)
 {
-	return	mk_kdev(sclp_console_major, sclp_console_minor);
+	*index = c->index;
+	return &sclp_tty_driver;
 }
 
 /*
@@ -167,13 +176,10 @@
 {
 	unsigned long flags;
 
+	sclp_conbuf_emit();
 	spin_lock_irqsave(&sclp_con_lock, flags);
 	if (timer_pending(&sclp_con_timer))
 		del_timer(&sclp_con_timer);
-	if (sclp_conbuf != NULL) {
-		__sclp_conbuf_emit(sclp_conbuf);
-		sclp_conbuf = NULL;
-	}
 	while (sclp_con_buffer_count > 0) {
 		spin_unlock_irqrestore(&sclp_con_lock, flags);
 		sclp_sync_wait();
@@ -204,17 +210,19 @@
 {
 	void *page;
 	int i;
+	int rc;
 
 	if (!CONSOLE_IS_SCLP)
 		return 0;
-	if (sclp_rw_init() != 0)
-		return 0;
+	rc = sclp_rw_init();
+	if (rc)
+		return rc;
 	/* Allocate pages for output buffering */
 	INIT_LIST_HEAD(&sclp_con_pages);
 	for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
 		page = alloc_bootmem_low_pages(PAGE_SIZE);
 		if (page == NULL)
-			return 0;
+			return -ENOMEM;
 		list_add_tail((struct list_head *) page, &sclp_con_pages);
 	}
 	INIT_LIST_HEAD(&sclp_con_outqueue);
diff -urN linux-2.5/drivers/s390/char/sclp_tty.c linux-2.5-s390/drivers/s390/char/sclp_tty.c
--- linux-2.5/drivers/s390/char/sclp_tty.c	Mon May  5 01:53:02 2003
+++ linux-2.5-s390/drivers/s390/char/sclp_tty.c	Mon May 26 19:20:47 2003
@@ -16,6 +16,8 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 
 #include "ctrlchar.h"
@@ -55,7 +57,7 @@
 static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
 static unsigned short int sclp_tty_chars_count;
 
-static struct tty_driver sclp_tty_driver;
+struct tty_driver sclp_tty_driver;
 static struct tty_struct * sclp_tty_table[1];
 static struct termios * sclp_tty_termios[1];
 static struct termios * sclp_tty_termios_locked[1];
@@ -710,7 +712,7 @@
 	.receiver_fn = sclp_tty_receiver
 };
 
-void
+int __init
 sclp_tty_init(void)
 {
 	void *page;
@@ -718,20 +720,20 @@
 	int rc;
 
 	if (!CONSOLE_IS_SCLP)
-		return;
+		return 0;
 	rc = sclp_rw_init();
-	if (rc != 0) {
+	if (rc) {
 		printk(KERN_ERR SCLP_TTY_PRINT_HEADER
 		       "could not register tty - "
 		       "sclp_rw_init returned %d\n", rc);
-		return;
+		return rc;
 	}
 	/* Allocate pages for output buffering */
 	INIT_LIST_HEAD(&sclp_tty_pages);
 	for (i = 0; i < MAX_KMEM_PAGES; i++) {
 		page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
 		if (page == NULL)
-			return;
+			return -ENOMEM;
 		list_add_tail((struct list_head *) page, &sclp_tty_pages);
 	}
 	INIT_LIST_HEAD(&sclp_tty_outqueue);
@@ -753,8 +755,9 @@
 	sclp_tty_chars_count = 0;
 	sclp_tty = NULL;
 
-	if (sclp_register(&sclp_input_event) != 0)
-		return;
+	rc = sclp_register(&sclp_input_event);
+	if (rc)
+		return rc;
 
 	memset (&sclp_tty_driver, 0, sizeof(struct tty_driver));
 	sclp_tty_driver.magic = TTY_DRIVER_MAGIC;
@@ -810,8 +813,10 @@
 	sclp_tty_driver.write_proc = NULL;
 
 	rc = tty_register_driver(&sclp_tty_driver);
-	if (rc != 0)
+	if (rc)
 		printk(KERN_ERR SCLP_TTY_PRINT_HEADER
 		       "could not register tty - "
-		       "sclp_drv_register returned %d\n", rc);
+		       "tty_register_driver returned %d\n", rc);
+	return rc;
 }
+module_init(sclp_tty_init);
diff -urN linux-2.5/drivers/s390/char/sclp_tty.h linux-2.5-s390/drivers/s390/char/sclp_tty.h
--- linux-2.5/drivers/s390/char/sclp_tty.h	Mon May  5 01:53:31 2003
+++ linux-2.5-s390/drivers/s390/char/sclp_tty.h	Mon May 26 19:20:47 2003
@@ -12,6 +12,8 @@
 #define __SCLP_TTY_H__
 
 #include <linux/ioctl.h>
+#include <linux/termios.h>
+#include <linux/tty_driver.h>
 
 /* This is the type of data structures storing sclp ioctl setting. */
 struct sclp_ioctls {
@@ -64,4 +66,6 @@
 /* get the number of buffers/pages got from kernel at startup */
 #define TIOCSCLPGKBUF	_IOR(SCLP_IOCTL_LETTER, 20, unsigned short)
 
+extern struct tty_driver sclp_tty_driver;
+
 #endif	/* __SCLP_TTY_H__ */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-05-26 17:21 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-26 17:27 [PATCH] s390 (8/10): console device drivers Martin Schwidefsky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).