struct irq_info { struct hlist_node node; int irq;
spinlock_t lock; /* Protects list not the hash */ struct list_head *head;
};
#define IRQ_HASH_BITS 5 /* Can be adjusted later */ static DEFINE_HASHTABLE(irq_lists, IRQ_HASH_BITS); 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;
spin_lock(&i->lock);
l = i->head; do { struct uart_8250_port *up = list_entry(l, struct uart_8250_port, list); struct uart_port *port = &up->port;
if (port->handle_irq(port)) {
handled = 1;
end = NULL;
} elseif (end == NULL)
end = l;
l = l->next;
if (l == i->head && pass_counter++ > PASS_LIMIT) break;
} while (l != end);
spin_unlock(&i->lock);
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.
*/ staticvoid 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);
}
}
/* * Either: * - find the corresponding info in the hashtable and return it, or * - allocate a new one, add it to the hashtable and return it.
*/ staticstruct irq_info *serial_get_or_create_irq_info(conststruct uart_8250_port *up)
{ struct irq_info *i;
mutex_lock(&hash_mutex);
hash_for_each_possible(irq_lists, i, node, up->port.irq) if (i->irq == up->port.irq) goto unlock;
i = kzalloc(sizeof(*i), GFP_KERNEL); if (i == NULL) {
i = ERR_PTR(-ENOMEM); goto unlock;
}
spin_lock_init(&i->lock);
i->irq = up->port.irq;
hash_add(irq_lists, &i->node, i->irq);
unlock:
mutex_unlock(&hash_mutex);
return i;
}
staticint serial_link_irq_chain(struct uart_8250_port *up)
{ struct irq_info *i; int ret;
i = serial_get_or_create_irq_info(up); if (IS_ERR(i)) return PTR_ERR(i);
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);
ret = request_irq(up->port.irq, serial8250_interrupt,
up->port.irqflags, up->port.name, i); if (ret < 0)
serial_do_unlink(i, up);
}
/* * 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).
*/ staticvoid serial8250_timeout(struct timer_list *t)
{ struct uart_8250_port *up = timer_container_of(up, t, timer);
/* * 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_lsr_in(up); if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!kfifo_is_empty(&up->port.state->port.xmit_fifo) ||
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);
uart_port_unlock_irqrestore(&up->port, flags);
/* Standard timer interval plus 0.2s to keep the port running */
mod_timer(&up->timer,
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
}
/* * 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);
/* * 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));
}
/** * 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);
/* * 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 < 0 || co->index >= UART_NR)
co->index = 0;
/* * If the console is past the initial isa ports, init more ports up to * co->index as needed and increment nr_uarts accordingly.
*/ for (i = nr_uarts; i <= co->index; i++) {
up = serial8250_setup_port(i); if (!up) return -ENODEV;
nr_uarts++;
}
port = &serial8250_ports[co->index].port; /* link port to console */
uart_port_set_cons(port, co);
port = &serial8250_ports[co->index].port; return serial8250_console_exit(port);
}
/** * 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
*/ staticint univ8250_console_match(struct console *co, char *name, int idx, char *options)
{ char match[] = "uart"; /* 8250-specific earlycon name */ enum uart_iotype 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;
/* * 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;
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;
/** * 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);
/* * 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);
staticstruct uart_8250_port *serial8250_find_match_or_unused(conststruct 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];
/** * 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(conststruct 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) { /* * If the port is past the initial isa ports, initialize a new * port and increment nr_uarts accordingly.
*/
uart = serial8250_setup_port(nr_uarts); if (!uart) goto unlock;
nr_uarts++;
}
/* Check if it is CIR already. We check this below again, see there why. */ if (uart->port.type == PORT_8250_CIR) {
ret = -ENODEV; goto unlock;
}
if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port);
/* 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;
ret = uart_get_rs485_mode(&uart->port); if (ret) goto err;
}
if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type;
/* * Only call mctrl_gpio_init(), if the device has no ACPI * companion device
*/ if (!has_acpi_companion(uart->port.dev)) { struct mctrl_gpios *gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) {
ret = PTR_ERR(gpios); goto err;
} else {
uart->gpios = gpios;
}
}
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;
/* Check the type (again)! It might have changed by the port.type assignment above. */ if (uart->port.type != PORT_8250_CIR) { if (uart_console_registered(&uart->port))
pm_runtime_get_sync(uart->port.dev);
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) goto err;
ret = uart->port.line;
} else {
dev_info(uart->port.dev, "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
uart->port.iobase,
(unsignedlonglong)uart->port.mapbase,
uart->port.irq);
ret = 0;
}
if (!uart->lsr_save_mask)
uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
/* Initialise interrupt backoff work if required */ if (up->overrun_backoff_time_ms > 0) {
uart->overrun_backoff_time_ms =
up->overrun_backoff_time_ms;
INIT_DELAYED_WORK(&uart->overrun_backoff,
serial_8250_overrun_backoff_work);
} else {
uart->overrun_backoff_time_ms = 0;
}
/** * 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];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.