mirror of
https://github.com/torvalds/linux.git
synced 2024-12-22 19:01:37 +00:00
9d7c249a1e
The printk() in serial8250_interrupt() was once hidden behind a debug macro in commitf4f653e987
("serial: 8250, disable "too much work" messages") and reverted back in commit12de375ec4
("Revert "serial: 8250, disable "too much work" messages""). This was introduced first in 0.99.13k with the "serial" driver itself (and called pass_number with a limit of 64 and no print). In 1.1.13 it was renamed to pass_counter and the printk was behind #if 0. In 1.1.94 the limit of 64 was increased to 256 and hidden behind RS_ISR_PASS_LIMIT. With this change the #if 0 turned into #if 1. It slowly become what we have today with a loop limit of 512. Usually, that printk isn't hit. However on KVM with a busy UART and overloaded host it might happen. It is also likely with threaded interrupts and a task which preempts the interrupt handler. If the UART has (legitimate) work to do and we break out of the loop, nothing changes: the interrupt is most likely already pending in the interrupt controller and we end up in the handler anyway. This printk is hardly helping. Older kernels also had a comment saying that a bad configuration might lead to this but I don't see how that should happen because a wrongly configured interrupt number would let the handler leave "early" with IRQ_NONE and the spurious detected will handle that (weill since 2.6.11, before that we had no spurious detector). In that case, we would never loop that often here. This loop looks like an optimisation in order to pull the bytes from the FIFO which were received while we were already here instead of waiting for the interrupt. This might have been a good idea while the CPUs were slow and FIFOs small. There are other serial driver in tree, like the amba-pl*, which also have this kind of a loop but without the printk (and were based on this driver). Remove the printk which might trigger in otherwise valid situtations. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1232 lines
31 KiB
C
1232 lines
31 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Universal/legacy driver for 8250/16550-type serial ports
|
|
*
|
|
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
|
|
*
|
|
* Copyright (C) 2001 Russell King.
|
|
*
|
|
* Supports: ISA-compatible 8250/16550 ports
|
|
* PNP 8250/16550 ports
|
|
* early_serial_setup() ports
|
|
* userspace-configurable "phantom" ports
|
|
* "serial8250" platform devices
|
|
* serial8250_register_8250_port() ports
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/init.h>
|
|
#include <linux/console.h>
|
|
#include <linux/sysrq.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/ratelimit.h>
|
|
#include <linux/tty_flip.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/serial_8250.h>
|
|
#include <linux/nmi.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/io.h>
|
|
#ifdef CONFIG_SPARC
|
|
#include <linux/sunserialcore.h>
|
|
#endif
|
|
|
|
#include <asm/irq.h>
|
|
|
|
#include "8250.h"
|
|
|
|
/*
|
|
* Configuration:
|
|
* share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
|
|
* is unsafe when used on edge-triggered interrupts.
|
|
*/
|
|
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
|
|
|
|
static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
|
|
|
|
static struct uart_driver serial8250_reg;
|
|
|
|
static unsigned int skip_txen_test; /* force skip of txen test at init time */
|
|
|
|
#define PASS_LIMIT 512
|
|
|
|
#include <asm/serial.h>
|
|
/*
|
|
* SERIAL_PORT_DFNS tells us about built-in ports that have no
|
|
* standard enumeration mechanism. Platforms that can find all
|
|
* serial ports via mechanisms like ACPI or PCI need not supply it.
|
|
*/
|
|
#ifndef SERIAL_PORT_DFNS
|
|
#define SERIAL_PORT_DFNS
|
|
#endif
|
|
|
|
static const struct old_serial_port old_serial_port[] = {
|
|
SERIAL_PORT_DFNS /* defined in asm/serial.h */
|
|
};
|
|
|
|
#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
#define PORT_RSA_MAX 4
|
|
static unsigned long probe_rsa[PORT_RSA_MAX];
|
|
static unsigned int probe_rsa_count;
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
|
|
struct irq_info {
|
|
struct hlist_node node;
|
|
int irq;
|
|
spinlock_t lock; /* Protects list not the hash */
|
|
struct list_head *head;
|
|
};
|
|
|
|
#define NR_IRQ_HASH 32 /* Can be adjusted later */
|
|
static struct hlist_head irq_lists[NR_IRQ_HASH];
|
|
static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
|
|
|
|
/*
|
|
* This is the serial driver's interrupt routine.
|
|
*
|
|
* Arjan thinks the old way was overly complex, so it got simplified.
|
|
* Alan disagrees, saying that need the complexity to handle the weird
|
|
* nature of ISA shared interrupts. (This is a special exception.)
|
|
*
|
|
* In order to handle ISA shared interrupts properly, we need to check
|
|
* that all ports have been serviced, and therefore the ISA interrupt
|
|
* line has been de-asserted.
|
|
*
|
|
* This means we need to loop through all ports. checking that they
|
|
* don't have an interrupt pending.
|
|
*/
|
|
static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct irq_info *i = dev_id;
|
|
struct list_head *l, *end = NULL;
|
|
int pass_counter = 0, handled = 0;
|
|
|
|
pr_debug("%s(%d): start\n", __func__, irq);
|
|
|
|
spin_lock(&i->lock);
|
|
|
|
l = i->head;
|
|
do {
|
|
struct uart_8250_port *up;
|
|
struct uart_port *port;
|
|
|
|
up = list_entry(l, struct uart_8250_port, list);
|
|
port = &up->port;
|
|
|
|
if (port->handle_irq(port)) {
|
|
handled = 1;
|
|
end = NULL;
|
|
} else if (end == NULL)
|
|
end = l;
|
|
|
|
l = l->next;
|
|
|
|
if (l == i->head && pass_counter++ > PASS_LIMIT)
|
|
break;
|
|
} while (l != end);
|
|
|
|
spin_unlock(&i->lock);
|
|
|
|
pr_debug("%s(%d): end\n", __func__, irq);
|
|
|
|
return IRQ_RETVAL(handled);
|
|
}
|
|
|
|
/*
|
|
* To support ISA shared interrupts, we need to have one interrupt
|
|
* handler that ensures that the IRQ line has been deasserted
|
|
* before returning. Failing to do this will result in the IRQ
|
|
* line being stuck active, and, since ISA irqs are edge triggered,
|
|
* no more IRQs will be seen.
|
|
*/
|
|
static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
|
|
{
|
|
spin_lock_irq(&i->lock);
|
|
|
|
if (!list_empty(i->head)) {
|
|
if (i->head == &up->list)
|
|
i->head = i->head->next;
|
|
list_del(&up->list);
|
|
} else {
|
|
BUG_ON(i->head != &up->list);
|
|
i->head = NULL;
|
|
}
|
|
spin_unlock_irq(&i->lock);
|
|
/* List empty so throw away the hash node */
|
|
if (i->head == NULL) {
|
|
hlist_del(&i->node);
|
|
kfree(i);
|
|
}
|
|
}
|
|
|
|
static int serial_link_irq_chain(struct uart_8250_port *up)
|
|
{
|
|
struct hlist_head *h;
|
|
struct hlist_node *n;
|
|
struct irq_info *i;
|
|
int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
|
|
|
|
mutex_lock(&hash_mutex);
|
|
|
|
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
|
|
|
|
hlist_for_each(n, h) {
|
|
i = hlist_entry(n, struct irq_info, node);
|
|
if (i->irq == up->port.irq)
|
|
break;
|
|
}
|
|
|
|
if (n == NULL) {
|
|
i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
|
|
if (i == NULL) {
|
|
mutex_unlock(&hash_mutex);
|
|
return -ENOMEM;
|
|
}
|
|
spin_lock_init(&i->lock);
|
|
i->irq = up->port.irq;
|
|
hlist_add_head(&i->node, h);
|
|
}
|
|
mutex_unlock(&hash_mutex);
|
|
|
|
spin_lock_irq(&i->lock);
|
|
|
|
if (i->head) {
|
|
list_add(&up->list, i->head);
|
|
spin_unlock_irq(&i->lock);
|
|
|
|
ret = 0;
|
|
} else {
|
|
INIT_LIST_HEAD(&up->list);
|
|
i->head = &up->list;
|
|
spin_unlock_irq(&i->lock);
|
|
irq_flags |= up->port.irqflags;
|
|
ret = request_irq(up->port.irq, serial8250_interrupt,
|
|
irq_flags, up->port.name, i);
|
|
if (ret < 0)
|
|
serial_do_unlink(i, up);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void serial_unlink_irq_chain(struct uart_8250_port *up)
|
|
{
|
|
/*
|
|
* yes, some broken gcc emit "warning: 'i' may be used uninitialized"
|
|
* but no, we are not going to take a patch that assigns NULL below.
|
|
*/
|
|
struct irq_info *i;
|
|
struct hlist_node *n;
|
|
struct hlist_head *h;
|
|
|
|
mutex_lock(&hash_mutex);
|
|
|
|
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
|
|
|
|
hlist_for_each(n, h) {
|
|
i = hlist_entry(n, struct irq_info, node);
|
|
if (i->irq == up->port.irq)
|
|
break;
|
|
}
|
|
|
|
BUG_ON(n == NULL);
|
|
BUG_ON(i->head == NULL);
|
|
|
|
if (list_empty(i->head))
|
|
free_irq(up->port.irq, i);
|
|
|
|
serial_do_unlink(i, up);
|
|
mutex_unlock(&hash_mutex);
|
|
}
|
|
|
|
/*
|
|
* This function is used to handle ports that do not have an
|
|
* interrupt. This doesn't work very well for 16450's, but gives
|
|
* barely passable results for a 16550A. (Although at the expense
|
|
* of much CPU overhead).
|
|
*/
|
|
static void serial8250_timeout(struct timer_list *t)
|
|
{
|
|
struct uart_8250_port *up = from_timer(up, t, timer);
|
|
|
|
up->port.handle_irq(&up->port);
|
|
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
|
|
}
|
|
|
|
static void serial8250_backup_timeout(struct timer_list *t)
|
|
{
|
|
struct uart_8250_port *up = from_timer(up, t, timer);
|
|
unsigned int iir, ier = 0, lsr;
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&up->port.lock, flags);
|
|
|
|
/*
|
|
* Must disable interrupts or else we risk racing with the interrupt
|
|
* based handler.
|
|
*/
|
|
if (up->port.irq) {
|
|
ier = serial_in(up, UART_IER);
|
|
serial_out(up, UART_IER, 0);
|
|
}
|
|
|
|
iir = serial_in(up, UART_IIR);
|
|
|
|
/*
|
|
* This should be a safe test for anyone who doesn't trust the
|
|
* IIR bits on their UART, but it's specifically designed for
|
|
* the "Diva" UART used on the management processor on many HP
|
|
* ia64 and parisc boxes.
|
|
*/
|
|
lsr = serial_in(up, UART_LSR);
|
|
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
|
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
|
|
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
|
|
(lsr & UART_LSR_THRE)) {
|
|
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
|
|
iir |= UART_IIR_THRI;
|
|
}
|
|
|
|
if (!(iir & UART_IIR_NO_INT))
|
|
serial8250_tx_chars(up);
|
|
|
|
if (up->port.irq)
|
|
serial_out(up, UART_IER, ier);
|
|
|
|
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
|
|
/* Standard timer interval plus 0.2s to keep the port running */
|
|
mod_timer(&up->timer,
|
|
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
|
|
}
|
|
|
|
static int univ8250_setup_irq(struct uart_8250_port *up)
|
|
{
|
|
struct uart_port *port = &up->port;
|
|
int retval = 0;
|
|
|
|
/*
|
|
* The above check will only give an accurate result the first time
|
|
* the port is opened so this value needs to be preserved.
|
|
*/
|
|
if (up->bugs & UART_BUG_THRE) {
|
|
pr_debug("%s - using backup timer\n", port->name);
|
|
|
|
up->timer.function = serial8250_backup_timeout;
|
|
mod_timer(&up->timer, jiffies +
|
|
uart_poll_timeout(port) + HZ / 5);
|
|
}
|
|
|
|
/*
|
|
* If the "interrupt" for this port doesn't correspond with any
|
|
* hardware interrupt, we use a timer-based system. The original
|
|
* driver used to do this with IRQ0.
|
|
*/
|
|
if (!port->irq) {
|
|
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
|
|
} else
|
|
retval = serial_link_irq_chain(up);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void univ8250_release_irq(struct uart_8250_port *up)
|
|
{
|
|
struct uart_port *port = &up->port;
|
|
|
|
del_timer_sync(&up->timer);
|
|
up->timer.function = serial8250_timeout;
|
|
if (port->irq)
|
|
serial_unlink_irq_chain(up);
|
|
}
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
static int serial8250_request_rsa_resource(struct uart_8250_port *up)
|
|
{
|
|
unsigned long start = UART_RSA_BASE << up->port.regshift;
|
|
unsigned int size = 8 << up->port.regshift;
|
|
struct uart_port *port = &up->port;
|
|
int ret = -EINVAL;
|
|
|
|
switch (port->iotype) {
|
|
case UPIO_HUB6:
|
|
case UPIO_PORT:
|
|
start += port->iobase;
|
|
if (request_region(start, size, "serial-rsa"))
|
|
ret = 0;
|
|
else
|
|
ret = -EBUSY;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void serial8250_release_rsa_resource(struct uart_8250_port *up)
|
|
{
|
|
unsigned long offset = UART_RSA_BASE << up->port.regshift;
|
|
unsigned int size = 8 << up->port.regshift;
|
|
struct uart_port *port = &up->port;
|
|
|
|
switch (port->iotype) {
|
|
case UPIO_HUB6:
|
|
case UPIO_PORT:
|
|
release_region(port->iobase + offset, size);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static const struct uart_ops *base_ops;
|
|
static struct uart_ops univ8250_port_ops;
|
|
|
|
static const struct uart_8250_ops univ8250_driver_ops = {
|
|
.setup_irq = univ8250_setup_irq,
|
|
.release_irq = univ8250_release_irq,
|
|
};
|
|
|
|
static struct uart_8250_port serial8250_ports[UART_NR];
|
|
|
|
/**
|
|
* serial8250_get_port - retrieve struct uart_8250_port
|
|
* @line: serial line number
|
|
*
|
|
* This function retrieves struct uart_8250_port for the specific line.
|
|
* This struct *must* *not* be used to perform a 8250 or serial core operation
|
|
* which is not accessible otherwise. Its only purpose is to make the struct
|
|
* accessible to the runtime-pm callbacks for context suspend/restore.
|
|
* The lock assumption made here is none because runtime-pm suspend/resume
|
|
* callbacks should not be invoked if there is any operation performed on the
|
|
* port.
|
|
*/
|
|
struct uart_8250_port *serial8250_get_port(int line)
|
|
{
|
|
return &serial8250_ports[line];
|
|
}
|
|
EXPORT_SYMBOL_GPL(serial8250_get_port);
|
|
|
|
static void (*serial8250_isa_config)(int port, struct uart_port *up,
|
|
u32 *capabilities);
|
|
|
|
void serial8250_set_isa_configurator(
|
|
void (*v)(int port, struct uart_port *up, u32 *capabilities))
|
|
{
|
|
serial8250_isa_config = v;
|
|
}
|
|
EXPORT_SYMBOL(serial8250_set_isa_configurator);
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
|
|
static void univ8250_config_port(struct uart_port *port, int flags)
|
|
{
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
up->probe &= ~UART_PROBE_RSA;
|
|
if (port->type == PORT_RSA) {
|
|
if (serial8250_request_rsa_resource(up) == 0)
|
|
up->probe |= UART_PROBE_RSA;
|
|
} else if (flags & UART_CONFIG_TYPE) {
|
|
int i;
|
|
|
|
for (i = 0; i < probe_rsa_count; i++) {
|
|
if (probe_rsa[i] == up->port.iobase) {
|
|
if (serial8250_request_rsa_resource(up) == 0)
|
|
up->probe |= UART_PROBE_RSA;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
base_ops->config_port(port, flags);
|
|
|
|
if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
|
|
serial8250_release_rsa_resource(up);
|
|
}
|
|
|
|
static int univ8250_request_port(struct uart_port *port)
|
|
{
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
int ret;
|
|
|
|
ret = base_ops->request_port(port);
|
|
if (ret == 0 && port->type == PORT_RSA) {
|
|
ret = serial8250_request_rsa_resource(up);
|
|
if (ret < 0)
|
|
base_ops->release_port(port);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void univ8250_release_port(struct uart_port *port)
|
|
{
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
if (port->type == PORT_RSA)
|
|
serial8250_release_rsa_resource(up);
|
|
base_ops->release_port(port);
|
|
}
|
|
|
|
static void univ8250_rsa_support(struct uart_ops *ops)
|
|
{
|
|
ops->config_port = univ8250_config_port;
|
|
ops->request_port = univ8250_request_port;
|
|
ops->release_port = univ8250_release_port;
|
|
}
|
|
|
|
#else
|
|
#define univ8250_rsa_support(x) do { } while (0)
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
|
|
static inline void serial8250_apply_quirks(struct uart_8250_port *up)
|
|
{
|
|
up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0;
|
|
}
|
|
|
|
static void __init serial8250_isa_init_ports(void)
|
|
{
|
|
struct uart_8250_port *up;
|
|
static int first = 1;
|
|
int i, irqflag = 0;
|
|
|
|
if (!first)
|
|
return;
|
|
first = 0;
|
|
|
|
if (nr_uarts > UART_NR)
|
|
nr_uarts = UART_NR;
|
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
struct uart_port *port = &up->port;
|
|
|
|
port->line = i;
|
|
serial8250_init_port(up);
|
|
if (!base_ops)
|
|
base_ops = port->ops;
|
|
port->ops = &univ8250_port_ops;
|
|
|
|
timer_setup(&up->timer, serial8250_timeout, 0);
|
|
|
|
up->ops = &univ8250_driver_ops;
|
|
|
|
/*
|
|
* ALPHA_KLUDGE_MCR needs to be killed.
|
|
*/
|
|
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
|
|
up->mcr_force = ALPHA_KLUDGE_MCR;
|
|
}
|
|
|
|
/* chain base port ops to support Remote Supervisor Adapter */
|
|
univ8250_port_ops = *base_ops;
|
|
univ8250_rsa_support(&univ8250_port_ops);
|
|
|
|
if (share_irqs)
|
|
irqflag = IRQF_SHARED;
|
|
|
|
for (i = 0, up = serial8250_ports;
|
|
i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
|
|
i++, up++) {
|
|
struct uart_port *port = &up->port;
|
|
|
|
port->iobase = old_serial_port[i].port;
|
|
port->irq = irq_canonicalize(old_serial_port[i].irq);
|
|
port->irqflags = 0;
|
|
port->uartclk = old_serial_port[i].baud_base * 16;
|
|
port->flags = old_serial_port[i].flags;
|
|
port->hub6 = 0;
|
|
port->membase = old_serial_port[i].iomem_base;
|
|
port->iotype = old_serial_port[i].io_type;
|
|
port->regshift = old_serial_port[i].iomem_reg_shift;
|
|
serial8250_set_defaults(up);
|
|
|
|
port->irqflags |= irqflag;
|
|
if (serial8250_isa_config != NULL)
|
|
serial8250_isa_config(i, &up->port, &up->capabilities);
|
|
}
|
|
}
|
|
|
|
static void __init
|
|
serial8250_register_ports(struct uart_driver *drv, struct device *dev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
if (up->port.type == PORT_8250_CIR)
|
|
continue;
|
|
|
|
if (up->port.dev)
|
|
continue;
|
|
|
|
up->port.dev = dev;
|
|
|
|
serial8250_apply_quirks(up);
|
|
uart_add_one_port(drv, &up->port);
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
|
|
|
static void univ8250_console_write(struct console *co, const char *s,
|
|
unsigned int count)
|
|
{
|
|
struct uart_8250_port *up = &serial8250_ports[co->index];
|
|
|
|
serial8250_console_write(up, s, count);
|
|
}
|
|
|
|
static int univ8250_console_setup(struct console *co, char *options)
|
|
{
|
|
struct uart_port *port;
|
|
int retval;
|
|
|
|
/*
|
|
* Check whether an invalid uart number has been specified, and
|
|
* if so, search for the first available port that does have
|
|
* console support.
|
|
*/
|
|
if (co->index >= nr_uarts)
|
|
co->index = 0;
|
|
port = &serial8250_ports[co->index].port;
|
|
/* link port to console */
|
|
port->cons = co;
|
|
|
|
retval = serial8250_console_setup(port, options, false);
|
|
if (retval != 0)
|
|
port->cons = NULL;
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* univ8250_console_match - non-standard console matching
|
|
* @co: registering console
|
|
* @name: name from console command line
|
|
* @idx: index from console command line
|
|
* @options: ptr to option string from console command line
|
|
*
|
|
* Only attempts to match console command lines of the form:
|
|
* console=uart[8250],io|mmio|mmio16|mmio32,<addr>[,<options>]
|
|
* console=uart[8250],0x<addr>[,<options>]
|
|
* This form is used to register an initial earlycon boot console and
|
|
* replace it with the serial8250_console at 8250 driver init.
|
|
*
|
|
* Performs console setup for a match (as required by interface)
|
|
* If no <options> are specified, then assume the h/w is already setup.
|
|
*
|
|
* Returns 0 if console matches; otherwise non-zero to use default matching
|
|
*/
|
|
static int univ8250_console_match(struct console *co, char *name, int idx,
|
|
char *options)
|
|
{
|
|
char match[] = "uart"; /* 8250-specific earlycon name */
|
|
unsigned char iotype;
|
|
resource_size_t addr;
|
|
int i;
|
|
|
|
if (strncmp(name, match, 4) != 0)
|
|
return -ENODEV;
|
|
|
|
if (uart_parse_earlycon(options, &iotype, &addr, &options))
|
|
return -ENODEV;
|
|
|
|
/* try to match the port specified on the command line */
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
struct uart_port *port = &serial8250_ports[i].port;
|
|
|
|
if (port->iotype != iotype)
|
|
continue;
|
|
if ((iotype == UPIO_MEM || iotype == UPIO_MEM16 ||
|
|
iotype == UPIO_MEM32 || iotype == UPIO_MEM32BE)
|
|
&& (port->mapbase != addr))
|
|
continue;
|
|
if (iotype == UPIO_PORT && port->iobase != addr)
|
|
continue;
|
|
|
|
co->index = i;
|
|
port->cons = co;
|
|
return serial8250_console_setup(port, options, true);
|
|
}
|
|
|
|
return -ENODEV;
|
|
}
|
|
|
|
static struct console univ8250_console = {
|
|
.name = "ttyS",
|
|
.write = univ8250_console_write,
|
|
.device = uart_console_device,
|
|
.setup = univ8250_console_setup,
|
|
.match = univ8250_console_match,
|
|
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
|
.index = -1,
|
|
.data = &serial8250_reg,
|
|
};
|
|
|
|
static int __init univ8250_console_init(void)
|
|
{
|
|
if (nr_uarts == 0)
|
|
return -ENODEV;
|
|
|
|
serial8250_isa_init_ports();
|
|
register_console(&univ8250_console);
|
|
return 0;
|
|
}
|
|
console_initcall(univ8250_console_init);
|
|
|
|
#define SERIAL8250_CONSOLE (&univ8250_console)
|
|
#else
|
|
#define SERIAL8250_CONSOLE NULL
|
|
#endif
|
|
|
|
static struct uart_driver serial8250_reg = {
|
|
.owner = THIS_MODULE,
|
|
.driver_name = "serial",
|
|
.dev_name = "ttyS",
|
|
.major = TTY_MAJOR,
|
|
.minor = 64,
|
|
.cons = SERIAL8250_CONSOLE,
|
|
};
|
|
|
|
/*
|
|
* early_serial_setup - early registration for 8250 ports
|
|
*
|
|
* Setup an 8250 port structure prior to console initialisation. Use
|
|
* after console initialisation will cause undefined behaviour.
|
|
*/
|
|
int __init early_serial_setup(struct uart_port *port)
|
|
{
|
|
struct uart_port *p;
|
|
|
|
if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0)
|
|
return -ENODEV;
|
|
|
|
serial8250_isa_init_ports();
|
|
p = &serial8250_ports[port->line].port;
|
|
p->iobase = port->iobase;
|
|
p->membase = port->membase;
|
|
p->irq = port->irq;
|
|
p->irqflags = port->irqflags;
|
|
p->uartclk = port->uartclk;
|
|
p->fifosize = port->fifosize;
|
|
p->regshift = port->regshift;
|
|
p->iotype = port->iotype;
|
|
p->flags = port->flags;
|
|
p->mapbase = port->mapbase;
|
|
p->mapsize = port->mapsize;
|
|
p->private_data = port->private_data;
|
|
p->type = port->type;
|
|
p->line = port->line;
|
|
|
|
serial8250_set_defaults(up_to_u8250p(p));
|
|
|
|
if (port->serial_in)
|
|
p->serial_in = port->serial_in;
|
|
if (port->serial_out)
|
|
p->serial_out = port->serial_out;
|
|
if (port->handle_irq)
|
|
p->handle_irq = port->handle_irq;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* serial8250_suspend_port - suspend one serial port
|
|
* @line: serial line number
|
|
*
|
|
* Suspend one serial port.
|
|
*/
|
|
void serial8250_suspend_port(int line)
|
|
{
|
|
struct uart_8250_port *up = &serial8250_ports[line];
|
|
struct uart_port *port = &up->port;
|
|
|
|
if (!console_suspend_enabled && uart_console(port) &&
|
|
port->type != PORT_8250) {
|
|
unsigned char canary = 0xa5;
|
|
serial_out(up, UART_SCR, canary);
|
|
if (serial_in(up, UART_SCR) == canary)
|
|
up->canary = canary;
|
|
}
|
|
|
|
uart_suspend_port(&serial8250_reg, port);
|
|
}
|
|
EXPORT_SYMBOL(serial8250_suspend_port);
|
|
|
|
/**
|
|
* serial8250_resume_port - resume one serial port
|
|
* @line: serial line number
|
|
*
|
|
* Resume one serial port.
|
|
*/
|
|
void serial8250_resume_port(int line)
|
|
{
|
|
struct uart_8250_port *up = &serial8250_ports[line];
|
|
struct uart_port *port = &up->port;
|
|
|
|
up->canary = 0;
|
|
|
|
if (up->capabilities & UART_NATSEMI) {
|
|
/* Ensure it's still in high speed mode */
|
|
serial_port_out(port, UART_LCR, 0xE0);
|
|
|
|
ns16550a_goto_highspeed(up);
|
|
|
|
serial_port_out(port, UART_LCR, 0);
|
|
port->uartclk = 921600*16;
|
|
}
|
|
uart_resume_port(&serial8250_reg, port);
|
|
}
|
|
EXPORT_SYMBOL(serial8250_resume_port);
|
|
|
|
/*
|
|
* Register a set of serial devices attached to a platform device. The
|
|
* list is terminated with a zero flags entry, which means we expect
|
|
* all entries to have at least UPF_BOOT_AUTOCONF set.
|
|
*/
|
|
static int serial8250_probe(struct platform_device *dev)
|
|
{
|
|
struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
|
|
struct uart_8250_port uart;
|
|
int ret, i, irqflag = 0;
|
|
|
|
memset(&uart, 0, sizeof(uart));
|
|
|
|
if (share_irqs)
|
|
irqflag = IRQF_SHARED;
|
|
|
|
for (i = 0; p && p->flags != 0; p++, i++) {
|
|
uart.port.iobase = p->iobase;
|
|
uart.port.membase = p->membase;
|
|
uart.port.irq = p->irq;
|
|
uart.port.irqflags = p->irqflags;
|
|
uart.port.uartclk = p->uartclk;
|
|
uart.port.regshift = p->regshift;
|
|
uart.port.iotype = p->iotype;
|
|
uart.port.flags = p->flags;
|
|
uart.port.mapbase = p->mapbase;
|
|
uart.port.hub6 = p->hub6;
|
|
uart.port.private_data = p->private_data;
|
|
uart.port.type = p->type;
|
|
uart.port.serial_in = p->serial_in;
|
|
uart.port.serial_out = p->serial_out;
|
|
uart.port.handle_irq = p->handle_irq;
|
|
uart.port.handle_break = p->handle_break;
|
|
uart.port.set_termios = p->set_termios;
|
|
uart.port.set_ldisc = p->set_ldisc;
|
|
uart.port.get_mctrl = p->get_mctrl;
|
|
uart.port.pm = p->pm;
|
|
uart.port.dev = &dev->dev;
|
|
uart.port.irqflags |= irqflag;
|
|
ret = serial8250_register_8250_port(&uart);
|
|
if (ret < 0) {
|
|
dev_err(&dev->dev, "unable to register port at index %d "
|
|
"(IO%lx MEM%llx IRQ%d): %d\n", i,
|
|
p->iobase, (unsigned long long)p->mapbase,
|
|
p->irq, ret);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Remove serial ports registered against a platform device.
|
|
*/
|
|
static int serial8250_remove(struct platform_device *dev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nr_uarts; i++) {
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
if (up->port.dev == &dev->dev)
|
|
serial8250_unregister_port(i);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < UART_NR; i++) {
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
|
uart_suspend_port(&serial8250_reg, &up->port);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int serial8250_resume(struct platform_device *dev)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < UART_NR; i++) {
|
|
struct uart_8250_port *up = &serial8250_ports[i];
|
|
|
|
if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
|
|
serial8250_resume_port(i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver serial8250_isa_driver = {
|
|
.probe = serial8250_probe,
|
|
.remove = serial8250_remove,
|
|
.suspend = serial8250_suspend,
|
|
.resume = serial8250_resume,
|
|
.driver = {
|
|
.name = "serial8250",
|
|
},
|
|
};
|
|
|
|
/*
|
|
* This "device" covers _all_ ISA 8250-compatible serial devices listed
|
|
* in the table in include/asm/serial.h
|
|
*/
|
|
static struct platform_device *serial8250_isa_devs;
|
|
|
|
/*
|
|
* serial8250_register_8250_port and serial8250_unregister_port allows for
|
|
* 16x50 serial ports to be configured at run-time, to support PCMCIA
|
|
* modems and PCI multiport cards.
|
|
*/
|
|
static DEFINE_MUTEX(serial_mutex);
|
|
|
|
static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* First, find a port entry which matches.
|
|
*/
|
|
for (i = 0; i < nr_uarts; i++)
|
|
if (uart_match_port(&serial8250_ports[i].port, port))
|
|
return &serial8250_ports[i];
|
|
|
|
/* try line number first if still available */
|
|
i = port->line;
|
|
if (i < nr_uarts && serial8250_ports[i].port.type == PORT_UNKNOWN &&
|
|
serial8250_ports[i].port.iobase == 0)
|
|
return &serial8250_ports[i];
|
|
/*
|
|
* We didn't find a matching entry, so look for the first
|
|
* free entry. We look for one which hasn't been previously
|
|
* used (indicated by zero iobase).
|
|
*/
|
|
for (i = 0; i < nr_uarts; i++)
|
|
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
|
|
serial8250_ports[i].port.iobase == 0)
|
|
return &serial8250_ports[i];
|
|
|
|
/*
|
|
* That also failed. Last resort is to find any entry which
|
|
* doesn't have a real port associated with it.
|
|
*/
|
|
for (i = 0; i < nr_uarts; i++)
|
|
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
|
|
return &serial8250_ports[i];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* serial8250_register_8250_port - register a serial port
|
|
* @up: serial port template
|
|
*
|
|
* Configure the serial port specified by the request. If the
|
|
* port exists and is in use, it is hung up and unregistered
|
|
* first.
|
|
*
|
|
* The port is then probed and if necessary the IRQ is autodetected
|
|
* If this fails an error is returned.
|
|
*
|
|
* On success the port is ready to use and the line number is returned.
|
|
*/
|
|
int serial8250_register_8250_port(struct uart_8250_port *up)
|
|
{
|
|
struct uart_8250_port *uart;
|
|
int ret = -ENOSPC;
|
|
|
|
if (up->port.uartclk == 0)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&serial_mutex);
|
|
|
|
uart = serial8250_find_match_or_unused(&up->port);
|
|
if (uart && uart->port.type != PORT_8250_CIR) {
|
|
if (uart->port.dev)
|
|
uart_remove_one_port(&serial8250_reg, &uart->port);
|
|
|
|
uart->port.iobase = up->port.iobase;
|
|
uart->port.membase = up->port.membase;
|
|
uart->port.irq = up->port.irq;
|
|
uart->port.irqflags = up->port.irqflags;
|
|
uart->port.uartclk = up->port.uartclk;
|
|
uart->port.fifosize = up->port.fifosize;
|
|
uart->port.regshift = up->port.regshift;
|
|
uart->port.iotype = up->port.iotype;
|
|
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
|
|
uart->bugs = up->bugs;
|
|
uart->port.mapbase = up->port.mapbase;
|
|
uart->port.mapsize = up->port.mapsize;
|
|
uart->port.private_data = up->port.private_data;
|
|
uart->tx_loadsz = up->tx_loadsz;
|
|
uart->capabilities = up->capabilities;
|
|
uart->port.throttle = up->port.throttle;
|
|
uart->port.unthrottle = up->port.unthrottle;
|
|
uart->port.rs485_config = up->port.rs485_config;
|
|
uart->port.rs485 = up->port.rs485;
|
|
uart->dma = up->dma;
|
|
|
|
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
|
if (uart->port.fifosize && !uart->tx_loadsz)
|
|
uart->tx_loadsz = uart->port.fifosize;
|
|
|
|
if (up->port.dev)
|
|
uart->port.dev = up->port.dev;
|
|
|
|
if (up->port.flags & UPF_FIXED_TYPE)
|
|
uart->port.type = up->port.type;
|
|
|
|
serial8250_set_defaults(uart);
|
|
|
|
/* Possibly override default I/O functions. */
|
|
if (up->port.serial_in)
|
|
uart->port.serial_in = up->port.serial_in;
|
|
if (up->port.serial_out)
|
|
uart->port.serial_out = up->port.serial_out;
|
|
if (up->port.handle_irq)
|
|
uart->port.handle_irq = up->port.handle_irq;
|
|
/* Possibly override set_termios call */
|
|
if (up->port.set_termios)
|
|
uart->port.set_termios = up->port.set_termios;
|
|
if (up->port.set_ldisc)
|
|
uart->port.set_ldisc = up->port.set_ldisc;
|
|
if (up->port.get_mctrl)
|
|
uart->port.get_mctrl = up->port.get_mctrl;
|
|
if (up->port.set_mctrl)
|
|
uart->port.set_mctrl = up->port.set_mctrl;
|
|
if (up->port.get_divisor)
|
|
uart->port.get_divisor = up->port.get_divisor;
|
|
if (up->port.set_divisor)
|
|
uart->port.set_divisor = up->port.set_divisor;
|
|
if (up->port.startup)
|
|
uart->port.startup = up->port.startup;
|
|
if (up->port.shutdown)
|
|
uart->port.shutdown = up->port.shutdown;
|
|
if (up->port.pm)
|
|
uart->port.pm = up->port.pm;
|
|
if (up->port.handle_break)
|
|
uart->port.handle_break = up->port.handle_break;
|
|
if (up->dl_read)
|
|
uart->dl_read = up->dl_read;
|
|
if (up->dl_write)
|
|
uart->dl_write = up->dl_write;
|
|
|
|
if (uart->port.type != PORT_8250_CIR) {
|
|
if (serial8250_isa_config != NULL)
|
|
serial8250_isa_config(0, &uart->port,
|
|
&uart->capabilities);
|
|
|
|
serial8250_apply_quirks(uart);
|
|
ret = uart_add_one_port(&serial8250_reg,
|
|
&uart->port);
|
|
if (ret == 0)
|
|
ret = uart->port.line;
|
|
} else {
|
|
dev_info(uart->port.dev,
|
|
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
|
|
uart->port.iobase,
|
|
(unsigned long long)uart->port.mapbase,
|
|
uart->port.irq);
|
|
|
|
ret = 0;
|
|
}
|
|
}
|
|
mutex_unlock(&serial_mutex);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(serial8250_register_8250_port);
|
|
|
|
/**
|
|
* serial8250_unregister_port - remove a 16x50 serial port at runtime
|
|
* @line: serial line number
|
|
*
|
|
* Remove one serial port. This may not be called from interrupt
|
|
* context. We hand the port back to the our control.
|
|
*/
|
|
void serial8250_unregister_port(int line)
|
|
{
|
|
struct uart_8250_port *uart = &serial8250_ports[line];
|
|
|
|
mutex_lock(&serial_mutex);
|
|
|
|
if (uart->em485) {
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&uart->port.lock, flags);
|
|
serial8250_em485_destroy(uart);
|
|
spin_unlock_irqrestore(&uart->port.lock, flags);
|
|
}
|
|
|
|
uart_remove_one_port(&serial8250_reg, &uart->port);
|
|
if (serial8250_isa_devs) {
|
|
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
|
|
uart->port.type = PORT_UNKNOWN;
|
|
uart->port.dev = &serial8250_isa_devs->dev;
|
|
uart->capabilities = 0;
|
|
serial8250_apply_quirks(uart);
|
|
uart_add_one_port(&serial8250_reg, &uart->port);
|
|
} else {
|
|
uart->port.dev = NULL;
|
|
}
|
|
mutex_unlock(&serial_mutex);
|
|
}
|
|
EXPORT_SYMBOL(serial8250_unregister_port);
|
|
|
|
static int __init serial8250_init(void)
|
|
{
|
|
int ret;
|
|
|
|
if (nr_uarts == 0)
|
|
return -ENODEV;
|
|
|
|
serial8250_isa_init_ports();
|
|
|
|
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
|
|
nr_uarts, share_irqs ? "en" : "dis");
|
|
|
|
#ifdef CONFIG_SPARC
|
|
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
|
|
#else
|
|
serial8250_reg.nr = UART_NR;
|
|
ret = uart_register_driver(&serial8250_reg);
|
|
#endif
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = serial8250_pnp_init();
|
|
if (ret)
|
|
goto unreg_uart_drv;
|
|
|
|
serial8250_isa_devs = platform_device_alloc("serial8250",
|
|
PLAT8250_DEV_LEGACY);
|
|
if (!serial8250_isa_devs) {
|
|
ret = -ENOMEM;
|
|
goto unreg_pnp;
|
|
}
|
|
|
|
ret = platform_device_add(serial8250_isa_devs);
|
|
if (ret)
|
|
goto put_dev;
|
|
|
|
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
|
|
|
|
ret = platform_driver_register(&serial8250_isa_driver);
|
|
if (ret == 0)
|
|
goto out;
|
|
|
|
platform_device_del(serial8250_isa_devs);
|
|
put_dev:
|
|
platform_device_put(serial8250_isa_devs);
|
|
unreg_pnp:
|
|
serial8250_pnp_exit();
|
|
unreg_uart_drv:
|
|
#ifdef CONFIG_SPARC
|
|
sunserial_unregister_minors(&serial8250_reg, UART_NR);
|
|
#else
|
|
uart_unregister_driver(&serial8250_reg);
|
|
#endif
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void __exit serial8250_exit(void)
|
|
{
|
|
struct platform_device *isa_dev = serial8250_isa_devs;
|
|
|
|
/*
|
|
* This tells serial8250_unregister_port() not to re-register
|
|
* the ports (thereby making serial8250_isa_driver permanently
|
|
* in use.)
|
|
*/
|
|
serial8250_isa_devs = NULL;
|
|
|
|
platform_driver_unregister(&serial8250_isa_driver);
|
|
platform_device_unregister(isa_dev);
|
|
|
|
serial8250_pnp_exit();
|
|
|
|
#ifdef CONFIG_SPARC
|
|
sunserial_unregister_minors(&serial8250_reg, UART_NR);
|
|
#else
|
|
uart_unregister_driver(&serial8250_reg);
|
|
#endif
|
|
}
|
|
|
|
module_init(serial8250_init);
|
|
module_exit(serial8250_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
|
|
|
|
module_param_hw(share_irqs, uint, other, 0644);
|
|
MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
|
|
|
|
module_param(nr_uarts, uint, 0644);
|
|
MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
|
|
|
|
module_param(skip_txen_test, uint, 0644);
|
|
MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
|
|
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
|
|
MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
|
|
#endif
|
|
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
|
|
|
|
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
|
|
#ifndef MODULE
|
|
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
|
|
* working as well for the module options so we don't break people. We
|
|
* need to keep the names identical and the convenient macros will happily
|
|
* refuse to let us do that by failing the build with redefinition errors
|
|
* of global variables. So we stick them inside a dummy function to avoid
|
|
* those conflicts. The options still get parsed, and the redefined
|
|
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
|
|
*
|
|
* This is hacky. I'm sorry.
|
|
*/
|
|
static void __used s8250_options(void)
|
|
{
|
|
#undef MODULE_PARAM_PREFIX
|
|
#define MODULE_PARAM_PREFIX "8250_core."
|
|
|
|
module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644);
|
|
module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644);
|
|
module_param_cb(skip_txen_test, ¶m_ops_uint, &skip_txen_test, 0644);
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
__module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
|
|
¶m_array_ops, .arr = &__param_arr_probe_rsa,
|
|
0444, -1, 0);
|
|
#endif
|
|
}
|
|
#else
|
|
MODULE_ALIAS("8250_core");
|
|
#endif
|
|
#endif
|