From 37f00f62affe2ff673a9d5e93fcab154b0e8406c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:53:45 +0200 Subject: TTY: crisv10, remove unused tmp_buf This used to be a helper buffer for generic_serial. generic_serial is gone, tmp_buf shall be removed. Signed-off-by: Jiri Slaby Cc: Mikael Starvik Acked-by: Jesper Nilsson Cc: linux-cris-kernel@axis.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/crisv10.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5b07c0c3a10c..004ee2e9003a 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Input */ #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DEFINE_MUTEX(tmp_buf_mutex); - /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { @@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty, /* first some sanity checks */ - if (!tty || !info->xmit.buf || !tmp_buf) + if (!tty || !info->xmit.buf) return 0; #ifdef SERIAL_DEBUG_DATA @@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp) { struct e100_serial *info; int retval; - unsigned long page; int allocated_resources = 0; info = rs_table + tty->index; @@ -4124,17 +4110,6 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - /* * If the port is in the middle of closing, bail out now */ -- cgit v1.2.3 From 953756e2fb02880d6d6b7d961540a064c6df9f97 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:53:46 +0200 Subject: TTY: crisv10, initialize tty_port The tty_port used in the driver is left uninitialized. Add the initialization there. Signed-off-by: Jiri Slaby Cc: Mikael Starvik Acked-by: Jesper Nilsson Cc: linux-cris-kernel@axis.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/crisv10.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 004ee2e9003a..80b6b1b1f725 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4462,6 +4462,7 @@ static int __init rs_init(void) info->enabled = 0; } } + tty_port_init(&info->port); info->uses_dma_in = 0; info->uses_dma_out = 0; info->line = i; -- cgit v1.2.3 From 560460b8b764b610b01b81f8f44193d77d06ed91 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:19 +0200 Subject: TTY: bfin_jtag_comm, add tty_port And use open count from there. Switch to tty from there will follow. Signed-off-by: Jiri Slaby Cc: Mike Frysinger Cc: uclinux-dist-devel@blackfin.uclinux.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/bfin_jtag_comm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 946f799861f5..d81013c3d229 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -63,8 +63,8 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) static struct tty_driver *bfin_jc_driver; static struct task_struct *bfin_jc_kthread; static struct tty_struct * volatile bfin_jc_tty; -static unsigned long bfin_jc_count; static DEFINE_MUTEX(bfin_jc_tty_mutex); +static struct tty_port port; static volatile struct circ_buf bfin_jc_write_buf; static int @@ -150,8 +150,7 @@ static int bfin_jc_open(struct tty_struct *tty, struct file *filp) { mutex_lock(&bfin_jc_tty_mutex); - pr_debug("open %lu\n", bfin_jc_count); - ++bfin_jc_count; + port.count++; bfin_jc_tty = tty; wake_up_process(bfin_jc_kthread); mutex_unlock(&bfin_jc_tty_mutex); @@ -162,8 +161,7 @@ static void bfin_jc_close(struct tty_struct *tty, struct file *filp) { mutex_lock(&bfin_jc_tty_mutex); - pr_debug("close %lu\n", bfin_jc_count); - if (--bfin_jc_count == 0) + if (--port.count == 0) bfin_jc_tty = NULL; wake_up_process(bfin_jc_kthread); mutex_unlock(&bfin_jc_tty_mutex); @@ -242,6 +240,8 @@ static int __init bfin_jc_init(void) { int ret; + tty_port_init(&port); + bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); if (IS_ERR(bfin_jc_kthread)) return PTR_ERR(bfin_jc_kthread); -- cgit v1.2.3 From e63f9f7478584e9a09d6aaf97f617937358b4dd2 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:20 +0200 Subject: TTY: bfin_jtag_comm, use tty from tty_port Switch from mutex to tty_port->lock and to tty refcounting. This needs a 'continue' to be added to re-grab a tty after schedule returns. And since tty is not protected by bfin_jc_tty_mutex remove it as well. But this needs tty_port->count to be protected by tty_port->lock now. Signed-off-by: Jiri Slaby Cc: Mike Frysinger Cc: uclinux-dist-devel@blackfin.uclinux.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/bfin_jtag_comm.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index d81013c3d229..61fc74fe1747 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -62,8 +62,6 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) static struct tty_driver *bfin_jc_driver; static struct task_struct *bfin_jc_kthread; -static struct tty_struct * volatile bfin_jc_tty; -static DEFINE_MUTEX(bfin_jc_tty_mutex); static struct tty_port port; static volatile struct circ_buf bfin_jc_write_buf; @@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg) uint32_t inbound_len = 0, outbound_len = 0; while (!kthread_should_stop()) { + struct tty_struct *tty = tty_port_tty_get(&port); /* no one left to give data to, so sleep */ - if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { + if (tty == NULL && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for readers\n"); __set_current_state(TASK_UNINTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); + continue; } /* no data available, so just chill */ if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); + tty_kref_put(tty); if (inbound_len) schedule(); else @@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg) /* if incoming data is ready, eat it */ if (bfin_read_DBGSTAT() & EMUDIF) { - struct tty_struct *tty; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty != NULL) { uint32_t emudat = bfin_read_emudat(); if (inbound_len == 0) { @@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg) tty_flip_buffer_push(tty); } } - mutex_unlock(&bfin_jc_tty_mutex); } /* if outgoing data is ready, post it */ @@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg) bfin_write_emudat(outbound_len); pr_debug("outgoing length: 0x%08x\n", outbound_len); } else { - struct tty_struct *tty; int tail = bfin_jc_write_buf.tail; size_t ate = (4 <= outbound_len ? 4 : outbound_len); uint32_t emudat = @@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg) ); bfin_jc_write_buf.tail += ate; outbound_len -= ate; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty) tty_wakeup(tty); - mutex_unlock(&bfin_jc_tty_mutex); pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); } } + tty_kref_put(tty); } __set_current_state(TASK_RUNNING); @@ -149,22 +143,28 @@ bfin_jc_emudat_manager(void *arg) static int bfin_jc_open(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); + unsigned long flags; + + spin_lock_irqsave(&port.lock, flags); port.count++; - bfin_jc_tty = tty; + spin_unlock_irqrestore(&port.lock, flags); + tty_port_tty_set(&port, tty); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); return 0; } static void bfin_jc_close(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); - if (--port.count == 0) - bfin_jc_tty = NULL; + unsigned long flags; + bool last; + + spin_lock_irqsave(&port.lock, flags); + last = --port.count == 0; + spin_unlock_irqrestore(&port.lock, flags); + if (last) + tty_port_tty_set(&port, NULL); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); } /* XXX: we dont handle the put_char() case where we must handle count = 1 */ -- cgit v1.2.3 From f3d9f25097b62eaeb9e5b71358b863c7bf54c600 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:21 +0200 Subject: TTY: HVC, add tty_port And use kref from that. This means we need tty_port->ops->destruct to properly free the structure. This is what destroy_hvc_struct used to do so we leverage that. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 23 ++++++++++++++--------- drivers/tty/hvc/hvc_console.h | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 8880adf5fc6f..12a42730d3c8 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kref_get(&hp->kref); + tty_port_get(&hp->port); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -229,9 +229,9 @@ static int __init hvc_console_init(void) console_initcall(hvc_console_init); /* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kref *kref) +static void hvc_port_destruct(struct tty_port *port) { - struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + struct hvc_struct *hp = container_of(port, struct hvc_struct, port); unsigned long flags; spin_lock(&hvc_structs_lock); @@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); return -1; } @@ -343,7 +343,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); tty_kref_put(tty); tty->driver_data = NULL; - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -397,7 +397,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) } tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } static void hvc_hangup(struct tty_struct *tty) @@ -437,7 +437,7 @@ static void hvc_hangup(struct tty_struct *tty) while(temp_open_count) { --temp_open_count; tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } } @@ -817,6 +817,10 @@ static const struct tty_operations hvc_ops = { #endif }; +static const struct tty_port_operations hvc_port_ops = { + .destruct = hvc_port_destruct, +}; + struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, const struct hv_ops *ops, int outbuf_size) @@ -842,7 +846,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kref_init(&hp->kref); + tty_port_init(&hp->port); + hp->port.ops = &hvc_port_ops; INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); @@ -891,7 +896,7 @@ int hvc_remove(struct hvc_struct *hp) * kref cause it to be removed, which will probably be the tty_vhangup * below. */ - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); /* * This function call will auto chain call hvc_hangup. diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index c335a1492a54..926d9e4b6db7 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -46,6 +46,7 @@ #define HVC_ALLOC_TTY_ADAPTERS 8 struct hvc_struct { + struct tty_port port; spinlock_t lock; int index; struct tty_struct *tty; @@ -61,7 +62,6 @@ struct hvc_struct { struct winsize ws; struct work_struct tty_resize; struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ }; /* implemented by a low level driver */ -- cgit v1.2.3 From 85bbc003b24335e253a392f6a9874103b77abb36 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:22 +0200 Subject: TTY: HVC, use tty from tty_port The driver already used refcounting. So we just switch it to tty_port helpers. And switch to tty_port->lock for tty. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 36 +++++++++++++++--------------------- drivers/tty/hvc/hvc_console.h | 1 - drivers/tty/hvc/hvsi_lib.c | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 12a42730d3c8..92b7f5d5441f 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -323,11 +323,10 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) } /* else count == 0 */ tty->driver_data = hp; - - hp->tty = tty_kref_get(tty); - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, tty); + if (hp->ops->notifier_add) rc = hp->ops->notifier_add(hp, hp->data); @@ -338,9 +337,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * tty fields and return the kref reference. */ if (rc) { - spin_lock_irqsave(&hp->lock, flags); - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); tty_kref_put(tty); tty->driver_data = NULL; tty_port_put(&hp->port); @@ -373,9 +370,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_lock_irqsave(&hp->lock, flags); if (--hp->count == 0) { - /* We are done with the tty pointer now. */ - hp->tty = NULL; spin_unlock_irqrestore(&hp->lock, flags); + /* We are done with the tty pointer now. */ + tty_port_tty_set(&hp->port, NULL); if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); @@ -427,9 +424,8 @@ static void hvc_hangup(struct tty_struct *tty) temp_open_count = hp->count; hp->count = 0; hp->n_outbuf = 0; - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); if (hp->ops->notifier_hangup) hp->ops->notifier_hangup(hp, hp->data); @@ -526,13 +522,12 @@ static void hvc_set_winsz(struct work_struct *work) hp = container_of(work, struct hvc_struct, tty_resize); - spin_lock_irqsave(&hp->lock, hvc_flags); - if (!hp->tty) { - spin_unlock_irqrestore(&hp->lock, hvc_flags); + tty = tty_port_tty_get(&hp->port); + if (!tty) return; - } - ws = hp->ws; - tty = tty_kref_get(hp->tty); + + spin_lock_irqsave(&hp->lock, hvc_flags); + ws = hp->ws; spin_unlock_irqrestore(&hp->lock, hvc_flags); tty_do_resize(tty, &ws); @@ -601,7 +596,7 @@ int hvc_poll(struct hvc_struct *hp) } /* No tty attached, just skip */ - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); if (tty == NULL) goto bail; @@ -681,8 +676,7 @@ int hvc_poll(struct hvc_struct *hp) tty_flip_buffer_push(tty); } - if (tty) - tty_kref_put(tty); + tty_kref_put(tty); return poll_mask; } @@ -880,9 +874,9 @@ int hvc_remove(struct hvc_struct *hp) unsigned long flags; struct tty_struct *tty; - spin_lock_irqsave(&hp->lock, flags); - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); + spin_lock_irqsave(&hp->lock, flags); if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 926d9e4b6db7..594a28fe0da0 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -49,7 +49,6 @@ struct hvc_struct { struct tty_port port; spinlock_t lock; int index; - struct tty_struct *tty; int count; int do_wakeup; char *outbuf; diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 6f4dd83d8695..59c135dd5d20 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp) pr_devel("HVSI@%x: open !\n", pv->termno); /* Keep track of the tty data structure */ - pv->tty = tty_kref_get(hp->tty); + pv->tty = tty_port_tty_get(&hp->port); hvsilib_establish(pv); -- cgit v1.2.3 From 0146b6939074ebe14ece3604fd00e7be128a3812 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:23 +0200 Subject: TTY: HVC, use count from tty_port Now, count is used from tty_port and protected by tty_port->lock. n_outbuf is left unprotected in hvc_hangup now, because there is no point to hold any lock, since other uses are unprotected too. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 40 +++++++++++++++++++++------------------- drivers/tty/hvc/hvc_console.h | 1 - 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 92b7f5d5441f..6c45cbf3fc91 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -313,18 +313,18 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ - if (hp->count++ > 0) { + if (hp->port.count++ > 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); + /* FIXME why taking a reference here? */ tty_kref_get(tty); - spin_unlock_irqrestore(&hp->lock, flags); hvc_kick(); return 0; } /* else count == 0 */ + spin_unlock_irqrestore(&hp->port.lock, flags); tty->driver_data = hp; - spin_unlock_irqrestore(&hp->lock, flags); - tty_port_tty_set(&hp->port, tty); if (hp->ops->notifier_add) @@ -367,10 +367,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); - if (--hp->count == 0) { - spin_unlock_irqrestore(&hp->lock, flags); + if (--hp->port.count == 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); /* We are done with the tty pointer now. */ tty_port_tty_set(&hp->port, NULL); @@ -387,10 +387,10 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) */ tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); } else { - if (hp->count < 0) + if (hp->port.count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", - hp->vtermno, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); + hp->vtermno, hp->port.count); + spin_unlock_irqrestore(&hp->port.lock, flags); } tty_kref_put(tty); @@ -409,24 +409,25 @@ static void hvc_hangup(struct tty_struct *tty) /* cancel pending tty resize work */ cancel_work_sync(&hp->tty_resize); - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* * The N_TTY line discipline has problems such that in a close vs * open->hangup case this can be called after the final close so prevent * that from happening for now. */ - if (hp->count <= 0) { - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->port.count <= 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); return; } - temp_open_count = hp->count; - hp->count = 0; - hp->n_outbuf = 0; - spin_unlock_irqrestore(&hp->lock, flags); + temp_open_count = hp->port.count; + hp->port.count = 0; + spin_unlock_irqrestore(&hp->port.lock, flags); tty_port_tty_set(&hp->port, NULL); + hp->n_outbuf = 0; + if (hp->ops->notifier_hangup) hp->ops->notifier_hangup(hp, hp->data); @@ -474,7 +475,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count if (!hp) return -EPIPE; - if (hp->count <= 0) + /* FIXME what's this (unprotected) check for? */ + if (hp->port.count <= 0) return -EIO; spin_lock_irqsave(&hp->lock, flags); diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 594a28fe0da0..674d23cb919a 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -49,7 +49,6 @@ struct hvc_struct { struct tty_port port; spinlock_t lock; int index; - int count; int do_wakeup; char *outbuf; int outbuf_size; -- cgit v1.2.3 From 1997cf044853a2d83cd0ebc307e292fa9fa819de Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:24 +0200 Subject: TTY: hvcs, add tty_port And use count from there. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 3436436fe2d7..a049ced97430 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); /* One vty-server per hvcs_struct */ struct hvcs_struct { + struct tty_port port; spinlock_t lock; /* @@ -270,7 +271,6 @@ struct hvcs_struct { unsigned int index; struct tty_struct *tty; - int open_count; /* * Used to tell the driver kernel_thread what operations need to take @@ -422,7 +422,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->open_count > 0) { + if (hvcsd->port.count > 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. " "The hvcs device node is still in use.\n"); @@ -789,7 +789,7 @@ static int __devinit hvcs_probe( if (!hvcsd) return -ENODEV; - + tty_port_init(&hvcsd->port); spin_lock_init(&hvcsd->lock); /* Automatically incs the refcount the first time */ kref_init(&hvcsd->kref); @@ -1138,7 +1138,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) if ((retval = hvcs_partner_connect(hvcsd))) goto error_release; - hvcsd->open_count = 1; + hvcsd->port.count = 1; hvcsd->tty = tty; tty->driver_data = hvcsd; @@ -1172,7 +1172,7 @@ fast_open: spin_lock_irqsave(&hvcsd->lock, flags); kref_get(&hvcsd->kref); - hvcsd->open_count++; + hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1216,7 +1216,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->open_count == 0) { + if (--hvcsd->port.count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1242,10 +1242,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) free_irq(irq, hvcsd); kref_put(&hvcsd->kref, destroy_hvcs_struct); return; - } else if (hvcsd->open_count < 0) { + } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); + hvcsd->vdev->unit_address, hvcsd->port.count); } spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1261,7 +1261,7 @@ static void hvcs_hangup(struct tty_struct * tty) spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->open_count; + temp_open_count = hvcsd->port.count; /* * Don't kref put inside the spinlock because the destruction @@ -1276,7 +1276,7 @@ static void hvcs_hangup(struct tty_struct * tty) hvcsd->tty->driver_data = NULL; hvcsd->tty = NULL; - hvcsd->open_count = 0; + hvcsd->port.count = 0; /* This will drop any buffered data on the floor which is OK in a hangup * scenario. */ @@ -1347,7 +1347,7 @@ static int hvcs_write(struct tty_struct *tty, * the middle of a write operation? This is a crummy place to do this * but we want to keep it all in the spinlock. */ - if (hvcsd->open_count <= 0) { + if (hvcsd->port.count <= 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); return -ENODEV; } @@ -1421,7 +1421,7 @@ static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - if (!hvcsd || hvcsd->open_count <= 0) + if (!hvcsd || hvcsd->port.count <= 0) return 0; return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; -- cgit v1.2.3 From 2cd9fa254508f71bd3025992ef5cecbf2120b0e4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:25 +0200 Subject: TTY: hvcs, use kref from tty_port A simple switch. Except we convert destroy_hvcs_struct to be tty_port_operations->destruct... Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index a049ced97430..817f94bf95a1 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -290,12 +290,11 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kref is valid before a tty is connected and + * Any variable below is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the kobject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -304,9 +303,6 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kref to its containing object */ -#define from_kref(k) container_of(k, struct hvcs_struct, kref) - static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_MUTEX(hvcs_init_mutex); @@ -701,10 +697,9 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kref ref count reaches zero */ -static void destroy_hvcs_struct(struct kref *kref) +static void hvcs_destruct_port(struct tty_port *p) { - struct hvcs_struct *hvcsd = from_kref(kref); + struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); struct vio_dev *vdev; unsigned long flags; @@ -741,6 +736,10 @@ static void destroy_hvcs_struct(struct kref *kref) kfree(hvcsd); } +static const struct tty_port_operations hvcs_port_ops = { + .destruct = hvcs_destruct_port, +}; + static int hvcs_get_index(void) { int i; @@ -790,9 +789,8 @@ static int __devinit hvcs_probe( return -ENODEV; tty_port_init(&hvcsd->port); + hvcsd->port.ops = &hvcs_port_ops; spin_lock_init(&hvcsd->lock); - /* Automatically incs the refcount the first time */ - kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev_set_drvdata(&dev->dev, hvcsd); @@ -860,7 +858,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); /* * The hangup is a scheduled function which will auto chain call @@ -1094,7 +1092,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kref_get(&hvcsd->kref); + tty_port_get(&hvcsd->port); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1160,7 +1158,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1171,7 +1169,7 @@ fast_open: hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kref_get(&hvcsd->kref); + tty_port_get(&hvcsd->port); hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1186,7 +1184,7 @@ open_success: error_release: spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1240,7 +1238,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); return; } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1249,7 +1247,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } static void hvcs_hangup(struct tty_struct * tty) @@ -1301,7 +1299,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } } -- cgit v1.2.3 From 6968a7592a1f27386174617b6dbef31044da91ed Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:26 +0200 Subject: TTY: hvcs, use tty from tty_port No refcounting, just a switch. The locking in the driver prevents races, so in fact the refcounting is not needed. But while we have a tty in tty_port, don't duplicate that and remove the one from hvcs_struct. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 817f94bf95a1..d56788c83974 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -270,8 +270,6 @@ struct hvcs_struct { */ unsigned int index; - struct tty_struct *tty; - /* * Used to tell the driver kernel_thread what operations need to take * place upon this hvcs_struct instance. @@ -560,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) static void hvcs_try_write(struct hvcs_struct *hvcsd) { uint32_t unit_address = hvcsd->vdev->unit_address; - struct tty_struct *tty = hvcsd->tty; + struct tty_struct *tty = hvcsd->port.tty; int sent; if (hvcsd->todo_mask & HVCS_TRY_WRITE) { @@ -598,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) spin_lock_irqsave(&hvcsd->lock, flags); unit_address = hvcsd->vdev->unit_address; - tty = hvcsd->tty; + tty = hvcsd->port.tty; hvcs_try_write(hvcsd); @@ -850,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) spin_lock_irqsave(&hvcsd->lock, flags); - tty = hvcsd->tty; + tty = hvcsd->port.tty; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1137,7 +1135,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) goto error_release; hvcsd->port.count = 1; - hvcsd->tty = tty; + hvcsd->port.tty = tty; tty->driver_data = hvcsd; memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); @@ -1223,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) * execute any operations on the TTY even though it is obligated * to deliver any pending I/O to the hypervisor. */ - hvcsd->tty = NULL; + hvcsd->port.tty = NULL; irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1271,8 +1269,8 @@ static void hvcs_hangup(struct tty_struct * tty) hvcsd->todo_mask = 0; /* I don't think the tty needs the hvcs_struct pointer after a hangup */ - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; + tty->driver_data = NULL; + hvcsd->port.tty = NULL; hvcsd->port.count = 0; -- cgit v1.2.3 From 5f566051fbc3e7754f903b3b4bf67a44e0ae2d1a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:27 +0200 Subject: TTY: hvsi, CLOCAL is not in tty->flags It is in termios cflags. So change the test in hvsi_recv_control to do the right thing. Previously it was actually testing TTY_LDISC_OPEN bit, i.e. whether an ldisc is active. And yes, it is most of the time. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index a7488b748647..4006aed42ee2 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -248,7 +248,7 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ - if (hp->tty && !(hp->tty->flags & CLOCAL)) + if (hp->tty && !C_CLOCAL(hp->tty)) *to_hangup = hp->tty; } break; -- cgit v1.2.3 From d73a4e790d05151dadf8c6de84382411a8f073fd Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:28 +0200 Subject: TTY: hvsi, add tty_port And use count from there. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvsi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 4006aed42ee2..113a09abcf7b 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -69,6 +69,7 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { + struct tty_port port; struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ @@ -76,7 +77,6 @@ struct hvsi_struct { spinlock_t lock; int index; struct tty_struct *tty; - int count; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ @@ -751,7 +751,7 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); hp->tty = tty; - hp->count++; + hp->port.count++; atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); spin_unlock_irqrestore(&hp->lock, flags); @@ -808,7 +808,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); - if (--hp->count == 0) { + if (--hp->port.count == 0) { hp->tty = NULL; hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ @@ -841,9 +841,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); } - } else if (hp->count < 0) + } else if (hp->port.count < 0) printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", - hp - hvsi_ports, hp->count); + hp - hvsi_ports, hp->port.count); spin_unlock_irqrestore(&hp->lock, flags); } @@ -857,7 +857,7 @@ static void hvsi_hangup(struct tty_struct *tty) spin_lock_irqsave(&hp->lock, flags); - hp->count = 0; + hp->port.count = 0; hp->n_outbuf = 0; hp->tty = NULL; @@ -1228,6 +1228,7 @@ static int __init hvsi_console_init(void) init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); + tty_port_init(&hp->port); hp->index = hvsi_count; hp->inbuf_end = hp->inbuf; hp->state = HVSI_CLOSED; -- cgit v1.2.3 From 28c0447d743ba94562f981bf09dda61bc4cc6f3b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:29 +0200 Subject: TTY: hvsi, sanitize uses of tty - use tty, not hp->tty wherever possible - pass tty down to some functions and go to step one - do not defer tty_hangup calls -- it is as simple as schedule_work, so might be called with hp->lock held - do not defer tty buffer flips -- since the driver does not use low_latency (it cannot actually), the flip is a simple tail move plus schedule_work. It will make our life easier in the next patch. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvsi.c | 88 +++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 58 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 113a09abcf7b..68b729b8d1eb 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -237,7 +237,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) } static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, - struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) + struct tty_struct *tty, struct hvsi_struct **to_handshake) { struct hvsi_control *header = (struct hvsi_control *)packet; @@ -247,9 +247,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; - /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ - if (hp->tty && !C_CLOCAL(hp->tty)) - *to_hangup = hp->tty; + if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); } break; case VSV_CLOSE_PROTOCOL: @@ -331,7 +330,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) } } -static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, + const char *buf, int len) { int i; @@ -347,7 +347,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) continue; } #endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(hp->tty, c, 0); + tty_insert_flip_char(tty, c, 0); } } @@ -360,7 +360,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) * revisited. */ #define TTY_THRESHOLD_THROTTLE 128 -static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, +static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, const uint8_t *packet) { const struct hvsi_header *header = (const struct hvsi_header *)packet; @@ -371,14 +371,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); if (datalen == 0) - return NULL; + return false; if (overflow > 0) { pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); datalen = TTY_THRESHOLD_THROTTLE; } - hvsi_insert_chars(hp, data, datalen); + hvsi_insert_chars(hp, tty, data, datalen); if (overflow > 0) { /* @@ -390,7 +390,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, hp->n_throttle = overflow; } - return hp->tty; + return true; } /* @@ -399,14 +399,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, * machine during console handshaking (in which case tty = NULL and we ignore * incoming data). */ -static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, - struct tty_struct **hangup, struct hvsi_struct **handshake) +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, + struct hvsi_struct **handshake) { uint8_t *packet = hp->inbuf; int chunklen; + bool flip = false; - *flip = NULL; - *hangup = NULL; *handshake = NULL; chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); @@ -440,12 +439,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, case VS_DATA_PACKET_HEADER: if (!is_open(hp)) break; - if (hp->tty == NULL) + if (tty == NULL) break; /* no tty buffer to put data in */ - *flip = hvsi_recv_data(hp, packet); + flip = hvsi_recv_data(hp, tty, packet); break; case VS_CONTROL_PACKET_HEADER: - hvsi_recv_control(hp, packet, hangup, handshake); + hvsi_recv_control(hp, packet, tty, handshake); break; case VS_QUERY_RESPONSE_PACKET_HEADER: hvsi_recv_response(hp, packet); @@ -462,28 +461,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, packet += len_packet(packet); - if (*hangup || *handshake) { - pr_debug("%s: hangup or handshake\n", __func__); - /* - * we need to send the hangup now before receiving any more data. - * If we get "data, hangup, data", we can't deliver the second - * data before the hangup. - */ + if (*handshake) { + pr_debug("%s: handshake\n", __func__); break; } } compact_inbuf(hp, packet); + if (flip) + tty_flip_buffer_push(tty); + return 1; } -static void hvsi_send_overflow(struct hvsi_struct *hp) +static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) { pr_debug("%s: delivering %i bytes overflow\n", __func__, hp->n_throttle); - hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle); hp->n_throttle = 0; } @@ -494,8 +491,6 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) static irqreturn_t hvsi_interrupt(int irq, void *arg) { struct hvsi_struct *hp = (struct hvsi_struct *)arg; - struct tty_struct *flip; - struct tty_struct *hangup; struct hvsi_struct *handshake; unsigned long flags; int again = 1; @@ -504,25 +499,9 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) while (again) { spin_lock_irqsave(&hp->lock, flags); - again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); + again = hvsi_load_chunk(hp, hp->tty, &handshake); spin_unlock_irqrestore(&hp->lock, flags); - /* - * we have to call tty_flip_buffer_push() and tty_hangup() outside our - * spinlock. But we also have to keep going until we've read all the - * available data. - */ - - if (flip) { - /* there was data put in the tty flip buffer */ - tty_flip_buffer_push(flip); - flip = NULL; - } - - if (hangup) { - tty_hangup(hangup); - } - if (handshake) { pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); schedule_work(&handshake->handshaker); @@ -534,15 +513,11 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { /* we weren't hung up and we weren't throttled, so we can deliver the * rest now */ - flip = hp->tty; - hvsi_send_overflow(hp); + hvsi_send_overflow(hp, hp->tty); + tty_flip_buffer_push(hp->tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (flip) { - tty_flip_buffer_push(flip); - } - return IRQ_HANDLED; } @@ -966,8 +941,8 @@ static int hvsi_write(struct tty_struct *tty, * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls * will see there is no room in outbuf and return. */ - while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { - int chunksize = min(count, hvsi_write_room(hp->tty)); + while ((count > 0) && (hvsi_write_room(tty) > 0)) { + int chunksize = min(count, hvsi_write_room(tty)); BUG_ON(hp->n_outbuf < 0); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); @@ -1014,19 +989,16 @@ static void hvsi_unthrottle(struct tty_struct *tty) { struct hvsi_struct *hp = tty->driver_data; unsigned long flags; - int shouldflip = 0; pr_debug("%s\n", __func__); spin_lock_irqsave(&hp->lock, flags); if (hp->n_throttle) { - hvsi_send_overflow(hp); - shouldflip = 1; + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (shouldflip) - tty_flip_buffer_push(hp->tty); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); } -- cgit v1.2.3 From daea440215ae86bf9fdfe82420710ae749eb73c7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:30 +0200 Subject: TTY: hvsi, use tty from tty_port Now, we switch to the refcounted model and do not need hp->lock to protect hp->tty anymore. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvsi.c | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 68b729b8d1eb..6f5bc49c441f 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -76,7 +76,6 @@ struct hvsi_struct { wait_queue_head_t stateq; /* woken when HVSI state changes */ spinlock_t lock; int index; - struct tty_struct *tty; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ @@ -492,14 +491,17 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) { struct hvsi_struct *hp = (struct hvsi_struct *)arg; struct hvsi_struct *handshake; + struct tty_struct *tty; unsigned long flags; int again = 1; pr_debug("%s\n", __func__); + tty = tty_port_tty_get(&hp->port); + while (again) { spin_lock_irqsave(&hp->lock, flags); - again = hvsi_load_chunk(hp, hp->tty, &handshake); + again = hvsi_load_chunk(hp, tty, &handshake); spin_unlock_irqrestore(&hp->lock, flags); if (handshake) { @@ -509,15 +511,16 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) } spin_lock_irqsave(&hp->lock, flags); - if (hp->tty && hp->n_throttle - && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { - /* we weren't hung up and we weren't throttled, so we can deliver the - * rest now */ - hvsi_send_overflow(hp, hp->tty); - tty_flip_buffer_push(hp->tty); + if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { + /* we weren't hung up and we weren't throttled, so we can + * deliver the rest now */ + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); + tty_kref_put(tty); + return IRQ_HANDLED; } @@ -724,8 +727,8 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) if (hp->state == HVSI_FSP_DIED) return -EIO; + tty_port_tty_set(&hp->port, tty); spin_lock_irqsave(&hp->lock, flags); - hp->tty = tty; hp->port.count++; atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); @@ -784,7 +787,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); if (--hp->port.count == 0) { - hp->tty = NULL; + tty_port_tty_set(&hp->port, NULL); hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ /* only close down connection if it is not the console */ @@ -830,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty) pr_debug("%s\n", __func__); - spin_lock_irqsave(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); + spin_lock_irqsave(&hp->lock, flags); hp->port.count = 0; hp->n_outbuf = 0; - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); } @@ -863,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work) { struct hvsi_struct *hp = container_of(work, struct hvsi_struct, writer.work); + struct tty_struct *tty; unsigned long flags; #ifdef DEBUG static long start_j = 0; @@ -896,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work) start_j = 0; #endif /* DEBUG */ wake_up_all(&hp->emptyq); - tty_wakeup(hp->tty); + tty = tty_port_tty_get(&hp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } out: -- cgit v1.2.3 From de3a60a3436ebfd780ced830cd09880ea9c45957 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:31 +0200 Subject: TTY: ipwireless, use synchronous hangup Do not touch internal workqueue. Call tty_vhangup instead. Note that finished hangup does not necessarily mean that all processes are dead. Especially when the tty is a console. The code assumes that right now. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 4daf962f7055..e5396212e223 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -565,11 +565,11 @@ void ipwireless_tty_free(struct ipw_tty *tty) ttyj->closing = 1; if (ttyj->linux_tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); - tty_hangup(ttyj->linux_tty); - /* Wait till the tty_hangup has completed */ - flush_work_sync(&ttyj->linux_tty->hangup_work); + tty_vhangup(ttyj->linux_tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ + /* FIXME2: hangup does not mean all processes + * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } while (ttyj->open_count) -- cgit v1.2.3 From e6df3cce07a25d7d65c7d3d2cec87cbf02fd21f0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:32 +0200 Subject: TTY: ipwireless, move prints to appropriate places There are two functions which only print a status. Let us do that directly at places where they are called. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index e5396212e223..4270bfd59a7f 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -73,23 +73,6 @@ static char *tty_type_name(int tty_type) return channel_names[tty_type]; } -static void report_registering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": deregistering %s device ttyIPWp%d\n", iftype, - tty->index); -} - static struct ipw_tty *get_tty(int index) { /* @@ -500,8 +483,12 @@ static int add_tty(int j, ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); - if (get_tty(j) == ttys[j]) - report_registering(ttys[j]); + /* check if we provide raw device (if loopback is enabled) */ + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": registering %s device ttyIPWp%d\n", + tty_type_name(tty_type), j); + return 0; } @@ -560,8 +547,10 @@ void ipwireless_tty_free(struct ipw_tty *tty) if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j) == ttyj) - report_deregistering(ttyj); + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": deregistering %s device ttyIPWp%d\n", + tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; if (ttyj->linux_tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); -- cgit v1.2.3 From 7393af808fe1564ad34289b507b950445dfc06ac Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:33 +0200 Subject: TTY: ipwireless, add tty_port And use count from that. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 4270bfd59a7f..0b4964d1eea5 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -44,6 +44,7 @@ #define TTYTYPE_RAS_RAW (2) struct ipw_tty { + struct tty_port port; int index; struct ipw_hardware *hardware; unsigned int channel_idx; @@ -51,7 +52,6 @@ struct ipw_tty { int tty_type; struct ipw_network *network; struct tty_struct *linux_tty; - int open_count; unsigned int control_lines; struct mutex ipw_tty_mutex; int tx_bytes_queued; @@ -100,10 +100,10 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) mutex_unlock(&tty->ipw_tty_mutex); return -ENODEV; } - if (tty->open_count == 0) + if (tty->port.count == 0) tty->tx_bytes_queued = 0; - tty->open_count++; + tty->port.count++; tty->linux_tty = linux_tty; linux_tty->driver_data = tty; @@ -119,9 +119,9 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) static void do_ipw_close(struct ipw_tty *tty) { - tty->open_count--; + tty->port.count--; - if (tty->open_count == 0) { + if (tty->port.count == 0) { struct tty_struct *linux_tty = tty->linux_tty; if (linux_tty != NULL) { @@ -142,7 +142,7 @@ static void ipw_hangup(struct tty_struct *linux_tty) return; mutex_lock(&tty->ipw_tty_mutex); - if (tty->open_count == 0) { + if (tty->port.count == 0) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -171,7 +171,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, return; } - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -213,7 +213,7 @@ static int ipw_write(struct tty_struct *linux_tty, return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return -EINVAL; } @@ -253,7 +253,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; @@ -295,7 +295,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty) if (!tty) return 0; - if (!tty->open_count) + if (!tty->port.count) return 0; return tty->tx_bytes_queued; @@ -376,7 +376,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return get_control_lines(tty); @@ -392,7 +392,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return set_control_lines(tty, set, clear); @@ -406,7 +406,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ @@ -475,6 +475,7 @@ static int add_tty(int j, ttys[j]->network = network; ttys[j]->tty_type = tty_type; mutex_init(&ttys[j]->ipw_tty_mutex); + tty_port_init(&ttys[j]->port); tty_register_device(ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); @@ -561,7 +562,7 @@ void ipwireless_tty_free(struct ipw_tty *tty) * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } - while (ttyj->open_count) + while (ttyj->port.count) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); -- cgit v1.2.3 From 19ef1b7151dc58c4d90a76d364dc93721bb04e9b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:34 +0200 Subject: TTY: ipwireless, use tty from tty_port It does not make the driver less racy though. Close and hangup should be rewritten and tty refcounting used properly. Signed-off-by: Jiri Slaby Cc: Jiri Kosina Acked-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ipwireless/tty.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 0b4964d1eea5..f8b5fa0093a3 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -51,7 +51,6 @@ struct ipw_tty { unsigned int secondary_channel_idx; int tty_type; struct ipw_network *network; - struct tty_struct *linux_tty; unsigned int control_lines; struct mutex ipw_tty_mutex; int tx_bytes_queued; @@ -105,7 +104,7 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) tty->port.count++; - tty->linux_tty = linux_tty; + tty->port.tty = linux_tty; linux_tty->driver_data = tty; linux_tty->low_latency = 1; @@ -122,10 +121,10 @@ static void do_ipw_close(struct ipw_tty *tty) tty->port.count--; if (tty->port.count == 0) { - struct tty_struct *linux_tty = tty->linux_tty; + struct tty_struct *linux_tty = tty->port.tty; if (linux_tty != NULL) { - tty->linux_tty = NULL; + tty->port.tty = NULL; linux_tty->driver_data = NULL; if (tty->tty_type == TTYTYPE_MODEM) @@ -165,7 +164,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, int work = 0; mutex_lock(&tty->ipw_tty_mutex); - linux_tty = tty->linux_tty; + linux_tty = tty->port.tty; if (linux_tty == NULL) { mutex_unlock(&tty->ipw_tty_mutex); return; @@ -553,9 +552,9 @@ void ipwireless_tty_free(struct ipw_tty *tty) ": deregistering %s device ttyIPWp%d\n", tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; - if (ttyj->linux_tty != NULL) { + if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); - tty_vhangup(ttyj->linux_tty); + tty_vhangup(ttyj->port.tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ /* FIXME2: hangup does not mean all processes @@ -651,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, */ if ((old_control_lines & IPW_CONTROL_LINE_DCD) && !(tty->control_lines & IPW_CONTROL_LINE_DCD) - && tty->linux_tty) { - tty_hangup(tty->linux_tty); + && tty->port.tty) { + tty_hangup(tty->port.tty); } } -- cgit v1.2.3 From cea4b2ce4613feae878c0352b1d76f522faef511 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:35 +0200 Subject: TTY: 68328serial, remove serial_state and friends serial_state in 68328serial.h is a duplicated structure. One is defined in linux/serial.h. So let us use that instead. And since the serial flags are identical, use ones from there too. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Acked-by: Greg Ungerer Cc: linux-m68k@lists.linux-m68k.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 55 ++++++++++++----------------- drivers/tty/serial/68328serial.h | 76 ---------------------------------------- 2 files changed, 22 insertions(+), 109 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 5ce782529d65..bf5f81113a0e 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -79,18 +80,6 @@ struct m68k_serial *m68k_consinfo = 0; struct tty_driver *serial_driver; -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW - -#define RS_ISR_PASS_LIMIT 256 - static void change_speed(struct m68k_serial *info); /* @@ -363,7 +352,7 @@ static int startup(struct m68k_serial * info) m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - if (info->flags & S_INITIALIZED) + if (info->flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { @@ -404,7 +393,7 @@ static int startup(struct m68k_serial * info) change_speed(info); - info->flags |= S_INITIALIZED; + info->flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; } @@ -419,7 +408,7 @@ static void shutdown(struct m68k_serial * info) unsigned long flags; uart->ustcnt = 0; /* All off! */ - if (!(info->flags & S_INITIALIZED)) + if (!(info->flags & ASYNC_INITIALIZED)) return; local_irq_save(flags); @@ -432,7 +421,7 @@ static void shutdown(struct m68k_serial * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~S_INITIALIZED; + info->flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -835,11 +824,11 @@ static int set_serial_info(struct m68k_serial * info, if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~S_USR_MASK) != - (info->flags & ~S_USR_MASK))) + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~S_USR_MASK) | - (new_serial.flags & S_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } @@ -853,8 +842,8 @@ static int set_serial_info(struct m68k_serial * info, */ info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~S_FLAGS) | - (new_serial.flags & S_FLAGS)); + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; @@ -1022,13 +1011,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->flags |= S_CLOSING; + info->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait != S_CLOSING_WAIT_NONE) + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we @@ -1064,7 +1053,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); } @@ -1083,7 +1072,7 @@ void rs_hangup(struct tty_struct *tty) shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~S_NORMAL_ACTIVE; + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1104,10 +1093,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (info->flags & S_CLOSING) { + if (info->flags & ASYNC_CLOSING) { interruptible_sleep_on(&info->close_wait); #ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) + if (info->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -1122,7 +1111,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= S_NORMAL_ACTIVE; + info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1147,9 +1136,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, local_irq_enable(); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || - !(info->flags & S_INITIALIZED)) { + !(info->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) + if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -1158,7 +1147,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & S_CLOSING) && do_clocal) + if (!(info->flags & ASYNC_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1176,7 +1165,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (retval) return retval; - info->flags |= S_NORMAL_ACTIVE; + info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h index 3d2faabd766f..a804ea56a0b5 100644 --- a/drivers/tty/serial/68328serial.h +++ b/drivers/tty/serial/68328serial.h @@ -11,69 +11,6 @@ #ifndef _MC683XX_SERIAL_H #define _MC683XX_SERIAL_H - -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; /* FIXME: We don't have AT&T Hub6 boards! */ - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define S_CLOSING_WAIT_INF 0 -#define S_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for S_struct (and serial_struct) flags field - */ -#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define S_SPD_MASK 0x0030 -#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define S_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define S_FLAGS 0x0FFF /* Possible legal S flags */ -#define S_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define S_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define S_CLOSING 0x08000000 /* Serial port is closing */ -#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ - /* * I believe this is the optimal setting that reduces the number of interrupts. * At high speeds the output might become a little "bursted" (use USTCNT_TXHE @@ -162,25 +99,12 @@ struct m68k_serial { wait_queue_head_t close_wait; }; - #define SERIAL_MAGIC 0x5301 -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - /* * Define the number of ports supported and their irqs. */ #define NR_PORTS 1 #define UART_IRQ_DEFNS {UART_IRQ_NUM} -#endif /* __KERNEL__ */ #endif /* !(_MC683XX_SERIAL_H) */ -- cgit v1.2.3 From c21e2654db10bc518b35987617337598fd91ff7e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:36 +0200 Subject: TTY: 68328serial, remove unused stuff from m68k_serial Not everything from struct m68k_serial is really used. So remove unused or only-set members of that structure. Next step is to move it to 68328serial.c and remove 68328serial.h completely. This change also takes status_handle and batten_down_hatches away since they use break_abort but do nothing. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 36 ++++-------------------------------- drivers/tty/serial/68328serial.h | 16 ---------------- 2 files changed, 4 insertions(+), 48 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index bf5f81113a0e..c1cd2147f9dd 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -213,25 +213,6 @@ static void rs_start(struct tty_struct *tty) local_irq_restore(flags); } -/* Drop into either the boot monitor or kadb upon receiving a break - * from keyboard/console input. - */ -static void batten_down_hatches(void) -{ - /* Drop into the debugger */ -} - -static void status_handle(struct m68k_serial *info, unsigned short status) -{ - /* If this is console input and this is a - * 'break asserted' status change interrupt - * see if we can drop into the debugger - */ - if((status & URX_BREAK) && info->break_abort) - batten_down_hatches(); - return; -} - static void receive_chars(struct m68k_serial *info, unsigned short rx) { struct tty_struct *tty = info->tty; @@ -248,7 +229,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) if(info->is_cons) { if(URX_BREAK & rx) { /* whee, break received */ - status_handle(info, rx); return; #ifdef CONFIG_MAGIC_SYSRQ } else if (ch == 0x10) { /* ^P */ @@ -269,16 +249,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) flag = TTY_NORMAL; - if(rx & URX_PARITY_ERROR) { + if (rx & URX_PARITY_ERROR) flag = TTY_PARITY; - status_handle(info, rx); - } else if(rx & URX_OVRUN) { + else if (rx & URX_OVRUN) flag = TTY_OVERRUN; - status_handle(info, rx); - } else if(rx & URX_FRAME_ERROR) { + else if (rx & URX_FRAME_ERROR) flag = TTY_FRAME; - status_handle(info, rx); - } + tty_insert_flip_char(tty, ch, flag); #ifndef CONFIG_XCOPILOT_BUGS } while((rx = uart->urx.w) & URX_DATA_READY); @@ -369,7 +346,6 @@ static int startup(struct m68k_serial * info) */ uart->ustcnt = USTCNT_UEN; - info->xmit_fifo_size = 1; uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; (void)uart->urx.w; @@ -499,7 +475,6 @@ static void change_speed(struct m68k_serial *info) i = (i & ~CBAUDEX) + B38400; } - info->baud = baud_table[i]; uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); @@ -1034,7 +1009,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - info->event = 0; info->tty = NULL; #warning "This is not and has never been valid so fix it" #if 0 @@ -1070,7 +1044,6 @@ void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); - info->event = 0; info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; @@ -1270,7 +1243,6 @@ rs68328_init(void) info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; - info->event = 0; info->count = 0; info->blocked_open = 0; init_waitqueue_head(&info->open_wait); diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h index a804ea56a0b5..971ead5a3918 100644 --- a/drivers/tty/serial/68328serial.h +++ b/drivers/tty/serial/68328serial.h @@ -60,16 +60,7 @@ */ struct m68k_serial { - char soft_carrier; /* Use soft carrier on this channel */ - char break_abort; /* Is serial console in, so process brk/abrt */ char is_cons; /* Is this our console. */ - - /* We need to know the current clock divisor - * to read the bps rate the chip has currently - * loaded. - */ - unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ - int baud; int magic; int baud_base; int port; @@ -77,17 +68,10 @@ struct m68k_serial { int flags; /* defined in tty.h */ int type; /* UART type */ struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; int custom_divisor; int x_char; /* xon/xoff character */ int close_delay; unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - unsigned long last_active; int line; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ -- cgit v1.2.3 From b8aa50f2da25824d378a409bd75325653c997200 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:37 +0200 Subject: TTY: 68328serial, remove garbage - empty functions - unused global variables Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index c1cd2147f9dd..81ed91ed7386 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -73,11 +73,6 @@ static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; /* multiple ports are contiguous in memory */ m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; -struct tty_struct m68k_ttys; -struct m68k_serial *m68k_consinfo = 0; - -#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ - struct tty_driver *serial_driver; static void change_speed(struct m68k_serial *info); @@ -132,17 +127,6 @@ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -/* Sets or clears DTR/RTS on the requested line */ -static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) -{ - if (set) { - /* set the RTS/CTS line */ - } else { - /* clear it */ - } - return; -} - /* Utility routines */ static inline int get_baud(struct m68k_serial *ss) { @@ -1104,9 +1088,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, info->count--; info->blocked_open++; while (1) { - local_irq_disable(); - m68k_rtsdtr(info, 1); - local_irq_enable(); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { -- cgit v1.2.3 From 107afb7a50726cb8ea9ed74d62311ddc59fef1da Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:38 +0200 Subject: TTY: 68328serial, use ulong flags for interrupts status flags passed to local_irq_save/restore should be ulong. Switch tehem to that. Otherwise we get compilation warnings: .../68328serial.c:248:9: warning: comparison of distinct pointer types lacks a cast [enabled by default] .../68328serial.c:257:9: warning: comparison of distinct pointer types lacks a cast [enabled by default] Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 81ed91ed7386..f0d5039a7b34 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -162,7 +162,8 @@ static void rs_stop(struct tty_struct *tty) static int rs_put_char(char ch) { - int flags, loops = 0; + unsigned long flags; + int loops = 0; local_irq_save(flags); @@ -1182,7 +1183,8 @@ static const struct tty_operations rs_ops = { static int __init rs68328_init(void) { - int flags, i; + unsigned long flags; + int i; struct m68k_serial *info; serial_driver = alloc_tty_driver(NR_PORTS); -- cgit v1.2.3 From 1bb2687c3bad13a061e98887bdfb1a6b9ad79542 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:39 +0200 Subject: TTY: 68328serial, remove 68328serial.h All the needed stuff is moved to 68328serial.c now. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 79 +++++++++++++++++++++++++++++++-- drivers/tty/serial/68328serial.h | 94 ---------------------------------------- 2 files changed, 76 insertions(+), 97 deletions(-) delete mode 100644 drivers/tty/serial/68328serial.h (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index f0d5039a7b34..116d932401ed 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -57,8 +57,6 @@ #endif /* CONFIG_M68VZ328 */ #endif /* CONFIG_M68EZ328 */ -#include "68328serial.h" - /* Turn off usage of real serial interrupt code, to "support" Copilot */ #ifdef CONFIG_XCOPILOT_BUGS #undef USE_INTS @@ -66,9 +64,84 @@ #define USE_INTS #endif +/* + * I believe this is the optimal setting that reduces the number of interrupts. + * At high speeds the output might become a little "bursted" (use USTCNT_TXHE + * if that bothers you), but in most cases it will not, since we try to + * transmit characters every time rs_interrupt is called. Thus, quite often + * you'll see that a receive interrupt occures before the transmit one. + * -- Vladimir Gurevich + */ +#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) + +/* + * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special + * "Old data interrupt" which occures whenever the data stay in the FIFO + * longer than 30 bits time. This allows us to use FIFO without compromising + * latency. '328 does not have this feature and without the real 328-based + * board I would assume that RXRE is the safest setting. + * + * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of + * interrupts. RXFE (receive queue full) causes the system to lose data + * at least at 115200 baud + * + * If your board is busy doing other stuff, you might consider to use + * RXRE (data ready intrrupt) instead. + * + * The other option is to make these INTR masks run-time configurable, so + * that people can dynamically adapt them according to the current usage. + * -- Vladimir Gurevich + */ + +/* (es) */ +#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) +#elif defined(CONFIG_M68328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) +#else +#error Please, define the Rx interrupt events for your CPU +#endif +/* (/es) */ + +/* + * This is our internal structure for each serial port's state. + * + * For definitions of the flags field, see serial.h + */ +struct m68k_serial { + char is_cons; /* Is this our console. */ + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +}; + +#define SERIAL_MAGIC 0x5301 + +/* + * Define the number of ports supported and their irqs. + */ +#define NR_PORTS 1 + static struct m68k_serial m68k_soft[NR_PORTS]; -static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; +static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM }; /* multiple ports are contiguous in memory */ m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h deleted file mode 100644 index 971ead5a3918..000000000000 --- a/drivers/tty/serial/68328serial.h +++ /dev/null @@ -1,94 +0,0 @@ -/* 68328serial.h: Definitions for the mc68328 serial driver. - * - * Copyright (C) 1995 David S. Miller - * Copyright (C) 1998 Kenneth Albanowski - * Copyright (C) 1998, 1999 D. Jeff Dionne - * Copyright (C) 1999 Vladimir Gurevich - * - * VZ Support/Fixes Evan Stawnyczy - */ - -#ifndef _MC683XX_SERIAL_H -#define _MC683XX_SERIAL_H - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - * -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real 328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - * -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct m68k_serial { - char is_cons; /* Is this our console. */ - int magic; - int baud_base; - int port; - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - int custom_divisor; - int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; - int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -}; - -#define SERIAL_MAGIC 0x5301 - -/* - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 -#define UART_IRQ_DEFNS {UART_IRQ_NUM} - -#endif /* !(_MC683XX_SERIAL_H) */ -- cgit v1.2.3 From 86264341bb1dafd4d38788b7c877de55b6c2f937 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:40 +0200 Subject: TTY: 68328serial, add tty_port And use count and blocked_count from that. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 116d932401ed..848662c3b16e 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -109,6 +109,7 @@ * For definitions of the flags field, see serial.h */ struct m68k_serial { + struct tty_port tport; char is_cons; /* Is this our console. */ int magic; int baud_base; @@ -122,8 +123,6 @@ struct m68k_serial { int close_delay; unsigned short closing_wait; int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -866,7 +865,7 @@ static int set_serial_info(struct m68k_serial * info, goto check_and_exit; } - if (info->count > 1) + if (info->tport.count > 1) return -EBUSY; /* @@ -1010,6 +1009,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void rs_close(struct tty_struct *tty, struct file * filp) { struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + struct tty_port *port = &info->tport; m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; @@ -1023,7 +1023,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1032,15 +1032,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; + "port->count is %d\n", port->count); + port->count = 1; } - if (--info->count < 0) { + if (--port->count < 0) { printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; + info->line, port->count); + port->count = 0; } - if (info->count) { + if (port->count) { local_irq_restore(flags); return; } @@ -1079,7 +1079,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) (tty->ldisc.open)(tty); } #endif - if (info->blocked_open) { + if (port->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } @@ -1102,7 +1102,7 @@ void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); - info->count = 0; + info->tport.count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); @@ -1116,6 +1116,7 @@ void rs_hangup(struct tty_struct *tty) static int block_til_ready(struct tty_struct *tty, struct file * filp, struct m68k_serial *info) { + struct tty_port *port = &info->tport; DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -1152,15 +1153,15 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that + * this loop, port->count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); - info->count--; - info->blocked_open++; + port->count--; + port->blocked_open++; while (1) { current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || @@ -1188,8 +1189,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; + port->count++; + port->blocked_open--; if (retval) return retval; @@ -1213,7 +1214,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; - info->count++; + info->tport.count++; tty->driver_data = info; info->tty = tty; @@ -1291,6 +1292,7 @@ rs68328_init(void) for(i=0;itport); info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; info->tty = NULL; @@ -1299,8 +1301,6 @@ rs68328_init(void) info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; - info->count = 0; - info->blocked_open = 0; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->line = i; -- cgit v1.2.3 From c26f0115c0fd931e6420b6f565e5f9d154ec627e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:41 +0200 Subject: TTY: 68328serial, use open/close_wait from tty_port Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 848662c3b16e..0c50f2e1ae01 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -127,8 +127,6 @@ struct m68k_serial { int xmit_head; int xmit_tail; int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; }; #define SERIAL_MAGIC 0x5301 @@ -1083,10 +1081,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&port->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); + wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } @@ -1105,7 +1103,7 @@ void rs_hangup(struct tty_struct *tty) info->tport.count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&info->tport.open_wait); } /* @@ -1126,7 +1124,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * until it's done, and then try again. */ if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); + interruptible_sleep_on(&port->close_wait); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -1158,7 +1156,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&info->open_wait, &wait); + add_wait_queue(&port->open_wait, &wait); port->count--; port->blocked_open++; @@ -1187,7 +1185,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, tty_lock(); } current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); + remove_wait_queue(&port->open_wait, &wait); if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; @@ -1301,8 +1299,6 @@ rs68328_init(void) info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); info->line = i; info->is_cons = 1; /* Means shortcuts work */ -- cgit v1.2.3 From 4a85b1fc59734ba2f2e91623d042eadc4efb7886 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:42 +0200 Subject: TTY: 68328serial, use close_delay/closing_wait from tty_port Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 0c50f2e1ae01..e9fd13ec52a8 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -120,8 +120,6 @@ struct m68k_serial { struct tty_struct *tty; int custom_divisor; int x_char; /* xon/xoff character */ - int close_delay; - unsigned short closing_wait; int line; unsigned char *xmit_buf; int xmit_head; @@ -828,8 +826,8 @@ static int get_serial_info(struct m68k_serial * info, tmp.irq = info->irq; tmp.flags = info->flags; tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; + tmp.close_delay = info->tport.close_delay; + tmp.closing_wait = info->tport.closing_wait; tmp.custom_divisor = info->custom_divisor; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -840,6 +838,7 @@ static int get_serial_info(struct m68k_serial * info, static int set_serial_info(struct m68k_serial * info, struct serial_struct * new_info) { + struct tty_port *port = &info->tport; struct serial_struct new_serial; struct m68k_serial old_info; int retval = 0; @@ -853,7 +852,7 @@ static int set_serial_info(struct m68k_serial * info, if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || + (new_serial.close_delay != port->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) return -EPERM; @@ -863,7 +862,7 @@ static int set_serial_info(struct m68k_serial * info, goto check_and_exit; } - if (info->tport.count > 1) + if (port->count > 1) return -EBUSY; /* @@ -875,8 +874,8 @@ static int set_serial_info(struct m68k_serial * info, info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; + port->close_delay = new_serial.close_delay; + port->closing_wait = new_serial.closing_wait; check_and_exit: retval = startup(info); @@ -1048,8 +1047,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1078,9 +1077,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } #endif if (port->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } + if (port->close_delay) + msleep_interruptible(jiffies_to_msecs(port->close_delay)); wake_up_interruptible(&port->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -1296,8 +1294,6 @@ rs68328_init(void) info->tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; info->x_char = 0; info->line = i; info->is_cons = 1; /* Means shortcuts work */ -- cgit v1.2.3 From a85dd82c966a4eb1f4502e62cf49d715d191cefc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:43 +0200 Subject: TTY: 68328serial, use flags from tty_port Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index e9fd13ec52a8..e3a1c557fe95 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -105,8 +105,6 @@ /* * This is our internal structure for each serial port's state. - * - * For definitions of the flags field, see serial.h */ struct m68k_serial { struct tty_port tport; @@ -115,7 +113,6 @@ struct m68k_serial { int baud_base; int port; int irq; - int flags; /* defined in tty.h */ int type; /* UART type */ struct tty_struct *tty; int custom_divisor; @@ -382,7 +379,7 @@ static int startup(struct m68k_serial * info) m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - if (info->flags & ASYNC_INITIALIZED) + if (info->tport.flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { @@ -422,7 +419,7 @@ static int startup(struct m68k_serial * info) change_speed(info); - info->flags |= ASYNC_INITIALIZED; + info->tport.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; } @@ -437,7 +434,7 @@ static void shutdown(struct m68k_serial * info) unsigned long flags; uart->ustcnt = 0; /* All off! */ - if (!(info->flags & ASYNC_INITIALIZED)) + if (!(info->tport.flags & ASYNC_INITIALIZED)) return; local_irq_save(flags); @@ -450,7 +447,7 @@ static void shutdown(struct m68k_serial * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - info->flags &= ~ASYNC_INITIALIZED; + info->tport.flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -824,7 +821,7 @@ static int get_serial_info(struct m68k_serial * info, tmp.line = info->line; tmp.port = info->port; tmp.irq = info->irq; - tmp.flags = info->flags; + tmp.flags = info->tport.flags; tmp.baud_base = info->baud_base; tmp.close_delay = info->tport.close_delay; tmp.closing_wait = info->tport.closing_wait; @@ -854,9 +851,9 @@ static int set_serial_info(struct m68k_serial * info, (new_serial.type != info->type) || (new_serial.close_delay != port->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) + (port->flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | + port->flags = ((port->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; goto check_and_exit; @@ -871,7 +868,7 @@ static int set_serial_info(struct m68k_serial * info, */ info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~ASYNC_FLAGS) | + port->flags = ((port->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->type = new_serial.type; port->close_delay = new_serial.close_delay; @@ -1041,7 +1038,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) local_irq_restore(flags); return; } - info->flags |= ASYNC_CLOSING; + port->flags |= ASYNC_CLOSING; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1081,7 +1078,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) msleep_interruptible(jiffies_to_msecs(port->close_delay)); wake_up_interruptible(&port->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } @@ -1099,7 +1096,7 @@ void rs_hangup(struct tty_struct *tty) rs_flush_buffer(tty); shutdown(info); info->tport.count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; + info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->tport.open_wait); } @@ -1121,10 +1118,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * If the device is in the middle of being closed, then block * until it's done, and then try again. */ - if (info->flags & ASYNC_CLOSING) { + if (port->flags & ASYNC_CLOSING) { interruptible_sleep_on(&port->close_wait); #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; @@ -1139,7 +1136,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -1161,9 +1158,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, while (1) { current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { + !(port->flags & ASYNC_INITIALIZED)) { #ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) + if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; @@ -1172,7 +1169,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & ASYNC_CLOSING) && do_clocal) + if (!(port->flags & ASYNC_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1190,7 +1187,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (retval) return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } -- cgit v1.2.3 From 467712c916764859f7ea698d38d03c51bb827da8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:44 +0200 Subject: TTY: 68328serial, propagate tty We need tty at some places, but info->tty might be NULL at those. Let us propagate tty from callers where we know we have a valid tty. This will make a switch to tty refcounting simpler. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 53 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index e3a1c557fe95..fde573b32ce0 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -140,7 +140,7 @@ m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; struct tty_driver *serial_driver; -static void change_speed(struct m68k_serial *info); +static void change_speed(struct m68k_serial *info, struct tty_struct *tty); /* * Setup for console. Argument comes from the boot command line. @@ -263,9 +263,9 @@ static void rs_start(struct tty_struct *tty) local_irq_restore(flags); } -static void receive_chars(struct m68k_serial *info, unsigned short rx) +static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, + unsigned short rx) { - struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -317,7 +317,7 @@ clear_and_exit: return; } -static void transmit_chars(struct m68k_serial *info) +static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; @@ -328,7 +328,7 @@ static void transmit_chars(struct m68k_serial *info) goto clear_and_return; } - if((info->xmit_cnt <= 0) || info->tty->stopped) { + if ((info->xmit_cnt <= 0) || !tty || tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; @@ -356,6 +356,7 @@ clear_and_return: irqreturn_t rs_interrupt(int irq, void *dev_id) { struct m68k_serial *info = dev_id; + struct tty_struct *tty = info->tty; m68328_uart *uart; unsigned short rx; unsigned short tx; @@ -366,15 +367,17 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) #ifdef USE_INTS tx = uart->utx.w; - if (rx & URX_DATA_READY) receive_chars(info, rx); - if (tx & UTX_TX_AVAIL) transmit_chars(info); + if (rx & URX_DATA_READY) + receive_chars(info, tty, rx); + if (tx & UTX_TX_AVAIL) + transmit_chars(info, tty); #else - receive_chars(info, rx); + receive_chars(info, tty, rx); #endif return IRQ_HANDLED; } -static int startup(struct m68k_serial * info) +static int startup(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; @@ -409,15 +412,15 @@ static int startup(struct m68k_serial * info) uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ - change_speed(info); + change_speed(info, tty); info->tport.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); @@ -428,7 +431,7 @@ static int startup(struct m68k_serial * info) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct m68k_serial * info) +static void shutdown(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; @@ -444,8 +447,8 @@ static void shutdown(struct m68k_serial * info) info->xmit_buf = 0; } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); info->tport.flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); @@ -503,7 +506,7 @@ struct { * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(struct m68k_serial *info) +static void change_speed(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned short port; @@ -511,9 +514,7 @@ static void change_speed(struct m68k_serial *info) unsigned cflag; int i; - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; + cflag = tty->termios->c_cflag; if (!(port = info->port)) return; @@ -832,7 +833,7 @@ static int get_serial_info(struct m68k_serial * info, return 0; } -static int set_serial_info(struct m68k_serial * info, +static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty, struct serial_struct * new_info) { struct tty_port *port = &info->tport; @@ -875,7 +876,7 @@ static int set_serial_info(struct m68k_serial * info, port->closing_wait = new_serial.closing_wait; check_and_exit: - retval = startup(info); + retval = startup(info, tty); return retval; } @@ -961,7 +962,7 @@ static int rs_ioctl(struct tty_struct *tty, return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: - return set_serial_info(info, + return set_serial_info(info, tty, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -980,7 +981,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - change_speed(info); + change_speed(info, tty); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1056,7 +1057,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) uart->ustcnt &= ~USTCNT_RXEN; uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); - shutdown(info); + shutdown(info, tty); rs_flush_buffer(tty); tty_ldisc_flush(tty); @@ -1094,7 +1095,7 @@ void rs_hangup(struct tty_struct *tty) return; rs_flush_buffer(tty); - shutdown(info); + shutdown(info, tty); info->tport.count = 0; info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; @@ -1214,7 +1215,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) /* * Start up serial port */ - retval = startup(info); + retval = startup(info, tty); if (retval) return retval; -- cgit v1.2.3 From 665569d0269be3dd67b768fb65061e1b54bb2faf Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:45 +0200 Subject: TTY: 68328serial, use tty from tty_port And refcount that properly. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index fde573b32ce0..77e10bb89e4b 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -114,7 +114,6 @@ struct m68k_serial { int port; int irq; int type; /* UART type */ - struct tty_struct *tty; int custom_divisor; int x_char; /* xon/xoff character */ int line; @@ -356,7 +355,7 @@ clear_and_return: irqreturn_t rs_interrupt(int irq, void *dev_id) { struct m68k_serial *info = dev_id; - struct tty_struct *tty = info->tty; + struct tty_struct *tty = tty_port_tty_get(&info->tport); m68328_uart *uart; unsigned short rx; unsigned short tx; @@ -374,6 +373,8 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) #else receive_chars(info, tty, rx); #endif + tty_kref_put(tty); + return IRQ_HANDLED; } @@ -1062,7 +1063,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) tty_ldisc_flush(tty); tty->closing = 0; - info->tty = NULL; + tty_port_tty_set(&info->tport, NULL); #warning "This is not and has never been valid so fix it" #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1098,7 +1099,7 @@ void rs_hangup(struct tty_struct *tty) shutdown(info, tty); info->tport.count = 0; info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = NULL; + tty_port_tty_set(&info->tport, NULL); wake_up_interruptible(&info->tport.open_wait); } @@ -1210,7 +1211,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) info->tport.count++; tty->driver_data = info; - info->tty = tty; + tty_port_tty_set(&info->tport, tty); /* * Start up serial port @@ -1289,7 +1290,6 @@ rs68328_init(void) tty_port_init(&info->tport); info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; - info->tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; info->x_char = 0; -- cgit v1.2.3 From 8e32841634958d4927a85b484faf9d2c3c222e4d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 2 Apr 2012 13:54:46 +0200 Subject: TTY: 68328serial, use tty_port_block_til_ready Since the code is identical, use the tty_port_block_til_ready helper instead of re-implemented variant. The code does not perform rtsdts handling, hence we do not need to provide tty port hooks for them. The default ones will be used instead. The only necessary thing is to provide tty_port_operations. It is empty, but has to be there... Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Greg Ungerer Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/68328serial.c | 96 +++------------------------------------- 1 file changed, 5 insertions(+), 91 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 77e10bb89e4b..3ed20e435e59 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -1103,96 +1103,6 @@ void rs_hangup(struct tty_struct *tty) wake_up_interruptible(&info->tport.open_wait); } -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct m68k_serial *info) -{ - struct tty_port *port = &info->tport; - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); -#ifdef SERIAL_DO_RESTART - if (port->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&port->open_wait, &wait); - - port->count--; - port->blocked_open++; - while (1) { - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (port->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(port->flags & ASYNC_CLOSING) && do_clocal) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&port->open_wait, &wait); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - - if (retval) - return retval; - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its S structure into @@ -1220,7 +1130,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) if (retval) return retval; - return block_til_ready(tty, filp, info); + return tty_port_block_til_ready(&info->tport, tty, filp); } /* Finally, routines used to initialize the serial driver. */ @@ -1248,6 +1158,9 @@ static const struct tty_operations rs_ops = { .set_ldisc = rs_set_ldisc, }; +static const struct tty_port_operations rs_port_ops = { +}; + /* rs_init inits the driver */ static int __init rs68328_init(void) @@ -1288,6 +1201,7 @@ rs68328_init(void) info = &m68k_soft[i]; tty_port_init(&info->tport); + info->tport.ops = &rs_port_ops; info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; info->irq = uart_irqs[i]; -- cgit v1.2.3 From 44db113212d86a5870c2bfe8fb767fa842d68805 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:00 +0900 Subject: pch_uart: Delete unused structure member Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 08b9962b8fda..110595ed33f5 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -236,7 +236,6 @@ struct eg20t_port { unsigned int fcr; unsigned int mcr; unsigned int use_dma; - unsigned int use_dma_flag; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; @@ -1441,7 +1440,6 @@ static int pch_uart_verify_port(struct uart_port *port, return -EOPNOTSUPP; #endif priv->use_dma = 1; - priv->use_dma_flag = 1; dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); } -- cgit v1.2.3 From 2a58364da0c04f8dc42cdfe7a4de9d17e536cda8 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:01 +0900 Subject: pch_uart: change type to u8 Target uart register access size is 8bit. However, 32bit is used at 2 points. This patch modifies type "unsigned int" to "unsigned char". Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 110595ed33f5..32ac7ea259db 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -552,14 +552,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, return i; } -static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) +static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv) { - unsigned int iir; - int ret; - - iir = ioread8(priv->membase + UART_IIR); - ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); - return ret; + return ioread8(priv->membase + UART_IIR) &\ + (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP); } static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) @@ -1045,7 +1041,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) unsigned int handled; u8 lsr; int ret = 0; - unsigned int iid; + unsigned char iid; unsigned long flags; spin_lock_irqsave(&priv->port.lock, flags); -- cgit v1.2.3 From b23954a3f73a68a80f260bd3569a81ccc6d13670 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:02 +0900 Subject: pch_uart: change type to %d to %02x %02x format is easier to understand better than %d. Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 32ac7ea259db..d035f8ff913d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1083,7 +1083,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ret = PCH_UART_HANDLED_MS_INT; break; default: /* Never junp to this label */ - dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, + dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__, iid, jiffies); ret = -1; break; -- cgit v1.2.3 From 5181fb3d51d2d886ec9b2fed13a9ad9d5d67ec1f Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:03 +0900 Subject: pch_uart: Support modem status interrupt Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d035f8ff913d..d11096c8ca81 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1043,10 +1043,15 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) int ret = 0; unsigned char iid; unsigned long flags; + int next = 1; + u8 msr; spin_lock_irqsave(&priv->port.lock, flags); handled = 0; - while ((iid = pch_uart_hal_get_iid(priv)) > 1) { + while (next) { + iid = pch_uart_hal_get_iid(priv); + if (iid & PCH_UART_IIR_IP) /* No Interrupt */ + break; switch (iid) { case PCH_UART_IID_RLS: /* Receiver Line Status */ lsr = pch_uart_hal_get_line_status(priv); @@ -1080,12 +1085,18 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ret = handle_tx(priv); break; case PCH_UART_IID_MS: /* Modem Status */ - ret = PCH_UART_HANDLED_MS_INT; + msr = pch_uart_hal_get_modem(priv); + next = 0; /* MS ir prioirty is the lowest. So, MS ir + means final interrupt */ + if ((msr & UART_MSR_ANY_DELTA) == 0) + break; + ret |= PCH_UART_HANDLED_MS_INT; break; default: /* Never junp to this label */ dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__, iid, jiffies); ret = -1; + next = 0; break; } handled |= (unsigned int)ret; -- cgit v1.2.3 From 159d4e1e73dc2c4745b3edb2f2ae51caaae37e5f Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:04 +0900 Subject: pch_uart: delete unused data structure Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d11096c8ca81..d2873c67d25d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -228,7 +228,6 @@ struct eg20t_port { int start_tx; int start_rx; int tx_empty; - int int_dis_flag; int trigger; int trigger_level; struct pch_uart_buffer rxbuf; @@ -1101,10 +1100,6 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) } handled |= (unsigned int)ret; } - if (handled == 0 && iid <= 1) { - if (priv->int_dis_flag) - priv->int_dis_flag = 0; - } spin_unlock_irqrestore(&priv->port.lock, flags); return IRQ_RETVAL(handled); @@ -1199,7 +1194,6 @@ static void pch_uart_stop_rx(struct uart_port *port) priv = container_of(port, struct eg20t_port, port); priv->start_rx = 0; pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); - priv->int_dis_flag = 1; } /* Enable the modem status interrupts. */ -- cgit v1.2.3 From 04e2c2e3bfb1652510d4c12ac2837a8f8b08bd3a Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:05 +0900 Subject: pch_uart: Fix return value issue Currently, occurring line status interrupt, returned value is not set in interrupt handler function. As a result, 0 can be returned. This patch adds setting returned value. Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d2873c67d25d..e7d91d973d52 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -39,6 +39,7 @@ enum { PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT, + PCH_UART_HANDLED_LS_INT_SHIFT, }; enum { @@ -63,6 +64,8 @@ enum { PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) + #define PCH_UART_RBR 0x00 #define PCH_UART_THR 0x00 @@ -1058,6 +1061,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) UART_LSR_PE | UART_LSR_OE)) { pch_uart_err_ir(priv, lsr); ret = PCH_UART_HANDLED_RX_ERR_INT; + } else { + ret = PCH_UART_HANDLED_LS_INT; } break; case PCH_UART_IID_RDR: /* Received Data Ready */ -- cgit v1.2.3 From ef4f9d4f09265b60fcb6bfa31a614ea84a72b7a8 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 26 Mar 2012 14:43:06 +0900 Subject: pch_uart: Fix duplicate memory release issue Add initialize variable to prevent duplicate free memory. Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index e7d91d973d52..6e96304b7c8f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -656,10 +656,13 @@ static void pch_free_dma(struct uart_port *port) dma_release_channel(priv->chan_rx); priv->chan_rx = NULL; } - if (sg_dma_address(&priv->sg_rx)) - dma_free_coherent(port->dev, port->fifosize, - sg_virt(&priv->sg_rx), - sg_dma_address(&priv->sg_rx)); + + if (priv->rx_buf_dma) { + dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, + priv->rx_buf_dma); + priv->rx_buf_virt = NULL; + priv->rx_buf_dma = 0; + } return; } -- cgit v1.2.3 From 871bdea6f8c64517635bec352b8bec6b72a26d80 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Wed, 21 Mar 2012 01:26:45 +0100 Subject: tty/vt: handle bad user buffer in {G,P}IO_CMAP ioctl set_get_cmap() ignored the result of {get,put}_user(), causing ioctl(vt, {G,P}IO_CMAP, 0xdeadbeef) to silently fail. Another side effect of this: calling the PIO_CMAP ioctl with an invalid buffer would zero the default colormap and the palette for all vts (all colors set to black). Leave the default colormap intact and return -EFAULT when reading/writing to the userspace buffer fails. Signed-off-by: Michael Gehring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 68 +++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 36 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3bdd4b19dd06..5836289bd861 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3893,36 +3893,6 @@ static void set_palette(struct vc_data *vc) vc->vc_sw->con_set_palette(vc, color_table); } -static int set_get_cmap(unsigned char __user *arg, int set) -{ - int i, j, k; - - WARN_CONSOLE_UNLOCKED(); - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(vc_cons[i].d); - } - } - return 0; -} - /* * Load palette into the DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. @@ -3930,24 +3900,50 @@ static int set_get_cmap(unsigned char __user *arg, int set) int con_set_cmap(unsigned char __user *arg) { - int rc; + int i, j, k; + unsigned char colormap[3*16]; + + if (copy_from_user(colormap, arg, sizeof(colormap))) + return -EFAULT; console_lock(); - rc = set_get_cmap (arg,1); + for (i = k = 0; i < 16; i++) { + default_red[i] = colormap[k++]; + default_grn[i] = colormap[k++]; + default_blu[i] = colormap[k++]; + } + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + for (j = k = 0; j < 16; j++) { + vc_cons[i].d->vc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + set_palette(vc_cons[i].d); + } console_unlock(); - return rc; + return 0; } int con_get_cmap(unsigned char __user *arg) { - int rc; + int i, k; + unsigned char colormap[3*16]; console_lock(); - rc = set_get_cmap (arg,0); + for (i = k = 0; i < 16; i++) { + colormap[k++] = default_red[i]; + colormap[k++] = default_grn[i]; + colormap[k++] = default_blu[i]; + } console_unlock(); - return rc; + if (copy_to_user(arg, colormap, sizeof(colormap))) + return -EFAULT; + + return 0; } void reset_palette(struct vc_data *vc) -- cgit v1.2.3 From c56a00a165712fd73081f40044b1e64407bb1875 Mon Sep 17 00:00:00 2001 From: Xiaobing Tu Date: Fri, 16 Mar 2012 03:00:26 +0000 Subject: tty: hold lock across tty buffer finding and buffer filling tty_buffer_request_room is well protected, but while after it returns, it releases the port->lock. tty->buf.tail might be modified by either irq handler or other threads. The patch adds more protection by holding the lock across tty buffer finding and buffer filling. Signed-off-by: Alek Du Signed-off-by: Xiaobing Tu Cc: Jiri Slaby Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 85 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 20 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6c9b7cd6778a..91e326ffe7db 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } - /** - * tty_buffer_request_room - grow tty buffer if needed + * __tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * - * Locking: Takes tty->buf.lock + * Locking: Caller must hold tty->buf.lock */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) { struct tty_buffer *b, *n; int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ @@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) size = left; } - spin_unlock_irqrestore(&tty->buf.lock, flags); return size; } + + +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + unsigned long flags; + int length; + + spin_lock_irqsave(&tty->buf.lock, flags); + length = __tty_buffer_request_room(tty, size); + spin_unlock_irqrestore(&tty->buf.lock, flags); + return length; +} EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** @@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, flag, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, flags); copied += space; chars += space; /* There is a small chance that we need to split the data over @@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, __flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, __flags); copied += space; chars += space; flags += space; @@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip); int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used; tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, __flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); -- cgit v1.2.3 From a2f892060f174e5f90041167ca00eb9e68badcb8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 13 Apr 2012 10:31:32 +0200 Subject: TTY: hvc, fix TTY refcounting A -next commit "TTY: HVC, use tty from tty_port" switched the driver to use tty_port helper for tty refcounting. But it omitted to remove manual tty refcounting from open, close and hangup. So now we are getting random crashes caused by use-after-free: Unable to handle kernel paging request for data at address 0xc0000003f9d550 Faulting instruction address: 0xc0000000001b7f40 Oops: Kernel access of bad area, sig: 11 [#1] ... NIP: c0000000001b7f40 LR: c0000000001b7f14 CTR: c0000000000e04f0 ... NIP [c0000000001b7f40] .__kmalloc+0x70/0x230 LR [c0000000001b7f14] .__kmalloc+0x44/0x230 Call Trace: [c0000003f68bf930] [c0000003f68bf9b0] 0xc0000003f68bf9b0 (unreliable) [c0000003f68bf9e0] [c0000000001e5424] .alloc_fdmem+0x24/0x70 [c0000003f68bfa60] [c0000000001e54f8] .alloc_fdtable+0x88/0x130 [c0000003f68bfaf0] [c0000000001e5924] .dup_fd+0x384/0x450 [c0000003f68bfbd0] [c00000000009a310] .copy_process+0x880/0x11d0 [c0000003f68bfcd0] [c00000000009aee0] .do_fork+0x70/0x400 [c0000003f68bfdc0] [c0000000000141c4] .sys_clone+0x54/0x70 [c0000003f68bfe30] [c000000000009aa0] .ppc_clone+0x8/0xc Fix that by complete removal of tty_kref_get/put in open/close/hangup paths. Signed-off-by: Jiri Slaby Reported-and-tested-by: Michael Neuling Cc: Stephen Rothwell Cc: ppc-dev Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_console.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 6c45cbf3fc91..2d691eb7c40a 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -317,8 +317,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) /* Check and then increment for fast path open. */ if (hp->port.count++ > 0) { spin_unlock_irqrestore(&hp->port.lock, flags); - /* FIXME why taking a reference here? */ - tty_kref_get(tty); hvc_kick(); return 0; } /* else count == 0 */ @@ -338,7 +336,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) */ if (rc) { tty_port_tty_set(&hp->port, NULL); - tty_kref_put(tty); tty->driver_data = NULL; tty_port_put(&hp->port); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); @@ -393,7 +390,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->port.lock, flags); } - tty_kref_put(tty); tty_port_put(&hp->port); } @@ -433,7 +429,6 @@ static void hvc_hangup(struct tty_struct *tty) while(temp_open_count) { --temp_open_count; - tty_kref_put(tty); tty_port_put(&hp->port); } } -- cgit v1.2.3 From 4fd0690bb0c3955983560bb2767ee82e2b197f9b Mon Sep 17 00:00:00 2001 From: "Rajanikanth H.V" Date: Mon, 26 Mar 2012 11:17:02 +0200 Subject: serial: pl011: implement workaround for CTS clear event issue Problem Observed: - interrupt status is set by rising or falling edge on CTS line - interrupt status is cleared on a .0. to .1. transition of the interrupt-clear register bit 1. - interrupt-clear register is reset by hardware once the interrupt status is .0.. Remark: It seems not possible to read this register back by the CPU though, but internally this register exists. - when simultaneous set and reset event on the interrupt status happens, then the set-event has priority and the status remains .1.. As a result the interrupt-clear register is not reset to .0., and no new .0. to .1. transition can be detected on it when writing a .1. to it. This implies race condition, the clear must be performed at least one UARTCLK the riding edge of CTS RIS interrupt. Fix: Instead of resetting UART as done in commit c16d51a32bbb61ac8fd96f78b5ce2fccfe0fb4c3 "amba pl011: workaround for uart registers lockup" do the following: write .0. and then .1. to the interrupt-clear register to make sure that this transition is detected. According to the datasheet writing a .0. does not have any effect, but actually it allows to reset the internal interrupt-clear register. Take into account: The .0. needs to last at least for one clk_uart clock period (~ 38 MHz, 26.08ns) This way we can do away with the tasklet and keep only a tiny fix triggered by the variant flag introduced in this patch. Signed-off-by: Guillaume Jaunet Signed-off-by: Christophe Arnal Signed-off-by: Matthias Locher Signed-off-by: Rajanikanth H.V Reviewed-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 109 +++++++--------------------------------- 1 file changed, 18 insertions(+), 91 deletions(-) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 0c65c9e66986..aee85238ccfc 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -67,30 +67,6 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) - -#define UART_WA_SAVE_NR 14 - -static void pl011_lockup_wa(unsigned long data); -static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { - ST_UART011_DMAWM, - ST_UART011_TIMEOUT, - ST_UART011_LCRH_RX, - UART011_IBRD, - UART011_FBRD, - ST_UART011_LCRH_TX, - UART011_IFLS, - ST_UART011_XFCR, - ST_UART011_XON1, - ST_UART011_XON2, - ST_UART011_XOFF1, - ST_UART011_XOFF2, - UART011_CR, - UART011_IMSC -}; - -static u32 uart_wa_regdata[UART_WA_SAVE_NR]; -static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); - /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -100,6 +76,7 @@ struct vendor_data { bool oversampling; bool interrupt_may_hang; /* vendor-specific */ bool dma_threshold; + bool cts_event_workaround; }; static struct vendor_data vendor_arm = { @@ -109,6 +86,7 @@ static struct vendor_data vendor_arm = { .lcrh_rx = UART011_LCRH, .oversampling = false, .dma_threshold = false, + .cts_event_workaround = false, }; static struct vendor_data vendor_st = { @@ -119,6 +97,7 @@ static struct vendor_data vendor_st = { .oversampling = true, .interrupt_may_hang = true, .dma_threshold = true, + .cts_event_workaround = true, }; static struct uart_amba_port *amba_ports[UART_NR]; @@ -1054,69 +1033,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #define pl011_dma_flush_buffer NULL #endif - -/* - * pl011_lockup_wa - * This workaround aims to break the deadlock situation - * when after long transfer over uart in hardware flow - * control, uart interrupt registers cannot be cleared. - * Hence uart transfer gets blocked. - * - * It is seen that during such deadlock condition ICR - * don't get cleared even on multiple write. This leads - * pass_counter to decrease and finally reach zero. This - * can be taken as trigger point to run this UART_BT_WA. - * - */ -static void pl011_lockup_wa(unsigned long data) -{ - struct uart_amba_port *uap = amba_ports[0]; - void __iomem *base = uap->port.membase; - struct circ_buf *xmit = &uap->port.state->xmit; - struct tty_struct *tty = uap->port.state->port.tty; - int buf_empty_retries = 200; - int loop; - - /* Stop HCI layer from submitting data for tx */ - tty->hw_stopped = 1; - while (!uart_circ_empty(xmit)) { - if (buf_empty_retries-- == 0) - break; - udelay(100); - } - - /* Backup registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); - - /* Disable UART so that FIFO data is flushed out */ - writew(0x00, uap->port.membase + UART011_CR); - - /* Soft reset UART module */ - if (uap->port.dev->platform_data) { - struct amba_pl011_data *plat; - - plat = uap->port.dev->platform_data; - if (plat->reset) - plat->reset(); - } - - /* Restore registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - writew(uart_wa_regdata[loop] , - uap->port.membase + uart_wa_reg[loop]); - - /* Initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + UART01x_FR) & - UART01x_FR_MODEM_ANY; - - if (readl(base + UART011_MIS) & 0x2) - printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); - - /* Start Tx/Rx */ - tty->hw_stopped = 0; -} - static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1245,12 +1161,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id) unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; + unsigned int dummy_read; spin_lock_irqsave(&uap->port.lock, flags); status = readw(uap->port.membase + UART011_MIS); if (status) { do { + if (uap->vendor->cts_event_workaround) { + /* workaround to make sure that all bits are unlocked.. */ + writew(0x00, uap->port.membase + UART011_ICR); + + /* + * WA: introduce 26ns(1 uart clk) delay before W1C; + * single apb access will incur 2 pclk(133.12Mhz) delay, + * so add 2 dummy reads + */ + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); + } + writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), uap->port.membase + UART011_ICR); @@ -1267,11 +1197,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & UART011_TXIS) pl011_tx_chars(uap); - if (pass_counter-- == 0) { - if (uap->interrupt_may_hang) - tasklet_schedule(&pl011_lockup_tlet); + if (pass_counter-- == 0) break; - } status = readw(uap->port.membase + UART011_MIS); } while (status != 0); -- cgit v1.2.3 From 7c77c8decfd14a611ddcba071782a9520e4bb3f8 Mon Sep 17 00:00:00 2001 From: "Govindraj.R" Date: Tue, 3 Apr 2012 19:12:34 +0530 Subject: OMAP2+: UART: Remove cpu checks for populating errata flags Currently the errata is populated based on cpu checks this can be removed and replaced with module version check of uart ip block. MVR reg is provided within the uart reg map use the same to populate the errata and thus now errata population and handling can be managed within the driver itself. Cc: Paul Walmsley Cc: Kevin Hilman Signed-off-by: Felipe Balbi Signed-off-by: Govindraj.R Reviewed-by: Jon Hunter Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/serial.c | 8 --- arch/arm/plat-omap/include/plat/omap-serial.h | 1 - drivers/tty/serial/omap-serial.c | 74 ++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 10 deletions(-) (limited to 'drivers/tty') diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 0cdd359a128e..6affdd4bee62 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -355,14 +355,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout; - /* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */ - if (!cpu_is_omap2420() && !cpu_is_ti816x()) - omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS; - - /* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */ - if (cpu_is_omap34xx() || cpu_is_omap3630()) - omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE; - pdata = &omap_up; pdata_size = sizeof(struct omap_uart_port_info); diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 9ff444469f3d..1a52725ffcf2 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -65,7 +65,6 @@ struct omap_uart_port_info { bool dma_enabled; /* To specify DMA Mode */ unsigned int uartclk; /* UART clock rate */ upf_t flags; /* UPF_* flags */ - u32 errata; unsigned int dma_rx_buf_size; unsigned int dma_rx_timeout; unsigned int autosuspend_timeout; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0121486ac4fa..0555c964e713 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -44,6 +44,13 @@ #include #include +#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) + +#define OMAP_UART_REV_42 0x0402 +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 + #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ /* SCR register bitmasks */ @@ -53,6 +60,17 @@ #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT 30 + +#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f + +#define OMAP_UART_MVR_MAJ_MASK 0x700 +#define OMAP_UART_MVR_MAJ_SHIFT 8 +#define OMAP_UART_MVR_MIN_MASK 0x3f + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ @@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) return; } +static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +{ + u32 mvr, scheme; + u16 revision, major, minor; + + mvr = serial_in(up, UART_OMAP_MVER); + + /* Check revision register scheme */ + scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + + switch (scheme) { + case 0: /* Legacy Scheme: OMAP2/3 */ + /* MINOR_REV[0:4], MAJOR_REV[4:7] */ + major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> + OMAP_UART_LEGACY_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); + break; + case 1: + /* New Scheme: OMAP4+ */ + /* MINOR_REV[0:5], MAJOR_REV[8:10] */ + major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> + OMAP_UART_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_MVR_MIN_MASK); + break; + default: + dev_warn(&up->pdev->dev, + "Unknown %s revision, defaulting to highest\n", + up->name); + /* highest possible revision */ + major = 0xff; + minor = 0xff; + } + + /* normalize revision for the driver */ + revision = UART_BUILD_REVISION(major, minor); + + switch (revision) { + case OMAP_UART_REV_46: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_52: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_63: + up->errata |= UART_ERRATA_i202_MDR1_ACCESS; + break; + default: + break; + } +} + static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1443,7 +1514,6 @@ static int serial_omap_probe(struct platform_device *pdev) "%d\n", DEFAULT_CLK_SPEED); } up->uart_dma.uart_base = mem->start; - up->errata = omap_up_info->errata; if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start; @@ -1473,6 +1543,8 @@ static int serial_omap_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); + omap_serial_fill_features_erratas(up); + ui[up->port.line] = up; serial_omap_add_console_port(up); -- cgit v1.2.3 From bf03f65b7967df5807ddef7b99f8a41d4c94fc70 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 10 Apr 2012 14:10:53 -0700 Subject: tegra, serial8250: add ->handle_break() uart_port op The "KT" serial port has another use case for a "received break" quirk, so before adding another special case to the 8250 core take this opportunity to push such quirks out of the core and into a uart_port op. Stephen says: "If the callback function is to no longer live in 8250.c itself, arch/arm/mach-tegra/devices.c isn't logically a good place to put it, and that file will be going away once we get rid of all the board files and move solely to device tree." ...so since 8250_pci.c houses all the quirks for pci serial devices this quirk is similarly housed in of_serial.c. Once the open firmware conversion completes the infrastructure details (include/linux/of_serial.h, and the export) can all be removed to make this self contained to of_serial.c. Cc: Nhan H Mai Cc: Colin Cross Cc: Olof Johansson [stephen: kill CONFIG_SERIAL_TEGRA in favor just using CONFIG_ARCH_TEGRA] Cc: Grant Likely Acked-by: Arnd Bergmann Acked-by: Sudhakar Mamillapalli Reported-by: Alan Cox Acked-by: Alan Cox Signed-off-by: Dan Williams Acked-by: Stephen Warren Tested-by: Stephen Warren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-tegra/board-harmony.c | 2 ++ arch/arm/mach-tegra/board-paz00.c | 3 +++ arch/arm/mach-tegra/board-seaboard.c | 2 ++ arch/arm/mach-tegra/board-trimslice.c | 2 ++ drivers/tty/serial/8250/8250.c | 34 +++------------------------------- drivers/tty/serial/of_serial.c | 26 ++++++++++++++++++++++++++ include/linux/of_serial.h | 17 +++++++++++++++++ include/linux/serial_8250.h | 1 + include/linux/serial_core.h | 5 +++++ 9 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 include/linux/of_serial.h (limited to 'drivers/tty') diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index c00aadb01e09..222182e00226 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { .irq = INT_UARTD, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .type = PORT_TEGRA, + .handle_break = tegra_serial_handle_break, .iotype = UPIO_MEM, .regshift = 2, .uartclk = 216000000, diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index 330afdfa2475..d0735c70d688 100644 --- a/arch/arm/mach-tegra/board-paz00.c +++ b/arch/arm/mach-tegra/board-paz00.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { .irq = INT_UARTA, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .type = PORT_TEGRA, + .handle_break = tegra_serial_handle_break, .iotype = UPIO_MEM, .regshift = 2, .uartclk = 216000000, @@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { .irq = INT_UARTC, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .type = PORT_TEGRA, + .handle_break = tegra_serial_handle_break, .iotype = UPIO_MEM, .regshift = 2, .uartclk = 216000000, diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c index d669847f0485..5b687b8258c0 100644 --- a/arch/arm/mach-tegra/board-seaboard.c +++ b/arch/arm/mach-tegra/board-seaboard.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { /* Memory and IRQ filled in before registration */ .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .type = PORT_TEGRA, + .handle_break = tegra_serial_handle_break, .iotype = UPIO_MEM, .regshift = 2, .uartclk = 216000000, diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c index cd52820a3e37..f7358586b523 100644 --- a/arch/arm/mach-tegra/board-trimslice.c +++ b/arch/arm/mach-tegra/board-trimslice.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = { .irq = INT_UARTA, .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE, .type = PORT_TEGRA, + .handle_break = tegra_serial_handle_break, .iotype = UPIO_MEM, .regshift = 2, .uartclk = 216000000, diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 5b149b466ec8..dffd623b7974 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -1331,27 +1331,6 @@ static void serial8250_enable_ms(struct uart_port *port) serial_port_out(port, UART_IER, up->ier); } -/* - * Clear the Tegra rx fifo after a break - * - * FIXME: This needs to become a port specific callback once we have a - * framework for this - */ -static void clear_rx_fifo(struct uart_8250_port *up) -{ - unsigned int status, tmout = 10000; - do { - status = serial_in(up, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = serial_in(up, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} - /* * serial8250_rx_chars: processes according to the passed in LSR * value, and returns the remaining LSR bits not handled @@ -1386,19 +1365,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) up->lsr_saved_flags = 0; if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ if (lsr & UART_LSR_BI) { lsr &= ~(UART_LSR_FE | UART_LSR_PE); port->icount.brk++; - /* - * If tegra port then clear the rx fifo to - * accept another break/character. - */ - if (port->type == PORT_TEGRA) - clear_rx_fifo(up); - /* * We do the SysRQ and SAK checking * here because otherwise the break @@ -3037,6 +3006,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_in = p->serial_in; port.serial_out = p->serial_out; port.handle_irq = p->handle_irq; + port.handle_break = p->handle_break; port.set_termios = p->set_termios; port.pm = p->pm; port.dev = &dev->dev; @@ -3209,6 +3179,8 @@ int serial8250_register_port(struct uart_port *port) uart->port.set_termios = port->set_termios; if (port->pm) uart->port.pm = port->pm; + if (port->handle_break) + uart->port.handle_break = port->handle_break; if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index e8c9cee07d00..5410c0637266 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -12,10 +12,13 @@ #include #include #include +#include #include #include +#include #include #include +#include #include #include @@ -24,6 +27,26 @@ struct of_serial_info { int line; }; +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} +/* FIXME remove this export when tegra finishes conversion to open firmware */ +EXPORT_SYMBOL_GPL(tegra_serial_handle_break); +#endif + /* * Fill a struct uart_port for a given device node */ @@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; + if (type == PORT_TEGRA) + port->handle_break = tegra_serial_handle_break; + return 0; } diff --git a/include/linux/of_serial.h b/include/linux/of_serial.h new file mode 100644 index 000000000000..4a73ed80b4c0 --- /dev/null +++ b/include/linux/of_serial.h @@ -0,0 +1,17 @@ +#ifndef __LINUX_OF_SERIAL_H +#define __LINUX_OF_SERIAL_H + +/* + * FIXME remove this file when tegra finishes conversion to open firmware, + * expectation is that all quirks will then be self-contained in + * drivers/tty/serial/of_serial.c. + */ +#ifdef CONFIG_ARCH_TEGRA +extern void tegra_serial_handle_break(struct uart_port *port); +#else +static inline void tegra_serial_handle_break(struct uart_port *port) +{ +} +#endif + +#endif /* __LINUX_OF_SERIAL */ diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 8f012f8ac8e9..a522fd977aad 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -38,6 +38,7 @@ struct plat_serial8250_port { int (*handle_irq)(struct uart_port *); void (*pm)(struct uart_port *, unsigned int state, unsigned old); + void (*handle_break)(struct uart_port *); }; /* diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f51bf2e70c69..0dd752f3039d 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -310,6 +310,7 @@ struct uart_port { int (*handle_irq)(struct uart_port *); void (*pm)(struct uart_port *, unsigned int state, unsigned int old); + void (*handle_break)(struct uart_port *); unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ @@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) static inline int uart_handle_break(struct uart_port *port) { struct uart_state *state = port->state; + + if (port->handle_break) + port->handle_break(port); + #ifdef SUPPORT_SYSRQ if (port->cons && port->cons->index == port->line) { if (!port->sysrq) { -- cgit v1.2.3 From 0ad372b962d109323d18ac2aa118b2ad100eb8dd Mon Sep 17 00:00:00 2001 From: Sudhakar Mamillapalli Date: Tue, 10 Apr 2012 14:10:58 -0700 Subject: serial/8250_pci: Clear FIFOs for Intel ME Serial Over Lan device on BI When using Serial Over Lan (SOL) over the virtual serial port in a Intel management engine (ME) device, on device reset the serial FIFOs need to be cleared to keep the FIFO indexes in-sync between the host and the engine. On a reset the serial device assertes BI, so using that as a cue FIFOs are cleared. So for this purpose a new handle_break callback has been added. One other problem is that the serial registers might temporarily go to 0 on reset of this device. So instead of using the IER register read, if 0 returned use the ier value in uart_8250_port. This is hidden under a custom serial_in. Cc: Nhan H Mai Signed-off-by: Sudhakar Mamillapalli Acked-by: Alan Cox Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.c | 10 ++++++++++ drivers/tty/serial/8250/8250.h | 2 ++ drivers/tty/serial/8250/8250_pci.c | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index cbd94c3b5702..182efcc90e2e 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -568,6 +568,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) } } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + unsigned char fcr; + + serial8250_clear_fifos(p); + fcr = uart_config[p->port.type].fcr; + serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + /* * IER sleep support. UARTs which have EFRs need the "extended * capability" bit enabled. Note that on XR16C850s, we need to diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 2868a1da254d..c9d0ebe952fc 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -96,6 +96,8 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca865d6a..024551acf874 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static void kt_handle_break(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + /* + * On receipt of a BI, serial device in Intel ME (Intel + * management engine) needs to have its fifos cleared for sane + * SOL (Serial Over Lan) output. + */ + serial8250_clear_and_reinit_fifos(up); +} + +static unsigned int kt_serial_in(struct uart_port *p, int offset) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + unsigned int val; + + /* + * When the Intel ME (management engine) gets reset its serial + * port registers could return 0 momentarily. Functions like + * serial8250_console_write, read and save the IER, perform + * some operation and then restore it. In order to avoid + * setting IER register inadvertently to 0, if the value read + * is 0, double check with ier value in uart_8250_port and use + * that instead. up->ier should be the same value as what is + * currently configured. + */ + val = inb(p->iobase + offset); + if (offset == UART_IER) { + if (val == 0) + val = up->ier; + } + return val; +} + static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_port *port, int idx) { port->flags |= UPF_BUG_THRE; + port->serial_in = kt_serial_in; + port->handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } -- cgit v1.2.3 From 5f1a38952b7e932a1c169c28917b9a831f641bcc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 10 Apr 2012 14:11:03 -0700 Subject: serial/8250_pci: fix suspend/resume vs init/exit quirks Commit e86ff4a6 "serial/8250_pci: init-quirk msi support for kt serial controller" introduced a regression in suspend/resume by causing msi's to be enabled twice without an intervening disable. 00:16.3 Serial controller: Intel Corporation Patsburg KT Controller (rev 05) (prog-if 02 [16550]) Subsystem: Intel Corporation Device 7270 Flags: bus master, 66MHz, fast devsel, latency 0, IRQ 72 I/O ports at 4080 [size=8] Memory at d1c30000 (32-bit, non-prefetchable) [size=4K] Capabilities: [c8] Power Management version 3 Capabilities: [d0] MSI: Enable+ Count=1/1 Maskable- 64bit+ Kernel driver in use: serial [ 365.250523] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:16.3/msi_irqs' [ 365.250525] Modules linked in: nls_utf8 ipv6 uinput sg iTCO_wdt iTCO_vendor_support ioatdma dca i2c_i801 i2c_core wmi sd_mod ahci libahci isci libsas libata scsi_transport_sas [last unloaded: scsi_wait_scan] [ 365.250540] Pid: 9030, comm: kworker/u:1 Tainted: G W 3.3.0-isci-3.0.213+ #1 [ 365.250542] Call Trace: [ 365.250545] [] ? sysfs_add_one+0x99/0xad [ 365.250548] [] warn_slowpath_common+0x85/0x9e [ 365.250551] [] warn_slowpath_fmt+0x6e/0x70 [ 365.250555] [] ? sysfs_add_one+0x3e/0xad [ 365.250558] [] ? sysfs_pathname+0x3c/0x44 [ 365.250561] [] ? sysfs_pathname+0x3c/0x44 [ 365.250564] [] ? sysfs_pathname+0x3c/0x44 [ 365.250567] [] ? sysfs_pathname+0x3c/0x44 [ 365.250570] [] sysfs_add_one+0x99/0xad [ 365.250573] [] create_dir+0x72/0xa5 [ 365.250577] [] sysfs_create_dir+0xa2/0xbe [ 365.250581] [] kobject_add_internal+0x126/0x1f8 [ 365.250585] [] kset_register+0x26/0x3f [ 365.250588] [] kset_create_and_add+0x62/0x7c [ 365.250592] [] populate_msi_sysfs+0x34/0x103 [ 365.250595] [] pci_enable_msi_block+0x1b3/0x216 [ 365.250599] [] try_enable_msi+0x13/0x17 [ 365.250603] [] pciserial_resume_ports+0x21/0x42 [ 365.250607] [] pciserial_resume_one+0x50/0x57 [ 365.250610] [] pci_legacy_resume+0x38/0x47 [ 365.250613] [] pci_pm_restore+0x54/0x87 [ 365.250616] [] ? pci_legacy_resume+0x47/0x47 [ 365.250619] [] dpm_run_callback+0x48/0x7b [ 365.250623] [] device_resume+0x342/0x394 [ 365.250626] [] async_resume+0x21/0x49 That patch has since been reverted, but by inspection it seems that pciserial_suspend_ports() should be invoking .exit() quirks to release resources acquired during .init(). Acked-by: Alan Cox Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 024551acf874..24ea98c6e77a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2814,6 +2814,12 @@ void pciserial_suspend_ports(struct serial_private *priv) for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_suspend_port(priv->line[i]); + + /* + * Ensure that every init quirk is properly torn down + */ + if (priv->quirk->exit) + priv->quirk->exit(priv->dev); } EXPORT_SYMBOL_GPL(pciserial_suspend_ports); -- cgit v1.2.3