Commit a863aaa3 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: console changes.

s390 console fixes for 3215 and sclp.
parent fefe4ef5
......@@ -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);
......
......@@ -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
......
......@@ -9,7 +9,6 @@
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/bootmem.h>
......@@ -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);
......@@ -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 */
......
......@@ -9,7 +9,6 @@
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/kmod.h>
#include <linux/console.h>
#include <linux/init.h>
......@@ -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);
......@@ -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);
......
......@@ -9,7 +9,6 @@
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/err.h>
......@@ -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;
......
......@@ -9,7 +9,7 @@
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
......@@ -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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment