mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-16 19:11:09 +07:00
[PATCH] serial: serial_txx9 driver update
Update the serial_txx9 driver. * More strict check in verify_port. Cleanup. * Do not insert a char caused previous overrun. * Fix some spin_locks. * Do not call uart_add_one_port for absent ports. Also, this patch removes a BROKEN tag from Kconfig. This driver has been marked as BROKEN by removal of uart_register_port, but it has been solved already on Sep 2005. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
4024ce5e0f
commit
83485f826b
@ -866,7 +866,7 @@ config SERIAL_M32R_PLDSIO
|
|||||||
|
|
||||||
config SERIAL_TXX9
|
config SERIAL_TXX9
|
||||||
bool "TMPTX39XX/49XX SIO support"
|
bool "TMPTX39XX/49XX SIO support"
|
||||||
depends HAS_TXX9_SERIAL && BROKEN
|
depends HAS_TXX9_SERIAL
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
* 1.02 Cleanup. (import 8250.c changes)
|
* 1.02 Cleanup. (import 8250.c changes)
|
||||||
* 1.03 Fix low-latency mode. (import 8250.c changes)
|
* 1.03 Fix low-latency mode. (import 8250.c changes)
|
||||||
* 1.04 Remove usage of deprecated functions, cleanup.
|
* 1.04 Remove usage of deprecated functions, cleanup.
|
||||||
|
* 1.05 More strict check in verify_port. Cleanup.
|
||||||
|
* 1.06 Do not insert a char caused previous overrun.
|
||||||
|
* Fix some spin_locks.
|
||||||
|
* Do not call uart_add_one_port for absent ports.
|
||||||
*/
|
*/
|
||||||
#include <linux/config.h>
|
#include <linux/config.h>
|
||||||
|
|
||||||
@ -57,7 +61,7 @@
|
|||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
||||||
static char *serial_version = "1.04";
|
static char *serial_version = "1.06";
|
||||||
static char *serial_name = "TX39/49 Serial driver";
|
static char *serial_name = "TX39/49 Serial driver";
|
||||||
|
|
||||||
#define PASS_LIMIT 256
|
#define PASS_LIMIT 256
|
||||||
@ -94,6 +98,8 @@ static char *serial_name = "TX39/49 Serial driver";
|
|||||||
#define UART_NR 4
|
#define UART_NR 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
|
||||||
|
|
||||||
struct uart_txx9_port {
|
struct uart_txx9_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
|
|
||||||
@ -210,7 +216,7 @@ static inline unsigned int sio_in(struct uart_txx9_port *up, int offset)
|
|||||||
{
|
{
|
||||||
switch (up->port.iotype) {
|
switch (up->port.iotype) {
|
||||||
default:
|
default:
|
||||||
return *(volatile u32 *)(up->port.membase + offset);
|
return __raw_readl(up->port.membase + offset);
|
||||||
case UPIO_PORT:
|
case UPIO_PORT:
|
||||||
return inl(up->port.iobase + offset);
|
return inl(up->port.iobase + offset);
|
||||||
}
|
}
|
||||||
@ -221,7 +227,7 @@ sio_out(struct uart_txx9_port *up, int offset, int value)
|
|||||||
{
|
{
|
||||||
switch (up->port.iotype) {
|
switch (up->port.iotype) {
|
||||||
default:
|
default:
|
||||||
*(volatile u32 *)(up->port.membase + offset) = value;
|
__raw_writel(value, up->port.membase + offset);
|
||||||
break;
|
break;
|
||||||
case UPIO_PORT:
|
case UPIO_PORT:
|
||||||
outl(value, up->port.iobase + offset);
|
outl(value, up->port.iobase + offset);
|
||||||
@ -259,34 +265,19 @@ sio_quot_set(struct uart_txx9_port *up, int quot)
|
|||||||
static void serial_txx9_stop_tx(struct uart_port *port)
|
static void serial_txx9_stop_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&up->port.lock, flags);
|
|
||||||
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
||||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_txx9_start_tx(struct uart_port *port)
|
static void serial_txx9_start_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&up->port.lock, flags);
|
|
||||||
sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
sio_set(up, TXX9_SIDICR, TXX9_SIDICR_TIE);
|
||||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_txx9_stop_rx(struct uart_port *port)
|
static void serial_txx9_stop_rx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&up->port.lock, flags);
|
|
||||||
up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
|
up->port.read_status_mask &= ~TXX9_SIDISR_RDIS;
|
||||||
#if 0
|
|
||||||
sio_mask(up, TXX9_SIDICR, TXX9_SIDICR_RIE);
|
|
||||||
#endif
|
|
||||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_txx9_enable_ms(struct uart_port *port)
|
static void serial_txx9_enable_ms(struct uart_port *port)
|
||||||
@ -302,12 +293,16 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
|
|||||||
unsigned int disr = *status;
|
unsigned int disr = *status;
|
||||||
int max_count = 256;
|
int max_count = 256;
|
||||||
char flag;
|
char flag;
|
||||||
|
unsigned int next_ignore_status_mask;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ch = sio_in(up, TXX9_SIRFIFO);
|
ch = sio_in(up, TXX9_SIRFIFO);
|
||||||
flag = TTY_NORMAL;
|
flag = TTY_NORMAL;
|
||||||
up->port.icount.rx++;
|
up->port.icount.rx++;
|
||||||
|
|
||||||
|
/* mask out RFDN_MASK bit added by previous overrun */
|
||||||
|
next_ignore_status_mask =
|
||||||
|
up->port.ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK;
|
||||||
if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
|
if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
|
||||||
TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
|
TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) {
|
||||||
/*
|
/*
|
||||||
@ -328,8 +323,17 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
|
|||||||
up->port.icount.parity++;
|
up->port.icount.parity++;
|
||||||
else if (disr & TXX9_SIDISR_UFER)
|
else if (disr & TXX9_SIDISR_UFER)
|
||||||
up->port.icount.frame++;
|
up->port.icount.frame++;
|
||||||
if (disr & TXX9_SIDISR_UOER)
|
if (disr & TXX9_SIDISR_UOER) {
|
||||||
up->port.icount.overrun++;
|
up->port.icount.overrun++;
|
||||||
|
/*
|
||||||
|
* The receiver read buffer still hold
|
||||||
|
* a char which caused overrun.
|
||||||
|
* Ignore next char by adding RFDN_MASK
|
||||||
|
* to ignore_status_mask temporarily.
|
||||||
|
*/
|
||||||
|
next_ignore_status_mask |=
|
||||||
|
TXX9_SIDISR_RFDN_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mask off conditions which should be ingored.
|
* Mask off conditions which should be ingored.
|
||||||
@ -349,6 +353,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
|
|||||||
uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
|
uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
|
||||||
|
|
||||||
ignore_char:
|
ignore_char:
|
||||||
|
up->port.ignore_status_mask = next_ignore_status_mask;
|
||||||
disr = sio_in(up, TXX9_SIDISR);
|
disr = sio_in(up, TXX9_SIDISR);
|
||||||
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
|
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
|
||||||
spin_unlock(&up->port.lock);
|
spin_unlock(&up->port.lock);
|
||||||
@ -450,14 +455,11 @@ static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
|
|||||||
static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
static void serial_txx9_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||||
{
|
{
|
||||||
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&up->port.lock, flags);
|
|
||||||
if (mctrl & TIOCM_RTS)
|
if (mctrl & TIOCM_RTS)
|
||||||
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
||||||
else
|
else
|
||||||
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSSC);
|
||||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
|
static void serial_txx9_break_ctl(struct uart_port *port, int break_state)
|
||||||
@ -784,8 +786,14 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
|
|||||||
static int
|
static int
|
||||||
serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
|
serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||||
{
|
{
|
||||||
if (ser->irq < 0 ||
|
unsigned long new_port = ser->port;
|
||||||
ser->baud_base < 9600 || ser->type != PORT_TXX9)
|
if (HIGH_BITS_OFFSET)
|
||||||
|
new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
|
||||||
|
if (ser->type != port->type ||
|
||||||
|
ser->irq != port->irq ||
|
||||||
|
ser->io_type != port->iotype ||
|
||||||
|
new_port != port->iobase ||
|
||||||
|
(unsigned long)ser->iomem_base != port->mapbase)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -827,7 +835,8 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
|
|||||||
|
|
||||||
up->port.line = i;
|
up->port.line = i;
|
||||||
up->port.ops = &serial_txx9_pops;
|
up->port.ops = &serial_txx9_pops;
|
||||||
uart_add_one_port(drv, &up->port);
|
if (up->port.iobase || up->port.mapbase)
|
||||||
|
uart_add_one_port(drv, &up->port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,11 +935,6 @@ static int serial_txx9_console_setup(struct console *co, char *options)
|
|||||||
if (!port->ops)
|
if (!port->ops)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/*
|
|
||||||
* Temporary fix.
|
|
||||||
*/
|
|
||||||
spin_lock_init(&port->lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable UART interrupts, set DTR and RTS high
|
* Disable UART interrupts, set DTR and RTS high
|
||||||
* and set speed.
|
* and set speed.
|
||||||
@ -1041,11 +1045,10 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
|
|||||||
mutex_lock(&serial_txx9_mutex);
|
mutex_lock(&serial_txx9_mutex);
|
||||||
for (i = 0; i < UART_NR; i++) {
|
for (i = 0; i < UART_NR; i++) {
|
||||||
uart = &serial_txx9_ports[i];
|
uart = &serial_txx9_ports[i];
|
||||||
if (uart->port.type == PORT_UNKNOWN)
|
if (!(uart->port.iobase || uart->port.mapbase))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i < UART_NR) {
|
if (i < UART_NR) {
|
||||||
uart_remove_one_port(&serial_txx9_reg, &uart->port);
|
|
||||||
uart->port.iobase = port->iobase;
|
uart->port.iobase = port->iobase;
|
||||||
uart->port.membase = port->membase;
|
uart->port.membase = port->membase;
|
||||||
uart->port.irq = port->irq;
|
uart->port.irq = port->irq;
|
||||||
@ -1080,9 +1083,8 @@ static void __devexit serial_txx9_unregister_port(int line)
|
|||||||
uart->port.type = PORT_UNKNOWN;
|
uart->port.type = PORT_UNKNOWN;
|
||||||
uart->port.iobase = 0;
|
uart->port.iobase = 0;
|
||||||
uart->port.mapbase = 0;
|
uart->port.mapbase = 0;
|
||||||
uart->port.membase = 0;
|
uart->port.membase = NULL;
|
||||||
uart->port.dev = NULL;
|
uart->port.dev = NULL;
|
||||||
uart_add_one_port(&serial_txx9_reg, &uart->port);
|
|
||||||
mutex_unlock(&serial_txx9_mutex);
|
mutex_unlock(&serial_txx9_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1198,8 +1200,11 @@ static void __exit serial_txx9_exit(void)
|
|||||||
#ifdef ENABLE_SERIAL_TXX9_PCI
|
#ifdef ENABLE_SERIAL_TXX9_PCI
|
||||||
pci_unregister_driver(&serial_txx9_pci_driver);
|
pci_unregister_driver(&serial_txx9_pci_driver);
|
||||||
#endif
|
#endif
|
||||||
for (i = 0; i < UART_NR; i++)
|
for (i = 0; i < UART_NR; i++) {
|
||||||
uart_remove_one_port(&serial_txx9_reg, &serial_txx9_ports[i].port);
|
struct uart_txx9_port *up = &serial_txx9_ports[i];
|
||||||
|
if (up->port.iobase || up->port.mapbase)
|
||||||
|
uart_remove_one_port(&serial_txx9_reg, &up->port);
|
||||||
|
}
|
||||||
|
|
||||||
uart_unregister_driver(&serial_txx9_reg);
|
uart_unregister_driver(&serial_txx9_reg);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user