Skip to content

Commit ac60197

Browse files
sumitsemwalgregkh
authored andcommitted
serial: 8250_pci: Detach low-level driver during PCI error recovery
From: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com> [ Upstream commit f209fa03fc9d131b3108c2e4936181eabab87416 ] During a PCI error recovery, like the ones provoked by EEH in the ppc64 platform, all IO to the device must be blocked while the recovery is completed. Current 8250_pci implementation only suspends the port instead of detaching it, which doesn't prevent incoming accesses like TIOCMGET and TIOCMSET calls from reaching the device. Those end up racing with the EEH recovery, crashing it. Similar races were also observed when opening the device and when shutting it down during recovery. This patch implements a more robust IO blockage for the 8250_pci recovery by unregistering the port at the beginning of the procedure and re-adding it afterwards. Since the port is detached from the uart layer, we can be sure that no request will make through to the device during recovery. This is similar to the solution used by the JSM serial driver. I thank Peter Hurley <peter@hurleysoftware.com> for valuable input on this one over one year ago. Signed-off-by: Gabriel Krisman Bertazi <krisman@linux.vnet.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b8687d8 commit ac60197

1 file changed

Lines changed: 19 additions & 4 deletions

File tree

drivers/tty/serial/8250/8250_pci.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct serial_private {
5757
unsigned int nr;
5858
void __iomem *remapped_bar[PCI_NUM_BAR_RESOURCES];
5959
struct pci_serial_quirk *quirk;
60+
const struct pciserial_board *board;
6061
int line[0];
6162
};
6263

@@ -4058,6 +4059,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
40584059
}
40594060
}
40604061
priv->nr = i;
4062+
priv->board = board;
40614063
return priv;
40624064

40634065
err_deinit:
@@ -4068,7 +4070,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
40684070
}
40694071
EXPORT_SYMBOL_GPL(pciserial_init_ports);
40704072

4071-
void pciserial_remove_ports(struct serial_private *priv)
4073+
void pciserial_detach_ports(struct serial_private *priv)
40724074
{
40734075
struct pci_serial_quirk *quirk;
40744076
int i;
@@ -4088,7 +4090,11 @@ void pciserial_remove_ports(struct serial_private *priv)
40884090
quirk = find_quirk(priv->dev);
40894091
if (quirk->exit)
40904092
quirk->exit(priv->dev);
4093+
}
40914094

4095+
void pciserial_remove_ports(struct serial_private *priv)
4096+
{
4097+
pciserial_detach_ports(priv);
40924098
kfree(priv);
40934099
}
40944100
EXPORT_SYMBOL_GPL(pciserial_remove_ports);
@@ -5819,7 +5825,7 @@ static pci_ers_result_t serial8250_io_error_detected(struct pci_dev *dev,
58195825
return PCI_ERS_RESULT_DISCONNECT;
58205826

58215827
if (priv)
5822-
pciserial_suspend_ports(priv);
5828+
pciserial_detach_ports(priv);
58235829

58245830
pci_disable_device(dev);
58255831

@@ -5844,9 +5850,18 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
58445850
static void serial8250_io_resume(struct pci_dev *dev)
58455851
{
58465852
struct serial_private *priv = pci_get_drvdata(dev);
5853+
const struct pciserial_board *board;
58475854

5848-
if (priv)
5849-
pciserial_resume_ports(priv);
5855+
if (!priv)
5856+
return;
5857+
5858+
board = priv->board;
5859+
kfree(priv);
5860+
priv = pciserial_init_ports(dev, board);
5861+
5862+
if (!IS_ERR(priv)) {
5863+
pci_set_drvdata(dev, priv);
5864+
}
58505865
}
58515866

58525867
static const struct pci_error_handlers serial8250_err_handler = {

0 commit comments

Comments
 (0)