Skip to content

Commit

Permalink
UBUNTU: SAUCE: PCI/DPC: Disable DPC interrupt during suspend
Browse files Browse the repository at this point in the history
BugLink: https://bugs.launchpad.net/bugs/1913691

Commit 5031060 ("iommu/vt-d: Enable PCI ACS for platform opt in
hint") enables ACS, and some platforms lose its NVMe after resume from
firmware:
[   50.947816] pcieport 0000:00:1b.0: DPC: containment event, status:0x1f01 source:0x0000
[   50.947817] pcieport 0000:00:1b.0: DPC: unmasked uncorrectable error detected
[   50.947829] pcieport 0000:00:1b.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Receiver ID)
[   50.947830] pcieport 0000:00:1b.0:   device [8086:06ac] error status/mask=00200000/00010000
[   50.947831] pcieport 0000:00:1b.0:    [21] ACSViol                (First)
[   50.947841] pcieport 0000:00:1b.0: AER: broadcast error_detected message
[   50.947843] nvme nvme0: frozen state error detected, reset controller

Like what previous patch does to AER, introduce new helpers to disable
DPC interrupt and enable it on system suspend and resume, respectively.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=209149
Fixes: 5031060 ("iommu/vt-d: Enable PCI ACS for platform opt in hint")
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Signed-off-by: Timo Aaltonen <timo.aaltonen@canonical.com>
  • Loading branch information
Kai-Heng Feng authored and Timo Aaltonen committed Jan 29, 2021
1 parent 3e31ff0 commit 689eccd
Showing 1 changed file with 38 additions and 11 deletions.
49 changes: 38 additions & 11 deletions drivers/pci/pcie/dpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,34 @@ void pci_dpc_init(struct pci_dev *pdev)
}
}

static void dpc_enable(struct pcie_device *dev)
{
struct pci_dev *pdev = dev->port;
u16 ctl;

pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);

ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
}

static void dpc_disable(struct pcie_device *dev)
{
struct pci_dev *pdev = dev->port;
u16 ctl;

pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);
ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN);
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
}

#define FLAG(x, y) (((x) & (y)) ? '+' : '-')
static int dpc_probe(struct pcie_device *dev)
{
struct pci_dev *pdev = dev->port;
struct device *device = &dev->device;
int status;
u16 ctl, cap;
u16 cap;

if (!pcie_aer_is_native(pdev) && !pcie_ports_dpc_native)
return -ENOTSUPP;
Expand All @@ -300,10 +321,7 @@ static int dpc_probe(struct pcie_device *dev)
}

pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CAP, &cap);
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);

ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
dpc_enable(dev);
pci_info(pdev, "enabled with IRQ %d\n", dev->irq);

pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
Expand All @@ -316,21 +334,30 @@ static int dpc_probe(struct pcie_device *dev)
return status;
}

static void dpc_remove(struct pcie_device *dev)
static int dpc_suspend(struct pcie_device *dev)
{
struct pci_dev *pdev = dev->port;
u16 ctl;
dpc_disable(dev);
return 0;
}

pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);
ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN);
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
static int dpc_resume(struct pcie_device *dev)
{
dpc_enable(dev);
return 0;
}

static void dpc_remove(struct pcie_device *dev)
{
dpc_disable(dev);
}

static struct pcie_port_service_driver dpcdriver = {
.name = "dpc",
.port_type = PCIE_ANY_PORT,
.service = PCIE_PORT_SERVICE_DPC,
.probe = dpc_probe,
.suspend = dpc_suspend,
.resume = dpc_resume,
.remove = dpc_remove,
};

Expand Down

0 comments on commit 689eccd

Please sign in to comment.