Skip to content

Commit 5249048

Browse files
committed
Merge branch 'pci/err'
- Disable AER and DPC during suspend so that if they share an interrupt with PME and errors occur during suspend, the AER or DPC interrupt doesn't cause spurious wakeups (Kai-Heng Feng) * pci/err: PCI/DPC: Disable DPC service on suspend PCI/AER: Disable AER service on suspend
2 parents 903a3b1 + 75c47c7 commit 5249048

File tree

2 files changed

+66
-12
lines changed

2 files changed

+66
-12
lines changed

drivers/pci/pcie/aer.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,22 @@ static int aer_probe(struct pcie_device *dev)
14971497
return 0;
14981498
}
14991499

1500+
static int aer_suspend(struct pcie_device *dev)
1501+
{
1502+
struct aer_rpc *rpc = get_service_data(dev);
1503+
1504+
aer_disable_rootport(rpc);
1505+
return 0;
1506+
}
1507+
1508+
static int aer_resume(struct pcie_device *dev)
1509+
{
1510+
struct aer_rpc *rpc = get_service_data(dev);
1511+
1512+
aer_enable_rootport(rpc);
1513+
return 0;
1514+
}
1515+
15001516
/**
15011517
* aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
15021518
* @dev: pointer to Root Port, RCEC, or RCiEP
@@ -1561,6 +1577,8 @@ static struct pcie_port_service_driver aerdriver = {
15611577
.service = PCIE_PORT_SERVICE_AER,
15621578

15631579
.probe = aer_probe,
1580+
.suspend = aer_suspend,
1581+
.resume = aer_resume,
15641582
.remove = aer_remove,
15651583
};
15661584

drivers/pci/pcie/dpc.c

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -412,13 +412,44 @@ void pci_dpc_init(struct pci_dev *pdev)
412412
}
413413
}
414414

415+
static void dpc_enable(struct pcie_device *dev)
416+
{
417+
struct pci_dev *pdev = dev->port;
418+
int dpc = pdev->dpc_cap;
419+
u16 ctl;
420+
421+
/*
422+
* Clear DPC Interrupt Status so we don't get an interrupt for an
423+
* old event when setting DPC Interrupt Enable.
424+
*/
425+
pci_write_config_word(pdev, dpc + PCI_EXP_DPC_STATUS,
426+
PCI_EXP_DPC_STATUS_INTERRUPT);
427+
428+
pci_read_config_word(pdev, dpc + PCI_EXP_DPC_CTL, &ctl);
429+
ctl &= ~PCI_EXP_DPC_CTL_EN_MASK;
430+
ctl |= PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
431+
pci_write_config_word(pdev, dpc + PCI_EXP_DPC_CTL, ctl);
432+
}
433+
434+
static void dpc_disable(struct pcie_device *dev)
435+
{
436+
struct pci_dev *pdev = dev->port;
437+
int dpc = pdev->dpc_cap;
438+
u16 ctl;
439+
440+
/* Disable DPC triggering and DPC interrupts */
441+
pci_read_config_word(pdev, dpc + PCI_EXP_DPC_CTL, &ctl);
442+
ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN);
443+
pci_write_config_word(pdev, dpc + PCI_EXP_DPC_CTL, ctl);
444+
}
445+
415446
#define FLAG(x, y) (((x) & (y)) ? '+' : '-')
416447
static int dpc_probe(struct pcie_device *dev)
417448
{
418449
struct pci_dev *pdev = dev->port;
419450
struct device *device = &dev->device;
420451
int status;
421-
u16 ctl, cap;
452+
u16 cap;
422453

423454
if (!pcie_aer_is_native(pdev) && !pcie_ports_dpc_native)
424455
return -ENOTSUPP;
@@ -433,11 +464,7 @@ static int dpc_probe(struct pcie_device *dev)
433464
}
434465

435466
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CAP, &cap);
436-
437-
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);
438-
ctl &= ~PCI_EXP_DPC_CTL_EN_MASK;
439-
ctl |= PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
440-
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
467+
dpc_enable(dev);
441468

442469
pci_info(pdev, "enabled with IRQ %d\n", dev->irq);
443470
pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
@@ -450,21 +477,30 @@ static int dpc_probe(struct pcie_device *dev)
450477
return status;
451478
}
452479

453-
static void dpc_remove(struct pcie_device *dev)
480+
static int dpc_suspend(struct pcie_device *dev)
454481
{
455-
struct pci_dev *pdev = dev->port;
456-
u16 ctl;
482+
dpc_disable(dev);
483+
return 0;
484+
}
457485

458-
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);
459-
ctl &= ~(PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN);
460-
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
486+
static int dpc_resume(struct pcie_device *dev)
487+
{
488+
dpc_enable(dev);
489+
return 0;
490+
}
491+
492+
static void dpc_remove(struct pcie_device *dev)
493+
{
494+
dpc_disable(dev);
461495
}
462496

463497
static struct pcie_port_service_driver dpcdriver = {
464498
.name = "dpc",
465499
.port_type = PCIE_ANY_PORT,
466500
.service = PCIE_PORT_SERVICE_DPC,
467501
.probe = dpc_probe,
502+
.suspend = dpc_suspend,
503+
.resume = dpc_resume,
468504
.remove = dpc_remove,
469505
};
470506

0 commit comments

Comments
 (0)