diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_pci.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca865d6a..28e7c7cce893 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 | ||
@@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
1609 | { | 1648 | { |
1610 | .vendor = PCI_VENDOR_ID_INTEL, | 1649 | .vendor = PCI_VENDOR_ID_INTEL, |
1611 | .device = 0x8811, | 1650 | .device = 0x8811, |
1651 | .subvendor = PCI_ANY_ID, | ||
1652 | .subdevice = PCI_ANY_ID, | ||
1612 | .init = pci_eg20t_init, | 1653 | .init = pci_eg20t_init, |
1613 | .setup = pci_default_setup, | 1654 | .setup = pci_default_setup, |
1614 | }, | 1655 | }, |
1615 | { | 1656 | { |
1616 | .vendor = PCI_VENDOR_ID_INTEL, | 1657 | .vendor = PCI_VENDOR_ID_INTEL, |
1617 | .device = 0x8812, | 1658 | .device = 0x8812, |
1659 | .subvendor = PCI_ANY_ID, | ||
1660 | .subdevice = PCI_ANY_ID, | ||
1618 | .init = pci_eg20t_init, | 1661 | .init = pci_eg20t_init, |
1619 | .setup = pci_default_setup, | 1662 | .setup = pci_default_setup, |
1620 | }, | 1663 | }, |
1621 | { | 1664 | { |
1622 | .vendor = PCI_VENDOR_ID_INTEL, | 1665 | .vendor = PCI_VENDOR_ID_INTEL, |
1623 | .device = 0x8813, | 1666 | .device = 0x8813, |
1667 | .subvendor = PCI_ANY_ID, | ||
1668 | .subdevice = PCI_ANY_ID, | ||
1624 | .init = pci_eg20t_init, | 1669 | .init = pci_eg20t_init, |
1625 | .setup = pci_default_setup, | 1670 | .setup = pci_default_setup, |
1626 | }, | 1671 | }, |
1627 | { | 1672 | { |
1628 | .vendor = PCI_VENDOR_ID_INTEL, | 1673 | .vendor = PCI_VENDOR_ID_INTEL, |
1629 | .device = 0x8814, | 1674 | .device = 0x8814, |
1675 | .subvendor = PCI_ANY_ID, | ||
1676 | .subdevice = PCI_ANY_ID, | ||
1630 | .init = pci_eg20t_init, | 1677 | .init = pci_eg20t_init, |
1631 | .setup = pci_default_setup, | 1678 | .setup = pci_default_setup, |
1632 | }, | 1679 | }, |
1633 | { | 1680 | { |
1634 | .vendor = 0x10DB, | 1681 | .vendor = 0x10DB, |
1635 | .device = 0x8027, | 1682 | .device = 0x8027, |
1683 | .subvendor = PCI_ANY_ID, | ||
1684 | .subdevice = PCI_ANY_ID, | ||
1636 | .init = pci_eg20t_init, | 1685 | .init = pci_eg20t_init, |
1637 | .setup = pci_default_setup, | 1686 | .setup = pci_default_setup, |
1638 | }, | 1687 | }, |
1639 | { | 1688 | { |
1640 | .vendor = 0x10DB, | 1689 | .vendor = 0x10DB, |
1641 | .device = 0x8028, | 1690 | .device = 0x8028, |
1691 | .subvendor = PCI_ANY_ID, | ||
1692 | .subdevice = PCI_ANY_ID, | ||
1642 | .init = pci_eg20t_init, | 1693 | .init = pci_eg20t_init, |
1643 | .setup = pci_default_setup, | 1694 | .setup = pci_default_setup, |
1644 | }, | 1695 | }, |
1645 | { | 1696 | { |
1646 | .vendor = 0x10DB, | 1697 | .vendor = 0x10DB, |
1647 | .device = 0x8029, | 1698 | .device = 0x8029, |
1699 | .subvendor = PCI_ANY_ID, | ||
1700 | .subdevice = PCI_ANY_ID, | ||
1648 | .init = pci_eg20t_init, | 1701 | .init = pci_eg20t_init, |
1649 | .setup = pci_default_setup, | 1702 | .setup = pci_default_setup, |
1650 | }, | 1703 | }, |
1651 | { | 1704 | { |
1652 | .vendor = 0x10DB, | 1705 | .vendor = 0x10DB, |
1653 | .device = 0x800C, | 1706 | .device = 0x800C, |
1707 | .subvendor = PCI_ANY_ID, | ||
1708 | .subdevice = PCI_ANY_ID, | ||
1654 | .init = pci_eg20t_init, | 1709 | .init = pci_eg20t_init, |
1655 | .setup = pci_default_setup, | 1710 | .setup = pci_default_setup, |
1656 | }, | 1711 | }, |
1657 | { | 1712 | { |
1658 | .vendor = 0x10DB, | 1713 | .vendor = 0x10DB, |
1659 | .device = 0x800D, | 1714 | .device = 0x800D, |
1715 | .subvendor = PCI_ANY_ID, | ||
1716 | .subdevice = PCI_ANY_ID, | ||
1660 | .init = pci_eg20t_init, | 1717 | .init = pci_eg20t_init, |
1661 | .setup = pci_default_setup, | 1718 | .setup = pci_default_setup, |
1662 | }, | 1719 | }, |
@@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv) | |||
2775 | for (i = 0; i < priv->nr; i++) | 2832 | for (i = 0; i < priv->nr; i++) |
2776 | if (priv->line[i] >= 0) | 2833 | if (priv->line[i] >= 0) |
2777 | serial8250_suspend_port(priv->line[i]); | 2834 | serial8250_suspend_port(priv->line[i]); |
2835 | |||
2836 | /* | ||
2837 | * Ensure that every init quirk is properly torn down | ||
2838 | */ | ||
2839 | if (priv->quirk->exit) | ||
2840 | priv->quirk->exit(priv->dev); | ||
2778 | } | 2841 | } |
2779 | EXPORT_SYMBOL_GPL(pciserial_suspend_ports); | 2842 | EXPORT_SYMBOL_GPL(pciserial_suspend_ports); |
2780 | 2843 | ||