mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-15 16:53:54 +08:00
Merge master.kernel.org:/home/rmk/linux-2.6-serial
* master.kernel.org:/home/rmk/linux-2.6-serial: [SERIAL] 8250: add locking to console write function [SERIAL] Remove unconditional enable of TX irq for console [SERIAL] 8250: set divisor register correctly for AMD Alchemy SoC uart [SERIAL] AMD Alchemy UART: claim memory range [SERIAL] Clean up serial locking when obtaining a reference to a port
This commit is contained in:
commit
2bf9d6d0f2
@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value)
|
||||
#define serial_inp(up, offset) serial_in(up, offset)
|
||||
#define serial_outp(up, offset, value) serial_out(up, offset, value)
|
||||
|
||||
/* Uart divisor latch read */
|
||||
static inline int _serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
|
||||
}
|
||||
|
||||
/* Uart divisor latch write */
|
||||
static inline void _serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
serial_outp(up, UART_DLL, value & 0xff);
|
||||
serial_outp(up, UART_DLM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_AU1X00
|
||||
/* Au1x00 haven't got a standard divisor latch */
|
||||
static int serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
if (up->port.iotype == UPIO_AU)
|
||||
return __raw_readl(up->port.membase + 0x28);
|
||||
else
|
||||
return _serial_dl_read(up);
|
||||
}
|
||||
|
||||
static void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
if (up->port.iotype == UPIO_AU)
|
||||
__raw_writel(value, up->port.membase + 0x28);
|
||||
else
|
||||
_serial_dl_write(up, value);
|
||||
}
|
||||
#else
|
||||
#define serial_dl_read(up) _serial_dl_read(up)
|
||||
#define serial_dl_write(up, value) _serial_dl_write(up, value)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For the 16C950
|
||||
@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up)
|
||||
*/
|
||||
static int size_fifo(struct uart_8250_port *up)
|
||||
{
|
||||
unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
|
||||
unsigned char old_fcr, old_mcr, old_lcr;
|
||||
unsigned short old_dl;
|
||||
int count;
|
||||
|
||||
old_lcr = serial_inp(up, UART_LCR);
|
||||
@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||
serial_outp(up, UART_MCR, UART_MCR_LOOP);
|
||||
serial_outp(up, UART_LCR, UART_LCR_DLAB);
|
||||
old_dll = serial_inp(up, UART_DLL);
|
||||
old_dlm = serial_inp(up, UART_DLM);
|
||||
serial_outp(up, UART_DLL, 0x01);
|
||||
serial_outp(up, UART_DLM, 0x00);
|
||||
old_dl = serial_dl_read(up);
|
||||
serial_dl_write(up, 0x0001);
|
||||
serial_outp(up, UART_LCR, 0x03);
|
||||
for (count = 0; count < 256; count++)
|
||||
serial_outp(up, UART_TX, count);
|
||||
@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
serial_outp(up, UART_FCR, old_fcr);
|
||||
serial_outp(up, UART_MCR, old_mcr);
|
||||
serial_outp(up, UART_LCR, UART_LCR_DLAB);
|
||||
serial_outp(up, UART_DLL, old_dll);
|
||||
serial_outp(up, UART_DLM, old_dlm);
|
||||
serial_dl_write(up, old_dl);
|
||||
serial_outp(up, UART_LCR, old_lcr);
|
||||
|
||||
return count;
|
||||
@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
|
||||
|
||||
serial_outp(up, UART_LCR, 0xE0);
|
||||
|
||||
quot = serial_inp(up, UART_DLM) << 8;
|
||||
quot += serial_inp(up, UART_DLL);
|
||||
quot = serial_dl_read(up);
|
||||
quot <<= 3;
|
||||
|
||||
status1 = serial_in(up, 0x04); /* EXCR1 */
|
||||
@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
|
||||
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
|
||||
serial_outp(up, 0x04, status1);
|
||||
|
||||
serial_outp(up, UART_DLL, quot & 0xff);
|
||||
serial_outp(up, UART_DLM, quot >> 8);
|
||||
serial_dl_write(up, quot);
|
||||
|
||||
serial_outp(up, UART_LCR, 0);
|
||||
|
||||
@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
|
||||
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
|
||||
}
|
||||
|
||||
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
|
||||
serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
|
||||
serial_dl_write(up, quot);
|
||||
|
||||
/*
|
||||
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
|
||||
@ -1906,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
|
||||
int ret = 0;
|
||||
|
||||
switch (up->port.iotype) {
|
||||
case UPIO_AU:
|
||||
size = 0x100000;
|
||||
/* fall thru */
|
||||
case UPIO_MEM:
|
||||
if (!up->port.mapbase)
|
||||
break;
|
||||
@ -1938,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
|
||||
unsigned int size = 8 << up->port.regshift;
|
||||
|
||||
switch (up->port.iotype) {
|
||||
case UPIO_AU:
|
||||
size = 0x100000;
|
||||
/* fall thru */
|
||||
case UPIO_MEM:
|
||||
if (!up->port.mapbase)
|
||||
break;
|
||||
@ -2200,10 +2235,17 @@ static void
|
||||
serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_8250_port *up = &serial8250_ports[co->index];
|
||||
unsigned long flags;
|
||||
unsigned int ier;
|
||||
int locked = 1;
|
||||
|
||||
touch_nmi_watchdog();
|
||||
|
||||
if (oops_in_progress) {
|
||||
locked = spin_trylock_irqsave(&up->port.lock, flags);
|
||||
} else
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
*/
|
||||
@ -2221,8 +2263,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
up->ier |= UART_IER_THRI;
|
||||
serial_out(up, UART_IER, ier | UART_IER_THRI);
|
||||
serial_out(up, UART_IER, ier);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
}
|
||||
|
||||
static int serial8250_console_setup(struct console *co, char *options)
|
||||
|
@ -30,13 +30,12 @@
|
||||
{ \
|
||||
.iobase = _base, \
|
||||
.membase = (void __iomem *)_base,\
|
||||
.mapbase = _base, \
|
||||
.mapbase = CPHYSADDR(_base), \
|
||||
.irq = _irq, \
|
||||
.uartclk = 0, /* filled */ \
|
||||
.regshift = 2, \
|
||||
.iotype = UPIO_AU, \
|
||||
.flags = UPF_SKIP_TEST | \
|
||||
UPF_IOREMAP, \
|
||||
.flags = UPF_SKIP_TEST \
|
||||
}
|
||||
|
||||
static struct plat_serial8250_port au1x00_data[] = {
|
||||
|
@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
|
||||
static struct uart_state *uart_get(struct uart_driver *drv, int line)
|
||||
{
|
||||
struct uart_state *state;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&port_mutex);
|
||||
state = drv->state + line;
|
||||
if (mutex_lock_interruptible(&state->mutex)) {
|
||||
state = ERR_PTR(-ERESTARTSYS);
|
||||
goto out;
|
||||
ret = -ERESTARTSYS;
|
||||
goto err;
|
||||
}
|
||||
|
||||
state->count++;
|
||||
if (!state->port) {
|
||||
state->count--;
|
||||
mutex_unlock(&state->mutex);
|
||||
state = ERR_PTR(-ENXIO);
|
||||
goto out;
|
||||
if (!state->port || state->port->flags & UPF_DEAD) {
|
||||
ret = -ENXIO;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (!state->info) {
|
||||
@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
|
||||
tasklet_init(&state->info->tlet, uart_tasklet_action,
|
||||
(unsigned long)state);
|
||||
} else {
|
||||
state->count--;
|
||||
mutex_unlock(&state->mutex);
|
||||
state = ERR_PTR(-ENOMEM);
|
||||
ret = -ENOMEM;
|
||||
goto err_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&port_mutex);
|
||||
return state;
|
||||
|
||||
err_unlock:
|
||||
state->count--;
|
||||
mutex_unlock(&state->mutex);
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2085,45 +2085,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This reverses the effects of uart_configure_port, hanging up the
|
||||
* port before removal.
|
||||
*/
|
||||
static void
|
||||
uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
|
||||
{
|
||||
struct uart_port *port = state->port;
|
||||
struct uart_info *info = state->info;
|
||||
|
||||
if (info && info->tty)
|
||||
tty_vhangup(info->tty);
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
||||
state->info = NULL;
|
||||
|
||||
/*
|
||||
* Free the port IO and memory resources, if any.
|
||||
*/
|
||||
if (port->type != PORT_UNKNOWN)
|
||||
port->ops->release_port(port);
|
||||
|
||||
/*
|
||||
* Indicate that there isn't a port here anymore.
|
||||
*/
|
||||
port->type = PORT_UNKNOWN;
|
||||
|
||||
/*
|
||||
* Kill the tasklet, and free resources.
|
||||
*/
|
||||
if (info) {
|
||||
tasklet_kill(&info->tlet);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
}
|
||||
|
||||
static struct tty_operations uart_ops = {
|
||||
.open = uart_open,
|
||||
.close = uart_close,
|
||||
@ -2270,6 +2231,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||
state = drv->state + port->line;
|
||||
|
||||
mutex_lock(&port_mutex);
|
||||
mutex_lock(&state->mutex);
|
||||
if (state->port) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -2304,7 +2266,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||
port->cons && !(port->cons->flags & CON_ENABLED))
|
||||
register_console(port->cons);
|
||||
|
||||
/*
|
||||
* Ensure UPF_DEAD is not set.
|
||||
*/
|
||||
port->flags &= ~UPF_DEAD;
|
||||
|
||||
out:
|
||||
mutex_unlock(&state->mutex);
|
||||
mutex_unlock(&port_mutex);
|
||||
|
||||
return ret;
|
||||
@ -2322,6 +2290,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||
{
|
||||
struct uart_state *state = drv->state + port->line;
|
||||
struct uart_info *info;
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
@ -2331,12 +2300,49 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
|
||||
|
||||
mutex_lock(&port_mutex);
|
||||
|
||||
/*
|
||||
* Mark the port "dead" - this prevents any opens from
|
||||
* succeeding while we shut down the port.
|
||||
*/
|
||||
mutex_lock(&state->mutex);
|
||||
port->flags |= UPF_DEAD;
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
/*
|
||||
* Remove the devices from devfs
|
||||
*/
|
||||
tty_unregister_device(drv->tty_driver, port->line);
|
||||
|
||||
uart_unconfigure_port(drv, state);
|
||||
info = state->info;
|
||||
if (info && info->tty)
|
||||
tty_vhangup(info->tty);
|
||||
|
||||
/*
|
||||
* All users of this port should now be disconnected from
|
||||
* this driver, and the port shut down. We should be the
|
||||
* only thread fiddling with this port from now on.
|
||||
*/
|
||||
state->info = NULL;
|
||||
|
||||
/*
|
||||
* Free the port IO and memory resources, if any.
|
||||
*/
|
||||
if (port->type != PORT_UNKNOWN)
|
||||
port->ops->release_port(port);
|
||||
|
||||
/*
|
||||
* Indicate that there isn't a port here anymore.
|
||||
*/
|
||||
port->type = PORT_UNKNOWN;
|
||||
|
||||
/*
|
||||
* Kill the tasklet, and free resources.
|
||||
*/
|
||||
if (info) {
|
||||
tasklet_kill(&info->tlet);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
state->port = NULL;
|
||||
mutex_unlock(&port_mutex);
|
||||
|
||||
|
@ -254,6 +254,7 @@ struct uart_port {
|
||||
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
|
||||
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
|
||||
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
|
||||
#define UPF_DEAD ((__force upf_t) (1 << 30))
|
||||
#define UPF_IOREMAP ((__force upf_t) (1 << 31))
|
||||
|
||||
#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
|
||||
|
Loading…
Reference in New Issue
Block a user