Merge branch 'remotes/lorenzo/pci/controller-fixes'

- Restore R-Car PCIe link early in resume (Kazufumi Ikeda)

  - Fix Hyper-V PCI ejection memory leak (Dexuan Cui)

  - Cleanup Hyper-V PCI slots on module unload (Dexuan Cui)

  - Cleanup Hyper-V PCI slot on device removal to address a race (Dexuan
    Cui)

* remotes/lorenzo/pci/controller-fixes:
  PCI: hv: Add pci_destroy_slot() in pci_devices_present_work(), if necessary
  PCI: hv: Add hv_pci_remove_slots() when we unload the driver
  PCI: hv: Fix a memory leak in hv_eject_device_work()
  PCI: rcar: Add the initialization of PCIe link in resume_noirq()
This commit is contained in:
Bjorn Helgaas 2019-05-13 18:34:37 -05:00
commit 4014eb8b61
2 changed files with 44 additions and 0 deletions

View File

@ -1486,6 +1486,21 @@ static void hv_pci_assign_slots(struct hv_pcibus_device *hbus)
}
}
/*
* Remove entries in sysfs pci slot directory.
*/
static void hv_pci_remove_slots(struct hv_pcibus_device *hbus)
{
struct hv_pci_dev *hpdev;
list_for_each_entry(hpdev, &hbus->children, list_entry) {
if (!hpdev->pci_slot)
continue;
pci_destroy_slot(hpdev->pci_slot);
hpdev->pci_slot = NULL;
}
}
/**
* create_root_hv_pci_bus() - Expose a new root PCI bus
* @hbus: Root PCI bus, as understood by this driver
@ -1761,6 +1776,10 @@ static void pci_devices_present_work(struct work_struct *work)
hpdev = list_first_entry(&removed, struct hv_pci_dev,
list_entry);
list_del(&hpdev->list_entry);
if (hpdev->pci_slot)
pci_destroy_slot(hpdev->pci_slot);
put_pcichild(hpdev);
}
@ -1900,6 +1919,9 @@ static void hv_eject_device_work(struct work_struct *work)
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
VM_PKT_DATA_INBAND, 0);
/* For the get_pcichild() in hv_pci_eject_device() */
put_pcichild(hpdev);
/* For the two refs got in new_pcichild_device() */
put_pcichild(hpdev);
put_pcichild(hpdev);
put_hvpcibus(hpdev->hbus);
@ -2677,6 +2699,7 @@ static int hv_pci_remove(struct hv_device *hdev)
pci_lock_rescan_remove();
pci_stop_root_bus(hbus->pci_bus);
pci_remove_root_bus(hbus->pci_bus);
hv_pci_remove_slots(hbus);
pci_unlock_rescan_remove();
hbus->state = hv_pcibus_removed;
}

View File

@ -46,6 +46,7 @@
/* Transfer control */
#define PCIETCTLR 0x02000
#define DL_DOWN BIT(3)
#define CFINIT 1
#define PCIETSTR 0x02004
#define DATA_LINK_ACTIVE 1
@ -94,6 +95,7 @@
#define MACCTLR 0x011058
#define SPEED_CHANGE BIT(24)
#define SCRAMBLE_DISABLE BIT(27)
#define PMSR 0x01105c
#define MACS2R 0x011078
#define MACCGSPSETR 0x011084
#define SPCNGRSN BIT(31)
@ -1130,6 +1132,7 @@ static int rcar_pcie_probe(struct platform_device *pdev)
pcie = pci_host_bridge_priv(bridge);
pcie->dev = dev;
platform_set_drvdata(pdev, pcie);
err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL);
if (err)
@ -1221,10 +1224,28 @@ err_free_bridge:
return err;
}
static int rcar_pcie_resume_noirq(struct device *dev)
{
struct rcar_pcie *pcie = dev_get_drvdata(dev);
if (rcar_pci_read_reg(pcie, PMSR) &&
!(rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN))
return 0;
/* Re-establish the PCIe link */
rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
return rcar_pcie_wait_for_dl(pcie);
}
static const struct dev_pm_ops rcar_pcie_pm_ops = {
.resume_noirq = rcar_pcie_resume_noirq,
};
static struct platform_driver rcar_pcie_driver = {
.driver = {
.name = "rcar-pcie",
.of_match_table = rcar_pcie_of_match,
.pm = &rcar_pcie_pm_ops,
.suppress_bind_attrs = true,
},
.probe = rcar_pcie_probe,