diff options
Diffstat (limited to 'drivers/tty')
76 files changed, 1848 insertions, 3556 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 33175504bb3..8816f53e004 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -354,3 +354,37 @@ config TRACE_SINK If you select this option, you need to select "Trace data router for MIPI P1149.7 cJTAG standard". + +config PPC_EPAPR_HV_BYTECHAN + tristate "ePAPR hypervisor byte channel driver" + depends on PPC + help + This driver creates /dev entries for each ePAPR hypervisor byte + channel, thereby allowing applications to communicate with byte + channels as if they were serial ports. + +config PPC_EARLY_DEBUG_EHV_BC + bool "Early console (udbg) support for ePAPR hypervisors" + depends on PPC_EPAPR_HV_BYTECHAN + help + Select this option to enable early console (a.k.a. "udbg") support + via an ePAPR byte channel. You also need to choose the byte channel + handle below. + +config PPC_EARLY_DEBUG_EHV_BC_HANDLE + int "Byte channel handle for early console (udbg)" + depends on PPC_EARLY_DEBUG_EHV_BC + default 0 + help + If you want early console (udbg) output through a byte channel, + specify the handle of the byte channel to use. + + For this to work, the byte channel driver must be compiled + in-kernel, not as a module. + + Note that only one early console driver can be enabled, so don't + enable any others if you enable this one. + + If the number you specify is not a valid byte channel handle, then + there simply will be no early console output. This is true also + if you don't boot under a hypervisor at all. diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index ea89b0bd15f..2953059530e 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_ROCKETPORT) += rocket.o obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_SYNCLINK) += synclink.o +obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-y += ipwireless/ diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 220579592c2..b84c83456dc 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1529,7 +1529,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { struct async_struct * info = tty->driver_data; unsigned long orig_jiffies, char_time; - int tty_was_locked = tty_locked(); int lsr; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) @@ -1541,12 +1540,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) orig_jiffies = jiffies; /* - * tty_wait_until_sent is called from lots of places, - * with or without the BTM. - */ - if (!tty_was_locked) - tty_lock(); - /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. @@ -1586,8 +1579,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) break; } __set_current_state(TASK_RUNNING); - if (!tty_was_locked) - tty_unlock(); + #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -2025,7 +2017,7 @@ static int __init amiga_serial_probe(struct platform_device *pdev) if (error) goto fail_unregister; - error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, + error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, 0, "serial RX", state); if (error) goto fail_free_irq; diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index c0e8f2eeb88..c9bf779481d 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -45,7 +45,6 @@ #undef CY_DEBUG_IO #undef CY_DEBUG_COUNT #undef CY_DEBUG_DTR -#undef CY_DEBUG_WAIT_UNTIL_SENT #undef CY_DEBUG_INTERRUPTS #undef CY_16Y_HACK #undef CY_ENABLE_MONITORING @@ -1678,16 +1677,10 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) */ if (!timeout || timeout > 2 * info->timeout) timeout = 2 * info->timeout; -#ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...", - timeout, char_time, jiffies); -#endif + card = info->card; if (!cy_is_Z(card)) { while (cyy_readb(info, CySRER) & CyTxRdy) { -#ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies); -#endif if (msleep_interruptible(jiffies_to_msecs(char_time))) break; if (timeout && time_after(jiffies, orig_jiffies + @@ -1697,9 +1690,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) } /* Run one more char cycle */ msleep_interruptible(jiffies_to_msecs(char_time * 5)); -#ifdef CY_DEBUG_WAIT_UNTIL_SENT - printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); -#endif } static void cy_flush_buffer(struct tty_struct *tty) @@ -3377,7 +3367,7 @@ static int __init cy_detect_isa(void) /* allocate IRQ */ if (request_irq(cy_isa_irq, cyy_interrupt, - IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) { + 0, "Cyclom-Y", &cy_card[j])) { printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " "could not allocate IRQ#%d.\n", (unsigned long)cy_isa_address, cy_isa_irq); diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c new file mode 100644 index 00000000000..1595dba0072 --- /dev/null +++ b/drivers/tty/ehv_bytechan.c @@ -0,0 +1,881 @@ +/* ePAPR hypervisor byte channel device driver + * + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * Author: Timur Tabi <timur@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + * This driver support three distinct interfaces, all of which are related to + * ePAPR hypervisor byte channels. + * + * 1) An early-console (udbg) driver. This provides early console output + * through a byte channel. The byte channel handle must be specified in a + * Kconfig option. + * + * 2) A normal console driver. Output is sent to the byte channel designated + * for stdout in the device tree. The console driver is for handling kernel + * printk calls. + * + * 3) A tty driver, which is used to handle user-space input and output. The + * byte channel used for the console is designated as the default tty. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <asm/epapr_hcalls.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/cdev.h> +#include <linux/console.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/circ_buf.h> +#include <asm/udbg.h> + +/* The size of the transmit circular buffer. This must be a power of two. */ +#define BUF_SIZE 2048 + +/* Per-byte channel private data */ +struct ehv_bc_data { + struct device *dev; + struct tty_port port; + uint32_t handle; + unsigned int rx_irq; + unsigned int tx_irq; + + spinlock_t lock; /* lock for transmit buffer */ + unsigned char buf[BUF_SIZE]; /* transmit circular buffer */ + unsigned int head; /* circular buffer head */ + unsigned int tail; /* circular buffer tail */ + + int tx_irq_enabled; /* true == TX interrupt is enabled */ +}; + +/* Array of byte channel objects */ +static struct ehv_bc_data *bcs; + +/* Byte channel handle for stdout (and stdin), taken from device tree */ +static unsigned int stdout_bc; + +/* Virtual IRQ for the byte channel handle for stdin, taken from device tree */ +static unsigned int stdout_irq; + +/**************************** SUPPORT FUNCTIONS ****************************/ + +/* + * Enable the transmit interrupt + * + * Unlike a serial device, byte channels have no mechanism for disabling their + * own receive or transmit interrupts. To emulate that feature, we toggle + * the IRQ in the kernel. + * + * We cannot just blindly call enable_irq() or disable_irq(), because these + * calls are reference counted. This means that we cannot call enable_irq() + * if interrupts are already enabled. This can happen in two situations: + * + * 1. The tty layer makes two back-to-back calls to ehv_bc_tty_write() + * 2. A transmit interrupt occurs while executing ehv_bc_tx_dequeue() + * + * To work around this, we keep a flag to tell us if the IRQ is enabled or not. + */ +static void enable_tx_interrupt(struct ehv_bc_data *bc) +{ + if (!bc->tx_irq_enabled) { + enable_irq(bc->tx_irq); + bc->tx_irq_enabled = 1; + } +} + +static void disable_tx_interrupt(struct ehv_bc_data *bc) +{ + if (bc->tx_irq_enabled) { + disable_irq_nosync(bc->tx_irq); + bc->tx_irq_enabled = 0; + } +} + +/* + * find the byte channel handle to use for the console + * + * The byte channel to be used for the console is specified via a "stdout" + * property in the /chosen node. + * + * For compatible with legacy device trees, we also look for a "stdout" alias. + */ +static int find_console_handle(void) +{ + struct device_node *np, *np2; + const char *sprop = NULL; + const uint32_t *iprop; + + np = of_find_node_by_path("/chosen"); + if (np) + sprop = of_get_property(np, "stdout-path", NULL); + + if (!np || !sprop) { + of_node_put(np); + np = of_find_node_by_name(NULL, "aliases"); + if (np) + sprop = of_get_property(np, "stdout", NULL); + } + + if (!sprop) { + of_node_put(np); + return 0; + } + + /* We don't care what the aliased node is actually called. We only + * care if it's compatible with "epapr,hv-byte-channel", because that + * indicates that it's a byte channel node. We use a temporary + * variable, 'np2', because we can't release 'np' until we're done with + * 'sprop'. + */ + np2 = of_find_node_by_path(sprop); + of_node_put(np); + np = np2; + if (!np) { + pr_warning("ehv-bc: stdout node '%s' does not exist\n", sprop); + return 0; + } + + /* Is it a byte channel? */ + if (!of_device_is_compatible(np, "epapr,hv-byte-channel")) { + of_node_put(np); + return 0; + } + + stdout_irq = irq_of_parse_and_map(np, 0); + if (stdout_irq == NO_IRQ) { + pr_err("ehv-bc: no 'interrupts' property in %s node\n", sprop); + of_node_put(np); + return 0; + } + + /* + * The 'hv-handle' property contains the handle for this byte channel. + */ + iprop = of_get_property(np, "hv-handle", NULL); + if (!iprop) { + pr_err("ehv-bc: no 'hv-handle' property in %s node\n", + np->name); + of_node_put(np); + return 0; + } + stdout_bc = be32_to_cpu(*iprop); + + of_node_put(np); + return 1; +} + +/*************************** EARLY CONSOLE DRIVER ***************************/ + +#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC + +/* + * send a byte to a byte channel, wait if necessary + * + * This function sends a byte to a byte channel, and it waits and + * retries if the byte channel is full. It returns if the character + * has been sent, or if some error has occurred. + * + */ +static void byte_channel_spin_send(const char data) +{ + int ret, count; + + do { + count = 1; + ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, + &count, &data); + } while (ret == EV_EAGAIN); +} + +/* + * The udbg subsystem calls this function to display a single character. + * We convert CR to a CR/LF. + */ +static void ehv_bc_udbg_putc(char c) +{ + if (c == '\n') + byte_channel_spin_send('\r'); + + byte_channel_spin_send(c); +} + +/* + * early console initialization + * + * PowerPC kernels support an early printk console, also known as udbg. + * This function must be called via the ppc_md.init_early function pointer. + * At this point, the device tree has been unflattened, so we can obtain the + * byte channel handle for stdout. + * + * We only support displaying of characters (putc). We do not support + * keyboard input. + */ +void __init udbg_init_ehv_bc(void) +{ + unsigned int rx_count, tx_count; + unsigned int ret; + + /* Verify the byte channel handle */ + ret = ev_byte_channel_poll(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, + &rx_count, &tx_count); + if (ret) + return; + + udbg_putc = ehv_bc_udbg_putc; + register_early_udbg_console(); + + udbg_printf("ehv-bc: early console using byte channel handle %u\n", + CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE); +} + +#endif + +/****************************** CONSOLE DRIVER ******************************/ + +static struct tty_driver *ehv_bc_driver; + +/* + * Byte channel console sending worker function. + * + * For consoles, if the output buffer is full, we should just spin until it + * clears. + */ +static int ehv_bc_console_byte_channel_send(unsigned int handle, const char *s, + unsigned int count) +{ + unsigned int len; + int ret = 0; + + while (count) { + len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES); + do { + ret = ev_byte_channel_send(handle, &len, s); + } while (ret == EV_EAGAIN); + count -= len; + s += len; + } + + return ret; +} + +/* + * write a string to the console + * + * This function gets called to write a string from the kernel, typically from + * a printk(). This function spins until all data is written. + * + * We copy the data to a temporary buffer because we need to insert a \r in + * front of every \n. It's more efficient to copy the data to the buffer than + * it is to make multiple hcalls for each character or each newline. + */ +static void ehv_bc_console_write(struct console *co, const char *s, + unsigned int count) +{ + char s2[EV_BYTE_CHANNEL_MAX_BYTES]; + unsigned int i, j = 0; + char c; + + for (i = 0; i < count; i++) { + c = *s++; + + if (c == '\n') + s2[j++] = '\r'; + + s2[j++] = c; + if (j >= (EV_BYTE_CHANNEL_MAX_BYTES - 1)) { + if (ehv_bc_console_byte_channel_send(stdout_bc, s2, j)) + return; + j = 0; + } + } + + if (j) + ehv_bc_console_byte_channel_send(stdout_bc, s2, j); +} + +/* + * When /dev/console is opened, the kernel iterates the console list looking + * for one with ->device and then calls that method. On success, it expects + * the passed-in int* to contain the minor number to use. + */ +static struct tty_driver *ehv_bc_console_device(struct console *co, int *index) +{ + *index = co->index; + + return ehv_bc_driver; +} + +static struct console ehv_bc_console = { + .name = "ttyEHV", + .write = ehv_bc_console_write, + .device = ehv_bc_console_device, + .flags = CON_PRINTBUFFER | CON_ENABLED, +}; + +/* + * Console initialization + * + * This is the first function that is called after the device tree is + * available, so here is where we determine the byte channel handle and IRQ for + * stdout/stdin, even though that information is used by the tty and character + * drivers. + */ +static int __init ehv_bc_console_init(void) +{ + if (!find_console_handle()) { + pr_debug("ehv-bc: stdout is not a byte channel\n"); + return -ENODEV; + } + +#ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC + /* Print a friendly warning if the user chose the wrong byte channel + * handle for udbg. + */ + if (stdout_bc != CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE) + pr_warning("ehv-bc: udbg handle %u is not the stdout handle\n", + CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE); +#endif + + /* add_preferred_console() must be called before register_console(), + otherwise it won't work. However, we don't want to enumerate all the + byte channels here, either, since we only care about one. */ + + add_preferred_console(ehv_bc_console.name, ehv_bc_console.index, NULL); + register_console(&ehv_bc_console); + + pr_info("ehv-bc: registered console driver for byte channel %u\n", + stdout_bc); + + return 0; +} +console_initcall(ehv_bc_console_init); + +/******************************** TTY DRIVER ********************************/ + +/* + * byte channel receive interupt handler + * + * This ISR is called whenever data is available on a byte channel. + */ +static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data) +{ + struct ehv_bc_data *bc = data; + struct tty_struct *ttys = tty_port_t |