From 76dc10b829f3beebd23c0c99dd653e50b429c5bd Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 4 Feb 2014 11:48:16 -0500 Subject: [PATCH] pci: Don't assume the removed device is a bridge. When we are instructed to remove a PCI device it is usally done from the initial domain via PHYSDEVOP_pci_device_remove or PHYSDEVOP_manage_pci_remove. That is OK except in the case where the initial domain has re-programmed the PCI bridges with a new PCI_SUBORDINATE_BUS value causing the bus number to change. That means a device that had been addressed via say this BDF: 06:00.0 is now addressed via 09:00.0. Now assume that the device that is being deleted is a bridge and it used to be 06:00.0 - but since the bus numbers are different any reads done on the PCI_SUBORDINATE_BUS can return bogus values (as we are now addressing a completetly new device). To guard against that we save away the subordinate and secondary bus numbers the first time the device is introduced. Then when the device is deleted we use those values instead of reading from the PCI device. Signed-off-by: Konrad Rzeszutek Wilk --- xen/drivers/passthrough/pci.c | 8 ++++---- xen/include/xen/pci.h | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 6152370..4e73427 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -201,6 +201,8 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn) sub_bus = pci_conf_read8(pseg->nr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_SUBORDINATE_BUS); + pdev->info.bus.sec = sec_bus; + pdev->info.bus.sub = sub_bus; spin_lock(&pseg->bus2bridge_lock); for ( ; sec_bus <= sub_bus; sec_bus++ ) { @@ -265,10 +267,8 @@ static void free_pdev(struct pci_seg *pseg, struct pci_dev *pdev) case DEV_TYPE_LEGACY_PCI_BRIDGE: dev = PCI_SLOT(pdev->devfn); func = PCI_FUNC(pdev->devfn); - sec_bus = pci_conf_read8(pseg->nr, pdev->bus, dev, func, - PCI_SECONDARY_BUS); - sub_bus = pci_conf_read8(pseg->nr, pdev->bus, dev, func, - PCI_SUBORDINATE_BUS); + sec_bus = pdev->info.bus.sec; + sub_bus = pdev->info.bus.sub; spin_lock(&pseg->bus2bridge_lock); for ( ; sec_bus <= sub_bus; sec_bus++ ) diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index cadb525..c3f6ee4 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -39,6 +39,10 @@ struct pci_dev_info { u8 bus; u8 devfn; } physfn; + struct { + u8 sec; + u8 sub; + } bus; /* Only set if device is a bridge */ }; struct pci_dev { -- 1.7.7.6