From a863aaa3367d4ebe16d01188e17bc02e4b1f6803 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 13 Apr 2003 21:25:35 -0700 Subject: [PATCH] [PATCH] s390: console changes. s390 console fixes for 3215 and sclp. --- drivers/char/tty_io.c | 2 +- drivers/s390/char/con3215.c | 13 +-- drivers/s390/char/sclp.c | 151 +++++++++++++++++++++-------------- drivers/s390/char/sclp.h | 1 + drivers/s390/char/sclp_con.c | 15 ++-- drivers/s390/char/sclp_cpi.c | 2 +- drivers/s390/char/sclp_rw.c | 46 ++--------- drivers/s390/char/sclp_tty.c | 59 +++++++++----- 8 files changed, 153 insertions(+), 136 deletions(-) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0a5814f00f372..ff54795c42a5b 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -151,7 +151,7 @@ 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 hwc_tty_init(void); +extern void sclp_tty_init(void); extern void tty3215_init(void); extern void tub3270_init(void); extern void rs_360_init(void); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index adcd293b01297..31a5102e84fcf 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -872,7 +872,7 @@ con3215_consetup(struct console *co, char *options) * The console structure for the 3215 console */ static struct console con3215 = { - .name = "tty3215", + .name = "ttyS", .write = con3215_write, .device = con3215_device, .unblank = con3215_unblank, @@ -884,7 +884,7 @@ static struct console con3215 = { * 3215 console initialization code called from console_init(). * NOTE: This is called before kmalloc is available. */ -static void __init +static int __init con3215_init(void) { struct ccw_device *cdev; @@ -894,7 +894,7 @@ con3215_init(void) /* Check if 3215 is to be the console */ if (!CONSOLE_IS_3215) - return; + return -ENODEV; /* Set the console mode for VM */ if (MACHINE_IS_VM) { @@ -913,7 +913,7 @@ con3215_init(void) cdev = ccw_device_probe_console(); if (!cdev) - return; + return -ENODEV; raw3215[0] = raw = (struct raw3215_info *) alloc_bootmem_low(sizeof(struct raw3215_info)); @@ -938,10 +938,12 @@ con3215_init(void) free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); raw3215[0] = NULL; printk("Couldn't find a 3215 console device\n"); - return; + return -ENODEV; } register_console(&con3215); + return 0; } +console_initcall(con3215_init); #endif /* @@ -1122,7 +1124,6 @@ tty3215_unthrottle(struct tty_struct * tty) spin_unlock_irqrestore(raw->lock, flags); } } -console_initcall(con3215_init); /* * Disable writing to a 3215 tty diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index cfef881fb52f4..f68a6b7ef04bb 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -25,14 +24,6 @@ #define SCLP_CORE_PRINT_HEADER "sclp low level driver: " -/* - * decides whether we make use of the macro MACHINE_IS_VM to - * configure the driver for VM at run time (a little bit - * different behaviour); otherwise we use the default - * settings in sclp_data.init_ioctls - */ -#define USE_VM_DETECTION - /* Structure for register_early_external_interrupt. */ static ext_int_info_t ext_int_info_hwc; @@ -111,30 +102,32 @@ __service_call(sclp_cmdw_t command, void *sccb) } static int -__sclp_start_request(void) +sclp_start_request(void) { struct sclp_req *req; int rc; + unsigned long flags; /* quick exit if sclp is already in use */ if (test_bit(SCLP_RUNNING, &sclp_status)) return -EBUSY; - /* quick exit if queue is empty */ - if (list_empty(&sclp_req_queue)) - return -EINVAL; - /* try to start the first request on the request queue. */ - req = list_entry(sclp_req_queue.next, struct sclp_req, list); - rc = __service_call(req->command, req->sccb); - switch (rc) { - case 0: - req->status = SCLP_REQ_RUNNING; - break; - case -EIO: - req->status = SCLP_REQ_FAILED; - if (req->callback != NULL) - req->callback(req, req->callback_data); - break; - } + spin_lock_irqsave(&sclp_lock, flags); + /* Get first request on queue if available */ + req = NULL; + if (!list_empty(&sclp_req_queue)) + req = list_entry(sclp_req_queue.next, struct sclp_req, list); + if (req) { + rc = __service_call(req->command, req->sccb); + if (rc) { + req->status = SCLP_REQ_FAILED; + list_del(&req->list); + } else + req->status = SCLP_REQ_RUNNING; + } else + rc = -EINVAL; + spin_unlock_irqrestore(&sclp_lock, flags); + if (rc == -EIO && req->callback != NULL) + req->callback(req, req->callback_data); return rc; } @@ -156,8 +149,12 @@ sclp_process_evbufs(struct sccb_header *sccb) list_for_each(l, &sclp_reg_list) { t = list_entry(l, struct sclp_register, list); if (t->receive_mask & (1 << (32 - evbuf->type))) { - if (t->receiver_fn != NULL) + if (t->receiver_fn != NULL) { + spin_unlock_irqrestore(&sclp_lock, + flags); t->receiver_fn(evbuf); + spin_lock_irqsave(&sclp_lock, flags); + } break; } else @@ -230,7 +227,7 @@ sclp_unconditional_read_cb(struct sclp_req *read_req, void *data) } /* - * Function to issue Read Event Data/Unconditional Read + * Function to queue Read Event Data/Unconditional Read */ static void __sclp_unconditional_read(void) @@ -278,45 +275,44 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) struct list_head *l; struct sclp_req *req, *tmp; + /* + * 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)) + 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(); - /* - * Only do request callbacks 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)) { - spin_lock(&sclp_lock); - req = NULL; - if (finished_sccb != 0U) { - list_for_each(l, &sclp_req_queue) { - tmp = list_entry(l, struct sclp_req, list); - if (finished_sccb == (u32)(addr_t) tmp->sccb) { - list_del(&tmp->list); - req = tmp; - break; - } + 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); + if (finished_sccb == (u32)(addr_t) tmp->sccb) { + list_del(&tmp->list); + req = tmp; + break; } } - spin_unlock(&sclp_lock); - if (req != NULL) { - req->status = SCLP_REQ_DONE; - 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(); + spin_unlock(&sclp_lock); + /* Perform callback */ + if (req != NULL) { + req->status = SCLP_REQ_DONE; + if (req->callback != NULL) + req->callback(req, req->callback_data); + } /* Now clear the running bit */ clear_bit(SCLP_RUNNING, &sclp_status); /* and start next request on the queue */ - __sclp_start_request(); - spin_unlock(&sclp_lock); + sclp_start_request(); irq_exit(); } @@ -368,15 +364,19 @@ sclp_add_request(struct sclp_req *req) { unsigned long flags; - if (!test_bit(SCLP_INIT, &sclp_status)) + if (!test_bit(SCLP_INIT, &sclp_status)) { + req->status = SCLP_REQ_FAILED; + if (req->callback != NULL) + req->callback(req, req->callback_data); return; + } spin_lock_irqsave(&sclp_lock, flags); /* queue the request */ req->status = SCLP_REQ_QUEUED; list_add_tail(&req->list, &sclp_req_queue); - /* try to start the first request on the queue */ - __sclp_start_request(); spin_unlock_irqrestore(&sclp_lock, flags); + /* try to start the first request on the queue */ + sclp_start_request(); } /* state change notification */ @@ -566,10 +566,9 @@ sclp_init_mask(void) if (test_bit(SCLP_INIT, &sclp_status)) { /* add request to sclp queue */ list_add_tail(&req->list, &sclp_req_queue); - /* and start if SCLP is idle */ - if (!test_bit(SCLP_RUNNING, &sclp_status)) - __sclp_start_request(); spin_unlock_irqrestore(&sclp_lock, flags); + /* and start if SCLP is idle */ + sclp_start_request(); /* now wait for completion */ while (req->status != SCLP_REQ_DONE && req->status != SCLP_REQ_FAILED) @@ -730,7 +729,41 @@ sclp_unregister(struct sclp_register *reg) sclp_init_mask(); } +#define SCLP_EVBUF_PROCESSED 0x80 + +/* + * Traverse array of event buffers contained in SCCB and remove all buffers + * with a set "processed" flag. Return the number of unprocessed buffers. + */ +int +sclp_remove_processed(struct sccb_header *sccb) +{ + struct evbuf_header *evbuf; + int unprocessed; + u16 remaining; + + evbuf = (struct evbuf_header *) (sccb + 1); + unprocessed = 0; + remaining = sccb->length - sizeof(struct sccb_header); + while (remaining > 0) { + remaining -= evbuf->length; + if (evbuf->flags & SCLP_EVBUF_PROCESSED) { + sccb->length -= evbuf->length; + memcpy((void *) evbuf, + (void *) ((addr_t) evbuf + evbuf->length), + remaining); + } else { + unprocessed++; + evbuf = (struct evbuf_header *) + ((addr_t) evbuf + evbuf->length); + } + } + + return unprocessed; +} + EXPORT_SYMBOL(sclp_add_request); EXPORT_SYMBOL(sclp_sync_wait); EXPORT_SYMBOL(sclp_register); EXPORT_SYMBOL(sclp_unregister); +EXPORT_SYMBOL(sclp_error_message); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 031a821ae7f28..b10ec0693efc7 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -126,6 +126,7 @@ void sclp_sync_wait(void); int sclp_register(struct sclp_register *reg); void sclp_unregister(struct sclp_register *reg); char *sclp_error_message(u16 response_code); +int sclp_remove_processed(struct sccb_header *sccb); /* useful inlines */ diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 8f8953740dd01..362ea96a91048 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -24,7 +23,7 @@ #define sclp_console_major 4 /* TTYAUX_MAJOR */ #define sclp_console_minor 64 -#define sclp_console_name "console" +#define sclp_console_name "ttyS" /* Lock to guard over changes to global variables */ static spinlock_t sclp_con_lock; @@ -193,28 +192,29 @@ static struct console sclp_console = .write = sclp_console_write, .device = sclp_console_device, .unblank = sclp_console_unblank, - .flags = CON_PRINTBUFFER + .flags = CON_PRINTBUFFER, + .index = 0 /* ttyS0 */ }; /* * called by console_init() in drivers/char/tty_io.c at boot-time. */ -void __init +static int __init sclp_console_init(void) { void *page; int i; if (!CONSOLE_IS_SCLP) - return; + return 0; if (sclp_rw_init() != 0) - return; + return 0; /* 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; + return 0; list_add_tail((struct list_head *) page, &sclp_con_pages); } INIT_LIST_HEAD(&sclp_con_outqueue); @@ -236,6 +236,7 @@ sclp_console_init(void) /* enable printk-access to this driver */ register_console(&sclp_console); + return 0; } console_initcall(sclp_console_init); diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index d483d8d8c7239..8b7b523925004 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -130,7 +130,7 @@ cpi_prepare_req(void) req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL); if (req == NULL) return ERR_PTR(-ENOMEM); - sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL); + sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA); if (sccb == NULL) { kfree(req); return ERR_PTR(-ENOMEM); diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 0f964f966a609..ff884229540db 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -374,39 +373,6 @@ sclp_rw_init(void) return rc; } -#define SCLP_EVBUF_PROCESSED 0x80 - -/* - * Traverse array of event buffers contained in SCCB and remove all buffers - * with a set "processed" flag. Return the number of unprocessed buffers. - */ -static int -sclp_remove_processed(struct sccb_header *sccb) -{ - struct evbuf_header *evbuf; - int unprocessed; - u16 remaining; - - evbuf = (struct evbuf_header *) (sccb + 1); - unprocessed = 0; - remaining = sccb->length - sizeof(struct sccb_header); - while (remaining > 0) { - remaining -= evbuf->length; - if (evbuf->flags & SCLP_EVBUF_PROCESSED) { - sccb->length -= evbuf->length; - memcpy((void *) evbuf, - (void *) ((addr_t) evbuf + evbuf->length), - remaining); - } else { - unprocessed++; - evbuf = (struct evbuf_header *) - ((addr_t) evbuf + evbuf->length); - } - } - - return unprocessed; -} - static void sclp_buffer_retry(unsigned long data) { @@ -480,10 +446,6 @@ sclp_writedata_callback(struct sclp_req *request, void *data) rc = -ENOMEM; else rc = -EINVAL; - printk(KERN_WARNING SCLP_RW_PRINT_HEADER - "sclp_writedata_callback: %s (response code=0x%x).\n", - sclp_error_message(sccb->header.response_code), - sccb->header.response_code); break; } if (buffer->callback != NULL) @@ -505,8 +467,11 @@ sclp_emit_buffer(struct sclp_buffer *buffer, sclp_finalize_mto(buffer); /* Are there messages in the output buffer ? */ - if (buffer->mto_number == 0) + if (buffer->mto_number == 0) { + if (callback != NULL) + callback(buffer, 0); return; + } sccb = buffer->sccb; if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask) @@ -516,7 +481,8 @@ sclp_emit_buffer(struct sclp_buffer *buffer, /* Use write priority message */ sccb->msg_buf.header.type = EvTyp_PMsgCmd; else { - callback(buffer, -ENOSYS); + if (callback != NULL) + callback(buffer, -ENOSYS); return; } buffer->request.command = SCLP_CMDW_WRITEDATA; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index b77af9e2c8edc..6aa8bc8dc896c 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include @@ -81,9 +81,6 @@ static struct sclp_ioctls sclp_ioctls_init = static int sclp_tty_open(struct tty_struct *tty, struct file *filp) { - /* only 1 SCLP terminal supported */ - if (minor(tty->device) != tty->driver.minor_start) - return -ENODEV; sclp_tty = tty; tty->driver_data = NULL; tty->low_latency = 0; @@ -94,9 +91,6 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp) static void sclp_tty_close(struct tty_struct *tty, struct file *filp) { - /* only 1 SCLP terminal supported */ - if (minor(tty->device) != tty->driver.minor_start) - return; if (tty->count > 1) return; sclp_tty = NULL; @@ -294,8 +288,15 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) static inline void __sclp_ttybuf_emit(struct sclp_buffer *buffer) { + unsigned long flags; + int count; + + spin_lock_irqsave(&sclp_tty_lock, flags); list_add_tail(&buffer->list, &sclp_tty_outqueue); - if (sclp_tty_buffer_count++ == 0) + count = sclp_tty_buffer_count++; + spin_unlock_irqrestore(&sclp_tty_lock, flags); + + if (count == 0) sclp_emit_buffer(buffer, sclp_ttybuf_callback); } @@ -307,13 +308,16 @@ static void sclp_tty_timeout(unsigned long data) { unsigned long flags; + struct sclp_buffer *buf; spin_lock_irqsave(&sclp_tty_lock, flags); - if (sclp_ttybuf != NULL) { - __sclp_ttybuf_emit(sclp_ttybuf); - sclp_ttybuf = NULL; - } + buf = sclp_ttybuf; + sclp_ttybuf = NULL; spin_unlock_irqrestore(&sclp_tty_lock, flags); + + if (buf != NULL) { + __sclp_ttybuf_emit(buf); + } } /* @@ -325,6 +329,7 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user) unsigned long flags; void *page; int written; + struct sclp_buffer *buf; if (count <= 0) return; @@ -353,8 +358,11 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user) * output buffer. Emit the buffer, create a new buffer * and then output the rest of the string. */ - __sclp_ttybuf_emit(sclp_ttybuf); + buf = sclp_ttybuf; sclp_ttybuf = NULL; + spin_unlock_irqrestore(&sclp_tty_lock, flags); + __sclp_ttybuf_emit(buf); + spin_lock_irqsave(&sclp_tty_lock, flags); str += written; count -= written; } while (count > 0); @@ -466,7 +474,8 @@ sclp_tty_flush_buffer(struct tty_struct *tty) /* * push input to tty */ -static void sclp_tty_input(unsigned char* buf, unsigned int count) +static void +sclp_tty_input(unsigned char* buf, unsigned int count) { unsigned int cchar; @@ -706,15 +715,21 @@ sclp_tty_init(void) { void *page; int i; + int rc; if (!CONSOLE_IS_SCLP) return; - if (sclp_rw_init() != 0) + rc = sclp_rw_init(); + if (rc != 0) { + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "sclp_rw_init returned %d\n", rc); return; + } /* 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); + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (page == NULL) return; list_add_tail((struct list_head *) page, &sclp_tty_pages); @@ -744,7 +759,7 @@ sclp_tty_init(void) memset (&sclp_tty_driver, 0, sizeof(struct tty_driver)); sclp_tty_driver.magic = TTY_DRIVER_MAGIC; sclp_tty_driver.owner = THIS_MODULE; - sclp_tty_driver.driver_name = "tty_sclp"; + sclp_tty_driver.driver_name = "sclp_line"; sclp_tty_driver.name = "ttyS"; sclp_tty_driver.name_base = 0; sclp_tty_driver.major = TTY_MAJOR; @@ -795,9 +810,9 @@ sclp_tty_init(void) sclp_tty_driver.read_proc = NULL; sclp_tty_driver.write_proc = NULL; - if (tty_register_driver(&sclp_tty_driver)) - panic("Couldn't register sclp_tty driver\n"); + rc = tty_register_driver(&sclp_tty_driver); + if (rc != 0) + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "sclp_drv_register returned %d\n", rc); } - -console_initcall(sclp_tty_init); - -- 2.53.0