diff options
| author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2003-05-25 23:35:25 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-05-25 23:35:25 -0700 |
| commit | ed0db08d1f1008ce07abcae8aab5810600aa91d7 (patch) | |
| tree | fd46b6304002980146dfe643c002068b06a93f2c | |
| parent | 9b2a15ef23641346266fc710f86a70663c49e02a (diff) | |
[PATCH] s390: console device drivers.
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.
| -rw-r--r-- | drivers/char/tty_io.c | 5 | ||||
| -rw-r--r-- | drivers/s390/char/con3215.c | 4 | ||||
| -rw-r--r-- | drivers/s390/char/sclp.c | 42 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_con.c | 54 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_tty.c | 25 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_tty.h | 4 |
6 files changed, 79 insertions, 55 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 62bcbcac3aa9..2f73626c2b68 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -145,8 +145,6 @@ static int tty_fasync(int fd, struct file * filp, int on); 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 @@ void __init tty_init(void) #ifdef CONFIG_TN3270 tub3270_init(); #endif -#ifdef CONFIG_SCLP_TTY - sclp_tty_init(); -#endif #ifdef CONFIG_A2232 a2232board_init(); #endif diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 0c4d434de5aa..d663c8b2ff63 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -697,12 +697,12 @@ raw3215_shutdown(struct raw3215_info *raw) 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 --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 92c3ae9b2113..fd22fec80fb2 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -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 @@ static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); /* 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 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) 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 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) } } } - /* 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 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) 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 @@ sclp_sync_wait(void) : "=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 @@ sclp_init(void) /* 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 @@ sclp_init(void) &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 @@ sclp_remove_processed(struct sccb_header *sccb) return unprocessed; } +module_init(sclp_init); + EXPORT_SYMBOL(sclp_add_request); EXPORT_SYMBOL(sclp_sync_wait); EXPORT_SYMBOL(sclp_register); diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 362ea96a9104..f71849549452 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -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 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) } 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 @@ __sclp_conbuf_emit(struct sclp_buffer *buffer) 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 @@ sclp_console_write(struct console *console, const char *message, * 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 @@ sclp_console_write(struct console *console, const char *message, 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 @@ sclp_console_unblank(void) { 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 @@ sclp_console_init(void) { 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 --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index d700ede517cd..57bdce0f673c 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -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 struct tty_struct *sclp_tty; 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 @@ static struct sclp_register sclp_input_event = .receiver_fn = sclp_tty_receiver }; -void +int __init sclp_tty_init(void) { void *page; @@ -718,20 +720,20 @@ sclp_tty_init(void) 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_init(void) 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_init(void) 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 --git a/drivers/s390/char/sclp_tty.h b/drivers/s390/char/sclp_tty.h index 81bfb39bd43c..cdf583f907ab 100644 --- a/drivers/s390/char/sclp_tty.h +++ b/drivers/s390/char/sclp_tty.h @@ -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 @@ struct sclp_ioctls { /* 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__ */ |
