Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  PCI: pci_slot: grab refcount on slot's bus
  PCI Hotplug: acpiphp: grab refcount on p2p subordinate bus
  PCI: allow PCI core hotplug to remove PCI root bus
  PCI: Fix oops in pci_vpd_truncate
  PCI: don't corrupt enable_cnt when doing manual resource alignment
  PCI: annotate pci_rescan_bus as __ref, not __devinit
  PCI-IOV: fix missing kernel-doc
  PCI: Setup disabled bridges even if buses are added
  PCI: SR-IOV quirk for Intel 82576 NIC
This commit is contained in:
Linus Torvalds 2009-04-07 11:24:19 -07:00
commit 8e2c4f2844
10 changed files with 88 additions and 15 deletions

View file

@ -164,6 +164,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
list_add(&slot->list, &slot_list); list_add(&slot->list, &slot_list);
mutex_unlock(&slot_list_lock); mutex_unlock(&slot_list_lock);
get_device(&pci_bus->dev);
dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n", dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n",
pci_slot, pci_bus->number, device, name); pci_slot, pci_bus->number, device, name);
@ -310,12 +312,15 @@ static void
acpi_pci_slot_remove(acpi_handle handle) acpi_pci_slot_remove(acpi_handle handle)
{ {
struct acpi_pci_slot *slot, *tmp; struct acpi_pci_slot *slot, *tmp;
struct pci_bus *pbus;
mutex_lock(&slot_list_lock); mutex_lock(&slot_list_lock);
list_for_each_entry_safe(slot, tmp, &slot_list, list) { list_for_each_entry_safe(slot, tmp, &slot_list, list) {
if (slot->root_handle == handle) { if (slot->root_handle == handle) {
list_del(&slot->list); list_del(&slot->list);
pbus = slot->pci_slot->bus;
pci_destroy_slot(slot->pci_slot); pci_destroy_slot(slot->pci_slot);
put_device(&pbus->dev);
kfree(slot); kfree(slot);
} }
} }

View file

@ -184,7 +184,7 @@ void pci_enable_bridges(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->subordinate) { if (dev->subordinate) {
if (atomic_read(&dev->enable_cnt) == 0) { if (!pci_is_enabled(dev)) {
retval = pci_enable_device(dev); retval = pci_enable_device(dev);
pci_set_master(dev); pci_set_master(dev);
} }

View file

@ -38,6 +38,8 @@
* - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
* when the bridge is scanned and it loses a refcount when the bridge * when the bridge is scanned and it loses a refcount when the bridge
* is removed. * is removed.
* - When a P2P bridge is present, we elevate the refcount on the subordinate
* bus. It loses the refcount when the the driver unloads.
*/ */
#include <linux/init.h> #include <linux/init.h>
@ -440,6 +442,12 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
goto err; goto err;
} }
/*
* Grab a ref to the subordinate PCI bus in case the bus is
* removed via PCI core logical hotplug. The ref pins the bus
* (which we access during module unload).
*/
get_device(&bridge->pci_bus->dev);
spin_lock_init(&bridge->res_lock); spin_lock_init(&bridge->res_lock);
init_bridge_misc(bridge); init_bridge_misc(bridge);
@ -619,6 +627,12 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
slot = next; slot = next;
} }
/*
* Only P2P bridges have a pci_dev
*/
if (bridge->pci_dev)
put_device(&bridge->pci_bus->dev);
pci_dev_put(bridge->pci_dev); pci_dev_put(bridge->pci_dev);
list_del(&bridge->list); list_del(&bridge->list);
kfree(bridge); kfree(bridge);

View file

@ -631,6 +631,7 @@ int pci_iov_bus_range(struct pci_bus *bus)
/** /**
* pci_enable_sriov - enable the SR-IOV capability * pci_enable_sriov - enable the SR-IOV capability
* @dev: the PCI device * @dev: the PCI device
* @nr_virtfn: number of virtual functions to enable
* *
* Returns 0 on success, or negative on failure. * Returns 0 on success, or negative on failure.
*/ */

View file

