Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Setup disabled bridges even if buses are added

This patch sets up disabled bridges even if buses have already been
added.

pci_assign_unassigned_resources is called after buses are added.
pci_assign_unassigned_resources calls pci_bus_assign_resources.
pci_bus_assign_resources calls pci_setup_bridge to configure BARs of
bridges.

Currently pci_setup_bridge returns immediately if the bus have already
been added. So pci_assign_unassigned_resources can't configure BARs of
bridges that were added in a disabled state; this patch fixes the issue.

On logical hot-add, we need to prevent the kernel from re-initializing
bridges that have already been initialized. To achieve this,
pci_setup_bridge returns immediately if the bridge have already been
enabled.

We don't need to check whether the specified bus is a root bus or not.
pci_setup_bridge is not called on a root bus, because a root bus does
not have a bridge.

The patch adds a new helper function, pci_is_enabled. I made the
function name similar to pci_is_managed. The codes which use
enable_cnt directly are changed to use pci_is_enabled.

Acked-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

authored by

Yuji Shimada and committed by
Jesse Barnes
296ccb08 7eb93b17

+10 -5
+1 -1
drivers/pci/bus.c
··· 184 184 185 185 list_for_each_entry(dev, &bus->devices, bus_list) { 186 186 if (dev->subordinate) { 187 - if (atomic_read(&dev->enable_cnt) == 0) { 187 + if (!pci_is_enabled(dev)) { 188 188 retval = pci_enable_device(dev); 189 189 pci_set_master(dev); 190 190 }
+1 -1
drivers/pci/pci-sysfs.c
··· 148 148 return -EPERM; 149 149 150 150 if (!val) { 151 - if (atomic_read(&pdev->enable_cnt) != 0) 151 + if (pci_is_enabled(pdev)) 152 152 pci_disable_device(pdev); 153 153 else 154 154 result = -EIO;
+2 -2
drivers/pci/pci.c
··· 844 844 */ 845 845 int pci_reenable_device(struct pci_dev *dev) 846 846 { 847 - if (atomic_read(&dev->enable_cnt)) 847 + if (pci_is_enabled(dev)) 848 848 return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); 849 849 return 0; 850 850 } ··· 1042 1042 */ 1043 1043 void pci_disable_enabled_device(struct pci_dev *dev) 1044 1044 { 1045 - if (atomic_read(&dev->enable_cnt)) 1045 + if (pci_is_enabled(dev)) 1046 1046 do_pci_disable_device(dev); 1047 1047 } 1048 1048
+1 -1
drivers/pci/setup-bus.c
··· 144 144 struct pci_bus_region region; 145 145 u32 l, bu, lu, io_upper16; 146 146 147 - if (!pci_is_root_bus(bus) && bus->is_added) 147 + if (pci_is_enabled(bridge)) 148 148 return; 149 149 150 150 dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n",
+5
include/linux/pci.h
··· 674 674 int __must_check pcim_enable_device(struct pci_dev *pdev); 675 675 void pcim_pin_device(struct pci_dev *pdev); 676 676 677 + static inline int pci_is_enabled(struct pci_dev *pdev) 678 + { 679 + return (atomic_read(&pdev->enable_cnt) > 0); 680 + } 681 + 677 682 static inline int pci_is_managed(struct pci_dev *pdev) 678 683 { 679 684 return pdev->is_managed;