Skip to content

Commit

Permalink
serial/8250_pci: Clear FIFOs for Intel ME Serial Over Lan device on BI
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sudhakar Mamillapalli authored and Greg Kroah-Hartman committed Apr 18, 2012
1 parent 665ab0f commit 0ad372b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/tty/serial/8250/8250.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions drivers/tty/serial/8250/8250.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 39 additions & 0 deletions drivers/tty/serial/8250/8250_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 0ad372b

Please sign in to comment.