diff options
-rw-r--r-- | drivers/tty/Kconfig | 13 | ||||
-rw-r--r-- | drivers/tty/Makefile | 1 | ||||
-rw-r--r-- | drivers/tty/metag_da.c | 665 |
3 files changed, 0 insertions, 679 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index b811442c5ce6..75a71ebcb369 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -402,19 +402,6 @@ config GOLDFISH_TTY_EARLY_CONSOLE default y if GOLDFISH_TTY=y select SERIAL_EARLYCON -config DA_TTY - bool "DA TTY" - depends on METAG_DA - select SERIAL_NONSTANDARD - help - This enables a TTY on a Dash channel. - -config DA_CONSOLE - bool "DA Console" - depends on DA_TTY - help - This enables a console on a Dash channel. - config MIPS_EJTAG_FDC_TTY bool "MIPS EJTAG Fast Debug Channel TTY" depends on MIPS_CDMM diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 8ce3a8661b31..47c71f43a397 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o -obj-$(CONFIG_DA_TTY) += metag_da.o obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o obj-$(CONFIG_VCC) += vcc.o diff --git a/drivers/tty/metag_da.c b/drivers/tty/metag_da.c deleted file mode 100644 index 99eaed4b2dbc..000000000000 --- a/drivers/tty/metag_da.c +++ /dev/null @@ -1,665 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * dashtty.c - tty driver for Dash channels interface. - * - * Copyright (C) 2007,2008,2012 Imagination Technologies - */ - -#include <linux/atomic.h> -#include <linux/completion.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/export.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/kthread.h> -#include <linux/moduleparam.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/serial.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/uaccess.h> - -#include <asm/da.h> - -/* Channel error codes */ -#define CONAOK 0 -#define CONERR 1 -#define CONBAD 2 -#define CONPRM 3 -#define CONADR 4 -#define CONCNT 5 -#define CONCBF 6 -#define CONCBE 7 -#define CONBSY 8 - -/* Default channel for the console */ -#define CONSOLE_CHANNEL 1 - -#define NUM_TTY_CHANNELS 6 - -/* Auto allocate */ -#define DA_TTY_MAJOR 0 - -/* A speedy poll rate helps the userland debug process connection response. - * But, if you set it too high then no other userland processes get much - * of a look in. - */ -#define DA_TTY_POLL (HZ / 50) - -/* - * A short put delay improves latency but has a high throughput overhead - */ -#define DA_TTY_PUT_DELAY (HZ / 100) - -static atomic_t num_channels_need_poll = ATOMIC_INIT(0); - -static struct timer_list poll_timer; - -static struct tty_driver *channel_driver; - -static struct timer_list put_timer; -static struct task_struct *dashtty_thread; - -/* - * The console_poll parameter determines whether the console channel should be - * polled for input. - * By default the console channel isn't polled at all, in order to avoid the - * overhead, but that means it isn't possible to have a login on /dev/console. - */ -static bool console_poll; -module_param(console_poll, bool, S_IRUGO); - -#define RX_BUF_SIZE 1024 - -enum { - INCHR = 1, - OUTCHR, - RDBUF, - WRBUF, - RDSTAT -}; - -/** - * struct dashtty_port - Wrapper struct for dashtty tty_port. - * @port: TTY port data - * @rx_lock: Lock for rx_buf. - * This protects between the poll timer and user context. - * It's also held during read SWITCH operations. - * @rx_buf: Read buffer - * @xmit_lock: Lock for xmit_*, and port.xmit_buf. - * This protects between user context and kernel thread. - * It's also held during write SWITCH operations. - * @xmit_cnt: Size of xmit buffer contents - * @xmit_head: Head of xmit buffer where data is written - * @xmit_tail: Tail of xmit buffer where data is read - * @xmit_empty: Completion for xmit buffer being empty - */ -struct dashtty_port { - struct tty_port port; - spinlock_t rx_lock; - void *rx_buf; - struct mutex xmit_lock; - unsigned int xmit_cnt; - unsigned int xmit_head; - unsigned int xmit_tail; - struct completion xmit_empty; -}; - -static struct dashtty_port dashtty_ports[NUM_TTY_CHANNELS]; - -static atomic_t dashtty_xmit_cnt = ATOMIC_INIT(0); -static wait_queue_head_t dashtty_waitqueue; - -/* - * Low-level DA channel access routines - */ -static int chancall(int in_bios_function, int in_channel, - int in_arg2, void *in_arg3, - void *in_arg4) -{ - register int bios_function asm("D1Ar1") = in_bios_function; - register int channel asm("D0Ar2") = in_channel; - register int arg2 asm("D1Ar3") = in_arg2; - register void *arg3 asm("D0Ar4") = in_arg3; - register void *arg4 asm("D1Ar5") = in_arg4; - register int bios_call asm("D0Ar6") = 3; - register int result asm("D0Re0"); - - asm volatile ( - "MSETL [A0StP++], %6,%4,%2\n\t" - "ADD A0StP, A0StP, #8\n\t" - "SWITCH #0x0C30208\n\t" - "GETD %0, [A0StP+#-8]\n\t" - "SUB A0StP, A0StP, #(4*6)+8\n\t" - : "=d" (result) /* outs */ - : "d" (bios_function), - "d" (channel), - "d" (arg2), - "d" (arg3), - "d" (arg4), - "d" (bios_call) /* ins */ - : "memory"); - - return result; -} - -/* - * Attempts to fetch count bytes from channel and returns actual count. - */ -static int fetch_data(unsigned int channel) -{ - struct dashtty_port *dport = &dashtty_ports[channel]; - int received = 0; - - spin_lock_bh(&dport->rx_lock); - /* check the port isn't being shut down */ - if (!dport->rx_buf) - goto unlock; - if (chancall(RDBUF, channel, RX_BUF_SIZE, - (void *)dport->rx_buf, &received) == CONAOK) { - if (received) { - int space; - unsigned char *cbuf; - - space = tty_prepare_flip_string(&dport->port, &cbuf, - received); - - if (space <= 0) - goto unlock; - - memcpy(cbuf, dport->rx_buf, space); - tty_flip_buffer_push(&dport->port); - } - } -unlock: - spin_unlock_bh(&dport->rx_lock); - - return received; -} - -/** - * find_channel_to_poll() - Returns number of the next channel to poll. - * Returns: The number of the next channel to poll, or -1 if none need - * polling. - */ -static int find_channel_to_poll(void) -{ - static int last_polled_channel; - int last = last_polled_channel; - int chan; - struct dashtty_port *dport; - - for (chan = last + 1; ; ++chan) { - if (chan >= NUM_TTY_CHANNELS) - chan = 0; - - dport = &dashtty_ports[chan]; - if (dport->rx_buf) { - last_polled_channel = chan; - return chan; - } - - if (chan == last) - break; - } - return -1; -} - -/** - * put_channel_data() - Write out a block of channel data. - * @chan: DA channel number. - * - * Write a single block of data out to the debug adapter. If the circular buffer - * is wrapped then only the first block is written. - * - * Returns: 1 if the remote buffer was too full to accept data. - * 0 otherwise. - */ -static int put_channel_data(unsigned int chan) -{ - struct dashtty_port *dport; - struct tty_struct *tty; - int number_written; - unsigned int count = 0; - - dport = &dashtty_ports[chan]; - mutex_lock(&dport->xmit_lock); - if (dport->xmit_cnt) { - count = min((unsigned int)(SERIAL_XMIT_SIZE - dport->xmit_tail), - dport->xmit_cnt); - chancall(WRBUF, chan, count, - dport->port.xmit_buf + dport->xmit_tail, - &number_written); - dport->xmit_cnt -= number_written; - if (!dport->xmit_cnt) { - /* reset pointers to avoid wraps */ - dport->xmit_head = 0; - dport->xmit_tail = 0; - complete(&dport->xmit_empty); - } else { - dport->xmit_tail += number_written; - if (dport->xmit_tail >= SERIAL_XMIT_SIZE) - dport->xmit_tail -= SERIAL_XMIT_SIZE; - } - atomic_sub(number_written, &dashtty_xmit_cnt); - } - mutex_unlock(&dport->xmit_lock); - - /* if we've made more data available, wake up tty */ - if (count && number_written) { - tty = tty_port_tty_get(&dport->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } - } - - /* did the write fail? */ - return count && !number_written; -} - -/** - * put_data() - Kernel thread to write out blocks of channel data to DA. - * @arg: Unused. - * - * This kernel thread runs while @dashtty_xmit_cnt != 0, and loops over the - * channels to write out any buffered data. If any of the channels stall due to - * the remote buffer being full, a hold off happens to allow the debugger to - * drain the buffer. - */ -static int put_data(void *arg) -{ - unsigned int chan, stall; - - __set_current_state(TASK_RUNNING); - while (!kthread_should_stop()) { - /* - * For each channel see if there's anything to transmit in the - * port's xmit_buf. - */ - stall = 0; - for (chan = 0; chan < NUM_TTY_CHANNELS; ++chan) - stall += put_channel_data(chan); - - /* - * If some of the buffers are full, hold off for a short while - * to allow them to empty. - */ - if (stall) - msleep(25); - - wait_event_interruptible(dashtty_waitqueue, - atomic_read(&dashtty_xmit_cnt)); - } - - return 0; -} - -/* - * This gets called every DA_TTY_POLL and polls the channels for data - */ -static void dashtty_timer(struct timer_list *poll_timer) -{ - int channel; - - /* If there are no ports open do nothing and don't poll again. */ - if (!atomic_read(&num_channels_need_poll)) - return; - - channel = find_channel_to_poll(); - - /* Did we find a channel to poll? */ - if (channel >= 0) - fetch_data(channel); - - mod_timer(poll_timer, jiffies + DA_TTY_POLL); -} - -static void add_poll_timer(struct timer_list *poll_timer) -{ - timer_setup(poll_timer, dashtty_timer, TIMER_PINNED); - poll_timer->expires = jiffies + DA_TTY_POLL; - - /* - * Always attach the timer to the boot CPU. The DA channels are per-CPU - * so all polling should be from a single CPU. - */ - add_timer_on(poll_timer, 0); -} - -static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct dashtty_port *dport = container_of(port, struct dashtty_port, - port); - void *rx_buf; - - /* Allocate the buffer we use for writing data */ - if (tty_port_alloc_xmit_buf(port) < 0) - goto err; - - /* Allocate the buffer we use for reading data */ - rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); - if (!rx_buf) - goto err_free_xmit; - - spin_lock_bh(&dport->rx_lock); - dport->rx_buf = rx_buf; - spin_unlock_bh(&dport->rx_lock); - - /* - * Don't add the poll timer if we're opening a console. This - * avoids the overhead of polling the Dash but means it is not - * possible to have a login on /dev/console. - * - */ - if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL]) - if (atomic_inc_return(&num_channels_need_poll) == 1) - add_poll_timer(&poll_timer); - - return 0; -err_free_xmit: - tty_port_free_xmit_buf(port); -err: - return -ENOMEM; -} - -static void dashtty_port_shutdown(struct tty_port *port) -{ - struct dashtty_port *dport = container_of(port, struct dashtty_port, - port); - void *rx_buf; - unsigned int count; - - /* stop reading */ - if (console_poll || dport != &dashtty_ports[CONSOLE_CHANNEL]) - if (atomic_dec_and_test(&num_channels_need_poll)) - del_timer_sync(&poll_timer); - - mutex_lock(&dport->xmit_lock); - count = dport->xmit_cnt; - mutex_unlock(&dport->xmit_lock); - if (count) { - /* - * There's still data to write out, so wake and wait for the - * writer thread to drain the buffer. - */ - del_timer(&put_timer); - wake_up_interruptible(&dashtty_waitqueue); - wait_for_completion(&dport->xmit_empty); - } - - /* Null the read buffer (timer could still be running!) */ - spin_lock_bh(&dport->rx_lock); - rx_buf = dport->rx_buf; - dport->rx_buf = NULL; - spin_unlock_bh(&dport->rx_lock); - /* Free the read buffer */ - kfree(rx_buf); - - /* Free the write buffer */ - tty_port_free_xmit_buf(port); -} - -static const struct tty_port_operations dashtty_port_ops = { - .activate = dashtty_port_activate, - .shutdown = dashtty_port_shutdown, -}; - -static int dashtty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - return tty_port_install(&dashtty_ports[tty->index].port, driver, tty); -} - -static int dashtty_open(struct tty_struct *tty, struct file *filp) -{ - return tty_port_open(tty->port, tty, filp); -} - -static void dashtty_close(struct tty_struct *tty, struct file *filp) -{ - return tty_port_close(tty->port, tty, filp); -} - -static void dashtty_hangup(struct tty_struct *tty) -{ - int channel; - struct dashtty_port *dport; - - channel = tty->index; - dport = &dashtty_ports[channel]; - - /* drop any data in the xmit buffer */ - mutex_lock(&dport->xmit_lock); - if (dport->xmit_cnt) { - atomic_sub(dport->xmit_cnt, &dashtty_xmit_cnt); - dport->xmit_cnt = 0; - dport->xmit_head = 0; - dport->xmit_tail = 0; - complete(&dport->xmit_empty); - } - mutex_unlock(&dport->xmit_lock); - - tty_port_hangup(tty->port); -} - -/** - * dashtty_put_timer() - Delayed wake up of kernel thread. - * @ignored: unused - * - * This timer function wakes up the kernel thread if any data exists in the - * buffers. It is used to delay the expensive writeout until the writer has - * stopped writing. - */ -static void dashtty_put_timer(struct timer_list *unused) -{ - if (atomic_read(&dashtty_xmit_cnt)) - wake_up_interruptible(&dashtty_waitqueue); -} - -static int dashtty_write(struct tty_struct *tty, const unsigned char *buf, - int total) -{ - int channel, count, block; - struct dashtty_port *dport; - - /* Determine the channel */ - channel = tty->index; - dport = &dashtty_ports[channel]; - - /* - * Write to output buffer. - * - * The reason that we asynchronously write the buffer is because if we - * were to write the buffer synchronously then because DA channels are - * per-CPU the buffer would be written to the channel of whatever CPU - * we're running on. - * - * What we actually want to happen is have all input and output done on - * one CPU. - */ - mutex_lock(&dport->xmit_lock); - /* work out how many bytes we can write to the xmit buffer */ - total = min(total, (int)(SERIAL_XMIT_SIZE - dport->xmit_cnt)); - atomic_add(total, &dashtty_xmit_cnt); - dport->xmit_cnt += total; - /* write the actual bytes (may need splitting if it wraps) */ - for (count = total; count; count -= block) { - block = min(count, (int)(SERIAL_XMIT_SIZE - dport->xmit_head)); - memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block); - dport->xmit_head += block; - if (dport->xmit_head >= SERIAL_XMIT_SIZE) - dport->xmit_head -= SERIAL_XMIT_SIZE; - buf += block; - } - count = dport->xmit_cnt; - /* xmit buffer no longer empty? */ - if (count) - reinit_completion(&dport->xmit_empty); - mutex_unlock(&dport->xmit_lock); - - if (total) { - /* - * If the buffer is full, wake up the kthread, otherwise allow - * some more time for the buffer to fill up a bit before waking - * it. - */ - if (count == SERIAL_XMIT_SIZE) { - del_timer(&put_timer); - wake_up_interruptible(&dashtty_waitqueue); - } else { - mod_timer(&put_timer, jiffies + DA_TTY_PUT_DELAY); - } - } - return total; -} - -static int dashtty_write_room(struct tty_struct *tty) -{ - struct dashtty_port *dport; - int channel; - int room; - - channel = tty->index; - dport = &dashtty_ports[channel]; - - /* report the space in the xmit buffer */ - mutex_lock(&dport->xmit_lock); - room = SERIAL_XMIT_SIZE - dport->xmit_cnt; - mutex_unlock(&dport->xmit_lock); - - return room; -} - -static int dashtty_chars_in_buffer(struct tty_struct *tty) -{ - struct dashtty_port *dport; - int channel; - int chars; - - channel = tty->index; - dport = &dashtty_ports[channel]; - - /* report the number of bytes in the xmit buffer */ - mutex_lock(&dport->xmit_lock); - chars = dport->xmit_cnt; - mutex_unlock(&dport->xmit_lock); - - return chars; -} - -static const struct tty_operations dashtty_ops = { - .install = dashtty_install, - .open = dashtty_open, - .close = dashtty_close, - .hangup = dashtty_hangup, - .write = dashtty_write, - .write_room = dashtty_write_room, - .chars_in_buffer = dashtty_chars_in_buffer, -}; - -static int __init dashtty_init(void) -{ - int ret; - int nport; - struct dashtty_port *dport; - - if (!metag_da_enabled()) - return -ENODEV; - - channel_driver = tty_alloc_driver(NUM_TTY_CHANNELS, - TTY_DRIVER_REAL_RAW); - if (IS_ERR(channel_driver)) - return PTR_ERR(channel_driver); - - channel_driver->driver_name = "metag_da"; - channel_driver->name = "ttyDA"; - channel_driver->major = DA_TTY_MAJOR; - channel_driver->minor_start = 0; - channel_driver->type = TTY_DRIVER_TYPE_SERIAL; - channel_driver->subtype = SERIAL_TYPE_NORMAL; - channel_driver->init_termios = tty_std_termios; - channel_driver->init_termios.c_cflag |= CLOCAL; - - tty_set_operations(channel_driver, &dashtty_ops); - for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { - dport = &dashtty_ports[nport]; - tty_port_init(&dport->port); - dport->port.ops = &dashtty_port_ops; - spin_lock_init(&dport->rx_lock); - mutex_init(&dport->xmit_lock); - /* the xmit buffer starts empty, i.e. completely written */ - init_completion(&dport->xmit_empty); - complete(&dport->xmit_empty); - } - - timer_setup(&put_timer, dashtty_put_timer, 0); - - init_waitqueue_head(&dashtty_waitqueue); - dashtty_thread = kthread_create(put_data, NULL, "ttyDA"); - if (IS_ERR(dashtty_thread)) { - pr_err("Couldn't create dashtty thread\n"); - ret = PTR_ERR(dashtty_thread); - goto err_destroy_ports; - } - /* - * Bind the writer thread to the boot CPU so it can't migrate. - * DA channels are per-CPU and we want all channel I/O to be on a single - * predictable CPU. - */ - kthread_bind(dashtty_thread, 0); - wake_up_process(dashtty_thread); - - ret = tty_register_driver(channel_driver); - - if (ret < 0) { - pr_err("Couldn't install dashtty driver: err %d\n", - ret); - goto err_stop_kthread; - } - - return 0; - -err_stop_kthread: - kthread_stop(dashtty_thread); -err_destroy_ports: - for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { - dport = &dashtty_ports[nport]; - tty_port_destroy(&dport->port); - } - put_tty_driver(channel_driver); - return ret; -} -device_initcall(dashtty_init); - -#ifdef CONFIG_DA_CONSOLE - -static void dash_console_write(struct console *co, const char *s, - unsigned int count) -{ - int actually_written; - - chancall(WRBUF, CONSOLE_CHANNEL, count, (void *)s, &actually_written); -} - -static struct tty_driver *dash_console_device(struct console *c, int *index) -{ - *index = c->index; - return channel_driver; -} - -struct console dash_console = { - .name = "ttyDA", - .write = dash_console_write, - .device = dash_console_device, - .flags = CON_PRINTBUFFER, - .index = 1, -}; - -#endif |