@ -148,7 +148,7 @@ static ssize_t is_enabled_store(struct device *dev,
return -EPERM; return -EPERM;
if (!val) { if (!val) {
if (atomic_read(&pdev->enable_cnt) != 0) if (pci_is_enabled(pdev))
pci_disable_device(pdev); pci_disable_device(pdev);
else else
result = -EIO; result = -EIO;
@ -277,14 +277,10 @@ remove_store(struct device *dev, struct device_attribute *dummy,
{ {
int ret = 0; int ret = 0;
unsigned long val; unsigned long val;
struct pci_dev *pdev = to_pci_dev(dev);
if (strict_strtoul(buf, 0, &val) < 0) if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL; return -EINVAL;
if (pci_is_root_bus(pdev->bus))
return -EBUSY;
/* An attribute cannot be unregistered by one of its own methods, /* An attribute cannot be unregistered by one of its own methods,
* so we have to use this roundabout approach. * so we have to use this roundabout approach.
*/ */

View file

@ -844,7 +844,7 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
*/ */
int pci_reenable_device(struct pci_dev *dev) int pci_reenable_device(struct pci_dev *dev)
{ {
if (atomic_read(&dev->enable_cnt)) if (pci_is_enabled(dev))
return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1); return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
return 0; return 0;
} }
@ -1042,7 +1042,7 @@ static void do_pci_disable_device(struct pci_dev *dev)
*/ */
void pci_disable_enabled_device(struct pci_dev *dev) void pci_disable_enabled_device(struct pci_dev *dev)
{ {
if (atomic_read(&dev->enable_cnt)) if (pci_is_enabled(dev))
do_pci_disable_device(dev); do_pci_disable_device(dev);
} }

View file

@ -1220,7 +1220,7 @@ EXPORT_SYMBOL(pci_scan_bus_parented);
* *
* Returns the max number of subordinate bus discovered. * Returns the max number of subordinate bus discovered.
*/ */
unsigned int __devinit pci_rescan_bus(struct pci_bus *bus) unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
{ {
unsigned int max; unsigned int max;
struct pci_dev *dev; struct pci_dev *dev;

View file

@ -36,17 +36,18 @@ EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_PCI_QUIRKS #ifdef CONFIG_PCI_QUIRKS
/* /*
* This quirk function disables the device and releases resources * This quirk function disables memory decoding and releases memory resources
* which is specified by kernel's boot parameter 'pci=resource_alignment='. * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
* It also rounds up size to specified alignment. * It also rounds up size to specified alignment.
* Later on, the kernel will assign page-aligned memory resource back * Later on, the kernel will assign page-aligned memory resource back
* to that device. * to the device.
*/ */
static void __devinit quirk_resource_alignment(struct pci_dev *dev) static void __devinit quirk_resource_alignment(struct pci_dev *dev)
{ {
int i; int i;
struct resource *r; struct resource *r;
resource_size_t align, size; resource_size_t align, size;
u16 command;
if (!pci_is_reassigndev(dev)) if (!pci_is_reassigndev(dev))
return; return;
@ -58,8 +59,11 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev)
return; return;
} }
dev_info(&dev->dev, "Disabling device and release resources.\n"); dev_info(&dev->dev,
pci_disable_device(dev); "Disabling memory decoding and releasing memory resources.\n");
pci_read_config_word(dev, PCI_COMMAND, &command);
command &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, command);
align = pci_specified_resource_alignment(dev); align = pci_specified_resource_alignment(dev);
for (i=0; i < PCI_BRIDGE_RESOURCES; i++) { for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
@ -2411,6 +2415,54 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
#endif /* CONFIG_PCI_MSI */ #endif /* CONFIG_PCI_MSI */
#ifdef CONFIG_PCI_IOV
/*
* For Intel 82576 SR-IOV NIC, if BIOS doesn't allocate resources for the
* SR-IOV BARs, zero the Flash BAR and program the SR-IOV BARs to use the
* old Flash Memory Space.
*/
static void __devinit quirk_i82576_sriov(struct pci_dev *dev)
{
int pos, flags;
u32 bar, start, size;
if (PAGE_SIZE > 0x10000)
return;
flags = pci_resource_flags(dev, 0);
if ((flags & PCI_BASE_ADDRESS_SPACE) !=
PCI_BASE_ADDRESS_SPACE_MEMORY ||
(flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) !=
PCI_BASE_ADDRESS_MEM_TYPE_32)
return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
if (!pos)
return;
pci_read_config_dword(dev, pos + PCI_SRIOV_BAR, &bar);
if (bar & PCI_BASE_ADDRESS_MEM_MASK)
return;
start = pci_resource_start(dev, 1);
size = pci_resource_len(dev, 1);
if (!start || size != 0x400000 || start & (size - 1))
return;
pci_resource_flags(dev, 1) = 0;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
pci_write_config_dword(dev, pos + PCI_SRIOV_BAR, start);
pci_write_config_dword(dev, pos + PCI_SRIOV_BAR + 12, start + size / 2);
dev_info(&dev->dev, "use Flash Memory Space for SR-IOV BARs\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov);
#endif /* CONFIG_PCI_IOV */
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end) struct pci_fixup *end)
{ {

View file

@ -144,7 +144,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
struct pci_bus_region region; struct pci_bus_region region;
u32 l, bu, lu, io_upper16; u32 l, bu, lu, io_upper16;
if (!pci_is_root_bus(bus) && bus->is_added) if (pci_is_enabled(bridge))
return; return;
dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n",

View file

@ -674,6 +674,11 @@ int __must_check pci_reenable_device(struct pci_dev *);
int __must_check pcim_enable_device(struct pci_dev *pdev); int __must_check pcim_enable_device(struct pci_dev *pdev);
void pcim_pin_device(struct pci_dev *pdev); void pcim_pin_device(struct pci_dev *pdev);
static inline int pci_is_enabled(struct pci_dev *pdev)
{
return (atomic_read(&pdev->enable_cnt) > 0);
}
static inline int pci_is_managed(struct pci_dev *pdev) static inline int pci_is_managed(struct pci_dev *pdev)
{ {
return pdev->is_managed; return pdev->is_managed;