diff options
author | Sudhakar Mamillapalli <sudhakar@fb.com> | 2012-04-10 17:10:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-18 19:26:17 -0400 |
commit | 0ad372b962d109323d18ac2aa118b2ad100eb8dd (patch) | |
tree | 82a9c1308720f9a96ff1432c063125a0695160d4 | |
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>
-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) | |||
568 | } | 568 | } |
569 | } | 569 | } |
570 | 570 | ||
571 | void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) | ||
572 | { | ||
573 | unsigned char fcr; | ||
574 | |||
575 | serial8250_clear_fifos(p); | ||
576 | fcr = uart_config[p->port.type].fcr; | ||
577 | serial_out(p, UART_FCR, fcr); | ||
578 | } | ||
579 | EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); | ||
580 | |||
571 | /* | 581 | /* |
572 | * IER sleep support. UARTs which have EFRs need the "extended | 582 | * IER sleep support. UARTs which have EFRs need the "extended |
573 | * capability" bit enabled. Note that on XR16C850s, we need to | 583 | * 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) | |||
96 | up->port.serial_out(&up->port, offset, value); | 96 | up->port.serial_out(&up->port, offset, value); |
97 | } | 97 | } |
98 | 98 | ||
99 | void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); | ||
100 | |||
99 | #if defined(__alpha__) && !defined(CONFIG_PCI) | 101 | #if defined(__alpha__) && !defined(CONFIG_PCI) |
100 | /* | 102 | /* |
101 | * Digital did something really horribly wrong with the OUT1 and OUT2 | 103 | * 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 @@ | |||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/tty.h> | 19 | #include <linux/tty.h> |
20 | #include <linux/serial_reg.h> | ||
20 | #include <linux/serial_core.h> | 21 | #include <linux/serial_core.h> |
21 | #include <linux/8250_pci.h> | 22 | #include <linux/8250_pci.h> |
22 | #include <linux/bitops.h> | 23 | #include <linux/bitops.h> |
@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, | |||
1092 | return pci_default_setup(priv, board, port, idx); | 1093 | return pci_default_setup(priv, board, port, idx); |
1093 | } | 1094 | } |
1094 | 1095 | ||
1096 | static void kt_handle_break(struct uart_port *p) | ||
1097 | { | ||
1098 | struct uart_8250_port *up = | ||
1099 | container_of(p, struct uart_8250_port, port); | ||
1100 | /* | ||
1101 | * On receipt of a BI, serial device in Intel ME (Intel | ||
1102 | * management engine) needs to have its fifos cleared for sane | ||
1103 | * SOL (Serial Over Lan) output. | ||
1104 | */ | ||
1105 | serial8250_clear_and_reinit_fifos(up); | ||
1106 | } | ||
1107 | |||
1108 | static unsigned int kt_serial_in(struct uart_port *p, int offset) | ||
1109 | { | ||
1110 | struct uart_8250_port *up = | ||
1111 | container_of(p, struct uart_8250_port, port); | ||
1112 | unsigned int val; | ||
1113 | |||
1114 | /* | ||
1115 | * When the Intel ME (management engine) gets reset its serial | ||
1116 | * port registers could return 0 momentarily. Functions like | ||
1117 | * serial8250_console_write, read and save the IER, perform | ||
1118 | * some operation and then restore it. In order to avoid | ||
1119 | * setting IER register inadvertently to 0, if the value read | ||
1120 | * is 0, double check with ier value in uart_8250_port and use | ||
1121 | * that instead. up->ier should be the same value as what is | ||
1122 | * currently configured. | ||
1123 | */ | ||
1124 | val = inb(p->iobase + offset); | ||
1125 | if (offset == UART_IER) { | ||
1126 | if (val == 0) | ||
1127 | val = up->ier; | ||
1128 | } | ||
1129 | return val; | ||
1130 | } | ||
1131 | |||
1095 | static int kt_serial_setup(struct serial_private *priv, | 1132 | static int kt_serial_setup(struct serial_private *priv, |
1096 | const struct pciserial_board *board, | 1133 | const struct pciserial_board *board, |
1097 | struct uart_port *port, int idx) | 1134 | struct uart_port *port, int idx) |
1098 | { | 1135 | { |
1099 | port->flags |= UPF_BUG_THRE; | 1136 | port->flags |= UPF_BUG_THRE; |
1137 | port->serial_in = kt_serial_in; | ||
1138 | port->handle_break = kt_handle_break; | ||
1100 | return skip_tx_en_setup(priv, board, port, idx); | 1139 | return skip_tx_en_setup(priv, board, port, idx); |
1101 | } | 1140 | } |
1102 | 1141 | ||