diff options
author | Sudhakar Mamillapalli <sudhakar@fb.com> | 2012-04-10 14:10:58 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-18 16:26:17 -0700 |
commit | 0ad372b962d109323d18ac2aa118b2ad100eb8dd (patch) | |
tree | 82a9c1308720f9a96ff1432c063125a0695160d4 /drivers/tty | |
parent | 665ab0f3c8b8f86bb77b25285ac93870c7054d63 (diff) |
serial/8250_pci: Clear FIFOs for Intel ME Serial Over Lan device on BI
When using Serial Over Lan (SOL) over the virtual serial port in a Intel
management engine (ME) device, on device reset the serial FIFOs need to
be cleared to keep the FIFO indexes in-sync between the host and the
engine.
On a reset the serial device assertes BI, so using that as a cue FIFOs
are cleared. So for this purpose a new handle_break callback has been
added. One other problem is that the serial registers might temporarily
go to 0 on reset of this device. So instead of using the IER register
read, if 0 returned use the ier value in uart_8250_port. This is hidden
under a custom serial_in.
Cc: Nhan H Mai <nhan.h.mai@intel.com>
Signed-off-by: Sudhakar Mamillapalli <sudhakar@fb.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/8250/8250.c | 10 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250.h | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 39 |
3 files changed, 51 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index cbd94c3b5702..182efcc90e2e 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -568,6 +568,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) } } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + unsigned char fcr; + + serial8250_clear_fifos(p); + fcr = uart_config[p->port.type].fcr; + serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + /* * IER sleep support. UARTs which have EFRs need the "extended * capability" bit enabled. Note that on XR16C850s, we need to diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 2868a1da254d..c9d0ebe952fc 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -96,6 +96,8 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca865d6a..024551acf874 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/tty.h> +#include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> @@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static void kt_handle_break(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + /* + * On receipt of a BI, serial device in Intel ME (Intel + * management engine) needs to have its fifos cleared for sane + * SOL (Serial Over Lan) output. + */ + serial8250_clear_and_reinit_fifos(up); +} + +static unsigned int kt_serial_in(struct uart_port *p, int offset) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + unsigned int val; + + /* + * When the Intel ME (management engine) gets reset its serial + * port registers could return 0 momentarily. Functions like + * serial8250_console_write, read and save the IER, perform + * some operation and then restore it. In order to avoid + * setting IER register inadvertently to 0, if the value read + * is 0, double check with ier value in uart_8250_port and use + * that instead. up->ier should be the same value as what is + * currently configured. + */ + val = inb(p->iobase + offset); + if (offset == UART_IER) { + if (val == 0) + val = up->ier; + } + return val; +} + static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_port *port, int idx) { port->flags |= UPF_BUG_THRE; + port->serial_in = kt_serial_in; + port->handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } |