Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
Linus Torvalds committed Apr 7, 2009
2 parents 6a5d263 + 7280036 commit 8e2c4f2
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 15 deletions.
5 changes: 5 additions & 0 deletions drivers/acpi/pci_slot.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
list_add(&slot->list, &slot_list);
mutex_unlock(&slot_list_lock);

get_device(&pci_bus->dev);

dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n",
pci_slot, pci_bus->number, device, name);

Expand Down Expand Up @@ -310,12 +312,15 @@ static void
acpi_pci_slot_remove(acpi_handle handle)
{
struct acpi_pci_slot *slot, *tmp;
struct pci_bus *pbus;

mutex_lock(&slot_list_lock);
list_for_each_entry_safe(slot, tmp, &slot_list, list) {
if (slot->root_handle == handle) {
list_del(&slot->list);
pbus = slot->pci_slot->bus;
pci_destroy_slot(slot->pci_slot);
put_device(&pbus->dev);
kfree(slot);
}
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ void pci_enable_bridges(struct pci_bus *bus)

list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->subordinate) {
if (atomic_read(&dev->enable_cnt) == 0) {
if (!pci_is_enabled(dev)) {
retval = pci_enable_device(dev);
pci_set_master(dev);
}
Expand Down
14 changes: 14 additions & 0 deletions drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
* - 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
* 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>
Expand Down Expand Up @@ -440,6 +442,12 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
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);

init_bridge_misc(bridge);
Expand Down Expand Up @@ -619,6 +627,12 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
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);
list_del(&bridge->list);
kfree(bridge);
Expand Down
1 change: 1 addition & 0 deletions drivers/pci/iov.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ int pci_iov_bus_range(struct pci_bus *bus)
/**
* pci_enable_sriov - enable the SR-IOV capability
* @dev: the PCI device
* @nr_virtfn: number of virtual functions to enable
*
* Returns 0 on success, or negative on failure.
*/
Expand Down
6 changes: 1 addition & 5 deletions drivers/pci/pci-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static ssize_t is_enabled_store(struct device *dev,
return -EPERM;

if (!val) {
if (atomic_read(&pdev->enable_cnt) != 0)
if (pci_is_enabled(pdev))
pci_disable_device(pdev);
else
result = -EIO;
Expand Down Expand Up @@ -277,14 +277,10 @@ remove_store(struct device *dev, struct device_attribute *dummy,
{
int ret = 0;
unsigned long val;
struct pci_dev *pdev = to_pci_dev(dev);

if (strict_strtoul(buf, 0, &val) < 0)
return -EINVAL;

if (pci_is_root_bus(pdev->bus))
return -EBUSY;

/* An attribute cannot be unregistered by one of its own methods,
* so we have to use this roundabout approach.
*/
Expand Down
4 changes: 2 additions & 2 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
*/
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 0;
}
Expand Down Expand Up @@ -1042,7 +1042,7 @@ static void do_pci_disable_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);
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ EXPORT_SYMBOL(pci_scan_bus_parented);
*
* 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;
struct pci_dev *dev;
Expand Down
62 changes: 57 additions & 5 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ EXPORT_SYMBOL(pcie_mch_quirk);

#ifdef CONFIG_PCI_QUIRKS
/*
* This quirk function disables the device and releases resources
* which is specified by kernel's boot parameter 'pci=resource_alignment='.
* This quirk function disables memory decoding and releases memory resources
* of the device specified by kernel's boot parameter 'pci=resource_alignment='.
* It also rounds up size to specified alignment.
* 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)
{
int i;
struct resource *r;
resource_size_t align, size;
u16 command;

if (!pci_is_reassigndev(dev))
return;
Expand All @@ -58,8 +59,11 @@ static void __devinit quirk_resource_alignment(struct pci_dev *dev)
return;
}

dev_info(&dev->dev, "Disabling device and release resources.\n");
pci_disable_device(dev);
dev_info(&dev->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);
for (i=0; i < PCI_BRIDGE_RESOURCES; i++) {
Expand Down Expand Up @@ -2411,6 +2415,54 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,

#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,
struct pci_fixup *end)
{
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/setup-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static void pci_setup_bridge(struct pci_bus *bus)
struct pci_bus_region region;
u32 l, bu, lu, io_upper16;

if (!pci_is_root_bus(bus) && bus->is_added)
if (pci_is_enabled(bridge))
return;

dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n",
Expand Down
5 changes: 5 additions & 0 deletions include/linux/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,11 @@ int __must_check pci_reenable_device(struct pci_dev *);
int __must_check pcim_enable_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)
{
return pdev->is_managed;
Expand Down

0 comments on commit 8e2c4f2

Please sign in to comment.